summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/extra/sendOSC.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pdbox/PDa/extra/sendOSC.c')
-rw-r--r--apps/plugins/pdbox/PDa/extra/sendOSC.c1463
1 files changed, 1 insertions, 1462 deletions
diff --git a/apps/plugins/pdbox/PDa/extra/sendOSC.c b/apps/plugins/pdbox/PDa/extra/sendOSC.c
index c00f693280..bc983cc31e 100644
--- a/apps/plugins/pdbox/PDa/extra/sendOSC.c
+++ b/apps/plugins/pdbox/PDa/extra/sendOSC.c
@@ -1458,1465 +1458,4 @@ static int OSC_WritePadding(char *dest, int i) {
1458 return i; 1458 return i;
1459} 1459}
1460 1460
1461 1461
1462/*
1463Written by Matt Wright, The Center for New Music and Audio Technologies,
1464University of California, Berkeley. Copyright (c) 1996,97,98,99,2000,01,02,03
1465The Regents of the University of California (Regents).
1466
1467Permission to use, copy, modify, distribute, and distribute modified versions
1468of this software and its documentation without fee and without a signed
1469licensing agreement, is hereby granted, provided that the above copyright
1470notice, this paragraph and the following two paragraphs appear in all copies,
1471modifications, and distributions.
1472
1473IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
1474SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
1475OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
1476BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1477
1478REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1479THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1480PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
1481HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
1482MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1483
1484
1485The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
1486*/
1487
1488
1489/* sendOSC.c
1490
1491 Matt Wright, 6/3/97
1492 based on sendOSC.c, which was based on a version by Adrian Freed
1493
1494 Text-based OpenSoundControl client. User can enter messages via command
1495 line arguments or standard input.
1496
1497 Version 0.1: "play" feature
1498 Version 0.2: Message type tags.
1499
1500 pd version branched from http://www.cnmat.berkeley.edu/OpenSoundControl/src/sendOSC/sendOSC.c
1501 -------------
1502 -- added bundle stuff to send. jdl 20020416
1503 -- tweaks for Win32 www.zeggz.com/raf 13-April-2002
1504 -- ost_at_test.at + i22_at_test.at, 2000-2002
1505 modified to compile as pd externel
1506*/
1507
1508#define MAX_ARGS 2000
1509#define SC_BUFFER_SIZE 64000
1510
1511#include "m_pd.h"
1512#include "OSC-client.h"
1513
1514#include <string.h>
1515#include <sys/types.h>
1516#include <stdlib.h>
1517#include <stdio.h>
1518#include <sys/stat.h>
1519#include <sys/types.h>
1520
1521#ifdef WIN32
1522#include <winsock2.h>
1523#include <io.h>
1524#include <errno.h>
1525#include <fcntl.h>
1526#include <winsock2.h>
1527#include <ctype.h>
1528#include <signal.h>
1529#else
1530#include <sys/socket.h>
1531#include <netinet/in.h>
1532#include <rpc/rpc.h>
1533#include <sys/times.h>
1534#include <sys/param.h>
1535#include <sys/time.h>
1536#include <sys/ioctl.h>
1537#include <netdb.h>
1538#endif
1539
1540#ifdef __APPLE__
1541 #include <string.h>
1542#endif
1543
1544#define UNIXDG_PATH "/tmp/htm"
1545#define UNIXDG_TMP "/tmp/htm.XXXXXX"
1546
1547
1548
1549OSCTimeTag OSCTT_Immediately(void) {
1550 OSCTimeTag result;
1551 result.seconds = 0;
1552 result.fraction = 1;
1553 return result;
1554}
1555
1556
1557OSCTimeTag OSCTT_CurrentTime(void) {
1558 OSCTimeTag result;
1559 result.seconds = 0;
1560 result.fraction = 1;
1561 return result;
1562}
1563
1564OSCTimeTag OSCTT_PlusSeconds(OSCTimeTag original, float secondsOffset) {
1565 OSCTimeTag result;
1566 result.seconds = 0;
1567 result.fraction = 1;
1568 return result;
1569}
1570
1571
1572typedef int bool;
1573
1574typedef struct
1575{
1576 float srate;
1577
1578 struct sockaddr_in serv_addr; /* udp socket */
1579 #ifndef WIN32
1580 struct sockaddr_un userv_addr; /* UNIX socket */
1581 #endif
1582 int sockfd; /* socket file descriptor */
1583 int index, len,uservlen;
1584 void *addr;
1585 int id;
1586} desc;
1587
1588
1589/* open a socket for HTM communication to given host on given portnumber */
1590/* if host is 0 then UNIX protocol is used (i.e. local communication */
1591void *OpenHTMSocket(char *host, int portnumber)
1592{
1593 struct sockaddr_in cl_addr;
1594 #ifndef WIN32
1595 int sockfd;
1596 struct sockaddr_un ucl_addr;
1597 #else
1598 unsigned int sockfd;
1599 #endif
1600
1601 desc *o;
1602 int oval = 1;
1603 o = malloc(sizeof(*o));
1604 if(!o) return 0;
1605
1606 #ifndef WIN32
1607
1608 if(!host)
1609 {
1610 char *mktemp(char *);
1611 int clilen;
1612 o->len = sizeof(ucl_addr);
1613 /*
1614 * Fill in the structure "userv_addr" with the address of the
1615 * server that we want to send to.
1616 */
1617
1618 bzero((char *) &o->userv_addr, sizeof(o->userv_addr));
1619 o->userv_addr.sun_family = AF_UNIX;
1620 strcpy(o->userv_addr.sun_path, UNIXDG_PATH);
1621 sprintf(o->userv_addr.sun_path+strlen(o->userv_addr.sun_path), "%d", portnumber);
1622 o->uservlen = sizeof(o->userv_addr.sun_family) + strlen(o->userv_addr.sun_path);
1623 o->addr = &(o->userv_addr);
1624 /*
1625 * Open a socket (a UNIX domain datagram socket).
1626 */
1627
1628 if ( (sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0)
1629 {
1630 /*
1631 * Bind a local address for us.
1632 * In the UNIX domain we have to choose our own name (that
1633 * should be unique). We'll use mktemp() to create a unique
1634 * pathname, based on our process id.
1635 */
1636
1637 bzero((char *) &ucl_addr, sizeof(ucl_addr)); /* zero out */
1638 ucl_addr.sun_family = AF_UNIX;
1639 strcpy(ucl_addr.sun_path, UNIXDG_TMP);
1640
1641 mktemp(ucl_addr.sun_path);
1642 clilen = sizeof(ucl_addr.sun_family) + strlen(ucl_addr.sun_path);
1643
1644 if (bind(sockfd, (struct sockaddr *) &ucl_addr, clilen) < 0)
1645 {
1646 perror("client: can't bind local address");
1647 close(sockfd);
1648 sockfd = -1;
1649 }
1650 }
1651 else
1652 perror("unable to make socket\n");
1653
1654 }else
1655
1656 #endif
1657
1658 {
1659 /*
1660 * Fill in the structure "serv_addr" with the address of the
1661 * server that we want to send to.
1662 */
1663 o->len = sizeof(cl_addr);
1664
1665 #ifdef WIN32
1666 ZeroMemory((char *)&o->serv_addr, sizeof(o->serv_addr));
1667 #else
1668 bzero((char *)&o->serv_addr, sizeof(o->serv_addr));
1669 #endif
1670
1671 o->serv_addr.sin_family = AF_INET;
1672
1673 /* MW 6/6/96: Call gethostbyname() instead of inet_addr(),
1674 so that host can be either an Internet host name (e.g.,
1675 "les") or an Internet address in standard dot notation
1676 (e.g., "128.32.122.13") */
1677 {
1678 struct hostent *hostsEntry;
1679 unsigned long address;
1680
1681 hostsEntry = gethostbyname(host);
1682 if (hostsEntry == NULL) {
1683 fprintf(stderr, "Couldn't decipher host name \"%s\"\n", host);
1684 #ifndef WIN32
1685 herror(NULL);
1686 #endif
1687 return 0;
1688 }
1689 address = *((unsigned long *) hostsEntry->h_addr_list[0]);
1690 o->serv_addr.sin_addr.s_addr = address;
1691 }
1692
1693 /* was: o->serv_addr.sin_addr.s_addr = inet_addr(host); */
1694
1695 /* End MW changes */
1696
1697 /*
1698 * Open a socket (a UDP domain datagram socket).
1699 */
1700
1701
1702 #ifdef WIN32
1703 o->serv_addr.sin_port = htons((USHORT)portnumber);
1704 o->addr = &(o->serv_addr);
1705 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) {
1706 ZeroMemory((char *)&cl_addr, sizeof(cl_addr));
1707 cl_addr.sin_family = AF_INET;
1708 cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1709 cl_addr.sin_port = htons(0);
1710
1711 // enable broadcast: jdl ~2003
1712 if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) {
1713 perror("setsockopt");
1714 }
1715
1716 if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
1717 perror("could not bind\n");
1718 closesocket(sockfd);
1719 sockfd = -1;
1720 }
1721 }
1722 else { perror("unable to make socket\n");}
1723 #else
1724 o->serv_addr.sin_port = htons(portnumber);
1725 o->addr = &(o->serv_addr);
1726 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
1727 bzero((char *)&cl_addr, sizeof(cl_addr));
1728 cl_addr.sin_family = AF_INET;
1729 cl_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1730 cl_addr.sin_port = htons(0);
1731
1732 // enable broadcast: jdl ~2003
1733 if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) {
1734 perror("setsockopt");
1735 }
1736
1737 if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
1738 perror("could not bind\n");
1739 close(sockfd);
1740 sockfd = -1;
1741 }
1742 }
1743 else { perror("unable to make socket\n");}
1744 #endif
1745 }
1746 #ifdef WIN32
1747 if(sockfd == INVALID_SOCKET) {
1748 #else
1749 if(sockfd < 0) {
1750 #endif
1751 free(o);
1752 o = 0;
1753 }
1754 else
1755 o->sockfd = sockfd;
1756 return o;
1757}
1758
1759static bool sendudp(const struct sockaddr *sp, int sockfd,int length, int count, void *b)
1760{
1761 int rcount;
1762 if((rcount=sendto(sockfd, b, count, 0, sp, length)) != count)
1763 {
1764 printf("sockfd %d count %d rcount %dlength %d\n", sockfd,count,rcount,length);
1765 return FALSE;
1766 }
1767 return TRUE;
1768}
1769
1770bool SendHTMSocket(void *htmsendhandle, int length_in_bytes, void *buffer)
1771{
1772 desc *o = (desc *)htmsendhandle;
1773 return sendudp(o->addr, o->sockfd, o->len, length_in_bytes, buffer);
1774}
1775void CloseHTMSocket(void *htmsendhandle)
1776{
1777 desc *o = (desc *)htmsendhandle;
1778 #ifdef WIN32
1779 if(SOCKET_ERROR == closesocket(o->sockfd)) {
1780 perror("CloseHTMSocket::closesocket failed\n");
1781 return;
1782 }
1783 #else
1784 if(close(o->sockfd) == -1)
1785 {
1786 perror("CloseHTMSocket::closesocket failed");
1787 return;
1788 }
1789 #endif
1790
1791 free(o);
1792}
1793
1794
1795///////////////////////
1796// from sendOSC
1797
1798typedef struct {
1799 //enum {INT, FLOAT, STRING} type;
1800 enum {INT_osc, FLOAT_osc, STRING_osc} type;
1801 union {
1802 int i;
1803 float f;
1804 char *s;
1805 } datum;
1806} typedArg;
1807
1808void CommandLineMode(int argc, char *argv[], void *htmsocket);
1809OSCTimeTag ParseTimeTag(char *s);
1810void ParseInteractiveLine(OSCbuf *buf, char *mesg);
1811typedArg ParseToken(char *token);
1812int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args);
1813void SendBuffer(void *htmsocket, OSCbuf *buf);
1814void SendData(void *htmsocket, int size, char *data);
1815/* defined in OSC-system-dependent.c now */
1816
1817//static void *htmsocket;
1818static int exitStatus = 0;
1819static int useTypeTags = 0;
1820
1821static char bufferForOSCbuf[SC_BUFFER_SIZE];
1822
1823
1824/////////
1825// end from sendOSC
1826
1827static t_class *sendOSC_class;
1828
1829typedef struct _sendOSC
1830{
1831 t_object x_obj;
1832 int x_protocol; // UDP/TCP (udp only atm)
1833 t_int x_typetags; // typetag flag
1834 void *x_htmsocket; // sending socket
1835 int x_bundle; // bundle open flag
1836 OSCbuf x_oscbuf[1]; // OSCbuffer
1837 t_outlet *x_bdpthout;// bundle-depth floatoutlet
1838} t_sendOSC;
1839
1840static void *sendOSC_new(t_floatarg udpflag)
1841{
1842 t_sendOSC *x = (t_sendOSC *)pd_new(sendOSC_class);
1843 outlet_new(&x->x_obj, &s_float);
1844 x->x_htmsocket = 0; // {{raf}}
1845 // set udp
1846 x->x_protocol = SOCK_STREAM;
1847 // set typetags to 1 by default
1848 x->x_typetags = 1;
1849 // bunlde is closed
1850 x->x_bundle = 0;
1851 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
1852 x->x_bdpthout = outlet_new(&x->x_obj, 0); // outlet_float();
1853 //x->x_oscbuf =
1854 return (x);
1855}
1856
1857
1858void sendOSC_openbundle(t_sendOSC *x)
1859{
1860 if (x->x_oscbuf->bundleDepth + 1 >= MAX_BUNDLE_NESTING ||
1861 OSC_openBundle(x->x_oscbuf, OSCTT_Immediately()))
1862 {
1863 post("Problem opening bundle: %s\n", OSC_errorMessage);
1864 return;
1865 }
1866 x->x_bundle = 1;
1867 outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
1868}
1869
1870static void sendOSC_closebundle(t_sendOSC *x)
1871{
1872 if (OSC_closeBundle(x->x_oscbuf)) {
1873 post("Problem closing bundle: %s\n", OSC_errorMessage);
1874 return;
1875 }
1876 outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
1877 // in bundle mode we send when bundle is closed?
1878 if(!OSC_isBufferEmpty(x->x_oscbuf) > 0 && OSC_isBufferDone(x->x_oscbuf)) {
1879 // post("x_oscbuf: something inside me?");
1880 if (x->x_htmsocket) {
1881 SendBuffer(x->x_htmsocket, x->x_oscbuf);
1882 } else {
1883 post("sendOSC: not connected");
1884 }
1885 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
1886 x->x_bundle = 0;
1887 return;
1888 }
1889 // post("x_oscbuf: something went wrong");
1890}
1891
1892static void sendOSC_settypetags(t_sendOSC *x, t_float *f)
1893 {
1894 x->x_typetags = (int)f;
1895 post("sendOSC.c: setting typetags %d",x->x_typetags);
1896 }
1897
1898
1899static void sendOSC_connect(t_sendOSC *x, t_symbol *hostname,
1900 t_floatarg fportno)
1901{
1902 int portno = fportno;
1903 /* create a socket */
1904
1905 // make sure handle is available
1906 if(x->x_htmsocket == 0) {
1907 //
1908 x->x_htmsocket = OpenHTMSocket(hostname->s_name, portno);
1909 if (!x->x_htmsocket)
1910 post("Couldn't open socket: ");
1911 else {
1912 post("connected to port %s:%d (hSock=%d)", hostname->s_name, portno, x->x_htmsocket);
1913 outlet_float(x->x_obj.ob_outlet, 1);
1914 }
1915 }
1916 else
1917 perror("call to sendOSC_connect() against UNavailable socket handle");
1918}
1919
1920void sendOSC_disconnect(t_sendOSC *x)
1921{
1922 if (x->x_htmsocket)
1923 {
1924 post("disconnecting htmsock (hSock=%d)...", x->x_htmsocket);
1925 CloseHTMSocket(x->x_htmsocket);
1926 x->x_htmsocket = 0; // {{raf}} semi-quasi-semaphorize this
1927 outlet_float(x->x_obj.ob_outlet, 0);
1928 }
1929 else {
1930 perror("call to sendOSC_disconnect() against unused socket handle");
1931 }
1932}
1933
1934void sendOSC_senduntyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
1935{
1936 char* targv[MAXPDARG];
1937 char tmparg[MAXPDSTRING];
1938 char* tmp = tmparg;
1939 //char testarg[MAXPDSTRING];
1940 int c;
1941
1942 post("sendOSC: use typetags 0/1 message and plain send method so send untypetagged...");
1943 return;
1944
1945 //atom_string(argv,testarg, MAXPDSTRING);
1946 for (c=0;c<argc;c++) {
1947 atom_string(argv+c,tmp, 80);
1948 targv[c] = tmp;
1949 tmp += strlen(tmp)+1;
1950 }
1951
1952 // this sock needs to be larger than 0, not >= ..
1953 if (x->x_htmsocket)
1954 {
1955 CommandLineMode(argc, targv, x->x_htmsocket);
1956 // post("test %d", c);
1957 }
1958 else {
1959 post("sendOSC: not connected");
1960 }
1961}
1962
1963//////////////////////////////////////////////////////////////////////
1964// this is the real and only sending routine now, for both typed and
1965// undtyped mode.
1966
1967static void sendOSC_sendtyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
1968{
1969 char* targv[MAX_ARGS];
1970 char tmparg[MAXPDSTRING];
1971 char* tmp = tmparg;
1972 int c;
1973
1974 char *messageName;
1975 char *token;
1976 typedArg args[MAX_ARGS];
1977 int i,j;
1978 int numArgs = 0;
1979
1980 messageName = "";
1981#ifdef DEBUG
1982 post ("sendOSC: messageName: %s", messageName);
1983#endif
1984
1985
1986
1987 for (c=0;c<argc;c++) {
1988 atom_string(argv+c,tmp, 80);
1989
1990#ifdef DEBUG
1991 // post ("sendOSC: %d, %s",c, tmp);
1992#endif
1993
1994 targv[c] = tmp;
1995 tmp += strlen(tmp)+1;
1996
1997#ifdef DEBUG
1998 // post ("sendOSC: %d, %s",c, targv[c]);
1999#endif
2000 }
2001
2002 // this sock needs to be larger than 0, not >= ..
2003 if (x->x_htmsocket > 0)
2004 {
2005#ifdef DEBUG
2006 post ("sendOSC: type tags? %d", useTypeTags);
2007#endif
2008
2009 messageName = strtok(targv[0], ",");
2010 j = 1;
2011 for (i = j; i < argc; i++) {
2012 token = strtok(targv[i],",");
2013 args[i-j] = ParseToken(token);
2014#ifdef DEBUG
2015 printf("cell-cont: %s\n", targv[i]);
2016 printf(" type-id: %d\n", args[i-j]);
2017#endif
2018 numArgs = i;
2019 }
2020
2021
2022 if(WriteMessage(x->x_oscbuf, messageName, numArgs, args)) {
2023 post("sendOSC: usage error, write-msg failed: %s", OSC_errorMessage);
2024 return;
2025 }
2026
2027 if(!x->x_bundle) {
2028 SendBuffer(x->x_htmsocket, x->x_oscbuf);
2029 OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
2030 }
2031
2032 //CommandLineMode(argc, targv, x->x_htmsocket);
2033 //useTypeTags = 0;
2034 }
2035 else {
2036 post("sendOSC: not connected");
2037 }
2038}
2039
2040void sendOSC_send(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
2041{
2042 if(!argc) {
2043 post("not sending empty message.");
2044 return;
2045 }
2046 if(x->x_typetags) {
2047 useTypeTags = 1;
2048 sendOSC_sendtyped(x,s,argc,argv);
2049 useTypeTags = 0;
2050 } else {
2051 sendOSC_sendtyped(x,s,argc,argv);
2052 }
2053}
2054
2055static void sendOSC_free(t_sendOSC *x)
2056{
2057 sendOSC_disconnect(x);
2058}
2059
2060#ifdef WIN32
2061 OSC_API void sendOSC_setup(void) {
2062#else
2063 void sendOSC_setup(void) {
2064#endif
2065 sendOSC_class = class_new(gensym("sendOSC"), (t_newmethod)sendOSC_new,
2066 (t_method)sendOSC_free,
2067 sizeof(t_sendOSC), 0, A_DEFFLOAT, 0);
2068 class_addmethod(sendOSC_class, (t_method)sendOSC_connect,
2069 gensym("connect"), A_SYMBOL, A_FLOAT, 0);
2070 class_addmethod(sendOSC_class, (t_method)sendOSC_disconnect,
2071 gensym("disconnect"), 0);
2072 class_addmethod(sendOSC_class, (t_method)sendOSC_settypetags,
2073 gensym("typetags"),
2074 A_FLOAT, 0);
2075 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
2076 gensym("send"),
2077 A_GIMME, 0);
2078 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
2079 gensym("senduntyped"),
2080 A_GIMME, 0);
2081 class_addmethod(sendOSC_class, (t_method)sendOSC_send,
2082 gensym("sendtyped"),
2083 A_GIMME, 0);
2084 class_addmethod(sendOSC_class, (t_method)sendOSC_openbundle,
2085 gensym("["),
2086 0, 0);
2087 class_addmethod(sendOSC_class, (t_method)sendOSC_closebundle,
2088 gensym("]"),
2089 0, 0);
2090 class_sethelpsymbol(sendOSC_class, gensym("sendOSC-help.pd"));
2091}
2092
2093
2094
2095
2096
2097/* Exit status codes:
2098 0: successful
2099 2: Message(s) dropped because of buffer overflow
2100 3: Socket error
2101 4: Usage error
2102 5: Internal error
2103*/
2104
2105void CommandLineMode(int argc, char *argv[], void *htmsocket) {
2106 char *messageName;
2107 char *token;
2108 typedArg args[MAX_ARGS];
2109 int i,j, numArgs;
2110 OSCbuf buf[1];
2111
2112 OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
2113
2114 if (argc > 1) {
2115 post("argc (%d) > 1", argc);
2116 }
2117
2118 // ParseInteractiveLine(buf, argv);
2119 messageName = strtok(argv[0], ",");
2120
2121 j = 1;
2122 for (i = j; i < argc; i++) {
2123 token = strtok(argv[i],",");
2124 args[i-j] = ParseToken(token);
2125#ifdef DEBUG
2126 printf("cell-cont: %s\n", argv[i]);
2127 printf(" type-id: %d\n", args[i-j]);
2128#endif
2129 numArgs = i;
2130 }
2131
2132 if(WriteMessage(buf, messageName, numArgs, args)) {
2133 post("sendOSC: usage error. write-msg failed: %s", OSC_errorMessage);
2134 return;
2135 }
2136
2137 SendBuffer(htmsocket, buf);
2138}
2139
2140#define MAXMESG 2048
2141
2142void InteractiveMode(void *htmsocket) {
2143 char mesg[MAXMESG];
2144 OSCbuf buf[1];
2145 int bundleDepth = 0; /* At first, we haven't seen "[". */
2146
2147 OSC_initBuffer(buf, SC_BUFFER_SIZE, bufferForOSCbuf);
2148
2149 while (fgets(mesg, MAXMESG, stdin) != NULL) {
2150 if (mesg[0] == '\n') {
2151 if (bundleDepth > 0) {
2152 /* Ignore blank lines inside a group. */
2153 } else {
2154 /* blank line => repeat previous send */
2155 SendBuffer(htmsocket, buf);
2156 }
2157 continue;
2158 }
2159
2160 if (bundleDepth == 0) {
2161 OSC_resetBuffer(buf);
2162 }
2163
2164 if (mesg[0] == '[') {
2165 OSCTimeTag tt = ParseTimeTag(mesg+1);
2166 if (OSC_openBundle(buf, tt)) {
2167 post("Problem opening bundle: %s\n", OSC_errorMessage);
2168 OSC_resetBuffer(buf);
2169 bundleDepth = 0;
2170 continue;
2171 }
2172 bundleDepth++;
2173 } else if (mesg[0] == ']' && mesg[1] == '\n' && mesg[2] == '\0') {
2174 if (bundleDepth == 0) {
2175 post("Unexpected ']': not currently in a bundle.\n");
2176 } else {
2177 if (OSC_closeBundle(buf)) {
2178 post("Problem closing bundle: %s\n", OSC_errorMessage);
2179 OSC_resetBuffer(buf);
2180 bundleDepth = 0;
2181 continue;
2182 }
2183
2184 bundleDepth--;
2185 if (bundleDepth == 0) {
2186 SendBuffer(htmsocket, buf);
2187 }
2188 }
2189 } else {
2190 ParseInteractiveLine(buf, mesg);
2191 if (bundleDepth != 0) {
2192 /* Don't send anything until we close all bundles */
2193 } else {
2194 SendBuffer(htmsocket, buf);
2195 }
2196 }
2197 }
2198}
2199
2200OSCTimeTag ParseTimeTag(char *s) {
2201 char *p, *newline;
2202 typedArg arg;
2203
2204 p = s;
2205 while (isspace(*p)) p++;
2206 if (*p == '\0') return OSCTT_Immediately();
2207
2208 if (*p == '+') {
2209 /* Time tag is for some time in the future. It should be a
2210 number of seconds as an int or float */
2211
2212 newline = strchr(s, '\n');
2213 if (newline != NULL) *newline = '\0';
2214
2215 p++; /* Skip '+' */
2216 while (isspace(*p)) p++;
2217
2218 arg = ParseToken(p);
2219 if (arg.type == STRING_osc) {
2220 post("warning: inscrutable time tag request: %s\n", s);
2221 return OSCTT_Immediately();
2222 } else if (arg.type == INT_osc) {
2223 return OSCTT_PlusSeconds(OSCTT_CurrentTime(),
2224 (float) arg.datum.i);
2225 } else if (arg.type == FLOAT_osc) {
2226 return OSCTT_PlusSeconds(OSCTT_CurrentTime(), arg.datum.f);
2227 } else {
2228 error("This can't happen!");
2229 }
2230 }
2231
2232 if (isdigit(*p) || (*p >= 'a' && *p <='f') || (*p >= 'A' && *p <='F')) {
2233 /* They specified the 8-byte tag in hex */
2234 OSCTimeTag tt;
2235 if (sscanf(p, "%llx", &tt) != 1) {
2236 post("warning: couldn't parse time tag %s\n", s);
2237 return OSCTT_Immediately();
2238 }
2239#ifndef HAS8BYTEINT
2240 if (ntohl(1) != 1) {
2241 /* tt is a struct of seconds and fractional part,
2242 and this machine is little-endian, so sscanf
2243 wrote each half of the time tag in the wrong half
2244 of the struct. */
2245 int temp;
2246 temp = tt.seconds;
2247 tt.seconds = tt.fraction ;
2248 tt.fraction = temp;
2249 }
2250#endif
2251 return tt;
2252 }
2253
2254 post("warning: invalid time tag: %s\n", s);
2255 return OSCTT_Immediately();
2256}
2257
2258
2259void ParseInteractiveLine(OSCbuf *buf, char *mesg) {
2260 char *messageName, *token, *p;
2261 typedArg args[MAX_ARGS];
2262 int thisArg;
2263
2264 p = mesg;
2265 while (isspace(*p)) p++;
2266 if (*p == '\0') return;
2267
2268 messageName = p;
2269
2270 if (strcmp(messageName, "play\n") == 0) {
2271 /* Special kludge feature to save typing */
2272 typedArg arg;
2273
2274 if (OSC_openBundle(buf, OSCTT_Immediately())) {
2275 post("Problem opening bundle: %s\n", OSC_errorMessage);
2276 return;
2277 }
2278
2279 arg.type = INT_osc;
2280 arg.datum.i = 0;
2281 WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg);
2282
2283 arg.type = FLOAT_osc;
2284 arg.datum.i = 0.0f;
2285 WriteMessage(buf, "/voices/0/tm/goto", 1, &arg);
2286
2287 if (OSC_closeBundle(buf)) {
2288 post("Problem closing bundle: %s\n", OSC_errorMessage);
2289 }
2290
2291 return;
2292 }
2293
2294 while (!isspace(*p) && *p != '\0') p++;
2295 if (isspace(*p)) {
2296 *p = '\0';
2297 p++;
2298 }
2299
2300 thisArg = 0;
2301 while (*p != '\0') {
2302 /* flush leading whitespace */
2303 while (isspace(*p)) p++;
2304 if (*p == '\0') break;
2305
2306 if (*p == '"') {
2307 /* A string argument: scan for close quotes */
2308 p++;
2309 args[thisArg].type = STRING_osc;
2310 args[thisArg].datum.s = p;
2311
2312 while (*p != '"') {
2313 if (*p == '\0') {
2314 post("Unterminated quote mark: ignoring line\n");
2315 return;
2316 }
2317 p++;
2318 }
2319 *p = '\0';
2320 p++;
2321 } else {
2322 token = p;
2323 while (!isspace(*p) && (*p != '\0')) p++;
2324 if (isspace(*p)) {
2325 *p = '\0';
2326 p++;
2327 }
2328 args[thisArg] = ParseToken(token);
2329 }
2330 thisArg++;
2331 if (thisArg >= MAX_ARGS) {
2332 post("Sorry, your message has more than MAX_ARGS (%d) arguments; ignoring the rest.\n",
2333 MAX_ARGS);
2334 break;
2335 }
2336 }
2337
2338 if (WriteMessage(buf, messageName, thisArg, args) != 0) {
2339 post("Problem sending message: %s\n", OSC_errorMessage);
2340 }
2341}
2342
2343typedArg ParseToken(char *token) {
2344 char *p = token;
2345 typedArg returnVal;
2346
2347 /* It might be an int, a float, or a string */
2348
2349 if (*p == '-') p++;
2350
2351 if (isdigit(*p) || *p == '.') {
2352 while (isdigit(*p)) p++;
2353 if (*p == '\0') {
2354 returnVal.type = INT_osc;
2355 returnVal.datum.i = atoi(token);
2356 return returnVal;
2357 }
2358 if (*p == '.') {
2359 p++;
2360 while (isdigit(*p)) p++;
2361 if (*p == '\0') {
2362 returnVal.type = FLOAT_osc;
2363 returnVal.datum.f = atof(token);
2364 return returnVal;
2365 }
2366 }
2367 }
2368
2369 returnVal.type = STRING_osc;
2370 returnVal.datum.s = token;
2371 return returnVal;
2372}
2373
2374int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) {
2375 int j, returnVal;
2376 const int wmERROR = -1;
2377
2378 returnVal = 0;
2379
2380#ifdef DEBUG
2381 printf("WriteMessage: %s ", messageName);
2382
2383 for (j = 0; j < numArgs; j++) {
2384 switch (args[j].type) {
2385 case INT_osc:
2386 printf("%d ", args[j].datum.i);
2387 break;
2388
2389 case FLOAT_osc:
2390 printf("%f ", args[j].datum.f);
2391 break;
2392
2393 case STRING_osc:
2394 printf("%s ", args[j].datum.s);
2395 break;
2396
2397 default:
2398 error("Unrecognized arg type, (not exiting)");
2399 return(wmERROR);
2400 }
2401 }
2402 printf("\n");
2403#endif
2404
2405 if (!useTypeTags) {
2406 returnVal = OSC_writeAddress(buf, messageName);
2407 if (returnVal) {
2408 post("Problem writing address: %s\n", OSC_errorMessage);
2409 }
2410 } else {
2411 /* First figure out the type tags */
2412 char typeTags[MAX_ARGS+2];
2413 int i;
2414
2415 typeTags[0] = ',';
2416
2417 for (i = 0; i < numArgs; ++i) {
2418 switch (args[i].type) {
2419 case INT_osc:
2420 typeTags[i+1] = 'i';
2421 break;
2422
2423 case FLOAT_osc:
2424 typeTags[i+1] = 'f';
2425 break;
2426
2427 case STRING_osc:
2428 typeTags[i+1] = 's';
2429 break;
2430
2431 default:
2432 error("Unrecognized arg type (not exiting)");
2433 return(wmERROR);
2434 }
2435 }
2436 typeTags[i+1] = '\0';
2437
2438 returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags);
2439 if (returnVal) {
2440 post("Problem writing address: %s\n", OSC_errorMessage);
2441 }
2442 }
2443
2444 for (j = 0; j < numArgs; j++) {
2445 switch (args[j].type) {
2446 case INT_osc:
2447 if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) {
2448 return returnVal;
2449 }
2450 break;
2451
2452 case FLOAT_osc:
2453 if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) {
2454 return returnVal;
2455 }
2456 break;
2457
2458 case STRING_osc:
2459 if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) {
2460 return returnVal;
2461 }
2462 break;
2463
2464 default:
2465 error("Unrecognized arg type (not exiting)");
2466 returnVal = wmERROR;
2467 }
2468 }
2469 return returnVal;
2470}
2471
2472void SendBuffer(void *htmsocket, OSCbuf *buf) {
2473#ifdef DEBUG
2474 printf("Sending buffer...\n");
2475#endif
2476 if (OSC_isBufferEmpty(buf)) {
2477 post("SendBuffer() called but buffer empty");
2478 return;
2479 }
2480 if (!OSC_isBufferDone(buf)) {
2481 error("SendBuffer() called but buffer not ready!, not exiting");
2482 return; //{{raf}}
2483 }
2484 SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf));
2485}
2486
2487void SendData(void *htmsocket, int size, char *data) {
2488 if (!SendHTMSocket(htmsocket, size, data)) {
2489 post("SendData::SendHTMSocket()failure -- not connected");
2490 CloseHTMSocket(htmsocket);
2491 }
2492}
2493
2494
2495
2496/* ----------------------
2497 OSC-client code
2498
2499 */
2500
2501/* Here are the possible values of the state field: */
2502
2503#define EMPTY 0 /* Nothing written to packet yet */
2504#define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */
2505#define NEED_COUNT 2 /* Just opened a bundle; must write message name or
2506 open another bundle */
2507#define GET_ARGS 3 /* Getting arguments to a message. If we see a message
2508 name or a bundle open/close then the current message
2509 will end. */
2510#define DONE 4 /* All open bundles have been closed, so can't write
2511 anything else */
2512
2513#ifdef WIN32
2514 #include <winsock2.h>
2515 #include <io.h>
2516 #include <stdio.h>
2517 #include <errno.h>
2518 #include <fcntl.h>
2519 #include <sys/types.h>
2520 #include <sys/stat.h>
2521#endif
2522
2523#ifdef __APPLE__
2524 #include <sys/types.h>
2525#endif
2526
2527#ifdef unix
2528 #include <netinet/in.h>
2529 #include <stdio.h>
2530#endif
2531
2532
2533char *OSC_errorMessage;
2534
2535static int OSC_padString(char *dest, char *str);
2536static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str);
2537static int OSC_WritePadding(char *dest, int i);
2538static int CheckTypeTag(OSCbuf *buf, char expectedType);
2539
2540void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray) {
2541 buf->buffer = byteArray;
2542 buf->size = size;
2543 OSC_resetBuffer(buf);
2544}
2545
2546void OSC_resetBuffer(OSCbuf *buf) {
2547 buf->bufptr = buf->buffer;
2548 buf->state = EMPTY;
2549 buf->bundleDepth = 0;
2550 buf->prevCounts[0] = 0;
2551 buf->gettingFirstUntypedArg = 0;
2552 buf->typeStringPtr = 0;
2553}
2554
2555int OSC_isBufferEmpty(OSCbuf *buf) {
2556 return buf->bufptr == buf->buffer;
2557}
2558
2559int OSC_freeSpaceInBuffer(OSCbuf *buf) {
2560 return buf->size - (buf->bufptr - buf->buffer);
2561}
2562
2563int OSC_isBufferDone(OSCbuf *buf) {
2564 return (buf->state == DONE || buf->state == ONE_MSG_ARGS);
2565}
2566
2567char *OSC_getPacket(OSCbuf *buf) {
2568#ifdef ERROR_CHECK_GETPACKET
2569 if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
2570 return buf->buffer;
2571 } else {
2572 OSC_errorMessage = "Packet has unterminated bundles";
2573 return 0;
2574 }
2575#else
2576 return buf->buffer;
2577#endif
2578}
2579
2580int OSC_packetSize(OSCbuf *buf) {
2581#ifdef ERROR_CHECK_PACKETSIZE
2582 if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
2583 return (buf->bufptr - buf->buffer);
2584 } else {
2585 OSC_errorMessage = "Packet has unterminated bundles";
2586 return 0;
2587 }
2588#else
2589 return (buf->bufptr - buf->buffer);
2590#endif
2591}
2592
2593#define CheckOverflow(buf, bytesNeeded) { if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) {OSC_errorMessage = "buffer overflow"; return 1;}}
2594
2595static void PatchMessageSize(OSCbuf *buf) {
2596 int4byte size;
2597 size = buf->bufptr - ((char *) buf->thisMsgSize) - 4;
2598 *(buf->thisMsgSize) = htonl(size);
2599}
2600
2601int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) {
2602 if (buf->state == ONE_MSG_ARGS) {
2603 OSC_errorMessage = "Can't open a bundle in a one-message packet";
2604 return 3;
2605 }
2606
2607 if (buf->state == DONE) {
2608 OSC_errorMessage = "This packet is finished; can't open a new bundle";
2609 return 4;
2610 }
2611
2612 if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) {
2613 OSC_errorMessage = "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h";
2614 return 2;
2615 }
2616
2617 if (CheckTypeTag(buf, '\0')) return 9;
2618
2619 if (buf->state == GET_ARGS) {
2620 PatchMessageSize(buf);
2621 }
2622
2623 if (buf->state == EMPTY) {
2624 /* Need 16 bytes for "#bundle" and time tag */
2625 CheckOverflow(buf, 16);
2626 } else {
2627 /* This bundle is inside another bundle, so we need to leave
2628 a blank size count for the size of this current bundle. */
2629 CheckOverflow(buf, 20);
2630 *((int4byte *)buf->bufptr) = 0xaaaaaaaa;
2631 buf->prevCounts[buf->bundleDepth] = (int4byte *)buf->bufptr;
2632
2633 buf->bufptr += 4;
2634 }
2635
2636 buf->bufptr += OSC_padString(buf->bufptr, "#bundle");
2637
2638
2639 *((OSCTimeTag *) buf->bufptr) = tt;
2640
2641 if (htonl(1) != 1) {
2642 /* Byte swap the 8-byte integer time tag */
2643 int4byte *intp = (int4byte *)buf->bufptr;
2644 intp[0] = htonl(intp[0]);
2645 intp[1] = htonl(intp[1]);
2646
2647#ifdef HAS8BYTEINT
2648 { /* tt is a 64-bit int so we have to swap the two 32-bit words.
2649 (Otherwise tt is a struct of two 32-bit words, and even though
2650 each word was wrong-endian, they were in the right order
2651 in the struct.) */
2652 int4byte temp = intp[0];
2653 intp[0] = intp[1];
2654 intp[1] = temp;
2655 }
2656#endif
2657 }
2658
2659 buf->bufptr += sizeof(OSCTimeTag);
2660
2661 buf->state = NEED_COUNT;
2662
2663 buf->gettingFirstUntypedArg = 0;
2664 buf->typeStringPtr = 0;
2665 return 0;
2666}
2667
2668
2669int OSC_closeBundle(OSCbuf *buf) {
2670 if (buf->bundleDepth == 0) {
2671 /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
2672 OSC_errorMessage = "Can't close bundle; no bundle is open!";
2673 return 5;
2674 }
2675
2676 if (CheckTypeTag(buf, '\0')) return 9;
2677
2678 if (buf->state == GET_ARGS) {
2679 PatchMessageSize(buf);
2680 }
2681
2682 if (buf->bundleDepth == 1) {
2683 /* Closing the last bundle: No bundle size to patch */
2684 buf->state = DONE;
2685 } else {
2686 /* Closing a sub-bundle: patch bundle size */
2687 int size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4;
2688 *(buf->prevCounts[buf->bundleDepth]) = htonl(size);
2689 buf->state = NEED_COUNT;
2690 }
2691
2692 --buf->bundleDepth;
2693 buf->gettingFirstUntypedArg = 0;
2694 buf->typeStringPtr = 0;
2695 return 0;
2696}
2697
2698
2699int OSC_closeAllBundles(OSCbuf *buf) {
2700 if (buf->bundleDepth == 0) {
2701 /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
2702 OSC_errorMessage = "Can't close all bundles; no bundle is open!";
2703 return 6;
2704 }
2705
2706 if (CheckTypeTag(buf, '\0')) return 9;
2707
2708 while (buf->bundleDepth > 0) {
2709 OSC_closeBundle(buf);
2710 }
2711 buf->typeStringPtr = 0;
2712 return 0;
2713}
2714
2715int OSC_writeAddress(OSCbuf *buf, char *name) {
2716 int4byte paddedLength;
2717
2718 if (buf->state == ONE_MSG_ARGS) {
2719 OSC_errorMessage = "This packet is not a bundle, so you can't write another address";
2720 return 7;
2721 }
2722
2723 if (buf->state == DONE) {
2724 OSC_errorMessage = "This packet is finished; can't write another address";
2725 return 8;
2726 }
2727
2728 if (CheckTypeTag(buf, '\0')) return 9;
2729
2730 paddedLength = OSC_effectiveStringLength(name);
2731
2732 if (buf->state == EMPTY) {
2733 /* This will be a one-message packet, so no sizes to worry about */
2734 CheckOverflow(buf, paddedLength);
2735 buf->state = ONE_MSG_ARGS;
2736 } else {
2737 /* GET_ARGS or NEED_COUNT */
2738 CheckOverflow(buf, 4+paddedLength);
2739 if (buf->state == GET_ARGS) {
2740 /* Close the old message */
2741 PatchMessageSize(buf);
2742 }
2743 buf->thisMsgSize = (int4byte *)buf->bufptr;
2744 *(buf->thisMsgSize) = 0xbbbbbbbb;
2745 buf->bufptr += 4;
2746 buf->state = GET_ARGS;
2747 }
2748
2749 /* Now write the name */
2750 buf->bufptr += OSC_padString(buf->bufptr, name);
2751 buf->typeStringPtr = 0;
2752 buf->gettingFirstUntypedArg = 1;
2753
2754 return 0;
2755}
2756
2757int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types) {
2758 int result;
2759 int4byte paddedLength;
2760
2761 if (CheckTypeTag(buf, '\0')) return 9;
2762
2763 result = OSC_writeAddress(buf, name);
2764
2765 if (result) return result;
2766
2767 paddedLength = OSC_effectiveStringLength(types);
2768
2769 CheckOverflow(buf, paddedLength);
2770
2771 buf->typeStringPtr = buf->bufptr + 1; /* skip comma */
2772 buf->bufptr += OSC_padString(buf->bufptr, types);
2773
2774 buf->gettingFirstUntypedArg = 0;
2775 return 0;
2776}
2777
2778static int CheckTypeTag(OSCbuf *buf, char expectedType) {
2779 if (buf->typeStringPtr) {
2780 if (*(buf->typeStringPtr) != expectedType) {
2781 if (expectedType == '\0') {
2782 OSC_errorMessage =
2783 "According to the type tag I expected more arguments.";
2784 } else if (*(buf->typeStringPtr) == '\0') {
2785 OSC_errorMessage =
2786 "According to the type tag I didn't expect any more arguments.";
2787 } else {
2788 OSC_errorMessage =
2789 "According to the type tag I expected an argument of a different type.";
2790 printf("* Expected %c, string now %s\n", expectedType, buf->typeStringPtr);
2791 }
2792 return 9;
2793 }
2794 ++(buf->typeStringPtr);
2795 }
2796 return 0;
2797}
2798
2799
2800int OSC_writeFloatArg(OSCbuf *buf, float arg) {
2801 int4byte *intp;
2802 //int result;
2803
2804 CheckOverflow(buf, 4);
2805
2806 if (CheckTypeTag(buf, 'f')) return 9;
2807
2808 /* Pretend arg is a long int so we can use htonl() */
2809 intp = ((int4byte *) &arg);
2810 *((int4byte *) buf->bufptr) = htonl(*intp);
2811
2812 buf->bufptr += 4;
2813
2814 buf->gettingFirstUntypedArg = 0;
2815 return 0;
2816}
2817
2818
2819
2820int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args) {
2821 int i;
2822 int4byte *intp;
2823
2824 CheckOverflow(buf, 4 * numFloats);
2825
2826 /* Pretend args are long ints so we can use htonl() */
2827 intp = ((int4byte *) args);
2828
2829 for (i = 0; i < numFloats; i++) {
2830 if (CheckTypeTag(buf, 'f')) return 9;
2831 *((int4byte *) buf->bufptr) = htonl(intp[i]);
2832 buf->bufptr += 4;
2833 }
2834
2835 buf->gettingFirstUntypedArg = 0;
2836 return 0;
2837}
2838
2839int OSC_writeIntArg(OSCbuf *buf, int4byte arg) {
2840 CheckOverflow(buf, 4);
2841 if (CheckTypeTag(buf, 'i')) return 9;
2842
2843 *((int4byte *) buf->bufptr) = htonl(arg);
2844 buf->bufptr += 4;
2845
2846 buf->gettingFirstUntypedArg = 0;
2847 return 0;
2848}
2849
2850int OSC_writeStringArg(OSCbuf *buf, char *arg) {
2851 int len;
2852
2853 if (CheckTypeTag(buf, 's')) return 9;
2854
2855 len = OSC_effectiveStringLength(arg);
2856
2857 if (buf->gettingFirstUntypedArg && arg[0] == ',') {
2858 /* This un-type-tagged message starts with a string
2859 that starts with a comma, so we have to escape it
2860 (with a double comma) so it won't look like a type
2861 tag string. */
2862
2863 CheckOverflow(buf, len+4); /* Too conservative */
2864 buf->bufptr +=
2865 OSC_padStringWithAnExtraStupidComma(buf->bufptr, arg);
2866
2867 } else {
2868 CheckOverflow(buf, len);
2869 buf->bufptr += OSC_padString(buf->bufptr, arg);
2870 }
2871
2872 buf->gettingFirstUntypedArg = 0;
2873 return 0;
2874
2875}
2876
2877/* String utilities */
2878
2879#define STRING_ALIGN_PAD 4
2880int OSC_effectiveStringLength(char *string) {
2881 int len = strlen(string) + 1; /* We need space for the null char. */
2882
2883 /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */
2884 if ((len % STRING_ALIGN_PAD) != 0) {
2885 len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD);
2886 }
2887 return len;
2888}
2889
2890static int OSC_padString(char *dest, char *str) {
2891 int i;
2892
2893 for (i = 0; str[i] != '\0'; i++) {
2894 dest[i] = str[i];
2895 }
2896
2897 return OSC_WritePadding(dest, i);
2898}
2899
2900static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str) {
2901 int i;
2902
2903 dest[0] = ',';
2904 for (i = 0; str[i] != '\0'; i++) {
2905 dest[i+1] = str[i];
2906 }
2907
2908 return OSC_WritePadding(dest, i+1);
2909}
2910
2911static int OSC_WritePadding(char *dest, int i) {
2912 dest[i] = '\0';
2913 i++;
2914
2915 for (; (i % STRING_ALIGN_PAD) != 0; i++) {
2916 dest[i] = '\0';
2917 }
2918
2919 return i;
2920}
2921
2922