Home | History | Annotate | Download | only in android
      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 android
     16 
     17 import (
     18 	"fmt"
     19 	"strings"
     20 	"unicode"
     21 )
     22 
     23 // Expand substitutes $() variables in a string
     24 // $(var) is passed to Expander(var)
     25 // $$ is converted to $
     26 func Expand(s string, mapping func(string) (string, error)) (string, error) {
     27 	// based on os.Expand
     28 	buf := make([]byte, 0, 2*len(s))
     29 	i := 0
     30 	for j := 0; j < len(s); j++ {
     31 		if s[j] == '$' {
     32 			if j+1 >= len(s) {
     33 				return "", fmt.Errorf("expected character after '$'")
     34 			}
     35 			buf = append(buf, s[i:j]...)
     36 			value, w, err := getMapping(s[j+1:], mapping)
     37 			if err != nil {
     38 				return "", err
     39 			}
     40 			buf = append(buf, value...)
     41 			j += w
     42 			i = j + 1
     43 		}
     44 	}
     45 	return string(buf) + s[i:], nil
     46 }
     47 
     48 func getMapping(s string, mapping func(string) (string, error)) (string, int, error) {
     49 	switch s[0] {
     50 	case '(':
     51 		// Scan to closing brace
     52 		for i := 1; i < len(s); i++ {
     53 			if s[i] == ')' {
     54 				ret, err := mapping(strings.TrimSpace(s[1:i]))
     55 				return ret, i + 1, err
     56 			}
     57 		}
     58 		return "", len(s), fmt.Errorf("missing )")
     59 	case '$':
     60 		return "$$", 1, nil
     61 	default:
     62 		i := strings.IndexFunc(s, unicode.IsSpace)
     63 		if i == 0 {
     64 			return "", 0, fmt.Errorf("unexpected character '%c' after '$'", s[0])
     65 		} else if i == -1 {
     66 			i = len(s)
     67 		}
     68 		return "", 0, fmt.Errorf("expected '(' after '$', did you mean $(%s)?", s[:i])
     69 	}
     70 }
     71