95 lines
2.1 KiB
Go
95 lines
2.1 KiB
Go
package preproc
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
type FileReader interface {
|
|
ReadLines(includeSpec string, currentDir string) ([]string, string, error)
|
|
}
|
|
|
|
type DiskFileReader struct {
|
|
cache map[string][]string
|
|
libPath string
|
|
}
|
|
|
|
func NewDiskFileReader() *DiskFileReader {
|
|
return &DiskFileReader{
|
|
cache: make(map[string][]string),
|
|
libPath: os.Getenv("C65LIBPATH"),
|
|
}
|
|
}
|
|
|
|
func (d *DiskFileReader) ReadLines(includeSpec string, currentDir string) ([]string, string, error) {
|
|
path, err := d.resolvePath(includeSpec, currentDir)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
abs, err := filepath.Abs(path)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
if lines, ok := d.cache[abs]; ok {
|
|
return lines, abs, nil
|
|
}
|
|
|
|
data, err := os.ReadFile(abs)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
lines := strings.Split(string(data), "\n")
|
|
d.cache[abs] = lines
|
|
return lines, abs, nil
|
|
}
|
|
|
|
func (d *DiskFileReader) resolvePath(spec string, curDir string) (string, error) {
|
|
if len(spec) == 0 {
|
|
return "", errors.New("empty include path")
|
|
}
|
|
|
|
// <file> -> library include
|
|
if strings.HasPrefix(spec, "<") && strings.HasSuffix(spec, ">") {
|
|
base := strings.TrimSpace(spec[1 : len(spec)-1])
|
|
if d.libPath == "" {
|
|
return "", errors.New("C65LIBPATH not set for angle-bracket include")
|
|
}
|
|
path := filepath.Join(d.libPath, base)
|
|
if _, err := os.Stat(path); err != nil {
|
|
return "", fmt.Errorf("library include not found: %s", path)
|
|
}
|
|
return path, nil
|
|
}
|
|
|
|
// quoted or bare -> relative to current dir
|
|
base := strings.Trim(spec, `"'`)
|
|
path := filepath.Join(curDir, base)
|
|
if _, err := os.Stat(path); err != nil {
|
|
return "", fmt.Errorf("include not found: %s", path)
|
|
}
|
|
return path, nil
|
|
}
|
|
|
|
type MockFileReader struct {
|
|
files map[string][]string
|
|
}
|
|
|
|
func NewMockFileReader(files map[string][]string) *MockFileReader {
|
|
return &MockFileReader{
|
|
files: files,
|
|
}
|
|
}
|
|
|
|
func (m *MockFileReader) ReadLines(includeSpec string, _ string) ([]string, string, error) {
|
|
lines, ok := m.files[includeSpec]
|
|
if !ok {
|
|
return nil, "", fmt.Errorf("open %s: no such file or directory", includeSpec)
|
|
}
|
|
return lines, includeSpec, nil
|
|
}
|