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 15package proptools 16 17import "strings" 18 19// NinjaEscapeList 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. 24func NinjaEscapeList(slice []string) []string { 25 slice = append([]string(nil), slice...) 26 for i, s := range slice { 27 slice[i] = NinjaEscape(s) 28 } 29 return slice 30} 31 32// NinjaEscapeList takes a string that may contain characters that are meaningful to ninja 33// ($), and escapes it so it will be passed to bash. It is not necessary on input, 34// output, or dependency names, those are handled by ModuleContext.Build. It is generally required 35// on strings from properties in Blueprint files that are used as Args to ModuleContext.Build. A 36// new slice containing the escaped strings is returned. 37func NinjaEscape(s string) string { 38 return ninjaEscaper.Replace(s) 39} 40 41var ninjaEscaper = strings.NewReplacer( 42 "$", "$$") 43 44// ShellEscapeList takes a slice of strings that may contain characters that are meaningful to bash and 45// escapes them if necessary by wrapping them in single quotes, and replacing internal single quotes with 46// '\'' (one single quote to end the quoting, a shell-escaped single quote to insert a real single 47// quote, and then a single quote to restarting quoting. A new slice containing the escaped strings 48// is returned. 49func ShellEscapeList(slice []string) []string { 50 slice = append([]string(nil), slice...) 51 52 for i, s := range slice { 53 slice[i] = ShellEscape(s) 54 } 55 return slice 56 57} 58 59func shellUnsafeChar(r rune) bool { 60 switch { 61 case 'A' <= r && r <= 'Z', 62 'a' <= r && r <= 'z', 63 '0' <= r && r <= '9', 64 r == '_', 65 r == '+', 66 r == '-', 67 r == '=', 68 r == '.', 69 r == ',', 70 r == '/': 71 return false 72 default: 73 return true 74 } 75} 76 77// ShellEscape takes string that may contain characters that are meaningful to bash and 78// escapes it if necessary by wrapping it in single quotes, and replacing internal single quotes with 79// '\'' (one single quote to end the quoting, a shell-escaped single quote to insert a real single 80// quote, and then a single quote to restarting quoting. 81func ShellEscape(s string) string { 82 shellUnsafeCharNotSpace := func(r rune) bool { 83 return r != ' ' && shellUnsafeChar(r) 84 } 85 86 if strings.IndexFunc(s, shellUnsafeCharNotSpace) == -1 { 87 // No escaping necessary 88 return s 89 } 90 91 return `'` + singleQuoteReplacer.Replace(s) + `'` 92} 93 94// ShellEscapeIncludingSpaces escapes the input `s` in a similar way to ShellEscape except that 95// this treats spaces as meaningful characters. 96func ShellEscapeIncludingSpaces(s string) string { 97 if strings.IndexFunc(s, shellUnsafeChar) == -1 { 98 // No escaping necessary 99 return s 100 } 101 102 return `'` + singleQuoteReplacer.Replace(s) + `'` 103} 104 105func NinjaAndShellEscapeList(slice []string) []string { 106 return ShellEscapeList(NinjaEscapeList(slice)) 107} 108 109func NinjaAndShellEscape(s string) string { 110 return ShellEscape(NinjaEscape(s)) 111} 112 113var singleQuoteReplacer = strings.NewReplacer(`'`, `'\''`) 114