Chris Pollett>Old Classes>PIC 10a, Spring 2000>Hw4>Hw4 Solutions
//
// Program Name: MyDatabase.cpp
//
// Purpose: A simple database application. Allows users to create tables
// add rows to existing tables and print out a table
//
// Known Bugs: switch/case and for loops
// would have been used in a program if we had learned them yet
#include <fstream.h>
#include <iostream.h>
#include <iomanip.h> //for setw
#include <stdlib.h> //for exit()
//
//Global constants
//
const int gNameSize=256; //Maximum size of a filename or character column
const int gMaxColumns=10; //Maximum number of columns allowed in a table
const int LEFT=1, RIGHT=2; //constants used in specifying left or right
//alignment of a field
//
// structs
//
struct ColInfo //struct used to hold data about how a column is formatted
{
char fieldName[gNameSize]; // name of the column
int typeNumber; // Type of column: 1= int, 2= double, 3= char string
int width; // Number of characters wide column is
int align; // Control whether characters aligned to left or right
int precision; // For a column of type double says number of digits
// precision one has
bool printFlag; // Controls whether this column will be printed
};
//
// Global data for current table being looked at
//
int gNumColumns; // Contains the total number of columns in the table
ColInfo gColData[gMaxColumns];//array containing for each column
//in current table what its ColInfo properties
//are
//
//Function prototypes
//
void ShowTitleAndOptions(); // Prints title screen and options available
void MainMenu(); // has main loop of program. calls above function then
// gets a choice, performs choice, and loops
bool MainMenuDoChoice(int choice); // used by MainMenu
void CreateTable(); // handles the creation of a new database table
void AddRow(); //asks the user for a tablename, then open that table
//calls GetTableData to gets the properties of its columns
//into gColData array. Closes file. Then opens file in
// append mode and allows the user to add one or more
// rows to the table
void PrintTable(); //asks the user for a tablename, then open that table
//calls GetTableData to gets the properties of its columns
//into gColData array. Closes file. Then for each column j
//asks the user if he wants to print column j when the
//table is printed. Sets the printFlag of gColData[j]
// accordingly. Then prints to the screen the desired
//portion of the table.
int GetChoice(int lo, int hi);
// Precondition: lo < hi have been assigned values
//
// Postcondition: has gotten a choice from the user between lo and hi
// and returned it
//
void GetTableData(ifstream& table);
// Precondition: table is an opened ifstream
//
// PostCondition: has read from table the information about how its columns
// are formatted and has stored this in the global array
// gColData. Has also stored the number of columns in
// in gNumColumns
//
void GetAndOutputDataFromStream( istream& in, int type, ostream& out, bool
prt);
// Precondition: in and out have been opened. type is either 1,2,3 and
// prt is true or false
// Postcondition: if type is 1 has read one int from in
// if type is 2 has read one double from in
// if type is 3 has read a character string from in
// if prt is true and the above read did not cause an eof
// then the above data is written to out
// Function name: main()
//
// Purpose: Calls MainMenu to start program
//
// Known Bugs: none
int main()
{
MainMenu();
return 0;
}
// Function name: ShowTitleAndOptions()
//
// Purpose: Prints title and main menu
//
// Known Bugs: none
void ShowTitleAndOptions()
{
cout <<endl;
cout << "****************************************\n";
cout << "* *\n";
cout << "* Welcome to MyDatabase *\n";
cout << "* *\n";
cout << "* A simple database application *\n";
cout << "* *\n";
cout << "****************************************\n";
cout << "\n\n";
cout << "Main Menu\n";
cout << "=========\n\n";
cout << "(1) Create table\n";
cout << "(2) Add a row to table\n";
cout << "(3) Print out table\n";
cout << "(4) Quit\n";
}
// Function name: MainMenu
//
// Purpose: main loop for database program, draws main menu, gets
// a menu choice from user and does that task, then loops
//
// Known Bugs: none
void MainMenu()
{
int choice;
bool stillRunning;
do
{
ShowTitleAndOptions();
choice = GetChoice(1,4);
stillRunning = MainMenuDoChoice(choice);
}while(stillRunning);
}
// Function name: MainMenuDoChoice(int lo, int hi)
//
// Purpose: called by MainMenu to perform the choice from the main menu
// that the user selected
//
// Known Bugs: none
bool MainMenuDoChoice( int choice)
{
bool keepRunning = true;
if(choice == 1) CreateTable();
else if(choice == 2) AddRow();
else if(choice == 3) PrintTable();
else if(choice == 4) keepRunning =false;
return keepRunning;
}
// Function name: GetChoice(int lo, int hi)
//
// Purpose: if lo < hi have been assigned values then gets a choice from
// the user between lo and hi
// and returns it
//
// Known Bugs: Can screw up if a non-integer input by user
int GetChoice(int lo, int hi)
{
int choice = lo-1;
bool flag =true;
do{
cout << "\nPlease enter a number between " << lo
<< " and " << hi << ": ";
cin >> choice;
if( choice <lo || choice >hi)
cout << "Invalid choice.\n";
else flag = false;
}while(flag);
return choice;
}
// Function name: CreateTable
//
// Purpose: sets up a database table so that rows can be added to it.
// To this a file for the table is created and information
// about how each column is formatted is collected from
// the user and stored in this file.
//
// Known Bugs: none
void CreateTable()
{
char tableName[gNameSize];
char fieldName[gNameSize];
int col, count = 0, typeChoice, width;
int align,precision, maxPrecision;
ofstream tableFile;
cout << "\nEnter a table name: ";
cin >> tableName;
//
// Try to create table by open filename supplied above
//
tableFile.open( tableName);
if(tableFile.fail())
{ cout << "Error opening file to write in Create Table.\n";
exit(1);
}
//
// Choose number of columns in table
//
cout << "\nEnter a number of columns...";
col = GetChoice(1,gMaxColumns);
tableFile << col << "\n";
//
// Now for each column we get its name and how it is formatted
//
while( count < col)
{
cout << "\nEnter field name for column " << count <<": ";
cin >> fieldName;
tableFile << fieldName << "\n";
cout << "\nSelect type:\n";
cout << "============\n";
cout << "(1) int\n";
cout << "(2) double\n";
cout << "(3) char string\n";
typeChoice = GetChoice(1,3);
tableFile << typeChoice << "\n";
cout << "\nHow wide is this field?...";
width = GetChoice(1,gNameSize);
tableFile << width << endl;
cout << "\nSelect alignment type:\n";
cout << "======================\n";
cout << "(1) LEFT\n";
cout << "(2) RIGHT\n";
align = GetChoice(1,2);
tableFile << align <<endl;
if (typeChoice == 2)
{
cout << "Select a precision to output double\n";
if(width <3) maxPrecision = 1;
else maxPrecision = width - 2;
precision = GetChoice (1,maxPrecision);
tableFile << precision <<endl;
}
else tableFile << 1 <<endl;
count++;
}
tableFile.close();
}
// Function name: GetTableData(ifstream & table)
//
// Purpose: reads from table the total number of columns stored in
// table and how table's columns are formatted. Then stores
// this information into the gColData array
//
// Known Bugs: none
void GetTableData(ifstream & table)
{
int count = 0;
table >> gNumColumns;
while( count < gNumColumns)
{
if(table.eof())
{
cout << "End of file occurred while reading table data.\n";
exit(1);
}
table >> gColData[count].fieldName;
table >> gColData[count].typeNumber;
table >> gColData[count].width;
table >> gColData[count].align;
table >> gColData[count].precision;
count++;
}
}
// Function name: GetAndOutputDataFromStream
//
// Precondition: in and out have been opened. type is either 1,2,3 and
// prt is true or false
// Postcondition: if type is 1 has read one int from in
// if type is 2 has read one double from in
// if type is 3 has read a character string from in
// if prt is true and the above read did not cause an eof
// then the above data is written to out
//
// Known Bugs: none
void GetAndOutputDataFromStream( istream& in, int type, ostream& out, bool prt)
{
char outChar[gNameSize];
int outInt;
double outDouble;
if( type == 1)
{
in >> outInt;
if(prt && !in.eof())
out << outInt;
}
if( type == 2)
{
in >> outDouble;
if(prt && !in.eof())
out << outDouble;
}
if( type == 3)
{
in >> outChar;
if(prt && !in.eof())
out << outChar;
}
}
// Function name: AddRow
//
// Purpose: asks the user for a table. Open that table to get the column
// information. Then allows the user to append one or more rows
// to the table using that column formatting information.
//
// Known Bugs: none
void AddRow()
{
char tableName[gNameSize];
ofstream tableFile;
ifstream infoFile;
int count;
int tmp;
cout << "\nEnter a table name:";
cin >>tableName;
infoFile.open(tableName);
if(infoFile.fail())
{ cout << "Error opening file to read in AddRow.\n";
exit(1);
}
GetTableData(infoFile);
infoFile.close();
tableFile.open( tableName, ios::app);
if(tableFile.fail())
{ cout << "Error opening file to append in AddRow.\n";
exit(1);
}
do
{
count = 0;
while(count < gNumColumns)
{
tmp = gColData[count].typeNumber;
cout << "\nField" << count <<": "<<gColData[count].fieldName;
cout << "\nPlease enter ";
if( tmp == 1)
{
cout << "an integer";
}
if( tmp == 2)
{
cout << "a double";
}
if( tmp == 3)
{
cout << "a character string";
}
cout << " value for this field: ";
GetAndOutputDataFromStream( cin, tmp, tableFile, true);
tableFile << "\n";
count++;
}
cout << "\n\nWould you like to enter another row?\n";
cout << "(1) Yes \n";
cout << "(2) No \n";
}while( GetChoice(1,2) == 1);
tableFile.close();
}
// Function name: PrintTable
//
// Purpose: allows user to select a table. Then gets the column formatting info
// for that table. Then asks user for the columns that they want to
// print. Then prints out the table restrcited to those columns
//
// Known Bugs: none
void PrintTable()
{
char tableName[gNameSize];
ifstream tableFile;
int count=0;
cout << "\nEnter a table name:";
cin >>tableName;
tableFile.open(tableName);
if(tableFile.fail())
{ cout << "Error opening file to read in PrintTable.\n";
exit(1);
}
GetTableData(tableFile);
while( count < gNumColumns)
{
cout << "\nDo you want to print the field "
<< gColData[count].fieldName << "?\n";
cout << "(1) Yes \n";
cout << "(2) No ";
gColData[count].printFlag = 1-(GetChoice(1,2) -1);
count++;
}
count =0;
cout <<"\n\n";
while (count < gNumColumns)
{
if(gColData[count].printFlag == true)
{
cout.setf(ios::left);
cout << setw(gColData[count].width)
<<gColData[count].fieldName << "|";
}
count++;
}
cout <<endl;
count =0;
while(!tableFile.eof())
{
if(gColData[count].printFlag)
{
cout.setf(ios::fixed);
cout.setf(ios::showpoint);
cout.precision(gColData[count].precision);
cout.width(gColData[count].width);
if(gColData[count].align == LEFT)
{
cout.unsetf(ios::right);
cout.setf(ios::left);
}
else
{
cout.unsetf(ios::left);
cout.setf(ios::right);
}
}
GetAndOutputDataFromStream( tableFile,
gColData[count].typeNumber, cout,
gColData[count].printFlag);
if(gColData[count].printFlag && !tableFile.eof())
cout << "|";
count++;
count %= gNumColumns;
if(count == 0 ){
cout <<endl;
}
}
cout <<"\n\n";
tableFile.close();
}