Chris Pollett>Old Classes>PIC 10a, Spring 2000>Hw4>Hw4 Solutions

Spring 2000 PIC 10a HW4 Solutions Page

//
// 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();
}