Why are stdin and stdout seemingly interchangeable? - c++

I understand that stdin and stdout (at least in UNIX parlance) are stream buffers, and that stdout is used to output from a program to the console (or to then be piped by a shell, etc), and that stdin is for standard input to a program..
So why is it, at least on macOS, that they can be used interchangeably (stdout as stdin, and vice versa?
Examples:
If you run cat /dev/stdin then type something in, and it echoes it back. Running the command as cat /dev/stdout does the same thing.
Similarly, echo "Hey There" > /dev/stdout and echo "Hey There" > /dev/stdin both output 'Hey There' back to the terminal.
It also works in C++:
example:
#include <iostream>
#include <string>
#include <fstream>
int main(int argc, const char * argv[]) {
std::string echoString;
std::fstream stdoutFile;
stdoutFile.open("/dev/stdout");
stdoutFile << "Hey look! I'm using stdout properly!\nNow You trying using it wrongly: " << std::endl;
stdoutFile >> echoString;
stdoutFile << "You Typed: " << echoString << std::endl;
}
When prompted, typing a single word, followed by EOF (Ctrl+D) works as expected.

Because, typically, when a program is invoked from an interactive terminal, with no redirection, both standard input and standard output are connected to the same terminal device, such as /dev/tty (the actual device name varies based on the operating system).
The terminal device is a read/write device. Reading from the terminal device reads terminal input. Writing to the terminal device generates output on the terminal.
You still have discrete file descriptors, 0 and 1, but they're connected to the same device.
Think of it as single, bi-directional pipe, that's duped to both file descriptors 0 and 1.
Linux behaves the same way (you can echo Foo >/dev/stdin and see the output):
$ ls -al /proc/self/fd/[01]
lrwx------. 1 mrsam mrsam 64 Nov 22 21:34 /proc/self/fd/0 -> /dev/pts/1
lrwx------. 1 mrsam mrsam 64 Nov 22 21:34 /proc/self/fd/1 -> /dev/pts/1
So, for this process, file descriptors 0 and 1 is connected to the /dev/pts/1, the same pseudo-terminal device. Whether you are reading from file descriptor 0 or file descriptor 1, you end up reading from the same underlying /dev device, so it makes no difference which actual file descriptor you use.
This is, of course, operating system-dependent. Other POSIX-based operating systems may implement their standard input and output in other ways, where you can't actually write to standard input and read from standard output.

As you said, they're just stream buffers. There is nothing about them that enforces a particular usage pattern - just convention. The stream buffers stdin, stdout, and stderr are all provided as a programming convenience.

Related

How a program in C++ can interface with shell scripts in Linux by using 'system' variables?

I have a shell script running on Linux that essentially takes a photo with a Webcam at intervals of 30s and stores the result in a directory, replacing the old image by overwriting it.
This photo is then read by a program written in C++, but once it is executed asynchronously to the script, I would like to use a semaphore in that script so that when I was about to update a new photo (say 5 sec before), the script indicates in this flag the unavailability of the picture for access to any other program.
The first thing that came to my mind was the script simply writing this information in a text file and the C++ program reads it back to know the status, but that struck me as a rough solution.
Another thing I thought, it was the C++ program itself to instantiate the script at 30s intervals, by using the command exec("./<script>.sh") but since this program is not always running, wont work.
So, I wonder how to use some kind of "dynamic" system variable (if it exists), something that acts as a RAM, so that I can use it as a flag where the script indicates some status, and the program then reads it.
It is possible ?
Based on the above tips, I got the solution based on 'named pipes' approach. What lies behind this is that FIFOs are essentially treated by the operacional system as 'files', so they can be manipulated with the same standard system libraries that are already available. Just sharing the CPP code used for testing:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/stat.h>
#define FIFO_FILE "MYFIFO"
int main(void)
{
FILE *fp;
char readbuf[80];
int StrCnt = 0 ;
/* Create the FIFO if it does not exist */
umask(0);
mknod(FIFO_FILE, S_IFIFO|0666, 0);
while(1)
{
fp = fopen(FIFO_FILE, "r");
if ( fp > 0 )
{
fgets(readbuf, 80, fp);
printf("Received %d\th string : %s\n", StrCnt++ , readbuf);
fclose(fp);
// remove(FIFO_FILE);
rewind(fp);
}
}
return(0);
}
I can put values to MYFIFO with e the following command:
echo "abcde12345" > MYFIFO
And ls -al command shows FIFO content, 10 characters + 1 null character, if code not running:
-rw-rw-r-- 1 esp8266 esp8266 11 10 22 16:10 MYFIFO
Whereas if the code is running, it empties the buffer (above function rewind()):
prw-rw-rw- 1 esp8266 esp8266 0 10 22 16:12 MYFIFO

Sending data to stdin of another process through linux terminal

I've been trying to send data to stdin of a running process. Here is what I do:
In a terminal I've started a c++ program that simply reads a string and prints it. Code excerpt:
while (true) {
cin >> s;
cout << "I've just read " << s << endl;
}
I get the PID of the running program
I go to /proc/PID/fd/
I execute echo text > 0
Result: text appears in the terminal where the program is run. Note, not I've just read text, but simply text.
What am I doing wrong and what should I do to get this thing to print 'I've just read text'?
When you're starting your C++ program you need to make sure its input comes from a pipe but not from a terminal. You may use cat | myapp to do that. Once it's running you may use PID of your application for echo text > /proc/PID/fd/0
It could be a matter of stdout not being properly flushed -- see "Unix Buffering". Or you could be in a different shell as some commentators have suggested.
Generally, it's more reliable to handle basic interprocess communication via FIFOs or NODs -- named pipes. (Or alternatively redirect stdout and/or stderr to a file and read from that with your c++ program.)
Here's some good resources on how to use those in both the terminal and c++.
"FIFO – Named pipes: mkfifo, mknod"
"Using Pipes in Linux Processes"
"Programming with FIFO: mkfifo(), mknod()"
FD 0 is the terminal the program is running from. When you write to FD 0, you are writing to the terminal the program is running from. FD 0 is not required to be opened in read-only mode; in practice it seems to be read/write mode, so you can write to it. (I suspect this is because FDs 0, 1 and 2 all refer to the same file description)
So echo text > /proc/PID/fd/0 just echoes text to the terminal.
To pipe input to the program, you would need to write to the other end of the pipe (actually a PTY, which mostly behaves like a pair of pipes). Most likely, whatever terminal emulator you're using (xterm, konsole, gnome-terminal) will have the other end open, so you could try writing to that.

Preventing Windows program from interpreting ^Z as end of file

My job is to translate a application from C -> C++ that have been installed on a linux distribution.so I wish the functionallity of C and linux.
I have a problem with reading binary file. It says that it reaches the EOF when it encounters a ctrl-Z character before it has reached the actual end of the file.
Precious execution in bash
zcat file.txt.gz | txtToBinary | binaryToOutput
Execution in command prompt
txtToBinary.exe < file.txt | binaryToOutput.exe
Raw text file
R 5643BYIDK DK0016060346 11DKKXKLY 160 1
R 10669VJK 98 1 IS0000004018 4ISKXICE 240 5000000
M814
txtToBinary.exe - Sample Output:
^#^#^# hello ^# ^Z^#^#^#^#
^#^#^[SWMA ^Y^YC
The problem is that the program interprets the first ^Z as the end of file.
Tried so far
My solutions has been to do the following when compiling on windows using c++
Execution in command prompt
txtToBinary.exe < file.txt | binaryToOutput.exe
int main(int argc, char* argv []){
int loop (args_t* args){
for (;;){
char data [1024];
int temp = read_msg (data, sizeof (data));
}
int read_msg(void* data, int size){
_setmode(_fileno(stdin), _O_BINARY);
_setmode(0,_0_BINARY);
if(fread(((unsigned char *)data)+sizeof(*hdr),hdr->size-sizeof (*hdr),1,stdin) != 1);
if(feof(stdin))
printf("End of file error\n");
}
I have also tried Cygwin which some of the answers have me. But that also failed.
StackOverflow Answers
When looking at answer here in SO, we see Windows, Windows EOF, Binary solution,Binary Mode and Stream data end at byte 26 and Reaching EOF early Windows. They tell me that:
- Windows keys (CTRL + Z, ^Z) makes an end of file
- I have to read in binary format
I found the answer to my question. It had to do with where you read from. You need to put
_setmode(0,_0_BINARY);
in the main() function!!!!!!!! Remember this, otherwise other reads or writes will not be included.
fread() is part of stdio. What you're doing is opening the raw file as binary, but then doing text-mode standard I/O.
You could replace your existing fread() call with the read() system call. (That is, fread() is a library call that does some buffering, ultimately to call through to read().)

C/C++ - Run system("process &") and then write to its stdin

I am working on Linux and C/C++. I wrote a program with some threads (#include pthread.h) and I run it with sudo.
One thread runs a process (mplayer) and leaves it running by adding " &", so that system() can return quickly.
system("mplayer -loop 0 /mnt/usb/* &");
The mplayer process runs normally and plays music as expected.
After that, I get its process ID by running pidof. Let's say that it returns 2449. A posix mutex is used to write/read that process ID on this thread and on the second thread.
On the second thread I try to write data to mplayer by using the /proc/2449/fd/0 pipe (is it called a pipe or stream?):
system("echo \">\" > /proc/2499/fd/0");
system() returns 0, but the mplayer process does not get anything. The ">" command should play the next track.
Is the stdin stream being inherited by some other process?
There are several fd's listed under the 2449 process, is one of them (besides 0) the stdin stream?
root#pisanlink:/proc# cd 2499
root#pisanlink:/proc/2499# cd fd
root#pisanlink:/proc/2499/fd# ls
0 1 2 3 4 5 7
root#pisanlink:/proc/2499/fd#
I also tried another approach... I used popen() with write permissions. I tried sending the command with fprintf, but mplayer didn't seem to receive anything as well.
If any more code is needed, please let me know.
Any hints will be appreciated. Thanks.
Use popen (not system) to open the process. It will create the process with a pipe that you can either read from or write to (but not both). In your case, you'd open it with "w" for writing. From there you can simply use fwrite to send data to the process' stdin.
Pseudo-code Example:
FILE * pFile = popen("mplayer -loop 0 /mnt/usb/*", "w");
if(pFile == NULL)
// Handle error
// Send ">" to process' stdin
const char * psData = ">";
const size_t nDataLen = strlen(psData);
size_t nNumWritten = fwrite(psData, 1, nDataLen, pFile);
if(nNumWritten != nDataLen)
// Handle error
...
pclose(pFile);
pFile = NULL;
I used the mplayer slave option and the input as a fifo file. It is working correctly.
Create the Linux fifo file with mkfifo:
system("mkfifo /tmp/slpiplay_fifo");
Open mplayer with:
system("mplayer -slave -idle -really-quiet -input file=/tmp/slpiplay_fifo /mnt/usb_slpiplay/* &");
Pass a "next" command to mplayer by using the fifo:
system("echo \"pt_step 1\" >> /tmp/slpiplay_fifo");

How do I check if my program has data piped into it

Im writing a program that should read input via stdin, so I have the following contruct.
FILE *fp=stdin;
But this just hangs if the user hasn't piped anything into the program, how can I check if the user is actually piping data into my program like
gunzip -c file.gz |./a.out #should work
./a.out #should exit program with nice msg.
thanks
Since you're using file pointers, you'll need both isatty() and fileno() to do this:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
FILE* fp = stdin;
if(isatty(fileno(fp)))
{
fprintf(stderr, "A nice msg.\n");
exit(1);
}
/* carry on... */
return 0;
}
Actually, that's the long way. The short way is to not use file pointers:
#include <unistd.h>
int main(int argc, char* argv[])
{
if(isatty(STDIN_FILENO))
{
fprintf(stderr, "A nice msg.\n");
exit(1);
}
/* carry on... */
return 0;
}
Several standard Unix programs do this check to modify their behavior. For example, if you have ls set up to give you pretty colors, it will turn the colors off if you pipe its stdout to another program.
Try "man isatty", I think that function will tell you if you are talking to the user or not.
Passing stdin to select() or poll() should tell you if input is waiting. Under many OSes you can also tell if stdin is a tty or pipe.
EDIT: I see I'm going to have to emphasize the also part of the tty test. A fifo is not a tty, yet there might be no input ready for an indefinite amount of time.
Use isatty to detect that stdin is coming from a terminal rather than a redirect.
See the function "isatty" - if STDIN is a terminal, you can skip reading from it. If it's not a terminal, you're getting data piped or redirected and you can read until EOF.
An additional option you get with select() is setting a timeout for reading from stdin (with respect to either the first read from stdin or consecutive reads from stdin).
For a code example using select on stdin see:
How to check if stdin is still opened without blocking?