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