Computer Science 2574
Intro to Data Structures & Soft Eng

BuildList.cpp

#include "BuildList.h"
#include "buildodb.h"

struct TestInfo 
{
	int NumStudents;            //These are the structures that the nodes for
	int NumQuestions;           //the doubly linked lists will be built out of.
	int NumKeys;
};

TestInfo ATest;

struct MemoInfo //holds the current memo
{
	char line1[Maxchars],
		 line2[Maxchars];
};

MemoInfo Memo;

struct KeyNode
{
	KeyNode *Next;
	int QuestionNum;
	char Answer;
};

struct KeyInfo
{
	char SSNum[SSLength],
		 FormCh,
		 GroupNum;
	KeyNode *KeyListPtr;
};

typedef KeyInfo* KeyInfoPtr;
KeyInfoPtr Head[MaxKeys], K;

KeyInfo AKey;

struct StudentInfo
{
	char Name[NameLength],
		 SSN[SSLength],
		 FormLetter,
		 NumCorrect[5],
		 GroupNum;               

	int NumOmitted,
		SeatNum;

	float PercentCorrect,
		  TScore;
};

StudentInfo AStudent;

struct AnswerNode
{
	AnswerNode *Next;
	int QuestionNum;
	char Answer;
};

AnswerNode AnAnswer;

typedef AnswerNode* AnsNodePtr;
AnsNodePtr l,p;

struct StudentNode
{
	AnsNodePtr AnswerListPtr;
	StudentNode *prev, *next;
	StudentInfo element;
};

typedef StudentNode* StuNodePtr;
StuNodePtr L, P, Header, Tail, HeadStudent, current;

struct ODBNode
{
	TestInfo ATest;
	KeyNode *AKeyPtrArray[MaxKeys];
	StudentNode* list;      
};

void MoveCurrent(int DisplayNum);

//**************************************************************************
// Function:	 BuildList
// Purpose:		 builds the linked lists for the student test and answer
//				 information, by reading from an ODB file.
// Called By:	 Main, View, BuildODB, OpenPrevious
// Calls:		 clearscreen, odbmenu, DisplayAnswer, DisplayResults,
//				 DisplayKeys, Resetmarker
//
// Parameters	 ifstream inFileODB - input file stream variable
//				 int DisplayNum - number that determines how many records are
//                              printed, depending on whether results or answers
//                              are being displayed
//
// Return Value:  void
// Author:		  John W. Boyd III & Cullen J. Morris
// Version		  1.1
//**************************************************************************

void BuildList(ifstream &inFileODB, int DisplayNum)
{	    
	int j=0,
		NumberOfKeys = 0;

	char line[Maxchars];
		
	inFileODB.getline(line, Maxchars);   // read in lines of test info. and store them in 
	strcat(Memo.line1, line);            // in a struct
	inFileODB.getline(line, Maxchars);
	strcat(Memo.line2, line);

	//read in the line that holds the number of students, the number of test
	//questions, and the number of keys.  Store them in the struct.
	inFileODB >> ATest.NumStudents >> ATest.NumQuestions;
	inFileODB >> ATest.NumKeys;
	
	NumberOfKeys = ATest.NumKeys;

	inFileODB.ignore(350,'\n'); //ignore the rest of the line

	while (NumberOfKeys != 0)
	{
		//read the keys and put their components in the appropriate nodes
		inFileODB >> AKey.SSNum >> AKey.FormCh >> AKey.GroupNum;
		
		K = new KeyInfo; //allocate a new node and fill in its fields
		strcpy(K->SSNum, AKey.SSNum);
		K->FormCh = AKey.FormCh;
		K->GroupNum = AKey.GroupNum;			K->KeyListPtr = NULL; //set the pointer to the answer list to NULL
		K->KeyListPtr = new KeyNode; //allocate a new node for the answer list
		KeyNode *Key_temp = K->KeyListPtr;
		Head[j] = K;
		j++;
		
		for (int t = 1;t < ATest.NumQuestions; t++) 
		//reads in each answer
		{
			Key_temp->QuestionNum = t;
			inFileODB >> Key_temp->Answer;
			Key_temp->Next = new KeyNode;
			Key_temp = Key_temp->Next;
		}

		Key_temp->QuestionNum = t;
		inFileODB >> Key_temp->Answer;
		Key_temp->Next = NULL;
		
		inFileODB.ignore(350,'\n');
		NumberOfKeys--;
	}
	
	clearscreen();

	
	StuNodePtr prevNode = NULL;
	P = NULL;
	L = NULL;

	StudentInfo element;
	
	inFileODB.get(AStudent.SSN, SSLength);
	inFileODB.get(AStudent.Name, NameLength-10);
	inFileODB.ignore(12,'\n');

	inFileODB.get(AStudent.NumCorrect,5); 
	inFileODB >> AStudent.NumOmitted;
	inFileODB >> AStudent.SeatNum >> AStudent.FormLetter;
	inFileODB >> AStudent.GroupNum >> AStudent.PercentCorrect;
	inFileODB >> AStudent.TScore;

	inFileODB.ignore(350, '\n');

	P = new StudentNode;
	P->element = AStudent;
	P->next = NULL;
	P->prev = NULL;
	P->AnswerListPtr = new AnswerNode;
	AnswerNode *Answer_temp = P->AnswerListPtr;
	L = P;
	prevNode = L;
	HeadStudent = L;

	for (int t = 1;t < ATest.NumQuestions; t++) 
	//reads in each answer 
	{
		
		Answer_temp->QuestionNum = t;
		inFileODB >> Answer_temp->Answer;
		Answer_temp->Next = new AnswerNode;
		Answer_temp = Answer_temp->Next;
	}

	Answer_temp->QuestionNum = ATest.NumQuestions;
	inFileODB >> Answer_temp->Answer;
	Answer_temp->Next = NULL;
	
	inFileODB.ignore(350, '\n');
	
	for (int i = 1; i < ATest.NumStudents; i++)
	//reads in student info for each student
	{
		inFileODB.get(AStudent.SSN,SSLength);
		inFileODB.get(AStudent.Name,NameLength-10);
		inFileODB.ignore(12,'\n');

		inFileODB.get(AStudent.NumCorrect,5); 
		inFileODB >> AStudent.NumOmitted;
		inFileODB >> AStudent.SeatNum >> AStudent.FormLetter;
		inFileODB >> AStudent.GroupNum >> AStudent.PercentCorrect;
		inFileODB >> AStudent.TScore;
	
		inFileODB.ignore(350, '\n');
		P = new StudentNode;
		P->element = AStudent;
		P->next = NULL;
		P->prev = prevNode;
		prevNode->next = P;
		prevNode = P;

		P->AnswerListPtr = new AnswerNode;
		AnswerNode *Answer_temp = P->AnswerListPtr;

		for (int t = 1; t < ATest.NumQuestions; t++) 
		//reads in student answers
		{
			Answer_temp->QuestionNum = t;
			inFileODB >> Answer_temp->Answer;
			Answer_temp->Next = new AnswerNode;
			Answer_temp = Answer_temp->Next;
		}

		Answer_temp->QuestionNum = t;
		inFileODB >> Answer_temp->Answer;
		Answer_temp->Next = NULL;
		
		inFileODB.ignore(350, '\n');

	}//ends for

	Tail = prevNode;

	if (DisplayNum == ResultNum)  //checks resultnum to see what should be displayed
		DisplayResults();
	else
	{
		if (DisplayNum == 9)
			DisplayKeys();
		else 
		{
			if (DisplayNum == 0)
				odbmenu();
			else
				DisplayAnswer();
		}
	}
	ResetMarker(inFileODB);

	inFileODB.close();
}


