// ------------------------------- //
// -------- 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 --------- //
// ------------------------------- //