EDIT: I've managed to narrow down the problem, but it still doesn't make much sense to me. My code becomes 8 lines:
int savedOut = dup(1);
printf("Changing the outstream to process.txt!")
if ( freopen("process.txt", "w"m stdout) == NULL)
printf("FREOPEN() FAILURE")
printf("Print to File\n");
dup2(savedOut, 1);
printf("Done with print to file");
return 1;
This code prints all to the terminal. Removing the two lines with "savedOut" prints all to process.txt. I understand the latter result, but I don't understand the former.
END EDIT
I'm having a lot of difficulty working with freopen(). Take this snippet of code:
int savedIn = dup(0);
int savedOut = dup(1);
while(1)
{
readFile[0] = '\0';
writeFile[0] = '\0';
dup2(savedIn, 0);
dup2(savedOut, 1);
if(getInputFlag == 1)
{
printf("myshell$ ");
gotInputFlag = getUserInput(arguments, command, readFile, writeFile, catOrApp, bkgdFlag);
}
else
{
gotInputFlag = getUserInput(arguments, command, readFile, writeFile, catOrApp, bkgdFlag);
}
if(gotInputFlag == 1)
{
history[historySize] = (char*)malloc(sizeof(char) * 1000);
if (writeFile[0] != '\0' && *catOrApp == 0)
{
printf("Changing the outstream!\n");
freopen(writeFile, "w", stdout);
}
printf("Print to File\n");
dup2(savedIn, 0);
dup2(savedOut, 1);
printf("Done with print to file!\n");
...
This program will execute and print "Changing the Outstream!" just as expected. "Print to File!" is never printed, neither to the terminal nor to the writeFile. "Done with print to file!\n" does not print either. Later on in the code, the code calls an execv() on a Hello World program, which prints to terminal as expected. However, upon program termination suddenly all the printf statements print to terminal, even the "Print to File" statements.
Save for a single fgets(), getUserInput() does not work with streams.
I can't for the life of me understand why this is happening. Does anyone have any idea?
This is what I believe is happening is all associated with stream buffering. You are starting with stdout pointing at your terminal. Because it is a character device, the stream is line-buffered. You print Changing the outstream to process.txt! without a new-line so the text stays in the buffer. You now reopen stdout to a file; the stream switches to fully-buffered. You then print Print to File\n which remains in the buffer despite the new-line.
Now you use dup2 to change stdout back to the terminal. However, this works on the fd that underlies the stream. The stream library code is unaware of this change and leaves the stream fully buffered. You print once more and exit, which flushes the stream to the fd (now your terminal).
Add fflush calls after each printf and I'll bet you see the behavior you expect.
Related
I study the process comunications. Hello everybody. I am studying interprocess communication in C. I am using Pipes as a means of communication. Here is the exercise:
The child process reads from the file and inserts into the buffer, the parent process reads from the buffer and prints to the screen.
My problem is the following:
I would like to insert the string "quit \ n" at the end of the reading. Unfortunately, when the father prints on the screen, the quit string is concatenated to the last element read.
This is my code :
int main(int argc, char const *argv[])
{
if(argc!=3)
{
perror(">>Error");
exit(1);
}
FILE *r_file, *w_file;
const char* filename= argv[2];
const char* word=argv[1];
int len=0;
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe");
exit(1);
}
if((r_file = fdopen(pipefd[0], "r"))==NULL){
perror("reader");
exit(1);
}
if((w_file = fdopen(pipefd[1], "w"))==NULL){
perror("writer");
exit(1);
}
char buffer[BUFFER_SIZE];
if(fork()==0)//child R
{
FILE* file;
if((file=fopen(filename,"r"))==NULL)
{
perror("fopen");
exit(1);
}
close(pipefd[0]);
char* n;
while((n=(fgets(buffer,BUFFER_SIZE,file)))!=NULL)
{
printf("leggo:%s",buffer );
fputs(buffer,w_file);
}
fputs("quit\n",w_file);
fclose(file);
exit(0);
}
else
{
printf("- Sono il padre\n");
close(pipefd[1]);
while(fgets(buffer,BUFFER_SIZE,r_file)>0)
{
len=strlen(buffer);
if(buffer[len-1]=='\n') buffer[len-1]='\0';
printf("\nbuffer: %s", buffer);
}
}
}
and this is my output:
leggo:House
leggo:Hello
leggo:Car
leggo:Moto
leggo:House
leggo:Mouse
leggo:City
leggo:Alex
leggo:PC
leggo:Hello
leggo:Hello
buffer: House
buffer: Hello
buffer: Car
buffer: Moto
buffer: House
buffer: Mouse
buffer: City
buffer: Alex
buffer: PC
buffer: Hello
buffer: Helloquit%
as you see
as you see, my last line is
"buffer: Helloquit%".
But I wish that my last line will be
"buffer: quit"
Help me please !!
That is just a problem in your file. If the last line of your file (containing "Hello") doesn't end with a \n then the 2 last things you fputs to your parent is "Hello" (without a \n) and then "quit\n".
So then, the last line your parent will read (it has strictly no way to know you send those in 2 steps. What it does is just reading every till it encounter an EOF or a \n) is "Helloquit\n"
As for the % it is probably the prompt of your shell.
Because, in the parent, you remove the \n from what you receive. But then print with a \n at the beginning of the line. Reason why you still print 1 word per line. But then the last line (independently of the concatenation Hello+quit problem) is printed without a ending \n.
So, correction:
For the concatenation Hello+quit problem. Either just correct your input file. Or, do in the child the same thing you did with the parent: remove the \n if there is one, from the lines you read. And then add it again yourself before fputs (or fprintf, like this fprintf(w_file, "%s\n", buffer)). So that you know that each line is ended with a \n in the communication with parent, whether there was one in the file or not.
For the last line ending with % (prompt of your shell), just add a printf("\n") at the end. Or, replace the printf("\n%s", buffer) by a more logical printf("%s\n", buffer). I suspect you've chosen this strange position of \n because otherwise the line is sometimes concatenated with the last "Hello" that doesn't end with a newline. But we have solved that now.
Anyway, we don't really know in which order the print will occur, since you have 2 independent process. In your demo, it occurs in an apparently orderly fashion, because w_file is not an interactive file, so flush occurs only when buffer (not yours, the internal buffer of FILE) is full, or when file is closed (if w_file was interactive, as stdout is, then buffer is also flushed at each newline).
So, you can't assume anything about how printf from child and printf from parent will be intricated on the shared display they have.
But I am pretty sure, those are only debugging messages anyway, so you don't really care, do you? (you shouldn't, at least)
When I run the following C code on a Linux system:
printf("This is sentence 1. ");
write(STDOUT_FILENO, "This is sentence 2.\n", 20);
I get the output in a wrong order:
This is sentence 2.
This is sentence 1.
I understand that this happens because 'printf' sends the data to a buffer in the user space, and it takes some time to get to the kernel space, while 'write' sends the data immediately to the cache buffer in the kernel space.
A way to fix this is by flushing the data from user-space buffer to kernel-space buffer this way:
printf("This is sentence 1. ");
fflush(stdout);
write(STDOUT_FILENO, "This is sentence 2.\n", 20);
And then the correct output is received:
This is sentence 1. This is sentence 2.
Another way that I tried to solve this issue is by trying to get the stdout stream from the STDOUT_FILENO fd:
FILE *file = fdopen(STDOUT_FILENO, "w");
printf("This is sentence 1. ");
fflush(file);
write(STDOUT_FILENO, "This is sentence 2.\n", 20);
But, I get the output in the wrong order:
This is sentence 2.
This is sentence 1.
In order to make sure that STDOUT_FILENO is a fd that represents stdout, I converted stdout to a fd:
int fd = fileno(stdout);
if(fd == STDOUT_FILENO)
printf("fd == STDOUT_FILENO == %d\n", fd);
And received the expected output:
fd == STDOUT_FILENO == 1
So, the question is why when converting STDOUT_FILENO to a stream that should be equivalent to stdout, the 'fflush' function doesn't work? Is there a problem with the way I use 'fdopen'?
The buffer is a property of the stdio stream, that is, the FILE structure. printf is always printing to stdout, so it's the stdout stream you need to call fflush on. When you wrote
FILE *file = fdopen(STDOUT_FILENO, "w");`
, that gave you a second, completely independent FILE stream, with its own buffer. But you don't print anything to that stream, so falling fflush on it accomplishes nothing, and meanwhile, the text you printfed to stdout remains unflushed.
If you've got buffered output on stdout, it's stdout you must call fflush on. (Or, alternatively, add a \n at the end of the string you print with printf, since stdout is typically line-buffered, at least if it's going to a terminal.)
In this:
FILE *file = fdopen(STDOUT_FILENO, "w");
printf("This is sentence 1. ");
fflush(file);
write(STDOUT_FILENO, "This is sentence 2.\n", 20);
printf does not send anything to file. It writes to stdout.
Each FILE object contains its own buffer (whether directly or via pointer to allocated memory). When you execute printf("This is sentence 1. ");, it writes to the buffer in the stdout FILE. When you fflush(file);, it flushes the buffer in file.
To make this work, you could write fprintf(file, "This is sentence 1. ");, since that will write to the buffer in file, and fflush(file); will flush it.
I'm using an UNIX online terminal to write this code. The program compliles successfully but it won't output anything to the console. It seems to ignore printf() and putchar instructions
if(pid > 0)
{
file = open("comenzi.txt", O_WRONLY);
read(file, ch, sizeof(ch));
printf("%s", ch);
write(fd[1], ch, sizeof(ch));
close(fd[1]);
close(file);
}
else { //procesul fiu
while(read(fd[0], &rd, 1) > 0);
putchar(rd);
close(fd[0]);
}
How do I make it output text to console? Thanks.
You're opening file in write-only only mode and yet you're attempting to read from it. Therefore, your call to read will fail and therefore you're not writing anything meaningful to stdout. Depending on how ch was initialized, you could be writing exactly nothing.
You need to change O_WRONLY to O_RDONLY.
I have a program x, which I want to cleanly terminate.
You can run it by simply doing ./x and use the terminal to write lines to stdin directly and terminate it by writing exit.
However, if you use: cat file.txt | ./x, the stdin is now piped from the file and therefore you can never type exit.
The best way to end this program would be for it to automatically terminate once the last line was read from the file.
Alternatively, I'd like to re-route stdin back to the terminal if that is at all possible, to further allow manual input as before.
Here is some sample code:
int main() {
// ...
while (ongoing) {
size_t n = 0;
char* ln = NULL;
getline(&ln, &n, stdin);
strtok(ln, "\n");
strtok(ln, "\r");
if (strcmp("exit", ln) == 0) {
break;
}
//...
}
}
you're using getline to read your input. getline returns -1 on EOF. This makes it easy.
if (-1==getline(...))
break;
When you have read all the input from a pipe, EOF will be raised up to indicate that the full input has been reached.
In your example, this will be rougly equivalent with exit, so you can also check the return value of getline to see if the EOF has reached (in which case -1 will be returned).
i have the following code
it prints to the screen: haha
to the file :
haha
hello
Father finished
if i remove line 6 and 7 , I get different results
why?
int main()
{
// creates a new file having full read/write permissions
int fd = open("myfile", O_RDWR|O_CREAT, 0666);
write(fd, "haha\n", 5);
close(fd); // line 6
fd = open("myfile", O_RDWR); // line 7
close(0);
close(1);
dup(fd);
dup(fd);
if (fork() == 0)
{
char s[100];
dup(fd);
scanf("%s", s);
printf("hello\n");
write(2, s, strlen(s));
return 0;
}
wait(NULL);
printf("Father finished\n");
close(fd);
return 0;
}
Try to comment out the scanf(), recompile and rerun. The scanf() trying to read beyond EOF might be doing something in the stdio library internal buffers that is causing this issue in printf() buffer not being flushed at the time of process _exit. Just a guess...
A file descriptor has only one position which is used both for writing and reading. When you write to the file in line 4 the position is advanced past what was just written, so the descriptor's position is at the end of the file. Calling close and open has the effect of resetting the position to the beginning of file (among other things).
You could replace the calls to close and open with lseek(fd, 0, SEEK_SET) to have the same effect, without closing and reopening the file.
Also, you should not mix the stdio functions scanf, printf and low level functions such as write. The results of the program will be unpredictable because of buffering in the stdio functions.