go-studybox/cmd/script-decode.go

171 lines
3.7 KiB
Go

package main
import (
"fmt"
"os"
"strings"
"strconv"
"slices"
"errors"
"github.com/alexflint/go-arg"
"git.zorchenhimer.com/Zorchenhimer/go-studybox/script"
)
type Arguments struct {
Input string `arg:"positional,required"`
Output string `arg:"positional"`
StartAddr string `arg:"--start" default:"0x6000" help:"base address for the start of the script"`
StatsFile string `arg:"--stats" help:"file to write some statistics to"`
LabelFile string `arg:"--labels" help:"file containing address/label pairs"`
CDL string `arg:"--cdl" help:"CodeDataLog json file"`
CDLOutput string `arg:"--cdl-output"`
Smart bool `arg:"--smart"`
NoAddrPrefix bool `arg:"--no-addr-prefix"`
start int
}
func run(args *Arguments) error {
if args.StartAddr == "" {
return fmt.Errorf("start address cannot be empty")
}
if strings.HasPrefix(args.StartAddr, "$") {
args.StartAddr = "0x"+args.StartAddr[1:]
}
val, err := strconv.ParseInt(args.StartAddr, 0, 32)
if err != nil {
return fmt.Errorf("invalid start address %q: %w", args.StartAddr, err)
}
args.start = int(val)
var cdl *script.CodeDataLog
if args.CDL != "" {
cdl, err = script.CdlFromJsonFile(args.CDL)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
fmt.Println("WARN: CDL file doesn't exist")
} else {
return fmt.Errorf("CDL Parse error: %w", err)
}
cdl = nil
}
}
var scr *script.Script
if args.Smart {
scr, err = script.SmartParseFile(args.Input, args.start, cdl)
} else {
scr, err = script.ParseFile(args.Input, args.start, cdl)
}
if err != nil {
if errors.Is(err, script.ErrEarlyEOF) || errors.Is(err, script.ErrNavigation) {
fmt.Println(err)
} else {
return fmt.Errorf("Script parse error: %w", err)
}
}
if args.LabelFile != "" {
err = scr.LabelsFromJsonFile(args.LabelFile)
//labels, err := parseLabelFile(args.LabelFile)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
fmt.Println("WARN: Label file doesn't exist")
} else {
return fmt.Errorf("Labels parse error: %w", err)
}
}
err = scr.WriteLabelsToFile(args.LabelFile)
if err != nil {
return fmt.Errorf("Labels write error: %w", err)
}
//for _, label := range labels {
// scr.Labels[label.Address] = label
//}
}
outfile := os.Stdout
if args.Output != "" {
outfile, err = os.Create(args.Output)
if err != nil {
return fmt.Errorf("unable to create output file: %w", err)
}
defer outfile.Close()
}
for _, w := range scr.Warnings {
//fmt.Fprintln(os.Stderr, w)
if args.Output != "" {
fmt.Fprintln(outfile, "; "+w)
}
}
fmt.Fprintf(outfile, "; Start address: $%04X\n", scr.StartAddress)
fmt.Fprintf(outfile, "; Stack address: $%04X\n\n", scr.StackAddress)
slices.SortFunc(scr.Tokens, func(a, b *script.Token) int {
if a.Offset < b.Offset { return -1 }
if a.Offset > b.Offset { return 1 }
return 0
})
for _, token := range scr.Tokens {
fmt.Fprintln(outfile, token.String(scr.Labels, args.NoAddrPrefix))
}
if args.StatsFile != "" {
statfile, err := os.Create(args.StatsFile)
if err != nil {
return fmt.Errorf("Unable to create stats file: %w", err)
}
defer statfile.Close()
_, err = scr.Stats().WriteTo(statfile)
if err != nil {
return fmt.Errorf("Error writing stats: %w", err)
}
}
if scr.CDL != nil {
cdlout := args.CDL
if args.CDLOutput != "" {
cdlout = args.CDLOutput
}
if cdlout == "" {
return nil
}
err = scr.CDL.WriteToFile(cdlout)
if err != nil {
return fmt.Errorf("Error writing CDL file: %w", err)
}
err = scr.DebugCDL(cdlout+".dbg")
if err != nil {
return fmt.Errorf("Error writing CDL debug file: %w", err)
}
}
return nil
}
func main() {
args := &Arguments{}
arg.MustParse(args)
err := run(args)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}