I was given a task and I made it a little more complicated by trying to write it in C++
My assignment:
Display on the screen hexadecimal codes of characters entered from the keyboard. Use characters R, L, Q, m,p and use these codes to start an Explorer program, indicate the path to a folder, create a text file, delete a file, close the current Explorer window, respectively.
#include <Windows.h>
#include <iostream>
#include <conio.h>
#include <shellapi.h>
#include <fstream>
using namespace std;
void create_file()
{
cout << "Enter file name: ";
char filename[21] = { 0 };
cin >> filename;
strcat_s(filename, ".txt");
FILE* file;
fopen_s(&file, filename, "w");
if (file != NULL)
{
cout << "File created\n";
fclose(file);
}
else
cout << "Error creating file\n";
}
void delete_file()
{
cout << "Enter name deleting file: ";
char filename[21] = { 0 };
cin >> filename;
if (remove(filename) != 0)
cout << "Error deleting file" << endl;
else
cout << "File sucsesfull deleted" << endl;
}
void open_folder()
{
cout << "Example folder path: D:\\Server\n";
TCHAR path[MAX_PATH];
cout << "Enter folder path: ";
wcin >> path;
try
{
ShellExecute(NULL, L"open", path, NULL, NULL, SW_SHOW);
}
catch (exception)
{
cout << "Can't open folder\n";
}
}
void symbol_output(int symb)
{
cout.unsetf(ios::dec);
cout.setf(ios::hex);
cout << "Symbol " << (char)symb << ", hexadecimal: 0x";
cout << hex << symb << endl;
}
//int convert_10_to_16(int symb) //this function does not fit here
//{
// std::string d = "0123456789abcd";
// int num = symb;
// std::string res;
//
// while (num > 0)
// {
// res = d[num % 16] + res;
// num /= 16;
// }
std::cout << res << std::endl;
return num;
}
void close_window()
{
HWND hwnd;
hwnd = FindWindow(L"CabinetWClass", NULL);
if (hwnd != NULL)
SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
}
int main()
{
setlocale(LC_ALL, "");
int symb;
cout << " R - Open explorer\n L - Open folder\n Q - Creating text file\n m - Deleting text file\n p - Close the current explorer window\n";
cout << "Input e for exit" << endl;
do
{
cout << "Input Symbol: ";
symb = _getch();
symbol_output(symb);
symb = convert_10_to_16(symb);
switch (symb)
{
case 0x52: // R
ShellExecuteA(0, "open", "Explorer", NULL, NULL, SW_RESTORE);
break;
case 0x4c: // L
open_folder();
break;
case 0x51: // Q
create_file();
break;
case 0x6d: // m
delete_file();
break;
case 0x70: // p
close_window();
break;
}
} while (symb != 0x65); // e
}
int convert_10_to_16(int symb) this function is absolutely incorrect.
Be kind enough to point out my mistakes, back it up with your arguments or references such as why it should or should not be done.
Also, is there a hex type in C++ and can it be passed to Switch or do I have to use another option?
I tried to pass code without 0x in int format, but two letters include a number and a letter.
Frankly, I'm completely confused.
Using the "0x" before your hex will tell the compiler to create an int with that hexcode. Therefore, your switch statement would work without using convert_10_to_16 at all because the compiler is already making the conversion for your hexcodes.
int main()
{
setlocale(LC_ALL, "");
int symb;
cout << " R - Open explorer\n L - Open folder\n Q - Creating text file\n m - Deleting text file\n p - Close the current explorer window\n";
cout << "Input e for exit" << endl;
do
{
cout << "Input Symbol: ";
symb = _getch();
symbol_output(symb);
switch (symb)
{
case 0x52: // R
ShellExecuteA(0, "open", "Explorer", NULL, NULL, SW_RESTORE);
break;
case 0x4c: // L
open_folder();
break;
case 0x51: // Q
create_file();
break;
case 0x6d: // m
delete_file();
break;
case 0x70: // p
close_window();
break;
}
} while (symb != 0x65); // e
}
Hope that helps!
Related
I have an unordered map assigning strings to function so I could execute them as if they were console commands, I can get the function but I'm unable to execute it no matter how I try. Most sources I have seen say I should use "this" but I still don't understand why won't it work
Here's my code:
main.h
#include <iostream>
#include <stdio.h>
#include <unordered_map>
#include <fstream>
#include <algorithm>
using namespace std;
class Func_runner
{
public:
unordered_map <string, void(Func_runner::*)()> commandHash =
{
{"help", &Func_runner::help},
{"clear", &Func_runner::clear},
{"ver", &Func_runner::displayVersion},
{"mkfile", &Func_runner::makeFile},
{"view", &Func_runner::viewFile}
};
void help();
void clear();
void displayVersion();
void makeFile();
void viewFile();
// commandHash["help"] = &Func_runner::help;
// commandHash["clear"] = &Func_runner::clear;
// commandHash["mkfile"] = &Func_runner::makeFile;
// commandHash["ver"] = &Func_runner::displayVersion;
// commandHash["view"] = &Func_runner::edit;
};
void Func_runner::help(){
cout << " help - Displays all available commands. \n version - Displays Operating Version.\n clear - Clears the screen.\n makefile - Creates files.\n view - Outputs text file contents to console.\n";
}
void Func_runner::clear(){
system("CLS");
}
void Func_runner::displayVersion(){
cout << " Version 1.2R" << endl;
}
void Func_runner::makeFile(){
string filename;
string path;
string text;
cout << " Filename: ";
getline(cin, filename);
cout << " Path: ";
getline(cin, path);
ofstream File(path + filename);
cout << " Text (Optional): ";
getline(cin, text);
File << text;
cout << "\n File " << filename << " created." << endl;
File.close();
}
void Func_runner::viewFile(){
string editorfile;
string myText;
cout << " Full path to file: ";
getline(cin, editorfile);
ifstream ReadFile(editorfile);
while (getline (ReadFile, myText)) {
cout << myText << endl;
}
}
main.cpp
#include <iostream>
#include <unordered_map>
#include "func_obj.h"
using namespace std;
int main(){
Func_runner runner;
bool running = true;
// unordered_map<string, void(Func_runner::*)()> commandHash;
// commandHash["help"] = &Func_runner::help;
// commandHash["clear"] = &Func_runner::clear;
// commandHash["mkfile"] = &Func_runner::makeFile;
// commandHash["ver"] = &Func_runner::displayVersion;
// commandHash["view"] = &Func_runner::edit;
while(running){
string command;
cout << "Command: ";
getline(cin, command);
if(runner.commandHash.find(command) != runner.commandHash.end())
{
(this->*runner.commandHash[command])();
// int command_index = commandHash[command]; // old switch case useless with string -> func hash
// switch (command_index){
// case 1:
// runner.help();
// break;
// case 2:
// runner.clear();
// break;
// case 3:
// runner.displayVersion();
// break;
// case 4:
// runner.makeFile();
// break;
// case 5:
// runner.edit();
// break;
// case 6:
// running = false;
// break;
// }
}
else
{
cout << "invalid command" << endl;
}
}
}
There are a lot of random comments as that was an older version, I deactivated as I was afraid of losing it, don't mind them.
While working on this project for my younger cousin, I encountered many difficulties. I was wondering if someone could help me use char to output complete sentences (or help me fix these bugs.) I'm a relatively new programmer (about 8 months). Here's my code/ what I have attempted. Most of the bugs cause the program to freeze once a sentence is imputed, or the files not responding when opened.
#include<iostream>
#include<fstream>
#include<cctype>
#include<iomanip>
class legoset
{
char setcatname[25];
char name[50];
char legoinclude[25];
char legotype[25];
public:
void create_category();
void show_category() const;
void modify();
void report() const;
int retacno() const;
};
void legoset::create_category()
{
std::cout << "Please enter a category name : \n";
std::cin >> setcatname;
//std::cin.getline(setcatname, 25);
std::cout << "Please enter your username! \n";
std::cin >> name;
std::cin.ignore();
std::cin.getline(name, 50);
std::cout << name << " , is it a vehicle or building (V/B)?\n";
std::cin >> legotype;
legotype[25] = toupper(legotype[25]);
std::cin.getline(legotype, 25);
std::cout << "\n Please enter the name of the lego set. \n";
std::cin >> legoinclude;
//std::cin.getline(legoinclude, 25);
std::cout << "\n\n Category Created Successfully!!!";
return;
}
void legoset::show_category() const
{
std::cout << "Category : \n" << setcatname;
std::cout << "Username Of Holder \n: " << name;
std::cout << " Lego type (B/V) : " << legotype;
std::cout << " Lego set (with details) : " << legoinclude;
return;
}
void legoset::modify()
{
std::cout << "Category : \n" << setcatname[25];
std::cout << "\nModify Holder's name : ";
std::cin.ignore();
std::cin.getline(name, 50);
std::cout << "\nModify A Building or vehicle class ( B/V ) : ";
std::cin >> legotype[25];
legotype[25] = toupper(legotype[25]);
std::cout << "\nModify Lego set (with details) : ";
std::cin >> legoinclude[25];
}
void legoset::report() const
{
std::cout << setcatname[25] << std::setw(10) << " " << name << std::setw(10) << " " << legotype[25] << std::setw(6) << legoinclude[25] << std::endl;
}
int legoset::retacno() const
{
return setcatname[25];
}
void write_legoset(); //function to write record in binary file
void display_sp(int); //function to display account details given by user
void modify_set(int); //function to modify record of file
void delete_set(int); //function to delete record of file
void display_all(); //function to display all account details
void intro(); //introductory screen function
int main()
{
char choice;
int num;
intro();
do
{
system("cls");
std::cout << "\n\n\n\tMAIN MENU";
std::cout << "\n\n\t01. New Category";
std::cout << "\n\n\t02. ADD A NEW SET";
std::cout << "\n\n\t03. ALL USERS HOLDER LIST";
std::cout << "\n\n\t04. DELETE A CATEGORY";
std::cout << "\n\n\t05. MODIFY A CATEGORY";
std::cout << "\n\n\t06. EXIT";
std::cout << "\n\n\tSelect Your Option (1-6) ";
std::cin >> choice;
system("cls");
switch (choice)
{
case '1':
write_legoset();
break;
case '2':
std::cout << "\n\n\tEnter The category Name : "; std::cin >> num;
display_sp(num);
break;
case '3':
display_all();
break;
case '4':
std::cout << "\n\n\tEnter The Category Name : "; std::cin >> num;
delete_set(num);
break;
case '5':
std::cout << "\n\n\tEnter The Category Name : "; std::cin >> num;
modify_set(num);
break;
case '6':
std::cout << "\n\n\tThanks for using lego managemnt system!";
std::exit;
break;
default: std::cout << "\a";
}
std::cin.ignore();
std::cin.get();
} while (choice != '6');
return 0;
}
//***************************************************************
// function to write in file
//****************************************************************
void write_legoset()
{
legoset lego;
std::ofstream outFile;
outFile.open("legoset.dat", std::ios::binary | std::ios::app);
lego.create_category();
outFile.write(reinterpret_cast<char *> (&lego), sizeof(legoset));
outFile.close();
}
//***************************************************************
// function to read specific record from file
//****************************************************************
void display_sp(int n)
{
legoset lego;
bool flag = false;
std::ifstream inFile;
inFile.open("legoset.dat", std::ios::binary);
if (!inFile)
{
std::cout << "File could not be open !! Press any Key...";
return;
}
std::cout << "\nLEGOSET DETAILS\n";
while (inFile.read(reinterpret_cast<char *> (&lego), sizeof(legoset)))
{
if (lego.retacno() == n)
{
lego.show_category();
flag = true;
}
}
inFile.close();
if (flag == false)
std::cout << "\n\nLego set does not exist in this file";
}
//***************************************************************
// function to modify record of file
//****************************************************************
void modify_set(int n)
{
bool found = false;
legoset lego;
std::fstream File;
File.open("legoset.dat", std::ios::binary | std::ios::in | std::ios::out);
if (!File)
{
std::cout << "File could not be open !! Press any Key...";
return;
}
while (!File.eof() && found == false)
{
File.read(reinterpret_cast<char *> (&lego), sizeof(legoset));
if (lego.retacno() == n)
{
lego.show_category();
std::cout << "\n\nPlease Enter The New Details For This Category." << std::endl;
lego.modify();
int pos = (-1)*static_cast<int>(sizeof(legoset));
File.seekp(pos, std::ios::cur);
File.write(reinterpret_cast<char *> (&lego), sizeof(legoset));
std::cout << "\n\n\t Category Updated!";
found = true;
}
}
File.close();
if (found == false)
std::cout << "\n\n Category Not Found ";
}
//***************************************************************
// function to delete record of file
//****************************************************************
void delete_set(int n)
{
legoset lego;
std::ifstream inFile;
std::ofstream outFile;
inFile.open("legoset.dat", std::ios::binary);
if (!inFile)
{
std::cout << "File could not be open !! Press any Key...";
return;
}
outFile.open("Temp.dat", std::ios::binary);
inFile.seekg(0, std::ios::beg);
while (inFile.read(reinterpret_cast<char *> (&lego), sizeof(legoset)))
{
if (lego.retacno() != n)
{
outFile.write(reinterpret_cast<char *> (&lego), sizeof(legoset));
}
}
inFile.close();
outFile.close();
remove("legoset.dat");
rename("Temp.dat", "legoset.dat");
std::cout << "\n\n\tCategory Deleted ..";
}
//***************************************************************
// function to display all accounts deposit list
//****************************************************************
void display_all()
{
legoset lego;
std::ifstream inFile;
inFile.open("legoset.dat", std::ios::binary);
if (!inFile)
{
std::cout << "File could not be open !! Press any Key...";
return;
}
std::cout << "\n\n\t\tUSER HOLDER LIST\n\n";
std::cout << "====================================================\n";
std::cout << "A/c no. NAME Type Balance\n";
std::cout << "====================================================\n";
while (inFile.read(reinterpret_cast<char *> (&lego), sizeof(legoset)))
{
lego.report();
}
inFile.close();
}
void intro()
{
std::cout << "\n\n\n\t LEGOSET";
std::cout << "\n\n\tMANAGEMENT";
std::cout << "\n\n\t SYSTEM";
std::cout << "\n\n\n\nMADE BY : Philippe Barry";
std::cin.get();
}
//***************************************************************
// END OF PROJECT
//***************************************************************
Note that array indices in C++ go from 0 to one less than the array size. Thus index 0 is the first element, index 1 is the second, etc. Thus if you declare a char array to be size 25, then accessing index 25 is past the end of the array and results in undefined behavior — your program may crash, freeze up, or literally anything else. Additionally, accessing index 24 would just give you the “null character” that comes after every string. If you’re sure that the input will be 24 characters long (and you shouldn’t be), then index 23 would contain the last character.
You really shouldn’t be using static-length char arrays in C++, anyway. Your current code, even if it worked most of the time with the char arrays, would fail when the input string was larger than the size of the array. Replace the types of all the char arrays with std::string, and the input function should work.
Furthermore, as Sam Varsavchik nicely put, don’t write an entire program at once. That makes it a nightmare to debug. Write your code in chunks — first write the input function, and a debug function that prints out the values of all the member variables. Debug that bit first, then go on to the rest.
I'm writing a tictactoe application which communicates between a server and client file. Currently, my program hangs when trying to read in the players move. The client is showing successful write to the pipe but the server is not reading the information. Any help would be appreciated. Heres the offending code from both portions. Edit: I just realized the formatting got completely buggered in the copy/paste, I am sorry.
client main() :
//used to define int holder for server read in
const int MAX = 2;
//used to define buffers to transfer information
const int BUFFERS = 10;
//path of the global pipe
const string PRIMARY = "/home/mking/GPipe";
int main() {
//variables
size_t result;
srand(time(NULL) );
int s = rand() % 10000;
if (s < 1000) { s += 1000; }
cout << s << endl;
string userWrite = "/temp/" + to_string(s);
s = rand() % 10000;
if (s < 1000) { s += 1000; }
cout << s << endl;
string serverWrite = "/temp/" + to_string(s);
cout << PRIMARY << endl;
cout << "User pipe is " << userWrite << endl;
cout << "Server pipe is " << serverWrite << endl;
// send personal pipe information through global pipe to server
FILE * comms = fopen(PRIMARY.c_str(), "w");
cout << "Comms open" << endl;
result = fwrite(userWrite.c_str(), 1, userWrite.length(), comms);
if (result < userWrite.length()) { cout << endl << endl << endl << endl << endl << "write error, userfifo" << endl; }
result = fwrite(serverWrite.c_str(), 1, serverWrite.length(), comms);
if (result < userWrite.length()) { cout << endl << endl << endl << endl << endl << "write error, serverfifo" << endl; }
cout << "Comms written to" << endl;
//done with comms so close it
fclose(comms);
// for some reason sending /tmp/ caused a hang also, so i improvised
userWrite.erase(2,1);
serverWrite.erase(2,1);
// make the personal pipes
cout << userWrite << " " << serverWrite << endl;
mkfifo(userWrite.c_str(), 0777);
mkfifo(serverWrite.c_str(), 0777);
// open the personal pipes with read or write privelege
cout << "fifos made" << endl;
FILE * pwrite = fopen(userWrite.c_str(), "w");
cout << "pwrite open" << endl;
FILE * pread = fopen(serverWrite.c_str(), "r");
cout << "pread open" << endl;
// if either pipe did not get made correctly, print an error
if (pwrite == NULL ) { cout << "pwrite is wrong" << endl; }
if (pread == NULL ) { cout << "pread is wrong" << endl; }
// used to transfer information between pipes
string buffer = "/temp/0000";
string catcher = "/temp/0000";
// initialize curses functions
initscr();
noecho();
keypad(stdscr,TRUE);
cbreak();
WINDOW * screen = newwin(LINES/2, COLS/2, 0, 0);
wclear(screen);
keypad(screen,TRUE);
//wait for input before playing the game
int c = getch();
displayOpening(screen);
c = getch();
//initialize the game data types
int row = 0;
int column = 0;
vector<pair<int, int> > userMoves;
vector<pair<int,int> > serverMoves;
int charInt[MAX];
bool invalid = 0;
//until game is over or user exits
while (1) {
// update the board
displayBoard(screen,userMoves,serverMoves, row, column, invalid);
// based on user input, do stuff, supports wsad or arrow keys
switch(c = getch() ) {
// if go up, move up a row or go back to bottom if at top
case KEY_UP:
case 'w':
if (row == 0) { row = 2; }
else { row--; }
break;
// if go down, move down a row or go back to the top if at bottom
case KEY_DOWN:
case 's':
if (row == 2) { row = 0; }
else { row++; }
break;
// if go left, move left a column or go back to the far right if at far left
case KEY_LEFT:
case 'a':
if (column == 0) { column = 2; }
else { column--; }
break;
// if go right, move right a column or go back to the far left if at far right
case KEY_RIGHT:
case 'd':
if (column == 2) { column = 0; }
else { column++; }
break;
// if spacebar is pressed, enter move if valid, otherwise tell invalid and get more input
case ' ':
if (checkX(row, column, userMoves, serverMoves)) {
invalid = 0;
// no longer used function, thought maybe was the issue
//addX(row,column,userMoves,buffer);
//catch information in buffer to send to server
buffer[8] = (row + '0');
buffer[9] = (column + '0');
//cout << "buffer 0 and 1 are " << int(buffer[0]) << " " << int(buffer[1]) << endl;
// add newest move to the list of user moves
userMoves.push_back(make_pair(row,column));
// check if the game is over, send a game over message to server if so and exit/clean up pipes
if (checkValid(userMoves,serverMoves) == 0 || (userMoves.size() + serverMoves.size() == 9) ) {
youwin(screen);
buffer[8] = (3 + '0');
buffer[9] = (3 + '0');
result = fwrite(buffer.c_str(), 1, buffer.length(), pwrite);
if (result < BUFFERS) { cout << endl << endl << endl << endl << endl << "write error, usermove" << endl; }
fclose(pread);
fclose(pwrite);
unlink(userWrite.c_str());
unlink(serverWrite.c_str());
endwin();
return 0;
}
//mvwaddch(screen, 12, 1, 'k');
//wrefresh(screen);
//cout << endl << endl << endl << endl << endl << buffer << " " << buffer.length() << endl;
// write newest move to server, currently where hangs!!!!!!
result = fwrite(buffer.c_str(),1,buffer.length(),pwrite);
if (result < BUFFERS) { cout << endl << endl << endl << endl << endl << "write error, usermove" << endl; }
//cout << endl << "written successfully" << endl;
//mvwaddch(screen,12,1,'l');
//wrefresh(screen);
// read in server counter move
result = fread(&catcher[0],1,BUFFERS,pread);
if (result < BUFFERS) { cout << endl << endl << endl << endl << endl << "read error, servermove" << endl; }
// catch newest computer move
charInt[0] = (catcher[8] - '0');
charInt[1] = (catcher[9] - '0');
// if the server says it won, clean up pipes and exit
if (charInt[0] == 3 && charInt[1] == 3) {
youlose(screen);
fclose(pread);
fclose(pwrite);
unlink(userWrite.c_str());
unlink(serverWrite.c_str());
endwin();
return 0;
}
// check if the server made a valid move
if (checkX(charInt[0], charInt[1], userMoves, serverMoves)) { invalid = 1; }
//addX(charInt[0],charInt[1],serverMoves,catcher);
// add newest server move to list of server moves
serverMoves.push_back(make_pair(charInt[0],charInt[1]));
// if server has won or a draw, tell the server and clean up pipes/exit
if (checkValid(userMoves,serverMoves) == 0) {
youlose(screen);
buffer[8] = (3 + '0');
buffer[9] = (3 + '0');
result = fwrite(&buffer[0],1,BUFFERS,pwrite);
if (result < BUFFERS) { cout << endl << endl << endl << endl << endl << "write error, usermove" << endl; }
fclose(pread);
fclose(pwrite);
unlink(userWrite.c_str());
unlink(serverWrite.c_str());
endwin();
return 0;
}
}
// if the move was invalid say so
else { invalid = 1; }
break;
// if user wants to exit, tell the server and clean up/exit
case 'q':
buffer[8] = 3 + '0';
buffer[9] = 3 + '0';
result = fwrite(&buffer[0],sizeof(char),BUFFERS,pwrite);
if (result < BUFFERS) { cout << endl << endl << endl << endl << endl << "write error, usermove" << endl; }
fclose(pread);
fclose(pwrite);
unlink(userWrite.c_str());
unlink(serverWrite.c_str());
endwin();
return 0;
break;
default:
break;
}
}
return 0;
}
server main() :
const int GRID = 9;
const int MAX_G = 10;
const int MAX_L = 10;
const string PRIMARY="/home/mking/GPipe";
int main() {
// variables to hold personal pipe input
char userWrite[MAX_L];
char serverWrite[MAX_L];
// open global pipe and prepare for input
cout << PRIMARY << endl;
FILE * comms = fopen(PRIMARY.c_str(), "r");
cout << "comms open" << endl;
pid_t pid;
bool valid = 1;
int charInt[MAX_G];
char prev[] = "/temp/0000";
size_t result;
// run until forced to close
while(1) {
// get the personal pipe names
//cout << "about to read user" << endl;
result = fread(&userWrite[0], sizeof(char),MAX_L,comms);
if (result < MAX_L && result > 0) { cout << "read error, user" << endl; }
//cout << "read user" << endl;
result = fread(&serverWrite[0], sizeof(char), MAX_L,comms);
if (result < MAX_L && result > 0) { cout << "read error, server" << endl; }
//cout << "read server" << endl;
//cout << "User pipe is " << userWrite << endl;
//cout << "Server pipe is " << serverWrite << endl;
// if a new pipe was detected, fork and play against a client
if (strcmp(prev, userWrite) != 0) { pid = fork(); }
strcpy(prev, userWrite);
// if a chiled, play against a client
if (pid == 0) {
//close comms and open personal pipes
cout << "In child" << endl;
fclose(comms);
string user(userWrite);
string server(serverWrite);
// was having issues with fread earlier also, roundabout fix
user.erase(2,1);
server.erase(2,1);
// set up pipes
cout << "opened pipes " << user << " " << server << endl;
FILE * userFifo = fopen(user.c_str(), "r");
cout << "opened user pipe" << endl;
FILE * serverFifo = fopen(server.c_str(), "w");
cout << "opened server pipe" << endl;
// set up data for server to check moves
pair<int,int> move;
vector<pair<int,int> > userMoves;
vector<pair<int,int> > serverMoves;
char buffer[MAX_G] = {'/','t','e','m','p','/','0','0' };
char filler[MAX_G];
vector<bool> untaken (GRID, 1);
// while game not over
while (valid) {
// get a new move, HANGS HERE!!!!!
cout << "waiting for user move" << endl;
result = fread(&filler[0], sizeof(char), MAX_G, userFifo);
if (result < MAX_G) { cout << "read error, usermove" << endl; }
cout << "move read in" << endl;
// catch user move
charInt[0] = filler[6] - '0';
charInt[1] = filler[7] - '0';
cout << charInt[0] << " " << charInt[1] << endl;
// if user says game over, close pipes
if (charInt[0] == 3 && charInt[1] == 3) {
fclose(userFifo);
fclose(serverFifo);
exit(0);
}
// add user move to list of moves
userMoves.push_back(make_pair(charInt[0], charInt[1]));
// mark location of taken moves
untaken[(userMoves.back().first * 3 + userMoves.back().second)] = 0;
// see if game can be ended and add a server move
valid = checkX(userMoves,serverMoves, untaken);
untaken[(serverMoves.back().first * 3 + serverMoves.back().second)] = 0;
//prepare server move for writing
buffer[6] = serverMoves.back().first + '0';
buffer[7] = serverMoves.back().second + '0';
//buffer[0] = -1;
//buffer[1] = -1;
// write servermove to client
//cout << buffer[0] << " " << buffer[1] << endl;
result = fwrite(&buffer[0],sizeof(char),MAX_G,serverFifo);
if (result < MAX_G) { cout << "write error, servermove" << endl; }
}
// close pipes if game is over
fclose(userFifo);
fclose(serverFifo);
exit(0);
}
}
fclose(comms);
return 0;
}
I have a C++ executable that, in normal use, accepts a file name as an argument option in the following manner:
executable -i myFile.txt
I want to use Bash process substitution to create a 'virtual file' and send information (simple, line by line data) to this executable in the following manner:
executable -i <(echo "${myData}")
However, my C++ program is not accessing the information when I use this process substitution. The main file reading section of code in the C++ program is the following:
ifstream file1 (fileName1);
string line;
int currentLineNumber = 0;
if (verboseFlag == 1) {cout << "reading data from file " << fileName1 << "..." << endl;}
while (getline (file1, line)){
currentLineNumber++;
if (verboseFlag == 1) {cout << "line " << currentLineNumber << ": ";}
istringstream linestream(line);
string item;
int itemNumber = 0;
while (getline (linestream, item, ',')){
itemNumber++;
if (verboseFlag == 1) {cout << "item " << itemNumber << ": " << item << " ";}
// data
if (itemNumber == 1) {x[currentLineNumber]=atof(item.c_str());}
if (itemNumber == 2) {y[currentLineNumber]=atof(item.c_str());}
}
}
file1.close();
Could you point me in the right direction on solving this reading problem? Is there some better approach that would work for both normal file reading and process substitution 'file' reading?
I'm new to this process substitution and I very much appreciate any assistance on this.
EDIT:
Following some comments, what follows is a minimal working example illustrating the problem I am encountering:
// definition of standard input/output stream objects
#include <iostream>
// manipulate strings as though they were input/output streams
#include <sstream>
// input and output operations
#include <stdio.h>
// file input and output operations
#include <fstream>
// manipulate C strings and arrays
#include <string.h>
// classify and transform individual characters
#include <ctype.h>
// Standard General Utilities Library
#include <stdlib.h>
// getopts (handle command line options and arguments)
#include <unistd.h>
// sstream (handle conversion from char* to double)
#include <sstream>
using namespace std;
double returnDoubleFromPointerToChar(const char *cText){
std::stringstream ss ( cText );
double dText = 0;
ss >> dText;
return dText;
}
int returnNumberOfLinesInFile(const char *fileName1){
int lineCount = 0;
string line;
ifstream file1(fileName1);
while (std::getline(file1, line))
++lineCount;
file1.close();
return lineCount;
}
int main (int argc, char **argv){
char *fileName1 = NULL; // input file name (i) (required input)
int verboseFlag = 0; // verbose flag (v)
int index; // internal variable
int c; // internal variable
opterr = 0;
// process command line arguments and options
while ((c = getopt (argc, argv, "i:v")) != -1)
switch (c){
case 'i':
fileName1 = optarg;
break;
case 'v':
verboseFlag = 1;
break;
case '?':
if (
optopt == 'i'
){
fprintf (stderr, "option -%c requires an argument.\n", optopt);
}
else if (isprint (optopt)){
fprintf (stderr, "unknown option `-%c'.\n", optopt);
}
else {
fprintf (stderr, "unknown option character `\\x%x'.\n", optopt);
}
return 1;
default:
abort ();
}
for (index = optind; index < argc; index++) printf ("non option argument %s\n", argv[index]);
if (verboseFlag == 1){
cout << endl;
cout << "input file name: " << fileName1 << endl;
}
// Determine the number of lines in the input file.
int numberOfLinesInInputFile=returnNumberOfLinesInFile(fileName1);
if (verboseFlag == 1) {cout << "number of lines in input file: " << numberOfLinesInInputFile << endl;}
// number of data points
int n=numberOfLinesInInputFile-1;
// x variable
double x[n];
// y variable
double y[n];
// Access the data in the input file.
ifstream file1 (fileName1);
string line;
int currentLineNumber = 0;
if (verboseFlag == 1) {cout << "reading data from file " << fileName1 << "..." << endl;}
while (getline (file1, line)){
currentLineNumber++;
if (verboseFlag == 1) {cout << "line " << currentLineNumber << ": ";}
istringstream linestream(line);
string item;
int itemNumber = 0;
while (getline (linestream, item, ',')){
itemNumber++;
if (verboseFlag == 1) {cout << "item " << itemNumber << ": " << item << " ";}
// data
if (itemNumber == 1) {x[currentLineNumber]=atof(item.c_str());}
if (itemNumber == 2) {y[currentLineNumber]=atof(item.c_str());}
}
if (verboseFlag == 1) {cout << endl;}
}
file1.close();
return 0;
}
EDIT:
I have added the solution code below (following from a comment by that other guy):
// include WBM C++ library
// #include "lib_cpp.c"
// definition of standard input/output stream objects
#include <iostream>
// manipulate strings as though they were input/output streams
#include <sstream>
// input and output operations
#include <stdio.h>
// file input and output operations
#include <fstream>
// manipulate C strings and arrays
#include <string.h>
// classify and transform individual characters
#include <ctype.h>
// Standard General Utilities Library
#include <stdlib.h>
// getopts (handle command line options and arguments)
#include <unistd.h>
// sstream (handle conversion from char* to double)
#include <sstream>
using namespace std;
// example usage:
// ./graph2d -i data.txt -o data.eps -v
// ./graph2d -i data.txt -o graph.eps -t "training test error versus epochs" -x "epochs" -y "error measure" -v
// ./graph2d -i data.txt -o graph.eps -t "training test error versus epochs" -x "epochs" -y "error measure" -a 70 -b 50 -c 22 -d 7 -v
// ./graph2d -i <(echo "${dataForTrainingErrorVersusEpoch}") -o graph.eps -t "training test error versus epochs" -x "epochs" -y "error measure" -v
double returnDoubleFromPointerToChar(const char *cText){
std::stringstream ss ( cText );
double dText = 0;
ss >> dText;
return dText;
}
int main (int argc, char **argv){
char *fileName1 = NULL; // input file name (i) (required input)
char *fileName2 = NULL; // output file name (o) (required input)
char *graphTitleMain = NULL; // graph title (t)
char *graphTitleAxisx = NULL; // graph x axis title (x)
char *graphTitleAxisy = NULL; // graph y axis title (y)
double axisyMaximum = DBL_MAX; // y axis maximum (a)
double axisyMinimum = DBL_MAX; // y axis minimum (b)
double axisxMaximum = DBL_MAX; // x axis maximum (c)
double axisxMinimum = DBL_MAX; // x axis minimum (d)
int verboseFlag = 0; // verbose flag (v)
int index; // internal variable
int c; // internal variable
opterr = 0;
// process command line arguments and options
while ((c = getopt (argc, argv, "i:o:t:x:y:a:b:c:d:v")) != -1)
switch (c){
case 'i':
fileName1 = optarg;
break;
case 'o':
fileName2 = optarg;
break;
case 't':
graphTitleMain = optarg;
break;
case 'x':
graphTitleAxisx = optarg;
break;
case 'y':
graphTitleAxisy = optarg;
break;
case 'a':
axisyMaximum = returnDoubleFromPointerToChar(optarg);
break;
case 'b':
axisyMinimum = returnDoubleFromPointerToChar(optarg);
break;
case 'c':
axisxMaximum = returnDoubleFromPointerToChar(optarg);
break;
case 'd':
axisxMinimum = returnDoubleFromPointerToChar(optarg);
break;
case 'v':
verboseFlag = 1;
break;
case '?':
if (
optopt == 'i' ||
optopt == 'o' ||
optopt == 't' ||
optopt == 'x' ||
optopt == 'y' ||
optopt == 'a' ||
optopt == 'b' ||
optopt == 'c' ||
optopt == 'd'
){
fprintf (stderr, "option -%c requires an argument.\n", optopt);
}
else if (isprint (optopt)){
fprintf (stderr, "unknown option `-%c'.\n", optopt);
}
else {
fprintf (stderr, "unknown option character `\\x%x'.\n", optopt);
}
return 1;
default:
abort ();
}
for (index = optind; index < argc; index++) printf ("non option argument %s\n", argv[index]);
if (verboseFlag == 1){
cout << endl;
cout << "input file name: " << fileName1 << endl;
cout << "output file name: " << fileName2 << endl;
}
// x variable
vector<int> x;
// y variable
vector<int> y;
// Access the data in the input file.
ifstream file1 (fileName1);
string line;
int currentLineNumber = 0;
if (verboseFlag == 1) {cout << "reading data from file " << fileName1 << "..." << endl;}
while (getline (file1, line)){
currentLineNumber++;
if (verboseFlag == 1) {cout << "line " << currentLineNumber << ": ";}
istringstream linestream(line);
string item;
int itemNumber = 0;
while (getline (linestream, item, ',')){
itemNumber++;
if (verboseFlag == 1) {cout << "item " << itemNumber << ": " << item << " ";}
// data
if (itemNumber == 1) {x.push_back(atof(item.c_str()));}
if (itemNumber == 2) {y.push_back(atof(item.c_str()));}
}
if (verboseFlag == 1) {cout << endl;}
}
file1.close();
int numberOfLinesInInputFile = currentLineNumber + 1;
// number of data points
int n=numberOfLinesInInputFile;
// graph
if (verboseFlag == 1){
cout << "graph main title: " << graphTitleMain << endl;
cout << "graph x axis title: " << graphTitleAxisx << endl;
cout << "graph y axis title: " << graphTitleAxisy << endl;
}
// Create a new canvas.
TCanvas *c1 = new TCanvas(graphTitleMain, graphTitleMain); // #u
// Create a new graph.
//TGraph *graph = new TGraph(n, x, y);
TGraph *graph = new TGraph(n, &x[0], &y[0]);
// Set the graph titles.
graph->SetTitle(graphTitleMain);
graph->GetXaxis()->SetTitle(graphTitleAxisx);
graph->GetYaxis()->SetTitle(graphTitleAxisy);
// Set the marker styles.
graph->SetMarkerColor(2); // red
graph->SetMarkerStyle(kFullCircle); // circle
graph->SetMarkerSize(1); // default size
// Set the graph range, if ranges have been specified in command line options.
if (
axisyMaximum != DBL_MAX &&
axisyMinimum != DBL_MAX
){
if (verboseFlag == 1){
cout << "graph y axis minimum: " << axisyMinimum << endl;
cout << "graph y axis maximum: " << axisyMaximum << endl;
}
graph->GetYaxis()->SetRangeUser(axisyMinimum, axisyMaximum);
}
if (
axisxMaximum != DBL_MAX &&
axisxMinimum != DBL_MAX
){
if (verboseFlag == 1){
cout << "graph x axis minimum: " << axisxMinimum << endl;
cout << "graph x axis maximum: " << axisxMaximum << endl;
}
graph->GetXaxis()->SetRangeUser(axisxMinimum, axisxMaximum);
}
// Draw the canvas, then draw the graph and then save the canvas to an image file.
c1->Draw();
graph->Draw("ALP");
// disable ROOT messages
gErrorIgnoreLevel = 5000;
if (verboseFlag == 1) {cout << "saving file " << fileName2 << "..." << endl;}
c1->SaveAs(fileName2);
if (verboseFlag == 1) {cout << endl;}
return 0;
}
First of all, I trimmed out two thirds of your program and it still shows the problem. This is significantly closer to minimal:
#include <iostream>
#include <fstream>
using namespace std;
int returnNumberOfLinesInFile(const char *fileName1){
int lineCount = 0;
string line;
ifstream file1(fileName1);
while (std::getline(file1, line))
++lineCount;
file1.close();
return lineCount;
}
int main (int argc, char **argv){
char *fileName1 = argv[1];
cout << "input file name: " << fileName1 << endl;
int numberOfLinesInInputFile=returnNumberOfLinesInFile(fileName1);
cout << "number of lines in input file: " << numberOfLinesInInputFile << endl;
ifstream file1(fileName1);
string line;
cout << "File contents: " << endl;
while (getline (file1, line)){
cout << "line: " << line << endl;
}
file1.close();
return 0;
}
The problem here is that you open the file twice. <(process substitution) only runs the command once and streams the result. Bash doesn't take the liberty of running the command again if you want to read output again, since the command could have been doing a lot of other things besides spitting out text.
Make sure your program only opens and reads the contents once, and it'll work. This may require you to rewrite your logic a bit, or just be lazy and read it all into memory at once.
Your code works fine for me (I'm on OS X).
Keep in mind that, unlike real files, "virtual files" are usually pipe endpoints (implemented in bash using file descriptor special files). So, you cannot open, read, and close a virtual file more than once, or you will get nothing the second time around.
First, thank for you all your help!
The error I am getting is:
Unhandled exception at 0x7c812afb
(kernel32.dll) in Readerboard.exe:
Microsoft C++ exception:
std::out_of_range at memory location
0x0012f8a8..
I have found the problem to be with this line:
str.replace(str.find(sought), sought.size(), replacement);
It is located in this procedure:
void DisplayMessages() {
ifstream myReadFile;
string str;
static string myMessages[10];
static int i; // of course my famous i
static int MyPosition;
string sought;
string replacement;
myReadFile.open("C:\\Documents and Settings\\agerho000\\Desktop\\cms_export_test\\outages.htm",ios::in);
i = 0; //the start of my array
sought = "</td>"; // value that I want to replace with nothing
replacement.clear();
if(!myReadFile) // is there any error?
{
cout << "Error opening the file! Aborting…\n";
exit(1);
}
if (myReadFile.is_open())
{
cout << endl;
while (!myReadFile.eof())
{
getline(myReadFile, str);
if (str == "<tr>")
{
myReadFile.seekg(4,ios::cur);
getline(myReadFile, str);
str.replace(str.find(sought), sought.size(), replacement);
cout << str;
myMessages[i]=str;
i++;
}
}
}
i=0;
while (i < 10)
{
cout << i << ") " << myMessages[i] << endl;
i++;
if (myMessages[i]=="")
{
break;
}
}
myReadFile.close();
mainMenu();
}
The whole cpp file is displayed below:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
void mainMenu();
void DisplayMessages();
void AddMessage();
void DeleteMessage();
void EditMessage();
void RunTests();
void CheckFile();
void CreateHtmlFile(string myMessages[10]);
/*
#define MIN 1
#define MAX 100
#define TRUE 1
#define FALSE 0
*/
int main() {
cout << endl;
cout << endl;
cout << "Hello Andrew.\n";
cout << "First you need some sort of menu.\n";
mainMenu();
return 0;
}
void mainMenu() {
int Command;
cout << endl;
cout << endl;
cout << endl;
cout << "What would you like to do?\n";
// cout << "1) Check that tests work!\n";
// cout << "2) Check that the file exists\n";
cout << "3) Display Messages\n";
// cout << "4) Edit a message\n";
// cout << "5) Add a message\n";
// cout << "6) Delete a message\n";
cout << "7) Exit\n";
cout << "Enter a number: ";
cin >> Command;
if (Command == 3)
{
DisplayMessages();
}
if (Command == 7)
{
cout << "Exiting...";
exit(EXIT_SUCCESS);
}
if (Command == 6)
{
DisplayMessages();
}
}
void DisplayMessages() {
ifstream myReadFile;
string str;
static string myMessages[10];
static int i; // of course my famous i
static int MyPosition;
string sought;
string replacement;
myReadFile.open("C:\\Documents and Settings\\agerho000\\Desktop\\cms_export_test\\outages.htm",ios::in);
i = 0; //the start of my array
sought = "</td>"; // value that I want to replace with nothing
replacement.clear();
if(!myReadFile) // is there any error?
{
cout << "Error opening the file! Aborting…\n";
exit(1);
}
if (myReadFile.is_open())
{
cout << endl;
while (!myReadFile.eof())
{
getline(myReadFile, str);
if (str == "<tr>")
{
myReadFile.seekg(4,ios::cur);
getline(myReadFile, str);
str.replace(str.find(sought), sought.size(), replacement);
cout << str;
myMessages[i]=str;
i++;
}
}
}
i=0;
while (i < 10)
{
cout << i << ") " << myMessages[i] << endl;
i++;
if (myMessages[i]=="")
{
break;
}
}
myReadFile.close();
mainMenu();
}
void AddMessage() {
}
/*
void DeleteMessage() {
ifstream myReadFile;
string str;
static string myMessages[10];
static int i; // of course my famous i
static int MyPosition;
string sought;
string replacement;
static int Command;
myReadFile.open("C:\\Documents and Settings\\agerho000\\Desktop\\cms_export_test\\outages.htm",ios::in);
i = 0; //the start of my array
sought = "</b></td>"; // value that I want to replace with nothing
replacement.clear();
if(!myReadFile) // is there any error?
{
cout << "Error opening the file! Aborting…\n";
exit(1);
}
if (myReadFile.is_open())
{
cout << endl;
while (!myReadFile.eof())
{
getline(myReadFile, str);
if (str == "<tr>")
{
myReadFile.seekg(7,ios::cur);
getline(myReadFile, str);
str.replace(str.find(sought), sought.size(), replacement);
myMessages[i]=str;
i++;
}
}
}
i=0;
while (i < 10)
{
cout << i << ") " << myMessages[i] << endl;
i++;
if (myMessages[i]=="")
{
break;
}
}
myReadFile.close();
cout << "Enter the number of the message you would like to delete?\n";
cout << "Or enter 11 to go back to the main menu.\n";
cin >> Command;
while (Command >= 12)
{
cout << "Invalid number, try again!\n";
cout << endl;
cout << "Enter the number of the message you would like to delete?\n";
cout << "Or enter 11 to go back to the main menu.\n";
cin >> Command;
}
if (Command == 11)
{
mainMenu();
}
myMessages[Command].clear();
//clear the string
//now rebuild the htm file with the new array
CreateHtmlFile(myMessages);
}
void EditMessage() {
}
void RunTests() {
}
void CheckFile() {
}
void CreateHtmlFile(string myMessages[])
{
}
//File.seekg(-5); moves the inside pointer 5 characters back
//File.seekg(40); moves the inside pointer 40 characters forward
//tellg() Returns an int type, that shows the current position of the inside-pointer for reading
//tellp() same as above but for writing
//seekp() just like seekg() but for writing
*/
Please help I am so stumped!
str.replace(str.find(sought), sought.size(), replacement); is wrong when str.find() doesn't find what it's looking for. str.find() will return str::npos, which will not be a valid location in the string. Hence, the call to replace fails with the index out of range exception you're seeing.
Change that to:
std::size_t foundIndex = str.find(sought);
if (foundIndex != str.npos)
str.replace(foundIndex, sought.size(), replacement);
else
std::cout << "Oops.. didn't find " << sought << std::endl;
and let us know if that helps you.
EDIT: You might also want to consider using boost::algorithm::replace_all from the Boost String Algorithms Library
A complete function for replacing strings:
std::string ReplaceString(std::string subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
If you need performance, here is an optimized function that modifies the input string, it does not create a copy of the string:
void ReplaceStringInPlace(std::string& subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
}
Tests:
std::string input = "abc abc def";
std::cout << "Input string: " << input << std::endl;
std::cout << "ReplaceString() return value: "
<< ReplaceString(input, "bc", "!!") << std::endl;
std::cout << "ReplaceString() input string not modified: "
<< input << std::endl;
ReplaceStringInPlace(input, "bc", "??");
std::cout << "ReplaceStringInPlace() input string modified: "
<< input << std::endl;
Output:
Input string: abc abc def
ReplaceString() return value: a!! a!! def
ReplaceString() input string not modified: abc abc def
ReplaceStringInPlace() input string modified: a?? a?? def