//**************************************************************************
// Function:	  DisplayKeys
// Purpose:		  displays all of the keys
// Called By:	  BuildList, ViewMenu2 
// Calls:		  AnswerHeader, odbmenu
// Parameters:	  NONE
// Return Value:  void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1
//**************************************************************************

void DisplayKeys()
{
	KeyNode *Key_temp = K->KeyListPtr;

	int i = 0,
		j = 0;
	
	AnswerHeader();
	
	for (i = 0; i < ATest.NumKeys; i++)
	//outputs keys for viewing
	{
		j = 0;
		Key_temp = Head[i]->KeyListPtr;

		cout << "     " << Head[i]->SSNum << "   " << Head[i]->FormCh;
		cout << " " << Head[i]->GroupNum << " " ;

		cout << Key_temp->Answer;

		while ((Key_temp->Next != NULL) && (j < ATest.NumQuestions ))
		//outputs each key answer
		{
			Key_temp = Key_temp->Next;
			cout << Key_temp->Answer;
			j++;
		}
		
		cout << endl;
	}
	cout << endl;
	
	odbmenu();
}


//**************************************************************************
// Function:	 DisplayResults
// Purpose:		 displays the first 20 students and their test information
// Called By:	 BuildList, ViewMenu2
// Calls:		 clearscreen, viewmenu
// Parameters:	 NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1
//**************************************************************************

void DisplayResults()
{
	
	cout.setf(ios::fixed, ios::floatfield);
	cout.setf(ios::showpoint);
	
	int count = 0,
		Less20 = 0;
	
	StudentNode *current = NULL;
	
	L = HeadStudent;
	current = HeadStudent;

	if (ATest.NumStudents < ResultNum)
	//count for when there are less than 20 students
	{
		count = ResultNum - ATest.NumStudents;
		Less20 = 1;
	}

	

	clearscreen();

	cout << "       SSN       NAME        Corr    Omit Seat F G Grade TScr" << endl;
	cout << "     ========================================================" << endl;

	while(count < ResultNum)
	//outputs Student info
	{
		cout << setw(3) << count + 1 << "  " << L->element.SSN << " " << L->element.Name << "     " << L->element.NumCorrect;
		cout << "   " << L->element.NumOmitted << "    " << L->element.SeatNum;
		cout << "   " << L->element.FormLetter << " " << L->element.GroupNum;
		cout << "   " << setw(2) << setprecision(0) << L->element.PercentCorrect;
		cout << "   " << setw(2) << setprecision(0) << L->element.TScore;
		cout << endl;
		L = L->next;
		count++;
	}

	cout << endl;
	
	if (!Less20)
	//calls viewmenu
		viewmenu(ResultNum);
}

//**************************************************************************
// Function:	 DisplayAnswer
// Purpose:		 displays the first 15 students and their answers
// Called By:    BuildList, ViewMenu2
// Calls:		 AnswerHeader, ViewMenu2
// Parameters:	 NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1
//**************************************************************************
void DisplayAnswer()
{
	AnswerHeader();

	int j = 0,
		i = 0;

	L = HeadStudent;
	current = L;

	AnswerNode *Answer_temp = L->AnswerListPtr;
	
	while ( j < AnswerNum )
	// outputs answers for each student
	{
		i=0;
		if(L->element.Name[1]=='?')
		//puts SSN in name field if they didn't fill in their name
			cout << setw(3) << j + 1 << "  " << setw(11) << L->element.SSN;
		else
			cout << setw(3) << j + 1 << "  " << setw(11) << L->element.Name;

		cout << " " << L->element.FormLetter << " " << L->element.GroupNum;
		cout << " ";
	
		while ((Answer_temp != NULL) && (i++ < ATest.NumQuestions ))
		//outputs answers
		{
			cout << Answer_temp->Answer;
			Answer_temp = Answer_temp->Next;
		
		}
		cout << endl;
		if(L->next != NULL) // moves thru the list until next = NULL
		{
		  L = L->next;
		  Answer_temp = L->AnswerListPtr;
		}
		j++;
	
	}
	
	cout << endl;
	viewmenu(AnswerNum);
}

//**************************************************************************
// Function:     Escape
// Purpose:	     To quit the program
// Called By:	 FileMenu, View
// Calls:		 clearscreen, Terminationscreen
// Parameters:   NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1
//**************************************************************************

void Escape()
{
	int exitStatus = 0;

	clearscreen();
	TerminationScreen();
	exit(exitStatus);
}


//******************************************************************************
// Function:     viewmenu
// Purpose:      To display the view menu and read in the choice
// Called By:	 Top, Up, Bottom, Stop, Down, Samescreen, EditMenu
// Calls:		 Top, Up, Bottom, Stop, Down, Samescreen, EditMenu
// Parameters:   NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1
//******************************************************************************

#include "menus.h"
#include "displayoptns.h"

