/* Environment-specific globbing pattern matching for GNU Pies.
Copyright (C) 2019 Sergey Poznyakoff
GNU Pies 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 Pies 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 Pies. If not, see . */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
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 = 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;
}