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
http://codereview.appspot.com/2476041
Committer: Rob Pike <r...@golang.org>
http://code.google.com/p/go/source/detail?r=1191d75682
Modified:
/src/pkg/path/match.go
/src/pkg/path/match_test.go
=======================================
--- /src/pkg/path/match.go Thu Feb 25 09:15:52 2010
+++ /src/pkg/path/match.go Fri Nov 5 10:47:56 2010
@@ -2,6 +2,7 @@
import (
"os"
+ "sort"
"strings"
"utf8"
)
@@ -202,3 +203,72 @@
}
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
+}
=======================================
--- /src/pkg/path/match_test.go Fri Oct 22 10:06:33 2010
+++ /src/pkg/path/match_test.go Fri Nov 5 10:47:56 2010
@@ -75,3 +75,31 @@
}
}
}
+
+// 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)
+ }
+ }
+}