/* odlistcomp Program to compare overdue checklists. Generates list of new books and of books no longer on list. haleyjd 2/28/08 */ #ifdef _MSC_VER #pragma warning( disable : 4786 ) #endif #include #include #include #include #include #include #include #include using namespace std; class ODBook { protected: int circNum; string callNum; public: ODBook() : circNum(0), callNum("") {} ODBook(int circ, string &call) { circNum = circ; callNum = call; } int getCircNum() const { return circNum; } void setCircNum(int cn) { circNum = cn; } const string &getCallNum() const { return callNum; } void setCallNum(string &str) { callNum = str; } bool operator <(const ODBook &b) { if(callNum < b.callNum) return true; else if(callNum == b.callNum) return (circNum < b.circNum); else return false; } bool operator >(const ODBook &b) { if(callNum > b.callNum) return true; else if(callNum == b.callNum) return (circNum > b.circNum); else return false; } bool operator ==(const ODBook &b) { return (circNum == b.circNum && callNum == b.callNum); } }; static vector oldCircNums; static vector newCircNums; static vector missingBooks; static vector newBooks; static string ReadCallNum(string &str) { size_t tab = str.find_first_of('\t'); if(tab == string::npos) { cout << "Critical Error: malformed input file" << endl; exit(1); } return str.substr(0, tab); } static int ReadCircNum(string &str) { size_t tab = str.find_first_of('\t'); if(tab != string::npos) { char num[33]; size_t i; int j = 0; memset(num, 0, sizeof(num)); for(i = tab + 1; i < str.length(); ++i, ++j) { try { if(str.at(i) >= '0' && str.at(i) <= '9') { num[j] = (char)(str.at(i)); } else break; } catch(...) { cout << "Critical Error: read outside of string" << endl; exit(1); } } return atoi(num); } else { cout << "Critical Error: malformed input file" << endl; exit(1); } return 0; } static void ReadInput(ifstream &infile, vector &v) { string str; char c; ODBook newBook; while(infile.read(&c, 1)) { switch(c) { case '\n': // newline newBook.setCallNum(ReadCallNum(str)); newBook.setCircNum(ReadCircNum(str)); v.push_back(newBook); str.erase(); break; default: str.append(1, c); break; } } } enum { STATE_BEGIN, STATE_EQUAL, STATE_MISSING, STATE_NEW, STATE_FINISHED, STATE_IDONE, STATE_JDONE, }; static void CompareLists(void) { int i = 0, j = 0, oldsize, newsize; int state = STATE_BEGIN; oldsize = oldCircNums.size(); newsize = newCircNums.size(); do { if(i == oldsize && j == newsize) // both lists are done? finished. state = STATE_FINISHED; switch(state) { case STATE_BEGIN: case STATE_EQUAL: if(oldCircNums[i] == newCircNums[j]) // equal: skip this one { ++i; ++j; if(i == oldsize && j == newsize) // both lists are done? finished. state = STATE_FINISHED; else if(i == oldsize) // only i is finished? state = STATE_IDONE; else if(j == newsize) // only j is finished? state = STATE_JDONE; else // keep scanning state = STATE_EQUAL; } else if(oldCircNums[i] < newCircNums[j]) // i < j - book on i not in j { state = STATE_MISSING; } else // i > j - book on j not in i { state = STATE_NEW; } break; case STATE_MISSING: // old list contains books not on new list. // scan forward in old list until i >= j while(oldCircNums[i] < newCircNums[j] && i != oldsize) { missingBooks.push_back(oldCircNums[i]); ++i; } if(i == oldsize) state = STATE_IDONE; // old is empty, finish off new else state = STATE_EQUAL; // keep scanning break; case STATE_NEW: // new list contains books not on old list. // scan forward in new list until j >= i while(newCircNums[j] < oldCircNums[i] && j != newsize) { newBooks.push_back(newCircNums[j]); ++j; } if(j == newsize) state = STATE_JDONE; // new is empty, finish off old else state = STATE_EQUAL; // keep scanning break; case STATE_IDONE: // i is finished before j - remainder of books in j are new while(j < newsize) { newBooks.push_back(newCircNums[j]); ++j; } state = STATE_FINISHED; // now we're done break; case STATE_JDONE: // j is finished before i - remainder of books in i are missing while(i < oldsize) { missingBooks.push_back(oldCircNums[i]); ++i; } state = STATE_FINISHED; // now we're done break; default: break; } } while(state != STATE_FINISHED); } static void PrintODVector(vector &v) { int i = 0; int size = v.size(); while(i != size) { cout << setw(14) << setiosflags(ios::left) << v[i].getCallNum().c_str() << v[i].getCircNum() << endl; ++i; } } static void PrintMissingBooks(void) { cout << "Books missing from new list:" << endl; PrintODVector(missingBooks); } static void PrintNewBooks(void) { cout << "\n\nNew books:" << endl; PrintODVector(newBooks); } // // Main Program // int main(int argc, char *argv[]) { ifstream oldinput; ifstream newinput; const char *oldfn, *newfn; if(argc < 3) { cout << "Usage: odlistcomp " << endl; return 0; } oldfn = argv[1]; newfn = argv[2]; oldinput.open(oldfn); newinput.open(newfn); if(!oldinput || oldinput.bad() || !newinput || newinput.bad()) { cout << "Error: could not open one or more input files." << endl; return 1; } // read old input ReadInput(oldinput, oldCircNums); // read new input ReadInput(newinput, newCircNums); // done with files oldinput.close(); newinput.close(); // sort input sort(oldCircNums.begin(), oldCircNums.end()); sort(newCircNums.begin(), newCircNums.end()); // generate difference lists CompareLists(); // print output PrintMissingBooks(); PrintNewBooks(); return 0; } // EOF