14 Replies - 1540 Views - Last Post: 10 December 2012 - 07:18 PM Rate Topic: -----

#1 neewb  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 81
  • Joined: 16-October 12

Infinite loops in a file program

Posted 28 November 2012 - 05:59 PM

This program is designed to store inventory information in a file. It allows the user to do such tasks as add new records to the file or display any record in the file among others. When compiled, the program gets very loopy if the user requests for an additional record to the file. Also, the information appears to be getting saved in the file, but it will not display anything on the screen. I really do believe the issue has to be with the loops, preferably the do loop for the menu. I tried using the debugger, but really have not been tutored at all on how to use it. Anybody out there have an idea of what is going wrong? Here is my code currently:

#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;

const int DESC_SIZE = 50;
const int DATE_SIZE = 10;

struct Inventory
{
	char desc[DESC_SIZE],
		 date[DATE_SIZE];
	int quantity;
	double whlCost,
		   rtlCost;
};

int menu();
void addRecord(fstream &);
void displayRecord(fstream &);
void changeRecord(fstream &);

int main ()
{
	Inventory rec = {"", 0, 0.0};
	cout << fixed << showpoint << setprecision(2);
	cout << "Auto Zone Inventory" << endl;
	
	int selection;
	fstream invtry("Inventory.dat", ios::out | ios::binary);
	if (!invtry)
	{
		cout << "Error opening the file.";
		return 0;
	}

	for (int count = 0; count < 10; count++)
	{
		invtry.write(reinterpret_cast<char*>(&rec),sizeof(rec));
	}
	invtry.close();

	invtry.open("Inventory.dat", ios::out | ios::binary);

	do
	{
		selection = menu();

	
		switch(selection)
		{
		case 1:
			
				addRecord(invtry);
				break;
			

		case 2:
			

				displayRecord(invtry);
				break;
			

		case 3:
			
				changeRecord(invtry);
				break;
			

		case 4:
			
				cout << "Thank you for using this program. Take care now!" << endl;
			}
				
		} while(selection!= 4);
		  invtry.close();
		  system("pause");
		  return 0;
	}
	
	
int menu ()
{
	int choice;

		//system("cls");
		cout << "Auto Zone Inventory" << endl;
		cout << "1. Add new records to the file" << endl;
		cout << "2. Display any record in the file" << endl;
		cout << "3. Change any record in the file" << endl;
		cout << "4. Quit the program" << endl;
		cout << endl;
		cout << "Please enter your choice (1-4): ";
		cin >> choice;

	while (choice < 1 || choice > 4)
	{
		cout << "Invalid entry. Please enter a number (1-4)" << endl;
		cin >> choice;
	}
	cout << endl;
	return choice;
}

void addRecord(fstream &file)
{
	cout << "Please enter new record data" << endl;
	Inventory rec;
	fstream invtry("Inventory.dat", ios::out | ios::binary);
	if (!invtry)
	{
		cout << "Error in opening the file.";
		exit(-1);
	}

	cout << "Item Description:" << endl;
	cin.ignore();
	cin.getline(rec.desc, DESC_SIZE);
	cout << rec.desc << endl;
	cout << "Quantity on hand:" << endl;
	cin >> rec.quantity;

	while (rec.quantity < 0)
	{
		cout << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.quantity;
	}

	cout << "Wholesale Cost" << endl;
	cin >> rec.whlCost;

	while (rec.whlCost < 0)
	{
		cout << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.whlCost;
	}

	cout << "Retail Cost" << endl;
	cin >> rec.rtlCost;

	while (rec.rtlCost < 0)
	{
		cout << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.rtlCost;
	}

	cout << "Date added to inventory" << endl;
	cin.ignore();
	cin.getline(rec.date, DATE_SIZE);
	invtry.write(reinterpret_cast<char *>(&rec),sizeof(rec));
	cout << "Record added to inventory";
	file.close();
}

void displayRecord(fstream &file)
{
	Inventory rec;
	fstream invtry("Inventory.dat", ios::in | ios::out | ios::binary);
	if (!invtry)
	{
		cout << "Error in opening the file.";
		exit(-1);
	}

	long num;

	cout << "Please enter the record you would like to view (1-10)" << endl;
	cin >> num;
	invtry.seekg(num * sizeof(rec), ios::beg);
	invtry.read(reinterpret_cast<char *>(&rec), sizeof(rec));
	while (!invtry.eof())
	{
		cout << "Here is your current record:";
		cout << "Item Description:";
		cout << rec.desc << endl;
		cout << "Quantity on hand:";
		cout << rec.quantity << endl;
		cout << "Wholesale cost";
		cout << rec.whlCost << endl;
		cout << "Retail cost:";
		cout << rec.rtlCost << endl;
		cout << "Date added to inventory:";
		cout << rec.date << endl;
		invtry.read(reinterpret_cast<char *>(&rec),sizeof(rec));	
		file.close();
	}
}

void changeRecord(fstream &file)
{
	Inventory rec;
	long num;
	fstream invtry("Inventory.dat", ios::in | ios::out | ios::binary);
	if (!invtry)
	{
		cout << "Error opening the file.";
		exit(-1);
	}

	cout << "Please enter the record you wish to edit (1-10)";
	cin >> num;
	invtry.seekg(num * sizeof(rec), ios::beg);
	invtry.read(reinterpret_cast<char *>(&rec), sizeof(rec));

	cout << "Here is your current record:";
	cout << "Item description:";
	cout << rec.desc << endl;
	cout << "Quantity on hand:";
	cout << rec.quantity << endl;
	cout << "Wholesale cost:";
	cout << rec.whlCost << endl;
	cout << "Retail cost:";
	cout << rec.rtlCost << endl;
	cout << "Date added to inventory:";
	cout << rec.date << endl;

	cout << "Please enter your new data to the record";
	cout << "Item description:";
	cin.ignore();
	cin.getline(rec.desc, DESC_SIZE);
	cout << "Quantity on hand:";
	cin >> rec.quantity;

	while (rec.quantity < 0)
	{
		cout << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.quantity;
	}

	cout << "Wholesale cost:";
	cin >> rec.whlCost;

	while (rec.whlCost < 0)
	{
		cout << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.whlCost;
	}

	cout << "Retail cost:";
	cin >> rec.rtlCost;

	while (rec.rtlCost < 0)
	{
		cout << "Invalid entry. Please enter only positve values." << endl;
		cin >> rec.rtlCost;
	}

	cout << "Date added to inventory:";
	cin.ignore();
	cin.getline(rec.date, DATE_SIZE);

	invtry.seekp(num * sizeof(rec), ios::beg);
	invtry.write(reinterpret_cast<char *>(&rec), sizeof(rec));
	cout << "The Record has been edited." << endl;
	invtry.close();
}


