]> git.deb.at Git - pkg/netris.git/blob - robot.c
Bump Standards-Version to 3.9.0
[pkg/netris.git] / robot.c
1 /*
2  * Netris -- A free networked version of T*tris
3  * Copyright (C) 1994,1995,1996  Mark H. Weaver <mhw@netris.org>
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * $Id: robot.c,v 1.8 1996/02/09 08:22:15 mhw Exp $
20  */
21
22 #include "netris.h"
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <sys/types.h>
29 #include <fcntl.h>
30 #include <errno.h>
31
32 static MyEventType RobotGenFunc(EventGenRec *gen, MyEvent *event);
33
34 static EventGenRec robotGen =
35                 { NULL, 0, FT_read, -1, RobotGenFunc, EM_robot };
36
37 static int robotProcess;
38 static FILE *toRobot;
39 static int toRobotFd, fromRobotFd;
40
41 static char robotBuf[128];
42 static int robotBufSize, robotBufMsg;
43
44 static int gotSigPipe;
45
46 ExtFunc void InitRobot(char *robotProg)
47 {
48         int to[2], from[2];
49         int status;
50         MyEvent event;
51
52         signal(SIGPIPE, CatchPipe);
53         AtExit(CloseRobot);
54         if (pipe(to) || pipe(from))
55                 die("pipe");
56         robotProcess = fork();
57         if (robotProcess < 0)
58                 die("fork");
59         if (robotProcess == 0) {
60                 dup2(to[0], STDIN_FILENO);
61                 dup2(from[1], STDOUT_FILENO);
62                 close(to[0]);
63                 close(to[1]);
64                 close(from[0]);
65                 close(from[1]);
66                 execl("/bin/sh", "sh", "-c", robotProg, NULL);
67                 die("execl failed");
68         }
69         close(to[0]);
70         close(from[1]);
71         toRobotFd = to[1];
72         robotGen.fd = fromRobotFd = from[0];
73         if (!(toRobot = fdopen(toRobotFd, "w")))
74                 die("fdopen");
75         if ((status = fcntl(fromRobotFd, F_GETFL, 0)) < 0)
76                 die("fcntl/F_GETFL");
77         status |= O_NONBLOCK;
78         if (fcntl(fromRobotFd, F_SETFL, status) < 0)
79                 die("fcntl/F_SETFL");
80         AddEventGen(&robotGen);
81         RobotCmd(1, "Version %d\n", ROBOT_VERSION);
82         if (WaitMyEvent(&event, EM_robot) != E_robot)
83                 fatal("Robot didn't start successfully");
84         if (1 > sscanf(event.u.robot.data, "Version %d", &robotVersion)
85                         || robotVersion < 1)
86                 fatal("Invalid Version line from robot");
87         if (robotVersion > ROBOT_VERSION)
88                 robotVersion = ROBOT_VERSION;
89 }
90
91 ExtFunc void CatchPipe(int sig)
92 {
93         robotGen.ready = gotSigPipe = 1;
94 }
95
96 ExtFunc void RobotCmd(int flush, char *fmt, ...)
97 {
98         va_list args;
99
100         va_start(args, fmt);
101         vfprintf(toRobot, fmt, args);
102         va_end(args);
103         if (flush)
104                 fflush(toRobot);
105 }
106
107 ExtFunc void RobotTimeStamp(void)
108 {
109         RobotCmd(1, "TimeStamp %.3f\n", CurTimeval() / 1.0e6);
110 }
111
112 ExtFunc void CloseRobot(void)
113 {
114         RemoveEventGen(&robotGen);
115         if (robotProcess > 0)
116                 RobotCmd(1, "Exit\n");
117         fclose(toRobot);
118         close(fromRobotFd);
119 }
120
121 static MyEventType RobotGenFunc(EventGenRec *gen, MyEvent *event)
122 {
123         static int more;
124         int result, i;
125         char *p;
126
127         if (gotSigPipe) {
128                 gotSigPipe = 0;
129                 robotGen.ready = more;
130                 return E_lostRobot;
131         }
132         if (robotBufMsg > 0) {
133                 /*
134                  *      Grrrrrr!  SunOS 4.1 doesn't have memmove (or atexit)
135                  *  I'm told some others have a broken memmove
136                  *
137                  *      memmove(robotBuf, robotBuf + robotBufMsg,
138                  *                      robotBufSize - robotBufMsg);
139                  */
140                 for (i = robotBufMsg; i < robotBufSize; ++i)
141                         robotBuf[i - robotBufMsg] = robotBuf[i];
142
143                 robotBufSize -= robotBufMsg;
144                 robotBufMsg = 0;
145         }
146         if (more)
147                 more = 0;
148         else {
149                 do {
150                         result = read(fromRobotFd, robotBuf + robotBufSize,
151                                         sizeof(robotBuf) - robotBufSize);
152                 } while (result < 0 && errno == EINTR);
153                 if (result <= 0)
154                         return E_lostRobot;
155                 robotBufSize += result;
156         }
157         if (!(p = memchr(robotBuf, '\n', robotBufSize))) {
158                 if (robotBufSize >= sizeof(robotBuf))
159                         fatal("Line from robot is too long");
160                 return E_none;
161         }
162         *p = 0;
163         robotBufMsg = p - robotBuf + 1;
164         robotGen.ready = more = (memchr(robotBuf + robotBufMsg, '\n',
165                         robotBufSize - robotBufMsg) != NULL);
166         event->u.robot.size = p - robotBuf;
167         event->u.robot.data = robotBuf;
168         return E_robot;
169 }
170
171 /*
172  * vi: ts=4 ai
173  * vim: noai si
174  */