| /* |
| * Copyright 1994 Christopher Seiwald. All rights reserved. |
| * |
| * This file is part of Jam - see jam.c for Copyright information. |
| */ |
| |
| /* |
| * glob.c - match a string against a simple pattern |
| * |
| * Understands the following patterns: |
| * |
| * * any number of characters |
| * ? any single character |
| * [a-z] any single character in the range a-z |
| * [^a-z] any single character not in the range a-z |
| * \x match x |
| * |
| * External functions: |
| * |
| * glob() - match a string against a simple pattern |
| * |
| * Internal functions: |
| * |
| * globchars() - build a bitlist to check for character group match |
| */ |
| |
| # include "jam.h" |
| |
| # define CHECK_BIT( tab, bit ) ( tab[ (bit)/8 ] & (1<<( (bit)%8 )) ) |
| # define BITLISTSIZE 16 /* bytes used for [chars] in compiled expr */ |
| |
| static void globchars( const char * s, const char * e, char * b ); |
| |
| |
| /* |
| * glob() - match a string against a simple pattern. |
| */ |
| |
| int glob( const char * c, const char * s ) |
| { |
| char bitlist[ BITLISTSIZE ]; |
| const char * here; |
| |
| for ( ; ; ) |
| switch ( *c++ ) |
| { |
| case '\0': |
| return *s ? -1 : 0; |
| |
| case '?': |
| if ( !*s++ ) |
| return 1; |
| break; |
| |
| case '[': |
| /* Scan for matching ]. */ |
| |
| here = c; |
| do if ( !*c++ ) return 1; |
| while ( ( here == c ) || ( *c != ']' ) ); |
| ++c; |
| |
| /* Build character class bitlist. */ |
| |
| globchars( here, c, bitlist ); |
| |
| if ( !CHECK_BIT( bitlist, *(const unsigned char *)s ) ) |
| return 1; |
| ++s; |
| break; |
| |
| case '*': |
| here = s; |
| |
| while ( *s ) |
| ++s; |
| |
| /* Try to match the rest of the pattern in a recursive */ |
| /* call. If the match fails we'll back up chars, retrying. */ |
| |
| while ( s != here ) |
| { |
| int r; |
| |
| /* A fast path for the last token in a pattern. */ |
| r = *c ? glob( c, s ) : *s ? -1 : 0; |
| |
| if ( !r ) |
| return 0; |
| if ( r < 0 ) |
| return 1; |
| --s; |
| } |
| break; |
| |
| case '\\': |
| /* Force literal match of next char. */ |
| if ( !*c || ( *s++ != *c++ ) ) |
| return 1; |
| break; |
| |
| default: |
| if ( *s++ != c[ -1 ] ) |
| return 1; |
| break; |
| } |
| } |
| |
| |
| /* |
| * globchars() - build a bitlist to check for character group match. |
| */ |
| |
| static void globchars( const char * s, const char * e, char * b ) |
| { |
| int neg = 0; |
| |
| memset( b, '\0', BITLISTSIZE ); |
| |
| if ( *s == '^' ) |
| { |
| ++neg; |
| ++s; |
| } |
| |
| while ( s < e ) |
| { |
| int c; |
| |
| if ( ( s + 2 < e ) && ( s[1] == '-' ) ) |
| { |
| for ( c = s[0]; c <= s[2]; ++c ) |
| b[ c/8 ] |= ( 1 << ( c % 8 ) ); |
| s += 3; |
| } |
| else |
| { |
| c = *s++; |
| b[ c/8 ] |= ( 1 << ( c % 8 ) ); |
| } |
| } |
| |
| if ( neg ) |
| { |
| int i; |
| for ( i = 0; i < BITLISTSIZE; ++i ) |
| b[ i ] ^= 0377; |
| } |
| |
| /* Do not include \0 in either $[chars] or $[^chars]. */ |
| b[0] &= 0376; |
| } |