/******* Made reentrant by Paul Kienitz 12/31/90. Used function prototypes just to avoid booboos. Also replaced _toupper with real toupper. I hope someday to eliminate the error return of CmplPat; make missing parens be assumed to be at the beginning or end as appropriate, and an empty half of | be treated like a %. I guess ' at the end is ignored? Actually it already ignores extra right parens at the end. But with an extra right paren in the middle it ignores everything after it. *******/ /* PatMatch.c - Implements AmigaDos Regular Expression Pattern Matching. ** ** This program will test whether a string is an AmigaDos regular expression ** It may be used to implement wild expressions such as: ** ** "copy #?.c to " to copy any file ending in .c ** ** The program has two entry points: CmplPat, and Match. ** ** CmplPat - takes a pattern and returns an auxilliary array of short ** ints which is used by Match. The pattern is not modified ** in any way. CmplPat returns 1 if no errors were detected ** while compiling the pattern; otherwise it returns 0; ** ** Match - takes the pattern, the auxilliary vector, and the string ** to be matched. It returns 1 if the string matches the ** pattern; otherwise it returns 0; ** ** Translated from BCPL by: ** Jeff Lydiatt ** Richmond B.C. Canada ** 16 May 1986. ** ** Source: "A Compact Function for Regular Expression Pattern Matching", ** Software - Practice and Experience, September 1979. ** ** Useage: ** To test if "file.c" matches the regular expression "#?.c" ** char *Pat = "#?.c"; ** char *Str = "file.c"; ** WORD Aux[128]; ** ** if ( CmplPat( Pat, Aux ) == 0 ) ** { ** printf("Bad Wildcard Expression\n"); ** exit(1); ** } ** if ( Match( Pat, Aux, Str ) == 1 ) ** printf("String matches the pattern\n"); ** else ** printf("String does NOT match the pattern\n"); **/ /*--- Included files ----*/ #include #include #include #define EOS '\0' /*----------------------------------------------------------------*/ /* The Interpreter */ /*----------------------------------------------------------------*/ struct GM { BOOL Succflag; short Wp; short *Work; }; static void Put(short N, register struct GM *m) { register short *ip; register short *to; if ( N == 0 ) m->Succflag = TRUE; else { for ( ip = m->Work + 1, to = m->Work + m->Wp; ip <= to; ip++) if ( *ip == N ) return; m->Work[ ++m->Wp ] = N; } } long Match( char Pat[], short Aux[], char Str[] ) { struct GM m; short W[ 128 ]; short S = 0; short I, N, Q, P, Strlength; char K, Ch; size_t strlen(char *s); m.Work = W; m.Wp = 0; m.Succflag = FALSE; Strlength = strlen( Str ); Put( 1, &m ); if ( Aux[ 0 ] != 0 ) Put( Aux[ 0 ], &m ); for(;;) { /* First complete the closure */ for( N=1; N <= m.Wp; N++ ) { P = m.Work[ N ]; K = Pat[ P-1 ]; Q = Aux[ P ]; switch( K ) { case '#': Put( P + 1, &m ); case '%': Put( Q, &m ); default : break; case '(': case '|': Put( P + 1, &m); if ( Q != 0 ) Put( Q, &m ); } } if ( S >= Strlength ) return m.Succflag; if ( m.Wp == 0 ) return FALSE; Ch = Str[ S++ ]; /* Now deal with the match items */ N = m.Wp; m.Wp = 0; m.Succflag = FALSE; for ( I = 1; I <= N; I++) { P = m.Work[ I ]; K = Pat[ P - 1 ]; switch( K ) { case '#': case '|': case '%': case '(': break; case '\'': K = Pat[ P ]; default : if ( toupper( Ch ) != toupper( K ) ) break; case '?': /* Successful match */ Put( Aux[ P ], &m ); } /* End Switch */ } /* End For I */ } /* End for(;;) */ } /*----------------------------------------------------------------*/ /* The Compiler */ /*----------------------------------------------------------------*/ struct CM { short *Aux; char *Pat; short PatP, Patlen; BOOL Errflag; char Ch; }; #define CC register struct CM *c static void Rch( CC ) /* Read next character from Pat */ { if ( c->PatP >= c->Patlen ) c->Ch = EOS; else c->Ch = c->Pat[ c->PatP++ ]; } static void Nextitem( CC ) /* Get next char from Pat; recognize ' escape char */ { if ( c->Ch == '\'' ) Rch( c ); Rch( c ); } static void Setexits( short List, short Val, short *Aux ) { short A; do { A = Aux[ List ]; Aux[ List ] = Val; List = A; } while ( List != 0 ); } static short Join( short A, short B, short *Aux ) { short T = A; if ( A == 0 ) return B; while ( Aux[ A ] != 0 ) A = Aux[ A ]; Aux[ A ] = B; return T; } static short Prim( CC ) /* Parse a Prim symbol */ { short A = c->PatP; char Op = c->Ch; short Exp( short A, CC ); Nextitem( c ); switch( Op ) { case EOS: /* empty string after | ? */ case ')': /* missing ( ? */ case '|': c->Errflag = TRUE; /* empty string before | ? */ default : return A; case '#': Setexits( Prim( c ), A, c->Aux ); return A; case '(': A = Exp( A, c ); if ( c->Ch != ')' ) c->Errflag = TRUE; /* missing ) ? */ Nextitem( c ); return A; } } static short Exp( short AltP, CC ) /* Parse an expression */ { short Exits = 0; short A; for (;;) { A = Prim( c ); if ( c->Ch == '|' || c->Ch == ')' || c->Ch == EOS ) { Exits = Join( Exits, A, c->Aux ); if ( c->Ch != '|' ) return Exits; c->Aux[ AltP ] = c->PatP; AltP = c->PatP; Nextitem( c ); } else Setexits( A, c->PatP, c->Aux ); } } long CmplPat( char Pattern[], short CmplPattern[] ) { short i; struct CM c; size_t strlen(); c.Pat = Pattern; c.Aux = CmplPattern; c.PatP = 0; c.Patlen = strlen( c.Pat ); c.Errflag = FALSE; for ( i = 0; i <= c.Patlen; i++ ) c.Aux[ i ] = 0; Rch( &c ); Setexits( Exp( 0, &c ), 0, &c.Aux[0] ); return (!c.Errflag); }