/* * liststorage: stores a number of lists * * (c) 1999-2011 IOhannes m zmölnig, forum::für::umläute, institute of electronic music and acoustics (iem) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ /* this is heavily based on code from [textfile], which is part of pd and written by Miller S. Puckette pd (and thus [textfile]) come with their own license */ #include "zexy.h" #ifdef __WIN32__ # include #else # include #endif #include #include #include /* ****************************************************************************** */ /* liststorage : store several lists in a slots (array of lists of lists) */ /* a list of lists */ typedef struct _msglist { int argc; t_atom *argv; struct _msglist *next; } t_msglist; typedef struct _liststorage { t_object x_obj; /* everything */ t_outlet*x_dataout; /* where the data appears */ t_outlet*x_infoout; /* where meta-information appears */ t_inlet*x_slotin; /* setting the current slot */ int x_numslots, x_defaultnumslots; int x_currentslot; t_msglist**x_slots; } t_liststorage; static t_class *liststorage_class; /* ************************************************************************ */ /* helper functions */ static t_msglist*_liststorage_getslot(t_liststorage*x, int slot) { // post("getting slot %d of %d|%d", slot, 0, x->x_numslots); if(slot<0 || slot>=x->x_numslots) { pd_error(x, "[liststorage]: attempting to access invalid slot %d", slot); return NULL; } return x->x_slots[slot]; } static void _liststorage_deletemsglist(t_msglist*list) { t_msglist*x=list; while(x) { t_msglist*y=x; x=x->next; freebytes(y->argv, y->argc*sizeof(t_atom)); y->argc=0; y->argv=NULL; y->next=NULL; freebytes(y, sizeof(t_msglist)); } } static void _liststorage_deleteslot(t_liststorage*x, int slot) { t_msglist*list=_liststorage_getslot(x, slot); if(list) { _liststorage_deletemsglist(list); x->x_slots[slot]=NULL; } } static t_msglist*_liststorage_newslot(int argc, t_atom*argv) { t_msglist*slot=getbytes(sizeof(t_msglist)); int i=0; slot->argv=getbytes(sizeof(t_atom)*argc); for(i=0; iargv[i]=argv[i]; } slot->argc=argc; slot->next=NULL; return slot; } static t_msglist*_liststorage_add2slot(t_msglist*slot, int argc, t_atom*argv) { t_msglist*dummy=slot; t_msglist*newlist=_liststorage_newslot(argc, argv); if(NULL==slot) { // post("no data yet: new data is %x", newlist); return newlist; } while(dummy->next) { dummy=dummy->next; } dummy->next=newlist; // post("added data to slot @ %x", slot); return slot; } static int _liststorage_resize(t_liststorage*x, int size) { t_msglist**newarray=NULL; int i=0; if(size<0) { pd_error(x, "[liststorage]: refusing to resize for negative amount of slots"); return 0; } if(size==x->x_numslots) { verbose(1, "[liststorate] no need to resize array"); return size; } /* create a new array */ newarray=getbytes(sizeof(t_msglist*)*size); for(i=0; ix_numslots)?size:x->x_numslots; while(i-->0) { newarray[i]=x->x_slots[i]; x->x_slots[i]=NULL; } /* delete the old array */ for(i=0; ix_numslots; i++) { _liststorage_deleteslot(x, i); } freebytes(x->x_slots, sizeof(t_msglist*)); /* make the new array the current */ x->x_slots=newarray; x->x_numslots=size; return size; } static int _liststorage_checkslot(t_liststorage*x, const char*string, const int resize) { int slot=x->x_currentslot; t_atom atom; SETFLOAT(&atom, (t_float)slot); if(slot<0) { if(NULL!=string) { pd_error(x, "[liststorage]: %s %d", string, slot); } outlet_anything(x->x_infoout, gensym("invalidslot"), 1, &atom); return -1; } if(slot>=x->x_numslots) { if(resize) { _liststorage_resize(x, slot+1); } else { if(NULL!=string) { pd_error(x, "[liststorage]: %s %d", string, slot); } outlet_anything(x->x_infoout, gensym("invalidslot"), 1, &atom); return -1; } } return slot; } /* ************************************************************************ */ /* object methods */ /* recall all lists from the current slot */ static void liststorage_bang(t_liststorage *x) { t_atom atom; t_msglist*list=NULL; int slot=_liststorage_checkslot(x, "attempting to read data from invalid slot", 0); if(slot<0) { return; } list=_liststorage_getslot(x, slot); while(list) { outlet_list(x->x_dataout, gensym("list"), list->argc, list->argv); list=list->next; } SETFLOAT(&atom, (t_float)slot); /* no need for done: use [t b b b] to get beginning and end of output */ // outlet_anything(x->x_infoout, gensym("done"), 1, &atom); } /* add a new list to the current slot */ static void liststorage_add(t_liststorage *x, t_symbol *s, int ac, t_atom *av) { t_msglist*list=NULL; int slot=_liststorage_checkslot(x, "attempting to add data to invalid slot", 1); if(slot<0) { return; } list=_liststorage_getslot(x, slot); x->x_slots[slot]=_liststorage_add2slot(x->x_slots[slot], ac, av); } /* clear the current slot */ static void liststorage_clear(t_liststorage *x) { int slot=_liststorage_checkslot(x, "attempting to clear invalid slot", 0); if(slot<0) { return; } _liststorage_deleteslot(x, slot); } /* clear all slots */ static void liststorage_clearall(t_liststorage *x) { int i=0; for(i=0; ix_numslots; i++) { _liststorage_deleteslot(x, i); } } /* insert an empty slot at (before) given position */ static void liststorage_insert(t_liststorage *x, t_floatarg f) { int current=x->x_currentslot; int slot=-1; int i=0; x->x_currentslot=f; slot=_liststorage_checkslot(x, "attempting to insert invalid slot", 1); x->x_currentslot=current; if(slot<0) { return; } _liststorage_resize(x, x->x_numslots+1); for(i=x->x_numslots-1; i>slot; i--) { x->x_slots[i]=x->x_slots[i-1]; } x->x_slots[slot]=NULL; } /* get the number of slots */ static void liststorage_info(t_liststorage *x) { t_atom ap; SETFLOAT(&ap, (t_float)x->x_numslots); outlet_anything(x->x_infoout, gensym("numslots"), 1, &ap); } /* get the number of slots */ static void liststorage_slot(t_liststorage *x, t_floatarg f) { int slot=f; x->x_currentslot=slot; } /* remove empty slots */ static void liststorage_compress(t_liststorage *x) { t_msglist**newarray=NULL; int i=0, j=0; int size=0; for(i=0; ix_numslots; i++) { if(NULL!=x->x_slots[i]) { size++; } } if(size>=x->x_numslots) { // post("incomressible: %d of %d", size, x->x_numslots); return; } if(sizex_defaultnumslots) { size=x->x_defaultnumslots; } /* create a new array */ newarray=getbytes(sizeof(t_msglist*)*size); for(i=0; ix_numslots; i++) { if(NULL!=x->x_slots[i]) { newarray[j]=x->x_slots[i]; j++; } x->x_slots[i]=NULL; } /* delete the old array */ for(i=0; ix_numslots; i++) { _liststorage_deleteslot(x, i); } freebytes(x->x_slots, sizeof(t_msglist*)); /* make the new array the current */ x->x_slots=newarray; x->x_numslots=size; } /* ************************************************************************ */ /* constructor/destructor */ static void liststorage_free(t_liststorage *x) { liststorage_clearall(x); _liststorage_resize(x, 0); } /* constructor: argument is initial number of slots (can grow) */ static void *liststorage_new(t_floatarg f) { t_liststorage *x = (t_liststorage *)pd_new(liststorage_class); int slots=f; x->x_slotin=inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("slot")); x->x_dataout=outlet_new(&x->x_obj, gensym("list")); x->x_infoout=outlet_new(&x->x_obj, 0); if(slots<=0) { slots=20; } x->x_defaultnumslots=slots; x->x_numslots=0; x->x_currentslot=0; x->x_slots=NULL; _liststorage_resize(x, x->x_defaultnumslots); return (x); } void liststorage_setup(void) { liststorage_class = class_new(gensym("liststorage"), (t_newmethod)liststorage_new, (t_method)liststorage_free, sizeof(t_liststorage), 0, A_DEFFLOAT, 0); /* recall all lists from the current slot */ class_addbang(liststorage_class, (t_method)liststorage_bang); /* add a new list to the current slot */ class_addmethod(liststorage_class, (t_method)liststorage_add, gensym("add"), A_GIMME, 0); /* clear the current slot */ class_addmethod(liststorage_class, (t_method)liststorage_clear, gensym("clear"), 0); /* clear all slots */ class_addmethod(liststorage_class, (t_method)liststorage_clearall, gensym("clearall"), 0); /* add a new list to the current slot */ class_addmethod(liststorage_class, (t_method)liststorage_slot, gensym("slot"), A_FLOAT, 0); /* insert an empty slot at (before) given position */ class_addmethod(liststorage_class, (t_method)liststorage_insert, gensym("insert"), A_DEFFLOAT, 0); /* remove empty slots */ class_addmethod(liststorage_class, (t_method)liststorage_compress, gensym("compress"), 0); /* get the number of slots */ class_addmethod(liststorage_class, (t_method)liststorage_info, gensym("info"), 0); zexy_register("liststorage"); }