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. */
14 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
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 */
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". */
56 void pdgui_setsock(int port
)
61 void pdgui_sethost(char *name
)
63 strncpy(hostname
, name
, 100);
67 static void pdgui_sockerror(char *s
)
70 int err
= WSAGetLastError();
76 fprintf(stderr
, "%s: %s (%d)\n", s
, strerror(err
), err
);
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
)
95 fd_set readset
, writeset
, exceptset
;
96 struct timeval timout
;
103 FD_SET(sockfd
, &readset
);
104 FD_SET(sockfd
, &exceptset
);
106 if (select(sockfd
+1, &readset
, &writeset
, &exceptset
, &timout
) < 0)
108 if (FD_ISSET(sockfd
, &exceptset
) || FD_ISSET(sockfd
, &readset
))
111 ret
= recv(sockfd
, pd_tkbuf
+ pd_spillbytes
,
112 SOCKSIZE
- pd_spillbytes
, 0);
113 if (ret
< 0) pdgui_sockerror("socket receive error");
116 /* fprintf(stderr, "read %d\n", SOCKSIZE - pd_spillbytes); */
117 fprintf(stderr
, "pd_gui: pd process exited\n");
122 char *lastcr
= 0, *bp
= pd_tkbuf
, *ep
= bp
+ (pd_spillbytes
+ ret
);
128 if (c
== '}' && brace
) brace
--;
129 else if (c
== '{') brace
++;
130 else if (!brace
&& c
== '\n' && lastc
!= '\\') lastcr
= bp
;
136 int xtra
= pd_tkbuf
+ pd_spillbytes
+ ret
- (lastcr
+1);
137 char bashwas
= lastcr
[1];
143 /* fprintf(stderr, "x %d\n", xtra); */
144 memmove(pd_tkbuf
, lastcr
+1, xtra
);
146 pd_spillbytes
= xtra
;
150 pd_spillbytes
+= ret
;
157 /* if we aren't UNIX, we add a tcl command to poll the
159 static int pd_pollsocketCmd(ClientData cd
, Tcl_Interp
*interp
,
160 int argc
, char **argv
)
162 pd_readsocket(cd
, 0);
167 void pdgui_setupsocket(void)
169 struct sockaddr_in server
;
177 short version
= MAKEWORD(2, 0);
180 if (WSAStartup(version
, &nobby
)) pdgui_sockerror("setup");
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
);
195 "localhost not found (inet protocol not installed?)\n");
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
);
206 if (connect(sockfd
, (struct sockaddr
*) &server
, sizeof (server
)) >= 0)
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
218 fd_set readset
, writeset
, exceptset
;
219 struct timeval timout
;
222 timout
.tv_usec
= 100000;
226 fprintf(stderr
, "retrying connect...\n");
227 if (select(1, &readset
, &writeset
, &exceptset
, &timout
) < 0)
232 pdgui_sockerror("connecting stream socket");
235 /* in unix we ask TK to call us back. In NT we have to poll. */
236 Tk_CreateFileHandler(sockfd
, TK_READABLE
| TK_EXCEPTION
,
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
)
253 int n
= strlen(argv
[1]);
254 if (send(sockfd
, argv
[1], n
, 0) < n
)
265 for (i
= 1; i
< argc
; i
++)
267 if (strlen(argv
[i
]) + strlen(buf
) + 2 > MAXWRITE
)
269 interp
->result
= "pd: arg list too long";
272 if (i
> 1) strcat(buf
, " ");
273 strcat(buf
, argv
[i
]);
275 if (send(sockfd
, buf
, strlen(buf
), 0) < 0)
284 /*********** "c" level access to tk functions. ******************/
286 static Tcl_Interp
*tk_myinterp
;
288 void tcl_mess(char *s
)
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
, ...)
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
);
317 void pdgui_doevalfile(Tcl_Interp
*interp
, char *s
)
320 sprintf(buf
, "set pd_guidir \"%s\"\n", pdgui_path
);
322 strcpy(buf
, pdgui_path
);
323 strcat(buf
, "/bin/");
325 if (Tcl_EvalFile(interp
, buf
) != TCL_OK
)
328 sprintf(buf2
, "puts [concat tcl: %s: can't open script]\n",
334 void pdgui_evalfile(char *s
)
336 pdgui_doevalfile(tk_myinterp
, s
);
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
);
351 Tcl_CreateCommand(interp
, "pd_pollsocket",(Tcl_CmdProc
*) pd_pollsocketCmd
,
352 (ClientData
)NULL
, (Tcl_CmdDeleteProc
*)NULL
);
356 /* read in the startup file */
357 #if !defined(MSW) && !defined(MACOSX)
358 pdgui_evalfile("pd.tk");
363 void pdgui_setname(char *s
)
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
, '/'))
381 int Pdtcl_Init(Tcl_Interp
*interp
)
383 const char *myvalue
= Tcl_GetVar(interp
, "argv", 0);
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";
394 int Pdtcl_SafeInit(Tcl_Interp
*interp
) {
395 fprintf(stderr
, "Pdtcl_Safeinit 51\n");