/* ------------------------- match ------------------------------------------ */ /* */ /* Outputs a list when a list of input values matches the creation args. */ /* Written by Krzysztof Czaja for his cyclone library. */ /* Modified to fit into maxlib by Olaf Matthes . */ /* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ /* */ /* 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, write to the Free Software */ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* */ /* Based on PureData by Miller Puckette and others. */ /* */ /* ---------------------------------------------------------------------------- */ /* this is the original copyright notice: */ /* Copyright (c) 1997-2002 Miller Puckette and others. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ #include #include "m_pd.h" #define MATCH_INISIZE 16 /* LATER rethink */ typedef struct _match { t_object x_ob; int x_size; /* as allocated */ int x_patlen; /* as used */ t_atom *x_pattern; t_atom x_patini[MATCH_INISIZE]; int x_quelen; t_atom *x_queue; t_atom x_queini[MATCH_INISIZE]; t_atom *x_queend; t_atom *x_queptr; /* writing head, post-incremented (oldest-pointing) */ int x_; } t_match; static t_class *match_class; /* a caller must check for nrequested > *sizep */ /* returns actual number of atoms: requested (success) or a default value of initial size (failure) */ /* the result is guaranteed to be >= min(nrequested, inisize) */ static int match_grow(int nrequested, int *sizep, t_atom **bufp, int inisize, t_atom *bufini) { int newsize = *sizep * 2; while (newsize < nrequested) newsize *= 2; if (*bufp == bufini) *bufp = (t_atom *)getbytes(newsize * sizeof(**bufp)); else *bufp = (t_atom *)resizebytes(*bufp, *sizep * sizeof(**bufp), newsize * sizeof(**bufp)); if (*bufp) *sizep = newsize; else { *bufp = bufini; nrequested = *sizep = inisize; } return (nrequested); } static void match_clear(t_match *x) { x->x_quelen = 0; x->x_queptr = x->x_queue; } /* x->x_patlen > 0 is assumed */ /* LATER use a lock to disable reentrant calls. I do not see any purpose of reentering match, but lets CHECKME first... */ static void match_checkin(t_match *x) { int i, patlen = x->x_patlen; t_atom *queptr, *pp, *qp; if (x->x_queptr >= x->x_queend) x->x_queptr = x->x_queue; else x->x_queptr++; if (x->x_quelen < patlen && ++(x->x_quelen) < patlen) return; qp = queptr = x->x_queptr; for (i = 0, pp = x->x_pattern; i < patlen; i++, pp++) { if (pp->a_type == A_FLOAT) { if (qp->a_type != A_FLOAT || qp->a_w.w_float != pp->a_w.w_float) break; } else if (pp->a_type == A_SYMBOL) { if (qp->a_type != A_SYMBOL || qp->a_w.w_symbol != pp->a_w.w_symbol) break; } else if (pp->a_type == A_NULL) { if (qp->a_type == A_FLOAT || qp->a_type == A_SYMBOL) { /* instantiating a pattern */ *pp = *qp; qp->a_type = A_NULL; } else break; /* LATER rethink */ } else break; /* LATER rethink */ if (qp >= x->x_queend) qp = x->x_queue; else qp++; } if (i == patlen) { pp = x->x_pattern; if (pp->a_type == A_FLOAT) { if (patlen == 1) outlet_float(((t_object *)x)->ob_outlet, pp->a_w.w_float); else outlet_list(((t_object *)x)->ob_outlet, &s_list, patlen, pp); } else /* assuming A_SYMBOL (see above) */ { if (pp->a_w.w_symbol == &s_symbol /* bypassing typedmess() */ && patlen == 2 && pp[1].a_type == A_SYMBOL) outlet_symbol(((t_object *)x)->ob_outlet, pp[1].a_w.w_symbol); else outlet_anything(((t_object *)x)->ob_outlet, pp->a_w.w_symbol, patlen - 1, pp + 1); } /* CHECKED: no implicit clear (resolving overlapping patterns) */ } /* restoring a pattern */ for (i = 0, pp = x->x_pattern; i < patlen; i++, pp++) { if (queptr->a_type == A_NULL) { queptr->a_type = pp->a_type; pp->a_type = A_NULL; } if (queptr >= x->x_queend) queptr = x->x_queue; else queptr++; } } static void match_float(t_match *x, t_float f) { if (x->x_patlen) { SETFLOAT(x->x_queptr, f); match_checkin(x); } } static void match_symbol(t_match *x, t_symbol *s) { if (s && s != &s_ && x->x_patlen) { SETSYMBOL(x->x_queptr, s); match_checkin(x); } } /* LATER gpointer */ static void match_list(t_match *x, t_symbol *s, int ac, t_atom *av) { while (ac--) { if (av->a_type == A_FLOAT) match_float(x, av->a_w.w_float); else if (av->a_type == A_SYMBOL) match_symbol(x, av->a_w.w_symbol); av++; } } static void match_anything(t_match *x, t_symbol *s, int ac, t_atom *av) { match_symbol(x, s); match_list(x, 0, ac, av); } static void match_set(t_match *x, t_symbol *s, int ac, t_atom *av) { if (ac) /* CHECKED */ { t_atom *pp; t_symbol *ps_nn; int newlen = ac * 2; if (newlen > x->x_size) { newlen = match_grow(newlen, &x->x_size, &x->x_pattern, MATCH_INISIZE * 2, x->x_patini); if (newlen == MATCH_INISIZE * 2) { x->x_queue = x->x_queini; ac = MATCH_INISIZE; } else x->x_queue = x->x_pattern + x->x_size / 2; } x->x_patlen = ac; x->x_queend = x->x_queue + ac - 1; match_clear(x); /* CHECKED */ memcpy(x->x_pattern, av, ac * sizeof(*x->x_pattern)); pp = x->x_pattern; ps_nn = gensym("nn"); while (ac--) { if (pp->a_type == A_SYMBOL && pp->a_w.w_symbol == ps_nn) pp->a_type = A_NULL; pp++; } } } static void match_free(t_match *x) { if (x->x_pattern != x->x_patini) freebytes(x->x_pattern, 2 * x->x_size * sizeof(*x->x_pattern)); } static void *match_new(t_symbol *s, int ac, t_atom *av) { t_match *x = (t_match *)pd_new(match_class); x->x_size = MATCH_INISIZE * 2; x->x_patlen = 0; x->x_pattern = x->x_patini; x->x_queue = x->x_queini; /* x->x_queend is not used unless x->x_patlen > 0, LATER consider chosing a more defensive way... */ outlet_new((t_object *)x, &s_anything); match_clear(x); match_set(x, 0, ac, av); return (x); } #ifndef MAXLIB void match_setup(void) { match_class = class_new(gensym("match"), (t_newmethod)match_new, (t_method)match_free, sizeof(t_match), 0, A_GIMME, 0); #else void maxlib_match_setup(void) { match_class = class_new(gensym("maxlib_match"), (t_newmethod)match_new, (t_method)match_free, sizeof(t_match), 0, A_GIMME, 0); class_addcreator((t_newmethod)match_new, gensym("match"), A_GIMME, 0); #endif class_addfloat(match_class, match_float); class_addsymbol(match_class, match_symbol); class_addlist(match_class, match_list); class_addanything(match_class, match_anything); class_addmethod(match_class, (t_method)match_set, gensym("set"), A_GIMME, 0); class_addmethod(match_class, (t_method)match_clear, gensym("clear"), 0); #ifndef MAXLIB #else class_sethelpsymbol(match_class, gensym("maxlib/match-help.pd")); #endif }