1
0
mirror of https://github.com/zellyn/go6502.git synced 2024-10-01 05:56:28 +00:00
go6502/asm/lines/files.go
2014-06-03 08:46:49 -07:00

118 lines
2.2 KiB
Go

package lines
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
)
type Opener interface {
Open(filename string) (io.ReadCloser, error)
}
type OsOpener struct{}
func (o OsOpener) Open(filename string) (io.ReadCloser, error) {
return os.Open(filename)
}
func NewFileLineSource(filename string, context Context, opener Opener, prefix int) (LineSource, error) {
if prefix < 0 {
return nil, fmt.Errorf("NewFileLineSource: want prefix >= 0; got %d", prefix)
}
var ls []string
file, err := opener.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
ls = append(ls, scanner.Text())
}
if err = scanner.Err(); err != nil {
return nil, err
}
return NewSimpleLineSource(context, ls, prefix), nil
}
type TestOpener map[string]string
func (o TestOpener) Open(filename string) (io.ReadCloser, error) {
contents, ok := o[filename]
if ok {
return ioutil.NopCloser(strings.NewReader(contents)), nil
} else {
return nil, fmt.Errorf("File not found: %s", filename)
}
}
func (o TestOpener) Clear() {
for k := range o {
delete(o, k)
}
}
func NewTestOpener() TestOpener {
return make(TestOpener)
}
var whitespace = " \t\f\r\n"
var prefixChars = "abcdefABCDEF0123456789:"
func linePrefix(line string) int {
start := 0
for i, c := range line {
switch {
case strings.IndexRune(whitespace, c) >= 0:
start = i + 1
case strings.IndexRune(prefixChars, c) < 0:
return start
}
}
return -1
}
// GuessFilePrefixSize takes an assembly listing with address, bytes,
// and possibly line numbers, and tries to guess the size of the
// prefix that will skip past all that, to the label column.
func GuessFilePrefixSize(filename string, opener Opener) (prefix int, err error) {
counts := make(map[int]int)
max := 0
lines := 0
rc, err := opener.Open(filename)
if err != nil {
return 0, err
}
defer func() {
err = rc.Close()
}()
scanner := bufio.NewScanner(rc)
for scanner.Scan() {
lines++
s := scanner.Text()
prefix := linePrefix(s)
if prefix >= 0 {
counts[prefix] = counts[prefix] + 1
if prefix > max {
max = prefix
}
}
}
min := max
for p, _ := range counts {
if p < min {
min = p
}
}
return min, nil
}