Is This A Good Question/Topic? 0
  • +

Replies To: Infinite loops in a file program

#2 jimblumberg  Icon User is offline

  • member icon


Reputation: 4025
  • View blog
  • Posts: 12,423
  • Joined: 25-December 09

Re: Infinite loops in a file program

Posted 28 November 2012 - 06:26 PM

Quote

Anybody out there have an idea of what is going wrong?

Yes, one of the problems is that you seem to try to open files that are already open. For example look at the following snippet:
void addRecord(fstream &file)
{
...
	fstream invtry("Inventory.dat", ios::out | ios::binary);
	if (!invtry)
	{
		cout << "Error in opening the file.";
		exit(-1);
	}
...

	invtry.write(reinterpret_cast<char *>(&rec),sizeof(rec));
	cout << "Record added to inventory";
	file.close();
}


In your calling function you have already opened Inventory.dat using the file instance. So why are you trying to reopen the same file in this function and naming the stream invtry? Next why are you closing file before you leave this function? You should really close the file in the same function that opened it in the first place, don't hide this closing of your stream. It will make finding problems harder.

In my opinion you should open you file once, and only once. You then pass this stream instance to your functions, as you are already doing. Then use this file stream in your functions. Make sure you check that the read/write operations succeed by testing the stream before and after the read/write operations.

Also unless the use of binary files is a requirement of your assignment I recommend you stick with text files until you are more familiar with file input and output. Is much more difficult to insure that you are properly writing your file when using binary files because you need specialty programs to view your file.


Jim
Was This Post Helpful? 2
  • +
  • -

#3 neewb  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 81
  • Joined: 16-October 12

Re: Infinite loops in a file program

Posted 29 November 2012 - 02:40 AM

"Next why are you closing file before you leave this function? You should really close the file in the same function that opened it in the first place, don't hide this closing of your stream. It will make finding problems harder."

I have to say that you explained everything very clearly here, and I never realized until you pointed this out. All I can say is that the only reason I kept closing the file, was because I thought that was what you were supposed to do, according to the book that I was reading. However; in their example, they were not using functions or menus, so I overlooked the real problem, which obviously is files opening and closing, and a looping mess!

I noticed that I did not make multiple checks for the files, only when I started the stream for each function, not afterward. So making another check during that could also help out in seeing if I have a problem, which I obviously do.

When you say that I should close the file in the same function that opened it,then wouldn't that then be the menu function? Is that where it should be closed and only closed? Makes sense if that is the case, since the menu will always be the function that opens up the option functions for the user.

I named the file stream "invrty" because I thought it was supposed to be a different name from the file name. Is that wrong? Please explain this, as that is how they showed me in the book.

"In your calling function you have already opened Inventory.dat using the file instance. So why are you trying to reopen the same file in this function and naming the stream invtry?"

I'm not sure I understand this, yes I created an instance with: Inventory rec = {"", 0, 0.0}; But I haven't even named the file yet until about 4 lines down. So can you explain to me how you say that I am opening the file up twice..

No, the assignment does not specifically require binary files, but when I when to practice one of the exercises in the book, I was able to use binary, and even though you can't read anything in the file, the display will still reveal the correct information that is stored there. But yeah you are right about reading it in the file, but is it really that much of a problem? As long as the screen is outputting the correct information, why would that matter?

This post has been edited by JackOfAllTrades: 02 December 2012 - 05:17 AM
Reason for edit:: Removed unecessary quote

Was This Post Helpful? 0
  • +
  • -

#4 jimblumberg  Icon User is offline

  • member icon


Reputation: 4025
  • View blog
  • Posts: 12,423
  • Joined: 25-December 09

Re: Infinite loops in a file program

Posted 29 November 2012 - 07:16 AM

Quote

When you say that I should close the file in the same function that opened it,then wouldn't that then be the menu function?

It looks like you are opening "Inventory.dat" in main(), so that is where I would close the file, but not until after I was totally finished processing that file. Also remember that C++ file streams will be automatically closed when they go out of scope. So in the following snippet:

void processFile();

int main()
{
   processFile();

   return 0;
}

void processFile()
{
   ifstream fin("Inventory.dat");

   // Do some reading...

}


The Inventory.dat file is opened in processFile() and it will automatically be closed when that function ends. This one of the nice things about using C++ streams the have destructors which will automatically clean up after themselves.

Quote

I named the file stream "invrty" because I thought it was supposed to be a different name from the file name. Is that wrong? Please explain this, as that is how they showed me in the book.


The name of the file stream can anything, as long as it is unique. It could be the same as the file name, but that is not necessary. Remember the name of the stream is a variable, and you must follow variable naming rules. I myself prefer to keep the name of file streams short, but at the same time descriptive. If I only have one file I usually use things like "fin" for input files and "fout" for output files. But there is nothing wrong with invrty, inventory, or any other name. However I would normally use something like inventory for the name of the class instance that is being used to handle the data from the file.

Quote

I'm not sure I understand this, yes I created an instance with: Inventory rec = {"", 0, 0.0}; But I haven't even named the file yet until about 4 lines down. So can you explain to me how you say that I am opening the file up twice..


In the following snippet:
void addRecord(fstream &file)
{
...
	fstream invtry("Inventory.dat", ios::out | ios::binary);
...
   file.close();
}



