CommonPrefix returns common directory path of provided files
(sep byte, paths ...string)
| 74 | |
| 75 | // CommonPrefix returns common directory path of provided files |
| 76 | func CommonPrefix(sep byte, paths ...string) string { |
| 77 | // Handle special cases. |
| 78 | switch len(paths) { |
| 79 | case 0: |
| 80 | return "" |
| 81 | case 1: |
| 82 | return path.Clean(paths[0]) |
| 83 | } |
| 84 | |
| 85 | // Note, we treat string as []byte, not []rune as is often |
| 86 | // done in Go. (And sep as byte, not rune). This is because |
| 87 | // most/all supported OS' treat paths as string of non-zero |
| 88 | // bytes. A filename may be displayed as a sequence of Unicode |
| 89 | // runes (typically encoded as UTF-8) but paths are |
| 90 | // not required to be valid UTF-8 or in any normalized form |
| 91 | // (e.g. "é" (U+00C9) and "é" (U+0065,U+0301) are different |
| 92 | // file names. |
| 93 | c := []byte(path.Clean(paths[0])) |
| 94 | |
| 95 | // We add a trailing sep to handle the case where the |
| 96 | // common prefix directory is included in the path list |
| 97 | // (e.g. /home/user1, /home/user1/foo, /home/user1/bar). |
| 98 | // path.Clean will have cleaned off trailing / separators with |
| 99 | // the exception of the root directory, "/" (in which case we |
| 100 | // make it "//", but this will get fixed up to "/" below). |
| 101 | c = append(c, sep) |
| 102 | |
| 103 | // Ignore the first path since it's already in c |
| 104 | for _, v := range paths[1:] { |
| 105 | // Clean up each path before testing it |
| 106 | v = path.Clean(v) + string(sep) |
| 107 | |
| 108 | // Find the first non-common byte and truncate c |
| 109 | if len(v) < len(c) { |
| 110 | c = c[:len(v)] |
| 111 | } |
| 112 | for i := 0; i < len(c); i++ { |
| 113 | if v[i] != c[i] { |
| 114 | c = c[:i] |
| 115 | break |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | // Remove trailing non-separator characters and the final separator |
| 121 | for i := len(c) - 1; i >= 0; i-- { |
| 122 | if c[i] == sep { |
| 123 | c = c[:i] |
| 124 | break |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | return string(c) |
| 129 | } |