// Original: src/path/filepath/match.go//// Copyright 2010 The Go Authors. All rights reserved.// Portions Copyright 2021 Hiroshi Ioka. All rights reserved.//// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * 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.// * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT// OWNER 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.package smb2import (.)// ErrBadPattern indicates a pattern was malformed.varErrBadPattern = errors.New("syntax error in pattern")// Match reports whether name matches the shell file name pattern.// The pattern syntax is://// pattern:// { term }// term:// '*' matches any sequence of non-Separator characters// '?' matches any single non-Separator character// '[' [ '^' ] { character-range } ']'// character class (must be non-empty)// c matches character c (c != '*', '?', '[')//// character-range:// c matches character c (c != '-', ']')// lo '-' hi matches character c for lo <= c <= hi//// Match requires pattern to match all of name, not just a substring.// The only possible returned error is ErrBadPattern, when pattern// is malformed.func (, string) ( bool, error) { = normPattern():forlen() > 0 {varboolvarstring , , = scanChunk()if && == "" {// Trailing * matches rest of string unless it has a /.return !strings.Contains(, string(PathSeparator)), nil }// Look for match at current position. , , := matchChunk(, )// if we're the last chunk, make sure we've exhausted the name // otherwise we'll give a false result even if we could still match // using the starif && (len() == 0 || len() > 0) { = continue }if != nil {returnfalse, }if {// Look for match skipping i+1 bytes. // Cannot skip /.for := 0; < len() && [] != PathSeparator; ++ { , , := matchChunk(, [+1:])if {// if we're the last chunk, make sure we exhausted the nameiflen() == 0 && len() > 0 {continue } = continue }if != nil {returnfalse, } } }returnfalse, nil }returnlen() == 0, nil}// scanChunk gets the next segment of pattern, which is a non-star string// possibly preceded by a star.func scanChunk( string) ( bool, , string) {forlen() > 0 && [0] == '*' { = [1:] = true } := falsevarint:for = 0; < len(); ++ {switch [] {case'[': = truecase']': = falsecase'*':if ! {break } } }return , [0:], [:]}// matchChunk checks whether chunk matches the beginning of s.// If so, it returns the remainder of s (after the match).// Chunk is all single-character operators: literals, char classes, and ?.func matchChunk(, string) ( string, bool, error) {// failed records whether the match has failed. // After the match fails, the loop continues on processing chunk, // checking that the pattern is well-formed but no longer reading s. := falseforlen() > 0 {if ! && len() == 0 { = true }switch [0] {case'[':// character classvarruneif ! {varint , = utf8.DecodeRuneInString() = [:] } = [1:]// possibly negated := falseiflen() > 0 && [0] == '^' { = true = [1:] }// parse all ranges := false := 0for {iflen() > 0 && [0] == ']' && > 0 { = [1:]break }var , runeif , , = getEsc(); != nil {return"", false, } = if [0] == '-' {if , , = getEsc([1:]); != nil {return"", false, } }if <= && <= { = true } ++ }if == { = true }case'?':if ! {if [0] == PathSeparator { = true } , := utf8.DecodeRuneInString() = [:] } = [1:]default:if ! {if [0] != [0] { = true } = [1:] } = [1:] } }if {return"", false, nil }return , true, nil}// getEsc gets a possibly-escaped character from chunk, for a character class.func getEsc( string) ( rune, string, error) {iflen() == 0 || [0] == '-' || [0] == ']' { = ErrBadPatternreturn } , := utf8.DecodeRuneInString()if == utf8.RuneError && == 1 { = ErrBadPattern } = [:]iflen() == 0 { = ErrBadPattern }return}// Glob should work like filepath.Glob.func ( *Share) ( string) ( []string, error) { = normPattern()// Check pattern is well-formed.if , := Match(, ""); != nil {returnnil, }if !hasMeta() {if _, = .Lstat(); != nil {returnnil, nil }return []string{}, nil } , := split() = cleanGlobPath()if !hasMeta() {return .glob(, , nil) }// Prevent infinite recursion. See issue 15879.if == {returnnil, ErrBadPattern }var []string , = .()if != nil {return }for , := range { , = .glob(, , )if != nil {return } }return}// cleanGlobPath prepares path for glob matching.func cleanGlobPath( string) string {switch {case"":return"."casestring(PathSeparator):// do nothing to the pathreturndefault:return [0 : len()-1] // chop off trailing separator }}var characterRangePattern = regexp.MustCompile(`\[^?[^\[\]]+\]`)func simplifyPattern( string) string {returncharacterRangePattern.ReplaceAllLiteralString(, "?")}// glob searches for files matching pattern in the directory dir// and appends them to matches. If the directory cannot be// opened, it returns the existing matches. New matches are// added in lexicographical order.func ( *Share) (, string, []string) ( []string, error) { = , := .Stat()if != nil {return// ignore I/O error }if !.IsDir() {return// ignore I/O error } , := .Open()if != nil {return// ignore I/O error }defer .Close()var []string:for { , := .readdir(simplifyPattern())for , := range { = append(, .Name()) }if != nil {if , := .(*ResponseError); {switchNtStatus(.Code) {caseSTATUS_NO_SUCH_FILE:return []string{}, nilcaseSTATUS_NO_MORE_FILES:break } }returnnil, &os.PathError{Op: "readdir", Path: .name, Err: } } }for , := range { , := Match(, )if != nil {return , }if { = append(, join(, )) } }sort.Strings()return}// hasMeta reports whether path contains any of the magic characters// recognized by Match.func hasMeta( string) bool {returnstrings.ContainsAny(, `*?[`)}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.