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