• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
58func ShellEscapeListIncludingSpaces(slice []string) []string {
59	slice = append([]string(nil), slice...)
60
61	for i, s := range slice {
62		slice[i] = ShellEscapeIncludingSpaces(s)
63	}
64	return slice
65}
66
67func shellUnsafeChar(r rune) bool {
68	switch {
69	case 'A' <= r && r <= 'Z',
70		'a' <= r && r <= 'z',
71		'0' <= r && r <= '9',
72		r == '_',
73		r == '+',
74		r == '-',
75		r == '=',
76		r == '.',
77		r == ',',
78		r == '/':
79		return false
80	default:
81		return true
82	}
83}
84
85// ShellEscape takes string that may contain characters that are meaningful to bash and
86// escapes it if necessary by wrapping it in single quotes, and replacing internal single quotes with
87// '\'' (one single quote to end the quoting, a shell-escaped single quote to insert a real single
88// quote, and then a single quote to restarting quoting.
89func ShellEscape(s string) string {
90	shellUnsafeCharNotSpace := func(r rune) bool {
91		return r != ' ' && shellUnsafeChar(r)
92	}
93
94	if strings.IndexFunc(s, shellUnsafeCharNotSpace) == -1 {
95		// No escaping necessary
96		return s
97	}
98
99	return `'` + singleQuoteReplacer.Replace(s) + `'`
100}
101
102// ShellEscapeIncludingSpaces escapes the input `s` in a similar way to ShellEscape except that
103// this treats spaces as meaningful characters.
104func ShellEscapeIncludingSpaces(s string) string {
105	if strings.IndexFunc(s, shellUnsafeChar) == -1 {
106		// No escaping necessary
107		return s
108	}
109
110	return `'` + singleQuoteReplacer.Replace(s) + `'`
111}
112
113func NinjaAndShellEscapeList(slice []string) []string {
114	return ShellEscapeList(NinjaEscapeList(slice))
115}
116
117func NinjaAndShellEscapeListIncludingSpaces(slice []string) []string {
118	return ShellEscapeListIncludingSpaces(NinjaEscapeList(slice))
119}
120
121func NinjaAndShellEscape(s string) string {
122	return ShellEscape(NinjaEscape(s))
123}
124
125var singleQuoteReplacer = strings.NewReplacer(`'`, `'\''`)
126