/*
* PATMAT.C - Pattern matching.
*
* Written November 29, 1988 by Sreenath Chary. Minor maintenance on
* December 21, 1996 by Andrew Clarke. Released to the public domain.
*
* Pass two string pointers as parameters. The first being a raw
* string and the second a pattern the raw string is to be matched
* against. If the raw string matches the pattern, the function returns
* 1, otherwise it returns 0.
*
* patmat("abcdefghi", "*ghi") returns 1
* patmat("abcdefghi", "??c??f*") returns 1
* patmat("abcdefghi", "*dh*") returns 0
* patmat("abcdefghi", "*def") returns 0
*
* The asterisk is a wildcard to allow any characters from its first
* appearance to the next specific character. The character ? is a
* wildcard for only one character in the position it appears.
*
* Combinations such as "*?" or "?*" or "**" are illegal for obvious
* reasons, and the functions may goof, although I think it will still
* work.
*
* The only simple way I could devise is to use recursion. Each
* character in the pattern is taken and compared with the character in
* the raw string. If it matches then the remaining amount of the
* string and the remaining amount of the pattern are passed as parameters
* to patmat again until the end of the pattern. If at any stage the
* pattern does not match, then we go back one level and at this level
* if the previous character was an asterisk in the pattern, we hunt
* again from where we left off, otherwise we return back one more level
* with a not found and the process goes on till the first level call.
*
* Only one character at a time is considered, except when the character
* is an asterisk. You'll get the logic as the program unfolds.
*/
#include <string.h>
#include "patmat.h"
int patmat(char *raw, char *pat)
{
/* if pointed to one, then match (both NULL also) */
if ( pat==raw )
{
return 1;
}
/* if only one is NULL, then mismatch */
if ( !pat || !raw )
{
return 0;
}
/* if it's the end of both strings, then match */
if (*pat == '\0' && *raw == '\0')
{
return 1;
}
/* if it's the end of only pat, then mismatch */
if (*pat == '\0')
{
return 0;
}
/* if pattern is a '*' */
if (*pat == '*')
{
unsigned int i;
/* match patterns *?****???***?? faster... */
while (*(++pat))
if (*pat == '*') {
/* do nothing */
} else if (*pat == '?') {
if (*raw) ++raw;
else return 0;
} else
break;
/* if it is the end of pat, then match */
if (*pat == '\0')
{
return 1;
}
/* else hunt for match or wildcard */
for (i = 0; i <= strlen(raw); i++)
{
if (*(raw + i) == *pat || *pat == '?')
{
/* if found, match rest of pat */
if (patmat(raw + i + 1, pat + 1) == 1)
{
return 1;
}
}
}
}
else
{
/* if end of raw, then mismatch */
if (*raw == '\0')
{
return 0;
}
/* if chars match then try and match the rest of it */
if (*pat == '?' || *pat == *raw)
{
if (patmat(raw + 1, pat + 1) == 1)
{
return 1;
}
}
}
/* fell through, no match was found */
return 0;
}
#ifdef TEST
#include <stdio.h>
int main(void)
{
printf("patmat(\"abcdefghi\", \"*ghi\"): %d\n", patmat("abcdefghi", "*ghi"));
printf("patmat(\"abcdefghi\", \"??c??f*\"): %d\n", patmat("abcdefghi", "??c??f*"));
printf("patmat(\"abcdefghi\", \"*dh*\"): %d\n", patmat("abcdefghi", "*dh*"));
printf("patmat(\"abcdefghi\", \"*def\"): %d\n", patmat("abcdefghi", "*def"));
return 0;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1