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
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
21 #include "../../pdbox.h"
27 #include <stdio.h> /* for read/write to files */
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
));
41 gs
->gs_which
= GP_GLIST
;
42 gs
->gs_un
.gs_glist
= gl
;
46 gs
->gs_which
= GP_ARRAY
;
47 gs
->gs_un
.gs_array
= a
;
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
;
86 if (gs
->gs_which
== GP_ARRAY
)
88 if (gs
->gs_un
.gs_array
->a_valid
!= gp
->gp_valid
) return (0);
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);
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
;
122 return (sc
->sc_template
);
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
)
138 gpto
->gp_stub
->gs_refcount
++;
139 else bug("gpointer_copy");
142 void gpointer_unset(t_gpointer
*gp
)
145 if((gs
= gp
->gp_stub
))
152 void gpointer_setglist(t_gpointer
*gp
, t_glist
*glist
, t_scalar
*x
)
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
;
162 static void gpointer_setarray(t_gpointer
*gp
, t_array
*array
, t_word
*w
)
165 if((gs
= gp
->gp_stub
)) gstub_dis(gs
);
166 gp
->gp_stub
= gs
= array
->a_stub
;
167 gp
->gp_valid
= array
->a_valid
;
172 void gpointer_init(t_gpointer
*gp
)
176 gp
->gp_un
.gp_scalar
= 0;
179 /* ---------------------- pointers ----------------------------- */
181 static t_class
*ptrobj_class
;
189 typedef struct _ptrobj
193 t_typedout
*x_typedout
;
195 t_outlet
*x_otherout
;
199 static void *ptrobj_new(t_symbol
*classname
, int argc
, t_atom
*argv
)
201 t_ptrobj
*x
= (t_ptrobj
*)pd_new(ptrobj_class
);
207 gpointer_init(&x
->x_gp
);
208 x
->x_typedout
= to
= (t_typedout
*)getbytes(argc
* sizeof (*to
));
209 x
->x_ntypedout
= n
= argc
;
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
);
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
)
231 t_gpointer
*gp
= &x
->x_gp
;
232 t_gstub
*gs
= gp
->gp_stub
;
234 int wantselected
= (f
!= 0);
238 pd_error(x
, "ptrobj_next: no current pointer");
241 if (gs
->gs_which
!= GP_GLIST
)
243 pd_error(x
, "ptrobj_next: lists only, not arrays");
246 glist
= gs
->gs_un
.gs_glist
;
247 if (glist
->gl_valid
!= gp
->gp_valid
)
249 pd_error(x
, "ptrobj_next: stale pointer");
252 if (wantselected
&& !glist_isvisible(glist
))
255 "ptrobj_vnext: next-selected only works for a visible window");
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
))))
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
);
282 outlet_pointer(x
->x_otherout
, &x
->x_gp
);
287 outlet_bang(x
->x_bangout
);
291 static void ptrobj_next(t_ptrobj
*x
)
296 static void ptrobj_sendwindow(t_ptrobj
*x
, t_symbol
*s
, int argc
, t_atom
*argv
)
302 t_symbol
*templatesym
;
309 if (!gpointer_check(&x
->x_gp
, 1))
311 pd_error(x
, "ptrobj_bang: empty pointer");
314 gs
= x
->x_gp
.gp_stub
;
315 if (gs
->gs_which
== GP_GLIST
)
316 glist
= gs
->gs_un
.gs_glist
;
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
;
335 if (!gpointer_check(&x
->x_gp
, 1))
337 pd_error(x
, "ptrobj_bang: empty pointer");
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
);
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
);
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"),
372 class_addmethod(ptrobj_class
, (t_method
)ptrobj_next
, gensym("next"), 0);
373 class_addmethod(ptrobj_class
, (t_method
)ptrobj_vnext
, gensym("vnext"),
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
394 t_symbol
*x_templatesym
;
396 t_getvariable
*x_variables
;
399 static void *get_new(t_symbol
*why
, int argc
, t_atom
*argv
)
401 t_get
*x
= (t_get
*)pd_new(get_class
);
404 x
->x_templatesym
= canvas_makebindsym(atom_getsymbolarg(0, argc
, argv
));
408 if (argc
) argc
--, argv
++;
410 = (t_getvariable
*)getbytes(argc
* sizeof (*x
->x_variables
));
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. */
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
;
433 pd_error(x
, "get: couldn't find template %s", templatesym
->s_name
);
436 if (gpointer_ishead(gp
))
438 pd_error(x
, "get: empty pointer");
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
470 t_float gv_f
; /* LATER take other types */
477 t_symbol
*x_templatesym
;
479 t_setvariable
*x_variables
;
482 static void *set_new(t_symbol
*why
, int argc
, t_atom
*argv
)
484 t_set
*x
= (t_set
*)pd_new(set_class
);
487 x
->x_templatesym
= canvas_makebindsym(atom_getsymbolarg(0, argc
, argv
));
491 if (argc
) argc
--, argv
++;
493 = (t_setvariable
*)getbytes(argc
* sizeof (*x
->x_variables
));
497 for (i
= 0, sp
= x
->x_variables
; i
< argc
; i
++, sp
++)
499 sp
->gv_sym
= atom_getsymbolarg(i
, argc
, argv
);
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
);
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
);
516 t_gpointer
*gp
= &x
->x_gp
;
517 t_gstub
*gs
= gp
->gp_stub
;
521 pd_error(x
, "set: couldn't find template %s", templatesym
->s_name
);
524 if (!gpointer_check(gp
, 0))
526 pd_error(x
, "set: empty pointer");
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
);
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
));
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
;
576 t_symbol
*x_templatesym
;
577 t_symbol
*x_fieldsym
;
579 t_gpointer x_gparent
;
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
);
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
,
599 t_template
*template = template_findbyname(templatesym
);
600 t_template
*elemtemplate
;
601 t_gpointer
*gparent
= &x
->x_gparent
;
606 if (!gpointer_check(gparent
, 0))
608 pd_error(x
, "element: empty pointer");
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
);
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
;
621 pd_error(x
, "element: couldn't find template %s", templatesym
->s_name
);
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
);
630 if (type
!= DT_ARRAY
)
632 pd_error(x
, "element: field %s not of type array", fieldsym
->s_name
);
635 if (!(elemtemplate
= template_findbyname(elemtemplatesym
)))
637 pd_error(x
, "element: couldn't find field template %s",
638 elemtemplatesym
->s_name
);
642 elemsize
= elemtemplate
->t_n
* sizeof(t_word
);
644 array
= *(t_array
**)(((char *)w
) + onset
);
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
)
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
678 t_symbol
*x_templatesym
;
679 t_symbol
*x_fieldsym
;
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
);
691 static void getsize_pointer(t_getsize
*x
, t_gpointer
*gp
)
696 int nitems
, onset
, type
;
698 t_symbol
*templatesym
= x
->x_templatesym
, *fieldsym
= x
->x_fieldsym
,
700 t_template
*template = template_findbyname(templatesym
);
706 t_gstub
*gs
= gp
->gp_stub
;
709 pd_error(x
, "getsize: couldn't find template %s", templatesym
->s_name
);
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
);
718 if (type
!= DT_ARRAY
)
720 pd_error(x
, "getsize: field %s not of type array", fieldsym
->s_name
);
723 if (gpointer_ishead(gp
))
725 pd_error(x
, "getsize: empty pointer");
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
);
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
755 t_symbol
*x_templatesym
;
756 t_symbol
*x_fieldsym
;
760 static void *setsize_new(t_symbol
*templatesym
, t_symbol
*fieldsym
,
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
);
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
,
780 t_template
*template = template_findbyname(templatesym
);
781 t_template
*elemtemplate
;
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");
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
);
803 if (gs
->gs_which
== GP_ARRAY
) w
= gp
->gp_un
.gp_w
;
804 else w
= gp
->gp_un
.gp_scalar
->sc_vec
;
808 pd_error(x
,"setsize: couldn't find template %s", templatesym
->s_name
);
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
);
817 if (type
!= DT_ARRAY
)
819 pd_error(x
,"setsize: field %s not of type array", fieldsym
->s_name
);
823 if (!(elemtemplate
= template_findbyname(elemtemplatesym
)))
825 pd_error(x
,"element: couldn't find field template %s",
826 elemtemplatesym
->s_name
);
830 elemsize
= elemtemplate
->t_n
* sizeof(t_word
);
832 array
= *(t_array
**)(((char *)w
) + onset
);
834 if (elemsize
!= array
->a_elemsize
) bug("setsize_gpointer");
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);
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
;
868 int nnew
= newsize
- nitems
;
870 int i
= 0, nnew
= newsize
- nitems
;
875 word_init((t_word
*)newelem
, elemtemplate
, gp
);
877 /* post("new %x %x, ntypes %d", newelem, *(int *)newelem, ntypes); */
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);
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
922 typedef struct _append
926 t_symbol
*x_templatesym
;
928 t_appendvariable
*x_variables
;
931 static void *append_new(t_symbol
*why
, int argc
, t_atom
*argv
)
933 t_append
*x
= (t_append
*)pd_new(append_class
);
935 t_appendvariable
*sp
;
936 x
->x_templatesym
= canvas_makebindsym(atom_getsymbolarg(0, argc
, argv
));
940 if (argc
) argc
--, argv
++;
942 = (t_appendvariable
*)getbytes(argc
* sizeof (*x
->x_variables
));
946 for (i
= 0, sp
= x
->x_variables
; i
< argc
; i
++, sp
++)
948 sp
->gv_sym
= atom_getsymbolarg(i
, argc
, argv
);
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
);
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
;
968 t_scalar
*sc
, *oldsc
;
972 pd_error(x
, "append: couldn't find template %s", templatesym
->s_name
);
977 pd_error(x
, "append: no current pointer");
980 if (gs
->gs_which
!= GP_GLIST
)
982 pd_error(x
, "append: lists only, not arrays");
985 glist
= gs
->gs_un
.gs_glist
;
986 if (glist
->gl_valid
!= gp
->gp_valid
)
988 pd_error(x
, "append: stale pointer");
992 x
->x_variables
[0].gv_f
= f
;
994 sc
= scalar_new(glist
, templatesym
);
997 pd_error(x
, "%s: couldn't create scalar", templatesym
->s_name
);
1000 oldsc
= gp
->gp_un
.gp_scalar
;
1004 sc
->sc_gobj
.g_next
= oldsc
->sc_gobj
.g_next
;
1005 oldsc
->sc_gobj
.g_next
= &sc
->sc_gobj
;
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
;
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
1047 t_symbol
*x_templatesym
;
1048 t_symbol
*x_fieldsym
;
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
);
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
;
1076 pd_error(x
, "sublist: couldn't find template %s", templatesym
->s_name
);
1079 if (gpointer_ishead(gp
))
1081 pd_error(x
, "sublist: empty pointer");
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
);
1090 if (type
!= DT_LIST
)
1092 pd_error(x
, "sublist: field %s not of type list", x
->x_fieldsym
->s_name
);
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
)
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)