--- On Wed, 8/25/10, richard boaz <[email protected]> wrote:

From: richard boaz <[email protected]>
Subject: GIOChannel & Intercepting stdout
To: "gtk-list" <[email protected]>
Date: Wednesday, August 25, 2010, 3:31 AM

So, after tweaking the attached program and pulling veritable tufts of hair, I 
am not one inch closer to understanding how GIOChannel should work, nor how it 
is actually working, in my particular case.  Which leads me to conclude that I 
suffer from a rather fundamental lack of understanding as to how GIOChannel 
should behave for this particular example.


What I want to do: wrap stdout (and eventually stderr as well) with GIOChannel 
within my program so that all messages going to stdout are intercepted (via 
g_io_add_watch()) for more processing.  I realize there are many other ways to 
solve this problem, except that my situation/requirements disallow them, since 
I need to: 

handle stdout and stderr messages being written to by libraries employed by my 
program that are external, i.e., i can't rewrite them to make their messages go 
elsewhere; and,



these messages need to go to two places, both a file and to a DB; and,



I would ideally like to intercept known error conditions and handle them 
real-time (thus requiring no user intervention).

My reading of GIOChannel functionality renders my usage understanding to 
be:create a channel using the file descriptor (in this case STDOUT_FILENO)

add a watch on the conditions of interest (in this case G_IO_IN)start the main 
loop

read the data on the channel within my callback and process accordingly

Which, I think, would result in:
the callback being called with condition G_IO_IN whenever anything is written 
to stdout

Except that I don't experience anything close to this result.
Below is sample code demonstrating what I'm trying to achieve here, but 
basically, it:creates a GIOChannel on stdout

adds a watch on condition G_IO_INadds an idle routine to write a message to 
stdoutstarts the main loopAs I said, what I would expect from this:callback 
fired with condition G_IO_IN when idle call writes to stdout

However, when this executes, I get:the test message output to the terminal 
(completely bypassing the callback routine)the callback gets fired only after 
the <ENTER> key is hit on the keyboard, with nothing to be read from the 
channel.  (huh?...)

Swapping the commented call to g_io_add_watch() (adding condition G_IO_OUT) 
also results in not understood results.  When this version executes, the 
callback fires immediately (before the idle call).  Further, when taking this 
path (G_IO_OUT) and subsequently writing to the channel (still stdout) using 
g_io_write_chars(), this output also goes directly to the terminal.


I have scoured the internet for two days to no avail (including google code 
search).  There are abundant examples of trapping stdout and stderr from 
spawned processes from within a program, but I could find no example doing what 
I would need to do here.  I have also tweaked the code below 1.1 million 
different ways (okay, i exaggerate somewhat, but only a little) and come no 
closer to understanding:

why it behaves the way it doeshow my understanding of how it should work is 
wronghow it needs to really be written to achieve what I need it to doWhat am I 
missing here?  Am I doing something that is "not allowed" or simply not 
possible?  If solving my problem is not possible with GIOChannel, is there 
another way I'm also yet unaware of?  But surely it is not true that GIOChannel 
can trap stdin, stdout, and stderr streams from spawned/child processes but not 
its own?


Any and all insight here is greatly appreciated.  My hope is that I'm just 
stupid and missing something totally obvious, i.e., that I'll be able to solve 
my problem elegantly with GIOChannel.


thanks in advance for any advice,
richard
p.s. OS = Ubuntu 9.10, glib = 2.22.3

==== BEGIN SAMPLE CODE =====

// save to: io.c// compile as: gcc io.c `pkg-config --cflags --libs glib-2.0`
#include <glib.h>

#include <stdio.h>#include <string.h>
gboolean my_callback(GIOChannel *source, GIOCondition condition, gpointer 
data){  GMainLoop *loop = (GMainLoop *) data;

  gchar *buf=NULL;  GError *error = NULL;
  switch (condition)  {    case G_IO_IN:      fprintf(stderr, "callback: 
condition G_IO_IN (%d)\n", condition);

      g_io_channel_read_line(source, &buf, NULL, NULL, &error);      if (buf)   
   {        FILE *fp = fopen("/tmp/test.out", "w+");        fprintf(fp, "%s", 
buf);

        g_free(buf);        fclose(fp);      }      g_main_loop_quit(loop);     
               // kill main loop, i.e., force pgm exit      
g_io_channel_shutdown(source,TRUE,NULL);   // close channel

    break;    case G_IO_OUT:    {      char *str = g_strdup("string OUT via 
g_io_channel_write_chars()\n");      fprintf(stderr, "callback: condition 
G_IO_OUT (%d)\n", condition);

      g_io_channel_read_line(source, &buf, NULL, NULL, &error);      if (buf)   
   {        fprintf(stderr, "read on channel returned data (%s)\n", buf);
        g_free(buf);
      }      else      {        fprintf(stderr, "read on channel returned NO 
data\n");      }      g_io_channel_write_chars(source, str, strlen(str), NULL, 
NULL);

      g_free(str);    }    break;    case G_IO_PRI:      fprintf(stderr, 
"callback: condition G_IO_PRI (%d)\n", condition);    break;    case G_IO_ERR:

      fprintf(stderr, "callback: condition G_IO_ERR (%d)\n", condition);    
break;    case G_IO_HUP:      fprintf(stderr, "callback: condition G_IO_HUP 
(%d)\n", condition);

    break;    case G_IO_NVAL:      fprintf(stderr, "callback: condition 
G_IO_NVAL (%d)\n", condition);    break;    default:      fprintf(stderr, 
"callback: unhandled condition (%d)\n", condition);

    break;  }
  return FALSE;}
gboolean idle_function(gpointer nil){  // write test message to 
stdout  fprintf(stdout, "test\n" );

  return FALSE;  // remove}
int main(){  GMainLoop *loop = g_main_loop_new(NULL,FALSE);  GIOChannel 
*channel;  int fd;


  g_idle_add((GSourceFunc) idle_function, NULL);
  fd = fileno(stdout);                             // fd = 
STDOUT_FILENO  channel = g_io_channel_unix_new(fd);             // wrap stdout 
with GIOChannel

  g_io_channel_set_encoding(channel, NULL, NULL);  // accept binary, allow no 
buffering  g_io_channel_set_buffered(channel, FALSE);       // don't 
buffer  g_io_add_watch(channel, G_IO_IN,(GIOFunc) my_callback, loop);

//  g_io_add_watch(channel, G_IO_IN | G_IO_OUT,(GIOFunc) my_callback, loop);
  g_main_loop_run(loop);    return 0;}


==== END SAMPLE CODE =====

-----Inline Attachment Follows-----

_______________________________________________
gtk-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/gtk-list

Richard,

maybe your problem has a generic solution. I thought along the following
lines:

1) you create a /bin/sh wrapper for your application and invoke it this
way:

your_app 1>your_app_stdout 2>your_app_stderr

2) by gtk+ means you watch your_app_stdout, your_app_stderr files which
now are actually not files opened by your application, but by the shell
wrapper, and if I understood your correctly, for foreign applications
watching works.

Furthermore, maybe your_app_stdout and your_app_stderr can be named
pipes, though I'm not sure it truly yields benefits.

Regards,
  Sergei.



      
_______________________________________________
gtk-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/gtk-list

Reply via email to