Compare commits

...

26 Commits
v1.3 ... main

Author SHA1 Message Date
Joshua Bell
b63dabb7cd Actions: Rev a couple dependencies 2024-01-31 20:31:14 -08:00
Joshua Bell
0c01446574 PATH: Shave 9 bytes 2024-01-02 22:17:14 -08:00
Joshua Bell
af1c8f1865 Shave 2 bytes from PATH 2024-01-01 21:43:55 -08:00
Joshua Bell
3360d44dd7 COPY: Preserve file modification time
Fixes #4
2024-01-01 19:35:14 -08:00
Joshua Bell
4bdb0808a2 Add HIDE / UNHIDE commands, to toggle the access "invisible" bit
This is used by the GS/OS Finder to conceal FINDER.DATA files.
Documented in "Exploring GS/OS and ProDOS 8" by Gary B. Little.
BASIC.SYSTEM's CAT/CATALOG are unaware of this, so the files are still
listed.

Note that the command is named "UNHIDE" rather than "SHOW" as that
sounds like a command to display file contents or something.
2023-05-11 09:37:00 -06:00
Joshua Bell
8cb8f98793 Workflows: bump ca65 action to v2 2023-03-02 20:02:32 -08:00
Joshua Bell
e21c518a06 Workflows: Bump ncipollo/release-action version 2022-11-29 18:38:59 -08:00
Joshua Bell
2c8d464108 Add MEM command, inspired by A2osX's BASIC.FX 2022-08-04 19:29:52 -07:00
Joshua Bell
e3f59575ed PATH: Fix missing relocation point
Oops - it's amazing anything worked.
2022-08-04 19:29:52 -07:00
Joshua Bell
6157963cc8 Workflow: use actions for cadius and ca65 2021-07-23 09:28:13 -07:00
Joshua Bell
ecf7459fb3 Workflow: Deploy on tag 2021-07-23 08:43:32 -07:00
Joshua Bell
7587db2f48 Migrate from Travis-CI to GitHub Actions 2021-06-19 17:22:51 -07:00
Joshua Bell
68f21a528b travis-ci.org -> .com 2021-06-09 20:20:29 -07:00
Joshua Bell
8a96373d9d whitespace change to trigger build 2021-05-15 09:00:35 -07:00
Joshua Bell
96b87c2180 Add TOUCH command 2021-05-02 11:16:11 -07:00
Joshua Bell
f124dd1bd5 Simplify make/package maintenance 2021-04-17 10:05:22 -07:00
Joshua Bell
46b4462a9e Add CD command 2021-04-17 09:58:22 -07:00
Joshua Bell
48f8921431
Update README.md 2021-04-15 20:05:51 -07:00
Joshua Bell
9971792f12 BI Error constants; coding style 2021-04-15 19:47:41 -07:00
Joshua Bell
827d121ef2 Use BI's general purposes buffer in PATH, and assume it's byte aligned
Also, use BI's GOSYSTEM in PATH since it's using BI structs anyway.
2021-04-15 19:12:04 -07:00
Joshua Bell
e20c65853d Handle ON_LINE errors 2021-04-14 22:27:39 -07:00
Joshua Bell
db4b9547b5 COPY: Fix issues with empty prefix. Fixes #3 2021-04-14 20:34:04 -07:00
Joshua Bell
42122f7a65 Add comments about relative path behavior w/o PREFIX set 2021-04-14 19:13:39 -07:00
Joshua Bell
e037edebcf Remove unnecessary parameter validation 2021-04-14 19:13:16 -07:00
Joshua Bell
86bafa4b76 Add BUZZ command 2021-04-13 21:20:12 -07:00
Joshua Bell
9085407ac5 Add DATE and TYPE commands 2021-04-13 19:12:07 -07:00
21 changed files with 1396 additions and 197 deletions

31
.github/workflows/main.yml vendored Normal file
View File

@ -0,0 +1,31 @@
name: build
on:
push:
branches: [ main ]
tags: ['*']
pull_request:
branches: [ main ]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: a2stuff/build-install-ca65-action@v2
- uses: a2stuff/build-install-cadius-action@v1
- name: build
env:
TERM: xterm-256color
run: >
make && make package
- name: deploy new version
if: startsWith(github.ref, 'refs/tags/')
uses: ncipollo/release-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
artifacts: "out/prodos-path.po"

View File

@ -1,11 +0,0 @@
sudo: enabled
os: linux
language: c
install:
- git clone https://github.com/cc65/cc65 /tmp/cc65 &&
sudo make -C /tmp/cc65 ca65 ld65 avail &&
ca65 --version
script:
- make

15
COMMANDS Normal file
View File

@ -0,0 +1,15 @@
bell
buzz
cd
chtime
chtype
copy
date
echo
hello
mem
online
type
touch
hide
unhide

View File

@ -5,9 +5,7 @@ LDFLAGS := --config apple2-asm.cfg
OUTDIR := out OUTDIR := out
TARGETS := $(OUTDIR)/path.BIN \ TARGETS := $(OUTDIR)/path.BIN \
$(OUTDIR)/chtype.CMD $(OUTDIR)/chtime.CMD \ $(shell cat COMMANDS | while read line; do echo "out/$${line}.CMD"; done)
$(OUTDIR)/copy.CMD \
$(OUTDIR)/bell.CMD $(OUTDIR)/hello.CMD $(OUTDIR)/echo.CMD $(OUTDIR)/online.CMD
XATTR := $(shell command -v xattr 2> /dev/null) XATTR := $(shell command -v xattr 2> /dev/null)

View File

