C process created with popen doesn't print it's output - c

I have to solve the following problem as homework: create two processes with popen. The parent process will read from stdin lines of at most 30 chars and give the first child the digits from the line and give the second child the letters from the line, which will transform them to uppercase. Both processes will then print these things to the parent's stdout.
So basically i want something similar to running the "tee" command. Read a line, write some output and repeat until ctrl-d
Here is my attempt:
#include <stdio.h>
#include <ctype.h>
int main() {
FILE *digits, *letters;
char string[31];
if ((digits = popen("tee", "w")) == NULL) {
perror("can't create pipe for digits");
return 1;
}
if ((letters = popen("tr a-z A-Z", "w")) == NULL) {
perror("can't create pipe for letters");
return 1;
}
while(!feof(stdin)) {
fgets(string, 31, stdin);
for (char* c = string; *c != '\0'; c++)
if (isdigit(*c))
fputc(*c, digits);
else if (isalpha(*c))
fputc(*c, letters);
fputc('\n', digits);
fputc('\n', letters);
}
pclose(digits);
pclose(letters);
return 0;
}
But after I write a line and press enter, the program expects input again, without printing anything. It prints all of the output at the end, after pressing ctrl-d. And I don't understand why. It reads the line correctly, then it feeds the correct characters to each child, followed by a new line. Why don't these processes immediately print their output? Is the actual command ran when pclose is called? Because I couldn't find any information about that. Also, is writing '\n' to a child's stdin the same as pressing enter? And what's even weirder is that the last line from the output of each child is printed twice.
For example, here is how I would like it to work:
(input)
1a2b3c
(output)
123
ABC
(input)
4d5e6f
(output)
456
DEF
(ctrl-d)
But I get this:
(input)
1a2b3c
(input)
4d5e6f
(ctrl-d)
(output)
123
456
456
ABC
DEF
DEF

Related

How can I add a new line at the end of the file descriptor in c?

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)

C program to output characters produces integers instead

I'm writing a program called split.c that takes from the stdin an input.txt file as input and then sends every other word within the input file to stdout and stderr.
My current codes is as follows:
#include <stdio.h>
int main(){
int input;
// keep getting characters until end-of-file
while ((input = fgetc(stdin)) != EOF){
// prints to stdout
fprintf(stdout, "%d", input);
if(input == " ")
printf("\n"); // encounters whitespace so print new line
// prints to stderr
fprintf(stderr, "%d", input);
if(input == " ")
printf("\n"); // encounters whitespace so print new line
}
return 0;
}
In ubuntu I run make then the command ./split < test/input.txt > myout.txt 2> myerr.txt
The expected output should be, for example.
If input.txt has the following: "Is my code working?"
The output should be:
In myout.txt:
"Is
code
In myerr.txt:
my
working?"
Instead I get the following in both files, a huge number:
6511032731101001051181051001179710...............
Any idea was to what may be wrong with the code? Is my thought process wrong? The idea is that it gets the input file, reads each character and then, when a whitespace is found, it prints a new line in stdout, then does the same thing, but now printing to stderr until it reaches EOF.
I'm still learning the in's and out's (pun intended :) ) of using stdin/out/err so I'm not surprised if I'm not coding correctly. Any guidance is appreciated!
You are using the %d specifier that interprets the corresponding argument as a number. You should be using %c to interpret the corresponding argument as a character.

Terminate C program which stdin is linked to output of other program

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).

C - change stdin and wait for user input

I have the following code:
#include <stdio.h>
int main()
{
char c = 0;
fclose(stdin);
stdin = fopen("newin", "r");
if(stdin != NULLL)
{
scanf("%c", &c);
printf("%d", c);
}
else
printf("Error");
}
I want my program to wait for a change in the stdin file. I created it blank, but it returns 0.
If a put like a 'a' char in it it prints 97 like it should.
How can I make the scanf wait for a change in the file, like it was waiting for me to write in the terminal window?
How can I make the scanf wait for a change in the file, like it was waiting for me to write in the terminal window?
You can't.
Input from stdin and a file from disk are handled differently. When you are reading from a file, the file must have everything in order before you open it to read from it.

junk characters from stdin after reading from file in C

After succesfully reading a re-directed file to my program from the console, I ask a user to enter a word, then use scanf() to read in the word.
The problem i'm having is that scanf() is immediately reading in junk characters and then the program continues. It doesn't even pause to let the user enter anything in the console. It doesn't happen when I don't open a file. EVERYTHING else works perfectly. What could be the issue:
**I tried everything suggested, still can't get it to work. I've made a new project that is just for getting this part to work, here it is. Ignore that scanf is only looking for a single character, even though I ask for a word. I did this just to see if the program would actually pause and allow me to enter something, but it doesn't. Just enters some garbage and program ends.
main(){
int n,i;
char ch;
char line[80];
while(fgets(line, 80, stdin) != NULL){
for(i=0;i<80;i++){
ch=line[i];
if(ch=='\n'){
printf("%c",ch);
break;
}
else{
printf("%c",ch);
}
}
}
printf("Please enter a word: ");
scanf("%c",&ch);
}
You can't re-direct stdin from a file and then also use the keyboard for input (that I know of). If you want to do that, it's simpler to have the program take the input file as a command-line argument and then run it like so: prog myfile.txt. Also, leave yourself a pad with fgets() -- use one less than the allocated array for maxlen. It's always safest with C char arrays to use one less than the allocated length for anything requiring a maximum length in case the maximum length is not including the '\0' terminating character.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char *argv[])
{
FILE *f;
int i;
char line[80];
if (argc<2)
{
printf("Usage: %s <inputfile>\n",argv[0]);
exit(10);
}
/* Open file and echo to stdout */
f=fopen(argv[1],"r");
if (f==NULL)
{
printf("Cannot open file %s for input.\n",argv[1]);
exit(20);
}
while (fgets(line, 79, f) != NULL)
printf("%s",line);
fclose(f);
/* Get user input from stdin */
printf("Please enter a word: ");
if (fgets(line,79,stdin)==NULL)
{
printf("Nothing entered. Program aborted.\n");
exit(30);
}
/* Remove CR/LF from end of line */
for (i=strlen(line)-1;i>=0 && (line[i]=='\n' || line[i]=='\r');i--)
;
line[i+1]='\0';
printf("The word entered is: '%s'\n",line);
return(0);
}
sscanf is used to input from a stream or a buffer, and in unix stdin is considered as file so u are supposed to use fscanf which inputs from a file so use fscanf(stdin,"%s",testword);

Resources