blob: fee3cf2a80d432dbd2423d1060cfd4cda1548c3f
1 | /* |
2 | * ##/%% variable matching code ripped out of ash shell for code sharing |
3 | * |
4 | * This code is derived from software contributed to Berkeley by |
5 | * Kenneth Almquist. |
6 | * |
7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
8 | * |
9 | * Copyright (c) 1989, 1991, 1993, 1994 |
10 | * The Regents of the University of California. All rights reserved. |
11 | * |
12 | * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au> |
13 | * was re-ported from NetBSD and debianized. |
14 | */ |
15 | #ifdef STANDALONE |
16 | # include <stdbool.h> |
17 | # include <stdio.h> |
18 | # include <stdlib.h> |
19 | # include <string.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 */ |
24 | #else |
25 | # include "libbb.h" |
26 | #endif |
27 | #include <fnmatch.h> |
28 | #include "match.h" |
29 | |
30 | char* FAST_FUNC scan_and_match(char *string, const char *pattern, unsigned flags) |
31 | { |
32 | char *loc; |
33 | char *end; |
34 | unsigned len = strlen(string); |
35 | int early_exit; |
36 | |
37 | /* We can stop the scan early only if the string part |
38 | * we are matching against is shrinking, and the pattern has |
39 | * an unquoted "star" at the corresponding end. There are two cases. |
40 | * Case 1: |
41 | * "qwerty" does not match against pattern "*zy", |
42 | * no point in trying to match "werty", "erty" etc: |
43 | */ |
44 | early_exit = (flags == (SCAN_MOVE_FROM_LEFT + SCAN_MATCH_RIGHT_HALF) && pattern[0] == '*'); |
45 | |
46 | if (flags & SCAN_MOVE_FROM_LEFT) { |
47 | loc = string; |
48 | end = string + len + 1; |
49 | } else { |
50 | loc = string + len; |
51 | end = string - 1; |
52 | if (flags == (SCAN_MOVE_FROM_RIGHT + SCAN_MATCH_LEFT_HALF)) { |
53 | /* Case 2: |
54 | * "qwerty" does not match against pattern "qz*", |
55 | * no point in trying to match "qwert", "qwer" etc: |
56 | */ |
57 | const char *p = pattern + strlen(pattern); |
58 | if (--p >= pattern && *p == '*') { |
59 | early_exit = 1; |
60 | while (--p >= pattern && *p == '\\') |
61 | early_exit ^= 1; |
62 | } |
63 | } |
64 | } |
65 | |
66 | while (loc != end) { |
67 | char c; |
68 | int r; |
69 | |
70 | c = *loc; |
71 | if (flags & SCAN_MATCH_LEFT_HALF) { |
72 | *loc = '\0'; |
73 | r = fnmatch(pattern, string, 0); |
74 | *loc = c; |
75 | } else { |
76 | r = fnmatch(pattern, loc, 0); |
77 | } |
78 | if (r == 0) /* match found */ |
79 | return loc; |
80 | if (early_exit) { |
81 | #ifdef STANDALONE |
82 | printf("(early exit) "); |
83 | #endif |
84 | break; |
85 | } |
86 | |
87 | if (flags & SCAN_MOVE_FROM_LEFT) { |
88 | loc++; |
89 | } else { |
90 | loc--; |
91 | } |
92 | } |
93 | return NULL; |
94 | } |
95 | |
96 | #ifdef STANDALONE |
97 | int main(int argc, char *argv[]) |
98 | { |
99 | char *string; |
100 | char *op; |
101 | char *pattern; |
102 | char *loc; |
103 | |
104 | setvbuf(stdout, NULL, _IONBF, 0); |
105 | |
106 | if (!argv[1]) { |
107 | puts( |
108 | "Usage: match <test> [test...]\n\n" |
109 | "Where a <test> is the form: <string><op><match>\n" |
110 | "This is to test the shell ${var#val} expression type.\n\n" |
111 | "e.g. `match 'abc#a*'` -> bc" |
112 | ); |
113 | return 1; |
114 | } |
115 | |
116 | while (*++argv) { |
117 | size_t off; |
118 | unsigned scan_flags; |
119 | |
120 | string = *argv; |
121 | off = strcspn(string, "#%"); |
122 | if (!off) { |
123 | printf("invalid format\n"); |
124 | continue; |
125 | } |
126 | op = string + off; |
127 | scan_flags = pick_scan(op[0], op[1]); |
128 | |
129 | printf("'%s': flags:%x, ", string, scan_flags); |
130 | pattern = op + 1; |
131 | if (op[0] == op[1]) |
132 | pattern++; |
133 | op[0] = '\0'; |
134 | |
135 | loc = scan_and_match(string, pattern, scan_flags); |
136 | |
137 | if (scan_flags & SCAN_MATCH_LEFT_HALF) { |
138 | printf("'%s'\n", loc); |
139 | } else { |
140 | if (loc) |
141 | *loc = '\0'; |
142 | printf("'%s'\n", string); |
143 | } |
144 | } |
145 | |
146 | return 0; |
147 | } |
148 | #endif |
149 |