You are passing in a reference to a file stream, this file stream was opened in the calling function. The name of the file used when opening this stream was "Inventory.dat". So after the call to fstream() you will have two file streams that are operating on the same actual file. One stream named file, the other named invtry. In this function since you have passed a properly opened fstream you should use that and not create a new fstream instance. At the end of this function you close the file that you passed in as an argument, why?
void readFile(std::fstream& fin);
void writeFile(std::fstream& fout);
int main()
{
   fstream finout("Inventory.dat");

   readFile(finout);
   writeFile(finout);
}
void readFile(std::fstream& fin)
{
    // Do some reading.
    fin.close();
}

void writeFile(std::fstream& fout)
{
   // Let's try to write to the file.
   fout << "HELLO WORLD"<< std::endl;
   
   fout.close();
}



When you try to run this program you may forget that the stream was closed in your functions. Remember in this simple program these functions are in the same file but in an actual program the functions may be in separate files, and possibly written by different people.

Quote

No, the assignment does not specifically require binary files, but when I when to practice one of the exercises in the book, I was able to use binary, and even though you can't read anything in the file, the display will still reveal the correct information that is stored there. But yeah you are right about reading it in the file, but is it really that much of a problem? As long as the screen is outputting the correct information, why would that matter?

In my opinion the problem with binary files is that when you make a change to the format of the file, you must rewrite the entire file. With a text file you and use a text editor to view and alter the file to suit your new requirements. It is also much easier to see whem you are not properly reading and writing to the file when you can see the differences in a text editor.


Jim

This post has been edited by jimblumberg: 29 November 2012 - 07:18 AM

Was This Post Helpful? 2
  • +
  • -

#5 neewb  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 81
  • Joined: 16-October 12

Re: Infinite loops in a file program

Posted 01 December 2012 - 08:25 PM

Quote

void readFile(std::fstream& fin);
void writeFile(std::fstream& fout);
int main()
{
   fstream finout("Inventory.dat");

   readFile(finout);
   writeFile(finout);
}
void readFile(std::fstream& fin)
{
    // Do some reading.
    fin.close();
}

void writeFile(std::fstream& fout)
{
   // Let's try to write to the file.
   fout << "HELLO WORLD"<< std::endl;
   
   fout.close();
}



In your example you have the streams named in the prototypes, but there is no in:: or out:: inside the function. My question is this; how is the compiler going to what to do with the file. If it needs to read it, wouldn't you need a in::, or to write an out::? I understand when you say that I shouldn't open the files up in the functions because they were already opened back in main, but how are you going to let the compiler know what to do with it? Here is an updated code, it will look funny to you, because I was trying to use the in:: and the out:: in the functions, because that is where I am stuck.

Also, I have another function called "changeRecord" and that is going to need two arguments; one to read what is currently in the file, and the other to write or change the file from what it was previously. How would I go about in passing two arguments for that function? Here is the updated code....

#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;

const int DESC_SIZE = 50;
const int DATE_SIZE = 10;

struct Inventory
{
	char desc[DESC_SIZE],
		 date[DATE_SIZE];
	int quantity;
	double whlCost,
		   rtlCost;
};

int menu();
void addRecord(std::fstream& fout);
void displayRecord(std::fstream& fin);
void changeRecord(std::fstream&);

int main ()
{
	Inventory rec = {"", 0, 0.0};
	cout << fixed << showpoint << setprecision(2);
	//cout << "Auto Zone Inventory" << endl;
	
	int selection;
	fstream finout("Inventory.dat", ios::out | ios::binary);
	if (!finout)
	{
		cout << "Error opening the file.";
		return 0;
	}

	for (int count = 0; count < 10; count++)
	{
		finout.write(reinterpret_cast<char*>(&rec),sizeof(rec));
	}
	//finout.close();

	//finout.open("Inventory.dat", ios::out | ios::binary);

	do
	{
		selection = menu();

	
		switch(selection)
		{
		case 1:
			
				addRecord(finout);
				break;
			

		case 2:
			

				displayRecord(finout);
				break;
			

		case 3:
			
				changeRecord(finout);
				break;
			

		case 4:
			
				cout << "Thank you for using this program. Take care now!" << endl;
			}
				
		} while(selection!= 4);
		  //invtry.close();
		  system("pause");
		  return 0;
	}
	
	
int menu ()
{
	int choice;

		//system("cls");
		cout << "Auto Zone Inventory" << endl;
		cout << "1. Add new records to the file" << endl;
		cout << "2. Display any record in the file" << endl;
		cout << "3. Change any record in the file" << endl;
		cout << "4. Quit the program" << endl;
		cout << endl;
		cout << "Please enter your choice (1-4): ";
		cin >> choice;

	while (choice < 1 || choice > 4)
	{
		cout << "Invalid entry. Please enter a number (1-4)" << endl;
		cin >> choice;
	}
	cout << endl;
	return choice;
}

void addRecord(std::fstream& fout)
{
	cout << "Please enter new record data" << endl;
	Inventory rec;
	//fstream fout("Inventory.dat", ios::out | ios::binary);
	if (!fout)
	{
		cout << "Error in opening the file.";
		exit(-1);
	}

	cout << "Item Description:" << endl;
	cin.ignore();
	cin.getline(rec.desc, DESC_SIZE);
	cout << rec.desc << endl;
	cout << "Quantity on hand:" << endl;
	cin >> rec.quantity;

	while (rec.quantity < 0)
	{
		cout << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.quantity;
	}

	cout << "Wholesale Cost" << endl;
	cin >> rec.whlCost;

	while (rec.whlCost < 0)
	{
		cout << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.whlCost;
	}

	cout << "Retail Cost" << endl;
	cin >> rec.rtlCost;

	while (rec.rtlCost < 0)
	{
		cout << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.rtlCost;
	}

	cout << "Date added to inventory" << endl;
	cin.ignore();
	cin.getline(rec.date, DATE_SIZE);
	fout.write(reinterpret_cast<char *>(&rec),sizeof(rec));
	cout << "Record added to inventory";
	fout.close();
}

