00001
00002
00003
00004
00005
00006
00007
00008 #include "wvstring.h"
00009 #include <ctype.h>
00010 #include <assert.h>
00011
00012 WvStringBuf WvFastString::nullbuf = { 0, 1 };
00013 const WvFastString WvFastString::null;
00014
00015 const WvString WvString::empty("");
00016
00017
00018
00019 static inline int _max(int x, int y)
00020 {
00021 return x>y ? x : y;
00022 }
00023
00024
00025 void WvFastString::setsize(size_t i)
00026 {
00027 unlink();
00028 newbuf(i);
00029 }
00030
00031
00032
00033 WvFastString::WvFastString()
00034 {
00035 link(&nullbuf, NULL);
00036 }
00037
00038
00039 WvFastString::WvFastString(const WvFastString &s)
00040 {
00041 link(s.buf, s.str);
00042 }
00043
00044
00045 WvFastString::WvFastString(const WvString &s)
00046 {
00047 link(s.buf, s.str);
00048 }
00049
00050
00051 void WvFastString::construct(const char *_str)
00052 {
00053
00054 str = (char *)_str;
00055 buf = NULL;
00056 }
00057
00058
00059 WvFastString::WvFastString(const char *_str)
00060 {
00061 construct(_str);
00062 }
00063
00064
00065 void WvString::copy_constructor(const WvFastString &s)
00066 {
00067 unlink();
00068
00069 if (!s.buf)
00070 {
00071 link(&nullbuf, s.str);
00072 unique();
00073 }
00074 else
00075 link(s.buf, s.str);
00076 }
00077
00078
00079 WvString::WvString(const char *_str)
00080 {
00081 unlink();
00082 construct(_str);
00083 }
00084
00085
00086
00087
00088 template <typename T>
00089 inline static char *wv_uitoar(char *begin, T i)
00090 {
00091 if (!begin)
00092 return NULL;
00093
00094 char *end = begin;
00095
00096 if (i == 0)
00097 *end++ = '0';
00098 else
00099 {
00100 while (i > 0)
00101 {
00102 switch (i % 10)
00103 {
00104 case 0: *end++ = '0'; break;
00105 case 1: *end++ = '1'; break;
00106 case 2: *end++ = '2'; break;
00107 case 3: *end++ = '3'; break;
00108 case 4: *end++ = '4'; break;
00109 case 5: *end++ = '5'; break;
00110 case 6: *end++ = '6'; break;
00111 case 7: *end++ = '7'; break;
00112 case 8: *end++ = '8'; break;
00113 case 9: *end++ = '9'; break;
00114 default: ;
00115 }
00116 i /= 10;
00117 }
00118 }
00119
00120 *end = '\0';
00121 return end;
00122 }
00123
00124
00125
00126 template <typename T>
00127 inline static char *wv_itoar(char *begin, T i)
00128 {
00129 if (!begin)
00130 return NULL;
00131
00132 bool negative = false;
00133 if (i < 0)
00134 {
00135 negative = true;
00136 i = -i;
00137 }
00138 char *end = wv_uitoar(begin, i);
00139 if (negative)
00140 {
00141 *end++ = '-';
00142 *end = '\0';
00143 }
00144 return end;
00145 }
00146
00147
00148 inline static void wv_strrev(char *begin, char *end)
00149 {
00150 if (!begin && !end)
00151 return;
00152
00153 --end;
00154
00155 while (begin < end)
00156 {
00157 *begin ^= *end;
00158 *end ^= *begin;
00159 *begin ^= *end;
00160 ++begin;
00161 --end;
00162 }
00163 }
00164
00165
00166
00167
00168
00169 WvFastString::WvFastString(short i)
00170 {
00171 newbuf(32);
00172 wv_strrev(str, wv_itoar(str, i));
00173 }
00174
00175
00176 WvFastString::WvFastString(unsigned short i)
00177 {
00178 newbuf(32);
00179 wv_strrev(str, wv_uitoar(str, i));
00180 }
00181
00182
00183 WvFastString::WvFastString(int i)
00184 {
00185 newbuf(32);
00186 wv_strrev(str, wv_itoar(str, i));
00187 }
00188
00189
00190 WvFastString::WvFastString(unsigned int i)
00191 {
00192 newbuf(32);
00193 wv_strrev(str, wv_uitoar(str, i));
00194 }
00195
00196
00197 WvFastString::WvFastString(long i)
00198 {
00199 newbuf(32);
00200 wv_strrev(str, wv_itoar(str, i));
00201 }
00202
00203
00204 WvFastString::WvFastString(unsigned long i)
00205 {
00206 newbuf(32);
00207 wv_strrev(str, wv_uitoar(str, i));
00208 }
00209
00210
00211 WvFastString::WvFastString(long long i)
00212 {
00213 newbuf(32);
00214 wv_strrev(str, wv_itoar(str, i));
00215 }
00216
00217
00218 WvFastString::WvFastString(unsigned long long i)
00219 {
00220 newbuf(32);
00221 wv_strrev(str, wv_uitoar(str, i));
00222 }
00223
00224
00225 WvFastString::WvFastString(double i)
00226 {
00227 newbuf(32);
00228 sprintf(str, "%g", i);
00229 }
00230
00231
00232 WvFastString::~WvFastString()
00233 {
00234 unlink();
00235 }
00236
00237
00238 void WvFastString::unlink()
00239 {
00240 if (buf && ! --buf->links)
00241 {
00242 free(buf);
00243 buf = NULL;
00244 }
00245 }
00246
00247
00248 void WvFastString::link(WvStringBuf *_buf, const char *_str)
00249 {
00250 buf = _buf;
00251 if (buf)
00252 buf->links++;
00253 str = (char *)_str;
00254 }
00255
00256
00257 WvStringBuf *WvFastString::alloc(size_t size)
00258 {
00259 WvStringBuf *abuf = (WvStringBuf *)malloc(
00260 (WVSTRINGBUF_SIZE(buf) + size + WVSTRING_EXTRA) | 3);
00261 abuf->links = 0;
00262 abuf->size = size;
00263 return abuf;
00264 }
00265
00266
00267 WvString &WvString::append(WvStringParm s)
00268 {
00269 if (s)
00270 {
00271 if (*this)
00272 *this = WvString("%s%s", *this, s);
00273 else
00274 *this = s;
00275 }
00276
00277 return *this;
00278 }
00279
00280
00281 size_t WvFastString::len() const
00282 {
00283 return str ? strlen(str) : 0;
00284 }
00285
00286
00287 void WvFastString::newbuf(size_t size)
00288 {
00289 buf = alloc(size);
00290 buf->links = 1;
00291 str = buf->data;
00292 }
00293
00294
00295
00296
00297 WvString &WvString::unique()
00298 {
00299 if (!is_unique() && str)
00300 {
00301 WvStringBuf *newb = alloc(len() + 1);
00302 memcpy(newb->data, str, newb->size);
00303 unlink();
00304 link(newb, newb->data);
00305 }
00306
00307 return *this;
00308 }
00309
00310
00311 bool WvString::is_unique() const
00312 {
00313 return (buf->links <= 1);
00314 }
00315
00316
00317 WvFastString &WvFastString::operator= (const WvFastString &s2)
00318 {
00319 if (s2.buf == buf && s2.str == str)
00320 return *this;
00321 else
00322 {
00323 unlink();
00324 link(s2.buf, s2.str);
00325 }
00326 return *this;
00327 }
00328
00329
00330 WvString &WvString::operator= (int i)
00331 {
00332 unlink();
00333 newbuf(32);
00334 sprintf(str, "%d", i);
00335 return *this;
00336 }
00337
00338
00339 WvString &WvString::operator= (const WvFastString &s2)
00340 {
00341 if (s2.str == str && (!s2.buf || s2.buf == buf))
00342 return *this;
00343 else if (!s2.buf)
00344 {
00345
00346 if (str && buf && buf->links == 1)
00347 {
00348
00349 if (buf->size == 0)
00350 buf->size = strlen(str);
00351
00352 if (str < s2.str && s2.str <= (str + buf->size))
00353 {
00354
00355
00356 memmove(buf->data, s2.str, buf->size);
00357 return *this;
00358 }
00359 }
00360
00361 unlink();
00362 link(&nullbuf, s2.str);
00363 unique();
00364 }
00365 else
00366 {
00367
00368 unlink();
00369 link(s2.buf, s2.str);
00370 }
00371 return *this;
00372 }
00373
00374
00375
00376 bool WvFastString::operator== (WvStringParm s2) const
00377 {
00378 return (str==s2.str) || (str && s2.str && !strcmp(str, s2.str));
00379 }
00380
00381
00382 bool WvFastString::operator!= (WvStringParm s2) const
00383 {
00384 return (str!=s2.str) && (!str || !s2.str || strcmp(str, s2.str));
00385 }
00386
00387
00388 bool WvFastString::operator< (WvStringParm s2) const
00389 {
00390 if (str == s2.str) return false;
00391 if (str == 0) return true;
00392 if (s2.str == 0) return false;
00393 return strcmp(str, s2.str) < 0;
00394 }
00395
00396
00397 bool WvFastString::operator== (const char *s2) const
00398 {
00399 return (str==s2) || (str && s2 && !strcmp(str, s2));
00400 }
00401
00402
00403 bool WvFastString::operator!= (const char *s2) const
00404 {
00405 return (str!=s2) && (!str || !s2 || strcmp(str, s2));
00406 }
00407
00408
00409 bool WvFastString::operator< (const char *s2) const
00410 {
00411 if (str == s2) return false;
00412 if (str == 0) return true;
00413 if (s2 == 0) return false;
00414 return strcmp(str, s2) < 0;
00415 }
00416
00417
00418
00419 bool WvFastString::operator! () const
00420 {
00421 return !str || !str[0];
00422 }
00423
00424
00436 static const char *pparse(const char *cptr, bool &zeropad,
00437 int &justify, int &maxlen, int &argnum)
00438 {
00439 assert(*cptr == '%');
00440 cptr++;
00441
00442 zeropad = (*cptr == '0');
00443
00444 justify = atoi(cptr);
00445
00446 for (; *cptr && *cptr!='.' && *cptr!='%' && *cptr!='$'
00447 && !isalpha(*cptr); cptr++)
00448 ;
00449 if (!*cptr) return cptr;
00450
00451 if (*cptr == '.')
00452 maxlen = atoi(cptr+1);
00453 else
00454 maxlen = 0;
00455
00456 for (; *cptr && *cptr!='%' && *cptr!='$' && !isalpha(*cptr); cptr++)
00457 ;
00458 if (!*cptr) return cptr;
00459
00460 if (*cptr == '$')
00461 argnum = atoi(cptr+1);
00462 else
00463 argnum = 0;
00464
00465 for (; *cptr && *cptr!='%' && !isalpha(*cptr); cptr++)
00466 ;
00467
00468 return cptr;
00469 }
00470
00471
00488 void WvFastString::do_format(WvFastString &output, const char *format,
00489 const WvFastString * const *argv)
00490 {
00491 static const char blank[] = "(nil)";
00492 const WvFastString * const *argptr = argv;
00493 const WvFastString * const *argP;
00494 const char *iptr = format, *arg;
00495 char *optr;
00496 int total = 0, aplen, ladd, justify, maxlen, argnum;
00497 bool zeropad;
00498
00499
00500 while (*iptr)
00501 {
00502 if (*iptr != '%')
00503 {
00504 total++;
00505 iptr++;
00506 continue;
00507 }
00508
00509
00510 argnum=0;
00511 iptr = pparse(iptr, zeropad, justify, maxlen, argnum);
00512 if (*iptr == '%')
00513 {
00514 total++;
00515 iptr++;
00516 continue;
00517 }
00518
00519 assert(*iptr == 's' || *iptr == 'c');
00520
00521 if (*iptr == 's')
00522 {
00523 argP = (argnum > 0 ) ? (argv + argnum -1): argptr;
00524 if (!*argP || !(**argP).cstr())
00525 arg = blank;
00526 else
00527 arg = (**argP).cstr();
00528 ladd = _max(abs(justify), strlen(arg));
00529 if (maxlen && maxlen < ladd)
00530 ladd = maxlen;
00531 total += ladd;
00532 if ( argnum <= 0 )
00533 argptr++;
00534 iptr++;
00535 continue;
00536 }
00537
00538 if (*iptr++ == 'c')
00539 {
00540 if ( argnum <= 0 )
00541 argptr++;
00542 total++;
00543 }
00544 }
00545
00546 output.setsize(total + 1);
00547
00548
00549 iptr = format;
00550 optr = output.str;
00551 argptr = argv;
00552 while (*iptr)
00553 {
00554 if (*iptr != '%')
00555 {
00556 *optr++ = *iptr++;
00557 continue;
00558 }
00559
00560
00561 argnum=0;
00562 iptr = pparse(iptr, zeropad, justify, maxlen, argnum);
00563 if (*iptr == '%')
00564 {
00565 *optr++ = *iptr++;
00566 continue;
00567 }
00568 if (*iptr == 's')
00569 {
00570 argP = (argnum > 0 ) ? (argv + argnum -1): argptr;
00571 if (!*argP || !(**argP).cstr())
00572 arg = blank;
00573 else
00574 arg = (**argP).cstr();
00575 aplen = strlen(arg);
00576 if (maxlen && maxlen < aplen)
00577 aplen = maxlen;
00578
00579 if (justify > aplen)
00580 {
00581 if (zeropad)
00582 memset(optr, '0', justify-aplen);
00583 else
00584 memset(optr, ' ', justify-aplen);
00585 optr += justify-aplen;
00586 }
00587
00588 strncpy(optr, arg, aplen);
00589 optr += aplen;
00590
00591 if (justify < 0 && -justify > aplen)
00592 {
00593 if (zeropad)
00594 memset(optr, '0', -justify-aplen);
00595 else
00596 memset(optr, ' ', -justify-aplen);
00597 optr += -justify - aplen;
00598 }
00599
00600 if ( argnum <= 0 )
00601 argptr++;
00602 iptr++;
00603 continue;
00604 }
00605 if (*iptr++ == 'c')
00606 {
00607 argP = (argnum > 0 ) ? (argv + argnum -1): argptr++;
00608 if (!*argP || !(**argP))
00609 arg = " ";
00610 else
00611 arg = (**argP);
00612 *optr++ = (char)atoi(arg);
00613 }
00614 }
00615 *optr = 0;
00616 }
00617
00618