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 59// ShellEscapeList takes string that may contain characters that are meaningful to bash and 60// escapes it if necessary by wrapping it in single quotes, and replacing internal single quotes with 61// '\'' (one single quote to end the quoting, a shell-escaped single quote to insert a real single 62// quote, and then a single quote to restarting quoting. 63func ShellEscape(s string) string { 64 shellUnsafeChar := func(r rune) bool { 65 switch { 66 case 'A' <= r && r <= 'Z', 67 'a' <= r && r <= 'z', 68 '0' <= r && r <= '9', 69 r == '_', 70 r == '+', 71 r == '-', 72 r == '=', 73 r == '.', 74 r == ',', 75 r == '/', 76 r == ' ': 77 return false 78 default: 79 return true 80 } 81 } 82 83 if strings.IndexFunc(s, shellUnsafeChar) == -1 { 84 // No escaping necessary 85 return s 86 } 87 88 return `'` + singleQuoteReplacer.Replace(s) + `'` 89} 90 91func NinjaAndShellEscapeList(slice []string) []string { 92 return ShellEscapeList(NinjaEscapeList(slice)) 93} 94 95func NinjaAndShellEscape(s string) string { 96 return ShellEscape(NinjaEscape(s)) 97} 98 99var singleQuoteReplacer = strings.NewReplacer(`'`, `'\''`) 100