[PD-cvs] externals/OSCx/src INVENTORY.txt,NONE,1.2 Makefile.in,NONE,1.2 OSC-common.h,NONE,1.2 OSC-pattern-match.c,NONE,1.2 OSC-pattern-match.h,NONE,1.2 OSC.001,NONE,1.2 OSC.c,NONE,1.2 OSC.dsp,NONE,1.2 OSC.dsw,NONE,1.2 OSCroute.c,NONE,1.2 TODO.txt,NONE,1.2 VERSION,NONE,1.2 dumpOSC.c,NONE,1.2 htmsocket.c,NONE,1.2 htmsocket.h,NONE,1.2 sendOSC.c,NONE,1.2

x75 at users.sourceforge.net x75 at users.sourceforge.net
Wed Mar 10 01:01:58 CET 2004


Update of /cvsroot/pure-data/externals/OSCx/src
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12318/src

Added Files:
	INVENTORY.txt Makefile.in OSC-common.h OSC-pattern-match.c 
	OSC-pattern-match.h OSC.001 OSC.c OSC.dsp OSC.dsw OSCroute.c 
	TODO.txt VERSION dumpOSC.c htmsocket.c htmsocket.h sendOSC.c 
Log Message:
changed to single external style ...


--- NEW FILE: INVENTORY.txt ---
OSC protocol inventory for OSC4PD

sendOSC, dumpOSC, OSCroute
==========================
  INCLUDES
    * typed and untyped packing of OSC messages
    * #bundle packing
    * transmission of OSC messages via UDP socket

    * receive OSC messages on UDP socket
    * unpacking of typed and untyped OSC messages
    * #bundle unpacking

    * static address resolution
    * pattern matching

  OMITS
    * working with timetags
    * all advanced protocol features of documentation, typesigs, etc
    * connection oriented communication


--- NEW FILE: Makefile.in ---
# current: all
# pd_linux
###############################
NAME=OSC
EXT=o
LIBS = -lm -lc
LIBOSC = 	../libOSC/libOSC.a
DEFS= -Dunix

prefix=$(DESTDIR)/usr

# ----------------------- LINUX i386 -----------------------

# pd_linux: $(NAME).pd_linux

SFX=@pd_suffix@

.SUFFIXES: .$(SFX)

CFLAGS += $(DEFS) -DPD -DUNIX -O2 -funroll-loops -fomit-frame-pointer \
    -Wall -W -Wshadow \
    -Wno-unused -Wno-parentheses -Wno-switch

# where is your m_pd.h ???
INCLUDE =  -I../../build/include

# LINUXEXTERNALS = htmsocket.o OSC-pattern-match.o sendOSC.o dumpOSC.o OSCroute.o
# SOURCES = $(wildcard *.c)
SOURCES = OSC-pattern-match.c  OSC.c  dumpOSC.c \
htmsocket.c  OSCroute.c  sendOSC.c
TARGETS = $(SOURCES:.c=.o)
EXTS=sendOSC. at pd_suffix@ dumpOSC. at pd_suffix@ OSCroute. at pd_suffix@ OSC. at pd_suffix@

all: $(EXTS)
sendOSC.pd_linux: htmsocket.o sendOSC.o
	cc -Wl,-export_dynamic -shared -o $*. at pd_suffix@ *.o -lc -lm ../libOSC/libOSC.a

dumpOSC.pd_linux: dumpOSC.o
	cc -Wl,-export_dynamic -shared -o $*. at pd_suffix@ $*.o -lc -lm
OSCroute.pd_linux: OSCroute.o OSC-pattern-match.o
	cc -Wl,-export_dynamic -shared -o $*. at pd_suffix@ $? -lc -lm

OSC.pd_linux: OSC.o
	cc -Wl,-export_dynamic -shared -o $*. at pd_suffix@ $? -lc -lm
	# $(LD) $(LDFLAGS) -o OSC.$(EXT) *.$(EXT) *.o $(LIBS) $(LIBOSC)
#	$(LD) $(LDFLAGS) -o OSC.$(EXT) *.$(EXT) $(LIBS) $(LIBOSC)
$(TARGETS): %.o : %.c
	cc $(CFLAGS) $(INCLUDE) -c -o $*.o $*.c

	# 	cc -c $(CFLAGS) OSC.c

# .c.pd_linux:
#	cc -O2 -Wall -DPD -fPIC $(LINUXCFLAGS) $(LINUXINCLUDE) -c *.c
#	ld -export_dynamic  -shared -o $*.pd_linux $*.o $(LINUXEXTERNALS) $(LIBS)  $(LIBOSC)
#	strip --strip-unneeded $*.pd_linux

# ----------------------------------------------------------

install-doc:
	@test -d $(prefix)/lib/pd/doc/5.reference || mkdir -p $(prefix)/lib/pd/doc/5.reference
	cp -r ../doc/* $(prefix)/lib/pd/doc/5.reference/

install: install-doc
	@test -d $(prefix)/lib/pd/extra || mkdir -p $(prefix)/lib/pd/extra
	install -m644 *.pd_linux $(prefix)/lib/pd/extra

clean:
	rm -rf *.$(EXT) *. at pd_suffix@

# ----------------------- Mac OS X (Darwin) -----------------------

pd_darwin: $(NAME).pd_darwin

SFX=.pd_darwin

.SUFFIXES: $(SFX)

DARWINCFLAGS = -DPD -DUNIX -DMACOSX -O2 \
    -Wall -W -Wshadow -Wstrict-prototypes \
    -Wno-unused -Wno-parentheses -Wno-switch

# where is your m_pd.h ???
DARWININCLUDE =  -I../../../pd/src

DARWINEXTERNALS = htmsocket.o OSC-pattern-match.o sendOSC.o dumpOSC.o OSCroute.o

.c.pd_darwin:
	cc $(DARWINCFLAGS) $(DARWININCLUDE) -c *.c
	cc -bundle -bundle_loader /usr/local/pd/bin/pd -flat_namespace -o $*.pd_darwin $*.o $(DARWINEXTERNALS) $(LIBS) $(LIBOSC)

	rm -f $*.o ../$*.pd_darwin
	ln -s $*/$*.pd_darwin ..



--- NEW FILE: OSC-common.h ---
/*
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.

The OpenSound Control WWW page is 
    http://www.cnmat.berkeley.edu/OpenSoundControl
*/


/* OSC-common.h
   Simple stuff to #include everywhere in the OSC package

   by Matt Wright, 3/13/98
*/

/* Boolean type */

#ifndef TRUE
typedef int Boolean;
#define TRUE 1
#define FALSE 0
#endif


/* Fixed byte width types */
typedef int int4;   /* 4 byte int */

/* Printing type procedures.  All take printf-style format string */

/* Catastrophic failure: print message and halt system */
void fatal_error(char *s, ...);

/* Error message for user */
void OSCProblem(char *s, ...);

/* Warning for user */
void OSCWarning(char *s, ...);



--- NEW FILE: OSC-pattern-match.c ---
/*
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.

The OpenSound Control WWW page is 
    http://www.cnmat.berkeley.edu/OpenSoundControl
*/


/*
    OSC-pattern-match.c
    Matt Wright, 3/16/98
    Adapted from oscpattern.c, by Matt Wright and Amar Chaudhury
 */
#ifdef UNIX
  #include <stdio.h>
#endif

// #ifdef MACOSX
// #include <stdio.h>
// #endif

#include "OSC-common.h"
#include "OSC-pattern-match.h"

static const char *theWholePattern;	/* Just for warning messages */

static Boolean MatchBrackets (const char *pattern, const char *test);
static Boolean MatchList (const char *pattern, const char *test);

