]> Cypherpunks repositories - gostls13.git/commitdiff
path: add Glob
authorBenny Siegert <bsiegert@gmail.com>
Fri, 5 Nov 2010 17:47:56 +0000 (10:47 -0700)
committerRob Pike <r@golang.org>
Fri, 5 Nov 2010 17:47:56 +0000 (10:47 -0700)
As discussed in http://groups.google.com/group/golang-dev/browse_thread/thread/926b7d550d98ec9e,
add a simple "path expander" function, which returns all the
files matching the given pattern. This function is called Glob
after glob(3) in libc.

Also add a convenience function, hasMeta, that checks whether
a string contains one of the characters which are specially handled
by Match.

R=rsc, r, r2
CC=golang-dev
https://golang.org/cl/2476041

src/pkg/path/match.go
src/pkg/path/match_test.go

index e3cf08cae2d21679b1b51408772ce37749875d85..d5cd19fd405ae1c914925fb836f50743381cd0e5 100644 (file)
@@ -2,6 +2,7 @@ package path
 
 import (
        "os"
+       "sort"
        "strings"
        "utf8"
 )
@@ -202,3 +203,72 @@ func getEsc(chunk string) (r int, nchunk string, err os.Error) {
        }
        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.
+//
+func Glob(pattern string) (matches []string) {
+       if !hasMeta(pattern) {
+               if _, err := os.Stat(pattern); err == nil {
+                       return []string{pattern}
+               }
+               return nil
+       }
+
+       dir, file := Split(pattern)
+       switch dir {
+       case "":
+               dir = "."
+       case "/":
+               // nothing
+       default:
+               dir = dir[0 : len(dir)-1] // chop off trailing '/'
+       }
+
+       if hasMeta(dir) {
+               for _, d := range Glob(dir) {
+                       matches = glob(d, file, matches)
+               }
+       } else {
+               return glob(dir, file, nil)
+       }
+       return matches
+}
+
+// glob searches for files matching pattern in the directory dir
+// and appends them to matches.
+func glob(dir, pattern string, matches []string) []string {
+       if fi, err := os.Stat(dir); err != nil || !fi.IsDirectory() {
+               return nil
+       }
+       d, err := os.Open(dir, os.O_RDONLY, 0666)
+       if err != nil {
+               return nil
+       }
+       defer d.Close()
+
+       names, err := d.Readdirnames(-1)
+       if err != nil {
+               return nil
+       }
+       sort.SortStrings(names)
+
+       for _, n := range names {
+               matched, err := Match(pattern, n)
+               if err != nil {
+                       return matches
+               }
+               if matched {
+                       matches = append(matches, Join(dir, n))
+               }
+       }
+       return matches
+}
+
+// hasMeta returns true if path contains any of the magic characters
+// recognized by Match.
+func hasMeta(path string) bool {
+       return strings.IndexAny(path, "*?[") != -1
+}
index f377f1083b77a25bf947d8859ae8a5fef73dde5f..a1bf508e3f9489bb477e4cf3557e0541068520a7 100644 (file)
@@ -75,3 +75,31 @@ func TestMatch(t *testing.T) {
                }
        }
 }
+
+// contains returns true if vector contains the string s.
+func contains(vector []string, s string) bool {
+       for _, elem := range vector {
+               if elem == s {
+                       return true
+               }
+       }
+       return false
+}
+
+var globTests = []struct {
+       pattern, result string
+}{
+       {"match.go", "match.go"},
+       {"mat?h.go", "match.go"},
+       {"*", "match.go"},
+       {"../*/match.go", "../path/match.go"},
+}
+
+func TestGlob(t *testing.T) {
+       for _, tt := range globTests {
+               matches := Glob(tt.pattern)
+               if !contains(matches, tt.result) {
+                       t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result)
+               }
+       }
+}