blob: 67fb4ee6ed0a4aea95661cdff7c5efba09b8e988 [file] [log] [blame]
Colin Cross6bde0942016-11-04 14:36:38 -07001// 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 android
16
17import (
18 "fmt"
19 "strings"
20 "unicode"
Colin Cross2647ced2019-07-11 10:58:17 -070021
22 "github.com/google/blueprint/proptools"
Colin Cross6bde0942016-11-04 14:36:38 -070023)
24
Colin Cross2647ced2019-07-11 10:58:17 -070025// ExpandNinjaEscaped substitutes $() variables in a string
26// $(var) is passed to mapping(var), which should return the expanded value, a bool for whether the result should
27// be left unescaped when using in a ninja value (generally false, true if the expanded value is a ninja variable like
28// '${in}'), and an error.
29// $$ is converted to $, which is escaped back to $$.
30func ExpandNinjaEscaped(s string, mapping func(string) (string, bool, error)) (string, error) {
31 return expand(s, true, mapping)
32}
33
Colin Cross6bde0942016-11-04 14:36:38 -070034// Expand substitutes $() variables in a string
Colin Cross2647ced2019-07-11 10:58:17 -070035// $(var) is passed to mapping(var), which should return the expanded value and an error.
36// $$ is converted to $.
Colin Cross6bde0942016-11-04 14:36:38 -070037func Expand(s string, mapping func(string) (string, error)) (string, error) {
Colin Cross2647ced2019-07-11 10:58:17 -070038 return expand(s, false, func(s string) (string, bool, error) {
39 s, err := mapping(s)
40 return s, false, err
41 })
42}
43
44func expand(s string, ninjaEscape bool, mapping func(string) (string, bool, error)) (string, error) {
Colin Cross6bde0942016-11-04 14:36:38 -070045 // based on os.Expand
46 buf := make([]byte, 0, 2*len(s))
47 i := 0
48 for j := 0; j < len(s); j++ {
49 if s[j] == '$' {
50 if j+1 >= len(s) {
51 return "", fmt.Errorf("expected character after '$'")
52 }
53 buf = append(buf, s[i:j]...)
Colin Cross2647ced2019-07-11 10:58:17 -070054 value, ninjaVariable, w, err := getMapping(s[j+1:], mapping)
Colin Cross6bde0942016-11-04 14:36:38 -070055 if err != nil {
56 return "", err
57 }
Colin Cross2647ced2019-07-11 10:58:17 -070058 if !ninjaVariable && ninjaEscape {
59 value = proptools.NinjaEscape(value)
60 }
Colin Cross6bde0942016-11-04 14:36:38 -070061 buf = append(buf, value...)
62 j += w
63 i = j + 1
64 }
65 }
66 return string(buf) + s[i:], nil
67}
68
Colin Cross2647ced2019-07-11 10:58:17 -070069func getMapping(s string, mapping func(string) (string, bool, error)) (string, bool, int, error) {
Colin Cross6bde0942016-11-04 14:36:38 -070070 switch s[0] {
71 case '(':
72 // Scan to closing brace
73 for i := 1; i < len(s); i++ {
74 if s[i] == ')' {
Colin Cross2647ced2019-07-11 10:58:17 -070075 ret, ninjaVariable, err := mapping(strings.TrimSpace(s[1:i]))
76 return ret, ninjaVariable, i + 1, err
Colin Cross6bde0942016-11-04 14:36:38 -070077 }
78 }
Colin Cross2647ced2019-07-11 10:58:17 -070079 return "", false, len(s), fmt.Errorf("missing )")
Colin Cross6bde0942016-11-04 14:36:38 -070080 case '$':
Colin Cross2647ced2019-07-11 10:58:17 -070081 return "$", false, 1, nil
Colin Cross6bde0942016-11-04 14:36:38 -070082 default:
Colin Cross6f080df2016-11-04 15:32:58 -070083 i := strings.IndexFunc(s, unicode.IsSpace)
Colin Cross6bde0942016-11-04 14:36:38 -070084 if i == 0 {
Colin Cross2647ced2019-07-11 10:58:17 -070085 return "", false, 0, fmt.Errorf("unexpected character '%c' after '$'", s[0])
Colin Cross6bde0942016-11-04 14:36:38 -070086 } else if i == -1 {
87 i = len(s)
88 }
Colin Cross2647ced2019-07-11 10:58:17 -070089 return "", false, 0, fmt.Errorf("expected '(' after '$', did you mean $(%s)?", s[:i])
Colin Cross6bde0942016-11-04 14:36:38 -070090 }
91}