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
TARGETS := $(OUTDIR)/path.BIN \
$(OUTDIR)/chtype.CMD $(OUTDIR)/chtime.CMD \
$(OUTDIR)/copy.CMD \
$(OUTDIR)/bell.CMD $(OUTDIR)/hello.CMD $(OUTDIR)/echo.CMD $(OUTDIR)/online.CMD
$(shell cat COMMANDS | while read line; do echo "out/$${line}.CMD"; done)
XATTR := $(shell command -v xattr 2> /dev/null)

View File

@ -1,62 +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.
* $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).
* 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`
* Commands can use the BI parser for arguments. See `chtype.cmd.s` for an example.
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:
* Useful utilities:
* `ONLINE` - lists online volumes (volume name, slot and drive)
* `COPY` - copy a single file, e.g. `copy /path/to/file,dstfile`
* `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.
* Other examples:
* `BELL` - beeps the speaker
* `HELLO` - shows a short message
* `ECHO` - echoes back anything following the command
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.

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.
lda #<execute
sta XTRNADDR
page_num2 := *+1 ; address needing updating
lda #>execute
sta XTRNADDR+1
@ -34,38 +33,20 @@
;; Set accepted parameter flags
lda #PBitsFlags::FN1 ; Filename
;; Filename
lda #PBitsFlags::FN1
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
sta PBITS+1
clc ; Success (so far)
rts ; Return to BASIC.SYSTEM
;;; ============================================================
not_ours:
sec ; Signal failure...
next_command := *+1
jmp $ffff ; Execute next command in chain
rts1: rts ; Return to BASIC.SYSTEM
;;; ============================================================
execute:
;; Verify required arguments
lda FBITS
and #PBitsFlags::FN1 ; Filename?
bne :+
lda #$10 ; SYNTAX ERROR
sec
rts1: rts
:
;;; --------------------------------------------------
;; Get the existing file info
lda #$A
sta SSGINFO

View File

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

View File

@ -21,7 +21,6 @@
;; Point BI's parser at the command execution routine.
lda #<execute
sta XTRNADDR
page_num2 := *+1 ; address needing updating
lda #>execute
sta XTRNADDR+1
@ -29,11 +28,11 @@
lda #0
sta XCNUM
;; Set accepted parameter flags (Name, Type, Address)
;; Set accepted parameter flags
lda #PBitsFlags::FN1 | PBitsFlags::FN2 ; Filenames
sta PBITS
lda #0
lda #0 ; See below for why PBitsFlags::SD is not used
sta PBITS+1
clc ; Success (so far)
@ -41,13 +40,33 @@
;;; ============================================================
FN1REF := $D6
FN2REF := $D7
FN1INFO := $2EE
FN1BUF := $4200
FN2BUF := $4600
DATABUF := $4A00
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
@ -57,9 +76,9 @@ execute:
;; Reject directory file
lda FIFILID
cmp #$F ; DIR
cmp #FT_DIR
bne :+
lda #$D ; FILE TYPE MISMATCH
lda #BI_ERR_FILE_TYPE_MISMATCH
sec
rts1: rts
:
@ -72,9 +91,7 @@ rts1: rts
bpl :-
;; Open FN1
lda #<FN1BUF
sta OSYSBUF
lda #>FN1BUF
lda HIMEM+1 ; Use BI's general purpose buffer (page aligned)
sta OSYSBUF+1
lda #OPEN
jsr GOSYSTEM
@ -101,21 +118,21 @@ rts1: rts
dey
bpl :-
;; Get FN1 info
;; Get FN2 info
lda #GET_FILE_INFO
jsr GOSYSTEM
bcs :+
lda #$13 ; DUPLICATE FILE NAME
lda #BI_ERR_DUPLICATE_FILE_NAME
err: pha
jsr close
jsr CloseFiles
pla
sec
rts
: cmp #6 ; BI Errors 6 and 7 cover
beq :+ ; vol dir, pathname, or filename
cmp #7 ; not found.
: cmp #BI_ERR_PATH_NOT_FOUND
beq :+
cmp #BI_ERR_VOLUME_DIR_NOT_FOUND
bne err ; Otherwise - fail.
:
@ -158,7 +175,7 @@ read: lda FN1REF
lda #READ
jsr GOSYSTEM
bcc :+
cmp #5 ; END OF DATA
cmp #BI_ERR_END_OF_DATA
beq finish
:
@ -179,11 +196,23 @@ read: lda FN1REF
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
rts
.proc close
.proc CloseFiles
lda FN1REF
sta CFREFNUM
lda #CLOSE
@ -195,7 +224,117 @@ finish: jsr close
rts
.endproc
FN1REF: .byte 0
FN2REF: .byte 0
;;; 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
.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 "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,13 +24,13 @@
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")

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
;;; ============================================================
;;; Zero Page
LINUM := $1B
;;; ============================================================
;;; I/O Locations
SPKR := $C030
;;; ============================================================
;;; Monitor ROM routines
PRTAX := $F941
WAIT := $FCA8
CROUT := $FD8E
PRBYTE := $FDDA
COUT := $FDED
@ -20,4 +32,5 @@ BELL := $FF3A
;;; ============================================================
;;; 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"
for file in bell echo hello online chtype chtime copy; do
for file in $(cat COMMANDS); do
add_file "out/${file}.CMD" "${file}#F04000"
done

133
path.s
View File

@ -35,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
@ -136,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
@ -145,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
@ -171,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
@ -193,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
@ -204,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
@ -223,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
@ -238,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
@ -247,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
@ -302,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'
@ -330,28 +330,26 @@ notok: dey
;; Indicate end of command string for BI's parser (if command uses it)
dex
stx XLEN
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 (clock driver?), so stash it in upper half.
ldx #$7F
@ -360,36 +358,36 @@ notok: dey
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
@ -398,17 +396,28 @@ notok: dey
dex
bpl :-
;; Invoke command
jsr cmd_load_addr
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:
@ -456,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'
@ -468,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,12 +2,21 @@
;;; 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
@ -19,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
@ -68,6 +91,7 @@ VPATH2 := $BE6E ; Pathname 2 buffer (RENAME)
GOSYSTEM := $BE70 ; Use instead of MLI
BADCALL := $BE8B ; convert MLI errors into BI equivalents
XRETURN := $BE9E ; Handy RTS
@ -121,3 +145,27 @@ 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
;;; --------------------------------------------------