Boolean PatternMatch (const char *  pattern, const char * test) {

  // printf("OSC-pattern-match.c: pattern: %s, test: %s\n", pattern, test);

  theWholePattern = pattern;

  // post("pattern: %s, test: %s", pattern, test);
  
  if(test[0] == '*') {
    return TRUE;
  }

  if (pattern == 0 || pattern[0] == 0) {
    return test[0] == 0;
  } 
  
  if (test[0] == 0) {
    if (pattern[0] == '*')
      return PatternMatch (pattern+1,test);
    else
      return FALSE;
  }

  switch (pattern[0]) {
    case 0      : return test[0] == 0;
    case '?'    : return PatternMatch (pattern + 1, test + 1);
    case '*'    : 
      if (PatternMatch (pattern+1, test)) {
        return TRUE;
      } else {
	return PatternMatch (pattern, test+1);
      }
    case ']'    :
    case '}'    :
      printf("Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern);
      return FALSE;
    case '['    :
      return MatchBrackets (pattern,test);
    case '{'    :
      return MatchList (pattern,test);
    case '\\'   :  
      if (pattern[1] == 0) {
	return test[0] == 0;
      } else if (pattern[1] == test[0]) {
	return PatternMatch (pattern+2,test+1);
      } else {
	return FALSE;
      }
    default     :
      if (pattern[0] == test[0]) {
	return PatternMatch (pattern+1,test+1);
      } else {
	return FALSE;
      }
  }
}


/* we know that pattern[0] == '[' and test[0] != 0 */

static Boolean MatchBrackets (const char *pattern, const char *test) {
  Boolean result;
  Boolean negated = FALSE;
  const char *p = pattern;

  if (pattern[1] == 0) {
    printf("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
    return FALSE;
  }

  if (pattern[1] == '!') {
    negated = TRUE;
    p++;
  }

  while (*p != ']') {
    if (*p == 0) {
      printf("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
      return FALSE;
    }
    if (p[1] == '-' && p[2] != 0) {
      if (test[0] >= p[0] && test[0] <= p[2]) {
	result = !negated;
	goto advance;
      }
    }
    if (p[0] == test[0]) {
      result = !negated;
      goto advance;
    }
    p++;
  }

  result = negated;

advance:

  if (!result)
    return FALSE;

  while (*p != ']') {
    if (*p == 0) {
      printf("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
      return FALSE;
    }
    p++;
  }

  return PatternMatch (p+1,test+1);
}

static Boolean MatchList (const char *pattern, const char *test) {

 const char *restOfPattern, *tp = test;


 for(restOfPattern = pattern; *restOfPattern != '}'; restOfPattern++) {
   if (*restOfPattern == 0) {
     printf("Unterminated { in pattern \".../%s/...\"", theWholePattern);
     return FALSE;
   }
 }

 restOfPattern++; /* skip close curly brace */


 pattern++; /* skip open curly brace */

 while (1) {
   
   if (*pattern == ',') {
     if (PatternMatch (restOfPattern, tp)) {
       return TRUE;
     } else {
       tp = test;
       ++pattern;
     }
   } else if (*pattern == '}') {
     return PatternMatch (restOfPattern, tp);
   } else if (*pattern == *tp) {
     ++pattern;
     ++tp;
   } else {
     tp = test;
     while (*pattern != ',' && *pattern != '}') {
       pattern++;
     }
     if (*pattern == ',') {
       pattern++;
     }
   }
 }

}

--- NEW FILE: OSC-pattern-match.h ---
/*
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.

    The OpenSound Control WWW page is http://www.cnmat.berkeley.edu/OpenSoundControl

    OSC-pattern-match.h
*/

//Boolean PatternMatch (const char *pattern, const char *test);
Boolean PatternMatch (const char *pattern, const char *test);


--- NEW FILE: OSC.001 ---
# Microsoft Developer Studio Project File - Name="OSC" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 5.00
# ** DO NOT EDIT **

# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102

CFG=OSC - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE 
!MESSAGE NMAKE /f "OSC.mak".
!MESSAGE 
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE 
!MESSAGE NMAKE /f "OSC.mak" CFG="OSC - Win32 Debug"
!MESSAGE 
!MESSAGE Possible choices for configuration are:
!MESSAGE 
!MESSAGE "OSC - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "OSC - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE 

# Begin Project
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe

!IF  "$(CFG)" == "OSC - Win32 Release"

# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RAFOSC_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../../pd/src" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OSC_EXPORTS" /D "NT" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 pd.lib libc.lib kernel32.lib wsock32.lib LIBOSC.lib /nologo /dll /machine:I386 /nodefaultlib /out:"../../../pd/extra/OSC.dll" /libpath:"../../../pd/lib" /libpath:"../../../pd/bin"
# SUBTRACT LINK32 /pdb:none

!ELSEIF  "$(CFG)" == "OSC - Win32 Debug"

# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /GX /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RAFOSC_EXPORTS" /YX /FD /ZI /GZ /c
# ADD CPP /nologo /MTd /W3 /GX /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OSC_EXPORTS" /D "NT" /YX /FD /ZI /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 pd.lib libc.lib kernel32.lib wsock32.lib LIBOSC.lib /nologo /dll /debug /machine:I386 /nodefaultlib /pdbtype:sept

!ENDIF 

# Begin Target

# Name "OSC - Win32 Release"
# Name "OSC - Win32 Debug"
# Begin Group "Source Files"

# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File

SOURCE=.\dumpOSC.c
# End Source File
# Begin Source File

SOURCE=.\htmsocket.c
# End Source File
# Begin Source File

SOURCE=".\OSC-pattern-match.c"
# End Source File
# Begin Source File

SOURCE=.\OSC.c
# End Source File
# Begin Source File

SOURCE=.\routeOSC.c
# End Source File
# Begin Source File

SOURCE=.\sendOSC.c
# End Source File
# End Group
# Begin Group "Header Files"

# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File

SOURCE=.\htmsocket.h
# End Source File
# Begin Source File

SOURCE=".\OSC-client.h"
# End Source File
# Begin Source File

SOURCE=".\OSC-common.h"
# End Source File
# Begin Source File

SOURCE=".\OSC-pattern-match.h"
# End Source File
# Begin Source File

SOURCE=".\OSC-timetag.h"
# End Source File
# End Group
# Begin Group "Resource Files"

# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

--- NEW FILE: OSC.c ---
/*

	pd
	-------------
		-- tweaks for Win32    www.zeggz.com/raf	13-April-2002

*/

#if HAVE_CONFIG_H 
#include <config.h> 
#endif

#include <m_pd.h>
#include "OSC-common.h"

#define VERSION "0.2"

#ifndef OSC_API 
#define OSC_API
#endif

typedef struct _OSC
{
     t_object x_obj;
} t_OSC;


OSC_API void OSC_setup(void);
OSC_API void OSC_version(t_OSC*);
/*
OSC_API void sendOSC_setup(void);
OSC_API void dumpOSC_setup(void);
OSC_API void OSCroute_setup(void);
*/

static t_class* OSC_class;


static void* OSC_new(t_symbol* s) {
    t_OSC *x = (t_OSC *)pd_new(OSC_class);
    return (x);
}


OSC_API void OSC_version (t_OSC *x) { 

  // EnterCallback();
  post("OSC4PD Version " VERSION
       "\n ¯\\    original code by matt wright. pd-fication jdl at xdv.org\n"
       "   ·   Win32-port raf at interaccess.com\n    \\_ Compiled " __TIME__ " " __DATE__);
  // ExitCallback();
}

OSC_API void OSC_setup(void) { 
  OSC_class = class_new(gensym("OSC"), (t_newmethod)OSC_new, 0,
			  sizeof(t_OSC), 0,0);
  class_addmethod(OSC_class, (t_method)OSC_version, gensym("version"), A_NULL, 0, 0);

  sendOSC_setup();
  dumpOSC_setup();
  OSCroute_setup();
  
  post("O  : Open Sound Control 4 PD, http://www.cnmat.berkeley.edu/OSC");
  post(" S : original code by matt wright, pd hakcs cxc, Win32-port raf at interaccess.com");
  post("  C: ver: "VERSION ", compiled: "__DATE__);
}

--- NEW FILE: OSC.dsp ---
# Microsoft Developer Studio Project File - Name="OSC" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **

# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102

CFG=OSC - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE 
!MESSAGE NMAKE /f "OSC.mak".
!MESSAGE 
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE 
!MESSAGE NMAKE /f "OSC.mak" CFG="OSC - Win32 Debug"
!MESSAGE 
!MESSAGE Possible choices for configuration are:
!MESSAGE 
!MESSAGE "OSC - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "OSC - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE 

# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe

!IF  "$(CFG)" == "OSC - Win32 Release"

# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RAFOSC_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../../pd/src" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OSC_EXPORTS" /D "NT" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 pd.lib libc.lib kernel32.lib wsock32.lib LIBOSC.lib /nologo /dll /machine:I386 /nodefaultlib /out:"../../../pd/extra/OSC.dll" /libpath:"../../../pd/lib" /libpath:"../../../pd/bin"
# SUBTRACT LINK32 /pdb:none

!ELSEIF  "$(CFG)" == "OSC - Win32 Debug"

# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RAFOSC_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OSC_EXPORTS" /D "NT" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 pd.lib libc.lib kernel32.lib wsock32.lib LIBOSC.lib /nologo /dll /debug /machine:I386 /nodefaultlib /pdbtype:sept

!ENDIF 

# Begin Target

# Name "OSC - Win32 Release"
# Name "OSC - Win32 Debug"
# Begin Group "Source Files"

# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File

SOURCE=.\dumpOSC.c
# End Source File
# Begin Source File

SOURCE=.\htmsocket.c
# End Source File
# Begin Source File

SOURCE=".\OSC-pattern-match.c"
# End Source File
# Begin Source File

SOURCE=.\OSC.c
# End Source File
# Begin Source File

SOURCE=.\routeOSC.c
# End Source File
# Begin Source File

SOURCE=.\sendOSC.c
# End Source File
# End Group
# Begin Group "Header Files"

# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File

SOURCE=.\htmsocket.h
# End Source File
# Begin Source File

SOURCE=".\OSC-client.h"
# End Source File
# Begin Source File

SOURCE=".\OSC-common.h"
# End Source File
# Begin Source File

SOURCE=".\OSC-pattern-match.h"
# End Source File
# Begin Source File

SOURCE=".\OSC-timetag.h"
# End Source File
# End Group
# Begin Group "Resource Files"

# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

--- NEW FILE: OSC.dsw ---
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!

###############################################################################

Project: "OSC"=.\OSC.dsp - Package Owner=<4>

Package=<5>
{{{
}}}

Package=<4>
{{{
}}}

###############################################################################

Global:

Package=<5>
{{{
}}}

Package=<3>
{{{
}}}

###############################################################################


--- NEW FILE: OSCroute.c ---
/*
Copyright (c) 1999, 2000, 20010 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.

The OpenSound Control WWW page is
     http://www.cnmat.berkeley.edu/OpenSoundControl

  OSC-route.c
  Max object for OSC-style dispatching

  To-do:

  	Match a pattern against a pattern?
  	Declare outlet types / distinguish leaf nodes from other children
  	More sophisticated (2-pass?) allmessages scheme
  	set message?


	pd
	-------------
		-- tweaks for Win32    www.zeggz.com/raf	13-April-2002


  */

#if HAVE_CONFIG_H 
#include <config.h> 
#endif


/* the required include files */
#include "m_pd.h"
#include "OSC-common.h"
#include "OSC-pattern-match.h"

#ifdef WIN32
	#include <stdlib.h>
	#include <string.h>
#endif
#ifdef MACOSX
  #include <stdio.h>
#endif
#ifdef UNIX
  #include <stdio.h>
#endif

/* structure definition of your object */
#define MAX_NUM 20
#define OSC_ROUTE_VERSION "1.05"
/* Version 1.04: Allows #1 thru #9 as typed-in arguments
   Version 1.05: Allows "list" messages as well as "message" messages.
*/

static t_class *OSCroute_class;

typedef struct _OSCroute
{
  t_object x_obj;			// required header
  t_int x_num;				// Number of address prefixes we store
  t_int x_complainmode;			// Do we print a message if no match?
  t_int x_sendmode;                     // use pd internal sends instead of outlets
  char *x_prefixes[MAX_NUM];
  void *x_outlets[MAX_NUM+1];
} t_OSCroute;

t_symbol *ps_list, *ps_complain, *ps_emptySymbol;

/* prototypes  */

void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);
/* //void *OSCroute_new(t_symbol *s, int argc, atom *argv); */
void *OSCroute_new(t_symbol *s, int argc, t_atom *argv);
void OSCroute_version (t_OSCroute *x);
/* void OSCroute_assist (OSCroute *x, void *box, long msg, long arg,  */
/* 		      char *dstString); */
void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv);

static char *NextSlashOrNull(char *p);
static void StrCopyUntilSlash(char *target, const char *source);


// free
static void OSCroute_free(t_OSCroute *x)
{
  //    freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
}

/* initialization routine */

// setup
#ifdef WIN32
 OSC_API void OSCroute_setup(void) { 
#else
void OSCroute_setup(void) {
#endif
  OSCroute_class = class_new(gensym("OSCroute"), (t_newmethod)OSCroute_new,
			     (t_method)OSCroute_free,sizeof(t_OSCroute), 0, A_GIMME, 0);
  class_addlist(OSCroute_class, OSCroute_list);
  class_addanything(OSCroute_class, OSCroute_anything);
  class_addmethod(OSCroute_class, (t_method)OSCroute_version, gensym("version"), A_NULL, 0, 0);
  class_sethelpsymbol(OSCroute_class, gensym("OSCroute-help.pd"));

  /*
  class_addmethod(OSCroute_class, (t_method)OSCroute_connect,
		  gensym("connect"), A_SYMBOL, A_FLOAT, 0);
  class_addmethod(OSCroute_class, (t_method)OSCroute_disconnect,
		  gensym("disconnect"), 0);
  class_addmethod(OSCroute_class, (t_method)OSCroute_send, gensym("send"),
		  A_GIMME, 0);
  */
/*   ps_list = gensym("list"); */
/*   ps_complain = gensym("complain"); */
  ps_emptySymbol = gensym("");
  
  post("OSCroute object version " OSC_ROUTE_VERSION " by Matt Wright. pd: jdl Win32 raf.");
  post("OSCroute Copyright © 1999 Regents of the University of California. All Rights Reserved.");
}



/* instance creation routine */

void *OSCroute_new(t_symbol *s, int argc, t_atom *argv)
{

  t_OSCroute *x = (t_OSCroute *)pd_new(OSCroute_class);   // get memory for a new object & initialize

  int i;	//{{raf}} n not used
  
  // EnterCallback();
  
  if (argc > MAX_NUM) {
    post("* OSC-route: too many arguments: %ld (max %ld)", argc, MAX_NUM);
    // ExitCallback();
    return 0;
  }

  x->x_complainmode = 0;
  x->x_num = 0;
  for (i = 0; i < argc; ++i) {
    if (argv[i].a_type == A_SYMBOL) {
      if (argv[i].a_w.w_symbol->s_name[0] == '/') {
	/* Now that's a nice prefix */
	x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name;
	++(x->x_num);
      } else if (argv[i].a_w.w_symbol->s_name[0] == '#' &&
		 argv[i].a_w.w_symbol->s_name[1] >= '1' &&
		 argv[i].a_w.w_symbol->s_name[1] <= '9') {
	/* The Max programmer is trying to make a patch that will be
	   a subpatch with arguments.  We have to make an outlet for this
	   argument. */
	x->x_prefixes[i] = "dummy";
	++(x->x_num);
      } else {
	/* Maybe this is an option we support */

/* 	if (argv[i].a_w.w_sym == ps_complain) { */
/* 	  x->x_complainmode = 1; */
/* 	} else { */
/* 	  post("* OSC-route: Unrecognized argument %s", argv[i].a_w.w_sym->s_name); */
/* 	} */

      }

      // no LONG

/*     } else if (argv[i].a_type == A_FLOAD) { */
/*       // Convert to a numeral.  Max ints are -2147483648 to 2147483647 */
/*       char *string = getbytes(12); */
/*       // I can't be bothered to plug this 12 byte memory leak */
/*       if (string == 0) { */
/* 	post("* OSC-route: out of memory!"); */
/* 	// ExitCallback(); */
/* 	return 0; */
/*       } */
/*       sprintf(string, "%d", argv[i].a_w.w_long); */
/*       x->x_prefixes[i] = string; */
/*       ++(x->x_num); */

    } else if (argv[i].a_type == A_FLOAT) {
      post("* OSC-route: float arguments are not OK.");
      // ExitCallback();
      return 0;
    } else {
      post("* OSC-route: unrecognized argument type!");
      // ExitCallback();
      return 0;
    }
  }
  
  
  /* Have to create the outlets in reverse order */
  /* well, not in pd ? */
  //  for (i = x->x_num-1; i >= 0; --i) {
  // for (i = 0; i <= x->x_num-1; i++) {
  for (i = 0; i <= x->x_num; i++) {
    //    x->x_outlets[i] = listout(x);
    x->x_outlets[i] = outlet_new(&x->x_obj, &s_list);
  }
  
  // ExitCallback();
  return (x);
}


void OSCroute_version (t_OSCroute *x) {
  // EnterCallback();
  post("OSCroute Version " OSC_ROUTE_VERSION
       ", by Matt Wright. pd jdl, win32: raf.\nOSCroute Compiled " __TIME__ " " __DATE__);
  // ExitCallback();
}

/* I don't know why these aren't defined in some Max #include file. */
#define ASSIST_INLET 1
#define ASSIST_OUTLET 2

void OSCroute_assist (t_OSCroute *x, void *box, long msg, long arg, 
		      char *dstString) {
  // EnterCallback();
  
  if (msg==ASSIST_INLET) {
    sprintf(dstString, "Incoming OSC messages");
  } else if (msg==ASSIST_OUTLET) {
    if (arg < 0 || arg >= x->x_num) {
      post("* OSCroute_assist: No outlet corresponds to arg %ld!", arg);
    } else {
      sprintf(dstString, "subaddress + args for prefix %s", x->x_prefixes[arg]);
    }
  } else {
    post("* OSCroute_assist: unrecognized message %ld", msg);
  }
  
  // ExitCallback();
}

void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
  // EnterCallback();
  if (argc > 0 && argv[0].a_type == A_SYMBOL) {
    /* Ignore the fact that this is a "list" */
    OSCroute_doanything(x, argv[0].a_w.w_symbol, argc-1, argv+1);
  } else {
    // post("* OSC-route: invalid list beginning with a number");
    // output on unmatched outlet jdl 20020908
    if (argv[0].a_type == A_FLOAT) {
      outlet_float(x->x_outlets[x->x_num], argv[0].a_w.w_float);
    } else {
      post("* OSC-route: unrecognized atom type!");
    }
  }
  // ExitCallback();
}


void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
  // EnterCallback();
  OSCroute_doanything(x, s, argc, argv);
  // ExitCallback();
}




void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
  char *pattern, *nextSlash;
  int i;
  int matchedAnything;
  // post("*** OSCroute_anything(s %s, argc %ld)", s->s_name, (long) argc);
  
  pattern = s->s_name;
  if (pattern[0] != '/') {
    post("* OSC-route: invalid message pattern %s does not begin with /", s->s_name);
    outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
    return;
  }
  
  matchedAnything = 0;
  
  nextSlash = NextSlashOrNull(pattern+1);
  if (*nextSlash == '\0') {
    /* last level of the address, so we'll output the argument list */
    

#ifdef NULL_IS_DIFFERENT_FROM_BANG
    if (argc==0) {
      post("* OSC-route: why are you matching one level pattern %s with no args?",
	   pattern);
      return;
    }
#endif
    
    for (i = 0; i < x->x_num; ++i) {
      if (PatternMatch(pattern+1, x->x_prefixes[i]+1)) {
	++matchedAnything;
	
	// I hate stupid Max lists with a special first element
	if (argc == 0) {
	  outlet_bang(x->x_outlets[i]);
	} else if (argv[0].a_type == A_SYMBOL) {
	  // Promote the symbol that was argv[0] to the special symbol
	  outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1);
	} else if (argc > 1) {
	  // Multiple arguments starting with a number, so naturally we have
	  // to use a special function to output this "list", since it's what
	  // Max originally meant by "list".
	  outlet_list(x->x_outlets[i], 0L, argc, argv);
	} else {
	  // There was only one argument, and it was a number, so we output it
	  // not as a list
/* 	  if (argv[0].a_type == A_LONG) { */
	    
/* 	    outlet_int(x->x_outlets[i], argv[0].a_w.w_long); */
	  //	  } else 
	  if (argv[0].a_type == A_FLOAT) {
	    
	    outlet_float(x->x_outlets[i], argv[0].a_w.w_float);
	  } else {
	    post("* OSC-route: unrecognized atom type!");
	  }
	}
      }
    }
  } else {
    /* There's more address after this part, so our output list will begin with
       the next slash.  */
    t_symbol *restOfPattern = 0; /* avoid the gensym unless we have to output */
    char patternBegin[1000];
    
    
    /* Get the first level of the incoming pattern to match against all our prefixes */
    StrCopyUntilSlash(patternBegin, pattern+1);
    
    for (i = 0; i < x->x_num; ++i) {
      if (PatternMatch(patternBegin, x->x_prefixes[i]+1)) {
	++matchedAnything;
	if (restOfPattern == 0) {
	  restOfPattern = gensym(nextSlash);
	}
	outlet_anything(x->x_outlets[i], restOfPattern, argc, argv);
      }
    }
  }

  if (x->x_complainmode) {
    if (!matchedAnything) {
      post("* OSC-route: pattern %s did not match any prefixes", pattern);
    }
  }

  // output unmatched data on rightmost outlet a la normal 'route' object, jdl 20020908
  if (!matchedAnything) {
    outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
  }


}

