diff --git a/cmd/put.go b/cmd/put.go new file mode 100644 index 0000000..888db14 --- /dev/null +++ b/cmd/put.go @@ -0,0 +1,56 @@ +// Copyright © 2016 Zellyn Hunter + +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/zellyn/diskii/lib/disk" + _ "github.com/zellyn/diskii/lib/dos3" + "github.com/zellyn/diskii/lib/helpers" + _ "github.com/zellyn/diskii/lib/supermon" +) + +// putCmd represents the put command, used to put the raw contents +// of a file. +var putCmd = &cobra.Command{ + Use: "put", + Short: "put the raw contents of a file", + Long: `Put the raw contents of a file. + +put disk-image.dsk HELLO +`, + Run: func(cmd *cobra.Command, args []string) { + if err := runPut(args); err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(-1) + } + }, +} + +func init() { + RootCmd.AddCommand(putCmd) +} + +// runPut performs the actual put logic. +func runPut(args []string) error { + if len(args) != 3 { + return fmt.Errorf("put expects a disk image filename, an disk-image filename, and a filename to read the contents from") + } + sd, err := disk.Open(args[0]) + if err != nil { + return err + } + op, err := disk.OperatorFor(sd) + if err != nil { + return err + } + contents, err := helpers.FileContentsOrStdIn(args[2]) + if err != nil { + return err + } + + return nil +} diff --git a/lib/disk/filetype.go b/lib/disk/filetype.go new file mode 100644 index 0000000..e921f3f --- /dev/null +++ b/lib/disk/filetype.go @@ -0,0 +1,181 @@ +// Copyright © 2016 Zellyn Hunter + +// filetype.go contains the Filetype type, along with routines for +// converting to and from strings. + +package disk + +import "fmt" + +// Filetype describes the type of a file. It's byte-compatible with +// the ProDOS/SOS filetype byte definitions in the range 00-FF. +type Filetype int + +const ( + FiletypeTypeless Filetype = 0x00 // | both | Typeless file + FiletypeBadBlocks Filetype = 0x01 // | both | Bad blocks file + FiletypeSOSPascalCode Filetype = 0x02 // | SOS | PASCAL code file + FiletypeSOSPascalText Filetype = 0x03 // | SOS | PASCAL text file + FiletypeASCIIText Filetype = 0x04 // TXT | both | ASCII text file + FiletypeSOSPascalText2 Filetype = 0x05 // | SOS | PASCAL text file + FiletypeBinary Filetype = 0x06 // BIN | both | Binary file + FiletypeFont Filetype = 0x07 // | SOS | Font file + FiletypeGraphicsScreen Filetype = 0x08 // | SOS | Graphics screen file + FiletypeBusinessBASIC Filetype = 0x09 // | SOS | Business BASIC program file + FiletypeBusinessBASICData Filetype = 0x0A // | SOS | Business BASIC data file + FiletypeSOSWordProcessor Filetype = 0x0B // | SOS | Word processor file + FiletypeSOSSystem Filetype = 0x0C // | SOS | SOS system file + FiletypeDirectory Filetype = 0x0F // DIR | both | Directory file + FiletypeRPSData Filetype = 0x10 // | SOS | RPS data file + FiletypeRPSIndex Filetype = 0x11 // | SOS | RPS index file + FiletypeAppleWorksDatabase Filetype = 0x19 // ADB | ProDOS | AppleWorks data base file + FiletypeAppleWorksWordProcessor Filetype = 0x1A // AWP | ProDOS | AppleWorks word processing file + FiletypeAppleWorksSpreadsheet Filetype = 0x1B // ASP | ProDOS | AppleWorks spreadsheet file + FiletypePascal Filetype = 0xEF // PAS | ProDOS | ProDOS PASCAL file + FiletypeCommand Filetype = 0xF0 // CMD | ProDOS | Added command file + FiletypeUserDefinedF1 Filetype = 0xF1 // | ProDOS | ProDOS user defined file type F1 + FiletypeUserDefinedF2 Filetype = 0xF2 // | ProDOS | ProDOS user defined file type F2 + FiletypeUserDefinedF3 Filetype = 0xF3 // | ProDOS | ProDOS user defined file type F3 + FiletypeUserDefinedF4 Filetype = 0xF4 // | ProDOS | ProDOS user defined file type F4 + FiletypeUserDefinedF5 Filetype = 0xF5 // | ProDOS | ProDOS user defined file type F5 + FiletypeUserDefinedF6 Filetype = 0xF6 // | ProDOS | ProDOS user defined file type F6 + FiletypeUserDefinedF7 Filetype = 0xF7 // | ProDOS | ProDOS user defined file type F7 + FiletypeUserDefinedF8 Filetype = 0xF8 // | ProDOS | ProDOS user defined file type F8 + FiletypeIntegerBASIC Filetype = 0xFA // INT | ProDOS | Integer BASIC program file + FiletypeIntegerBASICVariables Filetype = 0xFB // IVR | ProDOS | Integer BASIC variables file + FiletypeApplesoftBASIC Filetype = 0xFC // BAS | ProDOS | Applesoft BASIC program file + FiletypeApplesoftBASICVariables Filetype = 0xFD // VAR | ProDOS | Applesoft BASIC variables file + FiletypeRelocatable Filetype = 0xFE // REL | ProDOS | EDASM relocatable object module file + FiletypeSystem Filetype = 0xFF // SYS | ProDOS | System file + FiletypeS Filetype = 0x100 // DOS 3.3 Type "S" + FiletypeA Filetype = 0x101 // DOS 3.3 Type "new A" + FiletypeB Filetype = 0x102 // DOS 3.3 Type "new B" + // | 0D-0E | SOS | SOS reserved for future use + // | 12-18 | SOS | SOS reserved for future use + // | 1C-BF | SOS | SOS reserved for future use + // | C0-EE | ProDOS | ProDOS reserved for future use +) + +// filetypeInfo holds name information about filetype constants. +type filetypeInfo struct { + Type Filetype // The type itself + Name string // The constant name, without the "Filetype" prefix + ThreeLetter string // The three-letter abbreviation (ProDOS) + OneLetter string // The one-letter abbreviation (DOS 3.x) + Desc string // The description of the type + Stringified string // (Generated) result of calling String() on the Constant +} + +// names of Filetype constants above +var filetypeInfos = []filetypeInfo{ + {FiletypeTypeless, "Typeless", "", "", "Typeless file", ""}, + {FiletypeBadBlocks, "BadBlocks", "", "", "Bad blocks file", ""}, + {FiletypeSOSPascalCode, "SOSPascalCode", "", "", "PASCAL code file", ""}, + {FiletypeSOSPascalText, "SOSPascalText", "", "", "PASCAL text file", ""}, + {FiletypeASCIIText, "ASCIIText", "T", "TXT", "ASCII text file", ""}, + {FiletypeSOSPascalText2, "SOSPascalText2", "", "", "PASCAL text file", ""}, + {FiletypeBinary, "Binary", "B", "BIN", "Binary file", ""}, + {FiletypeFont, "Font", "", "", "Font file", ""}, + {FiletypeGraphicsScreen, "GraphicsScreen", "", "", "Graphics screen file", ""}, + {FiletypeBusinessBASIC, "BusinessBASIC", "", "", "Business BASIC program file", ""}, + {FiletypeBusinessBASICData, "BusinessBASICData", "", "", "Business BASIC data file", ""}, + {FiletypeSOSWordProcessor, "SOSWordProcessor", "", "", "Word processor file", ""}, + {FiletypeSOSSystem, "SOSSystem", "", "", "SOS system file", ""}, + {FiletypeDirectory, "Directory", "", "DIR", "Directory file", ""}, + {FiletypeRPSData, "RPSData", "", "", "RPS data file", ""}, + {FiletypeRPSIndex, "RPSIndex", "", "", "RPS index file", ""}, + {FiletypeAppleWorksDatabase, "AppleWorksDatabase", "", "ADB", "AppleWorks data base file", ""}, + {FiletypeAppleWorksWordProcessor, "AppleWorksWordProcessor", "", "AWP", "AppleWorks word processing file", ""}, + {FiletypeAppleWorksSpreadsheet, "AppleWorksSpreadsheet", "", "ASP", "AppleWorks spreadsheet file", ""}, + {FiletypePascal, "Pascal", "", "PAS", "ProDOS PASCAL file", ""}, + {FiletypeCommand, "Command", "", "CMD", "Added command file", ""}, + {FiletypeUserDefinedF1, "UserDefinedF1", "", "", "ProDOS user defined file type F1", ""}, + {FiletypeUserDefinedF2, "UserDefinedF2", "", "", "ProDOS user defined file type F2", ""}, + {FiletypeUserDefinedF3, "UserDefinedF3", "", "", "ProDOS user defined file type F3", ""}, + {FiletypeUserDefinedF4, "UserDefinedF4", "", "", "ProDOS user defined file type F4", ""}, + {FiletypeUserDefinedF5, "UserDefinedF5", "", "", "ProDOS user defined file type F5", ""}, + {FiletypeUserDefinedF6, "UserDefinedF6", "", "", "ProDOS user defined file type F6", ""}, + {FiletypeUserDefinedF7, "UserDefinedF7", "", "", "ProDOS user defined file type F7", ""}, + {FiletypeUserDefinedF8, "UserDefinedF8", "", "", "ProDOS user defined file type F8", ""}, + {FiletypeIntegerBASIC, "IntegerBASIC", "I", "INT", "Integer BASIC program file", ""}, + {FiletypeIntegerBASICVariables, "IntegerBASICVariables", "", "IVR", "Integer BASIC variables file", ""}, + {FiletypeApplesoftBASIC, "ApplesoftBASIC", "A", "BAS", "Applesoft BASIC program file", ""}, + {FiletypeApplesoftBASICVariables, "ApplesoftBASICVariables", "", "VAR", "Applesoft BASIC variables file", ""}, + {FiletypeRelocatable, "Relocatable", "R", "REL", "EDASM relocatable object module file", ""}, + {FiletypeSystem, "System", "", "SYS", "System file", ""}, + {FiletypeS, "S", "S", "", `DOS 3.3 Type "S"`, ""}, + {FiletypeA, "A", "A", "", `DOS 3.3 Type "new A"`, ""}, + {FiletypeB, "B", "B", "", `DOS 3.3 Type "new B"`, ""}, +} + +var filetypeInfosMap map[Filetype]filetypeInfo +var filetypeNames []string + +func init() { + sosReserved := []Filetype{0x0D, 0x0E, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18} + for i := Filetype(0x1C); i < 0xC0; i++ { + sosReserved = append(sosReserved, i) + } + prodosReserved := []Filetype{} + for i := Filetype(0xC0); i < 0xEF; i++ { + prodosReserved = append(prodosReserved, i) + } + for _, typ := range sosReserved { + info := filetypeInfo{ + Type: typ, + Name: fmt.Sprintf("SOSReserved%02X", typ), + ThreeLetter: "", + OneLetter: "", + Desc: fmt.Sprintf("SOS reserved for future use %02X", typ), + } + filetypeInfos = append(filetypeInfos, info) + } + for _, typ := range prodosReserved { + info := filetypeInfo{ + Type: typ, + Name: fmt.Sprintf("ProDOSReserved%02X", typ), + ThreeLetter: "", + OneLetter: "", + Desc: fmt.Sprintf("ProDOS reserved for future use %02X", typ), + } + filetypeInfos = append(filetypeInfos, info) + } + + for i, info := range filetypeInfos { + info.Stringified = info.Desc + " (" + info.Name + if info.ThreeLetter != "" { + info.Stringified += "|" + info.ThreeLetter + } + if info.OneLetter != "" { + info.Stringified += "|" + info.OneLetter + } + info.Stringified += ")" + + filetypeInfos[i] = info + filetypeInfosMap[info.Type] = info + filetypeNames = append(filetypeNames, info.Stringified) + } +} + +func (f Filetype) String() string { + if info, found := filetypeInfosMap[f]; found { + return info.Stringified + } + return fmt.Sprintf("Invalid/unknown filetype %02X", f) +} + +// FiletypeForName returns the filetype for a full, three-letter, or +// one-letter name for a Filetype. +func FiletypeForName(name string) (Filetype, error) { + for _, info := range filetypeInfos { + if info.Name == name || info.ThreeLetter == name || info.OneLetter == name { + return info.Type, nil + } + } + return 0, fmt.Errorf("Unknown Filetype: %q", name) +} + +// FiletypeNames returns a list of all filetype names. +func FiletypeNames() []string { + return filetypeNames +} diff --git a/lib/disk/ops.go b/lib/disk/ops.go index 3267612..180a0cf 100644 --- a/lib/disk/ops.go +++ b/lib/disk/ops.go @@ -13,55 +13,6 @@ import ( "strings" ) -// Filetype describes the type of a file. It's byte-compatible with -// the ProDOS/SOS filetype byte definitions in the range 00-FF. -type Filetype int - -const ( - FiletypeTypeless Filetype = 0x00 // | both | Typeless file - FiletypeBadBlocks Filetype = 0x01 // | both | Bad blocks file - FiletypeSOSPascalCode Filetype = 0x02 // | SOS | PASCAL code file - FiletypeSOSPascalText Filetype = 0x03 // | SOS | PASCAL text file - FiletypeASCIIText Filetype = 0x04 // TXT | both | ASCII text fil - FiletypeSOSPascalText2 Filetype = 0x05 // | SOS | PASCAL text file - FiletypeBinary Filetype = 0x06 // BIN | both | Binary file - FiletypeFont Filetype = 0x07 // | SOS | Font file - FiletypeGraphicsScreen Filetype = 0x08 // | SOS | Graphics screen file - FiletypeBusinessBASIC Filetype = 0x09 // | SOS | Business BASIC program file - FiletypeBusinessBASICData Filetype = 0x0A // | SOS | Business BASIC data file - FiletypeSOSWordProcessor Filetype = 0x0B // | SOS | Word processor file - FiletypeSOSSystem Filetype = 0x0C // | SOS | SOS system file - FiletypeDirectory Filetype = 0x0F // DIR | both | Directory file - FiletypeRPSData Filetype = 0x10 // | SOS | RPS data file - FiletypeRPSIndex Filetype = 0x11 // | SOS | RPS index file - FiletypeAppleWorksDatabase Filetype = 0x19 // ADB | ProDOS | AppleWorks data base file - FiletypeAppleWorksWordProcessor Filetype = 0x1A // AWP | ProDOS | AppleWorks word processing file - FiletypeAppleWorksSpreadsheet Filetype = 0x1B // ASP | ProDOS | AppleWorks spreadsheet file - FiletypePascal Filetype = 0xEF // PAS | ProDOS | ProDOS PASCAL file - FiletypeCommand Filetype = 0xF0 // CMD | ProDOS | Added command file - FiletypeUserDefinedF1 Filetype = 0xF1 // | ProDOS | ProDOS user defined file types - FiletypeUserDefinedF2 Filetype = 0xF2 // | ProDOS | ProDOS user defined file types - FiletypeUserDefinedF3 Filetype = 0xF3 // | ProDOS | ProDOS user defined file types - FiletypeUserDefinedF4 Filetype = 0xF4 // | ProDOS | ProDOS user defined file types - FiletypeUserDefinedF5 Filetype = 0xF5 // | ProDOS | ProDOS user defined file types - FiletypeUserDefinedF6 Filetype = 0xF6 // | ProDOS | ProDOS user defined file types - FiletypeUserDefinedF7 Filetype = 0xF7 // | ProDOS | ProDOS user defined file types - FiletypeUserDefinedF8 Filetype = 0xF8 // | ProDOS | ProDOS user defined file types - FiletypeIntegerBASIC Filetype = 0xFA // INT | ProDOS | Integer BASIC program file - FiletypeIntegerBASICVariables Filetype = 0xFB // IVR | ProDOS | Integer BASIC variables file - FiletypeApplesoftBASIC Filetype = 0xFC // BAS | ProDOS | Applesoft BASIC program file - FiletypeApplesoftBASICVariables Filetype = 0xFD // VAR | ProDOS | Applesoft BASIC variables file - FiletypeRelocatable Filetype = 0xFE // REL | ProDOS | EDASM relocatable object module file - FiletypeSystem Filetype = 0xFF // SYS | ProDOS | System file - FiletypeS Filetype = 0x100 // DOS 3.3 Type "S" - FiletypeA Filetype = 0x101 // DOS 3.3 Type "A" - FiletypeB Filetype = 0x102 // DOS 3.3 Type "B" - // | 0D-0E | SOS | SOS reserved for future use - // | 12-18 | SOS | SOS reserved for future use - // | 1C-BF | SOS | SOS reserved for future use - // | C0-EE | ProDOS | ProDOS reserved for future use -) - // Descriptor describes a file's characteristics. type Descriptor struct { Name string @@ -86,10 +37,10 @@ type Operator interface { // Delete deletes a file by name. It returns true if the file was // deleted, false if it didn't exist. Delete(filename string) (bool, error) - // WriteRaw writes raw contents of a file by name. If the file exists - // and overwrite is false, it returns with an error. Otherwise it - // returns true if an existing file was overwritten. - WriteRaw(filename string, contents []byte, overwrite bool) (existed bool, err error) + // PutFile writes a file by name. If the file exists and overwrite + // is false, it returns with an error. Otherwise it returns true if + // an existing file was overwritten. + PutFile(filename string, fileInfo FileInfo, overwrite bool) (existed bool, err error) } // FileInfo represents a file descriptor plus the content. diff --git a/lib/dos3/dos3.go b/lib/dos3/dos3.go index e9285ed..0dd2f33 100644 --- a/lib/dos3/dos3.go +++ b/lib/dos3/dos3.go @@ -657,11 +657,11 @@ func (o operator) Delete(filename string) (bool, error) { return false, fmt.Errorf("%s does not implement Delete yet", operatorName) } -// WriteRaw writes raw contents of a file by name. If the file exists -// and overwrite is false, it returns with an error. Otherwise it -// returns true if an existing file was overwritten. -func (o operator) WriteRaw(filename string, contents []byte, overwrite bool) (bool, error) { - return false, fmt.Errorf("%s does not implement WriteRaw yet", operatorName) +// PutFile writes a file by name. If the file exists and overwrite +// is false, it returns with an error. Otherwise it returns true if +// an existing file was overwritten. +func (o operator) PutFile(filename string, fileInfo disk.FileInfo, overwrite bool) (existed bool, err error) { + return false, fmt.Errorf("%s does not implement PutFile yet", operatorName) } // operatorFactory is the factory that returns dos3 operators given diff --git a/lib/notes.org b/lib/notes.org index 4387613..559234c 100644 --- a/lib/notes.org +++ b/lib/notes.org @@ -55,3 +55,10 @@ Beneath Apple ProDOS Table E.1 | FD | VAR | ProDOS | Applesoft BASIC variables file | | FE | REL | ProDOS | EDASM relocatable object module file | | FF | SYS | ProDOS | System file | +** NakedOS FHELLO +20 40 03 JSR NAKEDOS +6D 01 DC ADC NKRDFILE +2C 02 DF BIT ${filename} +2C 00 E0 BIT ${target page} +F8 CLD +4C 00 E0 JMP ${target page} diff --git a/lib/supermon/supermon.go b/lib/supermon/supermon.go index 611a14d..af26f1e 100644 --- a/lib/supermon/supermon.go +++ b/lib/supermon/supermon.go @@ -659,10 +659,17 @@ func (o operator) Delete(filename string) (bool, error) { return existed, nil } -// WriteRaw writes raw contents of a file by name. If the file exists -// and overwrite is false, it returns with an error. Otherwise it -// returns true if an existing file was overwritten. -func (o operator) WriteRaw(filename string, contents []byte, overwrite bool) (bool, error) { +// PutFile writes a file by name. If the file exists and overwrite +// is false, it returns with an error. Otherwise it returns true if +// an existing file was overwritten. +func (o operator) PutFile(filename string, fileInfo disk.FileInfo, overwrite bool) (existed bool, err error) { + if fileInfo.Descriptor.Type != disk.FiletypeBinary { + return false, fmt.Errorf("%s: only binary file type supported", operatorName) + } + if fileInfo.Descriptor.Length != len(fileInfo.Data) { + return false, fmt.Errorf("mismatch between FileInfo.Descriptor.Length (%d) and actual length of FileInfo.Data field (%d)", fileInfo.Descriptor.Length, len(fileInfo.Data)) + } + numFile, namedFile, symbol, err := o.st.FilesForCompoundName(filename) if err != nil { return false, err @@ -681,7 +688,7 @@ func (o operator) WriteRaw(filename string, contents []byte, overwrite bool) (bo return false, fmt.Errorf("all files already used") } } - existed, err := o.sm.WriteFile(o.sd, numFile, contents, overwrite) + existed, err = o.sm.WriteFile(o.sd, numFile, fileInfo.Data, overwrite) if err != nil { return existed, err }