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