From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001
From: upstream source tree <ports@midipix.org>
Date: Sun, 15 Mar 2015 20:14:05 -0400
Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified
 gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream
 tarball.

downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.

if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
---
 libgo/go/path/match.go        | 278 ++++++++++++++++++++++++++++++++++
 libgo/go/path/match_test.go   | 106 +++++++++++++
 libgo/go/path/path.go         | 212 ++++++++++++++++++++++++++
 libgo/go/path/path_test.go    | 345 ++++++++++++++++++++++++++++++++++++++++++
 libgo/go/path/path_unix.go    |  11 ++
 libgo/go/path/path_windows.go |  11 ++
 6 files changed, 963 insertions(+)
 create mode 100644 libgo/go/path/match.go
 create mode 100644 libgo/go/path/match_test.go
 create mode 100644 libgo/go/path/path.go
 create mode 100644 libgo/go/path/path_test.go
 create mode 100644 libgo/go/path/path_unix.go
 create mode 100644 libgo/go/path/path_windows.go

(limited to 'libgo/go/path')

diff --git a/libgo/go/path/match.go b/libgo/go/path/match.go
new file mode 100644
index 000000000..dd3422c42
--- /dev/null
+++ b/libgo/go/path/match.go
@@ -0,0 +1,278 @@
+package path
+
+import (
+	"os"
+	"sort"
+	"strings"
+	"utf8"
+)
+
+var ErrBadPattern = os.NewError("syntax error in pattern")
+
+// Match returns true if name matches the shell file name pattern.
+// The syntax used by pattern is:
+//
+//	pattern:
+//		{ term }
+//	term:
+//		'*'         matches any sequence of non-/ characters
+//		'?'         matches any single non-/ 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 is when pattern is malformed.
+//
+func Match(pattern, name string) (matched bool, err os.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, "/") < 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] != '/'; 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 section 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++
+			}
+			continue
+		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 os.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
+			notNegated := true
+			if len(chunk) > 0 && chunk[0] == '^' {
+				notNegated = false
+				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 int
+				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 != notNegated {
+				return
+			}
+
+		case '?':
+			if s[0] == '/' {
+				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 int, nchunk string, err os.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.
+//
+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 {
+	fi, err := os.Stat(dir)
+	if err != nil {
+		return nil
+	}
+	if !fi.IsDirectory() {
+		return matches
+	}
+	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
+}
diff --git a/libgo/go/path/match_test.go b/libgo/go/path/match_test.go
new file mode 100644
index 000000000..141cff7da
--- /dev/null
+++ b/libgo/go/path/match_test.go
@@ -0,0 +1,106 @@
+// Copyright 2009 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 path
+
+import (
+	"os"
+	"testing"
+)
+
+type MatchTest struct {
+	pattern, s string
+	match      bool
+	err        os.Error
+}
+
+var matchTests = []MatchTest{
+	{"abc", "abc", true, nil},
+	{"*", "abc", true, nil},
+	{"*c", "abc", true, nil},
+	{"a*", "a", true, nil},
+	{"a*", "abc", true, nil},
+	{"a*", "ab/c", false, nil},
+	{"a*/b", "abc/b", true, nil},
+	{"a*/b", "a/c/b", false, nil},
+	{"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
+	{"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
+	{"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
+	{"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
+	{"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
+	{"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
+	{"ab[c]", "abc", true, nil},
+	{"ab[b-d]", "abc", true, nil},
+	{"ab[e-g]", "abc", false, nil},
+	{"ab[^c]", "abc", false, nil},
+	{"ab[^b-d]", "abc", false, nil},
+	{"ab[^e-g]", "abc", true, nil},
+	{"a\\*b", "a*b", true, nil},
+	{"a\\*b", "ab", false, nil},
+	{"a?b", "a☺b", true, nil},
+	{"a[^a]b", "a☺b", true, nil},
+	{"a???b", "a☺b", false, nil},
+	{"a[^a][^a][^a]b", "a☺b", false, nil},
+	{"[a-ζ]*", "α", true, nil},
+	{"*[a-ζ]", "A", false, nil},
+	{"a?b", "a/b", false, nil},
+	{"a*b", "a/b", false, nil},
+	{"[\\]a]", "]", true, nil},
+	{"[\\-]", "-", true, nil},
+	{"[x\\-]", "x", true, nil},
+	{"[x\\-]", "-", true, nil},
+	{"[x\\-]", "z", false, nil},
+	{"[\\-x]", "x", true, nil},
+	{"[\\-x]", "-", true, nil},
+	{"[\\-x]", "a", false, nil},
+	{"[]a]", "]", false, ErrBadPattern},
+	{"[-]", "-", false, ErrBadPattern},
+	{"[x-]", "x", false, ErrBadPattern},
+	{"[x-]", "-", false, ErrBadPattern},
+	{"[x-]", "z", false, ErrBadPattern},
+	{"[-x]", "x", false, ErrBadPattern},
+	{"[-x]", "-", false, ErrBadPattern},
+	{"[-x]", "a", false, ErrBadPattern},
+	{"\\", "a", false, ErrBadPattern},
+	{"[a-b-c]", "a", false, ErrBadPattern},
+	{"*x", "xxx", true, nil},
+}
+
+func TestMatch(t *testing.T) {
+	for _, tt := range matchTests {
+		ok, err := Match(tt.pattern, tt.s)
+		if ok != tt.match || err != tt.err {
+			t.Errorf("Match(%#q, %#q) = %v, %v want %v, nil", tt.pattern, tt.s, ok, err, tt.match)
+		}
+	}
+}
+
+// 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"},
+	// Fails in the gccgo test environment.
+	// {"../*/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)
+		}
+	}
+}
diff --git a/libgo/go/path/path.go b/libgo/go/path/path.go
new file mode 100644
index 000000000..61eea8858
--- /dev/null
+++ b/libgo/go/path/path.go
@@ -0,0 +1,212 @@
+// Copyright 2009 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.
+
+// The path package implements utility routines for manipulating
+// slash-separated filename paths.
+package path
+
+import (
+	"io/ioutil"
+	"os"
+	"strings"
+)
+
+// Clean returns the shortest path name equivalent to path
+// by purely lexical processing.  It applies the following rules
+// iteratively until no further processing can be done:
+//
+//	1. Replace multiple slashes with a single slash.
+//	2. Eliminate each . path name element (the current directory).
+//	3. Eliminate each inner .. path name element (the parent directory)
+//	   along with the non-.. element that precedes it.
+//	4. Eliminate .. elements that begin a rooted path:
+//	   that is, replace "/.." by "/" at the beginning of a path.
+//
+// If the result of this process is an empty string, Clean
+// returns the string ".".
+//
+// See also Rob Pike, ``Lexical File Names in Plan 9 or
+// Getting Dot-Dot right,''
+// http://plan9.bell-labs.com/sys/doc/lexnames.html
+func Clean(path string) string {
+	if path == "" {
+		return "."
+	}
+
+	rooted := path[0] == '/'
+	n := len(path)
+
+	// Invariants:
+	//	reading from path; r is index of next byte to process.
+	//	writing to buf; w is index of next byte to write.
+	//	dotdot is index in buf where .. must stop, either because
+	//		it is the leading slash or it is a leading ../../.. prefix.
+	buf := []byte(path)
+	r, w, dotdot := 0, 0, 0
+	if rooted {
+		r, w, dotdot = 1, 1, 1
+	}
+
+	for r < n {
+		switch {
+		case path[r] == '/':
+			// empty path element
+			r++
+		case path[r] == '.' && (r+1 == n || path[r+1] == '/'):
+			// . element
+			r++
+		case path[r] == '.' && path[r+1] == '.' && (r+2 == n || path[r+2] == '/'):
+			// .. element: remove to last /
+			r += 2
+			switch {
+			case w > dotdot:
+				// can backtrack
+				w--
+				for w > dotdot && buf[w] != '/' {
+					w--
+				}
+			case !rooted:
+				// cannot backtrack, but not rooted, so append .. element.
+				if w > 0 {
+					buf[w] = '/'
+					w++
+				}
+				buf[w] = '.'
+				w++
+				buf[w] = '.'
+				w++
+				dotdot = w
+			}
+		default:
+			// real path element.
+			// add slash if needed
+			if rooted && w != 1 || !rooted && w != 0 {
+				buf[w] = '/'
+				w++
+			}
+			// copy element
+			for ; r < n && path[r] != '/'; r++ {
+				buf[w] = path[r]
+				w++
+			}
+		}
+	}
+
+	// Turn empty string into "."
+	if w == 0 {
+		buf[w] = '.'
+		w++
+	}
+
+	return string(buf[0:w])
+}
+
+// Split splits path immediately following the final path separator,
+// separating it into a directory and file name component.
+// If there is no separator in path, Split returns an empty dir and
+// file set to path.
+func Split(path string) (dir, file string) {
+	i := strings.LastIndexAny(path, PathSeps)
+	return path[:i+1], path[i+1:]
+}
+
+// Join joins any number of path elements into a single path, adding a
+// separating slash if necessary.  All empty strings are ignored.
+func Join(elem ...string) string {
+	for i, e := range elem {
+		if e != "" {
+			return Clean(strings.Join(elem[i:], "/"))
+		}
+	}
+	return ""
+}
+
+// Ext returns the file name extension used by path.
+// The extension is the suffix beginning at the final dot
+// in the final slash-separated element of path;
+// it is empty if there is no dot.
+func Ext(path string) string {
+	for i := len(path) - 1; i >= 0 && path[i] != '/'; i-- {
+		if path[i] == '.' {
+			return path[i:]
+		}
+	}
+	return ""
+}
+
+// Visitor methods are invoked for corresponding file tree entries
+// visited by Walk. The parameter path is the full path of f relative
+// to root.
+type Visitor interface {
+	VisitDir(path string, f *os.FileInfo) bool
+	VisitFile(path string, f *os.FileInfo)
+}
+
+func walk(path string, f *os.FileInfo, v Visitor, errors chan<- os.Error) {
+	if !f.IsDirectory() {
+		v.VisitFile(path, f)
+		return
+	}
+
+	if !v.VisitDir(path, f) {
+		return // skip directory entries
+	}
+
+	list, err := ioutil.ReadDir(path)
+	if err != nil {
+		if errors != nil {
+			errors <- err
+		}
+	}
+
+	for _, e := range list {
+		walk(Join(path, e.Name), e, v, errors)
+	}
+}
+
+// Walk walks the file tree rooted at root, calling v.VisitDir or
+// v.VisitFile for each directory or file in the tree, including root.
+// If v.VisitDir returns false, Walk skips the directory's entries;
+// otherwise it invokes itself for each directory entry in sorted order.
+// An error reading a directory does not abort the Walk.
+// If errors != nil, Walk sends each directory read error
+// to the channel.  Otherwise Walk discards the error.
+func Walk(root string, v Visitor, errors chan<- os.Error) {
+	f, err := os.Lstat(root)
+	if err != nil {
+		if errors != nil {
+			errors <- err
+		}
+		return // can't progress
+	}
+	walk(root, f, v, errors)
+}
+
+// Base returns the last path element of the slash-separated name.
+// Trailing slashes are removed before extracting the last element.  If the name is
+// empty, "." is returned.  If it consists entirely of slashes, "/" is returned.
+func Base(name string) string {
+	if name == "" {
+		return "."
+	}
+	// Strip trailing slashes.
+	for len(name) > 0 && name[len(name)-1] == '/' {
+		name = name[0 : len(name)-1]
+	}
+	// Find the last element
+	if i := strings.LastIndex(name, "/"); i >= 0 {
+		name = name[i+1:]
+	}
+	// If empty now, it had only slashes.
+	if name == "" {
+		return "/"
+	}
+	return name
+}
+
+// IsAbs returns true if the path is absolute.
+func IsAbs(path string) bool {
+	// TODO: Add Windows support
+	return strings.HasPrefix(path, "/")
+}
diff --git a/libgo/go/path/path_test.go b/libgo/go/path/path_test.go
new file mode 100644
index 000000000..6b4be07a9
--- /dev/null
+++ b/libgo/go/path/path_test.go
@@ -0,0 +1,345 @@
+// Copyright 2009 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 path
+
+import (
+	"os"
+	"runtime"
+	"testing"
+)
+
+type CleanTest struct {
+	path, clean string
+}
+
+var cleantests = []CleanTest{
+	// Already clean
+	{"", "."},
+	{"abc", "abc"},
+	{"abc/def", "abc/def"},
+	{"a/b/c", "a/b/c"},
+	{".", "."},
+	{"..", ".."},
+	{"../..", "../.."},
+	{"../../abc", "../../abc"},
+	{"/abc", "/abc"},
+	{"/", "/"},
+
+	// Remove trailing slash
+	{"abc/", "abc"},
+	{"abc/def/", "abc/def"},
+	{"a/b/c/", "a/b/c"},
+	{"./", "."},
+	{"../", ".."},
+	{"../../", "../.."},
+	{"/abc/", "/abc"},
+
+	// Remove doubled slash
+	{"abc//def//ghi", "abc/def/ghi"},
+	{"//abc", "/abc"},
+	{"///abc", "/abc"},
+	{"//abc//", "/abc"},
+	{"abc//", "abc"},
+
+	// Remove . elements
+	{"abc/./def", "abc/def"},
+	{"/./abc/def", "/abc/def"},
+	{"abc/.", "abc"},
+
+	// Remove .. elements
+	{"abc/def/ghi/../jkl", "abc/def/jkl"},
+	{"abc/def/../ghi/../jkl", "abc/jkl"},
+	{"abc/def/..", "abc"},
+	{"abc/def/../..", "."},
+	{"/abc/def/../..", "/"},
+	{"abc/def/../../..", ".."},
+	{"/abc/def/../../..", "/"},
+	{"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
+
+	// Combinations
+	{"abc/./../def", "def"},
+	{"abc//./../def", "def"},
+	{"abc/../../././../def", "../../def"},
+}
+
+func TestClean(t *testing.T) {
+	for _, test := range cleantests {
+		if s := Clean(test.path); s != test.clean {
+			t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.clean)
+		}
+	}
+}
+
+type SplitTest struct {
+	path, dir, file string
+}
+
+var splittests = []SplitTest{
+	{"a/b", "a/", "b"},
+	{"a/b/", "a/b/", ""},
+	{"a/", "a/", ""},
+	{"a", "", "a"},
+	{"/", "/", ""},
+}
+
+var winsplittests = []SplitTest{
+	{`C:\Windows\System32`, `C:\Windows\`, `System32`},
+	{`C:\Windows\`, `C:\Windows\`, ``},
+	{`C:\Windows`, `C:\`, `Windows`},
+	{`C:Windows`, `C:`, `Windows`},
+	{`\\?\c:\`, `\\?\c:\`, ``},
+}
+
+func TestSplit(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		splittests = append(splittests, winsplittests...)
+	}
+	for _, test := range splittests {
+		if d, f := Split(test.path); d != test.dir || f != test.file {
+			t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
+		}
+	}
+}
+
+type JoinTest struct {
+	elem []string
+	path string
+}
+
+var jointests = []JoinTest{
+	// zero parameters
+	{[]string{}, ""},
+
+	// one parameter
+	{[]string{""}, ""},
+	{[]string{"a"}, "a"},
+
+	// two parameters
+	{[]string{"a", "b"}, "a/b"},
+	{[]string{"a", ""}, "a"},
+	{[]string{"", "b"}, "b"},
+	{[]string{"/", "a"}, "/a"},
+	{[]string{"/", ""}, "/"},
+	{[]string{"a/", "b"}, "a/b"},
+	{[]string{"a/", ""}, "a"},
+	{[]string{"", ""}, ""},
+}
+
+// join takes a []string and passes it to Join.
+func join(elem []string, args ...string) string {
+	args = elem
+	return Join(args...)
+}
+
+func TestJoin(t *testing.T) {
+	for _, test := range jointests {
+		if p := join(test.elem); p != test.path {
+			t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
+		}
+	}
+}
+
+type ExtTest struct {
+	path, ext string
+}
+
+var exttests = []ExtTest{
+	{"path.go", ".go"},
+	{"path.pb.go", ".go"},
+	{"a.dir/b", ""},
+	{"a.dir/b.go", ".go"},
+	{"a.dir/", ""},
+}
+
+func TestExt(t *testing.T) {
+	for _, test := range exttests {
+		if x := Ext(test.path); x != test.ext {
+			t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext)
+		}
+	}
+}
+
+type Node struct {
+	name    string
+	entries []*Node // nil if the entry is a file
+	mark    int
+}
+
+var tree = &Node{
+	"testdata",
+	[]*Node{
+		&Node{"a", nil, 0},
+		&Node{"b", []*Node{}, 0},
+		&Node{"c", nil, 0},
+		&Node{
+			"d",
+			[]*Node{
+				&Node{"x", nil, 0},
+				&Node{"y", []*Node{}, 0},
+				&Node{
+					"z",
+					[]*Node{
+						&Node{"u", nil, 0},
+						&Node{"v", nil, 0},
+					},
+					0,
+				},
+			},
+			0,
+		},
+	},
+	0,
+}
+
+func walkTree(n *Node, path string, f func(path string, n *Node)) {
+	f(path, n)
+	for _, e := range n.entries {
+		walkTree(e, Join(path, e.name), f)
+	}
+}
+
+func makeTree(t *testing.T) {
+	walkTree(tree, tree.name, func(path string, n *Node) {
+		if n.entries == nil {
+			fd, err := os.Open(path, os.O_CREAT, 0660)
+			if err != nil {
+				t.Errorf("makeTree: %v", err)
+			}
+			fd.Close()
+		} else {
+			os.Mkdir(path, 0770)
+		}
+	})
+}
+
+func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) }
+
+func checkMarks(t *testing.T) {
+	walkTree(tree, tree.name, func(path string, n *Node) {
+		if n.mark != 1 {
+			t.Errorf("node %s mark = %d; expected 1", path, n.mark)
+		}
+		n.mark = 0
+	})
+}
+
+// Assumes that each node name is unique. Good enough for a test.
+func mark(name string) {
+	walkTree(tree, tree.name, func(path string, n *Node) {
+		if n.name == name {
+			n.mark++
+		}
+	})
+}
+
+type TestVisitor struct{}
+
+func (v *TestVisitor) VisitDir(path string, f *os.FileInfo) bool {
+	mark(f.Name)
+	return true
+}
+
+func (v *TestVisitor) VisitFile(path string, f *os.FileInfo) {
+	mark(f.Name)
+}
+
+func TestWalk(t *testing.T) {
+	makeTree(t)
+
+	// 1) ignore error handling, expect none
+	v := &TestVisitor{}
+	Walk(tree.name, v, nil)
+	checkMarks(t)
+
+	// 2) handle errors, expect none
+	errors := make(chan os.Error, 64)
+	Walk(tree.name, v, errors)
+	if err, ok := <-errors; ok {
+		t.Errorf("no error expected, found: %s", err)
+	}
+	checkMarks(t)
+
+	if os.Getuid() != 0 {
+		// introduce 2 errors: chmod top-level directories to 0
+		os.Chmod(Join(tree.name, tree.entries[1].name), 0)
+		os.Chmod(Join(tree.name, tree.entries[3].name), 0)
+		// mark respective subtrees manually
+		markTree(tree.entries[1])
+		markTree(tree.entries[3])
+		// correct double-marking of directory itself
+		tree.entries[1].mark--
+		tree.entries[3].mark--
+
+		// 3) handle errors, expect two
+		errors = make(chan os.Error, 64)
+		os.Chmod(Join(tree.name, tree.entries[1].name), 0)
+		Walk(tree.name, v, errors)
+		for i := 1; i <= 2; i++ {
+			if _, ok := <-errors; !ok {
+				t.Errorf("%d. error expected, none found", i)
+				break
+			}
+		}
+		if err, ok := <-errors; ok {
+			t.Errorf("only two errors expected, found 3rd: %v", err)
+		}
+		// the inaccessible subtrees were marked manually
+		checkMarks(t)
+	}
+
+	// cleanup
+	os.Chmod(Join(tree.name, tree.entries[1].name), 0770)
+	os.Chmod(Join(tree.name, tree.entries[3].name), 0770)
+	if err := os.RemoveAll(tree.name); err != nil {
+		t.Errorf("removeTree: %v", err)
+	}
+}
+
+var basetests = []CleanTest{
+	// Already clean
+	{"", "."},
+	{".", "."},
+	{"/.", "."},
+	{"/", "/"},
+	{"////", "/"},
+	{"x/", "x"},
+	{"abc", "abc"},
+	{"abc/def", "def"},
+	{"a/b/.x", ".x"},
+	{"a/b/c.", "c."},
+	{"a/b/c.x", "c.x"},
+}
+
+func TestBase(t *testing.T) {
+	for _, test := range basetests {
+		if s := Base(test.path); s != test.clean {
+			t.Errorf("Base(%q) = %q, want %q", test.path, s, test.clean)
+		}
+	}
+}
+
+type IsAbsTest struct {
+	path  string
+	isAbs bool
+}
+
+var isAbsTests = []IsAbsTest{
+	{"", false},
+	{"/", true},
+	{"/usr/bin/gcc", true},
+	{"..", false},
+	{"/a/../bb", true},
+	{".", false},
+	{"./", false},
+	{"lala", false},
+}
+
+func TestIsAbs(t *testing.T) {
+	for _, test := range isAbsTests {
+		if r := IsAbs(test.path); r != test.isAbs {
+			t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
+		}
+	}
+}
diff --git a/libgo/go/path/path_unix.go b/libgo/go/path/path_unix.go
new file mode 100644
index 000000000..7e8c5eb8b
--- /dev/null
+++ b/libgo/go/path/path_unix.go
@@ -0,0 +1,11 @@
+// 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 path
+
+const (
+	DirSeps    = `/`                  // directory separators
+	VolumeSeps = ``                   // volume separators
+	PathSeps   = DirSeps + VolumeSeps // all path separators
+)
diff --git a/libgo/go/path/path_windows.go b/libgo/go/path/path_windows.go
new file mode 100644
index 000000000..966eb49fb
--- /dev/null
+++ b/libgo/go/path/path_windows.go
@@ -0,0 +1,11 @@
+// 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 path
+
+const (
+	DirSeps    = `\/`                 // directory separators
+	VolumeSeps = `:`                  // volume separators
+	PathSeps   = DirSeps + VolumeSeps // all path separators
+)
-- 
cgit v1.2.3