Fix some greedy sed changes in imported code. Also provide a sys/types.h for compatib...
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / t_tkcmd.c
blobff12a2849401920a81a3d9f33ad44ce78dd55f4e
1 /* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5 #ifdef UNIX /* in unix this only works first; in NT it only works last. */
6 #include "tk.h"
7 #endif
9 #include "t_tk.h"
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14 #include <sys/types.h>
15 #ifdef UNIX
16 #include <unistd.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <netdb.h>
20 #ifdef HAVE_BSTRING_H
21 #include <bstring.h>
22 #endif
23 #include <sys/time.h>
24 #include <errno.h>
25 #endif
26 #ifdef MSW
27 #include <winsock.h>
28 #include <io.h>
29 #endif
30 #ifdef MSW
31 #pragma warning( disable : 4305 ) /* uncast const double to float */
32 #pragma warning( disable : 4244 ) /* uncast double to float */
33 #pragma warning( disable : 4101 ) /* unused local variables */
34 #endif
36 #ifdef MSW
37 #include "tk.h"
38 #endif
40 void tcl_mess(char *s);
42 /***************** the socket setup code ********************/
44 static int portno = 5400;
46 /* some installations of linux don't know about "localhost" so give
47 the loopback address; NT, on the other hand, can't understand the
48 hostname "127.0.0.1". */
49 char hostname[100] =
50 #ifdef __linux__
51 "127.0.0.1";
52 #else
53 "localhost";
54 #endif
56 void pdgui_setsock(int port)
58 portno = port;
61 void pdgui_sethost(char *name)
63 strncpy(hostname, name, 100);
64 hostname[99] = 0;
67 static void pdgui_sockerror(char *s)
69 #ifdef MSW
70 int err = WSAGetLastError();
71 #endif
72 #ifdef UNIX
73 int err = errno;
74 #endif
76 fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
77 tcl_mess("exit\n");
78 exit(1);
81 static int sockfd;
83 /* The "pd_suck" command, which polls the socket.
84 FIXME: if Pd sends something bigger than SOCKSIZE we're in trouble!
85 This has to be set bigger than any array update message for instance.
87 #define SOCKSIZE 20000
89 static char pd_tkbuf[SOCKSIZE+1];
90 int pd_spillbytes = 0;
92 static void pd_readsocket(ClientData cd, int mask)
94 int ngot;
95 fd_set readset, writeset, exceptset;
96 struct timeval timout;
98 timout.tv_sec = 0;
99 timout.tv_usec = 0;
100 FD_ZERO(&writeset);
101 FD_ZERO(&readset);
102 FD_ZERO(&exceptset);
103 FD_SET(sockfd, &readset);
104 FD_SET(sockfd, &exceptset);
106 if (select(sockfd+1, &readset, &writeset, &exceptset, &timout) < 0)
107 perror("select");
108 if (FD_ISSET(sockfd, &exceptset) || FD_ISSET(sockfd, &readset))
110 int ret;
111 ret = recv(sockfd, pd_tkbuf + pd_spillbytes,
112 SOCKSIZE - pd_spillbytes, 0);
113 if (ret < 0) pdgui_sockerror("socket receive error");
114 else if (ret == 0)
116 /* fprintf(stderr, "read %d\n", SOCKSIZE - pd_spillbytes); */
117 fprintf(stderr, "pd_gui: pd process exited\n");
118 tcl_mess("exit\n");
120 else
122 char *lastcr = 0, *bp = pd_tkbuf, *ep = bp + (pd_spillbytes + ret);
123 int brace = 0;
124 char lastc = 0;
125 while (bp < ep)
127 char c = *bp;
128 if (c == '}' && brace) brace--;
129 else if (c == '{') brace++;
130 else if (!brace && c == '\n' && lastc != '\\') lastcr = bp;
131 lastc = c;
132 bp++;
134 if (lastcr)
136 int xtra = pd_tkbuf + pd_spillbytes + ret - (lastcr+1);
137 char bashwas = lastcr[1];
138 lastcr[1] = 0;
139 tcl_mess(pd_tkbuf);
140 lastcr[1] = bashwas;
141 if (xtra)
143 /* fprintf(stderr, "x %d\n", xtra); */
144 memmove(pd_tkbuf, lastcr+1, xtra);
146 pd_spillbytes = xtra;
148 else
150 pd_spillbytes += ret;
156 #ifndef UNIX
157 /* if we aren't UNIX, we add a tcl command to poll the
158 socket for data. */
159 static int pd_pollsocketCmd(ClientData cd, Tcl_Interp *interp,
160 int argc, char **argv)
162 pd_readsocket(cd, 0);
163 return (TCL_OK);
165 #endif
167 void pdgui_setupsocket(void)
169 struct sockaddr_in server;
170 struct hostent *hp;
171 #ifdef UNIX
172 int retry = 10;
173 #else
174 int retry = 1;
175 #endif
176 #ifdef MSW
177 short version = MAKEWORD(2, 0);
178 WSADATA nobby;
180 if (WSAStartup(version, &nobby)) pdgui_sockerror("setup");
181 #endif
183 /* create a socket */
184 sockfd = socket(AF_INET, SOCK_STREAM, 0);
185 if (sockfd < 0) pdgui_sockerror("socket");
187 /* connect socket using hostname provided in command line */
188 server.sin_family = AF_INET;
190 hp = gethostbyname(hostname);
192 if (hp == 0)
194 fprintf(stderr,
195 "localhost not found (inet protocol not installed?)\n");
196 exit(1);
198 memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
200 /* assign client port number */
201 server.sin_port = htons((unsigned short)portno);
203 /* try to connect */
204 while (1)
206 if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) >= 0)
207 goto gotit;
208 retry--;
209 if (retry <= 0)
210 break;
211 /* In UNIX there's a race condition; the child won't be
212 able to connect before the parent (pd) has shed its
213 setuid-ness. In case this is the problem, sleep and
214 retry. */
215 else
217 #ifdef UNIX
218 fd_set readset, writeset, exceptset;
219 struct timeval timout;
221 timout.tv_sec = 0;
222 timout.tv_usec = 100000;
223 FD_ZERO(&writeset);
224 FD_ZERO(&readset);
225 FD_ZERO(&exceptset);
226 fprintf(stderr, "retrying connect...\n");
227 if (select(1, &readset, &writeset, &exceptset, &timout) < 0)
228 perror("select");
229 #endif /* UNIX */
232 pdgui_sockerror("connecting stream socket");
233 gotit: ;
234 #ifdef UNIX
235 /* in unix we ask TK to call us back. In NT we have to poll. */
236 Tk_CreateFileHandler(sockfd, TK_READABLE | TK_EXCEPTION,
237 pd_readsocket, 0);
238 #endif /* UNIX */
241 /**************************** commands ************************/
242 static char *pdgui_path;
244 /* The "pd" command, which cats its args together and throws the result
245 * at the Pd interpreter.
247 #define MAXWRITE 1024
249 static int pdCmd(ClientData cd, Tcl_Interp *interp, int argc, char **argv)
251 if (argc == 2)
253 int n = strlen(argv[1]);
254 if (send(sockfd, argv[1], n, 0) < n)
256 perror("stdout");
257 tcl_mess("exit\n");
260 else
262 int i;
263 char buf[MAXWRITE];
264 buf[0] = 0;
265 for (i = 1; i < argc; i++)
267 if (strlen(argv[i]) + strlen(buf) + 2 > MAXWRITE)
269 interp->result = "pd: arg list too long";
270 return (TCL_ERROR);
272 if (i > 1) strcat(buf, " ");
273 strcat(buf, argv[i]);
275 if (send(sockfd, buf, strlen(buf), 0) < 0)
277 perror("stdout");
278 tcl_mess("exit\n");
281 return (TCL_OK);
284 /*********** "c" level access to tk functions. ******************/
286 static Tcl_Interp *tk_myinterp;
288 void tcl_mess(char *s)
290 int result;
291 result = Tcl_Eval(tk_myinterp, s);
292 if (result != TCL_OK)
294 if (*tk_myinterp->result) printf("%s\n", tk_myinterp->result);
298 /* LATER should do a bounds check -- but how do you get printf to do that? */
299 void tcl_vmess(char *fmt, ...)
301 int result, i;
302 char buf[MAXWRITE];
303 va_list ap;
305 va_start(ap, fmt);
307 vsprintf(buf, fmt, ap);
308 result = Tcl_Eval(tk_myinterp, buf);
309 if (result != TCL_OK)
311 if (*tk_myinterp->result) printf("%s\n", tk_myinterp->result);
313 va_end(ap);
316 #ifdef UNIX
317 void pdgui_doevalfile(Tcl_Interp *interp, char *s)
319 char buf[GUISTRING];
320 sprintf(buf, "set pd_guidir \"%s\"\n", pdgui_path);
321 tcl_mess(buf);
322 strcpy(buf, pdgui_path);
323 strcat(buf, "/bin/");
324 strcat(buf, s);
325 if (Tcl_EvalFile(interp, buf) != TCL_OK)
327 char buf2[1000];
328 sprintf(buf2, "puts [concat tcl: %s: can't open script]\n",
329 buf);
330 tcl_mess(buf2);
334 void pdgui_evalfile(char *s)
336 pdgui_doevalfile(tk_myinterp, s);
338 #endif
340 void pdgui_startup(Tcl_Interp *interp)
343 /* save pointer to the main interpreter */
344 tk_myinterp = interp;
347 /* add our own TK commands */
348 Tcl_CreateCommand(interp, "pd", (Tcl_CmdProc*)pdCmd, (ClientData)NULL,
349 (Tcl_CmdDeleteProc *)NULL);
350 #ifndef UNIX
351 Tcl_CreateCommand(interp, "pd_pollsocket",(Tcl_CmdProc*) pd_pollsocketCmd,
352 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
353 #endif
354 pdgui_setupsocket();
356 /* read in the startup file */
357 #if !defined(MSW) && !defined(MACOSX)
358 pdgui_evalfile("pd.tk");
359 #endif
362 #ifdef UNIX
363 void pdgui_setname(char *s)
365 char *t;
366 char *str;
367 int n;
368 if (t = strrchr(s, '/')) str = s, n = (t-s) + 1;
369 else str = "./", n = 2;
370 if (n > GUISTRING-100) n = GUISTRING-100;
371 pdgui_path = malloc(n+9);
373 strncpy(pdgui_path, str, n);
374 while (strlen(pdgui_path) > 0 && pdgui_path[strlen(pdgui_path)-1] == '/')
375 pdgui_path[strlen(pdgui_path)-1] = 0;
376 if (t = strrchr(pdgui_path, '/'))
377 *t = 0;
379 #endif
381 int Pdtcl_Init(Tcl_Interp *interp)
383 const char *myvalue = Tcl_GetVar(interp, "argv", 0);
384 int myportno;
385 if (myvalue && (myportno = atoi(myvalue)) > 1)
386 pdgui_setsock(myportno);
387 tk_myinterp = interp;
388 pdgui_startup(interp);
389 interp->result = "loaded pdtcl_init";
391 return (TCL_OK);
394 int Pdtcl_SafeInit(Tcl_Interp *interp) {
395 fprintf(stderr, "Pdtcl_Safeinit 51\n");
396 return (TCL_OK);