// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I #include #include #include #include #include // initialiser used in all constructors void DREstring::initialise(void) { heap_check(p = new str); p->max_len = 0; p->len = 0; p->s = 0; p->ref = 1; } // generic constructor DREstring::DREstring(void) { this->initialise(); } // constructor with int DREstring::DREstring(const int max_length) { this->initialise(); p->max_len = max_length; } // constructor with long, int (int to DREstring type conversion) DREstring::DREstring(const long value, int radix) { char temp[20]; this->initialise(); *this = ltoa(value, temp, radix); } // constructor with char* DREstring::DREstring(const char* init_DREstring) { // cout << "Constructing with : " << init_DREstring << "\n"; this->initialise(); *this = init_DREstring; } // constructor with char DREstring::DREstring(const char c) { this->initialise(); heap_check(p->s = new char [2]); // ! *(p->s) = c; *(p->s + 1) = 0; p->len = 1; } // constructor with DREstring DREstring::DREstring(DREstring& rhs) { rhs.p->ref++; p = rhs.p; } // constructor with double, const char* DREstring::DREstring(double value, const char* format) { char temp[100]; this->initialise(); sprintf(temp, format, value); *this = temp; } // constructor with double, double DREstring::DREstring(double value, double format) { char t1[100]; sprintf(t1, "%1.1f", format); DREstring t2 = "%"; t2 += (DREstring)t1; t2 += (DREstring)"f"; this->initialise(); *this = DREstring(value, (const char*)t2); } // constructor with int, const char* DREstring::DREstring(int value, const char* format) { char temp[100]; this->initialise(); sprintf(temp, format, value); *this = temp; } // constructor with char*, int DREstring::DREstring(char* byte_array, int n_bytes) { this->initialise(); heap_check(p->s = new char [n_bytes + 1]); for (int n = 0; n < n_bytes; n++) *(p->s + n) = byte_array[n]; *(p->s + n_bytes) = 0; p->len = n_bytes; } // destructor DREstring::~DREstring() { if (!(p->ref)) then if (p->s) then fatal_error("Null reference count"); if (!(--p->ref)) then { if (p->s) delete [] p->s; delete p; } } // DREstring[n] char& DREstring::operator[](int n) { // if expression is on lhs, we must only change this reference if (p->ref > 1) then { DREstring temp = *this; this->disconnect(); p->len = temp.length(); heap_check(p->s = new char [p->len + 1]); for (int k = 0; k <= temp.length(); k++) *(p->s + k) = *(temp.p->s + k); } return *(p->s + n - 1); } // DREstring = char* void DREstring::operator=(const char* rhs) { if (p->ref > 1) then this->disconnect(); else { if (p->s) delete [] p->s; } p->len = (((strlen(rhs) <= p->max_len) || (p->max_len == 0)) ? strlen(rhs) : p->max_len); heap_check(p->s = new char [p->len + 1]); for (int n = 0; n <= p->len; n++) // keep the end-of-DREstring null !! *(p->s+n) = *(rhs+n); *(p->s + p->len) = '\0'; } // DREstring = DREstring void DREstring::operator=(DREstring& rhs) { if (this == &rhs) then return; if (p->ref > 1) then disconnect(); else { if (p->s) delete [] p->s; } p->len = (((rhs.length() <= p->max_len) || (p->max_len == 0)) ? rhs.length() : p->max_len); char *rhs_ptr = rhs.p->s; heap_check(p->s = new char [p->len + 1]); for (int n = 0; n < p->len; n++) *(p->s + n) = *(rhs_ptr + n); *(p->s + p->len) = '\0'; } // DREstring += DREstring void DREstring::operator+=(DREstring& rhs) { int total_length = p->len + rhs.p->len, original_length = p->len; if ((p->max_len) && (total_length > p->max_len)) then total_length = p->max_len; char* buf = p->s; boolean multiple = false; if (p->ref > 1) then { disconnect(); multiple = true; } heap_check(p->s = new char[total_length + 1]); for (int n = 0; n < original_length; n++) *(p->s+n) = *(buf+n); for (n = 0; n < (total_length - original_length); n++) *(p->s + original_length + n) = rhs.chr(n + 1); *(p->s + total_length) = '\0'; if (!multiple) then { if (buf) delete [] buf; } p->len = total_length; } // DREstring += const char* void DREstring::operator+=(const char* rhs) { int total_length = p->len + strlen(rhs), original_length = p->len; if ((p->max_len) && (total_length > p->max_len)) then total_length = p->max_len; char* buf = p->s; boolean multiple = false; if (p->ref > 1) then { disconnect(); multiple = true; } heap_check(p->s = new char[total_length + 1]); for (int n = 0; n < original_length; n++) *(p->s+n) = *(buf+n); for (n = 0; n < (total_length - original_length); n++) *(p->s + original_length + n) = rhs[n]; *(p->s + total_length) = '\0'; if (!multiple) then { if (buf) delete [] buf; } p->len = total_length; } // DREstring += char or DREstring += int void DREstring::operator+=(char& the_char) { char array[2]; array[0] = the_char; array[1] = '\0'; const char* char_ptr = array; *this += char_ptr; } // equality operator int DREstring::operator==(DREstring& rhs) { int equal = 1; equal = (equal && (length() == rhs.length())); if (equal) then { for (int n = 0; ((equal) && (n < length())); n++) equal = (*(p->s+n) == *(rhs.p->s+n)); } return equal; } // Borland C++ 3.1 will not permit this function to exist // (It could of course be emulated by using a different name, but then // we lose the syntactic nicety of using the equals operator) // char* = DREstring. If char* is to NULL then changes it and copies DREstring, // otherwise, DREstring must fit in the area pointed to by char* /* void operator=(char* lhs, const DREstring& rhs) // changes where lhs points iff lhs NULL { if (!lhs) then lhs = new char [rhs.length() + 1]; // change pointer if NULL for (int n = 0; n < rhs.length(); n++) *(lhs+n) = rhs.chr(n + 1); *(lhs + rhs.length()) = '\0'; } */ // forced type conversion to char. This is necessary because g++ handles // char* = DREstring as meaning char* = (char*)DREstring; I believe that this // behaviour is incorrect! void copy(char* cp, DREstring& st) { if (!cp) then heap_check(cp = new char [st.length() + 1]); for (int n = 0; n < st.length(); n++) *(cp + n) = *(st.p->s+n); *(cp + st.length()) = '\0'; } // DREstring + DREstring DREstring operator+(DREstring& lhs, DREstring& rhs) { DREstring plus_result = lhs; plus_result += rhs; return plus_result; } // disconnect a DREstring from itself void DREstring::disconnect() { p->ref--; str* temp = p; heap_check(p = new str); p->max_len = temp->max_len; p->ref = 1; p->s = 0; temp = 0; } void replace(DREstring& the_DREstring, char* old_char, char* new_char, const int n = 0) { int n_replacements = (n ? n : 10000); int index = 1; for (int m = 0; ((m < n_replacements) && (index <= the_DREstring.length())); index++) { if (the_DREstring[index] == *old_char) then { the_DREstring[index] = *new_char; m++; } } } DREstring left_fill(DREstring& the_DREstring, const int total_width, const char* insert_char) { DREstring left_fill_result; const int n_to_insert = total_width - the_DREstring.length(); for (int n = 1; n <= n_to_insert; n++) left_fill_result += insert_char; left_fill_result += the_DREstring; return left_fill_result; } DREstring right_fill(DREstring& the_DREstring, const int total_width, const char* insert_char) { DREstring right_fill_result; const int n_to_insert = total_width - the_DREstring.length(); right_fill_result = the_DREstring; for (int n = 1; n <= n_to_insert; n++) right_fill_result += insert_char; return right_fill_result; } DREstring centre(DREstring& the_DREstring, const int total_width, const char* surround_char) { DREstring centre_result = the_DREstring; const int padding_size = total_width - the_DREstring.length(); centre_result = left_fill(centre_result, padding_size / 2 + the_DREstring.length(), surround_char); centre_result = right_fill(centre_result, total_width, surround_char); return centre_result; } // a DREstring of a repeated character DREstring : total length = n DREstring filled_DREstring(char* the_char, int n) { DREstring filled_DREstring_result(n); while (filled_DREstring_result.length() < n) filled_DREstring_result += (DREstring)the_char; return filled_DREstring_result; } // return subDREstring DREstring subDREstring(DREstring& the_DREstring, const int start, const int len) { DREstring subDREstring_result; int true_start = ((start < 1) ? 1 : start); if (true_start > the_DREstring.length()) then return subDREstring_result; int end = start + len - 1; int true_end = ((end > the_DREstring.length()) ? the_DREstring.length() : end); for (int n = true_start; n <= true_end; n++) subDREstring_result += (DREstring)(the_DREstring.chr(n)); return subDREstring_result; } // find a given character int find(DREstring& the_DREstring, const char* the_char) { for (int n = 1; ((n <= the_DREstring.length()) && (the_DREstring.chr(n) != *the_char)); n++);; if (n <= the_DREstring.length()) then return n; else return 0; } int find(DREstring& the_DREstring, char& the_char) { return find(the_DREstring, (char*)(&the_char)); } // insert one DREstring into another DREstring insert(DREstring& DREstring1, int pos, DREstring& DREstring2) { if (pos > DREstring1.length()) then return DREstring1; DREstring insert_result = subDREstring(DREstring1, 1, pos - 1); int max_len = (DREstring1.max_length() ? DREstring1.max_length(): 10000); int chars_from_DREstring2 = (((pos - 1 + DREstring2.length()) > max_len) ? (DREstring1.max_length() - (pos - 1)) : DREstring2.length()); insert_result += subDREstring(DREstring2, 1, chars_from_DREstring2); int chars_from_DREstring1 = (((DREstring1.length() + DREstring2.length()) > max_len) ? (DREstring1.length() + DREstring2.length() - insert_result.length()) : DREstring1.length() - (pos - 1)); insert_result += subDREstring(DREstring1, pos, chars_from_DREstring1); return insert_result; } // overwrite one DREstring with another : length NOT extended DREstring overwrite(DREstring& DREstring1, const int pos, DREstring& DREstring2) { if (pos > DREstring1.length()) then return DREstring1; DREstring overwrite_result = subDREstring(DREstring1, 1, pos - 1); int chars_from_DREstring2 = ((pos - 1 + DREstring2.length() > DREstring1.length()) ? (DREstring1.length() - (pos - 1)) : DREstring2.length()); overwrite_result += subDREstring(DREstring2, 1, chars_from_DREstring2); int chars_from_DREstring_1 = DREstring1.length() - DREstring2.length() - (pos - 1); overwrite_result += subDREstring(DREstring1, pos + DREstring2.length(), chars_from_DREstring_1); return overwrite_result; } // remove a subDREstring from a DREstring DREstring remove(DREstring& the_DREstring, int pos, int len) { DREstring remove_result = subDREstring(the_DREstring, 1, pos - 1); remove_result += subDREstring(the_DREstring, pos + len); return remove_result; } // duplicate(destination, source) -- make a duplicate of a DREstring // a call to this routine should NEVER be necessary void duplicate(DREstring& dest, DREstring src) { // clear the destination DREstring if (dest.p->ref > 1) then dest.disconnect(); dest.p->len = src.p->len; dest.p->max_len = src.p->max_len; dest.p->ref = 1; heap_check(dest.p->s = new char [src.length() + 1]); // allow room for final zero for (int n = 0; n <= src.length(); n++) *(dest.p->s+n) = *(src.p->s+n); } void DREstring::operator++(void) { p->ref++; } ostream& operator<<(ostream& ost, const DREstring s) { const char* tc = s; ost << tc; return ost; } // read a line into a DREstring; the newline is NOT included istream& operator>>(istream& ist, DREstring& s) { char c; uint32 permitted_length = s.max_length(); if (!permitted_length) permitted_length = 100000; // arbitrary and large s = ""; while (s.length() < permitted_length) { ist.get(c); if ((c == '\n') || !(ist.good())) then return ist; else s += c; } // the line was too long warning("Incomplete line read in operator>>(istream&, DREstring&)"); return ist; } DREstring& DREstring::toupper(void) { for (int n = 1; n <= this->length(); n++) (*this)[n] = ::toupper(chr(n)); return *this; } DREstring DREstring::operator+(const char* cp) { DREstring plus_result = *this; plus_result += cp; return plus_result; }