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;
}
|