void displayRecord(std::fstream& fin)
{
	Inventory rec;
//	fstream fin("Inventory.dat", ios::in | ios::binary);
	if (!fin)
	{
		cout << "Error in opening the file.";
		exit(-1);
	}

	long num;

	cout << "Please enter the record you would like to view (1-10)" << endl;
	cin >> num;
	fin.seekg(num * sizeof(rec), ios::beg);
	fin.read(reinterpret_cast<char *>(&rec), sizeof(rec));
	while (!fin.eof())
	{
		cout << "Here is your current record:";
		cout << "Item Description:";
		cout << rec.desc << endl;
		cout << "Quantity on hand:";
		cout << rec.quantity << endl;
		cout << "Wholesale cost";
		cout << rec.whlCost << endl;
		cout << "Retail cost:";
		cout << rec.rtlCost << endl;
		cout << "Date added to inventory:";
		cout << rec.date << endl;
		fin.read(reinterpret_cast<char *>(&rec),sizeof(rec));	
		fin.close();
	}
}

void changeRecord(std::fstream& fin, std::fstream& fout)
{
	Inventory rec;
	long num;
	fstream invtry("Inventory.dat", ios::in | ios::out | ios::binary);
	if (!invtry)
	{
		cout << "Error opening the file.";
		exit(-1);
	}

	cout << "Please enter the record you wish to edit (1-10)";
	cin >> num;
	invtry.seekg(num * sizeof(rec), ios::beg);
	invtry.read(reinterpret_cast<char *>(&rec), sizeof(rec));

	cout << "Here is your current record:";
	cout << "Item description:";
	cout << rec.desc << endl;
	cout << "Quantity on hand:";
	cout << rec.quantity << endl;
	cout << "Wholesale cost:";
	cout << rec.whlCost << endl;
	cout << "Retail cost:";
	cout << rec.rtlCost << endl;
	cout << "Date added to inventory:";
	cout << rec.date << endl;

	cout << "Please enter your new data to the record";
	cout << "Item description:";
	cin.ignore();
	cin.getline(rec.desc, DESC_SIZE);
	cout << "Quantity on hand:";
	cin >> rec.quantity;

	while (rec.quantity < 0)
	{
		cout << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.quantity;
	}

	cout << "Wholesale cost:";
	cin >> rec.whlCost;

	while (rec.whlCost < 0)
	{
		cout << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.whlCost;
	}

	cout << "Retail cost:";
	cin >> rec.rtlCost;

	while (rec.rtlCost < 0)
	{
		cout << "Invalid entry. Please enter only positve values." << endl;
		cin >> rec.rtlCost;
	}

	cout << "Date added to inventory:";
	cin.ignore();
	cin.getline(rec.date, DATE_SIZE);

	invtry.seekp(num * sizeof(rec), ios::beg);
	invtry.write(reinterpret_cast<char *>(&rec), sizeof(rec));
	cout << "The Record has been edited." << endl;
	invtry.close();
}

This post has been edited by jimblumberg: 01 December 2012 - 09:43 PM
Reason for edit:: Removed unecessary quote.

Was This Post Helpful? 0
  • +
  • -

#6 jimblumberg  Icon User is offline

  • member icon


Reputation: 4025
  • View blog
  • Posts: 12,423
  • Joined: 25-December 09

Re: Infinite loops in a file program

Posted 01 December 2012 - 09:42 PM

The name of function parameter names in the function prototype do not need to be the same as the variable names in either the function call or the function implementation, if fact the prototype doesn't actually need names for the parameters, it just needs the types. The following are both valid function prototypes:

int someFunction(int);
int someFunction(int name);


The function implementation requires a name as well as the type. This name will be used inside the function to refer to the that variable. This name does not need to match either the function prototype variable name or the function call variable name.

But remember that the function prototype, function implementation, and the function call must all agree as to the number and the type of parameters. Don't confuse the name of the variables with the variable type. Types are things like int, double, float, fstream, etc.

Quote

Also, I have another function called "changeRecord" and that is going to need two arguments; one to read what is currently in the file, and the other to write or change the file from what it was previously. How would I go about in passing two arguments for that function? Here is the updated code....


Since you are using fstream you don't need to pass two different stream instances into your function. An fstream can read and write to the stream at the same time. This is the purpose of this class. This class has different stream pointers for input and output. You can be receiving input from one point in a file without affecting the position of the output pointer. But in order to read and write from the stream you first need to open the stream for both input and output.

fstream finout("yourFileName", std::ios::binary | std::ios::in | std::ios::out);


If you only want input or output, but not both then you should be using the ifstream and ofstream classes. These classes are designed to only read or write to the stream.

In your changeRecord() function you are still trying to re-open your already open stream. You don't want to do this, use the parameter you are passing into this function. And remember your function implementation doesn't agree with your function prototype, you will need to fix this issue. Also when you want to change the position of the get pointer you need to use the seekg() member function and when you want to change the position of the put pointer you need to use the seekp() member function.

Jim
Was This Post Helpful? 0
  • +
  • -

#7 neewb  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 81
  • Joined: 16-October 12

Re: Infinite loops in a file program

Posted 09 December 2012 - 08:15 PM

View Postjimblumberg, on 01 December 2012 - 09:42 PM, said:

The name of function parameter names in the function prototype do not need to be the same as the variable names in either the function call or the function implementation, if fact the prototype doesn't actually need names for the parameters, it just needs the types. The following are both valid function prototypes:

int someFunction(int);
int someFunction(int name);


The function implementation requires a name as well as the type. This name will be used inside the function to refer to the that variable. This name does not need to match either the function prototype variable name or the function call variable name.

But remember that the function prototype, function implementation, and the function call must all agree as to the number and the type of parameters. Don't confuse the name of the variables with the variable type. Types are things like int, double, float, fstream, etc.

Quote

Also, I have another function called "changeRecord" and that is going to need two arguments; one to read what is currently in the file, and the other to write or change the file from what it was previously. How would I go about in passing two arguments for that function? Here is the updated code....


Since you are using fstream you don't need to pass two different stream instances into your function. An fstream can read and write to the stream at the same time. This is the purpose of this class. This class has different stream pointers for input and output. You can be receiving input from one point in a file without affecting the position of the output pointer. But in order to read and write from the stream you first need to open the stream for both input and output.

fstream finout("yourFileName", std::ios::binary | std::ios::in | std::ios::out);