static char *NextSlashOrNull(char *p) {
  while (*p != '/' && *p != '\0') {
    p++;
  }
  return p;
}

static void StrCopyUntilSlash(char *target, const char *source) {
  while (*source != '/' && *source != '\0') {
    *target = *source;
    ++target;
    ++source;
  }
  *target = 0;
}

static int MyStrCopy(char *target, const char *source) {
  int i = 0;
  while (*source != '\0') {
    *target = *source;
    ++target;
    ++source;
    ++i;
  }
  *target = 0;
  return i;
}



void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) {
  int i;
  t_symbol *prefixSymbol = 0;
  char prefixBuf[1000];
  char *endOfPrefix;
  t_atom a[1];
  
  if (argc >= 1 && argv[0].a_type == A_SYMBOL) {
    prefixSymbol = argv[0].a_w.w_symbol;
    endOfPrefix = prefixBuf + MyStrCopy(prefixBuf, 
					prefixSymbol->s_name);
  } else {
    prefixSymbol = ps_emptySymbol;
    prefixBuf[0] = '\0';
    endOfPrefix = prefixBuf;
  }
  

  for (i = 0; i < x->x_num; ++i) {
    post("OSC:  %s%s", prefixSymbol->s_name, x->x_prefixes[i]);
    MyStrCopy(endOfPrefix, x->x_prefixes[i]);
    SETSYMBOL(a, gensym(prefixBuf));
    outlet_anything(x->x_outlets[i], s, 1, a);
  }
}

