aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan Jurish <mukau@users.sourceforge.net>2007-07-26 12:20:50 +0000
committerBryan Jurish <mukau@users.sourceforge.net>2007-07-26 12:20:50 +0000
commit0d8513a9086f284cb2cd33beacfd4e8d64adcc44 (patch)
treea2712f9623790f7fecc8e0c4d52529f6e20382dc
parent4613a9c711dfd5882bc1e1ce561bcff83097e33e (diff)
pdstring v0.05
+ added persistent string buffer to any2string + added initial buffer size and eos-character arguments to any2string, string2any - defaults are backwards-compatible but ugly + added --enable-object-externals option to configure svn path=/trunk/externals/moocow/pdstring/; revision=8247
-rw-r--r--README.txt45
-rw-r--r--configure.in29
-rw-r--r--src/Makefile.am10
-rw-r--r--src/any2string-help.pd39
-rw-r--r--src/any2string.c171
-rw-r--r--src/any2string_static.c246
-rw-r--r--src/pdstring-help.pd24
-rw-r--r--src/pdstring.c17
-rw-r--r--src/string2any-help.pd42
-rw-r--r--src/string2any.c129
10 files changed, 621 insertions, 131 deletions
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..b715526
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,45 @@
+ README for pd external package 'pdstring'
+
+ Last updated for pdstring v0.02
+
+DESCRIPTION
+ The 'pdstring' package contains objects for converting to and from
+ (ASCII)-strings, represented as lists of floats.
+
+INSTALLATION
+ Issue the following commands to the shell:
+
+ cd PACKAGE-XX.YY (or wherever you extracted the distribution)
+ ./configure
+ make
+ make install
+
+BUILD OPTIONS
+ The 'configure' script supports the following options, among others:
+
+ * --enable-debug , --disable-debug
+ Whether to enable verbose debugging messages. Default=no.
+
+ACKNOWLEDGEMENTS
+ PD by Miller Puckette and others.
+
+ Ideas, black magic, and other nuggets of information drawn from code by
+ Guenter Geiger, Larry Troxler, and iohannes m zmoelnig.
+
+KNOWN BUGS
+ Memory Usage
+ Encoding each byte of a string as its own float is shamefully wasteful:
+ it uses only 1 byte out of at least 3 which could be losslessly used
+ given ANSI/IEEE Std 754-1985 floats, not to mention the remaining
+ byte(s) (usually 1) of the float itself or the (usually 4) bytes used
+ for the a_type flag. Unfortunately, Pd trims some floating point
+ precision in message boxes and in float atoms, so a truly lossless float
+ encoding for Pd would only be possible using 2 bytes per float (wasting
+ 1/2 the space of the float itself), and (to me), the memory saving such
+ an encoding would provide is just not worth the lack of transparency and
+ additional workload it would involve (but contact me if you want the
+ code anyways).
+
+AUTHOR
+ Bryan Jurish <moocow@ling.uni-potsdam.de>
+
diff --git a/configure.in b/configure.in
index 703fa8f..350fb84 100644
--- a/configure.in
+++ b/configure.in
@@ -4,7 +4,7 @@ AC_PREREQ(2.5)
dnl Some handy macros
define([THE_PACKAGE_NAME], [pdstring])
-define([THE_PACKAGE_VERSION], [0.04])
+define([THE_PACKAGE_VERSION], [0.05])
define([THE_PACKAGE_AUTHOR], [moocow@ling.uni-potsdam.de])
AC_INIT(THE_PACKAGE_NAME, THE_PACKAGE_VERSION, THE_PACKAGE_AUTHOR)
@@ -72,8 +72,31 @@ AC_CHECK_HEADERS([string.h],
[/* nonempty includes: compile only */])
-dnl PD externals
+##------- PD externals
+PD_LIB_EXTERNALS="pdstring"
+PD_OBJ_EXTERNALS="any2string string2any"
+
+AC_ARG_ENABLE(object-externals,
+ AC_HELP_STRING([--enable-object-externals], [Whether to build single-object externals (default=no)]),
+ [want_objext="$enableval"],
+ [want_objext="no"])
+AC_MSG_CHECKING([whether to build single-object externals])
+
+##-- always build lib
PD_OBJECT_EXTERNALS="pdstring\$(EXEEXT)"
+
+if test "$want_objext" != "no" ; then
+ ##-- single-objects
+ AC_MSG_RESULT(yes)
+ for ext in $PD_OBJ_EXTERNALS ; do
+ PD_OBJECT_EXTERNALS="$PD_OBJECT_EXTERNALS ${ext}\$(EXEEXT)"
+ done
+ AC_DEFINE(PDSTRING_OBJECT_EXTERNALS,1,
+ [Define this if you are building single-object externals])
+else
+ ##-- libs
+ AC_MSG_RESULT(no)
+fi
AC_SUBST(PD_OBJECT_EXTERNALS)
@@ -128,7 +151,7 @@ if test "$enable_debug" == "yes" ; then
AC_DEFINE(ANY2STRING_DEBUG,1,
[Define this to include debugging code for the 'string2any' external.])
AC_DEFINE(STRING2ANY_DEBUG,1,
- [Define this to include debugging code for 'the any2string' external.])
+ [Define this to include debugging code for the 'any2string' external.])
else
AC_MSG_RESULT(no)
DEBUG="no"
diff --git a/src/Makefile.am b/src/Makefile.am
index 2ff35cd..fcc75a2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -39,17 +39,17 @@ EXTRA_PROGRAMS = \
pdexterns_DATA =
## --- documentation
-pddoc_DATA = pdstring-help.pd
+pddoc_DATA = \
+ pdstring-help.pd \
+ any2string-help.pd \
+ string2any-help.pd
#-----------------------------------------------------------------------
# sources
#-----------------------------------------------------------------------
-pdstring_SOURCES = \
- any2string.c \
- string2any.c \
- pdstring.c
+pdstring_SOURCES = pdstring.c
any2string_SOURCES = any2string.c
diff --git a/src/any2string-help.pd b/src/any2string-help.pd
new file mode 100644
index 0000000..695de06
--- /dev/null
+++ b/src/any2string-help.pd
@@ -0,0 +1,39 @@
+#N canvas 90 20 636 478 10;
+#X obj 25 400 print any2string-help;
+#X obj 25 314 any2string 128 -1;
+#X msg 109 197 0;
+#X msg 77 197 -1;
+#X text 19 47 INLETS:;
+#X text 31 61 1 - pd messages;
+#X text 247 49 OUTLETS:;
+#X text 263 63 1 - lists of ASCII-valued floats;
+#X floatatom 44 147 8 0 0 0 - - -;
+#X symbolatom 34 125 10 0 0 0 - - -;
+#X text 189 125 ... no special handling for symbols;
+#X text 188 103 anything can be converted to a list...;
+#X text 190 147 ... but "float" selector is silently dropped;
+#X msg 25 104 A B C;
+#X text 193 312 First argument: initial buffer size (length of object-local
+text buffer). This should get re-allocated when necessary. Specify
+0 (zero) to use the default value.;
+#X text 195 367 Second argument: initial EOS character. See above.
+;
+#X text 320 458 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X text 19 439 SEE ALSO:;
+#X msg 139 197 42;
+#X text 21 29 SYNTAX: any2string [INITIAL_BUFSIZE [EOS_CHAR]];
+#X text 184 194 The second inlet sets the terminating EOS ("end-of-string")
+character. This value gets implicitly appended to all output lists.
+Specify a negative value here to avoid implicit EOS characters entirely.
+For backwards compatibility \, the default EOS character is 0 (zero).
+;
+#X text 51 5 any2string : convert pd messages to a list of floats;
+#X text 31 75 2 - EOS character (float);
+#X obj 100 438 pdstring-help;
+#X connect 1 0 0 0;
+#X connect 2 0 1 1;
+#X connect 3 0 1 1;
+#X connect 8 0 1 0;
+#X connect 9 0 1 0;
+#X connect 13 0 1 0;
+#X connect 18 0 1 1;
diff --git a/src/any2string.c b/src/any2string.c
index 094907f..e005be2 100644
--- a/src/any2string.c
+++ b/src/any2string.c
@@ -1,8 +1,8 @@
/* -*- Mode: C -*- */
/*=============================================================================*\
- * File: any2string.c
+ * File: any2string_dynamic.c
* Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
- * Description: convert pd messages to strings
+ * Description: convert pd messages to strings (dynamic allocation)
*
* Copyright (c) 2004 - 2007 Bryan Jurish.
*
@@ -25,9 +25,12 @@
*=============================================================================*/
#include <string.h>
-
#include <m_pd.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
/* black magic */
#ifdef NT
#pragma warning( disable : 4244 )
@@ -45,7 +48,7 @@
# define A2SDEBUG(x)
#endif
-#define ANY2STRING_INITIAL_BUFLEN 32
+#define ANY2STRING_DEFAULT_BUFLEN 256
/*=====================================================================
@@ -58,8 +61,11 @@ typedef struct _any2string
t_object x_obj;
int x_alloc;
int x_argc;
+ t_float x_eos; //-- EOS character to add (<0 for none)
+ char *x_text;
t_atom *x_argv;
t_binbuf *x_binbuf;
+ t_inlet *x_eos_in;
t_outlet *x_outlet;
} t_any2string;
@@ -67,6 +73,7 @@ typedef struct _any2string
/*=====================================================================
* Constants
*=====================================================================*/
+static char *any2string_banner = "any2string: pdstring version " PACKAGE_VERSION " by Bryan Jurish";
/*=====================================================================
* Methods
@@ -78,75 +85,60 @@ typedef struct _any2string
static void any2string_anything(t_any2string *x, t_symbol *sel, int argc, t_atom *argv)
{
t_atom *a;
- char *text=NULL, *s, *s_max;
+ char *s, *s_max;
int len;
- A2SDEBUG(post("-------any2string_anything()---------"));
+ A2SDEBUG(post("-------any2string_anything(%p,...)---------", x));
/*-- set up binbuf --*/
- A2SDEBUG(post("any2string: binbuf_clear()"));
+ A2SDEBUG(post("any2string[%p]: binbuf_clear()", x));
binbuf_clear(x->x_binbuf);
- A2SDEBUG(post("any2string: binbuf_add()"));
+
+ /*-- binbuf_add(): selector --*/
+ if (sel != &s_float && sel != &s_list && sel != &s_) {
+ t_atom a;
+ A2SDEBUG(post("any2string[%p]: binbuf_add(): selector: '%s'", x, sel->s_name));
+ SETSYMBOL((&a), sel);
+ binbuf_add(x->x_binbuf, 1, &a);
+ }
+ A2SDEBUG(else { post("any2string[%p]: selector: '%s': IGNORED", x, sel->s_name); });
+
+ /*-- binbuf_add(): arg list --*/
+ A2SDEBUG(post("any2string[%p]: binbuf_add(): arg list", x));
binbuf_add(x->x_binbuf, argc, argv);
- A2SDEBUG(startpost("any2string: binbuf_print: "));
+ A2SDEBUG(post("any2string[%p]: binbuf_print: ", x));
A2SDEBUG(binbuf_print(x->x_binbuf));
- A2SDEBUG(post("any2string: binbuf_gettext()"));
- binbuf_gettext(x->x_binbuf, &text, &len);
- A2SDEBUG(post("any2string: binbuf_gettext() = \"%s\" ; len=%d", text, len));
- /*text[len] = 0;*/ /*-- ? avoid errors: free(): invalid next size(fast): [HEX_ADDRESS] */
+ A2SDEBUG(post("any2string[%p]: binbuf_gettext()", x));
+ binbuf_gettext(x->x_binbuf, &(x->x_text), &len);
+ A2SDEBUG(post("any2string[%p]: binbuf_gettext() = \"%s\" ; len=%d", x, x->x_text, len));
+ /*text[len] = 0;*/ /*-- ? avoid errors: "free(): invalid next size(fast): 0x..." */
- /*-- get string length --*/
- x->x_argc = len+1;
- if (sel != &s_float && sel != &s_list && sel != &s_) {
- x->x_argc += strlen(sel->s_name);
- if (argc > 0) x->x_argc++;
- }
- A2SDEBUG(post("any2string: argc=%d", x->x_argc));
+ /*-- get output atom-list length --*/
+ x->x_argc = len;
+ if (x->x_eos >= 0) { x->x_argc++; }
+ A2SDEBUG(post("any2string[%p]: argc=%d", x, x->x_argc));
- /*-- (re-)allocate --*/
+ /*-- (re-)allocate (maybe) --*/
if (x->x_alloc < x->x_argc) {
- A2SDEBUG(post("any2string: reallocate(%d->%d)", x->x_alloc, x->x_argc));
- freebytes(x->x_argv, x->x_alloc * sizeof(t_atom));
- x->x_argv = (t_atom *)getbytes(x->x_argc * sizeof(t_atom));
+ A2SDEBUG(post("any2string[%p]: reallocate(%d->%d)", x, x->x_alloc, x->x_argc));
+ freebytes(x->x_argv, x->x_alloc*sizeof(t_atom));
+ x->x_argv = (t_atom*)getbytes(x->x_argc * sizeof(t_atom));
x->x_alloc = x->x_argc;
}
- /*-- add selector (maybe) --*/
- a=x->x_argv;
- if (sel != &s_float && sel != &s_list && sel != &s_) {
- A2SDEBUG(post("any2string: for {...} //sel"));
- for (s=sel->s_name; *s; s++, a++) {
- A2SDEBUG(post("any2string: for: SETFLOAT(a,'%c'=%d) //sel", *s, *s));
- SETFLOAT(a,*s);
- }
- A2SDEBUG(post("any2string: /for {...} //sel"));
-
- if (argc > 0) {
- SETFLOAT(a,' ');
- a++;
- }
- }
-
- /*-- add binbuf text --*/
- A2SDEBUG(post("any2string: for {...}"));
- s_max = text+len;
- for (s=text; s < s_max; s++, a++) {
- A2SDEBUG(post("any2string: for: //SETFLOAT(a,'%c'=%d)", *s, *s));
+ /*-- atom buffer: binbuf text --*/
+ A2SDEBUG(post("any2string[%p]: atom buffer: for {...}", x));
+ a = x->x_argv;
+ s_max = x->x_text+len;
+ for (s=x->x_text; s < s_max; s++, a++) {
+ A2SDEBUG(post("any2string[%p]: atom buffer[%d]: SETFLOAT(a,%d='%c')", x, (a-x->x_argv), *s, *s));
SETFLOAT(a,*s);
}
- A2SDEBUG(post("any2string: /for {...}"));
-
- /*-- add terminating NUL --*/
- SETFLOAT(a,0);
-
- A2SDEBUG(post("any2string: freebytes()"));
- freebytes(text, len);
+ A2SDEBUG(post("any2string: atom buffer: DONE"));
- /*
- A2SDEBUG(post("any2string: binbuf_free()"));
- binbuf_free(x->x_binbuf);
- */
+ /*-- add EOS character (maybe) --*/
+ if (x->x_eos >= 0) { SETFLOAT(a, ((int)x->x_eos)); }
A2SDEBUG(post("any2string: outlet_list(..., %d, ...)", x->x_argc));
outlet_list(x->x_outlet, &s_list, x->x_argc, x->x_argv);
@@ -156,19 +148,39 @@ static void any2string_anything(t_any2string *x, t_symbol *sel, int argc, t_atom
/*--------------------------------------------------------------------
* new
*/
-static void *any2string_new(void)
+static void *any2string_new(t_symbol *sel, int argc, t_atom *argv)
{
t_any2string *x = (t_any2string *)pd_new(any2string_class);
//-- defaults
- x->x_alloc = ANY2STRING_INITIAL_BUFLEN;
- x->x_argc = 0;
- x->x_argv = (t_atom *)getbytes(x->x_alloc * sizeof(t_atom));
+ x->x_eos = 0;
+ x->x_alloc = ANY2STRING_DEFAULT_BUFLEN;
+
+ //-- args: 0: bufsize
+ if (argc > 0) {
+ int bufsize = atom_getintarg(0, argc, argv);
+ if (bufsize > 0) { x->x_alloc = bufsize; }
+ }
+ //-- args: 1: eos
+ if (argc > 1) {
+ x->x_eos = atom_getfloatarg(1, argc, argv);
+ }
+
+ //-- allocate
+ x->x_text = (char *)getbytes(x->x_alloc*sizeof(char));
+ x->x_argc = 0;
+ x->x_argv = (t_atom *)getbytes(x->x_alloc*sizeof(t_atom));
x->x_binbuf = binbuf_new();
+ //-- inlets
+ x->x_eos_in = floatinlet_new(&x->x_obj, &x->x_eos);
+
//-- outlets
x->x_outlet = outlet_new(&x->x_obj, &s_list);
+ //-- report
+ A2SDEBUG(post("any2string_new(): x=%p, alloc=%d, eos=%d, text=%p, argv=%p, binbuf=%p", x, x->x_alloc, x->x_eos, x->x_text, x->x_argv, x->x_binbuf));
+
return (void *)x;
}
@@ -177,36 +189,47 @@ static void *any2string_new(void)
*/
static void any2string_free(t_any2string *x)
{
+ if (x->x_text) {
+ freebytes(x->x_text, x->x_alloc*sizeof(char));
+ x->x_text = NULL;
+ }
if (x->x_argv) {
- freebytes(x->x_argv, x->x_alloc * sizeof(t_atom));
+ freebytes(x->x_argv, x->x_alloc*sizeof(t_atom));
x->x_argv = NULL;
}
binbuf_free(x->x_binbuf);
+ inlet_free(x->x_eos_in);
outlet_free(x->x_outlet);
return;
}
/*--------------------------------------------------------------------
- * setup
+ * setup (guts)
*/
-void any2string_setup(void)
+void any2string_setup_guts(void)
{
//-- class
any2string_class = class_new(gensym("any2string"),
- (t_newmethod)any2string_new,
- (t_method)any2string_free,
- sizeof(t_any2string),
- CLASS_DEFAULT,
- 0);
+ (t_newmethod)any2string_new,
+ (t_method)any2string_free,
+ sizeof(t_any2string),
+ CLASS_DEFAULT,
+ A_GIMME, //-- initial_bufsize, eos_char
+ 0);
//-- methods
- /*class_addmethod(any2string_class, (t_method)any2string_symbol, &s_symbol,
- A_DEFSYMBOL, 0);
- */
- class_addanything(any2string_class,
- (t_method)any2string_anything);
+ class_addanything(any2string_class, (t_method)any2string_anything);
//-- help symbol
- class_sethelpsymbol(any2string_class, gensym("pdstring-help.pd"));
+ class_sethelpsymbol(any2string_class, gensym("any2string-help.pd"));
+}
+
+/*--------------------------------------------------------------------
+ * setup
+ */
+void any2string_setup(void)
+{
+ post(any2string_banner);
+ any2string_setup_guts();
}
diff --git a/src/any2string_static.c b/src/any2string_static.c
new file mode 100644
index 0000000..50da35d
--- /dev/null
+++ b/src/any2string_static.c
@@ -0,0 +1,246 @@
+/* -*- Mode: C -*- */
+/*=============================================================================*\
+ * File: any2string_static.c
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: convert pd messages to strings (static buffer allocation)
+ *
+ * Copyright (c) 2004 - 2007 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file "COPYING", in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+#include <string.h>
+#include <stdio.h>
+
+#include <m_pd.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* black magic */
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+/*--------------------------------------------------------------------
+ * DEBUG
+ *--------------------------------------------------------------------*/
+/*#define ANY2STRING_DEBUG 1*/
+/*#undef ANY2STRING_DEBUG*/
+
+#ifdef ANY2STRING_DEBUG
+# define A2SDEBUG(x) x
+#else
+# define A2SDEBUG(x)
+#endif
+
+#define ANY2STRING_DEFAULT_BUFLEN 512
+
+
+/*=====================================================================
+ * Structures and Types: any2string
+ *=====================================================================*/
+static t_class *any2string_class;
+
+typedef struct _any2string
+{
+ t_object x_obj;
+ int x_alloc; //-- buffer size (text, x_argv)
+ int x_argc; //-- current number of atoms to outlet
+ t_atom *x_argv; //-- float-list to outlet
+ t_outlet *x_outlet; //-- outlet
+} t_any2string;
+
+
+/*=====================================================================
+ * Utilities
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * append_string
+ */
+static void any2string_append_string(t_any2string *x, char *s, unsigned int maxlen, int doescape)
+{
+ char *sp;
+ char *ep = s+maxlen;
+
+ for (sp=s; *sp && sp<ep && *sp && x->x_argc<x->x_alloc; sp++, x->x_argc++) {
+ if (doescape && (*sp==';' || *sp==',' || *sp=='\\'
+ || (*sp == '$' && sp<(ep-1) && sp[1] >= '0' && sp[1] <= '9')))
+ {
+ A2SDEBUG(post("any2string_append_string: ESCAPE: x_argv[%d] = '%c' = %d", x->x_argc, '\\', '\\'));
+ x->x_argv[x->x_argc++].a_w.w_float = '\\';
+ if (x->x_argc >= x->x_alloc) break;
+ }
+ A2SDEBUG(post("any2string_append_string: x_argv[%d] = '%c' = %d", x->x_argc, *sp, *sp));
+ x->x_argv[x->x_argc].a_w.w_float = *sp;
+ }
+}
+
+/*--------------------------------------------------------------------
+ * append_atom
+ */
+#define ANY2STRING_APPEND_BUFSIZE 30
+static void any2string_append_atom(t_any2string *x, t_atom *a)
+{
+ char buf[ANY2STRING_APPEND_BUFSIZE];
+ A2SDEBUG(post("~~ any2string_append_atom(%p,...) ~~", x));
+
+ if (x->x_argc >= x->x_alloc) { return; }
+
+ /*-- stringify a single atom (inspired by atom_string() from m_atom.c) --*/
+ switch (a->a_type) {
+ case A_SEMI: any2string_append_string(x, ";", 1, 0); break;
+ case A_COMMA: any2string_append_string(x, ",", 1, 0); break;
+ case A_POINTER: any2string_append_string(x, "(pointer)", 9, 0); break;
+ case A_FLOAT:
+ snprintf(buf, ANY2STRING_APPEND_BUFSIZE, "%g", a->a_w.w_float);
+ any2string_append_string(x, buf, ANY2STRING_APPEND_BUFSIZE, 0);
+ break;
+ case A_SYMBOL:
+ any2string_append_string(x, a->a_w.w_symbol->s_name, strlen(a->a_w.w_symbol->s_name), 1);
+ break;
+ case A_DOLLAR:
+ snprintf(buf, ANY2STRING_APPEND_BUFSIZE, "$%d", a->a_w.w_index);
+ any2string_append_string(x, buf, ANY2STRING_APPEND_BUFSIZE, 0);
+ break;
+ case A_DOLLSYM:
+ any2string_append_string(x, a->a_w.w_symbol->s_name, strlen(a->a_w.w_symbol->s_name), 0);
+ break;
+ default:
+ pd_error(x,"any2string_append_atom: unknown atom type '%d'", a->a_type);
+ break;
+ }
+
+ if (x->x_argc < x->x_alloc) {
+ A2SDEBUG(post("any2string_append_atom[%p]: x_argv[%d] = '%c' = %d", x, x->x_argc, ' ', ' '));
+ x->x_argv[x->x_argc++].a_w.w_float = ' ';
+ }
+}
+
+/*=====================================================================
+ * Methods
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * anything
+ */
+static void any2string_anything(t_any2string *x, t_symbol *sel, int argc, t_atom *argv)
+{
+ t_atom *argv_end = argv+argc;
+ x->x_argc=0;
+
+ A2SDEBUG(post("-------any2string_anything(%p,...) ---------", x));
+
+ /*-- stringify selector (maybe) --*/
+ if (sel != &s_float && sel != &s_list && sel != &s_) {
+ t_atom a;
+ SETSYMBOL(&a,sel);
+ any2string_append_atom(x, &a);
+ }
+
+ /*-- stringify arg list --*/
+ for ( ; argv<argv_end && x->x_argc<x->x_alloc; argv++) {
+ any2string_append_atom(x, argv);
+ }
+
+ /*-- add terminating NUL (if we can) --*/
+ A2SDEBUG(post("any2string[%p]: terminating NUL: x_argv[%d]=0", x, x->x_argc-1));
+ if (x->x_argc >= x->x_alloc) {
+ pd_error(x, "any2string: input length exceeds buffer size!");
+ x->x_argc = x->x_alloc;
+ x->x_argv[x->x_argc-1].a_w.w_float = '*'; //-- simulate atom_string() behavior
+ } else if (x->x_argc > 0) {
+ x->x_argv[x->x_argc-1].a_w.w_float = 0;
+ }
+
+ A2SDEBUG(post("any2string[%p]: outlet_list(..., %d, ...)", x, x->x_argc));
+ outlet_list(x->x_outlet, &s_list, x->x_argc, x->x_argv);
+}
+
+
+/*--------------------------------------------------------------------
+ * new
+ */
+static void *any2string_new(t_floatarg bufsize)
+{
+ t_any2string *x = (t_any2string *)pd_new(any2string_class);
+ int i;
+
+ //-- bufsize
+ if (bufsize <= 0) {
+ x->x_alloc = ANY2STRING_DEFAULT_BUFLEN;
+ } else {
+ x->x_alloc = bufsize;
+ }
+ A2SDEBUG(post("any2string_new: buf_req=%g, alloc=%d", bufsize, x->x_alloc));
+
+ //-- defaults
+ x->x_argc = 0;
+ x->x_argv = (t_atom*)getbytes(x->x_alloc*sizeof(t_atom));
+
+ //-- initialize (set a_type)
+ for (i=0; i < x->x_alloc; i++) {
+ SETFLOAT((x->x_argv+i),0);
+ }
+
+ //-- outlets
+ x->x_outlet = outlet_new(&x->x_obj, &s_list);
+ A2SDEBUG(post("any2string_new: x=%p, alloc=%d, argv=%p, nbytes=%d", x, x->x_alloc,x->x_argv,x->x_alloc*sizeof(t_atom)));
+ return (void *)x;
+}
+
+/*--------------------------------------------------------------------
+ * free
+ */
+static void any2string_free(t_any2string *x)
+{
+ A2SDEBUG(post("any2string_free(x=%p)", x));
+ if (x->x_argv) {
+ A2SDEBUG(post("any2string_free(x=%p): x_argv=%p (size=%d)", x, x->x_argv, x->x_alloc*sizeof(t_atom)));
+ freebytes(x->x_argv, x->x_alloc*sizeof(t_atom));
+ }
+ A2SDEBUG(post("any2string_free(x=%p): x_outlet=%p", x, x->x_outlet));
+ outlet_free(x->x_outlet);
+ return;
+}
+
+/*--------------------------------------------------------------------
+ * setup
+ */
+void any2string_setup(void)
+{
+ //-- class
+ any2string_class = class_new(gensym("any2string"),
+ (t_newmethod)any2string_new,
+ (t_method)any2string_free,
+ sizeof(t_any2string),
+ CLASS_DEFAULT,
+ A_DEFFLOAT,
+ 0);
+
+ //-- methods
+ class_addanything(any2string_class,
+ (t_method)any2string_anything);
+
+
+ //-- help symbol
+ class_sethelpsymbol(any2string_class, gensym("pdstring-help.pd"));
+}
diff --git a/src/pdstring-help.pd b/src/pdstring-help.pd
index e83b9db..2ab94b3 100644
--- a/src/pdstring-help.pd
+++ b/src/pdstring-help.pd
@@ -1,11 +1,9 @@
-#N canvas 381 42 563 311 10;
+#N canvas 191 76 563 311 10;
#X text 258 284 Bryan Jurish <moocow@ling.uni-potsdam.de>;
#X floatatom 56 81 8 0 0 0 - - -;
#X symbolatom 46 59 10 0 0 0 - - -;
#X text 201 59 ... no special handling for symbols;
#X text 200 37 anything can be converted to a list...;
-#X obj 383 3 pdstring;
-#X text 54 3 any2string \, string2any : ASCII conversions in;
#X obj 37 108 any2string;
#X obj 37 230 string2any;
#X floatatom 54 178 4 0 0 0 - - -;
@@ -48,12 +46,14 @@
#X obj 37 254 print string2any-out;
#X msg 37 38 A B C;
#X msg 55 199 list 49 50 51;
-#X connect 1 0 7 0;
-#X connect 2 0 7 0;
-#X connect 7 0 15 0;
-#X connect 7 0 8 0;
-#X connect 8 0 16 0;
-#X connect 9 0 8 0;
-#X connect 13 0 12 0;
-#X connect 17 0 7 0;
-#X connect 18 0 8 0;
+#X text 54 3 any2string \, string2any : ASCII conversions in [pdstring]
+lib;
+#X connect 1 0 5 0;
+#X connect 2 0 5 0;
+#X connect 5 0 13 0;
+#X connect 5 0 6 0;
+#X connect 6 0 14 0;
+#X connect 7 0 6 0;
+#X connect 11 0 10 0;
+#X connect 15 0 5 0;
+#X connect 16 0 6 0;
diff --git a/src/pdstring.c b/src/pdstring.c
index c77b68e..37bd4ff 100644
--- a/src/pdstring.c
+++ b/src/pdstring.c
@@ -54,8 +54,15 @@ typedef struct _pdstring
/*=====================================================================
* External declarations
*=====================================================================*/
-extern void any2string_setup(void);
-extern void string2any_setup(void);
+#ifndef PDSTRING_OBJECT_EXTERNALS
+/*
+extern void any2string_setup_guts(void);
+extern void string2any_setup_guts(void);
+*/
+#include "any2string.c"
+#include "string2any.c"
+
+#endif
/*--------------------------------------------------------------------
* new
@@ -81,8 +88,10 @@ void pdstring_setup(void)
{
post(pdstring_version);
- any2string_setup();
- string2any_setup();
+#ifndef PDSTRING_OBJECT_EXTERNALS
+ any2string_setup_guts();
+ string2any_setup_guts();
+#endif
pdstring_class = class_new(gensym("pdstring"),
(t_newmethod)pdstring_new,
diff --git a/src/string2any-help.pd b/src/string2any-help.pd
new file mode 100644
index 0000000..8e44e15
--- /dev/null
+++ b/src/string2any-help.pd
@@ -0,0 +1,42 @@
+#N canvas 121 48 612 604 10;
+#X text 59 7 string2any : convert lists of floats to pd messages;
+#X text 13 30 SYNTAX: string2any [INITIAL_BUFSIZE [EOS_CHAR]];
+#X text 13 52 INLETS:;
+#X text 27 68 1 - ASCII-valued float lists;
+#X text 309 54 OUTLETS:;
+#X text 325 68 1 - pd messages;
+#X text 325 82 2 - bang on done;
+#X obj 24 350 string2any 128 0;
+#X obj 24 529 print string2any-help;
+#X obj 131 454 print string2any-help-done;
+#X msg 24 113 97 32 98 32 99;
+#X msg 39 135 97 0 98 0 99;
+#X msg 99 206 0;
+#X msg 67 206 -1;
+#X msg 131 206 32;
+#X text 166 202 The second inlet sets the message-separating EOS ("end-of-string")
+character. If this character is encountered in an input list \, the
+list is "split" at that point \, and two separate messages are output
+at the leftmost outlet. You can specify a negative value here to avoid
+implicit input splitting entirely. For backwards compatibility \, the
+default EOS character is -1 \, which results in truncation of input
+messages whenever a 0 (zero) is encountered.;
+#X text 163 350 First argument: initial buffer size (length of object-local
+text buffer). This should get re-allocated when necessary. Specify
+0 (zero) to use the default value.;
+#X text 165 405 Second argument: initial EOS character. See above.
+;
+#X text 159 477 Right outlet gives a bang after the entire input list
+has been processed.;
+#X text 189 531 Parsed pd messages are sent to the left outlet.;
+#X text 306 580 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X text 27 83 2 - EOS character (float);
+#X text 161 121 lists of floats are converted to pd messages.;
+#X msg 54 161 StringThing 97;
+#X text 168 161 ... selector is ignored ...;
+#X text 21 571 SEE ALSO:;
+#X obj 102 570 pdstring-help;
+#X connect 7 0 8 0;
+#X connect 10 0 7 0;
+#X connect 11 0 7 0;
+#X connect 23 0 7 0;
diff --git a/src/string2any.c b/src/string2any.c
index 93756ec..bcde417 100644
--- a/src/string2any.c
+++ b/src/string2any.c
@@ -28,6 +28,10 @@
#include <m_pd.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
/* black magic */
#ifdef NT
#pragma warning( disable : 4244 )
@@ -37,7 +41,8 @@
/*--------------------------------------------------------------------
* DEBUG
*--------------------------------------------------------------------*/
-//#define STRING2ANY_DEBUG 1
+/*#define STRING2ANY_DEBUG 1*/
+/*#undef STRING2ANY_DEBUG*/
#ifdef STRING2ANY_DEBUG
# define S2ADEBUG(x) x
@@ -45,12 +50,13 @@
# define S2ADEBUG(x)
#endif
-#define STRING2ANY_INITIAL_BUFLEN 32
+#define STRING2ANY_DEFAULT_BUFLEN 256
/*=====================================================================
* Constants
*=====================================================================*/
+static char *string2any_banner = "string2any: pdstring version " PACKAGE_VERSION " by Bryan Jurish";
/*=====================================================================
* Structures and Types: any2string
@@ -62,34 +68,33 @@ typedef struct _string2any
{
t_object x_obj;
size_t x_size;
+ t_float x_eos; //-- eos character
char *x_text;
t_binbuf *x_binbuf;
+ t_inlet *x_eos_in;
t_outlet *x_outlet;
+ t_outlet *x_outlet_done;
} t_string2any;
/*=====================================================================
- * Constants
- *=====================================================================*/
-
-/*=====================================================================
- * Methods
+ * Utilities
*=====================================================================*/
/*--------------------------------------------------------------------
- * anything
+ * string2any_atoms()
*/
-static void string2any_anything(t_string2any *x, t_symbol *sel, int argc, t_atom *argv)
+static void string2any_atoms(t_string2any *x, int argc, t_atom *argv)
{
char *s;
- int x_argc;
+ int x_argc, a_argc=argc;
t_atom *x_argv;
/*-- allocate --*/
- if (x->x_size <= argc) {
+ if (x->x_size <= (argc+1)) {
freebytes(x->x_text, x->x_size*sizeof(char));
x->x_size = argc+1;
- x->x_text = (char *)getbytes(x->x_size * sizeof(char));
+ x->x_text = (char *)getbytes(x->x_size*sizeof(char));
}
/*-- get text --*/
@@ -97,12 +102,12 @@ static void string2any_anything(t_string2any *x, t_symbol *sel, int argc, t_atom
*s = atom_getfloat(argv);
}
*s = 0;
- S2ADEBUG(post("string2any: text: \"%s\"", x->x_text));
+ S2ADEBUG(post("string2any[%p]: text: \"%s\", strlen=%d, argc=%d", x, x->x_text, strlen(x->x_text), a_argc));
/*-- clear and fill binbuf --*/
binbuf_clear(x->x_binbuf);
- binbuf_text(x->x_binbuf, x->x_text, strlen(x->x_text));
- S2ADEBUG(startpost("string2any: buf: "));
+ binbuf_text(x->x_binbuf, x->x_text, a_argc); //-- handle NULs if binbuf will (but it won't) ?
+ S2ADEBUG(post("string2any[%p]: binbuf_print: ", x));
S2ADEBUG(binbuf_print(x->x_binbuf));
/*-- output --*/
@@ -123,20 +128,70 @@ static void string2any_anything(t_string2any *x, t_symbol *sel, int argc, t_atom
}
+/*=====================================================================
+ * Methods
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * anything
+ */
+static void string2any_anything(t_string2any *x, t_symbol *sel, int argc, t_atom *argv)
+{
+ int i0=0, i;
+
+ /*-- scan & output --*/
+ if (x->x_eos >= 0) {
+ for (i=i0; i < argc; i++) {
+ if (((int)atom_getfloatarg(i,argc,argv))==((int)x->x_eos)) {
+ string2any_atoms(x, i-i0, argv+i0);
+ i0=i+1;
+ }
+ }
+ }
+
+ if (i0 < argc) {
+ string2any_atoms(x, argc-i0, argv+i0);
+ }
+
+ outlet_bang(x->x_outlet_done);
+}
+
+
/*--------------------------------------------------------------------
* new
*/
-static void *string2any_new(void)
+static void *string2any_new(t_symbol *sel, int argc, t_atom *argv)
{
t_string2any *x = (t_string2any *)pd_new(string2any_class);
//-- defaults
x->x_binbuf = binbuf_new();
- x->x_size = STRING2ANY_INITIAL_BUFLEN;
- x->x_text = (char *)getbytes(x->x_size * sizeof(char));
+ x->x_size = STRING2ANY_DEFAULT_BUFLEN;
+ x->x_eos = -1;
+
+ //-- args: 0: bufsize
+ if (argc > 0) {
+ int initial_bufsize = atom_getintarg(0,argc,argv);
+ if (initial_bufsize > 0) x->x_size = initial_bufsize;
+ x->x_eos = -1; //-- backwards-compatibility hack: no default eos character if only bufsize is specified
+ }
+ //-- args: 1: separator
+ if (argc > 1) {
+ x->x_eos = atom_getfloatarg(1,argc,argv);
+ }
+
+ //-- allocate
+ x->x_text = (char *)getbytes(x->x_size*sizeof(char));
+
+ //-- inlets
+ x->x_eos_in = floatinlet_new(&x->x_obj, &x->x_eos);
//-- outlets
- x->x_outlet = outlet_new(&x->x_obj, &s_list);
+ x->x_outlet = outlet_new(&x->x_obj, &s_list);
+ x->x_outlet_done = outlet_new(&x->x_obj, &s_bang);
+
+ //-- debug
+ S2ADEBUG(post("string2any_new: x=%p, size=%d, eos=%d, binbuf=%p, text=%p", x, x->x_size, x->x_eos, x->x_binbuf, x->x_text));
return (void *)x;
}
@@ -147,35 +202,43 @@ static void *string2any_new(void)
static void string2any_free(t_string2any *x)
{
if (x->x_text) {
- freebytes(x->x_text, x->x_size * sizeof(char));
+ freebytes(x->x_text, x->x_size*sizeof(char));
x->x_text = NULL;
}
binbuf_free(x->x_binbuf);
+ inlet_free(x->x_eos_in);
+ outlet_free(x->x_outlet_done);
outlet_free(x->x_outlet);
return;
}
/*--------------------------------------------------------------------
- * setup
+ * setup: guts
*/
-void string2any_setup(void)
+void string2any_setup_guts(void)
{
//-- class
string2any_class = class_new(gensym("string2any"),
- (t_newmethod)string2any_new,
- (t_method)string2any_free,
- sizeof(t_string2any),
- CLASS_DEFAULT,
- 0);
+ (t_newmethod)string2any_new,
+ (t_method)string2any_free,
+ sizeof(t_string2any),
+ CLASS_DEFAULT,
+ A_GIMME, //-- initial_bufsize, eos_char
+ 0);
//-- methods
- /*class_addmethod(string2any_class, (t_method)string2any_symbol, &s_symbol,
- A_DEFSYMBOL, 0);
- */
- class_addanything(string2any_class,
- (t_method)string2any_anything);
+ class_addanything(string2any_class, (t_method)string2any_anything);
//-- help symbol
- class_sethelpsymbol(string2any_class, gensym("pdstring-help.pd"));
+ class_sethelpsymbol(string2any_class, gensym("string2any-help.pd"));
+}
+
+/*--------------------------------------------------------------------
+ * setup
+ */
+void string2any_setup(void)
+{
+ post(string2any_banner);
+ string2any_setup_guts();
}