I am watching a youtube video from 2020 on how to make login system with c++. I have the exact same code as him but I have 1 error where when I save my first password everything works fine the password and user are saved as ID:1, but when I add another user the ID is set to -858993459.
Here's the code, it's only in main.cpp.
#include <iostream>
#include <fstream>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
class loginManager {
public:
loginManager() {
accessGranted = false;
}
void login() {
cout << "Enter your UserName and Password.\n";
cout << "UserName: ";
cin >> userNameAttempt;
int usrID = retriveFile(userNameAttempt, "users.dat");
if (usrID != 0) {
cout << "Password: ";
cin >> passwordAttempt;
int pswID = retriveFile(passwordAttempt, "passwords.dat");
if (usrID == pswID) {
cout << "Successfull login!\n";
accessGranted = true;
login();
}
else {
cout << "Wrong password!\nTry Again!\n\n";
login();
}
}
else {
cout << "Wrong username!\nTry Again!\n\n";
login();
}
}
void addUser(const string username, const string password) {
if (retriveFile(username, "users.dat") != 0) {
cout << "That username is already in use!" << endl;
return;
}
int id = 1 + getLastID();
saveFile(username, "users.dat", id);
saveFile(password, "passwords.dat", id);
}
int getLastID() {
fstream file;
file.open("users.dat", ios::in);
file.seekg(0, ios::end);
if (file.tellg() == 0) {
return 0;
}
string s;
for (int i = -1; s.find("#") == string::npos; i--) {
file.seekg(i, ios::end);
file >> s;
}
file.close();
s.erase(0, 5);
int id;
istringstream(s) >> id;
return id;
}
int retriveFile(string attempt, const char* pathFile) {
string line;
fstream file;
string currentChar;
long long eChar;
file.open(pathFile, ios::in);
while(1) {
file >> currentChar;
if (currentChar.find("#ID:") != string::npos) {
if (attempt == line) {
file.close();
currentChar.erase(0,4);
int id;
istringstream(currentChar) >> id;
return id;
}
else {
line.erase(line.begin(), line.end());
}
}
else {
istringstream(currentChar) >> eChar;
line += (char)decrypt(eChar);
currentChar = "";
}
if (file.peek() == EOF) {
file.close();
return 0;
}
}
}
void saveFile(string p_line, const char* pathFile, const int& id) {
fstream file;
file.open(pathFile, ios::app);
file.seekg(0, ios::end);
if (file.tellg() != 0) {
file << "\n";
}
file.seekg(0, ios::beg);
for (int i = 0; i < p_line.length(); i++) {
file << encrypt(p_line[i]);
file << "\n";
}
file << "#ID:" << id;
file.close();
}
long long encrypt(int p_letter) {
return powf(p_letter, 7) * 3 - 70;
}
long long decrypt(long long p_letter) {
return powf((p_letter + 70) / 3, 1/7.f);
}
private:
string userNameAttempt;
string passwordAttempt;
bool accessGranted;
};
int main() {
loginManager app;
app.addUser("Something", "Somethingelse");
app.login();
return 0;
}
Related
Is this correct?
Here Update is member function of Product class.
I am using this pointer(pointing to calling product object) to read objects stored in file over and over.
file.read((char *)this, sizeof(product));
Here if the class(see the update member function):
class product
{
int product_num;
string product_name;
int quantity;
float sell_p;
float buy_p;
int gst;
float total;
float profit;
public:
void calculate()
{
this->total = this->quantity * (this->sell_p);
this->profit = this->total - (this->buy_p * this->quantity) * (1 + this->gst / 100);
}
product()
{
product_num = 0;
product_name = "\0";
}
product(int p_num, string name, int quantity, float sell_p, float buy_p, int gst)
{
this->product_num = p_num;
this->product_name = name;
this->quantity = quantity;
this->sell_p = sell_p;
this->buy_p = buy_p;
this->gst = gst;
calculate();
}
void get_data()
{
cout << "Enter Serial Number: ";
cin >> this->product_num;
cout << "Enter Product Name(MAX LENGTH: 20): ";
cin>>this->product_name;
cout << "Enter Quantity: ";
cin >> this->quantity;
cout << "Enter Buying Price: ";
cin >> this->buy_p;
cout << "Enter GST: ";
cin >> this->gst;
cout << "Enter Selling Price: (Selling Price should be greater than " << (this->buy_p + (this->gst / 100) * this->buy_p) << " to turn profit)";
cin >> this->sell_p;
calculate();
}
void show_product()
{
cout << "Serial: " << this->product_num
<< "\nName: " << this->product_name
<< "\nQuantity: " << this->quantity
<< "\nSelling Price: " << this->sell_p
<< "\nBuying Price: " << this->buy_p
<< "\nGST: " << this->gst << endl;
}
bool remove_product(int x)
{
if (x > this->quantity)
return false;
this->quantity -= x;
return true;
}
int getSerialNumber()
{
return this->product_num;
}
string getName()
{
return this->product_name;
}
int getQuantity()
{
return this->quantity;
}
int getGST()
{
return this->gst;
}
float getTotal()
{
return this->total;
}
float getProfit()
{
return this->profit;
}
float getSellPrice()
{
return this->sell_p;
}
float getBuyPrice()
{
return this->buy_p;
}
bool isValid()
{
if (product_num == 0 || product_name == "\0")
return false;
return true;
}
void save()
{
ofstream fout;
fout.open("product.dat", ios::binary | ios::app);
if (!fout)
{
cout << "Failed To Open File!!\nExiting..";
exit(0);
}
else
{
fout.write((char *)this, sizeof(product));
}
fout.close();
}
void update()
{
int s_num = this->product_num;
fstream file;
file.open("product.dat", ios::binary | ios::ate | ios::in | ios::out);
if (!file)
{
cout << "Failed to open file!!!\nExiting...." << endl;
exit(0);
}
else
{
file.seekg(0);
file.read((char *)this, sizeof(product));
while (!file.eof())
{
if (s_num == this->product_num)
{
cout << "Product Detail: ";
this->show_product();
cout << "Enter the Values: " << endl;
cout << "Note: IF DONT WISH TO CHANGE KINDLY ENTER SAME VALUE.";
this->get_data();
file.seekp(-(sizeof(product)),ios::cur);
file.write((char *)this, sizeof(product));
break;
}
file.read((char *)this, sizeof(product));
}
}
file.close();
}
void remove_it()
{
int s_num = this->product_num;
ofstream fout;
ifstream fin;
fin.open("product.dat", ios::in | ios::binary);
if (!fin)
{
cout << "Failed to open file!!\nExiting...";
exit(0);
}
else
{
fout.open("temp.dat", ios::binary | ios::out);
fin.read((char *)this, sizeof(product));
while (!fin.eof())
{
if (!(s_num == this->product_num))
{
fout.write((char *)this, sizeof(product));
}
fin.read((char *)this, sizeof(product));
}
fin.close();
fout.close();
if(remove("product.dat") == 0)
cout<<"Sucessfully Deleted file\n";
else
cout<<"File Removal Failed\n";
if(rename("temp.dat", "product.dat") == 0)
cout<<"Successfully Renamed\n";
else
cout<<"Failed to Rename\n";
}
}
};
So I have a .txt file looking like this:
1:Meat Dish:Steak:11.5
2:Fish Dish:Fish and chips:12
The first number is the itemNo, 'Meat Dish' is my category, 'Steak' is my description and finally '11.5' is my price.
So basically I want to search for the itemNo and I want it to display the price from that line. This is what I have until now:
#include <iostream>
#include <fstream>
#include <string>
#include <vector> // We will use this to store Players
using std::string;
using std::ofstream;
using std::ifstream;
using std::cout;
using std::cin;
struct MenuList // Define a "Player" data structure
{
string itemNo;
string category;
string descript;
double price;
};
std::istream& operator>>(std::istream& infile, MenuList& menu)
{
// In this function we will define how information is inputted into the player struct
// std::cin is derived from the istream class
getline(infile, menu.itemNo, ':');
getline(infile, menu.category, ':');
getline(infile, menu.descript, ':');
infile >> menu.price;
// When we have extracted all of our information, return the stream
return infile;
}
std::ostream& operator<<(std::ostream& os, MenuList& menu)
{
// Just like the istream, we define how a player struct is displayed when using std::cout
os << "" << menu.itemNo << " " << menu.category << " - " << menu.descript;
// When we have extracted all of our information, return the stream
return os;
}
void Load(std::vector<MenuList>& r, string filename)
{
std::ifstream ifs(filename.c_str()); // Open the file name
if(ifs)
{
while(ifs.good()) // While contents are left to be extracted
{
MenuList temp;
ifs >> temp; // Extract record into a temp object
r.push_back(temp); // Copy it to the record database
}
cout << "Read " << r.size() << " records.\n\n";
}
else
{
cout << "Could not open file.\n\n";
}
}
void Read(std::vector<MenuList>& r) // Read record contents
{
for(unsigned int i = 0; i < r.size(); i++)
cout << r[i] << "\n";
}
void Search(std::vector<MenuList>& r) // Search records for name
{
string n;
cout << "Search for: ";
cin >> n;
for(int i = 0; i < r.size(); i++)
{
if(r[i].itemNo.find(n) != string::npos)
cout << r[i];
}
}
int main()
{
std::vector<MenuList> records;
Load(records, "delete.txt");
Read(records);
Search(records);
return 0;
}
I don't really know how to make it so it shows just the price without showing the whole line.
I have written my own code that reads in your text file and stores the information in a struct. Once you have a vector of MenuList, it is dead simple to only print what you want.
include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
struct MenuList // Define a "Player" data structure
{
string itemNo;
string category;
string descript;
double price;
};
void addToList(vector<MenuList*>& vector_menu_list, string& itemNo, string& category, string& descript, string& price)
{
MenuList* p_menu_list = new MenuList;
p_menu_list->itemNo = itemNo;
p_menu_list->category = category;
p_menu_list->descript = descript;
p_menu_list->price = std::stod(price);
vector_menu_list.push_back(p_menu_list);
}
vector<MenuList*> readFile(string filename, bool& error_encountered)
{
vector<MenuList*> vector_menu_list;
ifstream file;
file.open(filename);
if (file.is_open())
{
string itemNo;
string category;
string descript;
string price;
short number_of_colons_encountered = 0;
char c;
while (file.get(c))
{
if ('\n' != c && EOF != c)
{
if (':' == c)
{
number_of_colons_encountered++;
continue;
}
switch (number_of_colons_encountered)
{
case 0:
itemNo += c;
break;
case 1:
category += c;
break;
case 2:
descript += c;
break;
case 3:
price += c;
break;
default:
error_encountered = true;
file.close();
return vector_menu_list;
}
}
else
{
addToList(vector_menu_list, itemNo, category, descript, price);
itemNo.clear();
category.clear();
descript.clear();
price.clear();
number_of_colons_encountered = 0;
}
}
addToList(vector_menu_list, itemNo, category, descript, price);
error_encountered = false;
}
else
{
error_encountered = true;
}
file.close();
return vector_menu_list;
}
int main()
{
bool error_encountered;
vector<MenuList*> p_menu_list = readFile("menu list.txt", error_encountered);
if (true == error_encountered)
{
return -1;
}
cout << "List menu items:" << endl;
for (unsigned long long i = 0; i < p_menu_list.size(); i++)
{
cout << p_menu_list.at(i)->itemNo << " ";
cout << p_menu_list.at(i)->category << " ";
cout << p_menu_list.at(i)->descript << " ";
cout << p_menu_list.at(i)->price << endl;
}
cout << "\n\nHere are only the prices: " << endl;
for (unsigned long long i = 0; i < p_menu_list.size(); i++)
{
cout << p_menu_list.at(i)->price << endl;
}
for (unsigned long long i = 0; i < p_menu_list.size(); i++)
{
delete p_menu_list.at(i);
}
return 0;
}
I'm working on ATM machine code in C++. I know it is best to use a binary file and classes so that each account has exact same size in file even if it is empty. I'm looking for something very very simple.
I'm having problem with parsing comma delimited values in .txt file. Sometime I get values, sometime I get just the first value. I have spent days to figure out it's solution. I have searched the internet and stackoverflow almost every answer used vectors or other stuff.
I didn't use strcmp for array comparison instead created my own function to compare character to character.
From the look of the code, it seems I have done a lot just a little push is required. Kindly have a look at my code and let me know where am I wrong. I want to eliminate semantic error! And to have the following code amended for the achievement of expected results.
#include<iostream>
#include<conio.h>
#include<fstream>
#include<cstring>
#include<string>
#include<sstream>
#include<stdlib.h>
using namespace std;
void checkBalance();
void createAccount();
void deposit();
void withdraw();
void transfer();
void login();
void mainScreen();
void menuScreen();
// For file handling
void saveAccountToFile();
bool checkAccountExists(char*);
void loadAccount(char *);
void loadBeneficiary(char*);
bool compare(char *, char *);
const char * FILE_NAME = "accounts.txt";
char username[50];
char pin[5];
double balance = 0.0;
// Beneficiary Variables
char b_username[50];
char b_pin[5];
double b_balance = 0.0;
void menuScreen()
{
char opt;
do {
system("cls");
cout << "\n\n\t\t CMD - ATM";
cout << "\n\n\tMENU";
cout << "\n\n\t01. Check Balance";
cout << "\n\n\t02. Withdraw";
cout << "\n\n\t03. Deposite";
cout << "\n\n\t04. Transfer to Another account";
cout << "\n\n\t05. Logout";
opt = _getch();
switch (opt)
{
case '1':
checkBalance();
break;
case '2':
withdraw();
break;
case '3':
deposite();
break;
case '4':
transfer();
case '5':
cout << "\n\nThanks for using CMD ATM. Press any key to exit...";
_getch();
exit(1);
default:
cout << "\a\n\nIncorrect input. Press any key to try agian!";
_getch();
}
} while (opt != '5');
}
void mainScreen()
{
char opt;
do {
system("cls");
cout << "\n\n\t\t CMD - ATM";
cout << "\n\n\tMENU";
cout << "\n\n\t01. Create Account";
cout << "\n\n\t02. Login";
cout << "\n\n\t03. Exit";
opt = _getch();
switch (opt)
{
case '1':
createAccount();
break;
case '2':
login();
break;
case '3':
exit(1);
default:
cout << "\a\n\nIncorrect input. Press any key to try agian!";
_getch();
}
} while (opt != '3');
}
void saveAccountToFile() {
ofstream outFile;
outFile.open(FILE_NAME, ios::app);
if (outFile.is_open()) {
outFile << username << ',' <<
pin << ',' << balance << "\n";
}
outFile.close();
}
bool checkAccountExists(char * userName)
{
int i = 0;
char temp[50] = {'0'};
ifstream inFile;
string line;
inFile.open(FILE_NAME);
if (inFile.is_open()) {
while (getline(inFile, line)) {
stringstream ss(line);
string value;
while (getline(ss, value, ',')) {
if (i == 0) {
strcpy(temp,value.c_str());
if(compare(userName, temp)){
cout << "closing";
getchar();
inFile.close();
return true;
}
i = 1;
}
else if (i == 1) {
i = 2;
}
else if (i == 2) {
i = 0;
}
}
}
inFile.close();
}
return false;
}
void loadAccount(char * userName)
{
int i = 0;
ifstream inFile;
string line;
inFile.open(FILE_NAME);
if (inFile.is_open()) {
while (getline(inFile, line)) {
stringstream ss(line);
string value;
while (getline(ss, value, ',')) {
if (i == 0) {
strcpy(username, value.c_str());
i = 1;
}
else if (i == 1) {
strcpy(pin, value.c_str());
i = 2;
}
else if (i == 2) {
balance = atof(value.c_str());
i = 0;
}
if(compare(username,userName))
{
inFile.close();
break;
}
}
}
inFile.close();
}
}
void loadBeneficiary(char * userName)
{
int i = 0;
ifstream inFile;
string line;
inFile.open(FILE_NAME);
if (inFile.is_open()) {
while (getline(inFile, line)) {
stringstream ss(line);
string value;
while (getline(ss, value, ',')) {
if (i == 0) {
strcpy(b_username, value.c_str());
i = 1;
}
else if (i == 1) {
strcpy(b_pin, value.c_str());
i = 2;
}
else if (i == 2) {
b_balance = atof(value.c_str());
i = 0;
}
if(strcmp(b_username, userName)){
inFile.close();
break;
}
}
}
inFile.close();
}
}
void login()
{
char tempName[50];
char tempPin[5];
cout << "\n\nEnter user name: ";
cin.getline(tempName, sizeof(tempName));
if (checkAccountExists(tempName)) {
cout << "\n\nEnter user pin: ";
cin.getline(tempPin,sizeof(tempPin));
loadAccount(tempName);
if (compare(tempPin, pin)) {
cout << "\n\nLog in successfull!";
cout << "\n\nPress any key to continue...";
_getch();
menuScreen();
}else {
cout << "User name or pin incorrect!";
_getch();
}
}
else {
cout << "\n\nRecord not found. Press any key to continue...";
_getch();
}
}
void checkBalance()
{
system("cls");
cout << "\n\n\tUser name = " << username;
cout << "\n\n\tBalance = " << balance;
_getch();
}
bool compare(char * msg1, char * msg2){
int count = 0;
int size = sizeof(msg1);
if(sizeof(msg2) == size){
for(int i = 0; i < size; i++){
if(msg1[i]==msg2[i]){
count++;
}
}
if(count == size)
return true;
}
return false;
}
int main(int argc, char** argv) {
mainScreen();
getchar();
return 0;
}
TXT FILE
jhon,5155,99999.99
bot,4414,232323
theta,2111,34234
Regarding how to simplify the reading loop, how about something like
while (getline(inFile, line)) {
stringstream ss(line);
string value;
getline(ss, value, ',');
string name = value;
getline(ss, value, ',')
string pin = value;
getline(ss, value)
double balance = stod(value);
// Now use the name, pin and balance some way...
}
For when you only need the name you don't need to have the second and third getline call, just the first.
Also consider using structures to store the name, pin and balance, and then having a container (for example a vector) to stor the structures.
Also in the name of simplicity I suggest you read the file only once. Then loop over the vector to find the data you need.
Here is an alternative without using stringstream
while(getline(inFile,line,',')){
strcpy(username, line.c_str());
getline(inFile,line,',');
strcpy(pin, line.c_str());
getline(inFile,line,'\n');
balance = atof(line.c_str());
if(compare(username,userName)){
inFile.close();
break;
}else
continue;
}
I am a little curious why the program I wrote on Xcode with a mac runs fine, but when I try compiling on a windows system with visual studio,
I get following error:
c:\users\bryan\documents\visual studio
2010\projects\new\new\new.cpp(172): error C3861: 'transform':
identifier not found.
When I write transform anywhere in the program, in fact, it says the same message, as if transform is not a part of the std namespace. Here is my code if you would like to see for yourself:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <cctype>
using namespace std;
string getInput ();
ifstream * openInFile ();
int getShiftValue ();
void cypherMenu ();
void menu ();
string shiftCharacters (int shiftNum, ifstream * inFile);
string getOutput ();
ofstream * openOutFile ();
void printSentence (string outData, ofstream * outFile);
void notOption (string optionString);
string capitalize (string choice);
string option ();
int main() {
ifstream * inFile;
ofstream * outFile;
string inFileName, outFileName, outData, optionString, capOptionString;
int shiftNum = 0;
bool isOption = false;
while (capOptionString.compare("2") != 0 ||
capOptionString.compare("QUIT") != 0) {
do {
menu();
optionString = option();
capOptionString = capitalize(optionString);
if (capOptionString.compare("1") == 0 || capOptionString.compare("CAESAR")
== 0) {
isOption = true;
}
else if (capOptionString.compare("2") == 0 ||
capOptionString.compare("QUIT") == 0) {
isOption = false;
return 0;
}
else {
notOption(optionString);
}
}
while (!isOption);
cypherMenu();
inFile = openInFile();
shiftNum = getShiftValue();
outData = shiftCharacters(shiftNum, inFile);
inFile->clear();
inFile->close();
outFile = openOutFile();
printSentence(outData, outFile);
outFile->clear();
outFile->close();
}
return 0;
}
// Input Functions
string getInput () {
cout << "Enter an input file name: ";
string inFileName;
getline(cin, inFileName);
return inFileName;
}
string getOutput () {
string outFileName;
cout << "Enter an output file name: ";
getline(cin, outFileName);
cout << endl;
return outFileName;
}
ifstream * openInFile () {
ifstream * inFile;
bool isGood = false;
string inFileName;
inFile = new ifstream;
do {
inFileName = getInput();
inFile->open(inFileName.c_str());
if (inFile->fail()) {
cout << "Couldn't open file" << endl;
}
else {
isGood = true;
}
}
while (!isGood);
return inFile;
}
ofstream * openOutFile () {
ifstream testStream;
ofstream * outFile;
bool isUnique = false;
string fileName;
do {
fileName = getOutput();
testStream.clear();
testStream.open(fileName.c_str(), ios_base::in);
if (testStream.good()) {
cout << "The file already exists, please choose another"
<< endl;
testStream.clear();
testStream.close();
}
else {
isUnique = true;
testStream.clear();
testStream.close();
}
}
while (!isUnique);
outFile = new ofstream;
outFile->open(fileName.c_str());
return outFile;
}
int getShiftValue () {
int shiftNum;
string trash;
cout << "Please enter shift value: ";
cin >> shiftNum;
getline(cin, trash);
return shiftNum;
}
string option () {
string optionString;
getline(cin, optionString);
cout << endl;
return optionString;
}
// Data manipulation functions
string shiftCharacters (int shiftNum, ifstream * inFile){
string inData, outData, trash, tempString;
char outChar;
int idx = 0, idxTwo = 0, newLines = 0;
stringstream outSentence;
do {
while (getline(* inFile, inData, '\n')) {
for (idx = 0; idx <= inData.length() - 1; idx++) {
if (inData[idx] >= 'a' && inData[idx] <= 'z') {
outChar = (((inData[idx] - 'a') + shiftNum) % 26) +
'a';
outSentence << outChar;
}
else if (inData[idx] >= 'A' && inData[idx] <= 'Z') {
outChar = (((inData[idx] - 'A') + shiftNum) % 26) +
'A';
outSentence << outChar;
}
else {
outChar = inData[idx];
outSentence << outChar;
}
}
outSentence << '\n';
newLines++;
}
}
while (!inFile->eof());
for (idxTwo = 0; idxTwo <= newLines + 1; idxTwo++) {
getline(outSentence, tempString);
outData.append(tempString);
outData += '\n';
}
return outData;
}
string capitalize (string choice) {
string outString;
outString.resize(choice.length());
transform(choice.begin(), choice.end(), outString.begin(), ::toupper);
return outString;
}
// Output funcitons
void cypherMenu () {
cout << "C A E S A R C Y P H E R P R O G R A M" << endl
<< "========================================" << endl;
return;
}
void printSentence (string outData, ofstream * outFile) {
int idx = 0;
char outChar;
stringstream outString;
outString << outData;
for (idx = 0; idx <= outData.length() - 1; idx++) {
outChar = outString.get();
outFile->put(outChar);
}
}
void menu () {
cout << "Available Options: " << endl
<< "1. CAESAR - encrypt a file using Caesar Cypher" << endl
<< "2. QUIT - exit the program" << endl << endl
<< "Enter a keyword or option index: ";
return;
}
void notOption (string optionString) {
cout << optionString << " is an unrecognized option, try again" << endl
<< endl;
return;
}
The problem is the transform under the capitalize funciton. It doesn't seem to know transform at all, I even tried to write std:: before it, but it said that there is no member called transform. Is there a problem with my compiler, or is transform even used anymore since i downloaded the new studio, or maybe it is just bad practice ?
As you would discover from reading documentation (e.g. http://en.cppreference.com/w/cpp/algorithm/transform), std::transform is defined in the standard header <algorithm>, which you aren't including.
if I have a text file like this :
this is line one
This is line two
this is line three
How would I use getline to read each into a stringstream, then print the stream into a new string while preserving the newline character? I am on a mac using Xcode 4. Here is my code: I am having trouble because the text it prints out only prints on one line.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <cctype>
using namespace std;
string getInput ();
ifstream * openInFile ();
int getShiftValue ();
void cypherMenu ();
void menu ();
string shiftCharacters (int shiftNum, ifstream * inFile);
string getOutput ();
ofstream * openOutFile ();
void printSentence (string outData, ofstream * outFile);
void notOption (string optionString);
string capitalize (string choice);
string option ();
int main() {
ifstream * inFile;
ofstream * outFile;
string inFileName, outFileName, outData, optionString, capOptionString;
int shiftNum = 0;
bool isOption = false;
while (capOptionString.compare("2") != 0 ||
capOptionString.compare("QUIT") != 0) {
do {
menu();
optionString = option();
capOptionString = capitalize(optionString);
if (capOptionString.compare("1") == 0 || capOptionString.compare("CAESAR")
== 0) {
isOption = true;
}
else if (capOptionString.compare("2") == 0 ||
capOptionString.compare("QUIT") == 0) {
isOption = false;
return 0;
}
else {
notOption(optionString);
}
}
while (!isOption);
cypherMenu();
inFile = openInFile();
shiftNum = getShiftValue();
outData = shiftCharacters(shiftNum, inFile);
inFile->clear();
inFile->close();
outFile = openOutFile();
printSentence(outData, outFile);
outFile->clear();
outFile->close();
}
return 0;
}
// Input Functions
string getInput () {
cout << "Enter an input file name: ";
string inFileName;
getline(cin, inFileName);
return inFileName;
}
string getOutput () {
string outFileName;
cout << "Enter an output file name: ";
getline(cin, outFileName);
cout << endl;
return outFileName;
}
ifstream * openInFile () {
ifstream * inFile;
bool isGood = false;
string inFileName;
inFile = new ifstream;
do {
inFileName = getInput();
inFile->open(inFileName.c_str());
if (inFile->fail()) {
cout << "Couldn't open file" << endl;
}
else {
isGood = true;
}
}
while (!isGood);
return inFile;
}
ofstream * openOutFile () {
ifstream testStream;
ofstream * outFile;
bool isUnique = false;
string fileName;
do {
fileName = getOutput();
testStream.clear();
testStream.open(fileName.c_str(), ios_base::in);
if (testStream.good()) {
cout << "The file already exists, please choose another"
<< endl;
testStream.clear();
testStream.close();
}
else {
isUnique = true;
testStream.clear();
testStream.close();
}
}
while (!isUnique);
outFile = new ofstream;
outFile->open(fileName.c_str());
return outFile;
}
int getShiftValue () {
int shiftNum;
string trash;
cout << "Please enter shift value: ";
cin >> shiftNum;
getline(cin, trash);
return shiftNum;
}
string option () {
string optionString;
getline(cin, optionString);
cout << endl;
return optionString;
}
// Data manipulation functions
**string shiftCharacters (int shiftNum, ifstream * inFile){
string inData, outData, trash;
char outChar;
int idx = 0, length = 0;
stringstream outSentence;
do {
while (getline(* inFile, inData, '\n')) {
getline(* inFile, trash);
for (idx = 0; idx <= inData.length() - 1; idx++) {
if (inData[idx] >= 'a' && inData[idx] <= 'z') {
outChar = (((inData[idx] - 'a') + shiftNum) % 26) +
'a';
outSentence << outChar;
length += 1;
}
else if (inData[idx] >= 'A' && inData[idx] <= 'Z') {
outChar = (((inData[idx] - 'A') + shiftNum) % 26) +
'A';
outSentence << outChar;
length += 1;
}
else {
outChar = inData[idx];
outSentence << outChar;
length += 1;
}
}
outSentence << trash;
}
}
while (!(inFile->eof()));
outData.resize(length);
while (!(outSentence).eof()) {
// outSentence >> noskipws >> outData;
getline(outSentence, outData);
}
return outData;
}**
string capitalize (string choice) {
string outString;
outString.resize(choice.length());
transform(choice.begin(), choice.end(), outString.begin(), ::toupper);
return outString;
}
// Output funcitons
void cypherMenu () {
cout << "C A E S A R C Y P H E R P R O G R A M" << endl
<< "========================================" << endl;
return;
}
void printSentence (string outData, ofstream * outFile) {
int idx = 0;
char outChar;
stringstream outString;
outString << outData;
for (idx = 0; idx <= outData.length() - 1; idx++) {
outChar = outString.get();
outFile->put(outChar);
}
}
void menu () {
cout << "Available Options: " << endl
<< "1. CAESAR - encrypt a file using Caesar Cypher" << endl
<< "2. QUIT - exit the program" << endl << endl
<< "Enter a keyword or option index: ";
return;
}
void notOption (string optionString) {
cout << optionString << " is an unrecognized option, try again" << endl
<< endl;
return;
}
The Problem lies within the function shiftCharacters. I am not sure how to get it to preserve the new line character please help?? The code is compilable.
I know this is an old question but I think I can improve a little on #Benjamin Lindley's answer above. Forcing a newline at the end of every call to getline() will, as #David L. mentions, "possibly not reflect the real input for the very last line."
Instead, you can call std::istream::peek() after reading the line to see if there are more characters. It's safe to add a newline only if peek() doesn't return EOF. Sample code below...
std::string s;
while (std::getline(std::cin, s)) {
std::cout << s;
if (std::cin.peek() != EOF) {
std::cout << std::endl;
}
}
Update: It looks like the above code worked because of a bug in the standard library that I was using. According to the std::getline spec...
1) ...
2) ...
b) the next available input character is delim, as tested by
Traits::eq(c, delim), in which case the delimiter character
is extracted from input, but is not appended to str.
So on a conformant standard library, the code should be as follows.
std::string s;
while (std::getline(std::cin, s)) {
std::cout << s;
if (std::cin.good()) {
std::cout << std::endl;
}
}
Online runnable example
getline( the_stream, the_string );
the_string += '\n';