#include "arclib.h"
#pragma hdrstop
#include "arclib.h"
#include "_match.h"
#ifndef BOOLEAN
#define BOOLEAN int
#define TRUE 1
#define FALSE 0
#endif
#define MATCH_CHAR_SINGLE '?'
#define MATCH_CHAR_KLEENE_CLOSURE '*'
#define MATCH_CHAR_RANGE_OPEN '['
#define MATCH_CHAR_RANGE '-'
#define MATCH_CHAR_RANGE_CLOSE ']'
#define MATCH_CHAR_LITERAL '\\'
#define MATCH_CHAR_NULL '\0'
#define MATCH_CHAR_CARAT_NEGATE '^'
#define MATCH_CHAR_EXCLAMATION_NEGATE '!'
int matche_after_star( const char *pattern, char *text);
int fast_match_after_star(char *pattern, char *text);
BOOLEAN AL_FUNCTION is_pattern( const char *p )
{
while (*p) {
switch (*p++) {
case MATCH_CHAR_SINGLE:
case MATCH_CHAR_KLEENE_CLOSURE:
case MATCH_CHAR_RANGE_OPEN:
#ifndef FILE_MATCH
case MATCH_CHAR_LITERAL:
#endif
return TRUE;
}
}
return FALSE;
}
BOOLEAN AL_FUNCTION is_valid_pattern( const char *p, int *error_type )
{
*error_type = PATTERN_VALID;
while (*p) {
switch (*p) {
#ifndef FILE_MATCH
case MATCH_CHAR_LITERAL:
if (!*++p) {
*error_type = PATTERN_ESC;
return FALSE;
}
p++;
break;
#endif
case MATCH_CHAR_RANGE_OPEN:
p++;
if (*p == MATCH_CHAR_RANGE_CLOSE) {
*error_type = PATTERN_EMPTY;
return FALSE;
}
if (!*p) {
*error_type = PATTERN_CLOSE;
return FALSE;
}
while (*p != MATCH_CHAR_RANGE_CLOSE) {
if (*p == MATCH_CHAR_LITERAL) {
p++;
if (!*p++) {
*error_type = PATTERN_ESC;
return FALSE;
}
}
else
p++;
if (!*p) {
*error_type = PATTERN_CLOSE;
return FALSE;
}
if (*p == MATCH_CHAR_RANGE) {
if (!*++p || *p == MATCH_CHAR_RANGE_CLOSE) {
*error_type = PATTERN_RANGE;
return FALSE;
}
else {
if (*p == MATCH_CHAR_LITERAL)
p++;
if (!*p++) {
*error_type = PATTERN_ESC;
return FALSE;
}
}
}
}
break;
case MATCH_CHAR_KLEENE_CLOSURE:
case MATCH_CHAR_SINGLE:
default:
p++;
break;
}
}
return TRUE;
}
int AL_FUNCTION matche( const char *p, char *t)
{
char range_start, range_end;
BOOLEAN invert;
BOOLEAN member_match;
BOOLEAN loop;
for (; *p; p++, t++) {
if (!*t) {
return (*p == MATCH_CHAR_KLEENE_CLOSURE &&
*++p == MATCH_CHAR_NULL) ?
MATCH_VALID : MATCH_ABORT;
}
switch (*p) {
case MATCH_CHAR_SINGLE:
break;
case MATCH_CHAR_KLEENE_CLOSURE:
return matche_after_star(p, t);
case MATCH_CHAR_RANGE_OPEN:{
p++;
invert = FALSE;
if (*p == MATCH_CHAR_EXCLAMATION_NEGATE ||
*p == MATCH_CHAR_CARAT_NEGATE) {
invert = TRUE;
p++;
}
if (*p == MATCH_CHAR_RANGE_CLOSE) {
return MATCH_PATTERN;
}
member_match = FALSE;
loop = TRUE;
while (loop != FALSE ) {
if (*p == MATCH_CHAR_RANGE_CLOSE) {
loop = FALSE;
continue;
}
if (*p == MATCH_CHAR_LITERAL) {
range_start = range_end = *++p;
}
else {
range_start = range_end = *p;
}
if (!*p)
return MATCH_PATTERN;
if (*++p == MATCH_CHAR_RANGE) {
range_end = *++p;
if (range_end == MATCH_CHAR_NULL ||
range_end == MATCH_CHAR_RANGE_CLOSE)
return MATCH_PATTERN;
if (range_end == MATCH_CHAR_LITERAL) {
range_end = *++p;
if (!range_end)
return MATCH_PATTERN;
}
p++;
}
if (range_start < range_end) {
if (*t >= range_start && *t <= range_end) {
member_match = TRUE;
loop = FALSE;
}
}
else {
if (*t >= range_end && *t <= range_start) {
member_match = TRUE;
loop = FALSE;
}
}
}
if ((invert && member_match) ||
!(invert || member_match))
return MATCH_RANGE;
if (member_match) {
while (*p != MATCH_CHAR_RANGE_CLOSE) {
if (!*p)
return MATCH_PATTERN;
if (*p == MATCH_CHAR_LITERAL) {
p++;
if (!*p)
return MATCH_PATTERN;
}
p++;
}
}
break;
}
#ifndef FILE_MATCH
case MATCH_CHAR_LITERAL:
p++;
if (!*p)
return MATCH_PATTERN;
#endif
default:
if (*p != *t)
return MATCH_LITERAL;
}
}
if (*t)
return MATCH_END;
else
return MATCH_VALID;
}
int matche_after_star( const char *p, char *t)
{
int match = 0;
char nextp;
while (*p == MATCH_CHAR_SINGLE ||
*p == MATCH_CHAR_KLEENE_CLOSURE) {
if (*p == MATCH_CHAR_SINGLE) {
if (!*t++) {
return MATCH_ABORT;
}
}
p++;
}
if (!*p) {
return MATCH_VALID;
}
nextp = *p;
#ifndef FILE_MATCH
if (nextp == MATCH_CHAR_LITERAL) {
nextp = p[1];
if (!nextp)
return MATCH_PATTERN;
}
#endif
do {
if (nextp == *t || nextp == MATCH_CHAR_RANGE_OPEN) {
match = matche(p, t);
}
if (!*t++)
match = MATCH_ABORT;
} while (match != MATCH_VALID &&
match != MATCH_ABORT &&
match != MATCH_PATTERN);
return match;
}
BOOLEAN AL_FUNCTION match( char *p, char *t)
{
int error_type;
error_type = matche(p, t);
return (error_type == MATCH_VALID) ? TRUE : FALSE;
}
#ifdef TEST
#include <stdio.h>
int main(int argc, char *argv[])
{
int error;
int is_valid_error;
if (argc != 3) {
printf("Usage: MATCH Pattern Text\n");
}
else {
printf("Pattern: %s\n", argv[1]);
printf("Text : %s\n", argv[2]);
if ( !is_pattern(argv[1])) {
printf(" First Argument Is Not A Pattern\n");
}
else {
#ifdef FILE_MATCH
match(argv[1], argv[2]) ? printf("TRUE") : printf("FALSE");
#endif
error = matche(argv[1], argv[2]);
is_valid_pattern(argv[1], &is_valid_error);
switch (error) {
case MATCH_VALID:
printf(" Match Successful");
if (is_valid_error != PATTERN_VALID)
printf(" -- is_valid_pattern() is complaining\n");
else
printf("\n");
break;
#ifndef FILE_MATCH
case MATCH_LITERAL:
printf(" Match Failed on Literal\n");
break;
#endif
case MATCH_RANGE:
printf(" Match Failed on [..]\n");
break;
case MATCH_ABORT:
printf(" Match Failed on Early Text Termination\n");
break;
case MATCH_END:
printf(" Match Failed on Early Pattern Termination\n");
break;
case MATCH_PATTERN:
switch (is_valid_error) {
case PATTERN_VALID:
printf(" Internal Disagreement On Pattern\n");
break;
#ifndef FILE_MATCH
case PATTERN_ESC:
printf(" Literal Escape at End of Pattern\n");
break;
#endif
case PATTERN_RANGE:
printf(" No End of Range in [..] Construct\n");
break;
case PATTERN_CLOSE:
printf(" [..] Construct is Open\n");
break;
case PATTERN_EMPTY:
printf(" [..] Construct is Empty\n");
break;
default:
printf(" Internal Error in is_valid_pattern()\n");
}
break;
default:
printf(" Internal Error in matche()\n");
break;
}
}
}
return (0);
}
#endif