Taking in user input - c++

I am programming a calculator that uses redirection (UNIX) ./calculator < expressions.txt to receive expressions from a file using a while loop in my main:
while(getline(cin, exp) ) {
try {
return the evaluated expressions
}
catch ( error ) { ... }
}
this works fine for me and returns the correct values.
However, I also want my program to take in user input if a file is not redirected (It currently error outs and core dumps). How can I take in user input if a file is not provided and avoid the while loop.
Thank you.

Rather than redirecting stdin why don't you just set up your program to accept command line arguments, one of which could be the file name. Then
int main(int argc, char* argv[]) {
if(argc > 1)
{
// File name is provided. Open the file and read the data
}
else
{
// File name is not provided. Get input from user.
}
return 0;
}
This is a bit trivial, but I'm sure you understand the point. For any more complex command line arg parsing, use a library.

When you are taking input from while like this:
./calculator < expressions.txt
It means you are taking input from STDIN only . So if user does not provide input file, the code will itself take input from user only. So you need not to handle file separately in your code. Just take input from stdin.

Related

C++ input redirection causing error while file arguments work

When I specify an input file as a file argument, like so:
./asm ex1_in
everything works as it should!
However, when I specify an input file using redirection, like so:
./asm < ex1_in
the program throws the error it is supposed to throw when the input file is corrupt or doesn't exist.
This is the part of the code that handles input and file arguments:
int main(int argc, char * argv []) {
ifstream InFile(argv[1], ios::in);
if (!(InFile.is_open())) { /* check file */
fprintf (stderr, "The input file cannot be open or cannot be read. \n");
return 2;
}
if (InFile.is_open()) {
//some stuff
InFile.close();
}
//other stuff
}
I would like to be able to keep using ifstream, as it is very helpful for the rest of the program.
Also, the program is supposed to accept input directly on stdin if no file argument is supplied. Currently, if no file arguments are supplied, it throws the same error, instead of looking for user input.
EDIT: I added a line in main to try to see what's going on, and it looks like when input redirection is used, the program doesn't see argv[1] or anything after it.
cout << argv[0] << " " << argv[1] << " " << argv[2];
prints out only ./asm.
When input redirection isn't used, it prints out:
./asm ex1_in my1_out
You are trying to open argv[1] as a file every time you run the program.
In the first case, argv has a lenght of two (the executable name and the filename) so it opens and does what it needs to do normally, but when you run it redirecting the file to the stdin, argv just contains the executable name, and since argv[1] is a C-style string, it will read everything until it finds a null byte, then pass whatever it read to the std::ifstream constructor, failing each time.
You should use argc to know the number of arguments passed, and use either the file or stdin depending on the number of arguments.

C++ remove empty lines from cin and save to same file

A part of my assignment is to make a program that reads a file that is passed from command line like this: inputfile.cpp | ./pg_rmv_empty_lines.
This (I guess) is for that reason that later on I can pipe(?) the same file to multiple programs.
I know I can read lines in that file with:
int main()
{
string line;
while(getline(cin, line))
{
cout << line << endl;
}
return 0;
}
What I need to do, is to remove all empty lines in the file that the program receives, remove those lines and then save the modified file.
I don't know the name of the file that needs modification, it's passed from the command line by "client"
Filename should stay the same after the modifications.
This is confusing me because every example I find, people suggests something that includes hardcoding filename into the source code like outfile.open("movieList.txt",ios_base::app);. In my case I don't know the name of the input file.
Bear in mind that I'm using C++ first time and it's already making me lose my faith in humanity.
To get the filename you need to parse command line arguments. Once you've done that, examples you referred to will work to read the lines from the file. Assuming file isn't big, you can read it into the memory, skipping the empty lines using if statement.
Once you've read the file into memory, you should either close it and re-open for writing or reset to the beginning and write the buffer out.
If the file is large and couldn't be read into the memory buffer, you only can pull this out by doing one line (or limited number of lines) at a time and save the results into a temporary file with a different name. After that you'd have to delete the old file and rename the new file. Of course, the other way (first rename original file and then save new one with the old name) works as well.
Getting the filename from the command line is easy.
#include <iostream>
#include <fstream>
#include <string> // Because why not.
int main(int argc, char** argv) {
if (argc != 2) {
return -1; // Indicates error
}
std::string filename = argv[1];
std::ifstream input(filename);
// Do your stuff...
return 0;
}
No more hints :-)
Are you sure that the requirement is to use the pipe command? I think what you want is to use command line arguments. Maybe this article here helps:
http://www.cplusplus.com/articles/DEN36Up4/
You can define your main function as:
int main(int argc, char* argv[])
{
...
}
and then argc is the amount of commandline arguments were given and argv is the arguments. The first argument is always the name of your program. So if you execute myprogram.exe ./pg_rmv_empty_lines, argv[0] would be myprogram.exe and argv[1] would be ./pg_rmv_empty_lines
You can then use this to dynamically read from that file in your code but you first need to open the file. For example something along the lines of:
std::ifstream myFile;
std::string lineAsString;
myFile.open(argv[1]);
std::getline(myFile, lineAsString);
... do things with the line
myFile.close();

Providing a file path to an input-dependent program

