Fix some greedy sed changes in imported code. Also provide a sys/types.h for compatib...
[kugel-rb.git] / apps / plugins / pdbox / PDa / extra / dumpOSC.c
blobb4ef97d7d1161f659cb2bdb9be99dbdc6b982ca3
1 /*
2 Written by Matt Wright and Adrian Freed, The Center for New Music and
3 Audio Technologies, University of California, Berkeley. Copyright (c)
4 1992,93,94,95,96,97,98,99,2000,01,02,03,04 The Regents of the University of
5 California (Regents).
7 Permission to use, copy, modify, distribute, and distribute modified versions
8 of this software and its documentation without fee and without a signed
9 licensing agreement, is hereby granted, provided that the above copyright
10 notice, this paragraph and the following two paragraphs appear in all copies,
11 modifications, and distributions.
13 IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
14 SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
15 OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
16 BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18 REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
21 HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
22 MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
29 /*
31 dumpOSC.c
32 server that displays OpenSoundControl messages sent to it
33 for debugging client udp and UNIX protocol
35 by Matt Wright, 6/3/97
36 modified from dumpSC.c, by Matt Wright and Adrian Freed
38 version 0.2: Added "-silent" option a.k.a. "-quiet"
40 version 0.3: Incorporated patches from Nicola Bernardini to make
41 things Linux-friendly. Also added ntohl() in the right places
42 to support little-endian architectures.
46 compile:
47 cc -o dumpOSC dumpOSC.c
49 to-do:
51 More robustness in saying exactly what's wrong with ill-formed
52 messages. (If they don't make sense, show exactly what was
53 received.)
55 Time-based features: print time-received for each packet
57 Clean up to separate OSC parsing code from socket/select stuff
59 pd: branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/dumpOSC/dumpOSC.c
60 -------------
61 -- added pd functions
62 -- socket is made differently than original via pd mechanisms
63 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
64 -- the OSX changes from cnmat didnt make it here yet but this compiles
65 on OSX anyway.
69 #if HAVE_CONFIG_H
70 #include <config.h>
71 #endif
73 #include "../src/m_pd.h"
74 //#include "m_imp.h"
75 #include "s_stuff.h"
77 /* declarations */
79 // typedef void (*t_fdpollfn)(void *ptr, int fd);
80 void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
83 #if defined(__sgi) || defined(__linux) || defined(WIN32) || defined(__APPLE__)
85 #ifdef WIN32
86 #include "OSC-common.h"
87 #include <winsock2.h>
88 #include <string.h>
89 #include <stdlib.h>
90 #include <fcntl.h>
91 #include <sys/types.h>
92 #include <sys/stat.h>
93 #include <ctype.h>
94 #include <signal.h>
95 #else
96 #include <stdio.h>
97 #include <string.h>
98 #include <stdlib.h>
99 #include <unistd.h>
100 #include <fcntl.h>
101 #include <sys/types.h>
102 #include <sys/stat.h>
103 #include <netinet/in.h>
104 #include <rpc/rpc.h>
105 #include <sys/socket.h>
106 #include <sys/un.h>
107 #include <sys/times.h>
108 #include <sys/param.h>
109 #include <sys/time.h>
110 #include <sys/ioctl.h>
111 #include <ctype.h>
112 #include <arpa/inet.h>
113 #include <netdb.h>
114 #include <pwd.h>
115 #include <signal.h>
116 #include <grp.h>
117 #include <sys/file.h>
118 //#include <sys/prctl.h>
120 #ifdef NEED_SCHEDCTL_AND_LOCK
121 #include <sys/schedctl.h>
122 #include <sys/lock.h>
123 #endif
124 #endif
127 char *htm_error_string;
128 typedef int Boolean;
129 typedef void *OBJ;
131 typedef struct ClientAddressStruct {
132 struct sockaddr_in cl_addr;
133 int clilen;
134 int sockfd;
135 } *ClientAddr;
137 typedef unsigned long long osc_time_t;
139 Boolean ShowBytes = FALSE;
140 Boolean Silent = FALSE;
142 /* Declarations */
143 #ifndef WIN32
144 static int unixinitudp(int chan);
145 #endif
147 static int initudp(int chan);
148 static void closeudp(int sockfd);
149 Boolean ClientReply(int packetsize, void *packet, int socketfd,
150 void *clientaddresspointer, int clientaddressbufferlength);
151 void sgi_CleanExit(void);
152 Boolean sgi_HaveToQuit(void);
153 int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy);
154 static void catch_sigint();
155 static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) ;
156 char *DataAfterAlignedString(char *string, char *boundary) ;
157 Boolean IsNiceString(char *string, char *boundary) ;
158 void complain(char *s, ...);
160 #define MAXMESG 32768
161 static char mbuf[MAXMESG];
163 /* ----------------------------- dumpOSC ------------------------- */
165 #define MAXOUTAT 50
167 static t_class *dumpOSC_class;
169 typedef struct _dumpOSC
171 t_object x_obj;
172 t_outlet *x_msgout;
173 t_outlet *x_connectout;
174 t_atom x_outat[MAXOUTAT];
175 int x_outatc;
176 t_binbuf *x_b;
177 int x_connectsocket;
178 int x_nconnections;
179 int x_udp;
180 struct sockaddr_in x_server;
181 int x_clilen;
182 } t_dumpOSC;
184 void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr);
185 Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd);
186 static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr);
187 static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n);
188 static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma);
190 static void dumpOSC_read(t_dumpOSC *x, int sockfd) {
191 int clilen = x->x_clilen;
192 int n;
193 struct ClientAddressStruct ras;
194 ClientAddr ra = &ras;
196 //catchupflag= FALSE;
198 /* if (ShowBytes) { */
199 /* int i; */
200 /* printf("%d byte message:\n", n); */
201 /* for (i = 0; i < n; ++i) { */
202 /* printf(" %x (%c)\t", m[i], m[i]); */
203 /* if (i%4 == 3) printf("\n"); */
204 /* } */
205 /* printf("\n"); */
206 /* } */
208 // return catchupflag;
209 //struct sockaddr_in x->x_server;
210 //while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &cl_addr, &clilen)) >0)
211 // while((
213 #ifdef WIN32
214 if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (SOCKADDR*)&x->x_server, &clilen)) >0)
215 #else
216 if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (struct sockaddr *)&x->x_server, &clilen)) >0)
217 #endif
219 //int r;
220 ras.cl_addr = *((struct sockaddr_in *) &x->x_server);
221 ras.clilen = x->x_clilen;
222 ras.sockfd = x->x_connectsocket;
224 #ifdef DEBUG
225 printf("dumpOSC_read: received UDP packet of length %d\n", n);
226 #endif
228 if(!dumpOSC_SendReply(mbuf, n, &x->x_server, clilen, sockfd))
230 dumpOSC_ParsePacket(x, mbuf, n, ra);
232 //r = Synthmessage(mbuf, n, &x->x_server, clilen, sockfd);
233 //post ("%d", r);
234 //outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
235 // emsg-msg-1, at + msg + 1);
236 // outlet_list(x->x_msgout, 0, n, mbuf);
237 //if( sgi_HaveToQuit()) goto out;
238 //if(r>0) goto back;
239 //clilen = maxclilen;
243 static void *dumpOSC_new(t_symbol *compatflag,
244 t_floatarg fportno) {
245 t_dumpOSC *x;
246 struct sockaddr_in server;
247 int clilen=sizeof(server);
248 int sockfd;
249 int portno=fportno;
250 int udp = 1;
252 //x->x_b = binbuf_new();
253 //x->x_outat = binbuf_getvec(x->x_b);
255 //{{raf}} pointer not valid yet...moving this down
256 //x->x_outatc = 0; {{raf}}
258 /* create a socket */
259 if ((sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0)) == -1)
261 sys_sockerror("socket");
262 return (0);
265 server.sin_family = AF_INET;
266 server.sin_addr.s_addr = INADDR_ANY;
267 /* assign server port number */
268 server.sin_port = htons((u_short)portno);
269 /* name the socket */
270 if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
272 sys_sockerror("bind");
273 sys_closesocket(sockfd);
274 return (0);
277 x = (t_dumpOSC *)pd_new(dumpOSC_class);
278 x->x_outatc = 0; // {{raf}} now pointer is valid (less invalid)
280 x->x_msgout = outlet_new(&x->x_obj, &s_anything);
282 // if (udp) /* datagram protocol */
285 sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_read, x);
286 x->x_connectout = 0;
288 // else /* streaming protocol */
289 /* { */
290 /* if (listen(sockfd, 5) < 0) */
291 /* { */
292 /* sys_sockerror("listen"); */
293 /* sys_closesocket(sockfd); */
294 /* sockfd = -1; */
295 /* } */
296 /* else */
297 /* { */
298 /* sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_connectpoll, x); */
299 /* x->x_connectout = outlet_new(&x->x_obj, &s_float); */
300 /* } */
301 /* } */
303 x->x_connectsocket = sockfd;
304 x->x_server = server;
305 x->x_clilen = clilen;
306 x->x_nconnections = 0;
307 x->x_udp = udp;
309 return (x);
312 static void dumpOSC_free(t_dumpOSC *x)
314 /* LATER make me clean up open connections */
315 if (x->x_connectsocket >= 0)
317 sys_rmpollfn(x->x_connectsocket);
318 sys_closesocket(x->x_connectsocket);
322 #ifdef WIN32
323 OSC_API void dumpOSC_setup(void)
324 #else
325 void dumpOSC_setup(void)
326 #endif
328 dumpOSC_class = class_new(gensym("dumpOSC"),
329 (t_newmethod)dumpOSC_new, (t_method)dumpOSC_free,
330 sizeof(t_dumpOSC), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT,
331 A_DEFSYM, 0);
332 class_sethelpsymbol(dumpOSC_class, gensym("dumpOSC-help.pd"));
336 #ifndef WIN32
337 #define UNIXDG_PATH "/tmp/htm"
338 #define UNIXDG_TMP "/tmp/htm.XXXXXX"
339 static int unixinitudp(int chan)
341 struct sockaddr_un serv_addr;
342 int sockfd;
344 if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
345 return sockfd;
347 bzero((char *)&serv_addr, sizeof(serv_addr));
348 serv_addr.sun_family = AF_UNIX;
349 strcpy(serv_addr.sun_path, UNIXDG_PATH);
350 sprintf(serv_addr.sun_path+strlen(serv_addr.sun_path), "%d", chan);
351 unlink(serv_addr.sun_path);
352 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr.sun_family)+strlen(serv_addr.sun_path)) < 0)
354 perror("unable to bind\n");
355 return -1;
358 fcntl(sockfd, F_SETFL, FNDELAY);
359 return sockfd;
361 #endif // #ifndef WIN32
365 static int initudp(int chan)
368 #ifdef WIN32
369 struct sockaddr_in serv_addr;
370 unsigned int sockfd;
371 ULONG nonBlocking = (ULONG) TRUE;
373 if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET ) {
374 ZeroMemory((char *)&serv_addr, sizeof(serv_addr));
375 serv_addr.sin_family = AF_INET;
376 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
377 serv_addr.sin_port = htons(chan);
378 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) >= 0) {
379 // set for non-blocking mode
380 if(ioctlsocket(sockfd, FIONBIO, &nonBlocking) == SOCKET_ERROR) {
381 perror("unable to set non-blocking\n");
382 return -1;
385 else { perror("unable to bind\n"); return -1; }
387 return (sockfd == INVALID_SOCKET ? -1 : (int)sockfd);
388 #else
389 struct sockaddr_in serv_addr;
390 int sockfd;
392 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
393 return sockfd;
395 bzero((char *)&serv_addr, sizeof(serv_addr));
396 serv_addr.sin_family = AF_INET;
397 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
398 serv_addr.sin_port = htons(chan);
400 if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
402 perror("unable to bind\n");
403 return -1;
406 fcntl(sockfd, F_SETFL, FNDELAY);
407 return sockfd;
408 #endif
418 static void closeudp(int sockfd) {
419 #ifdef WIN32
420 closesocket(sockfd);
421 #else
422 close(sockfd);
423 #endif
426 static Boolean catchupflag=FALSE;
427 Boolean ClientReply(int packetsize, void *packet, int socketfd,
428 void *clientaddresspointer, int clientaddressbufferlength)
430 if(!clientaddresspointer) return FALSE;
431 catchupflag= TRUE;
432 return packetsize==sendto(socketfd, packet, packetsize, 0, clientaddresspointer, clientaddressbufferlength);
435 static Boolean exitflag= FALSE;
436 void sgi_CleanExit(void) {
437 exitflag = TRUE;
440 Boolean sgi_HaveToQuit(void) {
441 return exitflag;
445 /* file descriptor poll table */
446 static int npolldevs =0;
447 typedef struct polldev
449 int fd;
450 void (*callbackfunction)(int , void *);
451 void *dummy;
452 } polldev;
453 #define TABMAX 8
454 static polldev polldevs[TABMAX];
457 /* Register a device (referred to by a file descriptor that the caller
458 should have already successfully obtained from a system call) to be
459 polled as real-time constraints allowed.
461 When a select(2) call indicates activity on the file descriptor, the
462 callback function is called with the file descripter as first
463 argument and the given dummy argument (presumably a pointer to the
464 instance variables associated with the device).
466 int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy)
468 if(npolldevs<TABMAX)
470 polldevs[npolldevs].fd = fd;
471 polldevs[npolldevs].callbackfunction = callbackfunction;
472 polldevs[npolldevs].dummy = dummy;
474 else return -1;
475 return npolldevs++;
478 static int caught_sigint;
480 static void catch_sigint() {
481 caught_sigint = 1;
483 static int sockfd, usockfd;
486 void PrintClientAddr(ClientAddr CA) {
487 unsigned long addr = CA->cl_addr.sin_addr.s_addr;
488 printf("Client address %p:\n", CA);
489 printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd);
490 printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family,
491 CA->cl_addr.sin_port);
492 printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr));
494 printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n",
495 CA->cl_addr.sin_zero[0],
496 CA->cl_addr.sin_zero[1],
497 CA->cl_addr.sin_zero[2],
498 CA->cl_addr.sin_zero[3],
499 CA->cl_addr.sin_zero[4],
500 CA->cl_addr.sin_zero[5],
501 CA->cl_addr.sin_zero[6],
502 CA->cl_addr.sin_zero[7]);
504 printf("\n");
507 //*******************
509 void WriteTime(char* dst, osc_time_t osctime)
511 *(int32_t*)dst = htonl((int32_t)(osctime >> 32));
512 *(int32_t*)(dst+4) = htonl((int32_t)osctime);
515 void WriteMode(char* dst)
517 *(int32_t*)dst = htonl(0);
520 osc_time_t ReadTime(const char* src)
522 osc_time_t osctime = ntohl(*(int32_t*)src);
523 return (osctime << 32) + ntohl(*(int32_t*)(src+4));
526 double TimeToSeconds(osc_time_t osctime)
528 return (double)osctime * 2.3283064365386962890625e-10 /* 1/2^32 */;
531 int timeRound(double x)
533 return x >= 0.0 ? x+0.5 : x-0.5;
536 void WriteLogicalTime(char* dst)
538 static double startTime = -1.0;
539 double sTime;
541 // Initialisierung der Startzeit.
542 // Knnte effizienter (ohne 'if') auch irgendwo vorher passieren.
543 // Knnte wahrscheinlich auch 0.0 sein.
544 if (startTime < 0.0) {
545 startTime = clock_getlogicaltime();
548 sTime = clock_gettimesince(startTime) * 0.001;
549 *(int32_t*)dst = hton'K l((int32_t)sTime);
550 *(int32_t*)(dst+4) = htonl((int32_t)(4294967296.0 * sTime));
554 void WriteLogicalTime(char* dst)
556 double sTime = clock_gettimesince(19230720) / 1000.0;
557 double tau = sTime - timeRound(sTime);
559 //fprintf(stderr, "sSec = %f tau = %f\n", sTime, tau);
561 *(int32_t*)dst = htonl((int32_t)(sTime));
562 *(int32_t*)(dst+4) = htonl((int32_t)(4294967296 * tau));
565 Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd)
567 if((n == 24) && (strcmp(buf, "#time") == 0))
569 osc_time_t t0, t1, t2;
570 double dt0, dt1, dt2;
572 WriteMode(buf+6);
574 t0 = ReadTime(buf+8);
576 WriteLogicalTime(buf+16);
577 t1 = ReadTime(buf+16); // reverse
578 dt0 = TimeToSeconds(t0); // client time
579 dt1 = TimeToSeconds(t1); // server time
581 // fprintf(stderr, "%f\t%f\t%f\n", dt0, dt1, dt0 - dt1);
583 sendto(fd, buf, n, 0, (struct sockaddr *)clientDesc, clientDescLenght);
584 return TRUE;
586 else
588 return FALSE;
592 //**********************
594 void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr) {
595 // t_dumpOSC *x;
596 int size, messageLen, i;
597 char *messageName;
598 char *args;
600 //#ifdef PRINTADDRS
601 #ifdef DEBUG
602 //PrintClientAddr(returnAddr);
603 #endif
606 if ((n%4) != 0) {
607 complain("SynthControl packet size (%d) not a multiple of 4 bytes: dropping", n);
608 return;
611 if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) {
612 /* This is a bundle message. */
613 #ifdef DEBUG
614 printf("dumpOSC_ParsePacket: bundle msg: bundles not yet supported\n");
615 #endif
617 if (n < 16) {
618 complain("Bundle message too small (%d bytes) for time tag", n);
619 return;
622 /* Print the time tag */
623 #ifdef DEBUG
624 printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf+8))), ntohl(*((unsigned long *)(buf+12))));
625 #endif
627 /* Note: if we wanted to actually use the time tag as a little-endian
628 64-bit int, we'd have to word-swap the two 32-bit halves of it */
630 i = 16; /* Skip "#group\0" and time tag */
632 while(i<n) {
633 size = ntohl(*((int *) (buf + i)));
634 if ((size % 4) != 0) {
635 complain("Bad size count %d in bundle (not a multiple of 4)", size);
636 return;
638 if ((size + i + 4) > n) {
639 complain("Bad size count %d in bundle (only %d bytes left in entire bundle)",
640 size, n-i-4);
641 return;
644 /* Recursively handle element of bundle */
645 dumpOSC_ParsePacket(x, buf+i+4, size, returnAddr);
646 i += 4 + size;
649 if (i != n) {
650 complain("This can't happen");
652 #ifdef DEBUG
653 printf("]\n");
654 #endif
657 else if ((n == 24) && (strcmp(buf, "#time") == 0))
659 complain("Time message: %s\n :).\n", htm_error_string);
660 return;
663 else
665 /* This is not a bundle message */
667 messageName = buf;
668 args = DataAfterAlignedString(messageName, buf+n);
669 if (args == 0) {
670 complain("Bad message name string: %s\nDropping entire message.\n",
671 htm_error_string);
672 return;
674 messageLen = args-messageName;
675 dumpOSC_Smessage(x, messageName, (void *)args, n-messageLen, returnAddr);
679 #define SMALLEST_POSITIVE_FLOAT 0.000001f
681 static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr) {
682 char *chars = v;
683 t_atom at;
684 //t_atom myargv[50];
686 int myargc = x->x_outatc;
687 t_atom* mya = x->x_outat;
688 int myi;
690 #ifdef DEBUG
691 printf("%s ", address);
692 #endif
694 // ztoln+cvt from envgen.c, ggee-0.18 ..
695 // outlet_anything's 'symbol' gets set to address
696 // so we dont need to append address to the atomlist
698 SETSYMBOL(mya,gensym(address));myargc++;
699 x->x_outatc = myargc;
702 if (n != 0) {
703 if (chars[0] == ',') {
704 if (chars[1] != ',') {
705 /* This message begins with a type-tag string */
706 dumpOSC_PrintTypeTaggedArgs(x, v, n);
707 } else {
708 /* Double comma means an escaped real comma, not a type string */
709 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 1);
711 } else {
712 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
716 outlet_anything(x->x_msgout,gensym(address),x->x_outatc,(t_atom*)&x->x_outat);
717 x->x_outatc = 0;
718 #ifdef DEBUG
719 printf("\n");
720 #endif
721 fflush(stdout); /* Added for Sami 5/21/98 */
724 static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n) {
725 char *typeTags, *thisType;
726 char *p;
728 int myargc = x->x_outatc;
729 t_atom* mya = x->x_outat;
730 int myi;
732 typeTags = v;
734 if (!IsNiceString(typeTags, typeTags+n)) {
735 /* No null-termination, so maybe it wasn't a type tag
736 string after all */
737 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
738 return;
741 p = DataAfterAlignedString(typeTags, typeTags+n);
744 for (thisType = typeTags + 1; *thisType != 0; ++thisType) {
745 switch (*thisType) {
746 case 'i': case 'r': case 'm': case 'c':
747 #ifdef DEBUG
748 //post("integer: %d", ntohl(*((int *) p)));
749 #endif
750 /* Martin Peach fix for negative floats:
751 * was: SETFLOAT(mya+myargc,ntohl(*((int *) p)));
752 * now is:
754 SETFLOAT(mya+myargc,(signed)ntohl(*((int *) p)));
755 myargc++;
757 p += 4;
758 break;
760 case 'f': {
761 int i = ntohl(*((int *) p));
762 float *floatp = ((float *) (&i));
763 #ifdef DEBUG
764 post("float: %f", *floatp);
765 #endif
766 SETFLOAT(mya+myargc,*floatp);
767 myargc++;
769 p += 4;
771 break;
773 case 'h': case 't':
774 #ifdef DEBUG
775 printf("[A 64-bit int] ");
776 #endif
777 post("[A 64-bit int] not implemented");
779 p += 8;
780 break;
782 case 'd':
783 #ifdef DEBUG
784 printf("[A 64-bit float] ");
785 #endif
786 post("[A 64-bit float] not implemented");
788 p += 8;
789 break;
791 case 's': case 'S':
792 if (!IsNiceString(p, typeTags+n)) {
793 post("Type tag said this arg is a string but it's not!\n");
794 return;
795 } else {
796 #ifdef DEBUG
797 post("string: \"%s\"", p);
798 #endif
799 SETSYMBOL(mya+myargc,gensym(p));
800 myargc++;
801 //outlet_list(x->x_msgout, 0,sizeof(p), p);
802 //outlet_anything(x->x_msgout, 0, sizeof(p), p);
803 p = DataAfterAlignedString(p, typeTags+n);
804 // append to output vector ..
806 break;
808 case 'T':
809 #ifdef DEBUG
810 printf("[True] ");
811 #endif
812 SETFLOAT(mya+myargc,1.);
813 myargc++;
814 break;
815 case 'F':
816 #ifdef DEBUG
817 printf("[False] ");
818 #endif
819 SETFLOAT(mya+myargc,0.);
820 myargc++;
821 break;
822 case 'N':
823 #ifdef DEBUG
824 printf("[Nil]");
825 #endif
826 post("sendOSC: [Nil] not implemented");
827 break;
828 case 'I':
829 #ifdef DEBUG
830 printf("[Infinitum]");
831 #endif
832 post("sendOSC: [Infinitum] not implemented");
833 break;
835 default:
836 post("sendOSC: [Unrecognized type tag %c]", *thisType);
837 // return;
840 x->x_outatc = myargc;
843 static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma) {
844 int i, thisi;
845 float thisf;
846 int *ints;
847 char *chars;
848 char *string, *nextString;
850 int myargc= x->x_outatc;
851 t_atom* mya = x->x_outat;
852 int myi;
855 /* Go through the arguments 32 bits at a time */
856 ints = v;
857 chars = v;
859 for (i = 0; i<n/4; ) {
860 string = &chars[i*4];
861 thisi = ntohl(ints[i]);
862 /* Reinterpret the (potentially byte-reversed) thisi as a float */
863 thisf = *(((float *) (&thisi)));
865 if (thisi >= -1000 && thisi <= 1000000) {
866 #ifdef DEBUG
867 printf("%d ", thisi);
868 #endif
869 // append to output vector ..
870 SETFLOAT(mya+myargc,(t_float) (thisi));
871 myargc++;
872 // outlet_float(x->x_msgout, thisi);
873 i++;
874 } else if (thisf >= -1000.f && thisf <= 1000000.f &&
875 (thisf <=0.0f || thisf >= SMALLEST_POSITIVE_FLOAT)) {
876 #ifdef DEBUG
877 printf("%f ", thisf);
878 #endif
879 // append to output vector ..
880 SETFLOAT(mya+myargc,thisf);
881 myargc++;
882 //outlet_float(x->x_msgout, thisf);
883 i++;
884 } else if (IsNiceString(string, chars+n)) {
885 nextString = DataAfterAlignedString(string, chars+n);
886 #ifdef DEBUG
887 printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string);
888 #endif
889 // append to output vector ..
890 SETSYMBOL(mya+myargc,gensym(string));
891 myargc++;
892 //outlet_symbol(x->x_msgout, gensym((i == 0 && skipComma) ? string +1 : string));
893 i += (nextString-string) / 4;
894 } else {
895 // unhandled .. ;)
896 #ifdef DEBUG
897 printf("0x%x xx", ints[i]);
898 #endif
899 i++;
901 x->x_outatc = myargc;
906 #define STRING_ALIGN_PAD 4
908 char *DataAfterAlignedString(char *string, char *boundary)
910 /* The argument is a block of data beginning with a string. The
911 string has (presumably) been padded with extra null characters
912 so that the overall length is a multiple of STRING_ALIGN_PAD
913 bytes. Return a pointer to the next byte after the null
914 byte(s). The boundary argument points to the character after
915 the last valid character in the buffer---if the string hasn't
916 ended by there, something's wrong.
918 If the data looks wrong, return 0, and set htm_error_string */
920 int i;
922 if ((boundary - string) %4 != 0) {
923 fprintf(stderr, "Internal error: DataAfterAlignedString: bad boundary\n");
924 return 0;
927 for (i = 0; string[i] != '\0'; i++) {
928 if (string + i >= boundary) {
929 htm_error_string = "DataAfterAlignedString: Unreasonably long string";
930 return 0;
934 /* Now string[i] is the first null character */
935 i++;
937 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
938 if (string + i >= boundary) {
939 htm_error_string = "DataAfterAlignedString: Unreasonably long string";
940 return 0;
942 if (string[i] != '\0') {
943 htm_error_string = "DataAfterAlignedString: Incorrectly padded string.";
944 return 0;
948 return string+i;
951 Boolean IsNiceString(char *string, char *boundary)
953 /* Arguments same as DataAfterAlignedString(). Is the given "string"
954 really a string? I.e., is it a sequence of isprint() characters
955 terminated with 1-4 null characters to align on a 4-byte boundary? */
957 int i;
959 if ((boundary - string) %4 != 0) {
960 fprintf(stderr, "Internal error: IsNiceString: bad boundary\n");
961 return 0;
964 for (i = 0; string[i] != '\0'; i++) {
965 if (!isprint(string[i])) return FALSE;
966 if (string + i >= boundary) return FALSE;
969 /* If we made it this far, it's a null-terminated sequence of printing characters
970 in the given boundary. Now we just make sure it's null padded... */
972 /* Now string[i] is the first null character */
973 i++;
974 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
975 if (string[i] != '\0') return FALSE;
978 return TRUE;
989 #include <stdarg.h>
990 void complain(char *s, ...) {
991 va_list ap;
992 va_start(ap, s);
993 fprintf(stderr, "*** ERROR: ");
994 vfprintf(stderr, s, ap);
995 fprintf(stderr, "\n");
996 va_end(ap);
999 #endif /* __sgi or LINUX or WIN32 */