forked from len0rd/rockbox
Change pdbox include paths to handle this git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24916 a1c6a512-1295-4272-9138-f99709370657
1131 lines
29 KiB
C
1131 lines
29 KiB
C
/* Copyright (c) 1997-1999 Miller Puckette.
|
|
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
|
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
|
|
|
/* This file defines Text objects which traverse data contained in scalars
|
|
and arrays:
|
|
|
|
pointer - point to an object belonging to a template
|
|
get - get numeric fields
|
|
set - change numeric fields
|
|
element - get an array element
|
|
getsize - get the size of an array
|
|
setsize - change the size of an array
|
|
append - add an element to a list
|
|
sublist - get a pointer into a list which is an element of another scalar
|
|
|
|
*/
|
|
|
|
#ifdef ROCKBOX
|
|
#include "plugin.h"
|
|
#include "../../pdbox.h"
|
|
#include "m_pd.h"
|
|
#include "g_canvas.h"
|
|
#else /* ROCKBOX */
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h> /* for read/write to files */
|
|
#include "m_pd.h"
|
|
#include "g_canvas.h"
|
|
#endif /* ROCKBOX */
|
|
|
|
/* ------------- gstubs and gpointers - safe pointing --------------- */
|
|
|
|
/* create a gstub which is "owned" by a glist (gl) or an array ("a"). */
|
|
|
|
t_gstub *gstub_new(t_glist *gl, t_array *a)
|
|
{
|
|
t_gstub *gs = t_getbytes(sizeof(*gs));
|
|
if (gl)
|
|
{
|
|
gs->gs_which = GP_GLIST;
|
|
gs->gs_un.gs_glist = gl;
|
|
}
|
|
else
|
|
{
|
|
gs->gs_which = GP_ARRAY;
|
|
gs->gs_un.gs_array = a;
|
|
}
|
|
gs->gs_refcount = 0;
|
|
return (gs);
|
|
}
|
|
|
|
/* when a "gpointer" is set to point to this stub (so we can later chase
|
|
down the owner) we increase a reference count. The following routine is called
|
|
whenever a gpointer is unset from pointing here. If the owner is
|
|
gone and the refcount goes to zero, we can free the gstub safely. */
|
|
|
|
static void gstub_dis(t_gstub *gs)
|
|
{
|
|
int refcount = --gs->gs_refcount;
|
|
if ((!refcount) && gs->gs_which == GP_NONE)
|
|
t_freebytes(gs, sizeof (*gs));
|
|
else if (refcount < 0) bug("gstub_dis");
|
|
}
|
|
|
|
/* this routing is called by the owner to inform the gstub that it is
|
|
being deleted. If no gpointers are pointing here, we can free the gstub;
|
|
otherwise we wait for the last gstub_dis() to free it. */
|
|
|
|
void gstub_cutoff(t_gstub *gs)
|
|
{
|
|
gs->gs_which = GP_NONE;
|
|
if (gs->gs_refcount < 0) bug("gstub_cutoff");
|
|
if (!gs->gs_refcount) t_freebytes(gs, sizeof (*gs));
|
|
}
|
|
|
|
/* call this to verify that a pointer is fresh, i.e., that it either
|
|
points to real data or to the head of a list, and that in either case
|
|
the object hasn't disappeared since this pointer was generated.
|
|
Unless "headok" is set, the routine also fails for the head of a list. */
|
|
|
|
int gpointer_check(const t_gpointer *gp, int headok)
|
|
{
|
|
t_gstub *gs = gp->gp_stub;
|
|
if (!gs) return (0);
|
|
if (gs->gs_which == GP_ARRAY)
|
|
{
|
|
if (gs->gs_un.gs_array->a_valid != gp->gp_valid) return (0);
|
|
else return (1);
|
|
}
|
|
else if (gs->gs_which == GP_GLIST)
|
|
{
|
|
if (!headok && !gp->gp_un.gp_scalar) return (0);
|
|
else if (gs->gs_un.gs_glist->gl_valid != gp->gp_valid) return (0);
|
|
else return (1);
|
|
}
|
|
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. */
|
|
|
|
static t_symbol *gpointer_gettemplatesym(const t_gpointer *gp)
|
|
{
|
|
t_gstub *gs = gp->gp_stub;
|
|
if (gs->gs_which == GP_GLIST)
|
|
{
|
|
t_scalar *sc = gp->gp_un.gp_scalar;
|
|
if (sc)
|
|
return (sc->sc_template);
|
|
else return (0);
|
|
}
|
|
else
|
|
{
|
|
t_array *a = gs->gs_un.gs_array;
|
|
return (a->a_templatesym);
|
|
}
|
|
}
|
|
|
|
/* copy a pointer to another, assuming the first one is fresh and
|
|
the second one hasn't yet been initialized. */
|
|
void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto)
|
|
{
|
|
*gpto = *gpfrom;
|
|
if (gpto->gp_stub)
|
|
gpto->gp_stub->gs_refcount++;
|
|
else bug("gpointer_copy");
|
|
}
|
|
|
|
void gpointer_unset(t_gpointer *gp)
|
|
{
|
|
t_gstub *gs;
|
|
if((gs = gp->gp_stub))
|
|
{
|
|
gstub_dis(gs);
|
|
gp->gp_stub = 0;
|
|
}
|
|
}
|
|
|
|
void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x)
|
|
{
|
|
t_gstub *gs;
|
|
if((gs = gp->gp_stub)) gstub_dis(gs);
|
|
gp->gp_stub = gs = glist->gl_stub;
|
|
gp->gp_valid = glist->gl_valid;
|
|
gp->gp_un.gp_scalar = x;
|
|
gs->gs_refcount++;
|
|
}
|
|
|
|
static void gpointer_setarray(t_gpointer *gp, t_array *array, t_word *w)
|
|
{
|
|
t_gstub *gs;
|
|
if((gs = gp->gp_stub)) gstub_dis(gs);
|
|
gp->gp_stub = gs = array->a_stub;
|
|
gp->gp_valid = array->a_valid;
|
|
gp->gp_un.gp_w = w;
|
|
gs->gs_refcount++;
|
|
}
|
|
|
|
void gpointer_init(t_gpointer *gp)
|
|
{
|
|
gp->gp_stub = 0;
|
|
gp->gp_valid = 0;
|
|
gp->gp_un.gp_scalar = 0;
|
|
}
|
|
|
|
/* ---------------------- pointers ----------------------------- */
|
|
|
|
static t_class *ptrobj_class;
|
|
|
|
typedef struct
|
|
{
|
|
t_symbol *to_type;
|
|
t_outlet *to_outlet;
|
|
} t_typedout;
|
|
|
|
typedef struct _ptrobj
|
|
{
|
|
t_object x_obj;
|
|
t_gpointer x_gp;
|
|
t_typedout *x_typedout;
|
|
int x_ntypedout;
|
|
t_outlet *x_otherout;
|
|
t_outlet *x_bangout;
|
|
} t_ptrobj;
|
|
|
|
static void *ptrobj_new(t_symbol *classname, int argc, t_atom *argv)
|
|
{
|
|
t_ptrobj *x = (t_ptrobj *)pd_new(ptrobj_class);
|
|
t_typedout *to;
|
|
int n;
|
|
#ifdef ROCKBOX
|
|
(void) classname;
|
|
#endif
|
|
gpointer_init(&x->x_gp);
|
|
x->x_typedout = to = (t_typedout *)getbytes(argc * sizeof (*to));
|
|
x->x_ntypedout = n = argc;
|
|
for (; n--; to++)
|
|
{
|
|
to->to_outlet = outlet_new(&x->x_obj, &s_pointer);
|
|
to->to_type = canvas_makebindsym(atom_getsymbol(argv++));
|
|
}
|
|
x->x_otherout = outlet_new(&x->x_obj, &s_pointer);
|
|
x->x_bangout = outlet_new(&x->x_obj, &s_bang);
|
|
pointerinlet_new(&x->x_obj, &x->x_gp);
|
|
return (x);
|
|
}
|
|
|
|
static void ptrobj_traverse(t_ptrobj *x, t_symbol *s)
|
|
{
|
|
t_glist *glist = (t_glist *)pd_findbyclass(s, canvas_class);
|
|
if (glist) gpointer_setglist(&x->x_gp, glist, 0);
|
|
else pd_error(x, "pointer: list '%s' not found", s->s_name);
|
|
}
|
|
|
|
static void ptrobj_vnext(t_ptrobj *x, float f)
|
|
{
|
|
t_gobj *gobj;
|
|
t_gpointer *gp = &x->x_gp;
|
|
t_gstub *gs = gp->gp_stub;
|
|
t_glist *glist;
|
|
int wantselected = (f != 0);
|
|
|
|
if (!gs)
|
|
{
|
|
pd_error(x, "ptrobj_next: no current pointer");
|
|
return;
|
|
}
|
|
if (gs->gs_which != GP_GLIST)
|
|
{
|
|
pd_error(x, "ptrobj_next: lists only, not arrays");
|
|
return;
|
|
}
|
|
glist = gs->gs_un.gs_glist;
|
|
if (glist->gl_valid != gp->gp_valid)
|
|
{
|
|
pd_error(x, "ptrobj_next: stale pointer");
|
|
return;
|
|
}
|
|
if (wantselected && !glist_isvisible(glist))
|
|
{
|
|
pd_error(x,
|
|
"ptrobj_vnext: next-selected only works for a visible window");
|
|
return;
|
|
}
|
|
gobj = &gp->gp_un.gp_scalar->sc_gobj;
|
|
|
|
if (!gobj) gobj = glist->gl_list;
|
|
else gobj = gobj->g_next;
|
|
while (gobj && ((pd_class(&gobj->g_pd) != scalar_class) ||
|
|
(wantselected && !glist_isselected(glist, gobj))))
|
|
gobj = gobj->g_next;
|
|
|
|
if (gobj)
|
|
{
|
|
t_typedout *to;
|
|
int n;
|
|
t_scalar *sc = (t_scalar *)gobj;
|
|
t_symbol *templatesym = sc->sc_template;
|
|
|
|
gp->gp_un.gp_scalar = sc;
|
|
for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
|
|
{
|
|
if (to->to_type == templatesym)
|
|
{
|
|
outlet_pointer(to->to_outlet, &x->x_gp);
|
|
return;
|
|
}
|
|
}
|
|
outlet_pointer(x->x_otherout, &x->x_gp);
|
|
}
|
|
else
|
|
{
|
|
gpointer_unset(gp);
|
|
outlet_bang(x->x_bangout);
|
|
}
|
|
}
|
|
|
|
static void ptrobj_next(t_ptrobj *x)
|
|
{
|
|
ptrobj_vnext(x, 0);
|
|
}
|
|
|
|
static void ptrobj_sendwindow(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv)
|
|
{
|
|
#ifdef ROCKBOX
|
|
(void) s;
|
|
#else /* ROCKBOX */
|
|
t_scalar *sc;
|
|
t_symbol *templatesym;
|
|
int n;
|
|
t_typedout *to;
|
|
#endif /* ROCKBOX */
|
|
t_glist *glist;
|
|
t_pd *canvas;
|
|
t_gstub *gs;
|
|
if (!gpointer_check(&x->x_gp, 1))
|
|
{
|
|
pd_error(x, "ptrobj_bang: empty pointer");
|
|
return;
|
|
}
|
|
gs = x->x_gp.gp_stub;
|
|
if (gs->gs_which == GP_GLIST)
|
|
glist = gs->gs_un.gs_glist;
|
|
else
|
|
{
|
|
t_array *owner_array = gs->gs_un.gs_array;
|
|
while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
|
|
owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
|
|
glist = owner_array->a_gp.gp_stub->gs_un.gs_glist;
|
|
}
|
|
canvas = (t_pd *)glist_getcanvas(glist);
|
|
if (argc && argv->a_type == A_SYMBOL)
|
|
pd_typedmess(canvas, argv->a_w.w_symbol, argc-1, argv+1);
|
|
else pd_error(x, "send-window: no message?");
|
|
}
|
|
|
|
static void ptrobj_bang(t_ptrobj *x)
|
|
{
|
|
t_symbol *templatesym;
|
|
int n;
|
|
t_typedout *to;
|
|
if (!gpointer_check(&x->x_gp, 1))
|
|
{
|
|
pd_error(x, "ptrobj_bang: empty pointer");
|
|
return;
|
|
}
|
|
templatesym = gpointer_gettemplatesym(&x->x_gp);
|
|
for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
|
|
{
|
|
if (to->to_type == templatesym)
|
|
{
|
|
outlet_pointer(to->to_outlet, &x->x_gp);
|
|
return;
|
|
}
|
|
}
|
|
outlet_pointer(x->x_otherout, &x->x_gp);
|
|
}
|
|
|
|
|
|
static void ptrobj_pointer(t_ptrobj *x, t_gpointer *gp)
|
|
{
|
|
gpointer_unset(&x->x_gp);
|
|
gpointer_copy(gp, &x->x_gp);
|
|
ptrobj_bang(x);
|
|
}
|
|
|
|
static void ptrobj_free(t_ptrobj *x)
|
|
{
|
|
freebytes(x->x_typedout, x->x_ntypedout * sizeof (*x->x_typedout));
|
|
gpointer_unset(&x->x_gp);
|
|
}
|
|
|
|
static void ptrobj_setup(void)
|
|
{
|
|
ptrobj_class = class_new(gensym("pointer"), (t_newmethod)ptrobj_new,
|
|
(t_method)ptrobj_free, sizeof(t_ptrobj), 0, A_GIMME, 0);
|
|
class_addmethod(ptrobj_class, (t_method)ptrobj_traverse, gensym("traverse"),
|
|
A_SYMBOL, 0);
|
|
class_addmethod(ptrobj_class, (t_method)ptrobj_next, gensym("next"), 0);
|
|
class_addmethod(ptrobj_class, (t_method)ptrobj_vnext, gensym("vnext"),
|
|
A_DEFFLOAT, 0);
|
|
class_addmethod(ptrobj_class, (t_method)ptrobj_sendwindow,
|
|
gensym("send-window"), A_GIMME, 0);
|
|
class_addpointer(ptrobj_class, ptrobj_pointer);
|
|
class_addbang(ptrobj_class, ptrobj_bang);
|
|
}
|
|
|
|
/* ---------------------- get ----------------------------- */
|
|
|
|
static t_class *get_class;
|
|
|
|
typedef struct _getvariable
|
|
{
|
|
t_symbol *gv_sym;
|
|
t_outlet *gv_outlet;
|
|
} t_getvariable;
|
|
|
|
typedef struct _get
|
|
{
|
|
t_object x_obj;
|
|
t_symbol *x_templatesym;
|
|
int x_nout;
|
|
t_getvariable *x_variables;
|
|
} t_get;
|
|
|
|
static void *get_new(t_symbol *why, int argc, t_atom *argv)
|
|
{
|
|
t_get *x = (t_get *)pd_new(get_class);
|
|
int i;
|
|
t_getvariable *sp;
|
|
x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
|
|
#ifdef ROCKBOX
|
|
(void) why;
|
|
#endif
|
|
if (argc) argc--, argv++;
|
|
x->x_variables
|
|
= (t_getvariable *)getbytes(argc * sizeof (*x->x_variables));
|
|
x->x_nout = argc;
|
|
for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
|
|
{
|
|
sp->gv_sym = atom_getsymbolarg(i, argc, argv);
|
|
sp->gv_outlet = outlet_new(&x->x_obj, 0);
|
|
/* LATER connect with the template and set the outlet's type
|
|
correctly. We can't yet guarantee that the template is there
|
|
before we hit this routine. */
|
|
}
|
|
return (x);
|
|
}
|
|
|
|
static void get_pointer(t_get *x, t_gpointer *gp)
|
|
{
|
|
int nitems = x->x_nout, i;
|
|
t_symbol *templatesym = x->x_templatesym;
|
|
t_template *template = template_findbyname(templatesym);
|
|
t_gstub *gs = gp->gp_stub;
|
|
t_word *vec;
|
|
t_getvariable *vp;
|
|
if (!template)
|
|
{
|
|
pd_error(x, "get: couldn't find template %s", templatesym->s_name);
|
|
return;
|
|
}
|
|
if (gpointer_ishead(gp))
|
|
{
|
|
pd_error(x, "get: empty pointer");
|
|
return;
|
|
}
|
|
if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
|
|
else vec = gp->gp_un.gp_scalar->sc_vec;
|
|
for (i = nitems - 1, vp = x->x_variables + i; i >= 0; i--, vp--)
|
|
{
|
|
float f = template_getfloat(template, vp->gv_sym, vec, 1);
|
|
outlet_float(vp->gv_outlet, f);
|
|
/* LATER deal with other types. */
|
|
}
|
|
}
|
|
|
|
static void get_free(t_get *x)
|
|
{
|
|
freebytes(x->x_variables, x->x_nout * sizeof (*x->x_variables));
|
|
}
|
|
|
|
static void get_setup(void)
|
|
{
|
|
get_class = class_new(gensym("get"), (t_newmethod)get_new,
|
|
(t_method)get_free, sizeof(t_get), 0, A_GIMME, 0);
|
|
class_addpointer(get_class, get_pointer);
|
|
}
|
|
|
|
/* ---------------------- set ----------------------------- */
|
|
|
|
static t_class *set_class;
|
|
|
|
typedef struct _setvariable
|
|
{
|
|
t_symbol *gv_sym;
|
|
t_float gv_f; /* LATER take other types */
|
|
} t_setvariable;
|
|
|
|
typedef struct _set
|
|
{
|
|
t_object x_obj;
|
|
t_gpointer x_gp;
|
|
t_symbol *x_templatesym;
|
|
int x_nin;
|
|
t_setvariable *x_variables;
|
|
} t_set;
|
|
|
|
static void *set_new(t_symbol *why, int argc, t_atom *argv)
|
|
{
|
|
t_set *x = (t_set *)pd_new(set_class);
|
|
int i;
|
|
t_setvariable *sp;
|
|
x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
|
|
#ifdef ROCKBOX
|
|
(void) why;
|
|
#endif
|
|
if (argc) argc--, argv++;
|
|
x->x_variables
|
|
= (t_setvariable *)getbytes(argc * sizeof (*x->x_variables));
|
|
x->x_nin = argc;
|
|
if (argc)
|
|
{
|
|
for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
|
|
{
|
|
sp->gv_sym = atom_getsymbolarg(i, argc, argv);
|
|
sp->gv_f = 0;
|
|
if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
|
|
/* LATER figure out type as in "get" object. */
|
|
}
|
|
}
|
|
pointerinlet_new(&x->x_obj, &x->x_gp);
|
|
gpointer_init(&x->x_gp);
|
|
return (x);
|
|
}
|
|
|
|
static void set_float(t_set *x, t_float f)
|
|
{
|
|
int nitems = x->x_nin, i;
|
|
t_symbol *templatesym = x->x_templatesym;
|
|
t_template *template = template_findbyname(templatesym);
|
|
t_setvariable *vp;
|
|
t_gpointer *gp = &x->x_gp;
|
|
t_gstub *gs = gp->gp_stub;
|
|
t_word *vec;
|
|
if (!template)
|
|
{
|
|
pd_error(x, "set: couldn't find template %s", templatesym->s_name);
|
|
return;
|
|
}
|
|
if (!gpointer_check(gp, 0))
|
|
{
|
|
pd_error(x, "set: empty pointer");
|
|
return;
|
|
}
|
|
if (gpointer_gettemplatesym(gp) != x->x_templatesym)
|
|
{
|
|
pd_error(x, "set %s: got wrong template (%s)",
|
|
x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
|
|
return;
|
|
}
|
|
if (!nitems) return;
|
|
x->x_variables[0].gv_f = f;
|
|
if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
|
|
else vec = gp->gp_un.gp_scalar->sc_vec;
|
|
for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
|
|
{
|
|
template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
|
|
/* LATER deal with other types ala get_pointer. */
|
|
}
|
|
if (gs->gs_which == GP_GLIST)
|
|
glist_redrawitem(gs->gs_un.gs_glist, (t_gobj *)(gp->gp_un.gp_scalar));
|
|
else
|
|
{
|
|
t_array *owner_array = gs->gs_un.gs_array;
|
|
while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
|
|
owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
|
|
glist_redrawitem(owner_array->a_gp.gp_stub->gs_un.gs_glist,
|
|
(t_gobj *)(owner_array->a_gp.gp_un.gp_scalar));
|
|
}
|
|
}
|
|
|
|
static void set_free(t_set *x)
|
|
{
|
|
freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
|
|
gpointer_unset(&x->x_gp);
|
|
}
|
|
|
|
static void set_setup(void)
|
|
{
|
|
set_class = class_new(gensym("set"), (t_newmethod)set_new,
|
|
(t_method)set_free, sizeof(t_set), 0, A_GIMME, 0);
|
|
class_addfloat(set_class, set_float);
|
|
}
|
|
|
|
/* ---------------------- elem ----------------------------- */
|
|
|
|
static t_class *elem_class;
|
|
|
|
typedef struct _elem
|
|
{
|
|
t_object x_obj;
|
|
t_symbol *x_templatesym;
|
|
t_symbol *x_fieldsym;
|
|
t_gpointer x_gp;
|
|
t_gpointer x_gparent;
|
|
} t_elem;
|
|
|
|
static void *elem_new(t_symbol *templatesym, t_symbol *fieldsym)
|
|
{
|
|
t_elem *x = (t_elem *)pd_new(elem_class);
|
|
x->x_templatesym = canvas_makebindsym(templatesym);
|
|
x->x_fieldsym = fieldsym;
|
|
gpointer_init(&x->x_gp);
|
|
gpointer_init(&x->x_gparent);
|
|
pointerinlet_new(&x->x_obj, &x->x_gparent);
|
|
outlet_new(&x->x_obj, &s_pointer);
|
|
return (x);
|
|
}
|
|
|
|
static void elem_float(t_elem *x, t_float f)
|
|
{
|
|
int indx = f, nitems, onset;
|
|
t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
|
|
*elemtemplatesym;
|
|
t_template *template = template_findbyname(templatesym);
|
|
t_template *elemtemplate;
|
|
t_gpointer *gparent = &x->x_gparent;
|
|
t_word *w;
|
|
t_array *array;
|
|
int elemsize, type;
|
|
|
|
if (!gpointer_check(gparent, 0))
|
|
{
|
|
pd_error(x, "element: empty pointer");
|
|
return;
|
|
}
|
|
if (gpointer_gettemplatesym(gparent) != x->x_templatesym)
|
|
{
|
|
pd_error(x, "element %s: got wrong template (%s)",
|
|
x->x_templatesym->s_name, gpointer_gettemplatesym(gparent)->s_name);
|
|
return;
|
|
}
|
|
if (gparent->gp_stub->gs_which == GP_ARRAY) w = gparent->gp_un.gp_w;
|
|
else w = gparent->gp_un.gp_scalar->sc_vec;
|
|
if (!template)
|
|
{
|
|
pd_error(x, "element: couldn't find template %s", templatesym->s_name);
|
|
return;
|
|
}
|
|
if (!template_find_field(template, fieldsym,
|
|
&onset, &type, &elemtemplatesym))
|
|
{
|
|
pd_error(x, "element: couldn't find array field %s", fieldsym->s_name);
|
|
return;
|
|
}
|
|
if (type != DT_ARRAY)
|
|
{
|
|
pd_error(x, "element: field %s not of type array", fieldsym->s_name);
|
|
return;
|
|
}
|
|
if (!(elemtemplate = template_findbyname(elemtemplatesym)))
|
|
{
|
|
pd_error(x, "element: couldn't find field template %s",
|
|
elemtemplatesym->s_name);
|
|
return;
|
|
}
|
|
|
|
elemsize = elemtemplate->t_n * sizeof(t_word);
|
|
|
|
array = *(t_array **)(((char *)w) + onset);
|
|
|
|
nitems = array->a_n;
|
|
if (indx < 0) indx = 0;
|
|
if (indx >= nitems) indx = nitems-1;
|
|
|
|
gpointer_setarray(&x->x_gp, array,
|
|
(t_word *)((char *)(array->a_vec) + indx * elemsize));
|
|
outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
|
|
}
|
|
|
|
static void elem_free(t_elem *x, t_gpointer *gp)
|
|
{
|
|
#ifdef ROCKBOX
|
|
(void) gp;
|
|
#endif
|
|
gpointer_unset(&x->x_gp);
|
|
gpointer_unset(&x->x_gparent);
|
|
}
|
|
|
|
static void elem_setup(void)
|
|
{
|
|
elem_class = class_new(gensym("element"), (t_newmethod)elem_new,
|
|
(t_method)elem_free, sizeof(t_elem), 0, A_DEFSYM, A_DEFSYM, 0);
|
|
class_addfloat(elem_class, elem_float);
|
|
}
|
|
|
|
/* ---------------------- getsize ----------------------------- */
|
|
|
|
static t_class *getsize_class;
|
|
|
|
typedef struct _getsize
|
|
{
|
|
t_object x_obj;
|
|
t_symbol *x_templatesym;
|
|
t_symbol *x_fieldsym;
|
|
} t_getsize;
|
|
|
|
static void *getsize_new(t_symbol *templatesym, t_symbol *fieldsym)
|
|
{
|
|
t_getsize *x = (t_getsize *)pd_new(getsize_class);
|
|
x->x_templatesym = canvas_makebindsym(templatesym);
|
|
x->x_fieldsym = fieldsym;
|
|
outlet_new(&x->x_obj, &s_float);
|
|
return (x);
|
|
}
|
|
|
|
static void getsize_pointer(t_getsize *x, t_gpointer *gp)
|
|
{
|
|
#ifdef ROCKBOX
|
|
int onset, type;
|
|
#else /* ROCKBOX */
|
|
int nitems, onset, type;
|
|
#endif /* ROCKBOX */
|
|
t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
|
|
*elemtemplatesym;
|
|
t_template *template = template_findbyname(templatesym);
|
|
t_word *w;
|
|
t_array *array;
|
|
#ifndef ROCKBOX
|
|
int elemsize;
|
|
#endif
|
|
t_gstub *gs = gp->gp_stub;
|
|
if (!template)
|
|
{
|
|
pd_error(x, "getsize: couldn't find template %s", templatesym->s_name);
|
|
return;
|
|
}
|
|
if (!template_find_field(template, fieldsym,
|
|
&onset, &type, &elemtemplatesym))
|
|
{
|
|
pd_error(x, "getsize: couldn't find array field %s", fieldsym->s_name);
|
|
return;
|
|
}
|
|
if (type != DT_ARRAY)
|
|
{
|
|
pd_error(x, "getsize: field %s not of type array", fieldsym->s_name);
|
|
return;
|
|
}
|
|
if (gpointer_ishead(gp))
|
|
{
|
|
pd_error(x, "getsize: empty pointer");
|
|
return;
|
|
}
|
|
if (gpointer_gettemplatesym(gp) != x->x_templatesym)
|
|
{
|
|
pd_error(x, "getsize %s: got wrong template (%s)",
|
|
x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
|
|
return;
|
|
}
|
|
if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
|
|
else w = gp->gp_un.gp_scalar->sc_vec;
|
|
|
|
array = *(t_array **)(((char *)w) + onset);
|
|
outlet_float(x->x_obj.ob_outlet, (float)(array->a_n));
|
|
}
|
|
|
|
static void getsize_setup(void)
|
|
{
|
|
getsize_class = class_new(gensym("getsize"), (t_newmethod)getsize_new, 0,
|
|
sizeof(t_getsize), 0, A_DEFSYM, A_DEFSYM, 0);
|
|
class_addpointer(getsize_class, getsize_pointer);
|
|
}
|
|
|
|
/* ---------------------- setsize ----------------------------- */
|
|
|
|
static t_class *setsize_class;
|
|
|
|
typedef struct _setsize
|
|
{
|
|
t_object x_obj;
|
|
t_symbol *x_templatesym;
|
|
t_symbol *x_fieldsym;
|
|
t_gpointer x_gp;
|
|
} t_setsize;
|
|
|
|
static void *setsize_new(t_symbol *templatesym, t_symbol *fieldsym,
|
|
t_floatarg newsize)
|
|
{
|
|
#ifdef ROCKBOX
|
|
(void) newsize;
|
|
#endif
|
|
t_setsize *x = (t_setsize *)pd_new(setsize_class);
|
|
x->x_templatesym = canvas_makebindsym(templatesym);
|
|
x->x_fieldsym = fieldsym;
|
|
gpointer_init(&x->x_gp);
|
|
|
|
pointerinlet_new(&x->x_obj, &x->x_gp);
|
|
return (x);
|
|
}
|
|
|
|
static void setsize_float(t_setsize *x, t_float f)
|
|
{
|
|
int nitems, onset, type;
|
|
t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
|
|
*elemtemplatesym;
|
|
t_template *template = template_findbyname(templatesym);
|
|
t_template *elemtemplate;
|
|
t_word *w;
|
|
#ifndef ROCKBOX
|
|
t_atom at;
|
|
#endif
|
|
t_array *array;
|
|
int elemsize;
|
|
int newsize = f;
|
|
t_gpointer *gp = &x->x_gp;
|
|
t_gstub *gs = gp->gp_stub;
|
|
if (!gpointer_check(&x->x_gp, 0))
|
|
{
|
|
pd_error(x, "setsize: empty pointer");
|
|
return;
|
|
}
|
|
if (gpointer_gettemplatesym(&x->x_gp) != x->x_templatesym)
|
|
{
|
|
pd_error(x, "setsize %s: got wrong template (%s)",
|
|
x->x_templatesym->s_name,
|
|
gpointer_gettemplatesym(&x->x_gp)->s_name);
|
|
return;
|
|
}
|
|
if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
|
|
else w = gp->gp_un.gp_scalar->sc_vec;
|
|
|
|
if (!template)
|
|
{
|
|
pd_error(x,"setsize: couldn't find template %s", templatesym->s_name);
|
|
return;
|
|
}
|
|
if (!template_find_field(template, fieldsym,
|
|
&onset, &type, &elemtemplatesym))
|
|
{
|
|
pd_error(x,"setsize: couldn't find array field %s", fieldsym->s_name);
|
|
return;
|
|
}
|
|
if (type != DT_ARRAY)
|
|
{
|
|
pd_error(x,"setsize: field %s not of type array", fieldsym->s_name);
|
|
return;
|
|
}
|
|
|
|
if (!(elemtemplate = template_findbyname(elemtemplatesym)))
|
|
{
|
|
pd_error(x,"element: couldn't find field template %s",
|
|
elemtemplatesym->s_name);
|
|
return;
|
|
}
|
|
|
|
elemsize = elemtemplate->t_n * sizeof(t_word);
|
|
|
|
array = *(t_array **)(((char *)w) + onset);
|
|
|
|
if (elemsize != array->a_elemsize) bug("setsize_gpointer");
|
|
|
|
nitems = array->a_n;
|
|
if (newsize < 1) newsize = 1;
|
|
if (newsize == nitems) return;
|
|
|
|
/* erase the array before resizing it. If we belong to a
|
|
scalar it's easy, but if we belong to an element of another
|
|
array we have to search back until we get to a scalar to erase.
|
|
When graphics updates become queueable this may fall apart... */
|
|
|
|
|
|
if (gs->gs_which == GP_GLIST)
|
|
{
|
|
if (glist_isvisible(gs->gs_un.gs_glist))
|
|
gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 0);
|
|
}
|
|
else
|
|
{
|
|
t_array *owner_array = gs->gs_un.gs_array;
|
|
while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
|
|
owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
|
|
if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
|
|
gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
|
|
owner_array->a_gp.gp_stub->gs_un.gs_glist, 0);
|
|
}
|
|
/* now do the resizing and, if growing, initialize new scalars */
|
|
array->a_vec = (char *)resizebytes(array->a_vec,
|
|
elemsize * nitems, elemsize * newsize);
|
|
array->a_n = newsize;
|
|
if (newsize > nitems)
|
|
{
|
|
char *newelem = ((char *)array->a_vec) + nitems * elemsize;
|
|
#ifdef ROCKBOX
|
|
int nnew = newsize - nitems;
|
|
#else /* ROCKBOX */
|
|
int i = 0, nnew = newsize - nitems;
|
|
#endif /* ROCKBOX */
|
|
|
|
while (nnew--)
|
|
{
|
|
word_init((t_word *)newelem, elemtemplate, gp);
|
|
newelem += elemsize;
|
|
/* post("new %x %x, ntypes %d", newelem, *(int *)newelem, ntypes); */
|
|
}
|
|
}
|
|
|
|
/* redraw again. */
|
|
if (gs->gs_which == GP_GLIST)
|
|
{
|
|
if (glist_isvisible(gs->gs_un.gs_glist))
|
|
gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 1);
|
|
}
|
|
else
|
|
{
|
|
t_array *owner_array = gs->gs_un.gs_array;
|
|
while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
|
|
owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
|
|
if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
|
|
gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
|
|
owner_array->a_gp.gp_stub->gs_un.gs_glist, 1);
|
|
}
|
|
}
|
|
|
|
|
|
static void setsize_free(t_setsize *x)
|
|
{
|
|
gpointer_unset(&x->x_gp);
|
|
}
|
|
|
|
static void setsize_setup(void)
|
|
{
|
|
setsize_class = class_new(gensym("setsize"), (t_newmethod)setsize_new,
|
|
(t_method)setsize_free, sizeof(t_setsize), 0,
|
|
A_DEFSYM, A_DEFSYM, A_DEFFLOAT, 0);
|
|
class_addfloat(setsize_class, setsize_float);
|
|
}
|
|
|
|
/* ---------------------- append ----------------------------- */
|
|
|
|
static t_class *append_class;
|
|
|
|
typedef struct _appendvariable
|
|
{
|
|
t_symbol *gv_sym;
|
|
t_float gv_f;
|
|
} t_appendvariable;
|
|
|
|
typedef struct _append
|
|
{
|
|
t_object x_obj;
|
|
t_gpointer x_gp;
|
|
t_symbol *x_templatesym;
|
|
int x_nin;
|
|
t_appendvariable *x_variables;
|
|
} t_append;
|
|
|
|
static void *append_new(t_symbol *why, int argc, t_atom *argv)
|
|
{
|
|
t_append *x = (t_append *)pd_new(append_class);
|
|
int i;
|
|
t_appendvariable *sp;
|
|
x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
|
|
#ifdef ROCKBOX
|
|
(void) why;
|
|
#endif
|
|
if (argc) argc--, argv++;
|
|
x->x_variables
|
|
= (t_appendvariable *)getbytes(argc * sizeof (*x->x_variables));
|
|
x->x_nin = argc;
|
|
if (argc)
|
|
{
|
|
for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
|
|
{
|
|
sp->gv_sym = atom_getsymbolarg(i, argc, argv);
|
|
sp->gv_f = 0;
|
|
if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
|
|
}
|
|
}
|
|
pointerinlet_new(&x->x_obj, &x->x_gp);
|
|
outlet_new(&x->x_obj, &s_pointer);
|
|
gpointer_init(&x->x_gp);
|
|
return (x);
|
|
}
|
|
|
|
static void append_float(t_append *x, t_float f)
|
|
{
|
|
int nitems = x->x_nin, i;
|
|
t_symbol *templatesym = x->x_templatesym;
|
|
t_template *template = template_findbyname(templatesym);
|
|
t_appendvariable *vp;
|
|
t_gpointer *gp = &x->x_gp;
|
|
t_gstub *gs = gp->gp_stub;
|
|
t_word *vec;
|
|
t_scalar *sc, *oldsc;
|
|
t_glist *glist;
|
|
if (!template)
|
|
{
|
|
pd_error(x, "append: couldn't find template %s", templatesym->s_name);
|
|
return;
|
|
}
|
|
if (!gs)
|
|
{
|
|
pd_error(x, "append: no current pointer");
|
|
return;
|
|
}
|
|
if (gs->gs_which != GP_GLIST)
|
|
{
|
|
pd_error(x, "append: lists only, not arrays");
|
|
return;
|
|
}
|
|
glist = gs->gs_un.gs_glist;
|
|
if (glist->gl_valid != gp->gp_valid)
|
|
{
|
|
pd_error(x, "append: stale pointer");
|
|
return;
|
|
}
|
|
if (!nitems) return;
|
|
x->x_variables[0].gv_f = f;
|
|
|
|
sc = scalar_new(glist, templatesym);
|
|
if (!sc)
|
|
{
|
|
pd_error(x, "%s: couldn't create scalar", templatesym->s_name);
|
|
return;
|
|
}
|
|
oldsc = gp->gp_un.gp_scalar;
|
|
|
|
if (oldsc)
|
|
{
|
|
sc->sc_gobj.g_next = oldsc->sc_gobj.g_next;
|
|
oldsc->sc_gobj.g_next = &sc->sc_gobj;
|
|
}
|
|
else
|
|
{
|
|
sc->sc_gobj.g_next = glist->gl_list;
|
|
glist->gl_list = &sc->sc_gobj;
|
|
}
|
|
if (glist_isvisible(glist_getcanvas(glist)))
|
|
gobj_vis(&sc->sc_gobj, glist, 1);
|
|
|
|
gp->gp_un.gp_scalar = sc;
|
|
vec = sc->sc_vec;
|
|
for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
|
|
{
|
|
template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
|
|
}
|
|
|
|
glist_redrawitem(glist, (t_gobj *)sc);
|
|
|
|
outlet_pointer(x->x_obj.ob_outlet, gp);
|
|
}
|
|
|
|
static void append_free(t_append *x)
|
|
{
|
|
freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
|
|
gpointer_unset(&x->x_gp);
|
|
}
|
|
|
|
static void append_setup(void)
|
|
{
|
|
append_class = class_new(gensym("append"), (t_newmethod)append_new,
|
|
(t_method)append_free, sizeof(t_append), 0, A_GIMME, 0);
|
|
class_addfloat(append_class, append_float);
|
|
}
|
|
|
|
/* ---------------------- sublist ----------------------------- */
|
|
|
|
static t_class *sublist_class;
|
|
|
|
typedef struct _sublist
|
|
{
|
|
t_object x_obj;
|
|
t_symbol *x_templatesym;
|
|
t_symbol *x_fieldsym;
|
|
t_gpointer x_gp;
|
|
} t_sublist;
|
|
|
|
static void *sublist_new(t_symbol *templatesym, t_symbol *fieldsym)
|
|
{
|
|
t_sublist *x = (t_sublist *)pd_new(sublist_class);
|
|
x->x_templatesym = canvas_makebindsym(templatesym);
|
|
x->x_fieldsym = fieldsym;
|
|
gpointer_init(&x->x_gp);
|
|
outlet_new(&x->x_obj, &s_pointer);
|
|
return (x);
|
|
}
|
|
|
|
static void sublist_pointer(t_sublist *x, t_gpointer *gp)
|
|
{
|
|
t_symbol *templatesym = x->x_templatesym, *dummy;
|
|
t_template *template = template_findbyname(templatesym);
|
|
t_gstub *gs = gp->gp_stub;
|
|
#ifndef ROCKBOX
|
|
t_word *vec;
|
|
t_getvariable *vp;
|
|
#endif
|
|
int onset, type;
|
|
t_word *w;
|
|
|
|
if (!template)
|
|
{
|
|
pd_error(x, "sublist: couldn't find template %s", templatesym->s_name);
|
|
return;
|
|
}
|
|
if (gpointer_ishead(gp))
|
|
{
|
|
pd_error(x, "sublist: empty pointer");
|
|
return;
|
|
}
|
|
if (!template_find_field(template, x->x_fieldsym,
|
|
&onset, &type, &dummy))
|
|
{
|
|
pd_error(x, "sublist: couldn't find field %s", x->x_fieldsym->s_name);
|
|
return;
|
|
}
|
|
if (type != DT_LIST)
|
|
{
|
|
pd_error(x, "sublist: field %s not of type list", x->x_fieldsym->s_name);
|
|
return;
|
|
}
|
|
if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
|
|
else w = gp->gp_un.gp_scalar->sc_vec;
|
|
|
|
gpointer_setglist(&x->x_gp, *(t_glist **)(((char *)w) + onset), 0);
|
|
|
|
outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
|
|
}
|
|
|
|
static void sublist_free(t_sublist *x, t_gpointer *gp)
|
|
{
|
|
#ifdef ROCKBOX
|
|
(void) gp;
|
|
#endif
|
|
gpointer_unset(&x->x_gp);
|
|
}
|
|
|
|
static void sublist_setup(void)
|
|
{
|
|
sublist_class = class_new(gensym("sublist"), (t_newmethod)sublist_new,
|
|
(t_method)sublist_free, sizeof(t_sublist), 0, A_DEFSYM, A_DEFSYM, 0);
|
|
class_addpointer(sublist_class, sublist_pointer);
|
|
}
|
|
|
|
/* ----------------- setup function ------------------- */
|
|
|
|
void g_traversal_setup(void)
|
|
{
|
|
ptrobj_setup();
|
|
get_setup();
|
|
set_setup();
|
|
elem_setup();
|
|
getsize_setup();
|
|
setsize_setup();
|
|
append_setup();
|
|
sublist_setup();
|
|
}
|
|
|