void viewmenu(int DisplayNum)
{
	char viewch;

	cout << "\t(T)op, (U)p, (D)own, (B)ottom, (E)dit, or (S)top?"<>viewch;
	
	while(viewch != 'T' && viewch != 'D' && viewch != 'B' && viewch != 'S'
		  && viewch != 'U' && viewch != 'E')
	//makes sure they input the right character
	{
		cout << endl << "\tInvalid response, please re-enter." << endl;
		cin >> viewch;
	}
	
	clearscreen();
	
	switch (viewch)
	//depending on which option they chose it calls a display function
	{
		case 'T': Top(DisplayNum);
			break;
		case 'U': Up(DisplayNum);
			break;
		case 'D': Down(DisplayNum);
			break;
		case 'B': Bottom(DisplayNum);
			break;
		case 'S': Stop(DisplayNum);
			break;
		case 'E': SameScreen(DisplayNum);
			      EditMenu(DisplayNum);
			break;  
	}
}


//**************************************************************************
// Function:     Top
// Purpose:      To display the top group of records
// Called By:	 viewmenu
// Calls:		 AnswerHeader, viewmenu
// Parameters:   DisplayNum - Number of students to display for Results and
//								Answers
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1                      
//**************************************************************************

void Top(int DisplayNum)
{
	current = L;
	
	int count = 0,
		i = 0;
	
	for (int j = 0; j < (DisplayNum) && L->prev != NULL; j++)
	//moves the pointer backwards
		L = L->prev;
	
	
	if(DisplayNum == 20)
	//checks to see what to display Answers or Results
	{
		if (L->prev == NULL)
		//tells them if they are at the top of the list
		{
			cout << "\tInvalid operation, already at top of list." << endl << endl;
			viewmenu(DisplayNum);
		}

		L = HeadStudent;
	    AnswerNode *Answer_temp = L->AnswerListPtr;



		while (L->prev != NULL)
		// moves the pointer to the first node
			L =     L->prev;

		cout << "       SSN       NAME        Corr    Omit Seat F G Grade TScr" << endl;
		cout << "     ========================================================" << endl;

		while(count < DisplayNum)
		//outputs the results 20 at a time
		{
			cout << setw(3) << count + 1 << "  " << L->element.SSN << " " << L->element.Name << "     " <<  L->element.NumCorrect;
			cout << "   " << L->element.NumOmitted << "    " << L->element.SeatNum;
			cout << "   " << L->element.FormLetter << " " << L->element.GroupNum;
			cout << "   " << setw(2) << setprecision(0) << L->element.PercentCorrect;
			cout << "   " << setw(2) << setprecision(0) << L->element.TScore;
			cout << endl;
			L = L->next;
			count++;
		}
	} //end if
	else
	//outputs the answers
	{
		count = 0;
		
		if (L->prev == NULL)
		//checks to see if previous pointer is null
		{
			cout << "\tInvalid operation, already at top of list." << endl << endl;
			viewmenu(DisplayNum);
		}

		L = HeadStudent;
		current = L;

		AnswerNode *Answer_temp = L->AnswerListPtr;

		AnswerHeader();

		while (count < DisplayNum)
		//outputs the answers  at a time
		{
			i = 0;
			
			if(L->element.Name[1]=='?')
			//puts SSN in name field if they didn't fill in their name
				cout << setw(3) << count + 1 << "  " << setw(11) << L->element.SSN;
			else
				cout << setw(3) << count + 1 << "  " << setw(11) << L->element.Name;
				
			cout << " " << L->element.FormLetter << " ";
			cout << L->element.GroupNum << " ";

			while ((Answer_temp != NULL) && (i++ < ATest.NumQuestions ))
			//checks for NULL pointer
			{
				cout << Answer_temp->Answer;
				Answer_temp = Answer_temp->Next;
			}
			cout << endl;
			count++;
			L = L->next;
			Answer_temp = L->AnswerListPtr;
		}
	}//end else

	cout << endl;
	
	viewmenu(DisplayNum);
}


//**************************************************************************
// Function:   Down
// Purpose:    To move down the list to the next group
//             of records.
// Called By:	 viewmenu
// Calls:		 AnswerHeader, viewmenu
// Parameters:   DisplayNum - Number of students to display for Results and
//								Answers
// Return Value: int zero
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1
//**************************************************************************

int Down(int DisplayNum)
{
	AnswerNode *Answer_temp = L->AnswerListPtr;

	current = L;
	
	int i = 0,
		j = 0,
		count = 0;

	if (DisplayNum == 20)
	//checks to see what to display, answers or results.
	{
		if (L->next == NULL)
		//checks to see if L->next equal NULL
		{
			cout << endl << "\tInvalid Operation, already at bottom of list." << endl << endl;
			viewmenu(DisplayNum);
			return 0;
		}

		cout << "       SSN       NAME        Corr    Omit Seat F G Grade TScr" << endl;
		cout << "     ========================================================" << endl;
	
		while ((i < DisplayNum) && (L->next != NULL))
		//makes sure L->next isn't NULL
		{
			L = L->next;
			i++;
		}
		
		int t = 0;
		if(L->next == NULL)
		{
			DisplayNum--;
			t=1;
		}

		while (j < DisplayNum)
		//moves pointer up 
		{
			L = L->prev;
			j++;
		}

		if(t == 1)
			DisplayNum++;

		while (count < DisplayNum)
		//outputs student info 20 at a time
		{
			cout << setw(3) << count + 1 << "  " << L->element.SSN << " " << L->element.Name << "     " << L->element.NumCorrect;
			cout << "   " << L->element.NumOmitted << "    " << L->element.SeatNum;
			cout << "   " << L->element.FormLetter << " " << L->element.GroupNum;
			cout << "   " << setw(2) << setprecision(0) << L->element.PercentCorrect;
			cout << "   " << setw(2) << setprecision(0) << L->element.TScore;
			cout << endl;
			L->next;
			count++;

			if (L->next != NULL)
			// makes sure L-> !=Null
				L = L->next;
		}
	} //end if
	else
	//outputs students and their answers
	{
		count = 0;
		i = 0;
		j = 0;
		
		if (L->next == NULL)
		//tells the user they are at the bottom of the list
		{
			cout << endl << "\tInvalid Operation, already at bottom of list." << endl << endl;
			viewmenu(DisplayNum);
			return 0;
		}
		
		AnswerHeader();

		while ((i < DisplayNum) && (L->next != NULL))
		//moves the pointer ahead 
		{
			L = L->next;
			i++;
		}                                                                          
	
		while (j < DisplayNum)
		//moves the pointer back 
		{
			L = L->prev;
			j++;
		}

		Answer_temp = L->AnswerListPtr;

		while (count < DisplayNum)
		//outputs the students and their answers
		{
			i = 0;
			
			if(L->element.Name[1]=='?')
		    //puts SSN in name field if they didn't fill in their name
			    cout << setw(3) << count + 1 << "  " << setw(11) << L->element.SSN;
		    else
			    cout << setw(3) << count + 1 << "  " << setw(11) << L->element.Name;

		    cout << " " << L->element.FormLetter << " " << L->element.GroupNum;
		    cout << " ";

			while ((Answer_temp != NULL) && (i++ < ATest.NumQuestions ))
			//outputs the students answers
			{
				cout << Answer_temp->Answer;
				Answer_temp = Answer_temp->Next;
			}
			cout << endl;
			count++;
			if(L->next != NULL)
			//moves pointer down list until next = NULL
			{
				L = L->next;
				Answer_temp = L->AnswerListPtr;
			}
			
		}
	}// end else

	cout << endl;
	
	viewmenu(DisplayNum);
	
	return 0;
}



