aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/matchbox.pd60
-rw-r--r--src/matchbox.c502
-rw-r--r--src/z_zexy.c1
-rw-r--r--src/z_zexy.h1
-rw-r--r--src/zexy.h2
-rw-r--r--src/zexyconf.h21
6 files changed, 573 insertions, 14 deletions
diff --git a/examples/matchbox.pd b/examples/matchbox.pd
new file mode 100644
index 0000000..c116012
--- /dev/null
+++ b/examples/matchbox.pd
@@ -0,0 +1,60 @@
+#N canvas 80 59 728 623 10;
+#X text 68 47 you can store a number of lists by sending them to its
+right inlet.;
+#X text 50 23 [matchbox] - retrieve matching lists;
+#X text 67 76 when you send a list to the left inlet of [matchbox]
+\, it will be compared to each stored list \; any matches will be send
+to the first output of [matchbox]. the number of matches is sent to
+the 2nd outlet.;
+#X text 69 141 there are several matching algorithms available. you
+can choose between them via the "mode" message or by providing an argument
+at object creation.;
+#X text 70 185 currently available matching-modes:;
+#X text 90 204 '==': only matches if lists are exactly equal;
+#X text 91 223 'OSC': list-atoms are compared using OSC-pattern matching
+;
+#X obj 205 384 matchbox;
+#X floatatom 248 405 5 0 0 1 num_results - -;
+#X obj 205 439 print results;
+#X msg 248 351 list this is my string \, list this is your string \,
+list this was my string;
+#X text 278 385 default is exact matching;
+#X msg 205 266 list this is my string;
+#X msg 218 285 list this is no string;
+#X msg 233 305 list this is * string;
+#X msg 119 332 mode ==;
+#X msg 120 350 mode OSC;
+#X msg 110 407 clear;
+#X msg 111 450 dump;
+#X text 37 395 delete all stored lists;
+#X text 35 438 output all stored lists;
+#X floatatom 240 595 5 0 0 1 num_results - -;
+#X msg 240 551 list this is my string \, list this is your string \,
+list this was my string;
+#X msg 173 480 list this is my string;
+#X obj 173 578 matchbox OSC;
+#X obj 173 613 print OSCresults;
+#X msg 201 513 list this *s * string;
+#X msg 186 496 list this is * string;
+#X obj 240 535 loadbang;
+#X obj 248 335 loadbang;
+#X text 301 336 add lists to the pool;
+#X text 52 314 change matching mode;
+#X connect 7 0 9 0;
+#X connect 7 1 8 0;
+#X connect 10 0 7 1;
+#X connect 12 0 7 0;
+#X connect 13 0 7 0;
+#X connect 14 0 7 0;
+#X connect 15 0 7 0;
+#X connect 16 0 7 0;
+#X connect 17 0 7 0;
+#X connect 18 0 7 0;
+#X connect 22 0 24 1;
+#X connect 23 0 24 0;
+#X connect 24 0 25 0;
+#X connect 24 1 21 0;
+#X connect 26 0 24 0;
+#X connect 27 0 24 0;
+#X connect 28 0 22 0;
+#X connect 29 0 10 0;
diff --git a/src/matchbox.c b/src/matchbox.c
new file mode 100644
index 0000000..2d1ab06
--- /dev/null
+++ b/src/matchbox.c
@@ -0,0 +1,502 @@
+/******************************************************
+ *
+ * zexy - implementation file
+ *
+ * copyleft (c) IOhannes m zmölnig
+ *
+ * 1999:forum::für::umläute:2004
+ *
+ * institute of electronic music and acoustics (iem)
+ *
+ ******************************************************
+ *
+ * license: GNU General Public License v.2
+ *
+ ******************************************************/
+
+
+
+/*
+OSC pattern matching code was written by Matt Wright,
+The Center for New Music and Audio Technologies,
+University of California, Berkeley. Copyright (c) 1998,99,2000,01,02,03,04
+The Regents of the University of California (Regents).
+
+Permission to use, copy, modify, distribute, and distribute modified versions
+of this software and its documentation without fee and without a signed
+licensing agreement, is hereby granted, provided that the above copyright
+notice, this paragraph and the following two paragraphs appear in all copies,
+modifications, and distributions.
+
+IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
+OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
+BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
+HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
+MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
+*/
+
+#include "zexy.h"
+
+#include <string.h>
+
+/*
+ * matchbox : see whether a regular expression matches the given symbol
+ */
+
+/* ------------------------- matchbox ------------------------------- */
+
+/* match the atoms of 2 lists */
+
+static t_class *matchbox_class;
+
+#define MATCHBOX_EXACT 0
+#define MATCHBOX_OSC 1
+
+
+typedef struct _listlist {
+ int argc;
+ t_atom *argv;
+ struct _listlist *next;
+} t_listlist;
+
+
+typedef struct _matchbox
+{
+ t_object x_obj;
+
+ t_listlist*x_lists;
+ unsigned int x_numlists;
+
+ int x_mode;
+
+ t_outlet*x_outResult;
+ t_outlet*x_outNumResults;
+} t_matchbox;
+
+
+/* ----------- here comes some infrastructure stuff -------------- */
+
+
+static t_listlist* addlistlist(t_listlist*list, int argc, t_atom*argv) {
+ t_listlist*ll=(t_listlist*)getbytes(sizeof(t_listlist));
+ ll->next=0;
+ ll->argc=argc;
+ ll->argv=(t_atom*)getbytes(argc*sizeof(t_atom));
+ memcpy(ll->argv, argv, argc*sizeof(t_atom));
+
+ if(0==list) {
+ return ll;
+ }
+
+ t_listlist*lp=list;
+ while(0!=lp->next)lp=lp->next;
+ lp->next=ll;
+
+ return list;
+}
+
+static void clearlistlist(t_listlist*list) {
+ while(list){
+ t_listlist*ll=list;
+ list=list->next;
+
+ if(ll->argv)freebytes(ll->argv, ll->argc*sizeof(t_atom));
+ ll->argv=0;
+ ll->argc=0;
+ ll->next=0;
+ freebytes(ll, sizeof(t_listlist));
+ }
+}
+
+
+
+/* -------------- here comes the matching algorithms ----------- */
+
+
+static int atommatch_exact(t_atom*pattern, t_atom*atom) {
+ if(pattern->a_type==atom->a_type) {
+ switch(pattern->a_type) {
+ case A_FLOAT:
+ return atom_getfloat(pattern)==atom_getfloat(atom);
+ case A_SYMBOL:
+ return atom_getsymbol(pattern)==atom_getsymbol(atom);
+ default:
+ return pattern==atom;
+ }
+ } else {
+ post("types don't match!");
+ return 0;
+ }
+
+ return 0;
+}
+
+#ifdef MATCHBOX_OSC /* OSC */
+
+#define OSCWarning post
+#define FALSE 0
+#define TRUE 1
+static int OSC_MatchBrackets (const char *pattern, const char *test, const char*theWholePattern);
+static int OSC_MatchList (const char *pattern, const char *test, const char*theWholePattern);
+
+static int OSC_PatternMatch (const char * pattern, const char * test, const char*theWholePattern) {
+ if (pattern == 0 || pattern[0] == 0) {
+ return test[0] == 0;
+ }
+
+ if (test[0] == 0) {
+ if (pattern[0] == '*')
+ return OSC_PatternMatch (pattern+1,test, theWholePattern);
+ else
+ return FALSE;
+ }
+
+ switch (pattern[0]) {
+ case 0 : return test[0] == 0;
+ case '?' : return OSC_PatternMatch (pattern + 1, test + 1, theWholePattern);
+ case '*' :
+ if (OSC_PatternMatch (pattern+1, test, theWholePattern)) {
+ return TRUE;
+ } else {
+ return OSC_PatternMatch (pattern, test+1, theWholePattern);
+ }
+ case ']' :
+ case '}' :
+ OSCWarning("Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern);
+ return FALSE;
+ case '[' :
+ return OSC_MatchBrackets (pattern,test, theWholePattern);
+ case '{' :
+ return OSC_MatchList (pattern,test, theWholePattern);
+ case '\\' :
+ if (pattern[1] == 0) {
+ return test[0] == 0;
+ } else if (pattern[1] == test[0]) {
+ return OSC_PatternMatch (pattern+2,test+1, theWholePattern);
+ } else {
+ return FALSE;
+ }
+ default :
+ if (pattern[0] == test[0]) {
+ return OSC_PatternMatch (pattern+1,test+1, theWholePattern);
+ } else {
+ return FALSE;
+ }
+ }
+}
+
+
+/* we know that pattern[0] == '[' and test[0] != 0 */
+
+static int OSC_MatchBrackets (const char *pattern, const char *test, const char*theWholePattern) {
+ int result;
+ int negated = FALSE;
+ const char *p = pattern;
+
+ if (pattern[1] == 0) {
+ OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
+ return FALSE;
+ }
+
+ if (pattern[1] == '!') {
+ negated = TRUE;
+ p++;
+ }
+
+ while (*p != ']') {
+ if (*p == 0) {
+ OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
+ return FALSE;
+ }
+ if (p[1] == '-' && p[2] != 0) {
+ if (test[0] >= p[0] && test[0] <= p[2]) {
+ result = !negated;
+ goto advance;
+ }
+ }
+ if (p[0] == test[0]) {
+ result = !negated;
+ goto advance;
+ }
+ p++;
+ }
+
+ result = negated;
+
+ advance:
+
+ if (!result)
+ return FALSE;
+
+ while (*p != ']') {
+ if (*p == 0) {
+ OSCWarning("Unterminated [ in pattern \".../%s/...\"", theWholePattern);
+ return FALSE;
+ }
+ p++;
+ }
+
+ return OSC_PatternMatch (p+1,test+1, theWholePattern);
+}
+
+static int OSC_MatchList (const char *pattern, const char *test, const char* theWholePattern) {
+
+ const char *restOfPattern, *tp = test;
+
+ for(restOfPattern = pattern; *restOfPattern != '}'; restOfPattern++) {
+ if (*restOfPattern == 0) {
+ OSCWarning("Unterminated { in pattern \".../%s/...\"", theWholePattern);
+ return FALSE;
+ }
+ }
+
+ restOfPattern++; /* skip close curly brace */
+
+
+ pattern++; /* skip open curly brace */
+
+ while (1) {
+
+ if (*pattern == ',') {
+ if (OSC_PatternMatch (restOfPattern, tp, theWholePattern)) {
+ return TRUE;
+ } else {
+ tp = test;
+ ++pattern;
+ }
+ } else if (*pattern == '}') {
+ return OSC_PatternMatch (restOfPattern, tp, theWholePattern);
+ } else if (*pattern == *tp) {
+ ++pattern;
+ ++tp;
+ } else {
+ tp = test;
+ while (*pattern != ',' && *pattern != '}') {
+ pattern++;
+ }
+ if (*pattern == ',') {
+ pattern++;
+ }
+ }
+ }
+}
+
+static int atommatch_osc(t_atom*pattern, t_atom*test) {
+ char*s_pattern=0;
+ char*s_test=0;
+ int pattern_size=0, test_size=0;
+
+ int result = FALSE;
+
+ //startpost("atommatch::OSC -> ");
+
+ if(pattern->a_type==A_SYMBOL) {
+ s_pattern=pattern->a_w.w_symbol->s_name;
+ } else {
+ pattern_size=sizeof(char)*MAXPDSTRING;
+ s_pattern=(char*)getbytes(pattern_size);
+ atom_string(pattern, s_pattern, pattern_size);
+ }
+ if(test->a_type==A_SYMBOL) {
+ s_test=test->a_w.w_symbol->s_name;
+ } else {
+ test_size=sizeof(char)*MAXPDSTRING;
+ s_test=(char*)getbytes(test_size);
+ atom_string(test, s_test, test_size);
+ }
+
+
+ result = OSC_PatternMatch(s_pattern, s_test, s_pattern);
+
+ //post("'%s' <-> '%s' = %d", s_pattern, s_test, result);
+
+ if(pattern_size>0) {
+ freebytes(s_pattern, pattern_size);
+ s_pattern=0; pattern_size=0;
+ }
+ if(test_size>0) {
+ freebytes(s_test, test_size);
+ s_test=0; test_size=0;
+ }
+
+
+ return result;
+}
+#endif /* OSC */
+
+
+
+
+static int matchbox_atommatch(t_atom*pattern, t_atom*atom, int mode) {
+ switch(mode) {
+ default:
+ case MATCHBOX_EXACT: return atommatch_exact(pattern, atom);
+#ifdef MATCHBOX_OSC
+ case MATCHBOX_OSC : return atommatch_osc(pattern, atom);
+#endif /* OSC */
+ }
+ return atommatch_exact(pattern, atom);
+}
+
+static int matchlist(int argc_pattern, t_atom*argv_pattern,
+ int argc, t_atom*argv, int mode) {
+ int i=0;
+
+ if(argc!=argc_pattern)
+ return 0;
+
+ for(i=0; i<argc; i++) {
+ if(0==matchbox_atommatch(argv_pattern+i, argv+i, mode))
+ return 0;
+ }
+
+ return 1;
+}
+
+static t_listlist*matchlistlist(unsigned int*numresults, t_listlist*searchlist, int p_argc, t_atom*p_argv, int mode) {
+ unsigned int num=0;
+ t_listlist*matchinglist=0, *sl;
+
+ for(sl=searchlist; 0!=sl; sl=sl->next) {
+ if(matchlist(p_argc, p_argv, sl->argc, sl->argv, mode)) {
+ matchinglist=addlistlist(matchinglist, sl->argc, sl->argv);
+ num++;
+ }
+ }
+
+ if(numresults!=0)
+ *numresults=num;
+ return matchinglist;
+}
+
+
+static void matchbox_list(t_matchbox*x, t_symbol*s, int argc, t_atom*argv) {
+ int results=0;
+ int mode=x->x_mode;
+ t_listlist*resultlist=matchlistlist(&results, x->x_lists, argc, argv, mode);
+ t_listlist*dummylist;
+
+ outlet_float(x->x_outNumResults, results);
+
+ for(dummylist=resultlist; 0!=dummylist; dummylist=dummylist->next)
+ outlet_list(x->x_outResult, &s_list, dummylist->argc, dummylist->argv);
+
+
+}
+
+static void matchbox_add(t_matchbox*x, t_symbol*s, int argc, t_atom*argv) {
+ // 1st match, whether we already have this entry
+ if(matchlistlist(0, x->x_lists, argc, argv, MATCHBOX_EXACT)) {
+ // already there, skip the rest
+ z_verbose(1, "this list is already in the buffer!, skipping...");
+ return;
+ }
+
+ // 2nd if this is a new entry, add it
+ x->x_lists=addlistlist(x->x_lists, argc, argv);
+ x->x_numlists++;
+}
+
+
+
+static void matchbox_dump(t_matchbox*x) {
+ t_listlist*lp=0;
+
+ if(0==x->x_lists){
+ outlet_float(x->x_outNumResults, 0);
+ return;
+ }
+
+ outlet_float(x->x_outNumResults, x->x_numlists);
+
+ for(lp=x->x_lists; 0!=lp; lp=lp->next)
+ {
+ outlet_list(x->x_outResult, &s_list, lp->argc, lp->argv);
+ }
+}
+
+
+static void matchbox_clear(t_matchbox*x) {
+ clearlistlist(x->x_lists);
+
+ x->x_lists=0;
+ x->x_numlists=0;
+}
+
+
+static void matchbox_mode(t_matchbox*x, t_symbol*s) {
+ if (gensym("OSC")==s)
+ x->x_mode=MATCHBOX_OSC;
+ else if(gensym("==")==s)
+ x->x_mode=MATCHBOX_EXACT;
+ else {
+ pd_error(x, "mode '%s' is unknown, switching to 'exact' mode", s->s_name);
+ x->x_mode=MATCHBOX_EXACT;
+ }
+}
+
+
+
+static void *matchbox_new(t_symbol *s, int argc, t_atom*argv)
+{
+ t_matchbox *x = (t_matchbox *)pd_new(matchbox_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("symbol"), gensym("add"));
+
+ x->x_outResult =outlet_new(&x->x_obj, gensym("list"));
+ x->x_outNumResults=outlet_new(&x->x_obj, gensym("float"));
+
+
+ x->x_lists=0;
+ x->x_numlists=0;
+
+ x->x_mode = MATCHBOX_EXACT;
+
+ if(argc && argv->a_type==A_SYMBOL) {
+ matchbox_mode(x, atom_getsymbol(argv));
+ }
+
+
+ return (x);
+}
+
+static void matchbox_free(t_matchbox *x)
+{
+ matchbox_clear(x);
+}
+
+static void matchbox_help(t_matchbox*x)
+{
+ post("\n%c matchbox\t\t:: find a list in a pool of lists", HEARTSYMBOL);
+}
+
+void matchbox_setup(void)
+{
+#ifdef MATCHBOX_OSC
+ post("matchbox: OSC-pattern matching code (c) Matt Wright, CNMAT");
+#endif /* MATCHBOX_OSC */
+
+
+
+ matchbox_class = class_new(gensym("matchbox"), (t_newmethod)matchbox_new,
+ (t_method)matchbox_free, sizeof(t_matchbox), 0, A_GIMME, 0);
+
+ class_addlist (matchbox_class, matchbox_list);
+
+ class_addmethod(matchbox_class, (t_method)matchbox_add, gensym("add"), A_GIMME, 0);
+ class_addmethod(matchbox_class, (t_method)matchbox_clear, gensym("clear"), A_NULL, 0);
+ class_addmethod(matchbox_class, (t_method)matchbox_dump, gensym("dump"), A_NULL);
+
+ class_addmethod(matchbox_class, (t_method)matchbox_mode, gensym("mode"), A_SYMBOL, 0);
+
+ class_addmethod(matchbox_class, (t_method)matchbox_help, gensym("help"), A_NULL);
+ class_sethelpsymbol(matchbox_class, gensym("zexy/matchbox"));
+ zexy_register("matchbox");
+}
diff --git a/src/z_zexy.c b/src/z_zexy.c
index fd3b86c..4b3a62c 100644
--- a/src/z_zexy.c
+++ b/src/z_zexy.c
@@ -39,6 +39,7 @@ void z_zexy_setup(void)
lister_setup(); /* lister */
lpt_setup(); /* lpt */
makesymbol_setup(); /* makesymbol */
+ matchbox_setup(); /* matchbox */
mavg_setup(); /* mavg */
minmax_setup(); /* minmax */
msgfile_setup(); /* msgfile */
diff --git a/src/z_zexy.h b/src/z_zexy.h
index 8b9fcdf..fb28f11 100644
--- a/src/z_zexy.h
+++ b/src/z_zexy.h
@@ -37,6 +37,7 @@ void list2symbol_setup(void); /* list2symbol */
void lister_setup(void); /* lister */
void lpt_setup(void); /* lpt */
void makesymbol_setup(void); /* makesymbol */
+void matchbox_setup(void); /* matchbox */
void mavg_setup(void); /* mavg */
void minmax_setup(void); /* minmax */
void msgfile_setup(void); /* msgfile */
diff --git a/src/zexy.h b/src/zexy.h
index fc9a8be..a27b051 100644
--- a/src/zexy.h
+++ b/src/zexy.h
@@ -60,7 +60,7 @@
#include <math.h>
-#define VERSION "2.1.1"
+#define VERSION "2.2.0"
/* these pragmas are only used for MSVC, not MinGW or Cygwin */
#ifdef _MSC_VER
diff --git a/src/zexyconf.h b/src/zexyconf.h
index b3b3041..0d263f3 100644
--- a/src/zexyconf.h
+++ b/src/zexyconf.h
@@ -1,26 +1,21 @@
-/* this is a zexyconf.h for windows
- * on unix-derivatives (linux, os-X,...) this file should be overwritten by configure
- * via the template zexyconf.h.in
- *
- * if you cannot use configure to re-generate this file, make sure all the defines
- * are set correctly
- */
-
+/* zexyconf.h. Generated from zexyconf.h.in by configure. */
+#ifndef _ZEXYCONF_H_
+#define _ZEXYCONF_H_
/* Define if you have the <regex.h> header file. */
-/* #undef HAVE_REGEX_H */
+#define HAVE_REGEX_H 1
/* Define if you have the <alloca.h> header file. */
-/* #undef HAVE_ALLOCA_H */
+#define HAVE_ALLOCA_H 1
/* define if you want parallelport-support (direct access to the port address) */
-/* most likely, you do not want to do this on apple hardware */
-/* #define Z_WANT_LPT 1 */
+#define Z_WANT_LPT 1
/* define if you have the <linux/ppdev.h> header file.
* (for parport _device_ support)
* you need Z_WANT_LPT for this to have an effect !
*/
-/* #undef HAVE_LINUX_PPDEV_H */
+#define HAVE_LINUX_PPDEV_H 1
+#endif /* _ZEXYCONF_H_ */