diff --git a/README.md b/README.md index c79cf24..602c058 100644 --- a/README.md +++ b/README.md @@ -98,15 +98,16 @@ operations matrix is listed below. Anything that an actual user needs will be likely to get priority. - [ ] Make `put` accept load address for appropriate filetypes. +- [ ] Fix `golint` errors - [ ] Implement `GetFile` for prodos -- [x] Build per-platform binaries for Linux, MacOS, Windows. -- [x] Implement `GetFile` for DOS 3.3 +- [ ] Implement `Delete` for Super-Mon +- [ ] Implement `Delete` for DOS 3.3 +- [ ] Implement `Delete` for ProDOS - [ ] Add and implement the `-l` flag for `ls` -- [x] Add `Delete` to the `disk.Operator` interface - - [ ] Implement it for Super-Mon - - [ ] Implement it for DOS 3.3 -- [ ] Add ProDOS support for all commands -- [x] Make `filetypes` command use a tabwriter to write as a table +- [ ] Make `OperatorFactory.SeemsToMatch` more sophisticated for ProDOS +- [ ] Make `OperatorFactory.SeemsToMatch` more sophisticated for DOS 3.3 +- [ ] Make `OperatorFactory.SeemsToMatch` more sophisticated for NakedOS +- [x] Build per-platform binaries for Linux, MacOS, Windows. # Related tools diff --git a/basic/integer/integer.go b/basic/integer/integer.go index 0b36efd..f5376da 100644 --- a/basic/integer/integer.go +++ b/basic/integer/integer.go @@ -186,6 +186,7 @@ func Decode(raw []byte) (Listing, error) { return listing, nil } +/* const ( tokenREM = 0x5D tokenUnaryPlus = 0x35 @@ -193,6 +194,7 @@ const ( tokenQuoteStart = 0x28 tokenQuoteEnd = 0x29 ) +*/ func isalnum(b byte) bool { switch { diff --git a/basic/integer/integer_test.go b/basic/integer/integer_test.go index 37c3f3b..59ed828 100644 --- a/basic/integer/integer_test.go +++ b/basic/integer/integer_test.go @@ -39,6 +39,7 @@ var helloListing = ` 10 REM THIS IS A COMMENT // TestParse tests the full parsing and output of a basic program from // bytes. func TestParse(t *testing.T) { + t.Skip("ignoring for now") listing, err := Decode(helloBinary) if err != nil { t.Fatal(err) @@ -46,6 +47,6 @@ func TestParse(t *testing.T) { text := basic.ChevronControlCodes(listing.String()) if text != helloListing { // TODO(zellyn): actually test, once we understand how adding spaces works. - // t.Fatalf("Wrong listing; want:\n%s\ngot:\n%s", helloListing, text) + t.Fatalf("Wrong listing; want:\n%s\ngot:\n%s", helloListing, text) } } diff --git a/bin/.golangci-lint-1.41.1.pkg b/bin/.golangci-lint-1.41.1.pkg new file mode 120000 index 0000000..383f451 --- /dev/null +++ b/bin/.golangci-lint-1.41.1.pkg @@ -0,0 +1 @@ +hermit \ No newline at end of file diff --git a/bin/README.hermit.md b/bin/README.hermit.md new file mode 100644 index 0000000..e889550 --- /dev/null +++ b/bin/README.hermit.md @@ -0,0 +1,7 @@ +# Hermit environment + +This is a [Hermit](https://github.com/cashapp/hermit) bin directory. + +The symlinks in this directory are managed by Hermit and will automatically +download and install Hermit itself as well as packages. These packages are +local to this environment. diff --git a/bin/activate-hermit b/bin/activate-hermit new file mode 100755 index 0000000..3b191fb --- /dev/null +++ b/bin/activate-hermit @@ -0,0 +1,19 @@ +#!/bin/bash +# This file must be used with "source bin/activate-hermit" from bash or zsh. +# You cannot run it directly + +if [ "${BASH_SOURCE-}" = "$0" ]; then + echo "You must source this script: \$ source $0" >&2 + exit 33 +fi + +BIN_DIR="$(dirname "${BASH_SOURCE[0]:-${(%):-%x}}")" +if "${BIN_DIR}/hermit" noop > /dev/null; then + eval "$("${BIN_DIR}/hermit" activate "${BIN_DIR}/..")" + + if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ]; then + hash -r 2>/dev/null + fi + + echo "Hermit environment $("${HERMIT_ENV}"/bin/hermit env HERMIT_ENV) activated" +fi diff --git a/bin/golangci-lint b/bin/golangci-lint new file mode 120000 index 0000000..8958d33 --- /dev/null +++ b/bin/golangci-lint @@ -0,0 +1 @@ +.golangci-lint-1.41.1.pkg \ No newline at end of file diff --git a/bin/hermit b/bin/hermit new file mode 100755 index 0000000..7f7ab76 --- /dev/null +++ b/bin/hermit @@ -0,0 +1,26 @@ +#!/bin/bash + +set -eo pipefail + +if [ -z "${HERMIT_STATE_DIR}" ]; then + case "$(uname -s)" in + Darwin) + export HERMIT_STATE_DIR="${HOME}/Library/Caches/hermit" + ;; + Linux) + export HERMIT_STATE_DIR="${XDG_CACHE_HOME:-${HOME}/.cache}/hermit" + ;; + esac +fi + +export HERMIT_DIST_URL="${HERMIT_DIST_URL:-https://d1abdrezunyhdp.cloudfront.net/square}" +HERMIT_CHANNEL="$(basename "${HERMIT_DIST_URL}")" +export HERMIT_CHANNEL +export HERMIT_EXE=${HERMIT_EXE:-${HERMIT_STATE_DIR}/pkg/hermit@${HERMIT_CHANNEL}/hermit} + +if [ ! -x "${HERMIT_EXE}" ]; then + echo "Bootstrapping ${HERMIT_EXE} from ${HERMIT_DIST_URL}" 1>&2 + curl -fsSL "${HERMIT_DIST_URL}/install.sh" | /bin/bash 1>&2 +fi + +exec "${HERMIT_EXE}" --level=fatal exec "$0" -- "$@" diff --git a/bin/hermit.hcl b/bin/hermit.hcl new file mode 100644 index 0000000..e69de29 diff --git a/cmd/catalog.go b/cmd/catalog.go index 3156d16..ae55392 100644 --- a/cmd/catalog.go +++ b/cmd/catalog.go @@ -12,13 +12,21 @@ import ( type LsCmd struct { Order types.DiskOrder `kong:"default='auto',enum='auto,do,po',help='Logical-to-physical sector order.'"` - System string `kong:"default='auto',enum='auto,dos3',help='DOS system used for image.'"` + System string `kong:"default='auto',enum='auto,dos3,prodos,nakedos',help='DOS system used for image.'"` ShortNames bool `kong:"short='s',help='Whether to print short filenames (only makes a difference on Super-Mon disks).'"` Image *os.File `kong:"arg,required,help='Disk/device image to read.'"` Directory string `kong:"arg,optional,help='Directory to list (ProDOS only).'"` } +func (l LsCmd) Help() string { + return `Examples: + # Simple ls of a disk image + diskii ls games.dsk + # Get really explicit about disk order and system + diskii ls --order do --system nakedos Super-Mon-2.0.dsk` +} + func (l *LsCmd) Run(globals *types.Globals) error { op, order, err := disk.OpenFile(l.Image, l.Order, l.System, globals.DiskOperatorFactories, globals.Debug) if err != nil { diff --git a/dos3/dos3.go b/dos3/dos3.go index 33785e2..189cbaa 100644 --- a/dos3/dos3.go +++ b/dos3/dos3.go @@ -32,7 +32,7 @@ func (ds DiskSector) GetTrack() byte { } // SetTrack sets the track that a DiskSector was loaded from. -func (ds DiskSector) SetTrack(track byte) { +func (ds *DiskSector) SetTrack(track byte) { ds.Track = track } @@ -42,7 +42,7 @@ func (ds DiskSector) GetSector() byte { } // SetSector sets the sector that a DiskSector was loaded from. -func (ds DiskSector) SetSector(sector byte) { +func (ds *DiskSector) SetSector(sector byte) { ds.Sector = sector } @@ -695,10 +695,7 @@ func (of OperatorFactory) Name() string { func (of OperatorFactory) SeemsToMatch(diskbytes []byte, debug bool) bool { // For now, just return true if we can run Catalog successfully. _, _, err := ReadCatalog(diskbytes, debug) - if err != nil { - return false - } - return true + return err == nil } // Operator returns an Operator for the []byte disk image. diff --git a/dos3/dos3_test.go b/dos3/dos3_test.go index 80c791f..e0908a8 100644 --- a/dos3/dos3_test.go +++ b/dos3/dos3_test.go @@ -10,11 +10,14 @@ import ( // TestVTOCMarshalRoundtrip checks a simple roundtrip of VTOC data. func TestVTOCMarshalRoundtrip(t *testing.T) { buf := make([]byte, 256) - rand.Read(buf) + _, _ = rand.Read(buf) buf1 := make([]byte, 256) copy(buf1, buf) vtoc1 := &VTOC{} - vtoc1.FromSector(buf1) + err := vtoc1.FromSector(buf1) + if err != nil { + t.Fatal(err) + } buf2, err := vtoc1.ToSector() if err != nil { t.Fatal(err) @@ -23,7 +26,10 @@ func TestVTOCMarshalRoundtrip(t *testing.T) { t.Errorf("Buffers differ: %v != %v", buf, buf2) } vtoc2 := &VTOC{} - vtoc2.FromSector(buf2) + err = vtoc2.FromSector(buf2) + if err != nil { + t.Fatal(err) + } if *vtoc1 != *vtoc2 { t.Errorf("Structs differ: %v != %v", vtoc1, vtoc2) } @@ -32,11 +38,14 @@ func TestVTOCMarshalRoundtrip(t *testing.T) { // TestCatalogSectorMarshalRoundtrip checks a simple roundtrip of CatalogSector data. func TestCatalogSectorMarshalRoundtrip(t *testing.T) { buf := make([]byte, 256) - rand.Read(buf) + _, _ = rand.Read(buf) buf1 := make([]byte, 256) copy(buf1, buf) cs1 := &CatalogSector{} - cs1.FromSector(buf1) + err := cs1.FromSector(buf1) + if err != nil { + t.Fatal(err) + } buf2, err := cs1.ToSector() if err != nil { t.Fatal(err) @@ -45,7 +54,10 @@ func TestCatalogSectorMarshalRoundtrip(t *testing.T) { t.Errorf("Buffers differ: %v != %v", buf, buf2) } cs2 := &CatalogSector{} - cs2.FromSector(buf2) + err = cs2.FromSector(buf2) + if err != nil { + t.Fatal(err) + } if *cs1 != *cs2 { t.Errorf("Structs differ: %v != %v", cs1, cs2) } @@ -54,11 +66,14 @@ func TestCatalogSectorMarshalRoundtrip(t *testing.T) { // TestTrackSectorListMarshalRoundtrip checks a simple roundtrip of TrackSectorList data. func TestTrackSectorListMarshalRoundtrip(t *testing.T) { buf := make([]byte, 256) - rand.Read(buf) + _, _ = rand.Read(buf) buf1 := make([]byte, 256) copy(buf1, buf) cs1 := &TrackSectorList{} - cs1.FromSector(buf1) + err := cs1.FromSector(buf1) + if err != nil { + t.Fatal(err) + } buf2, err := cs1.ToSector() if err != nil { t.Fatal(err) @@ -67,7 +82,10 @@ func TestTrackSectorListMarshalRoundtrip(t *testing.T) { t.Errorf("Buffers differ: %v != %v", buf, buf2) } cs2 := &TrackSectorList{} - cs2.FromSector(buf2) + err = cs2.FromSector(buf2) + if err != nil { + t.Fatal(err) + } if *cs1 != *cs2 { t.Errorf("Structs differ: %v != %v", cs1, cs2) } diff --git a/prodos/prodos.go b/prodos/prodos.go index 266c189..9cb4399 100644 --- a/prodos/prodos.go +++ b/prodos/prodos.go @@ -926,10 +926,7 @@ func (of OperatorFactory) Name() string { func (of OperatorFactory) SeemsToMatch(devicebytes []byte, debug bool) bool { // For now, just return true if we can run Catalog successfully. _, err := readVolume(devicebytes, 2, debug) - if err != nil { - return false - } - return true + return err == nil } // Operator returns an Operator for the []byte disk image. diff --git a/prodos/prodos_test.go b/prodos/prodos_test.go index 41497ad..307b724 100644 --- a/prodos/prodos_test.go +++ b/prodos/prodos_test.go @@ -11,7 +11,7 @@ import ( func randomBlock() disk.Block { var b1 disk.Block - rand.Read(b1[:]) + _, _ = rand.Read(b1[:]) return b1 } @@ -19,7 +19,10 @@ func randomBlock() disk.Block { func TestVolumeDirectoryKeyBlockMarshalRoundtrip(t *testing.T) { b1 := randomBlock() vdkb := &VolumeDirectoryKeyBlock{} - vdkb.FromBlock(b1) + err := vdkb.FromBlock(b1) + if err != nil { + t.Fatal(err) + } b2, err := vdkb.ToBlock() if err != nil { t.Fatal(err) @@ -28,7 +31,10 @@ func TestVolumeDirectoryKeyBlockMarshalRoundtrip(t *testing.T) { t.Fatalf("Blocks differ: %s", strings.Join(pretty.Diff(b1[:], b2[:]), "; ")) } vdkb2 := &VolumeDirectoryKeyBlock{} - vdkb2.FromBlock(b2) + err = vdkb2.FromBlock(b2) + if err != nil { + t.Fatal(err) + } if *vdkb != *vdkb2 { t.Errorf("Structs differ: %v != %v", vdkb, vdkb2) } @@ -38,7 +44,10 @@ func TestVolumeDirectoryKeyBlockMarshalRoundtrip(t *testing.T) { func TestVolumeDirectoryBlockMarshalRoundtrip(t *testing.T) { b1 := randomBlock() vdb := &VolumeDirectoryBlock{} - vdb.FromBlock(b1) + err := vdb.FromBlock(b1) + if err != nil { + t.Fatal(err) + } b2, err := vdb.ToBlock() if err != nil { t.Fatal(err) @@ -47,7 +56,10 @@ func TestVolumeDirectoryBlockMarshalRoundtrip(t *testing.T) { t.Fatalf("Blocks differ: %s", strings.Join(pretty.Diff(b1[:], b2[:]), "; ")) } vdb2 := &VolumeDirectoryBlock{} - vdb2.FromBlock(b2) + err = vdb2.FromBlock(b2) + if err != nil { + t.Fatal(err) + } if *vdb != *vdb2 { t.Errorf("Structs differ: %v != %v", vdb, vdb2) } @@ -57,7 +69,10 @@ func TestVolumeDirectoryBlockMarshalRoundtrip(t *testing.T) { func TestSubdirectoryKeyBlockMarshalRoundtrip(t *testing.T) { b1 := randomBlock() skb := &SubdirectoryKeyBlock{} - skb.FromBlock(b1) + err := skb.FromBlock(b1) + if err != nil { + t.Fatal(err) + } b2, err := skb.ToBlock() if err != nil { t.Fatal(err) @@ -66,7 +81,10 @@ func TestSubdirectoryKeyBlockMarshalRoundtrip(t *testing.T) { t.Fatalf("Blocks differ: %s", strings.Join(pretty.Diff(b1[:], b2[:]), "; ")) } skb2 := &SubdirectoryKeyBlock{} - skb2.FromBlock(b2) + err = skb2.FromBlock(b2) + if err != nil { + t.Fatal(err) + } if *skb != *skb2 { t.Errorf("Structs differ: %v != %v", skb, skb2) } @@ -76,7 +94,10 @@ func TestSubdirectoryKeyBlockMarshalRoundtrip(t *testing.T) { func TestSubdirectoryBlockMarshalRoundtrip(t *testing.T) { b1 := randomBlock() sb := &SubdirectoryBlock{} - sb.FromBlock(b1) + err := sb.FromBlock(b1) + if err != nil { + t.Fatal(err) + } b2, err := sb.ToBlock() if err != nil { t.Fatal(err) @@ -85,7 +106,10 @@ func TestSubdirectoryBlockMarshalRoundtrip(t *testing.T) { t.Fatalf("Blocks differ: %s", strings.Join(pretty.Diff(b1[:], b2[:]), "; ")) } sb2 := &SubdirectoryBlock{} - sb2.FromBlock(b2) + err = sb2.FromBlock(b2) + if err != nil { + t.Fatal(err) + } if *sb != *sb2 { t.Errorf("Structs differ: %v != %v", sb, sb2) } diff --git a/supermon/supermon.go b/supermon/supermon.go index dbe90a6..51942c9 100644 --- a/supermon/supermon.go +++ b/supermon/supermon.go @@ -61,7 +61,7 @@ func (sm SectorMap) FirstFreeFile() byte { return 0 } -// Persist writes the current contenst of a sector map back back to +// Persist writes the current contents of a sector map back back to // disk. func (sm SectorMap) Persist(diskbytes []byte) error { sector09, err := disk.ReadSector(diskbytes, 0, 9) diff --git a/woz/woz.go b/woz/woz.go index 849347e..4ae4005 100644 --- a/woz/woz.go +++ b/woz/woz.go @@ -129,8 +129,6 @@ func (d *decoder) parseChunk() (done bool, err error) { default: return false, d.parseUnknown(string(d.tmp[:4]), length) } - - return false, nil } func (d *decoder) parseINFO(length uint32) error {