diff options
author | Peter D'Hoye <peter.dhoye@gmail.com> | 2009-05-22 21:58:48 +0000 |
---|---|---|
committer | Peter D'Hoye <peter.dhoye@gmail.com> | 2009-05-22 21:58:48 +0000 |
commit | 513389b4c1bc8afe4b2dc9947c534bfeb105e3da (patch) | |
tree | 10e673b35651ac567fed2eda0c679c7ade64cbc6 /apps/plugins/pdbox/PDa/src/g_traversal.c | |
parent | 95fa7f6a2ef466444fbe3fe87efc6d5db6b77b36 (diff) | |
download | rockbox-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.c | 2168 |
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 | ||
6 | and arrays: | ||
7 | |||
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 | ||
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 | |||
29 | t_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 | ||
47 | down the owner) we increase a reference count. The following routine is called | ||
48 | whenever a gpointer is unset from pointing here. If the owner is | ||
49 | gone and the refcount goes to zero, we can free the gstub safely. */ | ||
50 | |||
51 | static 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 | ||
60 | being deleted. If no gpointers are pointing here, we can free the gstub; | ||
61 | otherwise we wait for the last gstub_dis() to free it. */ | ||
62 | |||
63 | void 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 | ||
71 | points to real data or to the head of a list, and that in either case | ||
72 | the object hasn't disappeared since this pointer was generated. | ||
73 | Unless "headok" is set, the routine also fails for the head of a list. */ | ||
74 | |||
75 | int 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 | ||
94 | to the head of a list or to real data. Any pointer is known to be fresh | ||
95 | when it appears as the argument of a message, but if your "pointer" method | ||
96 | or 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 | |||
100 | static 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 | ||
106 | freshness. Returns 0 if head of list. */ | ||
107 | |||
108 | static 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. */ | ||
127 | void 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 | |||
135 | void 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 | |||
145 | void 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 | |||
155 | static 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 | |||
165 | void 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 | |||
174 | static t_class *ptrobj_class; | ||
175 | |||
176 | typedef struct | ||
177 | { | ||
178 | t_symbol *to_type; | ||
179 | t_outlet *to_outlet; | ||
180 | } t_typedout; | ||
181 | |||
182 | typedef 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 | |||
192 | static 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 | |||
211 | static 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 | |||
218 | static 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 | |||
281 | static void ptrobj_next(t_ptrobj *x) | ||
282 | { | ||
283 | ptrobj_vnext(x, 0); | ||
284 | } | ||
285 | |||
286 | static 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 | |||
316 | static 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 | |||
339 | static 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 | |||
346 | static 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 | |||
352 | static 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 | |||
369 | static t_class *get_class; | ||
370 | |||
371 | typedef struct _getvariable | ||
372 | { | ||
373 | t_symbol *gv_sym; | ||
374 | t_outlet *gv_outlet; | ||
375 | } t_getvariable; | ||
376 | |||
377 | typedef 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 | |||
385 | static 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 | |||
406 | static 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 | |||
434 | static void get_free(t_get *x) | ||
435 | { | ||
436 | freebytes(x->x_variables, x->x_nout * sizeof (*x->x_variables)); | ||
437 | } | ||
438 | |||
439 | static 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 | |||
448 | static t_class *set_class; | ||
449 | |||
450 | typedef struct _setvariable | ||
451 | { | ||
452 | t_symbol *gv_sym; | ||
453 | t_float gv_f; /* LATER take other types */ | ||
454 | } t_setvariable; | ||
455 | |||
456 | typedef 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 | |||
465 | static 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 | |||
490 | static 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 | |||
536 | static 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 | |||
542 | static 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 | |||
551 | static t_class *elem_class; | ||
552 | |||
553 | typedef 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 | |||
562 | static 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 | |||
574 | static 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 | |||
635 | static void elem_free(t_elem *x, t_gpointer *gp) | ||
636 | { | ||
637 | gpointer_unset(&x->x_gp); | ||
638 | gpointer_unset(&x->x_gparent); | ||
639 | } | ||
640 | |||
641 | static 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 | |||
650 | static t_class *getsize_class; | ||
651 | |||
652 | typedef struct _getsize | ||
653 | { | ||
654 | t_object x_obj; | ||
655 | t_symbol *x_templatesym; | ||
656 | t_symbol *x_fieldsym; | ||
657 | } t_getsize; | ||
658 | |||
659 | static 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 | |||
668 | static 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 | |||
712 | static 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 | |||
721 | static t_class *setsize_class; | ||
722 | |||
723 | typedef 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 | |||
731 | static 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 | |||
743 | static 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 | |||
861 | static void setsize_free(t_setsize *x) | ||
862 | { | ||
863 | gpointer_unset(&x->x_gp); | ||
864 | } | ||
865 | |||
866 | static 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 | |||
876 | static t_class *append_class; | ||
877 | |||
878 | typedef struct _appendvariable | ||
879 | { | ||
880 | t_symbol *gv_sym; | ||
881 | t_float gv_f; | ||
882 | } t_appendvariable; | ||
883 | |||
884 | typedef 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 | |||
893 | static 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 | |||
918 | static 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 | |||
986 | static 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 | |||
992 | static 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 | |||
1001 | static t_class *sublist_class; | ||
1002 | |||
1003 | typedef 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 | |||
1011 | static 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 | |||
1021 | static 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 | |||
1060 | static void sublist_free(t_sublist *x, t_gpointer *gp) | ||
1061 | { | ||
1062 | gpointer_unset(&x->x_gp); | ||
1063 | } | ||
1064 | |||
1065 | static 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 | |||
1074 | void 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 | ||
1090 | and arrays: | ||
1091 | |||
1092 | pointer - point to an object belonging to a template | ||
1093 | get - get numeric fields | ||
1094 | set - change numeric fields | ||
1095 | element - get an array element | ||
1096 | getsize - get the size of an array | ||
1097 | setsize - change the size of an array | ||
1098 | append - add an element to a list | ||
1099 | sublist - 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 | |||
1113 | t_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 | ||
1131 | down the owner) we increase a reference count. The following routine is called | ||
1132 | whenever a gpointer is unset from pointing here. If the owner is | ||
1133 | gone and the refcount goes to zero, we can free the gstub safely. */ | ||
1134 | |||
1135 | static 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 | ||
1144 | being deleted. If no gpointers are pointing here, we can free the gstub; | ||
1145 | otherwise we wait for the last gstub_dis() to free it. */ | ||
1146 | |||
1147 | void 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 | ||
1155 | points to real data or to the head of a list, and that in either case | ||
1156 | the object hasn't disappeared since this pointer was generated. | ||
1157 | Unless "headok" is set, the routine also fails for the head of a list. */ | ||
1158 | |||
1159 | int 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 | ||
1178 | to the head of a list or to real data. Any pointer is known to be fresh | ||
1179 | when it appears as the argument of a message, but if your "pointer" method | ||
1180 | or 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 | |||
1184 | static 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 | ||
1190 | freshness. Returns 0 if head of list. */ | ||
1191 | |||
1192 | static 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. */ | ||
1211 | void 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 | |||
1219 | void 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 | |||
1229 | void 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 | |||
1239 | static 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 | |||
1249 | void 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 | |||
1258 | static t_class *ptrobj_class; | ||
1259 | |||
1260 | typedef struct | ||
1261 | { | ||
1262 | t_symbol *to_type; | ||
1263 | t_outlet *to_outlet; | ||
1264 | } t_typedout; | ||
1265 | |||
1266 | typedef 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 | |||
1276 | static 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 | |||
1295 | static 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 | |||
1302 | static 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 | |||
1365 | static void ptrobj_next(t_ptrobj *x) | ||
1366 | { | ||
1367 | ptrobj_vnext(x, 0); | ||
1368 | } | ||
1369 | |||
1370 | static 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 | |||
1400 | static 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 | |||
1423 | static 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 | |||
1430 | static 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 | |||
1436 | static 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 | |||
1453 | static t_class *get_class; | ||
1454 | |||
1455 | typedef struct _getvariable | ||
1456 | { | ||
1457 | t_symbol *gv_sym; | ||
1458 | t_outlet *gv_outlet; | ||
1459 | } t_getvariable; | ||
1460 | |||
1461 | typedef 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 | |||
1469 | static 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 | |||
1490 | static 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 | |||
1518 | static void get_free(t_get *x) | ||
1519 | { | ||
1520 | freebytes(x->x_variables, x->x_nout * sizeof (*x->x_variables)); | ||
1521 | } | ||
1522 | |||
1523 | static 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 | |||
1532 | static t_class *set_class; | ||
1533 | |||
1534 | typedef struct _setvariable | ||
1535 | { | ||
1536 | t_symbol *gv_sym; | ||
1537 | t_float gv_f; /* LATER take other types */ | ||
1538 | } t_setvariable; | ||
1539 | |||
1540 | typedef 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 | |||
1549 | static 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 | |||
1574 | static 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 | |||
1620 | static 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 | |||
1626 | static 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 | |||
1635 | static t_class *elem_class; | ||
1636 | |||
1637 | typedef 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 | |||
1646 | static 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 | |||
1658 | static 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 | |||
1719 | static void elem_free(t_elem *x, t_gpointer *gp) | ||
1720 | { | ||
1721 | gpointer_unset(&x->x_gp); | ||
1722 | gpointer_unset(&x->x_gparent); | ||
1723 | } | ||
1724 | |||
1725 | static 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 | |||
1734 | static t_class *getsize_class; | ||
1735 | |||
1736 | typedef struct _getsize | ||
1737 | { | ||
1738 | t_object x_obj; | ||
1739 | t_symbol *x_templatesym; | ||
1740 | t_symbol *x_fieldsym; | ||
1741 | } t_getsize; | ||
1742 | |||
1743 | static 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 | |||
1752 | static 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 | |||
1796 | static 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 | |||
1805 | static t_class *setsize_class; | ||
1806 | |||
1807 | typedef 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 | |||
1815 | static 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 | |||
1827 | static 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 | |||
1945 | static void setsize_free(t_setsize *x) | ||
1946 | { | ||
1947 | gpointer_unset(&x->x_gp); | ||
1948 | } | ||
1949 | |||
1950 | static 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 | |||
1960 | static t_class *append_class; | ||
1961 | |||
1962 | typedef struct _appendvariable | ||
1963 | { | ||
1964 | t_symbol *gv_sym; | ||
1965 | t_float gv_f; | ||
1966 | } t_appendvariable; | ||
1967 | |||
1968 | typedef 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 | |||
1977 | static 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 | |||
2002 | static 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 | |||
2070 | static 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 | |||
2076 | static 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 | |||
2085 | static t_class *sublist_class; | ||
2086 | |||
2087 | typedef 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 | |||
2095 | static 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 | |||
2105 | static 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 | |||
2144 | static void sublist_free(t_sublist *x, t_gpointer *gp) | ||
2145 | { | ||
2146 | gpointer_unset(&x->x_gp); | ||
2147 | } | ||
2148 | |||
2149 | static 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 | |||
2158 | void 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 | } | ||