//
// aegis - project change supervisor
// Copyright (C) 1997-1999, 2002, 2004-2006, 2008 Peter Miller
//
// This program 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 of the License, or
// (at your option) any later version.
//
// This program 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 this program. If not, see
// .
//
#include
#include
#include
#include
//
// NAME
// gmatch - match entryname pattern
//
// SYNOPSIS
// int gmatch(char *formal, char *actual);
//
// DESCRIPTION
// The formal strings is used as a template to match the given actual
// string against.
//
// The pattern elements understood are
// * match zero or more of any character
// ? match any single character
// [^xxx] match any single character not in the set given.
// [xxx] match any single character in the set given.
// The - character is understood to be a range indicator.
// If the ] character is the first of the set it is
// considered as part of the set, not the terminator.
//
// RETURNS
// the gmatch function returns zero if they do not match,
// and nonzero if they do. Returns -1 on error.
//
// CAVEAT
// This is a limited set of the sh(1) patterns.
// Assumes that the `original' global variable has been initialized,
// it is used for error reporting.
//
int
gmatch(const char *formal, const char *actual)
{
const char *cp;
int result;
trace(("gmatch(formal = %8.8lX, actual = %8.8lX)\n{\n", (long)formal,
(long)actual));
while (*formal)
{
trace(("formal == \"%s\";\n", formal));
trace(("actual = \"%s\";\n", actual));
switch (*formal)
{
default:
if (*actual++ != *formal++)
{
result = 0;
goto ret;
}
break;
case '?':
if (!*actual++)
{
result = 0;
goto ret;
}
++formal;
break;
case '*':
for (;;)
{
++formal;
switch (*formal)
{
case 0:
result = 1;
goto ret;
case '*':
continue;
case '?':
if (!*actual++)
{
result = 0;
goto ret;
}
continue;
default:
break;
}
break;
}
cp = actual + strlen(actual);
for (;;)
{
result = gmatch(formal, cp);
if (result)
{
result = 1;
break;
}
--cp;
if (cp < actual)
{
result = 0;
break;
}
}
goto ret;
case '[':
++formal;
if (*formal == '^')
{
++formal;
for (;;)
{
if (!*formal)
{
no_close:
result = -1;
goto ret;
}
//
// note: this allows leading close
// square bracket elegantly
//
if
(
formal[1] == '-'
&&
formal[2]
&&
formal[2] != ']'
&&
formal[3]
)
{
char c1;
char c2;
c1 = formal[0];
c2 = formal[2];
formal += 3;
if
(
c1 <= c2
?
(c1 <= *actual && *actual <= c2)
:
(c2 <= *actual && *actual <= c1)
)
{
result = 0;
goto ret;
}
}
else if (*actual == *formal++)
{
result = 0;
goto ret;
}
if (*formal == ']')
break;
}
++formal;
}
else
{
for (;;)
{
if (!*formal)
goto no_close;
//
// note: this allows leading close
// square bracket elegantly
//
trace(("formal == \"%s\";\n", formal));
trace(("actual = \"%s\";\n", actual));
if
(
formal[1] == '-'
&&
formal[2]
&&
formal[2] != ']'
&&
formal[3]
)
{
char c1;
char c2;
c1 = formal[0];
c2 = formal[2];
formal += 3;
if
(
c1 <= c2
?
(c1 <= *actual && *actual <= c2)
:
(c2 <= *actual && *actual <= c1)
)
break;
}
else if (*actual == *formal++)
break;
if (*formal == ']')
{
result = 0;
goto ret;
}
}
for (;;)
{
if (!*formal)
goto no_close;
trace(("formal == \"%s\";\n", formal));
trace(("actual = \"%s\";\n", actual));
if (*formal++ == ']')
break;
}
}
++actual;
break;
}
}
result = (*actual == 0);
//
// here for all exits
//
ret:
trace(("return %d;\n", result));
trace(("}\n"));
return result;
}
int
gmatch(const nstring &pattern, const nstring &candidate)
{
return gmatch(pattern.c_str(), candidate.c_str());
}