If you only want input or output, but not both then you should be using the ifstream and ofstream classes. These classes are designed to only read or write to the stream.

In your changeRecord() function you are still trying to re-open your already open stream. You don't want to do this, use the parameter you are passing into this function. And remember your function implementation doesn't agree with your function prototype, you will need to fix this issue. Also when you want to change the position of the get pointer you need to use the seekg() member function and when you want to change the position of the put pointer you need to use the seekp() member function.

Jim


Ok so I have been working on this program all week, and I have everything good except the date validation. I need to include in my regular expression algorithm leap year and dates that can be passed as valid. I was able to find the one I have online, but I am having trouble adding to it for the leap year and valid dates. The only thing this validation will check is for dashes, integers between 0-9, and not allow strings and that is it. Is there a way I can add to this expression that I have currently for leap year and valid dates? Here is my updated code:


// inventory.cpp : Defines the entry point for the console application.
//

#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <regex>
using namespace std;

const int DESC_SIZE = 50;

struct Date{
	int Month;
	int Day;
	int Year;
};

struct Inventory
{
	char desc[DESC_SIZE];	
	int quantity;
	double whlCost,
		   rtlCost;
	Date date;
};

void menu(std::fstream&);
bool addRecord(std::fstream&);
bool displayRecord(std::fstream&);
bool changeRecord(std::fstream&);
Date dateValidation(string);

int main()
{
		
	cout << fixed << showpoint << setprecision(2);
	fstream file;
	ifstream ifile("Inventory.dat");		
	if (!ifile)
	{
		Date date;
		date.Day = 1;
		date.Month = 1;
		date.Year = 1970;
		Inventory rec = {"Default", 0, 0.0, 0.0, date};
		file.open ("Inventory.dat", fstream::out | fstream::binary);
		for (int count = 0; count < 10; count++)
		{			
			file.write((char*)&rec,sizeof(rec));
		}
		cout << endl << "Warning, did not find file, so we created one.";
		cout << endl;		
		file.close();
	}	
	
	// Create Menu and run program
	menu(file);	
	system("pause");
	return 0;
	
}

Date dateValidation(string data){
	Date date;
    match_results<string::const_iterator> m;
    regex re("([0-9]+)-([0-9]+)-([0-9]*)?");	
    if (regex_match(data, m, re)) {
        date.Day = stoi(m[1].str()),
		date.Month = stoi(m[2].str()),
		date.Year = stoi(m[3].str());       
	}
	else date.Year = 0000;
	return date;
}
	
void menu(std::fstream& file)
{	
	int choice = 0;
	bool success;
	while(choice!= 4) {
		cout << "Auto Zone Inventory" << endl;
		cout << endl << "1. Add new records to the file" << endl;
		cout << "2. Display any record in the file" << endl;
		cout << "3. Change any record in the file" << endl;
		cout << "4. Quit the program" << endl;
		cout << endl;
		cout << "Please enter your choice (1-4): ";
		cin >> choice;

		while (choice < 1 || choice > 4)
		{
			cout << endl << "Invalid entry. Please enter a number (1-4)" << endl;
			cin >> choice;
		}
		cout << endl;
	
		switch(choice){
			case 1:
					success = addRecord(file);					
					break;					
			case 2:
					success = displayRecord(file);
					break;
			case 3:
					success = changeRecord(file);
					break;
			case 4:	
					success = true;
					cout << "Thank you for using this program. Auto Zone cares!" << endl;
					break;
			default : 
					cout << "Error " << choice << " is not a valid number";
					break;
		}				
		if (!success) cout << "File IO Error reading file!";
		else {
			system("Pause");
			system("cls");
		}
		
	}
}

bool addRecord(std::fstream& file)
{
	cout << "Please enter new record data" << endl;
	Inventory rec;
	string dateStr;
	file.open ("Inventory.dat", fstream::out | fstream::app | fstream::binary);

	cout << endl << "Item Description:" << endl;
	cin.ignore();
	cin.getline(rec.desc, DESC_SIZE);
	cout << rec.desc << endl;
	cout << endl << "Quantity on hand:" << endl;
	cin >> rec.quantity;

	while (rec.quantity < 0)
	{
		cout <<  endl << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.quantity;
	}

	cout << endl << "Wholesale Cost" << endl;
	cin >> rec.whlCost;

	while (rec.whlCost < 0)
	{
		cout << endl << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.whlCost;
	}

	cout << endl << "Retail Cost" << endl;
	cin >> rec.rtlCost;

	while (rec.rtlCost < 0)
	{
		cout << endl << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.rtlCost;
	}
		
	bool loop = true;
	while (loop){ 
		cout << endl << "Date added to inventory (MM-DD-YYYY)" << endl;
		cin.ignore();
		cin >> dateStr;	
		rec.date = dateValidation(dateStr);		
		if (rec.date.Year != 0000) {			
			loop = false;
		}
		else 
			cout << endl << "Error Date Format is (MM-DD-YYYY)" <<endl;
	}
	file.write(reinterpret_cast<char *>(&rec),sizeof(rec));
	cout << endl << "Record added to inventory" << endl;
	file.close();
	return true;
}

bool displayRecord(std::fstream& file)
{
	Inventory rec;
	file.open ("Inventory.dat", fstream::in | fstream::binary);
	long num;
	//Figure out How many records exist
	long a = file.tellg();
	file.seekg(0, fstream::end);
	long b = file.tellg();
	long sizeFile = b - a;
	int c = sizeof(rec);
	int numRecords = (sizeFile / c);

	if (numRecords > 0){
		cout << "Please enter the record you would like to view (1-"<< (numRecords) <<")" << endl;
		cin >> num;
		if ((num >= 0) && (num <= (numRecords))){
			num = num -1;
			file.seekg(num * sizeof(rec), fstream::beg);
			file.read(reinterpret_cast<char *>(&rec), sizeof(rec));
			if (!file.eof())
			{
				cout << endl << "Here is your current record:" << endl;
				cout << endl << "Item Description: ";
				cout << rec.desc << endl;
				cout << "Quantity on hand: ";
				cout << rec.quantity << endl;
				cout << "Wholesale cost: ";
				cout << rec.whlCost << endl;
				cout << "Retail cost: ";
				cout << rec.rtlCost << endl;
				cout << "Date added to inventory: ";
				cout << rec.date.Day << "-" << rec.date.Month << "-" << rec.date.Year << endl;						
			}
			file.close();
		}
		else {
			cout << "Record Outside of Database Range" << endl;
		}
	}
	else {
		cout << "No Records Found !" << endl;
		return false;
	}
	return true;
}