@ -1,62 +1,81 @@
# CMD executable PATH for ProDOS's BASIC.SYSTEM # CMD executable PATH for ProDOS's BASIC.SYSTEM
[![Build Status](https://travis-ci.org/a2stuff/prodos-path.svg?branch=master)](https://travis-ci.org/a2stuff/prodos-path) [![build](https://github.com/a2stuff/prodos-path/actions/workflows/main.yml/badge.svg)](https://github.com/a2stuff/prodos-path/actions/workflows/main.yml)
💾 Disk images can be found on the [Releases](https://github.com/a2stuff/prodos-path/releases) page 💾 💾 Disk images can be found on the [Releases](https://github.com/a2stuff/prodos-path/releases) page 💾
Build with [ca65](https://cc65.github.io/doc/ca65.html) Build with [ca65](https://cc65.github.io/doc/ca65.html)
Installation: ## Instructions For Users
* Copy target to ProDOS disk
* From BASIC.SYSTEM prompt, run: `-PATH` from STARTUP (or by hand)
Usage: Installation:
* 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:
``` ```
PATH prefix - set search path(s) - colon delimited PATH prefix - set search path(s) - colon delimited
PATH - view current search path(s) PATH - view current search path(s)
cmdname - load and execute named CMD, if in PATH cmdname - load and execute named CMD, if in PATH
``` ```
Once set, binary files of type `CMD` in the specified directories can be invoked by name. * Once set, binary files of type `CMD` in the specified directories can be invoked by name.
* CMD file is loaded at $4000 and invoked; should return (`rts`) on completion.
* $4000-$5FFF is assumed reserved for the CMD file and any buffers it needs.
* The command line will be present at $200 (`GETLN` input buffer).
* Supports multi-segment, colon-separated paths, e.g. `/hd/cmds:/hd2/more.cmds` * Supports multi-segment, colon-separated paths, e.g. `/hd/cmds:/hd2/more.cmds`
* Commands can use the BI parser for arguments. See `chtype.cmd.s` for an example.
Example: Example:
``` ```
] -/hd/path - install it ] -/hd/cmd/path - install it
] PATH /hd/cmds:/h2/bin - set PATH ] PATH /hd/cmd:/h2/bin - set PATH
] PATH - verify path ] PATH - verify path
/hd/cmds /hd/cmd:/h2/bin
] BELL - will invoke /hd/cmds/BELL if present ] BELL - will invoke /hd/cmd/BELL if present
] HELLO - will invoke /hd/cmds/HELLO if present ] HELLO - will invoke /hd/cmd/HELLO if present
] ONLINE - will invoke /hd/cmds/ONLINE if present ] ONLINE - will invoke /hd/cmd/ONLINE if present
``` ```
Notes: Notes:
* `PATH` can be invoked as lower case (e.g. `path /hd/cmd`)
* Commands can be invoked as lower case (e.g. `hello`)
* A relative `PATH` (e.g. `path bin`) only works if an explicit prefix is set.
* Note that if no prefix has been set, or if you run `prefix /`, BASIC.SYSTEM will use the last accessed slot and drive and the `PREFIX` command will report that volume as a prefix even though it is empty.
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)
* `MEM` - show memory stats for the BASIC environment
* `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`
* `TOUCH` - apply current ProDOS date/time to a file's modification time, e.g. `touch filename`
* `DATE` - prints the current ProDOS date and time
* `CHTYPE` - change the type/auxtype of a file, e.g. `chtype file,T$F1,A$1234`
* `T` (type) and `A` (auxtype) are optional. If neither is specified, current types are shown.
* `S` and `D` arguments can be used to specify slot and drive.
* `CHTIME` - change the modification date/time of a file, e.g. `chtime file,A$1234,B$5678`
* `A` (date) and `B` (time) are optional. If neither is specified, current values are shown.
* `S` and `D` arguments can be used to specify slot and drive.
* `BELL` - emits the standard Apple II beep
* `BUZZ` - emits the ProDOS "nice little tone"
* `HIDE` / `UNHIDE` - sets / clears the "invisible" bit on a file, used in GS/OS Finder
## Instructions For Developers
Behavior of `PATH`:
* Search order when a command is typed: * Search order when a command is typed:
* ProDOS BASIC.SYSTEM intrinsics (`CAT`, `PREFIX`, etc) * ProDOS BASIC.SYSTEM intrinsics (`CAT`, `PREFIX`, etc)
* BASIC keywords (`LIST`, `PRINT`, etc) * BASIC keywords (`LIST`, `PRINT`, etc)
* CMD files in paths, in listed order * CMD files in paths, in listed order
* Allocates a permanent buffer to store the code and path (2 pages) * Allocates a permanent buffer to store the code and path (2 pages)
* `PATH` can be invoked as lower case (e.g. `path /DISK/CMDS`)
* Commands can be invoked as lower case (e.g. `hello`)
* Applesoft BASIC commands are unaffected (but can't be CMD names) * Applesoft BASIC commands are unaffected (but can't be CMD names)
* Commands with BASIC keywords as _prefixes_ are allowed as long as the command continues with an alphabetic character. For example, `ONLINE` is allowed despite conflicting with the valid BASIC statement `ONLINE GOTO10` which is short for `ON LINE GOTO 10`. * Commands with BASIC keywords as _prefixes_ are allowed as long as the command continues with an alphabetic character. For example, `ONLINE` is allowed despite conflicting with the valid BASIC statement `ONLINE GOTO10` which is short for `ON LINE GOTO 10`.
Sample commands included: Protocol for `CMD` files:
* Useful utilities:
* `ONLINE` - lists online volumes (volume name, slot and drive) * CMD file is loaded at $4000 and invoked; should return (`rts`) on completion.
* `COPY` - copy a single file, e.g. `copy /path/to/file,dstfile` * $4000-$5FFF is assumed reserved for the CMD file and any buffers it needs.
* `CHTYPE` - change the type/auxtype of a file. e.g. `chtype file,T$F1,A$1234` * The command line will be present at $200 (`GETLN` input buffer).
* `T` (type) and `A` (auxtype) are optional. If neither is specified, current types are shown. * Commands can use the BI parser for arguments. See `chtype.cmd.s` for an example.
* `S` and `D` arguments can be used to specify slot and drive.
* `CHTIME` - change the modification date/time of a file. e.g. `chtime file,A$1234,B$5678`
* `A` (date) and `B` (time) are optional. If neither is specified, current values are shown.
* `S` and `D` arguments can be used to specify slot and drive.
* Other examples:
* `BELL` - beeps the speaker
* `HELLO` - shows a short message
* `ECHO` - echoes back anything following the command

31
buzz.cmd.s Normal file
View File

@ -0,0 +1,31 @@
;;; ============================================================
;;; Bell
;;;
;;; From ProDOS 8 Technical Reference Manual 5.4:
;;; "The standard Apple II "Air-raid" bell has been replaced with a
;;; gentler tone. Use it to give users some aural feedback that
;;; they are using a ProDOS program."
.include "apple2.inc"
.include "more_apple2.inc"
.org $4000
length := $06
;;; Generate a nice little tone
;;; Exits with Z-flag set (BEQ) for branching
;;; Destroys the contents of the accumulator
lda #32 ;duration of tone
sta length
bell1: lda #2 ;short delay...click
jsr WAIT
sta SPKR
lda #32 ;long delay...click
jsr WAIT
sta SPKR
dec length
bne bell1 ;repeat length times
clc
rts

236
cd.cmd.s Normal file
View File

@ -0,0 +1,236 @@
;;; ============================================================
;;;
;;; 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
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

View File

