xref: /aosp_15_r20/build/blueprint/ninja_writer.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2014 Google Inc. All rights reserved.
2*1fa6dee9SAndroid Build Coastguard Worker//
3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*1fa6dee9SAndroid Build Coastguard Worker//
7*1fa6dee9SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*1fa6dee9SAndroid Build Coastguard Worker//
9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License.
14*1fa6dee9SAndroid Build Coastguard Worker
15*1fa6dee9SAndroid Build Coastguard Workerpackage blueprint
16*1fa6dee9SAndroid Build Coastguard Worker
17*1fa6dee9SAndroid Build Coastguard Workerimport (
18*1fa6dee9SAndroid Build Coastguard Worker	"io"
19*1fa6dee9SAndroid Build Coastguard Worker	"strings"
20*1fa6dee9SAndroid Build Coastguard Worker	"unicode"
21*1fa6dee9SAndroid Build Coastguard Worker)
22*1fa6dee9SAndroid Build Coastguard Worker
23*1fa6dee9SAndroid Build Coastguard Workerconst (
24*1fa6dee9SAndroid Build Coastguard Worker	indentWidth    = 4
25*1fa6dee9SAndroid Build Coastguard Worker	maxIndentDepth = 2
26*1fa6dee9SAndroid Build Coastguard Worker	lineWidth      = 80
27*1fa6dee9SAndroid Build Coastguard Worker)
28*1fa6dee9SAndroid Build Coastguard Worker
29*1fa6dee9SAndroid Build Coastguard Workervar indentString = strings.Repeat(" ", indentWidth*maxIndentDepth)
30*1fa6dee9SAndroid Build Coastguard Worker
31*1fa6dee9SAndroid Build Coastguard Workertype StringWriterWriter interface {
32*1fa6dee9SAndroid Build Coastguard Worker	io.StringWriter
33*1fa6dee9SAndroid Build Coastguard Worker	io.Writer
34*1fa6dee9SAndroid Build Coastguard Worker}
35*1fa6dee9SAndroid Build Coastguard Worker
36*1fa6dee9SAndroid Build Coastguard Workertype ninjaWriter struct {
37*1fa6dee9SAndroid Build Coastguard Worker	writer StringWriterWriter
38*1fa6dee9SAndroid Build Coastguard Worker
39*1fa6dee9SAndroid Build Coastguard Worker	justDidBlankLine bool // true if the last operation was a BlankLine
40*1fa6dee9SAndroid Build Coastguard Worker}
41*1fa6dee9SAndroid Build Coastguard Worker
42*1fa6dee9SAndroid Build Coastguard Workerfunc newNinjaWriter(writer StringWriterWriter) *ninjaWriter {
43*1fa6dee9SAndroid Build Coastguard Worker	return &ninjaWriter{
44*1fa6dee9SAndroid Build Coastguard Worker		writer: writer,
45*1fa6dee9SAndroid Build Coastguard Worker	}
46*1fa6dee9SAndroid Build Coastguard Worker}
47*1fa6dee9SAndroid Build Coastguard Worker
48*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriter) Comment(comment string) error {
49*1fa6dee9SAndroid Build Coastguard Worker	n.justDidBlankLine = false
50*1fa6dee9SAndroid Build Coastguard Worker
51*1fa6dee9SAndroid Build Coastguard Worker	const lineHeaderLen = len("# ")
52*1fa6dee9SAndroid Build Coastguard Worker	const maxLineLen = lineWidth - lineHeaderLen
53*1fa6dee9SAndroid Build Coastguard Worker
54*1fa6dee9SAndroid Build Coastguard Worker	var lineStart, lastSplitPoint int
55*1fa6dee9SAndroid Build Coastguard Worker	for i, r := range comment {
56*1fa6dee9SAndroid Build Coastguard Worker		if unicode.IsSpace(r) {
57*1fa6dee9SAndroid Build Coastguard Worker			// We know we can safely split the line here.
58*1fa6dee9SAndroid Build Coastguard Worker			lastSplitPoint = i + 1
59*1fa6dee9SAndroid Build Coastguard Worker		}
60*1fa6dee9SAndroid Build Coastguard Worker
61*1fa6dee9SAndroid Build Coastguard Worker		var line string
62*1fa6dee9SAndroid Build Coastguard Worker		var writeLine bool
63*1fa6dee9SAndroid Build Coastguard Worker		switch {
64*1fa6dee9SAndroid Build Coastguard Worker		case r == '\n':
65*1fa6dee9SAndroid Build Coastguard Worker			// Output the line without trimming the left so as to allow comments
66*1fa6dee9SAndroid Build Coastguard Worker			// to contain their own indentation.
67*1fa6dee9SAndroid Build Coastguard Worker			line = strings.TrimRightFunc(comment[lineStart:i], unicode.IsSpace)
68*1fa6dee9SAndroid Build Coastguard Worker			writeLine = true
69*1fa6dee9SAndroid Build Coastguard Worker
70*1fa6dee9SAndroid Build Coastguard Worker		case (i-lineStart > maxLineLen) && (lastSplitPoint > lineStart):
71*1fa6dee9SAndroid Build Coastguard Worker			// The line has grown too long and is splittable.  Split it at the
72*1fa6dee9SAndroid Build Coastguard Worker			// last split point.
73*1fa6dee9SAndroid Build Coastguard Worker			line = strings.TrimSpace(comment[lineStart:lastSplitPoint])
74*1fa6dee9SAndroid Build Coastguard Worker			writeLine = true
75*1fa6dee9SAndroid Build Coastguard Worker		}
76*1fa6dee9SAndroid Build Coastguard Worker
77*1fa6dee9SAndroid Build Coastguard Worker		if writeLine {
78*1fa6dee9SAndroid Build Coastguard Worker			line = strings.TrimSpace("# "+line) + "\n"
79*1fa6dee9SAndroid Build Coastguard Worker			_, err := n.writer.WriteString(line)
80*1fa6dee9SAndroid Build Coastguard Worker			if err != nil {
81*1fa6dee9SAndroid Build Coastguard Worker				return err
82*1fa6dee9SAndroid Build Coastguard Worker			}
83*1fa6dee9SAndroid Build Coastguard Worker			lineStart = lastSplitPoint
84*1fa6dee9SAndroid Build Coastguard Worker		}
85*1fa6dee9SAndroid Build Coastguard Worker	}
86*1fa6dee9SAndroid Build Coastguard Worker
87*1fa6dee9SAndroid Build Coastguard Worker	if lineStart != len(comment) {
88*1fa6dee9SAndroid Build Coastguard Worker		line := strings.TrimSpace(comment[lineStart:])
89*1fa6dee9SAndroid Build Coastguard Worker		_, err := n.writer.WriteString("# ")
90*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
91*1fa6dee9SAndroid Build Coastguard Worker			return err
92*1fa6dee9SAndroid Build Coastguard Worker		}
93*1fa6dee9SAndroid Build Coastguard Worker		_, err = n.writer.WriteString(line)
94*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
95*1fa6dee9SAndroid Build Coastguard Worker			return err
96*1fa6dee9SAndroid Build Coastguard Worker		}
97*1fa6dee9SAndroid Build Coastguard Worker		_, err = n.writer.WriteString("\n")
98*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
99*1fa6dee9SAndroid Build Coastguard Worker			return err
100*1fa6dee9SAndroid Build Coastguard Worker		}
101*1fa6dee9SAndroid Build Coastguard Worker	}
102*1fa6dee9SAndroid Build Coastguard Worker
103*1fa6dee9SAndroid Build Coastguard Worker	return nil
104*1fa6dee9SAndroid Build Coastguard Worker}
105*1fa6dee9SAndroid Build Coastguard Worker
106*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriter) Pool(name string) error {
107*1fa6dee9SAndroid Build Coastguard Worker	n.justDidBlankLine = false
108*1fa6dee9SAndroid Build Coastguard Worker	return n.writeStatement("pool", name)
109*1fa6dee9SAndroid Build Coastguard Worker}
110*1fa6dee9SAndroid Build Coastguard Worker
111*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriter) Rule(name string) error {
112*1fa6dee9SAndroid Build Coastguard Worker	n.justDidBlankLine = false
113*1fa6dee9SAndroid Build Coastguard Worker	return n.writeStatement("rule", name)
114*1fa6dee9SAndroid Build Coastguard Worker}
115*1fa6dee9SAndroid Build Coastguard Worker
116*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts,
117*1fa6dee9SAndroid Build Coastguard Worker	explicitDeps, implicitDeps, orderOnlyDeps, validations []*ninjaString,
118*1fa6dee9SAndroid Build Coastguard Worker	outputStrings, implicitOutStrings, explicitDepStrings,
119*1fa6dee9SAndroid Build Coastguard Worker	implicitDepStrings, orderOnlyDepStrings, validationStrings []string,
120*1fa6dee9SAndroid Build Coastguard Worker	nameTracker *nameTracker) error {
121*1fa6dee9SAndroid Build Coastguard Worker
122*1fa6dee9SAndroid Build Coastguard Worker	n.justDidBlankLine = false
123*1fa6dee9SAndroid Build Coastguard Worker
124*1fa6dee9SAndroid Build Coastguard Worker	const lineWrapLen = len(" $")
125*1fa6dee9SAndroid Build Coastguard Worker	const maxLineLen = lineWidth - lineWrapLen
126*1fa6dee9SAndroid Build Coastguard Worker
127*1fa6dee9SAndroid Build Coastguard Worker	wrapper := &ninjaWriterWithWrap{
128*1fa6dee9SAndroid Build Coastguard Worker		ninjaWriter: n,
129*1fa6dee9SAndroid Build Coastguard Worker		maxLineLen:  maxLineLen,
130*1fa6dee9SAndroid Build Coastguard Worker	}
131*1fa6dee9SAndroid Build Coastguard Worker
132*1fa6dee9SAndroid Build Coastguard Worker	if comment != "" {
133*1fa6dee9SAndroid Build Coastguard Worker		err := wrapper.Comment(comment)
134*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
135*1fa6dee9SAndroid Build Coastguard Worker			return err
136*1fa6dee9SAndroid Build Coastguard Worker		}
137*1fa6dee9SAndroid Build Coastguard Worker	}
138*1fa6dee9SAndroid Build Coastguard Worker
139*1fa6dee9SAndroid Build Coastguard Worker	wrapper.WriteString("build")
140*1fa6dee9SAndroid Build Coastguard Worker
141*1fa6dee9SAndroid Build Coastguard Worker	for _, output := range outputStrings {
142*1fa6dee9SAndroid Build Coastguard Worker		wrapper.Space()
143*1fa6dee9SAndroid Build Coastguard Worker		outputEscaper.WriteString(wrapper, output)
144*1fa6dee9SAndroid Build Coastguard Worker	}
145*1fa6dee9SAndroid Build Coastguard Worker	for _, output := range outputs {
146*1fa6dee9SAndroid Build Coastguard Worker		wrapper.Space()
147*1fa6dee9SAndroid Build Coastguard Worker		output.ValueWithEscaper(wrapper, nameTracker, outputEscaper)
148*1fa6dee9SAndroid Build Coastguard Worker	}
149*1fa6dee9SAndroid Build Coastguard Worker
150*1fa6dee9SAndroid Build Coastguard Worker	if len(implicitOuts) > 0 || len(implicitOutStrings) > 0 {
151*1fa6dee9SAndroid Build Coastguard Worker		wrapper.WriteStringWithSpace("|")
152*1fa6dee9SAndroid Build Coastguard Worker
153*1fa6dee9SAndroid Build Coastguard Worker		for _, out := range implicitOutStrings {
154*1fa6dee9SAndroid Build Coastguard Worker			wrapper.Space()
155*1fa6dee9SAndroid Build Coastguard Worker			outputEscaper.WriteString(wrapper, out)
156*1fa6dee9SAndroid Build Coastguard Worker		}
157*1fa6dee9SAndroid Build Coastguard Worker		for _, out := range implicitOuts {
158*1fa6dee9SAndroid Build Coastguard Worker			wrapper.Space()
159*1fa6dee9SAndroid Build Coastguard Worker			out.ValueWithEscaper(wrapper, nameTracker, outputEscaper)
160*1fa6dee9SAndroid Build Coastguard Worker		}
161*1fa6dee9SAndroid Build Coastguard Worker	}
162*1fa6dee9SAndroid Build Coastguard Worker
163*1fa6dee9SAndroid Build Coastguard Worker	wrapper.WriteString(":")
164*1fa6dee9SAndroid Build Coastguard Worker
165*1fa6dee9SAndroid Build Coastguard Worker	wrapper.WriteStringWithSpace(rule)
166*1fa6dee9SAndroid Build Coastguard Worker
167*1fa6dee9SAndroid Build Coastguard Worker	for _, dep := range explicitDepStrings {
168*1fa6dee9SAndroid Build Coastguard Worker		wrapper.Space()
169*1fa6dee9SAndroid Build Coastguard Worker		inputEscaper.WriteString(wrapper, dep)
170*1fa6dee9SAndroid Build Coastguard Worker	}
171*1fa6dee9SAndroid Build Coastguard Worker	for _, dep := range explicitDeps {
172*1fa6dee9SAndroid Build Coastguard Worker		wrapper.Space()
173*1fa6dee9SAndroid Build Coastguard Worker		dep.ValueWithEscaper(wrapper, nameTracker, inputEscaper)
174*1fa6dee9SAndroid Build Coastguard Worker	}
175*1fa6dee9SAndroid Build Coastguard Worker
176*1fa6dee9SAndroid Build Coastguard Worker	if len(implicitDeps) > 0 || len(implicitDepStrings) > 0 {
177*1fa6dee9SAndroid Build Coastguard Worker		wrapper.WriteStringWithSpace("|")
178*1fa6dee9SAndroid Build Coastguard Worker
179*1fa6dee9SAndroid Build Coastguard Worker		for _, dep := range implicitDepStrings {
180*1fa6dee9SAndroid Build Coastguard Worker			wrapper.Space()
181*1fa6dee9SAndroid Build Coastguard Worker			inputEscaper.WriteString(wrapper, dep)
182*1fa6dee9SAndroid Build Coastguard Worker		}
183*1fa6dee9SAndroid Build Coastguard Worker		for _, dep := range implicitDeps {
184*1fa6dee9SAndroid Build Coastguard Worker			wrapper.Space()
185*1fa6dee9SAndroid Build Coastguard Worker			dep.ValueWithEscaper(wrapper, nameTracker, inputEscaper)
186*1fa6dee9SAndroid Build Coastguard Worker		}
187*1fa6dee9SAndroid Build Coastguard Worker	}
188*1fa6dee9SAndroid Build Coastguard Worker
189*1fa6dee9SAndroid Build Coastguard Worker	if len(orderOnlyDeps) > 0 || len(orderOnlyDepStrings) > 0 {
190*1fa6dee9SAndroid Build Coastguard Worker		wrapper.WriteStringWithSpace("||")
191*1fa6dee9SAndroid Build Coastguard Worker
192*1fa6dee9SAndroid Build Coastguard Worker		for _, dep := range orderOnlyDepStrings {
193*1fa6dee9SAndroid Build Coastguard Worker			wrapper.Space()
194*1fa6dee9SAndroid Build Coastguard Worker			inputEscaper.WriteString(wrapper, dep)
195*1fa6dee9SAndroid Build Coastguard Worker		}
196*1fa6dee9SAndroid Build Coastguard Worker		for _, dep := range orderOnlyDeps {
197*1fa6dee9SAndroid Build Coastguard Worker			wrapper.Space()
198*1fa6dee9SAndroid Build Coastguard Worker			dep.ValueWithEscaper(wrapper, nameTracker, inputEscaper)
199*1fa6dee9SAndroid Build Coastguard Worker		}
200*1fa6dee9SAndroid Build Coastguard Worker	}
201*1fa6dee9SAndroid Build Coastguard Worker
202*1fa6dee9SAndroid Build Coastguard Worker	if len(validations) > 0 || len(validationStrings) > 0 {
203*1fa6dee9SAndroid Build Coastguard Worker		wrapper.WriteStringWithSpace("|@")
204*1fa6dee9SAndroid Build Coastguard Worker
205*1fa6dee9SAndroid Build Coastguard Worker		for _, dep := range validationStrings {
206*1fa6dee9SAndroid Build Coastguard Worker			wrapper.Space()
207*1fa6dee9SAndroid Build Coastguard Worker			inputEscaper.WriteString(wrapper, dep)
208*1fa6dee9SAndroid Build Coastguard Worker		}
209*1fa6dee9SAndroid Build Coastguard Worker		for _, dep := range validations {
210*1fa6dee9SAndroid Build Coastguard Worker			wrapper.Space()
211*1fa6dee9SAndroid Build Coastguard Worker			dep.ValueWithEscaper(wrapper, nameTracker, inputEscaper)
212*1fa6dee9SAndroid Build Coastguard Worker		}
213*1fa6dee9SAndroid Build Coastguard Worker	}
214*1fa6dee9SAndroid Build Coastguard Worker
215*1fa6dee9SAndroid Build Coastguard Worker	return wrapper.Flush()
216*1fa6dee9SAndroid Build Coastguard Worker}
217*1fa6dee9SAndroid Build Coastguard Worker
218*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriter) Assign(name, value string) error {
219*1fa6dee9SAndroid Build Coastguard Worker	n.justDidBlankLine = false
220*1fa6dee9SAndroid Build Coastguard Worker	_, err := n.writer.WriteString(name)
221*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
222*1fa6dee9SAndroid Build Coastguard Worker		return err
223*1fa6dee9SAndroid Build Coastguard Worker	}
224*1fa6dee9SAndroid Build Coastguard Worker	_, err = n.writer.WriteString(" = ")
225*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
226*1fa6dee9SAndroid Build Coastguard Worker		return err
227*1fa6dee9SAndroid Build Coastguard Worker	}
228*1fa6dee9SAndroid Build Coastguard Worker	_, err = n.writer.WriteString(value)
229*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
230*1fa6dee9SAndroid Build Coastguard Worker		return err
231*1fa6dee9SAndroid Build Coastguard Worker	}
232*1fa6dee9SAndroid Build Coastguard Worker	_, err = n.writer.WriteString("\n")
233*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
234*1fa6dee9SAndroid Build Coastguard Worker		return err
235*1fa6dee9SAndroid Build Coastguard Worker	}
236*1fa6dee9SAndroid Build Coastguard Worker	return nil
237*1fa6dee9SAndroid Build Coastguard Worker}
238*1fa6dee9SAndroid Build Coastguard Worker
239*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriter) ScopedAssign(name, value string) error {
240*1fa6dee9SAndroid Build Coastguard Worker	n.justDidBlankLine = false
241*1fa6dee9SAndroid Build Coastguard Worker	_, err := n.writer.WriteString(indentString[:indentWidth])
242*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
243*1fa6dee9SAndroid Build Coastguard Worker		return err
244*1fa6dee9SAndroid Build Coastguard Worker	}
245*1fa6dee9SAndroid Build Coastguard Worker	_, err = n.writer.WriteString(name)
246*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
247*1fa6dee9SAndroid Build Coastguard Worker		return err
248*1fa6dee9SAndroid Build Coastguard Worker	}
249*1fa6dee9SAndroid Build Coastguard Worker	_, err = n.writer.WriteString(" = ")
250*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
251*1fa6dee9SAndroid Build Coastguard Worker		return err
252*1fa6dee9SAndroid Build Coastguard Worker	}
253*1fa6dee9SAndroid Build Coastguard Worker	_, err = n.writer.WriteString(value)
254*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
255*1fa6dee9SAndroid Build Coastguard Worker		return err
256*1fa6dee9SAndroid Build Coastguard Worker	}
257*1fa6dee9SAndroid Build Coastguard Worker	_, err = n.writer.WriteString("\n")
258*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
259*1fa6dee9SAndroid Build Coastguard Worker		return err
260*1fa6dee9SAndroid Build Coastguard Worker	}
261*1fa6dee9SAndroid Build Coastguard Worker	return nil
262*1fa6dee9SAndroid Build Coastguard Worker}
263*1fa6dee9SAndroid Build Coastguard Worker
264*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriter) Default(nameTracker *nameTracker, targets []*ninjaString, targetStrings []string) error {
265*1fa6dee9SAndroid Build Coastguard Worker	n.justDidBlankLine = false
266*1fa6dee9SAndroid Build Coastguard Worker
267*1fa6dee9SAndroid Build Coastguard Worker	const lineWrapLen = len(" $")
268*1fa6dee9SAndroid Build Coastguard Worker	const maxLineLen = lineWidth - lineWrapLen
269*1fa6dee9SAndroid Build Coastguard Worker
270*1fa6dee9SAndroid Build Coastguard Worker	wrapper := &ninjaWriterWithWrap{
271*1fa6dee9SAndroid Build Coastguard Worker		ninjaWriter: n,
272*1fa6dee9SAndroid Build Coastguard Worker		maxLineLen:  maxLineLen,
273*1fa6dee9SAndroid Build Coastguard Worker	}
274*1fa6dee9SAndroid Build Coastguard Worker
275*1fa6dee9SAndroid Build Coastguard Worker	wrapper.WriteString("default")
276*1fa6dee9SAndroid Build Coastguard Worker
277*1fa6dee9SAndroid Build Coastguard Worker	for _, target := range targetStrings {
278*1fa6dee9SAndroid Build Coastguard Worker		wrapper.Space()
279*1fa6dee9SAndroid Build Coastguard Worker		outputEscaper.WriteString(wrapper, target)
280*1fa6dee9SAndroid Build Coastguard Worker	}
281*1fa6dee9SAndroid Build Coastguard Worker	for _, target := range targets {
282*1fa6dee9SAndroid Build Coastguard Worker		wrapper.Space()
283*1fa6dee9SAndroid Build Coastguard Worker		target.ValueWithEscaper(wrapper, nameTracker, outputEscaper)
284*1fa6dee9SAndroid Build Coastguard Worker	}
285*1fa6dee9SAndroid Build Coastguard Worker
286*1fa6dee9SAndroid Build Coastguard Worker	return wrapper.Flush()
287*1fa6dee9SAndroid Build Coastguard Worker}
288*1fa6dee9SAndroid Build Coastguard Worker
289*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriter) Subninja(file string) error {
290*1fa6dee9SAndroid Build Coastguard Worker	n.justDidBlankLine = false
291*1fa6dee9SAndroid Build Coastguard Worker	return n.writeStatement("subninja", file)
292*1fa6dee9SAndroid Build Coastguard Worker}
293*1fa6dee9SAndroid Build Coastguard Worker
294*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriter) BlankLine() (err error) {
295*1fa6dee9SAndroid Build Coastguard Worker	// We don't output multiple blank lines in a row.
296*1fa6dee9SAndroid Build Coastguard Worker	if !n.justDidBlankLine {
297*1fa6dee9SAndroid Build Coastguard Worker		n.justDidBlankLine = true
298*1fa6dee9SAndroid Build Coastguard Worker		_, err = n.writer.WriteString("\n")
299*1fa6dee9SAndroid Build Coastguard Worker	}
300*1fa6dee9SAndroid Build Coastguard Worker	return err
301*1fa6dee9SAndroid Build Coastguard Worker}
302*1fa6dee9SAndroid Build Coastguard Worker
303*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriter) writeStatement(directive, name string) error {
304*1fa6dee9SAndroid Build Coastguard Worker	_, err := n.writer.WriteString(directive + " ")
305*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
306*1fa6dee9SAndroid Build Coastguard Worker		return err
307*1fa6dee9SAndroid Build Coastguard Worker	}
308*1fa6dee9SAndroid Build Coastguard Worker	_, err = n.writer.WriteString(name)
309*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
310*1fa6dee9SAndroid Build Coastguard Worker		return err
311*1fa6dee9SAndroid Build Coastguard Worker	}
312*1fa6dee9SAndroid Build Coastguard Worker	_, err = n.writer.WriteString("\n")
313*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
314*1fa6dee9SAndroid Build Coastguard Worker		return err
315*1fa6dee9SAndroid Build Coastguard Worker	}
316*1fa6dee9SAndroid Build Coastguard Worker	return nil
317*1fa6dee9SAndroid Build Coastguard Worker}
318*1fa6dee9SAndroid Build Coastguard Worker
319*1fa6dee9SAndroid Build Coastguard Worker// ninjaWriterWithWrap is an io.StringWriter that writes through to a ninjaWriter, but supports
320*1fa6dee9SAndroid Build Coastguard Worker// user-readable line wrapping on boundaries when ninjaWriterWithWrap.Space is called.
321*1fa6dee9SAndroid Build Coastguard Worker// It collects incoming calls to WriteString until either the line length is exceeded, in which case
322*1fa6dee9SAndroid Build Coastguard Worker// it inserts a wrap before the pending strings and then writes them, or the next call to Space, in
323*1fa6dee9SAndroid Build Coastguard Worker// which case it writes out the pending strings.
324*1fa6dee9SAndroid Build Coastguard Worker//
325*1fa6dee9SAndroid Build Coastguard Worker// WriteString never returns an error, all errors are held until Flush is called.  Once an error has
326*1fa6dee9SAndroid Build Coastguard Worker// occurred all writes become noops.
327*1fa6dee9SAndroid Build Coastguard Workertype ninjaWriterWithWrap struct {
328*1fa6dee9SAndroid Build Coastguard Worker	*ninjaWriter
329*1fa6dee9SAndroid Build Coastguard Worker	// pending lists the strings that have been written since the last call to Space.
330*1fa6dee9SAndroid Build Coastguard Worker	pending []string
331*1fa6dee9SAndroid Build Coastguard Worker
332*1fa6dee9SAndroid Build Coastguard Worker	// pendingLen accumulates the lengths of the strings in pending.
333*1fa6dee9SAndroid Build Coastguard Worker	pendingLen int
334*1fa6dee9SAndroid Build Coastguard Worker
335*1fa6dee9SAndroid Build Coastguard Worker	// lineLen accumulates the number of bytes on the current line.
336*1fa6dee9SAndroid Build Coastguard Worker	lineLen int
337*1fa6dee9SAndroid Build Coastguard Worker
338*1fa6dee9SAndroid Build Coastguard Worker	// maxLineLen is the length of the line before wrapping.
339*1fa6dee9SAndroid Build Coastguard Worker	maxLineLen int
340*1fa6dee9SAndroid Build Coastguard Worker
341*1fa6dee9SAndroid Build Coastguard Worker	// space is true if the strings in pending should be preceded by a space.
342*1fa6dee9SAndroid Build Coastguard Worker	space bool
343*1fa6dee9SAndroid Build Coastguard Worker
344*1fa6dee9SAndroid Build Coastguard Worker	// err holds any error that has occurred to return in Flush.
345*1fa6dee9SAndroid Build Coastguard Worker	err error
346*1fa6dee9SAndroid Build Coastguard Worker}
347*1fa6dee9SAndroid Build Coastguard Worker
348*1fa6dee9SAndroid Build Coastguard Worker// WriteString writes the string to buffer, wrapping on a previous Space call if necessary.
349*1fa6dee9SAndroid Build Coastguard Worker// It never returns an error, all errors are held until Flush is called.
350*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriterWithWrap) WriteString(s string) (written int, noError error) {
351*1fa6dee9SAndroid Build Coastguard Worker	// Always return the full length of the string and a nil error.
352*1fa6dee9SAndroid Build Coastguard Worker	// ninjaWriterWithWrap doesn't return errors to the caller, it saves them until Flush()
353*1fa6dee9SAndroid Build Coastguard Worker	written = len(s)
354*1fa6dee9SAndroid Build Coastguard Worker
355*1fa6dee9SAndroid Build Coastguard Worker	if n.err != nil {
356*1fa6dee9SAndroid Build Coastguard Worker		return
357*1fa6dee9SAndroid Build Coastguard Worker	}
358*1fa6dee9SAndroid Build Coastguard Worker
359*1fa6dee9SAndroid Build Coastguard Worker	const spaceLen = 1
360*1fa6dee9SAndroid Build Coastguard Worker	if !n.space {
361*1fa6dee9SAndroid Build Coastguard Worker		// No space is pending, so a line wrap can't be inserted before this, so just write
362*1fa6dee9SAndroid Build Coastguard Worker		// the string.
363*1fa6dee9SAndroid Build Coastguard Worker		n.lineLen += len(s)
364*1fa6dee9SAndroid Build Coastguard Worker		_, n.err = n.writer.WriteString(s)
365*1fa6dee9SAndroid Build Coastguard Worker	} else if n.lineLen+len(s)+spaceLen > n.maxLineLen {
366*1fa6dee9SAndroid Build Coastguard Worker		// A space is pending, and the pending strings plus the current string would exceed the
367*1fa6dee9SAndroid Build Coastguard Worker		// maximum line length.  Wrap and indent before the pending space and strings, then write
368*1fa6dee9SAndroid Build Coastguard Worker		// the pending and current strings.
369*1fa6dee9SAndroid Build Coastguard Worker		_, n.err = n.writer.WriteString(" $\n")
370*1fa6dee9SAndroid Build Coastguard Worker		if n.err != nil {
371*1fa6dee9SAndroid Build Coastguard Worker			return
372*1fa6dee9SAndroid Build Coastguard Worker		}
373*1fa6dee9SAndroid Build Coastguard Worker		_, n.err = n.writer.WriteString(indentString[:indentWidth*2])
374*1fa6dee9SAndroid Build Coastguard Worker		if n.err != nil {
375*1fa6dee9SAndroid Build Coastguard Worker			return
376*1fa6dee9SAndroid Build Coastguard Worker		}
377*1fa6dee9SAndroid Build Coastguard Worker		n.lineLen = indentWidth*2 + n.pendingLen
378*1fa6dee9SAndroid Build Coastguard Worker		s = strings.TrimLeftFunc(s, unicode.IsSpace)
379*1fa6dee9SAndroid Build Coastguard Worker		n.pending = append(n.pending, s)
380*1fa6dee9SAndroid Build Coastguard Worker		n.lineLen += len(s)
381*1fa6dee9SAndroid Build Coastguard Worker		n.writePending()
382*1fa6dee9SAndroid Build Coastguard Worker
383*1fa6dee9SAndroid Build Coastguard Worker		n.space = false
384*1fa6dee9SAndroid Build Coastguard Worker	} else {
385*1fa6dee9SAndroid Build Coastguard Worker		// A space is pending but the current string would not reach the maximum line length,
386*1fa6dee9SAndroid Build Coastguard Worker		// add it to the pending list.
387*1fa6dee9SAndroid Build Coastguard Worker		n.pending = append(n.pending, s)
388*1fa6dee9SAndroid Build Coastguard Worker		n.pendingLen += len(s)
389*1fa6dee9SAndroid Build Coastguard Worker		n.lineLen += len(s)
390*1fa6dee9SAndroid Build Coastguard Worker	}
391*1fa6dee9SAndroid Build Coastguard Worker
392*1fa6dee9SAndroid Build Coastguard Worker	return
393*1fa6dee9SAndroid Build Coastguard Worker}
394*1fa6dee9SAndroid Build Coastguard Worker
395*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriterWithWrap) Write(p []byte) (written int, noError error) {
396*1fa6dee9SAndroid Build Coastguard Worker	// Write is rarely used, implement it via WriteString.
397*1fa6dee9SAndroid Build Coastguard Worker	return n.WriteString(string(p))
398*1fa6dee9SAndroid Build Coastguard Worker}
399*1fa6dee9SAndroid Build Coastguard Worker
400*1fa6dee9SAndroid Build Coastguard Worker// Space inserts a space that is also a possible wrapping point into the string.
401*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriterWithWrap) Space() {
402*1fa6dee9SAndroid Build Coastguard Worker	if n.err != nil {
403*1fa6dee9SAndroid Build Coastguard Worker		return
404*1fa6dee9SAndroid Build Coastguard Worker	}
405*1fa6dee9SAndroid Build Coastguard Worker	if n.space {
406*1fa6dee9SAndroid Build Coastguard Worker		// A space was already pending, and the space plus any strings written after the space did
407*1fa6dee9SAndroid Build Coastguard Worker		// not reach the maxmimum line length, so write out the old space and pending strings.
408*1fa6dee9SAndroid Build Coastguard Worker		_, n.err = n.writer.WriteString(" ")
409*1fa6dee9SAndroid Build Coastguard Worker		n.lineLen++
410*1fa6dee9SAndroid Build Coastguard Worker		n.writePending()
411*1fa6dee9SAndroid Build Coastguard Worker	}
412*1fa6dee9SAndroid Build Coastguard Worker	n.space = true
413*1fa6dee9SAndroid Build Coastguard Worker}
414*1fa6dee9SAndroid Build Coastguard Worker
415*1fa6dee9SAndroid Build Coastguard Worker// writePending writes out all the strings stored in pending and resets it.
416*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriterWithWrap) writePending() {
417*1fa6dee9SAndroid Build Coastguard Worker	if n.err != nil {
418*1fa6dee9SAndroid Build Coastguard Worker		return
419*1fa6dee9SAndroid Build Coastguard Worker	}
420*1fa6dee9SAndroid Build Coastguard Worker	for _, pending := range n.pending {
421*1fa6dee9SAndroid Build Coastguard Worker		_, n.err = n.writer.WriteString(pending)
422*1fa6dee9SAndroid Build Coastguard Worker		if n.err != nil {
423*1fa6dee9SAndroid Build Coastguard Worker			return
424*1fa6dee9SAndroid Build Coastguard Worker		}
425*1fa6dee9SAndroid Build Coastguard Worker	}
426*1fa6dee9SAndroid Build Coastguard Worker	// Reset the length of pending back to 0 without reducing its capacity to avoid reallocating
427*1fa6dee9SAndroid Build Coastguard Worker	// the backing array.
428*1fa6dee9SAndroid Build Coastguard Worker	n.pending = n.pending[:0]
429*1fa6dee9SAndroid Build Coastguard Worker	n.pendingLen = 0
430*1fa6dee9SAndroid Build Coastguard Worker}
431*1fa6dee9SAndroid Build Coastguard Worker
432*1fa6dee9SAndroid Build Coastguard Worker// WriteStringWithSpace is a helper that calls Space and WriteString.
433*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriterWithWrap) WriteStringWithSpace(s string) {
434*1fa6dee9SAndroid Build Coastguard Worker	n.Space()
435*1fa6dee9SAndroid Build Coastguard Worker	_, _ = n.WriteString(s)
436*1fa6dee9SAndroid Build Coastguard Worker}
437*1fa6dee9SAndroid Build Coastguard Worker
438*1fa6dee9SAndroid Build Coastguard Worker// Flush writes out any pending space or strings and then a newline.  It also returns any errors
439*1fa6dee9SAndroid Build Coastguard Worker// that have previously occurred.
440*1fa6dee9SAndroid Build Coastguard Workerfunc (n *ninjaWriterWithWrap) Flush() error {
441*1fa6dee9SAndroid Build Coastguard Worker	if n.space {
442*1fa6dee9SAndroid Build Coastguard Worker		_, n.err = n.writer.WriteString(" ")
443*1fa6dee9SAndroid Build Coastguard Worker	}
444*1fa6dee9SAndroid Build Coastguard Worker	n.writePending()
445*1fa6dee9SAndroid Build Coastguard Worker	if n.err != nil {
446*1fa6dee9SAndroid Build Coastguard Worker		return n.err
447*1fa6dee9SAndroid Build Coastguard Worker	}
448*1fa6dee9SAndroid Build Coastguard Worker	_, err := n.writer.WriteString("\n")
449*1fa6dee9SAndroid Build Coastguard Worker	return err
450*1fa6dee9SAndroid Build Coastguard Worker}
451