--- NEW FILE: TODO.txt ---

for win32:   port also the command line utilities (send, dump)

-pd object hierarchy extract and automatic address construction
 a la [/hostname]/pd/patchname/subpatch/test ?

-dynamic space allocation for message buffers.

-configure proper (autoconf)


changelog:

20020903: refixed MAXPDARG vs. MAX_ARGS bug causind sendOSC to crash
          with msgs longer than 5 argmuents. ?

20020305: -typetags in send and receive
           sendOSC by default now send typetagged msgs
	   and dumOSC properly reads and outputs them.
	   
prior:

      -added OSCroute with source adapt from max object.
      -fixed shared htmsock bug
      -added sendtyped separately earlier and lost it again
	  
	   

--- NEW FILE: VERSION ---
0.2

--- NEW FILE: dumpOSC.c ---
/*
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

	pd
	-------------
		-- tweaks for Win32    www.zeggz.com/raf	13-April-2002
	
*/

#if HAVE_CONFIG_H 
#include <config.h> 
#endif

#include "m_pd.h"
//#include "m_imp.h"
#include "s_stuff.h"
//#include "x_osc.h"

/* declarations */

// typedef void (*t_fdpollfn)(void *ptr, int fd);
void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);


#if defined(__sgi) || defined(__linux) || defined(WIN32) || defined(MACOSX)

#ifdef WIN32
	#include "OSC-common.h"
	#include <winsock2.h>	
	#include <string.h>
	#include <stdlib.h>
	#include <fcntl.h>
	#include <sys/types.h>
	#include <sys/stat.h>
	#include <ctype.h>
	#include <signal.h>
#else
	#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
#endif


char *htm_error_string;
typedef int Boolean;
typedef void *OBJ;

typedef struct ClientAddressStruct {
        struct sockaddr_in  cl_addr;
        int clilen;
        int sockfd;
} *ClientAddr;

typedef unsigned long long osc_time_t;

Boolean ShowBytes = FALSE;
Boolean Silent = FALSE;

/* Declarations */
#ifndef WIN32
static int unixinitudp(int chan);
#endif

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) ;
char *DataAfterAlignedString(char *string, char *boundary) ;
Boolean IsNiceString(char *string, char *boundary) ;
void complain(char *s, ...);

#define MAXMESG 32768
static char mbuf[MAXMESG];

/* ----------------------------- dumpOSC ------------------------- */

#define MAXOUTAT 50

static t_class *dumpOSC_class;

typedef struct _dumpOSC
{
  t_object x_obj;
  t_outlet *x_msgout;
  t_outlet *x_connectout;
  t_atom x_outat[MAXOUTAT];
  int x_outatc;
  t_binbuf *x_b;
  int x_connectsocket;
  int x_nconnections;
  int x_udp;
  struct sockaddr_in x_server;
  int x_clilen;
} t_dumpOSC;

void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr);
Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd);
static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr);
static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n);
static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma);

