diff options
Diffstat (limited to 'shell/match.c')
-rw-r--r-- | shell/match.c | 106 |
1 files changed, 62 insertions, 44 deletions
diff --git a/shell/match.c b/shell/match.c index 01b843918..e77c5d732 100644 --- a/shell/match.c +++ b/shell/match.c | |||
@@ -18,6 +18,9 @@ | |||
18 | # include <stdlib.h> | 18 | # include <stdlib.h> |
19 | # include <string.h> | 19 | # include <string.h> |
20 | # include <unistd.h> | 20 | # include <unistd.h> |
21 | # define FAST_FUNC /* nothing */ | ||
22 | # define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN /* nothing */ | ||
23 | # define POP_SAVED_FUNCTION_VISIBILITY /* nothing */ | ||
21 | #else | 24 | #else |
22 | # include "libbb.h" | 25 | # include "libbb.h" |
23 | #endif | 26 | #endif |
@@ -26,16 +29,48 @@ | |||
26 | 29 | ||
27 | #define pmatch(a, b) !fnmatch((a), (b), 0) | 30 | #define pmatch(a, b) !fnmatch((a), (b), 0) |
28 | 31 | ||
29 | char *scanleft(char *string, char *pattern, bool match_at_left) | 32 | char* FAST_FUNC scan_and_match(char *string, const char *pattern, unsigned flags) |
30 | { | 33 | { |
31 | char c; | 34 | char *loc; |
32 | char *loc = string; | 35 | char *end; |
36 | unsigned len = strlen(string); | ||
37 | int early_exit; | ||
38 | |||
39 | /* We can stop the scan early only if the string part | ||
40 | * we are matching against is shrinking, and the pattern has | ||
41 | * an unquoted "star" at the corresponding end. There are two cases. | ||
42 | * Case 1: | ||
43 | * "qwerty" does not match against pattern "*zy", | ||
44 | * no point in trying to match "werty", "erty" etc: | ||
45 | */ | ||
46 | early_exit = (flags == (SCAN_MOVE_FROM_LEFT + SCAN_MATCH_RIGHT_HALF) && pattern[0] == '*'); | ||
47 | |||
48 | if (flags & SCAN_MOVE_FROM_LEFT) { | ||
49 | loc = string; | ||
50 | end = string + len + 1; | ||
51 | } else { | ||
52 | loc = string + len; | ||
53 | end = string - 1; | ||
54 | if (flags == (SCAN_MOVE_FROM_RIGHT + SCAN_MATCH_LEFT_HALF)) { | ||
55 | /* Case 2: | ||
56 | * "qwerty" does not match against pattern "qz*", | ||
57 | * no point in trying to match "qwert", "qwer" etc: | ||
58 | */ | ||
59 | const char *p = pattern + strlen(pattern); | ||
60 | if (--p >= pattern && *p == '*') { | ||
61 | early_exit = 1; | ||
62 | while (--p >= pattern && *p == '\\') | ||
63 | early_exit ^= 1; | ||
64 | } | ||
65 | } | ||
66 | } | ||
33 | 67 | ||
34 | while (1) { | 68 | while (loc != end) { |
69 | char c; | ||
35 | int match; | 70 | int match; |
36 | 71 | ||
37 | c = *loc; | 72 | c = *loc; |
38 | if (match_at_left) { | 73 | if (flags & SCAN_MATCH_LEFT_HALF) { |
39 | *loc = '\0'; | 74 | *loc = '\0'; |
40 | match = pmatch(pattern, string); | 75 | match = pmatch(pattern, string); |
41 | *loc = c; | 76 | *loc = c; |
@@ -44,33 +79,19 @@ char *scanleft(char *string, char *pattern, bool match_at_left) | |||
44 | } | 79 | } |
45 | if (match) | 80 | if (match) |
46 | return loc; | 81 | return loc; |
47 | if (!c) | 82 | if (early_exit) { |
48 | return NULL; | 83 | #ifdef STANDALONE |
49 | loc++; | 84 | printf("(early exit) "); |
50 | } | 85 | #endif |
51 | } | 86 | break; |
52 | 87 | } | |
53 | char *scanright(char *string, char *pattern, bool match_at_left) | ||
54 | { | ||
55 | char c; | ||
56 | char *loc = string + strlen(string); | ||
57 | |||
58 | while (loc >= string) { | ||
59 | int match; | ||
60 | 88 | ||
61 | c = *loc; | 89 | if (flags & SCAN_MOVE_FROM_LEFT) { |
62 | if (match_at_left) { | 90 | loc++; |
63 | *loc = '\0'; | ||
64 | match = pmatch(pattern, string); | ||
65 | *loc = c; | ||
66 | } else { | 91 | } else { |
67 | match = pmatch(pattern, loc); | 92 | loc--; |
68 | } | 93 | } |
69 | if (match) | ||
70 | return loc; | ||
71 | loc--; | ||
72 | } | 94 | } |
73 | |||
74 | return NULL; | 95 | return NULL; |
75 | } | 96 | } |
76 | 97 | ||
@@ -80,12 +101,11 @@ int main(int argc, char *argv[]) | |||
80 | char *string; | 101 | char *string; |
81 | char *op; | 102 | char *op; |
82 | char *pattern; | 103 | char *pattern; |
83 | bool match_at_left; | ||
84 | char *loc; | 104 | char *loc; |
85 | 105 | ||
86 | int i; | 106 | setvbuf(stdout, NULL, _IONBF, 0); |
87 | 107 | ||
88 | if (argc == 1) { | 108 | if (!argv[1]) { |
89 | puts( | 109 | puts( |
90 | "Usage: match <test> [test...]\n\n" | 110 | "Usage: match <test> [test...]\n\n" |
91 | "Where a <test> is the form: <string><op><match>\n" | 111 | "Where a <test> is the form: <string><op><match>\n" |
@@ -95,36 +115,34 @@ int main(int argc, char *argv[]) | |||
95 | return 1; | 115 | return 1; |
96 | } | 116 | } |
97 | 117 | ||
98 | for (i = 1; i < argc; ++i) { | 118 | while (*++argv) { |
99 | size_t off; | 119 | size_t off; |
100 | scan_t scan; | 120 | unsigned scan_flags; |
101 | |||
102 | printf("'%s': ", argv[i]); | ||
103 | 121 | ||
104 | string = strdup(argv[i]); | 122 | string = *argv; |
105 | off = strcspn(string, "#%"); | 123 | off = strcspn(string, "#%"); |
106 | if (!off) { | 124 | if (!off) { |
107 | printf("invalid format\n"); | 125 | printf("invalid format\n"); |
108 | free(string); | ||
109 | continue; | 126 | continue; |
110 | } | 127 | } |
111 | op = string + off; | 128 | op = string + off; |
112 | scan = pick_scan(op[0], op[1], &match_at_left); | 129 | scan_flags = pick_scan(op[0], op[1]); |
130 | |||
131 | printf("'%s': flags:%x, ", string, scan_flags); | ||
113 | pattern = op + 1; | 132 | pattern = op + 1; |
114 | if (op[0] == op[1]) | 133 | if (op[0] == op[1]) |
115 | op[1] = '\0', ++pattern; | 134 | pattern++; |
116 | op[0] = '\0'; | 135 | op[0] = '\0'; |
117 | 136 | ||
118 | loc = scan(string, pattern, match_at_left); | 137 | loc = scan_and_match(string, pattern, scan_flags); |
119 | 138 | ||
120 | if (match_at_left) { | 139 | if (scan_flags & SCAN_MATCH_LEFT_HALF) { |
121 | printf("'%s'\n", loc); | 140 | printf("'%s'\n", loc); |
122 | } else { | 141 | } else { |
123 | *loc = '\0'; | 142 | if (loc) |
143 | *loc = '\0'; | ||
124 | printf("'%s'\n", string); | 144 | printf("'%s'\n", string); |
125 | } | 145 | } |
126 | |||
127 | free(string); | ||
128 | } | 146 | } |
129 | 147 | ||
130 | return 0; | 148 | return 0; |