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_readwrite.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_readwrite.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/g_readwrite.c | 1446 |
1 files changed, 1446 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/g_readwrite.c b/apps/plugins/pdbox/PDa/src/g_readwrite.c new file mode 100644 index 0000000000..a25b60c443 --- /dev/null +++ b/apps/plugins/pdbox/PDa/src/g_readwrite.c | |||
@@ -0,0 +1,1446 @@ | |||
1 | /* Copyright (c) 1997-2002 Miller Puckette and others. | ||
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 reads and writes the "data" portions of a canvas to a file. | ||
6 | See also canvas_saveto(), etc., in g_editor.c. The data portion is a | ||
7 | collection of "scalar" objects. Routines here can save collections of | ||
8 | scalars into a file and reload them; also, support is included here for | ||
9 | */ | ||
10 | |||
11 | #include <stdlib.h> | ||
12 | #include <stdio.h> | ||
13 | #include "m_pd.h" | ||
14 | #include "g_canvas.h" | ||
15 | #include <string.h> | ||
16 | |||
17 | /* the following routines read "scalars" from a file into a canvas. */ | ||
18 | |||
19 | static int canvas_scanbinbuf(int natoms, t_atom *vec, int *p_indexout, | ||
20 | int *p_next) | ||
21 | { | ||
22 | int i, j; | ||
23 | int indexwas = *p_next; | ||
24 | *p_indexout = indexwas; | ||
25 | if (indexwas >= natoms) | ||
26 | return (0); | ||
27 | for (i = indexwas; i < natoms && vec[i].a_type != A_SEMI; i++) | ||
28 | ; | ||
29 | if (i >= natoms) | ||
30 | *p_next = i; | ||
31 | else *p_next = i + 1; | ||
32 | return (i - indexwas); | ||
33 | } | ||
34 | |||
35 | int glist_readscalar(t_glist *x, int natoms, t_atom *vec, | ||
36 | int *p_nextmsg, int selectit); | ||
37 | |||
38 | static void canvas_readerror(int natoms, t_atom *vec, int message, | ||
39 | int nline, char *s) | ||
40 | { | ||
41 | error(s); | ||
42 | startpost("line was:"); | ||
43 | postatom(nline, vec + message); | ||
44 | endpost(); | ||
45 | } | ||
46 | |||
47 | /* fill in the contents of the scalar into the vector w. */ | ||
48 | |||
49 | static void glist_readatoms(t_glist *x, int natoms, t_atom *vec, | ||
50 | int *p_nextmsg, t_symbol *templatesym, t_word *w, int argc, t_atom *argv) | ||
51 | { | ||
52 | int message, nline, n, i; | ||
53 | |||
54 | t_template *template = template_findbyname(templatesym); | ||
55 | if (!template) | ||
56 | { | ||
57 | error("%s: no such template", templatesym->s_name); | ||
58 | *p_nextmsg = natoms; | ||
59 | return; | ||
60 | } | ||
61 | word_restore(w, template, argc, argv); | ||
62 | n = template->t_n; | ||
63 | for (i = 0; i < n; i++) | ||
64 | { | ||
65 | if (template->t_vec[i].ds_type == DT_ARRAY) | ||
66 | { | ||
67 | int j; | ||
68 | t_array *a = w[i].w_array; | ||
69 | int elemsize = a->a_elemsize, nitems = 0; | ||
70 | t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate; | ||
71 | t_template *arraytemplate = | ||
72 | template_findbyname(arraytemplatesym); | ||
73 | if (!arraytemplate) | ||
74 | { | ||
75 | error("%s: no such template", arraytemplatesym->s_name); | ||
76 | } | ||
77 | else while (1) | ||
78 | { | ||
79 | t_word *element; | ||
80 | int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg); | ||
81 | /* empty line terminates array */ | ||
82 | if (!nline) | ||
83 | break; | ||
84 | array_resize(a, arraytemplate, nitems + 1); | ||
85 | element = (t_word *)(((char *)a->a_vec) + | ||
86 | nitems * elemsize); | ||
87 | glist_readatoms(x, natoms, vec, p_nextmsg, arraytemplatesym, | ||
88 | element, nline, vec + message); | ||
89 | nitems++; | ||
90 | } | ||
91 | } | ||
92 | else if (template->t_vec[i].ds_type == DT_LIST) | ||
93 | { | ||
94 | while (1) | ||
95 | { | ||
96 | if (!glist_readscalar(w->w_list, natoms, vec, | ||
97 | p_nextmsg, 0)) | ||
98 | break; | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | int glist_readscalar(t_glist *x, int natoms, t_atom *vec, | ||
105 | int *p_nextmsg, int selectit) | ||
106 | { | ||
107 | int message, i, j, nline; | ||
108 | t_template *template; | ||
109 | t_symbol *templatesym; | ||
110 | t_scalar *sc; | ||
111 | int nextmsg = *p_nextmsg; | ||
112 | int wasvis = glist_isvisible(x); | ||
113 | |||
114 | if (nextmsg >= natoms || vec[nextmsg].a_type != A_SYMBOL) | ||
115 | { | ||
116 | if (nextmsg < natoms) | ||
117 | post("stopping early: type %d", vec[nextmsg].a_type); | ||
118 | *p_nextmsg = natoms; | ||
119 | return (0); | ||
120 | } | ||
121 | templatesym = canvas_makebindsym(vec[nextmsg].a_w.w_symbol); | ||
122 | *p_nextmsg = nextmsg + 1; | ||
123 | |||
124 | if (!(template = template_findbyname(templatesym))) | ||
125 | { | ||
126 | error("canvas_read: %s: no such template", templatesym->s_name); | ||
127 | *p_nextmsg = natoms; | ||
128 | return (0); | ||
129 | } | ||
130 | sc = scalar_new(x, templatesym); | ||
131 | if (!sc) | ||
132 | { | ||
133 | error("couldn't create scalar \"%s\"", templatesym->s_name); | ||
134 | *p_nextmsg = natoms; | ||
135 | return (0); | ||
136 | } | ||
137 | if (wasvis) | ||
138 | { | ||
139 | /* temporarily lie about vis flag while this is built */ | ||
140 | glist_getcanvas(x)->gl_mapped = 0; | ||
141 | } | ||
142 | glist_add(x, &sc->sc_gobj); | ||
143 | |||
144 | nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg); | ||
145 | glist_readatoms(x, natoms, vec, p_nextmsg, templatesym, sc->sc_vec, | ||
146 | nline, vec + message); | ||
147 | if (wasvis) | ||
148 | { | ||
149 | /* reset vis flag as before */ | ||
150 | glist_getcanvas(x)->gl_mapped = 1; | ||
151 | gobj_vis(&sc->sc_gobj, x, 1); | ||
152 | } | ||
153 | if (selectit) | ||
154 | { | ||
155 | glist_select(x, &sc->sc_gobj); | ||
156 | } | ||
157 | return (1); | ||
158 | } | ||
159 | |||
160 | void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename, int selectem) | ||
161 | { | ||
162 | t_canvas *canvas = glist_getcanvas(x); | ||
163 | int cr = 0, natoms, nline, message, nextmsg = 0, i, j, nitems; | ||
164 | t_atom *vec; | ||
165 | t_gobj *gobj; | ||
166 | |||
167 | natoms = binbuf_getnatom(b); | ||
168 | vec = binbuf_getvec(b); | ||
169 | |||
170 | |||
171 | /* check for file type */ | ||
172 | nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); | ||
173 | if (nline != 1 && vec[message].a_type != A_SYMBOL && | ||
174 | strcmp(vec[message].a_w.w_symbol->s_name, "data")) | ||
175 | { | ||
176 | pd_error(x, "%s: file apparently of wrong type", filename); | ||
177 | binbuf_free(b); | ||
178 | return; | ||
179 | } | ||
180 | /* read in templates and check for consistency */ | ||
181 | while (1) | ||
182 | { | ||
183 | t_template *newtemplate, *existtemplate; | ||
184 | t_symbol *templatesym; | ||
185 | t_atom *templateargs = getbytes(0); | ||
186 | int ntemplateargs = 0, newnargs; | ||
187 | nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); | ||
188 | if (nline < 2) | ||
189 | break; | ||
190 | else if (nline > 2) | ||
191 | canvas_readerror(natoms, vec, message, nline, | ||
192 | "extra items ignored"); | ||
193 | else if (vec[message].a_type != A_SYMBOL || | ||
194 | strcmp(vec[message].a_w.w_symbol->s_name, "template") || | ||
195 | vec[message + 1].a_type != A_SYMBOL) | ||
196 | { | ||
197 | canvas_readerror(natoms, vec, message, nline, | ||
198 | "bad template header"); | ||
199 | continue; | ||
200 | } | ||
201 | templatesym = canvas_makebindsym(vec[message + 1].a_w.w_symbol); | ||
202 | while (1) | ||
203 | { | ||
204 | nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); | ||
205 | if (nline != 2 && nline != 3) | ||
206 | break; | ||
207 | newnargs = ntemplateargs + nline; | ||
208 | templateargs = (t_atom *)t_resizebytes(templateargs, | ||
209 | sizeof(*templateargs) * ntemplateargs, | ||
210 | sizeof(*templateargs) * newnargs); | ||
211 | templateargs[ntemplateargs] = vec[message]; | ||
212 | templateargs[ntemplateargs + 1] = vec[message + 1]; | ||
213 | if (nline == 3) | ||
214 | templateargs[ntemplateargs + 2] = vec[message + 2]; | ||
215 | ntemplateargs = newnargs; | ||
216 | } | ||
217 | newtemplate = template_new(templatesym, ntemplateargs, templateargs); | ||
218 | t_freebytes(templateargs, sizeof (*templateargs) * ntemplateargs); | ||
219 | if (!(existtemplate = template_findbyname(templatesym))) | ||
220 | { | ||
221 | error("%s: template not found in current patch", | ||
222 | templatesym->s_name); | ||
223 | template_free(newtemplate); | ||
224 | return; | ||
225 | } | ||
226 | if (!template_match(existtemplate, newtemplate)) | ||
227 | { | ||
228 | error("%s: template doesn't match current one", | ||
229 | templatesym->s_name); | ||
230 | template_free(newtemplate); | ||
231 | return; | ||
232 | } | ||
233 | template_free(newtemplate); | ||
234 | } | ||
235 | while (nextmsg < natoms) | ||
236 | { | ||
237 | glist_readscalar(x, natoms, vec, &nextmsg, selectem); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | static void glist_doread(t_glist *x, t_symbol *filename, t_symbol *format, | ||
242 | int clearme) | ||
243 | { | ||
244 | t_binbuf *b = binbuf_new(); | ||
245 | t_canvas *canvas = glist_getcanvas(x); | ||
246 | int wasvis = glist_isvisible(canvas); | ||
247 | int cr = 0, natoms, nline, message, nextmsg = 0, i, j; | ||
248 | t_atom *vec; | ||
249 | |||
250 | if (!strcmp(format->s_name, "cr")) | ||
251 | cr = 1; | ||
252 | else if (*format->s_name) | ||
253 | error("qlist_read: unknown flag: %s", format->s_name); | ||
254 | |||
255 | if (binbuf_read_via_path(b, filename->s_name, | ||
256 | canvas_getdir(canvas)->s_name, cr)) | ||
257 | { | ||
258 | pd_error(x, "read failed"); | ||
259 | binbuf_free(b); | ||
260 | return; | ||
261 | } | ||
262 | if (wasvis) | ||
263 | canvas_vis(canvas, 0); | ||
264 | if (clearme) | ||
265 | glist_clear(x); | ||
266 | glist_readfrombinbuf(x, b, filename->s_name, 0); | ||
267 | if (wasvis) | ||
268 | canvas_vis(canvas, 1); | ||
269 | binbuf_free(b); | ||
270 | } | ||
271 | |||
272 | void glist_read(t_glist *x, t_symbol *filename, t_symbol *format) | ||
273 | { | ||
274 | glist_doread(x, filename, format, 1); | ||
275 | } | ||
276 | |||
277 | void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format) | ||
278 | { | ||
279 | glist_doread(x, filename, format, 0); | ||
280 | } | ||
281 | |||
282 | /* read text from a "properties" window, called from a gfxstub set | ||
283 | up in scalar_properties(). We try to restore the object; if successful | ||
284 | we delete the scalar and put the new thing in its place on the list. */ | ||
285 | void canvas_dataproperties(t_canvas *x, t_scalar *sc, t_binbuf *b) | ||
286 | { | ||
287 | int ntotal, nnew, scindex; | ||
288 | t_gobj *y, *y2 = 0, *newone, *oldone = 0; | ||
289 | for (y = x->gl_list, ntotal = 0, scindex = -1; y; y = y->g_next) | ||
290 | { | ||
291 | if (y == &sc->sc_gobj) | ||
292 | scindex = ntotal, oldone = y; | ||
293 | ntotal++; | ||
294 | } | ||
295 | |||
296 | if (scindex == -1) | ||
297 | bug("data_properties: scalar disappeared"); | ||
298 | glist_readfrombinbuf(x, b, "properties dialog", 0); | ||
299 | newone = 0; | ||
300 | if (scindex >= 0) | ||
301 | { | ||
302 | /* take the new object off the list */ | ||
303 | if (ntotal) | ||
304 | { | ||
305 | for (y = x->gl_list, nnew = 1; y2 = y->g_next; | ||
306 | y = y2, nnew++) | ||
307 | if (nnew == ntotal) | ||
308 | { | ||
309 | newone = y2; | ||
310 | y->g_next = y2->g_next; | ||
311 | break; | ||
312 | } | ||
313 | } | ||
314 | else newone = x->gl_list, x->gl_list = newone->g_next; | ||
315 | } | ||
316 | if (!newone) | ||
317 | error("couldn't update properties (perhaps a format problem?)"); | ||
318 | else if (!oldone) | ||
319 | bug("data_properties: couldn't find old element"); | ||
320 | else | ||
321 | { | ||
322 | glist_delete(x, oldone); | ||
323 | if (scindex > 0) | ||
324 | { | ||
325 | for (y = x->gl_list, nnew = 1; y; | ||
326 | y = y->g_next, nnew++) | ||
327 | if (nnew == scindex || !y->g_next) | ||
328 | { | ||
329 | newone->g_next = y->g_next; | ||
330 | y->g_next = newone; | ||
331 | goto didit; | ||
332 | } | ||
333 | bug("data_properties: can't reinsert"); | ||
334 | } | ||
335 | else newone->g_next = x->gl_list, x->gl_list = newone; | ||
336 | } | ||
337 | didit: | ||
338 | ; | ||
339 | } | ||
340 | |||
341 | /* ----------- routines to write data to a binbuf ----------- */ | ||
342 | |||
343 | void canvas_doaddtemplate(t_symbol *templatesym, | ||
344 | int *p_ntemplates, t_symbol ***p_templatevec) | ||
345 | { | ||
346 | int n = *p_ntemplates, i; | ||
347 | t_symbol **templatevec = *p_templatevec; | ||
348 | for (i = 0; i < n; i++) | ||
349 | if (templatevec[i] == templatesym) | ||
350 | return; | ||
351 | templatevec = (t_symbol **)t_resizebytes(templatevec, | ||
352 | n * sizeof(*templatevec), (n+1) * sizeof(*templatevec)); | ||
353 | templatevec[n] = templatesym; | ||
354 | *p_templatevec = templatevec; | ||
355 | *p_ntemplates = n+1; | ||
356 | } | ||
357 | |||
358 | static void glist_writelist(t_gobj *y, t_binbuf *b); | ||
359 | |||
360 | void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b, | ||
361 | int amarrayelement) | ||
362 | { | ||
363 | t_dataslot *ds; | ||
364 | t_template *template = template_findbyname(templatesym); | ||
365 | t_atom *a = (t_atom *)t_getbytes(0); | ||
366 | int i, n = template->t_n, natom = 0; | ||
367 | if (!amarrayelement) | ||
368 | { | ||
369 | t_atom templatename; | ||
370 | SETSYMBOL(&templatename, gensym(templatesym->s_name + 3)); | ||
371 | binbuf_add(b, 1, &templatename); | ||
372 | } | ||
373 | if (!template) | ||
374 | bug("canvas_writescalar"); | ||
375 | /* write the atoms (floats and symbols) */ | ||
376 | for (i = 0; i < n; i++) | ||
377 | { | ||
378 | if (template->t_vec[i].ds_type == DT_FLOAT || | ||
379 | template->t_vec[i].ds_type == DT_SYMBOL) | ||
380 | { | ||
381 | a = (t_atom *)t_resizebytes(a, | ||
382 | natom * sizeof(*a), (natom + 1) * sizeof (*a)); | ||
383 | if (template->t_vec[i].ds_type == DT_FLOAT) | ||
384 | SETFLOAT(a + natom, w[i].w_float); | ||
385 | else SETSYMBOL(a + natom, w[i].w_symbol); | ||
386 | natom++; | ||
387 | } | ||
388 | } | ||
389 | /* array elements have to have at least something */ | ||
390 | if (natom == 0 && amarrayelement) | ||
391 | SETSYMBOL(a + natom, &s_bang), natom++; | ||
392 | binbuf_add(b, natom, a); | ||
393 | binbuf_addsemi(b); | ||
394 | t_freebytes(a, natom * sizeof(*a)); | ||
395 | for (i = 0; i < n; i++) | ||
396 | { | ||
397 | if (template->t_vec[i].ds_type == DT_ARRAY) | ||
398 | { | ||
399 | int j; | ||
400 | t_array *a = w[i].w_array; | ||
401 | int elemsize = a->a_elemsize, nitems = a->a_n; | ||
402 | t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate; | ||
403 | for (j = 0; j < nitems; j++) | ||
404 | canvas_writescalar(arraytemplatesym, | ||
405 | (t_word *)(((char *)a->a_vec) + elemsize * j), b, 1); | ||
406 | binbuf_addsemi(b); | ||
407 | } | ||
408 | else if (template->t_vec[i].ds_type == DT_LIST) | ||
409 | { | ||
410 | glist_writelist(w->w_list->gl_list, b); | ||
411 | binbuf_addsemi(b); | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | |||
416 | static void glist_writelist(t_gobj *y, t_binbuf *b) | ||
417 | { | ||
418 | for (; y; y = y->g_next) | ||
419 | { | ||
420 | if (pd_class(&y->g_pd) == scalar_class) | ||
421 | { | ||
422 | canvas_writescalar(((t_scalar *)y)->sc_template, | ||
423 | ((t_scalar *)y)->sc_vec, b, 0); | ||
424 | } | ||
425 | } | ||
426 | } | ||
427 | |||
428 | /* ------------ routines to write out templates for data ------- */ | ||
429 | |||
430 | static void canvas_addtemplatesforlist(t_gobj *y, | ||
431 | int *p_ntemplates, t_symbol ***p_templatevec); | ||
432 | |||
433 | static void canvas_addtemplatesforscalar(t_symbol *templatesym, | ||
434 | t_word *w, int *p_ntemplates, t_symbol ***p_templatevec) | ||
435 | { | ||
436 | t_dataslot *ds; | ||
437 | int i; | ||
438 | t_template *template = template_findbyname(templatesym); | ||
439 | canvas_doaddtemplate(templatesym, p_ntemplates, p_templatevec); | ||
440 | if (!template) | ||
441 | bug("canvas_addtemplatesforscalar"); | ||
442 | else for (ds = template->t_vec, i = template->t_n; i--; ds++, w++) | ||
443 | { | ||
444 | if (ds->ds_type == DT_ARRAY) | ||
445 | { | ||
446 | int j; | ||
447 | t_array *a = w->w_array; | ||
448 | int elemsize = a->a_elemsize, nitems = a->a_n; | ||
449 | t_symbol *arraytemplatesym = ds->ds_arraytemplate; | ||
450 | canvas_doaddtemplate(arraytemplatesym, p_ntemplates, p_templatevec); | ||
451 | for (j = 0; j < nitems; j++) | ||
452 | canvas_addtemplatesforscalar(arraytemplatesym, | ||
453 | (t_word *)(((char *)a->a_vec) + elemsize * j), | ||
454 | p_ntemplates, p_templatevec); | ||
455 | } | ||
456 | else if (ds->ds_type == DT_LIST) | ||
457 | canvas_addtemplatesforlist(w->w_list->gl_list, | ||
458 | p_ntemplates, p_templatevec); | ||
459 | } | ||
460 | } | ||
461 | |||
462 | static void canvas_addtemplatesforlist(t_gobj *y, | ||
463 | int *p_ntemplates, t_symbol ***p_templatevec) | ||
464 | { | ||
465 | for (; y; y = y->g_next) | ||
466 | { | ||
467 | if (pd_class(&y->g_pd) == scalar_class) | ||
468 | { | ||
469 | canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template, | ||
470 | ((t_scalar *)y)->sc_vec, p_ntemplates, p_templatevec); | ||
471 | } | ||
472 | } | ||
473 | } | ||
474 | |||
475 | /* write all "scalars" in a glist to a binbuf. */ | ||
476 | t_binbuf *glist_writetobinbuf(t_glist *x, int wholething) | ||
477 | { | ||
478 | int i; | ||
479 | t_symbol **templatevec = getbytes(0); | ||
480 | int ntemplates = 0; | ||
481 | t_gobj *y; | ||
482 | t_binbuf *b = binbuf_new(); | ||
483 | |||
484 | for (y = x->gl_list; y; y = y->g_next) | ||
485 | { | ||
486 | if ((pd_class(&y->g_pd) == scalar_class) && | ||
487 | (wholething || glist_isselected(x, y))) | ||
488 | { | ||
489 | canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template, | ||
490 | ((t_scalar *)y)->sc_vec, &ntemplates, &templatevec); | ||
491 | } | ||
492 | } | ||
493 | binbuf_addv(b, "s;", gensym("data")); | ||
494 | for (i = 0; i < ntemplates; i++) | ||
495 | { | ||
496 | t_template *template = template_findbyname(templatevec[i]); | ||
497 | int j, m = template->t_n; | ||
498 | /* drop "pd-" prefix from template symbol to print it: */ | ||
499 | binbuf_addv(b, "ss;", gensym("template"), | ||
500 | gensym(templatevec[i]->s_name + 3)); | ||
501 | for (j = 0; j < m; j++) | ||
502 | { | ||
503 | t_symbol *type; | ||
504 | switch (template->t_vec[j].ds_type) | ||
505 | { | ||
506 | case DT_FLOAT: type = &s_float; break; | ||
507 | case DT_SYMBOL: type = &s_symbol; break; | ||
508 | case DT_ARRAY: type = gensym("array"); break; | ||
509 | case DT_LIST: type = &s_list; break; | ||
510 | default: type = &s_float; bug("canvas_write"); | ||
511 | } | ||
512 | if (template->t_vec[j].ds_type == DT_ARRAY) | ||
513 | binbuf_addv(b, "sss;", type, template->t_vec[j].ds_name, | ||
514 | gensym(template->t_vec[j].ds_arraytemplate->s_name + 3)); | ||
515 | else binbuf_addv(b, "ss;", type, template->t_vec[j].ds_name); | ||
516 | } | ||
517 | binbuf_addsemi(b); | ||
518 | } | ||
519 | binbuf_addsemi(b); | ||
520 | /* now write out the objects themselves */ | ||
521 | for (y = x->gl_list; y; y = y->g_next) | ||
522 | { | ||
523 | if ((pd_class(&y->g_pd) == scalar_class) && | ||
524 | (wholething || glist_isselected(x, y))) | ||
525 | { | ||
526 | canvas_writescalar(((t_scalar *)y)->sc_template, | ||
527 | ((t_scalar *)y)->sc_vec, b, 0); | ||
528 | } | ||
529 | } | ||
530 | return (b); | ||
531 | } | ||
532 | |||
533 | static void glist_write(t_glist *x, t_symbol *filename, t_symbol *format) | ||
534 | { | ||
535 | int cr = 0, i; | ||
536 | t_binbuf *b; | ||
537 | char buf[MAXPDSTRING]; | ||
538 | t_symbol **templatevec = getbytes(0); | ||
539 | int ntemplates = 0; | ||
540 | t_gobj *y; | ||
541 | t_canvas *canvas = glist_getcanvas(x); | ||
542 | canvas_makefilename(canvas, filename->s_name, buf, MAXPDSTRING); | ||
543 | if (!strcmp(format->s_name, "cr")) | ||
544 | cr = 1; | ||
545 | else if (*format->s_name) | ||
546 | error("qlist_read: unknown flag: %s", format->s_name); | ||
547 | |||
548 | b = glist_writetobinbuf(x, 1); | ||
549 | if (b) | ||
550 | { | ||
551 | if (binbuf_write(b, buf, "", cr)) | ||
552 | error("%s: write failed", filename->s_name); | ||
553 | binbuf_free(b); | ||
554 | } | ||
555 | } | ||
556 | |||
557 | /* ------ routines to save and restore canvases (patches) recursively. ----*/ | ||
558 | |||
559 | /* save to a binbuf, called recursively; cf. canvas_savetofile() which | ||
560 | saves the document, and is only called on root canvases. */ | ||
561 | static void canvas_saveto(t_canvas *x, t_binbuf *b) | ||
562 | { | ||
563 | t_gobj *y; | ||
564 | t_linetraverser t; | ||
565 | t_outconnect *oc; | ||
566 | /* subpatch */ | ||
567 | if (x->gl_owner && !x->gl_env) | ||
568 | { | ||
569 | binbuf_addv(b, "ssiiiisi;", gensym("#N"), gensym("canvas"), | ||
570 | (t_int)(x->gl_screenx1), | ||
571 | (t_int)(x->gl_screeny1), | ||
572 | (t_int)(x->gl_screenx2 - x->gl_screenx1), | ||
573 | (t_int)(x->gl_screeny2 - x->gl_screeny1), | ||
574 | (*x->gl_name->s_name ? x->gl_name: gensym("(subpatch)")), | ||
575 | x->gl_mapped); | ||
576 | } | ||
577 | /* root or abstraction */ | ||
578 | else binbuf_addv(b, "ssiiiii;", gensym("#N"), gensym("canvas"), | ||
579 | (t_int)(x->gl_screenx1), | ||
580 | (t_int)(x->gl_screeny1), | ||
581 | (t_int)(x->gl_screenx2 - x->gl_screenx1), | ||
582 | (t_int)(x->gl_screeny2 - x->gl_screeny1), | ||
583 | x->gl_font); | ||
584 | |||
585 | for (y = x->gl_list; y; y = y->g_next) | ||
586 | gobj_save(y, b); | ||
587 | |||
588 | linetraverser_start(&t, x); | ||
589 | while (oc = linetraverser_next(&t)) | ||
590 | { | ||
591 | int srcno = canvas_getindex(x, &t.tr_ob->ob_g); | ||
592 | int sinkno = canvas_getindex(x, &t.tr_ob2->ob_g); | ||
593 | binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"), | ||
594 | srcno, t.tr_outno, sinkno, t.tr_inno); | ||
595 | } | ||
596 | /* unless everything is the default (as in ordinary subpatches) | ||
597 | print out a "coords" message to set up the coordinate systems */ | ||
598 | if (x->gl_isgraph || x->gl_x1 || x->gl_y1 || | ||
599 | x->gl_x2 != 1 || x->gl_y2 != 1 || x->gl_pixwidth || x->gl_pixheight) | ||
600 | binbuf_addv(b, "ssfffffff;", gensym("#X"), gensym("coords"), | ||
601 | x->gl_x1, x->gl_y1, | ||
602 | x->gl_x2, x->gl_y2, | ||
603 | (float)x->gl_pixwidth, (float)x->gl_pixheight, | ||
604 | (float)x->gl_isgraph); | ||
605 | } | ||
606 | |||
607 | /* call this recursively to collect all the template names for | ||
608 | a canvas or for the selection. */ | ||
609 | static void canvas_collecttemplatesfor(t_canvas *x, int *ntemplatesp, | ||
610 | t_symbol ***templatevecp, int wholething) | ||
611 | { | ||
612 | t_gobj *y; | ||
613 | |||
614 | for (y = x->gl_list; y; y = y->g_next) | ||
615 | { | ||
616 | if ((pd_class(&y->g_pd) == scalar_class) && | ||
617 | (wholething || glist_isselected(x, y))) | ||
618 | canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template, | ||
619 | ((t_scalar *)y)->sc_vec, ntemplatesp, templatevecp); | ||
620 | else if ((pd_class(&y->g_pd) == canvas_class) && | ||
621 | (wholething || glist_isselected(x, y))) | ||
622 | canvas_collecttemplatesfor((t_canvas *)y, | ||
623 | ntemplatesp, templatevecp, 1); | ||
624 | } | ||
625 | } | ||
626 | |||
627 | /* save the templates needed by a canvas to a binbuf. */ | ||
628 | static void canvas_savetemplatesto(t_canvas *x, t_binbuf *b, int wholething) | ||
629 | { | ||
630 | t_symbol **templatevec = getbytes(0); | ||
631 | int i, ntemplates = 0; | ||
632 | t_gobj *y; | ||
633 | canvas_collecttemplatesfor(x, &ntemplates, &templatevec, wholething); | ||
634 | for (i = 0; i < ntemplates; i++) | ||
635 | { | ||
636 | t_template *template = template_findbyname(templatevec[i]); | ||
637 | int j, m = template->t_n; | ||
638 | if (!template) | ||
639 | { | ||
640 | bug("canvas_savetemplatesto"); | ||
641 | continue; | ||
642 | } | ||
643 | /* drop "pd-" prefix from template symbol to print */ | ||
644 | binbuf_addv(b, "sss", &s__N, gensym("struct"), | ||
645 | gensym(templatevec[i]->s_name + 3)); | ||
646 | for (j = 0; j < m; j++) | ||
647 | { | ||
648 | t_symbol *type; | ||
649 | switch (template->t_vec[j].ds_type) | ||
650 | { | ||
651 | case DT_FLOAT: type = &s_float; break; | ||
652 | case DT_SYMBOL: type = &s_symbol; break; | ||
653 | case DT_ARRAY: type = gensym("array"); break; | ||
654 | case DT_LIST: type = &s_list; break; | ||
655 | default: type = &s_float; bug("canvas_write"); | ||
656 | } | ||
657 | if (template->t_vec[j].ds_type == DT_ARRAY) | ||
658 | binbuf_addv(b, "sss", type, template->t_vec[j].ds_name, | ||
659 | gensym(template->t_vec[j].ds_arraytemplate->s_name + 3)); | ||
660 | else binbuf_addv(b, "ss", type, template->t_vec[j].ds_name); | ||
661 | } | ||
662 | binbuf_addsemi(b); | ||
663 | } | ||
664 | } | ||
665 | |||
666 | void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except); | ||
667 | |||
668 | /* save a "root" canvas to a file; cf. canvas_saveto() which saves the | ||
669 | body (and which is called recursively.) */ | ||
670 | static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir) | ||
671 | { | ||
672 | t_binbuf *b = binbuf_new(); | ||
673 | canvas_savetemplatesto(x, b, 1); | ||
674 | canvas_saveto(x, b); | ||
675 | if (binbuf_write(b, filename->s_name, dir->s_name, 0)) sys_ouch(); | ||
676 | else | ||
677 | { | ||
678 | /* if not an abstraction, reset title bar and directory */ | ||
679 | if (!x->gl_owner) | ||
680 | canvas_rename(x, filename, dir); | ||
681 | post("saved to: %s/%s", dir->s_name, filename->s_name); | ||
682 | canvas_dirty(x, 0); | ||
683 | canvas_reload(filename, dir, &x->gl_gobj); | ||
684 | } | ||
685 | binbuf_free(b); | ||
686 | } | ||
687 | |||
688 | static void canvas_menusaveas(t_canvas *x) | ||
689 | { | ||
690 | t_canvas *x2 = canvas_getrootfor(x); | ||
691 | sys_vgui("pdtk_canvas_saveas .x%x \"%s\" \"%s\"\n", x2, | ||
692 | x2->gl_name->s_name, canvas_getdir(x2)->s_name); | ||
693 | } | ||
694 | |||
695 | static void canvas_menusave(t_canvas *x) | ||
696 | { | ||
697 | t_canvas *x2 = canvas_getrootfor(x); | ||
698 | char *name = x2->gl_name->s_name; | ||
699 | if (*name && strncmp(name, "Untitled", 8) | ||
700 | && (strlen(name) < 4 || strcmp(name + strlen(name)-4, ".pat"))) | ||
701 | canvas_savetofile(x2, x2->gl_name, canvas_getdir(x2)); | ||
702 | else canvas_menusaveas(x2); | ||
703 | } | ||
704 | |||
705 | |||
706 | void g_readwrite_setup(void) | ||
707 | { | ||
708 | class_addmethod(canvas_class, (t_method)glist_write, | ||
709 | gensym("write"), A_SYMBOL, A_DEFSYM, A_NULL); | ||
710 | class_addmethod(canvas_class, (t_method)glist_read, | ||
711 | gensym("read"), A_SYMBOL, A_DEFSYM, A_NULL); | ||
712 | class_addmethod(canvas_class, (t_method)glist_mergefile, | ||
713 | gensym("mergefile"), A_SYMBOL, A_DEFSYM, A_NULL); | ||
714 | class_addmethod(canvas_class, (t_method)canvas_savetofile, | ||
715 | gensym("savetofile"), A_SYMBOL, A_SYMBOL, 0); | ||
716 | class_addmethod(canvas_class, (t_method)canvas_saveto, | ||
717 | gensym("saveto"), A_CANT, 0); | ||
718 | /* ------------------ from the menu ------------------------- */ | ||
719 | class_addmethod(canvas_class, (t_method)canvas_menusave, | ||
720 | gensym("menusave"), 0); | ||
721 | class_addmethod(canvas_class, (t_method)canvas_menusaveas, | ||
722 | gensym("menusaveas"), 0); | ||
723 | } | ||
724 | /* Copyright (c) 1997-2002 Miller Puckette and others. | ||
725 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
726 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
727 | |||
728 | /* this file reads and writes the "data" portions of a canvas to a file. | ||
729 | See also canvas_saveto(), etc., in g_editor.c. The data portion is a | ||
730 | collection of "scalar" objects. Routines here can save collections of | ||
731 | scalars into a file and reload them; also, support is included here for | ||
732 | */ | ||
733 | |||
734 | #include <stdlib.h> | ||
735 | #include <stdio.h> | ||
736 | #include "m_pd.h" | ||
737 | #include "g_canvas.h" | ||
738 | #include <string.h> | ||
739 | |||
740 | /* the following routines read "scalars" from a file into a canvas. */ | ||
741 | |||
742 | static int canvas_scanbinbuf(int natoms, t_atom *vec, int *p_indexout, | ||
743 | int *p_next) | ||
744 | { | ||
745 | int i, j; | ||
746 | int indexwas = *p_next; | ||
747 | *p_indexout = indexwas; | ||
748 | if (indexwas >= natoms) | ||
749 | return (0); | ||
750 | for (i = indexwas; i < natoms && vec[i].a_type != A_SEMI; i++) | ||
751 | ; | ||
752 | if (i >= natoms) | ||
753 | *p_next = i; | ||
754 | else *p_next = i + 1; | ||
755 | return (i - indexwas); | ||
756 | } | ||
757 | |||
758 | int glist_readscalar(t_glist *x, int natoms, t_atom *vec, | ||
759 | int *p_nextmsg, int selectit); | ||
760 | |||
761 | static void canvas_readerror(int natoms, t_atom *vec, int message, | ||
762 | int nline, char *s) | ||
763 | { | ||
764 | error(s); | ||
765 | startpost("line was:"); | ||
766 | postatom(nline, vec + message); | ||
767 | endpost(); | ||
768 | } | ||
769 | |||
770 | /* fill in the contents of the scalar into the vector w. */ | ||
771 | |||
772 | static void glist_readatoms(t_glist *x, int natoms, t_atom *vec, | ||
773 | int *p_nextmsg, t_symbol *templatesym, t_word *w, int argc, t_atom *argv) | ||
774 | { | ||
775 | int message, nline, n, i; | ||
776 | |||
777 | t_template *template = template_findbyname(templatesym); | ||
778 | if (!template) | ||
779 | { | ||
780 | error("%s: no such template", templatesym->s_name); | ||
781 | *p_nextmsg = natoms; | ||
782 | return; | ||
783 | } | ||
784 | word_restore(w, template, argc, argv); | ||
785 | n = template->t_n; | ||
786 | for (i = 0; i < n; i++) | ||
787 | { | ||
788 | if (template->t_vec[i].ds_type == DT_ARRAY) | ||
789 | { | ||
790 | int j; | ||
791 | t_array *a = w[i].w_array; | ||
792 | int elemsize = a->a_elemsize, nitems = 0; | ||
793 | t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate; | ||
794 | t_template *arraytemplate = | ||
795 | template_findbyname(arraytemplatesym); | ||
796 | if (!arraytemplate) | ||
797 | { | ||
798 | error("%s: no such template", arraytemplatesym->s_name); | ||
799 | } | ||
800 | else while (1) | ||
801 | { | ||
802 | t_word *element; | ||
803 | int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg); | ||
804 | /* empty line terminates array */ | ||
805 | if (!nline) | ||
806 | break; | ||
807 | array_resize(a, arraytemplate, nitems + 1); | ||
808 | element = (t_word *)(((char *)a->a_vec) + | ||
809 | nitems * elemsize); | ||
810 | glist_readatoms(x, natoms, vec, p_nextmsg, arraytemplatesym, | ||
811 | element, nline, vec + message); | ||
812 | nitems++; | ||
813 | } | ||
814 | } | ||
815 | else if (template->t_vec[i].ds_type == DT_LIST) | ||
816 | { | ||
817 | while (1) | ||
818 | { | ||
819 | if (!glist_readscalar(w->w_list, natoms, vec, | ||
820 | p_nextmsg, 0)) | ||
821 | break; | ||
822 | } | ||
823 | } | ||
824 | } | ||
825 | } | ||
826 | |||
827 | int glist_readscalar(t_glist *x, int natoms, t_atom *vec, | ||
828 | int *p_nextmsg, int selectit) | ||
829 | { | ||
830 | int message, i, j, nline; | ||
831 | t_template *template; | ||
832 | t_symbol *templatesym; | ||
833 | t_scalar *sc; | ||
834 | int nextmsg = *p_nextmsg; | ||
835 | int wasvis = glist_isvisible(x); | ||
836 | |||
837 | if (nextmsg >= natoms || vec[nextmsg].a_type != A_SYMBOL) | ||
838 | { | ||
839 | if (nextmsg < natoms) | ||
840 | post("stopping early: type %d", vec[nextmsg].a_type); | ||
841 | *p_nextmsg = natoms; | ||
842 | return (0); | ||
843 | } | ||
844 | templatesym = canvas_makebindsym(vec[nextmsg].a_w.w_symbol); | ||
845 | *p_nextmsg = nextmsg + 1; | ||
846 | |||
847 | if (!(template = template_findbyname(templatesym))) | ||
848 | { | ||
849 | error("canvas_read: %s: no such template", templatesym->s_name); | ||
850 | *p_nextmsg = natoms; | ||
851 | return (0); | ||
852 | } | ||
853 | sc = scalar_new(x, templatesym); | ||
854 | if (!sc) | ||
855 | { | ||
856 | error("couldn't create scalar \"%s\"", templatesym->s_name); | ||
857 | *p_nextmsg = natoms; | ||
858 | return (0); | ||
859 | } | ||
860 | if (wasvis) | ||
861 | { | ||
862 | /* temporarily lie about vis flag while this is built */ | ||
863 | glist_getcanvas(x)->gl_mapped = 0; | ||
864 | } | ||
865 | glist_add(x, &sc->sc_gobj); | ||
866 | |||
867 | nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg); | ||
868 | glist_readatoms(x, natoms, vec, p_nextmsg, templatesym, sc->sc_vec, | ||
869 | nline, vec + message); | ||
870 | if (wasvis) | ||
871 | { | ||
872 | /* reset vis flag as before */ | ||
873 | glist_getcanvas(x)->gl_mapped = 1; | ||
874 | gobj_vis(&sc->sc_gobj, x, 1); | ||
875 | } | ||
876 | if (selectit) | ||
877 | { | ||
878 | glist_select(x, &sc->sc_gobj); | ||
879 | } | ||
880 | return (1); | ||
881 | } | ||
882 | |||
883 | void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename, int selectem) | ||
884 | { | ||
885 | t_canvas *canvas = glist_getcanvas(x); | ||
886 | int cr = 0, natoms, nline, message, nextmsg = 0, i, j, nitems; | ||
887 | t_atom *vec; | ||
888 | t_gobj *gobj; | ||
889 | |||
890 | natoms = binbuf_getnatom(b); | ||
891 | vec = binbuf_getvec(b); | ||
892 | |||
893 | |||
894 | /* check for file type */ | ||
895 | nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); | ||
896 | if (nline != 1 && vec[message].a_type != A_SYMBOL && | ||
897 | strcmp(vec[message].a_w.w_symbol->s_name, "data")) | ||
898 | { | ||
899 | pd_error(x, "%s: file apparently of wrong type", filename); | ||
900 | binbuf_free(b); | ||
901 | return; | ||
902 | } | ||
903 | /* read in templates and check for consistency */ | ||
904 | while (1) | ||
905 | { | ||
906 | t_template *newtemplate, *existtemplate; | ||
907 | t_symbol *templatesym; | ||
908 | t_atom *templateargs = getbytes(0); | ||
909 | int ntemplateargs = 0, newnargs; | ||
910 | nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); | ||
911 | if (nline < 2) | ||
912 | break; | ||
913 | else if (nline > 2) | ||
914 | canvas_readerror(natoms, vec, message, nline, | ||
915 | "extra items ignored"); | ||
916 | else if (vec[message].a_type != A_SYMBOL || | ||
917 | strcmp(vec[message].a_w.w_symbol->s_name, "template") || | ||
918 | vec[message + 1].a_type != A_SYMBOL) | ||
919 | { | ||
920 | canvas_readerror(natoms, vec, message, nline, | ||
921 | "bad template header"); | ||
922 | continue; | ||
923 | } | ||
924 | templatesym = canvas_makebindsym(vec[message + 1].a_w.w_symbol); | ||
925 | while (1) | ||
926 | { | ||
927 | nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); | ||
928 | if (nline != 2 && nline != 3) | ||
929 | break; | ||
930 | newnargs = ntemplateargs + nline; | ||
931 | templateargs = (t_atom *)t_resizebytes(templateargs, | ||
932 | sizeof(*templateargs) * ntemplateargs, | ||
933 | sizeof(*templateargs) * newnargs); | ||
934 | templateargs[ntemplateargs] = vec[message]; | ||
935 | templateargs[ntemplateargs + 1] = vec[message + 1]; | ||
936 | if (nline == 3) | ||
937 | templateargs[ntemplateargs + 2] = vec[message + 2]; | ||
938 | ntemplateargs = newnargs; | ||
939 | } | ||
940 | newtemplate = template_new(templatesym, ntemplateargs, templateargs); | ||
941 | t_freebytes(templateargs, sizeof (*templateargs) * ntemplateargs); | ||
942 | if (!(existtemplate = template_findbyname(templatesym))) | ||
943 | { | ||
944 | error("%s: template not found in current patch", | ||
945 | templatesym->s_name); | ||
946 | template_free(newtemplate); | ||
947 | return; | ||
948 | } | ||
949 | if (!template_match(existtemplate, newtemplate)) | ||
950 | { | ||
951 | error("%s: template doesn't match current one", | ||
952 | templatesym->s_name); | ||
953 | template_free(newtemplate); | ||
954 | return; | ||
955 | } | ||
956 | template_free(newtemplate); | ||
957 | } | ||
958 | while (nextmsg < natoms) | ||
959 | { | ||
960 | glist_readscalar(x, natoms, vec, &nextmsg, selectem); | ||
961 | } | ||
962 | } | ||
963 | |||
964 | static void glist_doread(t_glist *x, t_symbol *filename, t_symbol *format, | ||
965 | int clearme) | ||
966 | { | ||
967 | t_binbuf *b = binbuf_new(); | ||
968 | t_canvas *canvas = glist_getcanvas(x); | ||
969 | int wasvis = glist_isvisible(canvas); | ||
970 | int cr = 0, natoms, nline, message, nextmsg = 0, i, j; | ||
971 | t_atom *vec; | ||
972 | |||
973 | if (!strcmp(format->s_name, "cr")) | ||
974 | cr = 1; | ||
975 | else if (*format->s_name) | ||
976 | error("qlist_read: unknown flag: %s", format->s_name); | ||
977 | |||
978 | if (binbuf_read_via_path(b, filename->s_name, | ||
979 | canvas_getdir(canvas)->s_name, cr)) | ||
980 | { | ||
981 | pd_error(x, "read failed"); | ||
982 | binbuf_free(b); | ||
983 | return; | ||
984 | } | ||
985 | if (wasvis) | ||
986 | canvas_vis(canvas, 0); | ||
987 | if (clearme) | ||
988 | glist_clear(x); | ||
989 | glist_readfrombinbuf(x, b, filename->s_name, 0); | ||
990 | if (wasvis) | ||
991 | canvas_vis(canvas, 1); | ||
992 | binbuf_free(b); | ||
993 | } | ||
994 | |||
995 | void glist_read(t_glist *x, t_symbol *filename, t_symbol *format) | ||
996 | { | ||
997 | glist_doread(x, filename, format, 1); | ||
998 | } | ||
999 | |||
1000 | void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format) | ||
1001 | { | ||
1002 | glist_doread(x, filename, format, 0); | ||
1003 | } | ||
1004 | |||
1005 | /* read text from a "properties" window, called from a gfxstub set | ||
1006 | up in scalar_properties(). We try to restore the object; if successful | ||
1007 | we delete the scalar and put the new thing in its place on the list. */ | ||
1008 | void canvas_dataproperties(t_canvas *x, t_scalar *sc, t_binbuf *b) | ||
1009 | { | ||
1010 | int ntotal, nnew, scindex; | ||
1011 | t_gobj *y, *y2 = 0, *newone, *oldone = 0; | ||
1012 | for (y = x->gl_list, ntotal = 0, scindex = -1; y; y = y->g_next) | ||
1013 | { | ||
1014 | if (y == &sc->sc_gobj) | ||
1015 | scindex = ntotal, oldone = y; | ||
1016 | ntotal++; | ||
1017 | } | ||
1018 | |||
1019 | if (scindex == -1) | ||
1020 | bug("data_properties: scalar disappeared"); | ||
1021 | glist_readfrombinbuf(x, b, "properties dialog", 0); | ||
1022 | newone = 0; | ||
1023 | if (scindex >= 0) | ||
1024 | { | ||
1025 | /* take the new object off the list */ | ||
1026 | if (ntotal) | ||
1027 | { | ||
1028 | for (y = x->gl_list, nnew = 1; y2 = y->g_next; | ||
1029 | y = y2, nnew++) | ||
1030 | if (nnew == ntotal) | ||
1031 | { | ||
1032 | newone = y2; | ||
1033 | y->g_next = y2->g_next; | ||
1034 | break; | ||
1035 | } | ||
1036 | } | ||
1037 | else newone = x->gl_list, x->gl_list = newone->g_next; | ||
1038 | } | ||
1039 | if (!newone) | ||
1040 | error("couldn't update properties (perhaps a format problem?)"); | ||
1041 | else if (!oldone) | ||
1042 | bug("data_properties: couldn't find old element"); | ||
1043 | else | ||
1044 | { | ||
1045 | glist_delete(x, oldone); | ||
1046 | if (scindex > 0) | ||
1047 | { | ||
1048 | for (y = x->gl_list, nnew = 1; y; | ||
1049 | y = y->g_next, nnew++) | ||
1050 | if (nnew == scindex || !y->g_next) | ||
1051 | { | ||
1052 | newone->g_next = y->g_next; | ||
1053 | y->g_next = newone; | ||
1054 | goto didit; | ||
1055 | } | ||
1056 | bug("data_properties: can't reinsert"); | ||
1057 | } | ||
1058 | else newone->g_next = x->gl_list, x->gl_list = newone; | ||
1059 | } | ||
1060 | didit: | ||
1061 | ; | ||
1062 | } | ||
1063 | |||
1064 | /* ----------- routines to write data to a binbuf ----------- */ | ||
1065 | |||
1066 | void canvas_doaddtemplate(t_symbol *templatesym, | ||
1067 | int *p_ntemplates, t_symbol ***p_templatevec) | ||
1068 | { | ||
1069 | int n = *p_ntemplates, i; | ||
1070 | t_symbol **templatevec = *p_templatevec; | ||
1071 | for (i = 0; i < n; i++) | ||
1072 | if (templatevec[i] == templatesym) | ||
1073 | return; | ||
1074 | templatevec = (t_symbol **)t_resizebytes(templatevec, | ||
1075 | n * sizeof(*templatevec), (n+1) * sizeof(*templatevec)); | ||
1076 | templatevec[n] = templatesym; | ||
1077 | *p_templatevec = templatevec; | ||
1078 | *p_ntemplates = n+1; | ||
1079 | } | ||
1080 | |||
1081 | static void glist_writelist(t_gobj *y, t_binbuf *b); | ||
1082 | |||
1083 | void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b, | ||
1084 | int amarrayelement) | ||
1085 | { | ||
1086 | t_dataslot *ds; | ||
1087 | t_template *template = template_findbyname(templatesym); | ||
1088 | t_atom *a = (t_atom *)t_getbytes(0); | ||
1089 | int i, n = template->t_n, natom = 0; | ||
1090 | if (!amarrayelement) | ||
1091 | { | ||
1092 | t_atom templatename; | ||
1093 | SETSYMBOL(&templatename, gensym(templatesym->s_name + 3)); | ||
1094 | binbuf_add(b, 1, &templatename); | ||
1095 | } | ||
1096 | if (!template) | ||
1097 | bug("canvas_writescalar"); | ||
1098 | /* write the atoms (floats and symbols) */ | ||
1099 | for (i = 0; i < n; i++) | ||
1100 | { | ||
1101 | if (template->t_vec[i].ds_type == DT_FLOAT || | ||
1102 | template->t_vec[i].ds_type == DT_SYMBOL) | ||
1103 | { | ||
1104 | a = (t_atom *)t_resizebytes(a, | ||
1105 | natom * sizeof(*a), (natom + 1) * sizeof (*a)); | ||
1106 | if (template->t_vec[i].ds_type == DT_FLOAT) | ||
1107 | SETFLOAT(a + natom, w[i].w_float); | ||
1108 | else SETSYMBOL(a + natom, w[i].w_symbol); | ||
1109 | natom++; | ||
1110 | } | ||
1111 | } | ||
1112 | /* array elements have to have at least something */ | ||
1113 | if (natom == 0 && amarrayelement) | ||
1114 | SETSYMBOL(a + natom, &s_bang), natom++; | ||
1115 | binbuf_add(b, natom, a); | ||
1116 | binbuf_addsemi(b); | ||
1117 | t_freebytes(a, natom * sizeof(*a)); | ||
1118 | for (i = 0; i < n; i++) | ||
1119 | { | ||
1120 | if (template->t_vec[i].ds_type == DT_ARRAY) | ||
1121 | { | ||
1122 | int j; | ||
1123 | t_array *a = w[i].w_array; | ||
1124 | int elemsize = a->a_elemsize, nitems = a->a_n; | ||
1125 | t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate; | ||
1126 | for (j = 0; j < nitems; j++) | ||
1127 | canvas_writescalar(arraytemplatesym, | ||
1128 | (t_word *)(((char *)a->a_vec) + elemsize * j), b, 1); | ||
1129 | binbuf_addsemi(b); | ||
1130 | } | ||
1131 | else if (template->t_vec[i].ds_type == DT_LIST) | ||
1132 | { | ||
1133 | glist_writelist(w->w_list->gl_list, b); | ||
1134 | binbuf_addsemi(b); | ||
1135 | } | ||
1136 | } | ||
1137 | } | ||
1138 | |||
1139 | static void glist_writelist(t_gobj *y, t_binbuf *b) | ||
1140 | { | ||
1141 | for (; y; y = y->g_next) | ||
1142 | { | ||
1143 | if (pd_class(&y->g_pd) == scalar_class) | ||
1144 | { | ||
1145 | canvas_writescalar(((t_scalar *)y)->sc_template, | ||
1146 | ((t_scalar *)y)->sc_vec, b, 0); | ||
1147 | } | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | /* ------------ routines to write out templates for data ------- */ | ||
1152 | |||
1153 | static void canvas_addtemplatesforlist(t_gobj *y, | ||
1154 | int *p_ntemplates, t_symbol ***p_templatevec); | ||
1155 | |||
1156 | static void canvas_addtemplatesforscalar(t_symbol *templatesym, | ||
1157 | t_word *w, int *p_ntemplates, t_symbol ***p_templatevec) | ||
1158 | { | ||
1159 | t_dataslot *ds; | ||
1160 | int i; | ||
1161 | t_template *template = template_findbyname(templatesym); | ||
1162 | canvas_doaddtemplate(templatesym, p_ntemplates, p_templatevec); | ||
1163 | if (!template) | ||
1164 | bug("canvas_addtemplatesforscalar"); | ||
1165 | else for (ds = template->t_vec, i = template->t_n; i--; ds++, w++) | ||
1166 | { | ||
1167 | if (ds->ds_type == DT_ARRAY) | ||
1168 | { | ||
1169 | int j; | ||
1170 | t_array *a = w->w_array; | ||
1171 | int elemsize = a->a_elemsize, nitems = a->a_n; | ||
1172 | t_symbol *arraytemplatesym = ds->ds_arraytemplate; | ||
1173 | canvas_doaddtemplate(arraytemplatesym, p_ntemplates, p_templatevec); | ||
1174 | for (j = 0; j < nitems; j++) | ||
1175 | canvas_addtemplatesforscalar(arraytemplatesym, | ||
1176 | (t_word *)(((char *)a->a_vec) + elemsize * j), | ||
1177 | p_ntemplates, p_templatevec); | ||
1178 | } | ||
1179 | else if (ds->ds_type == DT_LIST) | ||
1180 | canvas_addtemplatesforlist(w->w_list->gl_list, | ||
1181 | p_ntemplates, p_templatevec); | ||
1182 | } | ||
1183 | } | ||
1184 | |||
1185 | static void canvas_addtemplatesforlist(t_gobj *y, | ||
1186 | int *p_ntemplates, t_symbol ***p_templatevec) | ||
1187 | { | ||
1188 | for (; y; y = y->g_next) | ||
1189 | { | ||
1190 | if (pd_class(&y->g_pd) == scalar_class) | ||
1191 | { | ||
1192 | canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template, | ||
1193 | ((t_scalar *)y)->sc_vec, p_ntemplates, p_templatevec); | ||
1194 | } | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | /* write all "scalars" in a glist to a binbuf. */ | ||
1199 | t_binbuf *glist_writetobinbuf(t_glist *x, int wholething) | ||
1200 | { | ||
1201 | int i; | ||
1202 | t_symbol **templatevec = getbytes(0); | ||
1203 | int ntemplates = 0; | ||
1204 | t_gobj *y; | ||
1205 | t_binbuf *b = binbuf_new(); | ||
1206 | |||
1207 | for (y = x->gl_list; y; y = y->g_next) | ||
1208 | { | ||
1209 | if ((pd_class(&y->g_pd) == scalar_class) && | ||
1210 | (wholething || glist_isselected(x, y))) | ||
1211 | { | ||
1212 | canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template, | ||
1213 | ((t_scalar *)y)->sc_vec, &ntemplates, &templatevec); | ||
1214 | } | ||
1215 | } | ||
1216 | binbuf_addv(b, "s;", gensym("data")); | ||
1217 | for (i = 0; i < ntemplates; i++) | ||
1218 | { | ||
1219 | t_template *template = template_findbyname(templatevec[i]); | ||
1220 | int j, m = template->t_n; | ||
1221 | /* drop "pd-" prefix from template symbol to print it: */ | ||
1222 | binbuf_addv(b, "ss;", gensym("template"), | ||
1223 | gensym(templatevec[i]->s_name + 3)); | ||
1224 | for (j = 0; j < m; j++) | ||
1225 | { | ||
1226 | t_symbol *type; | ||
1227 | switch (template->t_vec[j].ds_type) | ||
1228 | { | ||
1229 | case DT_FLOAT: type = &s_float; break; | ||
1230 | case DT_SYMBOL: type = &s_symbol; break; | ||
1231 | case DT_ARRAY: type = gensym("array"); break; | ||
1232 | case DT_LIST: type = &s_list; break; | ||
1233 | default: type = &s_float; bug("canvas_write"); | ||
1234 | } | ||
1235 | if (template->t_vec[j].ds_type == DT_ARRAY) | ||
1236 | binbuf_addv(b, "sss;", type, template->t_vec[j].ds_name, | ||
1237 | gensym(template->t_vec[j].ds_arraytemplate->s_name + 3)); | ||
1238 | else binbuf_addv(b, "ss;", type, template->t_vec[j].ds_name); | ||
1239 | } | ||
1240 | binbuf_addsemi(b); | ||
1241 | } | ||
1242 | binbuf_addsemi(b); | ||
1243 | /* now write out the objects themselves */ | ||
1244 | for (y = x->gl_list; y; y = y->g_next) | ||
1245 | { | ||
1246 | if ((pd_class(&y->g_pd) == scalar_class) && | ||
1247 | (wholething || glist_isselected(x, y))) | ||
1248 | { | ||
1249 | canvas_writescalar(((t_scalar *)y)->sc_template, | ||
1250 | ((t_scalar *)y)->sc_vec, b, 0); | ||
1251 | } | ||
1252 | } | ||
1253 | return (b); | ||
1254 | } | ||
1255 | |||
1256 | static void glist_write(t_glist *x, t_symbol *filename, t_symbol *format) | ||
1257 | { | ||
1258 | int cr = 0, i; | ||
1259 | t_binbuf *b; | ||
1260 | char buf[MAXPDSTRING]; | ||
1261 | t_symbol **templatevec = getbytes(0); | ||
1262 | int ntemplates = 0; | ||
1263 | t_gobj *y; | ||
1264 | t_canvas *canvas = glist_getcanvas(x); | ||
1265 | canvas_makefilename(canvas, filename->s_name, buf, MAXPDSTRING); | ||
1266 | if (!strcmp(format->s_name, "cr")) | ||
1267 | cr = 1; | ||
1268 | else if (*format->s_name) | ||
1269 | error("qlist_read: unknown flag: %s", format->s_name); | ||
1270 | |||
1271 | b = glist_writetobinbuf(x, 1); | ||
1272 | if (b) | ||
1273 | { | ||
1274 | if (binbuf_write(b, buf, "", cr)) | ||
1275 | error("%s: write failed", filename->s_name); | ||
1276 | binbuf_free(b); | ||
1277 | } | ||
1278 | } | ||
1279 | |||
1280 | /* ------ routines to save and restore canvases (patches) recursively. ----*/ | ||
1281 | |||
1282 | /* save to a binbuf, called recursively; cf. canvas_savetofile() which | ||
1283 | saves the document, and is only called on root canvases. */ | ||
1284 | static void canvas_saveto(t_canvas *x, t_binbuf *b) | ||
1285 | { | ||
1286 | t_gobj *y; | ||
1287 | t_linetraverser t; | ||
1288 | t_outconnect *oc; | ||
1289 | /* subpatch */ | ||
1290 | if (x->gl_owner && !x->gl_env) | ||
1291 | { | ||
1292 | binbuf_addv(b, "ssiiiisi;", gensym("#N"), gensym("canvas"), | ||
1293 | (t_int)(x->gl_screenx1), | ||
1294 | (t_int)(x->gl_screeny1), | ||
1295 | (t_int)(x->gl_screenx2 - x->gl_screenx1), | ||
1296 | (t_int)(x->gl_screeny2 - x->gl_screeny1), | ||
1297 | (*x->gl_name->s_name ? x->gl_name: gensym("(subpatch)")), | ||
1298 | x->gl_mapped); | ||
1299 | } | ||
1300 | /* root or abstraction */ | ||
1301 | else binbuf_addv(b, "ssiiiii;", gensym("#N"), gensym("canvas"), | ||
1302 | (t_int)(x->gl_screenx1), | ||
1303 | (t_int)(x->gl_screeny1), | ||
1304 | (t_int)(x->gl_screenx2 - x->gl_screenx1), | ||
1305 | (t_int)(x->gl_screeny2 - x->gl_screeny1), | ||
1306 | x->gl_font); | ||
1307 | |||
1308 | for (y = x->gl_list; y; y = y->g_next) | ||
1309 | gobj_save(y, b); | ||
1310 | |||
1311 | linetraverser_start(&t, x); | ||
1312 | while (oc = linetraverser_next(&t)) | ||
1313 | { | ||
1314 | int srcno = canvas_getindex(x, &t.tr_ob->ob_g); | ||
1315 | int sinkno = canvas_getindex(x, &t.tr_ob2->ob_g); | ||
1316 | binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"), | ||
1317 | srcno, t.tr_outno, sinkno, t.tr_inno); | ||
1318 | } | ||
1319 | /* unless everything is the default (as in ordinary subpatches) | ||
1320 | print out a "coords" message to set up the coordinate systems */ | ||
1321 | if (x->gl_isgraph || x->gl_x1 || x->gl_y1 || | ||
1322 | x->gl_x2 != 1 || x->gl_y2 != 1 || x->gl_pixwidth || x->gl_pixheight) | ||
1323 | binbuf_addv(b, "ssfffffff;", gensym("#X"), gensym("coords"), | ||
1324 | x->gl_x1, x->gl_y1, | ||
1325 | x->gl_x2, x->gl_y2, | ||
1326 | (float)x->gl_pixwidth, (float)x->gl_pixheight, | ||
1327 | (float)x->gl_isgraph); | ||
1328 | } | ||
1329 | |||
1330 | /* call this recursively to collect all the template names for | ||
1331 | a canvas or for the selection. */ | ||
1332 | static void canvas_collecttemplatesfor(t_canvas *x, int *ntemplatesp, | ||
1333 | t_symbol ***templatevecp, int wholething) | ||
1334 | { | ||
1335 | t_gobj *y; | ||
1336 | |||
1337 | for (y = x->gl_list; y; y = y->g_next) | ||
1338 | { | ||
1339 | if ((pd_class(&y->g_pd) == scalar_class) && | ||
1340 | (wholething || glist_isselected(x, y))) | ||
1341 | canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template, | ||
1342 | ((t_scalar *)y)->sc_vec, ntemplatesp, templatevecp); | ||
1343 | else if ((pd_class(&y->g_pd) == canvas_class) && | ||
1344 | (wholething || glist_isselected(x, y))) | ||
1345 | canvas_collecttemplatesfor((t_canvas *)y, | ||
1346 | ntemplatesp, templatevecp, 1); | ||
1347 | } | ||
1348 | } | ||
1349 | |||
1350 | /* save the templates needed by a canvas to a binbuf. */ | ||
1351 | static void canvas_savetemplatesto(t_canvas *x, t_binbuf *b, int wholething) | ||
1352 | { | ||
1353 | t_symbol **templatevec = getbytes(0); | ||
1354 | int i, ntemplates = 0; | ||
1355 | t_gobj *y; | ||
1356 | canvas_collecttemplatesfor(x, &ntemplates, &templatevec, wholething); | ||
1357 | for (i = 0; i < ntemplates; i++) | ||
1358 | { | ||
1359 | t_template *template = template_findbyname(templatevec[i]); | ||
1360 | int j, m = template->t_n; | ||
1361 | if (!template) | ||
1362 | { | ||
1363 | bug("canvas_savetemplatesto"); | ||
1364 | continue; | ||
1365 | } | ||
1366 | /* drop "pd-" prefix from template symbol to print */ | ||
1367 | binbuf_addv(b, "sss", &s__N, gensym("struct"), | ||
1368 | gensym(templatevec[i]->s_name + 3)); | ||
1369 | for (j = 0; j < m; j++) | ||
1370 | { | ||
1371 | t_symbol *type; | ||
1372 | switch (template->t_vec[j].ds_type) | ||
1373 | { | ||
1374 | case DT_FLOAT: type = &s_float; break; | ||
1375 | case DT_SYMBOL: type = &s_symbol; break; | ||
1376 | case DT_ARRAY: type = gensym("array"); break; | ||
1377 | case DT_LIST: type = &s_list; break; | ||
1378 | default: type = &s_float; bug("canvas_write"); | ||
1379 | } | ||
1380 | if (template->t_vec[j].ds_type == DT_ARRAY) | ||
1381 | binbuf_addv(b, "sss", type, template->t_vec[j].ds_name, | ||
1382 | gensym(template->t_vec[j].ds_arraytemplate->s_name + 3)); | ||
1383 | else binbuf_addv(b, "ss", type, template->t_vec[j].ds_name); | ||
1384 | } | ||
1385 | binbuf_addsemi(b); | ||
1386 | } | ||
1387 | } | ||
1388 | |||
1389 | void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except); | ||
1390 | |||
1391 | /* save a "root" canvas to a file; cf. canvas_saveto() which saves the | ||
1392 | body (and which is called recursively.) */ | ||
1393 | static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir) | ||
1394 | { | ||
1395 | t_binbuf *b = binbuf_new(); | ||
1396 | canvas_savetemplatesto(x, b, 1); | ||
1397 | canvas_saveto(x, b); | ||
1398 | if (binbuf_write(b, filename->s_name, dir->s_name, 0)) sys_ouch(); | ||
1399 | else | ||
1400 | { | ||
1401 | /* if not an abstraction, reset title bar and directory */ | ||
1402 | if (!x->gl_owner) | ||
1403 | canvas_rename(x, filename, dir); | ||
1404 | post("saved to: %s/%s", dir->s_name, filename->s_name); | ||
1405 | canvas_dirty(x, 0); | ||
1406 | canvas_reload(filename, dir, &x->gl_gobj); | ||
1407 | } | ||
1408 | binbuf_free(b); | ||
1409 | } | ||
1410 | |||
1411 | static void canvas_menusaveas(t_canvas *x) | ||
1412 | { | ||
1413 | t_canvas *x2 = canvas_getrootfor(x); | ||
1414 | sys_vgui("pdtk_canvas_saveas .x%x \"%s\" \"%s\"\n", x2, | ||
1415 | x2->gl_name->s_name, canvas_getdir(x2)->s_name); | ||
1416 | } | ||
1417 | |||
1418 | static void canvas_menusave(t_canvas *x) | ||
1419 | { | ||
1420 | t_canvas *x2 = canvas_getrootfor(x); | ||
1421 | char *name = x2->gl_name->s_name; | ||
1422 | if (*name && strncmp(name, "Untitled", 8) | ||
1423 | && (strlen(name) < 4 || strcmp(name + strlen(name)-4, ".pat"))) | ||
1424 | canvas_savetofile(x2, x2->gl_name, canvas_getdir(x2)); | ||
1425 | else canvas_menusaveas(x2); | ||
1426 | } | ||
1427 | |||
1428 | |||
1429 | void g_readwrite_setup(void) | ||
1430 | { | ||
1431 | class_addmethod(canvas_class, (t_method)glist_write, | ||
1432 | gensym("write"), A_SYMBOL, A_DEFSYM, A_NULL); | ||
1433 | class_addmethod(canvas_class, (t_method)glist_read, | ||
1434 | gensym("read"), A_SYMBOL, A_DEFSYM, A_NULL); | ||
1435 | class_addmethod(canvas_class, (t_method)glist_mergefile, | ||
1436 | gensym("mergefile"), A_SYMBOL, A_DEFSYM, A_NULL); | ||
1437 | class_addmethod(canvas_class, (t_method)canvas_savetofile, | ||
1438 | gensym("savetofile"), A_SYMBOL, A_SYMBOL, 0); | ||
1439 | class_addmethod(canvas_class, (t_method)canvas_saveto, | ||
1440 | gensym("saveto"), A_CANT, 0); | ||
1441 | /* ------------------ from the menu ------------------------- */ | ||
1442 | class_addmethod(canvas_class, (t_method)canvas_menusave, | ||
1443 | gensym("menusave"), 0); | ||
1444 | class_addmethod(canvas_class, (t_method)canvas_menusaveas, | ||
1445 | gensym("menusaveas"), 0); | ||
1446 | } | ||