static void dumpOSC_read(t_dumpOSC *x, int sockfd) {
  int clilen = x->x_clilen;
  int n;
  struct ClientAddressStruct ras;
  ClientAddr ra = &ras;
  
  //catchupflag= FALSE;
    
/*   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"); */
/*   } */

    //    return catchupflag;
  //struct sockaddr_in x->x_server;
  //while( (n = recvfrom(sockfd, mbuf, MAXMESG, 0, &cl_addr, &clilen)) >0) 
  //  while((
	#ifdef WIN32
	if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (SOCKADDR*)&x->x_server, &clilen)) >0)
	#else
	if ((n = recvfrom(sockfd, mbuf, MAXMESG, 0, (struct sockaddr *)&x->x_server, &clilen)) >0)
	#endif 
	{
		//int r;
		ras.cl_addr = *((struct sockaddr_in *) &x->x_server);
		ras.clilen = x->x_clilen;
		ras.sockfd = x->x_connectsocket;

		#ifdef DEBUG
		printf("dumpOSC_read: received UDP packet of length %d\n",  n);
		#endif
		
		if(!dumpOSC_SendReply(mbuf, n, &x->x_server, clilen, sockfd))
		{
			dumpOSC_ParsePacket(x, mbuf, n, ra);
		}
		//r = Synthmessage(mbuf, n, &x->x_server, clilen, sockfd);
		//post ("%d", r);
		//outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
		//		      emsg-msg-1, at + msg + 1);
		//      outlet_list(x->x_msgout, 0, n, mbuf);
		//if( sgi_HaveToQuit()) goto out;
		//if(r>0) goto back;
		//clilen = maxclilen;
	}  
}

static void *dumpOSC_new(t_symbol *compatflag,
			 t_floatarg fportno) {
  t_dumpOSC *x;
  struct sockaddr_in server;
  int clilen=sizeof(server);
  int sockfd;
  int portno=fportno;
  int udp = 1;

  //x->x_b = binbuf_new();
  //x->x_outat = binbuf_getvec(x->x_b);

  //{{raf}} pointer not valid yet...moving this down
  //x->x_outatc = 0;   {{raf}}

  /* create a socket */
  if ((sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0)) == -1)
    {
      sys_sockerror("socket");
      return (0);
    }

  server.sin_family = AF_INET;
  server.sin_addr.s_addr = INADDR_ANY;
  /* assign server port number */
  server.sin_port = htons((u_short)portno);
  /* name the socket */
  if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
    {
      sys_sockerror("bind");
      sys_closesocket(sockfd);
      return (0);
    }

  x = (t_dumpOSC *)pd_new(dumpOSC_class);
  x->x_outatc = 0;				// {{raf}} now pointer is valid (less invalid)

  x->x_msgout = outlet_new(&x->x_obj, &s_anything);
  
  // if (udp)	    /* datagram protocol */
    {
      
      sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_read, x);
      x->x_connectout = 0;
    }
  //    else    	/* streaming protocol */
  /*     { */
  /* 	if (listen(sockfd, 5) < 0) */
  /* 	{ */
  /*     	    sys_sockerror("listen"); */
  /*     	    sys_closesocket(sockfd); */
  /* 	    sockfd = -1; */
  /* 	} */
  /*     	else */
  /* 	{ */
  /* 	    sys_addpollfn(sockfd, (t_fdpollfn)dumpOSC_connectpoll, x); */
  /*     	    x->x_connectout = outlet_new(&x->x_obj, &s_float); */
  /* 	} */
  /*     } */
  
  x->x_connectsocket = sockfd;
  x->x_server = server;
  x->x_clilen = clilen;
  x->x_nconnections = 0;
  x->x_udp = udp;
  
  return (x);
}

static void dumpOSC_free(t_dumpOSC *x)
{
    	/* LATER make me clean up open connections */
    if (x->x_connectsocket >= 0)
    {
    	sys_rmpollfn(x->x_connectsocket);
    	sys_closesocket(x->x_connectsocket);
    }
}

#ifdef WIN32
OSC_API void dumpOSC_setup(void)
#else
void dumpOSC_setup(void)
#endif
{
    dumpOSC_class = class_new(gensym("dumpOSC"),
    	(t_newmethod)dumpOSC_new, (t_method)dumpOSC_free,
    	sizeof(t_dumpOSC), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT, 
	    A_DEFSYM, 0);
    class_sethelpsymbol(dumpOSC_class, gensym("dumpOSC-help.pd"));
}


#ifndef WIN32
	#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;
	}
#endif	// #ifndef WIN32



static int initudp(int chan)
{

#ifdef WIN32
	struct sockaddr_in serv_addr;
	unsigned int sockfd;
	ULONG nonBlocking = (ULONG) TRUE;

	if(   (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET     ) {
		ZeroMemory((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) {
		//	set for non-blocking mode
			if(ioctlsocket(sockfd, FIONBIO, &nonBlocking) == SOCKET_ERROR) {
				perror("unable to set non-blocking\n"); 
				return -1;
			}
		}
		else  { perror("unable to  bind\n"); return -1; }
	}
	return (sockfd == INVALID_SOCKET ? -1 : (int)sockfd);
#else
	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;
#endif
}








static void closeudp(int sockfd) {
	#ifdef WIN32
		closesocket(sockfd);
	#else
		close(sockfd);
	#endif
}

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;


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 WriteTime(char* dst, osc_time_t osctime)
{
	*(int32_t*)dst = htonl((int32_t)(osctime >> 32));
	*(int32_t*)(dst+4) = htonl((int32_t)osctime);
}

void WriteMode(char* dst)
{
	*(int32_t*)dst = htonl(0);
}

osc_time_t ReadTime(const char* src)
{
  osc_time_t osctime = ntohl(*(int32_t*)src);
  return (osctime << 32) + ntohl(*(int32_t*)(src+4));
}

double TimeToSeconds(osc_time_t osctime)
{
  return (double)osctime * 2.3283064365386962890625e-10 /* 1/2^32 */;
}

int timeRound(double x)
{	
	return x >= 0.0 ? x+0.5 : x-0.5;
}
/*
void WriteLogicalTime(char* dst)
{
        static double startTime = -1.0;
        double sTime;
                                                                                
        // Initialisierung der Startzeit.
        // Knnte effizienter (ohne 'if') auch irgendwo vorher passieren.
        // Knnte wahrscheinlich auch 0.0 sein.
        if (startTime < 0.0) {
                startTime = clock_getlogicaltime();
        }
                                                                                
        sTime = clock_gettimesince(startTime) * 0.001;
        *(int32_t*)dst = hton'K l((int32_t)sTime);
        *(int32_t*)(dst+4) = htonl((int32_t)(4294967296.0 * sTime));
}
*/

void WriteLogicalTime(char* dst)
{
	double sTime = clock_gettimesince(19230720) / 1000.0;
	double tau = sTime - timeRound(sTime);
	
	//fprintf(stderr, "sSec = %f tau = %f\n", sTime, tau);
	
	*(int32_t*)dst = htonl((int32_t)(sTime));
	*(int32_t*)(dst+4) = htonl((int32_t)(4294967296 * tau));
}

Boolean dumpOSC_SendReply(char *buf, int n, void *clientDesc, int clientDescLenght, int fd)
{
	if((n == 24) && (strcmp(buf, "#time") == 0))
	{		
		osc_time_t t0, t1, t2;
		double dt0, dt1, dt2;		

		WriteMode(buf+6);
		
		t0 = ReadTime(buf+8);		
		    
		WriteLogicalTime(buf+16);
		t1 = ReadTime(buf+16); // reverse
		dt0 = TimeToSeconds(t0); // client time
		dt1 = TimeToSeconds(t1); // server time	
		
		//		fprintf(stderr, "%f\t%f\t%f\n", dt0, dt1, dt0 - dt1);

		sendto(fd, buf, n, 0, (struct sockaddr *)clientDesc, clientDescLenght);		
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

//**********************

void dumpOSC_ParsePacket(t_dumpOSC *x, char *buf, int n, ClientAddr returnAddr) {
  //  t_dumpOSC *x;
  int size, messageLen, i;
  char *messageName;
  char *args;
  
  //#ifdef PRINTADDRS
  #ifdef DEBUG
	//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. */
		#ifdef DEBUG
			printf("dumpOSC_ParsePacket: bundle msg: bundles not yet supported\n");
		#endif

		if (n < 16) {
		  complain("Bundle message too small (%d bytes) for time tag", n);
		  return;
		}

		/* Print the time tag */
		#ifdef DEBUG
			printf("[ %lx%08lx\n", ntohl(*((unsigned long *)(buf+8))), ntohl(*((unsigned long *)(buf+12))));
		#endif

		/* 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 */
			dumpOSC_ParsePacket(x, buf+i+4, size, returnAddr);
			i += 4 + size;
		}

		if (i != n) {
			complain("This can't happen");
		}
		#ifdef DEBUG
			printf("]\n");
		#endif

  } 
  else if ((n == 24) && (strcmp(buf, "#time") == 0))
  {
 		complain("Time message: %s\n :).\n", htm_error_string);
		return; 	

  }
  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;
		dumpOSC_Smessage(x, messageName, (void *)args, n-messageLen, returnAddr);
  }
}

#define SMALLEST_POSITIVE_FLOAT 0.000001f

static void dumpOSC_Smessage(t_dumpOSC *x, char *address, void *v, int n, ClientAddr returnAddr) {
  char *chars = v;
  t_atom at;
  //t_atom myargv[50];

  int myargc = x->x_outatc;
  t_atom* mya = x->x_outat;
  int myi;

#ifdef DEBUG
  printf("%s ", address);
#endif

  // ztoln+cvt from envgen.c, ggee-0.18 ..
  // outlet_anything's 'symbol' gets set to address
  // so we dont need to append address to the atomlist
  /*
    SETSYMBOL(mya,gensym(address));myargc++;
    x->x_outatc = myargc;
  */

  if (n != 0) {
    if (chars[0] == ',') {
      if (chars[1] != ',') {
	/* This message begins with a type-tag string */
	dumpOSC_PrintTypeTaggedArgs(x, v, n);
      } else {
	/* Double comma means an escaped real comma, not a type string */
	dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 1);
      }
    } else {
      dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, v, n, 0);
    }
  }

  outlet_anything(x->x_msgout,gensym(address),x->x_outatc,(t_atom*)&x->x_outat);
  x->x_outatc = 0;