@ -24,7 +24,6 @@
;; Point BI's parser at the command execution routine. ;; Point BI's parser at the command execution routine.
lda #<execute lda #<execute
sta XTRNADDR sta XTRNADDR
page_num2 := *+1 ; address needing updating
lda #>execute lda #>execute
sta XTRNADDR+1 sta XTRNADDR+1
@ -34,38 +33,20 @@
;; Set accepted parameter flags ;; Set accepted parameter flags
lda #PBitsFlags::FN1 ; Filename ;; Filename
lda #PBitsFlags::FN1
sta PBITS sta PBITS
;; Address, Byte, Slot & Drive handling ;; Address (A=Date word), Byte (B=Time word), Slot & Drive handling
lda #PBitsFlags::AD | PBitsFlags::B | PBitsFlags::SD lda #PBitsFlags::AD | PBitsFlags::B | PBitsFlags::SD
sta PBITS+1 sta PBITS+1
clc ; Success (so far) clc ; Success (so far)
rts ; Return to BASIC.SYSTEM rts1: rts ; Return to BASIC.SYSTEM
;;; ============================================================
not_ours:
sec ; Signal failure...
next_command := *+1
jmp $ffff ; Execute next command in chain
;;; ============================================================ ;;; ============================================================
execute: execute:
;; Verify required arguments
lda FBITS
and #PBitsFlags::FN1 ; Filename?
bne :+
lda #$10 ; SYNTAX ERROR
sec
rts1: rts
:
;;; --------------------------------------------------
;; Get the existing file info ;; Get the existing file info
lda #$A lda #$A
sta SSGINFO sta SSGINFO

View File

@ -25,7 +25,6 @@
;; Point BI's parser at the command execution routine. ;; Point BI's parser at the command execution routine.
lda #<execute lda #<execute
sta XTRNADDR sta XTRNADDR
page_num2 := *+1 ; address needing updating
lda #>execute lda #>execute
sta XTRNADDR+1 sta XTRNADDR+1
@ -33,32 +32,22 @@
lda #0 lda #0
sta XCNUM sta XCNUM
;; Set accepted parameter flags (Name, Type, Address) ;; Set accepted parameter flags
lda #PBitsFlags::T | PBitsFlags::FN1 ; Filename and Type ;; Filename and Type
lda #PBitsFlags::T | PBitsFlags::FN1
sta PBITS sta PBITS
lda #PBitsFlags::AD | PBitsFlags::SD ; Address, Slot & Drive handling ;; Address (used as AuxType), Slot & Drive handling
lda #PBitsFlags::AD | PBitsFlags::SD
sta PBITS+1 sta PBITS+1
clc ; Success (so far) clc ; Success (so far)
rts ; Return to BASIC.SYSTEM rts1: rts ; Return to BASIC.SYSTEM
;;; ============================================================ ;;; ============================================================
execute: execute:
;; Verify required arguments
lda FBITS
and #PBitsFlags::FN1 ; Filename?
bne :+
lda #$10 ; SYNTAX ERROR
sec
rts1: rts
:
;;; --------------------------------------------------
;; Get the existing file info ;; Get the existing file info
lda #$A lda #$A
sta SSGINFO sta SSGINFO

View File

@ -21,7 +21,6 @@
;; Point BI's parser at the command execution routine. ;; Point BI's parser at the command execution routine.
lda #<execute lda #<execute
sta XTRNADDR sta XTRNADDR
page_num2 := *+1 ; address needing updating
lda #>execute lda #>execute
sta XTRNADDR+1 sta XTRNADDR+1
@ -29,11 +28,11 @@
lda #0 lda #0
sta XCNUM sta XCNUM
;; Set accepted parameter flags (Name, Type, Address) ;; Set accepted parameter flags
lda #PBitsFlags::FN1 | PBitsFlags::FN2 ; Filenames lda #PBitsFlags::FN1 | PBitsFlags::FN2 ; Filenames
sta PBITS sta PBITS
lda #0 lda #0 ; See below for why PBitsFlags::SD is not used
sta PBITS+1 sta PBITS+1
clc ; Success (so far) clc ; Success (so far)
@ -41,13 +40,33 @@
;;; ============================================================ ;;; ============================================================
FN1REF := $D6
FN2REF := $D7
FN1INFO := $2EE FN1INFO := $2EE
FN1BUF := $4200 FN2BUF := $4200
FN2BUF := $4600 DATABUF := $4600
DATABUF := $4A00
DATALEN = $6000 - DATABUF DATALEN = $6000 - DATABUF
execute: execute:
;; Fix relative paths. If PREFIX is not emptu, this is not needed.
;; If PREFIX is empty, then relative paths will fail. Specifying
;; PBitsFlags::SD is the usual fix for BI commands that take paths
;; but while it will make FN1 absolute if needed it applies the
;; same change to FN2 (nothing or prepending) without inspecting
;; FN2. So REL,/ABS becomes /PFX/REL,/PFX//ABS (oops!) and
;; /ABS,REL remains /ABS,REL (still relative!).
jsr GetPrefix
bcs rts1
lda VPATH1
ldx VPATH1+1
jsr FixPath
lda VPATH2
ldx VPATH2+1
jsr FixPath
;; Get FN1 info ;; Get FN1 info
lda #$A lda #$A
sta SSGINFO sta SSGINFO
@ -57,9 +76,9 @@ execute:
;; Reject directory file ;; Reject directory file
lda FIFILID lda FIFILID
cmp #$F ; DIR cmp #FT_DIR
bne :+ bne :+
lda #$D ; FILE TYPE MISMATCH lda #BI_ERR_FILE_TYPE_MISMATCH
sec sec
rts1: rts rts1: rts
: :
@ -72,9 +91,7 @@ rts1: rts
bpl :- bpl :-
;; Open FN1 ;; Open FN1
lda #<FN1BUF lda HIMEM+1 ; Use BI's general purpose buffer (page aligned)
sta OSYSBUF
lda #>FN1BUF
sta OSYSBUF+1 sta OSYSBUF+1
lda #OPEN lda #OPEN
jsr GOSYSTEM jsr GOSYSTEM
@ -101,21 +118,21 @@ rts1: rts
dey dey
bpl :- bpl :-
;; Get FN1 info ;; Get FN2 info
lda #GET_FILE_INFO lda #GET_FILE_INFO
jsr GOSYSTEM jsr GOSYSTEM
bcs :+ bcs :+
lda #$13 ; DUPLICATE FILE NAME lda #BI_ERR_DUPLICATE_FILE_NAME
err: pha err: pha
jsr close jsr CloseFiles
pla pla
sec sec
rts rts
: cmp #6 ; BI Errors 6 and 7 cover : cmp #BI_ERR_PATH_NOT_FOUND
beq :+ ; vol dir, pathname, or filename beq :+
cmp #7 ; not found. cmp #BI_ERR_VOLUME_DIR_NOT_FOUND
bne err ; Otherwise - fail. bne err ; Otherwise - fail.
: :
@ -158,7 +175,7 @@ read: lda FN1REF
lda #READ lda #READ
jsr GOSYSTEM jsr GOSYSTEM
bcc :+ bcc :+
cmp #5 ; END OF DATA cmp #BI_ERR_END_OF_DATA
beq finish beq finish
: :
@ -179,11 +196,23 @@ read: lda FN1REF
jmp err jmp err
finish: jsr close finish: jsr CloseFiles
;; Apply FN1 info to FN2 to preserve modification date
ldx #$D - 3
: lda FN1INFO+3,x
sta SSGINFO+3,x
dex
bpl :-
lda #$7
sta SSGINFO
lda #SET_FILE_INFO
jsr GOSYSTEM
clc clc
rts rts
.proc close .proc CloseFiles
lda FN1REF lda FN1REF
sta CFREFNUM sta CFREFNUM
lda #CLOSE lda #CLOSE
@ -195,7 +224,117 @@ finish: jsr close
rts rts
.endproc .endproc
FN1REF: .byte 0 ;;; Leave PREFIX at INBUF; infers it the same way as BI if empty.
FN2REF: .byte 0 ;;; Returns with Carry set on failure.
.proc GetPrefix
;; Try fetching prefix
MLI_CALL GET_PREFIX, get_prefix_params
lda INBUF
bne done
.assert * <= FN1BUF, error, "Too long" ;; 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 INBUF+1
and #$0F ; mask off name_len
tax
inx ; leading and trailing '/'
inx
stx INBUF
lda #'/'
sta INBUF+1 ; leading '/'
sta INBUF,x ; trailing '/'
done: clc
rts
get_prefix_params:
.byte 1
.addr INBUF
on_line_params:
.byte 2
unit: .byte 0
.addr INBUF+1 ; leave room to insert leading '/'
.endproc
;;; Fix path passed in A,X if it's relative. Uses prefix in INBUF
.proc FixPath
ptr := $06
ptr2 := $08
sta ptr
stx ptr+1
;; Already relative?
ldy #1
lda (ptr),y
cmp #'/'
beq done
;; Compute new length
ldy #0
lda (ptr),y
tay ; Y = current length
clc
adc INBUF ; add prefix length
pha ; stash for later
;; Shift path up to make room
lda INBUF
clc
adc ptr
sta ptr2
lda #0
adc ptr+1
sta ptr2+1
: lda (ptr),y
sta (ptr2),y
dey
bpl :-
;; Insert prefix
lda INBUF
tax
tay
: lda INBUF,x
sta (ptr),y
dex
dey
bne :-
;; Assign final length
pla
ldy #0
sta (ptr),y
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"

