diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/extra/sendOSC.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/extra/sendOSC.c | 2920 |
1 files changed, 1460 insertions, 1460 deletions
diff --git a/apps/plugins/pdbox/PDa/extra/sendOSC.c b/apps/plugins/pdbox/PDa/extra/sendOSC.c index bc983cc31e..ac7ae37954 100644 --- a/apps/plugins/pdbox/PDa/extra/sendOSC.c +++ b/apps/plugins/pdbox/PDa/extra/sendOSC.c | |||
@@ -1,1461 +1,1461 @@ | |||
1 | /* | 1 | /* |
2 | Written by Matt Wright, The Center for New Music and Audio Technologies, | 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 | 3 | University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03 |
4 | The Regents of the University of California (Regents). | 4 | The Regents of the University of California (Regents). |
5 | 5 | ||
6 | Permission to use, copy, modify, distribute, and distribute modified versions | 6 | Permission to use, copy, modify, distribute, and distribute modified versions |
7 | of this software and its documentation without fee and without a signed | 7 | of this software and its documentation without fee and without a signed |
8 | licensing agreement, is hereby granted, provided that the above copyright | 8 | licensing agreement, is hereby granted, provided that the above copyright |
9 | notice, this paragraph and the following two paragraphs appear in all copies, | 9 | notice, this paragraph and the following two paragraphs appear in all copies, |
10 | modifications, and distributions. | 10 | modifications, and distributions. |
11 | 11 | ||
12 | IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, | 12 | IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, |
13 | SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING | 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 | 14 | OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS |
15 | BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 15 | BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
16 | 16 | ||
17 | REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | 17 | REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
18 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 18 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED | 19 | PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED |
20 | HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE | 20 | HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE |
21 | MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 21 | MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
22 | 22 | ||
23 | 23 | ||
24 | The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl | 24 | The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl |
25 | */ | 25 | */ |
26 | 26 | ||
27 | 27 | ||
28 | /* sendOSC.c | 28 | /* sendOSC.c |
29 | 29 | ||
30 | Matt Wright, 6/3/97 | 30 | Matt Wright, 6/3/97 |
31 | based on sendOSC.c, which was based on a version by Adrian Freed | 31 | based on sendOSC.c, which was based on a version by Adrian Freed |
32 | 32 | ||
33 | Text-based OpenSoundControl client. User can enter messages via command | 33 | Text-based OpenSoundControl client. User can enter messages via command |
34 | line arguments or standard input. | 34 | line arguments or standard input. |
35 | 35 | ||
36 | Version 0.1: "play" feature | 36 | Version 0.1: "play" feature |
37 | Version 0.2: Message type tags. | 37 | Version 0.2: Message type tags. |
38 | 38 | ||
39 | pd version branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/sendOSC/sendOSC.c | 39 | pd version branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/sendOSC/sendOSC.c |
40 | ------------- | 40 | ------------- |
41 | -- added bundle stuff to send. jdl 20020416 | 41 | -- added bundle stuff to send. jdl 20020416 |
42 | -- tweaks for Win32 www.zeggz.com/raf 13-April-2002 | 42 | -- tweaks for Win32 www.zeggz.com/raf 13-April-2002 |
43 | -- ost_at_test.at + i22_at_test.at, 2000-2002 | 43 | -- ost_at_test.at + i22_at_test.at, 2000-2002 |
44 | modified to compile as pd externel | 44 | modified to compile as pd externel |
45 | */ | 45 | */ |
46 | 46 | ||
47 | #define MAX_ARGS 2000 | 47 | #define MAX_ARGS 2000 |
48 | #define SC_BUFFER_SIZE 64000 | 48 | #define SC_BUFFER_SIZE 64000 |
49 | 49 | ||
50 | #include "m_pd.h" | 50 | #include "m_pd.h" |
51 | #include "OSC-client.h" | 51 | #include "OSC-client.h" |
52 | 52 | ||
53 | #include <string.h> | 53 | #include <string.h> |
54 | #include <sys/types.h> | 54 | #include <sys/types.h> |
55 | #include <stdlib.h> | 55 | #include <stdlib.h> |
56 | #include <stdio.h> | 56 | #include <stdio.h> |
57 | #include <sys/stat.h> | 57 | #include <sys/stat.h> |
58 | #include <sys/types.h> | 58 | #include <sys/types.h> |
59 | 59 | ||
60 | #ifdef WIN32 | 60 | #ifdef WIN32 |
61 | #include <winsock2.h> | 61 | #include <winsock2.h> |
62 | #include <io.h> | 62 | #include <io.h> |
63 | #include <errno.h> | 63 | #include <errno.h> |
64 | #include <fcntl.h> | 64 | #include <fcntl.h> |
65 | #include <winsock2.h> | 65 | #include <winsock2.h> |
66 | #include <ctype.h> | 66 | #include <ctype.h> |
67 | #include <signal.h> | 67 | #include <signal.h> |
68 | #else | 68 | #else |
69 | #include <sys/socket.h> | 69 | #include <sys/socket.h> |
70 | #include <netinet/in.h> | 70 | #include <netinet/in.h> |
71 | #include <rpc/rpc.h> | 71 | #include <rpc/rpc.h> |
72 | #include <sys/times.h> | 72 | #include <sys/times.h> |
73 | #include <sys/param.h> | 73 | #include <sys/param.h> |
74 | #include <sys/time.h> | 74 | #include <sys/time.h> |
75 | #include <sys/ioctl.h> | 75 | #include <sys/ioctl.h> |
76 | #include <netdb.h> | 76 | #include <netdb.h> |
77 | #endif | 77 | #endif |
78 | 78 | ||
79 | #ifdef __APPLE__ | 79 | #ifdef __APPLE__ |
80 | #include <string.h> | 80 | #include <string.h> |
81 | #endif | 81 | #endif |
82 | 82 | ||
83 | #define UNIXDG_PATH "/tmp/htm" | 83 | #define UNIXDG_PATH "/tmp/htm" |
84 | #define UNIXDG_TMP "/tmp/htm.XXXXXX" | 84 | #define UNIXDG_TMP "/tmp/htm.XXXXXX" |
85 | 85 | ||
86 | 86 | ||
87 | 87 | ||
88 | OSCTimeTag OSCTT_Immediately(void) { | 88 | OSCTimeTag OSCTT_Immediately(void) { |
89 | OSCTimeTag result; | 89 | OSCTimeTag result; |
90 | result.seconds = 0; | 90 | result.seconds = 0; |
91 | result.fraction = 1; | 91 | result.fraction = 1; |
92 | return result; | 92 | return result; |
93 | } | 93 | } |
94 | 94 | ||
95 | 95 | ||
96 | OSCTimeTag OSCTT_CurrentTime(void) { | 96 | OSCTimeTag OSCTT_CurrentTime(void) { |
97 | OSCTimeTag result; | 97 | OSCTimeTag result; |
98 | result.seconds = 0; | 98 | result.seconds = 0; |
99 | result.fraction = 1; | 99 | result.fraction = 1; |
100 | return result; | 100 | return result; |
101 | } | 101 | } |
102 | 102 | ||
103 | OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) { | 103 | OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) { |
104 | OSCTimeTag result; | 104 | OSCTimeTag result; |
105 | result.seconds = 0; | 105 | result.seconds = 0; |
106 | result.fraction = 1; | 106 | result.fraction = 1; |
107 | return result; | 107 | return result; |
108 | } | 108 | } |
109 | 109 | ||
110 | 110 | ||
111 | typedef int bool; | 111 | typedef int bool; |
112 | 112 | ||
113 | typedef struct | 113 | typedef struct |
114 | { | 114 | { |
115 | float srate; | 115 | float srate; |
116 | 116 | ||
117 | struct sockaddr_in serv_addr; /* udp socket */ | 117 | struct sockaddr_in serv_addr; /* udp socket */ |
118 | #ifndef WIN32 | 118 | #ifndef WIN32 |
119 | struct sockaddr_un userv_addr; /* UNIX socket */ | 119 | struct sockaddr_un userv_addr; /* UNIX socket */ |
120 | #endif | 120 | #endif |
121 | int sockfd; /* socket file descriptor */ | 121 | int sockfd; /* socket file descriptor */ |
122 | int index, len,uservlen; | 122 | int index, len,uservlen; |
123 | void *addr; | 123 | void *addr; |
124 | int id; | 124 | int id; |
125 | } desc; | 125 | } desc; |
126 | 126 | ||
127 | 127 | ||
128 | /* open a socket for HTM communication to given host on given portnumber */ | 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 */ | 129 | /* if host is 0 then UNIX protocol is used (i.e. local communication */ |
130 | void *OpenHTMSocket(char *host, int portnumber) | 130 | void *OpenHTMSocket(char *host, int portnumber) |
131 | { | 131 | { |
132 | struct sockaddr_in cl_addr; | 132 | struct sockaddr_in cl_addr; |
133 | #ifndef WIN32 | 133 | #ifndef WIN32 |
134 | int sockfd; | 134 | int sockfd; |
135 | struct sockaddr_un ucl_addr; | 135 | struct sockaddr_un ucl_addr; |
136 | #else | 136 | #else |
137 | unsigned int sockfd; | 137 | unsigned int sockfd; |
138 | #endif | 138 | #endif |
139 | 139 | ||
140 | desc *o; | 140 | desc *o; |
141 | int oval = 1; | 141 | int oval = 1; |
142 | o = malloc(sizeof(*o)); | 142 | o = malloc(sizeof(*o)); |
143 | if(!o) return 0; | 143 | if(!o) return 0; |
144 | 144 | ||
145 | #ifndef WIN32 | 145 | #ifndef WIN32 |
146 | 146 | ||
147 | if(!host) | 147 | if(!host) |
148 | { | 148 | { |
149 | char *mktemp(char *); | 149 | char *mktemp(char *); |
150 | int clilen; | 150 | int clilen; |
151 | o->len = sizeof(ucl_addr); | 151 | o->len = sizeof(ucl_addr); |
152 | /* | 152 | /* |
153 | * Fill in the structure "userv_addr" with the address of the | 153 | * Fill in the structure "userv_addr" with the address of the |
154 | * server that we want to send to. | 154 | * server that we want to send to. |
155 | */ | 155 | */ |
156 | 156 | ||
157 | bzero((char *) &o->userv_addr, sizeof(o->userv_addr)); | 157 | bzero((char *) &o->userv_addr, sizeof(o->userv_addr)); |
158 | o->userv_addr.sun_family = AF_UNIX; | 158 | o->userv_addr.sun_family = AF_UNIX; |
159 | strcpy(o->userv_addr.sun_path, UNIXDG_PATH); | 159 | strcpy(o->userv_addr.sun_path, UNIXDG_PATH); |
160 | sprintf(o->userv_addr.sun_path+strlen(o->userv_addr.sun_path), "%d", portnumber); | 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); | 161 | o->uservlen = sizeof(o->userv_addr.sun_family) + strlen(o->userv_addr.sun_path); |
162 | o->addr = &(o->userv_addr); | 162 | o->addr = &(o->userv_addr); |
163 | /* | 163 | /* |
164 | * Open a socket (a UNIX domain datagram socket). | 164 | * Open a socket (a UNIX domain datagram socket). |
165 | */ | 165 | */ |
166 | 166 | ||
167 | if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0) | 167 | if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0) |
168 | { | 168 | { |
169 | /* | 169 | /* |
170 | * Bind a local address for us. | 170 | * Bind a local address for us. |
171 | * In the UNIX domain we have to choose our own name (that | 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 | 172 | * should be unique). We'll use mktemp() to create a unique |
173 | * pathname, based on our process id. | 173 | * pathname, based on our process id. |
174 | */ | 174 | */ |
175 | 175 | ||
176 | bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */ | 176 | bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */ |
177 | ucl_addr.sun_family = AF_UNIX; | 177 | ucl_addr.sun_family = AF_UNIX; |
178 | strcpy(ucl_addr.sun_path, UNIXDG_TMP); | 178 | strcpy(ucl_addr.sun_path, UNIXDG_TMP); |
179 | 179 | ||
180 | mktemp(ucl_addr.sun_path); | 180 | mktemp(ucl_addr.sun_path); |
181 | clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path); | 181 | clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path); |
182 | 182 | ||
183 | if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0) | 183 | if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0) |
184 | { | 184 | { |
185 | perror("client: can't bind local address"); | 185 | perror("client: can't bind local address"); |
186 | close(sockfd); | 186 | close(sockfd); |
187 | sockfd = -1; | 187 | sockfd = -1; |
188 | } | 188 | } |
189 | } | 189 | } |
190 | else | 190 | else |
191 | perror("unable to make socket\n"); | 191 | perror("unable to make socket\n"); |
192 | 192 | ||
193 | }else | 193 | }else |
194 | 194 | ||
195 | #endif | 195 | #endif |
196 | 196 | ||
197 | { | 197 | { |
198 | /* | 198 | /* |
199 | * Fill in the structure "serv_addr" with the address of the | 199 | * Fill in the structure "serv_addr" with the address of the |
200 | * server that we want to send to. | 200 | * server that we want to send to. |
201 | */ | 201 | */ |
202 | o->len = sizeof(cl_addr); | 202 | o->len = sizeof(cl_addr); |
203 | 203 | ||
204 | #ifdef WIN32 | 204 | #ifdef WIN32 |
205 | ZeroMemory((char *)&o->serv_addr, sizeof(o->serv_addr)); | 205 | ZeroMemory((char *)&o->serv_addr, sizeof(o->serv_addr)); |
206 | #else | 206 | #else |
207 | bzero((char *)&o->serv_addr, sizeof(o->serv_addr)); | 207 | bzero((char *)&o->serv_addr, sizeof(o->serv_addr)); |
208 | #endif | 208 | #endif |
209 | 209 | ||
210 | o->serv_addr.sin_family = AF_INET; | 210 | o->serv_addr.sin_family = AF_INET; |
211 | 211 | ||
212 | /* MW 6/6/96: Call gethostbyname() instead of inet_addr(), | 212 | /* MW 6/6/96: Call gethostbyname() instead of inet_addr(), |
213 | so that host can be either an Internet host name (e.g., | 213 | so that host can be either an Internet host name (e.g., |
214 | "les") or an Internet address in standard dot notation | 214 | "les") or an Internet address in standard dot notation |
215 | (e.g., "128.32.122.13") */ | 215 | (e.g., "128.32.122.13") */ |
216 | { | 216 | { |
217 | struct hostent *hostsEntry; | 217 | struct hostent *hostsEntry; |
218 | unsigned long address; | 218 | unsigned long address; |
219 | 219 | ||
220 | hostsEntry = gethostbyname(host); | 220 | hostsEntry = gethostbyname(host); |
221 | if (hostsEntry == NULL) { | 221 | if (hostsEntry == NULL) { |
222 | fprintf(stderr, "Couldn't decipher host name \"%s\"\n", host); | 222 | fprintf(stderr, "Couldn't decipher host name \"%s\"\n", host); |
223 | #ifndef WIN32 | 223 | #ifndef WIN32 |
224 | herror(NULL); | 224 | herror(NULL); |
225 | #endif | 225 | #endif |
226 | return 0; | 226 | return 0; |
227 | } | 227 | } |
228 | address = *((unsigned long *) hostsEntry->h_addr_list[0]); | 228 | address = *((unsigned long *) hostsEntry->h_addr_list[0]); |
229 | o->serv_addr.sin_addr.s_addr = address; | 229 | o->serv_addr.sin_addr.s_addr = address; |
230 | } | 230 | } |
231 | 231 | ||
232 | /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */ | 232 | /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */ |
233 | 233 | ||
234 | /* End MW changes */ | 234 | /* End MW changes */ |
235 | 235 | ||
236 | /* | 236 | /* |
237 | * Open a socket (a UDP domain datagram socket). | 237 | * Open a socket (a UDP domain datagram socket). |
238 | */ | 238 | */ |
239 | 239 | ||
240 | 240 | ||
241 | #ifdef WIN32 | 241 | #ifdef WIN32 |
242 | o->serv_addr.sin_port = htons((USHORT)portnumber); | 242 | o->serv_addr.sin_port = htons((USHORT)portnumber); |
243 | o->addr = &(o->serv_addr); | 243 | o->addr = &(o->serv_addr); |
244 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) { | 244 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) { |
245 | ZeroMemory((char *)&cl_addr, sizeof(cl_addr)); | 245 | ZeroMemory((char *)&cl_addr, sizeof(cl_addr)); |
246 | cl_addr.sin_family = AF_INET; | 246 | cl_addr.sin_family = AF_INET; |
247 | cl_addr.sin_addr.s_addr = htonl(INADDR_ANY); | 247 | cl_addr.sin_addr.s_addr = htonl(INADDR_ANY); |
248 | cl_addr.sin_port = htons(0); | 248 | cl_addr.sin_port = htons(0); |
249 | 249 | ||
250 | // enable broadcast: jdl ~2003 | 250 | // enable broadcast: jdl ~2003 |
251 | if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) { | 251 | if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) { |
252 | perror("setsockopt"); | 252 | perror("setsockopt"); |
253 | } | 253 | } |
254 | 254 | ||
255 | if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) { | 255 | if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) { |
256 | perror("could not bind\n"); | 256 | perror("could not bind\n"); |
257 | closesocket(sockfd); | 257 | closesocket(sockfd); |
258 | sockfd = -1; | 258 | sockfd = -1; |
259 | } | 259 | } |
260 | } | 260 | } |
261 | else { perror("unable to make socket\n");} | 261 | else { perror("unable to make socket\n");} |
262 | #else | 262 | #else |
263 | o->serv_addr.sin_port = htons(portnumber); | 263 | o->serv_addr.sin_port = htons(portnumber); |
264 | o->addr = &(o->serv_addr); | 264 | o->addr = &(o->serv_addr); |
265 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { | 265 | if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { |
266 | bzero((char *)&cl_addr, sizeof(cl_addr)); | 266 | bzero((char *)&cl_addr, sizeof(cl_addr)); |
267 | cl_addr.sin_family = AF_INET; | 267 | cl_addr.sin_family = AF_INET; |
268 | cl_addr.sin_addr.s_addr = htonl(INADDR_ANY); | 268 | cl_addr.sin_addr.s_addr = htonl(INADDR_ANY); |
269 | cl_addr.sin_port = htons(0); | 269 | cl_addr.sin_port = htons(0); |
270 | 270 | ||
271 | // enable broadcast: jdl ~2003 | 271 | // enable broadcast: jdl ~2003 |
272 | if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) { | 272 | if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) { |
273 | perror("setsockopt"); | 273 | perror("setsockopt"); |
274 | } | 274 | } |
275 | 275 | ||
276 | if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) { | 276 | if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) { |
277 | perror("could not bind\n"); | 277 | perror("could not bind\n"); |
278 | close(sockfd); | 278 | close(sockfd); |
279 | sockfd = -1; | 279 | sockfd = -1; |
280 | } | 280 | } |
281 | } | 281 | } |
282 | else { perror("unable to make socket\n");} | 282 | else { perror("unable to make socket\n");} |
283 | #endif | 283 | #endif |
284 | } | 284 | } |
285 | #ifdef WIN32 | 285 | #ifdef WIN32 |
286 | if(sockfd == INVALID_SOCKET) { | 286 | if(sockfd == INVALID_SOCKET) { |
287 | #else | 287 | #else |
288 | if(sockfd < 0) { | 288 | if(sockfd < 0) { |
289 | #endif | 289 | #endif |
290 | free(o); | 290 | free(o); |
291 | o = 0; | 291 | o = 0; |
292 | } | 292 | } |
293 | else | 293 | else |
294 | o->sockfd = sockfd; | 294 | o->sockfd = sockfd; |
295 | return o; | 295 | return o; |
296 | } | 296 | } |
297 | 297 | ||
298 | static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b) | 298 | static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b) |
299 | { | 299 | { |
300 | int rcount; | 300 | int rcount; |
301 | if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count) | 301 | if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count) |
302 | { | 302 | { |
303 | printf("sockfd %d count %d rcount %dlength %d\n", sockfd,count,rcount,length); | 303 | printf("sockfd %d count %d rcount %dlength %d\n", sockfd,count,rcount,length); |
304 | return FALSE; | 304 | return FALSE; |
305 | } | 305 | } |
306 | return TRUE; | 306 | return TRUE; |
307 | } | 307 | } |
308 | 308 | ||
309 | bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer) | 309 | bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer) |
310 | { | 310 | { |
311 | desc *o = (desc *)htmsendhandle; | 311 | desc *o = (desc *)htmsendhandle; |
312 | return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer); | 312 | return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer); |
313 | } | 313 | } |
314 | void CloseHTMSocket(void *htmsendhandle) | 314 | void CloseHTMSocket(void *htmsendhandle) |
315 | { | 315 | { |
316 | desc *o = (desc *)htmsendhandle; | 316 | desc *o = (desc *)htmsendhandle; |
317 | #ifdef WIN32 | 317 | #ifdef WIN32 |
318 | if(SOCKET_ERROR == closesocket(o->sockfd)) { | 318 | if(SOCKET_ERROR == closesocket(o->sockfd)) { |
319 | perror("CloseHTMSocket::closesocket failed\n"); | 319 | perror("CloseHTMSocket::closesocket failed\n"); |
320 | return; | 320 | return; |
321 | } | 321 | } |
322 | #else | 322 | #else |
323 | if(close(o->sockfd) == -1) | 323 | if(close(o->sockfd) == -1) |
324 | { | 324 | { |
325 | perror("CloseHTMSocket::closesocket failed"); | 325 | perror("CloseHTMSocket::closesocket failed"); |
326 | return; | 326 | return; |
327 | } | 327 | } |
328 | #endif | 328 | #endif |
329 | 329 | ||
330 | free(o); | 330 | free(o); |
331 | } | 331 | } |
332 | 332 | ||
333 | 333 | ||
334 | /////////////////////// | 334 | /////////////////////// |
335 | // from sendOSC | 335 | // from sendOSC |
336 | 336 | ||
337 | typedef struct { | 337 | typedef struct { |
338 | //enum {INT, FLOAT, STRING} type; | 338 | //enum {INT, FLOAT, STRING} type; |
339 | enum {INT_osc, FLOAT_osc, STRING_osc} type; | 339 | enum {INT_osc, FLOAT_osc, STRING_osc} type; |
340 | union { | 340 | union { |
341 | int i; | 341 | int i; |
342 | float f; | 342 | float f; |
343 | char *s; | 343 | char *s; |
344 | } datum; | 344 | } datum; |
345 | } typedArg; | 345 | } typedArg; |
346 | 346 | ||
347 | void CommandLineMode(int argc, char *argv[], void *htmsocket); | 347 | void CommandLineMode(int argc, char *argv[], void *htmsocket); |
348 | OSCTimeTag ParseTimeTag(char *s); | 348 | OSCTimeTag ParseTimeTag(char *s); |
349 | void ParseInteractiveLine(OSCbuf *buf, char *mesg); | 349 | void ParseInteractiveLine(OSCbuf *buf, char *mesg); |
350 | typedArg ParseToken(char *token); | 350 | typedArg ParseToken(char *token); |
351 | int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args); | 351 | int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args); |
352 | void SendBuffer(void *htmsocket, OSCbuf *buf); | 352 | void SendBuffer(void *htmsocket, OSCbuf *buf); |
353 | void SendData(void *htmsocket, int size, char *data); | 353 | void SendData(void *htmsocket, int size, char *data); |
354 | /* defined in OSC-system-dependent.c now */ | 354 | /* defined in OSC-system-dependent.c now */ |
355 | 355 | ||
356 | //static void *htmsocket; | 356 | //static void *htmsocket; |
357 | static int exitStatus = 0; | 357 | static int exitStatus = 0; |
358 | static int useTypeTags = 0; | 358 | static int useTypeTags = 0; |
359 | 359 | ||
360 | static char bufferForOSCbuf[SC_BUFFER_SIZE]; | 360 | static char bufferForOSCbuf[SC_BUFFER_SIZE]; |
361 | 361 | ||
362 | 362 | ||
363 | ///////// | 363 | ///////// |
364 | // end from sendOSC | 364 | // end from sendOSC |
365 | 365 | ||
366 | static t_class *sendOSC_class; | 366 | static t_class *sendOSC_class; |
367 | 367 | ||
368 | typedef struct _sendOSC | 368 | typedef struct _sendOSC |
369 | { | 369 | { |
370 | t_object x_obj; | 370 | t_object x_obj; |
371 | int x_protocol; // UDP/TCP (udp only atm) | 371 | int x_protocol; // UDP/TCP (udp only atm) |
372 | t_int x_typetags; // typetag flag | 372 | t_int x_typetags; // typetag flag |
373 | void *x_htmsocket; // sending socket | 373 | void *x_htmsocket; // sending socket |
374 | int x_bundle; // bundle open flag | 374 | int x_bundle; // bundle open flag |
375 | OSCbuf x_oscbuf[1]; // OSCbuffer | 375 | OSCbuf x_oscbuf[1]; // OSCbuffer |
376 | t_outlet *x_bdpthout;// bundle-depth floatoutlet | 376 | t_outlet *x_bdpthout;// bundle-depth floatoutlet |
377 | } t_sendOSC; | 377 | } t_sendOSC; |
378 | 378 | ||
379 | static void *sendOSC_new(t_floatarg udpflag) | 379 | static void *sendOSC_new(t_floatarg udpflag) |
380 | { | 380 | { |
381 | t_sendOSC *x = (t_sendOSC *)pd_new(sendOSC_class); | 381 | t_sendOSC *x = (t_sendOSC *)pd_new(sendOSC_class); |
382 | outlet_new(&x->x_obj, &s_float); | 382 | outlet_new(&x->x_obj, &s_float); |
383 | x->x_htmsocket = 0; // {{raf}} | 383 | x->x_htmsocket = 0; // {{raf}} |
384 | // set udp | 384 | // set udp |
385 | x->x_protocol = SOCK_STREAM; | 385 | x->x_protocol = SOCK_STREAM; |
386 | // set typetags to 1 by default | 386 | // set typetags to 1 by default |
387 | x->x_typetags = 1; | 387 | x->x_typetags = 1; |
388 | // bunlde is closed | 388 | // bunlde is closed |
389 | x->x_bundle = 0; | 389 | x->x_bundle = 0; |
390 | OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf); | 390 | OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf); |
391 | x->x_bdpthout = outlet_new(&x->x_obj, 0); // outlet_float(); | 391 | x->x_bdpthout = outlet_new(&x->x_obj, 0); // outlet_float(); |
392 | //x->x_oscbuf = | 392 | //x->x_oscbuf = |
393 | return (x); | 393 | return (x); |
394 | } | 394 | } |
395 | 395 | ||
396 | 396 | ||
397 | void sendOSC_openbundle(t_sendOSC *x) | 397 | void sendOSC_openbundle(t_sendOSC *x) |
398 | { | 398 | { |
399 | if (x->x_oscbuf->bundleDepth + 1 >= MAX_BUNDLE_NESTING || | 399 | if (x->x_oscbuf->bundleDepth + 1 >= MAX_BUNDLE_NESTING || |
400 | OSC_openBundle(x->x_oscbuf, OSCTT_Immediately())) | 400 | OSC_openBundle(x->x_oscbuf, OSCTT_Immediately())) |
401 | { | 401 | { |
402 | post("Problem opening bundle: %s\n", OSC_errorMessage); | 402 | post("Problem opening bundle: %s\n", OSC_errorMessage); |
403 | return; | 403 | return; |
404 | } | 404 | } |
405 | x->x_bundle = 1; | 405 | x->x_bundle = 1; |
406 | outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth); | 406 | outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth); |
407 | } | 407 | } |
408 | 408 | ||
409 | static void sendOSC_closebundle(t_sendOSC *x) | 409 | static void sendOSC_closebundle(t_sendOSC *x) |
410 | { | 410 | { |
411 | if (OSC_closeBundle(x->x_oscbuf)) { | 411 | if (OSC_closeBundle(x->x_oscbuf)) { |
412 | post("Problem closing bundle: %s\n", OSC_errorMessage); | 412 | post("Problem closing bundle: %s\n", OSC_errorMessage); |
413 | return; | 413 | return; |
414 | } | 414 | } |
415 | outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth); | 415 | outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth); |
416 | // in bundle mode we send when bundle is closed? | 416 | // in bundle mode we send when bundle is closed? |
417 | if(!OSC_isBufferEmpty(x->x_oscbuf) > 0 && OSC_isBufferDone(x->x_oscbuf)) { | 417 | if(!OSC_isBufferEmpty(x->x_oscbuf) > 0 && OSC_isBufferDone(x->x_oscbuf)) { |
418 | // post("x_oscbuf: something inside me?"); | 418 | // post("x_oscbuf: something inside me?"); |
419 | if (x->x_htmsocket) { | 419 | if (x->x_htmsocket) { |
420 | SendBuffer(x->x_htmsocket, x->x_oscbuf); | 420 | SendBuffer(x->x_htmsocket, x->x_oscbuf); |
421 | } else { | 421 | } else { |
422 | post("sendOSC: not connected"); | 422 | post("sendOSC: not connected"); |
423 | } | 423 | } |
424 | OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf); | 424 | OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf); |
425 | x->x_bundle = 0; | 425 | x->x_bundle = 0; |
426 | return; | 426 | return; |
427 | } | 427 | } |
428 | // post("x_oscbuf: something went wrong"); | 428 | // post("x_oscbuf: something went wrong"); |
429 | } | 429 | } |
430 | 430 | ||
431 | static void sendOSC_settypetags(t_sendOSC *x, t_float *f) | 431 | static void sendOSC_settypetags(t_sendOSC *x, t_float *f) |
432 | { | 432 | { |
433 | x->x_typetags = (int)f; | 433 | x->x_typetags = (int)f; |
434 | post("sendOSC.c: setting typetags %d",x->x_typetags); | 434 | post("sendOSC.c: setting typetags %d",x->x_typetags); |
435 | } | 435 | } |
436 | 436 | ||
437 | 437 | ||
438 | static void sendOSC_connect(t_sendOSC *x, t_symbol *hostname, | 438 | static void sendOSC_connect(t_sendOSC *x, t_symbol *hostname, |
439 | t_floatarg fportno) | 439 | t_floatarg fportno) |
440 | { | 440 | { |
441 | int portno = fportno; | 441 | int portno = fportno; |
442 | /* create a socket */ | 442 | /* create a socket */ |
443 | 443 | ||
444 | // make sure handle is available | 444 | // make sure handle is available |
445 | if(x->x_htmsocket == 0) { | 445 | if(x->x_htmsocket == 0) { |
446 | // | 446 | // |
447 | x->x_htmsocket = OpenHTMSocket(hostname->s_name, portno); | 447 | x->x_htmsocket = OpenHTMSocket(hostname->s_name, portno); |
448 | if (!x->x_htmsocket) | 448 | if (!x->x_htmsocket) |
449 | post("Couldn't open socket: "); | 449 | post("Couldn't open socket: "); |
450 | else { | 450 | else { |
451 | post("connected to port %s:%d (hSock=%d)", hostname->s_name, portno, x->x_htmsocket); | 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); | 452 | outlet_float(x->x_obj.ob_outlet, 1); |
453 | } | 453 | } |
454 | } | 454 | } |
455 | else | 455 | else |
456 | perror("call to sendOSC_connect() against UNavailable socket handle"); | 456 | perror("call to sendOSC_connect() against UNavailable socket handle"); |
457 | } | 457 | } |
458 | 458 | ||
459 | void sendOSC_disconnect(t_sendOSC *x) | 459 | void sendOSC_disconnect(t_sendOSC *x) |
460 | { | 460 | { |
461 | if (x->x_htmsocket) | 461 | if (x->x_htmsocket) |
462 | { | 462 | { |
463 | post("disconnecting htmsock (hSock=%d)...", x->x_htmsocket); | 463 | post("disconnecting htmsock (hSock=%d)...", x->x_htmsocket); |
464 | CloseHTMSocket(x->x_htmsocket); | 464 | CloseHTMSocket(x->x_htmsocket); |
465 | x->x_htmsocket = 0; // {{raf}} semi-quasi-semaphorize this | 465 | x->x_htmsocket = 0; // {{raf}} semi-quasi-semaphorize this |
466 | outlet_float(x->x_obj.ob_outlet, 0); | 466 | outlet_float(x->x_obj.ob_outlet, 0); |
467 | } | 467 | } |
468 | else { | 468 | else { |
469 | perror("call to sendOSC_disconnect() against unused socket handle"); | 469 | perror("call to sendOSC_disconnect() against unused socket handle"); |
470 | } | 470 | } |
471 | } | 471 | } |
472 | 472 | ||
473 | void sendOSC_senduntyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) | 473 | void sendOSC_senduntyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) |
474 | { | 474 | { |
475 | char* targv[MAXPDARG]; | 475 | char* targv[MAXPDARG]; |
476 | char tmparg[MAXPDSTRING]; | 476 | char tmparg[MAXPDSTRING]; |
477 | char* tmp = tmparg; | 477 | char* tmp = tmparg; |
478 | //char testarg[MAXPDSTRING]; | 478 | //char testarg[MAXPDSTRING]; |
479 | int c; | 479 | int c; |
480 | 480 | ||
481 | post("sendOSC: use typetags 0/1 message and plain send method so send untypetagged..."); | 481 | post("sendOSC: use typetags 0/1 message and plain send method so send untypetagged..."); |
482 | return; | 482 | return; |
483 | 483 | ||
484 | //atom_string(argv,testarg, MAXPDSTRING); | 484 | //atom_string(argv,testarg, MAXPDSTRING); |
485 | for (c=0;c<argc;c++) { | 485 | for (c=0;c<argc;c++) { |
486 | atom_string(argv+c,tmp, 80); | 486 | atom_string(argv+c,tmp, 80); |
487 | targv[c] = tmp; | 487 | targv[c] = tmp; |
488 | tmp += strlen(tmp)+1; | 488 | tmp += strlen(tmp)+1; |
489 | } | 489 | } |
490 | 490 | ||
491 | // this sock needs to be larger than 0, not >= .. | 491 | // this sock needs to be larger than 0, not >= .. |
492 | if (x->x_htmsocket) | 492 | if (x->x_htmsocket) |
493 | { | 493 | { |
494 | CommandLineMode(argc, targv, x->x_htmsocket); | 494 | CommandLineMode(argc, targv, x->x_htmsocket); |
495 | // post("test %d", c); | 495 | // post("test %d", c); |
496 | } | 496 | } |
497 | else { | 497 | else { |
498 | post("sendOSC: not connected"); | 498 | post("sendOSC: not connected"); |
499 | } | 499 | } |
500 | } | 500 | } |
501 | 501 | ||
502 | ////////////////////////////////////////////////////////////////////// | 502 | ////////////////////////////////////////////////////////////////////// |
503 | // this is the real and only sending routine now, for both typed and | 503 | // this is the real and only sending routine now, for both typed and |
504 | // undtyped mode. | 504 | // undtyped mode. |
505 | 505 | ||
506 | static void sendOSC_sendtyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) | 506 | static void sendOSC_sendtyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) |
507 | { | 507 | { |
508 | char* targv[MAX_ARGS]; | 508 | char* targv[MAX_ARGS]; |
509 | char tmparg[MAXPDSTRING]; | 509 | char tmparg[MAXPDSTRING]; |
510 | char* tmp = tmparg; | 510 | char* tmp = tmparg; |
511 | int c; | 511 | int c; |
512 | 512 | ||
513 | char *messageName; | 513 | char *messageName; |
514 | char *token; | 514 | char *token; |
515 | typedArg args[MAX_ARGS]; | 515 | typedArg args[MAX_ARGS]; |
516 | int i,j; | 516 | int i,j; |
517 | int numArgs = 0; | 517 | int numArgs = 0; |
518 | 518 | ||
519 | messageName = ""; | 519 | messageName = ""; |
520 | #ifdef DEBUG | 520 | #ifdef DEBUG |
521 | post ("sendOSC: messageName: %s", messageName); | 521 | post ("sendOSC: messageName: %s", messageName); |
522 | #endif | 522 | #endif |
523 | 523 | ||
524 | 524 | ||
525 | 525 | ||
526 | for (c=0;c<argc;c++) { | 526 | for (c=0;c<argc;c++) { |
527 | atom_string(argv+c,tmp, 80); | 527 | atom_string(argv+c,tmp, 80); |
528 | 528 | ||
529 | #ifdef DEBUG | 529 | #ifdef DEBUG |
530 | // post ("sendOSC: %d, %s",c, tmp); | 530 | // post ("sendOSC: %d, %s",c, tmp); |
531 | #endif | 531 | #endif |
532 | 532 | ||
533 | targv[c] = tmp; | 533 | targv[c] = tmp; |
534 | tmp += strlen(tmp)+1; | 534 | tmp += strlen(tmp)+1; |
535 | 535 | ||
536 | #ifdef DEBUG | 536 | #ifdef DEBUG |
537 | // post ("sendOSC: %d, %s",c, targv[c]); | 537 | // post ("sendOSC: %d, %s",c, targv[c]); |
538 | #endif | 538 | #endif |
539 | } | 539 | } |
540 | 540 | ||
541 | // this sock needs to be larger than 0, not >= .. | 541 | // this sock needs to be larger than 0, not >= .. |
542 | if (x->x_htmsocket > 0) | 542 | if (x->x_htmsocket > 0) |
543 | { | 543 | { |
544 | #ifdef DEBUG | 544 | #ifdef DEBUG |
545 | post ("sendOSC: type tags? %d", useTypeTags); | 545 | post ("sendOSC: type tags? %d", useTypeTags); |
546 | #endif | 546 | #endif |
547 | 547 | ||
548 | messageName = strtok(targv[0], ","); | 548 | messageName = strtok(targv[0], ","); |
549 | j = 1; | 549 | j = 1; |
550 | for (i = j; i < argc; i++) { | 550 | for (i = j; i < argc; i++) { |
551 | token = strtok(targv[i],","); | 551 | token = strtok(targv[i],","); |
552 | args[i-j] = ParseToken(token); | 552 | args[i-j] = ParseToken(token); |
553 | #ifdef DEBUG | 553 | #ifdef DEBUG |
554 | printf("cell-cont: %s\n", targv[i]); | 554 | printf("cell-cont: %s\n", targv[i]); |
555 | printf(" type-id: %d\n", args[i-j]); | 555 | printf(" type-id: %d\n", args[i-j]); |
556 | #endif | 556 | #endif |
557 | numArgs = i; | 557 | numArgs = i; |
558 | } | 558 | } |
559 | 559 | ||
560 | 560 | ||
561 | if(WriteMessage(x->x_oscbuf, messageName, numArgs, args)) { | 561 | if(WriteMessage(x->x_oscbuf, messageName, numArgs, args)) { |
562 | post("sendOSC: usage error, write-msg failed: %s", OSC_errorMessage); | 562 | post("sendOSC: usage error, write-msg failed: %s", OSC_errorMessage); |
563 | return; | 563 | return; |
564 | } | 564 | } |
565 | 565 | ||
566 | if(!x->x_bundle) { | 566 | if(!x->x_bundle) { |
567 | SendBuffer(x->x_htmsocket, x->x_oscbuf); | 567 | SendBuffer(x->x_htmsocket, x->x_oscbuf); |
568 | OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf); | 568 | OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf); |
569 | } | 569 | } |
570 | 570 | ||
571 | //CommandLineMode(argc, targv, x->x_htmsocket); | 571 | //CommandLineMode(argc, targv, x->x_htmsocket); |
572 | //useTypeTags = 0; | 572 | //useTypeTags = 0; |
573 | } | 573 | } |
574 | else { | 574 | else { |
575 | post("sendOSC: not connected"); | 575 | post("sendOSC: not connected"); |
576 | } | 576 | } |
577 | } | 577 | } |
578 | 578 | ||
579 | void sendOSC_send(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) | 579 | void sendOSC_send(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) |
580 | { | 580 | { |
581 | if(!argc) { | 581 | if(!argc) { |
582 | post("not sending empty message."); | 582 | post("not sending empty message."); |
583 | return; | 583 | return; |
584 | } | 584 | } |
585 | if(x->x_typetags) { | 585 | if(x->x_typetags) { |
586 | useTypeTags = 1; | 586 | useTypeTags = 1; |
587 | sendOSC_sendtyped(x,s,argc,argv); | 587 | sendOSC_sendtyped(x,s,argc,argv); |
588 | useTypeTags = 0; | 588 | useTypeTags = 0; |
589 | } else { | 589 | } else { |
590 | sendOSC_sendtyped(x,s,argc,argv); | 590 | sendOSC_sendtyped(x,s,argc,argv); |
591 | } | 591 | } |
592 | } | 592 | } |
593 | 593 | ||
594 | static void sendOSC_free(t_sendOSC *x) | 594 | static void sendOSC_free(t_sendOSC *x) |
595 | { | 595 | { |
596 | sendOSC_disconnect(x); | 596 | sendOSC_disconnect(x); |
597 | } | 597 | } |
598 | 598 | ||
599 | #ifdef WIN32 | 599 | #ifdef WIN32 |
600 | OSC_API void sendOSC_setup(void) { | 600 | OSC_API void sendOSC_setup(void) { |
601 | #else | 601 | #else |
602 | void sendOSC_setup(void) { | 602 | void sendOSC_setup(void) { |
603 | #endif | 603 | #endif |
604 | sendOSC_class = class_new(gensym("sendOSC"), (t_newmethod)sendOSC_new, | 604 | sendOSC_class = class_new(gensym("sendOSC"), (t_newmethod)sendOSC_new, |
605 | (t_method)sendOSC_free, | 605 | (t_method)sendOSC_free, |
606 | sizeof(t_sendOSC), 0, A_DEFFLOAT, 0); | 606 | sizeof(t_sendOSC), 0, A_DEFFLOAT, 0); |
607 | class_addmethod(sendOSC_class, (t_method)sendOSC_connect, | 607 | class_addmethod(sendOSC_class, (t_method)sendOSC_connect, |
608 | gensym("connect"), A_SYMBOL, A_FLOAT, 0); | 608 | gensym("connect"), A_SYMBOL, A_FLOAT, 0); |
609 | class_addmethod(sendOSC_class, (t_method)sendOSC_disconnect, | 609 | class_addmethod(sendOSC_class, (t_method)sendOSC_disconnect, |
610 | gensym("disconnect"), 0); | 610 | gensym("disconnect"), 0); |
611 | class_addmethod(sendOSC_class, (t_method)sendOSC_settypetags, | 611 | class_addmethod(sendOSC_class, (t_method)sendOSC_settypetags, |
612 | gensym("typetags"), | 612 | gensym("typetags"), |
613 | A_FLOAT, 0); | 613 | A_FLOAT, 0); |
614 | class_addmethod(sendOSC_class, (t_method)sendOSC_send, | 614 | class_addmethod(sendOSC_class, (t_method)sendOSC_send, |
615 | gensym("send"), | 615 | gensym("send"), |
616 | A_GIMME, 0); | 616 | A_GIMME, 0); |
617 | class_addmethod(sendOSC_class, (t_method)sendOSC_send, | 617 | class_addmethod(sendOSC_class, (t_method)sendOSC_send, |
618 | gensym("senduntyped"), | 618 | gensym("senduntyped"), |
619 | A_GIMME, 0); | 619 | A_GIMME, 0); |
620 | class_addmethod(sendOSC_class, (t_method)sendOSC_send, | 620 | class_addmethod(sendOSC_class, (t_method)sendOSC_send, |
621 | gensym("sendtyped"), | 621 | gensym("sendtyped"), |
622 | A_GIMME, 0); | 622 | A_GIMME, 0); |
623 | class_addmethod(sendOSC_class, (t_method)sendOSC_openbundle, | 623 | class_addmethod(sendOSC_class, (t_method)sendOSC_openbundle, |
624 | gensym("["), | 624 | gensym("["), |
625 | 0, 0); | 625 | 0, 0); |
626 | class_addmethod(sendOSC_class, (t_method)sendOSC_closebundle, | 626 | class_addmethod(sendOSC_class, (t_method)sendOSC_closebundle, |
627 | gensym("]"), | 627 | gensym("]"), |
628 | 0, 0); | 628 | 0, 0); |
629 | class_sethelpsymbol(sendOSC_class, gensym("sendOSC-help.pd")); | 629 | class_sethelpsymbol(sendOSC_class, gensym("sendOSC-help.pd")); |
630 | } | 630 | } |
631 | 631 | ||
632 | 632 | ||
633 | 633 | ||
634 | 634 | ||
635 | 635 | ||
636 | /* Exit status codes: | 636 | /* Exit status codes: |
637 | 0: successful | 637 | 0: successful |
638 | 2: Message(s) dropped because of buffer overflow | 638 | 2: Message(s) dropped because of buffer overflow |
639 | 3: Socket error | 639 | 3: Socket error |
640 | 4: Usage error | 640 | 4: Usage error |
641 | 5: Internal error | 641 | 5: Internal error |
642 | */ | 642 | */ |
643 | 643 | ||
644 | void CommandLineMode(int argc, char *argv[], void *htmsocket) { | 644 | void CommandLineMode(int argc, char *argv[], void *htmsocket) { |
645 | char *messageName; | 645 | char *messageName; |
646 | char *token; | 646 | char *token; |
647 | typedArg args[MAX_ARGS]; | 647 | typedArg args[MAX_ARGS]; |
648 | int i,j, numArgs; | 648 | int i,j, numArgs; |
649 | OSCbuf buf[1]; | 649 | OSCbuf buf[1]; |
650 | 650 | ||
651 | OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf); | 651 | OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf); |
652 | 652 | ||
653 | if (argc > 1) { | 653 | if (argc > 1) { |
654 | post("argc (%d) > 1", argc); | 654 | post("argc (%d) > 1", argc); |
655 | } | 655 | } |
656 | 656 | ||
657 | // ParseInteractiveLine(buf, argv); | 657 | // ParseInteractiveLine(buf, argv); |
658 | messageName = strtok(argv[0], ","); | 658 | messageName = strtok(argv[0], ","); |
659 | 659 | ||
660 | j = 1; | 660 | j = 1; |
661 | for (i = j; i < argc; i++) { | 661 | for (i = j; i < argc; i++) { |
662 | token = strtok(argv[i],","); | 662 | token = strtok(argv[i],","); |
663 | args[i-j] = ParseToken(token); | 663 | args[i-j] = ParseToken(token); |
664 | #ifdef DEBUG | 664 | #ifdef DEBUG |
665 | printf("cell-cont: %s\n", argv[i]); | 665 | printf("cell-cont: %s\n", argv[i]); |
666 | printf(" type-id: %d\n", args[i-j]); | 666 | printf(" type-id: %d\n", args[i-j]); |
667 | #endif | 667 | #endif |
668 | numArgs = i; | 668 | numArgs = i; |
669 | } | 669 | } |
670 | 670 | ||
671 | if(WriteMessage(buf, messageName, numArgs, args)) { | 671 | if(WriteMessage(buf, messageName, numArgs, args)) { |
672 | post("sendOSC: usage error. write-msg failed: %s", OSC_errorMessage); | 672 | post("sendOSC: usage error. write-msg failed: %s", OSC_errorMessage); |
673 | return; | 673 | return; |
674 | } | 674 | } |
675 | 675 | ||
676 | SendBuffer(htmsocket, buf); | 676 | SendBuffer(htmsocket, buf); |
677 | } | 677 | } |
678 | 678 | ||
679 | #define MAXMESG 2048 | 679 | #define MAXMESG 2048 |
680 | 680 | ||
681 | void InteractiveMode(void *htmsocket) { | 681 | void InteractiveMode(void *htmsocket) { |
682 | char mesg[MAXMESG]; | 682 | char mesg[MAXMESG]; |
683 | OSCbuf buf[1]; | 683 | OSCbuf buf[1]; |
684 | int bundleDepth = 0; /* At first, we haven't seen "[". */ | 684 | int bundleDepth = 0; /* At first, we haven't seen "[". */ |
685 | 685 | ||
686 | OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf); | 686 | OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf); |
687 | 687 | ||
688 | while (fgets(mesg, MAXMESG, stdin) != NULL) { | 688 | while (fgets(mesg, MAXMESG, stdin) != NULL) { |
689 | if (mesg[0] == '\n') { | 689 | if (mesg[0] == '\n') { |
690 | if (bundleDepth > 0) { | 690 | if (bundleDepth > 0) { |
691 | /* Ignore blank lines inside a group. */ | 691 | /* Ignore blank lines inside a group. */ |
692 | } else { | 692 | } else { |
693 | /* blank line => repeat previous send */ | 693 | /* blank line => repeat previous send */ |
694 | SendBuffer(htmsocket, buf); | 694 | SendBuffer(htmsocket, buf); |
695 | } | 695 | } |
696 | continue; | 696 | continue; |
697 | } | 697 | } |
698 | 698 | ||
699 | if (bundleDepth == 0) { | 699 | if (bundleDepth == 0) { |
700 | OSC_resetBuffer(buf); | 700 | OSC_resetBuffer(buf); |
701 | } | 701 | } |
702 | 702 | ||
703 | if (mesg[0] == '[') { | 703 | if (mesg[0] == '[') { |
704 | OSCTimeTag tt = ParseTimeTag(mesg+1); | 704 | OSCTimeTag tt = ParseTimeTag(mesg+1); |
705 | if (OSC_openBundle(buf, tt)) { | 705 | if (OSC_openBundle(buf, tt)) { |
706 | post("Problem opening bundle: %s\n", OSC_errorMessage); | 706 | post("Problem opening bundle: %s\n", OSC_errorMessage); |
707 | OSC_resetBuffer(buf); | 707 | OSC_resetBuffer(buf); |
708 | bundleDepth = 0; | 708 | bundleDepth = 0; |
709 | continue; | 709 | continue; |
710 | } | 710 | } |
711 | bundleDepth++; | 711 | bundleDepth++; |
712 | } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') { | 712 | } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') { |
713 | if (bundleDepth == 0) { | 713 | if (bundleDepth == 0) { |
714 | post("Unexpected ']': not currently in a bundle.\n"); | 714 | post("Unexpected ']': not currently in a bundle.\n"); |
715 | } else { | 715 | } else { |
716 | if (OSC_closeBundle(buf)) { | 716 | if (OSC_closeBundle(buf)) { |
717 | post("Problem closing bundle: %s\n", OSC_errorMessage); | 717 | post("Problem closing bundle: %s\n", OSC_errorMessage); |
718 | OSC_resetBuffer(buf); | 718 | OSC_resetBuffer(buf); |
719 | bundleDepth = 0; | 719 | bundleDepth = 0; |
720 | continue; | 720 | continue; |
721 | } | 721 | } |
722 | 722 | ||
723 | bundleDepth--; | 723 | bundleDepth--; |
724 | if (bundleDepth == 0) { | 724 | if (bundleDepth == 0) { |
725 | SendBuffer(htmsocket, buf); | 725 | SendBuffer(htmsocket, buf); |
726 | } | 726 | } |
727 | } | 727 | } |
728 | } else { | 728 | } else { |
729 | ParseInteractiveLine(buf, mesg); | 729 | ParseInteractiveLine(buf, mesg); |
730 | if (bundleDepth != 0) { | 730 | if (bundleDepth != 0) { |
731 | /* Don't send anything until we close all bundles */ | 731 | /* Don't send anything until we close all bundles */ |
732 | } else { | 732 | } else { |
733 | SendBuffer(htmsocket, buf); | 733 | SendBuffer(htmsocket, buf); |
734 | } | 734 | } |
735 | } | 735 | } |
736 | } | 736 | } |
737 | } | 737 | } |
738 | 738 | ||
739 | OSCTimeTag ParseTimeTag(char *s) { | 739 | OSCTimeTag ParseTimeTag(char *s) { |
740 | char *p, *newline; | 740 | char *p, *newline; |
741 | typedArg arg; | 741 | typedArg arg; |
742 | 742 | ||
743 | p = s; | 743 | p = s; |
744 | while (isspace(*p)) p++; | 744 | while (isspace(*p)) p++; |
745 | if (*p == '\0') return OSCTT_Immediately(); | 745 | if (*p == '\0') return OSCTT_Immediately(); |
746 | 746 | ||
747 | if (*p == '+') { | 747 | if (*p == '+') { |
748 | /* Time tag is for some time in the future. It should be a | 748 | /* Time tag is for some time in the future. It should be a |
749 | number of seconds as an int or float */ | 749 | number of seconds as an int or float */ |
750 | 750 | ||
751 | newline = strchr(s, '\n'); | 751 | newline = strchr(s, '\n'); |
752 | if (newline != NULL) *newline = '\0'; | 752 | if (newline != NULL) *newline = '\0'; |
753 | 753 | ||
754 | p++; /* Skip '+' */ | 754 | p++; /* Skip '+' */ |
755 | while (isspace(*p)) p++; | 755 | while (isspace(*p)) p++; |
756 | 756 | ||
757 | arg = ParseToken(p); | 757 | arg = ParseToken(p); |
758 | if (arg.type == STRING_osc) { | 758 | if (arg.type == STRING_osc) { |
759 | post("warning: inscrutable time tag request: %s\n", s); | 759 | post("warning: inscrutable time tag request: %s\n", s); |
760 | return OSCTT_Immediately(); | 760 | return OSCTT_Immediately(); |
761 | } else if (arg.type == INT_osc) { | 761 | } else if (arg.type == INT_osc) { |
762 | return OSCTT_PlusSeconds(OSCTT_CurrentTime(), | 762 | return OSCTT_PlusSeconds(OSCTT_CurrentTime(), |
763 | (float) arg.datum.i); | 763 | (float) arg.datum.i); |
764 | } else if (arg.type == FLOAT_osc) { | 764 | } else if (arg.type == FLOAT_osc) { |
765 | return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f); | 765 | return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f); |
766 | } else { | 766 | } else { |
767 | error("This can't happen!"); | 767 | error("This can't happen!"); |
768 | } | 768 | } |
769 | } | 769 | } |
770 | 770 | ||
771 | if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) { | 771 | if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) { |
772 | /* They specified the 8-byte tag in hex */ | 772 | /* They specified the 8-byte tag in hex */ |
773 | OSCTimeTag tt; | 773 | OSCTimeTag tt; |
774 | if (sscanf(p, "%llx", &tt) != 1) { | 774 | if (sscanf(p, "%llx", &tt) != 1) { |
775 | post("warning: couldn't parse time tag %s\n", s); | 775 | post("warning: couldn't parse time tag %s\n", s); |
776 | return OSCTT_Immediately(); | 776 | return OSCTT_Immediately(); |
777 | } | 777 | } |
778 | #ifndef HAS8BYTEINT | 778 | #ifndef HAS8BYTEINT |
779 | if (ntohl(1) != 1) { | 779 | if (ntohl(1) != 1) { |
780 | /* tt is a struct of seconds and fractional part, | 780 | /* tt is a struct of seconds and fractional part, |
781 | and this machine is little-endian, so sscanf | 781 | and this machine is little-endian, so sscanf |
782 | wrote each half of the time tag in the wrong half | 782 | wrote each half of the time tag in the wrong half |
783 | of the struct. */ | 783 | of the struct. */ |
784 | int temp; | 784 | int temp; |
785 | temp = tt.seconds; | 785 | temp = tt.seconds; |
786 | tt.seconds = tt.fraction ; | 786 | tt.seconds = tt.fraction ; |
787 | tt.fraction = temp; | 787 | tt.fraction = temp; |
788 | } | 788 | } |
789 | #endif | 789 | #endif |
790 | return tt; | 790 | return tt; |
791 | } | 791 | } |
792 | 792 | ||
793 | post("warning: invalid time tag: %s\n", s); | 793 | post("warning: invalid time tag: %s\n", s); |
794 | return OSCTT_Immediately(); | 794 | return OSCTT_Immediately(); |
795 | } | 795 | } |
796 | 796 | ||
797 | 797 | ||
798 | void ParseInteractiveLine(OSCbuf *buf, char *mesg) { | 798 | void ParseInteractiveLine(OSCbuf *buf, char *mesg) { |
799 | char *messageName, *token, *p; | 799 | char *messageName, *token, *p; |
800 | typedArg args[MAX_ARGS]; | 800 | typedArg args[MAX_ARGS]; |
801 | int thisArg; | 801 | int thisArg; |
802 | 802 | ||
803 | p = mesg; | 803 | p = mesg; |
804 | while (isspace(*p)) p++; | 804 | while (isspace(*p)) p++; |
805 | if (*p == '\0') return; | 805 | if (*p == '\0') return; |
806 | 806 | ||
807 | messageName = p; | 807 | messageName = p; |
808 | 808 | ||
809 | if (strcmp(messageName, "play\n") == 0) { | 809 | if (strcmp(messageName, "play\n") == 0) { |
810 | /* Special kludge feature to save typing */ | 810 | /* Special kludge feature to save typing */ |
811 | typedArg arg; | 811 | typedArg arg; |
812 | 812 | ||
813 | if (OSC_openBundle(buf, OSCTT_Immediately())) { | 813 | if (OSC_openBundle(buf, OSCTT_Immediately())) { |
814 | post("Problem opening bundle: %s\n", OSC_errorMessage); | 814 | post("Problem opening bundle: %s\n", OSC_errorMessage); |
815 | return; | 815 | return; |
816 | } | 816 | } |
817 | 817 | ||
818 | arg.type = INT_osc; | 818 | arg.type = INT_osc; |
819 | arg.datum.i = 0; | 819 | arg.datum.i = 0; |
820 | WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg); | 820 | WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg); |
821 | 821 | ||
822 | arg.type = FLOAT_osc; | 822 | arg.type = FLOAT_osc; |
823 | arg.datum.i = 0.0f; | 823 | arg.datum.i = 0.0f; |
824 | WriteMessage(buf, "/voices/0/tm/goto", 1, &arg); | 824 | WriteMessage(buf, "/voices/0/tm/goto", 1, &arg); |
825 | 825 | ||
826 | if (OSC_closeBundle(buf)) { | 826 | if (OSC_closeBundle(buf)) { |
827 | post("Problem closing bundle: %s\n", OSC_errorMessage); | 827 | post("Problem closing bundle: %s\n", OSC_errorMessage); |
828 | } | 828 | } |
829 | 829 | ||
830 | return; | 830 | return; |
831 | } | 831 | } |
832 | 832 | ||
833 | while (!isspace(*p) && *p != '\0') p++; | 833 | while (!isspace(*p) && *p != '\0') p++; |
834 | if (isspace(*p)) { | 834 | if (isspace(*p)) { |
835 | *p = '\0'; | 835 | *p = '\0'; |
836 | p++; | 836 | p++; |
837 | } | 837 | } |
838 | 838 | ||
839 | thisArg = 0; | 839 | thisArg = 0; |
840 | while (*p != '\0') { | 840 | while (*p != '\0') { |
841 | /* flush leading whitespace */ | 841 | /* flush leading whitespace */ |
842 | while (isspace(*p)) p++; | 842 | while (isspace(*p)) p++; |
843 | if (*p == '\0') break; | 843 | if (*p == '\0') break; |
844 | 844 | ||
845 | if (*p == '"') { | 845 | if (*p == '"') { |
846 | /* A string argument: scan for close quotes */ | 846 | /* A string argument: scan for close quotes */ |
847 | p++; | 847 | p++; |
848 | args[thisArg].type = STRING_osc; | 848 | args[thisArg].type = STRING_osc; |
849 | args[thisArg].datum.s = p; | 849 | args[thisArg].datum.s = p; |
850 | 850 | ||
851 | while (*p != '"') { | 851 | while (*p != '"') { |
852 | if (*p == '\0') { | 852 | if (*p == '\0') { |
853 | post("Unterminated quote mark: ignoring line\n"); | 853 | post("Unterminated quote mark: ignoring line\n"); |
854 | return; | 854 | return; |
855 | } | 855 | } |
856 | p++; | 856 | p++; |
857 | } | 857 | } |
858 | *p = '\0'; | 858 | *p = '\0'; |
859 | p++; | 859 | p++; |
860 | } else { | 860 | } else { |
861 | token = p; | 861 | token = p; |
862 | while (!isspace(*p) && (*p != '\0')) p++; | 862 | while (!isspace(*p) && (*p != '\0')) p++; |
863 | if (isspace(*p)) { | 863 | if (isspace(*p)) { |
864 | *p = '\0'; | 864 | *p = '\0'; |
865 | p++; | 865 | p++; |
866 | } | 866 | } |
867 | args[thisArg] = ParseToken(token); | 867 | args[thisArg] = ParseToken(token); |
868 | } | 868 | } |
869 | thisArg++; | 869 | thisArg++; |
870 | if (thisArg >= MAX_ARGS) { | 870 | if (thisArg >= MAX_ARGS) { |
871 | post("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n", | 871 | post("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n", |
872 | MAX_ARGS); | 872 | MAX_ARGS); |
873 | break; | 873 | break; |
874 | } | 874 | } |
875 | } | 875 | } |
876 | 876 | ||
877 | if (WriteMessage(buf, messageName, thisArg, args) != 0) { | 877 | if (WriteMessage(buf, messageName, thisArg, args) != 0) { |
878 | post("Problem sending message: %s\n", OSC_errorMessage); | 878 | post("Problem sending message: %s\n", OSC_errorMessage); |
879 | } | 879 | } |
880 | } | 880 | } |
881 | 881 | ||
882 | typedArg ParseToken(char *token) { | 882 | typedArg ParseToken(char *token) { |
883 | char *p = token; | 883 | char *p = token; |
884 | typedArg returnVal; | 884 | typedArg returnVal; |
885 | 885 | ||
886 | /* It might be an int, a float, or a string */ | 886 | /* It might be an int, a float, or a string */ |
887 | 887 | ||
888 | if (*p == '-') p++; | 888 | if (*p == '-') p++; |
889 | 889 | ||
890 | if (isdigit(*p) || *p == '.') { | 890 | if (isdigit(*p) || *p == '.') { |
891 | while (isdigit(*p)) p++; | 891 | while (isdigit(*p)) p++; |
892 | if (*p == '\0') { | 892 | if (*p == '\0') { |
893 | returnVal.type = INT_osc; | 893 | returnVal.type = INT_osc; |
894 | returnVal.datum.i = atoi(token); | 894 | returnVal.datum.i = atoi(token); |
895 | return returnVal; | 895 | return returnVal; |
896 | } | 896 | } |
897 | if (*p == '.') { | 897 | if (*p == '.') { |
898 | p++; | 898 | p++; |
899 | while (isdigit(*p)) p++; | 899 | while (isdigit(*p)) p++; |
900 | if (*p == '\0') { | 900 | if (*p == '\0') { |
901 | returnVal.type = FLOAT_osc; | 901 | returnVal.type = FLOAT_osc; |
902 | returnVal.datum.f = atof(token); | 902 | returnVal.datum.f = atof(token); |
903 | return returnVal; | 903 | return returnVal; |
904 | } | 904 | } |
905 | } | 905 | } |
906 | } | 906 | } |
907 | 907 | ||
908 | returnVal.type = STRING_osc; | 908 | returnVal.type = STRING_osc; |
909 | returnVal.datum.s = token; | 909 | returnVal.datum.s = token; |
910 | return returnVal; | 910 | return returnVal; |
911 | } | 911 | } |
912 | 912 | ||
913 | int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) { | 913 | int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) { |
914 | int j, returnVal; | 914 | int j, returnVal; |
915 | const int wmERROR = -1; | 915 | const int wmERROR = -1; |
916 | 916 | ||
917 | returnVal = 0; | 917 | returnVal = 0; |
918 | 918 | ||
919 | #ifdef DEBUG | 919 | #ifdef DEBUG |
920 | printf("WriteMessage: %s ", messageName); | 920 | printf("WriteMessage: %s ", messageName); |
921 | 921 | ||
922 | for (j = 0; j < numArgs; j++) { | 922 | for (j = 0; j < numArgs; j++) { |
923 | switch (args[j].type) { | 923 | switch (args[j].type) { |
924 | case INT_osc: | 924 | case INT_osc: |
925 | printf("%d ", args[j].datum.i); | 925 | printf("%d ", args[j].datum.i); |
926 | break; | 926 | break; |
927 | 927 | ||
928 | case FLOAT_osc: | 928 | case FLOAT_osc: |
929 | printf("%f ", args[j].datum.f); | 929 | printf("%f ", args[j].datum.f); |
930 | break; | 930 | break; |
931 | 931 | ||
932 | case STRING_osc: | 932 | case STRING_osc: |
933 | printf("%s ", args[j].datum.s); | 933 | printf("%s ", args[j].datum.s); |
934 | break; | 934 | break; |
935 | 935 | ||
936 | default: | 936 | default: |
937 | error("Unrecognized arg type, (not exiting)"); | 937 | error("Unrecognized arg type, (not exiting)"); |
938 | return(wmERROR); | 938 | return(wmERROR); |
939 | } | 939 | } |
940 | } | 940 | } |
941 | printf("\n"); | 941 | printf("\n"); |
942 | #endif | 942 | #endif |
943 | 943 | ||
944 | if (!useTypeTags) { | 944 | if (!useTypeTags) { |
945 | returnVal = OSC_writeAddress(buf, messageName); | 945 | returnVal = OSC_writeAddress(buf, messageName); |
946 | if (returnVal) { | 946 | if (returnVal) { |
947 | post("Problem writing address: %s\n", OSC_errorMessage); | 947 | post("Problem writing address: %s\n", OSC_errorMessage); |
948 | } | 948 | } |
949 | } else { | 949 | } else { |
950 | /* First figure out the type tags */ | 950 | /* First figure out the type tags */ |
951 | char typeTags[MAX_ARGS+2]; | 951 | char typeTags[MAX_ARGS+2]; |
952 | int i; | 952 | int i; |
953 | 953 | ||
954 | typeTags[0] = ','; | 954 | typeTags[0] = ','; |
955 | 955 | ||
956 | for (i = 0; i < numArgs; ++i) { | 956 | for (i = 0; i < numArgs; ++i) { |
957 | switch (args[i].type) { | 957 | switch (args[i].type) { |
958 | case INT_osc: | 958 | case INT_osc: |
959 | typeTags[i+1] = 'i'; | 959 | typeTags[i+1] = 'i'; |
960 | break; | 960 | break; |
961 | 961 | ||
962 | case FLOAT_osc: | 962 | case FLOAT_osc: |
963 | typeTags[i+1] = 'f'; | 963 | typeTags[i+1] = 'f'; |
964 | break; | 964 | break; |
965 | 965 | ||
966 | case STRING_osc: | 966 | case STRING_osc: |
967 | typeTags[i+1] = 's'; | 967 | typeTags[i+1] = 's'; |
968 | break; | 968 | break; |
969 | 969 | ||
970 | default: | 970 | default: |
971 | error("Unrecognized arg type (not exiting)"); | 971 | error("Unrecognized arg type (not exiting)"); |
972 | return(wmERROR); | 972 | return(wmERROR); |
973 | } | 973 | } |
974 | } | 974 | } |
975 | typeTags[i+1] = '\0'; | 975 | typeTags[i+1] = '\0'; |
976 | 976 | ||
977 | returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags); | 977 | returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags); |
978 | if (returnVal) { | 978 | if (returnVal) { |
979 | post("Problem writing address: %s\n", OSC_errorMessage); | 979 | post("Problem writing address: %s\n", OSC_errorMessage); |
980 | } | 980 | } |
981 | } | 981 | } |
982 | 982 | ||
983 | for (j = 0; j < numArgs; j++) { | 983 | for (j = 0; j < numArgs; j++) { |
984 | switch (args[j].type) { | 984 | switch (args[j].type) { |
985 | case INT_osc: | 985 | case INT_osc: |
986 | if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) { | 986 | if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) { |
987 | return returnVal; | 987 | return returnVal; |
988 | } | 988 | } |
989 | break; | 989 | break; |
990 | 990 | ||
991 | case FLOAT_osc: | 991 | case FLOAT_osc: |
992 | if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) { | 992 | if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) { |
993 | return returnVal; | 993 | return returnVal; |
994 | } | 994 | } |
995 | break; | 995 | break; |
996 | 996 | ||
997 | case STRING_osc: | 997 | case STRING_osc: |
998 | if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) { | 998 | if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) { |
999 | return returnVal; | 999 | return returnVal; |
1000 | } | 1000 | } |
1001 | break; | 1001 | break; |
1002 | 1002 | ||
1003 | default: | 1003 | default: |
1004 | error("Unrecognized arg type (not exiting)"); | 1004 | error("Unrecognized arg type (not exiting)"); |
1005 | returnVal = wmERROR; | 1005 | returnVal = wmERROR; |
1006 | } | 1006 | } |
1007 | } | 1007 | } |
1008 | return returnVal; | 1008 | return returnVal; |
1009 | } | 1009 | } |
1010 | 1010 | ||
1011 | void SendBuffer(void *htmsocket, OSCbuf *buf) { | 1011 | void SendBuffer(void *htmsocket, OSCbuf *buf) { |
1012 | #ifdef DEBUG | 1012 | #ifdef DEBUG |
1013 | printf("Sending buffer...\n"); | 1013 | printf("Sending buffer...\n"); |
1014 | #endif | 1014 | #endif |
1015 | if (OSC_isBufferEmpty(buf)) { | 1015 | if (OSC_isBufferEmpty(buf)) { |
1016 | post("SendBuffer() called but buffer empty"); | 1016 | post("SendBuffer() called but buffer empty"); |
1017 | return; | 1017 | return; |
1018 | } | 1018 | } |
1019 | if (!OSC_isBufferDone(buf)) { | 1019 | if (!OSC_isBufferDone(buf)) { |
1020 | error("SendBuffer() called but buffer not ready!, not exiting"); | 1020 | error("SendBuffer() called but buffer not ready!, not exiting"); |
1021 | return; //{{raf}} | 1021 | return; //{{raf}} |
1022 | } | 1022 | } |
1023 | SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf)); | 1023 | SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf)); |
1024 | } | 1024 | } |
1025 | 1025 | ||
1026 | void SendData(void *htmsocket, int size, char *data) { | 1026 | void SendData(void *htmsocket, int size, char *data) { |
1027 | if (!SendHTMSocket(htmsocket, size, data)) { | 1027 | if (!SendHTMSocket(htmsocket, size, data)) { |
1028 | post("SendData::SendHTMSocket()failure -- not connected"); | 1028 | post("SendData::SendHTMSocket()failure -- not connected"); |
1029 | CloseHTMSocket(htmsocket); | 1029 | CloseHTMSocket(htmsocket); |
1030 | } | 1030 | } |
1031 | } | 1031 | } |
1032 | 1032 | ||
1033 | 1033 | ||
1034 | 1034 | ||
1035 | /* ---------------------- | 1035 | /* ---------------------- |
1036 | OSC-client code | 1036 | OSC-client code |
1037 | 1037 | ||
1038 | */ | 1038 | */ |
1039 | 1039 | ||
1040 | /* Here are the possible values of the state field: */ | 1040 | /* Here are the possible values of the state field: */ |
1041 | 1041 | ||
1042 | #define EMPTY 0 /* Nothing written to packet yet */ | 1042 | #define EMPTY 0 /* Nothing written to packet yet */ |
1043 | #define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */ | 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 | 1044 | #define NEED_COUNT 2 /* Just opened a bundle; must write message name or |
1045 | open another bundle */ | 1045 | open another bundle */ |
1046 | #define GET_ARGS 3 /* Getting arguments to a message. If we see a message | 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 | 1047 | name or a bundle open/close then the current message |
1048 | will end. */ | 1048 | will end. */ |
1049 | #define DONE 4 /* All open bundles have been closed, so can't write | 1049 | #define DONE 4 /* All open bundles have been closed, so can't write |
1050 | anything else */ | 1050 | anything else */ |
1051 | 1051 | ||
1052 | #ifdef WIN32 | 1052 | #ifdef WIN32 |
1053 | #include <winsock2.h> | 1053 | #include <winsock2.h> |
1054 | #include <io.h> | 1054 | #include <io.h> |
1055 | #include <stdio.h> | 1055 | #include <stdio.h> |
1056 | #include <errno.h> | 1056 | #include <errno.h> |
1057 | #include <fcntl.h> | 1057 | #include <fcntl.h> |
1058 | #include <sys/types.h> | 1058 | #include <sys/types.h> |
1059 | #include <sys/stat.h> | 1059 | #include <sys/stat.h> |
1060 | #endif | 1060 | #endif |
1061 | 1061 | ||
1062 | #ifdef __APPLE__ | 1062 | #ifdef __APPLE__ |
1063 | #include <sys/types.h> | 1063 | #include <sys/types.h> |
1064 | #endif | 1064 | #endif |
1065 | 1065 | ||
1066 | #ifdef unix | 1066 | #ifdef unix |
1067 | #include <netinet/in.h> | 1067 | #include <netinet/in.h> |
1068 | #include <stdio.h> | 1068 | #include <stdio.h> |
1069 | #endif | 1069 | #endif |
1070 | 1070 | ||
1071 | 1071 | ||
1072 | char *OSC_errorMessage; | 1072 | char *OSC_errorMessage; |
1073 | 1073 | ||
1074 | static int OSC_padString(char *dest, char *str); | 1074 | static int OSC_padString(char *dest, char *str); |
1075 | static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str); | 1075 | static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str); |
1076 | static int OSC_WritePadding(char *dest, int i); | 1076 | static int OSC_WritePadding(char *dest, int i); |
1077 | static int CheckTypeTag(OSCbuf *buf, char expectedType); | 1077 | static int CheckTypeTag(OSCbuf *buf, char expectedType); |
1078 | 1078 | ||
1079 | void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray) { | 1079 | void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray) { |
1080 | buf->buffer = byteArray; | 1080 | buf->buffer = byteArray; |
1081 | buf->size = size; | 1081 | buf->size = size; |
1082 | OSC_resetBuffer(buf); | 1082 | OSC_resetBuffer(buf); |
1083 | } | 1083 | } |
1084 | 1084 | ||
1085 | void OSC_resetBuffer(OSCbuf *buf) { | 1085 | void OSC_resetBuffer(OSCbuf *buf) { |
1086 | buf->bufptr = buf->buffer; | 1086 | buf->bufptr = buf->buffer; |
1087 | buf->state = EMPTY; | 1087 | buf->state = EMPTY; |
1088 | buf->bundleDepth = 0; | 1088 | buf->bundleDepth = 0; |
1089 | buf->prevCounts[0] = 0; | 1089 | buf->prevCounts[0] = 0; |
1090 | buf->gettingFirstUntypedArg = 0; | 1090 | buf->gettingFirstUntypedArg = 0; |
1091 | buf->typeStringPtr = 0; | 1091 | buf->typeStringPtr = 0; |
1092 | } | 1092 | } |
1093 | 1093 | ||
1094 | int OSC_isBufferEmpty(OSCbuf *buf) { | 1094 | int OSC_isBufferEmpty(OSCbuf *buf) { |
1095 | return buf->bufptr == buf->buffer; | 1095 | return buf->bufptr == buf->buffer; |
1096 | } | 1096 | } |
1097 | 1097 | ||
1098 | int OSC_freeSpaceInBuffer(OSCbuf *buf) { | 1098 | int OSC_freeSpaceInBuffer(OSCbuf *buf) { |
1099 | return buf->size - (buf->bufptr - buf->buffer); | 1099 | return buf->size - (buf->bufptr - buf->buffer); |
1100 | } | 1100 | } |
1101 | 1101 | ||
1102 | int OSC_isBufferDone(OSCbuf *buf) { | 1102 | int OSC_isBufferDone(OSCbuf *buf) { |
1103 | return (buf->state == DONE || buf->state == ONE_MSG_ARGS); | 1103 | return (buf->state == DONE || buf->state == ONE_MSG_ARGS); |
1104 | } | 1104 | } |
1105 | 1105 | ||
1106 | char *OSC_getPacket(OSCbuf *buf) { | 1106 | char *OSC_getPacket(OSCbuf *buf) { |
1107 | #ifdef ERROR_CHECK_GETPACKET | 1107 | #ifdef ERROR_CHECK_GETPACKET |
1108 | if (buf->state == DONE || buf->state == ONE_MSG_ARGS) { | 1108 | if (buf->state == DONE || buf->state == ONE_MSG_ARGS) { |
1109 | return buf->buffer; | 1109 | return buf->buffer; |
1110 | } else { | 1110 | } else { |
1111 | OSC_errorMessage = "Packet has unterminated bundles"; | 1111 | OSC_errorMessage = "Packet has unterminated bundles"; |
1112 | return 0; | 1112 | return 0; |
1113 | } | 1113 | } |
1114 | #else | 1114 | #else |
1115 | return buf->buffer; | 1115 | return buf->buffer; |
1116 | #endif | 1116 | #endif |
1117 | } | 1117 | } |
1118 | 1118 | ||
1119 | int OSC_packetSize(OSCbuf *buf) { | 1119 | int OSC_packetSize(OSCbuf *buf) { |
1120 | #ifdef ERROR_CHECK_PACKETSIZE | 1120 | #ifdef ERROR_CHECK_PACKETSIZE |
1121 | if (buf->state == DONE || buf->state == ONE_MSG_ARGS) { | 1121 | if (buf->state == DONE || buf->state == ONE_MSG_ARGS) { |
1122 | return (buf->bufptr - buf->buffer); | 1122 | return (buf->bufptr - buf->buffer); |
1123 | } else { | 1123 | } else { |
1124 | OSC_errorMessage = "Packet has unterminated bundles"; | 1124 | OSC_errorMessage = "Packet has unterminated bundles"; |
1125 | return 0; | 1125 | return 0; |
1126 | } | 1126 | } |
1127 | #else | 1127 | #else |
1128 | return (buf->bufptr - buf->buffer); | 1128 | return (buf->bufptr - buf->buffer); |
1129 | #endif | 1129 | #endif |
1130 | } | 1130 | } |
1131 | 1131 | ||
1132 | #define CheckOverflow(buf, bytesNeeded) { if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) {OSC_errorMessage = "buffer overflow"; return 1;}} | 1132 | #define CheckOverflow(buf, bytesNeeded) { if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) {OSC_errorMessage = "buffer overflow"; return 1;}} |
1133 | 1133 | ||
1134 | static void PatchMessageSize(OSCbuf *buf) { | 1134 | static void PatchMessageSize(OSCbuf *buf) { |
1135 | int4byte size; | 1135 | int4byte size; |
1136 | size = buf->bufptr - ((char *) buf->thisMsgSize) - 4; | 1136 | size = buf->bufptr - ((char *) buf->thisMsgSize) - 4; |
1137 | *(buf->thisMsgSize) = htonl(size); | 1137 | *(buf->thisMsgSize) = htonl(size); |
1138 | } | 1138 | } |
1139 | 1139 | ||
1140 | int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) { | 1140 | int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) { |
1141 | if (buf->state == ONE_MSG_ARGS) { | 1141 | if (buf->state == ONE_MSG_ARGS) { |
1142 | OSC_errorMessage = "Can't open a bundle in a one-message packet"; | 1142 | OSC_errorMessage = "Can't open a bundle in a one-message packet"; |
1143 | return 3; | 1143 | return 3; |
1144 | } | 1144 | } |
1145 | 1145 | ||
1146 | if (buf->state == DONE) { | 1146 | if (buf->state == DONE) { |
1147 | OSC_errorMessage = "This packet is finished; can't open a new bundle"; | 1147 | OSC_errorMessage = "This packet is finished; can't open a new bundle"; |
1148 | return 4; | 1148 | return 4; |
1149 | } | 1149 | } |
1150 | 1150 | ||
1151 | if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) { | 1151 | if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) { |
1152 | OSC_errorMessage = "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h"; | 1152 | OSC_errorMessage = "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h"; |
1153 | return 2; | 1153 | return 2; |
1154 | } | 1154 | } |
1155 | 1155 | ||
1156 | if (CheckTypeTag(buf, '\0')) return 9; | 1156 | if (CheckTypeTag(buf, '\0')) return 9; |
1157 | 1157 | ||
1158 | if (buf->state == GET_ARGS) { | 1158 | if (buf->state == GET_ARGS) { |
1159 | PatchMessageSize(buf); | 1159 | PatchMessageSize(buf); |
1160 | } | 1160 | } |
1161 | 1161 | ||
1162 | if (buf->state == EMPTY) { | 1162 | if (buf->state == EMPTY) { |
1163 | /* Need 16 bytes for "#bundle" and time tag */ | 1163 | /* Need 16 bytes for "#bundle" and time tag */ |
1164 | CheckOverflow(buf, 16); | 1164 | CheckOverflow(buf, 16); |
1165 | } else { | 1165 | } else { |
1166 | /* This bundle is inside another bundle, so we need to leave | 1166 | /* This bundle is inside another bundle, so we need to leave |
1167 | a blank size count for the size of this current bundle. */ | 1167 | a blank size count for the size of this current bundle. */ |
1168 | CheckOverflow(buf, 20); | 1168 | CheckOverflow(buf, 20); |
1169 | *((int4byte *)buf->bufptr) = 0xaaaaaaaa; | 1169 | *((int4byte *)buf->bufptr) = 0xaaaaaaaa; |
1170 | buf->prevCounts[buf->bundleDepth] = (int4byte *)buf->bufptr; | 1170 | buf->prevCounts[buf->bundleDepth] = (int4byte *)buf->bufptr; |
1171 | 1171 | ||
1172 | buf->bufptr += 4; | 1172 | buf->bufptr += 4; |
1173 | } | 1173 | } |
1174 | 1174 | ||
1175 | buf->bufptr += OSC_padString(buf->bufptr, "#bundle"); | 1175 | buf->bufptr += OSC_padString(buf->bufptr, "#bundle"); |
1176 | 1176 | ||
1177 | 1177 | ||
1178 | *((OSCTimeTag *) buf->bufptr) = tt; | 1178 | *((OSCTimeTag *) buf->bufptr) = tt; |
1179 | 1179 | ||
1180 | if (htonl(1) != 1) { | 1180 | if (htonl(1) != 1) { |
1181 | /* Byte swap the 8-byte integer time tag */ | 1181 | /* Byte swap the 8-byte integer time tag */ |
1182 | int4byte *intp = (int4byte *)buf->bufptr; | 1182 | int4byte *intp = (int4byte *)buf->bufptr; |
1183 | intp[0] = htonl(intp[0]); | 1183 | intp[0] = htonl(intp[0]); |
1184 | intp[1] = htonl(intp[1]); | 1184 | intp[1] = htonl(intp[1]); |
1185 | 1185 | ||
1186 | #ifdef HAS8BYTEINT | 1186 | #ifdef HAS8BYTEINT |
1187 | { /* tt is a 64-bit int so we have to swap the two 32-bit words. | 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 | 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 | 1189 | each word was wrong-endian, they were in the right order |
1190 | in the struct.) */ | 1190 | in the struct.) */ |
1191 | int4byte temp = intp[0]; | 1191 | int4byte temp = intp[0]; |
1192 | intp[0] = intp[1]; | 1192 | intp[0] = intp[1]; |
1193 | intp[1] = temp; | 1193 | intp[1] = temp; |
1194 | } | 1194 | } |
1195 | #endif | 1195 | #endif |
1196 | } | 1196 | } |
1197 | 1197 | ||
1198 | buf->bufptr += sizeof(OSCTimeTag); | 1198 | buf->bufptr += sizeof(OSCTimeTag); |
1199 | 1199 | ||
1200 | buf->state = NEED_COUNT; | 1200 | buf->state = NEED_COUNT; |
1201 | 1201 | ||
1202 | buf->gettingFirstUntypedArg = 0; | 1202 | buf->gettingFirstUntypedArg = 0; |
1203 | buf->typeStringPtr = 0; | 1203 | buf->typeStringPtr = 0; |
1204 | return 0; | 1204 | return 0; |
1205 | } | 1205 | } |
1206 | 1206 | ||
1207 | 1207 | ||
1208 | int OSC_closeBundle(OSCbuf *buf) { | 1208 | int OSC_closeBundle(OSCbuf *buf) { |
1209 | if (buf->bundleDepth == 0) { | 1209 | if (buf->bundleDepth == 0) { |
1210 | /* This handles EMPTY, ONE_MSG, ARGS, and DONE */ | 1210 | /* This handles EMPTY, ONE_MSG, ARGS, and DONE */ |
1211 | OSC_errorMessage = "Can't close bundle; no bundle is open!"; | 1211 | OSC_errorMessage = "Can't close bundle; no bundle is open!"; |
1212 | return 5; | 1212 | return 5; |
1213 | } | 1213 | } |
1214 | 1214 | ||
1215 | if (CheckTypeTag(buf, '\0')) return 9; | 1215 | if (CheckTypeTag(buf, '\0')) return 9; |
1216 | 1216 | ||
1217 | if (buf->state == GET_ARGS) { | 1217 | if (buf->state == GET_ARGS) { |
1218 | PatchMessageSize(buf); | 1218 | PatchMessageSize(buf); |
1219 | } | 1219 | } |
1220 | 1220 | ||
1221 | if (buf->bundleDepth == 1) { | 1221 | if (buf->bundleDepth == 1) { |
1222 | /* Closing the last bundle: No bundle size to patch */ | 1222 | /* Closing the last bundle: No bundle size to patch */ |
1223 | buf->state = DONE; | 1223 | buf->state = DONE; |
1224 | } else { | 1224 | } else { |
1225 | /* Closing a sub-bundle: patch bundle size */ | 1225 | /* Closing a sub-bundle: patch bundle size */ |
1226 | int size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4; | 1226 | int size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4; |
1227 | *(buf->prevCounts[buf->bundleDepth]) = htonl(size); | 1227 | *(buf->prevCounts[buf->bundleDepth]) = htonl(size); |
1228 | buf->state = NEED_COUNT; | 1228 | buf->state = NEED_COUNT; |
1229 | } | 1229 | } |
1230 | 1230 | ||
1231 | --buf->bundleDepth; | 1231 | --buf->bundleDepth; |
1232 | buf->gettingFirstUntypedArg = 0; | 1232 | buf->gettingFirstUntypedArg = 0; |
1233 | buf->typeStringPtr = 0; | 1233 | buf->typeStringPtr = 0; |
1234 | return 0; | 1234 | return 0; |
1235 | } | 1235 | } |
1236 | 1236 | ||
1237 | 1237 | ||
1238 | int OSC_closeAllBundles(OSCbuf *buf) { | 1238 | int OSC_closeAllBundles(OSCbuf *buf) { |
1239 | if (buf->bundleDepth == 0) { | 1239 | if (buf->bundleDepth == 0) { |
1240 | /* This handles EMPTY, ONE_MSG, ARGS, and DONE */ | 1240 | /* This handles EMPTY, ONE_MSG, ARGS, and DONE */ |
1241 | OSC_errorMessage = "Can't close all bundles; no bundle is open!"; | 1241 | OSC_errorMessage = "Can't close all bundles; no bundle is open!"; |
1242 | return 6; | 1242 | return 6; |
1243 | } | 1243 | } |
1244 | 1244 | ||
1245 | if (CheckTypeTag(buf, '\0')) return 9; | 1245 | if (CheckTypeTag(buf, '\0')) return 9; |
1246 | 1246 | ||
1247 | while (buf->bundleDepth > 0) { | 1247 | while (buf->bundleDepth > 0) { |
1248 | OSC_closeBundle(buf); | 1248 | OSC_closeBundle(buf); |
1249 | } | 1249 | } |
1250 | buf->typeStringPtr = 0; | 1250 | buf->typeStringPtr = 0; |
1251 | return 0; | 1251 | return 0; |
1252 | } | 1252 | } |
1253 | 1253 | ||
1254 | int OSC_writeAddress(OSCbuf *buf, char *name) { | 1254 | int OSC_writeAddress(OSCbuf *buf, char *name) { |
1255 | int4byte paddedLength; | 1255 | int4byte paddedLength; |
1256 | 1256 | ||
1257 | if (buf->state == ONE_MSG_ARGS) { | 1257 | if (buf->state == ONE_MSG_ARGS) { |
1258 | OSC_errorMessage = "This packet is not a bundle, so you can't write another address"; | 1258 | OSC_errorMessage = "This packet is not a bundle, so you can't write another address"; |
1259 | return 7; | 1259 | return 7; |
1260 | } | 1260 | } |
1261 | 1261 | ||
1262 | if (buf->state == DONE) { | 1262 | if (buf->state == DONE) { |
1263 | OSC_errorMessage = "This packet is finished; can't write another address"; | 1263 | OSC_errorMessage = "This packet is finished; can't write another address"; |
1264 | return 8; | 1264 | return 8; |
1265 | } | 1265 | } |
1266 | 1266 | ||
1267 | if (CheckTypeTag(buf, '\0')) return 9; | 1267 | if (CheckTypeTag(buf, '\0')) return 9; |
1268 | 1268 | ||
1269 | paddedLength = OSC_effectiveStringLength(name); | 1269 | paddedLength = OSC_effectiveStringLength(name); |
1270 | 1270 | ||
1271 | if (buf->state == EMPTY) { | 1271 | if (buf->state == EMPTY) { |
1272 | /* This will be a one-message packet, so no sizes to worry about */ | 1272 | /* This will be a one-message packet, so no sizes to worry about */ |
1273 | CheckOverflow(buf, paddedLength); | 1273 | CheckOverflow(buf, paddedLength); |
1274 | buf->state = ONE_MSG_ARGS; | 1274 | buf->state = ONE_MSG_ARGS; |
1275 | } else { | 1275 | } else { |
1276 | /* GET_ARGS or NEED_COUNT */ | 1276 | /* GET_ARGS or NEED_COUNT */ |
1277 | CheckOverflow(buf, 4+paddedLength); | 1277 | CheckOverflow(buf, 4+paddedLength); |
1278 | if (buf->state == GET_ARGS) { | 1278 | if (buf->state == GET_ARGS) { |
1279 | /* Close the old message */ | 1279 | /* Close the old message */ |
1280 | PatchMessageSize(buf); | 1280 | PatchMessageSize(buf); |
1281 | } | 1281 | } |
1282 | buf->thisMsgSize = (int4byte *)buf->bufptr; | 1282 | buf->thisMsgSize = (int4byte *)buf->bufptr; |
1283 | *(buf->thisMsgSize) = 0xbbbbbbbb; | 1283 | *(buf->thisMsgSize) = 0xbbbbbbbb; |
1284 | buf->bufptr += 4; | 1284 | buf->bufptr += 4; |
1285 | buf->state = GET_ARGS; | 1285 | buf->state = GET_ARGS; |
1286 | } | 1286 | } |
1287 | 1287 | ||
1288 | /* Now write the name */ | 1288 | /* Now write the name */ |
1289 | buf->bufptr += OSC_padString(buf->bufptr, name); | 1289 | buf->bufptr += OSC_padString(buf->bufptr, name); |
1290 | buf->typeStringPtr = 0; | 1290 | buf->typeStringPtr = 0; |
1291 | buf->gettingFirstUntypedArg = 1; | 1291 | buf->gettingFirstUntypedArg = 1; |
1292 | 1292 | ||
1293 | return 0; | 1293 | return 0; |
1294 | } | 1294 | } |
1295 | 1295 | ||
1296 | int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types) { | 1296 | int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types) { |
1297 | int result; | 1297 | int result; |
1298 | int4byte paddedLength; | 1298 | int4byte paddedLength; |
1299 | 1299 | ||
1300 | if (CheckTypeTag(buf, '\0')) return 9; | 1300 | if (CheckTypeTag(buf, '\0')) return 9; |
1301 | 1301 | ||
1302 | result = OSC_writeAddress(buf, name); | 1302 | result = OSC_writeAddress(buf, name); |
1303 | 1303 | ||
1304 | if (result) return result; | 1304 | if (result) return result; |
1305 | 1305 | ||
1306 | paddedLength = OSC_effectiveStringLength(types); | 1306 | paddedLength = OSC_effectiveStringLength(types); |
1307 | 1307 | ||
1308 | CheckOverflow(buf, paddedLength); | 1308 | CheckOverflow(buf, paddedLength); |
1309 | 1309 | ||
1310 | buf->typeStringPtr = buf->bufptr + 1; /* skip comma */ | 1310 | buf->typeStringPtr = buf->bufptr + 1; /* skip comma */ |
1311 | buf->bufptr += OSC_padString(buf->bufptr, types); | 1311 | buf->bufptr += OSC_padString(buf->bufptr, types); |
1312 | 1312 | ||
1313 | buf->gettingFirstUntypedArg = 0; | 1313 | buf->gettingFirstUntypedArg = 0; |
1314 | return 0; | 1314 | return 0; |
1315 | } | 1315 | } |
1316 | 1316 | ||
1317 | static int CheckTypeTag(OSCbuf *buf, char expectedType) { | 1317 | static int CheckTypeTag(OSCbuf *buf, char expectedType) { |
1318 | if (buf->typeStringPtr) { | 1318 | if (buf->typeStringPtr) { |
1319 | if (*(buf->typeStringPtr) != expectedType) { | 1319 | if (*(buf->typeStringPtr) != expectedType) { |
1320 | if (expectedType == '\0') { | 1320 | if (expectedType == '\0') { |
1321 | OSC_errorMessage = | 1321 | OSC_errorMessage = |
1322 | "According to the type tag I expected more arguments."; | 1322 | "According to the type tag I expected more arguments."; |
1323 | } else if (*(buf->typeStringPtr) == '\0') { | 1323 | } else if (*(buf->typeStringPtr) == '\0') { |
1324 | OSC_errorMessage = | 1324 | OSC_errorMessage = |
1325 | "According to the type tag I didn't expect any more arguments."; | 1325 | "According to the type tag I didn't expect any more arguments."; |
1326 | } else { | 1326 | } else { |
1327 | OSC_errorMessage = | 1327 | OSC_errorMessage = |
1328 | "According to the type tag I expected an argument of a different type."; | 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); | 1329 | printf("* Expected %c, string now %s\n", expectedType, buf->typeStringPtr); |
1330 | } | 1330 | } |
1331 | return 9; | 1331 | return 9; |
1332 | } | 1332 | } |
1333 | ++(buf->typeStringPtr); | 1333 | ++(buf->typeStringPtr); |
1334 | } | 1334 | } |
1335 | return 0; | 1335 | return 0; |
1336 | } | 1336 | } |
1337 | 1337 | ||
1338 | 1338 | ||
1339 | int OSC_writeFloatArg(OSCbuf *buf, float arg) { | 1339 | int OSC_writeFloatArg(OSCbuf *buf, float arg) { |
1340 | int4byte *intp; | 1340 | int4byte *intp; |
1341 | //int result; | 1341 | //int result; |
1342 | 1342 | ||
1343 | CheckOverflow(buf, 4); | 1343 | CheckOverflow(buf, 4); |
1344 | 1344 | ||
1345 | if (CheckTypeTag(buf, 'f')) return 9; | 1345 | if (CheckTypeTag(buf, 'f')) return 9; |
1346 | 1346 | ||
1347 | /* Pretend arg is a long int so we can use htonl() */ | 1347 | /* Pretend arg is a long int so we can use htonl() */ |
1348 | intp = ((int4byte *) &arg); | 1348 | intp = ((int4byte *) &arg); |
1349 | *((int4byte *) buf->bufptr) = htonl(*intp); | 1349 | *((int4byte *) buf->bufptr) = htonl(*intp); |
1350 | 1350 | ||
1351 | buf->bufptr += 4; | 1351 | buf->bufptr += 4; |
1352 | 1352 | ||
1353 | buf->gettingFirstUntypedArg = 0; | 1353 | buf->gettingFirstUntypedArg = 0; |
1354 | return 0; | 1354 | return 0; |
1355 | } | 1355 | } |
1356 | 1356 | ||
1357 | 1357 | ||
1358 | 1358 | ||
1359 | int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args) { | 1359 | int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args) { |
1360 | int i; | 1360 | int i; |
1361 | int4byte *intp; | 1361 | int4byte *intp; |
1362 | 1362 | ||
1363 | CheckOverflow(buf, 4 * numFloats); | 1363 | CheckOverflow(buf, 4 * numFloats); |
1364 | 1364 | ||
1365 | /* Pretend args are long ints so we can use htonl() */ | 1365 | /* Pretend args are long ints so we can use htonl() */ |
1366 | intp = ((int4byte *) args); | 1366 | intp = ((int4byte *) args); |
1367 | 1367 | ||
1368 | for (i = 0; i < numFloats; i++) { | 1368 | for (i = 0; i < numFloats; i++) { |
1369 | if (CheckTypeTag(buf, 'f')) return 9; | 1369 | if (CheckTypeTag(buf, 'f')) return 9; |
1370 | *((int4byte *) buf->bufptr) = htonl(intp[i]); | 1370 | *((int4byte *) buf->bufptr) = htonl(intp[i]); |
1371 | buf->bufptr += 4; | 1371 | buf->bufptr += 4; |
1372 | } | 1372 | } |
1373 | 1373 | ||
1374 | buf->gettingFirstUntypedArg = 0; | 1374 | buf->gettingFirstUntypedArg = 0; |
1375 | return 0; | 1375 | return 0; |
1376 | } | 1376 | } |
1377 | 1377 | ||
1378 | int OSC_writeIntArg(OSCbuf *buf, int4byte arg) { | 1378 | int OSC_writeIntArg(OSCbuf *buf, int4byte arg) { |
1379 | CheckOverflow(buf, 4); | 1379 | CheckOverflow(buf, 4); |
1380 | if (CheckTypeTag(buf, 'i')) return 9; | 1380 | if (CheckTypeTag(buf, 'i')) return 9; |
1381 | 1381 | ||
1382 | *((int4byte *) buf->bufptr) = htonl(arg); | 1382 | *((int4byte *) buf->bufptr) = htonl(arg); |
1383 | buf->bufptr += 4; | 1383 | buf->bufptr += 4; |
1384 | 1384 | ||
1385 | buf->gettingFirstUntypedArg = 0; | 1385 | buf->gettingFirstUntypedArg = 0; |
1386 | return 0; | 1386 | return 0; |
1387 | } | 1387 | } |
1388 | 1388 | ||
1389 | int OSC_writeStringArg(OSCbuf *buf, char *arg) { | 1389 | int OSC_writeStringArg(OSCbuf *buf, char *arg) { |
1390 | int len; | 1390 | int len; |
1391 | 1391 | ||
1392 | if (CheckTypeTag(buf, 's')) return 9; | 1392 | if (CheckTypeTag(buf, 's')) return 9; |
1393 | 1393 | ||
1394 | len = OSC_effectiveStringLength(arg); | 1394 | len = OSC_effectiveStringLength(arg); |
1395 | 1395 | ||
1396 | if (buf->gettingFirstUntypedArg && arg[0] == ',') { | 1396 | if (buf->gettingFirstUntypedArg && arg[0] == ',') { |
1397 | /* This un-type-tagged message starts with a string | 1397 | /* This un-type-tagged message starts with a string |
1398 | that starts with a comma, so we have to escape it | 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 | 1399 | (with a double comma) so it won't look like a type |
1400 | tag string. */ | 1400 | tag string. */ |
1401 | 1401 | ||
1402 | CheckOverflow(buf, len+4); /* Too conservative */ | 1402 | CheckOverflow(buf, len+4); /* Too conservative */ |
1403 | buf->bufptr += | 1403 | buf->bufptr += |
1404 | OSC_padStringWithAnExtraStupidComma(buf->bufptr, arg); | 1404 | OSC_padStringWithAnExtraStupidComma(buf->bufptr, arg); |
1405 | 1405 | ||
1406 | } else { | 1406 | } else { |
1407 | CheckOverflow(buf, len); | 1407 | CheckOverflow(buf, len); |
1408 | buf->bufptr += OSC_padString(buf->bufptr, arg); | 1408 | buf->bufptr += OSC_padString(buf->bufptr, arg); |
1409 | } | 1409 | } |
1410 | 1410 | ||
1411 | buf->gettingFirstUntypedArg = 0; | 1411 | buf->gettingFirstUntypedArg = 0; |
1412 | return 0; | 1412 | return 0; |
1413 | 1413 | ||
1414 | } | 1414 | } |
1415 | 1415 | ||
1416 | /* String utilities */ | 1416 | /* String utilities */ |
1417 | 1417 | ||
1418 | #define STRING_ALIGN_PAD 4 | 1418 | #define STRING_ALIGN_PAD 4 |
1419 | int OSC_effectiveStringLength(char *string) { | 1419 | int OSC_effectiveStringLength(char *string) { |
1420 | int len = strlen(string) + 1; /* We need space for the null char. */ | 1420 | int len = strlen(string) + 1; /* We need space for the null char. */ |
1421 | 1421 | ||
1422 | /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */ | 1422 | /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */ |
1423 | if ((len % STRING_ALIGN_PAD) != 0) { | 1423 | if ((len % STRING_ALIGN_PAD) != 0) { |
1424 | len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD); | 1424 | len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD); |
1425 | } | 1425 | } |
1426 | return len; | 1426 | return len; |
1427 | } | 1427 | } |
1428 | 1428 | ||
1429 | static int OSC_padString(char *dest, char *str) { | 1429 | static int OSC_padString(char *dest, char *str) { |
1430 | int i; | 1430 | int i; |
1431 | 1431 | ||
1432 | for (i = 0; str[i] != '\0'; i++) { | 1432 | for (i = 0; str[i] != '\0'; i++) { |
1433 | dest[i] = str[i]; | 1433 | dest[i] = str[i]; |
1434 | } | 1434 | } |
1435 | 1435 | ||
1436 | return OSC_WritePadding(dest, i); | 1436 | return OSC_WritePadding(dest, i); |
1437 | } | 1437 | } |
1438 | 1438 | ||
1439 | static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str) { | 1439 | static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str) { |
1440 | int i; | 1440 | int i; |
1441 | 1441 | ||
1442 | dest[0] = ','; | 1442 | dest[0] = ','; |
1443 | for (i = 0; str[i] != '\0'; i++) { | 1443 | for (i = 0; str[i] != '\0'; i++) { |
1444 | dest[i+1] = str[i]; | 1444 | dest[i+1] = str[i]; |
1445 | } | 1445 | } |
1446 | 1446 | ||
1447 | return OSC_WritePadding(dest, i+1); | 1447 | return OSC_WritePadding(dest, i+1); |
1448 | } | 1448 | } |
1449 | 1449 | ||
1450 | static int OSC_WritePadding(char *dest, int i) { | 1450 | static int OSC_WritePadding(char *dest, int i) { |
1451 | dest[i] = '\0'; | 1451 | dest[i] = '\0'; |
1452 | i++; | 1452 | i++; |
1453 | 1453 | ||
1454 | for (; (i % STRING_ALIGN_PAD) != 0; i++) { | 1454 | for (; (i % STRING_ALIGN_PAD) != 0; i++) { |
1455 | dest[i] = '\0'; | 1455 | dest[i] = '\0'; |
1456 | } | 1456 | } |
1457 | 1457 | ||
1458 | return i; | 1458 | return i; |
1459 | } | 1459 | } |
1460 | 1460 | ||
1461 | 1461 | ||