#ifdef DEBUG
  printf("\n");
#endif
  fflush(stdout);	/* Added for Sami 5/21/98 */
}

static void dumpOSC_PrintTypeTaggedArgs(t_dumpOSC *x, void *v, int n) { 
  char *typeTags, *thisType;
  char *p;
  
  int myargc = x->x_outatc;
  t_atom* mya = x->x_outat;
  int myi;

  typeTags = v;
  
  if (!IsNiceString(typeTags, typeTags+n)) {
    /* No null-termination, so maybe it wasn't a type tag
       string after all */
    dumpOSC_PrintHeuristicallyTypeGuessedArgs(x, 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':
#ifdef DEBUG
      //post("integer: %d", ntohl(*((int *) p)));
#endif
      /* Martin Peach fix for negative floats:
	   * was: SETFLOAT(mya+myargc,ntohl(*((int *) p))); 
	   * now is: 
	   */
      SETFLOAT(mya+myargc,(signed)ntohl(*((int *) p)));
      myargc++;

      p += 4;
      break;

    case 'f': {
      int i = ntohl(*((int *) p));
      float *floatp = ((float *) (&i));
#ifdef DEBUG
      post("float: %f", *floatp);
#endif
      SETFLOAT(mya+myargc,*floatp);
      myargc++;

      p += 4;
    }
    break;

    case 'h': case 't':
#ifdef DEBUG
      printf("[A 64-bit int] ");
#endif
      post("[A 64-bit int] not implemented");

      p += 8;
      break;

    case 'd':
#ifdef DEBUG
      printf("[A 64-bit float] ");
#endif
      post("[A 64-bit float] not implemented");

      p += 8;
      break;

    case 's': case 'S':
      if (!IsNiceString(p, typeTags+n)) {
	post("Type tag said this arg is a string but it's not!\n");
	return;
      } else {
#ifdef DEBUG
	post("string: \"%s\"", p);
#endif
	SETSYMBOL(mya+myargc,gensym(p));
	myargc++;
	//outlet_list(x->x_msgout, 0,sizeof(p), p);
	//outlet_anything(x->x_msgout, 0, sizeof(p), p);
	p = DataAfterAlignedString(p, typeTags+n);
	// append to output vector ..
      }
      break;

    case 'T':
#ifdef DEBUG
      printf("[True] ");
#endif
      SETFLOAT(mya+myargc,1.);
      myargc++;
      break;
    case 'F':
#ifdef DEBUG
      printf("[False] ");
#endif
      SETFLOAT(mya+myargc,0.);
      myargc++;
      break;
    case 'N':
#ifdef DEBUG
      printf("[Nil]");
#endif
      post("sendOSC: [Nil] not implemented");
      break;
    case 'I':
#ifdef DEBUG
      printf("[Infinitum]");
#endif
      post("sendOSC: [Infinitum] not implemented");
      break;

    default:
      post("sendOSC: [Unrecognized type tag %c]", *thisType);
      // return;
    }
  }
  x->x_outatc = myargc;
}

