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 Sat Feb 21 21:05:33 2004 for WvStreams by doxygen 1.3.5