403 lines
17 KiB
ArmAsm
403 lines
17 KiB
ArmAsm
TTL 'ProDOS Block File Manager'
|
|
**************************************************
|
|
* ProDOS block file manager
|
|
* Perform filing or housekeeping functions
|
|
* (X)=call # ($00-$13)
|
|
|
|
BFMgr LDA Dispatch,X ;Translate into command address
|
|
ASL ;(bit 7 indicates a pathname to preprocess)
|
|
STA cmdTmp
|
|
AND #$3F ;(bit6 is refnum preprocess, 5 is for time, so strip em.)
|
|
TAX
|
|
LDA cmdTable,X ;Move address for indirect jump
|
|
STA goAdr
|
|
LDA cmdTable+1,X ;(high byte)
|
|
STA goAdr+1
|
|
LDA #backupNeeded ;Init "backup bit flag"
|
|
STA bkBitFlg ; to say "file modified"
|
|
BCC NoPath
|
|
|
|
* For MLI calls $C0-$C4, $C8
|
|
|
|
JSR SetPath ;Go process pathname before calling command
|
|
BCS ErrorSys ;Branch if bad name
|
|
|
|
NoPath ASL cmdTmp ;Test for refnum preprocessing
|
|
BCC NoPreRef
|
|
|
|
* For MLI calls $C9-$CB, $CE-$D3
|
|
|
|
JSR FindFCB ;Go set up pointers to fcb and vcb of this file
|
|
BCS ErrorSys ;branch if any errors are encountered
|
|
|
|
NoPreRef ASL cmdTmp ;Lastly check for necessity of time stamp
|
|
BCC Execute
|
|
|
|
* For MLI calls $C0-$C4, $CC, $CD
|
|
|
|
JSR DateTime ;(No error posible)
|
|
|
|
Execute JSR GoCmd ;Execute command
|
|
BCC GoodOp ;Branch if successful
|
|
|
|
ErrorSys JSR SysErr ;Don't come back
|
|
GoodOp RTS ;Good return
|
|
|
|
*-------------------------------------------------
|
|
* Check caller's pathname & copy to pathname buffer
|
|
|
|
SetPath LDY #c_path
|
|
LDA (parm),Y ;Get low pointer addr
|
|
STA tPath
|
|
INY
|
|
LDA (parm),Y
|
|
STA tPath+1 ; & hi pointer addr
|
|
|
|
SynPath EQU * ;Entry used by rename for second pathname
|
|
LDX #$00 ;X-reg is used as index to pathBuf
|
|
LDY #$00 ;Y-reg is index to input pathname
|
|
STX prfxFlg ;Assume prefix is in use
|
|
STX pathBuf ;Mark pathbuf to indicate nothing processed
|
|
LDA (tPath),Y ;Validate pathname length>0, and <65
|
|
BEQ ErrSyn
|
|
CMP #65
|
|
BCS ErrSyn
|
|
STA pathCnt ;This is used to compare for
|
|
INC pathCnt ; end of pathname processing
|
|
INY ;Now check for full pathname...
|
|
LDA (tPath),Y ;(Full name if starts with "/")
|
|
ORA #$80
|
|
CMP #"/"
|
|
BNE NotFullPN ;Branch if prefix appended
|
|
STA prfxFlg ;Set prefix flag to indicate prefix not used
|
|
INY ;Index to first character of pathname
|
|
|
|
NotFullPN LDA #$FF ;Set current position of pathBuf
|
|
STA pathBuf,X ; to indicate end of pathname
|
|
STA namCnt ;Also indicate no characters processed in local name
|
|
STX namPtr ;Preserve pointer to local name length byte
|
|
|
|
SynPath3 CPY pathCnt ;done with pathname processing?
|
|
BCS EndPath ;Yes
|
|
LDA (tPath),Y ;Get character
|
|
AND #$7F ;We're not interested in high order bit
|
|
INX ;Prepare for next character
|
|
INY
|
|
CMP #'/' ;Is it a slash delimiter?
|
|
BEQ EndName ;Branch if it is
|
|
CMP #'a' ;Is it lower case character?
|
|
BCC NotLower ;Branch if not
|
|
AND #$5F ;Upshift to upper case
|
|
NotLower STA pathBuf,X ;Store charcter
|
|
INC namCnt ;Is it the first of a local name?
|
|
BNE NotFirst ;Branch if not
|
|
INC namCnt ;Kick count to 1
|
|
BNE TestAlfa ;First char. Must be alpha (branch always taken)
|
|
|
|
NotFirst CMP #'.' ;Is it "."?
|
|
BEQ SynPath3 ;It's ok if it is, do next char
|
|
CMP #'0' ;Is it at least "0"?
|
|
BCC ErrSyn ;Report syntax error if not
|
|
CMP #'9'+1 ;Is it numeric?
|
|
BCC SynPath3 ;ok if it is, do next character
|
|
|
|
TestAlfa CMP #'A' ;Is it at least an "a"?
|
|
BCC ErrSyn ;Report err if not
|
|
CMP #'Z'+1 ;Is it g.t. "z"?
|
|
BCC SynPath3 ;Get next char if valid alpha
|
|
ErrSyn SEC ;Make sure carry set
|
|
LDA #badPathSyntax
|
|
RTS ;Report error
|
|
|
|
EndPath LDA #$00 ;End pathname with 0
|
|
BIT namCnt ;Also make sure name count is positive
|
|
BPL :1
|
|
STA namCnt ;=0
|
|
DEX
|
|
:1 INX
|
|
STA pathBuf,X
|
|
BEQ ErrSyn ;Report error if "/" only
|
|
STX pathCnt ;Save true length of pathname
|
|
TAX ;X=0 causes end of process, after endname
|
|
|
|
EndName LDA namCnt ;Validate local name <16
|
|
CMP #15+1
|
|
BCS ErrSyn
|
|
PHX ;Save current pointer
|
|
LDX namPtr ;Get index to beginning of local name
|
|
STA pathBuf,X ;Save local name's length
|
|
PLX ;Restore x
|
|
BNE NotFullPN ;Branch if more names to process
|
|
|
|
CLC ;Indicate success!
|
|
LDA prfxFlg ; but make sure all pathnames are
|
|
BNE EndRTS ; prefixed or begin with a "/"
|
|
LDA NewPfxPtr ; must be non-zero
|
|
BEQ ErrSyn
|
|
EndRTS RTS
|
|
|
|
**************************************************
|
|
* SETPREFIX Call
|
|
|
|
SetPrefix JSR SetPath ;Call is made here so a 'null' path may be detected
|
|
BCC :1 ;Branch if pathname ok
|
|
LDY pathBuf ;Was it a nul pathname?
|
|
BNE PfxErr ;Branch if true syntax error
|
|
JSR ZeroPfxPtrs ;Indicate null prefix. NB. (Y)=0
|
|
CLC
|
|
RTS
|
|
|
|
:1 JSR FindFile ;Go find specified prefix directory
|
|
BCC :2 ;Branch if no error
|
|
CMP #badPathSyntax
|
|
BNE PfxErr ;Branch if error is real (not root dir)
|
|
|
|
:2 LDA d_file+d_stor ;Make sure last local name is DIR type
|
|
AND #directoryFile*16;(either root or sub)
|
|
EOR #directoryFile*16;Is it a directory?
|
|
BNE PfxTypErr ;Report wrong type
|
|
LDY prfxFlg ;New or appended prefix?
|
|
BNE :3 ;(A)=0 if branch taken
|
|
LDA NewPfxPtr ;Append new prefix to old
|
|
:3 TAY
|
|
SEC ;Find new beginning of prefix
|
|
SBC pathCnt
|
|
CMP #$C0 ;Too long? ($100-$40)
|
|
BCC ErrSyn ;Report it if so
|
|
TAX
|
|
JSR SetPfxPtrs
|
|
LDA d_dev ;Save device number
|
|
STA pathDev
|
|
LDA d_file+d_first ; & addr of first block
|
|
STA pathBlok
|
|
LDA d_file+d_first+1
|
|
STA pathBlok+1
|
|
MovPrefix LDA pathBuf,Y
|
|
STA pathBuf,X
|
|
INY
|
|
INX
|
|
BNE MovPrefix
|
|
CLC ;Indicate good prefix
|
|
RTS
|
|
|
|
PfxTypErr LDA #badStoreType ;Report not a directory
|
|
PfxErr SEC ;indicate error
|
|
RTS
|
|
|
|
**************************************************
|
|
* GETPREFIX Call
|
|
|
|
GetPrefix CLC ;Calculate how big a buffer is needed to
|
|
LDY #c_path ;Get index to user's pathname buffer
|
|
LDA (parm),Y
|
|
STA userBuf
|
|
INY
|
|
LDA (parm),Y
|
|
STA userBuf+1
|
|
STZ cBytes+1 ;Set buf length at max
|
|
LDA #64 ;(64 characters max)
|
|
STA cBytes
|
|
JSR ValDBuf ;Go validate prefix buffer addr
|
|
BCS PfxErr
|
|
LDY #$00 ;Y is indirect index to user buffer
|
|
LDA NewPfxPtr ;Get address of beginning of prefix
|
|
TAX
|
|
BEQ NullPrefix ;Branch if null prefix
|
|
EOR #$FF ;Get total length of prefix
|
|
ADC #$02 ;Add 2 for leading and trailing slashes
|
|
NullPrefix STA (userBuf),Y ;Store length in user's buffer
|
|
BEQ GotPrefix ;Branch if null prefix
|
|
SendPrefix INY ;Bump to next user buf loc
|
|
LDA pathBuf,X ;Get next char of prefix
|
|
SndLimit STA (userBuf),Y ;Give character to user
|
|
AND #$F0 ;Check for length descriptor
|
|
BNE :1 ;Branch if regular character
|
|
LDA #'/' ;Otherwise, substitute a slash
|
|
BNE SndLimit ;Branch always
|
|
|
|
:1 INX
|
|
BNE SendPrefix ;Branch if more to send
|
|
INY
|
|
LDA #'/' ;End with slash
|
|
STA (userBuf),Y
|
|
GotPrefix CLC ;Indicate no error
|
|
RTS
|
|
|
|
*-------------------------------------------------
|
|
* Validity check the ref # passed by caller
|
|
|
|
FindFCB LDY #c_refNum ;Index to reference number
|
|
LDA (parm),Y ;Is it a valid file number?
|
|
BEQ ErrRefNum ;Must not be 0!
|
|
CMP #8+1 ;Must be 1 to 8 only
|
|
BCS ErrRefNum ;User must be stoned...
|
|
PHA
|
|
DEC ;(subtracts 1)
|
|
LSR ;Shift low 3 bits to high bits
|
|
ROR
|
|
ROR
|
|
ROR ;Effective multiply by 32
|
|
STA fcbPtr ;Later used as an index
|
|
TAY ; to FCB like now
|
|
PLA ;Restore refnum in A-reg
|
|
CMP fcb+fcbRefNum,Y ;Is it an open reference?
|
|
BNE ErrNoRef ;Branch if not
|
|
|
|
FndFCBuf LDA fcb+fcbFileBuf,Y;Get page addr of file buffer
|
|
JSR GetBufAdr ;Get file's address into bufAddrL & H
|
|
LDX bufAddrH ;(Y)=fcbptr - preserved
|
|
BEQ FCBDead ;Report FCB screwed up!!!
|
|
STX dataPtr+1 ;Save pointer to data area of buffer
|
|
INX
|
|
INX ;Index block always 2 pages after data
|
|
STX tIndex+1
|
|
LDA fcb+fcbDevNum,Y ;Also set up device number
|
|
STA DevNum
|
|
LDA bufAddrL
|
|
STA dataPtr ;Index and data buffers
|
|
STA tIndex ; always on page boundaries
|
|
|
|
SrchVCBs TAX ;Search for associated VCB
|
|
LDA vcb+vcbDevice,X
|
|
CMP fcb+fcbDevNum,Y ;Is this VCB the same device?
|
|
BEQ TestVOpen ;If it is, make sure volume is active
|
|
|
|
NxtBufr TXA ;Adjust index to next VCB
|
|
CLC
|
|
ADC #vcbSize
|
|
BCC SrchVCBs ;Loop until volume found
|
|
LDA #vcbUnusable ;Report open file has no volume...
|
|
JSR SysDeath ; & kill the system
|
|
|
|
FCBDead LDA #fcbUnusable ;Report FCB trashed
|
|
JSR SysDeath ; & kill the system
|
|
|
|
TestVOpen LDA vcb,X ;Make sure this VCB is open
|
|
BEQ NxtBufr ;Branch if it is not active
|
|
STX vcbPtr ;Save pointer to good VCB
|
|
CLC ;Indicate all's well
|
|
RTS
|
|
|
|
ErrNoRef LDA #$00 ;Drop a zero into this FCB
|
|
STA fcb+fcbRefNum,Y ; to show free FCB
|
|
|
|
ErrRefNum LDA #invalidRefNum ;Tell user that requested refnum
|
|
SEC ; is illegal (out of range) for this call
|
|
RTS
|
|
|
|
**************************************************
|
|
* ONLINE call
|
|
|
|
Online JSR MovDBuf ;Move user specified buffer pointer to usrbuf
|
|
STZ cBytes ;Figure out how big buffer has to be
|
|
STZ cBytes+1
|
|
LDY #c_devNum
|
|
LDA (parm),Y ;If zero then cbytes=$100, else =$010 for one device
|
|
AND #$F0
|
|
STA DevNum
|
|
BEQ :1 ;Branch if all devices
|
|
LDA #$10
|
|
STA cBytes
|
|
BNE :2 ;Always
|
|
:1 INC cBytes+1 ;Allow for up to 16 devices
|
|
:2 JSR ValDBuf ;Go validate buffer range against allocated memory
|
|
BCS OnlinErr
|
|
LDA #$00 ;Zero out user buffer space
|
|
LDY cBytes
|
|
:loop1 DEY
|
|
STA (userBuf),Y ;Zero either 16 or 256 bytes
|
|
BNE :loop1 ;Branch if more to zero
|
|
STA namPtr ;Use namPtr as pointer to user buffer
|
|
LDA DevNum
|
|
BNE OnlineZ ;Branch if only 1 device to process
|
|
JSR MovDevNums ;Get list of currently recognized devices
|
|
:loop2 PHX ;Save index to last item on list
|
|
LDA lookList,X ;Get next device #
|
|
STA DevNum
|
|
JSR OnlineZ ;Log this volume and return it's name to user
|
|
LDA namPtr
|
|
CLC
|
|
ADC #$10
|
|
STA namPtr
|
|
PLX ;Restore index to device list
|
|
DEX ;Index to next device
|
|
BPL :loop2 ;Branch if there is another device
|
|
LDA #$00 ;No errors for muliple on-line
|
|
CLC ;Indicate good on all volumes
|
|
OnlinErr RTS
|
|
|
|
* Generate return data for a specific device
|
|
|
|
OnlineZ JSR ScanVCB ;See if it has already been logged in
|
|
BCS OnlinErr1 ;Branch if VCB is full
|
|
LDX #$00 ;Read in root (volume) directory
|
|
LDA #$02 ;(X,A)=block #
|
|
JSR RdBlkAX ;Read it into general purpose buffer
|
|
LDX vcbPtr ;Use x as an index to the vcb entry
|
|
|
|
* This fix is to remove VCB entries that correspond to devices that
|
|
* are no longer in the device list (i.e. removed by the user).
|
|
|
|
BCC VolFound ;Branch if the read was ok
|
|
TAY ;Save error value in Y-reg
|
|
LDA vcb+vcbStatus,X ;Don't take the VCB off line if
|
|
BNE RtrnErr ; there are active files present!
|
|
STA vcb,X ;Now take the volume off line
|
|
STA vcb+vcbDevice,X
|
|
RtrnErr TYA ;Now return error to A
|
|
BCS OnlinErr1
|
|
|
|
* 1st vol dir blk has been read successfully
|
|
|
|
VolFound LDA vcb,X ;Has it been logged in before?
|
|
BEQ :1 ;Branch if not
|
|
LDA vcb+vcbStatus,X ;It has, are there active files?
|
|
BMI :2 ;Branch if the volume is currently busy
|
|
:1 JSR LogVCBZ ;Go log it in
|
|
BCS OnlinErr1 ;Branch if there is some problem (like notsos)
|
|
LDA #dupVolume ;Anticipate a duplicate active volume exists
|
|
BIT duplFlag
|
|
BMI OnlinErr1 ;Branch if we guessed right
|
|
:2 LDX vcbPtr ;Restore vcbptr just in case we lost it
|
|
JSR CmpVCB ;Does read in volume compare with logged volume?
|
|
LDA #drvrDiskSwitch ;Anticipate wrong volume mounted in active device
|
|
BCC Online2 ;Branch if no problem!
|
|
|
|
* On fall thru, (A)=disk switch error
|
|
* Store error code in user's data buffer
|
|
|
|
OnlinErr1 PHA ;Save error code
|
|
JSR SavDevNbr ;Tell user what device we looked at
|
|
PLA ;Get error code again
|
|
INY ;Tell user what error was encountered on this device
|
|
STA (userBuf),Y
|
|
CMP #dupVolume ;Was it a duplicate volume error?
|
|
BNE :1 ;Branch if not,
|
|
INY ;Otherwise tell user which other device has same name
|
|
LDX vcbEntry
|
|
LDA vcb+vcbDevice,X
|
|
STA (userBuf),Y
|
|
STZ duplFlag ;Clear duplicate flag
|
|
LDA #dupVolume ;Restore error code
|
|
:1 SEC ;Indicate error
|
|
RTS
|
|
|
|
* Make online volume entry
|
|
|
|
Online2 LDA vcb,X ;Get volume name count
|
|
STA namCnt
|
|
LDY namPtr ;Index to user's buffer
|
|
:loop LDA vcb,X ;Move name to user's buffer
|
|
STA (userBuf),Y
|
|
INX
|
|
INY
|
|
DEC namCnt ;Loop until all characters moved
|
|
BPL :loop
|
|
|
|
SavDevNbr LDY namPtr ;Index to first byte of this entry
|
|
LDA DevNum ;Put device number in upper nibble of this byte
|
|
ORA (userBuf),Y ;Lower nibble is name length
|
|
STA (userBuf),Y
|
|
CLC ;Indicate no errors
|
|
RTS
|