static void dumpOSC_PrintHeuristicallyTypeGuessedArgs(t_dumpOSC *x, void *v, int n, int skipComma) {
  int i, thisi;
  float thisf;
  int *ints;
  char *chars;
  char *string, *nextString;
	
  int myargc= x->x_outatc;
  t_atom* mya = x->x_outat;
  int myi;


  /* 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) {
#ifdef DEBUG
      printf("%d ", thisi);
#endif
      // append to output vector ..
      SETFLOAT(mya+myargc,(t_float) (thisi));
      myargc++;
      //      outlet_float(x->x_msgout, thisi);
      i++;
    } else if (thisf >= -1000.f && thisf <= 1000000.f &&
	       (thisf <=0.0f || thisf >= SMALLEST_POSITIVE_FLOAT)) {
#ifdef DEBUG
      printf("%f ",  thisf);
#endif
      // append to output vector ..
      SETFLOAT(mya+myargc,thisf);
      myargc++;
      //outlet_float(x->x_msgout, thisf);
      i++;
    } else if (IsNiceString(string, chars+n)) {
      nextString = DataAfterAlignedString(string, chars+n);
#ifdef DEBUG
      printf("\"%s\" ", (i == 0 && skipComma) ? string +1 : string);
#endif
      // append to output vector ..
      SETSYMBOL(mya+myargc,gensym(string));
      myargc++;
      //outlet_symbol(x->x_msgout, gensym((i == 0 && skipComma) ? string +1 : string));
      i += (nextString-string) / 4;
    } else {
      // unhandled .. ;)
#ifdef DEBUG
      printf("0x%x xx", ints[i]);
#endif
      i++;
    }
    x->x_outatc = myargc;
  }
}


#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;
}









#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 or WIN32 */

--- NEW FILE: htmsocket.c ---
/*
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.
 */

#if HAVE_CONFIG_H 
#include <config.h> 
#endif

#ifdef MACOSX
  #include <string.h>
#endif

#ifdef WIN32
	#include <sys/types.h>
	#include <sys/stat.h>
	#include <winsock2.h>	
	#include <ctype.h>
	#include <signal.h>
	#include <sys/types.h>
	#include <stdlib.h>
	#include "OSC-common.h"
#else
	#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>
#endif










#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 */
	#ifndef WIN32
		struct sockaddr_un userv_addr; /* UNIX socket */
	#endif
	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)
{
	struct sockaddr_in  cl_addr;
	#ifndef WIN32
		int sockfd;
		struct sockaddr_un ucl_addr;
	#else
		unsigned int sockfd;
	#endif

	desc *o;
	o = malloc(sizeof(*o));
	if(!o)
		return 0;
	int oval = 1;

  #ifndef WIN32

	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

  #endif

	{
		/*
		         * Fill in the structure "serv_addr" with the address of the
		         * server that we want to send to.
		*/
		o->len = sizeof(cl_addr);

		#ifdef WIN32
			ZeroMemory((char *)&o->serv_addr, sizeof(o->serv_addr));
		#else
			bzero((char *)&o->serv_addr, sizeof(o->serv_addr));
		#endif

		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);
				#ifndef WIN32
				herror(NULL);
				#endif
				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 */

		/*
		 * Open a socket (a UDP domain datagram socket).
		 */


		#ifdef WIN32
			o->serv_addr.sin_port = htons((USHORT)portnumber);
			o->addr = &(o->serv_addr);
			if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) {
				ZeroMemory((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);
				
				// enable broadcast
				if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) {
				  perror("setsockopt");
				}

				if(bind(sockfd, (struct sockaddr *) &cl_addr, sizeof(cl_addr)) < 0) {
					perror("could not bind\n");
					closesocket(sockfd);
					sockfd = -1;
				}
			}
			else { perror("unable to make socket\n");}
		#else
			o->serv_addr.sin_port = htons(portnumber);
			o->addr = &(o->serv_addr);
			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);
				
				// enable broadcast
				if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &oval, sizeof(int)) == -1) {
				  perror("setsockopt");
				}

				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");}
		#endif
	}
	#ifdef WIN32
		if(sockfd == INVALID_SOCKET) {
	#else
		if(sockfd < 0) {
	#endif
			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;
	#ifdef WIN32
	if(SOCKET_ERROR == closesocket(o->sockfd)) {
		perror("CloseHTMSocket::closesocket failed\n");
		return;
	}
	#else
	if(close(o->sockfd) == -1)
	  {
	    perror("CloseHTMSocket::closesocket failed");
	    return;
	  }
	#endif

	free(o);
}

--- NEW FILE: htmsocket.h ---
/*
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);

--- NEW FILE: sendOSC.c ---
/*
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 sendOSC.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.
   


   pd
   -------------
   -- added bundle stuff to send. jdl 20020416
   -- tweaks for Win32    www.zeggz.com/raf	13-April-2002
   -- ost_at_test.at + i22_at_test.at, 2000-2002
      modified to compile as pd externel

*/

#if HAVE_CONFIG_H 
#include <config.h> 
#endif

//#define VERSION "http://cnmat.berkeley.edu/OpenSoundControl/sendOSC-0.1.html"
#define MAX_ARGS 2000
#define SC_BUFFER_SIZE 64000

/*
compiling:
        cc -o sendOSC sendOSC.c htmsocket.c OpenSoundControl.c OSC_timeTag.c
*/

#ifdef WIN32
	#include "m_pd.h"
	#include "OSC-client.h"
	#include "htmsocket.h"
	#include "OSC-common.h"
	#include <winsock2.h>	
	#include <io.h>    
	#include <errno.h>
	#include <fcntl.h>
	#include <sys/stat.h>
	#include <stdlib.h>
	#include <string.h>
	#include <sys/types.h>
#else
	#include "m_pd.h"
	//#include "x_osc.h"
	#include "OSC-client.h"
	#include "htmsocket.h"

	#include <stdio.h>
	#include <stdlib.h>
	#include <string.h>
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <netdb.h>
	#include <ctype.h>
#endif

///////////////////////
// from sendOSC

typedef struct {
    //enum {INT, FLOAT, STRING} type;
    enum {INT_osc, FLOAT_osc, STRING_osc} 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 send_complain(char *s, ...);

//static void *htmsocket;
static int exitStatus = 0;  
static int useTypeTags = 0;

static char bufferForOSCbuf[SC_BUFFER_SIZE];


/////////
// end from sendOSC

static t_class *sendOSC_class;

typedef struct _sendOSC
{
  t_object x_obj;
  int x_protocol;      // UDP/TCP (udp only atm)
  t_int x_typetags;    // typetag flag
  void *x_htmsocket;   // sending socket
  int x_bundle;        // bundle open flag
  OSCbuf x_oscbuf[1];  // OSCbuffer
  t_outlet *x_bdpthout;// bundle-depth floatoutlet
} t_sendOSC;

static void *sendOSC_new(t_floatarg udpflag)
{
    t_sendOSC *x = (t_sendOSC *)pd_new(sendOSC_class);
    outlet_new(&x->x_obj, &s_float);
    x->x_htmsocket = 0;		// {{raf}}
    // set udp
    x->x_protocol = SOCK_STREAM;
    // set typetags to 1 by default
    x->x_typetags = 1;
    // bunlde is closed
    x->x_bundle   = 0;
    OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
    x->x_bdpthout = outlet_new(&x->x_obj, 0); // outlet_float();
    //x->x_oscbuf   =
    return (x);
}


void sendOSC_openbundle(t_sendOSC *x)
{
  if (x->x_oscbuf->bundleDepth + 1 >= MAX_BUNDLE_NESTING ||
      OSC_openBundle(x->x_oscbuf, OSCTT_Immediately()))
    {
    send_complain("Problem opening bundle: %s\n", OSC_errorMessage);
    return;
  }
  x->x_bundle = 1;
  outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
}

static void sendOSC_closebundle(t_sendOSC *x)
{
  if (OSC_closeBundle(x->x_oscbuf)) {
    send_complain("Problem closing bundle: %s\n", OSC_errorMessage);
    return;
  }
  outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
  // in bundle mode we send when bundle is closed?
  if(!OSC_isBufferEmpty(x->x_oscbuf) > 0 && OSC_isBufferDone(x->x_oscbuf)) {
    // post("x_oscbuf: something inside me?");
    if (x->x_htmsocket) {
      SendBuffer(x->x_htmsocket, x->x_oscbuf);
    } else {
      post("sendOSC: not connected");
    }
    OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
    x->x_bundle = 0;
    return;
  }
  // post("x_oscbuf: something went wrong");
}

static void sendOSC_settypetags(t_sendOSC *x, t_float *f)
 {
   x->x_typetags = (int)f;
   post("sendOSC.c: setting typetags %d",x->x_typetags);
 }


static void sendOSC_connect(t_sendOSC *x, t_symbol *hostname,
			    t_floatarg fportno)
{
	int portno = fportno;
	/* create a socket */

	//	make sure handle is available
	if(x->x_htmsocket == 0) {
		//
		x->x_htmsocket = OpenHTMSocket(hostname->s_name, portno);
		if (!x->x_htmsocket)
			post("Couldn't open socket: ");
		else {
			post("connected to port %s:%d (hSock=%d)",  hostname->s_name, portno, x->x_htmsocket);
			outlet_float(x->x_obj.ob_outlet, 1);
		}
	}
	else 
		perror("call to sendOSC_connect() against UNavailable socket handle");
}

void sendOSC_disconnect(t_sendOSC *x)
{
  if (x->x_htmsocket)
    {
      post("disconnecting htmsock (hSock=%d)...", x->x_htmsocket);
      CloseHTMSocket(x->x_htmsocket);
	  x->x_htmsocket = 0;	// {{raf}}  semi-quasi-semaphorize this
      outlet_float(x->x_obj.ob_outlet, 0);
    }
  else {
	perror("call to sendOSC_disconnect() against unused socket handle");
  }
}

void sendOSC_senduntyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
{
  char* targv[MAXPDARG];
  char tmparg[MAXPDSTRING];
  char* tmp = tmparg;
  //char testarg[MAXPDSTRING];
  int c;

  post("sendOSC: use typetags 0/1 message and plain send method so send untypetagged...");
  return;

  //atom_string(argv,testarg, MAXPDSTRING);
  for (c=0;c<argc;c++) {
    atom_string(argv+c,tmp, 80);
    //    post ("sendOSC: %d, %s",c, tmp);
    targv[c] = tmp;
    tmp += strlen(tmp)+1;
    //post ("sendOSC: %d, %s",c, targv[c]);
  }
  // this sock needs to be larger than 0, not >= ..
  if (x->x_htmsocket)
    {
      CommandLineMode(argc, targv, x->x_htmsocket);
      //      post("test %d", c);
    }
  else {
    post("sendOSC: not connected");
    //    exit(3);
  }
}

//////////////////////////////////////////////////////////////////////
// this is the real and only sending routine now, for both typed and undtyped mode.

static void sendOSC_sendtyped(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv)
{
  char* targv[MAX_ARGS];
  char tmparg[MAXPDSTRING];
  char* tmp = tmparg;
  int c;

  char *messageName;
  char *token;
  typedArg args[MAX_ARGS];
  int i,j;
  int numArgs = 0;

  messageName = "";
#ifdef DEBUG
  post ("sendOSC: messageName: %s", messageName);
#endif


  
  for (c=0;c<argc;c++) {
    atom_string(argv+c,tmp, 80);

#ifdef DEBUG
    // post ("sendOSC: %d, %s",c, tmp);
#endif

    targv[c] = tmp;
    tmp += strlen(tmp)+1;

#ifdef DEBUG
    // post ("sendOSC: %d, %s",c, targv[c]);
#endif
  }

  // this sock needs to be larger than 0, not >= ..
  if (x->x_htmsocket > 0)
    { 
#ifdef DEBUG
    post ("sendOSC: type tags? %d", useTypeTags);
#endif 

      messageName = strtok(targv[0], ",");
      j = 1;
      for (i = j; i < argc; i++) {
	token = strtok(targv[i],",");
	args[i-j] = ParseToken(token);
#ifdef DEBUG
	printf("cell-cont: %s\n", targv[i]);
	printf("  type-id: %d\n", args[i-j]);
#endif
	numArgs = i;
      }
      

      if(WriteMessage(x->x_oscbuf, messageName, numArgs, args)) {
	post("sendOSC: usage error, write-msg failed: %s", OSC_errorMessage);
	return;
      }
      
      if(!x->x_bundle) {
/* 	// post("sendOSC: accumulating bundle, not sending things ...");	 */
/*       } else { */
	// post("sendOSC: yeah and OUT!");
	SendBuffer(x->x_htmsocket, x->x_oscbuf);
	OSC_initBuffer(x->x_oscbuf, SC_BUFFER_SIZE, bufferForOSCbuf);
      }
      
      //CommandLineMode(argc, targv, x->x_htmsocket);
      //useTypeTags = 0;
    }
  else {
    post("sendOSC: not connected");
    //    exit(3);
  }
}

void sendOSC_send(t_sendOSC *x, t_symbol *s, int argc, t_atom *argv) 
{
  if(!argc) {
    post("not sending empty message.");
    return;
  }
  if(x->x_typetags) {
    useTypeTags = 1;
    sendOSC_sendtyped(x,s,argc,argv);
    useTypeTags = 0;
  } else {
    sendOSC_sendtyped(x,s,argc,argv);
  }
}

static void sendOSC_free(t_sendOSC *x)
{
    sendOSC_disconnect(x);
}

#ifdef WIN32
	OSC_API void sendOSC_setup(void) { 
#else
	void sendOSC_setup(void) {
#endif
    sendOSC_class = class_new(gensym("sendOSC"), (t_newmethod)sendOSC_new,
			      (t_method)sendOSC_free,
			      sizeof(t_sendOSC), 0, A_DEFFLOAT, 0);
    class_addmethod(sendOSC_class, (t_method)sendOSC_connect,
		    gensym("connect"), A_SYMBOL, A_FLOAT, 0);
    class_addmethod(sendOSC_class, (t_method)sendOSC_disconnect,
		    gensym("disconnect"), 0);
    class_addmethod(sendOSC_class, (t_method)sendOSC_settypetags,
		    gensym("typetags"),
		    A_FLOAT, 0);
    class_addmethod(sendOSC_class, (t_method)sendOSC_send,
		    gensym("send"),
		    A_GIMME, 0);
    class_addmethod(sendOSC_class, (t_method)sendOSC_send,
		    gensym("senduntyped"),
		    A_GIMME, 0);
    class_addmethod(sendOSC_class, (t_method)sendOSC_send,
		    gensym("sendtyped"),
		    A_GIMME, 0);
    class_addmethod(sendOSC_class, (t_method)sendOSC_openbundle,
		    gensym("["),
		    0, 0);
    class_addmethod(sendOSC_class, (t_method)sendOSC_closebundle,
		    gensym("]"),
		    0, 0);
    class_sethelpsymbol(sendOSC_class, gensym("sendOSC-help.pd"));
}





/* Exit status codes:
    0: successful
    2: Message(s) dropped because of buffer overflow
    3: Socket error
    4: Usage error
    5: Internal error
*/

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) {
    post("argc (%d) > 1", argc);
/* 	if (OSC_openBundle(buf, OSCTT_Immediately())) { */
/* 	    send_complain("Problem opening bundle: %s\n", OSC_errorMessage); */
/* 	    return; */
/* 	} */
    }

  //    ParseInteractiveLine(buf, argv);
  messageName = strtok(argv[0], ",");

    j = 1;
    for (i = j; i < argc; i++) {
      token = strtok(argv[i],",");
      args[i-j] = ParseToken(token);
#ifdef DEBUG
      printf("cell-cont: %s\n", argv[i]);
      printf("  type-id: %d\n", args[i-j]);
#endif
      numArgs = i;
    }

    if(WriteMessage(buf, messageName, numArgs, args)) {
      post("sendOSC: usage error. write-msg failed: %s", OSC_errorMessage);
      return;
    }

/*     for (i = 0; i < argc; i++) { */
/*         messageName = strtok(argv[i], ","); */
/* 	//send_complain ("commandlinemode: count: %d %s\n",i, messageName); */
/*         if (messageName == NULL) { */
/*             break; */
/*         } */

/*         j = 0; */
/*         while ((token = strtok(NULL, ",")) != NULL) { */
/*             args[j] = ParseToken(token); */
/*             j++; */
/* 	    if (j >= MAX_ARGS) { */
/* 		send_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)) { */
/* 	    send_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)) {
		send_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) {
                send_complain("Unexpected ']': not currently in a bundle.\n");
            } else {
		if (OSC_closeBundle(buf)) {
		    send_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_osc) {
	    send_complain("warning: inscrutable time tag request: %s\n", s);
	    return OSCTT_Immediately();
	} else if (arg.type == INT_osc) {
	    return OSCTT_PlusSeconds(OSCTT_CurrentTime(),
				     (float) arg.datum.i);
	} else if (arg.type == FLOAT_osc) {
	    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) {
	    send_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;
    }

    send_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())) {
	    send_complain("Problem opening bundle: %s\n", OSC_errorMessage);
	    return;
	}

	arg.type = INT_osc;
	arg.datum.i = 0;
	WriteMessage(buf, "/voices/0/tp/timbre_index", 1, &arg);

	arg.type = FLOAT_osc;
	arg.datum.i = 0.0f;
	WriteMessage(buf, "/voices/0/tm/goto", 1, &arg);

	if (OSC_closeBundle(buf)) {
	    send_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_osc;
            args[thisArg].datum.s = p;

            while (*p != '"') {
                if (*p == '\0') {
                    send_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) {
	  send_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)  {
	send_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_osc;
            returnVal.datum.i = atoi(token);
            return returnVal;
        }
        if (*p == '.') {
            p++;
            while (isdigit(*p)) p++;
            if (*p == '\0') {
                returnVal.type = FLOAT_osc;
                returnVal.datum.f = atof(token);
                return returnVal;
            }
        }
    }

    returnVal.type = STRING_osc;
    returnVal.datum.s = token;
    return returnVal;
}

int WriteMessage(OSCbuf *buf, char *messageName, int numArgs, typedArg *args) {
  int j, returnVal;
  const int wmERROR = -1;

  returnVal = 0;

#ifdef DEBUG
  printf("WriteMessage: %s ", messageName);

  for (j = 0; j < numArgs; j++) {
    switch (args[j].type) {
    case INT_osc:
      printf("%d ", args[j].datum.i);
      break;
      
    case FLOAT_osc:
      printf("%f ", args[j].datum.f);
      break;
      
    case STRING_osc:
      printf("%s ", args[j].datum.s);
      break;
      
    default:
      fatal_error("Unrecognized arg type, (not exiting)");
      return(wmERROR);
      // exit(5);
    }
  }
  printf("\n");
#endif
  
  if (!useTypeTags) {
    returnVal = OSC_writeAddress(buf, messageName);
    if (returnVal) {
      send_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_osc:
	typeTags[i+1] = 'i';
	break;
	
      case FLOAT_osc:
	typeTags[i+1] = 'f';
	break;
	
      case STRING_osc:
	typeTags[i+1] = 's';
	break;
	
      default:
	fatal_error("Unrecognized arg type (not exiting)");
	return(wmERROR);
	// exit(5);
      }
    }
    typeTags[i+1] = '\0';
    
    returnVal = OSC_writeAddressAndTypes(buf, messageName, typeTags);
    if (returnVal) {
      send_complain("Problem writing address: %s\n", OSC_errorMessage);
    }
  }

  for (j = 0; j < numArgs; j++) {
    switch (args[j].type) {
    case INT_osc:
      if ((returnVal = OSC_writeIntArg(buf, args[j].datum.i)) != 0) {
	return returnVal;
      }
      break;
      
    case FLOAT_osc:
      if ((returnVal = OSC_writeFloatArg(buf, args[j].datum.f)) != 0) {
	return returnVal;
      }
      break;
      
    case STRING_osc:
      if ((returnVal = OSC_writeStringArg(buf, args[j].datum.s)) != 0) {
	return returnVal;
      }
      break;
      
    default:
      fatal_error("Unrecognized arg type (not exiting)");
      returnVal = wmERROR;
      // exit(5);
    }
  }
  return returnVal;
}

void SendBuffer(void *htmsocket, OSCbuf *buf) {
#ifdef DEBUG
  printf("Sending buffer...\n");
#endif
  if (OSC_isBufferEmpty(buf)) {
		post("SendBuffer() called but buffer empty");
		return;
  }
  if (!OSC_isBufferDone(buf)) {
		fatal_error("SendBuffer() called but buffer not ready!, not exiting");
		// exit(5); 
		return;	//{{raf}}
  }
  SendData(htmsocket, OSC_packetSize(buf), OSC_getPacket(buf));
}

void SendData(void *htmsocket, int size, char *data) {
  if (!SendHTMSocket(htmsocket, size, data)) {
    post("SendData::SendHTMSocket()failure -- not connected");
    CloseHTMSocket(htmsocket);
    //    sendOSC_disconnect();
    //exit(3);
    //    return;
  }
}

void fatal_error(char *s) {
    fprintf(stderr, "FATAL ERROR: %s\n", s);
    post("fatal error, not exiting ...");
    //exit(4);
}

#include <stdarg.h>
void send_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_osc: case FLOAT_osc:
            size += 4;
            break;

            case STRING_osc:
            size += SynthControl_effectiveStringLength(args[j].datum.s);
            break;

            default:
            fatal_error("Unrecognized token type ( not exiting)");
            // exit(4);
        }
    }

    if (!SynthControl_willMessageFit(buf, size)) {
        send_complain("Message \"%s\" won't fit in buffer: dropping.", messageName);
        return;
    }
#endif





More information about the Pd-cvs mailing list