//**************************************************************************
// Function:	  Bottom
// Purpose:		  To move to the bottom of the list to of 
//				  records.
// Called By:	  viewmenu
// Calls:		  AnswerHeader, viewmenu
// Parameters:    DisplayNum - Number of students to display for Results and
//								Answers
// Return Value:  void
// Authors:		  John W. Boyd III & Cullen J. Morris
// Version:		  1.1     
//**************************************************************************

void Bottom(int DisplayNum)
{
	int i = 0,
		count = 0;
	
	AnswerNode *Answer_temp = L->AnswerListPtr;
	
	if (DisplayNum == 20)
	//checks to see what to display, answers or student info
	{
		if (L->next == NULL)
		//tells the user if they are at the bottom of the list
		{
			cout << "\tInvalid response, already at bottom of list." << endl << endl;
			viewmenu(DisplayNum);
		}
	

		L = Tail;
		
		for(i=1; i < DisplayNum; i++)
		//moves L back
			L = L->prev;

		current = L;
		
		cout << "       SSN       NAME        Corr    Omit Seat F G Grade TScr" << endl;
		cout << "     ========================================================" << endl;
	
		while(count < DisplayNum)
		//outputs the student info
		{
			cout << setw(3) << count + 1 << "  " << L->element.SSN << " " << L->element.Name << "     " <<  L->element.NumCorrect;
			cout << "   " << L->element.NumOmitted << "    " << L->element.SeatNum;
			cout << "   " << L->element.FormLetter << " " << L->element.GroupNum;
			cout << "   " << setw(2) << setprecision(0) << L->element.PercentCorrect;
			cout << "   " << setw(2) << setprecision(0) << L->element.TScore;
			cout << endl;
			count++;
			L->next;
			
			if (L->next != NULL)
			// advances the pointer
				L = L->next;
		}
	}
	else
	//displays the answers
	{
		count = 0;
		
		if (L->next == NULL)
		//tells the user they are at the bottom of the list
		{
			cout << endl <<"\tInvalid response, already at bottom of list." << endl << endl;
			viewmenu(DisplayNum);
		}
	
		AnswerHeader();		
		
		L = Tail;
				
		for(i=1; i < DisplayNum; i++)
		//moves L up the list
		{
			L = L->prev;
		}

		current = L;

		while (count < DisplayNum)
		//outputs the students and their answers
		{
			Answer_temp = L->AnswerListPtr;
			i = 0;
			
			if(L->element.Name[1]=='?')
		    //puts SSN in name field if they didn't fill in their name
				cout << setw(3) << count + 1 << "  " << setw(11) << L->element.SSN;
			else
				cout << setw(3) << count + 1 << "  " << setw(11) << L->element.Name;

			cout << " " << L->element.FormLetter << " " << L->element.GroupNum;
			cout << " ";

			while ((Answer_temp != NULL) && (i++ < ATest.NumQuestions ))
			//outputs the student answers
			{
				cout << Answer_temp->Answer;
				Answer_temp = Answer_temp->Next;
			}
			cout << endl;
			count++;
			if(L->next != NULL)// advances pointer one node
				L = L->next;
		}
	}//end else

	cout << endl;

	viewmenu(DisplayNum);
}


//**************************************************************************
// Function:	 Up
// Purpose:		 This function shows the previous group of records.
// Called By:	 viewmenu
// Calls:		 AnswerHeader, viewmenu
// Parameters:   DisplayNum - Number of students to display for Results and
//								Answers
// Return Value: int zero
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//**************************************************************************

int Up(int DisplayNum)
{
	AnswerNode *Answer_temp = L->AnswerListPtr;

	int i = 0,
		j = 0,
		count = 0;
	
	for (j = 0; j < (DisplayNum) && L->prev != NULL; j++)
	//moves the pointer backwards
		L = L->prev;
	
	if (L->prev == NULL)
	//tells the user they are at the top of the list
	{
		cout << endl << "\tInvalid Operation, already at top of list." << endl << endl;
		viewmenu(DisplayNum);
		return 0;
	}
	
	for (j = 0; j < (DisplayNum) && L->prev != NULL; j++)
	//moves the pointer backwards
		L = L->prev;
	
	current = L;
	
	if (DisplayNum == 20)
	//checks to see what to display, answers or results.
	{

		cout << "       SSN       NAME        Corr    Omit Seat F G Grade TScr" << endl;
		cout << "     ========================================================" << endl;
	
		while(count < DisplayNum)
		//outputs the list
		{
			cout << setw(3) << count + 1 << "  " << L->element.SSN << " " << L->element.Name << "     " << L->element.NumCorrect;
			cout << "   " << L->element.NumOmitted << "    " << L->element.SeatNum;
			cout << "   " << L->element.FormLetter << " " << L->element.GroupNum;
			cout << "   " << setw(2) << setprecision(0) << L->element.PercentCorrect;
			cout << "   " << setw(2) << setprecision(0) << L->element.TScore;
			cout << endl;
			count++;
			L->next;
			
			if (L->next != NULL)
			// advances L down the list
				L = L->next;
		}
	}
	else
	//outputs the students answers
	{
		count = 0;
		
		AnswerHeader();

		current = L; 
		
		while(count < DisplayNum)
		// outputs the students and their answers
		{
			i = 0;
			
			if(L->element.Name[1]=='?')
				//puts SSN in name field if they didn't fill in their name
				cout << setw(3) << count + 1 << "  " << setw(11) << L->element.SSN;
			else
				cout << setw(3) << count + 1 << "  " << setw(11) << L->element.Name;
			
			cout << " " << L->element.FormLetter << " ";
			cout << L->element.GroupNum << " ";
			
			Answer_temp = L->AnswerListPtr;

			while ((Answer_temp != NULL) && (i++ < ATest.NumQuestions ))
			//outputs the students answers
			{
				cout << Answer_temp->Answer;
				Answer_temp = Answer_temp->Next;
			}
			cout << endl;
			count++;
			if(L->next != NULL) // moves pointer down list one node
				L = L->next;
		}
	}//end else

	cout << endl;
	
	viewmenu(DisplayNum);
	
	return 0;
}


