aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2010-09-04 21:21:07 +0200
committerDenys Vlasenko <dvlasenk@redhat.com>2010-09-04 21:21:07 +0200
commit701e127f7d892909a58c6f3333e23588ccef9e22 (patch)
tree9d756fca6a1ef496dbf02529e090f2f711a6c261
parente298ce69baef029f3951dd1d5ed50fdbc6c55c80 (diff)
downloadbusybox-w32-701e127f7d892909a58c6f3333e23588ccef9e22.tar.gz
busybox-w32-701e127f7d892909a58c6f3333e23588ccef9e22.tar.bz2
busybox-w32-701e127f7d892909a58c6f3333e23588ccef9e22.zip
hush: optimize #[#] and %[%] for speed. size -2 bytes.
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
-rw-r--r--shell/hush.c22
-rw-r--r--shell/match.c106
-rw-r--r--shell/match.h29
3 files changed, 87 insertions, 70 deletions
diff --git a/shell/hush.c b/shell/hush.c
index d3dab5863..4f80b7d83 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -2829,23 +2829,21 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char
2829 * Then var's value is matched to it and matching part removed. 2829 * Then var's value is matched to it and matching part removed.
2830 */ 2830 */
2831 if (val) { 2831 if (val) {
2832 bool match_at_left; 2832 char *exp_exp_word;
2833 char *loc; 2833 char *loc;
2834 scan_t scan = pick_scan(exp_op, *exp_word, &match_at_left); 2834 unsigned scan_flags = pick_scan(exp_op, *exp_word);
2835 if (exp_op == *exp_word) /* ## or %% */ 2835 if (exp_op == *exp_word) /* ## or %% */
2836 exp_word++; 2836 exp_word++;
2837 val = to_be_freed = xstrdup(val); 2837 val = to_be_freed = xstrdup(val);
2838 { 2838 exp_exp_word = expand_pseudo_dquoted(exp_word);
2839 char *exp_exp_word = expand_pseudo_dquoted(exp_word); 2839 if (exp_exp_word)
2840 if (exp_exp_word) 2840 exp_word = exp_exp_word;
2841 exp_word = exp_exp_word; 2841 loc = scan_and_match(to_be_freed, exp_word, scan_flags);
2842 loc = scan(to_be_freed, exp_word, match_at_left); 2842 //bb_error_msg("op:%c str:'%s' pat:'%s' res:'%s'",
2843 //bb_error_msg("op:%c str:'%s' pat:'%s' res:'%s'", 2843 // exp_op, to_be_freed, exp_word, loc);
2844 // exp_op, to_be_freed, exp_word, loc); 2844 free(exp_exp_word);
2845 free(exp_exp_word);
2846 }
2847 if (loc) { /* match was found */ 2845 if (loc) { /* match was found */
2848 if (match_at_left) /* # or ## */ 2846 if (scan_flags & SCAN_MATCH_LEFT_HALF) /* # or ## */
2849 val = loc; 2847 val = loc;
2850 else /* % or %% */ 2848 else /* % or %% */
2851 *loc = '\0'; 2849 *loc = '\0';
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
29char *scanleft(char *string, char *pattern, bool match_at_left) 32char* 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 }
53char *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;
diff --git a/shell/match.h b/shell/match.h
index c022ceb25..aa393ed1a 100644
--- a/shell/match.h
+++ b/shell/match.h
@@ -7,25 +7,26 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
7 7
8//TODO! Why ash.c still uses internal version?! 8//TODO! Why ash.c still uses internal version?!
9 9
10typedef char *(*scan_t)(char *string, char *match, bool match_at_left); 10enum {
11 SCAN_MOVE_FROM_LEFT = (1 << 0),
12 SCAN_MOVE_FROM_RIGHT = (1 << 1),
13 SCAN_MATCH_LEFT_HALF = (1 << 2),
14 SCAN_MATCH_RIGHT_HALF = (1 << 3),
15};
11 16
12char *scanleft(char *string, char *match, bool match_at_left); 17char* FAST_FUNC scan_and_match(char *string, const char *pattern, unsigned flags);
13char *scanright(char *string, char *match, bool match_at_left);
14 18
15static inline scan_t pick_scan(char op1, char op2, bool *match_at_left) 19static inline unsigned pick_scan(char op1, char op2)
16{ 20{
17 /* # - scanleft 21 unsigned scan_flags;
18 * ## - scanright
19 * % - scanright
20 * %% - scanleft
21 */
22 if (op1 == '#') { 22 if (op1 == '#') {
23 *match_at_left = true; 23 scan_flags = SCAN_MATCH_LEFT_HALF +
24 return op1 == op2 ? scanright : scanleft; 24 (op1 == op2 ? SCAN_MOVE_FROM_RIGHT : SCAN_MOVE_FROM_LEFT);
25 } else { 25 } else { /* % */
26 *match_at_left = false; 26 scan_flags = SCAN_MATCH_RIGHT_HALF +
27 return op1 == op2 ? scanleft : scanright; 27 (op1 == op2 ? SCAN_MOVE_FROM_LEFT : SCAN_MOVE_FROM_RIGHT);
28 } 28 }
29 return scan_flags;
29} 30}
30 31
31POP_SAVED_FUNCTION_VISIBILITY 32POP_SAVED_FUNCTION_VISIBILITY