aboutsummaryrefslogtreecommitdiff
path: root/pd/src
diff options
context:
space:
mode:
Diffstat (limited to 'pd/src')
-rw-r--r--pd/src/configure.in4
-rw-r--r--pd/src/g_text.c40
-rw-r--r--pd/src/g_traversal.c31
-rw-r--r--pd/src/m_conf.c2
-rw-r--r--pd/src/makefile2
-rw-r--r--pd/src/makefile.dependencies8
-rw-r--r--pd/src/makefile.in2
-rw-r--r--pd/src/makefile.nt2
-rw-r--r--pd/src/notes.txt10
-rw-r--r--pd/src/s_inter.c1
-rw-r--r--pd/src/s_midi_alsa.c20
-rw-r--r--pd/src/u_main.tk4
-rw-r--r--pd/src/x_connective.c16
-rw-r--r--pd/src/x_list.c415
14 files changed, 509 insertions, 48 deletions
diff --git a/pd/src/configure.in b/pd/src/configure.in
index 84ab18c4..70b83ba5 100644
--- a/pd/src/configure.in
+++ b/pd/src/configure.in
@@ -60,7 +60,7 @@ AC_PROG_GCC_TRADITIONAL
AC_TYPE_SIGNAL
AC_FUNC_VPRINTF
AC_CHECK_FUNCS(gettimeofday select socket strerror)
-
+AC_FUNC_ALLOCA
dnl Checks for libraries.
dnl Checking for `dlopen' function in -ldl:
@@ -349,5 +349,5 @@ then
MORECFLAGS=$MORECFLAGS" -g3 -D__COMPAQC__ -arch host"
fi
-AC_OUTPUT(makefile)
+AC_OUTPUT(makefile config.h)
diff --git a/pd/src/g_text.c b/pd/src/g_text.c
index 535d993b..54b7ac37 100644
--- a/pd/src/g_text.c
+++ b/pd/src/g_text.c
@@ -332,6 +332,38 @@ static void message_add(t_message *x, t_symbol *s, int argc, t_atom *argv)
glist_retext(x->m_glist, &x->m_text);
}
+static void message_addcomma(t_message *x)
+{
+ t_atom a;
+ SETCOMMA(&a);
+ binbuf_add(x->m_text.te_binbuf, 1, &a);
+ glist_retext(x->m_glist, &x->m_text);
+}
+
+static void message_addsemi(t_message *x)
+{
+ message_add(x, 0, 0, 0);
+}
+
+static void message_adddollar(t_message *x, t_floatarg f)
+{
+ int n = f;
+ if (n < 0)
+ n = 0;
+ t_atom a;
+ SETDOLLAR(&a, n);
+ binbuf_add(x->m_text.te_binbuf, 1, &a);
+ glist_retext(x->m_glist, &x->m_text);
+}
+
+static void message_adddollsym(t_message *x, t_symbol *s)
+{
+ t_atom a;
+ SETDOLLSYM(&a, s);
+ binbuf_add(x->m_text.te_binbuf, 1, &a);
+ glist_retext(x->m_glist, &x->m_text);
+}
+
static void message_click(t_message *x,
t_floatarg xpos, t_floatarg ypos, t_floatarg shift,
t_floatarg ctrl, t_floatarg alt)
@@ -1295,6 +1327,14 @@ void g_text_setup(void)
A_GIMME, 0);
class_addmethod(message_class, (t_method)message_add2, gensym("add2"),
A_GIMME, 0);
+ class_addmethod(message_class, (t_method)message_addcomma,
+ gensym("addcomma"), 0);
+ class_addmethod(message_class, (t_method)message_addsemi,
+ gensym("addsemi"), 0);
+ class_addmethod(message_class, (t_method)message_adddollar,
+ gensym("adddollar"), A_FLOAT, 0);
+ class_addmethod(message_class, (t_method)message_adddollsym,
+ gensym("adddollsym"), A_SYMBOL, 0);
messresponder_class = class_new(gensym("messresponder"), 0, 0,
sizeof(t_text), CLASS_PD, 0);
diff --git a/pd/src/g_traversal.c b/pd/src/g_traversal.c
index 4addeff3..a9165b8d 100644
--- a/pd/src/g_traversal.c
+++ b/pd/src/g_traversal.c
@@ -90,18 +90,6 @@ int gpointer_check(const t_gpointer *gp, int headok)
else return (0);
}
-/* call this if you know the pointer is fresh but don't know if we're pointing
-to the head of a list or to real data. Any pointer is known to be fresh
-when it appears as the argument of a message, but if your "pointer" method
-or inlet stores it and you use it later, call gpointer_check above. */
-
-/* LATER reconsider the above... I no longer think it's true! */
-
-static int gpointer_ishead(const t_gpointer *gp)
-{
- return ((gp->gp_stub->gs_which == GP_GLIST) && !gp->gp_un.gp_scalar);
-}
-
/* get the template for the object pointer to. Assumes we've already checked
freshness. Returns 0 if head of list. */
@@ -122,8 +110,9 @@ static t_symbol *gpointer_gettemplatesym(const t_gpointer *gp)
}
}
- /* copy a pointer to another, assuming the first one is fresh and
- the second one hasn't yet been initialized. */
+ /* copy a pointer to another, assuming the second one hasn't yet been
+ initialized. New gpointers should be initialized either by this
+ routine or by gpointer_init below. */
void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto)
{
*gpto = *gpfrom;
@@ -132,6 +121,8 @@ void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto)
else bug("gpointer_copy");
}
+ /* clear a gpointer that was previously set, releasing the associted
+ gstub if this was the last reference to it. */
void gpointer_unset(t_gpointer *gp)
{
t_gstub *gs;
@@ -416,9 +407,9 @@ static void get_pointer(t_get *x, t_gpointer *gp)
pd_error(x, "get: couldn't find template %s", templatesym->s_name);
return;
}
- if (gpointer_ishead(gp))
+ if (!gpointer_check(gp, 0))
{
- pd_error(x, "get: empty pointer");
+ pd_error(x, "get: stale or empty pointer");
return;
}
if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
@@ -691,9 +682,9 @@ static void getsize_pointer(t_getsize *x, t_gpointer *gp)
pd_error(x, "getsize: field %s not of type array", fieldsym->s_name);
return;
}
- if (gpointer_ishead(gp))
+ if (!gpointer_check(gp, 0))
{
- pd_error(x, "getsize: empty pointer");
+ pd_error(x, "get: stale or empty pointer");
return;
}
if (gpointer_gettemplatesym(gp) != x->x_templatesym)
@@ -1033,9 +1024,9 @@ static void sublist_pointer(t_sublist *x, t_gpointer *gp)
pd_error(x, "sublist: couldn't find template %s", templatesym->s_name);
return;
}
- if (gpointer_ishead(gp))
+ if (!gpointer_check(gp, 0))
{
- pd_error(x, "sublist: empty pointer");
+ pd_error(x, "get: stale or empty pointer");
return;
}
if (!template_find_field(template, x->x_fieldsym,
diff --git a/pd/src/m_conf.c b/pd/src/m_conf.c
index d529ecd6..c7561920 100644
--- a/pd/src/m_conf.c
+++ b/pd/src/m_conf.c
@@ -37,6 +37,7 @@ void x_misc_setup(void);
void x_net_setup(void);
void x_qlist_setup(void);
void x_gui_setup(void);
+void x_list_setup(void);
void d_arithmetic_setup(void);
void d_array_setup(void);
void d_ctl_setup(void);
@@ -83,6 +84,7 @@ void conf_init(void)
x_net_setup();
x_qlist_setup();
x_gui_setup();
+ x_list_setup();
d_arithmetic_setup();
d_array_setup();
d_ctl_setup();
diff --git a/pd/src/makefile b/pd/src/makefile
index f69e9a00..9a560285 100644
--- a/pd/src/makefile
+++ b/pd/src/makefile
@@ -42,7 +42,7 @@ SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
d_math.c d_fft.c d_mayer_fft.c d_fftroutine.c d_array.c d_global.c \
d_delay.c d_resample.c \
x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \
- x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c d_soundfile.c \
+ x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c x_list.c d_soundfile.c \
$(SYSSRC)
diff --git a/pd/src/makefile.dependencies b/pd/src/makefile.dependencies
index 79c847aa..770c2ce3 100644
--- a/pd/src/makefile.dependencies
+++ b/pd/src/makefile.dependencies
@@ -890,6 +890,14 @@ x_gui.o: x_gui.c m_pd.h \
/usr/include/endian.h /usr/include/bits/endian.h /usr/include/stdlib.h \
/usr/include/unistd.h /usr/include/bits/posix_opt.h \
/usr/include/bits/confname.h /usr/include/getopt.h
+x_list.o: x_list.c m_pd.h \
+ /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stddef.h \
+ /usr/include/string.h /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/gnu/stubs.h /usr/include/bits/string.h \
+ /usr/include/bits/string2.h /usr/include/endian.h \
+ /usr/include/bits/endian.h /usr/include/bits/types.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h \
+ /usr/include/stdlib.h
d_soundfile.o: d_soundfile.c /usr/include/unistd.h \
/usr/include/features.h /usr/include/sys/cdefs.h \
/usr/include/gnu/stubs.h /usr/include/bits/posix_opt.h \
diff --git a/pd/src/makefile.in b/pd/src/makefile.in
index 2851e66a..c4a1987e 100644
--- a/pd/src/makefile.in
+++ b/pd/src/makefile.in
@@ -42,7 +42,7 @@ SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
d_math.c d_fft.c d_mayer_fft.c d_fftroutine.c d_array.c d_global.c \
d_delay.c d_resample.c \
x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \
- x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c d_soundfile.c \
+ x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c x_list.c d_soundfile.c \
$(SYSSRC)
diff --git a/pd/src/makefile.nt b/pd/src/makefile.nt
index a33296c1..22430d3c 100644
--- a/pd/src/makefile.nt
+++ b/pd/src/makefile.nt
@@ -34,7 +34,7 @@ SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
d_math.c d_fft.c d_mayer_fft.c d_fftroutine.c d_array.c d_global.c \
d_delay.c d_resample.c \
x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \
- x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c d_soundfile.c \
+ x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c x_list.c d_soundfile.c \
$(SYSSRC)
PADIR = ..\portaudio
diff --git a/pd/src/notes.txt b/pd/src/notes.txt
index 038c2a94..8fa53b39 100644
--- a/pd/src/notes.txt
+++ b/pd/src/notes.txt
@@ -16,11 +16,16 @@ GOP font depends on abstraction, not parent
------------ 0.39 ---------
problems:
+windows:
+ modal dialogs confuse watchdog
+mac:
+ .pd extension not added when saving?
TK commands to nonexistent windows? (maybe fixed)
array name changes don't show up on parent
arrays that don't fit in bounds don't update (same as red rectangle problem?)
what about upsampling inlet~s? ask Pd list...
+
flag for array to suppress printing name
check:
@@ -40,7 +45,6 @@ block resampling arguments
document tabwrite~_start
problems:
-modal dialogs confuse watchdog
patcher inlets don't deal with scalars (zbug.pd)
Macintosh .pd extension not added to filenames
need to optimize canvas_motion (get rid of box hit test??)
@@ -70,7 +74,6 @@ features:
flag to suppress printing array name above graph
rename windowname-pd instead of pd-windowname
fix copyright notices
-update portmusic to latest
IEM guis to use queued updates
pixel font sizes
pd to find running ones (pd -new to defeat)
@@ -85,7 +88,6 @@ tables:
queued graphics updates for IEMGUIs and scalars
think of a way to embed abstractions in a patch
make watchdog work for MACOSX
-GOP bounding box object
IEMGUIs better default font size
search path to include both calling patch and abstraction, if different
abstraction reload shouldn't have to vis everyone
@@ -96,7 +98,7 @@ put serial object in main dist (see rat@telecoma, Apr. 25; winfried May 22)
open/save panel to take messages to init directory, and to set extent list
flags to defeat pre-loading specified classes
expr to parse exponential notation
-
+pipe to handle symbols&pointers (just takes floats now???)
data:
data copy/paste doesn't check templates aren't changed
diff --git a/pd/src/s_inter.c b/pd/src/s_inter.c
index 5eb931ec..3e9ded5f 100644
--- a/pd/src/s_inter.c
+++ b/pd/src/s_inter.c
@@ -851,7 +851,6 @@ int sys_startgui(const char *guidir)
#ifdef UNISTD
int stdinpipe[2];
#endif
- fprintf(stderr, "gui; %s\n", guidir);
/* create an empty FD poll list */
sys_fdpoll = (t_fdpoll *)t_getbytes(0);
sys_nfdpoll = 0;
diff --git a/pd/src/s_midi_alsa.c b/pd/src/s_midi_alsa.c
index 437ac792..6e9143b3 100644
--- a/pd/src/s_midi_alsa.c
+++ b/pd/src/s_midi_alsa.c
@@ -48,6 +48,16 @@ void sys_alsa_do_open_midi(int nmidiin, int *midiinvec,
int i;
alsa_nmidiin = 0;
alsa_nmidiout = 0;
+ if(nmidiin>MAXMIDIINDEV )
+ {
+ post("midi input ports reduced to maximum %d", MAXMIDIINDEV);
+ nmidiin=MAXMIDIINDEV;
+ }
+ if(nmidiout>MAXMIDIOUTDEV)
+ {
+ post("midi output ports reduced to maximum %d", MAXMIDIOUTDEV);
+ nmidiout=MAXMIDIOUTDEV;
+ }
if (nmidiin>0 && nmidiout>0)
err = snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_DUPLEX,0);
@@ -200,8 +210,14 @@ void sys_alsa_poll_midi(void)
void sys_alsa_close_midi()
{
alsa_nmidiin = alsa_nmidiout = 0;
- snd_seq_close(midi_handle);
- snd_midi_event_free(midiev);
+ if(midi_handle)
+ {
+ snd_seq_close(midi_handle);
+ if(midiev)
+ {
+ snd_midi_event_free(midiev);
+ }
+ }
}
#define NSEARCH 10
diff --git a/pd/src/u_main.tk b/pd/src/u_main.tk
index 8da41f7a..401b37d6 100644
--- a/pd/src/u_main.tk
+++ b/pd/src/u_main.tk
@@ -4007,10 +4007,10 @@ proc pdtk_alsa_midi_dialog {id indevlist indev1 indev2 indev3 indev4 \
}
}
if {$alsa} {
- label $id.in1f.l1 -text "In Channels:"
+ label $id.in1f.l1 -text "In Ports:"
entry $id.in1f.x1 -textvariable midi_alsain -width 4
pack $id.in1f.l1 $id.in1f.x1 -side left
- label $id.in1f.l2 -text "Out Channels:"
+ label $id.in1f.l2 -text "Out Ports:"
entry $id.in1f.x2 -textvariable midi_alsaout -width 4
pack $id.in1f.l2 $id.in1f.x2 -side left
}
diff --git a/pd/src/x_connective.c b/pd/src/x_connective.c
index ad6219cd..3d62b319 100644
--- a/pd/src/x_connective.c
+++ b/pd/src/x_connective.c
@@ -505,11 +505,7 @@ static void route_list(t_route *x, t_symbol *sel, int argc, t_atom *argv)
if (x->x_type == A_FLOAT)
{
float f;
- if (!argc) /* empty lists go out reject outlet */
- {
- outlet_bang(x->x_rejectout);
- return;
- }
+ if (!argc) return;
f = atom_getfloat(argv);
for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
if (e->e_w.w_float == f)
@@ -584,8 +580,7 @@ static void *route_new(t_symbol *s, int argc, t_atom *argv)
{
int n;
t_routeelement *e;
- t_route *x;
-
+ t_route *x = (t_route *)pd_new(route_class);
t_atom a;
if (argc == 0)
{
@@ -593,13 +588,6 @@ static void *route_new(t_symbol *s, int argc, t_atom *argv)
SETFLOAT(&a, 0);
argv = &a;
}
- for (n = 1; n < argc; n++)
- if (argv[n].a_type != argv[0].a_type)
- {
- error("route: creation with mixed argument types failed");
- return (0);
- }
- x = (t_route *)pd_new(route_class);
x->x_type = argv[0].a_type;
x->x_nelement = argc;
x->x_vec = (t_routeelement *)getbytes(argc * sizeof(*x->x_vec));
diff --git a/pd/src/x_list.c b/pd/src/x_list.c
new file mode 100644
index 00000000..a867e293
--- /dev/null
+++ b/pd/src/x_list.c
@@ -0,0 +1,415 @@
+/* Copyright (c) 1997- Miller Puckette and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+/* #include <string.h> */
+#include <alloca.h>
+extern t_pd *newest;
+
+#define HAVE_ALLOCA 1 /* LATER this should be set by configure script! */
+#define LIST_NGETBYTE 100 /* bigger that this we use alloc, not alloca */
+
+/* the "list" object family.
+
+ list append - append a list to another
+ list prepend - prepend a list to another
+ list split - first n elements to first outlet, rest to second outlet
+ list strip - send message with leading symbol as selector
+ list length - output number of items in list
+ list nth - nth item in list, counting from zero
+
+Not sure we need these:
+ list cat - build a list by accumulating elements
+ list foreach - spit out elements of a list one by one
+ list array - get items from a named array as a list
+ list reverse - permute elements of a list back to front
+ list pack - synonym for 'pack'
+ list unpack - synonym for 'unpack'
+ list first - output first n elements.
+ list last - output last n elements
+*/
+
+/* -------------- utility functions: storage, copying -------------- */
+ /* List element for storage. Keep an atom and, in case it's a pointer,
+ an associated 'gpointer' to protect against stale pointers. */
+typedef struct _listelem
+{
+ t_atom l_a;
+ t_gpointer l_p;
+} t_listelem;
+
+typedef struct _alist
+{
+ t_pd l_pd; /* object to point inlets to */
+ int l_n; /* number of items */
+ t_listelem *l_vec; /* pointer to items */
+} t_alist;
+
+#if 0 /* probably won't use this version... */
+#ifdef HAVE_ALLOCA
+#define LIST_ALLOCA(x, n) ( \
+ (x).l_n = (n), \
+ (x).l_vec = (t_listelem *)((n) < LIST_NGETBYTE ? \
+ alloca((n) * sizeof(t_listelem)) : getbytes((n) * sizeof(t_listelem)))) \
+#define LIST_FREEA(x) ( \
+ ((x).l_n < LIST_NGETBYTE ||
+ (freebytes((x).l_vec, (x).l_n * sizeof(t_listelem)), 0)))
+
+#else
+#define LIST_ALLOCA(x, n) ( \
+ (x).l_n = (n), \
+ (x).l_vec = (t_listelem *)getbytes((n) * sizeof(t_listelem)))
+#define LIST_FREEA(x) (freebytes((x).l_vec, (x).l_n * sizeof(t_listelem)))
+#endif
+#endif
+
+#if HAVE_ALLOCA
+#define ATOMS_ALLOCA(x, n) ((x) = (t_atom *)((n) < LIST_NGETBYTE ? \
+ alloca((n) * sizeof(t_atom)) : getbytes((n) * sizeof(t_atom))))
+#define ATOMS_FREEA(x, n) ( \
+ ((n) < LIST_NGETBYTE || (freebytes((x), (n) * sizeof(t_atom)), 0)))
+#else
+#define ATOMS_ALLOCA(x, n) ((x) = (t_atom *)getbytes((n) * sizeof(t_atom)))
+#define ATOMS_FREEA(x, n) (freebytes((x), (n) * sizeof(t_atom)))
+#endif
+
+static void atoms_copy(int argc, t_atom *from, t_atom *to)
+{
+ int i;
+ for (i = 0; i < argc; i++)
+ to[i] = from[i];
+}
+
+/* ------------- fake class to divert inlets to ----------------- */
+
+t_class *alist_class;
+
+static void alist_init(t_alist *x)
+{
+ x->l_pd = alist_class;
+ x->l_n = 0;
+ x->l_vec = 0;
+}
+
+static void alist_clear(t_alist *x)
+{
+ int i;
+ for (i = 0; i < x->l_n; i++)
+ {
+ if (x->l_vec[i].l_a.a_type == A_POINTER)
+ gpointer_unset(x->l_vec[i].l_a.a_w.w_gpointer);
+ }
+ if (x->l_vec)
+ freebytes(x->l_vec, x->l_n * sizeof(*x->l_vec));
+}
+
+static void alist_list(t_alist *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int i;
+ alist_clear(x);
+ if (!(x->l_vec = (t_listelem *)getbytes(argc * sizeof(*x->l_vec))))
+ {
+ x->l_n = 0;
+ error("list_alloc: out of memory");
+ return;
+ }
+ x->l_n = argc;
+ for (i = 0; i < argc; i++)
+ {
+ x->l_vec[i].l_a = argv[i];
+ if (x->l_vec[i].l_a.a_type == A_POINTER)
+ gpointer_copy(x->l_vec[i].l_a.a_w.w_gpointer, &x->l_vec[i].l_p);
+ }
+}
+
+static void alist_anything(t_alist *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int i;
+ alist_clear(x);
+ if (!(x->l_vec = (t_listelem *)getbytes((argc+1) * sizeof(*x->l_vec))))
+ {
+ x->l_n = 0;
+ error("list_alloc: out of memory");
+ return;
+ }
+ x->l_n = argc+1;
+ SETSYMBOL(&x->l_vec[0].l_a, s);
+ for (i = 0; i < argc; i++)
+ {
+ x->l_vec[i+1].l_a = argv[i];
+ if (x->l_vec[i+1].l_a.a_type == A_POINTER)
+ gpointer_copy(x->l_vec[i+1].l_a.a_w.w_gpointer, &x->l_vec[i+1].l_p);
+ }
+}
+
+static void alist_toatoms(t_alist *x, t_atom *to)
+{
+ int i;
+ for (i = 0; i < x->l_n; i++)
+ to[i] = x->l_vec[i].l_a;
+}
+
+static void alist_setup(void)
+{
+ alist_class = class_new(gensym("list inlet"),
+ 0, 0, sizeof(t_alist), 0, 0);
+ class_addlist(alist_class, alist_list);
+ class_addanything(alist_class, alist_anything);
+}
+
+/* ------------- list append --------------------- */
+
+t_class *list_append_class;
+
+typedef struct _list_append
+{
+ t_object x_obj;
+ t_alist x_alist;
+} t_list_append;
+
+static void *list_append_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_list_append *x = (t_list_append *)pd_new(list_append_class);
+ alist_init(&x->x_alist);
+ alist_list(&x->x_alist, 0, argc, argv);
+ outlet_new(&x->x_obj, &s_list);
+ inlet_new(&x->x_obj, &x->x_alist.l_pd, 0, 0);
+ return (x);
+}
+
+static void list_append_list(t_list_append *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ t_atom *outv;
+ int n, outc = x->x_alist.l_n + argc;
+ ATOMS_ALLOCA(outv, outc);
+ atoms_copy(argc, argv, outv);
+ alist_toatoms(&x->x_alist, outv+argc);
+ outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
+ ATOMS_FREEA(outv, outc);
+}
+
+static void list_append_anything(t_list_append *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ t_atom *outv;
+ int n, outc = x->x_alist.l_n + argc + 1;
+ ATOMS_ALLOCA(outv, outc);
+ SETSYMBOL(outv, s);
+ atoms_copy(argc, argv, outv + 1);
+ alist_toatoms(&x->x_alist, outv + 1 + argc);
+ outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
+ ATOMS_FREEA(outv, outc);
+}
+
+static void list_append_free(t_list_append *x)
+{
+ alist_clear(&x->x_alist);
+}
+
+static void list_append_setup(void)
+{
+ list_append_class = class_new(gensym("list append"),
+ (t_newmethod)list_append_new, (t_method)list_append_free,
+ sizeof(t_list_append), 0, A_GIMME, 0);
+ class_addlist(list_append_class, list_append_list);
+ class_addanything(list_append_class, list_append_anything);
+ class_sethelpsymbol(list_append_class, &s_list);
+}
+
+/* ------------- list prepend --------------------- */
+
+t_class *list_prepend_class;
+
+typedef struct _list_prepend
+{
+ t_object x_obj;
+ t_alist x_alist;
+} t_list_prepend;
+
+static void *list_prepend_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_list_prepend *x = (t_list_prepend *)pd_new(list_prepend_class);
+ alist_init(&x->x_alist);
+ alist_list(&x->x_alist, 0, argc, argv);
+ outlet_new(&x->x_obj, &s_list);
+ inlet_new(&x->x_obj, &x->x_alist.l_pd, 0, 0);
+ return (x);
+}
+
+static void list_prepend_list(t_list_prepend *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ t_atom *outv;
+ int n, outc = x->x_alist.l_n + argc;
+ ATOMS_ALLOCA(outv, outc);
+ alist_toatoms(&x->x_alist, outv);
+ atoms_copy(argc, argv, outv + x->x_alist.l_n);
+ outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
+ ATOMS_FREEA(outv, outc);
+}
+
+static void list_prepend_anything(t_list_prepend *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ t_atom *outv;
+ int n, outc = x->x_alist.l_n + argc + 1;
+ ATOMS_ALLOCA(outv, outc);
+ alist_toatoms(&x->x_alist, outv);
+ SETSYMBOL(outv + x->x_alist.l_n, s);
+ atoms_copy(argc, argv, outv + x->x_alist.l_n + 1);
+ outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
+ ATOMS_FREEA(outv, outc);
+}
+
+static void list_prepend_free(t_list_prepend *x)
+{
+ alist_clear(&x->x_alist);
+}
+
+static void list_prepend_setup(void)
+{
+ list_prepend_class = class_new(gensym("list prepend"),
+ (t_newmethod)list_prepend_new, (t_method)list_prepend_free,
+ sizeof(t_list_prepend), 0, A_GIMME, 0);
+ class_addlist(list_prepend_class, list_prepend_list);
+ class_addanything(list_prepend_class, list_prepend_anything);
+ class_sethelpsymbol(list_prepend_class, &s_list);
+}
+
+/* ------------- list split --------------------- */
+
+t_class *list_split_class;
+
+typedef struct _list_split
+{
+ t_object x_obj;
+ t_float x_f;
+ t_outlet *x_out1;
+ t_outlet *x_out2;
+ t_outlet *x_out3;
+} t_list_split;
+
+static void *list_split_new(t_floatarg f)
+{
+ t_list_split *x = (t_list_split *)pd_new(list_split_class);
+ x->x_out1 = outlet_new(&x->x_obj, &s_list);
+ x->x_out2 = outlet_new(&x->x_obj, &s_list);
+ x->x_out3 = outlet_new(&x->x_obj, &s_list);
+ floatinlet_new(&x->x_obj, &x->x_f);
+ x->x_f = f;
+ return (x);
+}
+
+static void list_split_list(t_list_split *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ int n = x->x_f;
+ if (n < 0)
+ n = 0;
+ if (argc >= n)
+ {
+ outlet_list(x->x_out2, &s_list, argc-n, argv+n);
+ outlet_list(x->x_out1, &s_list, n, argv);
+ }
+ else outlet_list(x->x_out3, &s_list, argc, argv);
+}
+
+static void list_split_anything(t_list_split *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ t_atom *outv;
+ ATOMS_ALLOCA(outv, argc+1);
+ SETSYMBOL(outv, s);
+ atoms_copy(argc, argv, outv + 1);
+ list_split_list(x, &s_list, argc+1, outv);
+ ATOMS_FREEA(outv, argc+1);
+}
+
+static void list_split_setup(void)
+{
+ list_split_class = class_new(gensym("list split"),
+ (t_newmethod)list_split_new, 0,
+ sizeof(t_list_split), 0, A_DEFFLOAT, 0);
+ class_addlist(list_split_class, list_split_list);
+ class_addanything(list_split_class, list_split_anything);
+ class_sethelpsymbol(list_split_class, &s_list);
+}
+
+/* ------------- list trim --------------------- */
+
+t_class *list_trim_class;
+
+typedef struct _list_trim
+{
+ t_object x_obj;
+} t_list_trim;
+
+static void *list_trim_new( void)
+{
+ t_list_trim *x = (t_list_trim *)pd_new(list_trim_class);
+ outlet_new(&x->x_obj, &s_list);
+ return (x);
+}
+
+static void list_trim_list(t_list_trim *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ if (argc < 1 || argv[0].a_type != A_SYMBOL)
+ outlet_list(x->x_obj.ob_outlet, &s_list, argc, argv);
+ else outlet_anything(x->x_obj.ob_outlet, argv[0].a_w.w_symbol,
+ argc-1, argv+1);
+}
+
+static void list_trim_anything(t_list_trim *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
+}
+
+static void list_trim_setup(void)
+{
+ list_trim_class = class_new(gensym("list trim"),
+ (t_newmethod)list_trim_new, 0,
+ sizeof(t_list_trim), 0, 0);
+ class_addlist(list_trim_class, list_trim_list);
+ class_addanything(list_trim_class, list_trim_anything);
+ class_sethelpsymbol(list_trim_class, &s_list);
+}
+
+/* ------------- list ------------------- */
+
+static void *list_new(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+ if (!argc || argv[0].a_type != A_SYMBOL)
+ newest = list_append_new(s, argc, argv);
+ else
+ {
+ t_symbol *s2 = argv[0].a_w.w_symbol;
+ if (s2 == gensym("append"))
+ newest = list_append_new(s, argc-1, argv+1);
+ else if (s2 == gensym("prepend"))
+ newest = list_prepend_new(s, argc-1, argv+1);
+ else if (s2 == gensym("split"))
+ newest = list_split_new(atom_getfloatarg(1, argc, argv));
+ else if (s2 == gensym("trim"))
+ newest = list_trim_new();
+ else
+ {
+ error("list %s: unknown function", s2->s_name);
+ newest = 0;
+ }
+ }
+ return (newest);
+}
+
+void x_list_setup(void)
+{
+ alist_setup();
+ list_append_setup();
+ list_prepend_setup();
+ list_split_setup();
+ list_trim_setup();
+ class_addcreator((t_newmethod)list_new, &s_list, A_GIMME, 0);
+}