I have implemented a string type for Pure Data as well as a [str] object that uses it. For it to work, pd needs to be patched. The [str] is contained in a separate file but the infrastructural changes are part of pd. I have attached a patch file for anyone interested. If it is acceptable, where should I put it? I could check str.c into externals, but it won't build unless the source is patched... The str object can join, split, load, save, drip, compare and convert strings to other types. It should be useful for formatting arbitrary strings for communication via byte-oriented objects such as [comport] and [tcpserver], which can then talk to external hardware (e.g. serial LCD or lanbox), for example terminating strings with CR LF instead of semicolons. Other potential applications of the string type that I haven't yet implemented are math using very long integers and row-by-row image processing. Martin
Index: pd/src/g_text.c =================================================================== RCS file: /cvsroot/pure-data/pd/src/g_text.c,v retrieving revision 1.15 diff -u -w -r1.15 g_text.c --- pd/src/g_text.c 4 Oct 2006 19:35:06 -0000 1.15 +++ pd/src/g_text.c 18 Jan 2007 00:13:03 -0000 @@ -276,6 +276,11 @@ outlet_symbol(x->mr_outlet, s); }
+static void messresponder_string(t_messresponder *x, t_string *st) +{ /* MP 20070107 string type */ + outlet_string(x->mr_outlet, st); +} + static void messresponder_list(t_messresponder *x, t_symbol *s, int argc, t_atom *argv) { @@ -307,6 +312,13 @@ binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at); }
+static void message_string(t_message *x, t_string *st) +{ + t_atom at; + SETSTRING(&at, st); + binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at); +} + static void message_list(t_message *x, t_symbol *s, int argc, t_atom *argv) { binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, argc, argv); @@ -1333,6 +1345,7 @@ class_addbang(message_class, message_bang); class_addfloat(message_class, message_float); class_addsymbol(message_class, message_symbol); + class_addstring(message_class, message_string); class_addlist(message_class, message_list); class_addanything(message_class, message_list);
Index: pd/src/m_atom.c =================================================================== RCS file: /cvsroot/pure-data/pd/src/m_atom.c,v retrieving revision 1.4 diff -u -w -r1.4 m_atom.c --- pd/src/m_atom.c 11 Aug 2006 20:09:07 -0000 1.4 +++ pd/src/m_atom.c 18 Jan 2007 00:13:03 -0000 @@ -28,6 +28,14 @@ else return (&s_float); }
+t_string *atom_getstring(t_atom *a) /* MP 20070108 */ +{ + static unsigned char c = 0;/* a default string to avoid null pointers. This should be somewhere else...? */ + static t_string st = {1L, &c}; + if (a->a_type == A_STRING) return (a->a_w.w_string); + else return (&st); +} + t_symbol *atom_gensym(t_atom *a) /* this works better for graph labels */ { char buf[30]; Index: pd/src/m_binbuf.c =================================================================== RCS file: /cvsroot/pure-data/pd/src/m_binbuf.c,v retrieving revision 1.13 diff -u -w -r1.13 m_binbuf.c --- pd/src/m_binbuf.c 4 Oct 2006 19:35:06 -0000 1.13 +++ pd/src/m_binbuf.c 18 Jan 2007 00:13:03 -0000 @@ -672,6 +672,10 @@ case A_SYMBOL: typedmess(target, stackwas->a_w.w_symbol, nargs-1, stackwas+1); break; + case A_STRING: /* MP 20070106 string type */ + if (nargs == 1) pd_string(target, stackwas->a_w.w_string); + else pd_list(target, 0, nargs, stackwas); + break; case A_FLOAT: if (nargs == 1) pd_float(target, stackwas->a_w.w_float); else pd_list(target, 0, nargs, stackwas); Index: pd/src/m_class.c =================================================================== RCS file: /cvsroot/pure-data/pd/src/m_class.c,v retrieving revision 1.7 diff -u -w -r1.7 m_class.c --- pd/src/m_class.c 15 Aug 2006 04:54:15 -0000 1.7 +++ pd/src/m_class.c 18 Jan 2007 00:13:03 -0000 @@ -20,6 +20,7 @@
static t_symbol *class_loadsym; /* name under which an extern is invoked */ static void pd_defaultfloat(t_pd *x, t_float f); +static void pd_defaultstring(t_pd *x, t_string *st); /* MP20061226 string type */ static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv); t_pd pd_objectmaker; /* factory for creating "object" boxes */ t_pd pd_canvasmaker; /* factory for creating canvases */ @@ -38,6 +39,11 @@ else (*(*x)->c_anymethod)(x, &s_bang, 0, 0); }
+static void pd_defaultstring(t_pd *x, t_string *st) /* MP 20061226 string type */ +{ /* for now just reject it, later convert to symbol/float/list */ + pd_error(x, "%s: no method for string so far...", (*x)->c_name->s_name); +} + static void pd_defaultpointer(t_pd *x, t_gpointer *gp) { if (*(*x)->c_listmethod != pd_defaultlist) @@ -205,6 +211,7 @@ c->c_pointermethod = pd_defaultpointer; c->c_floatmethod = pd_defaultfloat; c->c_symbolmethod = pd_defaultsymbol; + c->c_stringmethod = pd_defaultstring; /* MP 20061226 string type */ c->c_listmethod = pd_defaultlist; c->c_anymethod = pd_defaultanything; c->c_wb = (typeflag == CLASS_PATCHABLE ? &text_widgetbehavior : 0); @@ -288,6 +295,12 @@ if (argtype != A_SYMBOL || va_arg(ap, t_atomtype)) goto phooey; class_addsymbol(c, fn); } + else if (sel == &s_string) /* MP 20070106 string type */ + { + post("class_addmethod: %p", fn); + if (argtype != A_STRING || va_arg(ap, t_atomtype)) goto phooey; + class_addstring(c, fn); + } else if (sel == &s_list) { if (argtype != A_GIMME) goto phooey; @@ -346,6 +359,11 @@ c->c_symbolmethod = (t_symbolmethod)fn; }
+void class_addstring(t_class *c, t_method fn) /* MP 20061226 string type */ +{ + c->c_stringmethod = (t_stringmethod)fn; +} + void class_addlist(t_class *c, t_method fn) { c->c_listmethod = (t_listmethod)fn; @@ -564,9 +582,10 @@ t_symbol s_x = {"x", 0, 0}; t_symbol s_y = {"y", 0, 0}; t_symbol s_ = {"", 0, 0}; +t_symbol s_string = {"string", 0, 0}; /* MP 20061223 string type */
static t_symbol *symlist[] = { &s_pointer, &s_float, &s_symbol, &s_bang, - &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_}; + &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_, &s_string}; /* MP 20061223 added s_string */
void mess_init(void) { @@ -654,6 +673,13 @@ (*c->c_symbolmethod)(x, &s_); return; } + if (s == &s_string) /* MP 20061226 string type */ + { + /*post("pd_typedmess argc = %d\n", argc);*//* MP 20061226 debug */ + if (argc == 1) (*c->c_stringmethod)(x, argv->a_w.w_string); + else goto badarg; + return; + } for (i = c->c_nmethod, m = c->c_methods; i--; m++) if (m->me_name == s) { @@ -698,6 +724,19 @@ } dp++; break; + case A_STRING:/* MP 20070106 string type */ + /*post("pd_typedmess A_STRING");*/ + if (!argc) goto badarg; + if (argv->a_type == A_STRING) + { + /*post("argv->a_type == A_STRING, argc = %d, narg= %d", argc, narg);*/ + *ap = (t_int)(argv->a_w.w_string); + } + argc--; + argv++; + narg++; + ap++; + break; case A_SYMBOL: if (!argc) goto badarg; case A_DEFSYM: @@ -772,6 +811,10 @@ { case 'f': SETFLOAT(at, va_arg(ap, double)); break; case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break; + case 't': + SETSTRING(at, va_arg(ap, t_string *)); + /*post("pd_vmess: arg[0].a_w.w_string = %p", arg[0].a_w.w_string);*/ + break; /* MP 20061226 string type */ case 'i': SETFLOAT(at, va_arg(ap, t_int)); break; case 'p': SETPOINTER(at, va_arg(ap, t_gpointer *)); break; default: goto done; Index: pd/src/m_imp.h =================================================================== RCS file: /cvsroot/pure-data/pd/src/m_imp.h,v retrieving revision 1.4 diff -u -w -r1.4 m_imp.h --- pd/src/m_imp.h 19 Aug 2005 23:28:03 -0000 1.4 +++ pd/src/m_imp.h 18 Jan 2007 00:13:03 -0000 @@ -25,6 +25,7 @@ typedef void (*t_pointermethod)(t_pd *x, t_gpointer *gp); typedef void (*t_floatmethod)(t_pd *x, t_float f); typedef void (*t_symbolmethod)(t_pd *x, t_symbol *s); +typedef void (*t_stringmethod)(t_pd *x, t_string *st); /* MP20061226 string type */ typedef void (*t_listmethod)(t_pd *x, t_symbol *s, int argc, t_atom *argv); typedef void (*t_anymethod)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
@@ -41,6 +42,7 @@ t_pointermethod c_pointermethod; t_floatmethod c_floatmethod; t_symbolmethod c_symbolmethod; + t_stringmethod c_stringmethod; /* MP20061226 string type */ t_listmethod c_listmethod; t_anymethod c_anymethod; struct _widgetbehavior *c_wb; /* "gobjs" only */ Index: pd/src/m_obj.c =================================================================== RCS file: /cvsroot/pure-data/pd/src/m_obj.c,v retrieving revision 1.4 diff -u -w -r1.4 m_obj.c --- pd/src/m_obj.c 18 May 2005 04:28:51 -0000 1.4 +++ pd/src/m_obj.c 18 Jan 2007 00:13:03 -0000 @@ -15,6 +15,7 @@ t_gpointer *iu_pointerslot; t_float *iu_floatslot; t_symbol **iu_symslot; + t_string **iu_stringslot; /* MP 20061226 string type */ t_sample iu_floatsignalvalue; };
@@ -32,9 +33,10 @@ #define i_pointerslot i_un.iu_pointerslot #define i_floatslot i_un.iu_floatslot #define i_symslot i_un.iu_symslot +#define i_stringslot i_un.iu_stringslot /* MP 20061226 string type */
static t_class *inlet_class, *pointerinlet_class, *floatinlet_class, - *symbolinlet_class; + *symbolinlet_class, *stringinlet_class; /* MP 20061226 added stringinlet_class */
#define ISINLET(pd) ((*(pd) == inlet_class) || \ (*(pd) == pointerinlet_class) || \ @@ -111,6 +113,26 @@ else inlet_wrong(x, &s_symbol); }
+static void inlet_string(t_inlet *x, t_string *st) /* MP20061226 string type */ +{ + /*post("inlet_string (%p): st %p", &inlet_string, st);*/ + if (x->i_symfrom == &s_string) + { + /*post("inlet_string calling pd_vmess");*/ + pd_vmess(x->i_dest, x->i_symto, "t", st); + } + else if (!x->i_symfrom) + { + /*post("inlet_string calling pd_string");*/ + pd_string(x->i_dest, st); + } + else + { + /*post("inlet_string calling inlet_wrong");*/ + inlet_wrong(x, &s_string); + } +} + static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv) { t_atom at; @@ -192,6 +214,23 @@ return (x); }
+t_inlet *stringinlet_new(t_object *owner, t_string **stp) /* MP 20061226 string type */ +{ + t_inlet *x = (t_inlet *)pd_new(stringinlet_class), *y, *y2; + x->i_owner = owner; + x->i_dest = 0; + x->i_symfrom = &s_string; + x->i_stringslot = stp; + x->i_next = 0; + if (y = owner->ob_inlet) + { + while (y2 = y->i_next) y = y2; + y->i_next = x; + } + else owner->ob_inlet = x; + return (x); +} + static void symbolinlet_symbol(t_inlet *x, t_symbol *s) { *(x->i_symslot) = s; @@ -244,6 +283,7 @@ class_addpointer(inlet_class, inlet_pointer); class_addfloat(inlet_class, inlet_float); class_addsymbol(inlet_class, inlet_symbol); + class_addstring(inlet_class, inlet_string); /* MP 20061226 string type */ class_addlist(inlet_class, inlet_list); class_addanything(inlet_class, inlet_anything);
@@ -366,6 +406,18 @@ --stackcount; }
+void outlet_string(t_outlet *x, t_string *st) /* MP 20061226 string type */ +{ + /*post("outlet_string %p %lu", st, st->s_length);*/ + t_outconnect *oc; + if(++stackcount >= STACKITER) + outlet_stackerror(x); + else + for (oc = x->o_connections; oc; oc = oc->oc_next) + pd_string(oc->oc_to, st); + --stackcount; +} + void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv) { t_outconnect *oc; Index: pd/src/m_pd.c =================================================================== RCS file: /cvsroot/pure-data/pd/src/m_pd.c,v retrieving revision 1.4 diff -u -w -r1.4 m_pd.c --- pd/src/m_pd.c 28 Nov 2004 21:20:42 -0000 1.4 +++ pd/src/m_pd.c 18 Jan 2007 00:13:03 -0000 @@ -284,6 +284,12 @@ (*(*x)->c_symbolmethod)(x, s); }
+void pd_string(t_pd *x, t_string *st) /* MP20061226 string type */ +{ + /*post("pd_string: st %p length %lu (*x)->c_stringmethod %p", st, st->s_length, (*x)->c_stringmethod);*/ + (*(*x)->c_stringmethod)(x, st); +} + void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv) { (*(*x)->c_listmethod)(x, &s_list, argc, argv); Index: pd/src/m_pd.h =================================================================== RCS file: /cvsroot/pure-data/pd/src/m_pd.h,v retrieving revision 1.17 diff -u -w -r1.17 m_pd.h --- pd/src/m_pd.h 22 Oct 2006 21:46:11 -0000 1.17 +++ pd/src/m_pd.h 18 Jan 2007 00:13:03 -0000 @@ -102,6 +102,15 @@ t_gstub *gp_stub; /* stub which points to glist/array */ } t_gpointer;
+/* MP20061223 string type: */ +typedef struct _string /* pointer to a string */ +{ + unsigned long s_length; /* length of string in bytes */ + unsigned char *s_data; /* pointer to 1st byte of string */ +} t_string; +/* ...MP20061223 string type */ + + typedef union word { t_float w_float; @@ -110,6 +119,7 @@ t_array *w_array; struct _glist *w_list; int w_index; + t_string *w_string; /* MP20061223 string type */ } t_word;
typedef enum @@ -125,7 +135,8 @@ A_DOLLAR, A_DOLLSYM, A_GIMME, - A_CANT + A_CANT, + A_STRING /* MP20061223 string type */ } t_atomtype;
#define A_DEFSYMBOL A_DEFSYM /* better name for this */ @@ -212,6 +223,7 @@ EXTERN t_symbol s_pointer; EXTERN t_symbol s_float; EXTERN t_symbol s_symbol; +EXTERN t_symbol s_string; EXTERN t_symbol s_bang; EXTERN t_symbol s_list; EXTERN t_symbol s_anything; @@ -255,6 +267,7 @@ #define SETFLOAT(atom, f) ((atom)->a_type = A_FLOAT, (atom)->a_w.w_float = (f)) #define SETSYMBOL(atom, s) ((atom)->a_type = A_SYMBOL, \ (atom)->a_w.w_symbol = (s)) +#define SETSTRING(atom, st) ((atom)->a_type = A_STRING, (atom)->a_w.w_string = (st)) /* MP 20061226 string type */ #define SETDOLLAR(atom, n) ((atom)->a_type = A_DOLLAR, \ (atom)->a_w.w_index = (n)) #define SETDOLLSYM(atom, s) ((atom)->a_type = A_DOLLSYM, \ @@ -263,6 +276,7 @@ EXTERN t_float atom_getfloat(t_atom *a); EXTERN t_int atom_getint(t_atom *a); EXTERN t_symbol *atom_getsymbol(t_atom *a); +EXTERN t_string *atom_getstring(t_atom *a);/* MP 20070108 sring type */ EXTERN t_symbol *atom_gensym(t_atom *a); EXTERN t_float atom_getfloatarg(int which, int argc, t_atom *argv); EXTERN t_int atom_getintarg(int which, int argc, t_atom *argv); @@ -326,6 +340,7 @@ EXTERN void pd_pointer(t_pd *x, t_gpointer *gp); EXTERN void pd_float(t_pd *x, t_float f); EXTERN void pd_symbol(t_pd *x, t_symbol *s); +EXTERN void pd_string(t_pd *x, t_string *st); /* MP 20061226 string type */ EXTERN void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv); EXTERN void pd_anything(t_pd *x, t_symbol *s, int argc, t_atom *argv); #define pd_class(x) (*(x)) @@ -350,6 +365,7 @@ EXTERN void outlet_pointer(t_outlet *x, t_gpointer *gp); EXTERN void outlet_float(t_outlet *x, t_float f); EXTERN void outlet_symbol(t_outlet *x, t_symbol *s); +EXTERN void outlet_string(t_outlet *x, t_string *st); /* MP 20061226 string type */ EXTERN void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv); EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv); EXTERN t_symbol *outlet_getsymbol(t_outlet *x); @@ -404,6 +420,7 @@ EXTERN void class_addpointer(t_class *c, t_method fn); EXTERN void class_doaddfloat(t_class *c, t_method fn); EXTERN void class_addsymbol(t_class *c, t_method fn); +EXTERN void class_addstring(t_class *c, t_method fn);/* MP 20061226 string type */ EXTERN void class_addlist(t_class *c, t_method fn); EXTERN void class_addanything(t_class *c, t_method fn); EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s); @@ -432,6 +449,7 @@ #define class_addpointer(x, y) class_addpointer((x), (t_method)(y)) #define class_addfloat(x, y) class_doaddfloat((x), (t_method)(y)) #define class_addsymbol(x, y) class_addsymbol((x), (t_method)(y)) +#define class_addstring(x, y) class_addstring((x), (t_method)(y)) /* MP20061226 string type */ #define class_addlist(x, y) class_addlist((x), (t_method)(y)) #define class_addanything(x, y) class_addanything((x), (t_method)(y)) #endif