📄 filmatch.c
字号:
/* EPSHeader File: filmatch.c Author: J. Kercheval Created: Thu, 03/14/1991 22:22:01*//* EPSRevision History J. Kercheval Wed, 02/20/1991 22:29:01 Released to Public Domain J. Kercheval Fri, 02/22/1991 15:29:01 fix '\' bugs (two :( of them) J. Kercheval Sun, 03/10/1991 19:31:29 add error return to matche() J. Kercheval Sun, 03/10/1991 20:11:11 add is_valid_pattern code J. Kercheval Sun, 03/10/1991 20:37:11 beef up main() J. Kercheval Tue, 03/12/1991 22:25:10 Released as V1.1 to Public Domain J. Kercheval Thu, 03/14/1991 22:22:25 remove '\' for DOS file parsing J. Kercheval Thu, 03/28/1991 20:58:27 include filmatch.h Jason Hood, 1 August, 1997 - removed error testing in matche() 4 August, 1997 - included TDE stuff, case testing renamed match() to wildcard() 10 August, 1997 - case testing in [] (oops) 31 July, 2005 - match multiple patterns and exclusions*//* Wildcard Pattern Matching*/#include "tdestr.h"#include "tdefunc.h"#include "common.h"/* * jmh 990505: Make UNIX always case sensitive, DOS always case insensitive. */#if defined( __UNIX__ )#define bj_tolower( ch ) ch#endifint matche_after_star (register char *pattern, register char *text);/*----------------------------------------------------------------------------** Return TRUE if PATTERN has any special wildcard characters*----------------------------------------------------------------------------*/BOOLEAN is_pattern (char *p){ while ( *p ) { switch ( *p++ ) { case '?': case '*': case '[': case '!': case ';':#if defined( __UNIX__ ) case ':':#endif return TRUE; } } return FALSE;}/*----------------------------------------------------------------------------** Return TRUE if PATTERN has is a well formed regular expression according* to the above syntax** error_type is a return code based on the type of pattern error. Zero is* returned in error_type if the pattern is a valid one. error_type return* values are as follows:** PATTERN_VALID - pattern is well formed* PATTERN_RANGE - [..] construct has a no end range in a '-' pair (ie [a-])* PATTERN_CLOSE - [..] construct has no end bracket (ie [abc-g )* PATTERN_EMPTY - [..] construct is empty (ie [])*----------------------------------------------------------------------------*/BOOLEAN is_valid_pattern (char *p, int *error_type){ /* init error_type */ *error_type = PATTERN_VALID; /* loop through pattern to EOS */ while( *p ) { /* determine pattern type */ switch( *p ) { /* the [..] construct must be well formed */ case '[': p++; /* if the next character is ']' then bad pattern */ if ( *p == ']' ) { *error_type = PATTERN_EMPTY; return FALSE; } /* if end of pattern here then bad pattern */ if ( !*p ) { *error_type = PATTERN_CLOSE; return FALSE; } /* loop to end of [..] construct */ while( *p != ']' ) { /* check for literal escape */ if( *p == '\\' ) { p++; /* if end of pattern here then bad pattern */ if ( !*p++ ) { *error_type = PATTERN_ESC; return FALSE; } } else p++; /* if end of pattern here then bad pattern */ if ( !*p ) { *error_type = PATTERN_CLOSE; return FALSE; } /* if this a range */ if( *p == '-' ) { /* we must have an end of range */ if ( !*++p || *p == ']' ) { *error_type = PATTERN_RANGE; return FALSE; } else { /* check for literal escape */ if( *p == '\\' ) p++; /* if end of pattern here then bad pattern */ if ( !*p++ ) { *error_type = PATTERN_ESC; return FALSE; } } } } break; /* all other characters are valid pattern elements */ case '*': case '?': default: p++; /* "normal" character */ break; } } return TRUE;}/*----------------------------------------------------------------------------** Match the pattern PATTERN against the string TEXT;** returns MATCH_VALID if pattern matches, or an errorcode as follows* otherwise:** MATCH_PATTERN - bad pattern* MATCH_RANGE - match failure on [..] construct* MATCH_ABORT - premature end of text string* MATCH_END - premature end of pattern string* MATCH_VALID - valid match*** A match means the entire string TEXT is used up in matching.** In the pattern string:* `*' matches any sequence of characters (zero or more)* `?' matches any character* [SET] matches any character in the specified set,* [!SET] or [^SET] matches any character not in the specified set.* \ is allowed within a set to escape a character like ']' or '-'** A set is composed of characters or ranges; a range looks like* character hyphen character (as in 0-9 or A-Z). [0-9a-zA-Z_] is the* minimal set of characters allowed in the [..] pattern construct.* Other characters are allowed (ie. 8 bit characters) if your system* will support them.** To suppress the special syntactic significance of any of `[]*?!^-\',* within a [..] construct and match the character exactly, precede it* with a `\'.*----------------------------------------------------------------------------*/int matche ( register char *p, register char *t ){ register char range_start, range_end; /* start and end in range */ BOOLEAN invert; /* is this [..] or [!..] */ BOOLEAN member_match; /* have I matched the [..] construct? */ for ( ; *p; p++, t++ ) { /* if this is the end of the text then this is the end of the match */ if (!*t) { return ( *p == '*' && *++p == '\0' ) ? MATCH_VALID : MATCH_ABORT; } /* determine and react to pattern type */ switch ( *p ) { /* single any character match */ case '?': break; /* multiple any character match */ case '*': return matche_after_star (p, t); /* [..] construct, single member/exclusion character match */ case '[': { /* move to beginning of range */ p++; /* check if this is a member match or exclusion match */ invert = FALSE; if ( *p == '!' || *p == '^') { invert = TRUE; p++; } member_match = FALSE; for ( ;; ) { /* if end of construct then loop is done */ if (*p == ']') { break; } /* matching a '!', '^', '-', '\' or a ']' */ if ( *p == '\\' ) { ++p; } range_start = range_end = *p; /* check for range bar */ if (*++p == '-') { /* special character range end */ if (*p == '\\') { ++p; } /* get the range end */ range_end = *++p; /* move just beyond this range */ p++; } range_start = bj_tolower( range_start ); range_end = bj_tolower( range_end ); /* make sure the range letters have the proper relationship to one another before comparison */ if (range_start > range_end) { char temp = range_start; range_start = range_end; range_end = temp; } /* if the text character is in range then match found. */ if (bj_tolower( *t ) >= range_start && bj_tolower( *t ) <= range_end) { member_match = TRUE; break; } } /* if there was a match in an exclusion set then no match */ /* if there was no match in a member set then no match */ if ((invert && member_match) || !(invert || member_match)) return MATCH_RANGE; /* if this is not an exclusion then skip the rest of the [...] construct that already matched. */ if (member_match) { while (*p != ']') { /* skip exact match */ if (*p == '\\') { p++; } /* move to next pattern char */ p++; } } break; } /* must match this character exactly */ default: if (bj_tolower( *p ) != bj_tolower( *t )) return MATCH_LITERAL; } } /* if end of text not reached then the pattern fails */ if ( *t ) return MATCH_END; else return MATCH_VALID;}/*----------------------------------------------------------------------------** recursively call matche() with final segment of PATTERN and of TEXT.*----------------------------------------------------------------------------*/int matche_after_star (register char *p, register char *t){ register int match = 0; register char nextp; /* pass over existing ? and * in pattern */ while ( *p == '?' || *p == '*' ) { /* take one char for each ? */ if ( *p == '?' ) { /* if end of text then no match */ if ( !*t++ ) { return MATCH_ABORT; } } /* move to next char in pattern */ p++; } /* if end of pattern we have matched regardless of text left */ if ( !*p ) { return MATCH_VALID; } /* get the next character to match which must be a literal or '[' */ nextp = bj_tolower( *p ); /* Continue until we run out of text or definite result seen */ do { /* a precondition for matching is that the next character in the pattern match the next character in the text or that the next pattern char is the beginning of a range. Increment text pointer as we go here */ if (nextp == bj_tolower( *t ) || nextp == '[' ) match = matche(p, t); /* if the end of text is reached then no match */ if ( !*t++ ) match = MATCH_ABORT; } while ( match != MATCH_VALID && match != MATCH_ABORT); /* return result */ return match;}/*----------------------------------------------------------------------------** match() is a shell to matche() to return only BOOLEAN values.** jmh 050731: allow it to match multiple patterns, separated by ';', and* exclusions, separated by '!'. Use the set notation to treat* the character literally.* eg: "!*.exe;*.com" will match all files except .EXE & .COM.* "!*.*" will match files with no extension.* "*.txt;*.doc!read*" will match all .TXT & .DOC files,* except those starting with READ.* "[\!]*" will match all files starting with '!'.*----------------------------------------------------------------------------*/BOOLEAN wildcard( char *p, char *t ){int error_type;char *alt; /* alternative */char *exc; /* exclusion */int falt, fexc; /* found ... */BOOLEAN inverted = FALSE; /* matching exclusion rather than pattern */int rc; if (!is_valid_pattern( p, &rc )) return( FALSE ); for (exc = p; *exc && *exc != '!'; ++exc) { if (*exc == '[') { do { if (*++exc == '\\') exc += 2; } while (*exc != ']'); } } fexc = *exc; *exc = '\0'; if (exc == p && fexc) p = "*"; rc = FALSE; do { for (alt = p; *alt && *alt != ';'#if defined( __UNIX__) && *alt != ':'#endif ; ++alt) { if (*alt == '[') { do { if (*++alt == '\\') alt += 2; } while (*alt != ']'); } } falt = *alt; if (falt) /* prevent modifying the static string */ *alt = '\0'; error_type = matche( p, t ); if (falt) *alt = falt; if (error_type == MATCH_VALID) { if (inverted) { rc = FALSE; break; } rc = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -