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 */