Search code examples
cconsolegtk3

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=%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


Solution

  • 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