A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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.
6See also canvas_saveto(), etc., in g_editor.c. The data portion is a
7collection of "scalar" objects. Routines here can save collections of
8scalars into a file and reload them; also, support is included here for
9*/
10
11#ifdef ROCKBOX
12#include "plugin.h"
13#include "../../pdbox.h"
14#include "m_pd.h"
15#include "g_canvas.h"
16#else /* ROCKBOX */
17#include <stdlib.h>
18#include <stdio.h>
19#include "m_pd.h"
20#include "g_canvas.h"
21#include <string.h>
22#endif /* ROCKBOX */
23
24 /* the following routines read "scalars" from a file into a canvas. */
25
26static int canvas_scanbinbuf(int natoms, t_atom *vec, int *p_indexout,
27 int *p_next)
28{
29#ifdef ROCKBOX
30 int i;
31#else
32 int i, j;
33#endif
34 int indexwas = *p_next;
35 *p_indexout = indexwas;
36 if (indexwas >= natoms)
37 return (0);
38 for (i = indexwas; i < natoms && vec[i].a_type != A_SEMI; i++)
39 ;
40 if (i >= natoms)
41 *p_next = i;
42 else *p_next = i + 1;
43 return (i - indexwas);
44}
45
46int glist_readscalar(t_glist *x, int natoms, t_atom *vec,
47 int *p_nextmsg, int selectit);
48
49static void canvas_readerror(int natoms, t_atom *vec, int message,
50 int nline, char *s)
51{
52#ifdef ROCKBOX
53 (void) natoms;
54#endif
55 error(s);
56 startpost("line was:");
57 postatom(nline, vec + message);
58 endpost();
59}
60
61 /* fill in the contents of the scalar into the vector w. */
62
63static void glist_readatoms(t_glist *x, int natoms, t_atom *vec,
64 int *p_nextmsg, t_symbol *templatesym, t_word *w, int argc, t_atom *argv)
65{
66#ifdef ROCKBOX
67 int message, n, i;
68#else
69 int message, nline, n, i;
70#endif
71
72 t_template *template = template_findbyname(templatesym);
73 if (!template)
74 {
75 error("%s: no such template", templatesym->s_name);
76 *p_nextmsg = natoms;
77 return;
78 }
79 word_restore(w, template, argc, argv);
80 n = template->t_n;
81 for (i = 0; i < n; i++)
82 {
83 if (template->t_vec[i].ds_type == DT_ARRAY)
84 {
85#ifndef ROCKBOX
86 int j;
87#endif
88 t_array *a = w[i].w_array;
89 int elemsize = a->a_elemsize, nitems = 0;
90 t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate;
91 t_template *arraytemplate =
92 template_findbyname(arraytemplatesym);
93 if (!arraytemplate)
94 {
95 error("%s: no such template", arraytemplatesym->s_name);
96 }
97 else while (1)
98 {
99 t_word *element;
100 int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg);
101 /* empty line terminates array */
102 if (!nline)
103 break;
104 array_resize(a, arraytemplate, nitems + 1);
105 element = (t_word *)(((char *)a->a_vec) +
106 nitems * elemsize);
107 glist_readatoms(x, natoms, vec, p_nextmsg, arraytemplatesym,
108 element, nline, vec + message);
109 nitems++;
110 }
111 }
112 else if (template->t_vec[i].ds_type == DT_LIST)
113 {
114 while (1)
115 {
116 if (!glist_readscalar(w->w_list, natoms, vec,
117 p_nextmsg, 0))
118 break;
119 }
120 }
121 }
122}
123
124int glist_readscalar(t_glist *x, int natoms, t_atom *vec,
125 int *p_nextmsg, int selectit)
126{
127#ifdef ROCKBOX
128 int message, nline;
129#else
130 int message, i, j, nline;
131#endif
132 t_template *template;
133 t_symbol *templatesym;
134 t_scalar *sc;
135 int nextmsg = *p_nextmsg;
136 int wasvis = glist_isvisible(x);
137
138 if (nextmsg >= natoms || vec[nextmsg].a_type != A_SYMBOL)
139 {
140 if (nextmsg < natoms)
141 post("stopping early: type %d", vec[nextmsg].a_type);
142 *p_nextmsg = natoms;
143 return (0);
144 }
145 templatesym = canvas_makebindsym(vec[nextmsg].a_w.w_symbol);
146 *p_nextmsg = nextmsg + 1;
147
148 if (!(template = template_findbyname(templatesym)))
149 {
150 error("canvas_read: %s: no such template", templatesym->s_name);
151 *p_nextmsg = natoms;
152 return (0);
153 }
154 sc = scalar_new(x, templatesym);
155 if (!sc)
156 {
157 error("couldn't create scalar \"%s\"", templatesym->s_name);
158 *p_nextmsg = natoms;
159 return (0);
160 }
161 if (wasvis)
162 {
163 /* temporarily lie about vis flag while this is built */
164 glist_getcanvas(x)->gl_mapped = 0;
165 }
166 glist_add(x, &sc->sc_gobj);
167
168 nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg);
169 glist_readatoms(x, natoms, vec, p_nextmsg, templatesym, sc->sc_vec,
170 nline, vec + message);
171 if (wasvis)
172 {
173 /* reset vis flag as before */
174 glist_getcanvas(x)->gl_mapped = 1;
175 gobj_vis(&sc->sc_gobj, x, 1);
176 }
177 if (selectit)
178 {
179 glist_select(x, &sc->sc_gobj);
180 }
181 return (1);
182}
183
184void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename, int selectem)
185{
186#ifdef ROCKBOX
187 int natoms, nline, message, nextmsg = 0;
188#else
189 t_canvas *canvas = glist_getcanvas(x);
190 int cr = 0, natoms, nline, message, nextmsg = 0, i, j, nitems;
191#endif
192 t_atom *vec;
193#ifndef ROCKBOX
194 t_gobj *gobj;
195#endif
196
197 natoms = binbuf_getnatom(b);
198 vec = binbuf_getvec(b);
199
200
201 /* check for file type */
202 nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
203 if (nline != 1 && vec[message].a_type != A_SYMBOL &&
204 strcmp(vec[message].a_w.w_symbol->s_name, "data"))
205 {
206 pd_error(x, "%s: file apparently of wrong type", filename);
207 binbuf_free(b);
208 return;
209 }
210 /* read in templates and check for consistency */
211 while (1)
212 {
213 t_template *newtemplate, *existtemplate;
214 t_symbol *templatesym;
215 t_atom *templateargs = getbytes(0);
216 int ntemplateargs = 0, newnargs;
217 nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
218 if (nline < 2)
219 break;
220 else if (nline > 2)
221 canvas_readerror(natoms, vec, message, nline,
222 "extra items ignored");
223 else if (vec[message].a_type != A_SYMBOL ||
224 strcmp(vec[message].a_w.w_symbol->s_name, "template") ||
225 vec[message + 1].a_type != A_SYMBOL)
226 {
227 canvas_readerror(natoms, vec, message, nline,
228 "bad template header");
229 continue;
230 }
231 templatesym = canvas_makebindsym(vec[message + 1].a_w.w_symbol);
232 while (1)
233 {
234 nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
235 if (nline != 2 && nline != 3)
236 break;
237 newnargs = ntemplateargs + nline;
238 templateargs = (t_atom *)t_resizebytes(templateargs,
239 sizeof(*templateargs) * ntemplateargs,
240 sizeof(*templateargs) * newnargs);
241 templateargs[ntemplateargs] = vec[message];
242 templateargs[ntemplateargs + 1] = vec[message + 1];
243 if (nline == 3)
244 templateargs[ntemplateargs + 2] = vec[message + 2];
245 ntemplateargs = newnargs;
246 }
247 newtemplate = template_new(templatesym, ntemplateargs, templateargs);
248 t_freebytes(templateargs, sizeof (*templateargs) * ntemplateargs);
249 if (!(existtemplate = template_findbyname(templatesym)))
250 {
251 error("%s: template not found in current patch",
252 templatesym->s_name);
253 template_free(newtemplate);
254 return;
255 }
256 if (!template_match(existtemplate, newtemplate))
257 {
258 error("%s: template doesn't match current one",
259 templatesym->s_name);
260 template_free(newtemplate);
261 return;
262 }
263 template_free(newtemplate);
264 }
265 while (nextmsg < natoms)
266 {
267 glist_readscalar(x, natoms, vec, &nextmsg, selectem);
268 }
269}
270
271static void glist_doread(t_glist *x, t_symbol *filename, t_symbol *format,
272 int clearme)
273{
274 t_binbuf *b = binbuf_new();
275 t_canvas *canvas = glist_getcanvas(x);
276 int wasvis = glist_isvisible(canvas);
277#ifdef ROCKBOX
278 int cr = 0;
279#else
280 int cr = 0, natoms, nline, message, nextmsg = 0, i, j;
281 t_atom *vec;
282#endif
283
284 if (!strcmp(format->s_name, "cr"))
285 cr = 1;
286 else if (*format->s_name)
287 error("qlist_read: unknown flag: %s", format->s_name);
288
289 if (binbuf_read_via_path(b, filename->s_name,
290 canvas_getdir(canvas)->s_name, cr))
291 {
292 pd_error(x, "read failed");
293 binbuf_free(b);
294 return;
295 }
296 if (wasvis)
297 canvas_vis(canvas, 0);
298 if (clearme)
299 glist_clear(x);
300 glist_readfrombinbuf(x, b, filename->s_name, 0);
301 if (wasvis)
302 canvas_vis(canvas, 1);
303 binbuf_free(b);
304}
305
306void glist_read(t_glist *x, t_symbol *filename, t_symbol *format)
307{
308 glist_doread(x, filename, format, 1);
309}
310
311void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format)
312{
313 glist_doread(x, filename, format, 0);
314}
315
316 /* read text from a "properties" window, called from a gfxstub set
317 up in scalar_properties(). We try to restore the object; if successful
318 we delete the scalar and put the new thing in its place on the list. */
319void canvas_dataproperties(t_canvas *x, t_scalar *sc, t_binbuf *b)
320{
321 int ntotal, nnew, scindex;
322 t_gobj *y, *y2 = 0, *newone, *oldone = 0;
323 for (y = x->gl_list, ntotal = 0, scindex = -1; y; y = y->g_next)
324 {
325 if (y == &sc->sc_gobj)
326 scindex = ntotal, oldone = y;
327 ntotal++;
328 }
329
330 if (scindex == -1)
331 bug("data_properties: scalar disappeared");
332 glist_readfrombinbuf(x, b, "properties dialog", 0);
333 newone = 0;
334 if (scindex >= 0)
335 {
336 /* take the new object off the list */
337 if (ntotal)
338 {
339 for(y = x->gl_list, nnew = 1; (y2 = y->g_next);
340 y = y2, nnew++)
341 if (nnew == ntotal)
342 {
343 newone = y2;
344 y->g_next = y2->g_next;
345 break;
346 }
347 }
348 else newone = x->gl_list, x->gl_list = newone->g_next;
349 }
350 if (!newone)
351 error("couldn't update properties (perhaps a format problem?)");
352 else if (!oldone)
353 bug("data_properties: couldn't find old element");
354 else
355 {
356 glist_delete(x, oldone);
357 if (scindex > 0)
358 {
359 for (y = x->gl_list, nnew = 1; y;
360 y = y->g_next, nnew++)
361 if (nnew == scindex || !y->g_next)
362 {
363 newone->g_next = y->g_next;
364 y->g_next = newone;
365 goto didit;
366 }
367 bug("data_properties: can't reinsert");
368 }
369 else newone->g_next = x->gl_list, x->gl_list = newone;
370 }
371didit:
372 ;
373}
374
375 /* ----------- routines to write data to a binbuf ----------- */
376
377void canvas_doaddtemplate(t_symbol *templatesym,
378 int *p_ntemplates, t_symbol ***p_templatevec)
379{
380 int n = *p_ntemplates, i;
381 t_symbol **templatevec = *p_templatevec;
382 for (i = 0; i < n; i++)
383 if (templatevec[i] == templatesym)
384 return;
385 templatevec = (t_symbol **)t_resizebytes(templatevec,
386 n * sizeof(*templatevec), (n+1) * sizeof(*templatevec));
387 templatevec[n] = templatesym;
388 *p_templatevec = templatevec;
389 *p_ntemplates = n+1;
390}
391
392static void glist_writelist(t_gobj *y, t_binbuf *b);
393
394void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b,
395 int amarrayelement)
396{
397#ifndef ROCKBOX
398 t_dataslot *ds;
399#endif
400 t_template *template = template_findbyname(templatesym);
401 t_atom *a = (t_atom *)t_getbytes(0);
402 int i, n = template->t_n, natom = 0;
403 if (!amarrayelement)
404 {
405 t_atom templatename;
406 SETSYMBOL(&templatename, gensym(templatesym->s_name + 3));
407 binbuf_add(b, 1, &templatename);
408 }
409 if (!template)
410 bug("canvas_writescalar");
411 /* write the atoms (floats and symbols) */
412 for (i = 0; i < n; i++)
413 {
414 if (template->t_vec[i].ds_type == DT_FLOAT ||
415 template->t_vec[i].ds_type == DT_SYMBOL)
416 {
417 a = (t_atom *)t_resizebytes(a,
418 natom * sizeof(*a), (natom + 1) * sizeof (*a));
419 if (template->t_vec[i].ds_type == DT_FLOAT)
420 SETFLOAT(a + natom, w[i].w_float);
421 else SETSYMBOL(a + natom, w[i].w_symbol);
422 natom++;
423 }
424 }
425 /* array elements have to have at least something */
426 if (natom == 0 && amarrayelement)
427 SETSYMBOL(a + natom, &s_bang), natom++;
428 binbuf_add(b, natom, a);
429 binbuf_addsemi(b);
430 t_freebytes(a, natom * sizeof(*a));
431 for (i = 0; i < n; i++)
432 {
433 if (template->t_vec[i].ds_type == DT_ARRAY)
434 {
435 int j;
436 t_array *a = w[i].w_array;
437 int elemsize = a->a_elemsize, nitems = a->a_n;
438 t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate;
439 for (j = 0; j < nitems; j++)
440 canvas_writescalar(arraytemplatesym,
441 (t_word *)(((char *)a->a_vec) + elemsize * j), b, 1);
442 binbuf_addsemi(b);
443 }
444 else if (template->t_vec[i].ds_type == DT_LIST)
445 {
446 glist_writelist(w->w_list->gl_list, b);
447 binbuf_addsemi(b);
448 }
449 }
450}
451
452static void glist_writelist(t_gobj *y, t_binbuf *b)
453{
454 for (; y; y = y->g_next)
455 {
456 if (pd_class(&y->g_pd) == scalar_class)
457 {
458 canvas_writescalar(((t_scalar *)y)->sc_template,
459 ((t_scalar *)y)->sc_vec, b, 0);
460 }
461 }
462}
463
464 /* ------------ routines to write out templates for data ------- */
465
466static void canvas_addtemplatesforlist(t_gobj *y,
467 int *p_ntemplates, t_symbol ***p_templatevec);
468
469static void canvas_addtemplatesforscalar(t_symbol *templatesym,
470 t_word *w, int *p_ntemplates, t_symbol ***p_templatevec)
471{
472 t_dataslot *ds;
473 int i;
474 t_template *template = template_findbyname(templatesym);
475 canvas_doaddtemplate(templatesym, p_ntemplates, p_templatevec);
476 if (!template)
477 bug("canvas_addtemplatesforscalar");
478 else for (ds = template->t_vec, i = template->t_n; i--; ds++, w++)
479 {
480 if (ds->ds_type == DT_ARRAY)
481 {
482 int j;
483 t_array *a = w->w_array;
484 int elemsize = a->a_elemsize, nitems = a->a_n;
485 t_symbol *arraytemplatesym = ds->ds_arraytemplate;
486 canvas_doaddtemplate(arraytemplatesym, p_ntemplates, p_templatevec);
487 for (j = 0; j < nitems; j++)
488 canvas_addtemplatesforscalar(arraytemplatesym,
489 (t_word *)(((char *)a->a_vec) + elemsize * j),
490 p_ntemplates, p_templatevec);
491 }
492 else if (ds->ds_type == DT_LIST)
493 canvas_addtemplatesforlist(w->w_list->gl_list,
494 p_ntemplates, p_templatevec);
495 }
496}
497
498static void canvas_addtemplatesforlist(t_gobj *y,
499 int *p_ntemplates, t_symbol ***p_templatevec)
500{
501 for (; y; y = y->g_next)
502 {
503 if (pd_class(&y->g_pd) == scalar_class)
504 {
505 canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template,
506 ((t_scalar *)y)->sc_vec, p_ntemplates, p_templatevec);
507 }
508 }
509}
510
511 /* write all "scalars" in a glist to a binbuf. */
512t_binbuf *glist_writetobinbuf(t_glist *x, int wholething)
513{
514 int i;
515 t_symbol **templatevec = getbytes(0);
516 int ntemplates = 0;
517 t_gobj *y;
518 t_binbuf *b = binbuf_new();
519
520 for (y = x->gl_list; y; y = y->g_next)
521 {
522 if ((pd_class(&y->g_pd) == scalar_class) &&
523 (wholething || glist_isselected(x, y)))
524 {
525 canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template,
526 ((t_scalar *)y)->sc_vec, &ntemplates, &templatevec);
527 }
528 }
529 binbuf_addv(b, "s;", gensym("data"));
530 for (i = 0; i < ntemplates; i++)
531 {
532 t_template *template = template_findbyname(templatevec[i]);
533 int j, m = template->t_n;
534 /* drop "pd-" prefix from template symbol to print it: */
535 binbuf_addv(b, "ss;", gensym("template"),
536 gensym(templatevec[i]->s_name + 3));
537 for (j = 0; j < m; j++)
538 {
539 t_symbol *type;
540 switch (template->t_vec[j].ds_type)
541 {
542 case DT_FLOAT: type = &s_float; break;
543 case DT_SYMBOL: type = &s_symbol; break;
544 case DT_ARRAY: type = gensym("array"); break;
545 case DT_LIST: type = &s_list; break;
546 default: type = &s_float; bug("canvas_write");
547 }
548 if (template->t_vec[j].ds_type == DT_ARRAY)
549 binbuf_addv(b, "sss;", type, template->t_vec[j].ds_name,
550 gensym(template->t_vec[j].ds_arraytemplate->s_name + 3));
551 else binbuf_addv(b, "ss;", type, template->t_vec[j].ds_name);
552 }
553 binbuf_addsemi(b);
554 }
555 binbuf_addsemi(b);
556 /* now write out the objects themselves */
557 for (y = x->gl_list; y; y = y->g_next)
558 {
559 if ((pd_class(&y->g_pd) == scalar_class) &&
560 (wholething || glist_isselected(x, y)))
561 {
562 canvas_writescalar(((t_scalar *)y)->sc_template,
563 ((t_scalar *)y)->sc_vec, b, 0);
564 }
565 }
566 return (b);
567}
568
569static void glist_write(t_glist *x, t_symbol *filename, t_symbol *format)
570{
571#ifdef ROCKBOX
572 int cr = 0;
573#else
574 int cr = 0, i;
575#endif
576 t_binbuf *b;
577 char buf[MAXPDSTRING];
578#ifndef ROCKBOX
579 t_symbol **templatevec = getbytes(0);
580 int ntemplates = 0;
581 t_gobj *y;
582#endif
583 t_canvas *canvas = glist_getcanvas(x);
584 canvas_makefilename(canvas, filename->s_name, buf, MAXPDSTRING);
585 if (!strcmp(format->s_name, "cr"))
586 cr = 1;
587 else if (*format->s_name)
588 error("qlist_read: unknown flag: %s", format->s_name);
589
590 b = glist_writetobinbuf(x, 1);
591 if (b)
592 {
593 if (binbuf_write(b, buf, "", cr))
594 error("%s: write failed", filename->s_name);
595 binbuf_free(b);
596 }
597}
598
599/* ------ routines to save and restore canvases (patches) recursively. ----*/
600
601 /* save to a binbuf, called recursively; cf. canvas_savetofile() which
602 saves the document, and is only called on root canvases. */
603static void canvas_saveto(t_canvas *x, t_binbuf *b)
604{
605 t_gobj *y;
606 t_linetraverser t;
607 t_outconnect *oc;
608 /* subpatch */
609 if (x->gl_owner && !x->gl_env)
610 {
611 binbuf_addv(b, "ssiiiisi;", gensym("#N"), gensym("canvas"),
612 (t_int)(x->gl_screenx1),
613 (t_int)(x->gl_screeny1),
614 (t_int)(x->gl_screenx2 - x->gl_screenx1),
615 (t_int)(x->gl_screeny2 - x->gl_screeny1),
616 (*x->gl_name->s_name ? x->gl_name: gensym("(subpatch)")),
617 x->gl_mapped);
618 }
619 /* root or abstraction */
620 else binbuf_addv(b, "ssiiiii;", gensym("#N"), gensym("canvas"),
621 (t_int)(x->gl_screenx1),
622 (t_int)(x->gl_screeny1),
623 (t_int)(x->gl_screenx2 - x->gl_screenx1),
624 (t_int)(x->gl_screeny2 - x->gl_screeny1),
625 x->gl_font);
626
627 for (y = x->gl_list; y; y = y->g_next)
628 gobj_save(y, b);
629
630 linetraverser_start(&t, x);
631 while((oc = linetraverser_next(&t)))
632 {
633 int srcno = canvas_getindex(x, &t.tr_ob->ob_g);
634 int sinkno = canvas_getindex(x, &t.tr_ob2->ob_g);
635 binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"),
636 srcno, t.tr_outno, sinkno, t.tr_inno);
637 }
638 /* unless everything is the default (as in ordinary subpatches)
639 print out a "coords" message to set up the coordinate systems */
640 if (x->gl_isgraph || x->gl_x1 || x->gl_y1 ||
641 x->gl_x2 != 1 || x->gl_y2 != 1 || x->gl_pixwidth || x->gl_pixheight)
642 binbuf_addv(b, "ssfffffff;", gensym("#X"), gensym("coords"),
643 x->gl_x1, x->gl_y1,
644 x->gl_x2, x->gl_y2,
645 (float)x->gl_pixwidth, (float)x->gl_pixheight,
646 (float)x->gl_isgraph);
647}
648
649 /* call this recursively to collect all the template names for
650 a canvas or for the selection. */
651static void canvas_collecttemplatesfor(t_canvas *x, int *ntemplatesp,
652 t_symbol ***templatevecp, int wholething)
653{
654 t_gobj *y;
655
656 for (y = x->gl_list; y; y = y->g_next)
657 {
658 if ((pd_class(&y->g_pd) == scalar_class) &&
659 (wholething || glist_isselected(x, y)))
660 canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template,
661 ((t_scalar *)y)->sc_vec, ntemplatesp, templatevecp);
662 else if ((pd_class(&y->g_pd) == canvas_class) &&
663 (wholething || glist_isselected(x, y)))
664 canvas_collecttemplatesfor((t_canvas *)y,
665 ntemplatesp, templatevecp, 1);
666 }
667}
668
669 /* save the templates needed by a canvas to a binbuf. */
670static void canvas_savetemplatesto(t_canvas *x, t_binbuf *b, int wholething)
671{
672 t_symbol **templatevec = getbytes(0);
673 int i, ntemplates = 0;
674#ifndef ROCKBOX
675 t_gobj *y;
676#endif
677 canvas_collecttemplatesfor(x, &ntemplates, &templatevec, wholething);
678 for (i = 0; i < ntemplates; i++)
679 {
680 t_template *template = template_findbyname(templatevec[i]);
681 int j, m = template->t_n;
682 if (!template)
683 {
684 bug("canvas_savetemplatesto");
685 continue;
686 }
687 /* drop "pd-" prefix from template symbol to print */
688 binbuf_addv(b, "sss", &s__N, gensym("struct"),
689 gensym(templatevec[i]->s_name + 3));
690 for (j = 0; j < m; j++)
691 {
692 t_symbol *type;
693 switch (template->t_vec[j].ds_type)
694 {
695 case DT_FLOAT: type = &s_float; break;
696 case DT_SYMBOL: type = &s_symbol; break;
697 case DT_ARRAY: type = gensym("array"); break;
698 case DT_LIST: type = &s_list; break;
699 default: type = &s_float; bug("canvas_write");
700 }
701 if (template->t_vec[j].ds_type == DT_ARRAY)
702 binbuf_addv(b, "sss", type, template->t_vec[j].ds_name,
703 gensym(template->t_vec[j].ds_arraytemplate->s_name + 3));
704 else binbuf_addv(b, "ss", type, template->t_vec[j].ds_name);
705 }
706 binbuf_addsemi(b);
707 }
708}
709
710void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except);
711
712 /* save a "root" canvas to a file; cf. canvas_saveto() which saves the
713 body (and which is called recursively.) */
714static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir)
715{
716 t_binbuf *b = binbuf_new();
717 canvas_savetemplatesto(x, b, 1);
718 canvas_saveto(x, b);
719 if (binbuf_write(b, filename->s_name, dir->s_name, 0)) sys_ouch();
720 else
721 {
722 /* if not an abstraction, reset title bar and directory */
723 if (!x->gl_owner)
724 canvas_rename(x, filename, dir);
725 post("saved to: %s/%s", dir->s_name, filename->s_name);
726 canvas_dirty(x, 0);
727 canvas_reload(filename, dir, &x->gl_gobj);
728 }
729 binbuf_free(b);
730}
731
732static void canvas_menusaveas(t_canvas *x)
733{
734#ifdef ROCKBOX
735 (void) x;
736#else /* ROCKBOX */
737 t_canvas *x2 = canvas_getrootfor(x);
738 sys_vgui("pdtk_canvas_saveas .x%x \"%s\" \"%s\"\n", x2,
739 x2->gl_name->s_name, canvas_getdir(x2)->s_name);
740#endif /* ROCKBOX */
741}
742
743static void canvas_menusave(t_canvas *x)
744{
745 t_canvas *x2 = canvas_getrootfor(x);
746 char *name = x2->gl_name->s_name;
747 if (*name && strncmp(name, "Untitled", 8)
748 && (strlen(name) < 4 || strcmp(name + strlen(name)-4, ".pat")))
749 canvas_savetofile(x2, x2->gl_name, canvas_getdir(x2));
750 else canvas_menusaveas(x2);
751}
752
753
754void g_readwrite_setup(void)
755{
756 class_addmethod(canvas_class, (t_method)glist_write,
757 gensym("write"), A_SYMBOL, A_DEFSYM, A_NULL);
758 class_addmethod(canvas_class, (t_method)glist_read,
759 gensym("read"), A_SYMBOL, A_DEFSYM, A_NULL);
760 class_addmethod(canvas_class, (t_method)glist_mergefile,
761 gensym("mergefile"), A_SYMBOL, A_DEFSYM, A_NULL);
762 class_addmethod(canvas_class, (t_method)canvas_savetofile,
763 gensym("savetofile"), A_SYMBOL, A_SYMBOL, 0);
764 class_addmethod(canvas_class, (t_method)canvas_saveto,
765 gensym("saveto"), A_CANT, 0);
766/* ------------------ from the menu ------------------------- */
767 class_addmethod(canvas_class, (t_method)canvas_menusave,
768 gensym("menusave"), 0);
769 class_addmethod(canvas_class, (t_method)canvas_menusaveas,
770 gensym("menusaveas"), 0);
771}
772