aboutsummaryrefslogtreecommitdiff
path: root/send+dump
diff options
context:
space:
mode:
Diffstat (limited to 'send+dump')
-rw-r--r--send+dump/Makefile25
-rw-r--r--send+dump/dumpOSC.c716
-rw-r--r--send+dump/dumpUDP.c191
-rw-r--r--send+dump/htmsocket.c230
-rw-r--r--send+dump/htmsocket.h49
-rw-r--r--send+dump/sendOSC.c600
6 files changed, 1811 insertions, 0 deletions
diff --git a/send+dump/Makefile b/send+dump/Makefile
new file mode 100644
index 0000000..7b14a43
--- /dev/null
+++ b/send+dump/Makefile
@@ -0,0 +1,25 @@
+LIBOSCDIR = ../libOSC
+LIBOSC = ${LIBOSCDIR}/libOSC.a
+CFLAGS= -O2 -I$(LIBOSCDIR)
+
+DUMPOBJS=dumpOSC.o
+
+
+both: sendOSC dumpOSC
+
+sendOSC: sendOSC.o htmsocket.o ${LIBOSC}
+ ${CC} -o sendOSC sendOSC.o htmsocket.o ${LIBOSC}
+
+dumpOSC: ${DUMPOBJS}
+ ${CC} -o $@ ${DUMPOBJS}
+
+dumpUDP: dumpUDP.o
+ ${CC} -o dumpUDP dumpUDP.o
+
+${LIBOSC}:
+ echo "You need to go to " ${LIBOSCDIR} " and do a make."
+
+clean:
+ rm -f sendOSC dumpOSC *.o
+
+
diff --git a/send+dump/dumpOSC.c b/send+dump/dumpOSC.c
new file mode 100644
index 0000000..143a994
--- /dev/null
+++ b/send+dump/dumpOSC.c
@@ -0,0 +1,716 @@
+/*
+Copyright (c) 1992,1993,1994,1995,1996,1997,2000.
+The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright and Adrian Freed, The Center for New Music and Audio
+Technologies, University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+ /*
+
+ dumpOSC.c
+ server that displays OpenSoundControl messages sent to it
+ for debugging client udp and UNIX protocol
+
+ by Matt Wright, 6/3/97
+ modified from dumpSC.c, by Matt Wright and Adrian Freed
+
+ version 0.2: Added "-silent" option a.k.a. "-quiet"
+
+ version 0.3: Incorporated patches from Nicola Bernardini to make
+ things Linux-friendly. Also added ntohl() in the right places
+ to support little-endian architectures.
+
+
+
+ compile:
+ cc -o dumpOSC dumpOSC.c
+
+ to-do:
+
+ More robustness in saying exactly what's wrong with ill-formed
+ messages. (If they don't make sense, show exactly what was
+ received.)
+
+ Time-based features: print time-received for each packet
+
+ Clean up to separate OSC parsing code from socket/select stuff
+
+*/
+
+
+#if defined(__sgi) || defined(__linux)
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/times.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <grp.h>
+#include <sys/file.h>
+#include <sys/prctl.h>
+
+#ifdef NEED_SCHEDCTL_AND_LOCK
+#include <sys/schedctl.h>
+#include <sys/lock.h>
+#endif
+
+
+char *htm_error_string;
+typedef int Boolean;
+typedef void *OBJ;
+
+typedef struct ClientAddressStruct {
+ struct sockaddr_in cl_addr;
+ int clilen;
+ int sockfd;
+} *ClientAddr;
+
+Boolean ShowBytes = FALSE;
+Boolean Silent = FALSE;
+
+/* Declarations */
+static int unixinitudp(int chan);
+static int initudp(int chan);
+static void closeudp(int sockfd);
+Boolean ClientReply(int packetsize, void *packet, int socketfd,
+ void *clientaddresspointer, int clientaddressbufferlength);
+void sgi_CleanExit(void);
+Boolean sgi_HaveToQuit(void);
+int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy);
+static void catch_sigint();
+static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) ;
+void ParseOSCPacket(char *buf, int n, ClientAddr returnAddr);
+static void Smessage(char *address, void *v, int n, ClientAddr returnAddr);
+static void PrintTypeTaggedArgs(void *v, int n);
+static void PrintHeuristicallyTypeGuessedArgs(void *v, int n, int skipComma);
+char *DataAfterAlignedString(char *string, char *boundary) ;
+Boolean IsNiceString(char *string, char *boundary) ;
+void complain(char *s, ...);
+
+
+#define UNIXDG_PATH "/tmp/htm"
+#define UNIXDG_TMP "/tmp/htm.XXXXXX"
+static int unixinitudp(int chan)
+{
+ struct sockaddr_un serv_addr;
+ int sockfd;
+
+ if((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
+ return sockfd;
+
+ bzero((char *)&serv_addr, sizeof(serv_addr));
+ serv_addr.sun_family = AF_UNIX;
+ strcpy(serv_addr.sun_path, UNIXDG_PATH);
+ sprintf(serv_addr.sun_path+strlen(serv_addr.sun_path), "%d", chan);
+ unlink(serv_addr.sun_path);
+ if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr.sun_family)+strlen(serv_addr.sun_path)) < 0)
+ {
+ perror("unable to bind\n");
+ return -1;
+ }
+
+ fcntl(sockfd, F_SETFL, FNDELAY);
+ return sockfd;
+}
+
+static int initudp(int chan)
+{
+ struct sockaddr_in serv_addr;
+ int sockfd;
+
+ if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return sockfd;
+ bzero((char *)&serv_addr, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serv_addr.sin_port = htons(chan);
+
+ if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
+ {
+ perror("unable to bind\n");
+ return -1;
+ }
+
+ fcntl(sockfd, F_SETFL, FNDELAY);
+ return sockfd;
+}
+
+static void closeudp(int sockfd) {
+ close(sockfd);
+}
+
+static Boolean catchupflag=FALSE;
+Boolean ClientReply(int packetsize, void *packet, int socketfd,
+ void *clientaddresspointer, int clientaddressbufferlength)
+{
+ if(!clientaddresspointer) return FALSE;
+ catchupflag= TRUE;
+ return packetsize==sendto(socketfd, packet, packetsize, 0, clientaddresspointer, clientaddressbufferlength);
+}
+
+static Boolean exitflag= FALSE;
+void sgi_CleanExit(void) {
+ exitflag = TRUE;
+}
+
+Boolean sgi_HaveToQuit(void) {
+ return exitflag;
+}
+
+
+/* file descriptor poll table */
+static int npolldevs =0;
+typedef struct polldev
+{
+ int fd;
+ void (*callbackfunction)(int , void *);
+ void *dummy;
+} polldev;
+#define TABMAX 8
+static polldev polldevs[TABMAX];
+
+
+/* Register a device (referred to by a file descriptor that the caller
+ should have already successfully obtained from a system call) to be
+ polled as real-time constraints allowed.
+
+ When a select(2) call indicates activity on the file descriptor, the
+ callback function is called with the file descripter as first
+ argument and the given dummy argument (presumably a pointer to the
+ instance variables associated with the device).
+*/
+int RegisterPollingDevice(int fd, void (*callbackfunction)(int , void *), void *dummy)
+{
+ if(npolldevs<TABMAX)
+ {
+ polldevs[npolldevs].fd = fd;
+ polldevs[npolldevs].callbackfunction = callbackfunction;
+ polldevs[npolldevs].dummy = dummy;
+ }
+ else return -1;
+ return npolldevs++;
+}
+
+static int caught_sigint;
+
+static void catch_sigint() {
+ caught_sigint = 1;
+}
+static int sockfd, usockfd;
+
+
+
+static int Synthmessage(char *m, int n, void *clientdesc, int clientdesclength, int fd) {
+ struct ClientAddressStruct ras;
+ ClientAddr ra = &ras;
+
+ catchupflag= FALSE;
+
+ ras.cl_addr = *((struct sockaddr_in *) clientdesc);
+ ras.clilen = clientdesclength;
+ ras.sockfd = fd;
+
+ if (ShowBytes) {
+ int i;
+ printf("%d byte message:\n", n);
+ for (i = 0; i < n; ++i) {
+ printf(" %x (%c)\t", m[i], m[i]);
+ if (i%4 == 3) printf("\n");
+ }
+ printf("\n");
+ }
+
+ ParseOSCPacket(m, n, ra);
+ return catchupflag;
+}
+
+void PrintClientAddr(ClientAddr CA) {
+ unsigned long addr = CA->cl_addr.sin_addr.s_addr;
+ printf("Client address %p:\n", CA);
+ printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd);
+ printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family,
+ CA->cl_addr.sin_port);
+ printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr));
+
+ printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n",
+ CA->cl_addr.sin_zero[0],
+ CA->cl_addr.sin_zero[1],
+ CA->cl_addr.sin_zero[2],
+ CA->cl_addr.sin_zero[3],
+ CA->cl_addr.sin_zero[4],
+ CA->cl_addr.sin_zero[5],
+ CA->cl_addr.sin_zero[6],
+ CA->cl_addr.sin_zero[7]);
+
+ printf("\n");
+}
+
+
+void ParseOSCPacket(char *buf, int n, ClientAddr returnAddr) {
+ int size, messageLen, i;
+ char *messageName;
+ char *args;
+
+#ifdef PRINTADDRS
+ PrintClientAddr(returnAddr);
+#endif
+
+
+ if ((n%4) != 0) {
+ complain("SynthControl packet size (%d) not a multiple of 4 bytes: dropping",
+ n);
+ return;
+ }
+
+ if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) {
+ /* This is a bundle message. */
+
+ if (n < 16) {
+ complain("Bundle message too small (%d bytes) for time tag", n);
+ return;
+ }
+
+ /* Print the time tag */
+ printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf+8))),
+ ntohl(*((unsigned long *)(buf+12))));
+ /* Note: if we wanted to actually use the time tag as a little-endian
+ 64-bit int, we'd have to word-swap the two 32-bit halves of it */
+
+ i = 16; /* Skip "#group\0" and time tag */
+ while(i<n) {
+ size = ntohl(*((int *) (buf + i)));
+ if ((size % 4) != 0) {
+ complain("Bad size count %d in bundle (not a multiple of 4)", size);
+ return;
+ }
+ if ((size + i + 4) > n) {
+ complain("Bad size count %d in bundle (only %d bytes left in entire bundle)",
+ size, n-i-4);
+ return;
+ }
+
+ /* Recursively handle element of bundle */
+ ParseOSCPacket(buf+i+4, size, returnAddr);
+ i += 4 + size;
+ }
+ if (i != n) {
+ complain("This can't happen");
+ }
+ printf("]\n");
+ } else {
+ /* This is not a bundle message */
+
+ messageName = buf;
+ args = DataAfterAlignedString(messageName, buf+n);
+ if (args == 0) {
+ complain("Bad message name string: %s\nDropping entire message.\n",
+ htm_error_string);
+ return;
+ }
+ messageLen = args-messageName;
+ Smessage(messageName, (void *)args, n-messageLen, returnAddr);
+ }
+}
+
+#define SMALLEST_POSITIVE_FLOAT 0.000001f
+
+static void Smessage(char *address, void *v, int n, ClientAddr returnAddr) {
+ char *chars = v;
+
+ printf("%s ", address);
+
+ if (n != 0) {
+ if (chars[0] == ',') {
+ if (chars[1] != ',') {
+ /* This message begins with a type-tag string */
+ PrintTypeTaggedArgs(v, n);
+ } else {
+ /* Double comma means an escaped real comma, not a type string */
+ PrintHeuristicallyTypeGuessedArgs(v, n, 1);
+ }
+ } else {
+ PrintHeuristicallyTypeGuessedArgs(v, n, 0);
+ }
+ }
+
+ printf("\n");
+ fflush(stdout); /* Added for Sami 5/21/98 */
+}
+
+static void PrintTypeTaggedArgs(void *v, int n) {
+ char *typeTags, *thisType;
+ char *p;
+
+ typeTags = v;
+
+ if (!IsNiceString(typeTags, typeTags+n)) {
+ /* No null-termination, so maybe it wasn't a type tag
+ string after all */
+ PrintHeuristicallyTypeGuessedArgs(v, n, 0);
+ return;
+ }
+
+ p = DataAfterAlignedString(typeTags, typeTags+n);
+
+
+ for (thisType = typeTags + 1; *thisType != 0; ++thisType) {
+ switch (*thisType) {
+ case 'i': case 'r': case 'm': case 'c':
+ printf("%d ", ntohl(*((int *) p)));
+ p += 4;
+ break;
+
+ case 'f': {
+ int i = ntohl(*((int *) p));
+ float *floatp = ((float *) (&i));
+ printf("%f ", *floatp);
+ p += 4;
+ }
+ break;
+
+ case 'h': case 't':
+ printf("[A 64-bit int] ");
+ p += 8;
+ break;
+
+ case 'd':
+ printf("[A 64-bit float] ");
+ p += 8;
+ break;
+
+ case 's': case 'S':
+ if (!IsNiceString(p, typeTags+n)) {
+ printf("Type tag said this arg is a string but it's not!\n");
+ return;
+ } else {
+ printf("\"%s\" ", p);
+ p = DataAfterAlignedString(p, typeTags+n);
+ }
+ break;
+
+ case 'T': printf("[True] "); break;
+ case 'F': printf("[False] "); break;
+ case 'N': printf("[Nil]"); break;
+ case 'I': printf("[Infinitum]"); break;
+
+ default:
+ printf("[Unrecognized type tag %c]", *thisType);
+ return;
+ }
+ }
+}
+
+static void PrintHeuristicallyTypeGuessedArgs(void *v, int n, int skipComma) {
+ int i, thisi;
+ float thisf;
+ int *ints;
+ char *chars;
+ char *string, *nextString;
+
+
+ /* Go through the arguments 32 bits at a time */
+ ints = v;
+ chars = v;
+
+ for (i = 0; i<n/4; ) {
+ string = &chars[i*4];
+ thisi = ntohl(ints[i]);
+ /* Reinterpret the (potentially byte-reversed) thisi as a float */
+ thisf = *(((float *) (&thisi)));
+
+ if (thisi >= -1000 && thisi <= 1000000) {
+ printf("%d ", thisi);
+ i++;
+ } else if (thisf >= -1000.f && thisf <= 1000000.f &&
+ (thisf <=0.0f || thisf >= SMALLEST_POSITIVE_FLOAT)) {
+ printf("%f ", thisf);
+ i++;
+ } else if (IsNiceString(string, chars+n)) {
+ nextString = DataAfterAlignedString(string, chars+n);
+ printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string);
+ i += (nextString-string) / 4;
+ } else {
+ printf("0x%x ", ints[i]);
+ i++;
+ }
+ }
+}
+
+
+#define STRING_ALIGN_PAD 4
+
+char *DataAfterAlignedString(char *string, char *boundary)
+{
+ /* The argument is a block of data beginning with a string. The
+ string has (presumably) been padded with extra null characters
+ so that the overall length is a multiple of STRING_ALIGN_PAD
+ bytes. Return a pointer to the next byte after the null
+ byte(s). The boundary argument points to the character after
+ the last valid character in the buffer---if the string hasn't
+ ended by there, something's wrong.
+
+ If the data looks wrong, return 0, and set htm_error_string */
+
+ int i;
+
+ if ((boundary - string) %4 != 0) {
+ fprintf(stderr, "Internal error: DataAfterAlignedString: bad boundary\n");
+ return 0;
+ }
+
+ for (i = 0; string[i] != '\0'; i++) {
+ if (string + i >= boundary) {
+ htm_error_string = "DataAfterAlignedString: Unreasonably long string";
+ return 0;
+ }
+ }
+
+ /* Now string[i] is the first null character */
+ i++;
+
+ for (; (i % STRING_ALIGN_PAD) != 0; i++) {
+ if (string + i >= boundary) {
+ htm_error_string = "DataAfterAlignedString: Unreasonably long string";
+ return 0;
+ }
+ if (string[i] != '\0') {
+ htm_error_string = "DataAfterAlignedString: Incorrectly padded string.";
+ return 0;
+ }
+ }
+
+ return string+i;
+}
+
+Boolean IsNiceString(char *string, char *boundary)
+{
+ /* Arguments same as DataAfterAlignedString(). Is the given "string"
+ really a string? I.e., is it a sequence of isprint() characters
+ terminated with 1-4 null characters to align on a 4-byte boundary? */
+
+ int i;
+
+ if ((boundary - string) %4 != 0) {
+ fprintf(stderr, "Internal error: IsNiceString: bad boundary\n");
+ return 0;
+ }
+
+ for (i = 0; string[i] != '\0'; i++) {
+ if (!isprint(string[i])) return FALSE;
+ if (string + i >= boundary) return FALSE;
+ }
+
+ /* If we made it this far, it's a null-terminated sequence of printing characters
+ in the given boundary. Now we just make sure it's null padded... */
+
+ /* Now string[i] is the first null character */
+ i++;
+ for (; (i % STRING_ALIGN_PAD) != 0; i++) {
+ if (string[i] != '\0') return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+
+
+
+#define MAXMESG 32768
+static char mbuf[MAXMESG];
+
+int main(int argc, char **argv) {
+ int udp_port; /* port to receive parameter updates from */
+
+ struct sockaddr_in cl_addr;
+ int clilen,maxclilen=sizeof(cl_addr);
+ struct sockaddr_un ucl_addr;
+ int uclilen,umaxclilen=sizeof(ucl_addr);
+ int i,n;
+
+
+ clilen = maxclilen;
+ uclilen = umaxclilen;
+
+ udp_port = -1;
+ for (i=1; i < argc; ++i) {
+ if (strcmp(argv[i], "-showbytes") == 0) {
+ ShowBytes = TRUE;
+ } else if (strcmp(argv[i], "-silent") == 0 ||
+ strcmp(argv[i], "-quiet") == 0) {
+ Silent = TRUE;
+ } else if (udp_port != -1) {
+ goto usageError;
+ } else {
+ udp_port = atoi(argv[i]);
+ if (udp_port == 0) {
+ goto usageError;
+ }
+ }
+ }
+
+ if (udp_port == -1) {
+ usageError:
+ fprintf(stderr, "Usage\n\tdumpOSC portno [-showbytes] [-quiet]\n\t(responds to udp and UNIX packets on that port no)\n");
+ exit(1);
+ }
+
+
+ n = recvfrom(0, mbuf, MAXMESG, 0, &cl_addr, &clilen);
+ if(n>0)
+ {
+ sockfd = 0;
+ udp_port = -1;
+ Synthmessage(mbuf, n, &cl_addr, clilen,sockfd) ;
+ }
+ else
+ { sockfd=initudp(udp_port);
+ usockfd=unixinitudp(udp_port);
+ }
+
+ if (!Silent) {
+ printf("dumpOSC version 0.2 (6/18/97 Matt Wright). Unix/UDP Port %d \n", udp_port);
+ printf("Copyright (c) 1992,1996,1997 Regents of the University of California.\n");
+ }
+ if(sockfd>=0 && usockfd>=0)
+ {
+ fd_set read_fds, write_fds;
+ int nfds;
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+ nfds = max(sockfd, usockfd)+ 1;
+ {
+ int j;
+ for(j=0;j<npolldevs;++j)
+ if(polldevs[j].fd>=nfds)
+ {
+ nfds = polldevs[j].fd+1;
+/*
+printf("polldev %d\n", polldevs[j].fd);
+*/
+ }
+ }
+/*
+ printf("nfds %d\n", nfds);
+*/
+ caught_sigint = 0;
+ sigset(SIGINT, catch_sigint); /* set sig handler */
+
+ while(!caught_sigint)
+ {
+
+ int r;
+
+ back:
+
+ FD_ZERO(&read_fds); /* clear read_fds */
+ FD_ZERO(&write_fds); /* clear write_fds */
+ FD_SET(sockfd, &read_fds);
+ FD_SET(usockfd, &read_fds);
+ {
+ int j;
+
+ for(j=0;j<npolldevs;++j)
+ FD_SET(polldevs[j].fd, &read_fds);
+ }
+
+ r = select(nfds, &read_fds, &write_fds, (fd_set *)0,
+ (struct timeval *)0);
+ if (r < 0) /* select reported an error */
+ goto out;
+ {
+ int j;
+
+ for(j=0;j<npolldevs;++j)
+ if(FD_ISSET(polldevs[j].fd, &read_fds))
+ (*(polldevs[j].callbackfunction))(polldevs[j].fd,polldevs[j].dummy );
+ }
+ if(FD_ISSET(sockfd, &read_fds))
+ {
+ clilen = maxclilen;
+ while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &cl_addr, &clilen)) >0)
+ {
+ int r;
+ /* printf("received UDP packet of length %d\n", n); */
+ r = Synthmessage(mbuf, n, &cl_addr, clilen, sockfd) ;
+
+ if( sgi_HaveToQuit()) goto out;
+ if(r>0) goto back;
+ clilen = maxclilen;
+ }
+ }
+ if(FD_ISSET(usockfd, &read_fds))
+ {
+ uclilen = umaxclilen;
+ while( (n = recvfrom(usockfd, mbuf, MAXMESG, 0, &ucl_addr, &uclilen)) >0)
+ {
+ int r;
+ /* printf("received UNIX packet of length %d\n", n); */
+
+ r=Synthmessage(mbuf, n, &ucl_addr, uclilen,usockfd) ;
+
+ if( sgi_HaveToQuit()) goto out;
+ if(r>0) goto back;
+ uclilen = umaxclilen;
+ }
+ }
+ } /* End of while(!caught_sigint) */
+
+
+out: ;
+ }
+ else
+ perror("initudp");
+
+ return 0;
+}
+
+
+#include <stdarg.h>
+void complain(char *s, ...) {
+ va_list ap;
+ va_start(ap, s);
+ fprintf(stderr, "*** ERROR: ");
+ vfprintf(stderr, s, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+#endif /* __sgi or LINUX */
diff --git a/send+dump/dumpUDP.c b/send+dump/dumpUDP.c
new file mode 100644
index 0000000..3876812
--- /dev/null
+++ b/send+dump/dumpUDP.c
@@ -0,0 +1,191 @@
+/*
+Copyright (c) 1998. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+
+dumpUDP.c: smallest UDP receiving application
+by Matt Wright, 9/9/98
+
+*/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/times.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <grp.h>
+#include <sys/file.h>
+#include <bstring.h>
+#include <sys/prctl.h>
+#include <sys/schedctl.h>
+#include <sys/lock.h>
+
+
+typedef struct ClientAddressStruct {
+ struct sockaddr_in cl_addr;
+ int clilen;
+ int sockfd;
+} *ClientAddr;
+
+void PrintClientAddr(ClientAddr CA) {
+ unsigned long addr = CA->cl_addr.sin_addr.s_addr;
+ printf("Client address %p:\n", CA);
+ printf(" clilen %d, sockfd %d\n", CA->clilen, CA->sockfd);
+ printf(" sin_family %d, sin_port %d\n", CA->cl_addr.sin_family,
+ CA->cl_addr.sin_port);
+ printf(" address: (%x) %s\n", addr, inet_ntoa(CA->cl_addr.sin_addr));
+
+ printf(" sin_zero = \"%c%c%c%c%c%c%c%c\"\n",
+ CA->cl_addr.sin_zero[0],
+ CA->cl_addr.sin_zero[1],
+ CA->cl_addr.sin_zero[2],
+ CA->cl_addr.sin_zero[3],
+ CA->cl_addr.sin_zero[4],
+ CA->cl_addr.sin_zero[5],
+ CA->cl_addr.sin_zero[6],
+ CA->cl_addr.sin_zero[7]);
+
+ printf("\n");
+}
+
+
+static int initudp(int port) {
+ struct sockaddr_in serv_addr;
+ int n, sockfd;
+
+ if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return sockfd;
+ bzero((char *)&serv_addr, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serv_addr.sin_port = htons(port);
+
+ if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
+ {
+ perror("unable to bind\n");
+ return -1;
+ }
+
+ fcntl(sockfd, F_SETFL, FNDELAY);
+ return sockfd;
+}
+
+
+static void closeudp(int sockfd) {
+ close(sockfd);
+}
+
+
+static int time_to_quit;
+
+static void catch_sigint() {
+ time_to_quit = 1;
+}
+
+void GotAPacket(char *buf, int n, ClientAddr returnAddr) {
+ printf("received UDP packet of length %d\n", n);
+ PrintClientAddr(returnAddr);
+}
+
+#define MAXMESG 32768
+static char mbuf[MAXMESG];
+
+void ReceivePacket(int sockfd) {
+ struct ClientAddressStruct returnAddress;
+ int maxclilen=sizeof(returnAddress.cl_addr);
+ int n;
+
+ returnAddress.clilen = maxclilen;
+ while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &(returnAddress.cl_addr),
+ &(returnAddress.clilen))) >0) {
+ GotAPacket(mbuf, n, &returnAddress);
+
+ if (time_to_quit) return;
+ returnAddress.clilen = maxclilen;
+ }
+}
+
+void main(int argc, char **argv) {
+ int udp_port; /* port to receive parameter updates from */
+ int sockfd;
+ int i;
+
+ fd_set read_fds, write_fds;
+ int nfds;
+
+ udp_port = 7000;
+
+ sockfd=initudp(udp_port);
+
+ if(sockfd<0) {
+ perror("initudp");
+ return;
+ }
+
+ nfds = sockfd + 1;
+
+ time_to_quit = 0;
+ sigset(SIGINT, catch_sigint); /* set sig handler */
+
+ while(!time_to_quit)
+ {
+
+ int c,r;
+
+ back:
+
+ FD_ZERO(&read_fds); /* clear read_fds */
+ FD_ZERO(&write_fds); /* clear write_fds */
+ FD_SET(sockfd, &read_fds);
+
+
+ r = select(nfds, &read_fds, &write_fds, (fd_set *)0,
+ (struct timeval *)0);
+ if (r < 0) /* select reported an error */
+ goto out;
+
+ if(FD_ISSET(sockfd, &read_fds)) {
+ ReceivePacket(sockfd);
+ }
+
+ } /* End of while(!time_to_quit) */
+out: ;
+}
diff --git a/send+dump/htmsocket.c b/send+dump/htmsocket.c
new file mode 100644
index 0000000..e4f447f
--- /dev/null
+++ b/send+dump/htmsocket.c
@@ -0,0 +1,230 @@
+/*
+Copyright (c) 1992,1996,1998.
+The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Adrian Freed, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+ /* htmsocket.c
+
+ Adrian Freed
+ send parameters to htm servers by udp or UNIX protocol
+
+ Modified 6/6/96 by Matt Wright to understand symbolic host names
+ in addition to X.X.X.X addresses.
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/times.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <ctype.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <grp.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+
+#include <stdlib.h>
+
+#define UNIXDG_PATH "/tmp/htm"
+#define UNIXDG_TMP "/tmp/htm.XXXXXX"
+#include "htmsocket.h"
+typedef struct
+{
+ float srate;
+
+ struct sockaddr_in serv_addr; /* udp socket */
+ struct sockaddr_un userv_addr; /* UNIX socket */
+ int sockfd; /* socket file descriptor */
+ int index, len,uservlen;
+ void *addr;
+ int id;
+} desc;
+
+/* open a socket for HTM communication to given host on given portnumber */
+/* if host is 0 then UNIX protocol is used (i.e. local communication */
+void *OpenHTMSocket(char *host, int portnumber)
+{
+ int sockfd;
+ struct sockaddr_in cl_addr;
+ struct sockaddr_un ucl_addr;
+ desc *o;
+ o = malloc(sizeof(*o));
+ if(!o)
+ return 0;
+ if(!host)
+ {
+ char *mktemp(char *);
+ int clilen;
+ o->len = sizeof(ucl_addr);
+ /*
+ * Fill in the structure "userv_addr" with the address of the
+ * server that we want to send to.
+ */
+
+ bzero((char *) &o->userv_addr, sizeof(o->userv_addr));
+ o->userv_addr.sun_family = AF_UNIX;
+ strcpy(o->userv_addr.sun_path, UNIXDG_PATH);
+ sprintf(o->userv_addr.sun_path+strlen(o->userv_addr.sun_path), "%d", portnumber);
+ o->uservlen = sizeof(o->userv_addr.sun_family) + strlen(o->userv_addr.sun_path);
+ o->addr = &(o->userv_addr);
+ /*
+ * Open a socket (a UNIX domain datagram socket).
+ */
+
+ if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0)
+ {
+ /*
+ * Bind a local address for us.
+ * In the UNIX domain we have to choose our own name (that
+ * should be unique). We'll use mktemp() to create a unique
+ * pathname, based on our process id.
+ */
+
+ bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */
+ ucl_addr.sun_family = AF_UNIX;
+ strcpy(ucl_addr.sun_path, UNIXDG_TMP);
+
+ mktemp(ucl_addr.sun_path);
+ clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path);
+
+ if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0)
+ {
+ perror("client: can't bind local address");
+ close(sockfd);
+ sockfd = -1;
+ }
+ }
+ else
+ perror("unable to make socket\n");
+
+ }else
+ {
+ /*
+ * Fill in the structure "serv_addr" with the address of the
+ * server that we want to send to.
+ */
+ o->len = sizeof(cl_addr);
+ bzero((char *)&o->serv_addr, sizeof(o->serv_addr));
+ o->serv_addr.sin_family = AF_INET;
+
+ /* MW 6/6/96: Call gethostbyname() instead of inet_addr(),
+ so that host can be either an Internet host name (e.g.,
+ "les") or an Internet address in standard dot notation
+ (e.g., "128.32.122.13") */
+ {
+ struct hostent *hostsEntry;
+ unsigned long address;
+
+ hostsEntry = gethostbyname(host);
+ if (hostsEntry == NULL) {
+ fprintf(stderr, "Couldn't decipher host name \"%s\"\n",
+ host);
+ herror(NULL);
+ return 0;
+ }
+
+ address = *((unsigned long *) hostsEntry->h_addr_list[0]);
+ o->serv_addr.sin_addr.s_addr = address;
+ }
+
+ /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */
+
+ /* End MW changes */
+
+ o->serv_addr.sin_port = htons(portnumber);
+ o->addr = &(o->serv_addr);
+ /*
+ * Open a socket (a UDP domain datagram socket).
+ */
+ if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0)
+ {
+ bzero((char *)&cl_addr, sizeof(cl_addr));
+ cl_addr.sin_family = AF_INET;
+ cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ cl_addr.sin_port = htons(0);
+
+ if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0)
+ {
+ perror("could not bind\n");
+ close(sockfd);
+ sockfd = -1;
+ }
+ }
+ else
+ {
+ perror("unable to make socket\n");
+ }
+
+ }
+ if(sockfd<0)
+ {
+ free(o); o = 0;
+ }
+ else
+ o->sockfd = sockfd;
+ return o;
+}
+#include <errno.h>
+
+static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b)
+{
+ int rcount;
+ if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count)
+ {
+/* printf("sockfd %d count %d rcount %dlength %d errno %d\n", sockfd,count,rcount,length,
+ errno); */
+ return FALSE;
+ }
+ return TRUE;
+}
+bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer)
+{
+ desc *o = (desc *)htmsendhandle;
+ return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer);
+}
+void CloseHTMSocket(void *htmsendhandle)
+{
+ desc *o = (desc *)htmsendhandle;
+ close(o->sockfd);
+ free(o);
+}
diff --git a/send+dump/htmsocket.h b/send+dump/htmsocket.h
new file mode 100644
index 0000000..b035b57
--- /dev/null
+++ b/send+dump/htmsocket.h
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 1992,1996. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Adrian Freed, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+ /* htmparam.h
+
+ Adrian Freed
+ send parameters to htm servers by udp or UNIX protocol
+ */
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+typedef int bool;
+
+/* open a socket for HTM communication to given host on given portnumber */
+/* if host is 0 then UNIX protocol is used (i.e. local communication) */
+void *OpenHTMSocket(char *host, int portnumber);
+
+/* send a buffer of data over htm socket, returns TRUE on success.
+ Note that udp sends rarely fail. UNIX sends fail if a kernal buffer overflows */
+bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer);
+
+/* close the socket(2) and release memory associated with it */
+void CloseHTMSocket(void *htmsendhandle);
diff --git a/send+dump/sendOSC.c b/send+dump/sendOSC.c
new file mode 100644
index 0000000..db188dd
--- /dev/null
+++ b/send+dump/sendOSC.c
@@ -0,0 +1,600 @@
+/*
+Copyright (c) 1996,1997. The Regents of the University of California (Regents).
+All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for educational, research, and not-for-profit purposes, without
+fee and without a signed licensing agreement, is hereby granted, provided that
+the above copyright notice, this paragraph and the following two paragraphs
+appear in all copies, modifications, and distributions. Contact The Office of
+Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
+CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
+
+Written by Matt Wright, The Center for New Music and Audio Technologies,
+University of California, Berkeley.
+
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
+ DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
+ REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+/* sendOSC.c
+
+ Matt Wright, 6/3/97
+ based on sendSC.c, which was based on a version by Adrian Freed
+
+ Text-based OpenSoundControl client. User can enter messages via command
+ line arguments or standard input.
+
+ Version 0.1: "play" feature
+ Version 0.2: Message type tags.
+
+*/
+
+#define VERSION "http://cnmat.berkeley.edu/OpenSoundControl/sendOSC-0.1.html"
+
+/*
+compiling:
+ cc -o sendOSC sendOSC.c htmsocket.c OpenSoundControl.c OSC_timeTag.c
+*/
+
+
+#include "OSC-client.h"
+#include "htmsocket.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+/* #include <bstring.h> */
+#include <string.h>
+
+
+typedef struct {
+ enum {INT, FLOAT, STRING} type;
+ union {
+ int i;
+ float f;
+ char *s;
+ } datum;
+} typedArg;
+
+void CommandLineMode(int argc, char *argv[], void *htmsocket);
+void InteractiveMode(void *htmsocket);
+OSCTimeTag ParseTimeTag(char *s);
+void ParseInteractiveLine(OSCbuf *buf, char *mesg);
+typedArg ParseToken(char *token);
+int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args);
+void SendBuffer(void *htmsocket, OSCbuf *buf);
+void SendData(void *htmsocket, int size, char *data);
+void fatal_error(char *s);
+void complain(char *s, ...);
+
+/* Exit status codes:
+ 0: successful
+ 2: Message(s) dropped because of buffer overflow
+ 3: Socket error
+ 4: Usage error
+ 5: Internal error
+*/
+static int exitStatus = 0;
+
+
+static int useTypeTags = 1;
+
+main(int argc, char *argv[]) {
+ int portnumber;
+ char *hostname = 0;
+ void *htmsocket;
+
+ argc--;
+ argv++;
+
+ if (argc == 0) {
+ goto usageerror;
+ }
+
+ if (argc >= 1 && (strncmp(*argv, "-notypetags", 2) == 0)) {
+ useTypeTags = 0;
+ argv++;
+ argc--;
+ }
+
+ if (argc >= 2 && (strncmp(*argv, "-r", 2) == 0)) {
+ hostname = getenv("REMOTE_ADDR");
+ if (hostname == NULL) {
+ complain("sendSC -r: REMOTE_ADDR not in environment\n");
+ exit(4);
+ }
+ argv++;
+ argc--;
+ }
+
+ if (argc >= 3 && (strncmp(*argv, "-h", 2) == 0)) {
+ hostname = argv[1];
+ argv += 2;
+ argc -= 2;
+ }
+ portnumber = atoi(*argv);
+ argv++;
+ argc--;
+
+ htmsocket = OpenHTMSocket(hostname, portnumber);
+ if (!htmsocket) {
+ perror("Couldn't open socket: ");
+ exit(3);
+ }
+
+ if (argc > 0) {
+ printf("host %s, port %d, %s\n", hostname, portnumber,
+ useTypeTags ? "use type tags" : "don't use type tags");
+ CommandLineMode(argc, argv, htmsocket);
+ } else {
+ printf("sendOSC version " VERSION "\n");
+ printf("by Matt Wright. Copyright (c) 1996, 1997 Regents of the University of California.\n");
+ printf("host %s, port %d, %s\n", hostname, portnumber,
+ useTypeTags ? "use type tags" : "don't use type tags");
+ InteractiveMode(htmsocket);
+ }
+ CloseHTMSocket(htmsocket);
+ exit(exitStatus);
+
+
+ usageerror:
+ complain("usage: %s [-notypetags] [-r] [-h target_host_name] port_number [message...]\n",
+ argv[-1]);
+ exit(4);
+
+}
+
+
+#define MAX_ARGS 2000
+#define SC_BUFFER_SIZE 32000
+static char bufferForOSCbuf[SC_BUFFER_SIZE];
+
+void CommandLineMode(int argc, char *argv[], void *htmsocket) {
+ char *messageName;
+ char *token;
+ typedArg args[MAX_ARGS];
+ int i,j, numArgs;
+ OSCbuf buf[1];
+
+ OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
+
+ if (argc > 1) {
+ if (OSC_openBundle(buf, OSCTT_Immediately())) {
+ complain("Problem opening bundle: %s\n", OSC_errorMessage);
+ return;
+ }
+ }
+
+ for (i = 0; i < argc; i++) {
+ messageName = strtok(argv[i], ",");
+ if (messageName == NULL) {
+ break;
+ }
+
+ j = 0;
+ while ((token = strtok(NULL, ",")) != NULL) {
+ args[j] = ParseToken(token);
+ j++;
+ if (j >= MAX_ARGS) {
+ complain("Sorry; your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n",
+ MAX_ARGS);
+ break;
+ }
+ }
+ numArgs = j;
+
+ WriteMessage(buf, messageName, numArgs, args);
+ }
+
+ if (argc > 1) {
+ if (OSC_closeBundle(buf)) {
+ complain("Problem closing bundle: %s\n", OSC_errorMessage);
+ return;
+ }
+ }
+
+ SendBuffer(htmsocket, buf);
+}
+
+#define MAXMESG 2048
+
+void InteractiveMode(void *htmsocket) {
+ char mesg[MAXMESG];
+ OSCbuf buf[1];
+ int bundleDepth = 0; /* At first, we haven't seen "[". */
+
+ OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
+
+ while (fgets(mesg, MAXMESG, stdin) != NULL) {
+ if (mesg[0] == '\n') {
+ if (bundleDepth > 0) {
+ /* Ignore blank lines inside a group. */
+ } else {
+ /* blank line => repeat previous send */
+ SendBuffer(htmsocket, buf);
+ }
+ continue;
+ }
+
+ if (bundleDepth == 0) {
+ OSC_resetBuffer(buf);
+ }
+
+ if (mesg[0] == '[') {
+ OSCTimeTag tt = ParseTimeTag(mesg+1);
+ if (OSC_openBundle(buf, tt)) {
+ complain("Problem opening bundle: %s\n", OSC_errorMessage);
+ OSC_resetBuffer(buf);
+ bundleDepth = 0;
+ continue;
+ }
+ bundleDepth++;
+ } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') {
+ if (bundleDepth == 0) {
+ complain("Unexpected ']': not currently in a bundle.\n");
+ } else {
+ if (OSC_closeBundle(buf)) {
+ complain("Problem closing bundle: %s\n", OSC_errorMessage);
+ OSC_resetBuffer(buf);
+ bundleDepth = 0;
+ continue;
+ }
+
+ bundleDepth--;
+ if (bundleDepth == 0) {
+ SendBuffer(htmsocket, buf);
+ }
+ }
+ } else {
+ ParseInteractiveLine(buf, mesg);
+ if (bundleDepth != 0) {
+ /* Don't send anything until we close all bundles */
+ } else {
+ SendBuffer(htmsocket, buf);
+ }
+ }
+ }
+}
+
+OSCTimeTag ParseTimeTag(char *s) {
+ char *p, *newline;
+ typedArg arg;
+
+ p = s;
+ while (isspace(*p)) p++;
+ if (*p == '\0') return OSCTT_Immediately();
+
+ if (*p == '+') {
+ /* Time tag is for some time in the future. It should be a
+ number of seconds as an int or float */
+
+ newline = strchr(s, '\n');
+ if (newline != NULL) *newline = '\0';
+
+ p++; /* Skip '+' */
+ while (isspace(*p)) p++;
+
+ arg = ParseToken(p);
+ if (arg.type == STRING) {
+ complain("warning: inscrutable time tag request: %s\n", s);
+ return OSCTT_Immediately();
+ } else if (arg.type == INT) {
+ return OSCTT_PlusSeconds(OSCTT_CurrentTime(),
+ (float) arg.datum.i);
+ } else if (arg.type == FLOAT) {
+ return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f);
+ } else {
+ fatal_error("This can't happen!");
+ }
+ }
+
+ if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) {
+ /* They specified the 8-byte tag in hex */
+ OSCTimeTag tt;
+ if (sscanf(p, "%llx", &tt) != 1) {
+ complain("warning: couldn't parse time tag %s\n", s);
+ return OSCTT_Immediately();
+ }
+#ifndef HAS8BYTEINT
+ if (ntohl(1) != 1) {
+ /* tt is a struct of seconds and fractional part,
+ and this machine is little-endian, so sscanf
+ wrote each half of the time tag in the wrong half
+ of the struct. */
+ uint32 temp;
+ temp = tt.seconds;
+ tt.seconds = tt.fraction ;
+ tt.fraction = temp;
+ }
+#endif
+ return tt;
+ }
+
+ complain("warning: invalid time tag: %s\n", s);
+ return OSCTT_Immediately();
+}
+
+
+void ParseInteractiveLine(OSCbuf *buf, char *mesg) {
+ char *messageName, *token, *p;
+ typedArg args[MAX_ARGS];
+ int thisArg;
+
+ p = mesg;
+ while (isspace(*p)) p++;
+ if (*p == '\0') return;
+
+ messageName = p;
+
+ if (strcmp(messageName, "play\n") == 0) {
+ /* Special kludge feature to save typing */
+ typedArg arg;
+
+ if (OSC_openBundle(buf, OSCTT_Immediately())) {
+ complain("Problem opening bundle: %s\n", OSC_errorMessage);
+ return;
+ }
+
+ arg.type = INT;
+ arg.datum.i = 0;
+ WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg);
+
+ arg.type = FLOAT;
+ arg.datum.i = 0.0f;
+ WriteMessage(buf, "/voices/0/tm/goto", 1, &arg);
+
+ if (OSC_closeBundle(buf)) {
+ complain("Problem closing bundle: %s\n", OSC_errorMessage);
+ }
+
+ return;
+ }
+
+ while (!isspace(*p) && *p != '\0') p++;
+ if (isspace(*p)) {
+ *p = '\0';
+ p++;
+ }
+
+ thisArg = 0;
+ while (*p != '\0') {
+ /* flush leading whitespace */
+ while (isspace(*p)) p++;
+ if (*p == '\0') break;
+
+ if (*p == '"') {
+ /* A string argument: scan for close quotes */
+ p++;
+ args[thisArg].type = STRING;
+ args[thisArg].datum.s = p;
+
+ while (*p != '"') {
+ if (*p == '\0') {
+ complain("Unterminated quote mark: ignoring line\n");
+ return;
+ }
+ p++;
+ }
+ *p = '\0';
+ p++;
+ } else {
+ token = p;
+ while (!isspace(*p) && (*p != '\0')) p++;
+ if (isspace(*p)) {
+ *p = '\0';
+ p++;
+ }
+ args[thisArg] = ParseToken(token);
+ }
+ thisArg++;
+ if (thisArg >= MAX_ARGS) {
+ complain("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n",
+ MAX_ARGS);
+ break;
+ }
+ }
+
+ if (WriteMessage(buf, messageName, thisArg, args) != 0) {
+ complain("Problem sending message: %s\n", OSC_errorMessage);
+ }
+}
+
+typedArg ParseToken(char *token) {
+ char *p = token;
+ typedArg returnVal;
+
+ /* It might be an int, a float, or a string */
+
+ if (*p == '-') p++;
+
+ if (isdigit(*p) || *p == '.') {
+ while (isdigit(*p)) p++;
+ if (*p == '\0') {
+ returnVal.type = INT;
+ returnVal.datum.i = atoi(token);
+ return returnVal;
+ }
+ if (*p == '.') {
+ p++;
+ while (isdigit(*p)) p++;
+ if (*p == '\0') {
+ returnVal.type = FLOAT;
+ returnVal.datum.f = atof(token);
+ return returnVal;
+ }
+ }
+ }
+
+ returnVal.type = STRING;
+ returnVal.datum.s = token;
+ return returnVal;
+}
+
+int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) {
+ int j, returnVal;
+
+ returnVal = 0;
+
+#ifdef DEBUG
+ printf("WriteMessage: %s ", messageName);
+
+ for (j = 0; j < numArgs; j++) {
+ switch (args[j].type) {
+ case INT:
+ printf("%d ", args[j].datum.i);
+ break;
+
+ case FLOAT:
+ printf("%f ", args[j].datum.f);
+ break;
+
+ case STRING:
+ printf("%s ", args[j].datum.s);
+ break;
+
+ default:
+ fatal_error("Unrecognized arg type");
+ exit(5);
+ }
+ }
+ printf("\n");
+#endif
+
+ if (!useTypeTags) {
+ returnVal = OSC_writeAddress(buf, messageName);
+ if (returnVal) {
+ complain("Problem writing address: %s\n", OSC_errorMessage);
+ }
+ } else {
+ /* First figure out the type tags */
+ char typeTags[MAX_ARGS+2];
+ int i;
+
+ typeTags[0] = ',';
+
+ for (i = 0; i < numArgs; ++i) {
+ switch (args[i].type) {
+ case INT:
+ typeTags[i+1] = 'i';
+ break;
+
+ case FLOAT:
+ typeTags[i+1] = 'f';
+ break;
+
+ case STRING:
+ typeTags[i+1] = 's';
+ break;
+
+ default:
+ fatal_error("Unrecognized arg type");
+ exit(5);
+ }
+ }
+ typeTags[i+1] = '\0';
+
+ returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags);
+ if (returnVal) {
+ complain("Problem writing address: %s\n", OSC_errorMessage);
+ }
+ }
+
+ for (j = 0; j < numArgs; j++) {
+ switch (args[j].type) {
+ case INT:
+ if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) {
+ return returnVal;
+ }
+ break;
+
+ case FLOAT:
+ if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) {
+ return returnVal;
+ }
+ break;
+
+ case STRING:
+ if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) {
+ return returnVal;
+ }
+ break;
+
+ default:
+ fatal_error("Unrecognized arg type");
+ exit(5);
+ }
+ }
+
+ return returnVal;
+}
+
+void SendBuffer(void *htmsocket, OSCbuf *buf) {
+#ifdef DEBUG
+ printf("Sending buffer...\n");
+#endif
+ if (OSC_isBufferEmpty(buf)) return;
+ if (!OSC_isBufferDone(buf)) {
+ fatal_error("SendBuffer() called but buffer not ready!");
+ exit(5);
+ }
+ SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf));
+}
+
+void SendData(void *htmsocket, int size, char *data) {
+ if (!SendHTMSocket(htmsocket, size, data)) {
+ perror("Couldn't send out socket: ");
+ CloseHTMSocket(htmsocket);
+ exit(3);
+ }
+}
+
+void fatal_error(char *s) {
+ fprintf(stderr, "%s\n", s);
+ exit(4);
+}
+
+#include <stdarg.h>
+void complain(char *s, ...) {
+ va_list ap;
+ va_start(ap, s);
+ vfprintf(stderr, s, ap);
+ va_end(ap);
+}
+
+
+#ifdef COMPUTE_MESSAGE_SIZE
+ /* Unused code to find the size of a message */
+
+ /* Compute size */
+ size = SynthControl_effectiveStringLength(messageName);
+
+ for (j = 0; j < numArgs; j++) {
+ switch (args[j].type) {
+ case INT: case FLOAT:
+ size += 4;
+ break;
+
+ case STRING:
+ size += SynthControl_effectiveStringLength(args[j].datum.s);
+ break;
+
+ default:
+ fatal_error("Unrecognized token type");
+ exit(4);
+ }
+ }
+
+ if (!SynthControl_willMessageFit(buf, size)) {
+ complain("Message \"%s\" won't fit in buffer: dropping.", messageName);
+ return;
+ }
+#endif