joker 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/HISTORY.markdown +5 -0
- data/README.markdown +8 -3
- data/Rakefile +5 -18
- data/VERSION +1 -1
- data/ext/joker_native/Joker.c +72 -0
- data/ext/joker_native/Joker.h +53 -0
- data/ext/joker_native/Wildcard.c +22 -0
- data/ext/joker_native/Wildcard.h +40 -0
- data/ext/joker_native/compile.c +158 -0
- data/ext/joker_native/compile.h +16 -0
- data/ext/joker_native/extconf.rb +6 -0
- data/ext/joker_native/match.c +272 -0
- data/ext/joker_native/match.h +21 -0
- data/lib/joker.rb +6 -70
- data/tasks/c_extensions.rake +29 -0
- data/tasks/jeweler.rake +28 -0
- data/tasks/rdoc.rake +9 -0
- data/tasks/shortcuts.rake +22 -0
- data/tasks/test.rake +6 -0
- data/test/c/test_compile.c +215 -0
- data/test/c/test_match.c +131 -0
- data/test/{test_joker.rb → ruby/test_joker.rb} +0 -18
- metadata +19 -3
data/HISTORY.markdown
CHANGED
data/README.markdown
CHANGED
@@ -9,14 +9,19 @@ for Ruby.
|
|
9
9
|
|
10
10
|
* Behaves much like Regexp
|
11
11
|
* ` * ` and ` ? ` as wildcard characters
|
12
|
-
* ` \ ` for escaping
|
13
|
-
|
12
|
+
* ` \ ` for escaping:
|
13
|
+
` \? ` matches ` ? `,
|
14
|
+
` \* ` matches ` * `,
|
15
|
+
` \[ ` matches ` [ `,
|
16
|
+
` \] ` matches ` ] `,
|
17
|
+
* But for all other characters:
|
18
|
+
` \a ` matches ` \a `, but not ` a `
|
14
19
|
* Wildcards must always match whole string
|
20
|
+
(thus ` uiae ` will only match the string ` uiae `)
|
15
21
|
* Wildcards can be case insensitive
|
16
22
|
|
17
23
|
## Installation ##
|
18
24
|
|
19
|
-
gem install karottenreibe-joker --source http://gems.github.com
|
20
25
|
gem install joker
|
21
26
|
|
22
27
|
## Usage ##
|
data/Rakefile
CHANGED
@@ -1,20 +1,7 @@
|
|
1
|
-
require 'jeweler'
|
2
1
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
'Joker is a simple wildcard implementation that works much like Regexps'
|
9
|
-
gem.email = 'karottenreibe@gmail.com'
|
10
|
-
gem.homepage = 'http://karottenreibe.github.com/joker'
|
11
|
-
gem.authors = ['Fabian Streitel']
|
12
|
-
gem.rubyforge_project = 'k-gems'
|
13
|
-
end
|
14
|
-
|
15
|
-
Jeweler::RubyforgeTasks.new
|
16
|
-
|
17
|
-
task :test do
|
18
|
-
sh 'bacon -Ilib test/test_*.rb'
|
19
|
-
end
|
2
|
+
load "tasks/jeweler.rake"
|
3
|
+
load "tasks/rdoc.rake"
|
4
|
+
load "tasks/c_extensions.rake"
|
5
|
+
load "tasks/test.rake"
|
6
|
+
load "tasks/shortcuts.rake"
|
20
7
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
1.0.0
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#include <malloc.h>
|
2
|
+
#include "Joker.h"
|
3
|
+
#include "Wildcard.h"
|
4
|
+
#include "compile.h"
|
5
|
+
#include "match.h"
|
6
|
+
|
7
|
+
|
8
|
+
void Init_joker_native(void) // {{{1
|
9
|
+
{
|
10
|
+
class_Wildcard = rb_define_class("Wildcard", rb_cObject);
|
11
|
+
rb_define_singleton_method(class_Wildcard, "new", class_method_new, -1);
|
12
|
+
rb_define_method(class_Wildcard, "=~", instance_operator_match, 1);
|
13
|
+
rb_define_method(class_Wildcard, "===", instance_operator_match, 1);
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
VALUE instance_operator_match(self, object) // {{{1
|
18
|
+
VALUE self;
|
19
|
+
VALUE object;
|
20
|
+
{
|
21
|
+
Wildcard * wildcard;
|
22
|
+
const char * cstring;
|
23
|
+
long int length;
|
24
|
+
int casefold;
|
25
|
+
|
26
|
+
// check types and get the C representation of stuff
|
27
|
+
Check_Type(object, T_STRING);
|
28
|
+
Data_Get_Struct(self, Wildcard, wildcard);
|
29
|
+
cstring = rb_str2cstr(object, &length);
|
30
|
+
casefold = RTEST(rb_iv_get(self, "@casefold"));
|
31
|
+
|
32
|
+
// match and return the result
|
33
|
+
if (Wildcard_match(wildcard, cstring, length, casefold)) {
|
34
|
+
return Qtrue;
|
35
|
+
} else {
|
36
|
+
return Qfalse;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
VALUE class_method_new(argc, argv, klass) // {{{1
|
42
|
+
int argc;
|
43
|
+
VALUE * argv;
|
44
|
+
VALUE klass;
|
45
|
+
{
|
46
|
+
VALUE wildcard_string;
|
47
|
+
VALUE casefold;
|
48
|
+
VALUE new_object;
|
49
|
+
Wildcard * new_wildcard;
|
50
|
+
const char * wildcard_cstring;
|
51
|
+
long int string_length;
|
52
|
+
|
53
|
+
// check arity and fill in defaults
|
54
|
+
rb_scan_args(argc, argv, "11", &wildcard_string, &casefold);
|
55
|
+
if (NIL_P(casefold)) {
|
56
|
+
casefold = Qfalse;
|
57
|
+
}
|
58
|
+
|
59
|
+
// get C representation of stuff and create Wildcard
|
60
|
+
wildcard_cstring = rb_str2cstr(wildcard_string, &string_length);
|
61
|
+
new_wildcard = Wildcard_compile(wildcard_cstring, string_length);
|
62
|
+
// wrap wildcard
|
63
|
+
new_object = Data_Wrap_Struct(klass, NULL, Wildcard_free, new_wildcard);
|
64
|
+
|
65
|
+
// set instance variables
|
66
|
+
rb_iv_set(new_object, "@casefold", casefold);
|
67
|
+
rb_iv_set(new_object, "@source", wildcard_string);
|
68
|
+
|
69
|
+
return new_object;
|
70
|
+
}
|
71
|
+
|
72
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
#ifndef JOKER_H_GUARD
|
2
|
+
#define JOKER_H_GUARD
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
|
6
|
+
|
7
|
+
VALUE class_Wildcard;
|
8
|
+
void Init_joker(void);
|
9
|
+
|
10
|
+
|
11
|
+
/*
|
12
|
+
* call-seq:
|
13
|
+
* Wildcard.new(wildcard_string, casefold = false) -> Wildcard
|
14
|
+
*
|
15
|
+
* Creates a new Wildcard from the given string.
|
16
|
+
* If casefold is true, the Wildcard will ignore case.
|
17
|
+
*
|
18
|
+
* Raisess a SyntaxError if the given string could not
|
19
|
+
* be interpreted as a Wildcard.
|
20
|
+
*
|
21
|
+
* Issues warnings to the console if the given Wildcard
|
22
|
+
* was malformed.
|
23
|
+
*
|
24
|
+
*/
|
25
|
+
VALUE class_method_new(int argc, VALUE * argv, VALUE klass);
|
26
|
+
|
27
|
+
|
28
|
+
/*
|
29
|
+
* call-seq:
|
30
|
+
* wildcard =~ 'string' -> true or false
|
31
|
+
* 'string' =~ wildcard -> true or false
|
32
|
+
* wildcard === 'string' -> true or false
|
33
|
+
*
|
34
|
+
* Matches the Wildcard against the given string.
|
35
|
+
*
|
36
|
+
* NOTE: Since a wildcard has to match the whole string,
|
37
|
+
* this method only returns true or false, not the position
|
38
|
+
* of the match.
|
39
|
+
*
|
40
|
+
* Wildcard['*fairy*'] =~ 'I love fairycake' #=> true
|
41
|
+
* 'I love fairycake' =~ Wildcard['*dairy*'] #=> false
|
42
|
+
*
|
43
|
+
* case 'I love fairycake'
|
44
|
+
* when Wildcard['*fairy*'] then puts 'fairy!'
|
45
|
+
* else puts 'no fairy...'
|
46
|
+
* end
|
47
|
+
*
|
48
|
+
*/
|
49
|
+
VALUE instance_operator_match(VALUE self, VALUE string);
|
50
|
+
|
51
|
+
|
52
|
+
#endif
|
53
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#include <malloc.h>
|
2
|
+
#include <stddef.h>
|
3
|
+
#include <Wildcard.h>
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
void Wildcard_free(wildcard) // {{{1
|
8
|
+
Wildcard * wildcard;
|
9
|
+
{
|
10
|
+
free(wildcard->first);
|
11
|
+
free(wildcard);
|
12
|
+
}
|
13
|
+
|
14
|
+
|
15
|
+
void Wildcard_enlarge(wildcard) // {{{1
|
16
|
+
Wildcard * wildcard;
|
17
|
+
{
|
18
|
+
wildcard->length += 2;
|
19
|
+
wildcard->first = realloc(wildcard->first, wildcard->length * sizeof(char));
|
20
|
+
wildcard->last = wildcard->first + wildcard->length - 2;
|
21
|
+
}
|
22
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#ifndef WILDCARD_H_GUARD
|
2
|
+
#define WILDCARD_H_GUARD
|
3
|
+
|
4
|
+
|
5
|
+
/*
|
6
|
+
* The different kinds of Wildcard components.
|
7
|
+
*
|
8
|
+
*/
|
9
|
+
typedef enum {
|
10
|
+
Kleene = 0,
|
11
|
+
Fixed = 1,
|
12
|
+
Group = 2,
|
13
|
+
Wild = 3,
|
14
|
+
EOW = 4, // only used in matching
|
15
|
+
} WildcardType;
|
16
|
+
|
17
|
+
/*
|
18
|
+
* Represents a Wildcard internally.
|
19
|
+
*
|
20
|
+
*/
|
21
|
+
typedef struct {
|
22
|
+
char * first; // The first Wildcard part (points to the first of the 2 chars)
|
23
|
+
char * last; // The last Wildcard part (points to the first of the 2 chars)
|
24
|
+
long int length; // How many chars there are (not parts!)
|
25
|
+
} Wildcard;
|
26
|
+
|
27
|
+
|
28
|
+
void Wildcard_free(Wildcard * wildcard);
|
29
|
+
|
30
|
+
|
31
|
+
/*
|
32
|
+
* Adds two additional characters at the end
|
33
|
+
* and adjusts all the pointers.
|
34
|
+
*
|
35
|
+
*/
|
36
|
+
void Wildcard_enlarge(Wildcard * wildcard);
|
37
|
+
|
38
|
+
|
39
|
+
#endif
|
40
|
+
|
@@ -0,0 +1,158 @@
|
|
1
|
+
#include <malloc.h>
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <stddef.h>
|
4
|
+
#include <string.h>
|
5
|
+
#include <string.h>
|
6
|
+
#include <ruby.h>
|
7
|
+
#include "compile.h"
|
8
|
+
|
9
|
+
|
10
|
+
static int hash(cchar) // {{{1
|
11
|
+
const char cchar;
|
12
|
+
{
|
13
|
+
switch (cchar) {
|
14
|
+
case '\\':
|
15
|
+
return 0;
|
16
|
+
case '[':
|
17
|
+
return 1;
|
18
|
+
case ']':
|
19
|
+
return 2;
|
20
|
+
case '*':
|
21
|
+
return 3;
|
22
|
+
case '?':
|
23
|
+
return 4;
|
24
|
+
default:
|
25
|
+
return 5;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
static void push(type, cchar, wildcard) // {{{1
|
31
|
+
const WildcardType type;
|
32
|
+
const char cchar;
|
33
|
+
Wildcard * wildcard;
|
34
|
+
{
|
35
|
+
Wildcard_enlarge(wildcard);
|
36
|
+
*wildcard->last = (char) type;
|
37
|
+
*(wildcard->last + 1) = cchar;
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
static void do_transition(transition, input, state, wildcard) // {{{1
|
42
|
+
const char transition;
|
43
|
+
const char input;
|
44
|
+
int * state;
|
45
|
+
Wildcard * wildcard;
|
46
|
+
{
|
47
|
+
switch (transition) {
|
48
|
+
case 0:
|
49
|
+
*state = 1;
|
50
|
+
break;
|
51
|
+
case 1:
|
52
|
+
*state = 2;
|
53
|
+
break;
|
54
|
+
case 2:
|
55
|
+
push(Fixed, input, wildcard);
|
56
|
+
rb_warning("wildcard has `]' without escape");
|
57
|
+
break;
|
58
|
+
case 3:
|
59
|
+
// refactor ** --> *
|
60
|
+
if (wildcard->last == NULL || *wildcard->last != (char) Kleene) {
|
61
|
+
push(Kleene, '*', wildcard);
|
62
|
+
}
|
63
|
+
break;
|
64
|
+
case 4:
|
65
|
+
push(Wild, '?', wildcard);
|
66
|
+
break;
|
67
|
+
case 5:
|
68
|
+
push(Fixed, input, wildcard);
|
69
|
+
break;
|
70
|
+
case 6:
|
71
|
+
*state = -1;
|
72
|
+
break;
|
73
|
+
case 7:
|
74
|
+
*state = 0;
|
75
|
+
push(Fixed, input, wildcard);
|
76
|
+
break;
|
77
|
+
case 8:
|
78
|
+
*state = 0;
|
79
|
+
push(Fixed, '\\', wildcard);
|
80
|
+
push(Fixed, input, wildcard);
|
81
|
+
break;
|
82
|
+
case 9:
|
83
|
+
*state = -1;
|
84
|
+
push(Fixed, '\\', wildcard);
|
85
|
+
break;
|
86
|
+
case 10:
|
87
|
+
*state = 3;
|
88
|
+
break;
|
89
|
+
case 11:
|
90
|
+
push(Group, input, wildcard);
|
91
|
+
rb_warning("character class has `[' without escape");
|
92
|
+
break;
|
93
|
+
case 12:
|
94
|
+
*state = 0;
|
95
|
+
break;
|
96
|
+
case 13:
|
97
|
+
push(Group, input, wildcard);
|
98
|
+
break;
|
99
|
+
case 14:
|
100
|
+
*state = -1;
|
101
|
+
rb_raise(rb_eSyntaxError, "premature end of wildcard");
|
102
|
+
break;
|
103
|
+
case 15:
|
104
|
+
*state = 2;
|
105
|
+
push(Group, input, wildcard);
|
106
|
+
break;
|
107
|
+
case 16:
|
108
|
+
*state = 2;
|
109
|
+
push(Group, '\\', wildcard);
|
110
|
+
push(Group, input, wildcard);
|
111
|
+
break;
|
112
|
+
default:
|
113
|
+
rb_fatal("Wildcard compilation state machine failure. This is a bug in Joker!");
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
|
118
|
+
Wildcard * Wildcard_compile(cstring, len) // {{{1
|
119
|
+
const char * cstring;
|
120
|
+
const long int len;
|
121
|
+
{
|
122
|
+
// the table that maps (state x input) -> transition
|
123
|
+
const char transition_table[4][7] = {
|
124
|
+
// \ [ ] * ? any EOS
|
125
|
+
{ 0, 1, 2, 3, 4, 5, 6},
|
126
|
+
{ 7, 7, 7, 7, 7, 8, 9},
|
127
|
+
{10, 11, 12, 13, 13, 13, 14},
|
128
|
+
{15, 15, 15, 16, 16, 16, 14}
|
129
|
+
};
|
130
|
+
int state = 0;
|
131
|
+
|
132
|
+
Wildcard * wildcard;
|
133
|
+
long int p;
|
134
|
+
char input;
|
135
|
+
int hashed;
|
136
|
+
char transition;
|
137
|
+
|
138
|
+
wildcard = malloc(sizeof(Wildcard));
|
139
|
+
wildcard->length = 0;
|
140
|
+
wildcard->first = NULL;
|
141
|
+
wildcard->last = NULL;
|
142
|
+
|
143
|
+
// for each char:
|
144
|
+
for (p = 0; p < len; p++) {
|
145
|
+
// get the input, it's type and what transition to make
|
146
|
+
input = cstring[p];
|
147
|
+
hashed = hash(input);
|
148
|
+
transition = transition_table[state][hashed];
|
149
|
+
// and execute the transition
|
150
|
+
do_transition(transition, input, &state, wildcard);
|
151
|
+
}
|
152
|
+
|
153
|
+
// finally: execute the finishing transition
|
154
|
+
transition = transition_table[state][6];
|
155
|
+
do_transition(transition, '\0', &state, wildcard);
|
156
|
+
return wildcard;
|
157
|
+
}
|
158
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#ifndef COMPILE_H_GUARD
|
2
|
+
#define COMPILE_H_GUARD
|
3
|
+
|
4
|
+
#include "Wildcard.h"
|
5
|
+
|
6
|
+
|
7
|
+
/*
|
8
|
+
* Compiles an input string to the internal Wildcard
|
9
|
+
* represenation.
|
10
|
+
*
|
11
|
+
*/
|
12
|
+
Wildcard * Wildcard_compile(const char * cstring, const long int len);
|
13
|
+
|
14
|
+
|
15
|
+
#endif
|
16
|
+
|
@@ -0,0 +1,272 @@
|
|
1
|
+
#include <malloc.h>
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <stddef.h>
|
4
|
+
#include <string.h>
|
5
|
+
#include <ruby.h>
|
6
|
+
#include <ctype.h>
|
7
|
+
#include "match.h"
|
8
|
+
|
9
|
+
#define SUCCESS_STATE 42
|
10
|
+
#define FAILURE_STATE 23
|
11
|
+
|
12
|
+
|
13
|
+
typedef struct {
|
14
|
+
const char * input;
|
15
|
+
const char * wildcard;
|
16
|
+
const char * pushed_input;
|
17
|
+
const char * pushed_wildcard;
|
18
|
+
int state;
|
19
|
+
void (*inc)(const char **, int);
|
20
|
+
} StateMachine;
|
21
|
+
|
22
|
+
|
23
|
+
typedef struct {
|
24
|
+
StateMachine * left;
|
25
|
+
StateMachine * right;
|
26
|
+
StateMachine * active;
|
27
|
+
} MatchData;
|
28
|
+
|
29
|
+
|
30
|
+
static void left_inc(pointer, offset) // {{{1
|
31
|
+
const char ** pointer;
|
32
|
+
int offset;
|
33
|
+
{
|
34
|
+
(*pointer) += offset;
|
35
|
+
}
|
36
|
+
|
37
|
+
|
38
|
+
static void right_inc(pointer, offset) // {{{1
|
39
|
+
const char ** pointer;
|
40
|
+
int offset;
|
41
|
+
{
|
42
|
+
(*pointer) -= offset;
|
43
|
+
}
|
44
|
+
|
45
|
+
static int matches(type, data, input, eos, casefold) // {{{1
|
46
|
+
WildcardType type;
|
47
|
+
const char data;
|
48
|
+
const char input;
|
49
|
+
bool eos;
|
50
|
+
bool casefold;
|
51
|
+
{
|
52
|
+
switch(type) {
|
53
|
+
case Fixed:
|
54
|
+
case Group:
|
55
|
+
if (casefold) {
|
56
|
+
return !eos && tolower(input) == tolower(data);
|
57
|
+
} else {
|
58
|
+
return !eos && input == data;
|
59
|
+
}
|
60
|
+
case Wild:
|
61
|
+
return !eos && input != '\0';
|
62
|
+
case Kleene:
|
63
|
+
return 1;
|
64
|
+
case EOW:
|
65
|
+
return eos;
|
66
|
+
default:
|
67
|
+
rb_raise(rb_eSyntaxError, "corrupted wildcard");
|
68
|
+
return 0;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
|
73
|
+
static bool eow(match_data) // {{{1
|
74
|
+
MatchData * match_data;
|
75
|
+
{
|
76
|
+
return match_data->left->wildcard == NULL || match_data->left->wildcard > match_data->right->wildcard;
|
77
|
+
}
|
78
|
+
|
79
|
+
|
80
|
+
static bool eos(match_data) // {{{1
|
81
|
+
MatchData * match_data;
|
82
|
+
{
|
83
|
+
return match_data->left->input > match_data->right->input;
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
static void push(match_data) // {{{1
|
88
|
+
MatchData * match_data;
|
89
|
+
{
|
90
|
+
StateMachine * sm;
|
91
|
+
|
92
|
+
if (!eos(match_data)) {
|
93
|
+
sm = match_data->active;
|
94
|
+
sm->pushed_input = sm->input;
|
95
|
+
sm->pushed_wildcard = sm->wildcard;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
|
100
|
+
static void pull(match_data) // {{{1
|
101
|
+
MatchData * match_data;
|
102
|
+
{
|
103
|
+
StateMachine * sm;
|
104
|
+
|
105
|
+
sm = match_data->active;
|
106
|
+
if (sm->pushed_input == NULL) {
|
107
|
+
sm->state = FAILURE_STATE;
|
108
|
+
} else {
|
109
|
+
sm->input = sm->pushed_input;
|
110
|
+
sm->wildcard = sm->pushed_wildcard;
|
111
|
+
sm->pushed_input = NULL;
|
112
|
+
sm->pushed_wildcard = NULL;
|
113
|
+
(*sm->inc)(&sm->input, 1);
|
114
|
+
|
115
|
+
if (sm == match_data->left) {
|
116
|
+
match_data->active = match_data->right;
|
117
|
+
} else {
|
118
|
+
match_data->active = match_data->left;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
123
|
+
|
124
|
+
static void do_transition(transition, match_data) // {{{1
|
125
|
+
const char transition;
|
126
|
+
MatchData * match_data;
|
127
|
+
{
|
128
|
+
StateMachine * sm;
|
129
|
+
|
130
|
+
sm = match_data->active;
|
131
|
+
switch (transition) {
|
132
|
+
case 0:
|
133
|
+
push(match_data);
|
134
|
+
(*sm->inc)(&sm->wildcard, 2);
|
135
|
+
break;
|
136
|
+
case 1:
|
137
|
+
sm->state = 1;
|
138
|
+
break;
|
139
|
+
case 2:
|
140
|
+
sm->state = 2;
|
141
|
+
break;
|
142
|
+
case 3:
|
143
|
+
sm->state = 4;
|
144
|
+
break;
|
145
|
+
case 4:
|
146
|
+
// does no exist
|
147
|
+
break;
|
148
|
+
case 5:
|
149
|
+
sm->state = SUCCESS_STATE;
|
150
|
+
break;
|
151
|
+
case 6:
|
152
|
+
sm->state = 0;
|
153
|
+
(*sm->inc)(&sm->wildcard, 2);
|
154
|
+
(*sm->inc)(&sm->input, 1);
|
155
|
+
break;
|
156
|
+
case 7:
|
157
|
+
sm->state = 0;
|
158
|
+
pull(match_data);
|
159
|
+
break;
|
160
|
+
case 8:
|
161
|
+
(*sm->inc)(&sm->wildcard, 2);
|
162
|
+
break;
|
163
|
+
case 9:
|
164
|
+
sm->state = 3;
|
165
|
+
(*sm->inc)(&sm->wildcard, 2);
|
166
|
+
(*sm->inc)(&sm->input, 1);
|
167
|
+
break;
|
168
|
+
case 10:
|
169
|
+
sm->state = 0;
|
170
|
+
break;
|
171
|
+
case 11:
|
172
|
+
(*sm->inc)(&sm->wildcard, 2);
|
173
|
+
break;
|
174
|
+
case 12:
|
175
|
+
sm->state = 0;
|
176
|
+
(*sm->inc)(&sm->wildcard, 2);
|
177
|
+
(*sm->inc)(&sm->input, 1);
|
178
|
+
break;
|
179
|
+
default:
|
180
|
+
rb_fatal("Wildcard matching state machine failure. This is a bug in Joker!");
|
181
|
+
}
|
182
|
+
}
|
183
|
+
|
184
|
+
|
185
|
+
bool Wildcard_match(wildcard, cstring, len, casefold) // {{{1
|
186
|
+
Wildcard * wildcard;
|
187
|
+
const char * cstring;
|
188
|
+
const long int len;
|
189
|
+
bool casefold;
|
190
|
+
{
|
191
|
+
// the table that maps (match x state x type) -> transition
|
192
|
+
const char transition_table[2][5][5] = {
|
193
|
+
// fail
|
194
|
+
{
|
195
|
+
// kleene, fixed, group, wild, EOW
|
196
|
+
{ 0, 1, 2, 3, 7}, // basic
|
197
|
+
{ 7, 7, 7, 7, 7}, // fixed
|
198
|
+
{ 7, 7, 8, 7, 7}, // group
|
199
|
+
{ 10, 10, 11, 10, 10}, // group_finish
|
200
|
+
{ 7, 7, 7, 7, 7}, // wild
|
201
|
+
},
|
202
|
+
|
203
|
+
// match
|
204
|
+
{
|
205
|
+
// kleene, fixed, group, wild, EOW
|
206
|
+
{ 0, 1, 2, 3, 5}, // basic
|
207
|
+
{ 6, 6, 6, 6, 6}, // fixed
|
208
|
+
{ 7, 7, 9, 7, 7}, // group
|
209
|
+
{ 10, 10, 11, 10, 10}, // group_finish
|
210
|
+
{ 12, 12, 12, 12, 12}, // wild
|
211
|
+
},
|
212
|
+
};
|
213
|
+
|
214
|
+
MatchData * match_data;
|
215
|
+
WildcardType type;
|
216
|
+
char data;
|
217
|
+
char input;
|
218
|
+
int match;
|
219
|
+
char transition;
|
220
|
+
|
221
|
+
match_data = malloc(sizeof(MatchData));
|
222
|
+
match_data->left = malloc(sizeof(StateMachine));
|
223
|
+
match_data->right = malloc(sizeof(StateMachine));
|
224
|
+
match_data->active = match_data->left;
|
225
|
+
|
226
|
+
match_data->left->input = cstring;
|
227
|
+
match_data->left->wildcard = wildcard->first;
|
228
|
+
match_data->left->pushed_input = NULL;
|
229
|
+
match_data->left->pushed_wildcard = NULL;
|
230
|
+
match_data->left->state = 0;
|
231
|
+
match_data->left->inc = left_inc;
|
232
|
+
|
233
|
+
match_data->right->input = cstring + len - 1;
|
234
|
+
match_data->right->wildcard = wildcard->last;
|
235
|
+
match_data->right->pushed_input = NULL;
|
236
|
+
match_data->right->pushed_wildcard = NULL;
|
237
|
+
match_data->right->state = 0;
|
238
|
+
match_data->right->inc = right_inc;
|
239
|
+
|
240
|
+
while (true) {
|
241
|
+
// get the data and it's type
|
242
|
+
if (eow(match_data)) {
|
243
|
+
type = EOW;
|
244
|
+
data = '\0';
|
245
|
+
} else {
|
246
|
+
type = (WildcardType) *match_data->active->wildcard;
|
247
|
+
data = *(match_data->active->wildcard + 1);
|
248
|
+
}
|
249
|
+
|
250
|
+
// get input, whether it matches the data and the transition to make
|
251
|
+
input = *match_data->active->input;
|
252
|
+
match = matches(type, data, input, eos(match_data), casefold);
|
253
|
+
transition = transition_table[match][(int)match_data->active->state][type];
|
254
|
+
// and execute the tansition
|
255
|
+
do_transition(transition, match_data);
|
256
|
+
|
257
|
+
// if the transition resulted in failure or success:
|
258
|
+
// clean up and terminate
|
259
|
+
if (match_data->active->state == SUCCESS_STATE) {
|
260
|
+
free(match_data->right);
|
261
|
+
free(match_data->left);
|
262
|
+
free(match_data);
|
263
|
+
return true;
|
264
|
+
} else if (match_data->active->state == FAILURE_STATE) {
|
265
|
+
free(match_data->right);
|
266
|
+
free(match_data->left);
|
267
|
+
free(match_data);
|
268
|
+
return false;
|
269
|
+
}
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|