A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1333 lines 35 kB view raw
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 6/* IOhannes : 7 * changed the canvas_restore in "g_canvas.c", so that it might accept $args as well (like "pd $0_test") 8 * so you can make multiple & distinguishable templates 9 * 1511:forum::für::umläute:2001 10 * change marked with IOhannes 11 */ 12 13#ifdef ROCKBOX 14#include "plugin.h" 15#include "../../pdbox.h" 16#ifdef SIMULATOR 17int printf(const char *fmt, ...); 18void perror(const char*); 19#endif 20#else /* ROCKBOX */ 21#include <stdlib.h> 22#include <stdio.h> 23#ifdef UNIX 24#include <unistd.h> 25#endif 26#ifdef MSW 27#include <io.h> 28#endif 29#include <fcntl.h> 30 31#include <string.h> 32#include <stdarg.h> 33#endif /* ROCKBOX */ 34 35#include "m_pd.h" 36#include "s_stuff.h" 37 38struct _binbuf 39{ 40 int b_n; 41 t_atom *b_vec; 42}; 43 44t_binbuf *binbuf_new(void) 45{ 46 t_binbuf *x = (t_binbuf *)t_getbytes(sizeof(*x)); 47 x->b_n = 0; 48 x->b_vec = t_getbytes(0); 49 return (x); 50} 51 52void binbuf_free(t_binbuf *x) 53{ 54 t_freebytes(x->b_vec, x->b_n * sizeof(*x->b_vec)); 55 t_freebytes(x, sizeof(*x)); 56} 57 58t_binbuf *binbuf_duplicate(t_binbuf *y) 59{ 60 t_binbuf *x = (t_binbuf *)t_getbytes(sizeof(*x)); 61 x->b_n = y->b_n; 62 x->b_vec = t_getbytes(x->b_n * sizeof(*x->b_vec)); 63 memcpy(x->b_vec, y->b_vec, x->b_n * sizeof(*x->b_vec)); 64 return (x); 65} 66 67void binbuf_clear(t_binbuf *x) 68{ 69 x->b_vec = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec), 0); 70 x->b_n = 0; 71} 72 73 /* convert text to a binbuf */ 74void binbuf_text(t_binbuf *x, char *text, size_t size) 75{ 76 char buf[MAXPDSTRING+1], *bufp, *ebuf = buf+MAXPDSTRING; 77 const char *textp = text, *etext = text+size; 78 t_atom *ap; 79 int nalloc = 16, natom = 0; 80 t_freebytes(x->b_vec, x->b_n * sizeof(*x->b_vec)); 81 x->b_vec = t_getbytes(nalloc * sizeof(*x->b_vec)); 82 ap = x->b_vec; 83 x->b_n = 0; 84 while (1) 85 { 86#ifndef ROCKBOX 87 int type; 88#endif 89 /* skip leading space */ 90 while ((textp != etext) && (*textp == ' ' || *textp == '\n' 91 || *textp == '\r' || *textp == '\t')) textp++; 92 if (textp == etext) break; 93 if (*textp == ';') SETSEMI(ap), textp++; 94 else if (*textp == ',') SETCOMMA(ap), textp++; 95 else 96 { 97 /* it's an atom other than a comma or semi */ 98 char c; 99 int floatstate = 0, slash = 0, /* lastslash = 0, */ 100 firstslash = (*textp == '\\'); 101 bufp = buf; 102 do 103 { 104 c = *bufp = *textp++; 105 /* lastslash = slash; */ 106 slash = (c == '\\'); 107 108 if (floatstate >= 0) 109 { 110 int digit = (c >= '0' && c <= '9'), 111 dot = (c == '.'), minus = (c == '-'), 112 plusminus = (minus || (c == '+')), 113 expon = (c == 'e' || c == 'E'); 114 if (floatstate == 0) /* beginning */ 115 { 116 if (minus) floatstate = 1; 117 else if (digit) floatstate = 2; 118 else if (dot) floatstate = 3; 119 else floatstate = -1; 120 } 121 else if (floatstate == 1) /* got minus */ 122 { 123 if (digit) floatstate = 2; 124 else if (dot) floatstate = 3; 125 else floatstate = -1; 126 } 127 else if (floatstate == 2) /* got digits */ 128 { 129 if (dot) floatstate = 4; 130 else if (expon) floatstate = 6; 131 else if (!digit) floatstate = -1; 132 } 133 else if (floatstate == 3) /* got '.' without digits */ 134 { 135 if (digit) floatstate = 5; 136 else floatstate = -1; 137 } 138 else if (floatstate == 4) /* got '.' after digits */ 139 { 140 if (digit) floatstate = 5; 141 else if (expon) floatstate = 6; 142 else floatstate = -1; 143 } 144 else if (floatstate == 5) /* got digits after . */ 145 { 146 if (expon) floatstate = 6; 147 else if (!digit) floatstate = -1; 148 } 149 else if (floatstate == 6) /* got 'e' */ 150 { 151 if (plusminus) floatstate = 7; 152 else if (digit) floatstate = 8; 153 else floatstate = -1; 154 } 155 else if (floatstate == 7) /* got plus or minus */ 156 { 157 if (digit) floatstate = 8; 158 else floatstate = -1; 159 } 160 else if (floatstate == 8) /* got digits */ 161 { 162 if (!digit) floatstate = -1; 163 } 164 } 165 if (!slash) bufp++; 166 } 167 while (textp != etext && bufp != ebuf && 168 (slash || (*textp != ' ' && *textp != '\n' && *textp != '\r' 169 && *textp != '\t' &&*textp != ',' && *textp != ';'))); 170 *bufp = 0; 171#if 0 172 post("buf %s", buf); 173#endif 174 175 if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9' && !firstslash) 176 { 177 for (bufp = buf+2; *bufp; bufp++) 178 if (*bufp < '0' || *bufp > '9') 179 { 180 SETDOLLSYM(ap, gensym(buf+1)); 181 goto didit; 182 } 183 SETDOLLAR(ap, atoi(buf+1)); 184 didit: ; 185 } 186 else 187 { 188 if (floatstate == 2 || floatstate == 4 || floatstate == 5 || 189 floatstate == 8) 190 SETFLOAT(ap, atof(buf)); 191 else SETSYMBOL(ap, gensym(buf)); 192 } 193 } 194 ap++; 195 natom++; 196 if (natom == nalloc) 197 { 198 x->b_vec = t_resizebytes(x->b_vec, nalloc * sizeof(*x->b_vec), 199 nalloc * (2*sizeof(*x->b_vec))); 200 nalloc = nalloc * 2; 201 ap = x->b_vec + natom; 202 } 203 if (textp == etext) break; 204 } 205 /* reallocate the vector to exactly the right size */ 206 x->b_vec = t_resizebytes(x->b_vec, nalloc * sizeof(*x->b_vec), 207 natom * sizeof(*x->b_vec)); 208 x->b_n = natom; 209} 210 211 /* convert a binbuf to text; no null termination. */ 212void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp) 213{ 214 char *buf = getbytes(0), *newbuf; 215 int length = 0; 216 char string[MAXPDSTRING]; 217 t_atom *ap; 218 int indx; 219 220 for (ap = x->b_vec, indx = x->b_n; indx--; ap++) 221 { 222 int newlength; 223 if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) && 224 length && buf[length-1] == ' ') length--; 225 atom_string(ap, string, MAXPDSTRING); 226 newlength = length + strlen(string) + 1; 227 if (!(newbuf = resizebytes(buf, length, newlength))) break; 228 buf = newbuf; 229 strcpy(buf + length, string); 230 length = newlength; 231 if (ap->a_type == A_SEMI) buf[length-1] = '\n'; 232 else buf[length-1] = ' '; 233 } 234 if (length && buf[length-1] == ' ') 235 { 236 if((newbuf = t_resizebytes(buf, length, length-1))) 237 { 238 buf = newbuf; 239 length--; 240 } 241 } 242 *bufp = buf; 243 *lengthp = length; 244} 245 246/* LATER improve the out-of-space behavior below. Also fix this so that 247writing to file doesn't buffer everything together. */ 248 249void binbuf_add(t_binbuf *x, int argc, t_atom *argv) 250{ 251 int newsize = x->b_n + argc, i; 252 t_atom *ap; 253 if((ap = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec), 254 newsize * sizeof(*x->b_vec)))) 255 x->b_vec = ap; 256 else 257 { 258 error("binbuf_addmessage: out of space"); 259 return; 260 } 261#if 0 262 startpost("binbuf_add: "); 263 postatom(argc, argv); 264 endpost(); 265#endif 266 for (ap = x->b_vec + x->b_n, i = argc; i--; ap++) 267 *ap = *(argv++); 268 x->b_n = newsize; 269} 270 271#define MAXADDMESSV 100 272void binbuf_addv(t_binbuf *x, char *fmt, ...) 273{ 274 va_list ap; 275 t_atom arg[MAXADDMESSV], *at =arg; 276 int nargs = 0; 277 char *fp = fmt; 278 279 va_start(ap, fmt); 280 while (1) 281 { 282 if (nargs >= MAXADDMESSV) 283 { 284 error("binbuf_addmessv: only %d allowed", MAXADDMESSV); 285 break; 286 } 287 switch(*fp++) 288 { 289 case 'i': SETFLOAT(at, va_arg(ap, t_int)); break; 290 case 'f': SETFLOAT(at, va_arg(ap, double)); break; 291 case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break; 292 case ';': SETSEMI(at); break; 293 case ',': SETCOMMA(at); break; 294 default: goto done; 295 } 296 at++; 297 nargs++; 298 } 299done: 300 va_end(ap); 301 binbuf_add(x, nargs, arg); 302} 303 304/* add a binbuf to another one for saving. Semicolons and commas go to 305symbols ";", "'",; the symbol ";" goes to "\;", etc. */ 306 307void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y) 308{ 309 t_binbuf *z = binbuf_new(); 310 int i; 311 t_atom *ap; 312 binbuf_add(z, y->b_n, y->b_vec); 313 for (i = 0, ap = z->b_vec; i < z->b_n; i++, ap++) 314 { 315 char tbuf[MAXPDSTRING]; 316 switch (ap->a_type) 317 { 318 case A_FLOAT: 319 break; 320 case A_SEMI: 321 SETSYMBOL(ap, gensym(";")); 322 break; 323 case A_COMMA: 324 SETSYMBOL(ap, gensym(",")); 325 break; 326 case A_DOLLAR: 327#ifdef ROCKBOX 328 snprintf(tbuf, sizeof(tbuf), "$%d", ap->a_w.w_index); 329#else /* ROCKBOX */ 330 sprintf(tbuf, "$%d", ap->a_w.w_index); 331#endif /* ROCKBOX */ 332 SETSYMBOL(ap, gensym(tbuf)); 333 break; 334 case A_DOLLSYM: 335#ifdef ROCKBOX 336 snprintf(tbuf, sizeof(tbuf), "$%s", ap->a_w.w_symbol->s_name); 337#else /* ROCKBOX */ 338 sprintf(tbuf, "$%s", ap->a_w.w_symbol->s_name); 339#endif /* ROCKBOX */ 340 SETSYMBOL(ap, gensym(tbuf)); 341 break; 342 case A_SYMBOL: 343 /* FIXME make this general */ 344 if (!strcmp(ap->a_w.w_symbol->s_name, ";")) 345 SETSYMBOL(ap, gensym(";")); 346 else if (!strcmp(ap->a_w.w_symbol->s_name, ",")) 347 SETSYMBOL(ap, gensym(",")); 348 break; 349 default: 350 bug("binbuf_addbinbuf"); 351 } 352 } 353 354 binbuf_add(x, z->b_n, z->b_vec); 355} 356 357void binbuf_addsemi(t_binbuf *x) 358{ 359 t_atom a; 360 SETSEMI(&a); 361 binbuf_add(x, 1, &a); 362} 363 364/* Supply atoms to a binbuf from a message, making the opposite changes 365from binbuf_addbinbuf. The symbol ";" goes to a semicolon, etc. */ 366 367void binbuf_restore(t_binbuf *x, int argc, t_atom *argv) 368{ 369 int newsize = x->b_n + argc, i; 370 t_atom *ap; 371 if((ap = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec), 372 newsize * sizeof(*x->b_vec)))) 373 x->b_vec = ap; 374 else 375 { 376 error("binbuf_addmessage: out of space"); 377 return; 378 } 379 380 for (ap = x->b_vec + x->b_n, i = argc; i--; ap++) 381 { 382 if (argv->a_type == A_SYMBOL) 383 { 384 char *str = argv->a_w.w_symbol->s_name; 385 if (!strcmp(str, ";")) SETSEMI(ap); 386 else if (!strcmp(str, ",")) SETCOMMA(ap); 387 else if (str[0] == '$' && str[1] >= '0' && str[1] <= '9') 388 { 389 int dollsym = 0; 390 char *str2; 391 for (str2 = str + 2; *str2; str2++) 392 if (*str2 < '0' || *str2 > '9') 393 dollsym = 1; 394 if (dollsym) 395 SETDOLLSYM(ap, gensym(str + 1)); 396 else 397 { 398 int dollar = 0; 399#ifdef ROCKBOX 400 dollar = atoi(argv->a_w.w_symbol->s_name + 1); 401#else 402 sscanf(argv->a_w.w_symbol->s_name + 1, "%d", &dollar); 403#endif 404 SETDOLLAR(ap, dollar); 405 } 406 } 407 else *ap = *argv; 408 argv++; 409 } 410 else *ap = *(argv++); 411 } 412 x->b_n = newsize; 413} 414 415 416#define MSTACKSIZE 2048 417 418void binbuf_print(t_binbuf *x) 419{ 420 int i, startedpost = 0, newline = 1; 421 for (i = 0; i < x->b_n; i++) 422 { 423 if (newline) 424 { 425 if (startedpost) endpost(); 426 startpost(""); 427 startedpost = 1; 428 } 429 postatom(1, x->b_vec + i); 430 if (x->b_vec[i].a_type == A_SEMI) 431 newline = 1; 432 else newline = 0; 433 } 434 if (startedpost) endpost(); 435} 436 437int binbuf_getnatom(t_binbuf *x) 438{ 439 return (x->b_n); 440} 441 442t_atom *binbuf_getvec(t_binbuf *x) 443{ 444 return (x->b_vec); 445} 446 447int canvas_getdollarzero( void); 448 449t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew) 450{ 451 int argno = atol(s->s_name), lastnum; 452 char buf[MAXPDSTRING], c, *sp; 453 for (lastnum = 0, sp = s->s_name; ((c = *sp) && c >= '0' && c <= '9'); 454 sp++, lastnum++) 455 if (!c || argno < 0 || argno > ac) 456 { 457 if (!tonew) 458 return (0); 459#ifdef ROCKBOX 460 else snprintf(buf, sizeof(buf), "$%d", argno); 461#else /* ROCKBOX */ 462 else sprintf(buf, "$%d", argno); 463#endif /* ROCKBOX */ 464 } 465 else if (argno == 0) 466#ifdef ROCKBOX 467 snprintf(buf, sizeof(buf), "%d", canvas_getdollarzero()); 468#else /* ROCKBOX */ 469 sprintf(buf, "%d", canvas_getdollarzero()); 470#endif /* ROCKBOX */ 471 else 472 atom_string(av+(argno-1), buf, MAXPDSTRING/2-1); 473 strncat(buf, sp, MAXPDSTRING/2-1); 474 return (gensym(buf)); 475} 476 477void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv) 478{ 479 static t_atom mstack[MSTACKSIZE], *msp = mstack, *ems = mstack+MSTACKSIZE; 480 t_atom *stackwas = msp; 481 t_atom *at = x->b_vec; 482 int ac = x->b_n; 483 int nargs; 484 while (1) 485 { 486 t_pd *nexttarget; 487 /* get a target. */ 488 while (!target) 489 { 490 t_symbol *s; 491 while (ac && (at->a_type == A_SEMI || at->a_type == A_COMMA)) 492 ac--, at++; 493 if (!ac) break; 494 if (at->a_type == A_DOLLAR) 495 { 496 if (at->a_w.w_index <= 0 || at->a_w.w_index > argc) 497 { 498 error("$%d: not enough arguments supplied", 499 at->a_w.w_index); 500 goto cleanup; 501 } 502 else if (argv[at->a_w.w_index-1].a_type != A_SYMBOL) 503 { 504 error("$%d: symbol needed as message destination", 505 at->a_w.w_index); 506 goto cleanup; 507 } 508 else s = argv[at->a_w.w_index-1].a_w.w_symbol; 509 } 510 else if (at->a_type == A_DOLLSYM) 511 { 512 if (!(s = binbuf_realizedollsym(at->a_w.w_symbol, 513 argc, argv, 0))) 514 { 515 error("$%s: not enough arguments supplied", 516 at->a_w.w_symbol->s_name); 517 goto cleanup; 518 } 519 } 520 else s = atom_getsymbol(at); 521 if (!(target = s->s_thing)) 522 { 523 error("%s: no such object", s->s_name); 524 cleanup: 525 do at++, ac--; 526 while (ac && at->a_type != A_SEMI); 527 /* LATER eat args until semicolon and continue */ 528 continue; 529 } 530 else 531 { 532 at++, ac--; 533 break; 534 } 535 } 536 if (!ac) break; 537 nargs = 0; 538 nexttarget = target; 539 while (1) 540 { 541 t_symbol *s9; 542 if (!ac) goto gotmess; 543 if (msp >= ems) 544 { 545 error("message stack overflow"); 546 goto broken; 547 } 548 switch (at->a_type) 549 { 550 case A_SEMI: 551 /* semis and commas in new message just get bashed to 552 a symbol. This is needed so you can pass them to "expr." */ 553 if (target == &pd_objectmaker) 554 { 555 SETSYMBOL(msp, gensym(";")); 556 break; 557 } 558 else 559 { 560 nexttarget = 0; 561 goto gotmess; 562 } 563 case A_COMMA: 564 if (target == &pd_objectmaker) 565 { 566 SETSYMBOL(msp, gensym(",")); 567 break; 568 } 569 else goto gotmess; 570 case A_FLOAT: 571 case A_SYMBOL: 572 *msp = *at; 573 break; 574 case A_DOLLAR: 575 if (at->a_w.w_index > 0 && at->a_w.w_index <= argc) 576 *msp = argv[at->a_w.w_index-1]; 577 else if (at->a_w.w_index == 0) 578 SETFLOAT(msp, canvas_getdollarzero()); 579 else 580 { 581 if (target == &pd_objectmaker) 582 SETFLOAT(msp, 0); 583 else 584 { 585 error("$%d: argument number out of range", 586 at->a_w.w_index); 587 SETFLOAT(msp, 0); 588 } 589 } 590 break; 591 case A_DOLLSYM: 592 s9 = binbuf_realizedollsym(at->a_w.w_symbol, argc, argv, 593 target == &pd_objectmaker); 594 if (!s9) 595 goto broken; 596 SETSYMBOL(msp, s9); 597 break; 598 default: 599 bug("bad item in binbuf"); 600 goto broken; 601 } 602 msp++; 603 ac--; 604 at++; 605 nargs++; 606 } 607 gotmess: 608 if (nargs) 609 { 610 switch (stackwas->a_type) 611 { 612 case A_SYMBOL: 613 typedmess(target, stackwas->a_w.w_symbol, nargs-1, stackwas+1); 614 break; 615 case A_FLOAT: 616 if (nargs == 1) pd_float(target, stackwas->a_w.w_float); 617 else pd_list(target, 0, nargs, stackwas); 618 break; 619#ifdef ROCKBOX 620 default: 621 break; 622#endif 623 } 624 } 625 msp = stackwas; 626 if (!ac) break; 627 target = nexttarget; 628 at++; 629 ac--; 630 } 631 632 return; 633broken: 634 msp = stackwas; 635} 636 637static int binbuf_doopen(char *s, int mode) 638{ 639 char namebuf[MAXPDSTRING]; 640#ifdef MSW 641 mode |= O_BINARY; 642#endif 643 sys_bashfilename(s, namebuf); 644 return (open(namebuf, mode, 0666)); 645} 646 647#ifndef ROCKBOX 648static FILE *binbuf_dofopen(char *s, char *mode) 649{ 650 char namebuf[MAXPDSTRING]; 651 sys_bashfilename(s, namebuf); 652 return (fopen(namebuf, mode)); 653} 654#endif 655 656int binbuf_read(t_binbuf *b, char *filename, char *dirname, int crflag) 657{ 658 long length; 659 int fd; 660 int readret; 661 char *buf; 662 char namebuf[MAXPDSTRING]; 663 664 namebuf[0] = 0; 665 if (*dirname) 666 strcat(namebuf, dirname), strcat(namebuf, "/"); 667 strcat(namebuf, filename); 668 669 if ((fd = binbuf_doopen(namebuf, 0)) < 0) 670 { 671#ifdef ROCKBOX 672#ifdef SIMULATOR 673 printf("open: "); 674 perror(namebuf); 675#endif /* SIMULATOR */ 676#else /* ROCKBOX */ 677 fprintf(stderr, "open: "); 678 perror(namebuf); 679#endif /* ROCKBOX */ 680 return (1); 681 } 682 if ((length = lseek(fd, 0, SEEK_END)) < 0 || lseek(fd, 0, SEEK_SET) < 0 683 || !(buf = t_getbytes(length))) 684 { 685#ifdef ROCKBOX 686#ifdef SIMULATOR 687 printf("lseek: "); 688 perror(namebuf); 689#endif /* SIMULATOR */ 690#else /* ROCKBOX */ 691 fprintf(stderr, "lseek: "); 692 perror(namebuf); 693#endif /* ROCKBOX */ 694 close(fd); 695 return(1); 696 } 697 if ((readret = read(fd, buf, length)) < length) 698 { 699#ifdef ROCKBOX 700#ifdef SIMULATOR 701 printf("read (%d %ld) -> %d\n", fd, length, readret); 702 perror(namebuf); 703#endif /* SIMULATOR */ 704#else /* ROCKBOX */ 705 fprintf(stderr, "read (%d %ld) -> %d\n", fd, length, readret); 706 perror(namebuf); 707#endif /* ROCKBOX */ 708 close(fd); 709 t_freebytes(buf, length); 710 return(1); 711 } 712 /* optionally map carriage return to semicolon */ 713 if (crflag) 714 { 715 int i; 716 for (i = 0; i < length; i++) 717 if (buf[i] == '\n') 718 buf[i] = ';'; 719 } 720 binbuf_text(b, buf, length); 721 722#if 0 723 startpost("binbuf_read "); postatom(b->b_n, b->b_vec); endpost(); 724#endif 725 726 t_freebytes(buf, length); 727 close(fd); 728 return (0); 729} 730 731int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname, 732 int crflag) 733{ 734 int filedesc; 735 char buf[MAXPDSTRING], *bufptr; 736 if ((filedesc = open_via_path( 737 dirname, filename, "", buf, &bufptr, MAXPDSTRING, 0)) < 0) 738 { 739 error("%s: can't open", filename); 740 return (1); 741 } 742 else close (filedesc); 743 if (binbuf_read(b, bufptr, buf, crflag)) 744 return (1); 745 else return (0); 746} 747 748#define WBUFSIZE 4096 749static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd); 750 751 /* write a binbuf to a text file. If "crflag" is set we suppress 752 semicolons. */ 753int binbuf_write(t_binbuf *x, char *filename, char *dir, int crflag) 754{ 755#ifdef ROCKBOX 756 int f = 0; 757 ssize_t bp_size; 758#else /* ROCKBOX */ 759 FILE *f = 0; 760#endif /* ROCKBOX */ 761 char sbuf[WBUFSIZE], fbuf[MAXPDSTRING], *bp = sbuf, *ep = sbuf + WBUFSIZE; 762 t_atom *ap; 763 int indx, deleteit = 0; 764 int ncolumn = 0; 765 766 fbuf[0] = 0; 767 if (*dir) 768 strcat(fbuf, dir), strcat(fbuf, "/"); 769 strcat(fbuf, filename); 770 if (!strcmp(filename + strlen(filename) - 4, ".pat")) 771 { 772 x = binbuf_convert(x, 0); 773 deleteit = 1; 774 } 775 776#ifdef ROCKBOX 777 if(!(f = binbuf_doopen(fbuf, O_WRONLY|O_CREAT|O_TRUNC))) 778#else /* ROCKBOX */ 779 if (!(f = binbuf_dofopen(fbuf, "w"))) 780#endif /* ROCKBOX */ 781 { 782#ifdef ROCKBOX 783#ifdef SIMULATOR 784 printf("open: "); 785#endif /* SIMULATOR */ 786#else /* ROCKBOX */ 787 fprintf(stderr, "open: "); 788#endif /* ROCKBOX */ 789 sys_unixerror(fbuf); 790 goto fail; 791 } 792 for (ap = x->b_vec, indx = x->b_n; indx--; ap++) 793 { 794 int length; 795 /* estimate how many characters will be needed. Printing out 796 symbols may need extra characters for inserting backslashes. */ 797 if (ap->a_type == A_SYMBOL || ap->a_type == A_DOLLSYM) 798 length = 80 + strlen(ap->a_w.w_symbol->s_name); 799 else length = 40; 800 if (ep - bp < length) 801 { 802#ifdef ROCKBOX 803 bp_size = bp - sbuf; 804 if(write(f, sbuf, bp_size) < bp_size) 805#else /* ROCKBOX */ 806 if (fwrite(sbuf, bp-sbuf, 1, f) < 1) 807#endif /* ROCKBOX */ 808 { 809 sys_unixerror(fbuf); 810 goto fail; 811 } 812 bp = sbuf; 813 } 814 if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) && 815 bp > sbuf && bp[-1] == ' ') bp--; 816 if (!crflag || ap->a_type != A_SEMI) 817 { 818 atom_string(ap, bp, (ep-bp)-2); 819 length = strlen(bp); 820 bp += length; 821 ncolumn += length; 822 } 823 if (ap->a_type == A_SEMI || (!crflag && ncolumn > 65)) 824 { 825 *bp++ = '\n'; 826 ncolumn = 0; 827 } 828 else 829 { 830 *bp++ = ' '; 831 ncolumn++; 832 } 833 } 834#ifdef ROCKBOX 835 bp_size = bp - sbuf; 836 if(write(f, sbuf, bp_size) < bp_size) 837#else /* ROCKBOX */ 838 if (fwrite(sbuf, bp-sbuf, 1, f) < 1) 839#endif /* ROCKBOX */ 840 { 841 sys_unixerror(fbuf); 842 goto fail; 843 } 844 if (deleteit) 845 binbuf_free(x); 846#ifdef ROCKBOX 847 close(f); 848#else /* ROCKBOX */ 849 fclose(f); 850#endif /* ROCKBOX */ 851 return (0); 852fail: 853 if (deleteit) 854 binbuf_free(x); 855 if (f) 856#ifdef ROCKBOX 857 close(f); 858#else /* ROCKBOX */ 859 fclose(f); 860#endif /* ROCKBOX */ 861 return (1); 862} 863 864/* The following routine attempts to convert from max to pd or back. The 865max to pd direction is working OK but you will need to make lots of 866abstractions for objects like "gate" which don't exist in Pd. conversion 867from Pd to Max hasn't been tested for patches with subpatches yet! */ 868 869#define MAXSTACK 1000 870 871#define ISSYMBOL(a, b) ((a)->a_type == A_SYMBOL && \ 872 !strcmp((a)->a_w.w_symbol->s_name, (b))) 873 874static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd) 875{ 876 t_binbuf *newb = binbuf_new(); 877 t_atom *vec = oldb->b_vec; 878 t_int n = oldb->b_n, nextindex, stackdepth = 0, stack[MAXSTACK], 879 nobj = 0, i; 880 t_atom outmess[MAXSTACK], *nextmess; 881 if (!maxtopd) 882 binbuf_addv(newb, "ss;", gensym("max"), gensym("v2")); 883 for (nextindex = 0; nextindex < n; ) 884 { 885 int endmess, natom; 886 char *first, *second; 887 for (endmess = nextindex; endmess < n && vec[endmess].a_type != A_SEMI; 888 endmess++) 889 ; 890 if (endmess == n) break; 891 if (endmess == nextindex || endmess == nextindex + 1 892 || vec[nextindex].a_type != A_SYMBOL || 893 vec[nextindex+1].a_type != A_SYMBOL) 894 { 895 nextindex = endmess + 1; 896 continue; 897 } 898 natom = endmess - nextindex; 899 if (natom > MAXSTACK-10) natom = MAXSTACK-10; 900 nextmess = vec + nextindex; 901 first = nextmess->a_w.w_symbol->s_name; 902 second = (nextmess+1)->a_w.w_symbol->s_name; 903 if (maxtopd) 904 { 905 /* case 1: importing a ".pat" file into Pd. */ 906 907 /* dollar signs in file translate to symbols */ 908 for (i = 0; i < natom; i++) 909 { 910 if (nextmess[i].a_type == A_DOLLAR) 911 { 912 char buf[100]; 913#ifdef ROCKBOX 914 snprintf(buf, sizeof(buf), "$%d", nextmess[i].a_w.w_index); 915#else /* ROCKBOX */ 916 sprintf(buf, "$%d", nextmess[i].a_w.w_index); 917#endif /* ROCKBOX */ 918 SETSYMBOL(nextmess+i, gensym(buf)); 919 } 920 else if (nextmess[i].a_type == A_DOLLSYM) 921 { 922 char buf[100]; 923#ifdef ROCKBOX 924 snprintf(buf, sizeof(buf), "$%s", nextmess[i].a_w.w_symbol->s_name); 925#else /* ROCKBOX */ 926 sprintf(buf, "$%s", nextmess[i].a_w.w_symbol->s_name); 927#endif /* ROCKBOX */ 928 SETSYMBOL(nextmess+i, gensym(buf)); 929 } 930 } 931 if (!strcmp(first, "#N")) 932 { 933 if (!strcmp(second, "vpatcher")) 934 { 935 if (stackdepth >= MAXSTACK) 936 { 937 post("too many embedded patches"); 938 return (newb); 939 } 940 stack[stackdepth] = nobj; 941 stackdepth++; 942 nobj = 0; 943 binbuf_addv(newb, "ssfffff;", 944 gensym("#N"), gensym("canvas"), 945 atom_getfloatarg(2, natom, nextmess), 946 atom_getfloatarg(3, natom, nextmess), 947 atom_getfloatarg(4, natom, nextmess) - 948 atom_getfloatarg(2, natom, nextmess), 949 atom_getfloatarg(5, natom, nextmess) - 950 atom_getfloatarg(3, natom, nextmess), 951#ifdef ROCKBOX 952 10.0); 953#else 954 (float)sys_defaultfont); 955#endif 956 } 957 } 958 if (!strcmp(first, "#P")) 959 { 960 /* drop initial "hidden" flag */ 961 if (!strcmp(second, "hidden")) 962 { 963 nextmess++; 964 natom--; 965 second = (nextmess+1)->a_w.w_symbol->s_name; 966 } 967 if (natom >= 7 && !strcmp(second, "newobj") 968 && (ISSYMBOL(&nextmess[6], "patcher") || 969 ISSYMBOL(&nextmess[6], "p"))) 970 { 971 binbuf_addv(newb, "ssffss;", 972 gensym("#X"), gensym("restore"), 973 atom_getfloatarg(2, natom, nextmess), 974 atom_getfloatarg(3, natom, nextmess), 975 gensym("pd"), atom_getsymbolarg(7, natom, nextmess)); 976 if (stackdepth) stackdepth--; 977 nobj = stack[stackdepth]; 978 nobj++; 979 } 980 else if (!strcmp(second, "newex") || !strcmp(second, "newobj")) 981 { 982 t_symbol *classname = 983 atom_getsymbolarg(6, natom, nextmess); 984 if (classname == gensym("trigger") || 985 classname == gensym("t")) 986 { 987 for (i = 7; i < natom; i++) 988 if (nextmess[i].a_type == A_SYMBOL && 989 nextmess[i].a_w.w_symbol == gensym("i")) 990 nextmess[i].a_w.w_symbol = gensym("f"); 991 } 992 if (classname == gensym("table")) 993 classname = gensym("TABLE"); 994 SETSYMBOL(outmess, gensym("#X")); 995 SETSYMBOL(outmess + 1, gensym("obj")); 996 outmess[2] = nextmess[2]; 997 outmess[3] = nextmess[3]; 998 SETSYMBOL(outmess+4, classname); 999 for (i = 7; i < natom; i++) 1000 outmess[i-2] = nextmess[i]; 1001 SETSEMI(outmess + natom - 2); 1002 binbuf_add(newb, natom - 1, outmess); 1003 nobj++; 1004 } 1005 else if (!strcmp(second, "message") || 1006 !strcmp(second, "comment")) 1007 { 1008 SETSYMBOL(outmess, gensym("#X")); 1009 SETSYMBOL(outmess + 1, gensym( 1010 (strcmp(second, "message") ? "text" : "msg"))); 1011 outmess[2] = nextmess[2]; 1012 outmess[3] = nextmess[3]; 1013 for (i = 6; i < natom; i++) 1014 outmess[i-2] = nextmess[i]; 1015 SETSEMI(outmess + natom - 2); 1016 binbuf_add(newb, natom - 1, outmess); 1017 nobj++; 1018 } 1019 else if (!strcmp(second, "button")) 1020 { 1021 binbuf_addv(newb, "ssffs;", 1022 gensym("#X"), gensym("obj"), 1023 atom_getfloatarg(2, natom, nextmess), 1024 atom_getfloatarg(3, natom, nextmess), 1025 gensym("bng")); 1026 nobj++; 1027 } 1028 else if (!strcmp(second, "number") || !strcmp(second, "flonum")) 1029 { 1030 binbuf_addv(newb, "ssff;", 1031 gensym("#X"), gensym("floatatom"), 1032 atom_getfloatarg(2, natom, nextmess), 1033 atom_getfloatarg(3, natom, nextmess)); 1034 nobj++; 1035 } 1036 else if (!strcmp(second, "slider")) 1037 { 1038 float inc = atom_getfloatarg(7, natom, nextmess); 1039 if (inc <= 0) 1040 inc = 1; 1041 binbuf_addv(newb, "ssffsffffffsssfffffffff;", 1042 gensym("#X"), gensym("obj"), 1043 atom_getfloatarg(2, natom, nextmess), 1044 atom_getfloatarg(3, natom, nextmess), 1045 gensym("vsl"), 1046 atom_getfloatarg(4, natom, nextmess), 1047 atom_getfloatarg(5, natom, nextmess), 1048 atom_getfloatarg(6, natom, nextmess), 1049 atom_getfloatarg(6, natom, nextmess) 1050 + (atom_getfloatarg(5, natom, nextmess) - 1) * inc, 1051 0., 0., 1052 gensym("empty"), gensym("empty"), gensym("empty"), 1053 0., -8., 0., 8., -262144., -1., -1., 0., 1.); 1054 nobj++; 1055 } 1056 else if (!strcmp(second, "toggle")) 1057 { 1058 binbuf_addv(newb, "ssffs;", 1059 gensym("#X"), gensym("obj"), 1060 atom_getfloatarg(2, natom, nextmess), 1061 atom_getfloatarg(3, natom, nextmess), 1062 gensym("tgl")); 1063 nobj++; 1064 } 1065 else if (!strcmp(second, "inlet")) 1066 { 1067 binbuf_addv(newb, "ssffs;", 1068 gensym("#X"), gensym("obj"), 1069 atom_getfloatarg(2, natom, nextmess), 1070 atom_getfloatarg(3, natom, nextmess), 1071 gensym((natom > 5 ? "inlet~" : "inlet"))); 1072 nobj++; 1073 } 1074 else if (!strcmp(second, "outlet")) 1075 { 1076 binbuf_addv(newb, "ssffs;", 1077 gensym("#X"), gensym("obj"), 1078 atom_getfloatarg(2, natom, nextmess), 1079 atom_getfloatarg(3, natom, nextmess), 1080 gensym((natom > 5 ? "outlet~" : "outlet"))); 1081 nobj++; 1082 } 1083 else if (!strcmp(second, "user")) 1084 { 1085 binbuf_addv(newb, "ssffs;", 1086 gensym("#X"), gensym("obj"), 1087 atom_getfloatarg(3, natom, nextmess), 1088 atom_getfloatarg(4, natom, nextmess), 1089 atom_getsymbolarg(2, natom, nextmess)); 1090 nobj++; 1091 } 1092 else if (!strcmp(second, "connect")|| 1093 !strcmp(second, "fasten")) 1094 { 1095 binbuf_addv(newb, "ssffff;", 1096 gensym("#X"), gensym("connect"), 1097 nobj - atom_getfloatarg(2, natom, nextmess) - 1, 1098 atom_getfloatarg(3, natom, nextmess), 1099 nobj - atom_getfloatarg(4, natom, nextmess) - 1, 1100 atom_getfloatarg(5, natom, nextmess)); 1101 } 1102 } 1103 } 1104 else /* Pd to Max */ 1105 { 1106 if (!strcmp(first, "#N")) 1107 { 1108 if (!strcmp(second, "canvas")) 1109 { 1110 if (stackdepth >= MAXSTACK) 1111 { 1112 post("too many embedded patches"); 1113 return (newb); 1114 } 1115 stack[stackdepth] = nobj; 1116 stackdepth++; 1117 nobj = 0; 1118 binbuf_addv(newb, "ssffff;", 1119 gensym("#N"), gensym("vpatcher"), 1120 atom_getfloatarg(2, natom, nextmess), 1121 atom_getfloatarg(3, natom, nextmess), 1122 atom_getfloatarg(4, natom, nextmess), 1123 atom_getfloatarg(5, natom, nextmess)); 1124 } 1125 } 1126 if (!strcmp(first, "#X")) 1127 { 1128 if (natom >= 5 && !strcmp(second, "restore") 1129 && (ISSYMBOL (&nextmess[4], "pd"))) 1130 { 1131 binbuf_addv(newb, "ss;", gensym("#P"), gensym("pop")); 1132 binbuf_addv(newb, "ssffffss;", 1133 gensym("#P"), gensym("newobj"), 1134 atom_getfloatarg(2, natom, nextmess), 1135 atom_getfloatarg(3, natom, nextmess), 50., 1., 1136 gensym("patcher"), 1137 atom_getsymbolarg(5, natom, nextmess)); 1138 if (stackdepth) stackdepth--; 1139 nobj = stack[stackdepth]; 1140 nobj++; 1141 } 1142 else if (!strcmp(second, "obj")) 1143 { 1144 t_symbol *classname = 1145 atom_getsymbolarg(4, natom, nextmess); 1146 if (classname == gensym("inlet")) 1147 binbuf_addv(newb, "ssfff;", gensym("#P"), 1148 gensym("inlet"), 1149 atom_getfloatarg(2, natom, nextmess), 1150 atom_getfloatarg(3, natom, nextmess), 1151 15.); 1152 else if (classname == gensym("inlet~")) 1153 binbuf_addv(newb, "ssffff;", gensym("#P"), 1154 gensym("inlet"), 1155 atom_getfloatarg(2, natom, nextmess), 1156 atom_getfloatarg(3, natom, nextmess), 1157 15., 1.); 1158 else if (classname == gensym("outlet")) 1159 binbuf_addv(newb, "ssfff;", gensym("#P"), 1160 gensym("outlet"), 1161 atom_getfloatarg(2, natom, nextmess), 1162 atom_getfloatarg(3, natom, nextmess), 1163 15.); 1164 else if (classname == gensym("outlet~")) 1165 binbuf_addv(newb, "ssffff;", gensym("#P"), 1166 gensym("outlet"), 1167 atom_getfloatarg(2, natom, nextmess), 1168 atom_getfloatarg(3, natom, nextmess), 1169 15., 1.); 1170 else if (classname == gensym("bng")) 1171 binbuf_addv(newb, "ssffff;", gensym("#P"), 1172 gensym("button"), 1173 atom_getfloatarg(2, natom, nextmess), 1174 atom_getfloatarg(3, natom, nextmess), 1175 atom_getfloatarg(5, natom, nextmess), 0.); 1176 else if (classname == gensym("tgl")) 1177 binbuf_addv(newb, "ssffff;", gensym("#P"), 1178 gensym("toggle"), 1179 atom_getfloatarg(2, natom, nextmess), 1180 atom_getfloatarg(3, natom, nextmess), 1181 atom_getfloatarg(5, natom, nextmess), 0.); 1182 else if (classname == gensym("vsl")) 1183 binbuf_addv(newb, "ssffffff;", gensym("#P"), 1184 gensym("slider"), 1185 atom_getfloatarg(2, natom, nextmess), 1186 atom_getfloatarg(3, natom, nextmess), 1187 atom_getfloatarg(5, natom, nextmess), 1188 atom_getfloatarg(6, natom, nextmess), 1189 (atom_getfloatarg(8, natom, nextmess) - 1190 atom_getfloatarg(7, natom, nextmess)) / 1191 (atom_getfloatarg(6, natom, nextmess) == 1? 1 : 1192 atom_getfloatarg(6, natom, nextmess) - 1), 1193 atom_getfloatarg(7, natom, nextmess)); 1194 else 1195 { 1196 SETSYMBOL(outmess, gensym("#P")); 1197 SETSYMBOL(outmess + 1, gensym("newex")); 1198 outmess[2] = nextmess[2]; 1199 outmess[3] = nextmess[3]; 1200 SETFLOAT(outmess + 4, 50); 1201 SETFLOAT(outmess + 5, 1); 1202 for (i = 4; i < natom; i++) 1203 outmess[i+2] = nextmess[i]; 1204 SETSEMI(outmess + natom + 2); 1205 binbuf_add(newb, natom + 3, outmess); 1206 } 1207 nobj++; 1208 1209 } 1210 else if (!strcmp(second, "msg") || 1211 !strcmp(second, "text")) 1212 { 1213 SETSYMBOL(outmess, gensym("#P")); 1214 SETSYMBOL(outmess + 1, gensym( 1215 (strcmp(second, "msg") ? "comment" : "message"))); 1216 outmess[2] = nextmess[2]; 1217 outmess[3] = nextmess[3]; 1218 SETFLOAT(outmess + 4, 50); 1219 SETFLOAT(outmess + 5, 1); 1220 for (i = 4; i < natom; i++) 1221 outmess[i+2] = nextmess[i]; 1222 SETSEMI(outmess + natom + 2); 1223 binbuf_add(newb, natom + 3, outmess); 1224 nobj++; 1225 } 1226 else if (!strcmp(second, "floatatom")) 1227 { 1228 binbuf_addv(newb, "ssfff;", 1229 gensym("#P"), gensym("flonum"), 1230 atom_getfloatarg(2, natom, nextmess), 1231 atom_getfloatarg(3, natom, nextmess), 35); 1232 nobj++; 1233 } 1234 else if (!strcmp(second, "connect")) 1235 { 1236 binbuf_addv(newb, "ssffff;", 1237 gensym("#P"), gensym("connect"), 1238 nobj - atom_getfloatarg(2, natom, nextmess) - 1, 1239 atom_getfloatarg(3, natom, nextmess), 1240 nobj - atom_getfloatarg(4, natom, nextmess) - 1, 1241 atom_getfloatarg(5, natom, nextmess)); 1242 } 1243 } 1244 } 1245 nextindex = endmess + 1; 1246 } 1247 if (!maxtopd) 1248 binbuf_addv(newb, "ss;", gensym("#P"), gensym("pop")); 1249#if 0 1250 binbuf_write(newb, "import-result.pd", "/tmp", 0); 1251#endif 1252 return (newb); 1253} 1254 1255 /* function to support searching */ 1256int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf) 1257{ 1258 int indexin, nmatched; 1259 for (indexin = 0; indexin <= inbuf->b_n - searchbuf->b_n; indexin++) 1260 { 1261 for (nmatched = 0; nmatched < searchbuf->b_n; nmatched++) 1262 { 1263 t_atom *a1 = &inbuf->b_vec[indexin + nmatched], 1264 *a2 = &searchbuf->b_vec[nmatched]; 1265 if (a1->a_type != a2->a_type || 1266 (a1->a_type == A_SYMBOL && a1->a_w.w_symbol != a2->a_w.w_symbol) 1267 || 1268 (a1->a_type == A_FLOAT && a1->a_w.w_float != a2->a_w.w_float) 1269 || 1270 (a1->a_type == A_DOLLAR && a1->a_w.w_index != a2->a_w.w_index) 1271 || 1272 (a1->a_type == A_DOLLSYM && a1->a_w.w_symbol != a2->a_w.w_symbol)) 1273 goto nomatch; 1274 } 1275 return (1); 1276 nomatch: ; 1277 } 1278 return (0); 1279} 1280 1281void pd_doloadbang(void); 1282 1283/* LATER make this evaluate the file on-the-fly. */ 1284/* LATER figure out how to log errors */ 1285void binbuf_evalfile(t_symbol *name, t_symbol *dir) 1286{ 1287 t_binbuf *b = binbuf_new(); 1288 int import = !strcmp(name->s_name + strlen(name->s_name) - 4, ".pat"); 1289 /* set filename so that new canvases can pick them up */ 1290 int dspstate = canvas_suspend_dsp(); 1291 glob_setfilename(0, name, dir); 1292 1293 if (binbuf_read(b, name->s_name, dir->s_name, 0)) 1294 { 1295#if !defined(ROCKBOX) || (defined(ROCKBOX) && defined(SIMULATOR)) 1296 perror(name->s_name); 1297#endif 1298 } 1299 else 1300 { 1301 if (import) 1302 { 1303 t_binbuf *newb = binbuf_convert(b, 1); 1304 binbuf_free(b); 1305 b = newb; 1306 } 1307 binbuf_eval(b, 0, 0, 0); 1308 } 1309 glob_setfilename(0, &s_, &s_); /* bug fix by Krzysztof Czaja */ 1310 binbuf_free(b); 1311 canvas_resume_dsp(dspstate); 1312} 1313 1314void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir) 1315{ 1316 t_pd *x = 0; 1317 1318#ifdef ROCKBOX 1319 (void) ignore; 1320#endif 1321 /* even though binbuf_evalfile appears to take care of dspstate, 1322 we have to do it again here, because canvas_startdsp() assumes 1323 that all toplevel canvases are visible. LATER check if this 1324 is still necessary -- probably not. */ 1325 1326 int dspstate = canvas_suspend_dsp(); 1327 binbuf_evalfile(name, dir); 1328 while ((x != s__X.s_thing) && (x = s__X.s_thing)) 1329 vmess(x, gensym("pop"), "i", 1); 1330 pd_doloadbang(); 1331 canvas_resume_dsp(dspstate); 1332} 1333