/* For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. iemlib2 written by Thomas Musil, Copyright (c) IEM KUG Graz Austria 2000 - 2009 */ #include "m_pd.h" #include "iemlib.h" #include #include #include #include /* ---------------------------- iem_pbank_csv ------------------------------- */ /* -- is a list storage and management object, can store an array of lists -- */ /* ------------------------------- as an csv file --------------------------- */ /* read and write method needs 2 symbols, 1. symbol is a filename, 2. symbol is a 2 character descriptor 1.char: 'b'...for blank as ITEM_SEPARATOR (" ") 1.char: 's'...for semicolon as ITEM_SEPARATOR (";") 1.char: 't'...for tabulator as ITEM_SEPARATOR (" " = 0x09) 2.char: 'b'...for blank,return as END_OF_LINE (" \n") 2.char: 's'...for semicolon,return as END_OF_LINE (";\n") 2.char: 't'...for tabulator,return as END_OF_LINE (" \n") 2.char: 'r'...for return-only as END_OF_LINE ("\n") change: recall + offset + number */ #define IEMLIB2_DEBUG 0 #define IEM_PBANK_ITEM_SEPARATOR 0 #define IEM_PBANK_END_OF_LINE 1 #define IEM_PBANK_FORMAT_SIZE 2 #define IEM_PBANK_UNIFIED_RET 0x01 #define IEM_PBANK_UNIFIED_SEP 0x02 #define IEM_PBANK_UNIFIED_EOL 0x03 static t_class *iem_pbank_csv_class; typedef struct _iem_pbank_csv { t_object x_obj; int x_nr_para; int x_nr_line; int x_line; t_atom *x_atbegmem; t_atom *x_atbegbuf; t_atom *x_atbegout; t_canvas *x_canvas; void *x_list_out; void *x_offset_list_out; } t_iem_pbank_csv; static void iem_pbank_csv_write(t_iem_pbank_csv *x, t_symbol *filename, t_symbol *format) { char completefilename[400], eol[8], sep, mode[4], string[200]; int size, p, l, nrl=x->x_nr_line, nrp=x->x_nr_para; int state, max=nrl*nrp, org_size, eol_offset; FILE *fh; t_atom *ap=x->x_atbegmem; char formattext[100]; strcpy(mode, "br"); // default: blank-separator, return-eol, return depends on operating system sep = ' '; sprintf(eol, ";\n"); eol_offset = 1; if(filename->s_name[0] == '/')// linux, OSX { strcpy(completefilename, filename->s_name); } else if(((filename->s_name[0] >= 'A')&&(filename->s_name[0] <= 'Z')|| (filename->s_name[0] >= 'a')&&(filename->s_name[0] <= 'z'))&& (filename->s_name[1] == ':')&&(filename->s_name[2] == '/'))// windows, backslash becomes slash in pd { strcpy(completefilename, filename->s_name); } else { strcpy(completefilename, canvas_getdir(x->x_canvas)->s_name); strcat(completefilename, "/"); strcat(completefilename, filename->s_name); } fh = fopen(completefilename,"wb"); if(!fh) { post("iem_pbank_csv_write: cannot create %s !!\n", completefilename); } else { if(strlen(format->s_name) >= IEM_PBANK_FORMAT_SIZE) { for(p=0; ps_name[p] >= 'A')&&(format->s_name[p] <= 'Z')) format->s_name[p] += 'a' - 'A'; } if((format->s_name[IEM_PBANK_ITEM_SEPARATOR] == 'b') ||(format->s_name[IEM_PBANK_ITEM_SEPARATOR] == 's') ||(format->s_name[IEM_PBANK_ITEM_SEPARATOR] == 't')) mode[IEM_PBANK_ITEM_SEPARATOR] = format->s_name[IEM_PBANK_ITEM_SEPARATOR]; if((format->s_name[IEM_PBANK_END_OF_LINE] == 'b') ||(format->s_name[IEM_PBANK_END_OF_LINE] == 's') ||(format->s_name[IEM_PBANK_END_OF_LINE] == 't') ||(format->s_name[IEM_PBANK_END_OF_LINE] == 'r')) mode[IEM_PBANK_END_OF_LINE] = format->s_name[IEM_PBANK_END_OF_LINE]; } else post("iem_pbank_csv_write: use default format %s !!\n", mode); if(mode[IEM_PBANK_ITEM_SEPARATOR] == 'b') { sep = ' '; strcpy(formattext, "item-separator = BLANK; "); } else if(mode[IEM_PBANK_ITEM_SEPARATOR] == 's') { sep = ';'; strcpy(formattext, "item-separator = SEMICOLON; "); } else if(mode[IEM_PBANK_ITEM_SEPARATOR] == 't') { sep = 0x09; strcpy(formattext, "item-separator = TABULATOR; "); } eol_offset = 0; if(mode[IEM_PBANK_END_OF_LINE] == 'b') { eol[0] = ' '; strcat(formattext, "end_of_line_terminator = BLANK-RETURN."); } else if(mode[IEM_PBANK_END_OF_LINE] == 's') { eol[0] = ';'; strcat(formattext, "end_of_line_terminator = SEMICOLON-RETURN."); } else if(mode[IEM_PBANK_END_OF_LINE] == 't') { eol[0] = 0x09; strcat(formattext, "end_of_line_terminator = TABULATOR-RETURN."); } else if(mode[IEM_PBANK_END_OF_LINE] == 'r') { eol_offset = 1; strcat(formattext, "end_of_line_terminator = RETURN."); } ap = x->x_atbegmem; for(l=0; la_w.w_float, sep); else if(IS_A_SYMBOL(ap, 0)) fprintf(fh, "%s%c", ap->a_w.w_symbol->s_name, sep); ap++; } if(IS_A_FLOAT(ap, 0)) fprintf(fh, "%g%s", ap->a_w.w_float, eol+eol_offset); else if(IS_A_SYMBOL(ap, 0)) fprintf(fh, "%s%s", ap->a_w.w_symbol->s_name, eol+eol_offset); ap++; } fclose(fh); post("iem_pbank_csv: wrote %d parameters x %d lines to file:\n%s\nwith following format:\n%s\n", nrp, nrl, completefilename, formattext); } } static int iem_pbank_csv_text2atom(char *text, int text_size, t_atom **at_beg, int *nalloc, char sep, char eol) { char buf[MAXPDSTRING+1], *bufp, *ebuf = buf+MAXPDSTRING; const char *textp = text, *etext = text + text_size; int natom = 0; t_atom *ap = *at_beg; t_float f; while(1) { int type; if(textp == etext) break; if(*textp == eol) { SETSEMI(ap); textp++; } else if(*textp == sep) { SETCOMMA(ap); textp++; } else { char c; int flst = 0, slash = 0, lastslash = 0; int firstslash = (*textp == '\\'); bufp = buf; do { c = *bufp = *textp++; lastslash = slash; slash = (c == '\\'); if (flst >= 0) { int digit = (c >= '0' && c <= '9'), dot = (c == '.'), minus = (c == '-'), plusminus = (minus || (c == '+')), expon = (c == 'e' || c == 'E'); if (flst == 0) /* beginning */ { if (minus) flst = 1; else if (digit) flst = 2; else if (dot) flst = 3; else flst = -1; } else if (flst == 1) /* got minus */ { if (digit) flst = 2; else if (dot) flst = 3; else flst = -1; } else if (flst == 2) /* got digits */ { if (dot) flst = 4; else if (expon) flst = 6; else if (!digit) flst = -1; } else if (flst == 3) /* got '.' without digits */ { if (digit) flst = 5; else flst = -1; } else if (flst == 4) /* got '.' after digits */ { if (digit) flst = 5; else if (expon) flst = 6; else flst = -1; } else if (flst == 5) /* got digits after . */ { if (expon) flst = 6; else if (!digit) flst = -1; } else if (flst == 6) /* got 'e' */ { if (plusminus) flst = 7; else if (digit) flst = 8; else flst = -1; } else if (flst == 7) /* got plus or minus */ { if (digit) flst = 8; else flst = -1; } else if (flst == 8) /* got digits */ { if (!digit) flst = -1; } } if (!slash) bufp++; } while (textp != etext && bufp != ebuf && *textp != ' ' && (slash || (*textp != sep && *textp != eol))); *bufp = 0; if(*buf == '$' && buf[1] >= '0' && buf[1] <= '9' && !firstslash) { for (bufp = buf+2; *bufp; bufp++) if (*bufp < '0' || *bufp > '9') { SETDOLLSYM(ap, gensym(buf+1)); goto iem_pbank_csv_didit; } SETDOLLAR(ap, atoi(buf+1)); iem_pbank_csv_didit: ; } else { if(flst == 2 || flst == 4 || flst == 5 || flst == 8) { f = atof(buf); if((f < 1.0e-20)&&(f > -1.0e-20)) f = 0.0; SETFLOAT(ap, f); } else SETSYMBOL(ap, gensym(buf)); } } ap++; natom++; if(natom == *nalloc) { *at_beg = t_resizebytes(*at_beg, *nalloc * sizeof(t_atom), *nalloc * (2*sizeof(t_atom))); *nalloc = *nalloc * 2; ap = *at_beg + natom; } if(textp == etext) break; } return(natom); } static void iem_pbank_csv_debug(char *buf, int n) { while(n >= 16) { post("%x %x %x %x | %x %x %x %x | %x %x %x %x | %x %x %x %x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); n -= 16; buf += 16; } switch(n) { case 15: post("%x %x %x %x | %x %x %x %x | %x %x %x %x | %x %x %x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14]); break; case 14: post("%x %x %x %x | %x %x %x %x | %x %x %x %x | %x %x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]); break; case 13: post("%x %x %x %x | %x %x %x %x | %x %x %x %x | %x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12]); break; case 12: post("%x %x %x %x | %x %x %x %x | %x %x %x %x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]); break; case 11: post("%x %x %x %x | %x %x %x %x | %x %x %x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10]); break; case 10: post("%x %x %x %x | %x %x %x %x | %x %x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9]); break; case 9: post("%x %x %x %x | %x %x %x %x | %x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]); break; case 8: post("%x %x %x %x | %x %x %x %x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); break; case 7: post("%x %x %x %x | %x %x %x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); break; case 6: post("%x %x %x %x | %x %x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); break; case 5: post("%x %x %x %x | %x", buf[0], buf[1], buf[2], buf[3], buf[4]); break; case 4: post("%x %x %x %x", buf[0], buf[1], buf[2], buf[3]); break; case 3: post("%x %x %x", buf[0], buf[1], buf[2]); break; case 2: post("%x %x", buf[0], buf[1]); break; case 1: post("%x", buf[0]); break; } } static void iem_pbank_csv_read(t_iem_pbank_csv *x, t_symbol *filename, t_symbol *format) { char completefilename[400], eol, sep, mode[4], *txbuf1, *txbuf2, *txvec_src, *txvec_dst; int size, p, l, i, j, nrl=x->x_nr_line, nrp=x->x_nr_para, atlen=0; int txlen, txalloc, hat_alloc, max, eol_length; FILE *fh; t_atom *ap, *hap, *at; char formattext[100], str_format[8]; strcpy(mode, "br"); // blank-separator, return-eol sep = ' '; // default SEP = space eol = ';'; // default any char eol_length = 1; // default: EOL = return only if(filename->s_name[0] == '/')/*make complete path + filename*/ { strcpy(completefilename, filename->s_name); } else if(((filename->s_name[0] >= 'A')&&(filename->s_name[0] <= 'Z')|| (filename->s_name[0] >= 'a')&&(filename->s_name[0] <= 'z'))&& (filename->s_name[1] == ':')&&(filename->s_name[2] == '/')) { strcpy(completefilename, filename->s_name); } else { strcpy(completefilename, canvas_getdir(x->x_canvas)->s_name); strcat(completefilename, "/"); strcat(completefilename, filename->s_name); } fh = fopen(completefilename,"rb"); if(!fh) { post("iem_pbank_csv_read: cannot open %s !!\n", completefilename); } else { if(strlen(format->s_name) >= IEM_PBANK_FORMAT_SIZE) { strncpy(str_format, format->s_name, IEM_PBANK_FORMAT_SIZE); str_format[IEM_PBANK_FORMAT_SIZE] = 0; for(p=0; p= 'A')&&(str_format[p] <= 'Z')) str_format[p] += 'a' - 'A'; } if((str_format[IEM_PBANK_ITEM_SEPARATOR] == 'b') ||(str_format[IEM_PBANK_ITEM_SEPARATOR] == 's') ||(str_format[IEM_PBANK_ITEM_SEPARATOR] == 't')) mode[IEM_PBANK_ITEM_SEPARATOR] = str_format[IEM_PBANK_ITEM_SEPARATOR]; if((str_format[IEM_PBANK_END_OF_LINE] == 'b') ||(str_format[IEM_PBANK_END_OF_LINE] == 's') ||(str_format[IEM_PBANK_END_OF_LINE] == 't') ||(str_format[IEM_PBANK_END_OF_LINE] == 'r')) mode[IEM_PBANK_END_OF_LINE] = str_format[IEM_PBANK_END_OF_LINE]; } else post("iem_pbank_csv_read: use default format %s !!\n", mode); if(mode[IEM_PBANK_ITEM_SEPARATOR] == 'b') { sep = ' '; strcpy(formattext, "item-separator = BLANK; "); } else if(mode[IEM_PBANK_ITEM_SEPARATOR] == 's') { sep = ';'; strcpy(formattext, "item-separator = SEMICOLON; "); } else if(mode[IEM_PBANK_ITEM_SEPARATOR] == 't') { sep = 0x09; strcpy(formattext, "item-separator = TABULATOR; "); } eol_length = 2; // if EOL are 2 char if(mode[IEM_PBANK_END_OF_LINE] == 'b') { eol = ' '; strcat(formattext, "end_of_line_terminator = BLANK-RETURN."); } else if(mode[IEM_PBANK_END_OF_LINE] == 's') { eol = ';'; strcat(formattext, "end_of_line_terminator = SEMICOLON-RETURN."); } else if(mode[IEM_PBANK_END_OF_LINE] == 't') { eol = 0x09; strcat(formattext, "end_of_line_terminator = TABULATOR-RETURN."); } else if(mode[IEM_PBANK_END_OF_LINE] == 'r') { eol_length = 1; // if EOL is only 1 char = return oly strcat(formattext, "end_of_line_terminator = RETURN."); } fseek(fh, 0, SEEK_END); txalloc = ftell(fh); fseek(fh,0,SEEK_SET); txbuf1 = (char *)getbytes((2 * txalloc + 256) * sizeof(char)); txbuf2 = (char *)getbytes((2 * txalloc + 256) * sizeof(char)); if(fread(txbuf1, sizeof(char), txalloc, fh) < sizeof(char)*txalloc) post("pbank.csv:435: warning read error (not specified)"); fclose(fh); // 1.) allow only readable ASCII (0x09, 0x0a, 0x0d, 0x20...0x7e = // = TAB, LF, CR, ' ' ... '~' = // = Tabulator, LineFeed, CarridgeReturn, Space ... Tilde), else drop txvec_src = txbuf1; txvec_dst = txbuf2; txlen = txalloc; p = 0; for(l=0; l= ' ') && (*txvec_src <= '~')) || (*txvec_src == 0x09) || (*txvec_src == 0x0a) || (*txvec_src == 0x0d)) { *txvec_dst++ = *txvec_src++; // copy the same char p++; } else txvec_src++;// drop anything else } txlen = p; // dst is 2 // 2.) unify windows return txvec_src = txbuf2; txvec_dst = txbuf1; p = 0; txlen--; // because we seek 2 char for(l=0; lx_atbegmem; for(l=0; lx_atbegmem; ap = hap; nrp++; i = 0; /* atom-counter */ j = 0; for(l=0; la_w.w_float); /*post("float");*/ p++; i++; at++; } else if(IS_A_SYMBOL(ap,0)) { SETSYMBOL(at, ap->a_w.w_symbol); /*post("sym");*/ p++; i++; at++; } else if(IS_A_SEMI(ap,0)) { /*post("semi");*/ for(; px_nr_para; t_atom *atbuf=x->x_atbegbuf, *atmem=x->x_atbegmem; t_atom *atout=x->x_atbegout; if(ac >= 2) nrp = atom_getintarg(1, ac, av); if(ac >= 1) beg = atom_getintarg(0, ac, av); if(beg < 0) beg = 0; else if(beg >= x->x_nr_para) beg = x->x_nr_para - 1; if(nrp < 0) nrp = 0; else if((beg+nrp) > x->x_nr_para) nrp = x->x_nr_para - beg; atmem += x->x_nr_para * x->x_line + beg; atbuf += beg; SETFLOAT(atout, (t_float)beg); atout++; for(i=0; ix_offset_list_out, &s_list, nrp+1, x->x_atbegout); outlet_list(x->x_list_out, &s_list, nrp, x->x_atbegout+1); } static void iem_pbank_csv_bang(t_iem_pbank_csv *x) { int i, nrp=x->x_nr_para; t_atom *atbuf=x->x_atbegbuf; t_atom *atout=x->x_atbegout; SETFLOAT(atout, 0.0f); atout++; for(i=0; ix_offset_list_out, &s_list, nrp+1, x->x_atbegout); outlet_list(x->x_list_out, &s_list, nrp, x->x_atbegout+1); } static void iem_pbank_csv_store(t_iem_pbank_csv *x, t_symbol *s, int ac, t_atom *av) { int i, beg=0, nrp=x->x_nr_para; t_atom *atbuf=x->x_atbegbuf, *atmem=x->x_atbegmem; if(ac >= 2) nrp = atom_getintarg(1, ac, av); if(ac >= 1) beg = atom_getintarg(0, ac, av); if(beg < 0) beg = 0; else if(beg >= x->x_nr_para) beg = x->x_nr_para - 1; if(nrp < 0) nrp = 0; else if((beg+nrp) > x->x_nr_para) nrp = x->x_nr_para - beg; atmem += x->x_nr_para * x->x_line; atmem += beg; atbuf += beg; for(i=0; i= 2) { int para_index = atom_getintarg(0, ac, av); if(para_index >= 0) { if((para_index+ac-1) <= x->x_nr_para) { int i; for(i=1; ix_atbegbuf[para_index] = av[i]; para_index++; } } } } } static void iem_pbank_csv_ft1(t_iem_pbank_csv *x, t_floatarg fline_nr) { int line = (int)fline_nr; if(line < 0) line = 0; else if(line >= x->x_nr_line) line = x->x_nr_line - 1; x->x_line = line; } static void iem_pbank_csv_free(t_iem_pbank_csv *x) { freebytes(x->x_atbegmem, x->x_nr_para * x->x_nr_line * sizeof(t_atom)); freebytes(x->x_atbegbuf, x->x_nr_para * sizeof(t_atom)); freebytes(x->x_atbegout, (x->x_nr_para+1) * sizeof(t_atom)); } static void *iem_pbank_csv_new(t_symbol *s, int ac, t_atom *av) { t_iem_pbank_csv *x = (t_iem_pbank_csv *)pd_new(iem_pbank_csv_class); int nrpp=0, nrp=10, nrl=10, p, l, i; t_atom *ap; if((ac >= 1) && IS_A_FLOAT(av,0)) nrp = atom_getintarg(0, ac, av); if((ac >= 2) && IS_A_FLOAT(av,1)) nrl = atom_getintarg(1, ac, av); if(nrp <= 0) nrp = 10; if(nrl <= 0) nrl = 10; x->x_line = 0; x->x_nr_para = nrp; x->x_nr_line = nrl; x->x_atbegmem = (t_atom *)getbytes(x->x_nr_para * x->x_nr_line * sizeof(t_atom)); x->x_atbegbuf = (t_atom *)getbytes(x->x_nr_para * sizeof(t_atom)); x->x_atbegout = (t_atom *)getbytes((x->x_nr_para+1) * sizeof(t_atom)); ap = x->x_atbegmem; for(l=0; lx_atbegbuf; for(p=0; px_list_out = outlet_new(&x->x_obj, &s_list); /*left out*/ x->x_offset_list_out = outlet_new(&x->x_obj, &s_list); /*right out*/ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1")); x->x_canvas = canvas_getcurrent(); return (x); } /* ---------------- global setup function -------------------- */ void iem_pbank_csv_setup(void ) { iem_pbank_csv_class = class_new(gensym("iem_pbank_csv"), (t_newmethod)iem_pbank_csv_new, (t_method)iem_pbank_csv_free, sizeof(t_iem_pbank_csv), 0, A_GIMME, 0); class_addmethod(iem_pbank_csv_class, (t_method)iem_pbank_csv_recall, gensym("recall"), A_GIMME, 0); class_addmethod(iem_pbank_csv_class, (t_method)iem_pbank_csv_store, gensym("store"), A_GIMME, 0); class_addmethod(iem_pbank_csv_class, (t_method)iem_pbank_csv_read, gensym("read"), A_SYMBOL, A_DEFSYM, 0); class_addmethod(iem_pbank_csv_class, (t_method)iem_pbank_csv_write, gensym("write"), A_SYMBOL, A_DEFSYM, 0); class_addlist(iem_pbank_csv_class, iem_pbank_csv_list); class_addbang(iem_pbank_csv_class, iem_pbank_csv_bang); class_addmethod(iem_pbank_csv_class, (t_method)iem_pbank_csv_ft1, gensym("ft1"), A_FLOAT, 0); // class_sethelpsymbol(iem_pbank_csv_class, gensym("iemhelp/help-iem_pbank_csv")); }