#!/bin/sh # This is a shar archive. # The rest of this file is a shell script which will extract: # # 7_8a.h 7_8a1.h 7_8a2.h 7_8a3.h 7_8a4.h 7_8a5.h 7_8decl.h 7_8x1.c 7_8x2.c 7_8x3.c 7_8x4.c makefile tst.c tst.cmp # # To extract the files from this shell archive file simply # create a directory for this file, move the archive file # to it and enter the command # # sh filename # # The files will be extracted automatically. # Note: Do not use csh. # # Archive created: Mon Jul 30 23:11:06 EDT 1990 # echo x - 7_8a.h sed 's/^X//' > 7_8a.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #define gdlink(TYPE) #define gdlist(TYPE) #define gdlinkdeclare(TYPE) #define gdlistdeclare(TYPE) #define gdlinkimplement(TYPE) #define gdlistimplement(TYPE) !EOF! ls -l 7_8a.h echo x - 7_8a1.h sed 's/^X//' > 7_8a1.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #define gdlink(TYPE) name2(gdlink,TYPE) #define gdlist(TYPE) name2(gdlist,TYPE) !EOF! ls -l 7_8a1.h echo x - 7_8a2.h sed 's/^X//' > 7_8a2.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #define gdlinkdeclare(TYPE) \ class gdlink(TYPE) \ { \ friend class gdlist(TYPE); \ gdlink(TYPE) *next; \ gdlink(TYPE) *prev; \ TYPE e; \ \ gdlink(TYPE)(TYPE a, \ gdlink(TYPE) *n = 0, \ gdlink(TYPE) *p = 0) \ { e = a; next = n; prev = p; } \ \ void insert(gdlink(TYPE) *n); \ void append(gdlink(TYPE) *n); \ void remove(); \ }; !EOF! ls -l 7_8a2.h echo x - 7_8a3.h sed 's/^X//' > 7_8a3.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #define gdlistdeclare(TYPE) \ /* manage a doubly-linked list */ \ class gdlist(TYPE) \ { \ gdlink(TYPE) *last; \ gdlink(TYPE) *curr; \ \ public: \ gdlist(TYPE)() { last = curr = 0; }; \ \ gdlist(TYPE)(TYPE a) \ { curr = 0; last = new gdlink(TYPE)(a); \ last->next = last->prev = last; \ } \ \ int isempty() { return last != 0; } \ \ void clear(); \ \ ~gdlist(TYPE)() { clear(); }; \ \ /* set current pointer to the */ \ /* ends of the list */ \ void reset() { curr = 0; } \ \ /* move around the list, */ \ /* leaving the links there */ \ int next(TYPE &e); \ int prev(TYPE &e); \ \ /* move around the list, */ \ /* removing the links */ \ int getnext(TYPE &e); \ int getprev(TYPE &e); \ \ /* manipulate around the beginning */ \ /* and end of the list */ \ void insert(TYPE e); \ void append(TYPE e); \ \ /* work around the current entry */ \ void inserthere(TYPE e); \ void appendhere(TYPE e); \ }; !EOF! ls -l 7_8a3.h echo x - 7_8a4.h sed 's/^X//' > 7_8a4.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #define gdlinkimplement(TYPE) \ /* insert a gdlink(TYPE) in */ \ /* front of this one */ \ void gdlink(TYPE):: \ insert(gdlink(TYPE) *newlink) \ { \ if (prev) \ prev->next = newlink; \ \ newlink->next = this; \ newlink->prev = prev; \ prev = newlink; \ } \ \ /* append a gdlink(TYPE) after this one */ \ void gdlink(TYPE):: \ append(gdlink(TYPE) *newlink) \ { \ if (next) \ next->prev = newlink; \ \ newlink->next = next; \ newlink->prev = this; \ next = newlink; \ } \ \ /* remove this link from the list */ \ void gdlink(TYPE)::remove() \ { \ if (prev) \ prev->next = next; \ \ if (next) \ next->prev = prev; \ \ next = prev = 0; \ } !EOF! ls -l 7_8a4.h echo x - 7_8a5.h sed 's/^X//' > 7_8a5.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #define gdlistimplement(TYPE) \ /* clear the list */ \ void gdlist(TYPE)::clear() \ { \ gdlink(TYPE) *l = last; \ if (!l) return; \ \ do { \ gdlink(TYPE) *ll = l; \ l = l->next; \ delete ll; \ } while (l != last); \ \ last = 0; \ } \ \ /* Get the next entry from a list, */ \ /* moving curr forward. */ \ int gdlist(TYPE)::next(TYPE &a) \ { \ if (!last) \ return 0; \ \ /* move curr forward, possibly to */ \ /* the beginning or end of the list. */ \ if (curr) \ if (curr == last) \ { \ curr = 0; \ return 0; \ } \ \ else \ curr = curr->next; \ \ else \ curr = last->next; \ \ a = curr->e; \ return 1; \ } \ \ /* Get the previous entry from a list, */ \ /* moving curr backwards. */ \ int gdlist(TYPE)::prev(TYPE &a) \ { \ if (!last) \ return 0; \ \ /* move curr backwards, possibly to */ \ /* the beginning or end of the list. */ \ if (curr) \ if (curr == last->next) \ { \ curr = 0; \ return 0; \ } \ \ else \ curr = curr->prev; \ \ else \ curr = last; \ \ a = curr->e; \ return 1; \ } \ \ /* Get the next entry from a list, */ \ /* removing it afterwards. */ \ /* curr is left alone. */ \ int gdlist(TYPE)::getnext(TYPE &a) \ { \ if (!last) \ return 0; \ \ /* choose the link to remove */ \ gdlink(TYPE) *f; \ if (curr) \ if (curr == last) \ { \ curr = 0; \ return 0; \ } \ \ else \ f = curr->next; \ \ else \ f = last->next; \ \ a = f->e; \ \ /* remove f from the list */ \ if (f == last) \ last = 0; \ \ else \ f->remove(); \ \ delete f; \ return 1; \ } \ \ /* Get the previous entry from a list, */ \ /* removing it afterwards */ \ int gdlist(TYPE)::getprev(TYPE &a) \ { \ if (!last) \ return 0; \ \ /* choose the link to remove */ \ gdlink(TYPE) *f; \ if (curr) \ if (curr == last->prev) \ { \ curr = 0; \ return 0; \ } \ \ else \ f = curr->prev; \ \ else \ curr = last; \ \ a = f->e; \ \ /* remove f from the list */ \ if (f == last) \ last = 0; \ \ else \ f->remove(); \ \ delete f; \ return 1; \ } \ \ /* insert an entry at the */ \ /* beginning of the list */ \ void gdlist(TYPE)::insert(TYPE a) \ { \ if (last) \ last->next-> \ insert(new gdlink(TYPE)(a)); \ \ else \ { \ last = new gdlink(TYPE)(a); \ last->next = last->prev = last; \ } \ } \ \ /* Append an entry at the end of the */ \ /* list. This is the same as */ \ /* gdlist(TYPE)::insert() */ \ /* except that gdlist(TYPE)::last is */ \ /* adjusted afterwards. */ \ void gdlist(TYPE)::append(TYPE a) \ { \ this->insert(a); \ last = last->next; \ } \ \ /* Insert an entry before the */ \ /* current location of the list. */ \ /* If curr is not set, insert at */ \ /* the beginning of the list. */ \ void gdlist(TYPE)::inserthere(TYPE a) \ { \ if (curr) \ curr->insert(new gdlink(TYPE)(a)); \ \ else \ this->insert(a); \ } \ \ /* Append an entry after the */ \ /* current location of the list. */ \ /* If curr is not set, append at */ \ /* the end of the list. */ \ void gdlist(TYPE)::appendhere(TYPE a) \ { \ if (curr) \ curr->append(new gdlink(TYPE)(a)); \ \ else \ this->append(a); \ } !EOF! ls -l 7_8a5.h echo x - 7_8decl.h sed 's/^X//' > 7_8decl.h << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // Exercise 7.8 // Generic doubly linked list. // The user would use the generic class gdlink(TYPE) // for a user type TYPE by the following steps: // // declare(gdlink, TYPE) // declare(gdlist, TYPE) // implement(gdlink, TYPE) // implement(gdlist, TYPE) // // gdlink(TYPE) X; // gdlist(TYPE) Y(X); #ifndef DLINK_H # define DLINK_H #include #include "7_8a1.h" // EXPAND gdlink(TYPE), gdlist(TYPE) #include "7_8a2.h" // EXPAND gdlinkdeclare(TYPE) #include "7_8a3.h" // EXPAND gdlistdeclare(TYPE) #include "7_8a4.h" // EXPAND gdlinkimplement(TYPE) #include "7_8a5.h" // EXPAND gdlistimplement(TYPE) #endif /* DLINK_H */ !EOF! ls -l 7_8decl.h echo x - 7_8x1.c sed 's/^X//' > 7_8x1.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ declare(GENERIC,int) implement(GENERIC,int) !EOF! ls -l 7_8x1.c echo x - 7_8x2.c sed 's/^X//' > 7_8x2.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ GENERIC(int) x; !EOF! ls -l 7_8x2.c echo x - 7_8x3.c sed 's/^X//' > 7_8x3.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #define GENERIC(type) #define GENERICdeclare(type) #define GENERICimplement(type) !EOF! ls -l 7_8x3.c echo x - 7_8x4.c sed 's/^X//' > 7_8x4.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #ifndef CLASS_H #define CLASS_H // ... #endif /* CLASS_H */ !EOF! ls -l 7_8x4.c echo x - makefile sed 's/^X//' > makefile << '!EOF!' CC= CC -I. -I../../CC CFLAGS= all: tst tst: tst.o $(CC) -o tst tst.o tst.o: tst.c 7_8decl.h 7_8a1.h 7_8a2.h 7_8a3.h 7_8a4.h 7_8a5.h $(CC) -c tst.c CMP= tst.cmp OUT= tst.out tst.out: tst ; tst > tst.out test: all $(CMP) $(OUT) cmp tst.out tst.cmp @echo test done !EOF! ls -l makefile echo x - tst.c sed 's/^X//' > tst.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include "7_8decl.h" #include typedef void *Ent; declare(gdlink,Ent) declare(gdlist,Ent) implement(gdlink,Ent) implement(gdlist,Ent) main() { gdlist(Ent) xdlist("hello"); xdlist.append("there"); xdlist.append("how"); xdlist.append("are"); xdlist.append("you"); xdlist.append("today"); void *x; cout << "forwards\n"; while (xdlist.next(x)) cout << "'" << (char*)x << "'\n"; cout << "\nbackwards\n"; while (xdlist.prev(x)) cout << "'" << (char*)x << "'\n"; xdlist.next(x); xdlist.next(x); xdlist.inserthere("Beep"); xdlist.appendhere("Boop"); xdlist.reset(); cout << "\nforwards, removing\n"; while (xdlist.getnext(x)) cout << "'" << (char*)x << "'\n"; cout << "\nbackwards\n"; while (xdlist.getprev(x)) cout << "'" << (char*)x << "'\n"; return 0; } !EOF! ls -l tst.c echo x - tst.cmp sed 's/^X//' > tst.cmp << '!EOF!' forwards 'hello' 'there' 'how' 'are' 'you' 'today' backwards 'today' 'you' 'are' 'how' 'there' 'hello' forwards, removing 'hello' 'Beep' 'there' 'Boop' 'how' 'are' 'you' 'today' backwards !EOF! ls -l tst.cmp # The following exit is to ensure that extra garbage # after the end of the shar file will be ignored. exit 0