Polaris: String.cc Source File

String.cc

Go to the documentation of this file.
00001 ///
00002 #ifdef POLARIS_GNU_PRAGMAS
00003 #pragma implementation
00004 #endif
00005 ///
00006 #include <stdlib.h>
00007 #include <stream.h>
00008 #include <strstream.h>
00009 #include <string.h>
00010 #include <ctype.h>
00011 
00012 #include "String.h"
00013 
00014 #include "rotate.h"
00015 #include "p-assert.h"
00016 
00017 
00018 /// String dec(int i){
00019 ///   strstream s;
00020 ///   s<<i<<'\0';
00021 ///   char* pc=s.str();
00022 ///   String toret(pc);
00023 ///   delete pc;
00024 ///   return toret;
00025 /// }
00026 
00027 /// String hex(int i){
00028 ///   strstream s;
00029 ///   s.setf(ios::hex);
00030 ///   s<<i<<'\0';
00031 ///   char* pc=s.str();
00032 ///   String toret(pc);
00033 ///   delete pc;
00034 ///   return toret;
00035 /// }
00036 
00037 static char    *
00038 alloc_str(int size)
00039 {
00040     char           *buf = new char[size];
00041 
00042     p_assert( buf, "String: Out of memory" );
00043 
00044     return buf;
00045 }
00046 
00047 char           *
00048 upcase_ch(const char *string)
00049 {
00050   if(string == NULL) return NULL;
00051 
00052     /// ...  Returns a copy of a string with all characters converted to upper case
00053     int             len = strlen(string);
00054     char           *buf = alloc_str(len + 1);
00055 
00056     for (int i = 0; i < len; i++) 
00057         buf[i] = toupper(string[i]);
00058     buf[len] = '\0';
00059 
00060     return buf;
00061 }
00062 
00063 int 
00064 fortran_string_length(const char *string)
00065     /// ...  Returns the length a char *string would be given in a Fortran program
00066     /// ...  (this strips the enclosing quotes and any doubled internal quotes)
00067 {
00068   if(string == NULL) return 0;
00069 
00070     int            len = strlen(string);
00071     int            string_len = 0;
00072 
00073     for (int i = 1; i < (len - 1); i++) {
00074         if ((string[i] == '\'') && (string[i + 1] == '\'')) 
00075             i++;
00076         string_len++;
00077     }
00078 
00079     return string_len;
00080 }
00081 
00082 
00083 String::~String()
00084 {
00085     #ifdef CLASS_INSTANCE_REGISTRY
00086     unregister_instance(STRING_CLASS, this);
00087     #endif
00088 
00089     if (_defined) {
00090         /// ...  Before deleting the buffer, overwrite the current string with
00091         /// ...  a distinctive footprint to help with debugging in the case
00092         /// ...  where a string is deleted but a pointer remains to its internal
00093         /// ...  buffer.
00094 
00095         const char     *delete_msg = "*-*";
00096         const int       delete_msg_len = 3;
00097 
00098         if (_len >= delete_msg_len) 
00099             strcpy(_ptr, delete_msg);
00100         else {
00101             /// ...  If not enough room for the message, just truncate the
00102             /// ...  string to zero length
00103             _ptr[0] = '\0';
00104         }
00105 
00106         /// ...  Now go ahead and delete the buffer
00107         delete [] _ptr;
00108     }
00109 
00110     _ptr = 0;
00111     _defined = 0;
00112 }
00113 
00114 void 
00115 String::fillin_string(const int size, const char *chars)
00116     /// ...  Fillin the values of the *this String structure
00117 {
00118     if (chars == 0) { /// ...  NULL pointer
00119         _defined = 0;
00120     _ptr = "";
00121     return;
00122     }
00123   
00124     _len = size >= 0 ? size : 0;
00125     _ptr = alloc_str(_len + 1);
00126 
00127     strncpy(_ptr, chars, (unsigned int) _len);
00128 
00129     _ptr[size] = '\000';
00130     _defined = 1;
00131 }
00132 
00133 Boolean         
00134 operator == (const char *str, const String & string) 
00135 {
00136     return (string == str);
00137 }
00138 
00139 Boolean         
00140 operator != (const char *str, const String & string) 
00141 {
00142     return !(string == str);
00143 }
00144 
00145 Boolean         
00146 operator < (const char *str, const String & string) 
00147 {
00148     return (string < str);
00149 }
00150 
00151 String          
00152 operator + (const char *str, const String & string) 
00153 {
00154   if(str == NULL) return string;
00155 
00156     int            str_len = strlen(str);
00157 
00158     String          new_s;
00159 
00160     new_s._len = str_len + string._len;
00161     new_s._ptr = alloc_str(new_s._len + 1);
00162 
00163     strcpy(new_s._ptr, str);
00164     strcpy(new_s._ptr + str_len, string._ptr);
00165 
00166     new_s._defined = 1;
00167 
00168     return new_s;
00169 }
00170 
00171 String::String(const char *str)
00172 {
00173     #ifdef CLASS_INSTANCE_REGISTRY
00174     register_instance(STRING_CLASS, sizeof(String), this);
00175     #endif
00176 
00177     _defined = 0;
00178     *this = str;
00179 }
00180 
00181 String::String(const String & other)
00182 {
00183     #ifdef CLASS_INSTANCE_REGISTRY
00184     register_instance(STRING_CLASS, sizeof(String), this);
00185     #endif
00186 
00187     _defined = 0;
00188     *this = other.defined() ? other._ptr : 0;
00189 }
00190 
00191 String::String(const char *str, int max_len)
00192 {
00193     #ifdef CLASS_INSTANCE_REGISTRY
00194     register_instance(STRING_CLASS, sizeof(String), this);
00195     #endif
00196 
00197   if (str == 0) {
00198     _defined = 0;
00199     _ptr = "";
00200     return;
00201   }
00202   
00203   int             len_to_use = max_len;
00204   
00205 /// Check to see if there is a terminating byte before str[max_len]
00206   const char     *s = str;
00207 
00208   for (int i = 0; i < max_len; ++i, ++s) {
00209     if (!*s) {
00210       len_to_use = i;
00211       break;
00212     }
00213   }
00214 
00215   fillin_string(len_to_use, str);
00216 }
00217 
00218 String::String(const String & other, int first, int last)
00219 {
00220     #ifdef CLASS_INSTANCE_REGISTRY
00221     register_instance(STRING_CLASS, sizeof(String), this);
00222     #endif
00223 
00224     /// ...  Make a new string which is the substring of the given string
00225     /// ...  starting at position "first", ending at position "last"
00226 
00227 
00228     if (((last - first) <= 0) || (first >= other._len)) {
00229         /// ...  Return an empty string
00230         fillin_string(0, "");
00231     }
00232 
00233     int             end = (last < other._len ? last : other._len - 1);
00234     int             size = end - first + 1;
00235 
00236     fillin_string(size, other._ptr + first);
00237 }
00238 
00239 String::String(const String & other, char *delim1, char *delim2)
00240 {
00241     #ifdef CLASS_INSTANCE_REGISTRY
00242     register_instance(STRING_CLASS, sizeof(String), this);
00243     #endif
00244 
00245     if ( ! other._defined) {
00246         _defined = 0;
00247         _ptr = "";
00248         return;
00249     }
00250   
00251     /// ...  Make a new string which is the substring of the given string
00252     /// ...  starting at the position of the first char in "delim1" to be found
00253     /// ...  and ending at the position of the first char in "delim2" to be found
00254 
00255     /// ...  If delim1==NULL, then start at the beginning of the string
00256     /// ...  If delim2==NULL, then end at the last char of the string
00257 
00258     int             first = -1;
00259     int             last = -1;
00260 
00261     if (!delim1) 
00262         first = 0;
00263     else {
00264         int             delim1_len = strlen(delim1);
00265 
00266         for (int i = 0; i < other._len; i++) {
00267             for (int j = 0; j < delim1_len; j++) {
00268                 if (other._ptr[i] == delim1[j]) {
00269                     first = i;
00270                     break;
00271                 }
00272             }
00273             if (first != -1) {
00274                 /// ...  found something in delim1 at i
00275                 break;
00276             }
00277         }
00278 
00279         if (first == -1) {
00280             /// ...  If we arrive here, then nothing in delim1 was found
00281             /// ...  at any position in the string
00282 
00283             fillin_string(0, "");
00284             return;
00285         }
00286     }
00287 
00288     if (!delim2) 
00289         last = other._len - 1;
00290     else {
00291         int             delim2_len = strlen(delim2);
00292 
00293         for (int i = first + 1; i < other._len; i++) {
00294             for (int j = 0; j < delim2_len; j++) {
00295                 if (other._ptr[i] == delim2[j]) {
00296                     last = i;
00297                     break;
00298                 }
00299             }
00300 
00301             if (last != -1) {
00302                 /// ...  found something in delim2 at i
00303                 break;
00304             }
00305         }
00306 
00307         /// ...  If we arrive here, then nothing in delim2 was found
00308         /// ...  at any position in the string
00309 
00310         if (last == -1) {
00311             /// ...  If we arrive here, then nothing in delim2 was found
00312             /// ...  from after the "first" delimiter until the end
00313 
00314             fillin_string(other._len - first, other._ptr + first);
00315             return;
00316         }
00317     }
00318 
00319     fillin_string(last - first + 1, other._ptr + first);
00320 }
00321 
00322 String & 
00323 String::operator = (const String & other) 
00324 {
00325     *this = other._defined ? other._ptr : "";
00326 
00327     return *this;
00328 }
00329 
00330 String & 
00331 String::operator = (const String * other) 
00332 {
00333     *this = (other && other->_defined) ? other->_ptr : "";
00334 
00335     return *this;
00336 }
00337 
00338 String & 
00339 String::operator = (const char *str) 
00340 {
00341   p_assert((str != NULL), "Assign NULL value through String::operator =");
00342     if (_defined)
00343         delete [] _ptr;
00344 
00345     fillin_string(strlen(str), str);
00346 
00347     return *this;
00348 }
00349 
00350 String          
00351 String::operator + (const String & other) const
00352 {
00353     return *this + other._ptr;
00354 }
00355 
00356 String          
00357 String::operator + (const char *str) const
00358 {
00359   if(str == NULL) return *this;
00360 
00361     int            str_len = strlen(str);
00362     String          new_s;
00363 
00364     new_s._len = str_len + _len;
00365     new_s._ptr = alloc_str(new_s._len + 1);
00366 
00367     strcpy(new_s._ptr, _ptr);
00368     strcpy(new_s._ptr + _len, str);
00369 
00370     new_s._defined = 1;
00371 
00372     return new_s;
00373 }
00374 
00375 String & 
00376 String::operator += (const String & other) 
00377 {
00378     *this += other._ptr;
00379 
00380     return *this;
00381 }
00382 
00383 String & 
00384 String::operator += (const char *str) 
00385 {
00386   p_assert((str != NULL), "NULL value for operand in String::operator =");
00387 
00388     int            new_len = strlen(str) + _len;
00389     char           *buf = alloc_str(new_len + 1);
00390 
00391     strcpy(buf, _defined ? _ptr : "");
00392     strcpy(buf + _len, str);
00393 
00394     if (_defined)
00395         delete [] _ptr;
00396 
00397     _ptr = buf;
00398     _len = new_len;
00399     _defined = 1;
00400 
00401     return *this;
00402 }
00403 
00404 
00405 /// Set the string to the value of allocated_str, without allocating new memory
00406 /// Note:  allocated_str must have been allocated using new (not malloc)
00407 /// THIS MEMORY WILL BE DELETED UPON DESTROYING THE STRING!!
00408 
00409 void 
00410 String::absorb(char *allocated_str)
00411 {
00412     if (_defined)
00413         delete [] _ptr;
00414 
00415     if (allocated_str == 0) {
00416       _defined = 0;
00417       _ptr = "";
00418       return;
00419     }
00420     
00421     _ptr = allocated_str;
00422     _len = strlen(_ptr);
00423     _defined = 1;
00424 }
00425 
00426 unsigned 
00427 String::hash_value() const
00428 {
00429     if (!_defined)
00430         return 0x12345654;
00431 
00432     /// ...  Start with something besides 0 so that even short strings will be
00433     /// ...  spread out across a fair spectrum of hash values
00434     unsigned        val = 0xA65C5793;
00435 
00436     for (char *p = _ptr; *p; ++p)
00437         val = rotate_right(val) ^ *p;
00438 
00439     return val;
00440 }
00441 
00442 int 
00443 String::index(const char *substring) const
00444     /// ...  Return the index into a string where the given substring begins
00445 {
00446     if ( ! _defined )
00447       return -1;
00448     
00449     char           *subptr = strstr(_ptr, substring);
00450 
00451     return subptr ? (subptr - _ptr) : -1;
00452 }
00453 
00454 int 
00455 String::index_case(const char *substring) const
00456     /// ...  Return the index into a string where the given substring begins,
00457     /// ...  ignoring the case of both strings
00458 {
00459     if ( ! _defined )
00460       return -1;
00461     
00462     /// ...  Make an upper-case copy of the *this String:
00463 
00464     char           *upstring = alloc_str(_len + 1);
00465 
00466     upstring = upcase_ch(_ptr);
00467     upstring[_len] = '\0';
00468 
00469     /// ...  Make an upper-case version of substring
00470 
00471     int             sublen = strlen(substring);
00472     char           *upsubstring = alloc_str(sublen + 1);
00473 
00474     upsubstring = upcase_ch(substring);
00475     upsubstring[sublen] = '\0';
00476 
00477     char           *subptr = strstr(upstring, upsubstring);
00478 
00479     if (subptr == 0) {
00480       delete [] upstring;
00481       delete [] upsubstring;
00482       return -1;
00483     }
00484     else {
00485       int ret = subptr - upstring;
00486       delete  [] upstring;
00487       delete  [] upsubstring;
00488       return ret;
00489     }
00490 }
00491 
00492 String 
00493 String::upcase() const
00494 {
00495     if (!_defined)
00496       return 0; /// ...  Return an undefined String
00497     
00498     String          str;
00499 
00500     str.fillin_string(_len, upcase_ch(_ptr));
00501 
00502     return str;
00503 }
00504 
00505 int 
00506 String::structures_OK() const
00507 {
00508     if (_ptr == 0) {
00509         cerr << "Error: String: structures_OK() found a string pointing "
00510              << "to NULL (which is bad even if the String is undefined)\n";
00511         return 0;
00512     }
00513 
00514     if (!_defined)
00515         return 1;
00516 
00517     /// ...  Make sure the length of the string matches _len
00518     int             len = strlen(_ptr);
00519 
00520     if (len != _len) {
00521         cerr << "Error: String: structures_OK() found a string of length "
00522              << len << " but expected a length of " << _len << ".  " << flush;
00523         if (len < 100) 
00524             cerr << "String = \"" << *this << "\"\n";
00525         else {
00526             cerr << "First 100 characters of string = \"";
00527             for (int i = 0; i<100; ++i) 
00528                 cerr << _ptr[i];
00529             cerr << "\"\n";
00530         }
00531 
00532         return 0;
00533     }
00534 
00535     return 1;
00536 }
00537 
 © 1995-2005 University of Illinois, Urbana-Champaign. All rights reserved.  Fri Mar 25 23:06:13 2005