1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
package ace
import (
"fmt"
"io/ioutil"
"path/filepath"
"strings"
)
// Special characters
const (
cr = "\r"
lf = "\n"
crlf = "\r\n"
space = " "
equal = "="
pipe = "|"
doublePipe = pipe + pipe
slash = "/"
sharp = "#"
dot = "."
doubleDot = dot + dot
colon = ":"
doubleColon = colon + colon
doubleQuote = `"`
lt = "<"
gt = ">"
exclamation = "!"
hyphen = "-"
bracketOpen = "["
bracketClose = "]"
)
// readFiles reads files and returns source for the parsing process.
func readFiles(basePath, innerPath string, opts *Options) (*source, error) {
// Read the base file.
base, err := readFile(basePath, opts)
if err != nil {
return nil, err
}
// Read the inner file.
inner, err := readFile(innerPath, opts)
if err != nil {
return nil, err
}
var includes []*File
// Find include files from the base file.
if err := findIncludes(base.data, opts, &includes, base); err != nil {
return nil, err
}
// Find include files from the inner file.
if err := findIncludes(inner.data, opts, &includes, inner); err != nil {
return nil, err
}
return NewSource(base, inner, includes), nil
}
// readFile reads a file and returns a file struct.
func readFile(path string, opts *Options) (*File, error) {
var data []byte
var err error
if path != "" {
name := filepath.Join(opts.BaseDir, path+dot+opts.Extension)
if opts.Asset != nil {
data, err = opts.Asset(name)
} else {
data, err = ioutil.ReadFile(name)
}
if err != nil {
return nil, err
}
}
return NewFile(path, data), nil
}
// findIncludes finds and adds include files.
func findIncludes(data []byte, opts *Options, includes *[]*File, targetFile *File) error {
includePaths, err := findIncludePaths(data, opts, targetFile)
if err != nil {
return err
}
for _, includePath := range includePaths {
if !hasFile(*includes, includePath) {
f, err := readFile(includePath, opts)
if err != nil {
return err
}
*includes = append(*includes, f)
if err := findIncludes(f.data, opts, includes, f); err != nil {
return err
}
}
}
return nil
}
// findIncludePaths finds and returns include paths.
func findIncludePaths(data []byte, opts *Options, f *File) ([]string, error) {
var includePaths []string
for i, str := range strings.Split(formatLF(string(data)), lf) {
ln := newLine(i+1, str, opts, f)
if ln.isHelperMethodOf(helperMethodNameInclude) {
if len(ln.tokens) < 3 {
return nil, fmt.Errorf("no template name is specified [file: %s][line: %d]", ln.fileName(), ln.no)
}
includePaths = append(includePaths, ln.tokens[2])
}
}
return includePaths, nil
}
// formatLF replaces the line feed codes with LF and returns the result.
func formatLF(s string) string {
return strings.Replace(strings.Replace(s, crlf, lf, -1), cr, lf, -1)
}
// hasFile return if files has a file which has the path specified by the parameter.
func hasFile(files []*File, path string) bool {
for _, f := range files {
if f.path == path {
return true
}
}
return false
}
|