OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [path/] [filepath/] [match.go] - Rev 801

Go to most recent revision | 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 filepath

import (
        "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 bool
                var chunk string
                star, 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 star
                if ok && (len(t) == 0 || len(pattern) > 0) {
                        name = t
                        continue
                }
                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 name
                                        if len(pattern) == 0 && len(t) > 0 {
                                                continue
                                        }
                                        name = t
                                        continue 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 := false
        var i int
Scan:
        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 = true
                case ']':
                        inrange = false
                case '*':
                        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 class
                        r, n := utf8.DecodeRuneInString(s)
                        s = s[n:]
                        chunk = chunk[1:]
                        // possibly negated
                        negated := chunk[0] == '^'
                        if negated {
                                chunk = chunk[1:]
                        }
                        // parse all ranges
                        match := false
                        nrange := 0
                        for {
                                if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 {
                                        chunk = chunk[1:]
                                        break
                                }
                                var lo, hi rune
                                if lo, chunk, err = getEsc(chunk); err != nil {
                                        return
                                }
                                hi = lo
                                if 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 = ErrBadPattern
                                return
                        }
                        fallthrough

                default:
                        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 = ErrBadPattern
                return
        }
        if chunk[0] == '\\' {
                chunk = chunk[1:]
                if len(chunk) == 0 {
                        err = ErrBadPattern
                        return
                }
        }
        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):
                // nothing
        default:
                dir = dir[0 : len(dir)-1] // chop off trailing separator
        }

        if !hasMeta(dir) {
                return glob(dir, file, nil)
        }

        var m []string
        m, 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 = matches
        fi, 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
}

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.