source: MondoRescue/branches/2.2.9/mindi-busybox/shell/match.c@ 3320

Last change on this file since 3320 was 3320, checked in by Bruno Cornec, 9 years ago
  • Re-add (thanks git BTW) the 2.2.9 branch which had been destroyed in the move to 3.0
  • Property svn:eol-style set to native
File size: 3.2 KB
Line 
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
30char* 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
97int 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
Note: See TracBrowser for help on using the repository browser.