Move all section handling to its own file automerge: f7e9207
automerge: e2cd612

* commit 'e2cd6126884f90ef06ad7c1d9de82da0e91a744c':
  Move all section handling to its own file
diff --git a/tools/codergen/template/functions.go b/tools/codergen/template/functions.go
index 7be15dc..1771817 100644
--- a/tools/codergen/template/functions.go
+++ b/tools/codergen/template/functions.go
@@ -16,12 +16,9 @@
 
 import (
 	"fmt"
-	"io"
-	"strconv"
 	"strings"
 
 	"android.googlesource.com/platform/tools/gpu/binary/schema"
-	"android.googlesource.com/platform/tools/gpu/reflow"
 )
 
 type variable struct {
@@ -44,18 +41,6 @@
 	return "", tmpl.Execute(t.writer, arg)
 }
 
-func (t *Templates) Section(name string) (string, error) {
-	w, ok := t.writer.(*reflow.Writer)
-	if !ok {
-		return "", fmt.Errorf("Section called inside nested writer")
-	}
-	depth := strconv.Itoa(w.Depth)
-	io.WriteString(t.writer, fmt.Sprintf(sectionMarker, sectionStart, name, depth))
-	err := t.execute(name, t.writer, t.File)
-	io.WriteString(t.writer, fmt.Sprintf(sectionMarker, sectionEnd, name, depth))
-	return "", err
-}
-
 func (*Templates) Lower(s interface{}) string {
 	return strings.ToLower(fmt.Sprint(s))
 }
diff --git a/tools/codergen/template/section.go b/tools/codergen/template/section.go
new file mode 100644
index 0000000..b62e7b0
--- /dev/null
+++ b/tools/codergen/template/section.go
@@ -0,0 +1,123 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package template
+
+import (
+	"fmt"
+	"io"
+	"regexp"
+	"strconv"
+
+	"android.googlesource.com/platform/tools/gpu/reflow"
+)
+
+const (
+	sectionMarker    = `<<<%s:%s:%s>>>`
+	sectionStart     = `Start`
+	sectionEnd       = `End`
+	sectionParameter = `([^\:>]+)`
+)
+
+var (
+	section = regexp.MustCompile(fmt.Sprintf(sectionMarker, sectionParameter, sectionParameter, sectionParameter))
+)
+
+// Section writes a new file section with associated templates.
+// It takes the name of the template to use to fill the section in, and wraps it
+// in the section markers.
+func (t *Templates) Section(name string) (string, error) {
+	w, ok := t.writer.(*reflow.Writer)
+	if !ok {
+		return "", fmt.Errorf("Section called inside nested writer")
+	}
+	depth := strconv.Itoa(w.Depth)
+	io.WriteString(t.writer, fmt.Sprintf(sectionMarker, sectionStart, name, depth))
+	err := t.execute(name, t.writer, t.File)
+	io.WriteString(t.writer, fmt.Sprintf(sectionMarker, sectionEnd, name, depth))
+	return "", err
+}
+
+// Section represents a span of text in a file, segmented using SectionSplit.
+// If the section has a Name it will also have a StartMarker and EndMarker, otherwise
+// they will be empty.
+type Section struct {
+	Name        string // The name the section was given.
+	Indentation int    // The indentation level of the section.
+	StartMarker []byte // The bytes that marked the start of the section.
+	Body        []byte // The content of the section.
+	EndMarker   []byte // The bytes that marked the end of the section.
+}
+
+// SectionSplit breaks a file up into it's sections, and returns the slices with
+// the section header.
+// Named sections are delimited by <<<Start:name:depth>>> to <<<End:name:depth>>>
+// markers, areas between named sections are returned as unnamed sections.
+func SectionSplit(data []byte) ([]Section, error) {
+	matches := section.FindAllSubmatchIndex(data, -1)
+	if len(matches) == 0 {
+		return nil, nil
+	}
+	s := Section{}
+	sections := make([]Section, 0, len(matches)+1)
+	last := 0
+	// we are doing a partial update...
+	for _, match := range matches {
+		marker := data[match[0]:match[1]]
+		mode := string(data[match[2]:match[3]])
+		name := string(data[match[4]:match[5]])
+		level := string(data[match[6]:match[7]])
+		depth, err := strconv.Atoi(string(data[match[6]:match[7]]))
+		if err != nil {
+			return nil, fmt.Errorf("Indentation depth malformed, got %s in %s", level, name)
+		}
+		switch mode {
+		case sectionStart:
+			if s.Name != "" {
+				return nil, fmt.Errorf("Overlapping template %s found starting %s", s.Name, name)
+			}
+			// section start, add the prefix section
+			if last != match[0] {
+				s.Body = data[last:match[0]]
+				sections = append(sections, s)
+			}
+			// And prepare the section itself
+			s = Section{Name: name, Indentation: depth, StartMarker: marker}
+			last = match[1]
+		case sectionEnd:
+			// section end marker, check it matches
+			if name != s.Name {
+				return nil, fmt.Errorf("Invalid end %s found, expected %s", name, s.Name)
+			}
+			// write the end marker out throught the formatting writer
+			s.Body = data[last:match[0]]
+			s.EndMarker = marker
+			sections = append(sections, s)
+			// prepare for the next section
+			s = Section{}
+			last = match[1]
+		default:
+			return nil, fmt.Errorf("Invalid section marker %q", mode)
+		}
+	}
+	if s.Name != "" {
+		return nil, fmt.Errorf("Unclosed template %s found", s.Name)
+	}
+	// section start, add the prefix section
+	if last != len(data) {
+		s.Body = data[last:]
+		sections = append(sections, s)
+	}
+	return sections, nil
+}
diff --git a/tools/codergen/template/template.go b/tools/codergen/template/template.go
index 3db0c76..e5dd907 100644
--- a/tools/codergen/template/template.go
+++ b/tools/codergen/template/template.go
@@ -22,8 +22,6 @@
 	"os"
 	"path/filepath"
 	"reflect"
