Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

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 __wvs_nb = { 0, 1 };
00013 const WvString __wvs_n;
00014 
00015 
00016 // always a handy function
00017 static inline int _max(int x, int y)
00018 {
00019     return x>y ? x : y;
00020 }
00021 
00022 
00023 void WvString::setsize(size_t i)
00024 {
00025     unlink();
00026     newbuf(i);
00027 }
00028 
00029 
00030 
00031 WvString::WvString()
00032 {
00033     buf = NULL;
00034     str = NULL;
00035 }
00036 
00037 
00038 WvString::WvString(const WvString &s)
00039 {
00040     link(s.buf, s.str);
00041 }
00042 
00043 
00044 WvString::WvString(const char *_str)
00045 {
00046     if (_str)
00047         link(&__wvs_nb, _str);
00048     else 
00049     {
00050         buf = NULL;
00051         str = NULL;
00052     }
00053 }
00054 
00055 
00056 // NOTE: make sure that 32 bytes is big enough for your longest int.
00057 // This is true up to at least 64 bits.
00058 WvString::WvString(int i) // auto-render int 'i' into a string
00059 {
00060     newbuf(32);
00061     sprintf(str, "%d", i);
00062 }
00063 
00064 
00065 WvString::~WvString()
00066 {
00067     unlink();
00068 }
00069 
00070 
00071 void WvString::unlink()
00072 { 
00073     if (!buf) return;
00074     if (! --buf->links)
00075         free(buf);
00076 }
00077     
00078 void WvString::link(WvStringBuf *_buf, const char *_str)
00079 {
00080     buf = _buf;
00081     if (buf) buf->links++;
00082     str = (char *)_str; // I promise not to change it without asking!
00083 }
00084     
00085 
00086 WvStringBuf *WvString::alloc(size_t size)
00087 { 
00088     WvStringBuf *buf = (WvStringBuf *)malloc(WVSTRINGBUF_SIZE(buf)
00089                                              + size + WVSTRING_EXTRA);
00090     buf->links = 0;
00091     buf->size = size;
00092     return buf;
00093 }
00094 
00095 
00096 void WvString::append(const WvString &s)
00097 {
00098     if (buf)
00099         *this = WvString("%s%s", *this, s);
00100     else
00101     {
00102         *this = s;
00103         unique();
00104     }
00105 }
00106 
00107 
00108 size_t WvString::len() const
00109 {
00110     if (!buf) return 0;
00111     return buf->size ? buf->size-1 : strlen(str);
00112 }
00113 
00114 
00115 void WvString::newbuf(size_t size)
00116 {
00117     buf = alloc(size);
00118     buf->links = 1;
00119     str = buf->data;
00120 }
00121 
00122 
00123 // If the string is linked to more than once, we need to make our own copy 
00124 // of it.  If it was linked to only once, then it's already "unique".
00125 WvString &WvString::unique()
00126 {
00127     if (buf->links > 1)
00128     {
00129         WvStringBuf *newb = alloc(len() + 1);
00130         memcpy(newb->data, str, newb->size);
00131         unlink();
00132         link(newb, newb->data);
00133     }
00134             
00135     return *this; 
00136 }
00137 
00138 
00139 WvString& WvString::operator= (const WvString &s2)
00140 {
00141     if (s2.buf == buf && s2.str == str)
00142         return *this;
00143     unlink();
00144     link(s2.buf, s2.str);
00145     return *this;
00146 }
00147 
00148 
00149 // string comparison
00150 bool WvString::operator== (const WvString &s2) const
00151 {
00152     return (str==s2.str) || (str && s2.str && !strcmp(str, s2.str));
00153 }
00154 
00155 
00156 bool WvString::operator!= (const WvString &s2) const
00157 {
00158     return (str!=s2.str) && (!str || !s2.str || strcmp(str, s2.str));
00159 }
00160 
00161 
00162 bool WvString::operator== (const char *s2) const
00163 {
00164     return (str==s2) || (str && s2 && !strcmp(str, s2));
00165 }
00166 
00167 
00168 bool WvString::operator!= (const char *s2) const
00169 {
00170     return (str!=s2) && (!str || !s2 || strcmp(str, s2));
00171 }
00172 
00173 
00174 // not operator is 'true' if string is empty
00175 bool WvString::operator! () const
00176 {
00177     return !buf || !str[0];
00178 }
00179 
00180 
00181 // parse a 'percent' operator from a format string.  For example:
00182 //        cptr      out:  zeropad  justify   maxlen  return pointer
00183 //        "%s"             false      0         0    "s"
00184 //        "%-15s"          false    -15         0    "s"
00185 //        "%15.5s"         false     15         5    "s"
00186 //        "%015.5s"        true      15         5    "s"
00187 // and so on.  On entry, cptr should _always_ point at a percent '%' char.
00188 //
00189 static char *pparse(char *cptr, bool &zeropad, int &justify, int &maxlen)
00190 {
00191     assert(*cptr == '%');
00192     cptr++;
00193 
00194     zeropad = (*cptr == '0');
00195 
00196     justify = atoi(cptr);
00197     
00198     for (; *cptr && *cptr!='.' && *cptr!='%' && !isalpha(*cptr); cptr++)
00199         ;
00200     if (!*cptr) return cptr;
00201     
00202     if (*cptr == '.')
00203         maxlen = atoi(cptr+1);
00204     else
00205         maxlen = 0;
00206     
00207     for (; *cptr && *cptr!='%' && !isalpha(*cptr); cptr++)
00208         ;
00209     
00210     return cptr;
00211 }
00212 
00213 
00214 // Accept a printf-like format specifier (but more limited) and an array
00215 // of WvStrings, and render them into another WvString.  For example:
00216 //          WvString x[] = {"foo", "blue", 1234};
00217 //          WvString ret = WvString::do_format("%s%10.2s%-10s", x);
00218 //
00219 // The 'ret' string will be:  "foo        bl1234      "
00220 // Note that only '%s' is supported, though integers can be rendered
00221 // automatically into WvStrings.  %d, %f, etc are not allowed!
00222 //
00223 // This function is usually called from some other function which allocates
00224 // the array automatically.
00225 //
00226 void WvString::do_format(WvString &output, char *format, const WvString **a)
00227 {
00228     static WvString blank("(nil)");
00229     const WvString **aptr = a;
00230     char *iptr = format, *optr;
00231     int total = 0, aplen, ladd, justify, maxlen;
00232     bool zeropad;
00233     
00234     while (*iptr)
00235     {
00236         if (*iptr != '%')
00237         {
00238             total++;
00239             iptr++;
00240             continue;
00241         }
00242         
00243         // otherwise, iptr is at a percent expression
00244         iptr = pparse(iptr, zeropad, justify, maxlen);
00245         if (*iptr == '%') // literal percent
00246         {
00247             total++;
00248             iptr++;
00249             continue;
00250         }
00251         
00252         assert(*iptr == 's');
00253 
00254         if (*iptr++ == 's')
00255         {
00256             if (!*aptr || !(const char *)**aptr)
00257                 *aptr = &blank;
00258             ladd = _max(abs(justify), strlen(**aptr));
00259             if (maxlen && maxlen < ladd)
00260                 ladd = maxlen;
00261             total += ladd;
00262             aptr++;
00263         }
00264     }
00265     
00266     output.setsize(total + 1);
00267     
00268     iptr = format;
00269     optr = output.edit();
00270     aptr = a;
00271     while (*iptr)
00272     {
00273         if (*iptr != '%')
00274         {
00275             *optr++ = *iptr++;
00276             continue;
00277         }
00278         
00279         // otherwise, iptr is at a percent expression
00280         iptr = pparse(iptr, zeropad, justify, maxlen);
00281         if (*iptr == '%')
00282         {
00283             *optr++ = *iptr++;
00284             continue;
00285         }
00286         if (*iptr++ == 's')
00287         {
00288             aplen = strlen(**aptr);
00289             if (maxlen && maxlen < aplen)
00290                 aplen = maxlen;
00291         
00292             if (justify > aplen)
00293             {
00294                 if (zeropad)
00295                     memset(optr, '0', justify-aplen);
00296                 else
00297                     memset(optr, ' ', justify-aplen);
00298                 optr += justify-aplen;
00299             }
00300         
00301             strncpy(optr, **aptr, aplen);
00302             optr += aplen;
00303         
00304             if (justify < 0 && -justify > aplen)
00305             {
00306                 if (zeropad)
00307                     memset(optr, '0', -justify-aplen);
00308                 else
00309                     memset(optr, ' ', -justify-aplen);
00310                 optr += -justify - aplen;
00311             }
00312             
00313             aptr++;
00314         }
00315     }
00316     *optr = 0;
00317 }

Generated on Sat Aug 24 21:09:36 2002 for WvStreams by doxygen1.2.15