133
date.cmd.s Normal file
View File

@ -0,0 +1,133 @@
;;; ============================================================
;;;
;;; DATE - Print the current date/time
;;;
;;; Usage: DATE
;;;
;;; NOTE: Only supports 2 digit years
;;;
;;; ============================================================
.include "apple2.inc"
.include "more_apple2.inc"
.include "prodos.inc"
;;; ============================================================
.org $4000
start:
jsr CROUT
;;; 49041 ($BF91) 49040 ($BF90)
;;; 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;;; DATE: | year | month | day |
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;;;
;;; 49043 ($BF93) 49042 ($BF92)
;;; 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;;; TIME: |0 0 0| hour | |0 0| minute |
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
lda #GET_TIME
jsr GOSYSTEM
lda DATELO
ora DATEHI
beq not_set
;; Date
lda DATELO+1 ; month
ror a
pha
lda DATELO
pha
rol a
rol a
rol a
rol a
and #%00001111
jsr PrintNumber
lda #'/'|$80 ; /
jsr COUT
pla ; day
and #%00011111
jsr PrintNumber
lda #'/'|$80 ; /
jsr COUT
pla ; year
jsr PrintNumber
lda #' '|$80 ;
jsr COUT
jsr COUT
;; Time
lda TIMELO+1 ; hour
and #%00011111
jsr PrintNumber
lda #':'|$80 ; ':'
jsr COUT
lda TIMELO ; minute
and #%00111111
jsr PrintNumber
finish: jsr CROUT
clc
rts
not_set:
ldx #0
: lda msg,x
beq finish
ora #$80
jsr COUT
inx
bne :- ; always
msg: .byte "<NO DATE>", 0
;;; ============================================================
;;; Print a 2-digit number, with leading zeros
.proc PrintNumber
;; Reduce to 2 digits
: cmp #100
bcc :+
sec
sbc #100
bne :-
;; Leading zero?
: ldx #0
cmp #10 ; >= 10?
bcc tens
;; Divide by 10, dividend(+'0') in X remainder in A
: sbc #10
inx
cmp #10
bcs :-
tens: pha
txa
ora #'0'|$80 ; convert to digit
jsr COUT
units: pla
ora #'0'|$80 ; convert to digit
jsr COUT
rts
.endproc

View File

@ -1,32 +1,17 @@
.include "apple2.inc" .include "apple2.inc"
.include "more_apple2.inc" .include "more_apple2.inc"
.include "prodos.inc"
.org $4000 .org $4000
jsr CROUT jsr CROUT
ldx #0 ldx #0
;; Skip any leading spaces ;; Skip command and any leading spaces
jsr skip_spaces ldx XLEN
;; Invoked with "-" ?
lda INBUF,x
cmp #'-'|$80
bne :+
inx inx
: jsr SkipSpaces
;; Skip any more leading spaces
jsr skip_spaces
;; Skip command name (i.e. "echo")
txa
clc
adc #cmd_length
tax
;; Skip leading spaces before string to echo
jsr skip_spaces
;; Echo string ;; Echo string
: lda INBUF,x : lda INBUF,x
@ -39,13 +24,13 @@
exit: clc exit: clc
rts rts
.proc skip_spaces .proc SkipSpaces
lda INBUF,x repeat: lda INBUF,x
cmp #' '|$80 cmp #' '|$80
beq :+ beq :+
rts rts
: inx : inx
jmp skip_spaces jmp repeat
.endproc .endproc
cmd_length = .strlen("echo") cmd_length = .strlen("echo")

68
hide.cmd.s Normal file
View File

@ -0,0 +1,68 @@
;;; ============================================================
;;;
;;; HIDE - Mark a file as invisible
;;;
;;; Usage: HIDE filename[,S#][,D#]
;;;
;;; * filename can be relative or absolute path
;;;
;;; ============================================================
.include "apple2.inc"
.include "more_apple2.inc"
.include "prodos.inc"
;;; ============================================================
.org $4000
;; NOTE: Assumes XLEN is set by PATH
;; Point BI's parser at the command execution routine.
lda #<execute
sta XTRNADDR
lda #>execute
sta XTRNADDR+1
;; Mark command as external (zero).
lda #0
sta XCNUM
;; Set accepted parameter flags
;; Filename
lda #PBitsFlags::FN1
sta PBITS
;; Slot & Drive handling
lda #PBitsFlags::SD
sta PBITS+1
clc ; Success (so far)
rts1: rts ; Return to BASIC.SYSTEM
;;; ============================================================
execute:
;; Get the existing file info
lda #$A
sta SSGINFO
lda #GET_FILE_INFO
jsr GOSYSTEM
bcs rts1
;;; --------------------------------------------------
;; Clear invisible bit
lda FIACESS
ora #ACCESS_I
sta FIACESS
;; Set new file info
lda #$7
sta SSGINFO
lda #SET_FILE_INFO
jmp GOSYSTEM
;;; --------------------------------------------------

76
mem.cmd.s Normal file
View File

@ -0,0 +1,76 @@
;;; ============================================================
;;;
;;; MEM - Print memory stats
;;;
;;; Usage: MEM
;;;
;;; Inspiration from A2osX
;;;
;;; ============================================================
.include "apple2.inc"
.include "more_apple2.inc"
;;; ============================================================
.org $4000
jsr CROUT
jsr CROUT
.macro SHOW suffix
lda #<.ident(.concat("str_", .string(suffix)))
ldx #>.ident(.concat("str_", .string(suffix)))
ldy #.ident(.concat("addr_", .string(suffix)))
jsr Print
.endmacro
SHOW pgm_start
SHOW lomem
SHOW array_start
SHOW array_end
SHOW string_start
SHOW himem
clc
rts
addr_pgm_start := $67
str_pgm_start: .byte "Program start: $", 0
addr_lomem := $69
str_lomem: .byte "LOMEM: $", 0
addr_array_start := $6B
str_array_start: .byte "Array start: $", 0
addr_array_end := $6D
str_array_end: .byte "Array end: $", 0
addr_string_start := $6F
str_string_start: .byte "String start: $", 0
addr_himem := $73
str_himem: .byte "HIMEM: $", 0
.proc Print
sta msg_addr
stx msg_addr+1
iny ; MSB first
sty zp_addr
ldx #0
msg_addr := *+1
loop: lda $1234,x ; self-modified
beq :+
ora #$80
jsr COUT
inx
bne loop ; always
:
jsr getb
jsr PRBYTE
jsr getb
jsr PRBYTE
jmp CROUT
zp_addr := *+1
getb: lda $12 ; self-modified
dec zp_addr
rts
.endproc

View File

@ -3,9 +3,21 @@
INBUF := $200 INBUF := $200
;;; ============================================================
;;; Zero Page
LINUM := $1B
;;; ============================================================
;;; I/O Locations
SPKR := $C030
;;; ============================================================ ;;; ============================================================
;;; Monitor ROM routines ;;; Monitor ROM routines
PRTAX := $F941
WAIT := $FCA8
CROUT := $FD8E CROUT := $FD8E
PRBYTE := $FDDA PRBYTE := $FDDA
COUT := $FDED COUT := $FDED
@ -20,4 +32,5 @@ BELL := $FF3A
;;; ============================================================ ;;; ============================================================
;;; Applesoft ROM locations ;;; Applesoft ROM locations
TOKEN_NAME_TABLE := $D0D0 TOKTABL := $D0D0
LINPRT := $ED24

View File

@ -18,7 +18,7 @@ add_file () {
} }
add_file "out/path.BIN" "path#062000" add_file "out/path.BIN" "path#062000"
for file in bell echo hello online chtype chtime copy; do for file in $(cat COMMANDS); do
add_file "out/${file}.CMD" "${file}#F04000" add_file "out/${file}.CMD" "${file}#F04000"
done done

133
path.s
View File

@ -35,7 +35,7 @@ CASE_MASK = $DF
lda #handler_pages lda #handler_pages
jsr GETBUFR jsr GETBUFR
bcc :+ bcc :+
lda #$C ; NO BUFFERS AVAILABLE lda #BI_ERR_NO_BUFFERS_AVAILABLE
rts rts
: sta new_page ; A = MSB of new page : sta new_page ; A = MSB of new page
@ -136,7 +136,7 @@ page_delta:
.proc handler .proc handler
ptr := $06 ; pointer into VPATH ptr := $06 ; pointer into VPATH
tptr := $08 ; pointer into TOKEN_NAME_TABLE tptr := $08 ; pointer into TOKTABL
lda VPATH1 lda VPATH1
sta ptr sta ptr
@ -145,12 +145,12 @@ page_delta:
;; Check for this command, character by character. ;; Check for this command, character by character.
reloc_point *+2 reloc_point *+2
jsr skip_leading_spaces jsr SkipLeadingSpaces
ldy #0 ; position in command string ldy #0 ; position in command string
reloc_point *+2 reloc_point *+2
nxtchr: jsr to_upper_ascii nxtchr: jsr ToUpperASCII
reloc_point *+2 reloc_point *+2
cmp command_string,y cmp command_string,y
@ -171,16 +171,15 @@ nxtchr: jsr to_upper_ascii
lda #>execute lda #>execute
sta XTRNADDR+1 sta XTRNADDR+1
;; Mark command as external (zero).
lda #0
sta XCNUM
;; Set accepted parameter flags (optional name) ;; Set accepted parameter flags (optional name)
lda #PBitsFlags::FNOPT | PBitsFlags::FN1 lda #PBitsFlags::FNOPT | PBitsFlags::FN1
sta PBITS sta PBITS
lda #0 lda #0
sta PBITS+1 sta PBITS+1
;; Mark command as external (zero).
sta XCNUM ; A=0 from above
clc ; Success (so far) clc ; Success (so far)
rts ; Return to BASIC.SYSTEM rts ; Return to BASIC.SYSTEM
@ -193,9 +192,9 @@ check_if_token:
beq not_ours beq not_ours
reloc_point *+2 reloc_point *+2
jsr skip_leading_spaces jsr SkipLeadingSpaces
reloc_point *+2 reloc_point *+2
jsr to_upper_ascii jsr ToUpperASCII
cmp #'A' cmp #'A'
bcc not_ours bcc not_ours
@ -204,15 +203,15 @@ check_if_token:
;; Check if it's a BASIC token. Based on the AppleSoft BASIC source. ;; Check if it's a BASIC token. Based on the AppleSoft BASIC source.
;; Point tptr at TOKEN_NAME_TABLE less one page (will advance below) ;; Point tptr at TOKTABL less one page (will advance below)
lda #<(TOKEN_NAME_TABLE-$100) lda #<(TOKTABL-$100)
sta tptr sta tptr
lda #>(TOKEN_NAME_TABLE-$100) lda #>(TOKTABL-$100)
sta tptr+1 sta tptr+1
;; These are immediately incremented ;; These are immediately incremented
dex dex
ldy #$FF ; (tptr),y offset TOKEN_NAME_TABLE ldy #$FF ; (tptr),y offset TOKTABL
;; Match loop ;; Match loop
mloop: iny ; Advance through token table mloop: iny ; Advance through token table
@ -223,7 +222,7 @@ mloop: iny ; Advance through token table
;; Check for match ;; Check for match
next_char: next_char:
reloc_point *+2 reloc_point *+2
jsr to_upper_ascii ; Next character jsr ToUpperASCII ; Next character
;; NOTE: Does not skip over spaces, unlike BASIC tokenizer ;; NOTE: Does not skip over spaces, unlike BASIC tokenizer
@ -238,7 +237,8 @@ next_char:
;; without preventing 'RUN100' from being typed. ;; without preventing 'RUN100' from being typed.
inx inx
jsr to_upper_ascii reloc_point *+2
jsr ToUpperASCII
cmp #'A' cmp #'A'
bcc not_ours bcc not_ours
cmp #'Z'+1 cmp #'Z'+1
@ -247,14 +247,14 @@ next_char:
;; Otherwise, advance to next token ;; Otherwise, advance to next token
next_token: next_token:
reloc_point *+2 reloc_point *+2
jsr skip_leading_spaces jsr SkipLeadingSpaces
sloop: lda (tptr),y ; Scan table looking for a high bit set sloop: lda (tptr),y ; Scan table looking for a high bit set
iny iny
bne :+ bne :+
inc tptr+1 inc tptr+1
: asl : asl
bcc sloop ; High bit clear, keep looking bcc sloop ; High bit clear, keep looking
lda (tptr),y ; End of table? lda (tptr),y ; End of table?
bne next_char ; Nope, check for a match bne next_char ; Nope, check for a match
beq maybe_invoke beq maybe_invoke
@ -302,9 +302,9 @@ compose:
;; Name from command line ;; Name from command line
reloc_point *+2 reloc_point *+2
jsr skip_leading_spaces jsr SkipLeadingSpaces
reloc_point *+2 reloc_point *+2
: jsr to_upper_ascii : jsr ToUpperASCII
cmp #'.' cmp #'.'
beq ok beq ok
cmp #'0' cmp #'0'
@ -330,28 +330,26 @@ notok: dey
;; Indicate end of command string for BI's parser (if command uses it) ;; Indicate end of command string for BI's parser (if command uses it)
dex dex
stx XLEN stx xlen ; assigned to `XLEN` later
;; Check to see if path exists. ;; Check to see if path exists.
lda #$A ; param length lda #$A ; param length
sta SSGINFO sta SSGINFO
MLI_CALL GET_FILE_INFO, SSGINFO lda #GET_FILE_INFO
jsr GOSYSTEM
bne compose ; no such file - try next path directory bne compose ; no such file - try next path directory
;; Check to see if type is CMD. ;; Check to see if type is CMD.
lda FIFILID lda FIFILID
cmp #$F0 ; CMD cmp #FT_CMD
bne compose ; wrong type - try next path directory bne compose ; wrong type - try next path directory
;; Tell BASIC.SYSTEM it was handled. ;; Tell BASIC.SYSTEM it was handled.
lda #0 ldx #xtrnaddr_len - 1
sta XCNUM : lda xtrnaddr,x
sta PBITS sta XTRNADDR,x
sta PBITS+1 dex
lda #<XRETURN bpl :-
sta XTRNADDR
lda #>XRETURN
sta XTRNADDR+1
;; MLI/BI trashes part of INBUF (clock driver?), so stash it in upper half. ;; MLI/BI trashes part of INBUF (clock driver?), so stash it in upper half.
ldx #$7F ldx #$7F
@ -360,36 +358,36 @@ notok: dey
dex dex
bpl :- bpl :-
;; Reserve buffer for I/O ;; Use BI general purpose buffer for I/O (page aligned)
lda #4 lda HIMEM+1
jsr GETBUFR sta OSYSBUF+1
bcc :+
lda #$C ; NO BUFFERS AVAILABLE
rts
: sta OSYSBUF+1
;; Now try to open/read/close and invoke it ;; Now try to open/read/close and invoke it
MLI_CALL OPEN, SOPEN lda #OPEN
bne fail_load jsr GOSYSTEM
bcs fail_load
lda OREFNUM lda OREFNUM
sta RWREFNUM sta RWREFNUM
sta CFREFNUM sta CFREFNUM
lda #<cmd_load_addr ;; Assign `RWDATA` and `RWCOUNT`
sta RWDATA ldx #rwdata_len - 1
lda #>cmd_load_addr : lda rwdata,x
sta RWDATA+1 sta RWDATA,x
lda #<max_cmd_size dex
sta RWCOUNT bpl :-
lda #>max_cmd_size
sta RWCOUNT+1
MLI_CALL READ, SREAD lda #READ
bne fail_load jsr GOSYSTEM
php ; save C in case it signals failure
pha ; if so, A has error code
MLI_CALL CLOSE, SCLOSE lda #CLOSE ; always close
jsr FREEBUFR jsr GOSYSTEM
pla
plp
bcs fail_load
;; Restore INBUF now that MLI/BI work is done. ;; Restore INBUF now that MLI/BI work is done.
ldx #$7F ldx #$7F
@ -398,17 +396,28 @@ notok: dey
dex dex
bpl :- bpl :-
;; Invoke command ;; Invoke command, allow it to return to BASIC.SYSTEM
jsr cmd_load_addr jmp cmd_load_addr
rts ; Return to BASIC.SYSTEM
fail_load: fail_load:
jsr FREEBUFR rts
reloc_point *+2
jmp fail_invoke
;;; Assigned to `XTRNADDR`, `XLEN`, `XCNUM`, and `PBITS`
xtrnaddr:
.addr XRETURN ; assigned to `XTRNADDR`
xlen: .byte 0 ; assigned to `XLEN`
.byte 0 ; assigned to `XCNUM`
.word 0 ; assigned to `PBITS`
xtrnaddr_len = * - xtrnaddr
;;; Assigned to `RWDATA` and `RWCOUNT`
rwdata:
.addr cmd_load_addr ; assigned to `RWDATA`
.word max_cmd_size ; assigned to `RWCOUNT`
rwdata_len = * - rwdata
;;; ============================================================
;;; ============================================================ ;;; ============================================================
execute: execute:
@ -456,7 +465,7 @@ set_path:
;;; Returns INBUF,x with high bit stripped and up-cased ;;; Returns INBUF,x with high bit stripped and up-cased
;;; (also converts {|}~DEL to [\]^_ but that's okay) ;;; (also converts {|}~DEL to [\]^_ but that's okay)
.proc to_upper_ascii .proc ToUpperASCII
lda INBUF,x lda INBUF,x
and #$7F and #$7F
cmp #'a' cmp #'a'
@ -468,7 +477,7 @@ skip: rts
;;; Returns with X pointing at first non-space in INBUF, ;;; Returns with X pointing at first non-space in INBUF,
;;; and that character loaded in A. ;;; and that character loaded in A.
.proc skip_leading_spaces .proc SkipLeadingSpaces
ldx #$FF ldx #$FF
: inx : inx
lda INBUF,x lda INBUF,x

View File

@ -2,12 +2,21 @@
;;; ProDOS MLI / Global Page ;;; ProDOS MLI / Global Page
MLI := $BF00 MLI := $BF00
DEVNUM := $BF30
DATE := $BF90 DATE := $BF90
DATELO := $BF90
DATEHI := $BF91
TIME := $BF92
TIMELO := $BF92
TIMEHI := $BF93
GET_TIME = $82
CREATE = $C0 CREATE = $C0
SET_FILE_INFO = $C3 SET_FILE_INFO = $C3
GET_FILE_INFO = $C4 GET_FILE_INFO = $C4
ON_LINE = $C5 ON_LINE = $C5
SET_PREFIX = $C6
GET_PREFIX = $C7
OPEN = $C8 OPEN = $C8
READ = $CA READ = $CA
WRITE = $CB WRITE = $CB
@ -19,16 +28,30 @@ CLOSE = $CC
.addr params .addr params
.endmacro .endmacro
FT_TXT = $04
FT_DIR = $0F
FT_CMD = $F0
FT_BAS = $FC
ACCESS_D = %10000000 ; Access: Destroy-Enable
ACCESS_RN = %01000000 ; Access: Rename-Enable
ACCESS_B = %00100000 ; Access: Backup
ACCESS_I = %00000100 ; Access: Invisible
ACCESS_W = %00000010 ; Access: Write-Enable
ACCESS_R = %00000001 ; Access: Read-Enable
;;; ============================================================ ;;; ============================================================
;;; BASIC.SYSTEM Global Page ;;; BASIC.SYSTEM Global Page
EXTRNCMD := $BE06 ; External command jmp vector EXTRNCMD := $BE06 ; External command jmp vector
ERROUT := $BE09 ; Error routine jmp vector ERROUT := $BE09 ; Error routine jmp vector
XTRNADDR := $BE50 ; Ext cmd implementation addr
DEFSLT := $BE3C ; Default slot, set by 'S' parm
DEFDRV := $BE3D ; Default drive, set by 'D' parm
XTRNADDR := $BE50 ; Ext cmd implementation addr
XLEN := $BE52 ; Length of command string minus 1 XLEN := $BE52 ; Length of command string minus 1
XCNUM := $BE53 ; Command number (ext cmd = 0). XCNUM := $BE53 ; Command number (ext cmd = 0).
PBITS := $BE54 ; Command parameter bits PBITS := $BE54 ; Command parameter bits
FBITS := $BE56 ; Found parameter bits FBITS := $BE56 ; Found parameter bits
@ -68,6 +91,7 @@ VPATH2 := $BE6E ; Pathname 2 buffer (RENAME)
GOSYSTEM := $BE70 ; Use instead of MLI GOSYSTEM := $BE70 ; Use instead of MLI
BADCALL := $BE8B ; convert MLI errors into BI equivalents
XRETURN := $BE9E ; Handy RTS XRETURN := $BE9E ; Handy RTS
@ -121,3 +145,27 @@ CCCSPARE := $BEDF
GETBUFR := $BEF5 GETBUFR := $BEF5
FREEBUFR := $BEF8 FREEBUFR := $BEF8
RSHIMEM := $BEFB 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

63
touch.cmd.s Normal file
View File

@ -0,0 +1,63 @@
;;; ============================================================
;;;
;;; TOUCH - Apply current ProDOS date/time stamp to file
;;;
;;; Usage: TOUCH filename[,S#][,D#]
;;;
;;; * filename can be relative or absolute path
;;;
;;; ============================================================
.include "apple2.inc"
.include "more_apple2.inc"
.include "prodos.inc"
;;; ============================================================
.org $4000
;; Point BI's parser at the command execution routine.
lda #<execute
sta XTRNADDR
lda #>execute
sta XTRNADDR+1
;; Mark command as external (zero).
lda #0
sta XCNUM
;; Set accepted parameter flags
;; Filename
lda #PBitsFlags::FN1
sta PBITS
;; Slot & Drive handling
lda #PBitsFlags::SD
sta PBITS+1
clc ; Success (so far)
rts1: rts ; Return to BASIC.SYSTEM
;;; ============================================================
execute:
;; Get the existing file info
lda #$A
sta SSGINFO
lda #GET_FILE_INFO
jsr GOSYSTEM
bcs rts1
;; Apply time/date stamp
ldx #3
: lda DATE,x
sta FIMDATE,x
dex
bpl :-
;; Set new file info
lda #$7
sta SSGINFO
lda #SET_FILE_INFO
jmp GOSYSTEM

308
type.cmd.s Normal file
View File

@ -0,0 +1,308 @@
;;; ============================================================
;;;
;;; TYPE - Dump contents of files to the screen
;;;
;;; Usage: TYPE pathname[,S#][,D#]
;;;
;;; Inspiration from OmniType by William H. Tudor, Nibble 2/1989
;;;
;;; ============================================================
.include "apple2.inc"
.include "more_apple2.inc"
.include "prodos.inc"
;;; ============================================================
.org $4000
;; NOTE: Assumes XLEN is set by PATH
;; Point BI's parser at the command execution routine.
lda #<execute
sta XTRNADDR
lda #>execute
sta XTRNADDR+1
;; Mark command as external (zero).
lda #0
sta XCNUM
;; Set accepted parameter flags (Filename)
lda #PBitsFlags::FN1 ; Filename
sta PBITS
lda #PBitsFlags::SD ; Slot & Drive handling
sta PBITS+1
clc ; Success (so far)
rts ; Return to BASIC.SYSTEM
;;; ============================================================
DATABUF := INBUF
execute:
;; Get FN1 info
lda #$A
sta SSGINFO
lda #GET_FILE_INFO
jsr GOSYSTEM
bcs rts1
;; Reject directory file
lda FIFILID
cmp #FT_DIR
bne :+
lda #BI_ERR_FILE_TYPE_MISMATCH
sec
rts1: rts
:
;; Open the file
lda HIMEM+1 ; Use BI's general purpose buffer (page aligned)
sta OSYSBUF+1
lda #OPEN
jsr GOSYSTEM
bcs rts1
;; Prepare the read arguments
lda OREFNUM
sta RWREFNUM
sta CFREFNUM
lda #<DATABUF ; Stash read data here
sta RWDATA
lda #>DATABUF
sta RWDATA+1
lda #<1 ; Read one byte at a time
sta RWCOUNT
lda #>1
sta RWCOUNT+1
lda #0 ; For BASIC
sta LINUM
sta LINUM+1
lda FIFILID ; File type
cmp #FT_TXT
beq Text
cmp #FT_BAS
bne :+
jmp Basic
:
;; fall through
;;; ============================================================
;;; Generic (Binary) file
.proc Binary
repeat: jsr ReadByte
bcc :+
jmp Exit
: pha
;; Line prefix
jsr CROUT
lda #'$'|$80
jsr COUT
ldx LINUM
lda LINUM+1
jsr PRTAX
lda #'-'|$80
jsr COUT
pla
ldx #8 ; 8 bytes at a time
bne byte ; always
;; Line of bytes in hex
bloop: jsr ReadByte
bcc byte
lda #' ' ; at EOF, space it out
sta INBUF,x
ldy #3
bne spaces ; always
byte: sta INBUF,x ; stash bytes
jsr PRBYTE
ldy #1
spaces: jsr PrintYSpaces
dex
bne bloop
;; Character display
lda #'|'|$80
jsr COUT
ldx #8 ; 8 bytes at a time
cloop: lda INBUF,x
ora #$80
cmp #' '|$80 ; control character?
bcs :+
lda #'.'|$80 ; yes, replace with period
: jsr COUT
dex
bne cloop
;; Increment offset
lda #8
clc
adc LINUM
sta LINUM
bcc :+
inc LINUM+1
:
jmp Binary
.endproc
;;; ============================================================
;;; Text file
.proc Text
repeat: jsr ReadByte
bcs Exit
ora #$80
cmp #$8D ; CR?
beq :+
cmp #' '|$80 ; other control character?
bcc repeat ; yes, ignore
: jsr COUT
jmp repeat
.endproc
;;; ============================================================
;;; BASIC file
.proc Basic
repeat: jsr CROUT
jsr ReadByte ; first two bytes are pointer to next line
jsr ReadByte
bcs Exit ; EOF
beq Exit ; null high byte = end of program
;; Line number
jsr ReadByte ; line number hi
bcs Exit
tax
jsr ReadByte ; line number lo
bcs Exit
jsr LINPRT ; print line number
jsr PrintSpace
;; Line contents: EOL, token, or character?
lloop: jsr ReadByte
beq repeat ; EOL
bmi token ; token
cout: ora #$80
jsr COUT
jmp lloop
ptr := $06
;; Token
token: and #$7F
tax ; command index
jsr PrintSpace ; space before token
lda #<TOKTABL
sta ptr
lda #>TOKTABL
sta ptr+1
;; Search through token table; last char
;; of each token has high bit set.
ldy #0
cpx #0
beq tloop2
tloop1: lda (ptr),y
bpl :+
dex ; last char, is next it?
beq found
: inc ptr ; nope, advance to next
bne :+
inc ptr+1
: bne tloop1 ; always
found: iny ; past last char of prev token
tloop2: lda (ptr),y
bmi :+
ora #$80
jsr COUT
iny
bne tloop2 ; always
: jsr COUT
lda #' ' ; space after token
bne cout ; always
.endproc
;;; ============================================================
PrintSpace:
ldy #1
;; fall through
.proc PrintYSpaces
lda #' '|$80
: jsr COUT
dey
bne :-
rts
.endproc
;;; ============================================================
.proc Exit
jsr Close
jsr CROUT
clc
rts
.endproc
.proc ExitWithError
pha
jsr Close
pla
sec
rts
.endproc
.proc Close
lda #CLOSE
jsr GOSYSTEM
rts
.endproc
;;; ============================================================
;;; Read a single byte; returns C=1 on EOF
;;; On error, exits.
.proc ReadByte
lda #READ
jsr GOSYSTEM
bcs :+
lda DATABUF
rts
: cmp #5 ; END OF DATA?
beq :+ ; exit with C=1 for EOF
tax ; stash error
pla ; pop return from stack
pla
txa ; unstash error
pha ; re-stash error
jsr Close
pla ; unstash error
: sec ; either w/ error or on EOF
rts
.endproc
;;; ============================================================

68
unhide.cmd.s Normal file
View File

@ -0,0 +1,68 @@
;;; ============================================================
;;;
;;; UNHIDE - Mark a file as not invisible
;;;
;;; Usage: UNHIDE filename[,S#][,D#]
;;;
;;; * filename can be relative or absolute path
;;;
;;; ============================================================
.include "apple2.inc"
.include "more_apple2.inc"
.include "prodos.inc"
;;; ============================================================
.org $4000
;; NOTE: Assumes XLEN is set by PATH
;; Point BI's parser at the command execution routine.
lda #<execute
sta XTRNADDR
lda #>execute
sta XTRNADDR+1
;; Mark command as external (zero).
lda #0
sta XCNUM
;; Set accepted parameter flags
;; Filename
lda #PBitsFlags::FN1
sta PBITS
;; Slot & Drive handling
lda #PBitsFlags::SD
sta PBITS+1
clc ; Success (so far)
rts1: rts ; Return to BASIC.SYSTEM
;;; ============================================================
execute:
;; Get the existing file info
lda #$A
sta SSGINFO
lda #GET_FILE_INFO
jsr GOSYSTEM
bcs rts1
;;; --------------------------------------------------
;; Set invisible bit
lda FIACESS
and #<(~ACCESS_I)
sta FIACESS
;; Set new file info
lda #$7
sta SSGINFO
lda #SET_FILE_INFO
jmp GOSYSTEM
;;; --------------------------------------------------