$include (..\lib\compStch.ext) /* * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Guido van Rossum. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * From FreeBSD fnmatch.c 1.11 */ fnmatchModule: do; $if not noID declare IDString (*) byte data ( '@(#)$Id: fnmatch.p86 943 2024-03-03 21:05:36Z rmgillmore $', 0 ); $endif /* * Function fnmatch() compares a filename or pathname to a pattern. */ $include (..\lib\comnDefs.ext) $include (..\lib\string.ext) $include (..\lib\numStrs.ext) $include (..\lib\fileIO.ext) $include (..\lib\ptrMath.ext) $set (FNMATCH_IMPLEMENTATION) $include (..\lib\fnmatch.ext) declare sccsid (*) char data ( '@(#) fnmatch.p86; ported from fnmatch.c 8.2 (Berkeley) 4/16/94', 0 ); /* * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. * Compares a filename or pathname to a pattern. */ declare ESCAPE_CHAR literally '''\''', EXCLAMATION literally '''!''', CIRCUMFLEX literally '''^''', OPEN_SEQUENCE literally '''[''', CLOSE_SEQUENCE literally ''']'''; rangematch: procedure ( patternPtr, testChar, flagValue ) pointer reentrant; declare patternPtr pointer, localPatternPtr pointer, patternChar based localPatternPtr char, testChar char, flagValue flagTypes, returnCharPtr pointer; declare ( negate, ok ) boolean, ( c, c2 ) char; localPatternPtr = patternPtr; /* * A bracket expression starting with an unquoted circumflex * character produces unspecified results (IEEE 1003.2-1992, * 3.13.2). This implementation treats it like '!', for * consistency with the regular expression syntax. * J.T. Conklin (conklin@ngai.kaleida.com) */ if ( patternChar = EXCLAMATION ) or ( patternChar = CIRCUMFLEX ) then negate = True; else negate = False; if ( negate ) then localPatternPtr = incPtr( localPatternPtr, size( patternChar ), 1 ); if ( ( flagValue and FNM_CASEFOLD ) <> 0 ) then testChar = tolower( testChar ); ok = 0; do while ( patternChar <> CLOSE_SEQUENCE ); c = patternChar; localPatternPtr = incPtr( localPatternPtr, size( patternChar ), 1 ); if ( c = ESCAPE_CHAR ) and ( ( flagValue and FNM_NOESCAPE ) <> 0 ) then do; c = patternChar; localPatternPtr = incPtr( localPatternPtr, size( patternChar ), 1 ); end; if ( c = EOS ) then returnCharPtr = NULL; else do; if ( ( flagValue and FNM_CASEFOLD ) <> 0 ) then c = tolower( c ); do; declare patternString based localPatternPtr (*) char; c2 = patternString( 1 ); end; if ( ( patternChar = HYPHEN ) and ( c2 <> EOS ) and ( c2 <> CLOSE_SEQUENCE ) ) then do; localPatternPtr = incPtr( localPatternPtr, size( patternChar ), 2 ); if ( ( c2 = ESCAPE_CHAR ) and ( ( flagValue and FNM_NOESCAPE ) <> 0 ) ) then do; c2 = patternChar; localPatternPtr = incPtr( localPatternPtr, size( patternChar ), 1 ); end; if ( c2 = EOS ) then returnCharPtr = NULL; else do; if ( ( flagValue and FNM_CASEFOLD ) <> 0 ) then c2 = tolower( c2 ); if ( ( c <= testChar ) and ( testChar <= c2 ) ) then ok = 1; end; end; else if ( c = testChar ) then ok = 1; if ( ok = negate ) then returnCharPtr = NULL; else returnCharPtr = localPatternPtr; end; end; return ( returnCharPtr ); end rangematch; prevChar: procedure ( stringPtr ) char reentrant; declare stringPtr pointer, localStringPtr pointer, returnChar based localStringPtr char; localStringPtr = decPtr( stringPtr, size( returnChar ), 1 ); return ( returnChar ); end prevChar; fnmatch: procedure ( patternPtr, stringInPtr, fileFlags ) boolean reentrant public; declare patternPtr pointer, pattern based patternPtr (*) char, stringInPtr pointer, stringIn based stringInPtr (*) char, fileFlags flagTypes; declare fileMatch boolean, done boolean; declare stringStartPtr pointer, stringStart based stringStartPtr (*) char, c char, test char, localPatternPtr pointer, localPattern based localPatternPtr (*) char; declare caseOptions (*) char data ( EOS, QUESTION, ASTERISK, OPEN_SEQUENCE /*, ESCAPE_CHAR */ ); declare numberCaseOptions word, caseIndex word; declare tempFlags flagTypes; fileMatch = false; stringStartPtr = stringInPtr; done = false; localPatternPtr = patternPtr; doWhile: do while ( not done ); fileMatch = false; c = localPattern( 0 ); localPatternPtr = incPtr( localPatternPtr, size( localPattern( 0 ) ), 1 ); numberCaseOptions = size( caseOptions ); caseIndex = findb( @caseOptions, pattern( 0 ), numberCaseOptions ); if ( caseIndex > numberCaseOptions ) then caseIndex = numberCaseOptions; do case caseIndex; caseEOS: do; if ( ( ( fileFlags and FNM_LEADING_DIR ) <> 0 ) and ( stringIn( 0 ) = PATH_DELIM ) ) then fileMatch = false; else if ( stringIn( 0 ) = EOS ) then fileMatch = false; else fileMatch = FNM_NOMATCH; done = true; end caseEOS; caseQuestion: do; if ( stringIn( 0 ) = EOS ) then do; fileMatch = FNM_NOMATCH; done = true; end; else if ( ( stringIn( 0 ) = PATH_DELIM ) and ( ( fileFlags and FNM_PATHNAME ) <> 0 ) ) then do; fileMatch = FNM_NOMATCH; done = true; end; else if ( ( stringIn( 0 ) = PERIOD ) and ( ( fileFlags and FNM_PERIOD ) <> 0 ) and ( stringInPtr = stringStartPtr ) or ( ( ( fileFlags and FNM_PATHNAME ) <> 0 ) and ( prevChar( stringInPtr ) = PATH_DELIM ) ) ) then do; fileMatch = FNM_NOMATCH; done = true; end; else stringInPtr = incPtr( stringInPtr, size( stringIn( 0 ) ), 1 ); end caseQuestion; caseAsterisk: do; /* * Collapse multiple stars. */ do while ( pattern( 0 ) = ASTERISK ); patternPtr = incPtr( patternPtr, size( pattern( 0 ) ), 1 ); end; if ( ( stringIn( 0 ) = PERIOD ) and ( ( fileFlags and FNM_PERIOD ) <> 0 ) and ( stringInPtr = stringStartPtr ) or ( ( fileFlags and FNM_PATHNAME ) <> 0 ) and ( prevChar( stringInPtr ) = PATH_DELIM ) ) then do; fileMatch = FNM_NOMATCH; done = true; end; /* * Optimize for pattern with * at end or before / */ if ( pattern( 0 ) = EOS ) then do; if ( ( fileFlags and FNM_PATHNAME ) <> 0 ) then if ( ( fileFlags and FNM_LEADING_DIR ) <> 0 ) then if ( strchr( stringInPtr, PATH_DELIM ) = NULL ) then fileMatch = 0; else fileMatch = FNM_NOMATCH; else fileMatch = FNM_NOMATCH; else fileMatch = 0; done = true; end; else if ( c = PATH_DELIM ) and ( ( fileFlags and FNM_PATHNAME ) <> 0 ) then do; stringInPtr = strchr( stringInPtr, PATH_DELIM ); if ( stringInPtr = NULL ) then do; fileMatch = FNM_NOMATCH; done = true; end; end; /* * General case, use recursion. */ do while ( stringIn( 0 ) <> EOS ); tempFlags = fileFlags and ( not FNM_PERIOD ); if ( not fnmatch( patternPtr, stringInPtr, tempFlags ) ) then do; fileMatch = 0; done = true; end; else if ( stringIn( 0 ) = PATH_DELIM ) and ( ( fileFlags and FNM_PATHNAME ) <> 0 ) then do; fileMatch = FNM_NOMATCH; done = true; end; else stringInPtr = incPtr( stringInPtr, size( stringIn( 0 ) ), 1 ); end; end caseAsterisk; caseOpenSequence: do; if ( stringIn( 0 ) = EOS ) then do; done = true; fileMatch = FNM_NOMATCH; end; else if ( stringIn( 0 ) = PATH_DELIM ) and ( ( fileFlags and FNM_PATHNAME ) <> 0 ) then do; done = true; fileMatch = FNM_NOMATCH; end; else do; patternPtr = rangematch( patternPtr, stringIn( 0 ), fileFlags ); if ( patternPtr = NULL) then do; done = true; fileMatch = FNM_NOMATCH; end; else stringInPtr = incPtr( stringInPtr, size( stringIn( 0 ) ), 1 ); end; end caseOpenSequence; caseDefault: do; /* * we need to fall through the traditional C switch. Since PL/M case clauses do not * handle the notion of a "fall through", we let two cases send us to the same place, * and we handle the case from which we should fall by an if clause. */ caseEscapeChar: if ( pattern( 0 ) = ESCAPE_CHAR ) then do; if ( ( fileFlags and FNM_NOESCAPE ) = 0 ) then do; c = pattern( 0 ); patternPtr = incPtr( patternPtr, size( pattern( 0 ) ), 1 ); if ( c = EOS ) then do; c = ESCAPE_CHAR; patternPtr = decPtr( patternPtr, size( pattern( 0 ) ), 1 ); end; end; end; /* * now "fall through" */ if ( c = stringIn( 0 ) ) then ; else if ( ( ( fileFlags and FNM_CASEFOLD ) <> 0 ) and ( tolower( c ) = tolower( stringIn( 0 ) ) ) ) then ; else if ( ( ( fileFlags and FNM_PREFIX_DIRS ) <> 0 ) and ( stringIn( 0 ) = EOS ) and ( ( c = PATH_DELIM ) and ( stringInPtr <> stringStartPtr ) ) or ( stringInPtr = incPtr( stringStartPtr, size( stringStart( 0 ) ), 1 ) and ( stringStart( 0 ) = PATH_DELIM ) ) ) then do; fileMatch = 0; done = true; end; else do; fileMatch = FNM_NOMATCH; done = true; end; if ( not done ) then stringInPtr = incPtr( stringInPtr, size( stringIn( 0 ) ), 1 ); end caseDefault; end; /* case caseIndex */ end doWhile; return ( fileMatch ); end fnmatch; end fnmatchModule;