diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/extra/sendOSC.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/extra/sendOSC.c | 2922 |
1 files changed, 2922 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/extra/sendOSC.c b/apps/plugins/pdbox/PDa/extra/sendOSC.c new file mode 100644 index 0000000000..c00f693280 --- /dev/null +++ b/apps/plugins/pdbox/PDa/extra/sendOSC.c | |||
@@ -0,0 +1,2922 @@ | |||
1 | /* | ||
2 | Written by Matt Wright, The Center for New Music and Audio Technologies, | ||
3 | University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03 | ||
4 | The Regents of the University of California (Regents). | ||
5 | |||
6 | Permission to use, copy, modify, distribute, and distribute modified versions | ||
7 | of this software and its documentation without fee and without a signed | ||
8 | licensing agreement, is hereby granted, provided that the above copyright | ||
9 | notice, this paragraph and the following two paragraphs appear in all copies, | ||
10 | modifications, and distributions. | ||
11 | |||
12 | IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, | ||
13 | SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING | ||
14 | OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS | ||
15 | BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
16 | |||
17 | REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | ||
18 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
19 | PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED | ||
20 | HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE | ||
21 | MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | ||
22 | |||
23 | |||
24 | The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl | ||
25 | */ | ||
26 | |||
27 | |||
28 | /* sendOSC.c | ||
29 | |||
30 | Matt Wright, 6/3/97 | ||
31 | based on sendOSC.c, which was based on a version by Adrian Freed | ||
32 | |||
33 | Text-based OpenSoundControl client. User can enter messages via command | ||
34 | line arguments or standard input. | ||
35 | |||
36 | Version 0.1: "play" feature | ||
37 | Version 0.2: Message type tags. | ||
38 | |||
39 | pd version branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/sendOSC/sendOSC.c | ||
40 | ------------- | ||
41 | -- added bundle stuff to send. jdl 20020416 | ||
42 | -- tweaks for Win32 www.zeggz.com/raf 13-April-2002 | ||
43 | -- ost_at_test.at + i22_at_test.at, 2000-2002 | ||
44 | modified to compile as pd externel | ||
45 | */ | ||
46 | |||
47 | #define MAX_ARGS 2000 | ||
48 | #define SC_BUFFER_SIZE 64000 | ||
49 | |||
50 | #include "m_pd.h" | ||
51 | #include "OSC-client.h" | ||
52 | |||
53 | #include <string.h> | ||
54 | #include <sys/types.h> | ||
55 | #include <stdlib.h> | ||
56 | #include <stdio.h> | ||
57 | #include <sys/stat.h> | ||
58 | #include <sys/types.h> | ||
59 | |||
60 | #ifdef WIN32 | ||
61 | #include <winsock2.h> | ||
62 | #include <io.h> | ||
63 | #include <errno.h> | ||
64 | #include <fcntl.h> | ||
65 | #include <winsock2.h> | ||
66 | #include <ctype.h> | ||
67 | #include <signal.h> | ||
68 | #else | ||
69 | #include <sys/socket.h> | ||
70 | #include <netinet/in.h> | ||
71 | #include <rpc/rpc.h> | ||
72 | #include <sys/times.h> | ||
73 | #include <sys/param.h> | ||
74 | #include <sys/time.h> | ||
75 | #include <sys/ioctl.h> | ||
76 | #include <netdb.h> | ||
77 | #endif | ||
78 | |||
79 | #ifdef __APPLE__ | ||
80 | #include <string.h> | ||
81 | #endif | ||
82 | |||
83 | #define UNIXDG_PATH "/tmp/htm" | ||
84 | #define UNIXDG_TMP "/tmp/htm.XXXXXX" | ||
85 | |||
86 | |||
87 | |||
88 | OSCTimeTag OSCTT_Immediately(void) { | ||
89 | OSCTimeTag result; | ||
90 | result.seconds = 0; | ||
91 | result.fraction = 1; | ||
92 | return result; | ||
93 | } | ||
94 | |||
95 | |||
96 | OSCTimeTag OSCTT_CurrentTime(void) { | ||
97 | OSCTimeTag result; | ||
98 | result.seconds = 0; | ||
99 | result.fraction = 1; | ||
100 | return result; | ||
101 | } | ||
102 | |||
103 | OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) { | ||
104 | OSCTimeTag result; | ||
105 | result.seconds = 0; | ||
106 | result.fraction = 1; | ||
107 | return result; | ||
108 | } | ||
109 | |||
110 | |||
111 | typedef int bool; | ||
112 | |||
113 | typedef struct | ||
114 | { | ||
115 | float srate; | ||
116 | |||
117 | struct sockaddr_in serv_addr; /* udp socket */ | ||
118 | #ifndef WIN32 | ||
119 | struct sockaddr_un userv_addr; /* UNIX socket */ | ||
120 | #endif | ||
121 | int sockfd; /* socket file descriptor */ | ||
122 | int index, len,uservlen; | ||
123 | void *addr; | ||
124 | int id; | ||
125 | } desc; | ||
126 | |||
127 | |||
128 | /* open a socket for HTM communication to given host on given portnumber */ | ||
129 | /* if host is 0 then UNIX protocol is used (i.e. local communication */ | ||
130 | void *OpenHTMSocket(char *host, int portnumber) | ||
131 | { | ||
132 | struct sockaddr_in cl_addr; | ||
133 | #ifndef WIN32 | ||
134 | int sockfd; | ||
135 | struct sockaddr_un ucl_addr; | ||
136 | #else | ||
137 | unsigned int sockfd; | ||
138 | #endif | ||
139 | |||
140 | desc *o; | ||
141 | int oval = 1; | ||
142 | o = malloc(sizeof(*o)); | ||
143 | if(!o) return 0; | ||
144 | |||
145 | #ifndef WIN32 | ||
146 | |||
147 | if(!host) | ||
148 | { | ||
149 | char *mktemp(char *); | ||
150 | int clilen; | ||
151 | o->len = sizeof(ucl_addr); | ||
152 | /* | ||
153 | * Fill in the structure "userv_addr" with the address of the | ||
154 | * server that we want to send to. | ||
155 | */ | ||
156 | |||
157 | bzero((char *) &o->userv_addr, sizeof(o->userv_addr)); | ||
158 | o->userv_addr.sun_family = AF_UNIX; | ||
159 | strcpy(o->userv_addr.sun_path, UNIXDG_PATH); | ||
160 | sprintf(o->userv_addr.sun_path+strlen(o->userv_addr.sun_path), "%d", portnumber); | ||
161 | o->uservlen = sizeof(o->userv_addr.sun_family) + strlen(o->userv_addr.sun_path); | ||
162 | o->addr = &(o->userv_addr); | ||
163 | /* | ||
164 | * Open a socket (a UNIX domain datagram socket). | ||
165 | */ | ||
166 | |||
167 | if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0) | ||
168 | { | ||
169 | /* | ||
170 | * Bind a local address for us. | ||
171 | * In the UNIX domain we have to choose our own name (that | ||
172 | * should be unique). We'll use mktemp() to create a unique | ||
173 | * pathname, based on our process id. | ||
174 | */ | ||
175 | |||
176 | bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */ | ||
177 | ucl_addr.sun_family = AF_UNIX; | ||
178 | strcpy(ucl_addr.sun_path, UNIXDG_TMP); | ||
179 | |||
180 | mktemp(ucl_addr.sun_path); | ||
181 | clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path); | ||
182 | |||
183 | if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0) | ||
184 | { | ||
185 | perror("client: can't bind local address"); | ||
186 | close(sockfd); | ||
187 | sockfd = -1; | ||
188 | } | ||
189 | } | ||
190 | else | ||
191 | perror("unable to make socket\n"); | ||
192 | |||
193 | }else | ||
194 | |||
195 | #endif | ||
196 | |||
197 | { | ||
198 | /* | ||
199 | * Fill in the structure "serv_addr" with the address of the | ||
200 | * server that we want to send to. | ||
201 | */ | ||
202 | o->len = sizeof(cl_addr); | ||
203 | |||
204 | #ifdef WIN32 | ||
205 | ZeroMemory((char *)&o->serv_addr, sizeof(o->serv_addr)); | ||
206 | #else | ||
207 | bzero((char *)&o->serv_addr, sizeof(o->serv_addr)); | ||
208 | #endif | ||
209 | |||
210 | o->serv_addr.sin_family = AF_INET; | ||
211 | |||
212 | /* MW 6/6/96: Call gethostbyname() instead of inet_addr(), | ||
213 | so that host can be either an Internet host name (e.g., | ||
214 | "les") or an Internet address in standard dot notation | ||
215 | (e.g., "128.32.122.13") */ | ||
216 | { | ||
217 | struct hostent *hostsEntry; | ||
218 | unsigned long address; | ||
219 | |||
220 | hostsEntry = gethostbyname(host); | ||
221 | if (hostsEntry == NULL) { | ||
222 | fprintf(stderr, "Couldn't decipher host name \"%s\"\n", host); | ||
223 | #ifndef WIN32 | ||
224 | herror(NULL); | ||
225 | #endif | ||
226 | return 0; | ||
227 | } | ||
228 | address = *((unsigned long *) hostsEntry->h_addr_list[0]); | ||
229 | o->serv_addr.sin_addr.s_addr = address; | ||
230 | } | ||
231 | |||
232 | /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */ | ||
233 | |||
234 | /* End MW changes */ | ||
235 | |||
236 | /* | ||
237 | * Open a socket (a UDP domain datagram socket). | ||
238 | */ | ||
239 | |||
240 | |||
241 | #ifdef WIN32 | ||
242 | o->serv_addr.sin_port = htons((USHORT)portnumber); | ||
243 | o->addr = &(o->serv_addr); | ||
244 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) { | ||
245 | ZeroMemory((char *)&cl_addr, sizeof(cl_addr)); | ||
246 | cl_addr.sin_family = AF_INET; | ||
247 | cl_addr.sin_addr.s_addr = htonl(INADDR_ANY); | ||
248 | cl_addr.sin_port = htons(0); | ||
249 | |||
250 | // enable broadcast: jdl ~2003 | ||
251 | if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) { | ||
252 | perror("setsockopt"); | ||
253 | } | ||
254 | |||
255 | if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) { | ||
256 | perror("could not bind\n"); | ||
257 | closesocket(sockfd); | ||
258 | sockfd = -1; | ||
259 | } | ||
260 | } | ||
261 | else { perror("unable to make socket\n");} | ||
262 | #else | ||
263 | o->serv_addr.sin_port = htons(portnumber); | ||
264 | o->addr = &(o->serv_addr); | ||
265 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { | ||
266 | bzero((char *)&cl_addr, sizeof(cl_addr)); | ||
267 | cl_addr.sin_family = AF_INET; | ||
268 | cl_addr.sin_addr.s_addr = htonl(INADDR_ANY); | ||
269 | cl_addr.sin_port = htons(0); | ||
270 | |||
271 | // enable broadcast: jdl ~2003 | ||
272 | if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) { | ||
273 | perror("setsockopt"); | ||
274 | } | ||
275 | |||
276 | if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) { | ||
277 | perror("could not bind\n"); | ||
278 | close(sockfd); | ||
279 | sockfd = -1; | ||
280 | } | ||
281 | } | ||
282 | else { perror("unable to make socket\n");} | ||
283 | #endif | ||
284 | } | ||
285 | #ifdef WIN32 | ||
286 | if(sockfd == INVALID_SOCKET) { | ||
287 | #else | ||
288 | if(sockfd < 0) { | ||
289 | #endif | ||
290 | free(o); | ||
291 | o = 0; | ||
292 | } | ||
293 | else | ||
294 | o->sockfd = sockfd; | ||
295 | return o; | ||
296 | } | ||
297 | |||
298 | static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b) | ||
299 | { | ||
300 | int rcount; | ||
301 | if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count) | ||
302 | { | ||
303 | printf("sockfd %d count %d rcount %dlength %d\n", sockfd,count,rcount,length); | ||
304 | return FALSE; | ||
305 | } | ||
306 | return TRUE; | ||
307 | } | ||
308 | |||
309 | bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer) | ||
310 | { | ||
311 | desc *o = (desc *)htmsendhandle; | ||
312 | return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer); | ||
313 | } | ||
314 | void CloseHTMSocket(void *htmsendhandle) | ||
315 | { | ||
316 | desc *o = (desc *)htmsendhandle; | ||
317 | #ifdef WIN32 | ||
318 | if(SOCKET_ERROR == closesocket(o->sockfd)) { | ||
319 | perror("CloseHTMSocket::closesocket failed\n"); | ||
320 | return; | ||
321 | } | ||
322 | #else | ||
323 | if(close(o->sockfd) == -1) | ||
324 | { | ||
325 | perror("CloseHTMSocket::closesocket failed"); | ||
326 | return; | ||
327 | } | ||
328 | #endif | ||
329 | |||
330 | free(o); | ||
331 | } | ||
332 | |||
333 | |||
334 | /////////////////////// | ||
335 | // from sendOSC | ||
336 | |||
337 | typedef struct { | ||
338 | //enum {INT, FLOAT, STRING} type; | ||
339 | enum {INT_osc, FLOAT_osc, STRING_osc} type; | ||
340 | union { | ||
341 | int i; | ||
342 | float f; | ||
343 | char *s; | ||
344 | } datum; | ||
345 | } typedArg; | ||
346 | |||
347 | void CommandLineMode(int argc, char *argv[], void *htmsocket); | ||
348 | OSCTimeTag ParseTimeTag(char *s); | ||
349 | void ParseInteractiveLine(OSCbuf *buf, char *mesg); | ||
350 | typedArg ParseToken(char *token); | ||
351 | int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args); | ||
352 | void SendBuffer(void *htmsocket, OSCbuf *buf); | ||
353 | void SendData(void *htmsocket, int size, char *data); | ||
354 | /* defined in OSC-system-dependent.c now */ | ||
355 | |||
356 | //static void *htmsocket; | ||
357 | static int exitStatus = 0; | ||
358 | static int useTypeTags = 0; | ||
359 | |||
360 | static char bufferForOSCbuf[SC_BUFFER_SIZE]; | ||
361 | |||
362 | |||
363 | ///////// | ||
364 | // end from sendOSC | ||
365 | |||
366 | static t_class *sendOSC_class; | ||
367 | |||
368 | typedef struct _sendOSC | ||
369 | { | ||
370 | t_object x_obj; | ||
371 | int x_protocol; // UDP/TCP (udp only atm) | ||
372 | t_int x_typetags; // typetag flag | ||
373 | void *x_htmsocket; // sending socket | ||
374 | int x_bundle; // bundle open flag | ||
375 | OSCbuf x_oscbuf[1]; // OSCbuffer | ||
376 | t_outlet *x_bdpthout;// bundle-depth floatoutlet | ||
377 | } t_sendOSC; | ||
378 | |||
379 | static void *sendOSC_new(t_floatarg udpflag) | ||
380 | { | ||
381 | t_sendOSC *x = (t_sendOSC *)pd_new(sendOSC_class); | ||
382 | outlet_new(&x->x_obj, &s_float); | ||
383 | x->x_htmsocket = 0; // {{raf}} | ||
384 | // set udp | ||
385 | x->x_protocol = SOCK_STREAM; | ||
386 | // set typetags to 1 by default | ||
387 | x->x_typetags = 1; | ||
388 | // bunlde is closed | ||
389 | x->x_bundle = 0; | ||
390 | OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf); | ||
391 | x->x_bdpthout = outlet_new(&x->x_obj, 0); // outlet_float(); | ||
392 | //x->x_oscbuf = | ||
393 | return (x); | ||
394 | } | ||
395 | |||
396 | |||
397 | void sendOSC_openbundle(t_sendOSC *x) | ||
398 | { | ||
399 | if (x->x_oscbuf->bundleDepth + 1 >= MAX_BUNDLE_NESTING || | ||
400 | OSC_openBundle(x->x_oscbuf, OSCTT_Immediately())) | ||
401 | { | ||
402 | post("Problem opening bundle: %s\n", OSC_errorMessage); | ||
403 | return; | ||
404 | } | ||
405 | x->x_bundle = 1; | ||
406 | outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth); | ||
407 | } | ||
408 | |||
409 | static void sendOSC_closebundle(t_sendOSC *x) | ||
410 | { | ||
411 | if (OSC_closeBundle(x->x_oscbuf)) { | ||
412 | post("Problem closing bundle: %s\n", OSC_errorMessage); | ||
413 | return; | ||
414 | } | ||
415 | outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth); | ||
416 | // in bundle mode we send when bundle is closed? | ||
417 | if(!OSC_isBufferEmpty(x->x_oscbuf) > 0 && OSC_isBufferDone(x->x_oscbuf)) { | ||
418 | // post("x_oscbuf: something inside me?"); | ||
419 | if (x->x_htmsocket) { | ||
420 | SendBuffer(x->x_htmsocket, x->x_oscbuf); | ||
421 | } else { | ||
422 | post("sendOSC: not connected"); | ||
423 | } | ||
424 | OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf); | ||
425 | x->x_bundle = 0; | ||
426 | return; | ||
427 | } | ||
428 | // post("x_oscbuf: something went wrong"); | ||
429 | } | ||
430 | |||
431 | static void sendOSC_settypetags(t_sendOSC *x, t_float *f) | ||
432 | { | ||
433 | x->x_typetags = (int)f; | ||
434 | post("sendOSC.c: setting typetags %d",x->x_typetags); | ||
435 | } | ||
436 | |||
437 | |||
438 | static void sendOSC_connect(t_sendOSC *x, t_symbol *hostname, | ||
439 | t_floatarg fportno) | ||
440 | { | ||
441 | int portno = fportno; | ||
442 | /* create a socket */ | ||
443 | |||
444 | // make sure handle is available | ||
445 | if(x->x_htmsocket == 0) { | ||
446 | // | ||
447 | x->x_htmsocket = OpenHTMSocket(hostname->s_name, portno); | ||
448 | if (!x->x_htmsocket) | ||
449 | post("Couldn't open socket: "); | ||
450 | else { | ||
451 | post("connected to port %s:%d (hSock=%d)", hostname->s_name, portno, x->x_htmsocket); | ||
452 | outlet_float(x->x_obj.ob_outlet, 1); | ||
453 | } | ||
454 | } | ||
455 | else | ||
456 | perror("call to sendOSC_connect() against UNavailable socket handle"); | ||
457 | } | ||
458 | |||
459 | void sendOSC_disconnect(t_sendOSC *x) | ||
460 | { | ||
461 | if (x->x_htmsocket) | ||
462 | { | ||
463 | post("disconnecting htmsock (hSock=%d)...", x->x_htmsocket); | ||
464 | CloseHTMSocket(x->x_htmsocket); | ||
465 | x->x_htmsocket = 0; // {{raf}} semi-quasi-semaphorize this | ||
466 | outlet_float(x->x_obj.ob_outlet, 0); | ||
467 | } | ||
468 | else { | ||
469 | perror("call to sendOSC_disconnect() against unused socket handle"); | ||
470 | } | ||
471 | } | ||
472 | |||
473 | void sendOSC_senduntyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) | ||
474 | { | ||
475 | char* targv[MAXPDARG]; | ||
476 | char tmparg[MAXPDSTRING]; | ||
477 | char* tmp = tmparg; | ||
478 | //char testarg[MAXPDSTRING]; | ||
479 | int c; | ||
480 | |||
481 | post("sendOSC: use typetags 0/1 message and plain send method so send untypetagged..."); | ||
482 | return; | ||
483 | |||
484 | //atom_string(argv,testarg, MAXPDSTRING); | ||
485 | for (c=0;c<argc;c++) { | ||
486 | atom_string(argv+c,tmp, 80); | ||
487 | targv[c] = tmp; | ||
488 | tmp += strlen(tmp)+1; | ||
489 | } | ||
490 | |||
491 | // this sock needs to be larger than 0, not >= .. | ||
492 | if (x->x_htmsocket) | ||
493 | { | ||
494 | CommandLineMode(argc, targv, x->x_htmsocket); | ||
495 | // post("test %d", c); | ||
496 | } | ||
497 | else { | ||
498 | post("sendOSC: not connected"); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | ////////////////////////////////////////////////////////////////////// | ||
503 | // this is the real and only sending routine now, for both typed and | ||
504 | // undtyped mode. | ||
505 | |||
506 | static void sendOSC_sendtyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) | ||
507 | { | ||
508 | char* targv[MAX_ARGS]; | ||
509 | char tmparg[MAXPDSTRING]; | ||
510 | char* tmp = tmparg; | ||
511 | int c; | ||
512 | |||
513 | char *messageName; | ||
514 | char *token; | ||
515 | typedArg args[MAX_ARGS]; | ||
516 | int i,j; | ||
517 | int numArgs = 0; | ||
518 | |||
519 | messageName = ""; | ||
520 | #ifdef DEBUG | ||
521 | post ("sendOSC: messageName: %s", messageName); | ||
522 | #endif | ||
523 | |||
524 | |||
525 | |||
526 | for (c=0;c<argc;c++) { | ||
527 | atom_string(argv+c,tmp, 80); | ||
528 | |||
529 | #ifdef DEBUG | ||
530 | // post ("sendOSC: %d, %s",c, tmp); | ||
531 | #endif | ||
532 | |||
533 | targv[c] = tmp; | ||
534 | tmp += strlen(tmp)+1; | ||
535 | |||
536 | #ifdef DEBUG | ||
537 | // post ("sendOSC: %d, %s",c, targv[c]); | ||
538 | #endif | ||
539 | } | ||
540 | |||
541 | // this sock needs to be larger than 0, not >= .. | ||
542 | if (x->x_htmsocket > 0) | ||
543 | { | ||
544 | #ifdef DEBUG | ||
545 | post ("sendOSC: type tags? %d", useTypeTags); | ||
546 | #endif | ||
547 | |||
548 | messageName = strtok(targv[0], ","); | ||
549 | j = 1; | ||
550 | for (i = j; i < argc; i++) { | ||
551 | token = strtok(targv[i],","); | ||
552 | args[i-j] = ParseToken(token); | ||
553 | #ifdef DEBUG | ||
554 | printf("cell-cont: %s\n", targv[i]); | ||
555 | printf(" type-id: %d\n", args[i-j]); | ||
556 | #endif | ||
557 | numArgs = i; | ||
558 | } | ||
559 | |||
560 | |||
561 | if(WriteMessage(x->x_oscbuf, messageName, numArgs, args)) { | ||
562 | post("sendOSC: usage error, write-msg failed: %s", OSC_errorMessage); | ||
563 | return; | ||
564 | } | ||
565 | |||
566 | if(!x->x_bundle) { | ||
567 | SendBuffer(x->x_htmsocket, x->x_oscbuf); | ||
568 | OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf); | ||
569 | } | ||
570 | |||
571 | //CommandLineMode(argc, targv, x->x_htmsocket); | ||
572 | //useTypeTags = 0; | ||
573 | } | ||
574 | else { | ||
575 | post("sendOSC: not connected"); | ||
576 | } | ||
577 | } | ||
578 | |||
579 | void sendOSC_send(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) | ||
580 | { | ||
581 | if(!argc) { | ||
582 | post("not sending empty message."); | ||
583 | return; | ||
584 | } | ||
585 | if(x->x_typetags) { | ||
586 | useTypeTags = 1; | ||
587 | sendOSC_sendtyped(x,s,argc,argv); | ||
588 | useTypeTags = 0; | ||
589 | } else { | ||
590 | sendOSC_sendtyped(x,s,argc,argv); | ||
591 | } | ||
592 | } | ||
593 | |||
594 | static void sendOSC_free(t_sendOSC *x) | ||
595 | { | ||
596 | sendOSC_disconnect(x); | ||
597 | } | ||
598 | |||
599 | #ifdef WIN32 | ||
600 | OSC_API void sendOSC_setup(void) { | ||
601 | #else | ||
602 | void sendOSC_setup(void) { | ||
603 | #endif | ||
604 | sendOSC_class = class_new(gensym("sendOSC"), (t_newmethod)sendOSC_new, | ||
605 | (t_method)sendOSC_free, | ||
606 | sizeof(t_sendOSC), 0, A_DEFFLOAT, 0); | ||
607 | class_addmethod(sendOSC_class, (t_method)sendOSC_connect, | ||
608 | gensym("connect"), A_SYMBOL, A_FLOAT, 0); | ||
609 | class_addmethod(sendOSC_class, (t_method)sendOSC_disconnect, | ||
610 | gensym("disconnect"), 0); | ||
611 | class_addmethod(sendOSC_class, (t_method)sendOSC_settypetags, | ||
612 | gensym("typetags"), | ||
613 | A_FLOAT, 0); | ||
614 | class_addmethod(sendOSC_class, (t_method)sendOSC_send, | ||
615 | gensym("send"), | ||
616 | A_GIMME, 0); | ||
617 | class_addmethod(sendOSC_class, (t_method)sendOSC_send, | ||
618 | gensym("senduntyped"), | ||
619 | A_GIMME, 0); | ||
620 | class_addmethod(sendOSC_class, (t_method)sendOSC_send, | ||
621 | gensym("sendtyped"), | ||
622 | A_GIMME, 0); | ||
623 | class_addmethod(sendOSC_class, (t_method)sendOSC_openbundle, | ||
624 | gensym("["), | ||
625 | 0, 0); | ||
626 | class_addmethod(sendOSC_class, (t_method)sendOSC_closebundle, | ||
627 | gensym("]"), | ||
628 | 0, 0); | ||
629 | class_sethelpsymbol(sendOSC_class, gensym("sendOSC-help.pd")); | ||
630 | } | ||
631 | |||
632 | |||
633 | |||
634 | |||
635 | |||
636 | /* Exit status codes: | ||
637 | 0: successful | ||
638 | 2: Message(s) dropped because of buffer overflow | ||
639 | 3: Socket error | ||
640 | 4: Usage error | ||
641 | 5: Internal error | ||
642 | */ | ||
643 | |||
644 | void CommandLineMode(int argc, char *argv[], void *htmsocket) { | ||
645 | char *messageName; | ||
646 | char *token; | ||
647 | typedArg args[MAX_ARGS]; | ||
648 | int i,j, numArgs; | ||
649 | OSCbuf buf[1]; | ||
650 | |||
651 | OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf); | ||
652 | |||
653 | if (argc > 1) { | ||
654 | post("argc (%d) > 1", argc); | ||
655 | } | ||
656 | |||
657 | // ParseInteractiveLine(buf, argv); | ||
658 | messageName = strtok(argv[0], ","); | ||
659 | |||
660 | j = 1; | ||
661 | for (i = j; i < argc; i++) { | ||
662 | token = strtok(argv[i],","); | ||
663 | args[i-j] = ParseToken(token); | ||
664 | #ifdef DEBUG | ||
665 | printf("cell-cont: %s\n", argv[i]); | ||
666 | printf(" type-id: %d\n", args[i-j]); | ||
667 | #endif | ||
668 | numArgs = i; | ||
669 | } | ||
670 | |||
671 | if(WriteMessage(buf, messageName, numArgs, args)) { | ||
672 | post("sendOSC: usage error. write-msg failed: %s", OSC_errorMessage); | ||
673 | return; | ||
674 | } | ||
675 | |||
676 | SendBuffer(htmsocket, buf); | ||
677 | } | ||
678 | |||
679 | #define MAXMESG 2048 | ||
680 | |||
681 | void InteractiveMode(void *htmsocket) { | ||
682 | char mesg[MAXMESG]; | ||
683 | OSCbuf buf[1]; | ||
684 | int bundleDepth = 0; /* At first, we haven't seen "[". */ | ||
685 | |||
686 | OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf); | ||
687 | |||
688 | while (fgets(mesg, MAXMESG, stdin) != NULL) { | ||
689 | if (mesg[0] == '\n') { | ||
690 | if (bundleDepth > 0) { | ||
691 | /* Ignore blank lines inside a group. */ | ||
692 | } else { | ||
693 | /* blank line => repeat previous send */ | ||
694 | SendBuffer(htmsocket, buf); | ||
695 | } | ||
696 | continue; | ||
697 | } | ||
698 | |||
699 | if (bundleDepth == 0) { | ||
700 | OSC_resetBuffer(buf); | ||
701 | } | ||
702 | |||
703 | if (mesg[0] == '[') { | ||
704 | OSCTimeTag tt = ParseTimeTag(mesg+1); | ||
705 | if (OSC_openBundle(buf, tt)) { | ||
706 | post("Problem opening bundle: %s\n", OSC_errorMessage); | ||
707 | OSC_resetBuffer(buf); | ||
708 | bundleDepth = 0; | ||
709 | continue; | ||
710 | } | ||
711 | bundleDepth++; | ||
712 | } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') { | ||
713 | if (bundleDepth == 0) { | ||
714 | post("Unexpected ']': not currently in a bundle.\n"); | ||
715 | } else { | ||
716 | if (OSC_closeBundle(buf)) { | ||
717 | post("Problem closing bundle: %s\n", OSC_errorMessage); | ||
718 | OSC_resetBuffer(buf); | ||
719 | bundleDepth = 0; | ||
720 | continue; | ||
721 | } | ||
722 | |||
723 | bundleDepth--; | ||
724 | if (bundleDepth == 0) { | ||
725 | SendBuffer(htmsocket, buf); | ||
726 | } | ||
727 | } | ||
728 | } else { | ||
729 | ParseInteractiveLine(buf, mesg); | ||
730 | if (bundleDepth != 0) { | ||
731 | /* Don't send anything until we close all bundles */ | ||
732 | } else { | ||
733 | SendBuffer(htmsocket, buf); | ||
734 | } | ||
735 | } | ||
736 | } | ||
737 | } | ||
738 | |||
739 | OSCTimeTag ParseTimeTag(char *s) { | ||
740 | char *p, *newline; | ||
741 | typedArg arg; | ||
742 | |||
743 | p = s; | ||
744 | while (isspace(*p)) p++; | ||
745 | if (*p == '\0') return OSCTT_Immediately(); | ||
746 | |||
747 | if (*p == '+') { | ||
748 | /* Time tag is for some time in the future. It should be a | ||
749 | number of seconds as an int or float */ | ||
750 | |||
751 | newline = strchr(s, '\n'); | ||
752 | if (newline != NULL) *newline = '\0'; | ||
753 | |||
754 | p++; /* Skip '+' */ | ||
755 | while (isspace(*p)) p++; | ||
756 | |||
757 | arg = ParseToken(p); | ||
758 | if (arg.type == STRING_osc) { | ||
759 | post("warning: inscrutable time tag request: %s\n", s); | ||
760 | return OSCTT_Immediately(); | ||
761 | } else if (arg.type == INT_osc) { | ||
762 | return OSCTT_PlusSeconds(OSCTT_CurrentTime(), | ||
763 | (float) arg.datum.i); | ||
764 | } else if (arg.type == FLOAT_osc) { | ||
765 | return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f); | ||
766 | } else { | ||
767 | error("This can't happen!"); | ||
768 | } | ||
769 | } | ||
770 | |||
771 | if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) { | ||
772 | /* They specified the 8-byte tag in hex */ | ||
773 | OSCTimeTag tt; | ||
774 | if (sscanf(p, "%llx", &tt) != 1) { | ||
775 | post("warning: couldn't parse time tag %s\n", s); | ||
776 | return OSCTT_Immediately(); | ||
777 | } | ||
778 | #ifndef HAS8BYTEINT | ||
779 | if (ntohl(1) != 1) { | ||
780 | /* tt is a struct of seconds and fractional part, | ||
781 | and this machine is little-endian, so sscanf | ||
782 | wrote each half of the time tag in the wrong half | ||
783 | of the struct. */ | ||
784 | int temp; | ||
785 | temp = tt.seconds; | ||
786 | tt.seconds = tt.fraction ; | ||
787 | tt.fraction = temp; | ||
788 | } | ||
789 | #endif | ||
790 | return tt; | ||
791 | } | ||
792 | |||
793 | post("warning: invalid time tag: %s\n", s); | ||
794 | return OSCTT_Immediately(); | ||
795 | } | ||
796 | |||
797 | |||
798 | void ParseInteractiveLine(OSCbuf *buf, char *mesg) { | ||
799 | char *messageName, *token, *p; | ||
800 | typedArg args[MAX_ARGS]; | ||
801 | int thisArg; | ||
802 | |||
803 | p = mesg; | ||
804 | while (isspace(*p)) p++; | ||
805 | if (*p == '\0') return; | ||
806 | |||
807 | messageName = p; | ||
808 | |||
809 | if (strcmp(messageName, "play\n") == 0) { | ||
810 | /* Special kludge feature to save typing */ | ||
811 | typedArg arg; | ||
812 | |||
813 | if (OSC_openBundle(buf, OSCTT_Immediately())) { | ||
814 | post("Problem opening bundle: %s\n", OSC_errorMessage); | ||
815 | return; | ||
816 | } | ||
817 | |||
818 | arg.type = INT_osc; | ||
819 | arg.datum.i = 0; | ||
820 | WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg); | ||
821 | |||
822 | arg.type = FLOAT_osc; | ||
823 | arg.datum.i = 0.0f; | ||
824 | WriteMessage(buf, "/voices/0/tm/goto", 1, &arg); | ||
825 | |||
826 | if (OSC_closeBundle(buf)) { | ||
827 | post("Problem closing bundle: %s\n", OSC_errorMessage); | ||
828 | } | ||
829 | |||
830 | return; | ||
831 | } | ||
832 | |||
833 | while (!isspace(*p) && *p != '\0') p++; | ||
834 | if (isspace(*p)) { | ||
835 | *p = '\0'; | ||
836 | p++; | ||
837 | } | ||
838 | |||
839 | thisArg = 0; | ||
840 | while (*p != '\0') { | ||
841 | /* flush leading whitespace */ | ||
842 | while (isspace(*p)) p++; | ||
843 | if (*p == '\0') break; | ||
844 | |||
845 | if (*p == '"') { | ||
846 | /* A string argument: scan for close quotes */ | ||
847 | p++; | ||
848 | args[thisArg].type = STRING_osc; | ||
849 | args[thisArg].datum.s = p; | ||
850 | |||
851 | while (*p != '"') { | ||
852 | if (*p == '\0') { | ||
853 | post("Unterminated quote mark: ignoring line\n"); | ||
854 | return; | ||
855 | } | ||
856 | p++; | ||
857 | } | ||
858 | *p = '\0'; | ||
859 | p++; | ||
860 | } else { | ||
861 | token = p; | ||
862 | while (!isspace(*p) && (*p != '\0')) p++; | ||
863 | if (isspace(*p)) { | ||
864 | *p = '\0'; | ||
865 | p++; | ||
866 | } | ||
867 | args[thisArg] = ParseToken(token); | ||
868 | } | ||
869 | thisArg++; | ||
870 | if (thisArg >= MAX_ARGS) { | ||
871 | post("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n", | ||
872 | MAX_ARGS); | ||
873 | break; | ||
874 | } | ||
875 | } | ||
876 | |||
877 | if (WriteMessage(buf, messageName, thisArg, args) != 0) { | ||
878 | post("Problem sending message: %s\n", OSC_errorMessage); | ||
879 | } | ||
880 | } | ||
881 | |||
882 | typedArg ParseToken(char *token) { | ||
883 | char *p = token; | ||
884 | typedArg returnVal; | ||
885 | |||
886 | /* It might be an int, a float, or a string */ | ||
887 | |||
888 | if (*p == '-') p++; | ||
889 | |||
890 | if (isdigit(*p) || *p == '.') { | ||
891 | while (isdigit(*p)) p++; | ||
892 | if (*p == '\0') { | ||
893 | returnVal.type = INT_osc; | ||
894 | returnVal.datum.i = atoi(token); | ||
895 | return returnVal; | ||
896 | } | ||
897 | if (*p == '.') { | ||
898 | p++; | ||
899 | while (isdigit(*p)) p++; | ||
900 | if (*p == '\0') { | ||
901 | returnVal.type = FLOAT_osc; | ||
902 | returnVal.datum.f = atof(token); | ||
903 | return returnVal; | ||
904 | } | ||
905 | } | ||
906 | } | ||
907 | |||
908 | returnVal.type = STRING_osc; | ||
909 | returnVal.datum.s = token; | ||
910 | return returnVal; | ||
911 | } | ||
912 | |||
913 | int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) { | ||
914 | int j, returnVal; | ||
915 | const int wmERROR = -1; | ||
916 | |||
917 | returnVal = 0; | ||
918 | |||
919 | #ifdef DEBUG | ||
920 | printf("WriteMessage: %s ", messageName); | ||
921 | |||
922 | for (j = 0; j < numArgs; j++) { | ||
923 | switch (args[j].type) { | ||
924 | case INT_osc: | ||
925 | printf("%d ", args[j].datum.i); | ||
926 | break; | ||
927 | |||
928 | case FLOAT_osc: | ||
929 | printf("%f ", args[j].datum.f); | ||
930 | break; | ||
931 | |||
932 | case STRING_osc: | ||
933 | printf("%s ", args[j].datum.s); | ||
934 | break; | ||
935 | |||
936 | default: | ||
937 | error("Unrecognized arg type, (not exiting)"); | ||
938 | return(wmERROR); | ||
939 | } | ||
940 | } | ||
941 | printf("\n"); | ||
942 | #endif | ||
943 | |||
944 | if (!useTypeTags) { | ||
945 | returnVal = OSC_writeAddress(buf, messageName); | ||
946 | if (returnVal) { | ||
947 | post("Problem writing address: %s\n", OSC_errorMessage); | ||
948 | } | ||
949 | } else { | ||
950 | /* First figure out the type tags */ | ||
951 | char typeTags[MAX_ARGS+2]; | ||
952 | int i; | ||
953 | |||
954 | typeTags[0] = ','; | ||
955 | |||
956 | for (i = 0; i < numArgs; ++i) { | ||
957 | switch (args[i].type) { | ||
958 | case INT_osc: | ||
959 | typeTags[i+1] = 'i'; | ||
960 | break; | ||
961 | |||
962 | case FLOAT_osc: | ||
963 | typeTags[i+1] = 'f'; | ||
964 | break; | ||
965 | |||
966 | case STRING_osc: | ||
967 | typeTags[i+1] = 's'; | ||
968 | break; | ||
969 | |||
970 | default: | ||
971 | error("Unrecognized arg type (not exiting)"); | ||
972 | return(wmERROR); | ||
973 | } | ||
974 | } | ||
975 | typeTags[i+1] = '\0'; | ||
976 | |||
977 | returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags); | ||
978 | if (returnVal) { | ||
979 | post("Problem writing address: %s\n", OSC_errorMessage); | ||
980 | } | ||
981 | } | ||
982 | |||
983 | for (j = 0; j < numArgs; j++) { | ||
984 | switch (args[j].type) { | ||
985 | case INT_osc: | ||
986 | if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) { | ||
987 | return returnVal; | ||
988 | } | ||
989 | break; | ||
990 | |||
991 | case FLOAT_osc: | ||
992 | if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) { | ||
993 | return returnVal; | ||
994 | } | ||
995 | break; | ||
996 | |||
997 | case STRING_osc: | ||
998 | if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) { | ||
999 | return returnVal; | ||
1000 | } | ||
1001 | break; | ||
1002 | |||
1003 | default: | ||
1004 | error("Unrecognized arg type (not exiting)"); | ||
1005 | returnVal = wmERROR; | ||
1006 | } | ||
1007 | } | ||
1008 | return returnVal; | ||
1009 | } | ||
1010 | |||
1011 | void SendBuffer(void *htmsocket, OSCbuf *buf) { | ||
1012 | #ifdef DEBUG | ||
1013 | printf("Sending buffer...\n"); | ||
1014 | #endif | ||
1015 | if (OSC_isBufferEmpty(buf)) { | ||
1016 | post("SendBuffer() called but buffer empty"); | ||
1017 | return; | ||
1018 | } | ||
1019 | if (!OSC_isBufferDone(buf)) { | ||
1020 | error("SendBuffer() called but buffer not ready!, not exiting"); | ||
1021 | return; //{{raf}} | ||
1022 | } | ||
1023 | SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf)); | ||
1024 | } | ||
1025 | |||
1026 | void SendData(void *htmsocket, int size, char *data) { | ||
1027 | if (!SendHTMSocket(htmsocket, size, data)) { | ||
1028 | post("SendData::SendHTMSocket()failure -- not connected"); | ||
1029 | CloseHTMSocket(htmsocket); | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | |||
1034 | |||
1035 | /* ---------------------- | ||
1036 | OSC-client code | ||
1037 | |||
1038 | */ | ||
1039 | |||
1040 | /* Here are the possible values of the state field: */ | ||
1041 | |||
1042 | #define EMPTY 0 /* Nothing written to packet yet */ | ||
1043 | #define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */ | ||
1044 | #define NEED_COUNT 2 /* Just opened a bundle; must write message name or | ||
1045 | open another bundle */ | ||
1046 | #define GET_ARGS 3 /* Getting arguments to a message. If we see a message | ||
1047 | name or a bundle open/close then the current message | ||
1048 | will end. */ | ||
1049 | #define DONE 4 /* All open bundles have been closed, so can't write | ||
1050 | anything else */ | ||
1051 | |||
1052 | #ifdef WIN32 | ||
1053 | #include <winsock2.h> | ||
1054 | #include <io.h> | ||
1055 | #include <stdio.h> | ||
1056 | #include <errno.h> | ||
1057 | #include <fcntl.h> | ||
1058 | #include <sys/types.h> | ||
1059 | #include <sys/stat.h> | ||
1060 | #endif | ||
1061 | |||
1062 | #ifdef __APPLE__ | ||
1063 | #include <sys/types.h> | ||
1064 | #endif | ||
1065 | |||
1066 | #ifdef unix | ||
1067 | #include <netinet/in.h> | ||
1068 | #include <stdio.h> | ||
1069 | #endif | ||
1070 | |||
1071 | |||
1072 | char *OSC_errorMessage; | ||
1073 | |||
1074 | static int OSC_padString(char *dest, char *str); | ||
1075 | static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str); | ||
1076 | static int OSC_WritePadding(char *dest, int i); | ||
1077 | static int CheckTypeTag(OSCbuf *buf, char expectedType); | ||
1078 | |||
1079 | void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray) { | ||
1080 | buf->buffer = byteArray; | ||
1081 | buf->size = size; | ||
1082 | OSC_resetBuffer(buf); | ||
1083 | } | ||
1084 | |||
1085 | void OSC_resetBuffer(OSCbuf *buf) { | ||
1086 | buf->bufptr = buf->buffer; | ||
1087 | buf->state = EMPTY; | ||
1088 | buf->bundleDepth = 0; | ||
1089 | buf->prevCounts[0] = 0; | ||
1090 | buf->gettingFirstUntypedArg = 0; | ||
1091 | buf->typeStringPtr = 0; | ||
1092 | } | ||
1093 | |||
1094 | int OSC_isBufferEmpty(OSCbuf *buf) { | ||
1095 | return buf->bufptr == buf->buffer; | ||
1096 | } | ||
1097 | |||
1098 | int OSC_freeSpaceInBuffer(OSCbuf *buf) { | ||
1099 | return buf->size - (buf->bufptr - buf->buffer); | ||
1100 | } | ||
1101 | |||
1102 | int OSC_isBufferDone(OSCbuf *buf) { | ||
1103 | return (buf->state == DONE || buf->state == ONE_MSG_ARGS); | ||
1104 | } | ||
1105 | |||
1106 | char *OSC_getPacket(OSCbuf *buf) { | ||
1107 | #ifdef ERROR_CHECK_GETPACKET | ||
1108 | if (buf->state == DONE || buf->state == ONE_MSG_ARGS) { | ||
1109 | return buf->buffer; | ||
1110 | } else { | ||
1111 | OSC_errorMessage = "Packet has unterminated bundles"; | ||
1112 | return 0; | ||
1113 | } | ||
1114 | #else | ||
1115 | return buf->buffer; | ||
1116 | #endif | ||
1117 | } | ||
1118 | |||
1119 | int OSC_packetSize(OSCbuf *buf) { | ||
1120 | #ifdef ERROR_CHECK_PACKETSIZE | ||
1121 | if (buf->state == DONE || buf->state == ONE_MSG_ARGS) { | ||
1122 | return (buf->bufptr - buf->buffer); | ||
1123 | } else { | ||
1124 | OSC_errorMessage = "Packet has unterminated bundles"; | ||
1125 | return 0; | ||
1126 | } | ||
1127 | #else | ||
1128 | return (buf->bufptr - buf->buffer); | ||
1129 | #endif | ||
1130 | } | ||
1131 | |||
1132 | #define CheckOverflow(buf, bytesNeeded) { if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) {OSC_errorMessage = "buffer overflow"; return 1;}} | ||
1133 | |||
1134 | static void PatchMessageSize(OSCbuf *buf) { | ||
1135 | int4byte size; | ||
1136 | size = buf->bufptr - ((char *) buf->thisMsgSize) - 4; | ||
1137 | *(buf->thisMsgSize) = htonl(size); | ||
1138 | } | ||
1139 | |||
1140 | int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) { | ||
1141 | if (buf->state == ONE_MSG_ARGS) { | ||
1142 | OSC_errorMessage = "Can't open a bundle in a one-message packet"; | ||
1143 | return 3; | ||
1144 | } | ||
1145 | |||
1146 | if (buf->state == DONE) { | ||
1147 | OSC_errorMessage = "This packet is finished; can't open a new bundle"; | ||
1148 | return 4; | ||
1149 | } | ||
1150 | |||
1151 | if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) { | ||
1152 | OSC_errorMessage = "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h"; | ||
1153 | return 2; | ||
1154 | } | ||
1155 | |||
1156 | if (CheckTypeTag(buf, '\0')) return 9; | ||
1157 | |||
1158 | if (buf->state == GET_ARGS) { | ||
1159 | PatchMessageSize(buf); | ||
1160 | } | ||
1161 | |||
1162 | if (buf->state == EMPTY) { | ||
1163 | /* Need 16 bytes for "#bundle" and time tag */ | ||
1164 | CheckOverflow(buf, 16); | ||
1165 | } else { | ||
1166 | /* This bundle is inside another bundle, so we need to leave | ||
1167 | a blank size count for the size of this current bundle. */ | ||
1168 | CheckOverflow(buf, 20); | ||
1169 | *((int4byte *)buf->bufptr) = 0xaaaaaaaa; | ||
1170 | buf->prevCounts[buf->bundleDepth] = (int4byte *)buf->bufptr; | ||
1171 | |||
1172 | buf->bufptr += 4; | ||
1173 | } | ||
1174 | |||
1175 | buf->bufptr += OSC_padString(buf->bufptr, "#bundle"); | ||
1176 | |||
1177 | |||
1178 | *((OSCTimeTag *) buf->bufptr) = tt; | ||
1179 | |||
1180 | if (htonl(1) != 1) { | ||
1181 | /* Byte swap the 8-byte integer time tag */ | ||
1182 | int4byte *intp = (int4byte *)buf->bufptr; | ||
1183 | intp[0] = htonl(intp[0]); | ||
1184 | intp[1] = htonl(intp[1]); | ||
1185 | |||
1186 | #ifdef HAS8BYTEINT | ||
1187 | { /* tt is a 64-bit int so we have to swap the two 32-bit words. | ||
1188 | (Otherwise tt is a struct of two 32-bit words, and even though | ||
1189 | each word was wrong-endian, they were in the right order | ||
1190 | in the struct.) */ | ||
1191 | int4byte temp = intp[0]; | ||
1192 | intp[0] = intp[1]; | ||
1193 | intp[1] = temp; | ||
1194 | } | ||
1195 | #endif | ||
1196 | } | ||
1197 | |||
1198 | buf->bufptr += sizeof(OSCTimeTag); | ||
1199 | |||
1200 | buf->state = NEED_COUNT; | ||
1201 | |||
1202 | buf->gettingFirstUntypedArg = 0; | ||
1203 | buf->typeStringPtr = 0; | ||
1204 | return 0; | ||
1205 | } | ||
1206 | |||
1207 | |||
1208 | int OSC_closeBundle(OSCbuf *buf) { | ||
1209 | if (buf->bundleDepth == 0) { | ||
1210 | /* This handles EMPTY, ONE_MSG, ARGS, and DONE */ | ||
1211 | OSC_errorMessage = "Can't close bundle; no bundle is open!"; | ||
1212 | return 5; | ||
1213 | } | ||
1214 | |||
1215 | if (CheckTypeTag(buf, '\0')) return 9; | ||
1216 | |||
1217 | if (buf->state == GET_ARGS) { | ||
1218 | PatchMessageSize(buf); | ||
1219 | } | ||
1220 | |||
1221 | if (buf->bundleDepth == 1) { | ||
1222 | /* Closing the last bundle: No bundle size to patch */ | ||
1223 | buf->state = DONE; | ||
1224 | } else { | ||
1225 | /* Closing a sub-bundle: patch bundle size */ | ||
1226 | int size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4; | ||
1227 | *(buf->prevCounts[buf->bundleDepth]) = htonl(size); | ||
1228 | buf->state = NEED_COUNT; | ||
1229 | } | ||
1230 | |||
1231 | --buf->bundleDepth; | ||
1232 | buf->gettingFirstUntypedArg = 0; | ||
1233 | buf->typeStringPtr = 0; | ||
1234 | return 0; | ||
1235 | } | ||
1236 | |||
1237 | |||
1238 | int OSC_closeAllBundles(OSCbuf *buf) { | ||
1239 | if (buf->bundleDepth == 0) { | ||
1240 | /* This handles EMPTY, ONE_MSG, ARGS, and DONE */ | ||
1241 | OSC_errorMessage = "Can't close all bundles; no bundle is open!"; | ||
1242 | return 6; | ||
1243 | } | ||
1244 | |||
1245 | if (CheckTypeTag(buf, '\0')) return 9; | ||
1246 | |||
1247 | while (buf->bundleDepth > 0) { | ||
1248 | OSC_closeBundle(buf); | ||
1249 | } | ||
1250 | buf->typeStringPtr = 0; | ||
1251 | return 0; | ||
1252 | } | ||
1253 | |||
1254 | int OSC_writeAddress(OSCbuf *buf, char *name) { | ||
1255 | int4byte paddedLength; | ||
1256 | |||
1257 | if (buf->state == ONE_MSG_ARGS) { | ||
1258 | OSC_errorMessage = "This packet is not a bundle, so you can't write another address"; | ||
1259 | return 7; | ||
1260 | } | ||
1261 | |||
1262 | if (buf->state == DONE) { | ||
1263 | OSC_errorMessage = "This packet is finished; can't write another address"; | ||
1264 | return 8; | ||
1265 | } | ||
1266 | |||
1267 | if (CheckTypeTag(buf, '\0')) return 9; | ||
1268 | |||
1269 | paddedLength = OSC_effectiveStringLength(name); | ||
1270 | |||
1271 | if (buf->state == EMPTY) { | ||
1272 | /* This will be a one-message packet, so no sizes to worry about */ | ||
1273 | CheckOverflow(buf, paddedLength); | ||
1274 | buf->state = ONE_MSG_ARGS; | ||
1275 | } else { | ||
1276 | /* GET_ARGS or NEED_COUNT */ | ||
1277 | CheckOverflow(buf, 4+paddedLength); | ||
1278 | if (buf->state == GET_ARGS) { | ||
1279 | /* Close the old message */ | ||
1280 | PatchMessageSize(buf); | ||
1281 | } | ||
1282 | buf->thisMsgSize = (int4byte *)buf->bufptr; | ||
1283 | *(buf->thisMsgSize) = 0xbbbbbbbb; | ||
1284 | buf->bufptr += 4; | ||
1285 | buf->state = GET_ARGS; | ||
1286 | } | ||
1287 | |||
1288 | /* Now write the name */ | ||
1289 | buf->bufptr += OSC_padString(buf->bufptr, name); | ||
1290 | buf->typeStringPtr = 0; | ||
1291 | buf->gettingFirstUntypedArg = 1; | ||
1292 | |||
1293 | return 0; | ||
1294 | } | ||
1295 | |||
1296 | int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types) { | ||
1297 | int result; | ||
1298 | int4byte paddedLength; | ||
1299 | |||
1300 | if (CheckTypeTag(buf, '\0')) return 9; | ||
1301 | |||
1302 | result = OSC_writeAddress(buf, name); | ||
1303 | |||
1304 | if (result) return result; | ||
1305 | |||
1306 | paddedLength = OSC_effectiveStringLength(types); | ||
1307 | |||
1308 | CheckOverflow(buf, paddedLength); | ||
1309 | |||
1310 | buf->typeStringPtr = buf->bufptr + 1; /* skip comma */ | ||
1311 | buf->bufptr += OSC_padString(buf->bufptr, types); | ||
1312 | |||
1313 | buf->gettingFirstUntypedArg = 0; | ||
1314 | return 0; | ||
1315 | } | ||
1316 | |||
1317 | static int CheckTypeTag(OSCbuf *buf, char expectedType) { | ||
1318 | if (buf->typeStringPtr) { | ||
1319 | if (*(buf->typeStringPtr) != expectedType) { | ||
1320 | if (expectedType == '\0') { | ||
1321 | OSC_errorMessage = | ||
1322 | "According to the type tag I expected more arguments."; | ||
1323 | } else if (*(buf->typeStringPtr) == '\0') { | ||
1324 | OSC_errorMessage = | ||
1325 | "According to the type tag I didn't expect any more arguments."; | ||
1326 | } else { | ||
1327 | OSC_errorMessage = | ||
1328 | "According to the type tag I expected an argument of a different type."; | ||
1329 | printf("* Expected %c, string now %s\n", expectedType, buf->typeStringPtr); | ||
1330 | } | ||
1331 | return 9; | ||
1332 | } | ||
1333 | ++(buf->typeStringPtr); | ||
1334 | } | ||
1335 | return 0; | ||
1336 | } | ||
1337 | |||
1338 | |||
1339 | int OSC_writeFloatArg(OSCbuf *buf, float arg) { | ||
1340 | int4byte *intp; | ||
1341 | //int result; | ||
1342 | |||
1343 | CheckOverflow(buf, 4); | ||
1344 | |||
1345 | if (CheckTypeTag(buf, 'f')) return 9; | ||
1346 | |||
1347 | /* Pretend arg is a long int so we can use htonl() */ | ||
1348 | intp = ((int4byte *) &arg); | ||
1349 | *((int4byte *) buf->bufptr) = htonl(*intp); | ||
1350 | |||
1351 | buf->bufptr += 4; | ||
1352 | |||
1353 | buf->gettingFirstUntypedArg = 0; | ||
1354 | return 0; | ||
1355 | } | ||
1356 | |||
1357 | |||
1358 | |||
1359 | int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args) { | ||
1360 | int i; | ||
1361 | int4byte *intp; | ||
1362 | |||
1363 | CheckOverflow(buf, 4 * numFloats); | ||
1364 | |||
1365 | /* Pretend args are long ints so we can use htonl() */ | ||
1366 | intp = ((int4byte *) args); | ||
1367 | |||
1368 | for (i = 0; i < numFloats; i++) { | ||
1369 | if (CheckTypeTag(buf, 'f')) return 9; | ||
1370 | *((int4byte *) buf->bufptr) = htonl(intp[i]); | ||
1371 | buf->bufptr += 4; | ||
1372 | } | ||
1373 | |||
1374 | buf->gettingFirstUntypedArg = 0; | ||
1375 | return 0; | ||
1376 | } | ||
1377 | |||
1378 | int OSC_writeIntArg(OSCbuf *buf, int4byte arg) { | ||
1379 | CheckOverflow(buf, 4); | ||
1380 | if (CheckTypeTag(buf, 'i')) return 9; | ||
1381 | |||
1382 | *((int4byte *) buf->bufptr) = htonl(arg); | ||
1383 | buf->bufptr += 4; | ||
1384 | |||
1385 | buf->gettingFirstUntypedArg = 0; | ||
1386 | return 0; | ||
1387 | } | ||
1388 | |||
1389 | int OSC_writeStringArg(OSCbuf *buf, char *arg) { | ||
1390 | int len; | ||
1391 | |||
1392 | if (CheckTypeTag(buf, 's')) return 9; | ||
1393 | |||
1394 | len = OSC_effectiveStringLength(arg); | ||
1395 | |||
1396 | if (buf->gettingFirstUntypedArg && arg[0] == ',') { | ||
1397 | /* This un-type-tagged message starts with a string | ||
1398 | that starts with a comma, so we have to escape it | ||
1399 | (with a double comma) so it won't look like a type | ||
1400 | tag string. */ | ||
1401 | |||
1402 | CheckOverflow(buf, len+4); /* Too conservative */ | ||
1403 | buf->bufptr += | ||
1404 | OSC_padStringWithAnExtraStupidComma(buf->bufptr, arg); | ||
1405 | |||
1406 | } else { | ||
1407 | CheckOverflow(buf, len); | ||
1408 | buf->bufptr += OSC_padString(buf->bufptr, arg); | ||
1409 | } | ||
1410 | |||
1411 | buf->gettingFirstUntypedArg = 0; | ||
1412 | return 0; | ||
1413 | |||
1414 | } | ||
1415 | |||
1416 | /* String utilities */ | ||
1417 | |||
1418 | #define STRING_ALIGN_PAD 4 | ||
1419 | int OSC_effectiveStringLength(char *string) { | ||
1420 | int len = strlen(string) + 1; /* We need space for the null char. */ | ||
1421 | |||
1422 | /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */ | ||
1423 | if ((len % STRING_ALIGN_PAD) != 0) { | ||
1424 | len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD); | ||
1425 | } | ||
1426 | return len; | ||
1427 | } | ||
1428 | |||
1429 | static int OSC_padString(char *dest, char *str) { | ||
1430 | int i; | ||
1431 | |||
1432 | for (i = 0; str[i] != '\0'; i++) { | ||
1433 | dest[i] = str[i]; | ||
1434 | } | ||
1435 | |||
1436 | return OSC_WritePadding(dest, i); | ||
1437 | } | ||
1438 | |||
1439 | static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str) { | ||
1440 | int i; | ||
1441 | |||
1442 | dest[0] = ','; | ||
1443 | for (i = 0; str[i] != '\0'; i++) { | ||
1444 | dest[i+1] = str[i]; | ||
1445 | } | ||
1446 | |||
1447 | return OSC_WritePadding(dest, i+1); | ||
1448 | } | ||
1449 | |||
1450 | static int OSC_WritePadding(char *dest, int i) { | ||
1451 | dest[i] = '\0'; | ||
1452 | i++; | ||
1453 | |||
1454 | for (; (i % STRING_ALIGN_PAD) != 0; i++) { | ||
1455 | dest[i] = '\0'; | ||
1456 | } | ||
1457 | |||
1458 | return i; | ||
1459 | } | ||
1460 | |||
1461 | |||
1462 | /* | ||
1463 | Written by Matt Wright, The Center for New Music and Audio Technologies, | ||
1464 | University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03 | ||
1465 | The Regents of the University of California (Regents). | ||
1466 | |||
1467 | Permission to use, copy, modify, distribute, and distribute modified versions | ||
1468 | of this software and its documentation without fee and without a signed | ||
1469 | licensing agreement, is hereby granted, provided that the above copyright | ||
1470 | notice, this paragraph and the following two paragraphs appear in all copies, | ||
1471 | modifications, and distributions. | ||
1472 | |||
1473 | IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, | ||
1474 | SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING | ||
1475 | OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS | ||
1476 | BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
1477 | |||
1478 | REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | ||
1479 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
1480 | PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED | ||
1481 | HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE | ||
1482 | MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | ||
1483 | |||
1484 | |||
1485 | The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl | ||
1486 | */ | ||
1487 | |||
1488 | |||
1489 | /* sendOSC.c | ||
1490 | |||
1491 | Matt Wright, 6/3/97 | ||
1492 | based on sendOSC.c, which was based on a version by Adrian Freed | ||
1493 | |||
1494 | Text-based OpenSoundControl client. User can enter messages via command | ||
1495 | line arguments or standard input. | ||
1496 | |||
1497 | Version 0.1: "play" feature | ||
1498 | Version 0.2: Message type tags. | ||
1499 | |||
1500 | pd version branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/sendOSC/sendOSC.c | ||
1501 | ------------- | ||
1502 | -- added bundle stuff to send. jdl 20020416 | ||
1503 | -- tweaks for Win32 www.zeggz.com/raf 13-April-2002 | ||
1504 | -- ost_at_test.at + i22_at_test.at, 2000-2002 | ||
1505 | modified to compile as pd externel | ||
1506 | */ | ||
1507 | |||
1508 | #define MAX_ARGS 2000 | ||
1509 | #define SC_BUFFER_SIZE 64000 | ||
1510 | |||
1511 | #include "m_pd.h" | ||
1512 | #include "OSC-client.h" | ||
1513 | |||
1514 | #include <string.h> | ||
1515 | #include <sys/types.h> | ||
1516 | #include <stdlib.h> | ||
1517 | #include <stdio.h> | ||
1518 | #include <sys/stat.h> | ||
1519 | #include <sys/types.h> | ||
1520 | |||
1521 | #ifdef WIN32 | ||
1522 | #include <winsock2.h> | ||
1523 | #include <io.h> | ||
1524 | #include <errno.h> | ||
1525 | #include <fcntl.h> | ||
1526 | #include <winsock2.h> | ||
1527 | #include <ctype.h> | ||
1528 | #include <signal.h> | ||
1529 | #else | ||
1530 | #include <sys/socket.h> | ||
1531 | #include <netinet/in.h> | ||
1532 | #include <rpc/rpc.h> | ||
1533 | #include <sys/times.h> | ||
1534 | #include <sys/param.h> | ||
1535 | #include <sys/time.h> | ||
1536 | #include <sys/ioctl.h> | ||
1537 | #include <netdb.h> | ||
1538 | #endif | ||
1539 | |||
1540 | #ifdef __APPLE__ | ||
1541 | #include <string.h> | ||
1542 | #endif | ||
1543 | |||
1544 | #define UNIXDG_PATH "/tmp/htm" | ||
1545 | #define UNIXDG_TMP "/tmp/htm.XXXXXX" | ||
1546 | |||
1547 | |||
1548 | |||
1549 | OSCTimeTag OSCTT_Immediately(void) { | ||
1550 | OSCTimeTag result; | ||
1551 | result.seconds = 0; | ||
1552 | result.fraction = 1; | ||
1553 | return result; | ||
1554 | } | ||
1555 | |||
1556 | |||
1557 | OSCTimeTag OSCTT_CurrentTime(void) { | ||
1558 | OSCTimeTag result; | ||
1559 | result.seconds = 0; | ||
1560 | result.fraction = 1; | ||
1561 | return result; | ||
1562 | } | ||
1563 | |||
1564 | OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) { | ||
1565 | OSCTimeTag result; | ||
1566 | result.seconds = 0; | ||
1567 | result.fraction = 1; | ||
1568 | return result; | ||
1569 | } | ||
1570 | |||
1571 | |||
1572 | typedef int bool; | ||
1573 | |||
1574 | typedef struct | ||
1575 | { | ||
1576 | float srate; | ||
1577 | |||
1578 | struct sockaddr_in serv_addr; /* udp socket */ | ||
1579 | #ifndef WIN32 | ||
1580 | struct sockaddr_un userv_addr; /* UNIX socket */ | ||
1581 | #endif | ||
1582 | int sockfd; /* socket file descriptor */ | ||
1583 | int index, len,uservlen; | ||
1584 | void *addr; | ||
1585 | int id; | ||
1586 | } desc; | ||
1587 | |||
1588 | |||
1589 | /* open a socket for HTM communication to given host on given portnumber */ | ||
1590 | /* if host is 0 then UNIX protocol is used (i.e. local communication */ | ||
1591 | void *OpenHTMSocket(char *host, int portnumber) | ||
1592 | { | ||
1593 | struct sockaddr_in cl_addr; | ||
1594 | #ifndef WIN32 | ||
1595 | int sockfd; | ||
1596 | struct sockaddr_un ucl_addr; | ||
1597 | #else | ||
1598 | unsigned int sockfd; | ||
1599 | #endif | ||
1600 | |||
1601 | desc *o; | ||
1602 | int oval = 1; | ||
1603 | o = malloc(sizeof(*o)); | ||
1604 | if(!o) return 0; | ||
1605 | |||
1606 | #ifndef WIN32 | ||
1607 | |||
1608 | if(!host) | ||
1609 | { | ||
1610 | char *mktemp(char *); | ||
1611 | int clilen; | ||
1612 | o->len = sizeof(ucl_addr); | ||
1613 | /* | ||
1614 | * Fill in the structure "userv_addr" with the address of the | ||
1615 | * server that we want to send to. | ||
1616 | */ | ||
1617 | |||
1618 | bzero((char *) &o->userv_addr, sizeof(o->userv_addr)); | ||
1619 | o->userv_addr.sun_family = AF_UNIX; | ||
1620 | strcpy(o->userv_addr.sun_path, UNIXDG_PATH); | ||
1621 | sprintf(o->userv_addr.sun_path+strlen(o->userv_addr.sun_path), "%d", portnumber); | ||
1622 | o->uservlen = sizeof(o->userv_addr.sun_family) + strlen(o->userv_addr.sun_path); | ||
1623 | o->addr = &(o->userv_addr); | ||
1624 | /* | ||
1625 | * Open a socket (a UNIX domain datagram socket). | ||
1626 | */ | ||
1627 | |||
1628 | if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0) | ||
1629 | { | ||
1630 | /* | ||
1631 | * Bind a local address for us. | ||
1632 | * In the UNIX domain we have to choose our own name (that | ||
1633 | * should be unique). We'll use mktemp() to create a unique | ||
1634 | * pathname, based on our process id. | ||
1635 | */ | ||
1636 | |||
1637 | bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */ | ||
1638 | ucl_addr.sun_family = AF_UNIX; | ||
1639 | strcpy(ucl_addr.sun_path, UNIXDG_TMP); | ||
1640 | |||
1641 | mktemp(ucl_addr.sun_path); | ||
1642 | clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path); | ||
1643 | |||
1644 | if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0) | ||
1645 | { | ||
1646 | perror("client: can't bind local address"); | ||
1647 | close(sockfd); | ||
1648 | sockfd = -1; | ||
1649 | } | ||
1650 | } | ||
1651 | else | ||
1652 | perror("unable to make socket\n"); | ||
1653 | |||
1654 | }else | ||
1655 | |||
1656 | #endif | ||
1657 | |||
1658 | { | ||
1659 | /* | ||
1660 | * Fill in the structure "serv_addr" with the address of the | ||
1661 | * server that we want to send to. | ||
1662 | */ | ||
1663 | o->len = sizeof(cl_addr); | ||
1664 | |||
1665 | #ifdef WIN32 | ||
1666 | ZeroMemory((char *)&o->serv_addr, sizeof(o->serv_addr)); | ||
1667 | #else | ||
1668 | bzero((char *)&o->serv_addr, sizeof(o->serv_addr)); | ||
1669 | #endif | ||
1670 | |||
1671 | o->serv_addr.sin_family = AF_INET; | ||
1672 | |||
1673 | /* MW 6/6/96: Call gethostbyname() instead of inet_addr(), | ||
1674 | so that host can be either an Internet host name (e.g., | ||
1675 | "les") or an Internet address in standard dot notation | ||
1676 | (e.g., "128.32.122.13") */ | ||
1677 | { | ||
1678 | struct hostent *hostsEntry; | ||
1679 | unsigned long address; | ||
1680 | |||
1681 | hostsEntry = gethostbyname(host); | ||
1682 | if (hostsEntry == NULL) { | ||
1683 | fprintf(stderr, "Couldn't decipher host name \"%s\"\n", host); | ||
1684 | #ifndef WIN32 | ||
1685 | herror(NULL); | ||
1686 | #endif | ||
1687 | return 0; | ||
1688 | } | ||
1689 | address = *((unsigned long *) hostsEntry->h_addr_list[0]); | ||
1690 | o->serv_addr.sin_addr.s_addr = address; | ||
1691 | } | ||
1692 | |||
1693 | /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */ | ||
1694 | |||
1695 | /* End MW changes */ | ||
1696 | |||
1697 | /* | ||
1698 | * Open a socket (a UDP domain datagram socket). | ||
1699 | */ | ||
1700 | |||
1701 | |||
1702 | #ifdef WIN32 | ||
1703 | o->serv_addr.sin_port = htons((USHORT)portnumber); | ||
1704 | o->addr = &(o->serv_addr); | ||
1705 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) { | ||
1706 | ZeroMemory((char *)&cl_addr, sizeof(cl_addr)); | ||
1707 | cl_addr.sin_family = AF_INET; | ||
1708 | cl_addr.sin_addr.s_addr = htonl(INADDR_ANY); | ||
1709 | cl_addr.sin_port = htons(0); | ||
1710 | |||
1711 | // enable broadcast: jdl ~2003 | ||
1712 | if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) { | ||
1713 | perror("setsockopt"); | ||
1714 | } | ||
1715 | |||
1716 | if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) { | ||
1717 | perror("could not bind\n"); | ||
1718 | closesocket(sockfd); | ||
1719 | sockfd = -1; | ||
1720 | } | ||
1721 | } | ||
1722 | else { perror("unable to make socket\n");} | ||
1723 | #else | ||
1724 | o->serv_addr.sin_port = htons(portnumber); | ||
1725 | o->addr = &(o->serv_addr); | ||
1726 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { | ||
1727 | bzero((char *)&cl_addr, sizeof(cl_addr)); | ||
1728 | cl_addr.sin_family = AF_INET; | ||
1729 | cl_addr.sin_addr.s_addr = htonl(INADDR_ANY); | ||
1730 | cl_addr.sin_port = htons(0); | ||
1731 | |||
1732 | // enable broadcast: jdl ~2003 | ||
1733 | if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) { | ||
1734 | perror("setsockopt"); | ||
1735 | } | ||
1736 | |||
1737 | if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) { | ||
1738 | perror("could not bind\n"); | ||
1739 | close(sockfd); | ||
1740 | sockfd = -1; | ||
1741 | } | ||
1742 | } | ||
1743 | else { perror("unable to make socket\n");} | ||
1744 | #endif | ||
1745 | } | ||
1746 | #ifdef WIN32 | ||
1747 | if(sockfd == INVALID_SOCKET) { | ||
1748 | #else | ||
1749 | if(sockfd < 0) { | ||
1750 | #endif | ||
1751 | free(o); | ||
1752 | o = 0; | ||
1753 | } | ||
1754 | else | ||
1755 | o->sockfd = sockfd; | ||
1756 | return o; | ||
1757 | } | ||
1758 | |||
1759 | static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b) | ||
1760 | { | ||
1761 | int rcount; | ||
1762 | if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count) | ||
1763 | { | ||
1764 | printf("sockfd %d count %d rcount %dlength %d\n", sockfd,count,rcount,length); | ||
1765 | return FALSE; | ||
1766 | } | ||
1767 | return TRUE; | ||
1768 | } | ||
1769 | |||
1770 | bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer) | ||
1771 | { | ||
1772 | desc *o = (desc *)htmsendhandle; | ||
1773 | return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer); | ||
1774 | } | ||
1775 | void CloseHTMSocket(void *htmsendhandle) | ||
1776 | { | ||
1777 | desc *o = (desc *)htmsendhandle; | ||
1778 | #ifdef WIN32 | ||
1779 | if(SOCKET_ERROR == closesocket(o->sockfd)) { | ||
1780 | perror("CloseHTMSocket::closesocket failed\n"); | ||
1781 | return; | ||
1782 | } | ||
1783 | #else | ||
1784 | if(close(o->sockfd) == -1) | ||
1785 | { | ||
1786 | perror("CloseHTMSocket::closesocket failed"); | ||
1787 | return; | ||
1788 | } | ||
1789 | #endif | ||
1790 | |||
1791 | free(o); | ||
1792 | } | ||
1793 | |||
1794 | |||
1795 | /////////////////////// | ||
1796 | // from sendOSC | ||
1797 | |||
1798 | typedef struct { | ||
1799 | //enum {INT, FLOAT, STRING} type; | ||
1800 | enum {INT_osc, FLOAT_osc, STRING_osc} type; | ||
1801 | union { | ||
1802 | int i; | ||
1803 | float f; | ||
1804 | char *s; | ||
1805 | } datum; | ||
1806 | } typedArg; | ||
1807 | |||
1808 | void CommandLineMode(int argc, char *argv[], void *htmsocket); | ||
1809 | OSCTimeTag ParseTimeTag(char *s); | ||
1810 | void ParseInteractiveLine(OSCbuf *buf, char *mesg); | ||
1811 | typedArg ParseToken(char *token); | ||
1812 | int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args); | ||
1813 | void SendBuffer(void *htmsocket, OSCbuf *buf); | ||
1814 | void SendData(void *htmsocket, int size, char *data); | ||
1815 | /* defined in OSC-system-dependent.c now */ | ||
1816 | |||
1817 | //static void *htmsocket; | ||
1818 | static int exitStatus = 0; | ||
1819 | static int useTypeTags = 0; | ||
1820 | |||
1821 | static char bufferForOSCbuf[SC_BUFFER_SIZE]; | ||
1822 | |||
1823 | |||
1824 | ///////// | ||
1825 | // end from sendOSC | ||
1826 | |||
1827 | static t_class *sendOSC_class; | ||
1828 | |||
1829 | typedef struct _sendOSC | ||
1830 | { | ||
1831 | t_object x_obj; | ||
1832 | int x_protocol; // UDP/TCP (udp only atm) | ||
1833 | t_int x_typetags; // typetag flag | ||
1834 | void *x_htmsocket; // sending socket | ||
1835 | int x_bundle; // bundle open flag | ||
1836 | OSCbuf x_oscbuf[1]; // OSCbuffer | ||
1837 | t_outlet *x_bdpthout;// bundle-depth floatoutlet | ||
1838 | } t_sendOSC; | ||
1839 | |||
1840 | static void *sendOSC_new(t_floatarg udpflag) | ||
1841 | { | ||
1842 | t_sendOSC *x = (t_sendOSC *)pd_new(sendOSC_class); | ||
1843 | outlet_new(&x->x_obj, &s_float); | ||
1844 | x->x_htmsocket = 0; // {{raf}} | ||
1845 | // set udp | ||
1846 | x->x_protocol = SOCK_STREAM; | ||
1847 | // set typetags to 1 by default | ||
1848 | x->x_typetags = 1; | ||
1849 | // bunlde is closed | ||
1850 | x->x_bundle = 0; | ||
1851 | OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf); | ||
1852 | x->x_bdpthout = outlet_new(&x->x_obj, 0); // outlet_float(); | ||
1853 | //x->x_oscbuf = | ||
1854 | return (x); | ||
1855 | } | ||
1856 | |||
1857 | |||
1858 | void sendOSC_openbundle(t_sendOSC *x) | ||
1859 | { | ||
1860 | if (x->x_oscbuf->bundleDepth + 1 >= MAX_BUNDLE_NESTING || | ||
1861 | OSC_openBundle(x->x_oscbuf, OSCTT_Immediately())) | ||
1862 | { | ||
1863 | post("Problem opening bundle: %s\n", OSC_errorMessage); | ||
1864 | return; | ||
1865 | } | ||
1866 | x->x_bundle = 1; | ||
1867 | outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth); | ||
1868 | } | ||
1869 | |||
1870 | static void sendOSC_closebundle(t_sendOSC *x) | ||
1871 | { | ||
1872 | if (OSC_closeBundle(x->x_oscbuf)) { | ||
1873 | post("Problem closing bundle: %s\n", OSC_errorMessage); | ||
1874 | return; | ||
1875 | } | ||
1876 | outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth); | ||
1877 | // in bundle mode we send when bundle is closed? | ||
1878 | if(!OSC_isBufferEmpty(x->x_oscbuf) > 0 && OSC_isBufferDone(x->x_oscbuf)) { | ||
1879 | // post("x_oscbuf: something inside me?"); | ||
1880 | if (x->x_htmsocket) { | ||
1881 | SendBuffer(x->x_htmsocket, x->x_oscbuf); | ||
1882 | } else { | ||
1883 | post("sendOSC: not connected"); | ||
1884 | } | ||
1885 | OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf); | ||
1886 | x->x_bundle = 0; | ||
1887 | return; | ||
1888 | } | ||
1889 | // post("x_oscbuf: something went wrong"); | ||
1890 | } | ||
1891 | |||
1892 | static void sendOSC_settypetags(t_sendOSC *x, t_float *f) | ||
1893 | { | ||
1894 | x->x_typetags = (int)f; | ||
1895 | post("sendOSC.c: setting typetags %d",x->x_typetags); | ||
1896 | } | ||
1897 | |||
1898 | |||
1899 | static void sendOSC_connect(t_sendOSC *x, t_symbol *hostname, | ||
1900 | t_floatarg fportno) | ||
1901 | { | ||
1902 | int portno = fportno; | ||
1903 | /* create a socket */ | ||
1904 | |||
1905 | // make sure handle is available | ||
1906 | if(x->x_htmsocket == 0) { | ||
1907 | // | ||
1908 | x->x_htmsocket = OpenHTMSocket(hostname->s_name, portno); | ||
1909 | if (!x->x_htmsocket) | ||
1910 | post("Couldn't open socket: "); | ||
1911 | else { | ||
1912 | post("connected to port %s:%d (hSock=%d)", hostname->s_name, portno, x->x_htmsocket); | ||
1913 | outlet_float(x->x_obj.ob_outlet, 1); | ||
1914 | } | ||
1915 | } | ||
1916 | else | ||
1917 | perror("call to sendOSC_connect() against UNavailable socket handle"); | ||
1918 | } | ||
1919 | |||
1920 | void sendOSC_disconnect(t_sendOSC *x) | ||
1921 | { | ||
1922 | if (x->x_htmsocket) | ||
1923 | { | ||
1924 | post("disconnecting htmsock (hSock=%d)...", x->x_htmsocket); | ||
1925 | CloseHTMSocket(x->x_htmsocket); | ||
1926 | x->x_htmsocket = 0; // {{raf}} semi-quasi-semaphorize this | ||
1927 | outlet_float(x->x_obj.ob_outlet, 0); | ||
1928 | } | ||
1929 | else { | ||
1930 | perror("call to sendOSC_disconnect() against unused socket handle"); | ||
1931 | } | ||
1932 | } | ||
1933 | |||
1934 | void sendOSC_senduntyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) | ||
1935 | { | ||
1936 | char* targv[MAXPDARG]; | ||
1937 | char tmparg[MAXPDSTRING]; | ||
1938 | char* tmp = tmparg; | ||
1939 | //char testarg[MAXPDSTRING]; | ||
1940 | int c; | ||
1941 | |||
1942 | post("sendOSC: use typetags 0/1 message and plain send method so send untypetagged..."); | ||
1943 | return; | ||
1944 | |||
1945 | //atom_string(argv,testarg, MAXPDSTRING); | ||
1946 | for (c=0;c<argc;c++) { | ||
1947 | atom_string(argv+c,tmp, 80); | ||
1948 | targv[c] = tmp; | ||
1949 | tmp += strlen(tmp)+1; | ||
1950 | } | ||
1951 | |||
1952 | // this sock needs to be larger than 0, not >= .. | ||
1953 | if (x->x_htmsocket) | ||
1954 | { | ||
1955 | CommandLineMode(argc, targv, x->x_htmsocket); | ||
1956 | // post("test %d", c); | ||
1957 | } | ||
1958 | else { | ||
1959 | post("sendOSC: not connected"); | ||
1960 | } | ||
1961 | } | ||
1962 | |||
1963 | ////////////////////////////////////////////////////////////////////// | ||
1964 | // this is the real and only sending routine now, for both typed and | ||
1965 | // undtyped mode. | ||
1966 | |||
1967 | static void sendOSC_sendtyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) | ||
1968 | { | ||
1969 | char* targv[MAX_ARGS]; | ||
1970 | char tmparg[MAXPDSTRING]; | ||
1971 | char* tmp = tmparg; | ||
1972 | int c; | ||
1973 | |||
1974 | char *messageName; | ||
1975 | char *token; | ||
1976 | typedArg args[MAX_ARGS]; | ||
1977 | int i,j; | ||
1978 | int numArgs = 0; | ||
1979 | |||
1980 | messageName = ""; | ||
1981 | #ifdef DEBUG | ||
1982 | post ("sendOSC: messageName: %s", messageName); | ||
1983 | #endif | ||
1984 | |||
1985 | |||
1986 | |||
1987 | for (c=0;c<argc;c++) { | ||
1988 | atom_string(argv+c,tmp, 80); | ||
1989 | |||
1990 | #ifdef DEBUG | ||
1991 | // post ("sendOSC: %d, %s",c, tmp); | ||
1992 | #endif | ||
1993 | |||
1994 | targv[c] = tmp; | ||
1995 | tmp += strlen(tmp)+1; | ||
1996 | |||
1997 | #ifdef DEBUG | ||
1998 | // post ("sendOSC: %d, %s",c, targv[c]); | ||
1999 | #endif | ||
2000 | } | ||
2001 | |||
2002 | // this sock needs to be larger than 0, not >= .. | ||
2003 | if (x->x_htmsocket > 0) | ||
2004 | { | ||
2005 | #ifdef DEBUG | ||
2006 | post ("sendOSC: type tags? %d", useTypeTags); | ||
2007 | #endif | ||
2008 | |||
2009 | messageName = strtok(targv[0], ","); | ||
2010 | j = 1; | ||
2011 | for (i = j; i < argc; i++) { | ||
2012 | token = strtok(targv[i],","); | ||
2013 | args[i-j] = ParseToken(token); | ||
2014 | #ifdef DEBUG | ||
2015 | printf("cell-cont: %s\n", targv[i]); | ||
2016 | printf(" type-id: %d\n", args[i-j]); | ||
2017 | #endif | ||
2018 | numArgs = i; | ||
2019 | } | ||
2020 | |||
2021 | |||
2022 | if(WriteMessage(x->x_oscbuf, messageName, numArgs, args)) { | ||
2023 | post("sendOSC: usage error, write-msg failed: %s", OSC_errorMessage); | ||
2024 | return; | ||
2025 | } | ||
2026 | |||
2027 | if(!x->x_bundle) { | ||
2028 | SendBuffer(x->x_htmsocket, x->x_oscbuf); | ||
2029 | OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf); | ||
2030 | } | ||
2031 | |||
2032 | //CommandLineMode(argc, targv, x->x_htmsocket); | ||
2033 | //useTypeTags = 0; | ||
2034 | } | ||
2035 | else { | ||
2036 | post("sendOSC: not connected"); | ||
2037 | } | ||
2038 | } | ||
2039 | |||
2040 | void sendOSC_send(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) | ||
2041 | { | ||
2042 | if(!argc) { | ||
2043 | post("not sending empty message."); | ||
2044 | return; | ||
2045 | } | ||
2046 | if(x->x_typetags) { | ||
2047 | useTypeTags = 1; | ||
2048 | sendOSC_sendtyped(x,s,argc,argv); | ||
2049 | useTypeTags = 0; | ||
2050 | } else { | ||
2051 | sendOSC_sendtyped(x,s,argc,argv); | ||
2052 | } | ||
2053 | } | ||
2054 | |||
2055 | static void sendOSC_free(t_sendOSC *x) | ||
2056 | { | ||
2057 | sendOSC_disconnect(x); | ||
2058 | } | ||
2059 | |||
2060 | #ifdef WIN32 | ||
2061 | OSC_API void sendOSC_setup(void) { | ||
2062 | #else | ||
2063 | void sendOSC_setup(void) { | ||
2064 | #endif | ||
2065 | sendOSC_class = class_new(gensym("sendOSC"), (t_newmethod)sendOSC_new, | ||
2066 | (t_method)sendOSC_free, | ||
2067 | sizeof(t_sendOSC), 0, A_DEFFLOAT, 0); | ||
2068 | class_addmethod(sendOSC_class, (t_method)sendOSC_connect, | ||
2069 | gensym("connect"), A_SYMBOL, A_FLOAT, 0); | ||
2070 | class_addmethod(sendOSC_class, (t_method)sendOSC_disconnect, | ||
2071 | gensym("disconnect"), 0); | ||
2072 | class_addmethod(sendOSC_class, (t_method)sendOSC_settypetags, | ||
2073 | gensym("typetags"), | ||
2074 | A_FLOAT, 0); | ||
2075 | class_addmethod(sendOSC_class, (t_method)sendOSC_send, | ||
2076 | gensym("send"), | ||
2077 | A_GIMME, 0); | ||
2078 | class_addmethod(sendOSC_class, (t_method)sendOSC_send, | ||
2079 | gensym("senduntyped"), | ||
2080 | A_GIMME, 0); | ||
2081 | class_addmethod(sendOSC_class, (t_method)sendOSC_send, | ||
2082 | gensym("sendtyped"), | ||
2083 | A_GIMME, 0); | ||
2084 | class_addmethod(sendOSC_class, (t_method)sendOSC_openbundle, | ||
2085 | gensym("["), | ||
2086 | 0, 0); | ||
2087 | class_addmethod(sendOSC_class, (t_method)sendOSC_closebundle, | ||
2088 | gensym("]"), | ||
2089 | 0, 0); | ||
2090 | class_sethelpsymbol(sendOSC_class, gensym("sendOSC-help.pd")); | ||
2091 | } | ||
2092 | |||
2093 | |||
2094 | |||
2095 | |||
2096 | |||
2097 | /* Exit status codes: | ||
2098 | 0: successful | ||
2099 | 2: Message(s) dropped because of buffer overflow | ||
2100 | 3: Socket error | ||
2101 | 4: Usage error | ||
2102 | 5: Internal error | ||
2103 | */ | ||
2104 | |||
2105 | void CommandLineMode(int argc, char *argv[], void *htmsocket) { | ||
2106 | char *messageName; | ||
2107 | char *token; | ||
2108 | typedArg args[MAX_ARGS]; | ||
2109 | int i,j, numArgs; | ||
2110 | OSCbuf buf[1]; | ||
2111 | |||
2112 | OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf); | ||
2113 | |||
2114 | if (argc > 1) { | ||
2115 | post("argc (%d) > 1", argc); | ||
2116 | } | ||
2117 | |||
2118 | // ParseInteractiveLine(buf, argv); | ||
2119 | messageName = strtok(argv[0], ","); | ||
2120 | |||
2121 | j = 1; | ||
2122 | for (i = j; i < argc; i++) { | ||
2123 | token = strtok(argv[i],","); | ||
2124 | args[i-j] = ParseToken(token); | ||
2125 | #ifdef DEBUG | ||
2126 | printf("cell-cont: %s\n", argv[i]); | ||
2127 | printf(" type-id: %d\n", args[i-j]); | ||
2128 | #endif | ||
2129 | numArgs = i; | ||
2130 | } | ||
2131 | |||
2132 | if(WriteMessage(buf, messageName, numArgs, args)) { | ||
2133 | post("sendOSC: usage error. write-msg failed: %s", OSC_errorMessage); | ||
2134 | return; | ||
2135 | } | ||
2136 | |||
2137 | SendBuffer(htmsocket, buf); | ||
2138 | } | ||
2139 | |||
2140 | #define MAXMESG 2048 | ||
2141 | |||
2142 | void InteractiveMode(void *htmsocket) { | ||
2143 | char mesg[MAXMESG]; | ||
2144 | OSCbuf buf[1]; | ||
2145 | int bundleDepth = 0; /* At first, we haven't seen "[". */ | ||
2146 | |||
2147 | OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf); | ||
2148 | |||
2149 | while (fgets(mesg, MAXMESG, stdin) != NULL) { | ||
2150 | if (mesg[0] == '\n') { | ||
2151 | if (bundleDepth > 0) { | ||
2152 | /* Ignore blank lines inside a group. */ | ||
2153 | } else { | ||
2154 | /* blank line => repeat previous send */ | ||
2155 | SendBuffer(htmsocket, buf); | ||
2156 | } | ||
2157 | continue; | ||
2158 | } | ||
2159 | |||
2160 | if (bundleDepth == 0) { | ||
2161 | OSC_resetBuffer(buf); | ||
2162 | } | ||
2163 | |||
2164 | if (mesg[0] == '[') { | ||
2165 | OSCTimeTag tt = ParseTimeTag(mesg+1); | ||
2166 | if (OSC_openBundle(buf, tt)) { | ||
2167 | post("Problem opening bundle: %s\n", OSC_errorMessage); | ||
2168 | OSC_resetBuffer(buf); | ||
2169 | bundleDepth = 0; | ||
2170 | continue; | ||
2171 | } | ||
2172 | bundleDepth++; | ||
2173 | } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') { | ||
2174 | if (bundleDepth == 0) { | ||
2175 | post("Unexpected ']': not currently in a bundle.\n"); | ||
2176 | } else { | ||
2177 | if (OSC_closeBundle(buf)) { | ||
2178 | post("Problem closing bundle: %s\n", OSC_errorMessage); | ||
2179 | OSC_resetBuffer(buf); | ||
2180 | bundleDepth = 0; | ||
2181 | continue; | ||
2182 | } | ||
2183 | |||
2184 | bundleDepth--; | ||
2185 | if (bundleDepth == 0) { | ||
2186 | SendBuffer(htmsocket, buf); | ||
2187 | } | ||
2188 | } | ||
2189 | } else { | ||
2190 | ParseInteractiveLine(buf, mesg); | ||
2191 | if (bundleDepth != 0) { | ||
2192 | /* Don't send anything until we close all bundles */ | ||
2193 | } else { | ||
2194 | SendBuffer(htmsocket, buf); | ||
2195 | } | ||
2196 | } | ||
2197 | } | ||
2198 | } | ||
2199 | |||
2200 | OSCTimeTag ParseTimeTag(char *s) { | ||
2201 | char *p, *newline; | ||
2202 | typedArg arg; | ||
2203 | |||
2204 | p = s; | ||
2205 | while (isspace(*p)) p++; | ||
2206 | if (*p == '\0') return OSCTT_Immediately(); | ||
2207 | |||
2208 | if (*p == '+') { | ||
2209 | /* Time tag is for some time in the future. It should be a | ||
2210 | number of seconds as an int or float */ | ||
2211 | |||
2212 | newline = strchr(s, '\n'); | ||
2213 | if (newline != NULL) *newline = '\0'; | ||
2214 | |||
2215 | p++; /* Skip '+' */ | ||
2216 | while (isspace(*p)) p++; | ||
2217 | |||
2218 | arg = ParseToken(p); | ||
2219 | if (arg.type == STRING_osc) { | ||
2220 | post("warning: inscrutable time tag request: %s\n", s); | ||
2221 | return OSCTT_Immediately(); | ||
2222 | } else if (arg.type == INT_osc) { | ||
2223 | return OSCTT_PlusSeconds(OSCTT_CurrentTime(), | ||
2224 | (float) arg.datum.i); | ||
2225 | } else if (arg.type == FLOAT_osc) { | ||
2226 | return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f); | ||
2227 | } else { | ||
2228 | error("This can't happen!"); | ||
2229 | } | ||
2230 | } | ||
2231 | |||
2232 | if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) { | ||
2233 | /* They specified the 8-byte tag in hex */ | ||
2234 | OSCTimeTag tt; | ||
2235 | if (sscanf(p, "%llx", &tt) != 1) { | ||
2236 | post("warning: couldn't parse time tag %s\n", s); | ||
2237 | return OSCTT_Immediately(); | ||
2238 | } | ||
2239 | #ifndef HAS8BYTEINT | ||
2240 | if (ntohl(1) != 1) { | ||
2241 | /* tt is a struct of seconds and fractional part, | ||
2242 | and this machine is little-endian, so sscanf | ||
2243 | wrote each half of the time tag in the wrong half | ||
2244 | of the struct. */ | ||
2245 | int temp; | ||
2246 | temp = tt.seconds; | ||
2247 | tt.seconds = tt.fraction ; | ||
2248 | tt.fraction = temp; | ||
2249 | } | ||
2250 | #endif | ||
2251 | return tt; | ||
2252 | } | ||
2253 | |||
2254 | post("warning: invalid time tag: %s\n", s); | ||
2255 | return OSCTT_Immediately(); | ||
2256 | } | ||
2257 | |||
2258 | |||
2259 | void ParseInteractiveLine(OSCbuf *buf, char *mesg) { | ||
2260 | char *messageName, *token, *p; | ||
2261 | typedArg args[MAX_ARGS]; | ||
2262 | int thisArg; | ||
2263 | |||
2264 | p = mesg; | ||
2265 | while (isspace(*p)) p++; | ||
2266 | if (*p == '\0') return; | ||
2267 | |||
2268 | messageName = p; | ||
2269 | |||
2270 | if (strcmp(messageName, "play\n") == 0) { | ||
2271 | /* Special kludge feature to save typing */ | ||
2272 | typedArg arg; | ||
2273 | |||
2274 | if (OSC_openBundle(buf, OSCTT_Immediately())) { | ||
2275 | post("Problem opening bundle: %s\n", OSC_errorMessage); | ||
2276 | return; | ||
2277 | } | ||
2278 | |||
2279 | arg.type = INT_osc; | ||
2280 | arg.datum.i = 0; | ||
2281 | WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg); | ||
2282 | |||
2283 | arg.type = FLOAT_osc; | ||
2284 | arg.datum.i = 0.0f; | ||
2285 | WriteMessage(buf, "/voices/0/tm/goto", 1, &arg); | ||
2286 | |||
2287 | if (OSC_closeBundle(buf)) { | ||
2288 | post("Problem closing bundle: %s\n", OSC_errorMessage); | ||
2289 | } | ||
2290 | |||
2291 | return; | ||
2292 | } | ||
2293 | |||
2294 | while (!isspace(*p) && *p != '\0') p++; | ||
2295 | if (isspace(*p)) { | ||
2296 | *p = '\0'; | ||
2297 | p++; | ||
2298 | } | ||
2299 | |||
2300 | thisArg = 0; | ||
2301 | while (*p != '\0') { | ||
2302 | /* flush leading whitespace */ | ||
2303 | while (isspace(*p)) p++; | ||
2304 | if (*p == '\0') break; | ||
2305 | |||
2306 | if (*p == '"') { | ||
2307 | /* A string argument: scan for close quotes */ | ||
2308 | p++; | ||
2309 | args[thisArg].type = STRING_osc; | ||
2310 | args[thisArg].datum.s = p; | ||
2311 | |||
2312 | while (*p != '"') { | ||
2313 | if (*p == '\0') { | ||
2314 | post("Unterminated quote mark: ignoring line\n"); | ||
2315 | return; | ||
2316 | } | ||
2317 | p++; | ||
2318 | } | ||
2319 | *p = '\0'; | ||
2320 | p++; | ||
2321 | } else { | ||
2322 | token = p; | ||
2323 | while (!isspace(*p) && (*p != '\0')) p++; | ||
2324 | if (isspace(*p)) { | ||
2325 | *p = '\0'; | ||
2326 | p++; | ||
2327 | } | ||
2328 | args[thisArg] = ParseToken(token); | ||
2329 | } | ||
2330 | thisArg++; | ||
2331 | if (thisArg >= MAX_ARGS) { | ||
2332 | post("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n", | ||
2333 | MAX_ARGS); | ||
2334 | break; | ||
2335 | } | ||
2336 | } | ||
2337 | |||
2338 | if (WriteMessage(buf, messageName, thisArg, args) != 0) { | ||
2339 | post("Problem sending message: %s\n", OSC_errorMessage); | ||
2340 | } | ||
2341 | } | ||
2342 | |||
2343 | typedArg ParseToken(char *token) { | ||
2344 | char *p = token; | ||
2345 | typedArg returnVal; | ||
2346 | |||
2347 | /* It might be an int, a float, or a string */ | ||
2348 | |||
2349 | if (*p == '-') p++; | ||
2350 | |||
2351 | if (isdigit(*p) || *p == '.') { | ||
2352 | while (isdigit(*p)) p++; | ||
2353 | if (*p == '\0') { | ||
2354 | returnVal.type = INT_osc; | ||
2355 | returnVal.datum.i = atoi(token); | ||
2356 | return returnVal; | ||
2357 | } | ||
2358 | if (*p == '.') { | ||
2359 | p++; | ||
2360 | while (isdigit(*p)) p++; | ||
2361 | if (*p == '\0') { | ||
2362 | returnVal.type = FLOAT_osc; | ||
2363 | returnVal.datum.f = atof(token); | ||
2364 | return returnVal; | ||
2365 | } | ||
2366 | } | ||
2367 | } | ||
2368 | |||
2369 | returnVal.type = STRING_osc; | ||
2370 | returnVal.datum.s = token; | ||
2371 | return returnVal; | ||
2372 | } | ||
2373 | |||
2374 | int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) { | ||
2375 | int j, returnVal; | ||
2376 | const int wmERROR = -1; | ||
2377 | |||
2378 | returnVal = 0; | ||
2379 | |||
2380 | #ifdef DEBUG | ||
2381 | printf("WriteMessage: %s ", messageName); | ||
2382 | |||
2383 | for (j = 0; j < numArgs; j++) { | ||
2384 | switch (args[j].type) { | ||
2385 | case INT_osc: | ||
2386 | printf("%d ", args[j].datum.i); | ||
2387 | break; | ||
2388 | |||
2389 | case FLOAT_osc: | ||
2390 | printf("%f ", args[j].datum.f); | ||
2391 | break; | ||
2392 | |||
2393 | case STRING_osc: | ||
2394 | printf("%s ", args[j].datum.s); | ||
2395 | break; | ||
2396 | |||
2397 | default: | ||
2398 | error("Unrecognized arg type, (not exiting)"); | ||
2399 | return(wmERROR); | ||
2400 | } | ||
2401 | } | ||
2402 | printf("\n"); | ||
2403 | #endif | ||
2404 | |||
2405 | if (!useTypeTags) { | ||
2406 | returnVal = OSC_writeAddress(buf, messageName); | ||
2407 | if (returnVal) { | ||
2408 | post("Problem writing address: %s\n", OSC_errorMessage); | ||
2409 | } | ||
2410 | } else { | ||
2411 | /* First figure out the type tags */ | ||
2412 | char typeTags[MAX_ARGS+2]; | ||
2413 | int i; | ||
2414 | |||
2415 | typeTags[0] = ','; | ||
2416 | |||
2417 | for (i = 0; i < numArgs; ++i) { | ||
2418 | switch (args[i].type) { | ||
2419 | case INT_osc: | ||
2420 | typeTags[i+1] = 'i'; | ||
2421 | break; | ||
2422 | |||
2423 | case FLOAT_osc: | ||
2424 | typeTags[i+1] = 'f'; | ||
2425 | break; | ||
2426 | |||
2427 | case STRING_osc: | ||
2428 | typeTags[i+1] = 's'; | ||
2429 | break; | ||
2430 | |||
2431 | default: | ||
2432 | error("Unrecognized arg type (not exiting)"); | ||
2433 | return(wmERROR); | ||
2434 | } | ||
2435 | } | ||
2436 | typeTags[i+1] = '\0'; | ||
2437 | |||
2438 | returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags); | ||
2439 | if (returnVal) { | ||
2440 | post("Problem writing address: %s\n", OSC_errorMessage); | ||
2441 | } | ||
2442 | } | ||
2443 | |||
2444 | for (j = 0; j < numArgs; j++) { | ||
2445 | switch (args[j].type) { | ||
2446 | case INT_osc: | ||
2447 | if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) { | ||
2448 | return returnVal; | ||
2449 | } | ||
2450 | break; | ||
2451 | |||
2452 | case FLOAT_osc: | ||
2453 | if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) { | ||
2454 | return returnVal; | ||
2455 | } | ||
2456 | break; | ||
2457 | |||
2458 | case STRING_osc: | ||
2459 | if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) { | ||
2460 | return returnVal; | ||
2461 | } | ||
2462 | break; | ||
2463 | |||
2464 | default: | ||
2465 | error("Unrecognized arg type (not exiting)"); | ||
2466 | returnVal = wmERROR; | ||
2467 | } | ||
2468 | } | ||
2469 | return returnVal; | ||
2470 | } | ||
2471 | |||
2472 | void SendBuffer(void *htmsocket, OSCbuf *buf) { | ||
2473 | #ifdef DEBUG | ||
2474 | printf("Sending buffer...\n"); | ||
2475 | #endif | ||
2476 | if (OSC_isBufferEmpty(buf)) { | ||
2477 | post("SendBuffer() called but buffer empty"); | ||
2478 | return; | ||
2479 | } | ||
2480 | if (!OSC_isBufferDone(buf)) { | ||
2481 | error("SendBuffer() called but buffer not ready!, not exiting"); | ||
2482 | return; //{{raf}} | ||
2483 | } | ||
2484 | SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf)); | ||
2485 | } | ||
2486 | |||
2487 | void SendData(void *htmsocket, int size, char *data) { | ||
2488 | if (!SendHTMSocket(htmsocket, size, data)) { | ||
2489 | post("SendData::SendHTMSocket()failure -- not connected"); | ||
2490 | CloseHTMSocket(htmsocket); | ||
2491 | } | ||
2492 | } | ||
2493 | |||
2494 | |||
2495 | |||
2496 | /* ---------------------- | ||
2497 | OSC-client code | ||
2498 | |||
2499 | */ | ||
2500 | |||
2501 | /* Here are the possible values of the state field: */ | ||
2502 | |||
2503 | #define EMPTY 0 /* Nothing written to packet yet */ | ||
2504 | #define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */ | ||
2505 | #define NEED_COUNT 2 /* Just opened a bundle; must write message name or | ||
2506 | open another bundle */ | ||
2507 | #define GET_ARGS 3 /* Getting arguments to a message. If we see a message | ||
2508 | name or a bundle open/close then the current message | ||
2509 | will end. */ | ||
2510 | #define DONE 4 /* All open bundles have been closed, so can't write | ||
2511 | anything else */ | ||
2512 | |||
2513 | #ifdef WIN32 | ||
2514 | #include <winsock2.h> | ||
2515 | #include <io.h> | ||
2516 | #include <stdio.h> | ||
2517 | #include <errno.h> | ||
2518 | #include <fcntl.h> | ||
2519 | #include <sys/types.h> | ||
2520 | #include <sys/stat.h> | ||
2521 | #endif | ||
2522 | |||
2523 | #ifdef __APPLE__ | ||
2524 | #include <sys/types.h> | ||
2525 | #endif | ||
2526 | |||
2527 | #ifdef unix | ||
2528 | #include <netinet/in.h> | ||
2529 | #include <stdio.h> | ||
2530 | #endif | ||
2531 | |||
2532 | |||
2533 | char *OSC_errorMessage; | ||
2534 | |||
2535 | static int OSC_padString(char *dest, char *str); | ||
2536 | static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str); | ||
2537 | static int OSC_WritePadding(char *dest, int i); | ||
2538 | static int CheckTypeTag(OSCbuf *buf, char expectedType); | ||
2539 | |||
2540 | void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray) { | ||
2541 | buf->buffer = byteArray; | ||
2542 | buf->size = size; | ||
2543 | OSC_resetBuffer(buf); | ||
2544 | } | ||
2545 | |||
2546 | void OSC_resetBuffer(OSCbuf *buf) { | ||
2547 | buf->bufptr = buf->buffer; | ||
2548 | buf->state = EMPTY; | ||
2549 | buf->bundleDepth = 0; | ||
2550 | buf->prevCounts[0] = 0; | ||
2551 | buf->gettingFirstUntypedArg = 0; | ||
2552 | buf->typeStringPtr = 0; | ||
2553 | } | ||
2554 | |||
2555 | int OSC_isBufferEmpty(OSCbuf *buf) { | ||
2556 | return buf->bufptr == buf->buffer; | ||
2557 | } | ||
2558 | |||
2559 | int OSC_freeSpaceInBuffer(OSCbuf *buf) { | ||
2560 | return buf->size - (buf->bufptr - buf->buffer); | ||
2561 | } | ||
2562 | |||
2563 | int OSC_isBufferDone(OSCbuf *buf) { | ||
2564 | return (buf->state == DONE || buf->state == ONE_MSG_ARGS); | ||
2565 | } | ||
2566 | |||
2567 | char *OSC_getPacket(OSCbuf *buf) { | ||
2568 | #ifdef ERROR_CHECK_GETPACKET | ||
2569 | if (buf->state == DONE || buf->state == ONE_MSG_ARGS) { | ||
2570 | return buf->buffer; | ||
2571 | } else { | ||
2572 | OSC_errorMessage = "Packet has unterminated bundles"; | ||
2573 | return 0; | ||
2574 | } | ||
2575 | #else | ||
2576 | return buf->buffer; | ||
2577 | #endif | ||
2578 | } | ||
2579 | |||
2580 | int OSC_packetSize(OSCbuf *buf) { | ||
2581 | #ifdef ERROR_CHECK_PACKETSIZE | ||
2582 | if (buf->state == DONE || buf->state == ONE_MSG_ARGS) { | ||
2583 | return (buf->bufptr - buf->buffer); | ||
2584 | } else { | ||
2585 | OSC_errorMessage = "Packet has unterminated bundles"; | ||
2586 | return 0; | ||
2587 | } | ||
2588 | #else | ||
2589 | return (buf->bufptr - buf->buffer); | ||
2590 | #endif | ||
2591 | } | ||
2592 | |||
2593 | #define CheckOverflow(buf, bytesNeeded) { if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) {OSC_errorMessage = "buffer overflow"; return 1;}} | ||
2594 | |||
2595 | static void PatchMessageSize(OSCbuf *buf) { | ||
2596 | int4byte size; | ||
2597 | size = buf->bufptr - ((char *) buf->thisMsgSize) - 4; | ||
2598 | *(buf->thisMsgSize) = htonl(size); | ||
2599 | } | ||
2600 | |||
2601 | int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) { | ||
2602 | if (buf->state == ONE_MSG_ARGS) { | ||
2603 | OSC_errorMessage = "Can't open a bundle in a one-message packet"; | ||
2604 | return 3; | ||
2605 | } | ||
2606 | |||
2607 | if (buf->state == DONE) { | ||
2608 | OSC_errorMessage = "This packet is finished; can't open a new bundle"; | ||
2609 | return 4; | ||
2610 | } | ||
2611 | |||
2612 | if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) { | ||
2613 | OSC_errorMessage = "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h"; | ||
2614 | return 2; | ||
2615 | } | ||
2616 | |||
2617 | if (CheckTypeTag(buf, '\0')) return 9; | ||
2618 | |||
2619 | if (buf->state == GET_ARGS) { | ||
2620 | PatchMessageSize(buf); | ||
2621 | } | ||
2622 | |||
2623 | if (buf->state == EMPTY) { | ||
2624 | /* Need 16 bytes for "#bundle" and time tag */ | ||
2625 | CheckOverflow(buf, 16); | ||
2626 | } else { | ||
2627 | /* This bundle is inside another bundle, so we need to leave | ||
2628 | a blank size count for the size of this current bundle. */ | ||
2629 | CheckOverflow(buf, 20); | ||
2630 | *((int4byte *)buf->bufptr) = 0xaaaaaaaa; | ||
2631 | buf->prevCounts[buf->bundleDepth] = (int4byte *)buf->bufptr; | ||
2632 | |||
2633 | buf->bufptr += 4; | ||
2634 | } | ||
2635 | |||
2636 | buf->bufptr += OSC_padString(buf->bufptr, "#bundle"); | ||
2637 | |||
2638 | |||
2639 | *((OSCTimeTag *) buf->bufptr) = tt; | ||
2640 | |||
2641 | if (htonl(1) != 1) { | ||
2642 | /* Byte swap the 8-byte integer time tag */ | ||
2643 | int4byte *intp = (int4byte *)buf->bufptr; | ||
2644 | intp[0] = htonl(intp[0]); | ||
2645 | intp[1] = htonl(intp[1]); | ||
2646 | |||
2647 | #ifdef HAS8BYTEINT | ||
2648 | { /* tt is a 64-bit int so we have to swap the two 32-bit words. | ||
2649 | (Otherwise tt is a struct of two 32-bit words, and even though | ||
2650 | each word was wrong-endian, they were in the right order | ||
2651 | in the struct.) */ | ||
2652 | int4byte temp = intp[0]; | ||
2653 | intp[0] = intp[1]; | ||
2654 | intp[1] = temp; | ||
2655 | } | ||
2656 | #endif | ||
2657 | } | ||
2658 | |||
2659 | buf->bufptr += sizeof(OSCTimeTag); | ||
2660 | |||
2661 | buf->state = NEED_COUNT; | ||
2662 | |||
2663 | buf->gettingFirstUntypedArg = 0; | ||
2664 | buf->typeStringPtr = 0; | ||
2665 | return 0; | ||
2666 | } | ||
2667 | |||
2668 | |||
2669 | int OSC_closeBundle(OSCbuf *buf) { | ||
2670 | if (buf->bundleDepth == 0) { | ||
2671 | /* This handles EMPTY, ONE_MSG, ARGS, and DONE */ | ||
2672 | OSC_errorMessage = "Can't close bundle; no bundle is open!"; | ||
2673 | return 5; | ||
2674 | } | ||
2675 | |||
2676 | if (CheckTypeTag(buf, '\0')) return 9; | ||
2677 | |||
2678 | if (buf->state == GET_ARGS) { | ||
2679 | PatchMessageSize(buf); | ||
2680 | } | ||
2681 | |||
2682 | if (buf->bundleDepth == 1) { | ||
2683 | /* Closing the last bundle: No bundle size to patch */ | ||
2684 | buf->state = DONE; | ||
2685 | } else { | ||
2686 | /* Closing a sub-bundle: patch bundle size */ | ||
2687 | int size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4; | ||
2688 | *(buf->prevCounts[buf->bundleDepth]) = htonl(size); | ||
2689 | buf->state = NEED_COUNT; | ||
2690 | } | ||
2691 | |||
2692 | --buf->bundleDepth; | ||
2693 | buf->gettingFirstUntypedArg = 0; | ||
2694 | buf->typeStringPtr = 0; | ||
2695 | return 0; | ||
2696 | } | ||
2697 | |||
2698 | |||
2699 | int OSC_closeAllBundles(OSCbuf *buf) { | ||
2700 | if (buf->bundleDepth == 0) { | ||
2701 | /* This handles EMPTY, ONE_MSG, ARGS, and DONE */ | ||
2702 | OSC_errorMessage = "Can't close all bundles; no bundle is open!"; | ||
2703 | return 6; | ||
2704 | } | ||
2705 | |||
2706 | if (CheckTypeTag(buf, '\0')) return 9; | ||
2707 | |||
2708 | while (buf->bundleDepth > 0) { | ||
2709 | OSC_closeBundle(buf); | ||
2710 | } | ||
2711 | buf->typeStringPtr = 0; | ||
2712 | return 0; | ||
2713 | } | ||
2714 | |||
2715 | int OSC_writeAddress(OSCbuf *buf, char *name) { | ||
2716 | int4byte paddedLength; | ||
2717 | |||
2718 | if (buf->state == ONE_MSG_ARGS) { | ||
2719 | OSC_errorMessage = "This packet is not a bundle, so you can't write another address"; | ||
2720 | return 7; | ||
2721 | } | ||
2722 | |||
2723 | if (buf->state == DONE) { | ||
2724 | OSC_errorMessage = "This packet is finished; can't write another address"; | ||
2725 | return 8; | ||
2726 | } | ||
2727 | |||
2728 | if (CheckTypeTag(buf, '\0')) return 9; | ||
2729 | |||
2730 | paddedLength = OSC_effectiveStringLength(name); | ||
2731 | |||
2732 | if (buf->state == EMPTY) { | ||
2733 | /* This will be a one-message packet, so no sizes to worry about */ | ||
2734 | CheckOverflow(buf, paddedLength); | ||
2735 | buf->state = ONE_MSG_ARGS; | ||
2736 | } else { | ||
2737 | /* GET_ARGS or NEED_COUNT */ | ||
2738 | CheckOverflow(buf, 4+paddedLength); | ||
2739 | if (buf->state == GET_ARGS) { | ||
2740 | /* Close the old message */ | ||
2741 | PatchMessageSize(buf); | ||
2742 | } | ||
2743 | buf->thisMsgSize = (int4byte *)buf->bufptr; | ||
2744 | *(buf->thisMsgSize) = 0xbbbbbbbb; | ||
2745 | buf->bufptr += 4; | ||
2746 | buf->state = GET_ARGS; | ||
2747 | } | ||
2748 | |||
2749 | /* Now write the name */ | ||
2750 | buf->bufptr += OSC_padString(buf->bufptr, name); | ||
2751 | buf->typeStringPtr = 0; | ||
2752 | buf->gettingFirstUntypedArg = 1; | ||
2753 | |||
2754 | return 0; | ||
2755 | } | ||
2756 | |||
2757 | int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types) { | ||
2758 | int result; | ||
2759 | int4byte paddedLength; | ||
2760 | |||
2761 | if (CheckTypeTag(buf, '\0')) return 9; | ||
2762 | |||
2763 | result = OSC_writeAddress(buf, name); | ||
2764 | |||
2765 | if (result) return result; | ||
2766 | |||
2767 | paddedLength = OSC_effectiveStringLength(types); | ||
2768 | |||
2769 | CheckOverflow(buf, paddedLength); | ||
2770 | |||
2771 | buf->typeStringPtr = buf->bufptr + 1; /* skip comma */ | ||
2772 | buf->bufptr += OSC_padString(buf->bufptr, types); | ||
2773 | |||
2774 | buf->gettingFirstUntypedArg = 0; | ||
2775 | return 0; | ||
2776 | } | ||
2777 | |||
2778 | static int CheckTypeTag(OSCbuf *buf, char expectedType) { | ||
2779 | if (buf->typeStringPtr) { | ||
2780 | if (*(buf->typeStringPtr) != expectedType) { | ||
2781 | if (expectedType == '\0') { | ||
2782 | OSC_errorMessage = | ||
2783 | "According to the type tag I expected more arguments."; | ||
2784 | } else if (*(buf->typeStringPtr) == '\0') { | ||
2785 | OSC_errorMessage = | ||
2786 | "According to the type tag I didn't expect any more arguments."; | ||
2787 | } else { | ||
2788 | OSC_errorMessage = | ||
2789 | "According to the type tag I expected an argument of a different type."; | ||
2790 | printf("* Expected %c, string now %s\n", expectedType, buf->typeStringPtr); | ||
2791 | } | ||
2792 | return 9; | ||
2793 | } | ||
2794 | ++(buf->typeStringPtr); | ||
2795 | } | ||
2796 | return 0; | ||
2797 | } | ||
2798 | |||
2799 | |||
2800 | int OSC_writeFloatArg(OSCbuf *buf, float arg) { | ||
2801 | int4byte *intp; | ||
2802 | //int result; | ||
2803 | |||
2804 | CheckOverflow(buf, 4); | ||
2805 | |||
2806 | if (CheckTypeTag(buf, 'f')) return 9; | ||
2807 | |||
2808 | /* Pretend arg is a long int so we can use htonl() */ | ||
2809 | intp = ((int4byte *) &arg); | ||
2810 | *((int4byte *) buf->bufptr) = htonl(*intp); | ||
2811 | |||
2812 | buf->bufptr += 4; | ||
2813 | |||
2814 | buf->gettingFirstUntypedArg = 0; | ||
2815 | return 0; | ||
2816 | } | ||
2817 | |||
2818 | |||
2819 | |||
2820 | int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args) { | ||
2821 | int i; | ||
2822 | int4byte *intp; | ||
2823 | |||
2824 | CheckOverflow(buf, 4 * numFloats); | ||
2825 | |||
2826 | /* Pretend args are long ints so we can use htonl() */ | ||
2827 | intp = ((int4byte *) args); | ||
2828 | |||
2829 | for (i = 0; i < numFloats; i++) { | ||
2830 | if (CheckTypeTag(buf, 'f')) return 9; | ||
2831 | *((int4byte *) buf->bufptr) = htonl(intp[i]); | ||
2832 | buf->bufptr += 4; | ||
2833 | } | ||
2834 | |||
2835 | buf->gettingFirstUntypedArg = 0; | ||
2836 | return 0; | ||
2837 | } | ||
2838 | |||
2839 | int OSC_writeIntArg(OSCbuf *buf, int4byte arg) { | ||
2840 | CheckOverflow(buf, 4); | ||
2841 | if (CheckTypeTag(buf, 'i')) return 9; | ||
2842 | |||
2843 | *((int4byte *) buf->bufptr) = htonl(arg); | ||
2844 | buf->bufptr += 4; | ||
2845 | |||
2846 | buf->gettingFirstUntypedArg = 0; | ||
2847 | return 0; | ||
2848 | } | ||
2849 | |||
2850 | int OSC_writeStringArg(OSCbuf *buf, char *arg) { | ||
2851 | int len; | ||
2852 | |||
2853 | if (CheckTypeTag(buf, 's')) return 9; | ||
2854 | |||
2855 | len = OSC_effectiveStringLength(arg); | ||
2856 | |||
2857 | if (buf->gettingFirstUntypedArg && arg[0] == ',') { | ||
2858 | /* This un-type-tagged message starts with a string | ||
2859 | that starts with a comma, so we have to escape it | ||
2860 | (with a double comma) so it won't look like a type | ||
2861 | tag string. */ | ||
2862 | |||
2863 | CheckOverflow(buf, len+4); /* Too conservative */ | ||
2864 | buf->bufptr += | ||
2865 | OSC_padStringWithAnExtraStupidComma(buf->bufptr, arg); | ||
2866 | |||
2867 | } else { | ||
2868 | CheckOverflow(buf, len); | ||
2869 | buf->bufptr += OSC_padString(buf->bufptr, arg); | ||
2870 | } | ||
2871 | |||
2872 | buf->gettingFirstUntypedArg = 0; | ||
2873 | return 0; | ||
2874 | |||
2875 | } | ||
2876 | |||
2877 | /* String utilities */ | ||
2878 | |||
2879 | #define STRING_ALIGN_PAD 4 | ||
2880 | int OSC_effectiveStringLength(char *string) { | ||
2881 | int len = strlen(string) + 1; /* We need space for the null char. */ | ||
2882 | |||
2883 | /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */ | ||
2884 | if ((len % STRING_ALIGN_PAD) != 0) { | ||
2885 | len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD); | ||
2886 | } | ||
2887 | return len; | ||
2888 | } | ||
2889 | |||
2890 | static int OSC_padString(char *dest, char *str) { | ||
2891 | int i; | ||
2892 | |||
2893 | for (i = 0; str[i] != '\0'; i++) { | ||
2894 | dest[i] = str[i]; | ||
2895 | } | ||
2896 | |||
2897 | return OSC_WritePadding(dest, i); | ||
2898 | } | ||
2899 | |||
2900 | static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str) { | ||
2901 | int i; | ||
2902 | |||
2903 | dest[0] = ','; | ||
2904 | for (i = 0; str[i] != '\0'; i++) { | ||
2905 | dest[i+1] = str[i]; | ||
2906 | } | ||
2907 | |||
2908 | return OSC_WritePadding(dest, i+1); | ||
2909 | } | ||
2910 | |||
2911 | static int OSC_WritePadding(char *dest, int i) { | ||
2912 | dest[i] = '\0'; | ||
2913 | i++; | ||
2914 | |||
2915 | for (; (i % STRING_ALIGN_PAD) != 0; i++) { | ||
2916 | dest[i] = '\0'; | ||
2917 | } | ||
2918 | |||
2919 | return i; | ||
2920 | } | ||
2921 | |||
2922 | |||