bool changeRecord(std::fstream& file)
{
	Inventory rec;
	Inventory* recs;
	string dateStr;
	string yn;	
	char* buffer;	

	long num;
	
	file.open ("Inventory.dat", fstream::in | fstream::out | fstream::binary);
	
	//Figure out How many records exist
	long a = file.tellg();
	file.seekg(0, fstream::end);
	long b = file.tellg();
	long sizeFile = b - a;
	int numRecords = 0;
	if (sizeFile > 4){
		int c = sizeof(rec);
		numRecords = (sizeFile / c);
	}

	if (numRecords > 0){
		cout << "Please enter the record you would like to view (1-"<< (numRecords) <<")" << endl;
		cin >> num;
		if (!file.eof()){
			num = num -1;
			file.seekg(num * sizeof(rec), fstream::beg);
			file.read(reinterpret_cast<char *>(&rec), sizeof(rec));

			cout << endl << "Here is your current record" << endl;
			cout << endl << "Item description: ";
			cout << rec.desc << endl;
			cout << "Quantity on hand: ";
			cout << rec.quantity << endl;
			cout << "Wholesale cost: ";
			cout << rec.whlCost << endl;
			cout << "Retail cost: ";
			cout << rec.rtlCost << endl;
			cout << "Date added to inventory: ";
			cout << rec.date.Day << "-" << rec.date.Month << "-" << rec.date.Year << endl;
				
		}
		
		cout << endl << "Do you want to proceed ? (Y/N)" << endl;
		cin >> yn;
		if ((yn == "Y")||(yn == "y")){
			cout << endl << "Please enter your new data to the record"<< endl;
			cout << endl << "Item description:" << endl;
			cin.ignore();
			cin.getline(rec.desc, DESC_SIZE);
			cout << endl << "Quantity on hand:" << endl;
			cin >> rec.quantity;

			while (rec.quantity < 0)
			{
				cout << endl << "Invalid entry. Please enter only positive values." << endl;
				cin >> rec.quantity;
			}

			cout << endl << "Wholesale cost:" << endl;
			cin >> rec.whlCost;

			while (rec.whlCost < 0)
			{
				cout << endl << "Invalid entry. Please enter only positive values." << endl;
				cin >> rec.whlCost;
			}

			cout << endl << "Retail cost:" << endl;
			cin >> rec.rtlCost;

			while (rec.rtlCost < 0)
			{
				cout << endl << "Invalid entry. Please enter only positve values." << endl;
				cin >> rec.rtlCost;
			}

			bool loop = true;
			while (loop){ 
				cout << endl << "Date added to inventory (MM-DD-YYYY)" << endl;
				cin.ignore();
				cin >> dateStr;	
				rec.date = dateValidation(dateStr);		
				if (rec.date.Year != 0000) {			
					loop = false;
				}
				else 
					cout << endl << "Error Date Format is (MM-DD-YYYY)" <<endl;
			}

			file.seekp(num * sizeof(rec), fstream::beg);
			file.write(reinterpret_cast<char *>(&rec), sizeof(rec));
			cout << endl << "The Record has been edited." << endl;
		}
	}
	else cout << endl << "File contains no records!" << endl;
	file.close();
	return true;
}




Was This Post Helpful? 0
  • +
  • -

#8 AKMafia001  Icon User is offline

  • </code.in.dream>

Reputation: 187
  • View blog
  • Posts: 624
  • Joined: 11-June 11

Re: Infinite loops in a file program

Posted 10 December 2012 - 05:13 AM

If you want to validate the date or some members of the class. One way is to use utility functions to validate them...

Example:
// validate the time while setting it
void Time::setTime(int h, int m, int s)
{
	setHour(h);
	setMinute(m);
	setSecond(s);

}

void Time::setHour(int h)
{ hour = (h >= 0 && h < 24) ? h : 0; }

void Time::setMinute(int m)
{ minute = (m >= 0 && m < 60) ? m : 0; }

void Time::setSecond(int s)
{ second = (s >= 0 && s < 60) ? s : 0; }



Hope this Helps!
Was This Post Helpful? 0
  • +
  • -

#9 neewb  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 81
  • Joined: 16-October 12

Re: Infinite loops in a file program

Posted 10 December 2012 - 01:38 PM

This program runs fine, but it needs more validation. All I can come up with is checking for integers (0-9), and dashes in mm-dd-yyyy format and that is it. I would like this program to also check for invalid dates and leap year. I have a regular expression already implemented in the program, but is there a way I can add to it for the date validation and leap year check. Or, will I need to create new functions separately for both? I do not want to add any classes to this,as I already am using structures. Preferably I would just like to find a way to add to my regular expression if that is possible. Here is my code:


// inventory.cpp : Defines the entry point for the console application.
//

#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <regex>
using namespace std;

const int DESC_SIZE = 50;

struct Date{
	int Month;
	int Day;
	int Year;
};

struct Inventory
{
	char desc[DESC_SIZE];	
	int quantity;
	double whlCost,
		   rtlCost;
	Date date;
};

void menu(std::fstream&);
bool addRecord(std::fstream&);
bool displayRecord(std::fstream&);
bool changeRecord(std::fstream&);
Date dateValidation(string);

int main()
{
		
	cout << fixed << showpoint << setprecision(2);
	fstream file;
	ifstream ifile("Inventory.dat");		
	if (!ifile)
	{
		Date date;
		date.Day = 1;
		date.Month = 1;
		date.Year = 1970;
		Inventory rec = {"Default", 0, 0.0, 0.0, date};
		file.open ("Inventory.dat", fstream::out | fstream::binary);
		for (int count = 0; count < 10; count++)
		{			
			file.write((char*)&rec,sizeof(rec));
		}
		cout << endl << "Warning, did not find file, so we created one.";
		cout << endl;		
		file.close();
	}	
	
	// Create Menu and run program
	menu(file);	
	system("pause");
	return 0;
	
}

