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
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
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.
47 cc -o dumpOSC dumpOSC.c
51 More robustness in saying exactly what's wrong with ill-formed
52 messages. (If they don't make sense, show exactly what was
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
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
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__)
86 #include "OSC-common.h"
91 #include <sys/types.h>
101 #include <sys/types.h>
102 #include <sys/stat.h>
103 #include <netinet/in.h>
105 #include <sys/socket.h>
107 #include <sys/times.h>
108 #include <sys/param.h>
109 #include <sys/time.h>
110 #include <sys/ioctl.h>
112 #include <arpa/inet.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>
127 char *htm_error_string
;
131 typedef struct ClientAddressStruct
{
132 struct sockaddr_in cl_addr
;
137 typedef unsigned long long osc_time_t
;
139 Boolean ShowBytes
= FALSE
;
140 Boolean Silent
= FALSE
;
144 static int unixinitudp(int chan
);
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 ------------------------- */
167 static t_class
*dumpOSC_class
;
169 typedef struct _dumpOSC
173 t_outlet
*x_connectout
;
174 t_atom x_outat
[MAXOUTAT
];
180 struct sockaddr_in x_server
;
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
;
193 struct ClientAddressStruct ras
;
194 ClientAddr ra
= &ras
;
196 //catchupflag= FALSE;
198 /* if (ShowBytes) { */
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"); */
208 // return catchupflag;
209 //struct sockaddr_in x->x_server;
210 //while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &cl_addr, &clilen)) >0)
214 if ((n
= recvfrom(sockfd
, mbuf
, MAXMESG
, 0, (SOCKADDR
*)&x
->x_server
, &clilen
)) >0)
216 if ((n
= recvfrom(sockfd
, mbuf
, MAXMESG
, 0, (struct sockaddr
*)&x
->x_server
, &clilen
)) >0)
220 ras
.cl_addr
= *((struct sockaddr_in
*) &x
->x_server
);
221 ras
.clilen
= x
->x_clilen
;
222 ras
.sockfd
= x
->x_connectsocket
;
225 printf("dumpOSC_read: received UDP packet of length %d\n", n
);
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);
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;
239 //clilen = maxclilen;
243 static void *dumpOSC_new(t_symbol
*compatflag
,
244 t_floatarg fportno
) {
246 struct sockaddr_in server
;
247 int clilen
=sizeof(server
);
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");
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
);
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
);
288 // else /* streaming protocol */
290 /* if (listen(sockfd, 5) < 0) */
292 /* sys_sockerror("listen"); */
293 /* sys_closesocket(sockfd); */
298 /* sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_connectpoll, x); */
299 /* x->x_connectout = outlet_new(&x->x_obj, &s_float); */
303 x
->x_connectsocket
= sockfd
;
304 x
->x_server
= server
;
305 x
->x_clilen
= clilen
;
306 x
->x_nconnections
= 0;
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
);
323 OSC_API
void dumpOSC_setup(void)
325 void dumpOSC_setup(void)
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
,
332 class_sethelpsymbol(dumpOSC_class
, gensym("dumpOSC-help.pd"));
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
;
344 if((sockfd
= socket(AF_UNIX
, SOCK_DGRAM
, 0)) < 0)
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");
358 fcntl(sockfd
, F_SETFL
, FNDELAY
);
361 #endif // #ifndef WIN32
365 static int initudp(int chan
)
369 struct sockaddr_in serv_addr
;
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");
385 else { perror("unable to bind\n"); return -1; }
387 return (sockfd
== INVALID_SOCKET
? -1 : (int)sockfd
);
389 struct sockaddr_in serv_addr
;
392 if((sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
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");
406 fcntl(sockfd
, F_SETFL
, FNDELAY
);
418 static void closeudp(int sockfd
) {
426 static Boolean catchupflag
=FALSE
;
427 Boolean
ClientReply(int packetsize
, void *packet
, int socketfd
,
428 void *clientaddresspointer
, int clientaddressbufferlength
)
430 if(!clientaddresspointer
) return FALSE
;
432 return packetsize
==sendto(socketfd
, packet
, packetsize
, 0, clientaddresspointer
, clientaddressbufferlength
);
435 static Boolean exitflag
= FALSE
;
436 void sgi_CleanExit(void) {
440 Boolean
sgi_HaveToQuit(void) {
445 /* file descriptor poll table */
446 static int npolldevs
=0;
447 typedef struct polldev
450 void (*callbackfunction
)(int , void *);
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
)
470 polldevs
[npolldevs
].fd
= fd
;
471 polldevs
[npolldevs
].callbackfunction
= callbackfunction
;
472 polldevs
[npolldevs
].dummy
= dummy
;
478 static int caught_sigint
;
480 static void catch_sigint() {
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]);
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;
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
;
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
);
592 //**********************
594 void dumpOSC_ParsePacket(t_dumpOSC
*x
, char *buf
, int n
, ClientAddr returnAddr
) {
596 int size
, messageLen
, i
;
602 //PrintClientAddr(returnAddr);
607 complain("SynthControl packet size (%d) not a multiple of 4 bytes: dropping", n
);
611 if ((n
>= 8) && (strncmp(buf
, "#bundle", 8) == 0)) {
612 /* This is a bundle message. */
614 printf("dumpOSC_ParsePacket: bundle msg: bundles not yet supported\n");
618 complain("Bundle message too small (%d bytes) for time tag", n
);
622 /* Print the time tag */
624 printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf
+8))), ntohl(*((unsigned long *)(buf
+12))));
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 */
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
);
638 if ((size
+ i
+ 4) > n
) {
639 complain("Bad size count %d in bundle (only %d bytes left in entire bundle)",
644 /* Recursively handle element of bundle */
645 dumpOSC_ParsePacket(x
, buf
+i
+4, size
, returnAddr
);
650 complain("This can't happen");
657 else if ((n
== 24) && (strcmp(buf
, "#time") == 0))
659 complain("Time message: %s\n :).\n", htm_error_string
);
665 /* This is not a bundle message */
668 args
= DataAfterAlignedString(messageName
, buf
+n
);
670 complain("Bad message name string: %s\nDropping entire message.\n",
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
) {
686 int myargc
= x
->x_outatc
;
687 t_atom
* mya
= x
->x_outat
;
691 printf("%s ", address
);
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;
703 if (chars
[0] == ',') {
704 if (chars
[1] != ',') {
705 /* This message begins with a type-tag string */
706 dumpOSC_PrintTypeTaggedArgs(x
, v
, n
);
708 /* Double comma means an escaped real comma, not a type string */
709 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x
, v
, n
, 1);
712 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x
, v
, n
, 0);
716 outlet_anything(x
->x_msgout
,gensym(address
),x
->x_outatc
,(t_atom
*)&x
->x_outat
);
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
;
728 int myargc
= x
->x_outatc
;
729 t_atom
* mya
= x
->x_outat
;
734 if (!IsNiceString(typeTags
, typeTags
+n
)) {
735 /* No null-termination, so maybe it wasn't a type tag
737 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x
, v
, n
, 0);
741 p
= DataAfterAlignedString(typeTags
, typeTags
+n
);
744 for (thisType
= typeTags
+ 1; *thisType
!= 0; ++thisType
) {
746 case 'i': case 'r': case 'm': case 'c':
748 //post("integer: %d", ntohl(*((int *) p)));
750 /* Martin Peach fix for negative floats:
751 * was: SETFLOAT(mya+myargc,ntohl(*((int *) p)));
754 SETFLOAT(mya
+myargc
,(signed)ntohl(*((int *) p
)));
761 int i
= ntohl(*((int *) p
));
762 float *floatp
= ((float *) (&i
));
764 post("float: %f", *floatp
);
766 SETFLOAT(mya
+myargc
,*floatp
);
775 printf("[A 64-bit int] ");
777 post("[A 64-bit int] not implemented");
784 printf("[A 64-bit float] ");
786 post("[A 64-bit float] not implemented");
792 if (!IsNiceString(p
, typeTags
+n
)) {
793 post("Type tag said this arg is a string but it's not!\n");
797 post("string: \"%s\"", p
);
799 SETSYMBOL(mya
+myargc
,gensym(p
));
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 ..
812 SETFLOAT(mya
+myargc
,1.);
819 SETFLOAT(mya
+myargc
,0.);
826 post("sendOSC: [Nil] not implemented");
830 printf("[Infinitum]");
832 post("sendOSC: [Infinitum] not implemented");
836 post("sendOSC: [Unrecognized type tag %c]", *thisType
);
840 x
->x_outatc
= myargc
;
843 static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC
*x
, void *v
, int n
, int skipComma
) {
848 char *string
, *nextString
;
850 int myargc
= x
->x_outatc
;
851 t_atom
* mya
= x
->x_outat
;
855 /* Go through the arguments 32 bits at a time */
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) {
867 printf("%d ", thisi
);
869 // append to output vector ..
870 SETFLOAT(mya
+myargc
,(t_float
) (thisi
));
872 // outlet_float(x->x_msgout, thisi);
874 } else if (thisf
>= -1000.f
&& thisf
<= 1000000.f
&&
875 (thisf
<=0.0f
|| thisf
>= SMALLEST_POSITIVE_FLOAT
)) {
877 printf("%f ", thisf
);
879 // append to output vector ..
880 SETFLOAT(mya
+myargc
,thisf
);
882 //outlet_float(x->x_msgout, thisf);
884 } else if (IsNiceString(string
, chars
+n
)) {
885 nextString
= DataAfterAlignedString(string
, chars
+n
);
887 printf("\"%s\" ", (i
== 0 && skipComma
) ? string
+1 : string
);
889 // append to output vector ..
890 SETSYMBOL(mya
+myargc
,gensym(string
));
892 //outlet_symbol(x->x_msgout, gensym((i == 0 && skipComma) ? string +1 : string));
893 i
+= (nextString
-string
) / 4;
897 printf("0x%x xx", ints
[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 */
922 if ((boundary
- string
) %4 != 0) {
923 fprintf(stderr
, "Internal error: DataAfterAlignedString: bad boundary\n");
927 for (i
= 0; string
[i
] != '\0'; i
++) {
928 if (string
+ i
>= boundary
) {
929 htm_error_string
= "DataAfterAlignedString: Unreasonably long string";
934 /* Now string[i] is the first null character */
937 for (; (i
% STRING_ALIGN_PAD
) != 0; i
++) {
938 if (string
+ i
>= boundary
) {
939 htm_error_string
= "DataAfterAlignedString: Unreasonably long string";
942 if (string
[i
] != '\0') {
943 htm_error_string
= "DataAfterAlignedString: Incorrectly padded string.";
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? */
959 if ((boundary
- string
) %4 != 0) {
960 fprintf(stderr
, "Internal error: IsNiceString: bad boundary\n");
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 */
974 for (; (i
% STRING_ALIGN_PAD
) != 0; i
++) {
975 if (string
[i
] != '\0') return FALSE
;
990 void complain(char *s
, ...) {
993 fprintf(stderr
, "*** ERROR: ");
994 vfprintf(stderr
, s
, ap
);
995 fprintf(stderr
, "\n");
999 #endif /* __sgi or LINUX or WIN32 */
1001 Written by Matt Wright and Adrian Freed, The Center for New Music and
1002 Audio Technologies, University of California, Berkeley. Copyright (c)
1003 1992,93,94,95,96,97,98,99,2000,01,02,03,04 The Regents of the University of
1004 California (Regents).
1006 Permission to use, copy, modify, distribute, and distribute modified versions
1007 of this software and its documentation without fee and without a signed
1008 licensing agreement, is hereby granted, provided that the above copyright
1009 notice, this paragraph and the following two paragraphs appear in all copies,
1010 modifications, and distributions.
1012 IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
1013 SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
1014 OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
1015 BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1017 REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1018 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1019 PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
1020 HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
1021 MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1024 The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
1031 server that displays OpenSoundControl messages sent to it
1032 for debugging client udp and UNIX protocol
1034 by Matt Wright, 6/3/97
1035 modified from dumpSC.c, by Matt Wright and Adrian Freed
1037 version 0.2: Added "-silent" option a.k.a. "-quiet"
1039 version 0.3: Incorporated patches from Nicola Bernardini to make
1040 things Linux-friendly. Also added ntohl() in the right places
1041 to support little-endian architectures.
1046 cc -o dumpOSC dumpOSC.c
1050 More robustness in saying exactly what's wrong with ill-formed
1051 messages. (If they don't make sense, show exactly what was
1054 Time-based features: print time-received for each packet
1056 Clean up to separate OSC parsing code from socket/select stuff
1058 pd: branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/dumpOSC/dumpOSC.c
1060 -- added pd functions
1061 -- socket is made differently than original via pd mechanisms
1062 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
1063 -- the OSX changes from cnmat didnt make it here yet but this compiles
1073 //#include "m_imp.h"
1074 #include "s_stuff.h"
1078 // typedef void (*t_fdpollfn)(void *ptr, int fd);
1079 void sys_addpollfn(int fd
, t_fdpollfn fn
, void *ptr
);
1082 #if defined(__sgi) || defined(__linux) || defined(WIN32) || defined(__APPLE__)
1085 #include "OSC-common.h"
1086 #include <winsock2.h>
1090 #include <sys/types.h>
1091 #include <sys/stat.h>
1100 #include <sys/types.h>
1101 #include <sys/stat.h>
1102 #include <netinet/in.h>
1103 #include <rpc/rpc.h>
1104 #include <sys/socket.h>
1106 #include <sys/times.h>
1107 #include <sys/param.h>
1108 #include <sys/time.h>
1109 #include <sys/ioctl.h>
1111 #include <arpa/inet.h>
1116 #include <sys/file.h>
1117 //#include <sys/prctl.h>
1119 #ifdef NEED_SCHEDCTL_AND_LOCK
1120 #include <sys/schedctl.h>
1121 #include <sys/lock.h>
1126 char *htm_error_string
;
1127 typedef int Boolean
;
1130 typedef struct ClientAddressStruct
{
1131 struct sockaddr_in cl_addr
;
1136 typedef unsigned long long osc_time_t
;
1138 Boolean ShowBytes
= FALSE
;
1139 Boolean Silent
= FALSE
;
1143 static int unixinitudp(int chan
);
1146 static int initudp(int chan
);
1147 static void closeudp(int sockfd
);
1148 Boolean
ClientReply(int packetsize
, void *packet
, int socketfd
,
1149 void *clientaddresspointer
, int clientaddressbufferlength
);
1150 void sgi_CleanExit(void);
1151 Boolean
sgi_HaveToQuit(void);
1152 int RegisterPollingDevice(int fd
, void (*callbackfunction
)(int , void *), void *dummy
);
1153 static void catch_sigint();
1154 static int Synthmessage(char *m
, int n
, void *clientdesc
, int clientdesclength
, int fd
) ;
1155 char *DataAfterAlignedString(char *string
, char *boundary
) ;
1156 Boolean
IsNiceString(char *string
, char *boundary
) ;
1157 void complain(char *s
, ...);
1159 #define MAXMESG 32768
1160 static char mbuf
[MAXMESG
];
1162 /* ----------------------------- dumpOSC ------------------------- */
1166 static t_class
*dumpOSC_class
;
1168 typedef struct _dumpOSC
1172 t_outlet
*x_connectout
;
1173 t_atom x_outat
[MAXOUTAT
];
1176 int x_connectsocket
;
1179 struct sockaddr_in x_server
;
1183 void dumpOSC_ParsePacket(t_dumpOSC
*x
, char *buf
, int n
, ClientAddr returnAddr
);
1184 Boolean
dumpOSC_SendReply(char *buf
, int n
, void *clientDesc
, int clientDescLenght
, int fd
);
1185 static void dumpOSC_Smessage(t_dumpOSC
*x
, char *address
, void *v
, int n
, ClientAddr returnAddr
);
1186 static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC
*x
, void *v
, int n
);
1187 static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC
*x
, void *v
, int n
, int skipComma
);
1189 static void dumpOSC_read(t_dumpOSC
*x
, int sockfd
) {
1190 int clilen
= x
->x_clilen
;
1192 struct ClientAddressStruct ras
;
1193 ClientAddr ra
= &ras
;
1195 //catchupflag= FALSE;
1197 /* if (ShowBytes) { */
1199 /* printf("%d byte message:\n", n); */
1200 /* for (i = 0; i < n; ++i) { */
1201 /* printf(" %x (%c)\t", m[i], m[i]); */
1202 /* if (i%4 == 3) printf("\n"); */
1207 // return catchupflag;
1208 //struct sockaddr_in x->x_server;
1209 //while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &cl_addr, &clilen)) >0)
1213 if ((n
= recvfrom(sockfd
, mbuf
, MAXMESG
, 0, (SOCKADDR
*)&x
->x_server
, &clilen
)) >0)
1215 if ((n
= recvfrom(sockfd
, mbuf
, MAXMESG
, 0, (struct sockaddr
*)&x
->x_server
, &clilen
)) >0)
1219 ras
.cl_addr
= *((struct sockaddr_in
*) &x
->x_server
);
1220 ras
.clilen
= x
->x_clilen
;
1221 ras
.sockfd
= x
->x_connectsocket
;
1224 printf("dumpOSC_read: received UDP packet of length %d\n", n
);
1227 if(!dumpOSC_SendReply(mbuf
, n
, &x
->x_server
, clilen
, sockfd
))
1229 dumpOSC_ParsePacket(x
, mbuf
, n
, ra
);
1231 //r = Synthmessage(mbuf, n, &x->x_server, clilen, sockfd);
1233 //outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
1234 // emsg-msg-1, at + msg + 1);
1235 // outlet_list(x->x_msgout, 0, n, mbuf);
1236 //if( sgi_HaveToQuit()) goto out;
1237 //if(r>0) goto back;
1238 //clilen = maxclilen;
1242 static void *dumpOSC_new(t_symbol
*compatflag
,
1243 t_floatarg fportno
) {
1245 struct sockaddr_in server
;
1246 int clilen
=sizeof(server
);
1251 //x->x_b = binbuf_new();
1252 //x->x_outat = binbuf_getvec(x->x_b);
1254 //{{raf}} pointer not valid yet...moving this down
1255 //x->x_outatc = 0; {{raf}}
1257 /* create a socket */
1258 if ((sockfd
= socket(AF_INET
, (udp
? SOCK_DGRAM
: SOCK_STREAM
), 0)) == -1)
1260 sys_sockerror("socket");
1264 server
.sin_family
= AF_INET
;
1265 server
.sin_addr
.s_addr
= INADDR_ANY
;
1266 /* assign server port number */
1267 server
.sin_port
= htons((u_short
)portno
);
1268 /* name the socket */
1269 if (bind(sockfd
, (struct sockaddr
*)&server
, sizeof(server
)) < 0)
1271 sys_sockerror("bind");
1272 sys_closesocket(sockfd
);
1276 x
= (t_dumpOSC
*)pd_new(dumpOSC_class
);
1277 x
->x_outatc
= 0; // {{raf}} now pointer is valid (less invalid)
1279 x
->x_msgout
= outlet_new(&x
->x_obj
, &s_anything
);
1281 // if (udp) /* datagram protocol */
1284 sys_addpollfn(sockfd
, (t_fdpollfn
)dumpOSC_read
, x
);
1285 x
->x_connectout
= 0;
1287 // else /* streaming protocol */
1289 /* if (listen(sockfd, 5) < 0) */
1291 /* sys_sockerror("listen"); */
1292 /* sys_closesocket(sockfd); */
1297 /* sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_connectpoll, x); */
1298 /* x->x_connectout = outlet_new(&x->x_obj, &s_float); */
1302 x
->x_connectsocket
= sockfd
;
1303 x
->x_server
= server
;
1304 x
->x_clilen
= clilen
;
1305 x
->x_nconnections
= 0;
1311 static void dumpOSC_free(t_dumpOSC
*x
)
1313 /* LATER make me clean up open connections */
1314 if (x
->x_connectsocket
>= 0)
1316 sys_rmpollfn(x
->x_connectsocket
);
1317 sys_closesocket(x
->x_connectsocket
);
1322 OSC_API
void dumpOSC_setup(void)
1324 void dumpOSC_setup(void)
1327 dumpOSC_class
= class_new(gensym("dumpOSC"),
1328 (t_newmethod
)dumpOSC_new
, (t_method
)dumpOSC_free
,
1329 sizeof(t_dumpOSC
), CLASS_NOINLET
, A_DEFFLOAT
, A_DEFFLOAT
,
1331 class_sethelpsymbol(dumpOSC_class
, gensym("dumpOSC-help.pd"));
1336 #define UNIXDG_PATH "/tmp/htm"
1337 #define UNIXDG_TMP "/tmp/htm.XXXXXX"
1338 static int unixinitudp(int chan
)
1340 struct sockaddr_un serv_addr
;
1343 if((sockfd
= socket(AF_UNIX
, SOCK_DGRAM
, 0)) < 0)
1346 bzero((char *)&serv_addr
, sizeof(serv_addr
));
1347 serv_addr
.sun_family
= AF_UNIX
;
1348 strcpy(serv_addr
.sun_path
, UNIXDG_PATH
);
1349 sprintf(serv_addr
.sun_path
+strlen(serv_addr
.sun_path
), "%d", chan
);
1350 unlink(serv_addr
.sun_path
);
1351 if(bind(sockfd
, (struct sockaddr
*) &serv_addr
, sizeof(serv_addr
.sun_family
)+strlen(serv_addr
.sun_path
)) < 0)
1353 perror("unable to bind\n");
1357 fcntl(sockfd
, F_SETFL
, FNDELAY
);
1360 #endif // #ifndef WIN32
1364 static int initudp(int chan
)
1368 struct sockaddr_in serv_addr
;
1369 unsigned int sockfd
;
1370 ULONG nonBlocking
= (ULONG
) TRUE
;
1372 if( (sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0)) != INVALID_SOCKET
) {
1373 ZeroMemory((char *)&serv_addr
, sizeof(serv_addr
));
1374 serv_addr
.sin_family
= AF_INET
;
1375 serv_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
1376 serv_addr
.sin_port
= htons(chan
);
1377 if(bind(sockfd
, (struct sockaddr
*) &serv_addr
, sizeof(serv_addr
)) >= 0) {
1378 // set for non-blocking mode
1379 if(ioctlsocket(sockfd
, FIONBIO
, &nonBlocking
) == SOCKET_ERROR
) {
1380 perror("unable to set non-blocking\n");
1384 else { perror("unable to bind\n"); return -1; }
1386 return (sockfd
== INVALID_SOCKET
? -1 : (int)sockfd
);
1388 struct sockaddr_in serv_addr
;
1391 if((sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
1394 bzero((char *)&serv_addr
, sizeof(serv_addr
));
1395 serv_addr
.sin_family
= AF_INET
;
1396 serv_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
1397 serv_addr
.sin_port
= htons(chan
);
1399 if(bind(sockfd
, (struct sockaddr
*) &serv_addr
, sizeof(serv_addr
)) < 0)
1401 perror("unable to bind\n");
1405 fcntl(sockfd
, F_SETFL
, FNDELAY
);
1417 static void closeudp(int sockfd
) {
1419 closesocket(sockfd
);
1425 static Boolean catchupflag
=FALSE
;
1426 Boolean
ClientReply(int packetsize
, void *packet
, int socketfd
,
1427 void *clientaddresspointer
, int clientaddressbufferlength
)
1429 if(!clientaddresspointer
) return FALSE
;
1431 return packetsize
==sendto(socketfd
, packet
, packetsize
, 0, clientaddresspointer
, clientaddressbufferlength
);
1434 static Boolean exitflag
= FALSE
;
1435 void sgi_CleanExit(void) {
1439 Boolean
sgi_HaveToQuit(void) {
1444 /* file descriptor poll table */
1445 static int npolldevs
=0;
1446 typedef struct polldev
1449 void (*callbackfunction
)(int , void *);
1453 static polldev polldevs
[TABMAX
];
1456 /* Register a device (referred to by a file descriptor that the caller
1457 should have already successfully obtained from a system call) to be
1458 polled as real-time constraints allowed.
1460 When a select(2) call indicates activity on the file descriptor, the
1461 callback function is called with the file descripter as first
1462 argument and the given dummy argument (presumably a pointer to the
1463 instance variables associated with the device).
1465 int RegisterPollingDevice(int fd
, void (*callbackfunction
)(int , void *), void *dummy
)
1467 if(npolldevs
<TABMAX
)
1469 polldevs
[npolldevs
].fd
= fd
;
1470 polldevs
[npolldevs
].callbackfunction
= callbackfunction
;
1471 polldevs
[npolldevs
].dummy
= dummy
;
1477 static int caught_sigint
;
1479 static void catch_sigint() {
1482 static int sockfd
, usockfd
;
1485 void PrintClientAddr(ClientAddr CA
) {
1486 unsigned long addr
= CA
->cl_addr
.sin_addr
.s_addr
;
1487 printf("Client address %p:\n", CA
);
1488 printf(" clilen %d, sockfd %d\n", CA
->clilen
, CA
->sockfd
);
1489 printf(" sin_family %d, sin_port %d\n", CA
->cl_addr
.sin_family
,
1490 CA
->cl_addr
.sin_port
);
1491 printf(" address: (%x) %s\n", addr
, inet_ntoa(CA
->cl_addr
.sin_addr
));
1493 printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n",
1494 CA
->cl_addr
.sin_zero
[0],
1495 CA
->cl_addr
.sin_zero
[1],
1496 CA
->cl_addr
.sin_zero
[2],
1497 CA
->cl_addr
.sin_zero
[3],
1498 CA
->cl_addr
.sin_zero
[4],
1499 CA
->cl_addr
.sin_zero
[5],
1500 CA
->cl_addr
.sin_zero
[6],
1501 CA
->cl_addr
.sin_zero
[7]);
1506 //*******************
1508 void WriteTime(char* dst
, osc_time_t osctime
)
1510 *(int32_t*)dst
= htonl((int32_t)(osctime
>> 32));
1511 *(int32_t*)(dst
+4) = htonl((int32_t)osctime
);
1514 void WriteMode(char* dst
)
1516 *(int32_t*)dst
= htonl(0);
1519 osc_time_t
ReadTime(const char* src
)
1521 osc_time_t osctime
= ntohl(*(int32_t*)src
);
1522 return (osctime
<< 32) + ntohl(*(int32_t*)(src
+4));
1525 double TimeToSeconds(osc_time_t osctime
)
1527 return (double)osctime
* 2.3283064365386962890625e-10 /* 1/2^32 */;
1530 int timeRound(double x
)
1532 return x
>= 0.0 ? x
+0.5 : x
-0.5;
1535 void WriteLogicalTime(char* dst)
1537 static double startTime = -1.0;
1540 // Initialisierung der Startzeit.
1541 // Knnte effizienter (ohne 'if') auch irgendwo vorher passieren.
1542 // Knnte wahrscheinlich auch 0.0 sein.
1543 if (startTime < 0.0) {
1544 startTime = clock_getlogicaltime();
1547 sTime = clock_gettimesince(startTime) * 0.001;
1548 *(int32_t*)dst = hton'K l((int32_t)sTime);
1549 *(int32_t*)(dst+4) = htonl((int32_t)(4294967296.0 * sTime));
1553 void WriteLogicalTime(char* dst
)
1555 double sTime
= clock_gettimesince(19230720) / 1000.0;
1556 double tau
= sTime
- timeRound(sTime
);
1558 //fprintf(stderr, "sSec = %f tau = %f\n", sTime, tau);
1560 *(int32_t*)dst
= htonl((int32_t)(sTime
));
1561 *(int32_t*)(dst
+4) = htonl((int32_t)(4294967296 * tau
));
1564 Boolean
dumpOSC_SendReply(char *buf
, int n
, void *clientDesc
, int clientDescLenght
, int fd
)
1566 if((n
== 24) && (strcmp(buf
, "#time") == 0))
1568 osc_time_t t0
, t1
, t2
;
1569 double dt0
, dt1
, dt2
;
1573 t0
= ReadTime(buf
+8);
1575 WriteLogicalTime(buf
+16);
1576 t1
= ReadTime(buf
+16); // reverse
1577 dt0
= TimeToSeconds(t0
); // client time
1578 dt1
= TimeToSeconds(t1
); // server time
1580 // fprintf(stderr, "%f\t%f\t%f\n", dt0, dt1, dt0 - dt1);
1582 sendto(fd
, buf
, n
, 0, (struct sockaddr
*)clientDesc
, clientDescLenght
);
1591 //**********************
1593 void dumpOSC_ParsePacket(t_dumpOSC
*x
, char *buf
, int n
, ClientAddr returnAddr
) {
1595 int size
, messageLen
, i
;
1601 //PrintClientAddr(returnAddr);
1606 complain("SynthControl packet size (%d) not a multiple of 4 bytes: dropping", n
);
1610 if ((n
>= 8) && (strncmp(buf
, "#bundle", 8) == 0)) {
1611 /* This is a bundle message. */
1613 printf("dumpOSC_ParsePacket: bundle msg: bundles not yet supported\n");
1617 complain("Bundle message too small (%d bytes) for time tag", n
);
1621 /* Print the time tag */
1623 printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf
+8))), ntohl(*((unsigned long *)(buf
+12))));
1626 /* Note: if we wanted to actually use the time tag as a little-endian
1627 64-bit int, we'd have to word-swap the two 32-bit halves of it */
1629 i
= 16; /* Skip "#group\0" and time tag */
1632 size
= ntohl(*((int *) (buf
+ i
)));
1633 if ((size
% 4) != 0) {
1634 complain("Bad size count %d in bundle (not a multiple of 4)", size
);
1637 if ((size
+ i
+ 4) > n
) {
1638 complain("Bad size count %d in bundle (only %d bytes left in entire bundle)",
1643 /* Recursively handle element of bundle */
1644 dumpOSC_ParsePacket(x
, buf
+i
+4, size
, returnAddr
);
1649 complain("This can't happen");
1656 else if ((n
== 24) && (strcmp(buf
, "#time") == 0))
1658 complain("Time message: %s\n :).\n", htm_error_string
);
1664 /* This is not a bundle message */
1667 args
= DataAfterAlignedString(messageName
, buf
+n
);
1669 complain("Bad message name string: %s\nDropping entire message.\n",
1673 messageLen
= args
-messageName
;
1674 dumpOSC_Smessage(x
, messageName
, (void *)args
, n
-messageLen
, returnAddr
);
1678 #define SMALLEST_POSITIVE_FLOAT 0.000001f
1680 static void dumpOSC_Smessage(t_dumpOSC
*x
, char *address
, void *v
, int n
, ClientAddr returnAddr
) {
1683 //t_atom myargv[50];
1685 int myargc
= x
->x_outatc
;
1686 t_atom
* mya
= x
->x_outat
;
1690 printf("%s ", address
);
1693 // ztoln+cvt from envgen.c, ggee-0.18 ..
1694 // outlet_anything's 'symbol' gets set to address
1695 // so we dont need to append address to the atomlist
1697 SETSYMBOL(mya,gensym(address));myargc++;
1698 x->x_outatc = myargc;
1702 if (chars
[0] == ',') {
1703 if (chars
[1] != ',') {
1704 /* This message begins with a type-tag string */
1705 dumpOSC_PrintTypeTaggedArgs(x
, v
, n
);
1707 /* Double comma means an escaped real comma, not a type string */
1708 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x
, v
, n
, 1);
1711 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x
, v
, n
, 0);
1715 outlet_anything(x
->x_msgout
,gensym(address
),x
->x_outatc
,(t_atom
*)&x
->x_outat
);
1720 fflush(stdout
); /* Added for Sami 5/21/98 */
1723 static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC
*x
, void *v
, int n
) {
1724 char *typeTags
, *thisType
;
1727 int myargc
= x
->x_outatc
;
1728 t_atom
* mya
= x
->x_outat
;
1733 if (!IsNiceString(typeTags
, typeTags
+n
)) {
1734 /* No null-termination, so maybe it wasn't a type tag
1736 dumpOSC_PrintHeuristicallyTypeGuessedArgs(x
, v
, n
, 0);
1740 p
= DataAfterAlignedString(typeTags
, typeTags
+n
);
1743 for (thisType
= typeTags
+ 1; *thisType
!= 0; ++thisType
) {
1744 switch (*thisType
) {
1745 case 'i': case 'r': case 'm': case 'c':
1747 //post("integer: %d", ntohl(*((int *) p)));
1749 /* Martin Peach fix for negative floats:
1750 * was: SETFLOAT(mya+myargc,ntohl(*((int *) p)));
1753 SETFLOAT(mya
+myargc
,(signed)ntohl(*((int *) p
)));
1760 int i
= ntohl(*((int *) p
));
1761 float *floatp
= ((float *) (&i
));
1763 post("float: %f", *floatp
);
1765 SETFLOAT(mya
+myargc
,*floatp
);
1774 printf("[A 64-bit int] ");
1776 post("[A 64-bit int] not implemented");
1783 printf("[A 64-bit float] ");
1785 post("[A 64-bit float] not implemented");
1791 if (!IsNiceString(p
, typeTags
+n
)) {
1792 post("Type tag said this arg is a string but it's not!\n");
1796 post("string: \"%s\"", p
);
1798 SETSYMBOL(mya
+myargc
,gensym(p
));
1800 //outlet_list(x->x_msgout, 0,sizeof(p), p);
1801 //outlet_anything(x->x_msgout, 0, sizeof(p), p);
1802 p
= DataAfterAlignedString(p
, typeTags
+n
);
1803 // append to output vector ..
1811 SETFLOAT(mya
+myargc
,1.);
1818 SETFLOAT(mya
+myargc
,0.);
1825 post("sendOSC: [Nil] not implemented");
1829 printf("[Infinitum]");
1831 post("sendOSC: [Infinitum] not implemented");
1835 post("sendOSC: [Unrecognized type tag %c]", *thisType
);
1839 x
->x_outatc
= myargc
;
1842 static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC
*x
, void *v
, int n
, int skipComma
) {
1847 char *string
, *nextString
;
1849 int myargc
= x
->x_outatc
;
1850 t_atom
* mya
= x
->x_outat
;
1854 /* Go through the arguments 32 bits at a time */
1858 for (i
= 0; i
<n
/4; ) {
1859 string
= &chars
[i
*4];
1860 thisi
= ntohl(ints
[i
]);
1861 /* Reinterpret the (potentially byte-reversed) thisi as a float */
1862 thisf
= *(((float *) (&thisi
)));
1864 if (thisi
>= -1000 && thisi
<= 1000000) {
1866 printf("%d ", thisi
);
1868 // append to output vector ..
1869 SETFLOAT(mya
+myargc
,(t_float
) (thisi
));
1871 // outlet_float(x->x_msgout, thisi);
1873 } else if (thisf
>= -1000.f
&& thisf
<= 1000000.f
&&
1874 (thisf
<=0.0f
|| thisf
>= SMALLEST_POSITIVE_FLOAT
)) {
1876 printf("%f ", thisf
);
1878 // append to output vector ..
1879 SETFLOAT(mya
+myargc
,thisf
);
1881 //outlet_float(x->x_msgout, thisf);
1883 } else if (IsNiceString(string
, chars
+n
)) {
1884 nextString
= DataAfterAlignedString(string
, chars
+n
);
1886 printf("\"%s\" ", (i
== 0 && skipComma
) ? string
+1 : string
);
1888 // append to output vector ..
1889 SETSYMBOL(mya
+myargc
,gensym(string
));
1891 //outlet_symbol(x->x_msgout, gensym((i == 0 && skipComma) ? string +1 : string));
1892 i
+= (nextString
-string
) / 4;
1896 printf("0x%x xx", ints
[i
]);
1900 x
->x_outatc
= myargc
;
1905 #define STRING_ALIGN_PAD 4
1907 char *DataAfterAlignedString(char *string
, char *boundary
)
1909 /* The argument is a block of data beginning with a string. The
1910 string has (presumably) been padded with extra null characters
1911 so that the overall length is a multiple of STRING_ALIGN_PAD
1912 bytes. Return a pointer to the next byte after the null
1913 byte(s). The boundary argument points to the character after
1914 the last valid character in the buffer---if the string hasn't
1915 ended by there, something's wrong.
1917 If the data looks wrong, return 0, and set htm_error_string */
1921 if ((boundary
- string
) %4 != 0) {
1922 fprintf(stderr
, "Internal error: DataAfterAlignedString: bad boundary\n");
1926 for (i
= 0; string
[i
] != '\0'; i
++) {
1927 if (string
+ i
>= boundary
) {
1928 htm_error_string
= "DataAfterAlignedString: Unreasonably long string";
1933 /* Now string[i] is the first null character */
1936 for (; (i
% STRING_ALIGN_PAD
) != 0; i
++) {
1937 if (string
+ i
>= boundary
) {
1938 htm_error_string
= "DataAfterAlignedString: Unreasonably long string";
1941 if (string
[i
] != '\0') {
1942 htm_error_string
= "DataAfterAlignedString: Incorrectly padded string.";
1950 Boolean
IsNiceString(char *string
, char *boundary
)
1952 /* Arguments same as DataAfterAlignedString(). Is the given "string"
1953 really a string? I.e., is it a sequence of isprint() characters
1954 terminated with 1-4 null characters to align on a 4-byte boundary? */
1958 if ((boundary
- string
) %4 != 0) {
1959 fprintf(stderr
, "Internal error: IsNiceString: bad boundary\n");
1963 for (i
= 0; string
[i
] != '\0'; i
++) {
1964 if (!isprint(string
[i
])) return FALSE
;
1965 if (string
+ i
>= boundary
) return FALSE
;
1968 /* If we made it this far, it's a null-terminated sequence of printing characters
1969 in the given boundary. Now we just make sure it's null padded... */
1971 /* Now string[i] is the first null character */
1973 for (; (i
% STRING_ALIGN_PAD
) != 0; i
++) {
1974 if (string
[i
] != '\0') return FALSE
;
1989 void complain(char *s
, ...) {
1992 fprintf(stderr
, "*** ERROR: ");
1993 vfprintf(stderr
, s
, ap
);
1994 fprintf(stderr
, "\n");
1998 #endif /* __sgi or LINUX or WIN32 */