//**************************************************************************
// Function:	 SameScreen
// Purpose:		 redisplays the current screen of list elements
// Called By:	 viewmenu, EditMenu, MoveCurrent
// Calls:		 AnswerHeader, viewmenu
// Parameters:   DisplayNum - Number of students to display for Results and
//								Answers
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//**************************************************************************

void SameScreen(int DisplayNum)
{
	int count = 0;
	
	AnswerNode *Answer_temp = L->AnswerListPtr;

	for (int j = 0; j < (DisplayNum) && L->prev != NULL; j++)
		//moves the pointer backwards
		L = L->prev;
	
	if (DisplayNum == 20)
	//checks to see what to display, answers or results.
	{

		cout << "       SSN       NAME        Corr    Omit Seat F G Grade TScr" << endl;
		cout << "     ========================================================" << endl;
	
		current = L;
		
		while(count < DisplayNum)
		//outputs the list
		{
			cout << setw(3) << count + 1 << "  " << L->element.SSN << " " << L->element.Name << "     " << L->element.NumCorrect;
			cout << "   " << L->element.NumOmitted << "    " << L->element.SeatNum;
			cout << "   " << L->element.FormLetter << " " << L->element.GroupNum;
			cout << "   " << setw(2) << setprecision(0) << L->element.PercentCorrect;
			cout << "   " << setw(2) << setprecision(0) << L->element.TScore;
			cout << endl;
			count++;
			L->next;
			
			if (L->next != NULL)
			// advances L down the list
				L = L->next;
		}
	}
	else
	//outputs the students answers
	{
		count = 0;
		
		AnswerHeader();

		current = L;
		
		while(count < DisplayNum)
		// outputs the students and their answers
		{	
			int i = 0;
			
			if(L->element.Name[1]=='?')
			//puts SSN in name field if they didn't fill in their name
				cout << setw(3) << count + 1 << "  " << setw(11) << L->element.SSN;
			else
				cout << setw(3) << count + 1 << "  " << setw(11) << L->element.Name;

			cout << " " << L->element.FormLetter << " " << L->element.GroupNum;
			cout << " ";

			Answer_temp = L->AnswerListPtr;

			while ((Answer_temp != NULL) && (i++ < ATest.NumQuestions ))
			//outputs the students answers
			{
				cout << Answer_temp->Answer;
				Answer_temp = Answer_temp->Next;
			}
			cout << endl;
			count++;
			if(L->next != NULL) // moves pointer down list one
				L = L->next;
		}

	}//end else

	cout << endl;

	for (j = 0; j < (DisplayNum) && L->prev != NULL; j++)
		//moves the pointer backwards
		L = L->prev;

}

//**************************************************************************
// Function:	 Stop
// Purpose:		 This function stops the list viewing and returns the user
//				  to the ODB menu  
// Called By:    viewmenu
// Calls:		 clearscreen, odbmenu
// Parameters:	 DisplayNum - Number of students to display for Results and
//								Answers
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//**************************************************************************

void Stop(int DisplayNum)
{	
	clearscreen();
	odbmenu();
	cout << endl;

}


//********************************************************************************
// Function:	 AnswerHeader
// Purpose:		 Display the answer header
// Called By:	 DisplayKeys, DisplayAnswers, Top, Down, Bottom, Up, SameScreen
// Calls:		 NONE
// Parameters:   NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1
//********************************************************************************

void AnswerHeader()
{
	clearscreen();
	
	cout << "                   G                  A N S W E R S " << endl;
	cout << "                 F R" << endl;
	cout << "       STUDENT   O O                 question  numbers " << endl;
	cout << "         NAME    R U 00000000011111111112222222222333333333344444444445" << endl;
	cout << "                 M P 12345678901234567890123456789012345678901234567890" << endl;
	cout << "     ==================================================================" << endl; 

}

//**************************************************************************
// Function:	 EditSSN
// Purpose:		 Allows the user to edit a student social security number
// Called By:	 EditMenu
// Calls:		 clearscreen, odbmenu
// Parameters:   NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//**************************************************************************

void EditSSN()
{
	char NewSSN[SSLength],
		 tmpchar;

	int t = 0,
		resultNum = 20;

	MoveCurrent(resultNum);
	
	cout << " Please enter the new SSN or press enter to escape edit SSN." << endl;
	
	cin.getline(NewSSN, SSLength);
	cin.getline(NewSSN, SSLength);
	
	if (!NewSSN[0]) // checks to see if the string is empty
		t = SSLength - 1;
	
	else
	{
		while(isdigit(NewSSN[t]))
			t++;
	}
	
	if (t != SSLength - 1) // checks to make sure the SSN is of valid lenght
	{
		clearscreen();
		cout << "Invalid SSN." << endl;
		EditSSN();
	}

 	if (!NewSSN[0]) // checks to see if change has been made
		cout << " No change has been made.  Press enter to return to the main menu." << endl;
	
	else
	{
		strcpy(current->element.SSN, NewSSN);

		cout << "Your change has been made.  Press enter to continue." << endl;
	}

	scanf("%c",&tmpchar); //read in a character from the keyboard
	while(tmpchar != '\n') //make sure the character is the newline
	{
		scanf("%c",&tmpchar);
	}

	clearscreen();
	odbmenu();

}

