Fix pdbox makefile to actually take part in dependency generation
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / g_traversal.c
blob7ca9f5b4383682d615dc80ab7b23eeca35a154cb
1 /* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5 /* This file defines Text objects which traverse data contained in scalars
6 and arrays:
8 pointer - point to an object belonging to a template
9 get - get numeric fields
10 set - change numeric fields
11 element - get an array element
12 getsize - get the size of an array
13 setsize - change the size of an array
14 append - add an element to a list
15 sublist - get a pointer into a list which is an element of another scalar
19 #ifdef ROCKBOX
20 #include "plugin.h"
21 #include "../../pdbox.h"
22 #include "m_pd.h"
23 #include "g_canvas.h"
24 #else /* ROCKBOX */
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h> /* for read/write to files */
28 #include "m_pd.h"
29 #include "g_canvas.h"
30 #endif /* ROCKBOX */
32 /* ------------- gstubs and gpointers - safe pointing --------------- */
34 /* create a gstub which is "owned" by a glist (gl) or an array ("a"). */
36 t_gstub *gstub_new(t_glist *gl, t_array *a)
38 t_gstub *gs = t_getbytes(sizeof(*gs));
39 if (gl)
41 gs->gs_which = GP_GLIST;
42 gs->gs_un.gs_glist = gl;
44 else
46 gs->gs_which = GP_ARRAY;
47 gs->gs_un.gs_array = a;
49 gs->gs_refcount = 0;
50 return (gs);
53 /* when a "gpointer" is set to point to this stub (so we can later chase
54 down the owner) we increase a reference count. The following routine is called
55 whenever a gpointer is unset from pointing here. If the owner is
56 gone and the refcount goes to zero, we can free the gstub safely. */
58 static void gstub_dis(t_gstub *gs)
60 int refcount = --gs->gs_refcount;
61 if ((!refcount) && gs->gs_which == GP_NONE)
62 t_freebytes(gs, sizeof (*gs));
63 else if (refcount < 0) bug("gstub_dis");
66 /* this routing is called by the owner to inform the gstub that it is
67 being deleted. If no gpointers are pointing here, we can free the gstub;
68 otherwise we wait for the last gstub_dis() to free it. */
70 void gstub_cutoff(t_gstub *gs)
72 gs->gs_which = GP_NONE;
73 if (gs->gs_refcount < 0) bug("gstub_cutoff");
74 if (!gs->gs_refcount) t_freebytes(gs, sizeof (*gs));
77 /* call this to verify that a pointer is fresh, i.e., that it either
78 points to real data or to the head of a list, and that in either case
79 the object hasn't disappeared since this pointer was generated.
80 Unless "headok" is set, the routine also fails for the head of a list. */
82 int gpointer_check(const t_gpointer *gp, int headok)
84 t_gstub *gs = gp->gp_stub;
85 if (!gs) return (0);
86 if (gs->gs_which == GP_ARRAY)
88 if (gs->gs_un.gs_array->a_valid != gp->gp_valid) return (0);
89 else return (1);
91 else if (gs->gs_which == GP_GLIST)
93 if (!headok && !gp->gp_un.gp_scalar) return (0);
94 else if (gs->gs_un.gs_glist->gl_valid != gp->gp_valid) return (0);
95 else return (1);
97 else return (0);
100 /* call this if you know the pointer is fresh but don't know if we're pointing
101 to the head of a list or to real data. Any pointer is known to be fresh
102 when it appears as the argument of a message, but if your "pointer" method
103 or inlet stores it and you use it later, call gpointer_check above. */
105 /* LATER reconsider the above... I no longer think it's true! */
107 static int gpointer_ishead(const t_gpointer *gp)
109 return ((gp->gp_stub->gs_which == GP_GLIST) && !gp->gp_un.gp_scalar);
112 /* get the template for the object pointer to. Assumes we've already checked
113 freshness. Returns 0 if head of list. */
115 static t_symbol *gpointer_gettemplatesym(const t_gpointer *gp)
117 t_gstub *gs = gp->gp_stub;
118 if (gs->gs_which == GP_GLIST)
120 t_scalar *sc = gp->gp_un.gp_scalar;
121 if (sc)
122 return (sc->sc_template);
123 else return (0);
125 else
127 t_array *a = gs->gs_un.gs_array;
128 return (a->a_templatesym);
132 /* copy a pointer to another, assuming the first one is fresh and
133 the second one hasn't yet been initialized. */
134 void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto)
136 *gpto = *gpfrom;
137 if (gpto->gp_stub)
138 gpto->gp_stub->gs_refcount++;
139 else bug("gpointer_copy");
142 void gpointer_unset(t_gpointer *gp)
144 t_gstub *gs;
145 if((gs = gp->gp_stub))
147 gstub_dis(gs);
148 gp->gp_stub = 0;
152 void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x)
154 t_gstub *gs;
155 if((gs = gp->gp_stub)) gstub_dis(gs);
156 gp->gp_stub = gs = glist->gl_stub;
157 gp->gp_valid = glist->gl_valid;
158 gp->gp_un.gp_scalar = x;
159 gs->gs_refcount++;
162 static void gpointer_setarray(t_gpointer *gp, t_array *array, t_word *w)
164 t_gstub *gs;
165 if((gs = gp->gp_stub)) gstub_dis(gs);
166 gp->gp_stub = gs = array->a_stub;
167 gp->gp_valid = array->a_valid;
168 gp->gp_un.gp_w = w;
169 gs->gs_refcount++;
172 void gpointer_init(t_gpointer *gp)
174 gp->gp_stub = 0;
175 gp->gp_valid = 0;
176 gp->gp_un.gp_scalar = 0;
179 /* ---------------------- pointers ----------------------------- */
181 static t_class *ptrobj_class;
183 typedef struct
185 t_symbol *to_type;
186 t_outlet *to_outlet;
187 } t_typedout;
189 typedef struct _ptrobj
191 t_object x_obj;
192 t_gpointer x_gp;
193 t_typedout *x_typedout;
194 int x_ntypedout;
195 t_outlet *x_otherout;
196 t_outlet *x_bangout;
197 } t_ptrobj;
199 static void *ptrobj_new(t_symbol *classname, int argc, t_atom *argv)
201 t_ptrobj *x = (t_ptrobj *)pd_new(ptrobj_class);
202 t_typedout *to;
203 int n;
204 #ifdef ROCKBOX
205 (void) classname;
206 #endif
207 gpointer_init(&x->x_gp);
208 x->x_typedout = to = (t_typedout *)getbytes(argc * sizeof (*to));
209 x->x_ntypedout = n = argc;
210 for (; n--; to++)
212 to->to_outlet = outlet_new(&x->x_obj, &s_pointer);
213 to->to_type = canvas_makebindsym(atom_getsymbol(argv++));
215 x->x_otherout = outlet_new(&x->x_obj, &s_pointer);
216 x->x_bangout = outlet_new(&x->x_obj, &s_bang);
217 pointerinlet_new(&x->x_obj, &x->x_gp);
218 return (x);
221 static void ptrobj_traverse(t_ptrobj *x, t_symbol *s)
223 t_glist *glist = (t_glist *)pd_findbyclass(s, canvas_class);
224 if (glist) gpointer_setglist(&x->x_gp, glist, 0);
225 else pd_error(x, "pointer: list '%s' not found", s->s_name);
228 static void ptrobj_vnext(t_ptrobj *x, float f)
230 t_gobj *gobj;
231 t_gpointer *gp = &x->x_gp;
232 t_gstub *gs = gp->gp_stub;
233 t_glist *glist;
234 int wantselected = (f != 0);
236 if (!gs)
238 pd_error(x, "ptrobj_next: no current pointer");
239 return;
241 if (gs->gs_which != GP_GLIST)
243 pd_error(x, "ptrobj_next: lists only, not arrays");
244 return;
246 glist = gs->gs_un.gs_glist;
247 if (glist->gl_valid != gp->gp_valid)
249 pd_error(x, "ptrobj_next: stale pointer");
250 return;
252 if (wantselected && !glist_isvisible(glist))
254 pd_error(x,
255 "ptrobj_vnext: next-selected only works for a visible window");
256 return;
258 gobj = &gp->gp_un.gp_scalar->sc_gobj;
260 if (!gobj) gobj = glist->gl_list;
261 else gobj = gobj->g_next;
262 while (gobj && ((pd_class(&gobj->g_pd) != scalar_class) ||
263 (wantselected && !glist_isselected(glist, gobj))))
264 gobj = gobj->g_next;
266 if (gobj)
268 t_typedout *to;
269 int n;
270 t_scalar *sc = (t_scalar *)gobj;
271 t_symbol *templatesym = sc->sc_template;
273 gp->gp_un.gp_scalar = sc;
274 for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
276 if (to->to_type == templatesym)
278 outlet_pointer(to->to_outlet, &x->x_gp);
279 return;
282 outlet_pointer(x->x_otherout, &x->x_gp);
284 else
286 gpointer_unset(gp);
287 outlet_bang(x->x_bangout);
291 static void ptrobj_next(t_ptrobj *x)
293 ptrobj_vnext(x, 0);
296 static void ptrobj_sendwindow(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv)
298 #ifdef ROCKBOX
299 (void) s;
300 #else /* ROCKBOX */
301 t_scalar *sc;
302 t_symbol *templatesym;
303 int n;
304 t_typedout *to;
305 #endif /* ROCKBOX */
306 t_glist *glist;
307 t_pd *canvas;
308 t_gstub *gs;
309 if (!gpointer_check(&x->x_gp, 1))
311 pd_error(x, "ptrobj_bang: empty pointer");
312 return;
314 gs = x->x_gp.gp_stub;
315 if (gs->gs_which == GP_GLIST)
316 glist = gs->gs_un.gs_glist;
317 else
319 t_array *owner_array = gs->gs_un.gs_array;
320 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
321 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
322 glist = owner_array->a_gp.gp_stub->gs_un.gs_glist;
324 canvas = (t_pd *)glist_getcanvas(glist);
325 if (argc && argv->a_type == A_SYMBOL)
326 pd_typedmess(canvas, argv->a_w.w_symbol, argc-1, argv+1);
327 else pd_error(x, "send-window: no message?");
330 static void ptrobj_bang(t_ptrobj *x)
332 t_symbol *templatesym;
333 int n;
334 t_typedout *to;
335 if (!gpointer_check(&x->x_gp, 1))
337 pd_error(x, "ptrobj_bang: empty pointer");
338 return;
340 templatesym = gpointer_gettemplatesym(&x->x_gp);
341 for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
343 if (to->to_type == templatesym)
345 outlet_pointer(to->to_outlet, &x->x_gp);
346 return;
349 outlet_pointer(x->x_otherout, &x->x_gp);
353 static void ptrobj_pointer(t_ptrobj *x, t_gpointer *gp)
355 gpointer_unset(&x->x_gp);
356 gpointer_copy(gp, &x->x_gp);
357 ptrobj_bang(x);
360 static void ptrobj_free(t_ptrobj *x)
362 freebytes(x->x_typedout, x->x_ntypedout * sizeof (*x->x_typedout));
363 gpointer_unset(&x->x_gp);
366 static void ptrobj_setup(void)
368 ptrobj_class = class_new(gensym("pointer"), (t_newmethod)ptrobj_new,
369 (t_method)ptrobj_free, sizeof(t_ptrobj), 0, A_GIMME, 0);
370 class_addmethod(ptrobj_class, (t_method)ptrobj_traverse, gensym("traverse"),
371 A_SYMBOL, 0);
372 class_addmethod(ptrobj_class, (t_method)ptrobj_next, gensym("next"), 0);
373 class_addmethod(ptrobj_class, (t_method)ptrobj_vnext, gensym("vnext"),
374 A_DEFFLOAT, 0);
375 class_addmethod(ptrobj_class, (t_method)ptrobj_sendwindow,
376 gensym("send-window"), A_GIMME, 0);
377 class_addpointer(ptrobj_class, ptrobj_pointer);
378 class_addbang(ptrobj_class, ptrobj_bang);
381 /* ---------------------- get ----------------------------- */
383 static t_class *get_class;
385 typedef struct _getvariable
387 t_symbol *gv_sym;
388 t_outlet *gv_outlet;
389 } t_getvariable;
391 typedef struct _get
393 t_object x_obj;
394 t_symbol *x_templatesym;
395 int x_nout;
396 t_getvariable *x_variables;
397 } t_get;
399 static void *get_new(t_symbol *why, int argc, t_atom *argv)
401 t_get *x = (t_get *)pd_new(get_class);
402 int i;
403 t_getvariable *sp;
404 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
405 #ifdef ROCKBOX
406 (void) why;
407 #endif
408 if (argc) argc--, argv++;
409 x->x_variables
410 = (t_getvariable *)getbytes(argc * sizeof (*x->x_variables));
411 x->x_nout = argc;
412 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
414 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
415 sp->gv_outlet = outlet_new(&x->x_obj, 0);
416 /* LATER connect with the template and set the outlet's type
417 correctly. We can't yet guarantee that the template is there
418 before we hit this routine. */
420 return (x);
423 static void get_pointer(t_get *x, t_gpointer *gp)
425 int nitems = x->x_nout, i;
426 t_symbol *templatesym = x->x_templatesym;
427 t_template *template = template_findbyname(templatesym);
428 t_gstub *gs = gp->gp_stub;
429 t_word *vec;
430 t_getvariable *vp;
431 if (!template)
433 pd_error(x, "get: couldn't find template %s", templatesym->s_name);
434 return;
436 if (gpointer_ishead(gp))
438 pd_error(x, "get: empty pointer");
439 return;
441 if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
442 else vec = gp->gp_un.gp_scalar->sc_vec;
443 for (i = nitems - 1, vp = x->x_variables + i; i >= 0; i--, vp--)
445 float f = template_getfloat(template, vp->gv_sym, vec, 1);
446 outlet_float(vp->gv_outlet, f);
447 /* LATER deal with other types. */
451 static void get_free(t_get *x)
453 freebytes(x->x_variables, x->x_nout * sizeof (*x->x_variables));
456 static void get_setup(void)
458 get_class = class_new(gensym("get"), (t_newmethod)get_new,
459 (t_method)get_free, sizeof(t_get), 0, A_GIMME, 0);
460 class_addpointer(get_class, get_pointer);
463 /* ---------------------- set ----------------------------- */
465 static t_class *set_class;
467 typedef struct _setvariable
469 t_symbol *gv_sym;
470 t_float gv_f; /* LATER take other types */
471 } t_setvariable;
473 typedef struct _set
475 t_object x_obj;
476 t_gpointer x_gp;
477 t_symbol *x_templatesym;
478 int x_nin;
479 t_setvariable *x_variables;
480 } t_set;
482 static void *set_new(t_symbol *why, int argc, t_atom *argv)
484 t_set *x = (t_set *)pd_new(set_class);
485 int i;
486 t_setvariable *sp;
487 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
488 #ifdef ROCKBOX
489 (void) why;
490 #endif
491 if (argc) argc--, argv++;
492 x->x_variables
493 = (t_setvariable *)getbytes(argc * sizeof (*x->x_variables));
494 x->x_nin = argc;
495 if (argc)
497 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
499 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
500 sp->gv_f = 0;
501 if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
502 /* LATER figure out type as in "get" object. */
505 pointerinlet_new(&x->x_obj, &x->x_gp);
506 gpointer_init(&x->x_gp);
507 return (x);
510 static void set_float(t_set *x, t_float f)
512 int nitems = x->x_nin, i;
513 t_symbol *templatesym = x->x_templatesym;
514 t_template *template = template_findbyname(templatesym);
515 t_setvariable *vp;
516 t_gpointer *gp = &x->x_gp;
517 t_gstub *gs = gp->gp_stub;
518 t_word *vec;
519 if (!template)
521 pd_error(x, "set: couldn't find template %s", templatesym->s_name);
522 return;
524 if (!gpointer_check(gp, 0))
526 pd_error(x, "set: empty pointer");
527 return;
529 if (gpointer_gettemplatesym(gp) != x->x_templatesym)
531 pd_error(x, "set %s: got wrong template (%s)",
532 x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
533 return;
535 if (!nitems) return;
536 x->x_variables[0].gv_f = f;
537 if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
538 else vec = gp->gp_un.gp_scalar->sc_vec;
539 for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
541 template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
542 /* LATER deal with other types ala get_pointer. */
544 if (gs->gs_which == GP_GLIST)
545 glist_redrawitem(gs->gs_un.gs_glist, (t_gobj *)(gp->gp_un.gp_scalar));
546 else
548 t_array *owner_array = gs->gs_un.gs_array;
549 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
550 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
551 glist_redrawitem(owner_array->a_gp.gp_stub->gs_un.gs_glist,
552 (t_gobj *)(owner_array->a_gp.gp_un.gp_scalar));
556 static void set_free(t_set *x)
558 freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
559 gpointer_unset(&x->x_gp);
562 static void set_setup(void)
564 set_class = class_new(gensym("set"), (t_newmethod)set_new,
565 (t_method)set_free, sizeof(t_set), 0, A_GIMME, 0);
566 class_addfloat(set_class, set_float);
569 /* ---------------------- elem ----------------------------- */
571 static t_class *elem_class;
573 typedef struct _elem
575 t_object x_obj;
576 t_symbol *x_templatesym;
577 t_symbol *x_fieldsym;
578 t_gpointer x_gp;
579 t_gpointer x_gparent;
580 } t_elem;
582 static void *elem_new(t_symbol *templatesym, t_symbol *fieldsym)
584 t_elem *x = (t_elem *)pd_new(elem_class);
585 x->x_templatesym = canvas_makebindsym(templatesym);
586 x->x_fieldsym = fieldsym;
587 gpointer_init(&x->x_gp);
588 gpointer_init(&x->x_gparent);
589 pointerinlet_new(&x->x_obj, &x->x_gparent);
590 outlet_new(&x->x_obj, &s_pointer);
591 return (x);
594 static void elem_float(t_elem *x, t_float f)
596 int indx = f, nitems, onset;
597 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
598 *elemtemplatesym;
599 t_template *template = template_findbyname(templatesym);
600 t_template *elemtemplate;
601 t_gpointer *gparent = &x->x_gparent;
602 t_word *w;
603 t_array *array;
604 int elemsize, type;
606 if (!gpointer_check(gparent, 0))
608 pd_error(x, "element: empty pointer");
609 return;
611 if (gpointer_gettemplatesym(gparent) != x->x_templatesym)
613 pd_error(x, "element %s: got wrong template (%s)",
614 x->x_templatesym->s_name, gpointer_gettemplatesym(gparent)->s_name);
615 return;
617 if (gparent->gp_stub->gs_which == GP_ARRAY) w = gparent->gp_un.gp_w;
618 else w = gparent->gp_un.gp_scalar->sc_vec;
619 if (!template)
621 pd_error(x, "element: couldn't find template %s", templatesym->s_name);
622 return;
624 if (!template_find_field(template, fieldsym,
625 &onset, &type, &elemtemplatesym))
627 pd_error(x, "element: couldn't find array field %s", fieldsym->s_name);
628 return;
630 if (type != DT_ARRAY)
632 pd_error(x, "element: field %s not of type array", fieldsym->s_name);
633 return;
635 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
637 pd_error(x, "element: couldn't find field template %s",
638 elemtemplatesym->s_name);
639 return;
642 elemsize = elemtemplate->t_n * sizeof(t_word);
644 array = *(t_array **)(((char *)w) + onset);
646 nitems = array->a_n;
647 if (indx < 0) indx = 0;
648 if (indx >= nitems) indx = nitems-1;
650 gpointer_setarray(&x->x_gp, array,
651 (t_word *)((char *)(array->a_vec) + indx * elemsize));
652 outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
655 static void elem_free(t_elem *x, t_gpointer *gp)
657 #ifdef ROCKBOX
658 (void) gp;
659 #endif
660 gpointer_unset(&x->x_gp);
661 gpointer_unset(&x->x_gparent);
664 static void elem_setup(void)
666 elem_class = class_new(gensym("element"), (t_newmethod)elem_new,
667 (t_method)elem_free, sizeof(t_elem), 0, A_DEFSYM, A_DEFSYM, 0);
668 class_addfloat(elem_class, elem_float);
671 /* ---------------------- getsize ----------------------------- */
673 static t_class *getsize_class;
675 typedef struct _getsize
677 t_object x_obj;
678 t_symbol *x_templatesym;
679 t_symbol *x_fieldsym;
680 } t_getsize;
682 static void *getsize_new(t_symbol *templatesym, t_symbol *fieldsym)
684 t_getsize *x = (t_getsize *)pd_new(getsize_class);
685 x->x_templatesym = canvas_makebindsym(templatesym);
686 x->x_fieldsym = fieldsym;
687 outlet_new(&x->x_obj, &s_float);
688 return (x);
691 static void getsize_pointer(t_getsize *x, t_gpointer *gp)
693 #ifdef ROCKBOX
694 int onset, type;
695 #else /* ROCKBOX */
696 int nitems, onset, type;
697 #endif /* ROCKBOX */
698 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
699 *elemtemplatesym;
700 t_template *template = template_findbyname(templatesym);
701 t_word *w;
702 t_array *array;
703 #ifndef ROCKBOX
704 int elemsize;
705 #endif
706 t_gstub *gs = gp->gp_stub;
707 if (!template)
709 pd_error(x, "getsize: couldn't find template %s", templatesym->s_name);
710 return;
712 if (!template_find_field(template, fieldsym,
713 &onset, &type, &elemtemplatesym))
715 pd_error(x, "getsize: couldn't find array field %s", fieldsym->s_name);
716 return;
718 if (type != DT_ARRAY)
720 pd_error(x, "getsize: field %s not of type array", fieldsym->s_name);
721 return;
723 if (gpointer_ishead(gp))
725 pd_error(x, "getsize: empty pointer");
726 return;
728 if (gpointer_gettemplatesym(gp) != x->x_templatesym)
730 pd_error(x, "getsize %s: got wrong template (%s)",
731 x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
732 return;
734 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
735 else w = gp->gp_un.gp_scalar->sc_vec;
737 array = *(t_array **)(((char *)w) + onset);
738 outlet_float(x->x_obj.ob_outlet, (float)(array->a_n));
741 static void getsize_setup(void)
743 getsize_class = class_new(gensym("getsize"), (t_newmethod)getsize_new, 0,
744 sizeof(t_getsize), 0, A_DEFSYM, A_DEFSYM, 0);
745 class_addpointer(getsize_class, getsize_pointer);
748 /* ---------------------- setsize ----------------------------- */
750 static t_class *setsize_class;
752 typedef struct _setsize
754 t_object x_obj;
755 t_symbol *x_templatesym;
756 t_symbol *x_fieldsym;
757 t_gpointer x_gp;
758 } t_setsize;
760 static void *setsize_new(t_symbol *templatesym, t_symbol *fieldsym,
761 t_floatarg newsize)
763 #ifdef ROCKBOX
764 (void) newsize;
765 #endif
766 t_setsize *x = (t_setsize *)pd_new(setsize_class);
767 x->x_templatesym = canvas_makebindsym(templatesym);
768 x->x_fieldsym = fieldsym;
769 gpointer_init(&x->x_gp);
771 pointerinlet_new(&x->x_obj, &x->x_gp);
772 return (x);
775 static void setsize_float(t_setsize *x, t_float f)
777 int nitems, onset, type;
778 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
779 *elemtemplatesym;
780 t_template *template = template_findbyname(templatesym);
781 t_template *elemtemplate;
782 t_word *w;
783 #ifndef ROCKBOX
784 t_atom at;
785 #endif
786 t_array *array;
787 int elemsize;
788 int newsize = f;
789 t_gpointer *gp = &x->x_gp;
790 t_gstub *gs = gp->gp_stub;
791 if (!gpointer_check(&x->x_gp, 0))
793 pd_error(x, "setsize: empty pointer");
794 return;
796 if (gpointer_gettemplatesym(&x->x_gp) != x->x_templatesym)
798 pd_error(x, "setsize %s: got wrong template (%s)",
799 x->x_templatesym->s_name,
800 gpointer_gettemplatesym(&x->x_gp)->s_name);
801 return;
803 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
804 else w = gp->gp_un.gp_scalar->sc_vec;
806 if (!template)
808 pd_error(x,"setsize: couldn't find template %s", templatesym->s_name);
809 return;
811 if (!template_find_field(template, fieldsym,
812 &onset, &type, &elemtemplatesym))
814 pd_error(x,"setsize: couldn't find array field %s", fieldsym->s_name);
815 return;
817 if (type != DT_ARRAY)
819 pd_error(x,"setsize: field %s not of type array", fieldsym->s_name);
820 return;
823 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
825 pd_error(x,"element: couldn't find field template %s",
826 elemtemplatesym->s_name);
827 return;
830 elemsize = elemtemplate->t_n * sizeof(t_word);
832 array = *(t_array **)(((char *)w) + onset);
834 if (elemsize != array->a_elemsize) bug("setsize_gpointer");
836 nitems = array->a_n;
837 if (newsize < 1) newsize = 1;
838 if (newsize == nitems) return;
840 /* erase the array before resizing it. If we belong to a
841 scalar it's easy, but if we belong to an element of another
842 array we have to search back until we get to a scalar to erase.
843 When graphics updates become queueable this may fall apart... */
846 if (gs->gs_which == GP_GLIST)
848 if (glist_isvisible(gs->gs_un.gs_glist))
849 gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 0);
851 else
853 t_array *owner_array = gs->gs_un.gs_array;
854 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
855 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
856 if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
857 gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
858 owner_array->a_gp.gp_stub->gs_un.gs_glist, 0);
860 /* now do the resizing and, if growing, initialize new scalars */
861 array->a_vec = (char *)resizebytes(array->a_vec,
862 elemsize * nitems, elemsize * newsize);
863 array->a_n = newsize;
864 if (newsize > nitems)
866 char *newelem = ((char *)array->a_vec) + nitems * elemsize;
867 #ifdef ROCKBOX
868 int nnew = newsize - nitems;
869 #else /* ROCKBOX */
870 int i = 0, nnew = newsize - nitems;
871 #endif /* ROCKBOX */
873 while (nnew--)
875 word_init((t_word *)newelem, elemtemplate, gp);
876 newelem += elemsize;
877 /* post("new %x %x, ntypes %d", newelem, *(int *)newelem, ntypes); */
881 /* redraw again. */
882 if (gs->gs_which == GP_GLIST)
884 if (glist_isvisible(gs->gs_un.gs_glist))
885 gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 1);
887 else
889 t_array *owner_array = gs->gs_un.gs_array;
890 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
891 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
892 if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
893 gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
894 owner_array->a_gp.gp_stub->gs_un.gs_glist, 1);
899 static void setsize_free(t_setsize *x)
901 gpointer_unset(&x->x_gp);
904 static void setsize_setup(void)
906 setsize_class = class_new(gensym("setsize"), (t_newmethod)setsize_new,
907 (t_method)setsize_free, sizeof(t_setsize), 0,
908 A_DEFSYM, A_DEFSYM, A_DEFFLOAT, 0);
909 class_addfloat(setsize_class, setsize_float);
912 /* ---------------------- append ----------------------------- */
914 static t_class *append_class;
916 typedef struct _appendvariable
918 t_symbol *gv_sym;
919 t_float gv_f;
920 } t_appendvariable;
922 typedef struct _append
924 t_object x_obj;
925 t_gpointer x_gp;
926 t_symbol *x_templatesym;
927 int x_nin;
928 t_appendvariable *x_variables;
929 } t_append;
931 static void *append_new(t_symbol *why, int argc, t_atom *argv)
933 t_append *x = (t_append *)pd_new(append_class);
934 int i;
935 t_appendvariable *sp;
936 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
937 #ifdef ROCKBOX
938 (void) why;
939 #endif
940 if (argc) argc--, argv++;
941 x->x_variables
942 = (t_appendvariable *)getbytes(argc * sizeof (*x->x_variables));
943 x->x_nin = argc;
944 if (argc)
946 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
948 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
949 sp->gv_f = 0;
950 if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
953 pointerinlet_new(&x->x_obj, &x->x_gp);
954 outlet_new(&x->x_obj, &s_pointer);
955 gpointer_init(&x->x_gp);
956 return (x);
959 static void append_float(t_append *x, t_float f)
961 int nitems = x->x_nin, i;
962 t_symbol *templatesym = x->x_templatesym;
963 t_template *template = template_findbyname(templatesym);
964 t_appendvariable *vp;
965 t_gpointer *gp = &x->x_gp;
966 t_gstub *gs = gp->gp_stub;
967 t_word *vec;
968 t_scalar *sc, *oldsc;
969 t_glist *glist;
970 if (!template)
972 pd_error(x, "append: couldn't find template %s", templatesym->s_name);
973 return;
975 if (!gs)
977 pd_error(x, "append: no current pointer");
978 return;
980 if (gs->gs_which != GP_GLIST)
982 pd_error(x, "append: lists only, not arrays");
983 return;
985 glist = gs->gs_un.gs_glist;
986 if (glist->gl_valid != gp->gp_valid)
988 pd_error(x, "append: stale pointer");
989 return;
991 if (!nitems) return;
992 x->x_variables[0].gv_f = f;
994 sc = scalar_new(glist, templatesym);
995 if (!sc)
997 pd_error(x, "%s: couldn't create scalar", templatesym->s_name);
998 return;
1000 oldsc = gp->gp_un.gp_scalar;
1002 if (oldsc)
1004 sc->sc_gobj.g_next = oldsc->sc_gobj.g_next;
1005 oldsc->sc_gobj.g_next = &sc->sc_gobj;
1007 else
1009 sc->sc_gobj.g_next = glist->gl_list;
1010 glist->gl_list = &sc->sc_gobj;
1012 if (glist_isvisible(glist_getcanvas(glist)))
1013 gobj_vis(&sc->sc_gobj, glist, 1);
1015 gp->gp_un.gp_scalar = sc;
1016 vec = sc->sc_vec;
1017 for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
1019 template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
1022 glist_redrawitem(glist, (t_gobj *)sc);
1024 outlet_pointer(x->x_obj.ob_outlet, gp);
1027 static void append_free(t_append *x)
1029 freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
1030 gpointer_unset(&x->x_gp);
1033 static void append_setup(void)
1035 append_class = class_new(gensym("append"), (t_newmethod)append_new,
1036 (t_method)append_free, sizeof(t_append), 0, A_GIMME, 0);
1037 class_addfloat(append_class, append_float);
1040 /* ---------------------- sublist ----------------------------- */
1042 static t_class *sublist_class;
1044 typedef struct _sublist
1046 t_object x_obj;
1047 t_symbol *x_templatesym;
1048 t_symbol *x_fieldsym;
1049 t_gpointer x_gp;
1050 } t_sublist;
1052 static void *sublist_new(t_symbol *templatesym, t_symbol *fieldsym)
1054 t_sublist *x = (t_sublist *)pd_new(sublist_class);
1055 x->x_templatesym = canvas_makebindsym(templatesym);
1056 x->x_fieldsym = fieldsym;
1057 gpointer_init(&x->x_gp);
1058 outlet_new(&x->x_obj, &s_pointer);
1059 return (x);
1062 static void sublist_pointer(t_sublist *x, t_gpointer *gp)
1064 t_symbol *templatesym = x->x_templatesym, *dummy;
1065 t_template *template = template_findbyname(templatesym);
1066 t_gstub *gs = gp->gp_stub;
1067 #ifndef ROCKBOX
1068 t_word *vec;
1069 t_getvariable *vp;
1070 #endif
1071 int onset, type;
1072 t_word *w;
1074 if (!template)
1076 pd_error(x, "sublist: couldn't find template %s", templatesym->s_name);
1077 return;
1079 if (gpointer_ishead(gp))
1081 pd_error(x, "sublist: empty pointer");
1082 return;
1084 if (!template_find_field(template, x->x_fieldsym,
1085 &onset, &type, &dummy))
1087 pd_error(x, "sublist: couldn't find field %s", x->x_fieldsym->s_name);
1088 return;
1090 if (type != DT_LIST)
1092 pd_error(x, "sublist: field %s not of type list", x->x_fieldsym->s_name);
1093 return;
1095 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
1096 else w = gp->gp_un.gp_scalar->sc_vec;
1098 gpointer_setglist(&x->x_gp, *(t_glist **)(((char *)w) + onset), 0);
1100 outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
1103 static void sublist_free(t_sublist *x, t_gpointer *gp)
1105 #ifdef ROCKBOX
1106 (void) gp;
1107 #endif
1108 gpointer_unset(&x->x_gp);
1111 static void sublist_setup(void)
1113 sublist_class = class_new(gensym("sublist"), (t_newmethod)sublist_new,
1114 (t_method)sublist_free, sizeof(t_sublist), 0, A_DEFSYM, A_DEFSYM, 0);
1115 class_addpointer(sublist_class, sublist_pointer);
1118 /* ----------------- setup function ------------------- */
1120 void g_traversal_setup(void)
1122 ptrobj_setup();
1123 get_setup();
1124 set_setup();
1125 elem_setup();
1126 getsize_setup();
1127 setsize_setup();
1128 append_setup();
1129 sublist_setup();