Date dateValidation(string data){
	Date date;
    match_results<string::const_iterator> m;
    regex re("([0-9]+)-([0-9]+)-([0-9]*)?");	
    if (regex_match(data, m, re)) {
        date.Day = stoi(m[1].str()),
		date.Month = stoi(m[2].str()),
		date.Year = stoi(m[3].str());       
	}
	else date.Year = 0000;
	return date;
}


	
	
void menu(std::fstream& file)
{	
	int choice = 0;
	bool success;
	while(choice!= 4) {
		cout << "Auto Zone Inventory" << endl;
		cout << endl << "1. Add new records to the file" << endl;
		cout << "2. Display any record in the file" << endl;
		cout << "3. Change any record in the file" << endl;
		cout << "4. Quit the program" << endl;
		cout << endl;
		cout << "Please enter your choice (1-4): ";
		cin >> choice;

		while (choice < 1 || choice > 4)
		{
			cout << endl << "Invalid entry. Please enter a number (1-4)" << endl;
			cin >> choice;
		}
		cout << endl;
	
		switch(choice){
			case 1:
					success = addRecord(file);					
					break;					
			case 2:
					success = displayRecord(file);
					break;
			case 3:
					success = changeRecord(file);
					break;
			case 4:	
					success = true;
					cout << "Thank you for using this program. Auto Zone cares!" << endl;
					break;
			default : 
					cout << "Error " << choice << " is not a valid number";
					break;
		}				
		if (!success) cout << "File IO Error reading file!";
		else {
			system("Pause");
			system("cls");
		}
		
	}
}

bool addRecord(std::fstream& file)
{
	cout << "Please enter new record data" << endl;
	Inventory rec;
	string dateStr;
	file.open ("Inventory.dat", fstream::out | fstream::app | fstream::binary);

	cout << endl << "Item Description:" << endl;
	cin.ignore();
	cin.getline(rec.desc, DESC_SIZE);
	cout << rec.desc << endl;
	cout << endl << "Quantity on hand:" << endl;
	cin >> rec.quantity;

	while (rec.quantity < 0)
	{
		cout <<  endl << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.quantity;
	}

	cout << endl << "Wholesale Cost" << endl;
	cin >> rec.whlCost;

	while (rec.whlCost < 0)
	{
		cout << endl << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.whlCost;
	}

	cout << endl << "Retail Cost" << endl;
	cin >> rec.rtlCost;

	while (rec.rtlCost < 0)
	{
		cout << endl << "Invalid entry. Please enter only positive values." << endl;
		cin >> rec.rtlCost;
	}
		
	bool loop = true;
	while (loop){ 
		cout << endl << "Date added to inventory (MM-DD-YYYY)" << endl;
		cin.ignore();
		cin >> dateStr;	
		rec.date = dateValidation(dateStr);		
		if (rec.date.Year != 0000) {			
			loop = false;
		}
		else 
			cout << endl << "Error Date Format is (MM-DD-YYYY)" <<endl;
	}
	file.write(reinterpret_cast<char *>(&rec),sizeof(rec));
	cout << endl << "Record added to inventory" << endl;
	file.close();
	return true;
}

bool displayRecord(std::fstream& file)
{
	Inventory rec;
	file.open ("Inventory.dat", fstream::in | fstream::binary);
	long num;
	//Figure out How many records exist
	long a = file.tellg();
	file.seekg(0, fstream::end);
	long b = file.tellg();
	long sizeFile = b - a;
	int c = sizeof(rec);
	int numRecords = (sizeFile / c);

	if (numRecords > 0){
		cout << "Please enter the record you would like to view (1-"<< (numRecords) <<")" << endl;
		cin >> num;
		if ((num >= 0) && (num <= (numRecords))){
			num = num -1;
			file.seekg(num * sizeof(rec), fstream::beg);
			file.read(reinterpret_cast<char *>(&rec), sizeof(rec));
			if (!file.eof())
			{
				cout << endl << "Here is your current record:" << endl;
				cout << endl << "Item Description: ";
				cout << rec.desc << endl;
				cout << "Quantity on hand: ";
				cout << rec.quantity << endl;
				cout << "Wholesale cost: ";
				cout << rec.whlCost << endl;
				cout << "Retail cost: ";
				cout << rec.rtlCost << endl;
				cout << "Date added to inventory: ";
				cout << rec.date.Day << "-" << rec.date.Month << "-" << rec.date.Year << endl;						
			}
			file.close();
		}
		else {
			cout << "Record Outside of Database Range" << endl;
		}
	}
	else {
		cout << "No Records Found !" << endl;
		return false;
	}
	return true;
}