//**************************************************************************
// Function:	 EditName
// Purpose:		 Allows the user to edit a student's name
// Called By:	 EditMenu
// Calls:		 MoveCurrent, odbmenu, clearscreen
// Parameters:	 NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//**************************************************************************

void EditName()
{
	char NewName[NameLength],
		 tempName[NameLength],
		 BlankString[NameLength] = "  ",
		 tmpchar;

	int resultNum = 20,
		k = 0,
		t = 0;
	
	MoveCurrent(resultNum);

	cout << "Please enter the new student last name.";
	cout << endl;

	cin.getline(tempName,NameLength);
	cin.getline(NewName, NameLength);

	if (!NewName[0])// checks to see if change has been made
		cout << " No change has been made.  Press enter to return to the main menu." << endl;
	else
	{
		strcat(BlankString, NewName);
		
		k = strlen(BlankString);
		t = ShortName - k;

		while (t != 1) // alligns colums for tabular format by adding 2 blanks to name
		{
			strcat(BlankString, Blank);
			t--;
		}

		strcpy(current->element.Name, BlankString);

		cout << "Your change has been made.  Press enter to continue." << endl;
	}

	scanf("%c",&tmpchar); //read in a character from the keyboard
	while(tmpchar != '\n') //make sure the character is the newline
	{
		scanf("%c",&tmpchar);
	}

	clearscreen();
	odbmenu();
}

//**************************************************************************
// Function:	 EditForm
// Purpose:		 Allows the user to edit a student's form letter
// Called By:	 EditMenu
// Calls:		 MoveCurrent, clearscreen, odbmenu
// Parameters:	 NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//**************************************************************************

void EditForm()
{
	char NewForm,
		 tmpchar;

	int resultNum = 20;
	
	MoveCurrent(resultNum);

	cout << "Please enter the new form letter.";
	cout << endl;

	scanf("%c", &NewForm);

	if (NewForm == '\n') // checks to see if changes have been made to the form
		cout << "No change has been made.  Press enter to return to the main menu." << endl;
		
	else
	{
		while (!isalpha(NewForm))// checks to make sure input is valid
		{
			clearscreen();
			cout << endl << "Invalid Form Letter.  Please re-enter." << endl;
			cin >> NewForm;
		}

		toupper(NewForm);
	
		current->element.FormLetter = NewForm;

		cout << "Your change has been made.  Press enter to continue." << endl;
	}

	scanf("%c",&tmpchar);
	scanf("%c",&tmpchar); //read in a character from the keyboard
	while(tmpchar != '\n') //make sure the character is the newline
	{
		scanf("%c",&tmpchar);
	}

	clearscreen();
	odbmenu();

	
}

//**************************************************************************
// Function: EditGroup
// Purpose: Allows the user to edit a student's group number
// Called By:	 EditMenu
// Calls:		 MoveCurrent, odbmenu, clearscreen
// Parameters:	 NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1
//**************************************************************************

void EditGroup()
{
	char NewGroup,
		 tmpchar;

	int resultNum = 20;
	
	MoveCurrent(resultNum);

	cout << "Please enter the new group number.";
	cout << endl;

	scanf("%c", &NewGroup);

	if (NewGroup == '\n') // checks to see if group has been edited
		cout << "No change has been made.  Press enter to return to the main menu." << endl;

	else
	{
		while(!isdigit(NewGroup)) // makes sure input is vaild
		{
			clearscreen();
			cout << "Invalid response.  Please re-enter group number." << endl;
			cin >> NewGroup;
		}
	
		current->element.GroupNum = NewGroup;

		cout << "Your change has been made.  Press enter to continue." << endl;
	}

	scanf("%c",&tmpchar);
	scanf("%c",&tmpchar); //read in a character from the keyboard
	while(tmpchar != '\n') //make sure the character is the newline
	{
		scanf("%c",&tmpchar);
	}

	clearscreen();
	odbmenu();
}

//**************************************************************************
// Function: EditChair
// Purpose: Allows the user to edit a student's chair number
// Called By:	 EditMenu
// Calls:		 MoveCurrent, odbmenu, clearscreen
// Parameters:	 NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1
//**************************************************************************
#include 

void EditChair()
{
	char NewChair[2];
	
	int ChairNum = 0,
		resultNum = 20;

	char tmpchar;

	MoveCurrent(resultNum);

	cout << "Please enter the new chair number.";
	cout << endl;

	scanf("%c", &NewChair);

	if (NewChair[0] == '\n') // checks to see if chair has been edited
		cout << "No change has been made.  Press enter to return to the main menu." << endl;
	
	else
	{
		ChairNum = atoi(NewChair);

		current->element.SeatNum = ChairNum;

		cout << " Your change has been made.  Press enter to continue." << endl;
	}
	
	scanf("%c",&tmpchar);
	scanf("%c",&tmpchar); //read in a character from the keyboard
	while(tmpchar != '\n') //make sure the character is the newline
	{
		scanf("%c",&tmpchar);
	}

	clearscreen();
	odbmenu();

}

//**************************************************************************
// Function:	 EditAnswer
// Purpose:		 Allows the user to edit a student's answer to a question
// Called By:	 EditMenu
// Calls:		 Movecurrent, clearscreen, odbmenu
// Parameters:	 NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//**************************************************************************

void EditAnswer()
{
	char NewAnswer[2],
		 tmpchar;
	int	QuestionNum,
		i = 0,
		answerNum = 15;

	MoveCurrent(answerNum);

	cout << "Please enter the question number you would like to edit.";
	cout << endl;

	cin >> QuestionNum;

	AnswerNode *Answer_temp = current->AnswerListPtr;

	while ( i < QuestionNum - 1)// moves pointer to correct position for editing
	{
		Answer_temp = Answer_temp->Next;
		i++;
	}

	cout << endl << "Please enter the new student answer." << endl;

	scanf("%c", &NewAnswer);

	if (NewAnswer[0] == '\n') // checks to see if answer has been edited
		cout << "No change has been made.  Press enter to return to the main menu."  << endl;

	else
	{
	
		while (!isdigit(NewAnswer[0])) // checks to see if input is vaild
		{
			clearscreen();
			cout << endl << "Invalid response.  Please re-enter the new answer." << endl;
			cin >> NewAnswer;
		}

		Answer_temp->Answer = NewAnswer[0];

		cout << endl << "Your change has been made." << endl;
	}

	scanf("%c",&tmpchar);
	scanf("%c",&tmpchar); //read in a character from the keyboard
	while(tmpchar != '\n') //make sure the character is the newline
	{
		scanf("%c",&tmpchar);
	}

	clearscreen();
	odbmenu();
}


