74 lines
No EOL
2.3 KiB
Go
74 lines
No EOL
2.3 KiB
Go
package preproc
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// HybridFileReader implements FileReader with support for both embedded
|
|
// standard library (when C65LIBPATH is not set) and disk-based includes.
|
|
type HybridFileReader struct {
|
|
diskReader *DiskFileReader // For relative includes & C65LIBPATH overrides
|
|
libPath string // From C65LIBPATH env var
|
|
usedEmbedded bool // Track if we've used embedded library
|
|
embeddedCache map[string][]string // Cache for embedded files
|
|
}
|
|
|
|
// NewHybridFileReader creates a new HybridFileReader.
|
|
func NewHybridFileReader() *HybridFileReader {
|
|
return &HybridFileReader{
|
|
diskReader: NewDiskFileReader(),
|
|
libPath: os.Getenv("C65LIBPATH"),
|
|
embeddedCache: make(map[string][]string),
|
|
}
|
|
}
|
|
|
|
// ReadLines implements the FileReader interface.
|
|
func (h *HybridFileReader) ReadLines(includeSpec string, currentDir string) ([]string, string, error) {
|
|
// Check if this is an angle-bracket include
|
|
if strings.HasPrefix(includeSpec, "<") && strings.HasSuffix(includeSpec, ">") {
|
|
// If C65LIBPATH is set, delegate to DiskFileReader
|
|
if h.libPath != "" {
|
|
return h.diskReader.ReadLines(includeSpec, currentDir)
|
|
}
|
|
|
|
// Otherwise, use embedded library
|
|
if !h.usedEmbedded {
|
|
h.usedEmbedded = true
|
|
// Note: Library source message is printed by NewDefaultFileReader factory
|
|
}
|
|
|
|
return h.readEmbeddedLibrary(includeSpec)
|
|
}
|
|
|
|
// Relative includes always go to disk
|
|
return h.diskReader.ReadLines(includeSpec, currentDir)
|
|
}
|
|
|
|
// readEmbeddedLibrary reads a file from the embedded standard library.
|
|
func (h *HybridFileReader) readEmbeddedLibrary(spec string) ([]string, string, error) {
|
|
// Convert angle-bracket spec to embedded path
|
|
embeddedPath, err := embeddedLibPath(spec)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
// Check cache
|
|
if lines, ok := h.embeddedCache[embeddedPath]; ok {
|
|
// Return cached lines with virtual path for error messages
|
|
return lines, "<embedded>/" + strings.TrimPrefix(embeddedPath, "lib/"), nil
|
|
}
|
|
|
|
// Read from embedded filesystem
|
|
lines, err := readEmbeddedFile(embeddedPath)
|
|
if err != nil {
|
|
return nil, "", fmt.Errorf("embedded library include not found: %s", spec)
|
|
}
|
|
|
|
// Cache the result
|
|
h.embeddedCache[embeddedPath] = lines
|
|
|
|
// Return with virtual path for error messages
|
|
return lines, "<embedded>/" + strings.TrimPrefix(embeddedPath, "lib/"), nil
|
|
} |