/* child.c input buffer, fork child, main loop */ /* * xcheckers: a point and click checkerboard * (C): 1999, 2000 Peter Chiocchetti * this part from xics-2.3 bye Shirish Chinchalkar, * Urban Koistinen, Nelson Minar and Patrick Surry */ #include #include #include #include #include #include #include #include #include #include #include "xcheckers.h" #include "resource.h" #include "status.h" #include "read.h" #include "events.h" #define syserr(string) (perror(string), exit(1)) #define fatal(string) (printf("ERROR : %s\n", string), exit(1)) int pfdout[2]; /* split engine output into lines */ static void packbuf(char *buf, int nbytes, int icds) { /* packs buffer; eliminates CR's and calls readPos[S5] */ static char savebuf[512]; static int index = 0; int i; /* search for a CR */ for (i = 0; i < nbytes; i++) { if (buf[i] != '\n' && buf[i] != (char) 13) { savebuf[index] = buf[i]; index++; } if (buf[i] == '\n') { /* buffer ready. display it */ savebuf[index] = '\0'; readPos5(savebuf); readPosS(savebuf); index = 0; } } } /* start engine, process engine and player input */ void loop(char *hostname, char *portnum, int icds) { int pfdin[2], nbytes; char buf[512]; char move[80]; int done = 0; fd_set fileSet; /* nelson@reed.edu */ fd_set *readFDs = &fileSet; /* used for select */ int xServerFD = ConnectionNumber(dpy); /* watch here, too! */ int nds; int childpid; int rc; struct timeval timeout; setvbuf(stdout, NULL, _IONBF, 0); if (pipe(pfdout) == -1 || pipe(pfdin) == -1) syserr("pipe"); childpid = fork(); switch (childpid) { case -1: syserr("fork"); break; case 0: if (close(0) == -1) syserr("close"); if (dup(pfdout[0]) != 0) fatal("dup"); if (close(1) == -1) syserr("close"); if (dup(pfdin[1]) != 1) fatal("dup"); if (close(pfdout[0]) == -1 || close(pfdout[1]) == -1 || close(pfdin[0]) == -1 || close(pfdin[1]) == -1) syserr("close"); if (close(xServerFD) == -1) syserr("close"); if (icds) execlp("telnet", "telnet", hostname, portnum, NULL); else execlp("sh", "sh", "-c", hostname, NULL); syserr("execlp"); } if (close(pfdout[0]) == -1 || close(pfdin[1]) == -1) syserr("close"); /* * main read loop for the program. Look for things from the keyboard, from * telnet, or from the X server. nelson@reed.edu - replace original non * blocking IO with regular blocking IO, by calling select() to allow for * multiple input sources. this is much more efficient and fixes bugs. */ nds = (pfdin[0] > xServerFD ? pfdin[0] : xServerFD) + 1; while (!done) { FD_ZERO(readFDs); /* nelson@reed.edu */ FD_SET(0, readFDs); /* we care about these 3 */ FD_SET(pfdin[0], readFDs); /* file descriptors */ FD_SET(xServerFD, readFDs); /* kbd, telnet, and X */ checkClock(); timeout.tv_sec = 1; timeout.tv_usec = 0; rc = select(nds, readFDs, 0, 0, &timeout); /* wait for input */ if (rc < 0) syserr("select"); if (FD_ISSET(0, readFDs)) { nbytes = read(0, buf, sizeof(buf)); if (nbytes <= 0) syserr("read stdin"); if (write(pfdout[1], buf, nbytes) == -1) syserr("pfdout[1]"); } if (FD_ISSET(pfdin[0], readFDs)) { nbytes = read(pfdin[0], buf, sizeof(buf)); if (nbytes == 0) { if (icds) fprintf(stderr, "%s: Server hung up!\n", progname); else fprintf(stderr, "%s: Engine shut down!\n", progname); return; } else if (nbytes < 0) { syserr("read pfdin[0]"); } if (write(1, buf, nbytes) == -1) syserr("write stdout"); packbuf(buf, nbytes, icds); } if (FD_ISSET(xServerFD, readFDs)) { if (events(move)) { /* * made a move. print it on the screen and * send it to ICS */ if (strcmp(move, "exit") == 0) { fprintf(stdout, "\n"); done = 1; /* will exit soon */ } else { fprintf(stdout, "%s", move); fflush(stdout); nbytes = strlen(move); if (write(pfdout[1], move, nbytes) == -1) syserr("write"); } } } } if (close(pfdin[0]) == -1) syserr("close"); if (close(pfdout[1]) == -1) syserr("close"); /* telnet quits */ /* in case telnet is still alive, kill it */ if (!kill(childpid, SIGKILL)) waitpid(childpid, NULL, 0); } /* send a string to the engine */ void message(char *mess) { int nbytes = strlen(mess); fprintf(stdout, "%s", mess); fflush(stdout); if (write(pfdout[1], mess, nbytes) == -1) syserr("write"); free(mess); }