wvstring.cc

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 void WvFastString::construct(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 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); // already in a nice, safe WvStreamBuf
00074 }
00075 
00076 
00077 WvString::WvString(const char *_str)
00078 {
00079     construct(_str);
00080 }
00081 
00082 
00083 // This function returns the NULL of a reversed string representation
00084 // for unsigned integers
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 // This function returns the NULL of a reversed string representation
00122 // for signed integers
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 // NOTE: make sure that 32 bytes is big enough for your longest int.
00165 // This is true up to at least 64 bits.
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; // I promise not to change it without asking!
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 // If the string is linked to more than once, we need to make our own copy 
00293 // of it.  If it was linked to only once, then it's already "unique".
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; // no change
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; // no change
00340     else if (!s2.buf)
00341     {
00342         // We have a string, and we're about to free() it.
00343         if (str && buf && buf->links == 1)
00344         {
00345             // Set buf->size, if we don't already know it.
00346             if (buf->size == 0)
00347                 buf->size = strlen(str);
00348 
00349             if (str < s2.str && s2.str <= (str + buf->size))
00350             {
00351                 // If the two strings overlap, we'll just need to
00352                 // shift s2.str over to here.
00353                 memmove(buf->data, s2.str, buf->size);
00354                 return *this;
00355             }
00356         }
00357         // assigning from a non-copied string - copy data if needed.
00358         unlink();
00359         link(&nullbuf, s2.str);
00360         unique();
00361     }
00362     else
00363     {
00364         // just a normal string link
00365         unlink();
00366         link(s2.buf, s2.str);
00367     }
00368     return *this;
00369 }
00370 
00371 
00372 // string comparison
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 // not operator is 'true' if string is empty
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     // count the number of bytes we'll need
00481     while (*iptr)
00482     {
00483         if (*iptr != '%')
00484         {
00485             total++;
00486             iptr++;
00487             continue;
00488         }
00489         
00490         // otherwise, iptr is at a percent expression
00491         iptr = pparse(iptr, zeropad, justify, maxlen);
00492         if (*iptr == '%') // literal percent
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     // actually render the final string
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         // otherwise, iptr is at a "percent expression"
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 

Generated on Thu May 25 21:51:04 2006 for WvStreams by  doxygen 1.4.6