1// Copyright 2015 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package android 16 17import ( 18 "fmt" 19 "regexp" 20 "runtime" 21 "sort" 22 "strings" 23) 24 25// CopyOf returns a new slice that has the same contents as s. 26func CopyOf(s []string) []string { 27 return append([]string(nil), s...) 28} 29 30func JoinWithPrefix(strs []string, prefix string) string { 31 if len(strs) == 0 { 32 return "" 33 } 34 35 if len(strs) == 1 { 36 return prefix + strs[0] 37 } 38 39 n := len(" ") * (len(strs) - 1) 40 for _, s := range strs { 41 n += len(prefix) + len(s) 42 } 43 44 ret := make([]byte, 0, n) 45 for i, s := range strs { 46 if i != 0 { 47 ret = append(ret, ' ') 48 } 49 ret = append(ret, prefix...) 50 ret = append(ret, s...) 51 } 52 return string(ret) 53} 54 55func sortedKeys(m map[string][]string) []string { 56 s := make([]string, 0, len(m)) 57 for k := range m { 58 s = append(s, k) 59 } 60 sort.Strings(s) 61 return s 62} 63 64func IndexList(s string, list []string) int { 65 for i, l := range list { 66 if l == s { 67 return i 68 } 69 } 70 71 return -1 72} 73 74func InList(s string, list []string) bool { 75 return IndexList(s, list) != -1 76} 77 78func PrefixInList(s string, list []string) bool { 79 for _, prefix := range list { 80 if strings.HasPrefix(s, prefix) { 81 return true 82 } 83 } 84 return false 85} 86 87func FilterList(list []string, filter []string) (remainder []string, filtered []string) { 88 for _, l := range list { 89 if InList(l, filter) { 90 filtered = append(filtered, l) 91 } else { 92 remainder = append(remainder, l) 93 } 94 } 95 96 return 97} 98 99func RemoveListFromList(list []string, filter_out []string) (result []string) { 100 result = make([]string, 0, len(list)) 101 for _, l := range list { 102 if !InList(l, filter_out) { 103 result = append(result, l) 104 } 105 } 106 return 107} 108 109func RemoveFromList(s string, list []string) (bool, []string) { 110 i := IndexList(s, list) 111 if i == -1 { 112 return false, list 113 } 114 115 result := make([]string, 0, len(list)-1) 116 result = append(result, list[:i]...) 117 for _, l := range list[i+1:] { 118 if l != s { 119 result = append(result, l) 120 } 121 } 122 return true, result 123} 124 125// FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of 126// each. It modifies the slice contents in place, and returns a subslice of the original slice. 127func FirstUniqueStrings(list []string) []string { 128 k := 0 129outer: 130 for i := 0; i < len(list); i++ { 131 for j := 0; j < k; j++ { 132 if list[i] == list[j] { 133 continue outer 134 } 135 } 136 list[k] = list[i] 137 k++ 138 } 139 return list[:k] 140} 141 142// LastUniqueStrings returns all unique elements of a slice of strings, keeping the last copy of 143// each. It modifies the slice contents in place, and returns a subslice of the original slice. 144func LastUniqueStrings(list []string) []string { 145 totalSkip := 0 146 for i := len(list) - 1; i >= totalSkip; i-- { 147 skip := 0 148 for j := i - 1; j >= totalSkip; j-- { 149 if list[i] == list[j] { 150 skip++ 151 } else { 152 list[j+skip] = list[j] 153 } 154 } 155 totalSkip += skip 156 } 157 return list[totalSkip:] 158} 159 160// checkCalledFromInit panics if a Go package's init function is not on the 161// call stack. 162func checkCalledFromInit() { 163 for skip := 3; ; skip++ { 164 _, funcName, ok := callerName(skip) 165 if !ok { 166 panic("not called from an init func") 167 } 168 169 if funcName == "init" || strings.HasPrefix(funcName, "init·") || 170 strings.HasPrefix(funcName, "init.") { 171 return 172 } 173 } 174} 175 176// A regex to find a package path within a function name. It finds the shortest string that is 177// followed by '.' and doesn't have any '/'s left. 178var pkgPathRe = regexp.MustCompile(`^(.*?)\.([^/]+)$`) 179 180// callerName returns the package path and function name of the calling 181// function. The skip argument has the same meaning as the skip argument of 182// runtime.Callers. 183func callerName(skip int) (pkgPath, funcName string, ok bool) { 184 var pc [1]uintptr 185 n := runtime.Callers(skip+1, pc[:]) 186 if n != 1 { 187 return "", "", false 188 } 189 190 f := runtime.FuncForPC(pc[0]).Name() 191 s := pkgPathRe.FindStringSubmatch(f) 192 if len(s) < 3 { 193 panic(fmt.Errorf("failed to extract package path and function name from %q", f)) 194 } 195 196 return s[1], s[2], true 197} 198 199func GetNumericSdkVersion(v string) string { 200 if strings.Contains(v, "system_") { 201 return strings.Replace(v, "system_", "", 1) 202 } 203 return v 204} 205 206// copied from build/kati/strutil.go 207func substPattern(pat, repl, str string) string { 208 ps := strings.SplitN(pat, "%", 2) 209 if len(ps) != 2 { 210 if str == pat { 211 return repl 212 } 213 return str 214 } 215 in := str 216 trimed := str 217 if ps[0] != "" { 218 trimed = strings.TrimPrefix(in, ps[0]) 219 if trimed == in { 220 return str 221 } 222 } 223 in = trimed 224 if ps[1] != "" { 225 trimed = strings.TrimSuffix(in, ps[1]) 226 if trimed == in { 227 return str 228 } 229 } 230 231 rs := strings.SplitN(repl, "%", 2) 232 if len(rs) != 2 { 233 return repl 234 } 235 return rs[0] + trimed + rs[1] 236} 237 238// copied from build/kati/strutil.go 239func matchPattern(pat, str string) bool { 240 i := strings.IndexByte(pat, '%') 241 if i < 0 { 242 return pat == str 243 } 244 return strings.HasPrefix(str, pat[:i]) && strings.HasSuffix(str, pat[i+1:]) 245} 246