//**************************************************************************
// Function:	 ChangeKey
// Purpose:		 To let the user change the answers in the keys
// Called By:	 KeyMenu
// Calls:		 odbmenu, clearscreen
// Parameters:	 NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1
//**************************************************************************

void ChangeKey()
{
	char NewAnswer[2],
		 tmpchar;

	int	QuestionNum,
		i = 0,
		j = 0;

	char formletter;

	KeyNode *Key_temp = K->KeyListPtr;
	
	cout << "Please enter the form letter of the key you wish to edit.";
	cout << endl;
	
	cin >> formletter;
	
	while (formletter != Head[i]->FormCh) // moves to the correct key
		i++;

	cout << "Please enter the question number that you wish to change.";
	cout << endl;

	cin >> QuestionNum;

	KeyNode *TmpPtr;
	TmpPtr = Head[i]->KeyListPtr;

	while (j < QuestionNum - 1)// moves pointer to correct answer
	{
		TmpPtr = TmpPtr->Next;
		j++;
	}

	cout << endl << "Please enter the new key answer." << endl;

	scanf("%c", NewAnswer);

	if (NewAnswer[0] == '\n')  //  checks to see if anser has been edited
		cout << "No change has been made.  Press enter to return to the main menu." << endl;

	else
	{
		while (!isdigit(NewAnswer[0]) || NewAnswer[1] != '\0') // checks to make sure input
		{													   // is valid
			clearscreen();
			cout << endl << "Invalid response.  Please re-enter the new answer." << endl;
			cin >> NewAnswer;
		}

		TmpPtr->Answer = NewAnswer[0];

		cout << endl << "Your change has been made.  Press enter to continue." << endl;
	}

	scanf("%c",&tmpchar); //read in a character from the keyboard
	while(tmpchar != '\n') //make sure the character is the newline
	{
		scanf("%c",&tmpchar);
	}

	clearscreen();
	odbmenu();
}

//**************************************************************************
// Function:	 EditMemo
// Purpose:		 Allows the user to edit the odb file memo
// Called By:	 EditMenu
// Calls:		 odbmenu, clearscreen
// Parameters:	 NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//**************************************************************************

void EditMemo()
{
	char tmpchar,
		 templine1[Maxchars];

	clearscreen();

	cout << "This is your current memo:" << endl << endl << endl;
	cout << Memo.line1 << endl << Memo.line2 << endl << endl;
	cin.getline(templine1,Maxchars);
	cout << endl << endl << "\t Please enter Line 1 of your new memo." << endl;

	cin.getline(templine1, Maxchars);

	if (!templine1[0]) // checks to see if memo has been chaged
		cout << "No changes have been made.  Press enter to return to the main menu." << endl;

	else
	{
		strcpy(Memo.line1, templine1);

		cout << endl << "\t Please enter Line 2 of your new memo." << endl;
	
		cin.getline(Memo.line2, Maxchars);

		cout << endl << endl << "\t Your change has been made.  Press enter to continue." << endl;
	}

	scanf("%c",&tmpchar); //read in a character from the keyboard
	while(tmpchar != '\n') //make sure the character is the newline
	{
		scanf("%c",&tmpchar);
	}

	clearscreen();
	odbmenu();

}

//**************************************************************************
// Function:	 Statistics
// Purpose:		 recalculates the standard deviation and the average
//				   of the grades
// Called By:	 ViewMenu2, CalculateMenu
// Calls:		 odbmenu, clearscreen
// Parameters:	 int showstat - value to determine if the statistics
//								are displayed
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//**************************************************************************
#include 

void Statistics(int showstat)
{
	float x = 0.0, 
		  xtotal = 0.0,
		  xSqrd = 0.0,
		  xSqrdTotal = 0.0,
		  StdDev = 0.0,
		  Avg = 0.0;
	
	int i = 0;

	char tmpchar;
	
	cout.setf(ios::fixed, ios::floatfield);
	cout.setf(ios::showpoint);
	
	L = HeadStudent;

	for (i; i < ATest.NumStudents; i++) // reads in and adds up each students test score
	{
		x = L->element.PercentCorrect;
		xtotal = x + xtotal;
		xSqrd = x*x;
		xSqrdTotal = xSqrd + xSqrdTotal;
		L = L->next;
	}

	StdDev = sqrt((xSqrdTotal - ((xtotal)*(xtotal)
		          /ATest.NumStudents))/ATest.NumStudents);

	Avg = xtotal/ATest.NumStudents;

	clearscreen();

	cout << endl << " The standard deviation and average have been calculated." << endl << endl;

	if (showstat) // checks to see if stats should be displayed
	{
		cout << Memo.line1 << endl;
		cout << Memo.line2 << endl << endl;
		
		cout << endl << " The class average is: " << setw(5);
		cout << setprecision(2) << Avg << endl;
		cout << endl << " The standard deviation for the class is: ";
		cout << setw(5) << setprecision(2) << StdDev << endl;
	}
	
	cout << endl << endl << " Press enter to continue." << endl;

	scanf("%c",&tmpchar); //read in a character from the keyboard
	while(tmpchar != '\n') //make sure the character is the newline
	{
		scanf("%c",&tmpchar);
	}
	
	clearscreen();

	cout << endl;
	odbmenu();
}


//**************************************************************************
// Function:	 ReGrade
// Purpose:		 regrade the test with the edited answers or keys
// Called By:	 CalculateMenu
// Calls:		 odbmenu,
// Parameters:	 NONE
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//**************************************************************************

