Thanks, David, now it's working.
After I saw your message I added fflush(stdout) after the printf to gnugo.
That isn't the first thing I tried but I don't really want to tell everyone how stupid I was. But now that I've rebooted my computer ...
This may have fixed the other problem too which was apparently caused by the EOF that comes down stdin when you type a ^D (one way to terminate metamachine) not getting flushed. Unclear, but I don't have a lingering gnugo process this time.
The current (working) version looks like this.
Dan
#include <stdio.h> #include <unistd.h>
void error(const char *msg);
/* This program uses two pipes to communicate with the * GNU Go client. To an external client it appears to * be a gtp engine. It accomplishes this by intercepting * gtp commands and passing them on to GNU Go. * * This program in and of itself is not useful but it * can be the basis of useful programs. Example: hack * in gmp.c and get a gtp / gmp translator. * * Pipe a: client --> gnugo * Pipe b: gnugo --> client */
int main() { int pfd_a[2]; int pfd_b[2]; char gnugo_line[128], client_line[128]; int length = 0; FILE *to_gnugo_stream, *from_gnugo_stream;
if (pipe(pfd_a) == -1) error("can't open pipe a"); if (pipe(pfd_b) == -1) error("can't open pipe b"); switch(fork()) { case -1: error("fork failed (try chopsticks)"); case 0: /* Attach pipe a to stdin */ if (close(0) == -1) error("close(0) failed"); if (dup(pfd_a[0]) != 0) error("dup pfd_a[0] failed"); /* attach pipe b to stdout" */ if (close(1) == -1) error("close(1) failed"); if (dup(pfd_b[1]) != 1) error("dup pfd_b[1] failed"); execlp("gnugo", "gnugo", "--mode", "gtp", "--quiet", NULL); error("execlp failed"); } /* We use stderr to communicate with the client since stdout is needed. */ /* Attach pipe a to to_gnugo_stream */ to_gnugo_stream = fdopen(pfd_a[1], "w"); /* Attach pipe b to from_gnugo_stream */ from_gnugo_stream = fdopen(pfd_b[0], "r");
while (1) { int length = 0;
if (!fgets(client_line, 128, stdin)) error("can't get command\n"); if (!strncmp(client_line, "quit", 4)) { fprintf(to_gnugo_stream, "%s", "quit\n"); fflush(to_gnugo_stream); return 1; }
if (fprintf(to_gnugo_stream, "%s", client_line) < 0) error("can't write command to to_gnugo_stream"); fflush(to_gnugo_stream); while (length != 1) { if (!fgets(gnugo_line, 128, from_gnugo_stream)) error("can't get response"); length = strlen(gnugo_line); printf(gnugo_line); fflush(stdout); } } }
void error(const char *msg) { fprintf(stderr, "metamachine: %s\n", msg); abort(); }
void setlinebuf(FILE *stream);
Dan,
You might prefer to use the setlinebuf call.
setlinebuf(stdout);
This makes all printf's to stdout flush whenever a \n is encountered, makes the code a little nicer and covers your butt if you forget somewhere to use fflush.
Don
Date: Tue, 28 Aug 2001 11:30:05 -0700 X-Authentication-Warning: match.Stanford.EDU: bump set sender to bump@match.Stanford.EDU using -f From: Daniel Bump bump@match.stanford.edu CC: gnugo@gnu.org, gtp@lists.lysator.liu.se Content-Type: text Content-Length: 2759
Thanks, David, now it's working.
After I saw your message I added fflush(stdout) after the printf to gnugo.
That isn't the first thing I tried but I don't really want to tell everyone how stupid I was. But now that I've rebooted my computer ...
This may have fixed the other problem too which was apparently caused by the EOF that comes down stdin when you type a ^D (one way to terminate metamachine) not getting flushed. Unclear, but I don't have a lingering gnugo process this time.
The current (working) version looks like this.
Dan
#include <stdio.h> #include <unistd.h>
void error(const char *msg);
/* This program uses two pipes to communicate with the * GNU Go client. To an external client it appears to * be a gtp engine. It accomplishes this by intercepting * gtp commands and passing them on to GNU Go. * * This program in and of itself is not useful but it * can be the basis of useful programs. Example: hack * in gmp.c and get a gtp / gmp translator. * * Pipe a: client --> gnugo * Pipe b: gnugo --> client */
int main() { int pfd_a[2]; int pfd_b[2]; char gnugo_line[128], client_line[128]; int length = 0; FILE *to_gnugo_stream, *from_gnugo_stream;
if (pipe(pfd_a) == -1) error("can't open pipe a"); if (pipe(pfd_b) == -1) error("can't open pipe b"); switch(fork()) { case -1: error("fork failed (try chopsticks)"); case 0: /* Attach pipe a to stdin */ if (close(0) == -1) error("close(0) failed"); if (dup(pfd_a[0]) != 0) error("dup pfd_a[0] failed"); /* attach pipe b to stdout" */ if (close(1) == -1) error("close(1) failed"); if (dup(pfd_b[1]) != 1) error("dup pfd_b[1] failed"); execlp("gnugo", "gnugo", "--mode", "gtp", "--quiet", NULL); error("execlp failed"); } /* We use stderr to communicate with the client since stdout is needed. */ /* Attach pipe a to to_gnugo_stream */ to_gnugo_stream = fdopen(pfd_a[1], "w"); /* Attach pipe b to from_gnugo_stream */ from_gnugo_stream = fdopen(pfd_b[0], "r");
while (1) { int length = 0;
if (!fgets(client_line, 128, stdin)) error("can't get command\n"); if (!strncmp(client_line, "quit", 4)) { fprintf(to_gnugo_stream, "%s", "quit\n"); fflush(to_gnugo_stream); return 1; }
if (fprintf(to_gnugo_stream, "%s", client_line) < 0) error("can't write command to to_gnugo_stream"); fflush(to_gnugo_stream); while (length != 1) { if (!fgets(gnugo_line, 128, from_gnugo_stream)) error("can't get response"); length = strlen(gnugo_line); printf(gnugo_line); fflush(stdout); } } }
void error(const char *msg) { fprintf(stderr, "metamachine: %s\n", msg); abort(); }
You might prefer to use the setlinebuf call.
setlinebuf(stdout);
This makes all printf's to stdout flush whenever a \n is encountered, makes the code a little nicer and covers your butt if you forget somewhere to use fflush.
Thanks. I may or may not end up doing this but I appreciate learning all my options.
One of the applications I have in mind is a metaengine into which you can plug an engine like GNU Go and get another engine that's stronger and slower because it does limited full board search through the GTP. I'm past the point where I was stuck in the pipes thanks to David Denholm.
So we'll see if the experiment works ...
Dan