1 // Copyright 2016 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 15 package proptools 16 17 import "strings" 18 19 // NinjaEscape takes a slice of strings that may contain characters that are meaningful to ninja 20 // ($), and escapes each string so they will be passed to bash. It is not necessary on input, 21 // output, or dependency names, those are handled by ModuleContext.Build. It is generally required 22 // on strings from properties in Blueprint files that are used as Args to ModuleContext.Build. A 23 // new slice containing the escaped strings is returned. 24 func NinjaEscape(slice []string) []string { 25 slice = append([]string(nil), slice...) 26 for i, s := range slice { 27 slice[i] = ninjaEscaper.Replace(s) 28 } 29 return slice 30 } 31 32 var ninjaEscaper = strings.NewReplacer( 33 "$", "$$") 34 35 // ShellEscape takes a slice of strings that may contain characters that are meaningful to bash and 36 // escapes if necessary by wrapping them in single quotes, and replacing internal single quotes with 37 // '\'' (one single quote to end the quoting, a shell-escaped single quote to insert a real single 38 // quote, and then a single quote to restarting quoting. A new slice containing the escaped strings 39 // is returned. 40 func ShellEscape(slice []string) []string { 41 shellUnsafeChar := func(r rune) bool { 42 switch { 43 case 'A' <= r && r <= 'Z', 44 'a' <= r && r <= 'z', 45 '0' <= r && r <= '9', 46 r == '_', 47 r == '+', 48 r == '-', 49 r == '=', 50 r == '.', 51 r == ',', 52 r == '/', 53 r == ' ': 54 return false 55 default: 56 return true 57 } 58 } 59 60 slice = append([]string(nil), slice...) 61 62 for i, s := range slice { 63 if strings.IndexFunc(s, shellUnsafeChar) == -1 { 64 // No escaping necessary 65 continue 66 } 67 68 slice[i] = `'` + singleQuoteReplacer.Replace(s) + `'` 69 } 70 return slice 71 72 } 73 74 func NinjaAndShellEscape(slice []string) []string { 75 return ShellEscape(NinjaEscape(slice)) 76 } 77 78 var singleQuoteReplacer = strings.NewReplacer(`'`, `'\''`) 79