-	"regexp"
-	"strconv"
 	"strings"
 	"text/template"
 	"unicode"
@@ -92,13 +90,6 @@
 	return f
 }
 
-var (
-	sectionMarker = "<<<%s:%s:%s>>>"
-	sectionStart  = "Start"
-	sectionEnd    = "End"
-	section       = regexp.MustCompile(fmt.Sprintf(sectionMarker, "(.+)", "(.+)", "(.+)"))
-)
-
 // Generate is an implementation of generate.Generator
 func (t *Templates) Generate(g generate.Generate) (bool, error) {
 	t.File = g.Arg
@@ -107,52 +98,30 @@
 	buf := &bytes.Buffer{}
 	out := reflow.New(buf)
 	out.Indent = g.Indent
-	matches := section.FindAllSubmatchIndex(old, -1)
-	if len(matches) > 0 {
-		last := 0
-		tmpl := ""
+
+	sections, err := SectionSplit(old)
+	if err != nil {
+		return false, err
+	}
+	if len(sections) > 0 {
 		// we are doing a partial update...
-		for _, match := range matches {
-			mode := string(old[match[2]:match[3]])
-			name := string(old[match[4]:match[5]])
-			level := string(old[match[6]:match[7]])
-			depth, err := strconv.Atoi(string(old[match[6]:match[7]]))
-			if err != nil {
-				return false, fmt.Errorf("Indentation depth malformed, got %s in %s", level, name)
-			}
-			switch mode {
-			case sectionStart:
-				if tmpl != "" {
-					return false, fmt.Errorf("Overlapping template %s found starting %s", tmpl, name)
-				}
-				// section start, write the prefix
-				buf.Write(old[last:match[1]])
-				// now run the template
-				tmpl = name
-				out.Depth = depth
-				if err := t.execute(tmpl, out, g.Arg); err != nil {
+		for _, s := range sections {
+			if s.Name == "" {
+				// copy the non template section straight to the underlying buf
+				buf.Write(s.Body)
+			} else {
+				// Write the start marker straight to the underlying buf
+				buf.Write(s.StartMarker)
+				out.Depth = s.Indentation
+				// Execute the template to generate a new body
+				if err := t.execute(s.Name, out, g.Arg); err != nil {
 					return false, err
 				}
-			case sectionEnd:
-				// section end marker, check it matches
-				if name != tmpl {
-					return false, fmt.Errorf("Invalid end %s found, expected %s", name, tmpl)
-				}
-				// write the end marker out throught the formatting writer
-				out.Write(old[match[0]:match[1]])
+				// write the end marker out through the formatting writer
+				out.Write(s.EndMarker)
 				out.Flush()
-				// set the markers ready for the next write
-				tmpl = ""
-				last = match[1]
-			default:
-				return false, fmt.Errorf("Invalid section marker %s:%s", mode, name)
 			}
 		}
-		if tmpl != "" {
-			return false, fmt.Errorf("Unclosed template %s found", tmpl)
-		}
-		// write the prefix
-		buf.Write(old[last:])
 	} else {
 		if err := t.execute(g.Name, out, g.Arg); err != nil {
 			return false, err