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