Compare commits

...

33 Commits
v1.1 ... 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
Joshua Bell ef8857752f Add COPY command. Fixes #2 2021-04-12 20:43:49 -07:00
Joshua Bell f5fc93e608 Include new files in package 2021-03-07 19:26:19 -08:00
Joshua Bell fb08e649cc Only run xattr if present try 3 2021-03-07 16:31:54 -08:00
Joshua Bell a646cf6611 Only run xattr if present 2021-03-07 16:05:55 -08:00
Joshua Bell e6943cb0b2 Only run xattr if present 2021-03-07 15:59:03 -08:00
Joshua Bell f1caa15b0c Add CHTYPE and CHTIME 2021-03-07 15:29:51 -08:00
Joshua Bell 9c07b36b09
Create LICENSE 2020-11-08 12:43:04 -08:00
25 changed files with 1931 additions and 161 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: osx
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

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Joshua Bell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,11 +1,13 @@
CAFLAGS = --target apple2enh --list-bytes 0
LDFLAGS = --config apple2-asm.cfg
CAFLAGS := --target apple2enh --list-bytes 0
LDFLAGS := --config apple2-asm.cfg
OUTDIR = out
OUTDIR := out
TARGETS = $(OUTDIR)/path.BIN \
$(OUTDIR)/bell.CMD $(OUTDIR)/hello.CMD $(OUTDIR)/echo.CMD $(OUTDIR)/online.CMD
TARGETS := $(OUTDIR)/path.BIN \
$(shell cat COMMANDS | while read line; do echo "out/$${line}.CMD"; done)
XATTR := $(shell command -v xattr 2> /dev/null)
.PHONY: clean all package
all: $(OUTDIR) $(TARGETS)
@ -13,7 +15,7 @@ all: $(OUTDIR) $(TARGETS)
$(OUTDIR):
mkdir -p $(OUTDIR)
HEADERS = $(wildcard *.inc)
HEADERS := $(wildcard *.inc)
clean:
rm -f $(OUTDIR)/*.o
@ -28,7 +30,9 @@ $(OUTDIR)/%.o: %.s $(HEADERS)
$(OUTDIR)/%.BIN $(OUTDIR)/%.SYS: $(OUTDIR)/%.o
ld65 $(LDFLAGS) -o $@ $<
ifdef XATTR
xattr -wx prodos.AuxType '00 20' $@
endif
$(OUTDIR)/%.CMD: $(OUTDIR)/%.cmd.o
ld65 $(LDFLAGS) -o $@ $<

View File

@ -1,50 +1,81 @@
# 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 💾
Build with [ca65](https://cc65.github.io/doc/ca65.html)
Installation:
* Copy target to ProDOS disk
* From BASIC.SYSTEM prompt, run: `-PATH` from STARTUP (or by hand)
## Instructions For Users
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 - view current search path(s)
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.
* CMD file is loaded at $4000 and invoked; should return (`rts`) on completion.
* The command line will be present at $200 (`GETLN` input buffer).
* Once set, binary files of type `CMD` in the specified directories can be invoked by name.
* Supports multi-segment, colon-separated paths, e.g. `/hd/cmds:/hd2/more.cmds`
Example:
```
] -/hd/path - install it
] PATH /hd/cmds:/h2/bin - set PATH
] -/hd/cmd/path - install it
] PATH /hd/cmd:/h2/bin - set PATH
] PATH - verify path
/hd/cmds
] BELL - will invoke /hd/cmds/BELL if present
] HELLO - will invoke /hd/cmds/HELLO if present
] ONLINE - will invoke /hd/cmds/ONLINE if present
/hd/cmd:/h2/bin
] BELL - will invoke /hd/cmd/BELL if present
] HELLO - will invoke /hd/cmd/HELLO if present
] ONLINE - will invoke /hd/cmd/ONLINE if present
```
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:
* ProDOS BASIC.SYSTEM intrinsics (`CAT`, `PREFIX`, etc)
* BASIC keywords (`LIST`, `PRINT`, etc)
* CMD files in paths, in listed order
* 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)
* 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:
* `BELL` - beeps the speaker
* `HELLO` - shows a short message
* `ONLINE` - lists online volumes (volume name, slot and drive)
Protocol for `CMD` files:
* 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).
* Commands can use the BI parser for arguments. See `chtype.cmd.s` for an example.

View File

@ -1,9 +1,10 @@
.include "apple2.inc"
BELL := $FF3A
.include "more_apple2.inc"
.org $4000
jsr BELL
clc
rts

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

123
chtime.cmd.s Normal file
View File

@ -0,0 +1,123 @@
;;; ============================================================
;;;
;;; CHTIME - File modification time changing command for ProDOS-8
;;;
;;; Usage: CHTIME filename[,Adate][,Btime][,S#][,D#]
;;;
;;; * filename can be relative or absolute path
;;; * specify A$nnnn to set file date
;;; * specify B$nnnn to set file time
;;; * with neither A nor B option, prints current values
;;;
;;; ============================================================
.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
;; Address (A=Date word), Byte (B=Time word), Slot & Drive handling
lda #PBitsFlags::AD | PBitsFlags::B | 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 options
ldy #0 ; count number of options
;; Apply optional Address argument as new date
lda FBITS+1
and #PBitsFlags::AD ; Address set?
beq :+
iny
lda VADDR
sta FIMDATE
lda VADDR+1
sta FIMDATE+1
:
;; Apply optional Byte argument as new time
lda FBITS+1
and #PBitsFlags::B ; Type set?
beq :+
iny
lda VBYTE
sta FIMDATE+2
lda VBYTE+1
sta FIMDATE+3
:
;; If no options were used, show current details instead.
cpy #0
beq show
;; Set new file info
lda #$7
sta SSGINFO
lda #SET_FILE_INFO
jmp GOSYSTEM
;;; --------------------------------------------------
show:
lda #'A'|$80
jsr COUT
lda #'='|$80
jsr COUT
lda #'$'|$80
jsr COUT
lda FIMDATE+1
jsr PRBYTE
lda FIMDATE
jsr PRBYTE
jsr CROUT
lda #'B'|$80
jsr COUT
lda #'='|$80
jsr COUT
lda #'$'|$80
jsr COUT
lda FIMDATE+3
jsr PRBYTE
lda FIMDATE+2
jsr PRBYTE
jsr CROUT
clc
rts

127
chtype.cmd.s Normal file
View File

@ -0,0 +1,127 @@
;;; ============================================================
;;;
;;; CHTYPE - File type changing command for ProDOS-8
;;;
;;; Usage: CHTYPE filename[,Ttype][,Aaux][,S#][,D#]
;;;
;;; * filename can be relative or absolute path
;;; * specify T$nn to set file type
;;; * specify A$nnnn to set aux type info
;;; * type can be BIN, SYS, TXT (etc) or $nn
;;; * with neither T nor A option, prints current values
;;;
;;; ============================================================
.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 and Type
lda #PBitsFlags::T | PBitsFlags::FN1
sta PBITS
;; Address (used as AuxType), Slot & Drive handling
lda #PBitsFlags::AD | 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 options
ldy #0 ; count number of options
;; Apply optional Type argument as new file type
lda FBITS
and #PBitsFlags::T ; Type set?
beq :+
iny
lda VTYPE
sta FIFILID
:
;; Apply optional Address argument as new aux type
lda FBITS+1
and #PBitsFlags::AD ; Address set?
beq :+
iny
lda VADDR
sta FIAUXID
lda VADDR+1
sta FIAUXID+1
:
;; If no options were used, show current details instead.
cpy #0
beq show
;; Apply current date/time
ldx #3
: lda DATE,x
sta FIMDATE,x
dex
bpl :-
;; Set new file info
lda #$7
sta SSGINFO
lda #SET_FILE_INFO
jmp GOSYSTEM
;;; --------------------------------------------------
show:
lda #'T'|$80
jsr COUT
lda #'='|$80
jsr COUT
lda #'$'|$80
jsr COUT
lda FIFILID
jsr PRBYTE
jsr CROUT
lda #'A'|$80
jsr COUT
lda #'='|$80
jsr COUT
lda #'$'|$80
jsr COUT
lda FIAUXID+1
jsr PRBYTE
lda FIAUXID
jsr PRBYTE
jsr CROUT
clc
rts

340
copy.cmd.s Normal file
View File

@ -0,0 +1,340 @@
;;; ============================================================
;;;
;;; COPY - Copy changing command for ProDOS-8
;;;
;;; Usage: COPY pathname1,pathname2
;;;
;;; Inspiration from COPY.ALL by Sandy Mossberg, Nibble 6/1987
;;;
;;; ============================================================
.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
lda #PBitsFlags::FN1 | PBitsFlags::FN2 ; Filenames
sta PBITS
lda #0 ; See below for why PBitsFlags::SD is not used
sta PBITS+1
clc ; Success (so far)
rts ; Return to BASIC.SYSTEM
;;; ============================================================
FN1REF := $D6
FN2REF := $D7
FN1INFO := $2EE
FN2BUF := $4200
DATABUF := $4600
DATALEN = $6000 - DATABUF
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
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
:
;; Save FN1 info
ldx #$11
: lda SSGINFO,x
sta FN1INFO,x
dex
bpl :-
;; Open FN1
lda HIMEM+1 ; Use BI's general purpose buffer (page aligned)
sta OSYSBUF+1
lda #OPEN
jsr GOSYSTEM
bcs rts1
lda OREFNUM
sta FN1REF
;; Copy FN2 to FN1
ptr1 := $06
ptr2 := $08
lda VPATH1
sta ptr1
lda VPATH1+1
sta ptr1+1
lda VPATH2
sta ptr2
lda VPATH2+1
sta ptr2+1
ldy #0
lda (ptr2),y
tay
: lda (ptr2),y
sta (ptr1),y
dey
bpl :-
;; Get FN2 info
lda #GET_FILE_INFO
jsr GOSYSTEM
bcs :+
lda #BI_ERR_DUPLICATE_FILE_NAME
err: pha
jsr CloseFiles
pla
sec
rts
: cmp #BI_ERR_PATH_NOT_FOUND
beq :+
cmp #BI_ERR_VOLUME_DIR_NOT_FOUND
bne err ; Otherwise - fail.
:
;; Create FN2
lda #$C3 ; Free access
sta CRACESS
ldx #3
: lda FN1INFO+4,x ; storage type, file type,
sta CRFKIND-3,x ; aux type, create date/time
lda FN1INFO+$E,x
sta CRFKIND+1,x
dex
bpl :-
lda #CREATE
jsr GOSYSTEM
bcs err
;; Open FN2
lda #<FN2BUF
sta OSYSBUF
lda #>FN2BUF
sta OSYSBUF+1
lda #OPEN
jsr GOSYSTEM
bcs err
lda OREFNUM
sta FN2REF
;; Read
read: lda FN1REF
sta RWREFNUM
lda #<DATABUF
sta RWDATA
lda #>DATABUF
sta RWDATA+1
lda #<DATALEN
sta RWCOUNT
lda #>DATALEN
sta RWCOUNT+1
lda #READ
jsr GOSYSTEM
bcc :+
cmp #BI_ERR_END_OF_DATA
beq finish
:
;; Write
lda FN2REF
sta RWREFNUM
lda #<DATABUF
sta RWDATA
lda #>DATABUF
sta RWDATA+1
lda RWTRANS
sta RWCOUNT
lda RWTRANS+1
sta RWCOUNT+1
lda #WRITE
jsr GOSYSTEM
bcc read
jmp err
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
rts
.proc CloseFiles
lda FN1REF
sta CFREFNUM
lda #CLOSE
jsr GOSYSTEM
lda FN2REF
sta CFREFNUM
lda #CLOSE
jsr GOSYSTEM
rts
.endproc
;;; Leave PREFIX at INBUF; 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_prefix_params
lda INBUF
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 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,35 +1,17 @@
.include "apple2.inc"
CROUT := $FD8E
COUT := $FDED
INBUF := $200
.include "more_apple2.inc"
.include "prodos.inc"
.org $4000
jsr CROUT
ldx #0
;; Skip any leading spaces
jsr skip_spaces
;; Invoked with "-" ?
lda INBUF,x
cmp #'-'|$80
bne :+
;; Skip command and any leading spaces
ldx XLEN
inx
:
;; 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
jsr SkipSpaces
;; Echo string
: lda INBUF,x
@ -39,15 +21,16 @@ INBUF := $200
inx
jmp :-
exit: rts
exit: clc
rts
.proc skip_spaces
lda INBUF,x
.proc SkipSpaces
repeat: lda INBUF,x
cmp #' '|$80
beq :+
rts
: inx
jmp skip_spaces
jmp repeat
.endproc
cmd_length = .strlen("echo")

View File

@ -1,8 +1,6 @@
.include "apple2.inc"
CROUT := $FD8E
COUT := $FDED
.include "more_apple2.inc"
.org $4000
@ -16,6 +14,8 @@ COUT := $FDED
jmp :-
done: jsr CROUT
clc
rts
str: .byte "Hello, world!", 0

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

36
more_apple2.inc Normal file
View File

@ -0,0 +1,36 @@
;;; ============================================================
;;; Memory locations
INBUF := $200
;;; ============================================================
;;; Zero Page
LINUM := $1B
;;; ============================================================
;;; I/O Locations
SPKR := $C030
;;; ============================================================
;;; Monitor ROM routines
PRTAX := $F941
WAIT := $FCA8
CROUT := $FD8E
PRBYTE := $FDDA
COUT := $FDED
MOVE := $FE2C ; call with Y=0
MOVE_SRC := $3C
MOVE_END := $3E
MOVE_DST := $42
BELL := $FF3A
;;; ============================================================
;;; Applesoft ROM locations
TOKTABL := $D0D0
LINPRT := $ED24

View File

@ -1,10 +1,8 @@
.include "apple2.inc"
.include "more_apple2.inc"
.include "prodos.inc"
CROUT := $FD8E ; Issue a carriage return.
COUT := $FDED ; Output a character.
.org $4000
;;; ============================================================
@ -83,7 +81,8 @@ next: dec count
sta ptr+1
jmp loop
exit: rts
exit: clc
rts
;;; ============================================================

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# Use Cadius to create a disk image for distribution
# https://github.com/mach-kernel/cadius
@ -18,10 +18,9 @@ add_file () {
}
add_file "out/path.BIN" "path#062000"
add_file "out/bell.CMD" "bell#F04000"
add_file "out/echo.CMD" "echo#F04000"
add_file "out/hello.CMD" "hello#F04000"
add_file "out/online.CMD" "online#F04000"
for file in $(cat COMMANDS); do
add_file "out/${file}.CMD" "${file}#F04000"
done
rm -r "$PACKDIR"

154
path.s
View File

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

View File

@ -2,11 +2,24 @@
;;; ProDOS MLI / Global Page
MLI := $BF00
DEVNUM := $BF30
DATE := $BF90
DATELO := $BF90
DATEHI := $BF91
TIME := $BF92
TIMELO := $BF92
TIMEHI := $BF93
GET_TIME = $82
CREATE = $C0
SET_FILE_INFO = $C3
GET_FILE_INFO = $C4
ON_LINE = $C5
SET_PREFIX = $C6
GET_PREFIX = $C7
OPEN = $C8
READ = $CA
WRITE = $CB
CLOSE = $CC
.macro MLI_CALL cmd, params
@ -15,16 +28,30 @@ CLOSE = $CC
.addr params
.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
EXTRNCMD := $BE06 ; External command 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
XCNUM := $BE53 ; Command number (ext cmd = 0).
PBITS := $BE54 ; Command parameter bits
FBITS := $BE56 ; Found parameter bits
@ -55,27 +82,90 @@ FBITS := $BE56 ; Found parameter bits
;; paths must be used if no prefix is set.
.endenum
VPATH1 := $BE6C ; Pathname buffer
VADDR := $BE58 ; Address parameter
VBYTE := $BE5A ; Byte parameter
VSLOT := $BE61 ; Slot parameter
VTYPE := $BE6A ; Type parameter
VPATH1 := $BE6C ; Pathname 1 buffer
VPATH2 := $BE6E ; Pathname 2 buffer (RENAME)
GOSYSTEM := $BE70 ; Use instead of MLI
BADCALL := $BE8B ; convert MLI errors into BI equivalents
XRETURN := $BE9E ; Handy RTS
SSGINFO := $BEB4 ; GET_FILE_INFO Parameter block
FIFILID := $BEB8 ; (set size $A)
SCREATE := $BEA0 ; CREATE Parameter block
CRACESS := $BEA3 ; $C1 if directory create
CRFILID := $BEA4
CRAUXID := $BEA5
CRFKIND := $BEA7
SSGPREFX := $BEAC
SDSTROY := $BEAC
SRECNAME := $BEAF
SSGINFO := $BEB4 ; GET_FILE_INFO Parameter block
FIACESS := $BEB7 ; Access used by lock/unlock
FIFILID := $BEB8 ; FILE ID is type specifier
FIAUXID := $BEB9 ; Aux_id is used for load addr and record length
FIFKIND := $BEBB ; Identifies trees vs. directories
FIBLOKS := $BEBC ; Used by CAT commands for root
FIMDATE := $BEBE
SONLINE := $BEC6
SSETMKR := $BEC6
SGETMRK := $BEC6
SSETEOF := $BEC6
SGETEOF := $BEC6
SSETBUF := $BEC6
SGETBUF := $BEC6
SBUFREF := $BEC7
SREFNUM := $BEC7
SUNITNUM := $BEC7
SDATPTR := $BEC8
SMARK := $BEC8
SEOF := $BEC8
SBUFADR := $BEC8
SOPEN := $BECB ; OPEN
OSYSBUF := $BECE
OREFNUM := $BED0
SREAD := $BED5 ; READ
SWRITE := $BED5 ; WRITE
RWREFNUM := $BED6
RWDATA := $BED7
RWCOUNT := $BED9
RWTRANS := $BEDB
SCLOSE := $BEDD ; CLOSE
SFLUSH := $BEDD ; FLUSH
CFREFNUM := $BEDE
CCCSPARE := $BEDF
GETBUFR := $BEF5
FREEBUFR := $BEF8
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
;;; --------------------------------------------------