File: wildmatch.c

package info (click to toggle)
rush 2.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 8,276 kB
  • sloc: ansic: 46,428; sh: 18,253; yacc: 881; lex: 760; makefile: 284; awk: 87; lisp: 56; sed: 24
file content (128 lines) | stat: -rw-r--r-- 3,057 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* This file is part of GNU Rush.                  
   Copyright (C) 2008-2024 Sergey Poznyakoff

   GNU Rush is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   GNU Rush is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with GNU Rush.  If not, see <http://www.gnu.org/licenses/>. */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "wordsplit.h"

enum {
	WILD_FALSE = 0,
	WILD_TRUE,
	WILD_ABORT
};

static int
match_char_class(char const **pexpr, char c)
{
	int res;
	int rc;
	char const *expr = *pexpr;

	expr++;
	if (*expr == '^') {
		res = 0;
		expr++;
	} else
		res = 1;

	if (*expr == '-' || *expr == ']')
		rc = c == *expr++;
	else
		rc = !res;
	
	for (; *expr && *expr != ']'; expr++) {
		if (rc == res) {
			if (*expr == '\\' && expr[1] == ']')
				expr++;
		} else if (expr[1] == '-') {
			if (*expr == '\\')
				rc = *++expr == c;
			else {
				rc = *expr <= c && c <= expr[2];
				expr += 2;
			}
		} else if (*expr == '\\' && expr[1] == ']')
			rc = *++expr == c;
		else
			rc = *expr == c;
	}
	*pexpr = *expr ? expr + 1 : expr;
	return rc == res;
}

#define END_OF_NAME(s,l) ((l) == 0 || *(s) == 0)
#define NEXT_CHAR(s,l) (s++, l--)

int
wilder_match(char const *expr, char const *name, size_t len)
{
        int c;

        while (expr && *expr) {
		if (END_OF_NAME(name, len) && *expr != '*')
			return WILD_ABORT;
                switch (*expr) {
                case '*':
			while (*++expr == '*')
				;
			if (*expr == 0)
				return WILD_TRUE;
			while (!END_OF_NAME(name, len)) {
				int res;
				res = wilder_match(expr, name, len);
				if (res != WILD_FALSE)
					return res;
				NEXT_CHAR(name, len);
			}
                        return WILD_ABORT;
                        
                case '?':
                        expr++;
			NEXT_CHAR(name, len);
                        break;
                        
		case '[':
			if (!match_char_class(&expr, *name))
				return WILD_FALSE;
			NEXT_CHAR(name, len);
			break;
			
                case '\\':
                        if (expr[1]) {
				c = *++expr; expr++;
				if (*name != wordsplit_c_unquote_char(c))
					return WILD_FALSE;
				NEXT_CHAR(name, len);
				break;
			}
			/* fall through */
                default:
			if (*expr != *name)
                                return WILD_FALSE;
                        expr++;
			NEXT_CHAR(name, len);
                }
        }
        return END_OF_NAME(name, len) ? WILD_TRUE : WILD_FALSE;
}

/* Return 0 if first LEN bytes of NAME match globbing pattern EXPR. */
int
wildmatch(char const *expr, char const *name, size_t len)
{
	return wilder_match(expr, name, len) != WILD_TRUE;
}