// ------------------------------- // // -------- Start of File -------- // // ------------------------------- // // ----------------------------------------------------------- // // C++ Source Code File Name: testprog.cpp // Compiler Used: MSVC, BCC32, GCC, HPUX aCC, SOLARIS CC // Produced By: glNET Software // File Creation Date: 09/18/1997 // Date Last Modified: 05/25/2001 // Copyright (c) 2001 glNET Software // ----------------------------------------------------------- // // ------------- Program Description and Details ------------- // // ----------------------------------------------------------- // /* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA This is a test program use to test the Persistent base class. */ // ----------------------------------------------------------- // #include <iostream.h> #include "grocery.h" void PausePrg() // Function used to pause the program. { cout << endl; cout << "Press enter to continue..." << endl; cin.get(); } void ClearInputStream(istream &s) // Function used to clear the input stream. { char c; s.clear(); while(s.get(c) && c != '\n') { ; } } int Quit() { cout << "Exiting..." << endl; return 0; } char *InputData() // Function used to read a string from the input stream. // Returns a null terminated string or a null value if an // error occurs. NOTE: The calling function must free the // memory allocated for this string. { char buf[MAX_NAME_LENGTH]; for(unsigned i = 0; i < MAX_NAME_LENGTH; i++) buf[i] = 0; cout << "Item name: "; cin.getline(buf, sizeof(buf)); char *s = new char[strlen(buf)+1]; // Account for null terminator if(!s) return 0; strcpy(s, buf); return s; } void DisplayItem(Grocery &grocery, int full = 1) // Function used to print a grocery list object to the stdout. { cout << endl; cout << "Item's Name = " << grocery.Name() << endl; if(full) { cout << "Stock Number = " << grocery.StockNumber() << endl; cout.setf(ios::showpoint | ios::fixed); cout.precision(2); cout << "Price = $" << grocery.Price() << endl; cout << endl; } } void AddItem(const POD *DB) // Function used to add an object to the database. { char *buf = InputData(); Grocery grocery(DB); grocery.SetName((Name_t)buf); int exists = grocery.FindObject(); if(exists) { cout << "Item: " << buf << " already exists at address " << grocery.ObjectAddress() << endl; delete buf; return; } int stock_number; double price; cout << "Enter the items's stock number: "; cin >> stock_number; if(cin) { grocery.SetStockNumber(stock_number); cout << "Enter the items's price: $"; cin >> price; } else { cout << "Invalid entry. Object not added!" << endl; delete buf; return; } if(cin) { grocery.SetPrice(price); } else { cout << "Invalid entry. Object not added!" << endl; delete buf; return; } ClearInputStream(cin); if(!grocery.WriteObject()) { cout << "Could not add object to the database" << endl; } delete buf; } void DeleteItem(const POD *DB) // Function used to delete an object from the database. { char *buf = InputData(); Grocery grocery(DB); grocery.SetName((Name_t)buf); if(!grocery.DeleteObject()) { cout << "Could not find item: " << buf << " in the database" << endl; delete buf; return; } cout << "Deleted item: " << buf << " at address " << grocery.ObjectAddress() << endl; delete buf; } void ListInOrder(const POD *DB, unsigned index_number) // List the contents of the database using the index file. { int i = 0; Grocery grocery(DB); GroceryKey key, compare_key; gxBtree *btx = DB->Index(index_number); // Ensure that the in memory buffers and the file data // stay in sync during multiple file access. btx->TestTree(index_number); // Walk through the tree starting at the first key if(btx->FindFirst(key)) { if(!grocery.ReadObject(key.ObjectID())) { cout << "Error reading the object" << endl; return; } DisplayItem(grocery); grocery.ClearName(); while(btx->FindNext(key, compare_key)) { if(!grocery.ReadObject(key.ObjectID())) { cout << "Error reading the object" << endl; return; } DisplayItem(grocery); grocery.ClearName(); } } } void ListInOrder(const POD *DB) // List contents of the database without using the index file. { FAU addr = (FAU)0; Grocery grocery(DB); unsigned count = 0; ClearInputStream(cin); // Clear input stream while(1) { addr = DB->OpenDataFile()->FindFirstObject(addr); if(!addr) break; if(!grocery.ReadObject(addr)) { cout << "Error reading the object" << endl; return; } DisplayItem(grocery); grocery.ClearName(); count++; if(count == 2) { PausePrg(); count = 0; } } } void FindItem(const POD *DB) // Function used to find an object in the database. { char *buf = InputData(); Grocery grocery(DB); grocery.SetName((Name_t)buf); if(!grocery.FindObject()) { cout << "Could not find item: " << grocery.Name() << " in the database" << endl; delete buf; return; } cout << "Found item: " << buf << " at address " << grocery.ObjectAddress() << endl; delete buf; if(!grocery.ReadObject()) { cout << "Error reading the object" << endl; grocery.ClearName(); // Prevent memory leak return; } DisplayItem(grocery); grocery.ClearName(); // Prevent memory leak } void BuildDatabase(const POD *DB) // Function used to build a test database. { const int NUM_OBJECTS = 1000; int i; Grocery grocery(DB); char name[MAX_NAME_LENGTH]; int stock_number = 2000; double price = 0.95; cout << "Adding " << NUM_OBJECTS << " objects to the database..." << endl; for(i = 0; i < NUM_OBJECTS; i++) { sprintf(name, "Item %i", i); // Set the item's name, stock number, price grocery.SetName((Name_t)name); grocery.SetStockNumber(StockNumber_t(stock_number+i)); grocery.SetPrice(Price_t(price+i)); // Write the grocery list item to the database if(!grocery.WriteObject()) { cout << "Could not add object number " << i << " to the database" << endl; return; } } } void Menu() // Console based user menu. { cout << "(A, a) Add object to the database" << endl; cout << "(B, b) Build a test database" << endl; cout << "(D, d) Delete object from the database" << endl; cout << "(F, f) Find item by name" << endl; cout << "(L, l) List without using index file" << endl; cout << "(H, h, ?) Help (prints this menu)" << endl; cout << "(I, i) List using the index file" << endl; cout << "(Q, q) Quit" << endl; cout << "(X, x) Compare the index file to the data file" << endl; cout << "(Y, y) Rebuild the index file" << endl; } void Compare(const POD *DB) // Function used to compare the contents of the data file to the // index file. { if(!DB->UsingIndex()) { cout << "This database is not using the indexing sub-system" << endl; return; } Grocery grocery(DB); cout << endl; cout << "Comparing the index file to the data file..." << endl; int rv = grocery.CompareIndex(0); if(!rv) { cout << "The index file does not match the data file!" << endl; cout << "The index file needs to be rebuilt." << endl; cout << endl; return; } cout << "The index file checks good" << endl; cout << endl; } void Rebuild(const POD *DB, const char *fname) // Function used to rebuild the index file if the index file // entries no longer match the data file entries. { if(!DB->UsingIndex()) return; Grocery grocery(DB); cout << endl; cout << "Rebuilding the index file..." << endl; // Rebuild index number 0 with room for 1 tree header int rv = grocery.RebuildIndexFile(fname, 0, 1, POD_DEFAULT_ORDER); if(!rv) { cout << "The index file was not rebuilt!" << endl; cout << endl; return; } cout << "The index file was rebuilt." << endl; cout << "A new index file named " << fname << " was created."; cout << endl; } int main() { const char *data_file = "grocery.gxd"; const char *index_file = "grocery.btx"; GroceryKey key_type; // Create or open an existing database using a single index file POD pod; gxDatabaseError err = pod.Open(data_file, index_file, key_type, POD_DEFAULT_ORDER); // Test for any errors if(err != gxDBASE_NO_ERROR) { cout << gxDatabaseExceptionMessage(err) << endl; return 1; } char c; int rv = 1; Menu(); while(rv) { if (!cin) { ClearInputStream(cin); if (!cin) { cout << "Input stream error" << endl; return 0; } } cout << '>'; cin >> c; if (!cin) continue; switch(c) { case 'a' : case 'A' : ClearInputStream(cin); AddItem(&pod); break; case 'b' : case 'B' : BuildDatabase(&pod); break; case 'd' : case 'D' : ClearInputStream(cin); DeleteItem(&pod); break; case 'f' : case 'F' : ClearInputStream(cin); FindItem(&pod); break; case 'l' : case 'L' : ListInOrder(&pod); break; case 'i' : case 'I' : ListInOrder(&pod, 0); break; case 'h' : case 'H' : case '?' : Menu(); break; case 'q' : case 'Q' : rv = Quit(); break; case 'x' : case 'X' : Compare(&pod); break; case 'y' : case 'Y' : Rebuild(&pod, "newindex.btx"); break; default: cout << "Unrecognized command" << endl; } } return 0; } // ----------------------------------------------------------- // // ------------------------------- // // --------- End of File --------- // // ------------------------------- //