Realize a console in a GTK3 GUI programming in C


Realize a console in a GTK3 GUI programming in C



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=%dn",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 need to improve your answer to tell a lot more about your exe program.
– Basile Starynkevitch
Mar 10 at 2:28


exe





Without more information about that exe program your question is unclear. Is that exe program always running very quickly (in a fraction of a second) like e.g. some ps command?
– Basile Starynkevitch
Mar 10 at 2:45



exe


exe


ps





The exe program is designed to performs the measurement of a physical variable. After the configuration of several instruments via LAN, it start to make measurements. The time needed to ends all measurements is, more or less, about 1 hour. What I want displays on the console is something like: "Total N. points of measurements 1000" "Measured 3 points of 1000" "Measured 4 points of 1000" etc.
– arkkimede
Mar 10 at 9:32






That should go in the question
– Basile Starynkevitch
Mar 10 at 11:30





I have rollbacked your heavy changes to the question after it got answered twice. Please do not include a solution in your question itself: instead, post your own answer (or edit the deleted one that you already made, then flag it for undeletion).
– Cœur
Jul 1 at 10:11





2 Answers
2



You should use popen instead of executing system("exe input.dat &"), then it's easy to read from the stdout output of the program.


popen


system("exe input.dat &")


stdout



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.


stderr


stdout


stderr


fork


dup2


stderr


stdout


exec



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 waitn");
return 1;
}

if(WIFEXITED(status) == 0)
{
fprintf(stderr, "ls exited abnormallyn");
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





Pablo, thank you for your codes. I will try to use them.
– arkkimede
Mar 10 at 9:59



Pablo's answer is correct, you need to use pipe(7)-s.



And you could probably use GTK & Glib's g_spawn_async_with_pipes (which is based on pipe and fork and execve on Linux) for that (instead of fork or popen). In a GTK interactive program, it is better than the usual popen because the forked program would run concurrently with your event loop.


g_spawn_async_with_pipes


pipe


fork


execve


fork


popen


popen



You could even consider using g_source_add_unix_fd on the (or on some) of the pipe fd-s given by pipe(2) or by g_spawn_async_with_pipes which use that pipe(2) call. But you might prefer g_io_channel_unix_new and g_io_add_watch


g_source_add_unix_fd


g_spawn_async_with_pipes


g_io_channel_unix_new


g_io_add_watch



Be aware that the GTK main loop (and Gtk Input and Event Handling Model), i.e. GtkApplication and the related g_application_run or the older gtk_main are an event loop around some multiplexing system call like poll(2) (or the older select(2)) and you probably need that loop to be aware of your pipes. When some data arrives on the pipe, you probably want to read(2) it (and then call some GtkTextBuffer insert function).


g_application_run


gtk_main



You should make design choices: do you want the GUI interface and the other process to run concurrently? Or is the other exe process always so quick and with a small output (and no input) that you might just use popen?


exe


popen



On current GUI applications, the event loop should run quickly (at least 30 or 50 times per second) if you want a responsive GUI app.



Look also for inspiration inside the source code of some existing free software GTK application (e.g. on github or from your Linux distro).





Nice answer. I haven't used GTK other than for trivial "hello world" programs, so I didn't know about any of these functions.
– Pablo
Mar 10 at 2:15






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

List of Kim Possible characters

Audio Livestreaming with Python & Flask

NSwag: Generate C# Client from multiple Versions of an API