Reading std::cin hangs if no pipe is provided - c++

I have a function of the general form
void readStuff(std::istream& input){
int var;
while(input>>var){
//... do stuff
}
}
where input is passed as either std::cin or std::ifstream, depending on whether a command line option -c is set. Reading from file
myprog file.txt
works fine. If std::cin is used,
cat file.txt | myprog -c
that works fine as well. However, it hangs if the user tries
myprog -c
How can I handle this case from within my code? I've tried checking ifstream's flags, but in all cases they are 0 except for ifstream.good().

Your program isn't hanging; cin is just waiting for input from the terminal.
When you piped cat command's stdout into your program's stdin, there was an EOF in your stdin. This would cause the eof flag to be set which in turn would cause while(input>>var) to fail; hence exiting the loop.
When you execute your program directly from the terminal, cin keeps waiting for input from the terminal until the input stream is closed. You can exit your program by sending an EOF through the terminal which will close the input stream which in turn will break the loop in your code.
If you want your program to exit if it is not in a pipe, you can check using isatty on POSIX systems and _isatty on Windows.

Related

Program that writes to /dev/stdout: how to send EOF?

I have a program that writes data to a file. Normally, the file is on disk, but I am experimenting with writing to /dev/stdout. Currently, when I do this, the program will not exit until I press Ctrl-C . Is there a way for the program to signal that the output is done ?
Edit:
Currently, a disk file is opened via fopen(FILE_NAME), so I am now trying to pass in /dev/stdout as FILE_NAME.
Edit 2:
command line is
MY_PROGRAM -i foo -o /dev/stdout > dump.png
Edit 3:
It looks like the problem here is that stdout is already open, and I am opening it a second time.
The EOF condition on a FIFO (which, if you're piping from your program into something else, is what your stdout is) is set when no file handles are still open for write.
In C, the standard-library is fclose(stdout), whereas the syscall interface is close(1) -- if you're using fopen(), you'll want to pair it with fclose().
If you're also doing a separate outFile = fopen("/dev/stdout", "w") or similar, then you'll need to close that copy as well: fclose(outFile) as well as fclose(stdout).

Writing a Shell Script that runs my program with inputs

Ok so I created my own shell, and I've tested it plenty on my own, but I need shell scripts that will run it and test it.
I've create a script which consist of this:
#!/bin/bash
echo "ls && echo dog" | ./a.out
However, all it does is print the command prompt "$" infinitely, and I have to force quit the program. therefore I am pretty sure my program does not like my script lol. My program works by using getline to capture the user input until they push <enter> and the boost library to tokenize the string and look for connector e.g "||" "&&" ";" and and so on, then run the commands. All of this is done in a while loop that loops until the user types exit and I close my program. Being as I am new to writing scripts I am sure I probably am not writing my script in the best of manners. I created a simple program to ask for your age and then output it and this script method works for that, but being as my shell isn't as simple I am not surprised this scrip doesn't seem to work.
string user_input;
bool good = true;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
while(good){
//command prompt
cout << "$ ";
//read in user input
getline(cin, user_input);
//tokenize user input
tokenizer tok(user_input);
//parse and execute commands inputed by user in string
//only exit while loop if user command is <exit> good = false
}
my shell works if I execute the program normally and I enter inputs into the program what I need is a shell script that I can use to run and test the program for me. Ex. if I type ./script.sh in the standard linux shell it will run my script which will then execute my a.out and then test my own shell with a variety of commands Examples being ls echo ...
You should exit the shell when you reach EOF (End Of File). Getline while return -1 in that case.
I can't think of any other advice as you didn't provide any code, but this might resolve the infinite loop issue.

How to stop getline() loop over cin automatically

Hello my code is the following:
while (getline(cin, line))
{
// process on line
}
so this causes the user to keep putting lines until he inputs ^z.
How can I make it so that it automatically stops without user intervention? For example, when the user pastes the input lines without ^z, I need the above loop to do the processing and then stop.
std::getline will extract until:
EOF was encountered, which sets eofbit
A delimiter was encountered (no flag is set, so the next extraction won't fail)
You encountered std::string::max_size, which sets failbit
An error occurred
You can't have the user copy/paste and expect the program to automatically know that the user is done. What if the input was something else, like a file?
RE comment: you can still pipe input from a file and the program can't tell the difference.
# will stop extraction via EOF
cat file | ./a.out

gdb create a Stream

i have a program, which get the information from the stream and use cin to read and later convert the input.
This is the calling of the program:
cat file1 | ./converter
in C++ it is this line
while ( ! cin.eof( ) )
which reads from the stream.
Is it possible to simulate the pipeline in gdb?
Because i can not debug the source without it.
If you read the documentation, like the section on program input/output, you will see that you can use normal redirection for the run command:
(gdb) run < file1
This will run your program with stdin redirected from file1.

Can system() return before piped command is finished

I am having trouble using system() from libc on Linux. My code is this:
system( "tar zxvOf some.tar.gz fileToExtract | sed 's/some text to remove//' > output" );
std::string line;
int count = 0;
std::ifstream inputFile( "output" );
while( std::getline( input, line != NULL ) )
++count;
I run this snippet repeatedly and occasionally I find that count == 0 at the end of the run - no lines have been read from the file. I look at the file system and the file has the contents I would expect (greater than zero lines).
My question is should system() return when the entire command passed in has completed or does the presence of the pipe '|' mean system() can return before the part of the command after the pipe is completed?
I have explicitly not used a '&' to background any part of the command to system().
To further clarify I do in practice run the code snippet multiples times in parallel but the output file is a unique filename named after the thread ID and a static integer incremented per call to system(). I'm confident that the file being output to and read is unique for each call to system().
According to the documentation
The system() function shall not return until the child process has terminated.
Perhaps capture the output of "output" when it fails and see what it is? In addition, checking the return value of system would be a good idea. One scenario is that the shell command you are running is failing and you aren't checking the return value.
system(...) calls the standard shell to execute the command, and the shell itself should return only after the shell has regained control over the terminal. So if there's one of the programs backgrounded, system will return early.
Backgrounding happens through suffixing a command with & so check if the string you pass to system(...) contains any & and if so make sure they're properly quoted from shell processing.
System will only return after completion of its command and the file output should be readable in full after that. But ...
... multiple instances of your code snippet run in parallel would interfere because all use the same file output. If you just want to examine the contents of output and do not need the file itself, I would use popen instead of system. popen allows you to read the output of the pipe via a FILE*.
In case of a full file system, you could also see an empty output while the popen version would have no trouble with this condition.
To notice errors like a full file system, always check the return code of your calls (system, popen, ...). If there is an error the manpage will tell you to check errno. The number errno can be converted to a human readable text by strerror and output by perror.