URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [path/] [filepath/] [match.go] - Rev 747
Compare with Previous | Blame | View Log
// Copyright 2010 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package filepathimport ("errors""os""sort""strings""unicode/utf8")var ErrBadPattern = errors.New("syntax error in pattern")// Match returns true if 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 != '*', '?', '\\', '[')// '\\' c matches character c//// character-range:// c matches character c (c != '\\', '-', ']')// '\\' c matches character 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 error return occurs when the pattern is malformed.//func Match(pattern, name string) (matched bool, err error) {Pattern:for len(pattern) > 0 {var star boolvar chunk stringstar, chunk, pattern = scanChunk(pattern)if star && chunk == "" {// Trailing * matches rest of string unless it has a /.return strings.Index(name, string(Separator)) < 0, nil}// Look for match at current position.t, ok, err := matchChunk(chunk, name)// 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 ok && (len(t) == 0 || len(pattern) > 0) {name = tcontinue}if err != nil {return false, err}if star {// Look for match skipping i+1 bytes.// Cannot skip /.for i := 0; i < len(name) && name[i] != Separator; i++ {t, ok, err := matchChunk(chunk, name[i+1:])if ok {// if we're the last chunk, make sure we exhausted the nameif len(pattern) == 0 && len(t) > 0 {continue}name = tcontinue Pattern}if err != nil {return false, err}}}return false, nil}return len(name) == 0, nil}// scanChunk gets the next segment of pattern, which is a non-star string// possibly preceded by a star.func scanChunk(pattern string) (star bool, chunk, rest string) {for len(pattern) > 0 && pattern[0] == '*' {pattern = pattern[1:]star = true}inrange := falsevar i intScan:for i = 0; i < len(pattern); i++ {switch pattern[i] {case '\\':// error check handled in matchChunk: bad pattern.if i+1 < len(pattern) {i++}case '[':inrange = truecase ']':inrange = falsecase '*':if !inrange {break Scan}}}return star, pattern[0:i], pattern[i:]}// 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(chunk, s string) (rest string, ok bool, err error) {for len(chunk) > 0 {if len(s) == 0 {return}switch chunk[0] {case '[':// character classr, n := utf8.DecodeRuneInString(s)s = s[n:]chunk = chunk[1:]// possibly negatednegated := chunk[0] == '^'if negated {chunk = chunk[1:]}// parse all rangesmatch := falsenrange := 0for {if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 {chunk = chunk[1:]break}var lo, hi runeif lo, chunk, err = getEsc(chunk); err != nil {return}hi = loif chunk[0] == '-' {if hi, chunk, err = getEsc(chunk[1:]); err != nil {return}}if lo <= r && r <= hi {match = true}nrange++}if match == negated {return}case '?':if s[0] == Separator {return}_, n := utf8.DecodeRuneInString(s)s = s[n:]chunk = chunk[1:]case '\\':chunk = chunk[1:]if len(chunk) == 0 {err = ErrBadPatternreturn}fallthroughdefault:if chunk[0] != s[0] {return}s = s[1:]chunk = chunk[1:]}}return s, true, nil}// getEsc gets a possibly-escaped character from chunk, for a character class.func getEsc(chunk string) (r rune, nchunk string, err error) {if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {err = ErrBadPatternreturn}if chunk[0] == '\\' {chunk = chunk[1:]if len(chunk) == 0 {err = ErrBadPatternreturn}}r, n := utf8.DecodeRuneInString(chunk)if r == utf8.RuneError && n == 1 {err = ErrBadPattern}nchunk = chunk[n:]if len(nchunk) == 0 {err = ErrBadPattern}return}// Glob returns the names of all files matching pattern or nil// if there is no matching file. The syntax of patterns is the same// as in Match. The pattern may describe hierarchical names such as// /usr/*/bin/ed (assuming the Separator is '/').// The only possible error return occurs when the pattern is malformed.//func Glob(pattern string) (matches []string, err error) {if !hasMeta(pattern) {if _, err = os.Stat(pattern); err != nil {return nil, nil}return []string{pattern}, nil}dir, file := Split(pattern)switch dir {case "":dir = "."case string(Separator):// nothingdefault:dir = dir[0 : len(dir)-1] // chop off trailing separator}if !hasMeta(dir) {return glob(dir, file, nil)}var m []stringm, err = Glob(dir)if err != nil {return}for _, d := range m {matches, err = glob(d, file, matches)if err != nil {return}}return}// 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.// The only possible error return occurs when the pattern is malformed.func glob(dir, pattern string, matches []string) (m []string, e error) {m = matchesfi, err := os.Stat(dir)if err != nil {return}if !fi.IsDir() {return}d, err := os.Open(dir)if err != nil {return}defer d.Close()names, err := d.Readdirnames(-1)if err != nil {return}sort.Strings(names)for _, n := range names {matched, err := Match(pattern, n)if err != nil {return m, err}if matched {m = append(m, Join(dir, n))}}return}// hasMeta returns true if path contains any of the magic characters// recognized by Match.func hasMeta(path string) bool {// TODO(niemeyer): Should other magic characters be added here?return strings.IndexAny(path, "*?[") >= 0}
