summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/g_traversal.c
diff options
context:
space:
mode:
authorPeter D'Hoye <peter.dhoye@gmail.com>2009-05-22 21:58:48 +0000
committerPeter D'Hoye <peter.dhoye@gmail.com>2009-05-22 21:58:48 +0000
commit513389b4c1bc8afe4b2dc9947c534bfeb105e3da (patch)
tree10e673b35651ac567fed2eda0c679c7ade64cbc6 /apps/plugins/pdbox/PDa/src/g_traversal.c
parent95fa7f6a2ef466444fbe3fe87efc6d5db6b77b36 (diff)
downloadrockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.tar.gz
rockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.zip
Add FS #10214. Initial commit of the original PDa code for the GSoC Pure Data plugin project of Wincent Balin. Stripped some non-sourcefiles and added a rockbox readme that needs a bit more info from Wincent. Is added to CATEGORIES and viewers, but not yet to SUBDIRS (ie doesn't build yet)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21044 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/g_traversal.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/g_traversal.c2168
1 files changed, 2168 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/g_traversal.c b/apps/plugins/pdbox/PDa/src/g_traversal.c
new file mode 100644
index 0000000000..2a34f5c1e6
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/g_traversal.c
@@ -0,0 +1,2168 @@
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. */
4
5/* This file defines Text objects which traverse data contained in scalars
6and arrays:
7
8pointer - point to an object belonging to a template
9get - get numeric fields
10set - change numeric fields
11element - get an array element
12getsize - get the size of an array
13setsize - change the size of an array
14append - add an element to a list
15sublist - get a pointer into a list which is an element of another scalar
16
17*/
18
19#include <stdlib.h>
20#include <string.h>
21#include <stdio.h> /* for read/write to files */
22#include "m_pd.h"
23#include "g_canvas.h"
24
25/* ------------- gstubs and gpointers - safe pointing --------------- */
26
27/* create a gstub which is "owned" by a glist (gl) or an array ("a"). */
28
29t_gstub *gstub_new(t_glist *gl, t_array *a)
30{
31 t_gstub *gs = t_getbytes(sizeof(*gs));
32 if (gl)
33 {
34 gs->gs_which = GP_GLIST;
35 gs->gs_un.gs_glist = gl;
36 }
37 else
38 {
39 gs->gs_which = GP_ARRAY;
40 gs->gs_un.gs_array = a;
41 }
42 gs->gs_refcount = 0;
43 return (gs);
44}
45
46/* when a "gpointer" is set to point to this stub (so we can later chase
47down the owner) we increase a reference count. The following routine is called
48whenever a gpointer is unset from pointing here. If the owner is
49gone and the refcount goes to zero, we can free the gstub safely. */
50
51static void gstub_dis(t_gstub *gs)
52{
53 int refcount = --gs->gs_refcount;
54 if ((!refcount) && gs->gs_which == GP_NONE)
55 t_freebytes(gs, sizeof (*gs));
56 else if (refcount < 0) bug("gstub_dis");
57}
58
59/* this routing is called by the owner to inform the gstub that it is
60being deleted. If no gpointers are pointing here, we can free the gstub;
61otherwise we wait for the last gstub_dis() to free it. */
62
63void gstub_cutoff(t_gstub *gs)
64{
65 gs->gs_which = GP_NONE;
66 if (gs->gs_refcount < 0) bug("gstub_cutoff");
67 if (!gs->gs_refcount) t_freebytes(gs, sizeof (*gs));
68}
69
70/* call this to verify that a pointer is fresh, i.e., that it either
71points to real data or to the head of a list, and that in either case
72the object hasn't disappeared since this pointer was generated.
73Unless "headok" is set, the routine also fails for the head of a list. */
74
75int gpointer_check(const t_gpointer *gp, int headok)
76{
77 t_gstub *gs = gp->gp_stub;
78 if (!gs) return (0);
79 if (gs->gs_which == GP_ARRAY)
80 {
81 if (gs->gs_un.gs_array->a_valid != gp->gp_valid) return (0);
82 else return (1);
83 }
84 else if (gs->gs_which == GP_GLIST)
85 {
86 if (!headok && !gp->gp_un.gp_scalar) return (0);
87 else if (gs->gs_un.gs_glist->gl_valid != gp->gp_valid) return (0);
88 else return (1);
89 }
90 else return (0);
91}
92
93/* call this if you know the pointer is fresh but don't know if we're pointing
94to the head of a list or to real data. Any pointer is known to be fresh
95when it appears as the argument of a message, but if your "pointer" method
96or inlet stores it and you use it later, call gpointer_check above. */
97
98/* LATER reconsider the above... I no longer think it's true! */
99
100static int gpointer_ishead(const t_gpointer *gp)
101{
102 return ((gp->gp_stub->gs_which == GP_GLIST) && !gp->gp_un.gp_scalar);
103}
104
105/* get the template for the object pointer to. Assumes we've already checked
106freshness. Returns 0 if head of list. */
107
108static t_symbol *gpointer_gettemplatesym(const t_gpointer *gp)
109{
110 t_gstub *gs = gp->gp_stub;
111 if (gs->gs_which == GP_GLIST)
112 {
113 t_scalar *sc = gp->gp_un.gp_scalar;
114 if (sc)
115 return (sc->sc_template);
116 else return (0);
117 }
118 else
119 {
120 t_array *a = gs->gs_un.gs_array;
121 return (a->a_templatesym);
122 }
123}
124
125 /* copy a pointer to another, assuming the first one is fresh and
126 the second one hasn't yet been initialized. */
127void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto)
128{
129 *gpto = *gpfrom;
130 if (gpto->gp_stub)
131 gpto->gp_stub->gs_refcount++;
132 else bug("gpointer_copy");
133}
134
135void gpointer_unset(t_gpointer *gp)
136{
137 t_gstub *gs;
138 if (gs = gp->gp_stub)
139 {
140 gstub_dis(gs);
141 gp->gp_stub = 0;
142 }
143}
144
145void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x)
146{
147 t_gstub *gs;
148 if (gs = gp->gp_stub) gstub_dis(gs);
149 gp->gp_stub = gs = glist->gl_stub;
150 gp->gp_valid = glist->gl_valid;
151 gp->gp_un.gp_scalar = x;
152 gs->gs_refcount++;
153}
154
155static void gpointer_setarray(t_gpointer *gp, t_array *array, t_word *w)
156{
157 t_gstub *gs;
158 if (gs = gp->gp_stub) gstub_dis(gs);
159 gp->gp_stub = gs = array->a_stub;
160 gp->gp_valid = array->a_valid;
161 gp->gp_un.gp_w = w;
162 gs->gs_refcount++;
163}
164
165void gpointer_init(t_gpointer *gp)
166{
167 gp->gp_stub = 0;
168 gp->gp_valid = 0;
169 gp->gp_un.gp_scalar = 0;
170}
171
172/* ---------------------- pointers ----------------------------- */
173
174static t_class *ptrobj_class;
175
176typedef struct
177{
178 t_symbol *to_type;
179 t_outlet *to_outlet;
180} t_typedout;
181
182typedef struct _ptrobj
183{
184 t_object x_obj;
185 t_gpointer x_gp;
186 t_typedout *x_typedout;
187 int x_ntypedout;
188 t_outlet *x_otherout;
189 t_outlet *x_bangout;
190} t_ptrobj;
191
192static void *ptrobj_new(t_symbol *classname, int argc, t_atom *argv)
193{
194 t_ptrobj *x = (t_ptrobj *)pd_new(ptrobj_class);
195 t_typedout *to;
196 int n;
197 gpointer_init(&x->x_gp);
198 x->x_typedout = to = (t_typedout *)getbytes(argc * sizeof (*to));
199 x->x_ntypedout = n = argc;
200 for (; n--; to++)
201 {
202 to->to_outlet = outlet_new(&x->x_obj, &s_pointer);
203 to->to_type = canvas_makebindsym(atom_getsymbol(argv++));
204 }
205 x->x_otherout = outlet_new(&x->x_obj, &s_pointer);
206 x->x_bangout = outlet_new(&x->x_obj, &s_bang);
207 pointerinlet_new(&x->x_obj, &x->x_gp);
208 return (x);
209}
210
211static void ptrobj_traverse(t_ptrobj *x, t_symbol *s)
212{
213 t_glist *glist = (t_glist *)pd_findbyclass(s, canvas_class);
214 if (glist) gpointer_setglist(&x->x_gp, glist, 0);
215 else pd_error(x, "pointer: list '%s' not found", s->s_name);
216}
217
218static void ptrobj_vnext(t_ptrobj *x, float f)
219{
220 t_gobj *gobj;
221 t_gpointer *gp = &x->x_gp;
222 t_gstub *gs = gp->gp_stub;
223 t_glist *glist;
224 int wantselected = (f != 0);
225
226 if (!gs)
227 {
228 pd_error(x, "ptrobj_next: no current pointer");
229 return;
230 }
231 if (gs->gs_which != GP_GLIST)
232 {
233 pd_error(x, "ptrobj_next: lists only, not arrays");
234 return;
235 }
236 glist = gs->gs_un.gs_glist;
237 if (glist->gl_valid != gp->gp_valid)
238 {
239 pd_error(x, "ptrobj_next: stale pointer");
240 return;
241 }
242 if (wantselected && !glist_isvisible(glist))
243 {
244 pd_error(x,
245 "ptrobj_vnext: next-selected only works for a visible window");
246 return;
247 }
248 gobj = &gp->gp_un.gp_scalar->sc_gobj;
249
250 if (!gobj) gobj = glist->gl_list;
251 else gobj = gobj->g_next;
252 while (gobj && ((pd_class(&gobj->g_pd) != scalar_class) ||
253 (wantselected && !glist_isselected(glist, gobj))))
254 gobj = gobj->g_next;
255
256 if (gobj)
257 {
258 t_typedout *to;
259 int n;
260 t_scalar *sc = (t_scalar *)gobj;
261 t_symbol *templatesym = sc->sc_template;
262
263 gp->gp_un.gp_scalar = sc;
264 for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
265 {
266 if (to->to_type == templatesym)
267 {
268 outlet_pointer(to->to_outlet, &x->x_gp);
269 return;
270 }
271 }
272 outlet_pointer(x->x_otherout, &x->x_gp);
273 }
274 else
275 {
276 gpointer_unset(gp);
277 outlet_bang(x->x_bangout);
278 }
279}
280
281static void ptrobj_next(t_ptrobj *x)
282{
283 ptrobj_vnext(x, 0);
284}
285
286static void ptrobj_sendwindow(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv)
287{
288 t_scalar *sc;
289 t_symbol *templatesym;
290 int n;
291 t_typedout *to;
292 t_glist *glist;
293 t_pd *canvas;
294 t_gstub *gs;
295 if (!gpointer_check(&x->x_gp, 1))
296 {
297 pd_error(x, "ptrobj_bang: empty pointer");
298 return;
299 }
300 gs = x->x_gp.gp_stub;
301 if (gs->gs_which == GP_GLIST)
302 glist = gs->gs_un.gs_glist;
303 else
304 {
305 t_array *owner_array = gs->gs_un.gs_array;
306 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
307 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
308 glist = owner_array->a_gp.gp_stub->gs_un.gs_glist;
309 }
310 canvas = (t_pd *)glist_getcanvas(glist);
311 if (argc && argv->a_type == A_SYMBOL)
312 pd_typedmess(canvas, argv->a_w.w_symbol, argc-1, argv+1);
313 else pd_error(x, "send-window: no message?");
314}
315
316static void ptrobj_bang(t_ptrobj *x)
317{
318 t_symbol *templatesym;
319 int n;
320 t_typedout *to;
321 if (!gpointer_check(&x->x_gp, 1))
322 {
323 pd_error(x, "ptrobj_bang: empty pointer");
324 return;
325 }
326 templatesym = gpointer_gettemplatesym(&x->x_gp);
327 for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
328 {
329 if (to->to_type == templatesym)
330 {
331 outlet_pointer(to->to_outlet, &x->x_gp);
332 return;
333 }
334 }
335 outlet_pointer(x->x_otherout, &x->x_gp);
336}
337
338
339static void ptrobj_pointer(t_ptrobj *x, t_gpointer *gp)
340{
341 gpointer_unset(&x->x_gp);
342 gpointer_copy(gp, &x->x_gp);
343 ptrobj_bang(x);
344}
345
346static void ptrobj_free(t_ptrobj *x)
347{
348 freebytes(x->x_typedout, x->x_ntypedout * sizeof (*x->x_typedout));
349 gpointer_unset(&x->x_gp);
350}
351
352static void ptrobj_setup(void)
353{
354 ptrobj_class = class_new(gensym("pointer"), (t_newmethod)ptrobj_new,
355 (t_method)ptrobj_free, sizeof(t_ptrobj), 0, A_GIMME, 0);
356 class_addmethod(ptrobj_class, (t_method)ptrobj_traverse, gensym("traverse"),
357 A_SYMBOL, 0);
358 class_addmethod(ptrobj_class, (t_method)ptrobj_next, gensym("next"), 0);
359 class_addmethod(ptrobj_class, (t_method)ptrobj_vnext, gensym("vnext"),
360 A_DEFFLOAT, 0);
361 class_addmethod(ptrobj_class, (t_method)ptrobj_sendwindow,
362 gensym("send-window"), A_GIMME, 0);
363 class_addpointer(ptrobj_class, ptrobj_pointer);
364 class_addbang(ptrobj_class, ptrobj_bang);
365}
366
367/* ---------------------- get ----------------------------- */
368
369static t_class *get_class;
370
371typedef struct _getvariable
372{
373 t_symbol *gv_sym;
374 t_outlet *gv_outlet;
375} t_getvariable;
376
377typedef struct _get
378{
379 t_object x_obj;
380 t_symbol *x_templatesym;
381 int x_nout;
382 t_getvariable *x_variables;
383} t_get;
384
385static void *get_new(t_symbol *why, int argc, t_atom *argv)
386{
387 t_get *x = (t_get *)pd_new(get_class);
388 int i;
389 t_getvariable *sp;
390 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
391 if (argc) argc--, argv++;
392 x->x_variables
393 = (t_getvariable *)getbytes(argc * sizeof (*x->x_variables));
394 x->x_nout = argc;
395 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
396 {
397 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
398 sp->gv_outlet = outlet_new(&x->x_obj, 0);
399 /* LATER connect with the template and set the outlet's type
400 correctly. We can't yet guarantee that the template is there
401 before we hit this routine. */
402 }
403 return (x);
404}
405
406static void get_pointer(t_get *x, t_gpointer *gp)
407{
408 int nitems = x->x_nout, i;
409 t_symbol *templatesym = x->x_templatesym;
410 t_template *template = template_findbyname(templatesym);
411 t_gstub *gs = gp->gp_stub;
412 t_word *vec;
413 t_getvariable *vp;
414 if (!template)
415 {
416 pd_error(x, "get: couldn't find template %s", templatesym->s_name);
417 return;
418 }
419 if (gpointer_ishead(gp))
420 {
421 pd_error(x, "get: empty pointer");
422 return;
423 }
424 if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
425 else vec = gp->gp_un.gp_scalar->sc_vec;
426 for (i = nitems - 1, vp = x->x_variables + i; i >= 0; i--, vp--)
427 {
428 float f = template_getfloat(template, vp->gv_sym, vec, 1);
429 outlet_float(vp->gv_outlet, f);
430 /* LATER deal with other types. */
431 }
432}
433
434static void get_free(t_get *x)
435{
436 freebytes(x->x_variables, x->x_nout * sizeof (*x->x_variables));
437}
438
439static void get_setup(void)
440{
441 get_class = class_new(gensym("get"), (t_newmethod)get_new,
442 (t_method)get_free, sizeof(t_get), 0, A_GIMME, 0);
443 class_addpointer(get_class, get_pointer);
444}
445
446/* ---------------------- set ----------------------------- */
447
448static t_class *set_class;
449
450typedef struct _setvariable
451{
452 t_symbol *gv_sym;
453 t_float gv_f; /* LATER take other types */
454} t_setvariable;
455
456typedef struct _set
457{
458 t_object x_obj;
459 t_gpointer x_gp;
460 t_symbol *x_templatesym;
461 int x_nin;
462 t_setvariable *x_variables;
463} t_set;
464
465static void *set_new(t_symbol *why, int argc, t_atom *argv)
466{
467 t_set *x = (t_set *)pd_new(set_class);
468 int i;
469 t_setvariable *sp;
470 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
471 if (argc) argc--, argv++;
472 x->x_variables
473 = (t_setvariable *)getbytes(argc * sizeof (*x->x_variables));
474 x->x_nin = argc;
475 if (argc)
476 {
477 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
478 {
479 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
480 sp->gv_f = 0;
481 if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
482 /* LATER figure out type as in "get" object. */
483 }
484 }
485 pointerinlet_new(&x->x_obj, &x->x_gp);
486 gpointer_init(&x->x_gp);
487 return (x);
488}
489
490static void set_float(t_set *x, t_float f)
491{
492 int nitems = x->x_nin, i;
493 t_symbol *templatesym = x->x_templatesym;
494 t_template *template = template_findbyname(templatesym);
495 t_setvariable *vp;
496 t_gpointer *gp = &x->x_gp;
497 t_gstub *gs = gp->gp_stub;
498 t_word *vec;
499 if (!template)
500 {
501 pd_error(x, "set: couldn't find template %s", templatesym->s_name);
502 return;
503 }
504 if (!gpointer_check(gp, 0))
505 {
506 pd_error(x, "set: empty pointer");
507 return;
508 }
509 if (gpointer_gettemplatesym(gp) != x->x_templatesym)
510 {
511 pd_error(x, "set %s: got wrong template (%s)",
512 x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
513 return;
514 }
515 if (!nitems) return;
516 x->x_variables[0].gv_f = f;
517 if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
518 else vec = gp->gp_un.gp_scalar->sc_vec;
519 for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
520 {
521 template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
522 /* LATER deal with other types ala get_pointer. */
523 }
524 if (gs->gs_which == GP_GLIST)
525 glist_redrawitem(gs->gs_un.gs_glist, (t_gobj *)(gp->gp_un.gp_scalar));
526 else
527 {
528 t_array *owner_array = gs->gs_un.gs_array;
529 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
530 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
531 glist_redrawitem(owner_array->a_gp.gp_stub->gs_un.gs_glist,
532 (t_gobj *)(owner_array->a_gp.gp_un.gp_scalar));
533 }
534}
535
536static void set_free(t_set *x)
537{
538 freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
539 gpointer_unset(&x->x_gp);
540}
541
542static void set_setup(void)
543{
544 set_class = class_new(gensym("set"), (t_newmethod)set_new,
545 (t_method)set_free, sizeof(t_set), 0, A_GIMME, 0);
546 class_addfloat(set_class, set_float);
547}
548
549/* ---------------------- elem ----------------------------- */
550
551static t_class *elem_class;
552
553typedef struct _elem
554{
555 t_object x_obj;
556 t_symbol *x_templatesym;
557 t_symbol *x_fieldsym;
558 t_gpointer x_gp;
559 t_gpointer x_gparent;
560} t_elem;
561
562static void *elem_new(t_symbol *templatesym, t_symbol *fieldsym)
563{
564 t_elem *x = (t_elem *)pd_new(elem_class);
565 x->x_templatesym = canvas_makebindsym(templatesym);
566 x->x_fieldsym = fieldsym;
567 gpointer_init(&x->x_gp);
568 gpointer_init(&x->x_gparent);
569 pointerinlet_new(&x->x_obj, &x->x_gparent);
570 outlet_new(&x->x_obj, &s_pointer);
571 return (x);
572}
573
574static void elem_float(t_elem *x, t_float f)
575{
576 int indx = f, nitems, onset;
577 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
578 *elemtemplatesym;
579 t_template *template = template_findbyname(templatesym);
580 t_template *elemtemplate;
581 t_gpointer *gparent = &x->x_gparent;
582 t_word *w;
583 t_array *array;
584 int elemsize, type;
585
586 if (!gpointer_check(gparent, 0))
587 {
588 pd_error(x, "element: empty pointer");
589 return;
590 }
591 if (gpointer_gettemplatesym(gparent) != x->x_templatesym)
592 {
593 pd_error(x, "element %s: got wrong template (%s)",
594 x->x_templatesym->s_name, gpointer_gettemplatesym(gparent)->s_name);
595 return;
596 }
597 if (gparent->gp_stub->gs_which == GP_ARRAY) w = gparent->gp_un.gp_w;
598 else w = gparent->gp_un.gp_scalar->sc_vec;
599 if (!template)
600 {
601 pd_error(x, "element: couldn't find template %s", templatesym->s_name);
602 return;
603 }
604 if (!template_find_field(template, fieldsym,
605 &onset, &type, &elemtemplatesym))
606 {
607 pd_error(x, "element: couldn't find array field %s", fieldsym->s_name);
608 return;
609 }
610 if (type != DT_ARRAY)
611 {
612 pd_error(x, "element: field %s not of type array", fieldsym->s_name);
613 return;
614 }
615 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
616 {
617 pd_error(x, "element: couldn't find field template %s",
618 elemtemplatesym->s_name);
619 return;
620 }
621
622 elemsize = elemtemplate->t_n * sizeof(t_word);
623
624 array = *(t_array **)(((char *)w) + onset);
625
626 nitems = array->a_n;
627 if (indx < 0) indx = 0;
628 if (indx >= nitems) indx = nitems-1;
629
630 gpointer_setarray(&x->x_gp, array,
631 (t_word *)((char *)(array->a_vec) + indx * elemsize));
632 outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
633}
634
635static void elem_free(t_elem *x, t_gpointer *gp)
636{
637 gpointer_unset(&x->x_gp);
638 gpointer_unset(&x->x_gparent);
639}
640
641static void elem_setup(void)
642{
643 elem_class = class_new(gensym("element"), (t_newmethod)elem_new,
644 (t_method)elem_free, sizeof(t_elem), 0, A_DEFSYM, A_DEFSYM, 0);
645 class_addfloat(elem_class, elem_float);
646}
647
648/* ---------------------- getsize ----------------------------- */
649
650static t_class *getsize_class;
651
652typedef struct _getsize
653{
654 t_object x_obj;
655 t_symbol *x_templatesym;
656 t_symbol *x_fieldsym;
657} t_getsize;
658
659static void *getsize_new(t_symbol *templatesym, t_symbol *fieldsym)
660{
661 t_getsize *x = (t_getsize *)pd_new(getsize_class);
662 x->x_templatesym = canvas_makebindsym(templatesym);
663 x->x_fieldsym = fieldsym;
664 outlet_new(&x->x_obj, &s_float);
665 return (x);
666}
667
668static void getsize_pointer(t_getsize *x, t_gpointer *gp)
669{
670 int nitems, onset, type;
671 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
672 *elemtemplatesym;
673 t_template *template = template_findbyname(templatesym);
674 t_word *w;
675 t_array *array;
676 int elemsize;
677 t_gstub *gs = gp->gp_stub;
678 if (!template)
679 {
680 pd_error(x, "getsize: couldn't find template %s", templatesym->s_name);
681 return;
682 }
683 if (!template_find_field(template, fieldsym,
684 &onset, &type, &elemtemplatesym))
685 {
686 pd_error(x, "getsize: couldn't find array field %s", fieldsym->s_name);
687 return;
688 }
689 if (type != DT_ARRAY)
690 {
691 pd_error(x, "getsize: field %s not of type array", fieldsym->s_name);
692 return;
693 }
694 if (gpointer_ishead(gp))
695 {
696 pd_error(x, "getsize: empty pointer");
697 return;
698 }
699 if (gpointer_gettemplatesym(gp) != x->x_templatesym)
700 {
701 pd_error(x, "getsize %s: got wrong template (%s)",
702 x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
703 return;
704 }
705 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
706 else w = gp->gp_un.gp_scalar->sc_vec;
707
708 array = *(t_array **)(((char *)w) + onset);
709 outlet_float(x->x_obj.ob_outlet, (float)(array->a_n));
710}
711
712static void getsize_setup(void)
713{
714 getsize_class = class_new(gensym("getsize"), (t_newmethod)getsize_new, 0,
715 sizeof(t_getsize), 0, A_DEFSYM, A_DEFSYM, 0);
716 class_addpointer(getsize_class, getsize_pointer);
717}
718
719/* ---------------------- setsize ----------------------------- */
720
721static t_class *setsize_class;
722
723typedef struct _setsize
724{
725 t_object x_obj;
726 t_symbol *x_templatesym;
727 t_symbol *x_fieldsym;
728 t_gpointer x_gp;
729} t_setsize;
730
731static void *setsize_new(t_symbol *templatesym, t_symbol *fieldsym,
732 t_floatarg newsize)
733{
734 t_setsize *x = (t_setsize *)pd_new(setsize_class);
735 x->x_templatesym = canvas_makebindsym(templatesym);
736 x->x_fieldsym = fieldsym;
737 gpointer_init(&x->x_gp);
738
739 pointerinlet_new(&x->x_obj, &x->x_gp);
740 return (x);
741}
742
743static void setsize_float(t_setsize *x, t_float f)
744{
745 int nitems, onset, type;
746 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
747 *elemtemplatesym;
748 t_template *template = template_findbyname(templatesym);
749 t_template *elemtemplate;
750 t_word *w;
751 t_atom at;
752 t_array *array;
753 int elemsize;
754 int newsize = f;
755 t_gpointer *gp = &x->x_gp;
756 t_gstub *gs = gp->gp_stub;
757 if (!gpointer_check(&x->x_gp, 0))
758 {
759 pd_error(x, "setsize: empty pointer");
760 return;
761 }
762 if (gpointer_gettemplatesym(&x->x_gp) != x->x_templatesym)
763 {
764 pd_error(x, "setsize %s: got wrong template (%s)",
765 x->x_templatesym->s_name,
766 gpointer_gettemplatesym(&x->x_gp)->s_name);
767 return;
768 }
769 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
770 else w = gp->gp_un.gp_scalar->sc_vec;
771
772 if (!template)
773 {
774 pd_error(x,"setsize: couldn't find template %s", templatesym->s_name);
775 return;
776 }
777 if (!template_find_field(template, fieldsym,
778 &onset, &type, &elemtemplatesym))
779 {
780 pd_error(x,"setsize: couldn't find array field %s", fieldsym->s_name);
781 return;
782 }
783 if (type != DT_ARRAY)
784 {
785 pd_error(x,"setsize: field %s not of type array", fieldsym->s_name);
786 return;
787 }
788
789 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
790 {
791 pd_error(x,"element: couldn't find field template %s",
792 elemtemplatesym->s_name);
793 return;
794 }
795
796 elemsize = elemtemplate->t_n * sizeof(t_word);
797
798 array = *(t_array **)(((char *)w) + onset);
799
800 if (elemsize != array->a_elemsize) bug("setsize_gpointer");
801
802 nitems = array->a_n;
803 if (newsize < 1) newsize = 1;
804 if (newsize == nitems) return;
805
806 /* erase the array before resizing it. If we belong to a
807 scalar it's easy, but if we belong to an element of another
808 array we have to search back until we get to a scalar to erase.
809 When graphics updates become queueable this may fall apart... */
810
811
812 if (gs->gs_which == GP_GLIST)
813 {
814 if (glist_isvisible(gs->gs_un.gs_glist))
815 gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 0);
816 }
817 else
818 {
819 t_array *owner_array = gs->gs_un.gs_array;
820 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
821 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
822 if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
823 gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
824 owner_array->a_gp.gp_stub->gs_un.gs_glist, 0);
825 }
826 /* now do the resizing and, if growing, initialize new scalars */
827 array->a_vec = (char *)resizebytes(array->a_vec,
828 elemsize * nitems, elemsize * newsize);
829 array->a_n = newsize;
830 if (newsize > nitems)
831 {
832 char *newelem = ((char *)array->a_vec) + nitems * elemsize;
833 int i = 0, nnew = newsize - nitems;
834
835 while (nnew--)
836 {
837 word_init((t_word *)newelem, elemtemplate, gp);
838 newelem += elemsize;
839 /* post("new %x %x, ntypes %d", newelem, *(int *)newelem, ntypes); */
840 }
841 }
842
843 /* redraw again. */
844 if (gs->gs_which == GP_GLIST)
845 {
846 if (glist_isvisible(gs->gs_un.gs_glist))
847 gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 1);
848 }
849 else
850 {
851 t_array *owner_array = gs->gs_un.gs_array;
852 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
853 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
854 if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
855 gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
856 owner_array->a_gp.gp_stub->gs_un.gs_glist, 1);
857 }
858}
859
860
861static void setsize_free(t_setsize *x)
862{
863 gpointer_unset(&x->x_gp);
864}
865
866static void setsize_setup(void)
867{
868 setsize_class = class_new(gensym("setsize"), (t_newmethod)setsize_new,
869 (t_method)setsize_free, sizeof(t_setsize), 0,
870 A_DEFSYM, A_DEFSYM, A_DEFFLOAT, 0);
871 class_addfloat(setsize_class, setsize_float);
872}
873
874/* ---------------------- append ----------------------------- */
875
876static t_class *append_class;
877
878typedef struct _appendvariable
879{
880 t_symbol *gv_sym;
881 t_float gv_f;
882} t_appendvariable;
883
884typedef struct _append
885{
886 t_object x_obj;
887 t_gpointer x_gp;
888 t_symbol *x_templatesym;
889 int x_nin;
890 t_appendvariable *x_variables;
891} t_append;
892
893static void *append_new(t_symbol *why, int argc, t_atom *argv)
894{
895 t_append *x = (t_append *)pd_new(append_class);
896 int i;
897 t_appendvariable *sp;
898 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
899 if (argc) argc--, argv++;
900 x->x_variables
901 = (t_appendvariable *)getbytes(argc * sizeof (*x->x_variables));
902 x->x_nin = argc;
903 if (argc)
904 {
905 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
906 {
907 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
908 sp->gv_f = 0;
909 if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
910 }
911 }
912 pointerinlet_new(&x->x_obj, &x->x_gp);
913 outlet_new(&x->x_obj, &s_pointer);
914 gpointer_init(&x->x_gp);
915 return (x);
916}
917
918static void append_float(t_append *x, t_float f)
919{
920 int nitems = x->x_nin, i;
921 t_symbol *templatesym = x->x_templatesym;
922 t_template *template = template_findbyname(templatesym);
923 t_appendvariable *vp;
924 t_gpointer *gp = &x->x_gp;
925 t_gstub *gs = gp->gp_stub;
926 t_word *vec;
927 t_scalar *sc, *oldsc;
928 t_glist *glist;
929 if (!template)
930 {
931 pd_error(x, "append: couldn't find template %s", templatesym->s_name);
932 return;
933 }
934 if (!gs)
935 {
936 pd_error(x, "append: no current pointer");
937 return;
938 }
939 if (gs->gs_which != GP_GLIST)
940 {
941 pd_error(x, "append: lists only, not arrays");
942 return;
943 }
944 glist = gs->gs_un.gs_glist;
945 if (glist->gl_valid != gp->gp_valid)
946 {
947 pd_error(x, "append: stale pointer");
948 return;
949 }
950 if (!nitems) return;
951 x->x_variables[0].gv_f = f;
952
953 sc = scalar_new(glist, templatesym);
954 if (!sc)
955 {
956 pd_error(x, "%s: couldn't create scalar", templatesym->s_name);
957 return;
958 }
959 oldsc = gp->gp_un.gp_scalar;
960
961 if (oldsc)
962 {
963 sc->sc_gobj.g_next = oldsc->sc_gobj.g_next;
964 oldsc->sc_gobj.g_next = &sc->sc_gobj;
965 }
966 else
967 {
968 sc->sc_gobj.g_next = glist->gl_list;
969 glist->gl_list = &sc->sc_gobj;
970 }
971 if (glist_isvisible(glist_getcanvas(glist)))
972 gobj_vis(&sc->sc_gobj, glist, 1);
973
974 gp->gp_un.gp_scalar = sc;
975 vec = sc->sc_vec;
976 for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
977 {
978 template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
979 }
980
981 glist_redrawitem(glist, (t_gobj *)sc);
982
983 outlet_pointer(x->x_obj.ob_outlet, gp);
984}
985
986static void append_free(t_append *x)
987{
988 freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
989 gpointer_unset(&x->x_gp);
990}
991
992static void append_setup(void)
993{
994 append_class = class_new(gensym("append"), (t_newmethod)append_new,
995 (t_method)append_free, sizeof(t_append), 0, A_GIMME, 0);
996 class_addfloat(append_class, append_float);
997}
998
999/* ---------------------- sublist ----------------------------- */
1000
1001static t_class *sublist_class;
1002
1003typedef struct _sublist
1004{
1005 t_object x_obj;
1006 t_symbol *x_templatesym;
1007 t_symbol *x_fieldsym;
1008 t_gpointer x_gp;
1009} t_sublist;
1010
1011static void *sublist_new(t_symbol *templatesym, t_symbol *fieldsym)
1012{
1013 t_sublist *x = (t_sublist *)pd_new(sublist_class);
1014 x->x_templatesym = canvas_makebindsym(templatesym);
1015 x->x_fieldsym = fieldsym;
1016 gpointer_init(&x->x_gp);
1017 outlet_new(&x->x_obj, &s_pointer);
1018 return (x);
1019}
1020
1021static void sublist_pointer(t_sublist *x, t_gpointer *gp)
1022{
1023 t_symbol *templatesym = x->x_templatesym, *dummy;
1024 t_template *template = template_findbyname(templatesym);
1025 t_gstub *gs = gp->gp_stub;
1026 t_word *vec;
1027 t_getvariable *vp;
1028 int onset, type;
1029 t_word *w;
1030
1031 if (!template)
1032 {
1033 pd_error(x, "sublist: couldn't find template %s", templatesym->s_name);
1034 return;
1035 }
1036 if (gpointer_ishead(gp))
1037 {
1038 pd_error(x, "sublist: empty pointer");
1039 return;
1040 }
1041 if (!template_find_field(template, x->x_fieldsym,
1042 &onset, &type, &dummy))
1043 {
1044 pd_error(x, "sublist: couldn't find field %s", x->x_fieldsym->s_name);
1045 return;
1046 }
1047 if (type != DT_LIST)
1048 {
1049 pd_error(x, "sublist: field %s not of type list", x->x_fieldsym->s_name);
1050 return;
1051 }
1052 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
1053 else w = gp->gp_un.gp_scalar->sc_vec;
1054
1055 gpointer_setglist(&x->x_gp, *(t_glist **)(((char *)w) + onset), 0);
1056
1057 outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
1058}
1059
1060static void sublist_free(t_sublist *x, t_gpointer *gp)
1061{
1062 gpointer_unset(&x->x_gp);
1063}
1064
1065static void sublist_setup(void)
1066{
1067 sublist_class = class_new(gensym("sublist"), (t_newmethod)sublist_new,
1068 (t_method)sublist_free, sizeof(t_sublist), 0, A_DEFSYM, A_DEFSYM, 0);
1069 class_addpointer(sublist_class, sublist_pointer);
1070}
1071
1072/* ----------------- setup function ------------------- */
1073
1074void g_traversal_setup(void)
1075{
1076 ptrobj_setup();
1077 get_setup();
1078 set_setup();
1079 elem_setup();
1080 getsize_setup();
1081 setsize_setup();
1082 append_setup();
1083 sublist_setup();
1084}
1085/* Copyright (c) 1997-1999 Miller Puckette.
1086* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1087* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1088
1089/* This file defines Text objects which traverse data contained in scalars
1090and arrays:
1091
1092pointer - point to an object belonging to a template
1093get - get numeric fields
1094set - change numeric fields
1095element - get an array element
1096getsize - get the size of an array
1097setsize - change the size of an array
1098append - add an element to a list
1099sublist - get a pointer into a list which is an element of another scalar
1100
1101*/
1102
1103#include <stdlib.h>
1104#include <string.h>
1105#include <stdio.h> /* for read/write to files */
1106#include "m_pd.h"
1107#include "g_canvas.h"
1108
1109/* ------------- gstubs and gpointers - safe pointing --------------- */
1110
1111/* create a gstub which is "owned" by a glist (gl) or an array ("a"). */
1112
1113t_gstub *gstub_new(t_glist *gl, t_array *a)
1114{
1115 t_gstub *gs = t_getbytes(sizeof(*gs));
1116 if (gl)
1117 {
1118 gs->gs_which = GP_GLIST;
1119 gs->gs_un.gs_glist = gl;
1120 }
1121 else
1122 {
1123 gs->gs_which = GP_ARRAY;
1124 gs->gs_un.gs_array = a;
1125 }
1126 gs->gs_refcount = 0;
1127 return (gs);
1128}
1129
1130/* when a "gpointer" is set to point to this stub (so we can later chase
1131down the owner) we increase a reference count. The following routine is called
1132whenever a gpointer is unset from pointing here. If the owner is
1133gone and the refcount goes to zero, we can free the gstub safely. */
1134
1135static void gstub_dis(t_gstub *gs)
1136{
1137 int refcount = --gs->gs_refcount;
1138 if ((!refcount) && gs->gs_which == GP_NONE)
1139 t_freebytes(gs, sizeof (*gs));
1140 else if (refcount < 0) bug("gstub_dis");
1141}
1142
1143/* this routing is called by the owner to inform the gstub that it is
1144being deleted. If no gpointers are pointing here, we can free the gstub;
1145otherwise we wait for the last gstub_dis() to free it. */
1146
1147void gstub_cutoff(t_gstub *gs)
1148{
1149 gs->gs_which = GP_NONE;
1150 if (gs->gs_refcount < 0) bug("gstub_cutoff");
1151 if (!gs->gs_refcount) t_freebytes(gs, sizeof (*gs));
1152}
1153
1154/* call this to verify that a pointer is fresh, i.e., that it either
1155points to real data or to the head of a list, and that in either case
1156the object hasn't disappeared since this pointer was generated.
1157Unless "headok" is set, the routine also fails for the head of a list. */
1158
1159int gpointer_check(const t_gpointer *gp, int headok)
1160{
1161 t_gstub *gs = gp->gp_stub;
1162 if (!gs) return (0);
1163 if (gs->gs_which == GP_ARRAY)
1164 {
1165 if (gs->gs_un.gs_array->a_valid != gp->gp_valid) return (0);
1166 else return (1);
1167 }
1168 else if (gs->gs_which == GP_GLIST)
1169 {
1170 if (!headok && !gp->gp_un.gp_scalar) return (0);
1171 else if (gs->gs_un.gs_glist->gl_valid != gp->gp_valid) return (0);
1172 else return (1);
1173 }
1174 else return (0);
1175}
1176
1177/* call this if you know the pointer is fresh but don't know if we're pointing
1178to the head of a list or to real data. Any pointer is known to be fresh
1179when it appears as the argument of a message, but if your "pointer" method
1180or inlet stores it and you use it later, call gpointer_check above. */
1181
1182/* LATER reconsider the above... I no longer think it's true! */
1183
1184static int gpointer_ishead(const t_gpointer *gp)
1185{
1186 return ((gp->gp_stub->gs_which == GP_GLIST) && !gp->gp_un.gp_scalar);
1187}
1188
1189/* get the template for the object pointer to. Assumes we've already checked
1190freshness. Returns 0 if head of list. */
1191
1192static t_symbol *gpointer_gettemplatesym(const t_gpointer *gp)
1193{
1194 t_gstub *gs = gp->gp_stub;
1195 if (gs->gs_which == GP_GLIST)
1196 {
1197 t_scalar *sc = gp->gp_un.gp_scalar;
1198 if (sc)
1199 return (sc->sc_template);
1200 else return (0);
1201 }
1202 else
1203 {
1204 t_array *a = gs->gs_un.gs_array;
1205 return (a->a_templatesym);
1206 }
1207}
1208
1209 /* copy a pointer to another, assuming the first one is fresh and
1210 the second one hasn't yet been initialized. */
1211void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto)
1212{
1213 *gpto = *gpfrom;
1214 if (gpto->gp_stub)
1215 gpto->gp_stub->gs_refcount++;
1216 else bug("gpointer_copy");
1217}
1218
1219void gpointer_unset(t_gpointer *gp)
1220{
1221 t_gstub *gs;
1222 if (gs = gp->gp_stub)
1223 {
1224 gstub_dis(gs);
1225 gp->gp_stub = 0;
1226 }
1227}
1228
1229void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x)
1230{
1231 t_gstub *gs;
1232 if (gs = gp->gp_stub) gstub_dis(gs);
1233 gp->gp_stub = gs = glist->gl_stub;
1234 gp->gp_valid = glist->gl_valid;
1235 gp->gp_un.gp_scalar = x;
1236 gs->gs_refcount++;
1237}
1238
1239static void gpointer_setarray(t_gpointer *gp, t_array *array, t_word *w)
1240{
1241 t_gstub *gs;
1242 if (gs = gp->gp_stub) gstub_dis(gs);
1243 gp->gp_stub = gs = array->a_stub;
1244 gp->gp_valid = array->a_valid;
1245 gp->gp_un.gp_w = w;
1246 gs->gs_refcount++;
1247}
1248
1249void gpointer_init(t_gpointer *gp)
1250{
1251 gp->gp_stub = 0;
1252 gp->gp_valid = 0;
1253 gp->gp_un.gp_scalar = 0;
1254}
1255
1256/* ---------------------- pointers ----------------------------- */
1257
1258static t_class *ptrobj_class;
1259
1260typedef struct
1261{
1262 t_symbol *to_type;
1263 t_outlet *to_outlet;
1264} t_typedout;
1265
1266typedef struct _ptrobj
1267{
1268 t_object x_obj;
1269 t_gpointer x_gp;
1270 t_typedout *x_typedout;
1271 int x_ntypedout;
1272 t_outlet *x_otherout;
1273 t_outlet *x_bangout;
1274} t_ptrobj;
1275
1276static void *ptrobj_new(t_symbol *classname, int argc, t_atom *argv)
1277{
1278 t_ptrobj *x = (t_ptrobj *)pd_new(ptrobj_class);
1279 t_typedout *to;
1280 int n;
1281 gpointer_init(&x->x_gp);
1282 x->x_typedout = to = (t_typedout *)getbytes(argc * sizeof (*to));
1283 x->x_ntypedout = n = argc;
1284 for (; n--; to++)
1285 {
1286 to->to_outlet = outlet_new(&x->x_obj, &s_pointer);
1287 to->to_type = canvas_makebindsym(atom_getsymbol(argv++));
1288 }
1289 x->x_otherout = outlet_new(&x->x_obj, &s_pointer);
1290 x->x_bangout = outlet_new(&x->x_obj, &s_bang);
1291 pointerinlet_new(&x->x_obj, &x->x_gp);
1292 return (x);
1293}
1294
1295static void ptrobj_traverse(t_ptrobj *x, t_symbol *s)
1296{
1297 t_glist *glist = (t_glist *)pd_findbyclass(s, canvas_class);
1298 if (glist) gpointer_setglist(&x->x_gp, glist, 0);
1299 else pd_error(x, "pointer: list '%s' not found", s->s_name);
1300}
1301
1302static void ptrobj_vnext(t_ptrobj *x, float f)
1303{
1304 t_gobj *gobj;
1305 t_gpointer *gp = &x->x_gp;
1306 t_gstub *gs = gp->gp_stub;
1307 t_glist *glist;
1308 int wantselected = (f != 0);
1309
1310 if (!gs)
1311 {
1312 pd_error(x, "ptrobj_next: no current pointer");
1313 return;
1314 }
1315 if (gs->gs_which != GP_GLIST)
1316 {
1317 pd_error(x, "ptrobj_next: lists only, not arrays");
1318 return;
1319 }
1320 glist = gs->gs_un.gs_glist;
1321 if (glist->gl_valid != gp->gp_valid)
1322 {
1323 pd_error(x, "ptrobj_next: stale pointer");
1324 return;
1325 }
1326 if (wantselected && !glist_isvisible(glist))
1327 {
1328 pd_error(x,
1329 "ptrobj_vnext: next-selected only works for a visible window");
1330 return;
1331 }
1332 gobj = &gp->gp_un.gp_scalar->sc_gobj;
1333
1334 if (!gobj) gobj = glist->gl_list;
1335 else gobj = gobj->g_next;
1336 while (gobj && ((pd_class(&gobj->g_pd) != scalar_class) ||
1337 (wantselected && !glist_isselected(glist, gobj))))
1338 gobj = gobj->g_next;
1339
1340 if (gobj)
1341 {
1342 t_typedout *to;
1343 int n;
1344 t_scalar *sc = (t_scalar *)gobj;
1345 t_symbol *templatesym = sc->sc_template;
1346
1347 gp->gp_un.gp_scalar = sc;
1348 for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
1349 {
1350 if (to->to_type == templatesym)
1351 {
1352 outlet_pointer(to->to_outlet, &x->x_gp);
1353 return;
1354 }
1355 }
1356 outlet_pointer(x->x_otherout, &x->x_gp);
1357 }
1358 else
1359 {
1360 gpointer_unset(gp);
1361 outlet_bang(x->x_bangout);
1362 }
1363}
1364
1365static void ptrobj_next(t_ptrobj *x)
1366{
1367 ptrobj_vnext(x, 0);
1368}
1369
1370static void ptrobj_sendwindow(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv)
1371{
1372 t_scalar *sc;
1373 t_symbol *templatesym;
1374 int n;
1375 t_typedout *to;
1376 t_glist *glist;
1377 t_pd *canvas;
1378 t_gstub *gs;
1379 if (!gpointer_check(&x->x_gp, 1))
1380 {
1381 pd_error(x, "ptrobj_bang: empty pointer");
1382 return;
1383 }
1384 gs = x->x_gp.gp_stub;
1385 if (gs->gs_which == GP_GLIST)
1386 glist = gs->gs_un.gs_glist;
1387 else
1388 {
1389 t_array *owner_array = gs->gs_un.gs_array;
1390 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
1391 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
1392 glist = owner_array->a_gp.gp_stub->gs_un.gs_glist;
1393 }
1394 canvas = (t_pd *)glist_getcanvas(glist);
1395 if (argc && argv->a_type == A_SYMBOL)
1396 pd_typedmess(canvas, argv->a_w.w_symbol, argc-1, argv+1);
1397 else pd_error(x, "send-window: no message?");
1398}
1399
1400static void ptrobj_bang(t_ptrobj *x)
1401{
1402 t_symbol *templatesym;
1403 int n;
1404 t_typedout *to;
1405 if (!gpointer_check(&x->x_gp, 1))
1406 {
1407 pd_error(x, "ptrobj_bang: empty pointer");
1408 return;
1409 }
1410 templatesym = gpointer_gettemplatesym(&x->x_gp);
1411 for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
1412 {
1413 if (to->to_type == templatesym)
1414 {
1415 outlet_pointer(to->to_outlet, &x->x_gp);
1416 return;
1417 }
1418 }
1419 outlet_pointer(x->x_otherout, &x->x_gp);
1420}
1421
1422
1423static void ptrobj_pointer(t_ptrobj *x, t_gpointer *gp)
1424{
1425 gpointer_unset(&x->x_gp);
1426 gpointer_copy(gp, &x->x_gp);
1427 ptrobj_bang(x);
1428}
1429
1430static void ptrobj_free(t_ptrobj *x)
1431{
1432 freebytes(x->x_typedout, x->x_ntypedout * sizeof (*x->x_typedout));
1433 gpointer_unset(&x->x_gp);
1434}
1435
1436static void ptrobj_setup(void)
1437{
1438 ptrobj_class = class_new(gensym("pointer"), (t_newmethod)ptrobj_new,
1439 (t_method)ptrobj_free, sizeof(t_ptrobj), 0, A_GIMME, 0);
1440 class_addmethod(ptrobj_class, (t_method)ptrobj_traverse, gensym("traverse"),
1441 A_SYMBOL, 0);
1442 class_addmethod(ptrobj_class, (t_method)ptrobj_next, gensym("next"), 0);
1443 class_addmethod(ptrobj_class, (t_method)ptrobj_vnext, gensym("vnext"),
1444 A_DEFFLOAT, 0);
1445 class_addmethod(ptrobj_class, (t_method)ptrobj_sendwindow,
1446 gensym("send-window"), A_GIMME, 0);
1447 class_addpointer(ptrobj_class, ptrobj_pointer);
1448 class_addbang(ptrobj_class, ptrobj_bang);
1449}
1450
1451/* ---------------------- get ----------------------------- */
1452
1453static t_class *get_class;
1454
1455typedef struct _getvariable
1456{
1457 t_symbol *gv_sym;
1458 t_outlet *gv_outlet;
1459} t_getvariable;
1460
1461typedef struct _get
1462{
1463 t_object x_obj;
1464 t_symbol *x_templatesym;
1465 int x_nout;
1466 t_getvariable *x_variables;
1467} t_get;
1468
1469static void *get_new(t_symbol *why, int argc, t_atom *argv)
1470{
1471 t_get *x = (t_get *)pd_new(get_class);
1472 int i;
1473 t_getvariable *sp;
1474 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
1475 if (argc) argc--, argv++;
1476 x->x_variables
1477 = (t_getvariable *)getbytes(argc * sizeof (*x->x_variables));
1478 x->x_nout = argc;
1479 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
1480 {
1481 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
1482 sp->gv_outlet = outlet_new(&x->x_obj, 0);
1483 /* LATER connect with the template and set the outlet's type
1484 correctly. We can't yet guarantee that the template is there
1485 before we hit this routine. */
1486 }
1487 return (x);
1488}
1489
1490static void get_pointer(t_get *x, t_gpointer *gp)
1491{
1492 int nitems = x->x_nout, i;
1493 t_symbol *templatesym = x->x_templatesym;
1494 t_template *template = template_findbyname(templatesym);
1495 t_gstub *gs = gp->gp_stub;
1496 t_word *vec;
1497 t_getvariable *vp;
1498 if (!template)
1499 {
1500 pd_error(x, "get: couldn't find template %s", templatesym->s_name);
1501 return;
1502 }
1503 if (gpointer_ishead(gp))
1504 {
1505 pd_error(x, "get: empty pointer");
1506 return;
1507 }
1508 if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
1509 else vec = gp->gp_un.gp_scalar->sc_vec;
1510 for (i = nitems - 1, vp = x->x_variables + i; i >= 0; i--, vp--)
1511 {
1512 float f = template_getfloat(template, vp->gv_sym, vec, 1);
1513 outlet_float(vp->gv_outlet, f);
1514 /* LATER deal with other types. */
1515 }
1516}
1517
1518static void get_free(t_get *x)
1519{
1520 freebytes(x->x_variables, x->x_nout * sizeof (*x->x_variables));
1521}
1522
1523static void get_setup(void)
1524{
1525 get_class = class_new(gensym("get"), (t_newmethod)get_new,
1526 (t_method)get_free, sizeof(t_get), 0, A_GIMME, 0);
1527 class_addpointer(get_class, get_pointer);
1528}
1529
1530/* ---------------------- set ----------------------------- */
1531
1532static t_class *set_class;
1533
1534typedef struct _setvariable
1535{
1536 t_symbol *gv_sym;
1537 t_float gv_f; /* LATER take other types */
1538} t_setvariable;
1539
1540typedef struct _set
1541{
1542 t_object x_obj;
1543 t_gpointer x_gp;
1544 t_symbol *x_templatesym;
1545 int x_nin;
1546 t_setvariable *x_variables;
1547} t_set;
1548
1549static void *set_new(t_symbol *why, int argc, t_atom *argv)
1550{
1551 t_set *x = (t_set *)pd_new(set_class);
1552 int i;
1553 t_setvariable *sp;
1554 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
1555 if (argc) argc--, argv++;
1556 x->x_variables
1557 = (t_setvariable *)getbytes(argc * sizeof (*x->x_variables));
1558 x->x_nin = argc;
1559 if (argc)
1560 {
1561 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
1562 {
1563 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
1564 sp->gv_f = 0;
1565 if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
1566 /* LATER figure out type as in "get" object. */
1567 }
1568 }
1569 pointerinlet_new(&x->x_obj, &x->x_gp);
1570 gpointer_init(&x->x_gp);
1571 return (x);
1572}
1573
1574static void set_float(t_set *x, t_float f)
1575{
1576 int nitems = x->x_nin, i;
1577 t_symbol *templatesym = x->x_templatesym;
1578 t_template *template = template_findbyname(templatesym);
1579 t_setvariable *vp;
1580 t_gpointer *gp = &x->x_gp;
1581 t_gstub *gs = gp->gp_stub;
1582 t_word *vec;
1583 if (!template)
1584 {
1585 pd_error(x, "set: couldn't find template %s", templatesym->s_name);
1586 return;
1587 }
1588 if (!gpointer_check(gp, 0))
1589 {
1590 pd_error(x, "set: empty pointer");
1591 return;
1592 }
1593 if (gpointer_gettemplatesym(gp) != x->x_templatesym)
1594 {
1595 pd_error(x, "set %s: got wrong template (%s)",
1596 x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
1597 return;
1598 }
1599 if (!nitems) return;
1600 x->x_variables[0].gv_f = f;
1601 if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
1602 else vec = gp->gp_un.gp_scalar->sc_vec;
1603 for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
1604 {
1605 template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
1606 /* LATER deal with other types ala get_pointer. */
1607 }
1608 if (gs->gs_which == GP_GLIST)
1609 glist_redrawitem(gs->gs_un.gs_glist, (t_gobj *)(gp->gp_un.gp_scalar));
1610 else
1611 {
1612 t_array *owner_array = gs->gs_un.gs_array;
1613 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
1614 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
1615 glist_redrawitem(owner_array->a_gp.gp_stub->gs_un.gs_glist,
1616 (t_gobj *)(owner_array->a_gp.gp_un.gp_scalar));
1617 }
1618}
1619
1620static void set_free(t_set *x)
1621{
1622 freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
1623 gpointer_unset(&x->x_gp);
1624}
1625
1626static void set_setup(void)
1627{
1628 set_class = class_new(gensym("set"), (t_newmethod)set_new,
1629 (t_method)set_free, sizeof(t_set), 0, A_GIMME, 0);
1630 class_addfloat(set_class, set_float);
1631}
1632
1633/* ---------------------- elem ----------------------------- */
1634
1635static t_class *elem_class;
1636
1637typedef struct _elem
1638{
1639 t_object x_obj;
1640 t_symbol *x_templatesym;
1641 t_symbol *x_fieldsym;
1642 t_gpointer x_gp;
1643 t_gpointer x_gparent;
1644} t_elem;
1645
1646static void *elem_new(t_symbol *templatesym, t_symbol *fieldsym)
1647{
1648 t_elem *x = (t_elem *)pd_new(elem_class);
1649 x->x_templatesym = canvas_makebindsym(templatesym);
1650 x->x_fieldsym = fieldsym;
1651 gpointer_init(&x->x_gp);
1652 gpointer_init(&x->x_gparent);
1653 pointerinlet_new(&x->x_obj, &x->x_gparent);
1654 outlet_new(&x->x_obj, &s_pointer);
1655 return (x);
1656}
1657
1658static void elem_float(t_elem *x, t_float f)
1659{
1660 int indx = f, nitems, onset;
1661 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
1662 *elemtemplatesym;
1663 t_template *template = template_findbyname(templatesym);
1664 t_template *elemtemplate;
1665 t_gpointer *gparent = &x->x_gparent;
1666 t_word *w;
1667 t_array *array;
1668 int elemsize, type;
1669
1670 if (!gpointer_check(gparent, 0))
1671 {
1672 pd_error(x, "element: empty pointer");
1673 return;
1674 }
1675 if (gpointer_gettemplatesym(gparent) != x->x_templatesym)
1676 {
1677 pd_error(x, "element %s: got wrong template (%s)",
1678 x->x_templatesym->s_name, gpointer_gettemplatesym(gparent)->s_name);
1679 return;
1680 }
1681 if (gparent->gp_stub->gs_which == GP_ARRAY) w = gparent->gp_un.gp_w;
1682 else w = gparent->gp_un.gp_scalar->sc_vec;
1683 if (!template)
1684 {
1685 pd_error(x, "element: couldn't find template %s", templatesym->s_name);
1686 return;
1687 }
1688 if (!template_find_field(template, fieldsym,
1689 &onset, &type, &elemtemplatesym))
1690 {
1691 pd_error(x, "element: couldn't find array field %s", fieldsym->s_name);
1692 return;
1693 }
1694 if (type != DT_ARRAY)
1695 {
1696 pd_error(x, "element: field %s not of type array", fieldsym->s_name);
1697 return;
1698 }
1699 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
1700 {
1701 pd_error(x, "element: couldn't find field template %s",
1702 elemtemplatesym->s_name);
1703 return;
1704 }
1705
1706 elemsize = elemtemplate->t_n * sizeof(t_word);
1707
1708 array = *(t_array **)(((char *)w) + onset);
1709
1710 nitems = array->a_n;
1711 if (indx < 0) indx = 0;
1712 if (indx >= nitems) indx = nitems-1;
1713
1714 gpointer_setarray(&x->x_gp, array,
1715 (t_word *)((char *)(array->a_vec) + indx * elemsize));
1716 outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
1717}
1718
1719static void elem_free(t_elem *x, t_gpointer *gp)
1720{
1721 gpointer_unset(&x->x_gp);
1722 gpointer_unset(&x->x_gparent);
1723}
1724
1725static void elem_setup(void)
1726{
1727 elem_class = class_new(gensym("element"), (t_newmethod)elem_new,
1728 (t_method)elem_free, sizeof(t_elem), 0, A_DEFSYM, A_DEFSYM, 0);
1729 class_addfloat(elem_class, elem_float);
1730}
1731
1732/* ---------------------- getsize ----------------------------- */
1733
1734static t_class *getsize_class;
1735
1736typedef struct _getsize
1737{
1738 t_object x_obj;
1739 t_symbol *x_templatesym;
1740 t_symbol *x_fieldsym;
1741} t_getsize;
1742
1743static void *getsize_new(t_symbol *templatesym, t_symbol *fieldsym)
1744{
1745 t_getsize *x = (t_getsize *)pd_new(getsize_class);
1746 x->x_templatesym = canvas_makebindsym(templatesym);
1747 x->x_fieldsym = fieldsym;
1748 outlet_new(&x->x_obj, &s_float);
1749 return (x);
1750}
1751
1752static void getsize_pointer(t_getsize *x, t_gpointer *gp)
1753{
1754 int nitems, onset, type;
1755 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
1756 *elemtemplatesym;
1757 t_template *template = template_findbyname(templatesym);
1758 t_word *w;
1759 t_array *array;
1760 int elemsize;
1761 t_gstub *gs = gp->gp_stub;
1762 if (!template)
1763 {
1764 pd_error(x, "getsize: couldn't find template %s", templatesym->s_name);
1765 return;
1766 }
1767 if (!template_find_field(template, fieldsym,
1768 &onset, &type, &elemtemplatesym))
1769 {
1770 pd_error(x, "getsize: couldn't find array field %s", fieldsym->s_name);
1771 return;
1772 }
1773 if (type != DT_ARRAY)
1774 {
1775 pd_error(x, "getsize: field %s not of type array", fieldsym->s_name);
1776 return;
1777 }
1778 if (gpointer_ishead(gp))
1779 {
1780 pd_error(x, "getsize: empty pointer");
1781 return;
1782 }
1783 if (gpointer_gettemplatesym(gp) != x->x_templatesym)
1784 {
1785 pd_error(x, "getsize %s: got wrong template (%s)",
1786 x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
1787 return;
1788 }
1789 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
1790 else w = gp->gp_un.gp_scalar->sc_vec;
1791
1792 array = *(t_array **)(((char *)w) + onset);
1793 outlet_float(x->x_obj.ob_outlet, (float)(array->a_n));
1794}
1795
1796static void getsize_setup(void)
1797{
1798 getsize_class = class_new(gensym("getsize"), (t_newmethod)getsize_new, 0,
1799 sizeof(t_getsize), 0, A_DEFSYM, A_DEFSYM, 0);
1800 class_addpointer(getsize_class, getsize_pointer);
1801}
1802
1803/* ---------------------- setsize ----------------------------- */
1804
1805static t_class *setsize_class;
1806
1807typedef struct _setsize
1808{
1809 t_object x_obj;
1810 t_symbol *x_templatesym;
1811 t_symbol *x_fieldsym;
1812 t_gpointer x_gp;
1813} t_setsize;
1814
1815static void *setsize_new(t_symbol *templatesym, t_symbol *fieldsym,
1816 t_floatarg newsize)
1817{
1818 t_setsize *x = (t_setsize *)pd_new(setsize_class);
1819 x->x_templatesym = canvas_makebindsym(templatesym);
1820 x->x_fieldsym = fieldsym;
1821 gpointer_init(&x->x_gp);
1822
1823 pointerinlet_new(&x->x_obj, &x->x_gp);
1824 return (x);
1825}
1826
1827static void setsize_float(t_setsize *x, t_float f)
1828{
1829 int nitems, onset, type;
1830 t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
1831 *elemtemplatesym;
1832 t_template *template = template_findbyname(templatesym);
1833 t_template *elemtemplate;
1834 t_word *w;
1835 t_atom at;
1836 t_array *array;
1837 int elemsize;
1838 int newsize = f;
1839 t_gpointer *gp = &x->x_gp;
1840 t_gstub *gs = gp->gp_stub;
1841 if (!gpointer_check(&x->x_gp, 0))
1842 {
1843 pd_error(x, "setsize: empty pointer");
1844 return;
1845 }
1846 if (gpointer_gettemplatesym(&x->x_gp) != x->x_templatesym)
1847 {
1848 pd_error(x, "setsize %s: got wrong template (%s)",
1849 x->x_templatesym->s_name,
1850 gpointer_gettemplatesym(&x->x_gp)->s_name);
1851 return;
1852 }
1853 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
1854 else w = gp->gp_un.gp_scalar->sc_vec;
1855
1856 if (!template)
1857 {
1858 pd_error(x,"setsize: couldn't find template %s", templatesym->s_name);
1859 return;
1860 }
1861 if (!template_find_field(template, fieldsym,
1862 &onset, &type, &elemtemplatesym))
1863 {
1864 pd_error(x,"setsize: couldn't find array field %s", fieldsym->s_name);
1865 return;
1866 }
1867 if (type != DT_ARRAY)
1868 {
1869 pd_error(x,"setsize: field %s not of type array", fieldsym->s_name);
1870 return;
1871 }
1872
1873 if (!(elemtemplate = template_findbyname(elemtemplatesym)))
1874 {
1875 pd_error(x,"element: couldn't find field template %s",
1876 elemtemplatesym->s_name);
1877 return;
1878 }
1879
1880 elemsize = elemtemplate->t_n * sizeof(t_word);
1881
1882 array = *(t_array **)(((char *)w) + onset);
1883
1884 if (elemsize != array->a_elemsize) bug("setsize_gpointer");
1885
1886 nitems = array->a_n;
1887 if (newsize < 1) newsize = 1;
1888 if (newsize == nitems) return;
1889
1890 /* erase the array before resizing it. If we belong to a
1891 scalar it's easy, but if we belong to an element of another
1892 array we have to search back until we get to a scalar to erase.
1893 When graphics updates become queueable this may fall apart... */
1894
1895
1896 if (gs->gs_which == GP_GLIST)
1897 {
1898 if (glist_isvisible(gs->gs_un.gs_glist))
1899 gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 0);
1900 }
1901 else
1902 {
1903 t_array *owner_array = gs->gs_un.gs_array;
1904 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
1905 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
1906 if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
1907 gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
1908 owner_array->a_gp.gp_stub->gs_un.gs_glist, 0);
1909 }
1910 /* now do the resizing and, if growing, initialize new scalars */
1911 array->a_vec = (char *)resizebytes(array->a_vec,
1912 elemsize * nitems, elemsize * newsize);
1913 array->a_n = newsize;
1914 if (newsize > nitems)
1915 {
1916 char *newelem = ((char *)array->a_vec) + nitems * elemsize;
1917 int i = 0, nnew = newsize - nitems;
1918
1919 while (nnew--)
1920 {
1921 word_init((t_word *)newelem, elemtemplate, gp);
1922 newelem += elemsize;
1923 /* post("new %x %x, ntypes %d", newelem, *(int *)newelem, ntypes); */
1924 }
1925 }
1926
1927 /* redraw again. */
1928 if (gs->gs_which == GP_GLIST)
1929 {
1930 if (glist_isvisible(gs->gs_un.gs_glist))
1931 gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 1);
1932 }
1933 else
1934 {
1935 t_array *owner_array = gs->gs_un.gs_array;
1936 while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
1937 owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
1938 if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
1939 gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
1940 owner_array->a_gp.gp_stub->gs_un.gs_glist, 1);
1941 }
1942}
1943
1944
1945static void setsize_free(t_setsize *x)
1946{
1947 gpointer_unset(&x->x_gp);
1948}
1949
1950static void setsize_setup(void)
1951{
1952 setsize_class = class_new(gensym("setsize"), (t_newmethod)setsize_new,
1953 (t_method)setsize_free, sizeof(t_setsize), 0,
1954 A_DEFSYM, A_DEFSYM, A_DEFFLOAT, 0);
1955 class_addfloat(setsize_class, setsize_float);
1956}
1957
1958/* ---------------------- append ----------------------------- */
1959
1960static t_class *append_class;
1961
1962typedef struct _appendvariable
1963{
1964 t_symbol *gv_sym;
1965 t_float gv_f;
1966} t_appendvariable;
1967
1968typedef struct _append
1969{
1970 t_object x_obj;
1971 t_gpointer x_gp;
1972 t_symbol *x_templatesym;
1973 int x_nin;
1974 t_appendvariable *x_variables;
1975} t_append;
1976
1977static void *append_new(t_symbol *why, int argc, t_atom *argv)
1978{
1979 t_append *x = (t_append *)pd_new(append_class);
1980 int i;
1981 t_appendvariable *sp;
1982 x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
1983 if (argc) argc--, argv++;
1984 x->x_variables
1985 = (t_appendvariable *)getbytes(argc * sizeof (*x->x_variables));
1986 x->x_nin = argc;
1987 if (argc)
1988 {
1989 for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
1990 {
1991 sp->gv_sym = atom_getsymbolarg(i, argc, argv);
1992 sp->gv_f = 0;
1993 if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
1994 }
1995 }
1996 pointerinlet_new(&x->x_obj, &x->x_gp);
1997 outlet_new(&x->x_obj, &s_pointer);
1998 gpointer_init(&x->x_gp);
1999 return (x);
2000}
2001
2002static void append_float(t_append *x, t_float f)
2003{
2004 int nitems = x->x_nin, i;
2005 t_symbol *templatesym = x->x_templatesym;
2006 t_template *template = template_findbyname(templatesym);
2007 t_appendvariable *vp;
2008 t_gpointer *gp = &x->x_gp;
2009 t_gstub *gs = gp->gp_stub;
2010 t_word *vec;
2011 t_scalar *sc, *oldsc;
2012 t_glist *glist;
2013 if (!template)
2014 {
2015 pd_error(x, "append: couldn't find template %s", templatesym->s_name);
2016 return;
2017 }
2018 if (!gs)
2019 {
2020 pd_error(x, "append: no current pointer");
2021 return;
2022 }
2023 if (gs->gs_which != GP_GLIST)
2024 {
2025 pd_error(x, "append: lists only, not arrays");
2026 return;
2027 }
2028 glist = gs->gs_un.gs_glist;
2029 if (glist->gl_valid != gp->gp_valid)
2030 {
2031 pd_error(x, "append: stale pointer");
2032 return;
2033 }
2034 if (!nitems) return;
2035 x->x_variables[0].gv_f = f;
2036
2037 sc = scalar_new(glist, templatesym);
2038 if (!sc)
2039 {
2040 pd_error(x, "%s: couldn't create scalar", templatesym->s_name);
2041 return;
2042 }
2043 oldsc = gp->gp_un.gp_scalar;
2044
2045 if (oldsc)
2046 {
2047 sc->sc_gobj.g_next = oldsc->sc_gobj.g_next;
2048 oldsc->sc_gobj.g_next = &sc->sc_gobj;
2049 }
2050 else
2051 {
2052 sc->sc_gobj.g_next = glist->gl_list;
2053 glist->gl_list = &sc->sc_gobj;
2054 }
2055 if (glist_isvisible(glist_getcanvas(glist)))
2056 gobj_vis(&sc->sc_gobj, glist, 1);
2057
2058 gp->gp_un.gp_scalar = sc;
2059 vec = sc->sc_vec;
2060 for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
2061 {
2062 template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
2063 }
2064
2065 glist_redrawitem(glist, (t_gobj *)sc);
2066
2067 outlet_pointer(x->x_obj.ob_outlet, gp);
2068}
2069
2070static void append_free(t_append *x)
2071{
2072 freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
2073 gpointer_unset(&x->x_gp);
2074}
2075
2076static void append_setup(void)
2077{
2078 append_class = class_new(gensym("append"), (t_newmethod)append_new,
2079 (t_method)append_free, sizeof(t_append), 0, A_GIMME, 0);
2080 class_addfloat(append_class, append_float);
2081}
2082
2083/* ---------------------- sublist ----------------------------- */
2084
2085static t_class *sublist_class;
2086
2087typedef struct _sublist
2088{
2089 t_object x_obj;
2090 t_symbol *x_templatesym;
2091 t_symbol *x_fieldsym;
2092 t_gpointer x_gp;
2093} t_sublist;
2094
2095static void *sublist_new(t_symbol *templatesym, t_symbol *fieldsym)
2096{
2097 t_sublist *x = (t_sublist *)pd_new(sublist_class);
2098 x->x_templatesym = canvas_makebindsym(templatesym);
2099 x->x_fieldsym = fieldsym;
2100 gpointer_init(&x->x_gp);
2101 outlet_new(&x->x_obj, &s_pointer);
2102 return (x);
2103}
2104
2105static void sublist_pointer(t_sublist *x, t_gpointer *gp)
2106{
2107 t_symbol *templatesym = x->x_templatesym, *dummy;
2108 t_template *template = template_findbyname(templatesym);
2109 t_gstub *gs = gp->gp_stub;
2110 t_word *vec;
2111 t_getvariable *vp;
2112 int onset, type;
2113 t_word *w;
2114
2115 if (!template)
2116 {
2117 pd_error(x, "sublist: couldn't find template %s", templatesym->s_name);
2118 return;
2119 }
2120 if (gpointer_ishead(gp))
2121 {
2122 pd_error(x, "sublist: empty pointer");
2123 return;
2124 }
2125 if (!template_find_field(template, x->x_fieldsym,
2126 &onset, &type, &dummy))
2127 {
2128 pd_error(x, "sublist: couldn't find field %s", x->x_fieldsym->s_name);
2129 return;
2130 }
2131 if (type != DT_LIST)
2132 {
2133 pd_error(x, "sublist: field %s not of type list", x->x_fieldsym->s_name);
2134 return;
2135 }
2136 if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
2137 else w = gp->gp_un.gp_scalar->sc_vec;
2138
2139 gpointer_setglist(&x->x_gp, *(t_glist **)(((char *)w) + onset), 0);
2140
2141 outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
2142}
2143
2144static void sublist_free(t_sublist *x, t_gpointer *gp)
2145{
2146 gpointer_unset(&x->x_gp);
2147}
2148
2149static void sublist_setup(void)
2150{
2151 sublist_class = class_new(gensym("sublist"), (t_newmethod)sublist_new,
2152 (t_method)sublist_free, sizeof(t_sublist), 0, A_DEFSYM, A_DEFSYM, 0);
2153 class_addpointer(sublist_class, sublist_pointer);
2154}
2155
2156/* ----------------- setup function ------------------- */
2157
2158void g_traversal_setup(void)
2159{
2160 ptrobj_setup();
2161 get_setup();
2162 set_setup();
2163 elem_setup();
2164 getsize_setup();
2165 setsize_setup();
2166 append_setup();
2167 sublist_setup();
2168}