Apply post-1.17.3 fixes, bump version to 1.17.4
[oweals/busybox.git] / shell / match.c
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 the GPL v2 or later, see the file LICENSE in this tarball.
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 #else
22 # include "libbb.h"
23 #endif
24 #include <fnmatch.h>
25 #include "match.h"
26
27 #define pmatch(a, b) !fnmatch((a), (b), 0)
28
29 char *scanleft(char *string, char *pattern, bool match_at_left)
30 {
31         char c;
32         char *loc = string;
33
34         do {
35                 int match;
36                 const char *s;
37
38                 c = *loc;
39                 if (match_at_left) {
40                         *loc = '\0';
41                         s = string;
42                 } else
43                         s = loc;
44                 match = pmatch(pattern, s);
45                 *loc = c;
46
47                 if (match)
48                         return loc;
49
50                 loc++;
51         } while (c);
52
53         return NULL;
54 }
55
56 char *scanright(char *string, char *pattern, bool match_at_left)
57 {
58         char c;
59         char *loc = string + strlen(string);
60
61         while (loc >= string) {
62                 int match;
63                 const char *s;
64
65                 c = *loc;
66                 if (match_at_left) {
67                         *loc = '\0';
68                         s = string;
69                 } else
70                         s = loc;
71                 match = pmatch(pattern, s);
72                 *loc = c;
73
74                 if (match)
75                         return loc;
76
77                 loc--;
78         }
79
80         return NULL;
81 }
82
83 #ifdef STANDALONE
84 int main(int argc, char *argv[])
85 {
86         char *string;
87         char *op;
88         char *pattern;
89         bool match_at_left;
90         char *loc;
91
92         int i;
93
94         if (argc == 1) {
95                 puts(
96                         "Usage: match <test> [test...]\n\n"
97                         "Where a <test> is the form: <string><op><match>\n"
98                         "This is to test the shell ${var#val} expression type.\n\n"
99                         "e.g. `match 'abc#a*'` -> bc"
100                 );
101                 return 1;
102         }
103
104         for (i = 1; i < argc; ++i) {
105                 size_t off;
106                 scan_t scan;
107
108                 printf("'%s': ", argv[i]);
109
110                 string = strdup(argv[i]);
111                 off = strcspn(string, "#%");
112                 if (!off) {
113                         printf("invalid format\n");
114                         free(string);
115                         continue;
116                 }
117                 op = string + off;
118                 scan = pick_scan(op[0], op[1], &match_at_left);
119                 pattern = op + 1;
120                 if (op[0] == op[1])
121                         op[1] = '\0', ++pattern;
122                 op[0] = '\0';
123
124                 loc = scan(string, pattern, match_at_left);
125
126                 if (match_at_left) {
127                         printf("'%s'\n", loc);
128                 } else {
129                         *loc = '\0';
130                         printf("'%s'\n", string);
131                 }
132
133                 free(string);
134         }
135
136         return 0;
137 }
138 #endif