String.cc

Go to the documentation of this file.
00001 //
00002 // String.cc
00003 //
00004 // String: (interface in htString.h) Just Another String class.
00005 //
00006 // Part of the ht://Dig package   <http://www.htdig.org/>
00007 // Copyright (c) 1999, 2000, 2001 The ht://Dig Group
00008 // For copyright details, see the file COPYING in your distribution
00009 // or the GNU General Public License version 2 or later 
00010 // <http://www.gnu.org/copyleft/gpl.html>
00011 //
00012 // $Id: String_8cc-source.html,v 1.1 2008/06/08 10:12:56 sebdiaz Exp $
00013 //
00014 #ifdef HAVE_CONFIG_H
00015 #include "config.h"
00016 #endif /* HAVE_CONFIG_H */
00017 
00018 #include "htString.h"
00019 #include "Object.h"
00020 
00021 #include <unistd.h>
00022 #include <stream.h>
00023 #include <ctype.h>
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 
00027 
00028 const int MinimumAllocationSize = 4;    // Should be power of two.
00029 
00030 #ifdef NOINLINE
00031 String::String()
00032 {
00033     Length = Allocated = 0;
00034     Data = 0;
00035 }
00036 #endif
00037 
00038 String::String(int init)
00039 {
00040     Length = 0;
00041     Allocated = init >= MinimumAllocationSize ? init : MinimumAllocationSize;
00042     Data = new char[Allocated];
00043 }
00044 
00045 String::String(const char *s)
00046 {
00047     Allocated = Length = 0;
00048     Data = 0;
00049 
00050     int len;
00051     if (s)
00052       {
00053         len = strlen(s);
00054         copy(s, len, len);
00055       }
00056 }
00057 
00058 String::String(const char *s, int len)
00059 {
00060     Allocated = Length = 0;
00061     Data = 0;
00062     if (s && len != 0)
00063         copy(s, len, len);
00064 }
00065 
00066 String::String(const String &s) : Object()
00067 {
00068     Allocated = Length = 0;
00069     Data = 0;
00070 
00071     if (s.length() != 0)
00072       copy(s.Data, s.length(), s.length());
00073 }
00074 
00075 //
00076 // This can be used for performance reasons if it is known the
00077 // String will need to grow.
00078 //
00079 String::String(const String &s, int allocation_hint)
00080 {
00081     Allocated = Length = 0;
00082     Data = 0;
00083 
00084     if (s.length() != 0)
00085       {
00086         if (allocation_hint < s.length())
00087           allocation_hint = s.length();
00088         copy(s.Data, s.length(), allocation_hint);
00089       }
00090 }
00091 
00092 String::~String()
00093 {
00094     if (Allocated)
00095         delete [] Data;
00096 }
00097 
00098 void String::operator = (const String &s)
00099 {
00100     allocate_space(s.length());
00101     Length = s.length();
00102     copy_data_from(s.Data, Length);
00103 }
00104 
00105 void String::operator = (const char *s)
00106 {
00107     if (s)
00108     {
00109       int len = strlen(s);
00110         allocate_fix_space(len);
00111         Length = len;
00112         copy_data_from(s, Length);      
00113     }
00114     else
00115         Length = 0;
00116 }
00117 
00118 void String::append(const String &s)
00119 {
00120     if (s.length() == 0)
00121         return;
00122     int new_len = Length + s.length();
00123 
00124     reallocate_space(new_len);
00125     copy_data_from(s.Data, s.length(), Length);
00126     Length = new_len;
00127 }
00128 
00129 void String::append(const char *s)
00130 {
00131     if (!s)
00132         return;
00133         
00134     append(s,strlen(s));
00135 }
00136 
00137 void String::append(const char *s, int slen)
00138 {
00139     if (!s || !slen)
00140         return;
00141 
00142 //    if ( slen == 1 ) 
00143 //    {
00144 //        append(*s);
00145 //        return;
00146 //    }
00147     int new_len = Length + slen;
00148 
00149     if (new_len + 1 > Allocated)
00150     reallocate_space(new_len);
00151     copy_data_from(s, slen, Length);
00152     Length = new_len;
00153 }
00154 
00155 void String::append(char ch)
00156 {
00157     int new_len = Length +1;
00158     if (new_len + 1 > Allocated)
00159         reallocate_space(new_len);
00160     Data[Length] = ch;
00161     Length = new_len;
00162 }
00163 
00164 int String::compare(const String& obj) const
00165 {
00166     int len;
00167     int result;
00168     const char  *p1 = Data;
00169     const char  *p2 = obj.Data;
00170 
00171     len = Length;
00172     result = 0;
00173 
00174     if (Length > obj.Length)
00175     {
00176         result = 1;
00177         len = obj.Length;
00178     }
00179     else if (Length < obj.Length)
00180         result = -1;
00181 
00182     while (len)
00183     {
00184         if (*p1 > *p2)
00185             return 1;
00186         if (*p1 < *p2)
00187             return -1;
00188         p1++;
00189         p2++;
00190         len--;
00191     }
00192     //
00193     // Strings are equal up to the shortest length.
00194     // The result depends upon the length difference.
00195     //
00196     return result;
00197 }
00198 
00199 int String::nocase_compare(const String &s) const
00200 {
00201     const char  *p1 = get();
00202     const char  *p2 = s.get();
00203 
00204     return strcasecmp(p1, p2);
00205 }
00206 
00207 int String::Write(int fd) const
00208 {
00209     int left = Length;
00210     char        *wptr = Data;
00211         
00212     while (left)
00213     {
00214         int result = write(fd, wptr, left);
00215                 
00216         if (result < 0)
00217             return result;
00218                 
00219         left -= result;
00220         wptr += result;
00221     }
00222     return left;
00223 }
00224 
00225 const char *String::get() const
00226 {
00227   static const char     *null = "";
00228   if (!Allocated)
00229     return null;
00230   Data[Length] = '\0';  // We always leave room for this.
00231   return Data;
00232 }
00233 
00234 char *String::get()
00235 {
00236   static char   *null = "";
00237   if (!Allocated)
00238     return null;
00239   Data[Length] = '\0';  // We always leave room for this.
00240   return Data;
00241 }
00242 
00243 String::operator int () const
00244 {
00245   fprintf(stderr, "String: int(): either use empty() or as_integer()\n");
00246   abort();
00247 }
00248 
00249 char *String::new_char() const
00250 {
00251     char        *r;
00252     if (!Allocated)
00253     {
00254         r = new char[1];
00255         *r = '\0';
00256         return r;
00257     }
00258     Data[Length] = '\0';        // We always leave room for this.
00259     r = new char[Length + 1];
00260     strcpy(r, Data);
00261     return r;
00262 }
00263 
00264 
00265 int String::as_integer(int def) const
00266 {
00267     if (Length <= 0)
00268         return def;
00269     Data[Length] = '\0';
00270     return atoi(Data);
00271 }
00272 
00273 double String::as_double(double def) const
00274 {
00275     if (Length <= 0)
00276         return def;
00277     Data[Length] = '\0';
00278     return atof(Data);
00279 }
00280 
00281 String String::sub(int start, int len) const
00282 {
00283     if (start > Length)
00284         return 0;
00285 
00286     if (len > Length - start)
00287         len = Length - start;
00288 
00289     return String(Data + start, len);
00290 }
00291 
00292 String String::sub(int start) const
00293 {
00294     return sub(start, Length - start);
00295 }
00296 
00297 int String::indexOf(const char *str) const
00298 {
00299     char        *c;    
00300     //
00301     // Set the first char after string end to zero to prevent finding
00302     // substrings including symbols after actual end of string
00303     //
00304     if (!Allocated)
00305         return -1;
00306     Data[Length] = '\0';
00307     
00308     /* OLD CODE: for (i = 0; i < Length; i++) */
00309 #ifdef HAVE_STRSTR
00310     if ((c = strstr(Data, str)) != NULL)
00311         return(c -Data);
00312 #else
00313     int         len = strlen(str);
00314     int         i;
00315     for (i = 0; i <= Length-len; i++)
00316     {
00317         if (strncmp(&Data[i], str, len) == 0)
00318             return i;
00319     }
00320 #endif
00321     return -1;
00322 }
00323 
00324 int String::indexOf(char ch) const
00325 {
00326     int         i;
00327     for (i = 0; i < Length; i++)
00328     {
00329         if (Data[i] == ch)
00330             return i;
00331     }
00332     return -1;
00333 }
00334 
00335 int String::indexOf(char ch, int pos) const
00336 {
00337     if (pos >= Length)
00338       return -1;
00339     for (int i = pos; i < Length; i++)
00340     {
00341         if (Data[i] == ch)
00342             return i;
00343     }
00344     return -1;
00345 }
00346 
00347 int String::lastIndexOf(char ch, int pos) const
00348 {
00349     if (pos >= Length)
00350         return -1;
00351     while (pos >= 0)
00352     {
00353         if (Data[pos] == ch)
00354             return pos;
00355         pos--;
00356     }
00357     return -1;
00358 }
00359 
00360 int String::lastIndexOf(char ch) const
00361 {
00362     return lastIndexOf(ch, Length - 1);
00363 }
00364 #ifdef NOINLINE
00365 String &String::operator << (const char *str)
00366 {
00367     append(str);
00368     return *this;
00369 }
00370 
00371 String &String::operator << (char ch)
00372 {
00373     append(&ch, 1);
00374     return *this;
00375 }
00376 #endif
00377 
00378 String &String::operator << (int i)
00379 {
00380     char        str[20];
00381     sprintf(str, "%d", i);
00382     append(str);
00383     return *this;
00384 }
00385 
00386 String &String::operator << (unsigned int i)
00387 {
00388     char        str[20];
00389     sprintf(str, "%u", i);
00390     append(str);
00391     return *this;
00392 }
00393 
00394 String &String::operator << (long l)
00395 {
00396     char        str[20];
00397     sprintf(str, "%ld", l);
00398     append(str);
00399     return *this;
00400 }
00401 
00402 String &String::operator << (const String &s)
00403 {
00404     append(s.get(), s.length());
00405     return *this;
00406 }
00407 
00408 char    String::operator >> (char c)
00409 {
00410     c = '\0';
00411         
00412     if (Allocated && Length)
00413     {
00414         c = Data[Length - 1];
00415         Data[Length - 1] = '\0';
00416         Length--;
00417     }
00418 
00419     return c;
00420 }
00421 
00422 int String::lowercase()
00423 {
00424   int converted = 0;
00425   for (int i = 0; i < Length; i++)
00426     {
00427       if (isupper((unsigned char)Data[i])) {
00428         Data[i] = tolower((unsigned char)Data[i]);
00429         converted++;
00430       }
00431     }
00432   return converted;
00433 }
00434 
00435 
00436 int String::uppercase()
00437 {
00438   int converted = 0;
00439   for (int i = 0; i < Length; i++)
00440     {
00441       if (islower((unsigned char)Data[i])) {
00442         Data[i] = toupper((unsigned char)Data[i]);
00443         converted++;
00444       }
00445     }
00446   return converted;
00447 }
00448 
00449 
00450 void String::replace(char c1, char c2)
00451 {
00452     for (int i = 0; i < Length; i++)
00453         if (Data[i] == c1)
00454             Data[i] = c2;
00455 }
00456 
00457 
00458 int String::remove(const char *chars)
00459 {
00460     if (Length <= 0)
00461         return 0;
00462 
00463     char        *good, *bad;
00464     int         skipped = 0;
00465 
00466     good = bad = Data;
00467     for (int i = 0; i < Length; i++)
00468     {
00469         if (strchr(chars, *bad))
00470             skipped++;
00471         else
00472             *good++ = *bad;
00473         bad++;
00474     }
00475     Length -= skipped;
00476 
00477     return skipped;
00478 }
00479 
00480 String &String::chop(int n)
00481 {
00482     Length -= n;
00483     if (Length < 0)
00484         Length = 0;
00485     return *this;
00486 }
00487 
00488 
00489 String &String::chop(char ch)
00490 {
00491         while (Length > 0 && Data[Length - 1] == ch)
00492             Length--;
00493     return *this;
00494 }
00495 
00496 
00497 String &String::chop(const char *str)
00498 {
00499         while (Length > 0 && strchr(str, Data[Length - 1]))
00500             Length--;
00501     return *this;
00502 }
00503 
00504 
00505 void String::Serialize(String &dest)
00506 {
00507     dest.append((char *) &Length, sizeof(Length));
00508     dest.append(get(), Length);
00509 }
00510 
00511 
00512 void String::Deserialize(String &source, int &index)
00513 {
00514     memcpy((char *) &Length, (char *) source.get() + index, sizeof(Length));
00515     index += sizeof(Length);
00516     allocate_fix_space(Length);
00517     copy_data_from(source.get() + index, Length);
00518     index += Length;
00519 }
00520 
00521 
00522 //------------------------------------------------------------------------
00523 // Non member operators.
00524 //
00525 String operator + (const String &a, const String &b)
00526 {
00527     String      result(a, a.length() + b.length());
00528         
00529     result.append(b);
00530     return result;
00531 }
00532 
00533 int operator == (const String &a, const String &b)
00534 {
00535     if (a.Length != b.Length)
00536         return 0;
00537 
00538     return a.compare(b) == 0;
00539 }
00540 
00541 int operator != (const String &a, const String &b)
00542 {
00543     return a.compare(b) != 0;
00544 }
00545 
00546 int operator < (const String &a, const String &b)
00547 {
00548     return a.compare(b) == -1;
00549 }
00550 
00551 int operator > (const String &a, const String &b)
00552 {
00553     return a.compare(b) == 1;
00554 }
00555 
00556 int operator <= (const String &a, const String &b)
00557 {
00558     return a.compare(b) <= 0;
00559 }
00560 
00561 int operator >= (const String &a, const String &b)
00562 {
00563     return a.compare(b) >= 0;
00564 }
00565 
00566 #ifndef NOSTREAM
00567 ostream &operator << (ostream &o, const String &s)
00568 {
00569     o.write(s.Data, s.length());
00570     return o;
00571 }
00572 #endif /* NOSTREAM */
00573 
00574 //------------------------------------------------------------------------
00575 // Private Methods.
00576 //
00577 
00578 void String::copy_data_from(const char *s, int len, int dest_offset)
00579 {
00580     memcpy(Data + dest_offset, s, len);
00581 }
00582 
00583 void String::allocate_space(int len)
00584 {
00585     len++;                              // In case we want to add a null.
00586 
00587     if (len <= Allocated)
00588       return;
00589 
00590     if (Allocated)
00591       delete [] Data;
00592 
00593     Allocated = MinimumAllocationSize;
00594     while (Allocated < len)
00595       Allocated <<= 1;
00596 
00597     Data = new char[Allocated];
00598 }
00599 
00600 void String::allocate_fix_space(int len)
00601 {
00602     len++;                              // In case we want to add a null.
00603 
00604     if (len <= Allocated)
00605       return;
00606 
00607     if (Allocated)
00608       delete [] Data;
00609 
00610     Allocated = len;
00611     if (Allocated < MinimumAllocationSize)
00612       Allocated = MinimumAllocationSize;
00613     Data = new char[Allocated];
00614 }
00615 
00616 void String::reallocate_space(int len)
00617 {
00618         char    *old_data = 0;
00619         int      old_data_len = 0;
00620 
00621     if (Allocated)
00622         {
00623             old_data = Data;
00624             old_data_len = Length;
00625             Allocated = 0;
00626         }
00627     allocate_space(len);
00628     if (old_data)
00629       {
00630         copy_data_from(old_data, old_data_len);
00631         delete [] old_data;
00632       }
00633 }
00634 
00635 void String::copy(const char *s, int len, int allocation_hint)
00636 {
00637   if (len == 0 || allocation_hint == 0)
00638     return;         // We're not actually copying anything!
00639   allocate_fix_space(allocation_hint);
00640   Length = len;
00641   copy_data_from(s, len);
00642 }
00643 
00644 #ifndef NOSTREAM
00645 void String::debug(ostream &o)
00646 {
00647     o << "Length: " << Length << " Allocated: " << Allocated <<
00648         " Data: " << ((void*) Data) << " '" << *this << "'\n";
00649 }
00650 #endif /* NOSTREAM */
00651 
00652 int String::readLine(FILE *in)
00653 {
00654     Length = 0;
00655     allocate_fix_space(2048);
00656 
00657     while (fgets(Data + Length, Allocated - Length, in))
00658     {
00659         Length += strlen(Data + Length);
00660         if (Length == 0)
00661             continue;
00662         if (Data[Length - 1] == '\n')
00663         {
00664             //
00665             // A full line has been read.  Return it.
00666             //
00667             chop('\n');
00668             return 1;
00669         }
00670         if (Allocated > Length + 1)
00671         {
00672             //
00673             // Not all available space filled. Probably EOF?
00674             //
00675             continue;
00676         }
00677         //
00678         // Only a partial line was read. Increase available space in 
00679         // string and read some more.
00680         //
00681         reallocate_space(Allocated << 1);
00682     }
00683     chop('\n');
00684 
00685     return Length > 0;
00686 }
00687 
00688 #ifndef NOSTREAM
00689 istream &operator >> (istream &in, String &line)
00690 {
00691     line.Length = 0;
00692     line.allocate_fix_space(2048);
00693 
00694     while (in.get(line.Data + line.Length, line.Allocated - line.Length))
00695     {
00696         line.Length += strlen(line.Data + line.Length);
00697         int c = in.get();
00698         if (c == '\n' || c == EOF)
00699         {
00700             //
00701             // A full line has been read.  Return it.
00702             //
00703             break;
00704         }
00705         if (line.Allocated > line.Length + 2)
00706         {
00707             //
00708             // Not all available space filled.
00709             //
00710             line.Data[line.Length++] = char(c);
00711             continue;
00712         }
00713         //
00714         // Only a partial line was read. Increase available space in 
00715         // string and read some more.
00716         //
00717         line.reallocate_space(line.Allocated << 1);
00718         line.Data[line.Length++] = char(c);
00719     }
00720 
00721     return in;
00722 }
00723 #endif /* NOSTREAM */

Generated on Sun Jun 8 10:56:39 2008 for GNUmifluz by  doxygen 1.5.5