xref: /aosp_15_r20/build/soong/androidmk/parser/make_strings.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2017 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage parser
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"fmt"
19*333d2b36SAndroid Build Coastguard Worker	"strings"
20*333d2b36SAndroid Build Coastguard Worker	"unicode"
21*333d2b36SAndroid Build Coastguard Worker	"unicode/utf8"
22*333d2b36SAndroid Build Coastguard Worker)
23*333d2b36SAndroid Build Coastguard Worker
24*333d2b36SAndroid Build Coastguard Worker// A MakeString is a string that may contain variable substitutions in it.
25*333d2b36SAndroid Build Coastguard Worker// It can be considered as an alternating list of raw Strings and variable
26*333d2b36SAndroid Build Coastguard Worker// substitutions, where the first and last entries in the list must be raw
27*333d2b36SAndroid Build Coastguard Worker// Strings (possibly empty). The entirety of the text before the first variable,
28*333d2b36SAndroid Build Coastguard Worker// between two variables, and after the last variable will be considered a
29*333d2b36SAndroid Build Coastguard Worker// single String value. A MakeString that starts with a variable will have an
30*333d2b36SAndroid Build Coastguard Worker// empty first raw string, and a MakeString that ends with a  variable will have
31*333d2b36SAndroid Build Coastguard Worker// an empty last raw string.  Two sequential Variables will have an empty raw
32*333d2b36SAndroid Build Coastguard Worker// string between them.
33*333d2b36SAndroid Build Coastguard Worker//
34*333d2b36SAndroid Build Coastguard Worker// The MakeString is stored as two lists, a list of raw Strings and a list
35*333d2b36SAndroid Build Coastguard Worker// of Variables.  The raw string list is always one longer than the variable
36*333d2b36SAndroid Build Coastguard Worker// list.
37*333d2b36SAndroid Build Coastguard Worker//
38*333d2b36SAndroid Build Coastguard Worker// For example, "$(FOO)/bar/baz" will be represented as the
39*333d2b36SAndroid Build Coastguard Worker// following lists:
40*333d2b36SAndroid Build Coastguard Worker//
41*333d2b36SAndroid Build Coastguard Worker//	{
42*333d2b36SAndroid Build Coastguard Worker//	  Strings: ["", "/bar/baz"],
43*333d2b36SAndroid Build Coastguard Worker//	  Variables: ["FOO"]
44*333d2b36SAndroid Build Coastguard Worker//	}
45*333d2b36SAndroid Build Coastguard Workertype MakeString struct {
46*333d2b36SAndroid Build Coastguard Worker	StringPos Pos
47*333d2b36SAndroid Build Coastguard Worker	Strings   []string
48*333d2b36SAndroid Build Coastguard Worker	Variables []Variable
49*333d2b36SAndroid Build Coastguard Worker}
50*333d2b36SAndroid Build Coastguard Worker
51*333d2b36SAndroid Build Coastguard Workerfunc SimpleMakeString(s string, pos Pos) *MakeString {
52*333d2b36SAndroid Build Coastguard Worker	return &MakeString{
53*333d2b36SAndroid Build Coastguard Worker		StringPos: pos,
54*333d2b36SAndroid Build Coastguard Worker		Strings:   []string{s},
55*333d2b36SAndroid Build Coastguard Worker	}
56*333d2b36SAndroid Build Coastguard Worker}
57*333d2b36SAndroid Build Coastguard Worker
58*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) Clone() (result *MakeString) {
59*333d2b36SAndroid Build Coastguard Worker	clone := *ms
60*333d2b36SAndroid Build Coastguard Worker	return &clone
61*333d2b36SAndroid Build Coastguard Worker}
62*333d2b36SAndroid Build Coastguard Worker
63*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) Pos() Pos {
64*333d2b36SAndroid Build Coastguard Worker	return ms.StringPos
65*333d2b36SAndroid Build Coastguard Worker}
66*333d2b36SAndroid Build Coastguard Worker
67*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) End() Pos {
68*333d2b36SAndroid Build Coastguard Worker	pos := ms.StringPos
69*333d2b36SAndroid Build Coastguard Worker	if len(ms.Strings) > 1 {
70*333d2b36SAndroid Build Coastguard Worker		pos = ms.Variables[len(ms.Variables)-1].End()
71*333d2b36SAndroid Build Coastguard Worker	}
72*333d2b36SAndroid Build Coastguard Worker	return Pos(int(pos) + len(ms.Strings[len(ms.Strings)-1]))
73*333d2b36SAndroid Build Coastguard Worker}
74*333d2b36SAndroid Build Coastguard Worker
75*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) appendString(s string) {
76*333d2b36SAndroid Build Coastguard Worker	if len(ms.Strings) == 0 {
77*333d2b36SAndroid Build Coastguard Worker		ms.Strings = []string{s}
78*333d2b36SAndroid Build Coastguard Worker		return
79*333d2b36SAndroid Build Coastguard Worker	} else {
80*333d2b36SAndroid Build Coastguard Worker		ms.Strings[len(ms.Strings)-1] += s
81*333d2b36SAndroid Build Coastguard Worker	}
82*333d2b36SAndroid Build Coastguard Worker}
83*333d2b36SAndroid Build Coastguard Worker
84*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) appendVariable(v Variable) {
85*333d2b36SAndroid Build Coastguard Worker	if len(ms.Strings) == 0 {
86*333d2b36SAndroid Build Coastguard Worker		ms.Strings = []string{"", ""}
87*333d2b36SAndroid Build Coastguard Worker		ms.Variables = []Variable{v}
88*333d2b36SAndroid Build Coastguard Worker	} else {
89*333d2b36SAndroid Build Coastguard Worker		ms.Strings = append(ms.Strings, "")
90*333d2b36SAndroid Build Coastguard Worker		ms.Variables = append(ms.Variables, v)
91*333d2b36SAndroid Build Coastguard Worker	}
92*333d2b36SAndroid Build Coastguard Worker}
93*333d2b36SAndroid Build Coastguard Worker
94*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) appendMakeString(other *MakeString) {
95*333d2b36SAndroid Build Coastguard Worker	last := len(ms.Strings) - 1
96*333d2b36SAndroid Build Coastguard Worker	ms.Strings[last] += other.Strings[0]
97*333d2b36SAndroid Build Coastguard Worker	ms.Strings = append(ms.Strings, other.Strings[1:]...)
98*333d2b36SAndroid Build Coastguard Worker	ms.Variables = append(ms.Variables, other.Variables...)
99*333d2b36SAndroid Build Coastguard Worker}
100*333d2b36SAndroid Build Coastguard Worker
101*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) Value(scope Scope) string {
102*333d2b36SAndroid Build Coastguard Worker	if len(ms.Strings) == 0 {
103*333d2b36SAndroid Build Coastguard Worker		return ""
104*333d2b36SAndroid Build Coastguard Worker	} else {
105*333d2b36SAndroid Build Coastguard Worker		ret := unescape(ms.Strings[0])
106*333d2b36SAndroid Build Coastguard Worker		for i := range ms.Strings[1:] {
107*333d2b36SAndroid Build Coastguard Worker			ret += ms.Variables[i].Value(scope)
108*333d2b36SAndroid Build Coastguard Worker			ret += unescape(ms.Strings[i+1])
109*333d2b36SAndroid Build Coastguard Worker		}
110*333d2b36SAndroid Build Coastguard Worker		return ret
111*333d2b36SAndroid Build Coastguard Worker	}
112*333d2b36SAndroid Build Coastguard Worker}
113*333d2b36SAndroid Build Coastguard Worker
114*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) Dump() string {
115*333d2b36SAndroid Build Coastguard Worker	if len(ms.Strings) == 0 {
116*333d2b36SAndroid Build Coastguard Worker		return ""
117*333d2b36SAndroid Build Coastguard Worker	} else {
118*333d2b36SAndroid Build Coastguard Worker		ret := ms.Strings[0]
119*333d2b36SAndroid Build Coastguard Worker		for i := range ms.Strings[1:] {
120*333d2b36SAndroid Build Coastguard Worker			ret += ms.Variables[i].Dump()
121*333d2b36SAndroid Build Coastguard Worker			ret += ms.Strings[i+1]
122*333d2b36SAndroid Build Coastguard Worker		}
123*333d2b36SAndroid Build Coastguard Worker		return ret
124*333d2b36SAndroid Build Coastguard Worker	}
125*333d2b36SAndroid Build Coastguard Worker}
126*333d2b36SAndroid Build Coastguard Worker
127*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) Const() bool {
128*333d2b36SAndroid Build Coastguard Worker	return len(ms.Strings) <= 1
129*333d2b36SAndroid Build Coastguard Worker}
130*333d2b36SAndroid Build Coastguard Worker
131*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) Empty() bool {
132*333d2b36SAndroid Build Coastguard Worker	return len(ms.Strings) == 0 || (len(ms.Strings) == 1 && ms.Strings[0] == "")
133*333d2b36SAndroid Build Coastguard Worker}
134*333d2b36SAndroid Build Coastguard Worker
135*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) Split(sep string) []*MakeString {
136*333d2b36SAndroid Build Coastguard Worker	return ms.SplitN(sep, -1)
137*333d2b36SAndroid Build Coastguard Worker}
138*333d2b36SAndroid Build Coastguard Worker
139*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) SplitN(sep string, n int) []*MakeString {
140*333d2b36SAndroid Build Coastguard Worker	return ms.splitNFunc(n, func(s string, n int) []string {
141*333d2b36SAndroid Build Coastguard Worker		return splitAnyN(s, sep, n)
142*333d2b36SAndroid Build Coastguard Worker	})
143*333d2b36SAndroid Build Coastguard Worker}
144*333d2b36SAndroid Build Coastguard Worker
145*333d2b36SAndroid Build Coastguard Worker// Words splits MakeString into multiple makeStrings separated by whitespace.
146*333d2b36SAndroid Build Coastguard Worker// Thus, " a $(X)b  c " will be split into ["a", "$(X)b", "c"].
147*333d2b36SAndroid Build Coastguard Worker// Splitting a MakeString consisting solely of whitespace yields empty array.
148*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) Words() []*MakeString {
149*333d2b36SAndroid Build Coastguard Worker	var ch rune    // current character
150*333d2b36SAndroid Build Coastguard Worker	const EOF = -1 // no more characters
151*333d2b36SAndroid Build Coastguard Worker	const EOS = -2 // at the end of a string chunk
152*333d2b36SAndroid Build Coastguard Worker
153*333d2b36SAndroid Build Coastguard Worker	// Next character's chunk and position
154*333d2b36SAndroid Build Coastguard Worker	iString := 0
155*333d2b36SAndroid Build Coastguard Worker	iChar := 0
156*333d2b36SAndroid Build Coastguard Worker
157*333d2b36SAndroid Build Coastguard Worker	var words []*MakeString
158*333d2b36SAndroid Build Coastguard Worker	word := SimpleMakeString("", ms.Pos())
159*333d2b36SAndroid Build Coastguard Worker
160*333d2b36SAndroid Build Coastguard Worker	nextChar := func() {
161*333d2b36SAndroid Build Coastguard Worker		if iString >= len(ms.Strings) {
162*333d2b36SAndroid Build Coastguard Worker			ch = EOF
163*333d2b36SAndroid Build Coastguard Worker		} else if iChar >= len(ms.Strings[iString]) {
164*333d2b36SAndroid Build Coastguard Worker			iString++
165*333d2b36SAndroid Build Coastguard Worker			iChar = 0
166*333d2b36SAndroid Build Coastguard Worker			ch = EOS
167*333d2b36SAndroid Build Coastguard Worker		} else {
168*333d2b36SAndroid Build Coastguard Worker			var w int
169*333d2b36SAndroid Build Coastguard Worker			ch, w = utf8.DecodeRuneInString(ms.Strings[iString][iChar:])
170*333d2b36SAndroid Build Coastguard Worker			iChar += w
171*333d2b36SAndroid Build Coastguard Worker		}
172*333d2b36SAndroid Build Coastguard Worker	}
173*333d2b36SAndroid Build Coastguard Worker
174*333d2b36SAndroid Build Coastguard Worker	appendVariableAndAdvance := func() {
175*333d2b36SAndroid Build Coastguard Worker		if iString-1 < len(ms.Variables) {
176*333d2b36SAndroid Build Coastguard Worker			word.appendVariable(ms.Variables[iString-1])
177*333d2b36SAndroid Build Coastguard Worker		}
178*333d2b36SAndroid Build Coastguard Worker		nextChar()
179*333d2b36SAndroid Build Coastguard Worker	}
180*333d2b36SAndroid Build Coastguard Worker
181*333d2b36SAndroid Build Coastguard Worker	appendCharAndAdvance := func(c rune) {
182*333d2b36SAndroid Build Coastguard Worker		if c != EOF {
183*333d2b36SAndroid Build Coastguard Worker			word.appendString(string(c))
184*333d2b36SAndroid Build Coastguard Worker		}
185*333d2b36SAndroid Build Coastguard Worker		nextChar()
186*333d2b36SAndroid Build Coastguard Worker	}
187*333d2b36SAndroid Build Coastguard Worker
188*333d2b36SAndroid Build Coastguard Worker	nextChar()
189*333d2b36SAndroid Build Coastguard Worker	for ch != EOF {
190*333d2b36SAndroid Build Coastguard Worker		// Skip whitespace
191*333d2b36SAndroid Build Coastguard Worker		for ch == ' ' || ch == '\t' {
192*333d2b36SAndroid Build Coastguard Worker			nextChar()
193*333d2b36SAndroid Build Coastguard Worker		}
194*333d2b36SAndroid Build Coastguard Worker		if ch == EOS {
195*333d2b36SAndroid Build Coastguard Worker			// "... $(X)... " case. The current word should be empty.
196*333d2b36SAndroid Build Coastguard Worker			if !word.Empty() {
197*333d2b36SAndroid Build Coastguard Worker				panic(fmt.Errorf("%q: EOS while current word %q is not empty, iString=%d",
198*333d2b36SAndroid Build Coastguard Worker					ms.Dump(), word.Dump(), iString))
199*333d2b36SAndroid Build Coastguard Worker			}
200*333d2b36SAndroid Build Coastguard Worker			appendVariableAndAdvance()
201*333d2b36SAndroid Build Coastguard Worker		}
202*333d2b36SAndroid Build Coastguard Worker		// Copy word
203*333d2b36SAndroid Build Coastguard Worker		for ch != EOF {
204*333d2b36SAndroid Build Coastguard Worker			if ch == ' ' || ch == '\t' {
205*333d2b36SAndroid Build Coastguard Worker				words = append(words, word)
206*333d2b36SAndroid Build Coastguard Worker				word = SimpleMakeString("", ms.Pos())
207*333d2b36SAndroid Build Coastguard Worker				break
208*333d2b36SAndroid Build Coastguard Worker			}
209*333d2b36SAndroid Build Coastguard Worker			if ch == EOS {
210*333d2b36SAndroid Build Coastguard Worker				// "...a$(X)..." case. Append variable to the current word
211*333d2b36SAndroid Build Coastguard Worker				appendVariableAndAdvance()
212*333d2b36SAndroid Build Coastguard Worker			} else {
213*333d2b36SAndroid Build Coastguard Worker				if ch == '\\' {
214*333d2b36SAndroid Build Coastguard Worker					appendCharAndAdvance('\\')
215*333d2b36SAndroid Build Coastguard Worker				}
216*333d2b36SAndroid Build Coastguard Worker				appendCharAndAdvance(ch)
217*333d2b36SAndroid Build Coastguard Worker			}
218*333d2b36SAndroid Build Coastguard Worker		}
219*333d2b36SAndroid Build Coastguard Worker	}
220*333d2b36SAndroid Build Coastguard Worker	if !word.Empty() {
221*333d2b36SAndroid Build Coastguard Worker		words = append(words, word)
222*333d2b36SAndroid Build Coastguard Worker	}
223*333d2b36SAndroid Build Coastguard Worker	return words
224*333d2b36SAndroid Build Coastguard Worker}
225*333d2b36SAndroid Build Coastguard Worker
226*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) splitNFunc(n int, splitFunc func(s string, n int) []string) []*MakeString {
227*333d2b36SAndroid Build Coastguard Worker	ret := []*MakeString{}
228*333d2b36SAndroid Build Coastguard Worker
229*333d2b36SAndroid Build Coastguard Worker	curMs := SimpleMakeString("", ms.Pos())
230*333d2b36SAndroid Build Coastguard Worker
231*333d2b36SAndroid Build Coastguard Worker	var i int
232*333d2b36SAndroid Build Coastguard Worker	var s string
233*333d2b36SAndroid Build Coastguard Worker	for i, s = range ms.Strings {
234*333d2b36SAndroid Build Coastguard Worker		if n != 0 {
235*333d2b36SAndroid Build Coastguard Worker			split := splitFunc(s, n)
236*333d2b36SAndroid Build Coastguard Worker			if n != -1 {
237*333d2b36SAndroid Build Coastguard Worker				if len(split) > n || len(split) == 0 {
238*333d2b36SAndroid Build Coastguard Worker					panic("oops!")
239*333d2b36SAndroid Build Coastguard Worker				} else {
240*333d2b36SAndroid Build Coastguard Worker					n -= len(split) - 1
241*333d2b36SAndroid Build Coastguard Worker				}
242*333d2b36SAndroid Build Coastguard Worker			}
243*333d2b36SAndroid Build Coastguard Worker			curMs.appendString(split[0])
244*333d2b36SAndroid Build Coastguard Worker
245*333d2b36SAndroid Build Coastguard Worker			for _, r := range split[1:] {
246*333d2b36SAndroid Build Coastguard Worker				ret = append(ret, curMs)
247*333d2b36SAndroid Build Coastguard Worker				curMs = SimpleMakeString(r, ms.Pos())
248*333d2b36SAndroid Build Coastguard Worker			}
249*333d2b36SAndroid Build Coastguard Worker		} else {
250*333d2b36SAndroid Build Coastguard Worker			curMs.appendString(s)
251*333d2b36SAndroid Build Coastguard Worker		}
252*333d2b36SAndroid Build Coastguard Worker
253*333d2b36SAndroid Build Coastguard Worker		if i < len(ms.Strings)-1 {
254*333d2b36SAndroid Build Coastguard Worker			curMs.appendVariable(ms.Variables[i])
255*333d2b36SAndroid Build Coastguard Worker		}
256*333d2b36SAndroid Build Coastguard Worker	}
257*333d2b36SAndroid Build Coastguard Worker
258*333d2b36SAndroid Build Coastguard Worker	ret = append(ret, curMs)
259*333d2b36SAndroid Build Coastguard Worker	return ret
260*333d2b36SAndroid Build Coastguard Worker}
261*333d2b36SAndroid Build Coastguard Worker
262*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) TrimLeftSpaces() {
263*333d2b36SAndroid Build Coastguard Worker	l := len(ms.Strings[0])
264*333d2b36SAndroid Build Coastguard Worker	ms.Strings[0] = strings.TrimLeftFunc(ms.Strings[0], unicode.IsSpace)
265*333d2b36SAndroid Build Coastguard Worker	ms.StringPos += Pos(len(ms.Strings[0]) - l)
266*333d2b36SAndroid Build Coastguard Worker}
267*333d2b36SAndroid Build Coastguard Worker
268*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) TrimRightSpaces() {
269*333d2b36SAndroid Build Coastguard Worker	last := len(ms.Strings) - 1
270*333d2b36SAndroid Build Coastguard Worker	ms.Strings[last] = strings.TrimRightFunc(ms.Strings[last], unicode.IsSpace)
271*333d2b36SAndroid Build Coastguard Worker}
272*333d2b36SAndroid Build Coastguard Worker
273*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) TrimRightOne() {
274*333d2b36SAndroid Build Coastguard Worker	last := len(ms.Strings) - 1
275*333d2b36SAndroid Build Coastguard Worker	if len(ms.Strings[last]) > 1 {
276*333d2b36SAndroid Build Coastguard Worker		ms.Strings[last] = ms.Strings[last][0 : len(ms.Strings[last])-1]
277*333d2b36SAndroid Build Coastguard Worker	}
278*333d2b36SAndroid Build Coastguard Worker}
279*333d2b36SAndroid Build Coastguard Worker
280*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) EndsWith(ch rune) bool {
281*333d2b36SAndroid Build Coastguard Worker	s := ms.Strings[len(ms.Strings)-1]
282*333d2b36SAndroid Build Coastguard Worker	return len(s) > 0 && s[len(s)-1] == uint8(ch)
283*333d2b36SAndroid Build Coastguard Worker}
284*333d2b36SAndroid Build Coastguard Worker
285*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) ReplaceLiteral(input string, output string) {
286*333d2b36SAndroid Build Coastguard Worker	for i := range ms.Strings {
287*333d2b36SAndroid Build Coastguard Worker		ms.Strings[i] = strings.Replace(ms.Strings[i], input, output, -1)
288*333d2b36SAndroid Build Coastguard Worker	}
289*333d2b36SAndroid Build Coastguard Worker}
290*333d2b36SAndroid Build Coastguard Worker
291*333d2b36SAndroid Build Coastguard Worker// If MakeString is $(var) after trimming, returns var
292*333d2b36SAndroid Build Coastguard Workerfunc (ms *MakeString) SingleVariable() (*MakeString, bool) {
293*333d2b36SAndroid Build Coastguard Worker	if len(ms.Strings) != 2 || strings.TrimSpace(ms.Strings[0]) != "" ||
294*333d2b36SAndroid Build Coastguard Worker		strings.TrimSpace(ms.Strings[1]) != "" {
295*333d2b36SAndroid Build Coastguard Worker		return nil, false
296*333d2b36SAndroid Build Coastguard Worker	}
297*333d2b36SAndroid Build Coastguard Worker	return ms.Variables[0].Name, true
298*333d2b36SAndroid Build Coastguard Worker}
299*333d2b36SAndroid Build Coastguard Worker
300*333d2b36SAndroid Build Coastguard Workerfunc splitAnyN(s, sep string, n int) []string {
301*333d2b36SAndroid Build Coastguard Worker	ret := []string{}
302*333d2b36SAndroid Build Coastguard Worker	for n == -1 || n > 1 {
303*333d2b36SAndroid Build Coastguard Worker		index := strings.IndexAny(s, sep)
304*333d2b36SAndroid Build Coastguard Worker		if index >= 0 {
305*333d2b36SAndroid Build Coastguard Worker			ret = append(ret, s[0:index])
306*333d2b36SAndroid Build Coastguard Worker			s = s[index+1:]
307*333d2b36SAndroid Build Coastguard Worker			if n > 0 {
308*333d2b36SAndroid Build Coastguard Worker				n--
309*333d2b36SAndroid Build Coastguard Worker			}
310*333d2b36SAndroid Build Coastguard Worker		} else {
311*333d2b36SAndroid Build Coastguard Worker			break
312*333d2b36SAndroid Build Coastguard Worker		}
313*333d2b36SAndroid Build Coastguard Worker	}
314*333d2b36SAndroid Build Coastguard Worker	ret = append(ret, s)
315*333d2b36SAndroid Build Coastguard Worker	return ret
316*333d2b36SAndroid Build Coastguard Worker}
317*333d2b36SAndroid Build Coastguard Worker
318*333d2b36SAndroid Build Coastguard Workerfunc unescape(s string) string {
319*333d2b36SAndroid Build Coastguard Worker	ret := ""
320*333d2b36SAndroid Build Coastguard Worker	for {
321*333d2b36SAndroid Build Coastguard Worker		index := strings.IndexByte(s, '\\')
322*333d2b36SAndroid Build Coastguard Worker		if index < 0 {
323*333d2b36SAndroid Build Coastguard Worker			break
324*333d2b36SAndroid Build Coastguard Worker		}
325*333d2b36SAndroid Build Coastguard Worker
326*333d2b36SAndroid Build Coastguard Worker		if index+1 == len(s) {
327*333d2b36SAndroid Build Coastguard Worker			break
328*333d2b36SAndroid Build Coastguard Worker		}
329*333d2b36SAndroid Build Coastguard Worker
330*333d2b36SAndroid Build Coastguard Worker		switch s[index+1] {
331*333d2b36SAndroid Build Coastguard Worker		case ' ', '\\', '#', ':', '*', '[', '|', '\t', '\n', '\r':
332*333d2b36SAndroid Build Coastguard Worker			ret += s[:index] + s[index+1:index+2]
333*333d2b36SAndroid Build Coastguard Worker		default:
334*333d2b36SAndroid Build Coastguard Worker			ret += s[:index+2]
335*333d2b36SAndroid Build Coastguard Worker		}
336*333d2b36SAndroid Build Coastguard Worker		s = s[index+2:]
337*333d2b36SAndroid Build Coastguard Worker	}
338*333d2b36SAndroid Build Coastguard Worker	return ret + s
339*333d2b36SAndroid Build Coastguard Worker}
340