_OBJECT-ORIENTED DEBUGGING_ by Simon Tooke [LISTING ONE] #ifndef STRING_H #define STRING_H #include <string.h> #include <memory.h> #include <malloc.h> #ifdef NULL # undef NULL #endif #define NULL 0 typedef enum { False, True } Boolean; // a String is a simple implementation of a C++ string class class String { char *s; // actual pointer to text public: String(void) { s = strdup(""); } String(char *c) { s = strdup(c); } String(char *c, int n) { s = new char[n+1]; memcpy(s,c,n); s[n]=0; } String(String &ss, char *c) { s = malloc(strlen(ss.s)+strlen(c)+1); strcpy(s,ss.s); strcat(s,c); } String(String &ss) { s = strdup(ss.s); } ~String(void) { delete s; } operator char *(void) { return s; } String& operator +(char *c) { String *a = new String(*this,c); return *a;} String& operator +=(char *c) { *this = *this + c; return *this; } String& operator =(char *c) { delete s; s = strdup(c); return *this; } String& operator =(String& a){ delete s; s = strdup(a.s); return *this; } operator ==(char *c) const; operator ==(String *c) const; #ifdef DEBUG void dump() const; Boolean verify() const; #endif /*DEBUG*/ }; // a StringListElement is a single item in a StringList class StringListElement { String s; // this String in the list StringListElement *next; // pointer to next element in list public: StringListElement(void) : next(NULL), s("") {} StringListElement(char *c) : next(NULL), s(c) {} StringListElement(char *c, int n) : next(NULL), s(c,n) {} StringListElement(String &ss) : next(NULL), s(ss) {} ~StringListElement(void) { if (next) delete next; next=NULL; } friend class StringList; friend class StringListIterator; #ifdef DEBUG void dump() const; Boolean verify() const; #endif /*DEBUG*/ }; // a StringList is a simple single-linked list of strings class StringList { StringListElement *head; // first String in list StringListElement *tail; // last String in list public: StringList(void) : head(NULL), tail(NULL) {} StringList(String& ss) { head = tail = new StringListElement(ss); } StringList(char *ss) { head = tail = new StringListElement(ss); } ~StringList(void) { if (head) { delete head; head=NULL; } } String& find(char *s) const; void clear(void) { delete head; head = tail = NULL; } StringList& operator +=(StringList& xx); StringList& operator +=(char *ss); StringList& operator +=(String& ss); StringList& operator =(StringList& xx); operator int(); friend class StringListIterator; #ifdef DEBUG void dump() const; Boolean verify() const; #endif /*DEBUG*/ }; // a StringListIterator is a method of traversing a list of strings class StringListIterator { const StringList *list; // StringList to be traversed StringListElement *nxt; // current String in StringList public: StringListIterator(void) : list(NULL), nxt(NULL) {} StringListIterator(const StringList *l) : list(l), nxt(l->head) {} String *next(void); void reset() { nxt = (list != NULL) ? list->head: NULL; } int anymore() const { return (nxt != NULL); } StringListIterator& operator =(const StringList& ss); #ifdef DEBUG void dump() const; Boolean verify() const; #endif /*DEBUG*/ }; #endif // STRING_H [LISTING TWO] #include <stream.h> #include "String.h" int main (int, char *[]) { String a("Hello "); String *b = new String("world."); String c; c = a + *b + "\n"; cout << "a + b = " << (char *)c; cout << "a = " << (char *)a << "\n"; cout << "b = " << (char *)*b << "\n"; StringList l(a); l += *b; l.dump(); } [LISTING THREE] #ifndef ASSERT_HDR #define ASSERT_HDR #ifdef DEBUG extern void _assertRtn(char *, int); # define assert(condition) \ if (condition) ; else _assertRtn(__FILE__,__LINE__); #else /*ifndef DEBUG*/ # define assert(condition) #endif #endif /*ASSERT_HDR*/ [LISTING FOUR] #include <stream.h> #ifdef DEBUG void _assertRtn(char *file, int line) { cerr << "\nAssertion Failure in file '" << file << "' line " << line << "\n"; line = 0; line /= line; // force core dump } #endif [LISTING FIVE] #include "String.h" #include "Assert.h" #ifdef DEBUG # include <stream.h> #endif /***** String class ******/ // String comparison operator String::operator ==(char *c) const { assert(this->verify()); // compare String to char array return strcmp(s,c) == 0; } // String comparison operator String::operator ==(String *c) const { assert(this->verify()); // compare String to String return strcmp(s,(char *)c) == 0; } #ifdef DEBUG void String::dump(void) const { assert(this->verify()); cerr << "String(\"" << s << "\")"; } Boolean String::verify(void) const { // Strings must always point to something. if (s == NULL) return False; return True; } #endif /****** StringList class (and StringListElement) ******/ StringList& StringList::operator +=(String& ss) { assert(this->verify()); if (tail) { tail->next = new StringListElement(ss); tail = tail->next; } else head = tail = new StringListElement(ss); return *this; } StringList& StringList::operator +=(char *ss) { assert(this->verify()); if (tail) { tail->next = new StringListElement(ss); tail = tail->next; } else head = tail = new StringListElement(ss); return *this; } StringList& StringList::operator +=(StringList& xx) { assert(this->verify()); // add new list to old list item by item for (StringListElement *le=xx.head; le; le=le->next) *this += le->s; return *this; } // StringList assignment operator (performs deep copy) StringList& StringList::operator =(StringList& xx) { assert(this->verify()); // get rid of old list clear(); // add new list to (clear) old list item by item for (StringListElement *le=xx.head; le; le=le->next) *this += le->s; // return new copy of old list return *this; } // (int)(StringList) cast returns number of strings in list StringList::operator int() { int count = 0; StringListIterator ll(this); assert(this->verify()); while (ll.next() != NULL) count++; return count; } #ifdef DEBUG // // dump() - display instance in format "StringList(...)" // void StringList::dump(void) const { // check consistancy assert(this->verify()); // print header cerr << "StringList("; // use StringListElement::dump() to recursively display all members if (head != NULL) head->dump(); // print trailer cerr << ")\n"; } Boolean StringList::verify(void) const { // if there are elements in this list, ensure they are valid. // (note that head->verify() ensures the entire list is valid.) if ((head!=NULL) && !head->verify()) return False; // Both the head and tail must either be null or non-null. if ((head!=NULL) && (tail==NULL)) return False; if ((head==NULL) && (tail!=NULL)) return False; return True; } #endif /*DEBUG*/ #ifdef DEBUG void StringListElement::dump(void) const { assert(this->verify()); s.dump(); if (next != NULL) { cerr << ','; next->dump(); } } Boolean StringListElement::verify(void) const { // An element of a list of Strings must point to a valid String. if ((char *)(s) == NULL) return False; if (!s.verify()) return False; // If there is another element within this list, it must be valid. if ((next!=NULL) && !next->verify()) return False; return True; } #endif /****** StringListIterator class ******/ // assignment operator StringListIterator& StringListIterator::operator =(const StringList& ss) { assert(this->verify()); list = &ss; nxt = ss.head; return *this; } // get next item in list of strings pointed to by iterator String *StringListIterator::next(void) { assert(this->verify()); if (list == NULL) return NULL; // no StringList, so no next item if (nxt == NULL) return NULL; // at end of list, so no next item String *aa = &(nxt->s); // save pointer to String nxt = nxt->next; // point to next item in list return aa; // return pointer to String } #ifdef DEBUG Boolean StringListIterator::verify(void) const { // if there is a list available, verify it. if (!list->verify()) return False; // if we haven't reached the end of the list, // verify the next element if (nxt != NULL && !nxt->verify()) return False; // everything appears correct return True; } #endif /*DEBUG*/ [LISTING SIX] CC = CC CFLAGS = -DDEBUG prog : main.o String.o lib.o $(CC) main.o String.o lib.o -o prog String.o : String.C String.h $(CC) -c $(CFLAGS) String.C main.o : main.C String.h $(CC) -c $(CFLAGS) main.C lib.o : lib.C $(CC) -c $(CFLAGS) lib.C clean : rm -f *.o a.out core clobber : clean rm -f prog