1
/******************************************************
3
* zexy - implementation file
5
* copyleft (c) IOhannes m zm�lnig
7
* 1999:forum::f�r::uml�ute:2004
9
* institute of electronic music and acoustics (iem)
11
******************************************************
13
* license: GNU General Public License v.2
15
******************************************************/
20
# include <sys/types.h>
25
# define NUM_REGMATCHES 10
28
* regex : see whether a regular expression matches the given symbol
31
/* ------------------------- regex ------------------------------- */
33
/* match a regular expression against a string */
35
static t_class *regex_class;
41
char *x_regexstring; /* the uncompiled regular expression */
42
int x_regexstringlength;
47
int x_flags; /* flags for the regex-compiler; REG_EXTENDED is always enabled */
51
t_outlet*x_outDetails;
52
t_outlet*x_outNumDetails;
57
static char*regex_l2s(int *reslen, t_symbol*s, int argc, t_atom*argv)
63
if(reslen)*reslen=length;
65
/* 1st get the length of the symbol */
66
if(s)length+=strlen(s->s_name);
73
char buffer[MAXPDSTRING];
75
if(A_SYMBOL==ap->a_type){
76
len=strlen(ap->a_w.w_symbol->s_name);
78
atom_string(ap, buffer, MAXPDSTRING);
85
if(length<=0)return(0);
87
result = (char*)getbytes((length+1)*sizeof(char));
90
char *buf = s->s_name;
91
strcpy(result+pos, buf);
94
strcpy(result+pos, " ");
102
if(A_SYMBOL==ap->a_type){
103
strcpy(result+pos, ap->a_w.w_symbol->s_name);
104
pos+= strlen(ap->a_w.w_symbol->s_name);
106
char buffer[MAXPDSTRING];
107
atom_string(ap, buffer, MAXPDSTRING);
108
strcpy(result+pos, buffer);
109
pos += strlen(buffer);
113
strcpy(result+pos, " ");
119
if(reslen)*reslen=length;
123
static void regex_compile(t_regex *x)
125
int flags = x->x_flags;
126
flags |= REG_EXTENDED;
128
if(0==x->x_regexstring || 0==x->x_regexstringlength){
129
pd_error(x, "[regex]: no regular expression given");
135
regfree(x->x_regexp);
136
freebytes(x->x_regexp, sizeof(t_regex));
139
x->x_regexp=(regex_t*)getbytes(sizeof(t_regex));
141
if(regcomp(x->x_regexp, x->x_regexstring, flags)) {
142
pd_error(x, "[regex]: invalid regular expression: %s", x->x_regexstring);
143
if(x->x_regexp)freebytes(x->x_regexp, sizeof(t_regex));
150
static void regex_case(t_regex *x, t_float f){
153
x->x_flags |= REG_ICASE;
155
x->x_flags ^= REG_ICASE;
162
static void regex_regex(t_regex *x, t_symbol*s, int argc, t_atom*argv)
168
result=regex_l2s(&length, 0, argc, argv);
170
if(0==result || 0==length){
171
pd_error(x, "[regex]: no regular expression given");
175
if(x->x_regexstring) {
176
freebytes(x->x_regexstring, x->x_regexstringlength);
178
x->x_regexstringlength=0;
181
x->x_regexstring=result;
182
x->x_regexstringlength=length;
188
/* compare the given list as string with the precompiled regex */
189
static void regex_symbol(t_regex *x, t_symbol *s, int argc, t_atom*argv)
195
int num_matches=x->x_matchnum;
196
regmatch_t*match=(regmatch_t*)getbytes(sizeof(regmatch_t)*num_matches);
197
t_atom*ap=(t_atom*)getbytes(sizeof(t_atom)*(3*num_matches));
202
pd_error(x, "[regex]: no regular expression!");
205
teststring=regex_l2s(&length, 0, argc, argv);
206
if(!teststring||!length){
207
pd_error(x, "[regex]: cannot evaluate string");
211
/* do the actual comparing against the regex */
212
err=regexec(x->x_regexp, teststring, num_matches, match, 0);
214
freebytes(teststring, length);
218
if(err) { /* NO match */
220
freebytes(match, sizeof(regmatch_t)*num_matches);
224
outlet_float(x->x_outResult, 0.f);
225
} else { /* match! */
230
for(i=0; i<num_matches; i++){
231
if(match[i].rm_so!=-1){
232
/* output the matches */
233
if(i>0 && (match[i].rm_so==match[i-1].rm_so) && (match[i].rm_eo==match[i-1].rm_eo)){
234
/* duplicate matches */
236
SETFLOAT(ap2+0, (t_float)i);
237
SETFLOAT(ap2+1, (t_float)match[i].rm_so);
238
SETFLOAT(ap2+2, (t_float)match[i].rm_eo);
245
freebytes(match, sizeof(regmatch_t)*num_matches);
248
outlet_float(x->x_outNumDetails, (t_float)num_results);
249
for(i=0; i<num_results; i++){
250
outlet_list(x->x_outDetails, gensym("list"), 3, ap+(i*3));
252
outlet_float(x->x_outResult, 1.f);
255
if(teststring)freebytes(teststring, length);
256
if(match)freebytes(match, sizeof(regmatch_t)*num_matches);
259
freebytes(ap, sizeof(t_atom)*(1+2*num_matches));
264
static void *regex_new(t_symbol *s, int argc, t_atom*argv)
266
t_regex *x = (t_regex *)pd_new(regex_class);
268
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("symbol"), gensym("regex"));
270
x->x_outResult=outlet_new(&x->x_obj, 0);
271
x->x_outDetails=outlet_new(&x->x_obj, gensym("list"));
272
x->x_outNumDetails=outlet_new(&x->x_obj, &s_float);
279
x->x_regexstringlength=0;
282
x->x_matchnum=NUM_REGMATCHES;
283
if(argc)regex_regex(x, gensym(""), argc, argv);
286
SETSYMBOL(&a, gensym(".*"));
287
regex_regex(x, 0, 1, &a);
290
error("[regex] non-functional: compiled without regex-support!");
296
static void regex_free(t_regex *x)
299
if(x->x_regexstring){
300
freebytes(x->x_regexstring, x->x_regexstringlength);
302
x->x_regexstringlength=0;
306
regfree(x->x_regexp);
307
freebytes(x->x_regexp, sizeof(t_regex));
313
static void regex_help(t_regex*x)
315
post("\n%c regex\t\t:: test the input whether it matches a regular expression", HEARTSYMBOL);
318
void regex_setup(void)
320
regex_class = class_new(gensym("regex"), (t_newmethod)regex_new,
321
(t_method)regex_free, sizeof(t_regex), 0, A_GIMME, 0);
323
class_addlist (regex_class, regex_symbol);
324
class_addmethod(regex_class, (t_method)regex_regex, gensym("regex"), A_GIMME, 0);
326
class_addmethod(regex_class, (t_method)regex_case, gensym("case"), A_FLOAT, 0);
328
class_addmethod(regex_class, (t_method)regex_help, gensym("help"), A_NULL);
329
zexy_register("regex");