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") } // -> 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 }