]> Sergey Matveev's repositories - glocate.git/blob - names.go
Newer ZFS has different octalize rule
[glocate.git] / names.go
1 /*
2 glocate -- ZFS-diff-friendly locate-like utility
3 Copyright (C) 2022-2023 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package main
19
20 import (
21         "log"
22         "path"
23         "strconv"
24         "strings"
25 )
26
27 func IsDir(s string) bool {
28         return s[len(s)-1] == '/'
29 }
30
31 type ByName [][]string
32
33 func (a ByName) Len() int {
34         return len(a)
35 }
36
37 func (a ByName) Swap(i, j int) {
38         a[i], a[j] = a[j], a[i]
39 }
40
41 func (a ByName) Less(i, j int) bool {
42         return namesCmp(a[i], a[j]) < 0
43 }
44
45 func nameSplit(name string) []string {
46         cols := strings.Split(name, "/")
47         if IsDir(name) {
48                 cols = cols[:len(cols)-1]
49                 cols[len(cols)-1] += "/"
50         }
51         return cols
52 }
53
54 func nameJoin(name []string) (s string) {
55         s = path.Join(name...)
56         if IsDir(name[len(name)-1]) {
57                 s += "/"
58         }
59         return
60 }
61
62 func namesCmp(n1, n2 []string) int {
63         min := len(n1)
64         if len(n2) < min {
65                 min = len(n2)
66         }
67         var t1, t2 string
68         for i := 0; i < min; i++ {
69                 t1 = strings.TrimSuffix(n1[i], "/")
70                 t2 = strings.TrimSuffix(n2[i], "/")
71                 if t1 < t2 {
72                         return -1
73                 }
74                 if t1 > t2 {
75                         return +1
76                 }
77         }
78         if len(n1) > len(n2) {
79                 return +1
80         }
81         if len(n1) < len(n2) {
82                 return -1
83         }
84         return 0
85 }
86
87 func hasPrefix(name, prefix []string) bool {
88         if len(name) < len(prefix) {
89                 return false
90         }
91         return namesCmp(name[:len(prefix)], prefix) == 0
92 }
93
94 func deoctalize(s string) string {
95         chars := make([]byte, 0, len(s))
96         for i := 0; i < len(s); i++ {
97                 if s[i] == '\\' {
98                         b, err := strconv.ParseUint(s[i+1:i+1+4], 0, 8)
99                         if err != nil {
100                                 log.Fatalln(err)
101                         }
102                         chars = append(chars, byte(b))
103                         i += 4
104                 } else {
105                         chars = append(chars, s[i])
106                 }
107         }
108         return string(chars)
109 }