Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wvstring.cc

Go to the documentation of this file.
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * Implementation of a simple and efficient printable-string class. Most 00006 * of the class is actually inlined and can be found in wvstring.h. 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 // always a handy function 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 WvFastString::WvFastString(const char *_str) 00052 { 00053 // just copy the pointer - no need to allocate memory! 00054 str = (char *)_str; // I promise not to change anything! 00055 buf = NULL; 00056 } 00057 00058 00059 void WvString::copy_constructor(const WvFastString &s) 00060 { 00061 if (!s.buf) 00062 { 00063 link(&nullbuf, s.str); 00064 unique(); 00065 } 00066 else 00067 link(s.buf, s.str); // already in a nice, safe WvStreamBuf 00068 } 00069 00070 00071 WvString::WvString(const char *_str) 00072 { 00073 link(&nullbuf, _str); 00074 00075 // apenwarr (2002/04/24): from now on, all WvString objects are created 00076 // with unique(), so you should _never_ have to call it explicitly. We 00077 // still can (and should!) use fast parameter passing via WvFastString. 00078 unique(); 00079 } 00080 00081 00082 // NOTE: make sure that 32 bytes is big enough for your longest int. 00083 // This is true up to at least 64 bits. 00084 WvFastString::WvFastString(short i) 00085 { 00086 newbuf(32); 00087 sprintf(str, "%hd", i); 00088 } 00089 00090 00091 WvFastString::WvFastString(unsigned short i) 00092 { 00093 newbuf(32); 00094 sprintf(str, "%hu", i); 00095 } 00096 00097 00098 WvFastString::WvFastString(int i) 00099 { 00100 newbuf(32); 00101 sprintf(str, "%d", i); 00102 } 00103 00104 00105 WvFastString::WvFastString(unsigned int i) 00106 { 00107 newbuf(32); 00108 sprintf(str, "%u", i); 00109 } 00110 00111 00112 WvFastString::WvFastString(long i) 00113 { 00114 newbuf(32); 00115 sprintf(str, "%ld", i); 00116 } 00117 00118 00119 WvFastString::WvFastString(unsigned long i) 00120 { 00121 newbuf(32); 00122 sprintf(str, "%lu", i); 00123 } 00124 00125 00126 WvFastString::WvFastString(long long i) 00127 { 00128 newbuf(32); 00129 sprintf(str, "%lld", i); 00130 } 00131 00132 00133 WvFastString::WvFastString(unsigned long long i) 00134 { 00135 newbuf(32); 00136 sprintf(str, "%llu", i); 00137 } 00138 00139 00140 WvFastString::WvFastString(double i) 00141 { 00142 newbuf(32); 00143 sprintf(str, "%g", i); 00144 } 00145 00146 00147 WvFastString::~WvFastString() 00148 { 00149 unlink(); 00150 } 00151 00152 00153 void WvFastString::unlink() 00154 { 00155 if (buf && ! --buf->links) 00156 { 00157 free(buf); 00158 buf = NULL; 00159 } 00160 } 00161 00162 00163 void WvFastString::link(WvStringBuf *_buf, const char *_str) 00164 { 00165 buf = _buf; 00166 if (buf) 00167 buf->links++; 00168 str = (char *)_str; // I promise not to change it without asking! 00169 } 00170 00171 00172 WvStringBuf *WvFastString::alloc(size_t size) 00173 { 00174 WvStringBuf *abuf = (WvStringBuf *)malloc(WVSTRINGBUF_SIZE(buf) 00175 + size + WVSTRING_EXTRA); 00176 abuf->links = 0; 00177 abuf->size = size; 00178 return abuf; 00179 } 00180 00181 00182 WvString &WvString::append(WvStringParm s) 00183 { 00184 if (s) 00185 { 00186 if (*this) 00187 *this = WvString("%s%s", *this, s); 00188 else 00189 *this = s; 00190 } 00191 00192 return *this; 00193 } 00194 00195 00196 size_t WvFastString::len() const 00197 { 00198 return str ? strlen(str) : 0; 00199 } 00200 00201 00202 void WvFastString::newbuf(size_t size) 00203 { 00204 buf = alloc(size); 00205 buf->links = 1; 00206 str = buf->data; 00207 } 00208 00209 00210 // If the string is linked to more than once, we need to make our own copy 00211 // of it. If it was linked to only once, then it's already "unique". 00212 WvString &WvString::unique() 00213 { 00214 if (buf->links > 1 && str) 00215 { 00216 WvStringBuf *newb = alloc(len() + 1); 00217 memcpy(newb->data, str, newb->size); 00218 unlink(); 00219 link(newb, newb->data); 00220 } 00221 00222 return *this; 00223 } 00224 00225 00226 WvFastString &WvFastString::operator= (const WvFastString &s2) 00227 { 00228 if (s2.buf == buf && s2.str == str) 00229 return *this; // no change 00230 else 00231 { 00232 unlink(); 00233 link(s2.buf, s2.str); 00234 } 00235 return *this; 00236 } 00237 00238 00239 WvString &WvString::operator= (int i) 00240 { 00241 unlink(); 00242 newbuf(32); 00243 sprintf(str, "%d", i); 00244 return *this; 00245 } 00246 00247 00248 WvString &WvString::operator= (const WvFastString &s2) 00249 { 00250 if (s2.buf == buf && s2.str == str) 00251 return *this; // no change 00252 else if (!s2.buf) 00253 { 00254 // assigning from a non-copied string - copy data if needed. 00255 unlink(); 00256 link(&nullbuf, s2.str); 00257 unique(); 00258 } 00259 else 00260 { 00261 // just a normal string link 00262 unlink(); 00263 link(s2.buf, s2.str); 00264 } 00265 return *this; 00266 } 00267 00268 00269 // string comparison 00270 bool WvFastString::operator== (WvStringParm s2) const 00271 { 00272 return (str==s2.str) || (str && s2.str && !strcmp(str, s2.str)); 00273 } 00274 00275 00276 bool WvFastString::operator!= (WvStringParm s2) const 00277 { 00278 return (str!=s2.str) && (!str || !s2.str || strcmp(str, s2.str)); 00279 } 00280 00281 00282 bool WvFastString::operator< (WvStringParm s2) const 00283 { 00284 if (str == s2.str) return false; 00285 if (str == 0) return true; 00286 if (s2.str == 0) return false; 00287 return strcmp(str, s2.str) < 0; 00288 } 00289 00290 00291 bool WvFastString::operator== (const char *s2) const 00292 { 00293 return (str==s2) || (str && s2 && !strcmp(str, s2)); 00294 } 00295 00296 00297 bool WvFastString::operator!= (const char *s2) const 00298 { 00299 return (str!=s2) && (!str || !s2 || strcmp(str, s2)); 00300 } 00301 00302 00303 bool WvFastString::operator< (const char *s2) const 00304 { 00305 if (str == s2) return false; 00306 if (str == 0) return true; 00307 if (s2 == 0) return false; 00308 return strcmp(str, s2) < 0; 00309 } 00310 00311 00312 // not operator is 'true' if string is empty 00313 bool WvFastString::operator! () const 00314 { 00315 return !str || !str[0]; 00316 } 00317 00318 00319 // parse a 'percent' operator from a format string. For example: 00320 // cptr out: zeropad justify maxlen return pointer 00321 // "%s" false 0 0 "s" 00322 // "%-15s" false -15 0 "s" 00323 // "%15.5s" false 15 5 "s" 00324 // "%015.5s" true 15 5 "s" 00325 // and so on. On entry, cptr should _always_ point at a percent '%' char. 00326 // 00327 static const char *pparse(const char *cptr, 00328 bool &zeropad, int &justify, int &maxlen) 00329 { 00330 assert(*cptr == '%'); 00331 cptr++; 00332 00333 zeropad = (*cptr == '0'); 00334 00335 justify = atoi(cptr); 00336 00337 for (; *cptr && *cptr!='.' && *cptr!='%' && !isalpha(*cptr); cptr++) 00338 ; 00339 if (!*cptr) return cptr; 00340 00341 if (*cptr == '.') 00342 maxlen = atoi(cptr+1); 00343 else 00344 maxlen = 0; 00345 00346 for (; *cptr && *cptr!='%' && !isalpha(*cptr); cptr++) 00347 ; 00348 00349 return cptr; 00350 } 00351 00352 00353 // Accept a printf-like format specifier (but more limited) and an array 00354 // of WvStrings, and render them into another WvString. For example: 00355 // WvString x[] = {"foo", "blue", 1234}; 00356 // WvString ret = WvString::do_format("%s%10.2s%-10s", x); 00357 // 00358 // The 'ret' string will be: "foo bl1234 " 00359 // Note that only '%s' is supported, though integers can be rendered 00360 // automatically into WvStrings. %d, %f, etc are not allowed! 00361 // 00362 // This function is usually called from some other function which allocates 00363 // the array automatically. 00364 // 00365 void WvFastString::do_format(WvFastString &output, const char *format, 00366 const WvFastString * const *a) 00367 { 00368 static const char blank[] = "(nil)"; 00369 const WvFastString * const *argptr = a; 00370 const char *iptr = format, *arg; 00371 char *optr; 00372 int total = 0, aplen, ladd, justify, maxlen; 00373 bool zeropad; 00374 00375 // count the number of bytes we'll need 00376 while (*iptr) 00377 { 00378 if (*iptr != '%') 00379 { 00380 total++; 00381 iptr++; 00382 continue; 00383 } 00384 00385 // otherwise, iptr is at a percent expression 00386 iptr = pparse(iptr, zeropad, justify, maxlen); 00387 if (*iptr == '%') // literal percent 00388 { 00389 total++; 00390 iptr++; 00391 continue; 00392 } 00393 00394 assert(*iptr == 's' || *iptr == 'c'); 00395 00396 if (*iptr == 's') 00397 { 00398 if (!*argptr || !(**argptr).cstr()) 00399 arg = blank; 00400 else 00401 arg = (**argptr).cstr(); 00402 ladd = _max(abs(justify), strlen(arg)); 00403 if (maxlen && maxlen < ladd) 00404 ladd = maxlen; 00405 total += ladd; 00406 argptr++; 00407 iptr++; 00408 continue; 00409 } 00410 00411 if (*iptr++ == 'c') 00412 { 00413 argptr++; 00414 total++; 00415 } 00416 } 00417 00418 output.setsize(total + 1); 00419 00420 // actually render the final string 00421 iptr = format; 00422 optr = output.str; 00423 argptr = a; 00424 while (*iptr) 00425 { 00426 if (*iptr != '%') 00427 { 00428 *optr++ = *iptr++; 00429 continue; 00430 } 00431 00432 // otherwise, iptr is at a "percent expression" 00433 iptr = pparse(iptr, zeropad, justify, maxlen); 00434 if (*iptr == '%') 00435 { 00436 *optr++ = *iptr++; 00437 continue; 00438 } 00439 if (*iptr == 's') 00440 { 00441 if (!*argptr || !(**argptr).cstr()) 00442 arg = blank; 00443 else 00444 arg = (**argptr).cstr(); 00445 aplen = strlen(arg); 00446 if (maxlen && maxlen < aplen) 00447 aplen = maxlen; 00448 00449 if (justify > aplen) 00450 { 00451 if (zeropad) 00452 memset(optr, '0', justify-aplen); 00453 else 00454 memset(optr, ' ', justify-aplen); 00455 optr += justify-aplen; 00456 } 00457 00458 strncpy(optr, arg, aplen); 00459 optr += aplen; 00460 00461 if (justify < 0 && -justify > aplen) 00462 { 00463 if (zeropad) 00464 memset(optr, '0', -justify-aplen); 00465 else 00466 memset(optr, ' ', -justify-aplen); 00467 optr += -justify - aplen; 00468 } 00469 00470 argptr++; 00471 iptr++; 00472 continue; 00473 } 00474 if (*iptr++ == 'c') 00475 { 00476 arg = **argptr++; 00477 *optr++ = (char)atoi(arg); 00478 00479 argptr++; 00480 } 00481 } 00482 *optr = 0; 00483 } 00484 00485

Generated on Tue Oct 5 01:09:21 2004 for WvStreams by doxygen 1.3.7