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     unlink();   // WvFastString has already been created by now
00068 
00069     if (!s.buf)
00070     {
00071         link(&nullbuf, s.str);
00072         unique();
00073     }
00074     else
00075         link(s.buf, s.str); // already in a nice, safe WvStreamBuf
00076 }
00077 
00078 
00079 WvString::WvString(const char *_str)
00080 {
00081     unlink();   // WvFastString has already been created by now
00082     construct(_str);
00083 }
00084 
00085 
00086 // This function returns the NULL of a reversed string representation
00087 // for unsigned integers
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 // This function returns the NULL of a reversed string representation
00125 // for signed integers
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 // NOTE: make sure that 32 bytes is big enough for your longest int.
00168 // This is true up to at least 64 bits.
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; // I promise not to change it without asking!
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 // If the string is linked to more than once, we need to make our own copy 
00296 // of it.  If it was linked to only once, then it's already "unique".
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; // no change
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; // no change
00343     else if (!s2.buf)
00344     {
00345         // We have a string, and we're about to free() it.
00346         if (str && buf && buf->links == 1)
00347         {
00348             // Set buf->size, if we don't already know it.
00349             if (buf->size == 0)
00350                 buf->size = strlen(str);
00351 
00352             if (str < s2.str && s2.str <= (str + buf->size))
00353             {
00354                 // If the two strings overlap, we'll just need to
00355                 // shift s2.str over to here.
00356                 memmove(buf->data, s2.str, buf->size);
00357                 return *this;
00358             }
00359         }
00360         // assigning from a non-copied string - copy data if needed.
00361         unlink();
00362         link(&nullbuf, s2.str);
00363         unique();
00364     }
00365     else
00366     {
00367         // just a normal string link
00368         unlink();
00369         link(s2.buf, s2.str);
00370     }
00371     return *this;
00372 }
00373 
00374 
00375 // string comparison
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 // not operator is 'true' if string is empty
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     // count the number of bytes we'll need
00500     while (*iptr)
00501     {
00502         if (*iptr != '%')
00503         {
00504             total++;
00505             iptr++;
00506             continue;
00507         }
00508         
00509         // otherwise, iptr is at a percent expression
00510         argnum=0;
00511         iptr = pparse(iptr, zeropad, justify, maxlen, argnum);
00512         if (*iptr == '%') // literal percent
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     // actually render the final string
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         // otherwise, iptr is at a "percent expression"
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 

Generated on Fri Oct 5 18:20:28 2007 for WvStreams by  doxygen 1.5.3