First off, sorry if the title makes no sense. The nature of my question makes it very hard for me to phrase.
I am working on an assignment for my datastructures class and I am completely and totally brand new to c++ due to only having learned Java at my old school. The project is a weather logger that reads in data from a text file climatedata.txt. My teacher has provided us with a main function in the file (that we are NOT allowed to modify in any way) weatherlog.cpp which is below.
#include <iostream>
#include <fstream>
#include "datalogger.h"
using namespace std;
int main(int argc, char** argv) {
datalogger dl;
if (argc != 2) {
cout << "Usage: " << argv[0] << " <datafile>" << endl;
exit(0);
}
// Read the data
char* datafile = argv[1];
ifstream infile(datafile);
int timestamp;
double temperature;
double windspeed;
while (!infile.eof()) {
infile >> timestamp;
infile >> temperature;
infile >> windspeed;
if (!infile.eof()) {
dl.addData(timestamp, temperature, windspeed);
}
}
// Output the report
dl.printReport();
return(0);
}
Initially I was confused as to why the program would never fully execute until I figured out what argc is in the scope of a main function. It seems that he wants me to provide the text file name while compiling so that argc will be 2 instead of 1 (the value I saw when debugging) so that it can actually execute the rest of the program instead of immediately exiting.
My problem is I'm not sure how to provide the program with the text file location. I've looked all over the internet but since I'm not even sure at which stage to provide the file path I haven't had any success. Is that information supposed to be passed when compiling with g++? After successfully compiling when I'm trying to run the executable? What does the terminal command to do so look like?
So I understand that you need to provide a file name in argv (Comment below if I'm incorrect). argv is an array of arguments passed by the commandline, and argc is the amount of arguments passed (automatically set). To do that simply call the program in terminal like this: ./<progam> <file_name>
Example:
compile just as you would a hello world progam.
Call the program weatherlog climatedata.txt.
If your file has spaces in its name either remove them or do this enclose its name in quotes.
argc stores number of passed in parameters, while argv points to parameters.
if (argc != 2) means checking number of input parameters passed in via Console mode. The first parameter is always the program name. From the second parameter you can pass anything you want. char* datafile = argv[1]; means taking the second parameter as data filename.
In short, open Console mode (CMD on Windows, Terminal on Linux) and type something like: yourprogram C:\path\to\climatedata.txt.

How to use istringstream to determine if first number in text file via file redirection on terminal in mac is a valid integer for the program?

I have random text files that I have to read and check if the first number of the file is a positive integer. If not, the program terminates. Hoping to get some help figuring out why my isValid method isn't working, and how to properly redirect my input file on terminal to the code (right now I just
bool isValid(int& number)
{
string integer;
getline(cin,integer);
if (istringstream(integer)>>number )
{
if(number>0)
{
return true;
}
else
{
cout<<"Bad Data. Need (+)"<<endl;
return false;
}
}
else
{
cout<<"Bad Data. Int needed";
return false;
}
}
I defined a method to call in main :
I call this in main by declaring an int representing the number and calling the function on it.
int numberInput;
isValid(numberInput);
Ideally I want to be able to just drag my executable to terminal and then direct the text file into terminal to read the first line and validate the program. Am I screwing up by how I am calling it in main? Or is it my attempt at entering inputfile in terminal by dragging the executable path onto terminal then "<" then the file location?

C++ Read/write file on Unix

I know this is a very specific question. I am compiling a c++ code using g++ compiler on a unix machine.
I have the following one line code to read a text file specified as parameter in C++: test.cc
int main(int argc, char *argv[])
{
ifstream inputfile(argv[1]);
}
Now after compiling with g++, I will call it as:
./test file.txt
But what should I do, if I want to call it as
./test <file.txt
In short how do I do a file read using default input/output
You should check the arguments to main to see if there is an argument given to the program. If it is then you can use that as the file, otherwise you use std::cin.
Here is an example:
void do_something(istream &input)
{
// Read some stuff from the input
}
int main(int argc, char *argv[])
{
if (argc == 1)
do_something(cin);
else if (argc == 2)
do_something(ifstream(argv[1]));
else
{
cout << "Error: Must supply a file\n";
return 1;
}
}
The reason I call another function to read and process the input, is because you can not assign streams, but must use references or pointers. It's also good to put separate tasks in separate functions, because it will increase readability of the code.
When you want to read from standard input, use std::cin instead of opening your own stream.
For example:
std::string s;
std::getline(std::cin, s);
Using < redirects that file to stdin, so you'd get at it via std::cin in c++.
You need instead to read from stdin, da file.
in other words read from the keyboard.
when you pipe stuff in, it will be read as if typed from the keyboard.
You can do what most of the Unix commands do: read from the file if the filename is specified. If the file name is missing read from standard input.
The cin object is already defined in iostream. Just read from cin instead of inputfile.
Perhaps
ifstream &myin;
if (argc>1) {
ifstream* inputfilep = new infstream(argv[1]);
myin = *inputfile;
}
else myin = cin;
/* do your input on myin */
you will need to modify your example to check argc to see if any command line arguments are passed in, as the input redirection is stripped off by the shell so if argc is 0 then read from standard in as given by the other examples, otherwise as your example code.
You don't have to do anything.
Just write your program as if your are reading from the command line.