I realized a GUI with GTK3 that, essentially, generates an input text file for an exe program that with these inputs can do elaborations. This exe is put in executions in the GUI by mean of a System call ( system("exe input.dat &") ).
This exe can print on screen message of information or error.
What I want to do is redirect these message on a GtkTextView.
The idea that I had is to redirect output and error on a file ( system("exe input.dat > output_file.txt 2>&1 &") ) and in the GUI read line by line this file and send this strings in the textView.
I was not sure that 2 process can write and read the same file and to test this concept I used these 2 simple programs: the writer (used like ./writer > out_file.txt):
#include <stdio.h>
#include <unistd.h>
main()
{
int a;
while(1)
{
fprintf(stdout,"a=%d\n",a);
fflush(stdout);
sleep(1);
a++;
}
}
and the reader:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
fp = fopen("out_file.txt","r");
char string_new[1024];
char string_old[1024];
strcpy(string_old," ");
while(1)
{
fgets(string_new,1024,fp);
if ( strlen(string_new) != 0 )
{
if ( strcmp(string_new, string_old) != 0 )
{
fprintf(stdout,"%s",string_new);
fflush(stdout);
strcpy(string_old,string_new);
}
}
}
}
This two programs run correctly and the second one print the output of the first one.
Putting in the GUI a similar code, the GUI read only the first line of the file.
How I can solve this issue? Thank you
You should use popen
instead of executing system("exe input.dat &")
, then it's easy to read from the stdout
output of the program.
Like this:
#include <stdio.h>
int main(void)
{
FILE *fp = popen("ls -lah /tmp", "r");
if(fp == NULL)
return 1;
char buffer[1024];
int linecnt = 0;
while(fgets(buffer, sizeof buffer, fp))
printf("Line: %d: %s", ++linecnt, buffer);
putchar('\n');
fclose(fp);
return 0;
}
which outputs:
$ ./b
Line: 1: total 108K
Line: 2: drwxrwxrwt 8 root root 12K Mar 10 02:30 .
Line: 3: drwxr-xr-x 26 root root 4.0K Feb 15 01:05 ..
Line: 4: -rwxr-xr-x 1 shaoran shaoran 16K Mar 9 22:29 a
Line: 5: -rw-r--r-- 1 shaoran shaoran 3.6K Mar 9 22:29 a.c
Line: 6: -rw------- 1 shaoran shaoran 16K Mar 9 22:29 .a.c.swp
Line: 7: -rwxr-xr-x 1 shaoran shaoran 11K Mar 10 02:30 b
Line: 8: -rw-r--r-- 1 shaoran shaoran 274 Mar 10 02:30 b.c
Line: 9: -rw------- 1 shaoran shaoran 12K Mar 10 02:30 .b.c.swp
Line: 10: drwx------ 2 shaoran shaoran 4.0K Mar 9 20:08 firefox_shaoran
Line: 11: drwxrwxrwt 2 root root 4.0K Mar 9 20:06 .ICE-unix
Line: 12: srwx------ 1 mongodb mongodb 0 Mar 9 20:07 mongodb-27017.sock
Line: 13: prwx------ 1 shaoran shaoran 0 Mar 9 20:08 oaucipc-c2s-1874
Line: 14: prwx------ 1 shaoran shaoran 0 Mar 9 20:08 oaucipc-s2c-1874
Line: 15: drwxrwxr-x 2 root utmp 4.0K Mar 9 20:06 screen
Line: 16: drwx------ 2 shaoran shaoran 4.0K Mar 9 20:07 ssh-XueH0w8zWCSE
Line: 17: drwx------ 2 shaoran shaoran 4.0K Mar 9 20:08 thunderbird_shaoran
Line: 18: -r--r--r-- 1 root root 11 Mar 9 20:07 .X0-lock
Line: 19: drwxrwxrwt 2 root root 4.0K Mar 9 20:07 .X11-unix
If you need more control and want also to read stderr
, then you would have to create pipes for stdout
and stderr
,
make a fork
and the child dup2
the pipes to stderr
& stdout
and
then execute exec
(or any other function of that family) to execute the
program.
Like this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
int stdout_pipe[2];
int stderr_pipe[2];
pipe(stdout_pipe);
pipe(stderr_pipe);
pid_t pid = fork();
if(pid < 0)
return 1;
if(pid == 0)
{
// closing reading ends and duplicating writing ends
close(stdout_pipe[0]);
dup2(stdout_pipe[1], STDOUT_FILENO);
close(stderr_pipe[0]);
dup2(stderr_pipe[1], STDERR_FILENO);
execlp("ls", "ls", "-alh", "a.c", "kslkdl", NULL);
exit(1);
}
// closing writing end
close(stdout_pipe[1]);
close(stderr_pipe[1]);
int status;
if(waitpid(pid, &status, 0) < 0)
{
fprintf(stderr, "could not wait\n");
return 1;
}
if(WIFEXITED(status) == 0)
{
fprintf(stderr, "ls exited abnormally\n");
close(stdout_pipe[0]);
close(stderr_pipe[0]);
return 1;
}
puts("STDOUT:");
char buffer[1024];
ssize_t len;
while((len = read(stdout_pipe[0], buffer, sizeof(buffer) - 1)) > 0)
{
buffer[len] = 0;
printf("%s", buffer);
}
putchar('\n');
close(stdout_pipe[0]);
puts("STDERR:");
while((len = read(stderr_pipe[0], buffer, sizeof(buffer) - 1)) > 0)
{
buffer[len] = 0;
printf("%s", buffer);
}
putchar('\n');
close(stderr_pipe[0]);
return 0;
}
which outputs:
$ ./b
STDOUT:
-rw-r--r-- 1 shaoran shaoran 3.6K Mar 9 22:29 a.c
STDERR:
ls: cannot access 'kslkdl': No such file or directory