void ReGrade()
{
	int i = 0,
		right,
		wrong,
		omit;
	float Grade = 0.0;

	char correct[5];

	AnswerNode *Answer_temp = L->AnswerListPtr;
	KeyNode *Key_temp = Head[i]->KeyListPtr;

	L = HeadStudent;
	
	while (L->next != NULL) // goes thru each student
	{
		i = 0;
		right = 0;
		wrong = 0;
		omit = 0;
		
		while (L->element.FormLetter != Head[i]->FormCh) 
			// gets to correct key for grading
			i++;

		Answer_temp = L->AnswerListPtr;
		Key_temp = Head[i]->KeyListPtr;
		
		while (Answer_temp != NULL && Key_temp != NULL) // makes sure that pointer is
														// not at end each list
		{
			if (Answer_temp->Answer == Key_temp->Answer)
				// checks to see if answer is correct
				right++;
	
			else
				wrong++;
				
			if (Answer_temp->Answer == '?')
			// checks to see if the omitted the question
				omit++;

			Key_temp = Key_temp->Next;
	
			Answer_temp = Answer_temp->Next;
		}

		Grade = (float(right)/ATest.NumQuestions) * 100.0;

		itoa(right,correct,10);

		L->element.PercentCorrect = Grade;
		strcpy(L->element.NumCorrect, correct);
		L->element.NumOmitted = omit;

		L = L->next;
	}

	odbmenu();
}


//*****************************************************************************
// Function:	 destroylist
// Purpose:		 destroys all of the nodes of the linked list structure
// Called By:	 Close
// Calls:		 NONE
// Parameters:	 NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//******************************************************************************

void destroyList()
{
	L = HeadStudent;
	AnswerNode *Answer_temp = L->AnswerListPtr;
	StuNodePtr del = L;
	AnswerNode *DEL = Answer_temp;

	while (L->next != NULL) // goes thru each student to delete list
	{

		AnswerNode *Answer_temp = L->AnswerListPtr;

		while (Answer_temp->Next != NULL) // goes thru answers
		{
			Answer_temp = Answer_temp->Next;
			delete DEL;
			DEL = Answer_temp;
		}
		
		L = L->next;
		delete del;
		del = L;
	}
}


//***********************************************************************************
// Function:	 Close
// Purpose:		 This function closes the open ODB file
// Called By:	 FileMenu
// Calls:		 clearscreen, odbmenu, destroylist, 
// Parameters:	 inFileODB - closes the ODB file opened for building the list
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//*********************************************************************************** 

void Close(ifstream &FileODB)
{
	if (!L || L->next == NULL)// checks to see if file is not open or already closed
	{
		clearscreen();
		cout << " Invalid operation.  Must have an open file to close." << endl;
		odbmenu();
	}
	
	else
	{
		destroyList();
		FileODB.close();
		clearscreen();
		odbmenu();
	}
}

//**************************************************************************
// Function:	 MoveCurrent
// Purpose:		 Moves the current pointer to the position that the 
//					user wishes to edit
// Called By:	 EditName, EditForm, EditChair, EditAnswer, EditGroup
// Calls:		 SameScreem
// Parameters:	 int DisplayNum - Value that determines  which type of student
//								  record that is displayed  
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//**************************************************************************

void MoveCurrent(int DisplayNum)
{
	int lineNum;
	
	SameScreen(DisplayNum);
	
	cout << " Please enter the line number of the line you wish to edit." << endl;
	
	cin >> lineNum;
	
	for (int i = 1; i < lineNum; i++)
		//moves current pointer to the user selected line
		current = current->next;
}


//**************************************************************************
// Function:	 Save
// Purpose:		 Save the current list structure
// Called By:    FileMenu, SaveAs
// Calls:		 odbmenu
// Parameters:	 NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1     
//**************************************************************************

void Save()
{
	int j = 0,
		i = 0,
		NumberOfKeys = 0;

	char ODBname[NameLength] = "";

	AnswerNode *Answer_temp = L->AnswerListPtr;
	KeyNode *Key_temp = Head[i]->KeyListPtr;

	ofstream outFile;
	ifstream inFile;

	inFile.open(tempfile);

	inFile >> ODBname;

	outFile.open(ODBname);

	outFile << Memo.line1 << endl;
	outFile << Memo.line2 << endl;

	outFile << ATest.NumStudents << "  " << ATest.NumQuestions << "  " << ATest.NumKeys << endl;

	NumberOfKeys = ATest.NumKeys;	
	
	for (i; i < ATest.NumKeys; i++)  // goes thru keys to output each to file
	{
		outFile << Head[i]->SSNum << "  " << Head[i]->FormCh << "  " << Head[i]->GroupNum << "  ";
		
		Key_temp = Head[i]->KeyListPtr;
		
		j = 0;

		while (j < ATest.NumQuestions) // writes key answers to file
		{
			outFile << Key_temp->Answer;
			Key_temp = Key_temp->Next;
			j++;
		}

		outFile << endl;
	}

	L = HeadStudent;

	while (L != NULL) // writes student info to file
	{
		outFile << L->element.SSN << " " << L->element.Name << "           " << L->element.NumCorrect;
		outFile << "  " << L->element.NumOmitted << "  " << L->element.SeatNum;
		outFile << "  " << L->element.FormLetter << " " << L->element.GroupNum;
		outFile << " " << L->element.PercentCorrect << "   " << L->element.TScore;
		outFile << endl;

		i = 0;
		Answer_temp = L->AnswerListPtr;
		while ((Answer_temp != NULL) && (i++ < ATest.NumQuestions ))
		//outputs answers
		{
			outFile << Answer_temp->Answer;
			Answer_temp = Answer_temp->Next;
		
		}
		
		outFile << endl;
		L = L->next;
	}

	odbmenu();
}


//**************************************************************************
// Function:	 SaveAs
// Purpose:		 Saves the current list to disk with new filename
// Called By:    FileMenu
// Calls:		 Save, GetODBName
// Parameters:	 NONE
// Return Value: void
// Authors:		 John W. Boyd III & Cullen J. Morris
// Version:		 1.1
//**************************************************************************

void SaveAs()
{
	ofstream outFile;
	ofstream data;

	char ODBFileName[NameLength],
		 ODBExt[ExtensionLength] = ".odb";
	
	getODBname(ODBFileName, ODBExt, outFile); // gets name of file to be saved

	outFile.close();
	data.open(tempfile);
	data << ODBFileName;
	data.close();

	Save();

}