From 46b4462a9e6c89693e40a812040c6694e4892254 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 17 Apr 2021 09:58:22 -0700 Subject: [PATCH] Add CD command --- Makefile | 1 + README.md | 3 +- cd.cmd.s | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++++ copy.cmd.s | 10 +++ echo.cmd.s | 21 +---- package.sh | 2 +- prodos.inc | 16 ++++ 7 files changed, 270 insertions(+), 20 deletions(-) create mode 100644 cd.cmd.s diff --git a/Makefile b/Makefile index 7a501c2..a48d1f8 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ LDFLAGS := --config apple2-asm.cfg OUTDIR := out TARGETS := $(OUTDIR)/path.BIN \ + $(OUTDIR)/cd.CMD \ $(OUTDIR)/chtype.CMD $(OUTDIR)/chtime.CMD $(OUTDIR)/buzz.CMD \ $(OUTDIR)/copy.CMD $(OUTDIR)/date.CMD $(OUTDIR)/type.CMD \ $(OUTDIR)/bell.CMD $(OUTDIR)/hello.CMD $(OUTDIR)/echo.CMD $(OUTDIR)/online.CMD diff --git a/README.md b/README.md index e561930..930cd6f 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Build with [ca65](https://cc65.github.io/doc/ca65.html) ## Instructions For Users Installation: -* Copy files from the floppy disk image to your Apple's hard disk, in a subdirectory e.g. `/HD/CMD` +* Copy files from the floppy disk image to your Apple's hard disk, in a subdirectory e.g. `/HD/CMD` * From BASIC.SYSTEM prompt, run: `PATH`, e.g. `-/HD/CMD/PATH`, either from `STARTUP` or manually After installation, the usage is: @@ -40,6 +40,7 @@ Notes: Sample commands included: * `HELLO` - shows a short message, for testing purposes * `ECHO` - echoes back anything following the command +* `CD` - like `PREFIX` but accepts `..`, e.g. `cd ../dir` * `ONLINE` - lists online volumes (volume name, slot and drive) * `COPY` - copy a single file, e.g. `copy /path/to/file,dstfile` * `TYPE` - show file contents (TXT, BAS, or BIN/other), e.g. `type filename` diff --git a/cd.cmd.s b/cd.cmd.s new file mode 100644 index 0000000..6922d09 --- /dev/null +++ b/cd.cmd.s @@ -0,0 +1,237 @@ +;;; ============================================================ +;;; +;;; CD - Change Directory (like PREFIX, plus .. support) +;;; +;;; Usage: CD path +;;; +;;; * path can be absolute, e.g. CD /VOL/DIR +;;; * path can be relative, e.g. CD SUBDIR/SUBDIR +;;; * segments can be .. to go up a dir, e.g. CD ../DIR +;;; * segments can be . to mean same dir, e.g. CD ./SUBDIR +;;; * with no path, echoes current PREFIX +;;; +;;; ============================================================ + + .include "apple2.inc" + .include "more_apple2.inc" + .include "prodos.inc" + +;;; ============================================================ + + .org $4000 + + ;; Follow the BI external command protocol. Although + ;; the parser is not used, this allows returning + ;; BI error codes. + + ;; Point BI's parser at the command execution routine. + lda #execute + sta XTRNADDR+1 + + ;; Mark command as external (zero). + lda #0 + sta XCNUM + + ;; Set accepted parameter flags + lda #0 + sta PBITS + lda #0 + sta PBITS+1 + + clc ; Success (so far) +rts1: rts ; Return to BASIC.SYSTEM + +;;; ============================================================ + + PFXBUF := $280 + tmp := $06 + +execute: + ;; Skip command and leading spaces + ldx XLEN + inx + jsr SkipSpaces + + ;; Absolute? + lda INBUF,x + cmp #'/'|$80 + beq abs + + ;; No, will need current prefix + stx tmp + jsr GetPrefix + bcs rts1 + ldx tmp + + ;; Empty? + lda INBUF,x + cmp #$8D ; CR + bne common ; no, start processing + + ;; Echo the current prefix + jsr CROUT + ldx #0 +: inx + lda PFXBUF,x + ora #$80 + jsr COUT + cpx PFXBUF + bne :- + jsr CROUT + jsr CROUT + clc + rts + +;;; -------------------------------------------------- +;;; Absolute path + +abs: lda #1 ; init prefix to just '/' + sta PFXBUF + lda #'/' + sta PFXBUF+1 + inx ; consume leading '/' + ;; fall through + +;;; -------------------------------------------------- +;;; Process the relative path +;;; +;;; PFXBUF has the prefix; Y holds the length +;;; X holds position in INBUF + +common: ldy PFXBUF + + ;; Loop over segments +loop: jsr GetC + cmp #$D ; EOL? + beq done + + cmp #'.' ; Maybe "." or ".." ? + beq dot + +put: jsr PutC + jsr GetC + + cmp #$D ; EOL? + beq done + cmp #'/' ; end of segment? + bne put + jsr PutC + bne loop ; always + +dot: jsr GetC + cmp #'.' ; ".." ? + bne :+ + jsr Pop ; yes, pop the last segment + jsr GetC +: cmp #$D ; EOL? + beq done ; groovy + cmp #'/' ; "./" or "../"? + beq loop ; also groovy + + lda #BI_ERR_SYNTAX_ERROR + sec + rts + +;;; -------------------------------------------------- +;;; Try setting the new PREFIX + +done: sty PFXBUF + MLI_CALL SET_PREFIX, get_set_prefix_params + bcc :+ + jsr BADCALL ; Convert MLI error to BI error +: rts + + +;;; ============================================================ +;;; Pop a segment +.proc Pop + cpy #1 + beq done +: dey + lda PFXBUF,y + cmp #'/' + bne :- + +done: rts +.endproc + +;;; ============================================================ +;;; Get next character from INBUF at X. +.proc GetC + lda INBUF,x + inx + and #$7F + rts +.endproc + +;;; ============================================================ +;;; Append to PFXBUF at Y. Returns non-zero. +.proc PutC + iny + sta PFXBUF,y + rts +.endproc + +;;; ============================================================ +;;; Skip over spaces in INBUF, advancing X; returns first non-space. +.proc SkipSpaces +repeat: lda INBUF,x + cmp #' '|$80 + beq :+ + rts +: inx + jmp repeat +.endproc + +;;; ============================================================ +;;; Leave PREFIX at PFXBUF; infers it the same way as BI if empty. +;;; Returns with Carry set on failure. +.proc GetPrefix + ;; Try fetching prefix + MLI_CALL GET_PREFIX, get_set_prefix_params + lda PFXBUF + bne done + + ;; Use BI's current slot and drive to construct unit number + lda DEFSLT ; xxxxxSSS + asl ; xxxxSSS0 + asl ; xxxSSS00 + asl ; xxSSS000 + asl ; xSSS0000 + asl ; SSS00000 + ldx DEFDRV + cpx #2 ; C=0 if 1, C=1 if 2 + ror ; DSSS0000 + sta unit + + ;; Get volume name and convert to path + MLI_CALL ON_LINE, on_line_params + bcc :+ + jsr BADCALL ; sets Carry + rts + +: lda PFXBUF+1 + and #$0F ; mask off name_len + tax + inx ; leading and trailing '/' + inx + stx PFXBUF + lda #'/' + sta PFXBUF+1 ; leading '/' + sta PFXBUF,x ; trailing '/' + +done: clc + rts + +on_line_params: + .byte 2 +unit: .byte 0 + .addr PFXBUF+1 ; leave room to insert leading '/' +.endproc + +get_set_prefix_params: + .byte 1 + .addr PFXBUF diff --git a/copy.cmd.s b/copy.cmd.s index d445aad..9a585e6 100644 --- a/copy.cmd.s +++ b/copy.cmd.s @@ -315,5 +315,15 @@ unit: .byte 0 done: rts .endproc +.proc SkipSpaces +repeat: lda INBUF,x + cmp #' '|$80 + beq :+ + rts +: inx + jmp repeat +.endproc + +cmd_length = .strlen("echo") .assert * <= FN2BUF, error, "Too long" diff --git a/echo.cmd.s b/echo.cmd.s index f69ef96..89a5473 100644 --- a/echo.cmd.s +++ b/echo.cmd.s @@ -1,31 +1,16 @@ .include "apple2.inc" .include "more_apple2.inc" + .include "prodos.inc" .org $4000 jsr CROUT ldx #0 - ;; Skip any leading spaces - jsr SkipSpaces - - ;; Invoked with "-" ? - lda INBUF,x - cmp #'-'|$80 - bne :+ + ;; Skip command and any leading spaces + ldx XLEN inx -: - ;; Skip any more leading spaces - jsr SkipSpaces - - ;; Skip command name (i.e. "echo") - txa - clc - adc #cmd_length - tax - - ;; Skip leading spaces before string to echo jsr SkipSpaces ;; Echo string diff --git a/package.sh b/package.sh index b65c35e..8a037e1 100755 --- a/package.sh +++ b/package.sh @@ -18,7 +18,7 @@ add_file () { } add_file "out/path.BIN" "path#062000" -for file in bell echo hello online chtype chtime copy date type buzz; do +for file in bell echo hello online chtype chtime copy date type buzz cd; do add_file "out/${file}.CMD" "${file}#F04000" done diff --git a/prodos.inc b/prodos.inc index 6ce0dd2..109574c 100644 --- a/prodos.inc +++ b/prodos.inc @@ -15,6 +15,7 @@ CREATE = $C0 SET_FILE_INFO = $C3 GET_FILE_INFO = $C4 ON_LINE = $C5 +SET_PREFIX = $C6 GET_PREFIX = $C7 OPEN = $C8 READ = $CA @@ -140,9 +141,24 @@ RSHIMEM := $BEFB ;;; Error Codes +BI_ERR_RANGE_ERROR = 2 +BI_ERR_NO_DEVICE_CONNECTED = 3 +BI_ERR_WRITE_PROTECTED = 4 BI_ERR_END_OF_DATA = 5 BI_ERR_PATH_NOT_FOUND = 6 BI_ERR_VOLUME_DIR_NOT_FOUND = 7 ; Also shows as PATH NOT FOUND +BI_ERR_IO_ERROR = 8 +BI_ERR_DISK_FULL = 9 +BI_ERR_FILE_LOCKED = 10 +BI_ERR_INVALID_PARAMETER = 11 BI_ERR_NO_BUFFERS_AVAILABLE = 12 BI_ERR_FILE_TYPE_MISMATCH = 13 +BI_ERR_PROGRAM_TOO_LARGE = 14 +BI_ERR_NOT_DIRECT_COMMAND = 15 +BI_ERR_SYNTAX_ERROR = 16 +BI_ERR_DIRECTORY_FULL = 17 +BI_ERR_FILE_NOT_OPEN = 18 BI_ERR_DUPLICATE_FILE_NAME = 19 +BI_ERR_FILE_BUSY = 20 +BI_ERR_FILES_STILL_OPEN = 21 +BI_ERR_DIRECT_COMMAND = 22