2013-04-10 21:29:02 -07:00
|
|
|
|
package main
|
|
|
|
|
|
|
2015-02-20 00:35:01 -05:00
|
|
|
|
import (
|
2013-04-10 21:29:02 -07:00
|
|
|
|
"fmt"
|
2015-02-20 00:35:01 -05:00
|
|
|
|
"os"
|
2013-04-10 21:29:02 -07:00
|
|
|
|
"path"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2015-02-20 00:35:01 -05:00
|
|
|
|
func CommonPrefix(sep byte, paths ...string) string {
|
2013-04-10 21:29:02 -07:00
|
|
|
|
// Handle special cases.
|
|
|
|
|
|
switch len(paths) {
|
2015-02-20 00:35:01 -05:00
|
|
|
|
case 0:
|
|
|
|
|
|
return ""
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
return path.Clean(paths[0])
|
2013-04-10 21:29:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-02-20 00:35:01 -05:00
|
|
|
|
// Note, we treat string as []byte, not []rune as is often
|
|
|
|
|
|
// done in Go. (And sep as byte, not rune). This is because
|
|
|
|
|
|
// most/all supported OS' treat paths as string of non-zero
|
|
|
|
|
|
// bytes. A filename may be displayed as a sequence of Unicode
|
|
|
|
|
|
// runes (typically encoded as UTF-8) but paths are
|
|
|
|
|
|
// not required to be valid UTF-8 or in any normalized form
|
|
|
|
|
|
// (e.g. "é" (U+00C9) and "é" (U+0065,U+0301) are different
|
|
|
|
|
|
// file names.
|
2013-04-10 21:29:02 -07:00
|
|
|
|
c := []byte(path.Clean(paths[0]))
|
|
|
|
|
|
|
2015-02-20 00:35:01 -05:00
|
|
|
|
// We add a trailing sep to handle the case where the
|
|
|
|
|
|
// common prefix directory is included in the path list
|
|
|
|
|
|
// (e.g. /home/user1, /home/user1/foo, /home/user1/bar).
|
|
|
|
|
|
// path.Clean will have cleaned off trailing / separators with
|
|
|
|
|
|
// the exception of the root directory, "/" (in which case we
|
|
|
|
|
|
// make it "//", but this will get fixed up to "/" bellow).
|
|
|
|
|
|
c = append(c, sep)
|
2013-04-10 21:29:02 -07:00
|
|
|
|
|
2015-02-20 00:35:01 -05:00
|
|
|
|
// Ignore the first path since it's already in c
|
|
|
|
|
|
for _, v := range paths[1:] {
|
|
|
|
|
|
// Clean up each path before testing it
|
|
|
|
|
|
v = path.Clean(v) + string(sep)
|
2013-04-10 21:29:02 -07:00
|
|
|
|
|
2015-02-20 00:35:01 -05:00
|
|
|
|
// Find the first non-common byte and truncate c
|
|
|
|
|
|
if len(v) < len(c) {
|
|
|
|
|
|
c = c[:len(v)]
|
|
|
|
|
|
}
|
|
|
|
|
|
for i := 0; i < len(c); i++ {
|
2013-04-10 21:29:02 -07:00
|
|
|
|
if v[i] != c[i] {
|
2015-02-20 00:35:01 -05:00
|
|
|
|
c = c[:i]
|
2013-04-10 21:29:02 -07:00
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-02-20 00:35:01 -05:00
|
|
|
|
// Remove trailing non-separator characters and the final separator
|
|
|
|
|
|
for i := len(c) - 1; i >= 0; i-- {
|
|
|
|
|
|
if c[i] == sep {
|
|
|
|
|
|
c = c[:i]
|
2013-04-10 21:29:02 -07:00
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return string(c)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func main() {
|
2015-02-20 00:35:01 -05:00
|
|
|
|
c := CommonPrefix(os.PathSeparator,
|
|
|
|
|
|
//"/home/user1/tmp",
|
2013-04-10 21:29:02 -07:00
|
|
|
|
"/home/user1/tmp/coverage/test",
|
|
|
|
|
|
"/home/user1/tmp/covert/operator",
|
|
|
|
|
|
"/home/user1/tmp/coven/members",
|
2015-02-20 00:35:01 -05:00
|
|
|
|
"/home//user1/tmp/coventry",
|
|
|
|
|
|
"/home/user1/././tmp/covertly/foo",
|
|
|
|
|
|
"/home/bob/../user1/tmp/coved/bar",
|
2013-04-10 21:29:02 -07:00
|
|
|
|
)
|
2015-02-20 00:35:01 -05:00
|
|
|
|
if c == "" {
|
|
|
|
|
|
fmt.Println("No common path")
|
|
|
|
|
|
} else {
|
|
|
|
|
|
fmt.Println("Common path:", c)
|
|
|
|
|
|
}
|
2013-04-10 21:29:02 -07:00
|
|
|
|
}
|