// File: bstring.C // // Implementation of BString class #include #include #include #include "bstring.h" #define INITLEN 5 //=========================================================================== // Local function prototypes // static void CrashOnNULL(void *) ; static char *reallocate(char *, int) ; //=========================================================================== // Local function implementations // // Exit program if pointer s is NULL. // call after using malloc() or new. // static void CrashOnNULL(void *s) { if (s == NULL) { cerr << "Could not allocate memory! Bye!" << endl ; exit(1) ; } } // Quick & dirty function to change the size of memory block. // Returns pointer to block of n bytes. Memory that s originally // points to is freed. Not for public consumption. // static char *reallocate(char *s, int n) { char *newstr ; newstr = new char[n] ; CrashOnNULL(newstr) ; if (s == NULL) return newstr ; strncpy(newstr, s, n) ; delete [] s ; return newstr ; } //=========================================================================== // BString member functions // // Default constructor // BString::BString() { bufsize = 0 ; // initially str is NULL not "" str = NULL ; len = 0 ; } // Constructor with initial buffer size // BString::BString(int n) { if (n <= 0) n = INITLEN ; bufsize = n ; str = new char[bufsize] ; CrashOnNULL(str) ; str[0] = '\0' ; len = 0 ; } // Initialize with string and buffer size // BString::BString(char *s, int n /* = 0 */ ){ if (s == NULL) { bufsize = n ; if (bufsize > 0) { str = new char[bufsize] ; CrashOnNULL(str) ; str[0] = '\0' ; } else { str = NULL ; } len = 0 ; return ; } len = strlen(s) ; if (len < n) { // always have enough memory for s bufsize = n ; } else { bufsize = len + 1 ; } str = new char[bufsize] ; CrashOnNULL(str) ; strncpy(str, s, bufsize) ; } // Copy Constructor // BString::BString(const BString& bs) { // ***DEBUG // // cerr << "Copy constructor: this="<< this << endl ; len = bs.len ; bufsize = bs.bufsize ; if (bufsize > 0) { // might be 0 str = new char[bufsize] ; CrashOnNULL(str) ; } if (bs.str != NULL) { strncpy(str, bs.str, bufsize) ; } else { str = NULL ; } } // Destructor // BString::~BString() { // ***DEBUG // // cerr << "Destroying... this=" << this << " str=" << str << endl ; delete [] str ; } // Add char(s) to the end of this string // void BString::append(char c) { if (len > bufsize - 2) { // need more space? bufsize = ( bufsize >= INITLEN ? 2*bufsize : INITLEN ) ; str = reallocate(str, bufsize) ; } str[len] = c ; str[len+1] = '\0' ; len++ ; } void BString::append(const char *s) { int newlen ; if (s == NULL) return ; newlen = len + strlen(s) ; // length of combined string if (bufsize < newlen + 1) { bufsize = newlen + 1 ; str = reallocate(str, bufsize) ; } strcpy(str+len, s) ; len = newlen ; } void BString::append(const BString& bs) { int newlen ; if (bs.str == NULL) return ; newlen = len + bs.len ; // length of combined string if (bufsize < newlen + 1) { bufsize = newlen + 1 ; str = reallocate(str, bufsize) ; } strcpy(str+len, bs.str) ; len = newlen ; } // Remove char(s) at the end of the string // void BString::chop(int n /* =1 */) { // degnerate cases // if (n <= 0) return ; if (n > len) n = len ; len = len - n ; str[len] = '\0' ; trim() ; } // Reduce buffer size if it's a good idea. // void BString::trim() { // Do nothing if string is short or uses 3/4 of buffer // if (bufsize == INITLEN || len >= 0.75*bufsize) return ; force_trim() ; } // Always reduce to just the right buffer size. // void BString::force_trim() { bufsize = len + 1 ; str = reallocate(str, bufsize) ; } // Overloaded Operators // // assignment // BString& BString::operator =(const BString& bs) { // *** DEBUG // // cerr << "String Assignment: this=" << this << endl ; // Handle degenerate case of self-assignment if (this == &bs) return *this ; // free old string! delete [] str ; len = bs.len ; bufsize = bs.bufsize ; if (bufsize > 0) { str = new char[bufsize] ; CrashOnNULL(str) ; } if (bs.str != NULL) { strncpy(str, bs.str, bufsize) ; } else { str = NULL ; } return *this ; } // + is concatenate // BString BString::operator +(const BString& bs) { BString newbs(*this) ; newbs.append(bs) ; return newbs ; } // Allow use of str[i] notation for the ith character. // char& BString::operator [](int i) { if (i < 0 || i > len) { cerr << "String index out of bounds: " << i << endl ; exit(1) ; } return str[i] ; } // comparisons // use convention that NULL pointer is the smallest string // bool BString::operator <(const BString& bs) { if (str == NULL && bs.str == NULL) return false ; if (str == NULL) return true ; if (bs.str == NULL) return false ; if (strcmp(str, bs.str) < 0) return true ; return false ; } bool BString::operator <=(const BString& bs) { if (str == NULL && bs.str == NULL) return true ; if (str == NULL) return true ; if (bs.str == NULL) return false ; if (strcmp(str, bs.str) <= 0) return true ; return false ; } bool BString::operator ==(const BString& bs) { if (str == NULL && bs.str == NULL) return true ; if (str == NULL) return false ; if (bs.str == NULL) return false ; if (strcmp(str, bs.str) == 0) return true ; return false ; } bool BString::operator >=(const BString& bs) { if (str == NULL && bs.str == NULL) return true ; if (str == NULL) return false ; if (bs.str == NULL) return true ; if (strcmp(str, bs.str) >= 0) return true ; return false ; } bool BString::operator >(const BString& bs) { if (str == NULL && bs.str == NULL) return false ; if (str == NULL) return false ; if (bs.str == NULL) return true ; if (strcmp(str, bs.str) > 0) return true ; return false ; } // Type conversion from BString to "char *" string // BString::operator char *() { char *newstr ; if (str == NULL) return NULL ; newstr = strdup(str) ; CrashOnNULL(newstr) ; return newstr ; } // Read a line from specified stream and store it in the host object. // void BString::GetLine(istream& istrm) { char *newstr ; int ch, i=0, j, newlen ; // Remove old data. Zero out buffer. // delete [] str ; len = 0 ; str = NULL ; bufsize = 0 ; // First check for EOF // ch = istrm.get() ; // peek ahead to trigger EOF settings if (istrm.eof()) { return ; } istrm.putback(ch) ; // continue as if we didn't peek // keep reading until done // while(true) { ch = istrm.get() ; if (ch == EOF || ch == '\n') break ; append(ch) ; // piece of cake! } trim() ; } // Dump vital stats // void BString::debug() { cout << "*** BString::debug()" << endl ; cout << "this="<< this << " str=" << (void *) str << endl ; cout << "str=" << str << endl ; cout << "len=" << len << endl ; cout << "bufsize=" << bufsize << endl ; cout << "***" << endl ; } //=========================================================================== // Overloaded I/O operators << and >> istream& operator >>(istream& istrm, BString& bs) { bs.GetLine(istrm) ; return istrm ; } ostream& operator <<(ostream& ostrm, const BString& bs) { ostrm << bs.str ; // must be friend of BString return ostrm ; }