bool changeRecord(std::fstream& file)
{
	Inventory rec;
	Inventory* recs;
	string dateStr;
	string yn;	
	char* buffer;	

	long num;
	
	file.open ("Inventory.dat", fstream::in | fstream::out | fstream::binary);
	
	//Figure out How many records exist
	long a = file.tellg();
	file.seekg(0, fstream::end);
	long b = file.tellg();
	long sizeFile = b - a;
	int numRecords = 0;
	if (sizeFile > 4){
		int c = sizeof(rec);
		numRecords = (sizeFile / c);
	}

	if (numRecords > 0){
		cout << "Please enter the record you would like to view (1-"<< (numRecords) <<")" << endl;
		cin >> num;
		if (!file.eof()){
			num = num -1;
			file.seekg(num * sizeof(rec), fstream::beg);
			file.read(reinterpret_cast<char *>(&rec), sizeof(rec));

			cout << endl << "Here is your current record" << endl;
			cout << endl << "Item description: ";
			cout << rec.desc << endl;
			cout << "Quantity on hand: ";
			cout << rec.quantity << endl;
			cout << "Wholesale cost: ";
			cout << rec.whlCost << endl;
			cout << "Retail cost: ";
			cout << rec.rtlCost << endl;
			cout << "Date added to inventory: ";
			cout << rec.date.Day << "-" << rec.date.Month << "-" << rec.date.Year << endl;
				
		}
		
		cout << endl << "Do you want to proceed ? (Y/N)" << endl;
		cin >> yn;
		if ((yn == "Y")||(yn == "y")){
			cout << endl << "Please enter your new data to the record"<< endl;
			cout << endl << "Item description:" << endl;
			cin.ignore();
			cin.getline(rec.desc, DESC_SIZE);
			cout << endl << "Quantity on hand:" << endl;
			cin >> rec.quantity;

			while (rec.quantity < 0)
			{
				cout << endl << "Invalid entry. Please enter only positive values." << endl;
				cin >> rec.quantity;
			}

			cout << endl << "Wholesale cost:" << endl;
			cin >> rec.whlCost;

			while (rec.whlCost < 0)
			{
				cout << endl << "Invalid entry. Please enter only positive values." << endl;
				cin >> rec.whlCost;
			}

			cout << endl << "Retail cost:" << endl;
			cin >> rec.rtlCost;

			while (rec.rtlCost < 0)
			{
				cout << endl << "Invalid entry. Please enter only positve values." << endl;
				cin >> rec.rtlCost;
			}

			bool loop = true;
			while (loop){ 
				cout << endl << "Date added to inventory (MM-DD-YYYY)" << endl;
				cin.ignore();
				cin >> dateStr;	
				rec.date = dateValidation(dateStr);		
				if (rec.date.Year != 0000) {			
					loop = false;
				}
				else 
					cout << endl << "Error Date Format is (MM-DD-YYYY)" <<endl;

				
			}

			file.seekp(num * sizeof(rec), fstream::beg);
			file.write(reinterpret_cast<char *>(&rec), sizeof(rec));
			cout << endl << "The Record has been edited." << endl;
		}
	}
	else cout << endl << "File contains no records!" << endl;
	file.close();
	return true;
}



Was This Post Helpful? 0
  • +
  • -

#10 Martyr2  Icon User is offline

  • Programming Theoretician
  • member icon

Reputation: 4332
  • View blog
  • Posts: 12,127
  • Joined: 18-April 07

Re: Infinite loops in a file program

Posted 10 December 2012 - 01:50 PM

Was there any particular reason you are using a regex for date validation than simply creating a function to check the day/month/year values individually? The reason I suggest this is because you can run the year through the typical "isLeapYear()" style function and have it return true or false. Once you have this, you simply have to see if they try to specify a day/month which won't work with a year because it is/is not a leap year.

Remember, regex is for pattern matching, not for logic to tell if something is logically valid or not. That is 88/59/0987 is matched, but not logically valid. Probably why you are having a bit of trouble here.

:)
Was This Post Helpful? 0
  • +
  • -

#11 AKMafia001  Icon User is offline

  • </code.in.dream>

Reputation: 187
  • View blog
  • Posts: 624
  • Joined: 11-June 11

Re: Infinite loops in a file program

Posted 10 December 2012 - 01:52 PM

I posted in your another thread, but that solution was for a class where you can implement utility functions...

Well! A simple solution is, when setting your date you can check it, if it is valid assign it, if not, then reset it.

Example:
// where 1 denotes the default value to reset the date to
// nDay is the input day
date.day = (nDay >= 1 && nDay <= 31)? nDay : 1;    



Hope this Helps!
Was This Post Helpful? 0
  • +
  • -

#12 neewb  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 81
  • Joined: 16-October 12

Re: Infinite loops in a file program

Posted 10 December 2012 - 02:03 PM

View PostAKMafia001, on 10 December 2012 - 01:52 PM, said:

I posted in your another thread, but that solution was for a class where you can implement utility functions...

Well! A simple solution is, when setting your date you can check it, if it is valid assign it, if not, then reset it.

Example:
// where 1 denotes the default value to reset the date to
// nDay is the input day
date.day = (nDay >= 1 && nDay <= 31)? nDay : 1;    



Hope this Helps!


Thanks for replying. This looks good, but where should I place it? Should it go in the dateValidation function? Or inside the while (loop) where the user can input its choice? Also, will I need to have an array for the months? Something like: {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} Or could I just create if / else statements for each of the months. I think I really did create a mess with the regular expression approach, but I want to keep going with it since the program works, and the fact that the assignment is due today.....
Was This Post Helpful? 0
  • +
  • -

#13 neewb  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 81
  • Joined: 16-October 12

Re: Infinite loops in a file program

Posted 10 December 2012 - 02:09 PM

View PostMartyr2, on 10 December 2012 - 01:50 PM, said:

Was there any particular reason you are using a regex for date validation than simply creating a function to check the day/month/year values individually? The reason I suggest this is because you can run the year through the typical "isLeapYear()" style function and have it return true or false. Once you have this, you simply have to see if they try to specify a day/month which won't work with a year because it is/is not a leap year.

Remember, regex is for pattern matching, not for logic to tell if something is logically valid or not. That is 88/59/0987 is matched, but not logically valid. Probably why you are having a bit of trouble here.

:)/>


Thanks for replying. No there really is no other reason other than the fact that the program works with it. I searched a long time online to find something that worked and that is all I could come up with. But I get what you are saying about pattern matching. I guess then is there a way I could then create the isLeapYear() function you suggested, and test each condition separately? If possible then, how can I get this function to work with the loop since I only have one argument for the user to send to the function?
Was This Post Helpful? 0
  • +
  • -

#14 jimblumberg  Icon User is offline

  • member icon


Reputation: 4025
  • View blog
  • Posts: 12,423
  • Joined: 25-December 09

Re: Infinite loops in a file program

Posted 10 December 2012 - 03:02 PM

Merged topics. Please don't open multiple topics for the same problem.

Jim
Was This Post Helpful? 0
  • +
  • -

#15 neewb  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 81
  • Joined: 16-October 12

Re: Infinite loops in a file program

Posted 10 December 2012 - 07:18 PM

View Postjimblumberg, on 10 December 2012 - 03:02 PM, said:

Merged topics. Please don't open multiple topics for the same problem.

Jim


Sorry about that, won't happen again....
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1