blob: 8024f2747978463ca187b168993f3a1a16c2f06e [file] [log] [blame]
Mike Frysingera4f331d2009-04-07 06:03:22 +00001/*
2 * ##/%% variable matching code ripped out of ash shell for code sharing
3 *
Denys Vlasenko73067272010-01-12 22:11:24 +01004 * This code is derived from software contributed to Berkeley by
5 * Kenneth Almquist.
6 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02007 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Denys Vlasenko73067272010-01-12 22:11:24 +01008 *
Mike Frysingera4f331d2009-04-07 06:03:22 +00009 * 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.
Mike Frysingera4f331d2009-04-07 06:03:22 +000014 */
Mike Frysingera4f331d2009-04-07 06:03:22 +000015#ifdef STANDALONE
16# include <stdbool.h>
17# include <stdio.h>
18# include <stdlib.h>
19# include <string.h>
20# include <unistd.h>
Denys Vlasenko701e1272010-09-04 21:21:07 +020021# define FAST_FUNC /* nothing */
22# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN /* nothing */
23# define POP_SAVED_FUNCTION_VISIBILITY /* nothing */
Mike Frysingera4f331d2009-04-07 06:03:22 +000024#else
Denis Vlasenko1943aec2009-04-09 14:15:57 +000025# include "libbb.h"
Mike Frysingera4f331d2009-04-07 06:03:22 +000026#endif
27#include <fnmatch.h>
28#include "match.h"
29
Denys Vlasenko701e1272010-09-04 21:21:07 +020030char* FAST_FUNC scan_and_match(char *string, const char *pattern, unsigned flags)
Mike Frysingera4f331d2009-04-07 06:03:22 +000031{
Denys Vlasenko701e1272010-09-04 21:21:07 +020032 char *loc;
33 char *end;
34 unsigned len = strlen(string);
35 int early_exit;
Mike Frysingera4f331d2009-04-07 06:03:22 +000036
Denys Vlasenko701e1272010-09-04 21:21:07 +020037 /* 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) {
Denys Vlasenko2d8187c2010-09-12 15:06:42 +020067 int r;
Mike Frysingera4f331d2009-04-07 06:03:22 +000068
Denys Vlasenko701e1272010-09-04 21:21:07 +020069 if (flags & SCAN_MATCH_LEFT_HALF) {
Denys Vlasenko49cc3ca2021-07-27 17:53:55 +020070 char c = *loc;
Mike Frysingera4f331d2009-04-07 06:03:22 +000071 *loc = '\0';
Denys Vlasenko2d8187c2010-09-12 15:06:42 +020072 r = fnmatch(pattern, string, 0);
Denys Vlasenko55f81332018-03-02 18:12:12 +010073 //bb_error_msg("fnmatch('%s','%s',0):%d", pattern, string, r);
Denys Vlasenkoe298ce62010-09-04 19:52:44 +020074 *loc = c;
75 } else {
Denys Vlasenko2d8187c2010-09-12 15:06:42 +020076 r = fnmatch(pattern, loc, 0);
Denys Vlasenkod4802c62018-03-02 20:48:36 +010077 //bb_error_msg("fnmatch('%s','%s',0):%d", pattern, loc, r);
Denys Vlasenkoe298ce62010-09-04 19:52:44 +020078 }
Denys Vlasenko2d8187c2010-09-12 15:06:42 +020079 if (r == 0) /* match found */
Mike Frysingera4f331d2009-04-07 06:03:22 +000080 return loc;
Denys Vlasenko701e1272010-09-04 21:21:07 +020081 if (early_exit) {
82#ifdef STANDALONE
83 printf("(early exit) ");
84#endif
85 break;
Denys Vlasenkoe298ce62010-09-04 19:52:44 +020086 }
Mike Frysingera4f331d2009-04-07 06:03:22 +000087
Denys Vlasenko701e1272010-09-04 21:21:07 +020088 if (flags & SCAN_MOVE_FROM_LEFT) {
89 loc++;
90 } else {
91 loc--;
92 }
93 }
Mike Frysingera4f331d2009-04-07 06:03:22 +000094 return NULL;
95}
96
97#ifdef STANDALONE
Denys Vlasenko9b6f44e2022-05-01 17:06:00 +020098int main(int argc, char **argv)
Mike Frysingera4f331d2009-04-07 06:03:22 +000099{
100 char *string;
101 char *op;
102 char *pattern;
Mike Frysingera4f331d2009-04-07 06:03:22 +0000103 char *loc;
104
Denys Vlasenko701e1272010-09-04 21:21:07 +0200105 setvbuf(stdout, NULL, _IONBF, 0);
Mike Frysingera4f331d2009-04-07 06:03:22 +0000106
Denys Vlasenko701e1272010-09-04 21:21:07 +0200107 if (!argv[1]) {
Mike Frysingera4f331d2009-04-07 06:03:22 +0000108 puts(
109 "Usage: match <test> [test...]\n\n"
110 "Where a <test> is the form: <string><op><match>\n"
111 "This is to test the shell ${var#val} expression type.\n\n"
112 "e.g. `match 'abc#a*'` -> bc"
113 );
114 return 1;
115 }
116
Denys Vlasenko701e1272010-09-04 21:21:07 +0200117 while (*++argv) {
Mike Frysingera4f331d2009-04-07 06:03:22 +0000118 size_t off;
Denys Vlasenko701e1272010-09-04 21:21:07 +0200119 unsigned scan_flags;
Mike Frysingera4f331d2009-04-07 06:03:22 +0000120
Denys Vlasenko701e1272010-09-04 21:21:07 +0200121 string = *argv;
Mike Frysingera4f331d2009-04-07 06:03:22 +0000122 off = strcspn(string, "#%");
123 if (!off) {
124 printf("invalid format\n");
Mike Frysingera4f331d2009-04-07 06:03:22 +0000125 continue;
126 }
127 op = string + off;
Denys Vlasenko701e1272010-09-04 21:21:07 +0200128 scan_flags = pick_scan(op[0], op[1]);
129
130 printf("'%s': flags:%x, ", string, scan_flags);
Mike Frysingera4f331d2009-04-07 06:03:22 +0000131 pattern = op + 1;
132 if (op[0] == op[1])
Denys Vlasenko701e1272010-09-04 21:21:07 +0200133 pattern++;
Mike Frysingera4f331d2009-04-07 06:03:22 +0000134 op[0] = '\0';
135
Denys Vlasenko701e1272010-09-04 21:21:07 +0200136 loc = scan_and_match(string, pattern, scan_flags);
Mike Frysingera4f331d2009-04-07 06:03:22 +0000137
Denys Vlasenko701e1272010-09-04 21:21:07 +0200138 if (scan_flags & SCAN_MATCH_LEFT_HALF) {
Mike Frysingera4f331d2009-04-07 06:03:22 +0000139 printf("'%s'\n", loc);
140 } else {
Denys Vlasenko701e1272010-09-04 21:21:07 +0200141 if (loc)
142 *loc = '\0';
Mike Frysingera4f331d2009-04-07 06:03:22 +0000143 printf("'%s'\n", string);
144 }
Mike Frysingera4f331d2009-04-07 06:03:22 +0000145 }
146
147 return 0;
148}
149#endif