Hi my project have many csv files. Which is located in the same directory as Datafolder/IAG/day1.csv, Datafolder/IAG/day2.csv and Datafolder/IAG/day3.csv. Same for Datafolder/CBA/day1.csv, Datafolder/CBA/day2.csv and Datafolder/CBA/day3.csv and Datafolder/NAB/day1.csv, Datafolder/NAB/day2.csv and Datafolder/NAB/day3.csv.
my goal is user can input which day's data they want and input. Once they input it will ask the user to enter either 1(to get the highest price value) or 2(lowest price value). But in my code I dont why once the user select the day and get the highest price it is stored as that value. Even though the user select another day and look for the highest price it is not actually displaying that day's highest value but the previous day's highest value which copied over again The following is codes. Thanks in advance guys.
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
#include "vector.h"
#include "stock.h"
#include <map>
using namespace std;
int counter = 0;
double highestPrice=0, lowestPrice=0;
ofstream outfile;
string sFileName;
string record;
Stock S1;
Vector<Stock> data;
int option;
ifstream codeindex;
ifstream IAGsales;
ifstream CBAsales;
ifstream NABsales;
ifstream* Tempsales = 0;
ifstream infile;
map<string,Vector<Stock>> mapIAG;
map<string,Vector<Stock>> mapCBA;
map<string,Vector<Stock>> mapNAB;
map<string,Vector<Stock>> mapTemp;
map<string,Vector<Stock>>::iterator it;
double price1, price2;
Time time1, time2;
Date date1;
string sXCode,sInputDate;
int main()
{
void initializing();
codeindex.open("Datafolder/code_index.txt");
if(! codeindex)
{
cout << codeindex <<" : File not found!!" << endl;
system("PAUSE");
exit(1);
}
do
{
initializing();
time1.initialize();
highestPrice = (data.getvalue(0)).getprice();//Initialise highest price
lowestPrice=0;
lowestPrice = (data.getvalue(0)).getprice();//Initialise lowest price
(data.getvalue(0)).gettime(time1, data.getvalue(0));//Initialise time1
switch (option)
{
case 1:
{
Date datehigh;
for(int i = 1 ; i < counter ; i ++)
{
if((data.getvalue(i)).getprice() > highestPrice)
{
highestPrice = (data.getvalue(i)).getprice();
(data.getvalue(i)).gettime(time1, data.getvalue(i));//get the time when highest price first occurred
(data.getvalue(i)).getdate(datehigh, data.getvalue(i));
}
}
cout << "Date: " << datehigh << endl;
cout << "Highest price : " << highestPrice << endl;
cout << "Start time(s): " << endl;
cout << time1 ;
for(int i = 0 ; i < counter ; i ++)
{
if( (data.getvalue(i)).getprice() == highestPrice)
{
(data.getvalue(i)).gettime(time2, data.getvalue(i));//get the time when highest price occurred
if(time2 != time1)//avoid duplicated time
{
(data.getvalue(i)).printtime();
(data.getvalue(i)).gettime(time1, data.getvalue(i));
//(data.getvalue(i)).getdate(datehigh, data.getvalue(i));
}
}//End of if( (data.get(i)).getprice() == highestPrice)
}//End of for(int i = 0 ; i < count ; i ++)
//main();
//initialize();
//(data.getvalue(0)).printdate();
break;
}
case 2:
{
Date datelow;
for(int i = 1 ; i < counter ; i ++)
{
if(((data.getvalue(i)).getprice() < lowestPrice) && ((data.getvalue(i)).getprice() > 0))
{
lowestPrice = (data.getvalue(i)).getprice();
(data.getvalue(i)).gettime(time1, data.getvalue(i));//get the time when lowest price first occurred
(data.getvalue(i)).getdate(datelow, data.getvalue(i));
}
}
int j =0;
//(data.getvalue(j)).printdate();
cout << "Date: " << datelow << endl;
cout << "Lowest price: " << lowestPrice << endl;
cout << "Start time(s): " << endl;
cout << time1<<endl;
for(int i = 0 ; i < counter ; i ++)
{
if( (data.getvalue(i)).getprice() == lowestPrice)
{
(data.getvalue(i)).gettime(time2, data.getvalue(i));//get the time when highest price occurred
if(time2 != time1)//avoid duplicated time
{
(data.getvalue(i)).printtime();
(data.getvalue(i)).gettime(time1, data.getvalue(i));
}
}//End of if( (data.get(i)).getprice() == lowestPrice)
}//End of for(int i = 0 ; i < count ; i ++)
//main();
//initialize();
break;
}
case 3:
{
outfile.open("output.csv");
if(! outfile)
{
cout << "Can not open outfile" << endl;
exit(1);
}
cout << "Data processing" << endl;
outfile << fixed << showpoint << setprecision(2);
outfile << "Date,Start time,Price of share,Volume of shares traded,Total value of shares traded" << endl;
price1 = data.getvalue(counter-1).getprice();//get price for the last row
double nVolumeOfTrades = data.getvalue(counter-1).getvolume();
double ntotalValueOfShares = data.getvalue(counter-1).getvalue();
// Get Date of trading
data.getvalue(counter-1).getdate(date1,data.getvalue(counter-1));
// Get Start time
data.getvalue(counter-1).gettime(time1,data.getvalue(counter-1));
for(int i = counter-2; i > -1 ; i --)
{
price2 = data.getvalue(i).getprice();
if(price2 != 0 && price1 != price2)
{
// Write values to file.
outfile << date1 << "," << time1 << "," << price1 << "," << nVolumeOfTrades << "," << ntotalValueOfShares << endl;
// Get Date of trading
data.getvalue(i).getdate(date1,data.getvalue(i));
// Get Start time
data.getvalue(i).gettime(time1,data.getvalue(i));
price1 = data.getvalue(i).getprice();
nVolumeOfTrades = 0;
ntotalValueOfShares = 0;
}
nVolumeOfTrades += data.getvalue(i).getvolume();
ntotalValueOfShares += data.getvalue(i).getvalue();
}
cout << "Data processed" << endl;
outfile.close();
//initialize();
//main();
break;
}
case 4:
{
break;
}
default:
{
cout << "Invalid option" << endl;
cout<<"Choose from options 1 to 4: "<<endl;
cout << "Enter 1 to get the highest stock price & time:" << endl;
cout << "Enter 2 to get the lowest stock price & time:" << endl;
cout << "Enter 3 to output the csv file: " << endl;
cout << "Enter 4 to exit from the program:" << endl;
cin >> option;
break;
}
}
if(option==4)
{
break;
}
cout << "\n\n" << endl;
}
while(1);
return 0;
}
void initializing()
{
// Present the user with Input options
cout<<"Enter the code of transaction:" <<endl;
while(! codeindex.eof()){
getline(codeindex,record);
cout<<record<<endl;
}
cin>>sXCode;
codeindex.clear();
codeindex.seekg(0,ios::beg);
while(sXCode!="IAG" && sXCode!="CBA" && sXCode!="NAB"){
cout<<"Wrong input .. Please enter again \n";
cin>>sXCode;
}
// Get code file name.
if(sXCode=="IAG")
{
if(IAGsales.is_open()==true){
IAGsales.close();
}
IAGsales.open("Datafolder/IAG/sales_index.txt");
if(!IAGsales)
{
cout << IAGsales<<" :File not found!!" << endl;
system("PAUSE");
exit(1);
}
// Read IAG file names.
while(!IAGsales.eof())
{
getline(IAGsales, sFileName);
if(sFileName.size() > 0)
{ //cout<<"before: "<< sFilePath <<endl;
string sFilePath = "Datafolder/IAG/";
sFilePath = sFilePath.append(sFileName);
cout<<"after append: "<< sFilePath <<endl;
// Read the csv file
infile.open(sFilePath);
if(! infile)
{
cout << sFileName<<": File not found!!" << endl;
exit(1);
}
getline(infile, record);//first line
getline(infile, record);//second line
while(! infile.eof())
{
getline(infile, record);
if(record.size() > 0)
{
S1.readfile(record, S1);
data.insert(S1);
counter ++;
}
}//while(! infile.eof())
infile.close();
// Insert to Map
mapIAG.insert(pair<string,Vector<Stock>>(sFileName,data));
}
}
IAGsales.clear();
IAGsales.seekg(0,ios::beg);
Tempsales = &IAGsales;
//cout<<"test1";
//IAGsales.close();
}
else if(sXCode=="CBA")
{
if(CBAsales.is_open()==true){
CBAsales.close();
}
CBAsales.open("Datafolder/CBA/sales_index.txt");
if(!CBAsales)
{
cout << CBAsales<<" : File not found!!" << endl;
system("PAUSE");
exit(1);
}
// Read IAG file names.
while(!CBAsales.eof())
{
getline(CBAsales, sFileName);
if(sFileName.size() > 0)
{
string sFilePath = "Datafolder/CBA/";
sFilePath = sFilePath.append(sFileName);
// Read the csv file
infile.open(sFilePath);
if(! infile)
{
cout << sFileName<<": File not foud!!!" << endl;
exit(1);
}
getline(infile, record);//first line
getline(infile, record);//second line
while(! infile.eof())
{
getline(infile, record);
if(record.size() > 0)
{
S1.readfile(record, S1);
data.insert(S1);
counter ++;
}
}//while(! infile.eof())
infile.close();
// Insert to Map
mapIAG.insert(pair<string,Vector<Stock>>(sFileName,data));
}
}
CBAsales.clear();
CBAsales.seekg(0,ios::beg);
Tempsales = &CBAsales;
//cout<<"test2";
}
else
{
if(NABsales.is_open()==true){
NABsales.close();
}
NABsales.open("Datafolder/NAB/sales_index.txt");
if(!NABsales)
{
cout << NABsales<<" : File not found!!!!" << endl;
system("PAUSE");
exit(1);
}
// Read IAG file names.
while(!NABsales.eof())
{
getline(NABsales, sFileName);
if(sFileName.size() > 0)
{
string sFilePath = "Datafolder/NAB/";
sFilePath = sFilePath.append(sFileName);
// Read the csv file
infile.open(sFilePath);
if(! infile)
{
cout << sFileName<<": File not foud!!" << endl;
exit(1);
}
getline(infile, record);//first line
getline(infile, record);//second line
while(! infile.eof())
{
getline(infile, record);
if(record.size() > 0)
{
S1.readfile(record, S1);
data.insert(S1);
counter ++;
}
}//while(! infile.eof())
infile.close();
// Insert to Map
mapIAG.insert(pair<string,Vector<Stock>>(sFileName,data));
}
}
NABsales.clear();
NABsales.seekg(0,ios::beg);
Tempsales = &NABsales;
//cout<<"test3";
}
highestPrice = (data.getvalue(0)).getprice();//Initialise highest price
lowestPrice = (data.getvalue(0)).getprice();//Initialise lowest price
(data.getvalue(0)).gettime(time1, data.getvalue(0));//Initialise time1
cout<<"Enter the date of transaction:" <<endl;
while(!Tempsales->eof()){
getline(*Tempsales,record);
cout<<record<<endl;
}
cin>>sInputDate;
cout<<"Choose from options 1 to 4: "<<endl;
cout << "Enter 1 to get the highest stock price & time:" << endl;
cout << "Enter 2 to get the lowest stock price & time:" << endl;
cout << "Enter 3 to output the csv file: " << endl;
cout << "Enter 4 to exit from the program:" << endl;
cin >> option;
// Get the vector from Map based on Date.
if(sXCode=="IAG")
{
it = mapIAG.find(sInputDate);
data = it->second;
}
else if(sXCode=="CBA")
{
it = mapIAG.find(sInputDate);
data = it->second;
}
else
{
it = mapIAG.find(sInputDate);
data = it->second;
}
}
Stock is a Vector.
Related
I'm not quite getting a structure search. I have a task, I need to search for students by full name, year of birth, group number or course number. I can search by group number or course number, but the search by full name and date of birth is problematic.
Here are my code and my input file. (I'm sorry if my code is unprofessional, I'm just learning and I need to pass this task, but I'm having no luck and I have no one to turn to for help)
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct Student
{
string name;
string yearob;
int course;
int group;
};
ostream& operator<<(ostream& out, const Student obj)
{
out << obj.name << " " << obj.yearob << " " << obj.group << " " << obj.course;
return out;
}
int main()
{
setlocale(LC_ALL, "");
int search = 0;
string name_s, yearob_s;
int course_s, group_s;
int chek = 1;
while (chek == 1)
{
cout << "Enter 1 to start, 0 to exit > ";
cin >> chek;
switch (chek)
{
case(0):
break;
case(1):
{
int leng = 0;
string s;
ifstream fle("input.txt");
while (getline(fle, s))
{
leng += 1;
}
Student* list = new Student[leng];
int a = 0;
fle.close();
ifstream file("input.txt");
string ss, buff;
while (getline(file, s))
{
buff.assign(s);
list[a].course = buff[0] - '0';
buff.erase(0, 2);
ss += buff[0];
ss += buff[1];
list[a].group = stoi(ss);
ss.clear();
buff.erase(0, 3);
for (int i = 0; i < 4; i++)
list[a].yearob += buff[i];
buff.erase(0, 5);
list[a].name.assign(buff);
a += 1;
buff.clear();
}
cout << "What parameter should be used to find students: 1 - by name, 2 - by year of birth, 3 - by course, 4 - by group number: ";
cin >> search;
switch (search) {
case(1):
cin >> name_s;
for (int i = 0; i <= leng; i++) {
if (list[i].name.find(name_s, 10)) {
cout << list[i].name << ", " << list[i].course << " course, " << list[i].group << " group, " << list[i].yearob << " year of birth; " << endl;
}
else {
continue;
}
}
case(2):
cin >> yearob_s;
for (int i = 0; i <= leng; i++) {
if (list[i].yearob.find(yearob_s, 5)) {
cout << list[i].name << ", " << list[i].course << " course, " << list[i].group << " group, " << list[i].yearob << " year of birth; " << endl;
}
else {
continue;
}
}
case(3): {
cin >> course_s;
for (int i = 0; i <= leng; i++) {
if (course_s == list[i].course) {
cout << list[i].name << ", " << list[i].course << " course, " << list[i].group << " group, " << list[i].yearob << " year of birth; " << endl;
}
else {
continue;
}
}
}
case(4):
cin >> group_s;
for (int i = 0; i <= leng; i++) {
if (group_s == list[i].group) {
cout << list[i].name << ", " << list[i].course << " course, " << list[i].group << " group, " << list[i].yearob << " year of birth; " << endl;
}
else {
continue;
}
}
}
file.close();
continue;
}
default:
{
cout << "Input error" << endl;
continue;
}
}
}
}
Input file:
2 01 1999 Cody Hoyt
2 01 2002 Danielle Robyn Diaz
3 01 1999 Mayra Marie Collins
2 05 2000 Marc Nunez
4 05 2000 Tricia Gilmore
5 04 2001 Dale Lucas
1 01 1998 Ruby Merritt
2 01 2001 Tabitha Jenkins
4 02 1995 George Kris Oneill
2 03 1999 Bonnie Blair
Just maybe a shorter version of your code. I provide it not as a solution to your main question (because the following code is pretty advanced), but as an example of how you could avoid repeating code and making big nested constructions.
Here I moved out the code of reading students from a file into a separate function, and inside it should easily read each student using operator>> from a file. Similarly you can define operator<< to specify in which format you want students to be printed.
The repetitive code of printing filtered students is moved into a single function, that iterates all students and prints only pass a given test. You then give this test as a lambda function in each branch of switch operator
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <functional>
using namespace std;
struct Student
{
string name;
string yearob;
int course;
int group;
};
ostream& operator<<(ostream& out, const Student& stud)
{
out << stud.name << ", " << stud.course << " course, " << stud.group << " group, " << stud.yearob << " year of birth; " << endl;
return out;
}
istream& operator>>(istream& in, Student& stud)
{
in >> stud.course >> stud.group >> stud.yearob >> stud.name;
return in;
}
vector<Student> read_students_file(const string& filename) {
vector<Student> students;
ifstream file(filename);
while (file)
{
students.push_back({}); // insert empty student
file >> students[students.size() - 1]; // fill student
}
file.close();
return students ;
}
void print_filtered(const vector<Student>& students, function<bool(const Student&)> should_print) {
for (const Student& student : students) {
if (should_print(student)) {
cout << student;
}
}
}
int main()
{
setlocale(LC_ALL, "");
while (true)
{
cout << "Enter 1 to start, 0 to exit > ";
int check;
cin >> check;
if (check == 0) {
break;
} else if (check != 1) {
continue;
}
vector<Student> students = read_students_file("input.txt");
cout << "What parameter should be used to find students: 1 - by name, 2 - by year of birth, 3 - by course, 4 - by group number: ";
int search_variant;
cin >> search_variant;
switch (search_variant) {
case(1): {
string find_name;
cin >> find_name;
print_filtered(students,
[&](auto& student){ return student.name == find_name; });
break;
}
case(2): {
string find_yearob;
cin >> find_yearob;
print_filtered(students,
[&](auto& student){ return student.yearob == find_yearob; });
break;
}
case(3): {
int find_course;
cin >> find_course;
print_filtered(students,
[&](auto& student){ return student.course == find_course; });
break;
}
case(4): {
int find_group;
cin >> find_group;
print_filtered(students,
[&](auto& student){ return student.group == find_group; });
break;
}
default: {
cout << "Input error" << endl;
continue;
}
}
}
}
Ok so, this is gonna be a long one...
Explanation of what the project is supposed to do:
My final project is a bank teller system that stores all the account related data on a text files.
The file in question, "accounts.txt", is where all the account data is stored. It is read and write, and behaves strangely when an ofstream is introduced...
The "accounts.txt" file is formated as follows
01481
554-00-8336
Jane Jones
1483 N. RealmSecond Ave., Burlington, VT 05401
564 425 5052
02650
727-22-1072
Jennifer Armstrong
1450 W. Main Rd., Burlington, VT 05401
202 545 5485
it continues repeating the same ordered sets of information...
One of the core parts of the program relies on reading these values into 5 separate arrays, each pertaining to type of data (name, address, etc).
I am going to dump the entire program because I think it might be necessary to fix the problem, just understand that the main function in question is addAccount() and is located at the bottom.
Note that the purpose of this function is to read the entire accounts.txt file line by line into memory, determine at what point the arrays used to store the file are being filled with empty data (we were told by the course instructor to make the array size 100, meaning that most of the data read into the array is empty space) get the desired account information from the user, update the file in memory, and rewrite the file...
also note that the file format was predetermined by the course instructor
The code:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
const int TELLERS_SIZE = 5;
const int ACCOUNTS_SIZE = 100;
const string TELLERS_FILE = "tellers.txt";
const string ACCOUNTS_FILE = "accounts.txt";
int beginMenu();
bool login(string fileName);
int baseMenu();
void searchAccount(string fileName);
void addAccount(string fileName);
int main() {
int beginSelection;
do {
beginSelection = beginMenu();
if (beginSelection == 2) {
return 0;
}
bool loginIsTrue = login(TELLERS_FILE);
while (loginIsTrue) {
int baseSelection = baseMenu();
if (baseSelection == 1) {
addAccount(ACCOUNTS_FILE);
}
if (baseSelection == 4) {
searchAccount(ACCOUNTS_FILE);
}
if (baseSelection == 8) {
loginIsTrue = false;
}
}
} while (beginSelection == 1);
}
// Print the fisrt menu and return selection
int beginMenu() {
// Establish return value and validation
int menuSelection;
string userInput;
bool menuSelectionIsValid = false;
// Print options
do {
cout << "\n";
cout << "[1] Login" << "\n";
cout << "[2] Quit" << "\n";
cout << "Please enter a selection";
cout << "\n";
getline(cin, userInput);
// Validate input
if (userInput == "1") {
menuSelectionIsValid = true;
menuSelection = 1;
}
else if (userInput == "2") {
menuSelectionIsValid = true;
menuSelection = 2;
}
else {
cout << "Invalid input!" << "\n";
}
} while (!menuSelectionIsValid);
return menuSelection;
}
// Perform login and return true or false
bool login(string fileName) {
// Establish variables
string username[TELLERS_SIZE];
string password[TELLERS_SIZE];
string usernameInput;
string passwordInput;
bool loginIsValid = false;
// Establish fin
ifstream fin(fileName);
if (!fin.is_open()) {
cout << "File cannot be opened " << fileName << "\n";
return false;
}
// Read tellers.dat
for (int i = 0; i < TELLERS_SIZE; i++) {
fin >> username[i];
fin >> password[i];
}
// Read user input
cout << "\n";
cout << "Username: ";
getline(cin, usernameInput);
cout << "Password: ";
getline(cin, passwordInput);
// Verify login information
for (int i = 0; i < TELLERS_SIZE; i++) {
if (username[i] == usernameInput && password[i] == passwordInput) {
cout << "Login succesful" << "\n";
loginIsValid = true;
return true;
}
}
// Inform user of error
cout << "Invalid username or password!" << "\n";
return false;
}
// Print base functions menu and return selection
int baseMenu () {
// Establish return value and validation
int menuSelection;
string userInput;
bool menuSelectionIsValid = false;
do {
// Print options
cout << "\n";
cout << "[1] Add Account" << "\n";
cout << "[2] Remove Account" << "\n";
cout << "[3] Update Account" << "\n";
cout << "[4] Search Account" << "\n";
cout << "[5] Make A Deposit" << "\n";
cout << "[6] Make A Withdrawal" << "\n";
cout << "[7] Check Balance" << "\n";
cout << "[8] Logout" << "\n";
cout << "Please enter a selection";
cout << "\n";
getline(cin, userInput);
// Validate input
if (userInput == "1") {
menuSelectionIsValid = true;
menuSelection = 1;
}
else if (userInput == "2") {
menuSelectionIsValid = true;
menuSelection = 2;
}
else if (userInput == "3") {
menuSelectionIsValid = true;
menuSelection = 3;
}
else if (userInput == "4") {
menuSelectionIsValid = true;
menuSelection = 4;
}
else if (userInput == "5") {
menuSelectionIsValid = true;
menuSelection = 5;
}
else if (userInput == "6") {
menuSelectionIsValid = true;
menuSelection = 6;
}
else if (userInput == "7") {
menuSelectionIsValid = true;
menuSelection = 7;
}
else if (userInput == "8") {
menuSelectionIsValid = true;
menuSelection = 8;
}
else {
cout << "Invalid input!" << "\n";
}
} while (!menuSelectionIsValid);
return menuSelection;
}
// Locate account and print relevant information
void searchAccount(string fileName) {
// Establish arrays
string accountNumber[ACCOUNTS_SIZE];
string accountSSN[ACCOUNTS_SIZE];
string accountName[ACCOUNTS_SIZE];
string accountAddress[ACCOUNTS_SIZE];
string accountPhone[ACCOUNTS_SIZE];
// Establish validation variables
string userInput;
bool accountFound = false;
// Establish and validate fin
ifstream fin(fileName);
if (!fin.is_open()) {
cout << "File cannot be opened " << fileName << "\n";
}
// Get desired account number
cout << "\n";
cout << "Account number: ";
getline(cin, userInput);
// Read information from file
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
getline(fin, accountNumber[i]);
getline(fin, accountSSN[i]);
getline(fin, accountName[i]);
getline(fin, accountAddress[i]);
getline(fin, accountPhone[i]);
}
// Search for account
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
if (accountNumber[i] == userInput && userInput != "") {
accountFound = true;
}
// Display account information
if (accountFound == true) {
cout << "Account Found" << "\n";
cout << "Displaying account information" << "\n" << "\n";
cout << accountNumber[i] << "\n";
cout << accountSSN[i] << "\n";
cout << accountName[i] << "\n";
cout << accountAddress[i] << "\n";
cout << accountPhone[i] << "\n";
break;
}
}
// Inform user that account doesnt exist
if (accountFound == false) {
cout << "Unable to find account: " << userInput << "\n";
}
}
void addAccount(string fileName) {
string accountNumber[ACCOUNTS_SIZE];
string accountSSN[ACCOUNTS_SIZE];
string accountName[ACCOUNTS_SIZE];
string accountAddress[ACCOUNTS_SIZE];
string accountPhone[ACCOUNTS_SIZE];
ifstream fin(fileName);
// ofstream fout(fileName);
string userAccountNumber;
string userAccountSSN;
string userAccountName;
string userAccountAddress;
string userAccountPhone;
bool accountNumberIsTaken = true;
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
getline(fin, accountNumber[i]);
getline(fin, accountSSN[i]);
getline(fin, accountName[i]);
getline(fin, accountAddress[i]);
getline(fin, accountPhone[i]);
}
do {
accountNumberIsTaken = false;
cout << "\n";
cout << "Enter desired account number: ";
getline(cin, userAccountNumber);
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
if (userAccountNumber == accountNumber[i] || userAccountNumber == "") {
cout << "That account number is already in use" << "\n";
accountNumberIsTaken = true;
break;
}
}
} while (accountNumberIsTaken);
/*
cout << "Enter SSN: ";
getline(cin, userAccountSSN);
cout << "Enter full name: ";
getline(cin, userAccountName);
cout << "Enter address: ";
getline(cin, userAccountAddress);
cout << "Enter phone number: ";
getline(cin, userAccountPhone);
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
if (accountNumber[i] == "") {
cout << "empty space found at" << i;
accountNumber[i] = userAccountNumber;
accountSSN[i] = userAccountSSN;
accountName[i] = userAccountName;
accountAddress[i] = userAccountAddress;
accountPhone[i] = userAccountPhone;
break;
}
}
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
fout << accountNumber[i] << "\n";
fout << accountSSN[i] << "\n";
fout << accountName[i] << "\n";
fout << accountAddress[i] << "\n";
fout << accountPhone[i] << "\n";
}
*/
}
The issue:
The base code, without anything commented out, does not work at all.
Both the accountSearch() and addAccount() functions which rely on reading "accounts.txt" will report that an account number clearly present on "accounts.dat" is not present.
After commenting out ofstream fout(fileName); and the lower part of the addAccount() that relies on writing to the file AND making a slight change to the "accounts.txt" file and saving changes, things start working again
This project is being written in Visual Studio 2019.
Apologies if this is a poor explanation. Please ask for clarification if necessary.
You can't have filename opened as both an ifstream and an ofstream at the same time! So, move your declaration/constructor for fout to after the code for reading fin, like this:
void addAccount(string fileName) {
string accountNumber[ACCOUNTS_SIZE];
string accountSSN[ACCOUNTS_SIZE];
string accountName[ACCOUNTS_SIZE];
string accountAddress[ACCOUNTS_SIZE];
string accountPhone[ACCOUNTS_SIZE];
ifstream fin(fileName);
// ofstream fout(fileName); /// CANNOT BE HERE!
string userAccountNumber;
///... Here, have all your reading and input code (as it is) …
///...
///... Finished reading, etc., so CLOSE "fin" then get the "fout" …
fin.close();
ofstream fout(fileName); // NOW we can create the output stream!
///... and use your existing code to do the writing
for (int i = 0; i < ACCOUNTS_SIZE; i++) {
fout << accountNumber[i] << "\n";
fout << accountSSN[i] << "\n";
fout << accountName[i] << "\n";
fout << accountAddress[i] << "\n";
fout << accountPhone[i] << "\n";
}
fout.close(); /// When finished, CLOSE the file!
}
I have been having some trouble on my code for my final project. I have looked everwhere and I am having a hard time so I thought I would ask on here. I need to make sure that when all the names are listed in this phonebook that they will come out in alphabetical order but as of yet I am unsure how to do that. Here is the program that i currently have! Thank you!
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
struct Contact {
string name, number, notes;
};
Contact contactList[100];
int rec_num = 0;
int num_entries;
string toUpper (string S) {
for (int i= 0; i < S.length(); i++)
S[i] = toupper(S[i]);
return S;
}
void ReadFile () {
string S;
fstream input("PhoneData.txt");
while (!input.eof() && !input.fail()){
input >> contactList[rec_num].name >> contactList[rec_num].number;
getline(input, S);
contactList[rec_num].notes = S;
rec_num++;
}
cout << "Book read." << endl;
num_entries = rec_num;
input.close();
return;
}
// stores phonebook for future runs of the program
void StoreFile () {
fstream F ("PhoneData.txt");
rec_num = 0;
while (rec_num < num_entries){
F << contactList[rec_num].name << " " << contactList[rec_num].number << " " << contactList[rec_num].notes << " " << endl;
rec_num++;
}
cout << "Phonebook stored." << endl;
return;
}
// adds contact
void add_name(string name, string number, string notes){
contactList[num_entries].name = name;
contactList[num_entries].number = number;
contactList[num_entries].notes = notes;
num_entries++;
return;
}
// finds contact
void retrieve_name(string name){
for (int i = 0; i < num_entries; i++){
if (toUpper(contactList[i].name) == toUpper(name)) {
cout << "Phone Number: " << contactList[i].number << endl << "Notes: " << contactList[i].notes << endl;
return;
}
}
cout << "Name not found" << endl;
return;
}
// updates contact info
void update_name(string name){
string new_number;
string new_notes;
cout<<"New Phone Number"<<endl;
cin>> new_number;
cout<<"New Notes"<<endl;
cin>> new_notes;
for (int i = 0; i < num_entries; i++){
if (toUpper(contactList[i].name) == toUpper(name)) {
contactList[i].number = new_number;
contactList[i].notes = new_notes;
return;
}
}
}
// deletes contact
void delete_name(string name){
int INDEX=0;
for (int i = 0; i < num_entries; i++){
if (toUpper(contactList[i].name) == toUpper(name)) {
INDEX=i;
for ( int j=INDEX; j < num_entries; j++ ){
contactList[j].name = contactList[j+1].name;
contactList[j].number = contactList[j+1].number;
contactList[j].notes = contactList[j+1].notes;
}
}
}
return;
}
void listAllContacts() {
int i = 0;
while (i < num_entries) {
cout << "-- " << contactList[i].name << " " << contactList[i].number << endl << "-- " << contactList[i].notes << endl << endl;
i++;
}
}
int main(){
string name, number, notes;
string FileName;
char command;
FileName = "PhoneData.txt";
ReadFile ();
cout << "Use \"e\" for enter, \"f\" for find, \"l\" for list, \"d\" for delete, \"u\" for update, \"s\" for send message, \"q\" to quit." << endl << "Command: ";
cin >> command;
while (command != 'q'){
switch (command){
case 'e': cin >> name; cout << "Enter Number: ";
cin >> number; cout << "Enter Notes: ";
cin.ignore(); getline(cin, notes);
add_name(name, number, notes); break;
case 'f': cin >> name; retrieve_name(name); break;
case 'l':
listAllContacts(); break;
case 'u': cin>> name; update_name (name);break;
case 'd' : cin>> name; delete_name (name); break;
}
cout << "\nCommand: "; cin >> command;
}
StoreFile();
cout << "All set !";
return 0;
}
Given
Contact contactList[100];
int num_entries;
you can use std::sort to sort the list of contacts. std::sort has two forms. In the first form, you can use:
std::sort(contanctList, contactList+num_entries);
if you define operator< for Contact objects.
In the second form, you can use:
std::sort(contanctList, contactList+num_entries, myCompare);
if you define myCompare to be callable object that can compare two Contact objects.
To use the first form, change Contact to:
struct Contact {
string name, number, notes;
bool operator<(Contact const& rhs) const
{
return (this->name < rhs.name);
}
};
If you want to the comparison of names to be case insensitive, convert both names to either uppercase or lowercase and them compare them.
I am working on a project using arrays and structures to further my poor programming skillz. I cannot figure out how to shift the array to the right. In the function editContact, I am trying to sort the contacts by last name after the name is changed. The plan is to shift the array right and put the edited contact in the appropriate alphabetized spot.
Do I need to put
"int numContacts=0;
Contact entries[500];"
into a structure?
This is the code I am struggling with specifically:
void shiftUp(int startIndex) {
entries = new int[entries.Length];
for (int i = startIndex; i < entries.Length - 1; i++)
{
entries[i] = entries[i + 1];
}
entries[entries.Length - 1] = entries[0];
}
This is the error message I receive from the compiler:
addressbook.cpp:311: error: request for member 'Length' in 'entries', which is of non-class type 'Contact [500]'
addressbook.cpp:311: error: incompatible types in assignment of 'int*' to 'Contact [500]'
addressbook.cpp:313: error: request for member 'Length' in 'entries', which is of non-class type 'Contact [500]'
addressbook.cpp:318: error: request for member 'Length' in 'entries', which is of non-class type 'Contact [500]'
This is the bulk of the program:
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
/*structures*/
struct Contact {
string firstName;
string lastName;
string middleInitial;
string phoneNumber;
string streetAddress;
string city;
string state;
string zipCode;
};
int numContacts=0;
Contact entries[500];
/*prototypes*/
int mainMenu();
int searchResults(string searchTerm);
void searchContacts();
void contactDetail(int contactIndex);
void editContact(int contactIndex);
bool deleteContact(int contactIndex);
void listContacts();
void addContact();
void shiftUp(int startIndex);
void shiftDown(int startIndex);
void saveData();
void loadData();
int findLocation(string lastName);
void saveContact(ofstream dataFile, Contact& newContact);
void loadContact(ifstream dataFile, Contact& newContact);
/*consts*/
const int SEARCH_CMD = 1;
const int LIST_CMD = 2;
const int ADD_CMD = 3;
const int EXIT_CMD = 4;
int main(){
loadData();
int selection;
do {
selection = mainMenu();
switch(selection) {
case SEARCH_CMD:
searchContacts();
break;
case LIST_CMD:
listContacts();
break;
case ADD_CMD:
addContact();
break;
}
} while (selection !=EXIT_CMD);
saveData();
}
int mainMenu(){
/*show the menu*/
cout << "**** Welcome to AddressBook ****" << endl << "1. Search for Contacts" << endl << "2. List Contacts" << endl << "3. Add New Contact" << endl << "4. Exit" << endl << "Enter Selection:";
/*input the selection*/
int selection;
while(1) {
cin >> selection;
/*validate the selection and reprompt if neccessary*/
if ((selection >4) || (selection < 1)) {
cout << "This is not a valid menu option. Please try again.";
break;
}
if ((selection <=4) && (selection >=1)) {
break;
}
}
/* return a valid selection */
return(selection);
}
void searchContacts() {
/*output "Enter search term: " */
cout << "Enter search term: ";
/*input the string searchTerm */
string searchTerm;
cin >> searchTerm;
/* call searchResults(searchTerm) */
searchResults(searchTerm);
}
int searchResults(string searchTerm){
/* output "Search Results:"*/
int noMatch =0;
cout << "Search Results: " << endl;
/*loop through every contact*/
int contactsIndex[500];
for (int i=0; i<=numContacts; i++) {
if (entries[i].lastName == searchTerm) {
noMatch++;
cout << noMatch << ". " << entries[i].firstName << " " << entries[i].lastName << " " << entries[i].phoneNumber << endl;
contactsIndex[noMatch] = i;
}
}
if (noMatch == 0) {
cout << "No match found\n";
return(1);
}
int selectContact;
cout << "Select a contact (or M for Main Menu): ";
cin >> selectContact;
if ((selectContact > 0) && (selectContact <= noMatch)) {
contactDetail(contactsIndex[selectContact]);
}
if ((selectContact=='m') || (selectContact=='M')) {
}
/* compare each field (using substr) to searchTerm*/
/* if the searchTerm is in any field, output the contact*/
/* save the index of the contact to contactsIndex array*/
/* output "Select a Contact (or M for Main Menu): "*/
/*input selection*/
/*if selection is a contact number, call contactDetail(contactsIndex[selection-1]);*/
}
void contactDetail(int contactsIndex){
/*show the indicated contact - addressBook.entries[contactIndex]*/
cout << entries[contactsIndex].firstName << " " << entries[contactsIndex].middleInitial << ". " << entries[contactsIndex].lastName << endl;
cout << entries[contactsIndex].streetAddress << endl << entries[contactsIndex].city << ", " << entries[contactsIndex].state << ", " << entries[contactsIndex].zipCode << endl;
cout << "Phone: " << entries[contactsIndex].phoneNumber << endl;
/* output "Select E for Edit, D to delete or M for Main Menu: "*/
cout << "Select E for Edit, D to delete, or M for Main Menu:" ;
/* read selection*/
char menuSelection;
cin >> menuSelection;
/*if selection is E*/
if (menuSelection == 'E') {
editContact(contactsIndex);
}
/* editContact(contactIndex)*/
/*if selection is D*/
if (menuSelection == 'D') {
bool retValue;
retValue = deleteContact(contactsIndex);
}
/* retValue = deleteContact(contactIndex)*/
/*else m, break*/
if (menuSelection == 'M') {
}
/* loop while retValue is false*/
}
void editContact(int contactsIndex){
/*output "**Press Enter to leave field unchanged. Enter a new value to change it.**"*/
cout << "Press Enter to leave field unchanged. Enter a new value to change it." << endl;
/*use addressBook.entries[contactIndex]*/
string editEntry;
cout << "First Name: ";
cin >> editEntry;
entries[contactsIndex].firstName = editEntry;
cout << "Last Name: ";
cin >> editEntry;
entries[contactsIndex].lastName = editEntry;
cout << "Middle Initial: ";
cin >> editEntry;
entries[contactsIndex].middleInitial = editEntry;
cout << "Phone Number: ";
cin >> editEntry;
entries[contactsIndex].phoneNumber = editEntry;
cout << "Street Address: ";
cin >> editEntry;
entries[contactsIndex].streetAddress = editEntry;
cout << "City: ";
cin >> editEntry;
entries[contactsIndex].city = editEntry;
cout << "State: ";
cin >> editEntry;
entries[contactsIndex].state = editEntry;
cout << "Zip Code: ";
cin >> editEntry;
entries[contactsIndex].zipCode = editEntry;
/* prompt for each field */
/* input fields*/
/* if input is not empty*/
/* set corresponding field with input*/
/* shiftUp(contactIndex)*/
shiftUp(contactsIndex);
int newIndex;
newIndex = findLocation (entries[contactsIndex].lastName);
/* newIndex = findLocation(lastName)
if (newIndex != numContacts) {
shiftDown(newIndex);
}*/
/* if newIndex != numContacts*/
/* shiftDown(newIndex)*/
/* add the new contact at [newindex]*/
/* output "Select E to Edit or M for Main Menu: "*/
/* if selection is Edit*/
/*loop*/
}
bool deleteContact(int contactIndex){
/*output "Are you sure you want to delete this contact? (Y/N): "*/
/*read selection*/
/*validate selection*/
/* if yes*/
/*shiftUp(contactIndex)*/
/* output "Contact deleted! Press any key to return to main menu."*/
/*return true - means contact was deleted*/
/*else if No*/
/*return false*/
return(false);
}
void listContacts(){
/*output "Contact List: "*/
cout << "Contact List: " << endl;
/* for all contacts:*/
for (int i=0; i < numContacts; i++) {
cout << entries[i].firstName << " " << entries[i].middleInitial << ". " << entries[i].lastName << endl;
cout << entries[i].streetAddress << endl << entries[i].city << ", " << entries[i].state << ", " << entries[i].zipCode << endl;
cout << "Phone: " << entries[i].phoneNumber << endl << endl;
/* output firstName, lastName, and phone (formatted)*/
/* output "Select a Contact (or M for Main Menu): "*/
/*input selection*/
/*validate selection*/
/*if selection is a contact number, call contactDetail(contactsIndex[selection-1]);*/
}
}
void addContact(){
cout << "Add A Contact! Please enter each value as prompted." << endl;
/*
string newEntry;
cout << "First Name: ";
cin >> newEntry;
entries[contactsIndex].firstName = newEntry;
cout << "Last Name: ";
cin >> newEntry;
entries[contactsIndex].lastName = newEntry;
cout << "Middle Initial: ";
cin >> newEntry;
entries[contactsIndex].middleInitial = newEntry;
cout << "Phone Number: ";
cin >> newEntry;
entries[contactsIndex].phoneNumber = newEntry;
cout << "Street Address: ";
cin >> newEntry;
entries[contactsIndex].streetAddress = newEntry;
cout << "City: ";
cin >> newEntry;
entries[contactsIndex].city = newEntry;
cout << "State: ";
cin >> newEntry;
entries[contactsIndex].state = newEntry;
cout << "Zip Code: ";
cin >> newEntry;
entries[contactsIndex].zipCode = newEntry;
*/
/*First Name:*/
/*Last Name:*/
/*Middle Initial:*/
/*Phone Number:*/
/*Street Address:*/
/*City: */
/*State:*/
/*Zip Code:*/
/* add the new contact to the addressBook*/
/* newIndex = findLocation(lastName)*/
/* if newIndex != numContacts*/
/* shiftDown(newIndex)*/
/* add the new contact at [newindex]*/
/* addressBook.numContacts++*/
/*set contactIndex to index of added contact*/
/*Enter 'E' for Edit Again, 'D' to Delete, or 'M' for Main Menu: M*/
/*if selection is E*/
/* editContact(contactIndex)*/
}
void shiftDown(int startIndex) {
/*shift the addressBook.entries up */
/*starting at startIndex+1 through the end of the array (loop should loop from bottom)*/
/*addressBook.numContacts++;*/
}
void shiftUp(int startIndex) {
entries = new int[entries.Length];
for (int i = startIndex; i < entries.Length - 1; i++)
{
entries[i] = entries[i + 1];
}
entries[entries.Length - 1] = entries[0];
/*shift the addressBook.entries down */
/*starting at startIndex through the end of the array (loop should loop from top)*/
/*addressBook.numContacts--;*/
}
int findLocation(string lastName) {
/*go through the addressBook and find the first lastName that is greater than the lastName passed to the function*/
int nameOrder;
for (int i=0; lastName < entries[i].lastName; i++) {
nameOrder++;
}
/* if you reach the end of the array, return the number of the next available slot*/
return(nameOrder);
}
void loadData(){
string newContact;
ifstream dataFile;
dataFile.open("addressBook.dat");
/*open addressBook.dat for input. call stream dataFile*/
/*for loop until end of file using i as loop counter*/
if (dataFile.is_open()) {
for (int i=0;!dataFile.eof();i++) {
getline (dataFile,newContact);
entries[i].firstName = newContact;
cout << entries[i].firstName << endl;
getline (dataFile,newContact);
entries[i].lastName = newContact;
cout << entries[i].lastName << endl;
getline (dataFile,newContact);
entries[i].middleInitial = newContact;
getline (dataFile,newContact);
entries[i].phoneNumber = newContact;
getline (dataFile,newContact);
entries[i].streetAddress = newContact;
getline (dataFile,newContact);
entries[i].city = newContact;
getline (dataFile,newContact);
entries[i].state = newContact;
getline (dataFile,newContact);
entries[i].zipCode = newContact;
numContacts++;
}
}
else cout << "Unable to open file";
/*loadContact(dataFile, addressBook.entries[i]);*/
/*close addressBook.dat*/
dataFile.close();
}
Thanks for your help, this is the solution I ended up using
void shiftUp(int startIndex) {
/*shift the addressBook.entries up to delete entries*/
/*starting at startIndex+1 through the end of the array (loop should loop from bottom)*/
for (int i = startIndex; i <= numContacts; ++i ){
entries[i] = entries[i+1];
Technically, instead of this:
void shiftUp(int startIndex) {
entries = new int[entries.Length];
for (int i = startIndex; i < entries.Length - 1; i++)
{
entries[i] = entries[i + 1];
}
entries[entries.Length - 1] = entries[0];
}
do:
void shiftUp( int startIndex )
{
int const n = sizeof( entries )/sizeof( *entries );
for( int i = n - 1; i > startIndex; --i )
{
entries[i] = entries[i - 1];
}
}
Examine the differences to learn some new C++ things.
Instead of raw arrays, consider using C++ standard library containers like vector and map.
Raw arrays has some problems, including how to safely find the size.
With C++11 and later, instead of the above C expression consider using std::end(a) - std::begin(a), expressed as a function template (e.g. called size).
Also, you may or will discover that resorting by shifting for each new item, gives O(n2) time. Things just get slower and slower the more items you have. Unproportionally so.
This is also a good reason to use standard library containers.
They employ far more efficient strategies for keeping things sorted.
What i am trying to do is get user to enter a key code and if it matches to display the information on the data input file. I am getting this error which i have no idea what for.
std::out_of_range at memory location 0x0043f7c4..
Below is my input file and my code
HEA,EMA,British Airways,030,025
HEA,EMA,Thomas Cook Airlines,020,040
HEA,DUB,British Airways,420,450
HEA,DUB,Thomas Cook Airlines,400,550
EMA,BAR,British Airways,120,140
EMA,BAR,Thomas Cook Airlines,100,150
ROM,EMA,British Airways, 120,125
ROM,EMA,Thomas Cook Airlines,150,090
ROM,BAR,British Airways,106,050
ROM,BAR,Thomas Cook Airlines,100,080
BAR,HEA,British Airways,125,090
BAR,HEA,Thomas Cook Airlines,100,120
DUB,EMA,Thomas Cook Airlines,450,380
DUB,EMA,Thomas Cook Airlines,420,450
below is my C++ code
#include <vector>
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
//#include "TravelFunctions.h"
using namespace std;
vector<string>flightDetails;
vector<string>flightSearch;
string airportDepart;
string airportArrive;
bool errorArrive = false;
bool errorDepart = false;
string timeTaken;
int tax;
int cost;
bool needtoentercodes = false;
string entry;
int main()
{
// first i will read in the airport.txt data and store the information into a vector.
ifstream flightdata("flightinfo.txt");
string flightnextline;
if (!flightdata)
{
cout << "Cannot Open the file 'flightdata.txt'";
}
else
{
while (flightdata.good())
{
getline (flightdata, flightnextline);
flightDetails.push_back(flightnextline);
}
flightdata.close();
}
cout << " ___________________ " << endl;
cout << "| Airport Key Code |" << endl;
cout << "|EMA = East Midlands|" << endl;
cout << "|HEA = Heathrow |" << endl;
cout << "|BAR = Barcelona |" << endl;
cout << "|ROM = ROME |" << endl;
cout << "|DUB = DUBAI |" << endl;
cout << "| |" << endl;
cout << "|___________________|" << endl;
cout << endl;
cout << endl;
cout << endl;
entry = "Please enter the ID code of the starting destination.\n";
while (needtoentercodes == false)
{
cout<< entry;
cout << "Use the key above to see which airports are available. \n";
string userdepartid;
cin>> userdepartid;
bool k = false;
//VALIDATING USER INPUT FOR DEPARTURE AIRPORT CODE - As mentioned above, this little section validates the starting departure id code.
while (k==false){
if ((userdepartid != "HEA") && (userdepartid != "EMA") && (userdepartid != "DUB") && (userdepartid != "BAR") && (userdepartid != "ROM"))
{
cout << "You have entered an incorrect departure code.\nPlease Try Again...\n";
cin >> userdepartid;
}
else
{
k=true;
}
}
cout << "\n";
cout << "Please enter the code of the arrival destination.\n";
string userarrivalid;
cin >> userarrivalid;
//VALIDATING USER INPUT FOR ARRIVAL AIRPORT CODE - This little section of code validates the arrival id airport code inputted in by the user.
bool a = false;
while (a==false){
if ((userarrivalid != "HEA") && (userarrivalid != "EMA") && (userarrivalid != "ROM") && (userarrivalid != "DUB") && (userarrivalid != "BAR"))
{
cout << "You have entered an incorrect departure code.\nPlease Try Again...\n";
cin >> userarrivalid;
}
else
{
a=true;
}
}
int j = 1;
bool resultsfound = false;
cout << "\n";
//RETURN THE RESULTS AND PUT THE RESULTS IN AN ARRAY - This little section places the searched results in a unique vector which then can be used later on in the program.
for (int i=0; i < flightDetails.size(); i++)
{
string tempflightdata = flightDetails[i];
string departid = tempflightdata.substr(0,3);
string arrivalid = tempflightdata.substr(4,3);
if ((departid == userdepartid) && (arrivalid == userarrivalid))
{
cout << j << ":" << flightDetails[i] << "\n";
flightSearch.push_back(flightDetails[i]);
j++;
needtoentercodes = false;
}
else
{
entry = "| Incorrect Entry. No direct connections! |\nPlease enter the ID code of the starting destination.\n";
}
}
}
}
It's the old, old problem
while (flightdata.good())
{
getline (flightdata, flightnextline);
flightDetails.push_back(flightnextline);
}
flightdata.close();
should be
while (getline (flightdata, flightnextline))
{
flightDetails.push_back(flightnextline);
}
flightdata.close();
Your while loop goes round one too many times because flightdata is still good() even after you've read the last line, and so you end up adding a blank line to your flightDetails vector. Later when you do tempflightdata.substr(4,3); on a blank line this causes the out_of_range error you see.
Caveat, I've only looked at the code, not debugged it.