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