💾 Archived View for mirrors.apple2.org.za › archive › www.textfiles.com › apple › ANATOMY › cmdbsave… captured on 2024-08-19 at 03:01:33.
View Raw
More Information
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
- *****************************************************************
- *
- BSAVE Command Handler *
- *
- ----------------------------------------------------------------*
- *
- The BSAVE Command saves an image of memory as a binary *
- file on the disk. The portion of memory saved is defined by *
- the starting address (A-parameter) and the number of bytes to *
- be stored (L-parameter). Both parameters must be issued and *
- can be specified in either decimal or hexadecimal notation. *
- The maximum file length that can be saved is 32767 ($7FFF) *
- bytes. A file name must also accompany the command. Drive, *
- volume and slot parameters are optional. *
- *
- Execution pattern: *
- The BSAVE command closes (if necessary) and then opens *
- the file. Next the address and length values are placed in *
- the data sector buffer. The rest of the file is then *
- sequentially stored in the data sector buffer. Each time the *
- buffer is filled, it is written to the disk. If the last *
- segment of the program does not completely fill the data sector*
- buffer, the update flag (UPDATFLG, $B5D5) is set to indicate *
- that the disk requires updating. When the file is closed, the *
- status of the flag is tested & (if necessary) the last data *
- sector is written to the disk. The file is then verified and *
- reclosed via the verify command. *
- In order to avoid a possible source of confusion, note *
- that the file manager makes different assumptions about the *
- structure of the binary file depending on whether the file is *
- being BLOADED or BSAVED. During the BSAVE process, the binary *
- file is considered to be a single record with a record length *
- equal to the length of the file (val of L-parameter = LENPRSD *
- --> RECLENFM). However, during the BLOAD process a binary *
- file is treated as a collection of single-byte-long records. *
- *
- *****************************************************************
- On entry - CUMLOPTN ($AA65) has been updated
- to reflect parsed option words.
- - the validity of the options issued
- with the command (and their numeric
- values) have been checked. (Only
- volume, drive, slot, address and
- length parameters are allowed with the
- BSAVE command. Their parsed values are
- stored at VOLPRSD ($AA66-67), DRVPRSD
- ($AA68-69), SLOTPRSD ($AA6A-6B), ADRPRSD
- ($AA72) & LENPRSD ($AA6C) respectively.
- - a legal file name has been parsed and
- stored in the primary file name buffer
- (PRIMFNBF, $AA75).
(A331)
CMDBSAVE LDA #%00001001 ;Test bits 0 and 3 of CUMLOPTN to see if the
AND CUMLOPTN ;A(ddress) and L(ength) parms were issued with BSAVE cmd.
CMP #%00001001
BEQ DOBSAV ;Both A- & L-parameters present.
(A33A) JMP CKIFCTRL ;Got a syntax error.
------------ ;(See error routine at end of this dis'mbly.)
(A33D)
DOBSAV LDA #4 ;Code for BINARY file.
(A33F) JSR OPNCKTYP ;Close (if necessary) & then reopen file.
(A3D5)
OPNCKTYP STA FILTYPFM ;Put code for file type in the FM parameter
(A3D8) PHA ;list & save it on the stack.
;($00=Text, $01=Integer, $02=Applesoft,
;$04=Binary, $08=S-type, $10=Relocatable,
;$20=A-type and $40=B-type.)
(A3D9) JSR HNDLCMD ;Use the file manager command handler to open the file.
* Common file manager command handler code.
(A2A8)
HNDLCMD LDA #1 ;Open opcode.
HNDLCMD1 STA TEMPBYT ;Store opcode in temporary location.
LDA LENPRSD ;Get L-parameter from parsed table.
BNE SAVLENFM ;Was a non-zero L-parm issued with cmd?
LDA LENPRSD+1
BNE SAVLENFM
LDA #1 ;Length was 0 so make it 1 instead.
STA LENPRSD
SAVLENFM LDA LENPRSD ;Put length in FM parm list.
STA RECLENFM
LDA LENPRSD+1
STA RECLENFM+1
CLSLOCBF JSR CMDCLOSE ;Close file if it's already open.
(A2C8)
(A2EA)
CMDCLOSE .
.
(See dis'mbly of CMDCLOSE given below.)
.
.
- Note that execution flows thru CMDCLOSE twice if the
file is already open.
- The first time thru, the matching DOS filename buffer is
located & then CLOSEONE is used to close the file.
- Execution then jumps back to the start of CMDCLOSE.
- On this second pass, a matching filename is not found
because the DOS filename buffer was released on the
first pass. Therefore, A5L/H is left pointing at the
highest numbered (lowest in memory) FREE DOS buffer
when CMCLOSE is exited via EVENTXIT and CLOSERTS.
- If the file is not already open on the first entry to
CMDCLOSE, only one pass is made. This single pass
resembles the second pass mentioned above.
.
.
- If necessary, the CLOSE FUNCTION updates the data
sector, T/S list sector & the VTOC. It also fixes
up links in the directory sectors and updates the
file size if needed.
.
.
(RTS)
(A2CB) LDA A5L+1 ;Hi byte of A5L/H pointer which points at the highest
;numbered (lowest in memory) free DOS name buffer (in chain).
(A2CD) BNE SAVFNPTR ;Branch if found a free buffer.
(A2CF) JMP NOBUFERR ;Go issue an out-of-buffers message.
------------ ;(See dis'mbly of errors.)
(A2D2)
SAVFNPTR STA A3L+1 ;Reset A3L/H to point at DOS buffer that we
LDA A5L ;will use for file name field buffer (chain).
STA A3L
(A2D8) JSR CPYPFN
* NOTE: This (re)assigns a DOS buffer to the
* file we want to OPEN. The buffer may or may
* not be the same one that was just released by
* the CLOSE cmd above. The highest numbered
* (lowest in memory) free DOS buffer is used.
(A743)
CPYPFN LDY #29 ;30 bytes to copy (0 to 29).
CPYPRIM LDA PRIMFNBF,Y ;Copy the name of the file wanted from
STA (A3L),Y ;the primary filename buffer into the
DEY ;filename field buffer (in DOS chain).
BPL CPYRIM ;More chars to get.
(A74D) RTS
(A2DB) JSR BUFS2PRM
* Get addresses of the various DOS buffers from the
* chain buffer & put them in the FM parameter list.
(A74E)
BUFS2PRM LDY #30 ;Get addr of FM work buf, T/S list
ADRINPRM LDA (A3L),Y ;buf, data sector buf & next DOS
STA WRKBUFFM-30,Y ;filename buf from chain
INY ;pointer buffer & put them in FM parm list.
CPY #38 ;(P.S. Adr of next DOS file name buf is
BNE ADRINPRM ;not used by DOS.)
(A75A) RTS
(A2DE) JSR CPY2PARM
* Put volume, drive, & slot values plus the
* address of the primary filename buffer
* in the FM parameter list.
(A71A)
CPY2PARM LDA VOLPRSD ;From parsed table.
STA VOLFM
LDA DRVPRSD ;From parsed table.
STA DRVFM
LDA SLOTPRSD ;From parsed table.
STA SLOTFM
LDA ADRPFNBF ;Get the adr of the primary file
STA FNAMBUFM ;name buf from the constants tbl
LDA ADRPFNBF+1 ;and put it in the FM parm list.
STA FNAMBUFM+1
LDA A3L ;Save adr of current DOS file name
STA CURFNADR ;buf in table of DOS variables.
LDA A3L+1
STA CURFNADR+1
(A742) RTS
(A2E1) LDA TEMPBYT ;Get open opcode back from temporary
STA OPCODEFM ;buffer & put it in the FM parameter list.
(A2E7) JMP FMDRIVER
------------
* Use the file manager driver to do the OPEN FUNCTION.
(A6A8)
FMDRIVER JSR FILEMGR ;Call the file manager to do the function.
* File manager proper.
(AB06)
FILEMGR TSX ;Save stk ptr so can later rtn 2 caller.
STX STKSAV
(AB0A) JSR RSTRFMWA
* Copy FM work buf (in DOS chain) to
* FM work area (not in DOS chain).
(AE6A)
RSTRFMWA JSR SELWKBUF ;Point A4L/H at FM
;work buffer.
* Get addr of FM
* work buff from
* the FM parm list
* & put it in the
* A4L/H pointer.
(AF08)
SELWKBUF LDX #0
(AF0A) BEQ PT2FMBUF
(AF12)
PT2FMBUF LDA WRKBUFFM,X
STA A4L
LDA WRKBUFFM+1,X
STA A4L+1
(AF1C) RTS
(AE6D) LDY #0 ;Zero out return
(AE6F) STY RTNCODFM ;code in FM parm
;list to signal
;no errors as
;default.
(AE72)
STORFMWK LDA (A4L),Y ;Copy FM wrk buf
STA FMWKAREA,Y ;to FM wrk area.
INY
CPY #45 ;45 bytes to copy
BNE STORFMWK ;(0 to 44).
CLC ;WHY?????
(AE7D) RTS
(AB0D) LDA OPCODEFM ;Check if opcode is legal.
CMP #13 ;(Must be less than 13.)
BCS TOERROP ;Opcode too large so got range error.
ASL ;Double val of opcode & put it in (x)
TAX ;so it indexes tables of adrs.
LDA FMFUNCTB+1,X ;Stick adr of appropriate function
PHA ;handler on stack (hi byte first).
LDA FMFUNCTB,X
PHA
(AB1E) RTS ;DO STACK JUMP TO FUNCTION ENTRY POINT.
.
.
(AB22)
FNOPEN .
.
- uses part of COMNOPEN routine.
- reads in VTOC to get link to 1rst directory.
- reads directory secs in & looks for file
description entry with matching filename.
- if matching name found, reads in the 1rst
T/S list sector belonging to the file.
- if no match found, starts a new file:
(1) creates new file description entry
- copies name to 1rst available space
in the directory sector. (If can't
find an available space, then issues
a disk-full error message.)
- assigns secs for file.
- writes updated VTOC to disk.
- puts link to first T/S list, file size,
etc. in directory entry space.
- writes directory sector buffer to disk.
(2) creates new T/S list & writes it to disk.
- reads T/S list back into T/S list buffer.
.
.
(RTS)
============
TOERROP JMP RNGERROP ;Go handle range error.
(AB1F) ------------ ;(See dis'mbly of errors.)
* Return here after doing the OPEN function.
* (Cause after @ function is done, use the
* stack to get back to the original caller.)
(A6AB)
AFTRFUNC BCC FMDRVRTN ;(c) = 0 = no errors.
LDA RTNCODFM ;Get error code from FM parameter list.
CMP #5 ;End-of-data error?
(A6B2) BEQ TOAPPTCH ;Yes - Got a zeroed-out T/S link or a
;zeroed-out data pair listed in a T/S list.
;(Not applicable to the open function.)
(A6B4) JMP OTHRERR ;No. See dis'mbly of errors.
------------
(A6C3)
FMDRVRTN RTS
(A3DC) PLA ;Pull file type code wanted from stack.
(A3DD) JMP CHKFTYPE ;Go check if type wanted = type found.
------------
* Check if file type wanted = file type found.
* (If saving a file which has same name as one already
* on disk, may get a type-mismatch error. However,
* a mismatch error is not possible if saving a new file.)
(A7C4)
CHKFTYPE EOR FILTYPFM ;Type found (via OPEN function).
(A7C7) BEQ CKTYPRTN ;Branch if type wanted = type found.
* File types didn't match.
* Check if correct type but locked.
(A7C9) AND #%01111111 ;Maybe matched - disregard lock bit.
(A7CB) BEQ CKTYPRTN ;Branch if matched.
* Type wanted < > type found!!!!!
* So go close file & then issue a
* type-mismatch-error message.
(A7CD) JSR CMDCLOSE ;Wrong kind of file so go close it.
(A2EA)
CMDCLOSE .
.
(See dis'mbly of CLOSE command.)
.
.
(RTS)
(A7D0) JMP TYPMISM ;Exit with type-mismatch error.
------------ ;(See dis'mbly of errors.)
CKTYPRTN RTS
(A7D3) ============
(A342) LDA ADRPRSD+1 ;Prepare to write address to disk.
LDY ADRPRSD ;(a) & (y) = hi / low bytes of parsed address values.
(A348) JSR WRADRLEN ;WRITE THE ADDRESS OF THE FILE by using the
;write-one-byte subfunction (WRITEONE, $ACBE) twice.
* Write two bytes.
* Code which writes address and length values
* to the data sector buffer. (Later, the data
* sector buffer is written to the disk.) Calls
* write-one-byte subfunction twice. Note that
* LEN2RDWR is used as a temporary buffer for data
* transfer as shown below:
* low byte of address (ADRPRSD) --> LEN2RDWR --> ONEIOBUF --> data sector buffer.
* hi byte of address (ADRPRSD+1) --> LEN2RDWR+1 --> ONEIOBUF --> data sector buffer.
(A3E0)
WRADRLEN STY LEN2RDWR ;Put low byte in FM parm list in case
;this is a L-parameter and we need it
;as a counter when later write data
;to the disk.
(A3E3) STY ONEIOBUF ;Put byte to write in parm list.
(A3E6) STA LEN2RDWR+1 ;Put hi byte in FM parm list in case
;this is a L-parameter and we need it
;as a counter when later write data
;to the disk.
(A3E9) LDA #4 ;Put write opcode in the FM parm list.
STA OPCODEFM
LDA #1 ;Put one-byte subcode in FM parm list.
STA SUBCODFM
(A3F3) JSR FMDRIVER ;Call FM driver to do the write.
* USE THE FILE MANAGER DRIVER TO
* WRITE THE LOW BYTE OF THE ADDRESS.
(A6A8)
FMDRIVER JSR FILEMGR ;Call the file manager to do the function.
* File manager proper.
(AB06)
FILEMGR TSX ;Save stk ptr so can later rtn to caller.
STX STKSAV
(AB0A) JSR RSTRFMWA
* Copy FM work buf (in DOS chain) to
* FM work area (not in DOS chain).
(AE6A)
RSTRFMWA JSR SELWKBUF ;Point A4L/H at
;FM work buf.
* Get addr of FM
* work buff from
* the FM parm list
* & put it in the
* A4L/H pointer.
(AF08)
SELWKBUF LDX #0
(AF0A) BEQ PT2FMBUF
(AF12)
PT2FMBUF LDA WRKBUFFM,X
STA A4L
LDA WRKBUFFM+1,X
STA A4L+1
(AF1C) RTS
(AE6D) LDY #0 ;Zero out return
(AE6F) STY RTNCODFM ;code in FM parm
;list 2 signal no
(AE72) ;errors as default.
STORFMWK LDA (A4L),Y ;Copy FM work buf
STA FMWKAREA,Y ;to FM work area.
INY
CPY #45 ;45 bytes to copy
BNE STORFMWK ;(0 to 44).
CLC ;WHY?????
(AE7D) RTS
(AB0D) LDA OPCODEFM ;Check if opcode is legal.
CMP #13 ;(Must be less than 13.)
BCS TOERROP ;Opcode too large so got range error.
ASL ;Double val of opcode & put it in (x)
TAX ;so it indexes tables of adrs.
LDA FMFUNCTB+1,X ;Stick adr of appropriate function
PHA ;handler on stack (hi byte first).
LDA FMFUNCTB,X
PHA
(AB1E) RTS ;DO STACK JUMP TO FUNCTION ENTRY POINT.
.
.
(See dis'mbly of write function (FNWRITE, $AC70) and
write-one-byte subfunction (WRITEONE, $ACBE).
.
.
Conditions on entry:
- File was just opened so appropriate T/S list is in memory.
- Since this is the very first time this function is called by
the BSAVE command, then:
FILPTSEC: $0000, FILPTBYT: $00,
RECNMBFM: $0000, RECNMBWA: $0000,
BYTOFFWA: $0000, BYTOFFFM: $0000,
RELFIRST: $0000, RELASTP1: $007A,
RELPREV: $FFFF,
LEN2RDWR: contents of ADRPRSD,
ONEIOBUF: low byte of parsed addr value.
(ONEIOBUF is low byte of the 2-byte CURIOBUF buffer.)
RECLENWA = RECLENFM = LENPRSD = val issued as L-parameter.
- Note the condition of the RELPREV and RELASTP1 flags.
These settings cause execution to eventually branch to the
GETDATPR ($B0F3) routine.
- When a brand new file is being created, GETDATPR detects the
zero bytes in the zeroed out T/S list. As a result, ASGNTKSC
($B244) is eventually called via NEWPAIR ($B10E) to allocate a
new data sector. The new trk/sec values (data pair) are then
placed in the T/S list buffer. Next, the data sector is
initialized (zeroed out) and bits 6 and 7 of the update flag
(UPDATFLG, $B5D5) are set to signal that both the data and T/S
list sectors require updating. Finally, the data to be written
is transferred from the ONEIOBUF ($B5C3) to the data sector.
- If the named file already exists, the trk/sec values of the
first data sector are obtained from the original T/S list
sector. Next, the data sector is read and one byte of data is
transferred from the ONEIOBUF ($B5C3) to the data sector
buffer. (This new byte overwrites an old (orignal) data byte.)
The write-one-byte subfunction is exited after bit 6 of the
update flag (UPDATFLG, $B5D5) is set to signal that the data
sector requires updating.
.
.
(RTS)
============
TOERROP JMP RNGERROP ;Go handle range error.
(AB1F) ------------ ;(See dis'mbly of errors.)
* Return here after doing the WRITE function.
* (Cause after @ function is done, use stack
* to get back to the original caller.)
(A6AB)
AFTRFUNC BCC FMDRVRTN ;(c) = 0 = no errors.
LDA RTNCODFM ;Get error code from FM parameter list.
CMP #5 ;End-of-data error?
(A6B2) BEQ TOAPPTCH ;Yes. Got a zeroed-out T/S link or a
;zeroed-out data pair listed in a T/S list.
;(Not applicable to the write function.)
(A6B4) JMP OTHRERR ;No. See dis'mbly of errors.
------------
FMDRVRTN RTS
(A6C3)
* Now send the high byte of the addr
* to the data sector buffer.
(A3F6) LDA LEN2RDWR+1 ;Put hi byte of address to write in parm list.
STA ONEIOBUF
(A3FC) JMP FMDRIVER ;Go write hi byte.
------------
* USE THE FILE MANAGER DRIVER TO WRITE
* THE HI BYTE OF THE ADDRESS.
(A6A8)
FMDRIVER JSR FILEMGR ;Call the file manager to do the function.
* File manager proper.
(AB06)
FILEMGR TSX ;Save stk pointer so can later rtn to caller of FM.
STX STKSAV
(AB0A) JSR RSTRFMWA
* Copy FM work buf (in DOS chain) to
* FM work area (not in DOS chain).
(AE6A)
RSTRFMWA JSR SELWKBUF ;Point A4L/H at FM work buf.
* Get addr of FM work buff from
* the FM parm list & put it in
* the A4L/H pointer.
(AF08)
SELWKBUF LDX #0 ;Offset to select
;work buffer.
(AF0A) BEQ PT2FMBUF ;ALWAYS.
(AF12)
PT2FMBUF LDA WRKBUFFM,X
STA A4L
LDA WRKBUFFM+1,X
STA A4L+1
(AF1C) RTS
(AE6D) LDY #0 ;Zero out return code in FM parm list to
STY RTNCODFM ;signal no errors as default condition.
STORFMWK LDA (A4L),Y ;Copy FM work buf to FM work area.
STA FMWKAREA,Y
INY
CPY #45 ;45 bytes to copy (0 to 44).
BNE STORFMWK
CLC ;WHY?????
(AE7D) RTS
(AB0D) LDA OPCODEFM ;Check if opcode is legal.
CMP #13 ;(Must be less than 13.)
BCS TOERROP ;Opcode too large so got range error.
ASL ;Double val of opcode & put it in (x)
TAX ;so it indexes tables of adrs.
LDA FMFUNCTB+1,X ;Stick adr of appropriate function
PHA ;handler on stack (hi byte first).
LDA FMFUNCTB,X
PHA
(AB1E) RTS ;DO STACK JUMP TO FUNCTION ENTRY POINT.
.
.
(See dis'mbly of write function (FNWRITE, $AC70)
and write-one-byte (WRITEONE, $ACBE) subfunction.
On entry - file was recently opened so appropriate
T/S list sec is in memory.
- FILPTSEC: $0000, FILPTBYT: $01,
RECNMBFM: $0000, RECNMBWA: $0000,
BYTOFFWA: $0001, BYTOFFFM: $0000,
RELFIRST: $0000, RELASTP1: $007A,
RELPREV: $0000,
LEN2RDWR: contents of ADRPRSD,
ONEIOBUF: hi byte of parsed addr value.
(ONEIOBUF is low byte of the 2-byte CURIOBUF buffer.)
RECLENWA = RECLENFM = LENPRSD = val issued as L-parameter.
- the 2nd byte of the address is transferred
from ONEIOBUF ($B5C3) to the data sector buffer.
.
.
(RTS)
============
TOERROP JMP RNGERROP ;Go handle range error.
(AB1F) ------------ ;(See dis'mbly of errors.)
* Return here after doing the write function.
* (Cause after @ function is done, use stack to get
* back to the original caller.)
(A6AB)
AFTRFUNC BCC FMDRVRTN ;(c) = 0 = no errors.
LDA RTNCODFM ;Get error code from FM parameter list.
CMP #5 ;End-of-data error?
(A6B2) BEQ TOAPPTCH ;Yes. Got a zeroed-out T/S link or a
;zeroed-out data pair listed in a T/S list.
;(Not applicable to the write function.)
(A6B4) JMP OTHRERR ;No. See dis'mbly of errors.
------------
(A6C3)
FMDRVRTN RTS
- Prepare to write file length fo file.
(A34B) LDA LENPRSD+1 ;(a) = hi byte of parsed length value.
LDY LENPRSD ;(y) = low byte of parsed length value.
(A351) JSR WRADRLEN ;Write file length (in low/hi format) as the
;3rd & 4th bytes in the data sector buffer.
* WRITE LENGTH OF FILE TO FILE.
(A3E0)
WRADRLEN .
.
(As per dis'mbly given above.)
.
.
Calls write-one-byte subfunction twice to put L(ength) parameter
as the 3rd & 4th bytes in the data sector buffer. (Later, the
buffer is written as the 1rst sector in the file.) Note that
LEN2RDWR ($B5C1) is used as a temporary buffer for data transfer:
low byte of length (LENPRSD) --> LEN2RDWR --> ONEIOBUF --> data sector buffer.
hi byte of length (LENPRSD+1) --> LEN2RDWR+1 --> ONEIOBUF --> data sector buffer.
Conditions on entry to 1rst call to write-one-byte subfunction:
FILPTSEC: $0000, FILPTBYT: $02,
RECNMBFM: $0000, RECNMBWA: $0000,
BYTOFFWA: $0002, BYTOFFFM: $0001,
RELFIRST: $0000, RELASTP1: $007A,
RELPREV: $0000,
LEN2RDWR: parsed length value,
ONEIOBUF: low byte of parsed length value.
(ONEIOBUF is low byte of the 2-byte CURIOBUF buffer.)
RECLENWA = RECLENFM = LENPRSD = val issued as L-parameter.
Conditions on entry for 2nd call to write-one-byte subfunction:
FILPTSEC: $0000, FILPTBYT: $03,
RECNMBFM: $0000, RECNMBWA: $0000,
BYTOFFWA: $0003, BYTOFFFM: $0002,
RELFIRST: $0000, RELASTP1: $007A,
RELPREV: $0000,
LEN2RDWR: parsed length value,
ONEIOBUF: hi byte of parsed length value.
(ONEIOBUF is low byte of the 2-byte CURIOBUF buffer.)
RECLENWA = RECLENFM = LENPRSD = val issued as L-parameter.
.
.
(RTS)
- Prepare to write rest of BINARY file.
(A354) LDA ADRPRSD+1 ;Put addr of source buffer in the Fm parm list.
LDY ADRPRSD
(A35A) JMP RWRANGE ;Go to write-range routine to write rest
------------ ;of file to disk. (File is also verified.)
- Prepare to write a range of bytes.
(A3FF)
RDWRANGE STY CURIOBUF ;Put adr of output buf in FM parm list.
(A402) STA CURIOBUF+1 ;(P.S. NOTE: THE LOW BYTE OF (CURIOBUF,
;$B5C3, $B5C4) IS THE ONE-BYTE BUFFER
;(ONEIOBUF, $B5C3) THAT WAS USED FOR
; WRITING VIA THE ONE-BYTE FUNCTION ABOVE.)
(A405) LDA #2 ;Set subcode for range of bytes.
;(Opcode is still set to write.)
(A407) JMP VRFYRWNG ;Go call file manager to write data to
------------ ;the disk. Next verify the info & close file.
(B686)
VRFYRWNG STA SUBCODFM ;Put range-of-bytes subcode in RWTS's IOB.
(B689) JSR FMDRIVER ;Call FM driver to write a range of bytes.
* USE THE FILE MANAGER DRIVER TO
* WRITE THE REST OF THE FILE.
(A6A8)
FMDRIVER JSR FILEMGR ;Call the file manager to do the function.
* File manager proper.
(AB06)
FILEMGR TSX ;Save stk pointer so can later rtn to caller of FM.
STX STKSAV
(AB0A) JSR RSTRFMWA
* Copy FM work buf (in DOS chain) to
* FM work area (not in DOS chain).
(AE6A)
RSTRFMWA JSR SELWKBUF ;Point A4L/H at FM work buf.
* Get addr of FM work buff from
* the FM parm list & put it in
* the A4L/H pointer.
(AF08)
SELWKBUF LDX #0 ;Offset to select
;work buffer.
(AF0A) BEQ PT2FMBUF ;ALWAYS.
(AF12)
PT2FMBUF LDA WRKBUFFM,X
STA A4L
LDA WRKBUFFM+1,X
STA A4L+1
(AF1C) RTS
(AE6D) LDY #0 ;Zero out return code in FM parm list to
STY RTNCODFM ;signal no errors as default condition.
STORFMWK LDA (A4L),Y ;Copy FM work buf to FM work area.
STA FMWKAREA,Y
INY
CPY #45 ;45 bytes to copy (0 to 44).
BNE STORFMWK
CLC ;WHY?????
(AE7D) RTS
(AB0D) LDA OPCODEFM ;Check if opcode is legal.
CMP #13 ;(Must be less than 13.)
BCS TOERROP ;Opcode too large so got range error.
ASL ;Double val of opcode & put it in (x)
TAX ;so it indexes tables of adrs.
LDA FMFUNCTB+1,X ;Stick adr of appropriate function
PHA ;handler on stack (hi byte first).
LDA FMFUNCTB,X
PHA
(AB1E) RTS ;DO STACK JUMP TO FUNCTION ENTRY POINT.
.
.
(See dis'mbly of the write function and (FNWRITE, $AC70) and
write-a-range-of-bytes subfunction (WRITERNG, $ACCA).)
On entry - file was recently opened so appropriate
T/S list sector is in memory.
- FILPTSEC: $0000, FILPTBYT: $04,
RECNMBFM: $0000, RECNMBWA: $0000,
BYTOFFWA: $0004, BYTOFFFM: $0003,
RELFIRST: $0000, RELASTP1: $007A,
RELPREV: $0000, CURIOBUF: starting addr from ADRPRSD,
LEN2RDWR: parsed length value.
(ONEIOBUF = low byte of CURIOBUF),
RECLENWA = RECLENFM = LENPRSD = val issued as L-parameter.
On exit - FILPTSEC: variable, FILPTBYT: variable
RECNMBFM: $0000, RECNMBWA: $0000,
BYTOFFWA: variable, BYTOFFFM: variable
RELFIRST: $0000, or $007A or multiple of $007A,
RELASTP1: $007A, or multiple of $007A,
RELPREV: variable, CURIOBUF: (val in ADRPRSD) * (parsed length),
LEN2RDWR: $0000
(ONEIOBUF = low byte of CURIOBUF),
RECLENWA = RECLENFM = LENPRSD = val issued as L-parameter.
Data are transferred from the source buffer to
the data sector buffer. As the data are
transferred, the value in CURIOBUF ($B5C3) is incremented
to point at the next byte in the source buffer.
Similarly, the value in LEN2RDWR ($B5C1) is decremented.
When LEN2RDWR=0, all the data have been transferred.
Each time a byte is transferred to the data sec buf,
bit 6 of UPFDATFLG ($B5D5) is set to indicate that the data
sec requires updating on the disk. When the data
sec buffer is full, it is written to the disk. If
a new file is being created, or if a pre-existing
file is being enlarged, the ASNGTKSC ($B244) routine
is called to find a free data sec. The trk & sec values
of the data sec are then added to the T/S list. The
write subfunction can be exited when the data sec buffer
is not completely, full. However, the close function
eventually tests the status of the UPDATFLG ($B5D5) flag
and if necessary, writes the updated data sec & T/S list
sec buffers to the disk. (P.S. Note that when an
Applesoft or binary file is being written, it is considered
to consist of a collection of one-byte long records.)
.
.
(RTS)
============
TOERROP JMP RNGERROP ;Go handle range error.
(AB1F) ------------ ;(See dis'mbly of errors.)
* Return here after doing the write function.
*(Cause after @ function is done, use stack to get
* back to the original caller.)
(A6AB)
AFTRFUNC BCC FMDRVRTN ;(c) = 0 = no errors.
LDA RTNCODFM ;Get error code from FM parameter list.
CMP #5 ;End-of-data error?
(A6B2) BEQ TOAPPTCH ;Yes. Got a zeroed-out T/S link or a
;zeroed-out data pair listed in a T/S list.
;(Not applicable to the write function.)
(A6B4) JMP OTHRERR ;No. See dis'mbly of errors.
------------
(A6C3)
FMDRVRTN RTS
(B68C) JSR CMDCLOSE ;Close file & then verify the data.
(A2EA)
CMDCLOSE .
.
(See dis'mbly of CLOSE command.)
- USE CLOSE COMMAND TO WRITE LAST DATA AND
T/S LIST SECTORS TO THE DISK IF NECESSARY
AND THEN FREE THE DOS BUFFER.
- Because the file is open, execution flows
through the CLOSE command twice. The first
time thru, the matching DOS filename buffer
is located and then CLOSEONE ($A2FC) is used
to close the file via the close FUNCTION. The second
time thru, a matching filename buffer is not found
because the DOS buffer was released on the first pass.
Therefore, A5L/H is left pointing at the highest
numbered (lowest in memory) FREE DOS buffer when
the CLOSE command is exited via EVENTXIT and CLOSERTS.
.
.
(RTS)
(B68F) JMP CMDVERFY ;Go verify the data.
------------
(A27D)
CMDVERFY LDA #12 ;Verify opcode.
(A27F) BNE LOKUNLOK ;ALWAYS.
(A277)
LOKUNLOK JSR HNDLCMD1 ;Call part of the main command handler
;routine to VERIFY the file.
* Part of common file manager command handler code.
(A2AA)
HNDLCMD1 STA TEMPBYT ;Store opcode in temporary location.
LDA LENPRSD ;Get L-parameter from parsed table.
BNE SAVLENFM ;Was a non-zero L-parm issued with cmd?
LDA LENPRSD+1
BNE SAVLENFM
LDA #1 ;Length was 0 so make it 1 instead.
STA LENPRSD
SAVLENFM LDA LENPRSD ;Put length in FM parm list.
STA RECLENFM
LDA LENPRSD+1
STA RECLENFM+1
CLSLOCBF JSR CMDCLOSE ;Close file if it's already open.
(A2C8)
(A2EA)
CMDCLOSE .
.
(See dis'mbly of CMDCLOSE command.)
.
.
- File was just closed, so now the close command
is simply used to locate a free DOS buffer for
verification by reading. (A5L/H is left pointing
at the highest numbered (lowest in memory)
FREE DOS buffer when CMCLOSE is exited via
EVENTXIT and CLOSERTS.)
.
.
(RTS)
(A2CB) LDA A5L+1 ;Hi byte of A5L/H pointer which points at the highest
;numbered (lowest in memory) free DOS name buffer (in chain).
(A2CD) BNE SAVFNPTR ;Branch if found a free buffer.
(A2CF) JMP NOBUFERR ;Go issue an out-of-buffers message.
------------ ;(See dis'mbly of errors.)
(A2D2)
SAVFNPTR STA A3L+1 ;Reset A3L/H to point at DOS buffer that we
LDA A5L ;will use for file name field buffer (chain).
STA A3L
(A2D8) JSR CPYPFN
* NOTE: This (re)assigns a DOS buffer to the
* file we want to VERIFY. The buffer may or may not
* be the same one that was just released by the close cmd
* above. The highest numbered (lowest in memory) free
* DOS buffer is used.
(A743)
CPYPFN LDY #29 ;30 bytes to copy (0 to 29).
CPYPRIM LDA PRIMFNBF,Y ;Copy the name of the file wanted from
STA (A3L),Y ;the primary filename buffer into the
DEY ;filename field buffer (in DOS chain).
BPL CPYRIM ;More chars to get.
(A74D) RTS
(A2DB) JSR BUFS2PRM
* Get addresses of the various DOS buffers from the
* chain buffer & put them in the FM parameter list.
(A74E)
BUFS2PRM LDY #30 ;Get addr of FM work buf, T/S list
ADRINPRM LDA (A3L),Y ;buf, data sector buf & next DOS
STA WRKBUFFM-30,Y ;filename buf from chain
INY ;pointer buffer & put them in FM parm list.
CPY #38 ;(P.S. Adr of next DOS file name buf is
BNE ADRINPRM ;not used by DOS.)
(A75A) RTS
(A2DE) JSR CPY2PARM
* Put volume, drive, & slot values plus the
* address of the primary filename buffer
* in the FM parameter list.
(A71A)
CPY2PARM LDA VOLPRSD ;From parsed table.
STA VOLFM
LDA DRVPRSD ;From parsed table.
STA DRVFM
LDA SLOTPRSD ;From parsed table.
STA SLOTFM
LDA ADRPFNBF ;Get the adr of the primary file
STA FNAMBUFM ;name buf from the constants tbl
LDA ADRPFNBF+1 ;and put it in the FM parm list.
STA FNAMBUFM+1
LDA A3L ;Save adr of current DOS file name
STA CURFNADR ;buf in table of DOS variables.
LDA A3L+1
STA CURFNADR+1
(A742) RTS
(A2E1) LDA TEMPBYT ;Get verify opcode back from the temporary
STA OPCODEFM ;buffer & put it in the FM parameter list.
(A2E7) JMP FMDRIVER
------------
* Use the file manager driver to do the VERIFY function.
(A6A8)
FMDRIVER JSR FILEMGR ;Call the file manager to do the function.
* File manager proper.
(AB06)
FILEMGR TSX ;Save stk pointer so can later rtn to caller of FM.
STX STKSAV
(AB0A) JSR RSTRFMWA
* Copy FM work buf (in DOS chain) to
* FM work area (not in DOS chain).
(AE6A)
RSTRFMWA JSR SELWKBUF ;Point A4L/H at FM work buf.
* Get addr of FM work buff from
* the FM parm list & put it in
* the A4L/H pointer.
(AF08)
SELWKBUF LDX #0 ;Offset to select
;work buffer.
(AF0A) BEQ PT2FMBUF ;ALWAYS.
(AF12)
PT2FMBUF LDA WRKBUFFM,X
STA A4L
LDA WRKBUFFM+1,X
STA A4L+1
(AF1C) RTS
(AE6D) LDY #0 ;Zero out return code in FM parm list to
STY RTNCODFM ;signal no errors as default condition.
STORFMWK LDA (A4L),Y ;Copy FM work buf to FM work area.
STA FMWKAREA,Y
INY
CPY #45 ;45 bytes to copy (0 to 44).
BNE STORFMWK
CLC ;WHY?????
(AE7D) RTS
(AB0D) LDA OPCODEFM ;Check if opcode is legal.
CMP #13 ;(Must be less than 13.)
BCS TOERROP ;Opcode too large so got range error.
ASL ;Double val of opcode & put it in (x)
TAX ;so it indexes tables of adrs.
LDA FMFUNCTB+1,X ;Stick adr of appropriate function
PHA ;handler on stack (hi byte first).
LDA FMFUNCTB,X
PHA
(AB1E) RTS ;DO STACK JUMP TO FUNCTION ENTRY POINT.
.
.
(AD18)
FNVERIFY .
.
(See dis'mbly of the VERIFY function.)
- reads in VTOC & appropriate directory, T/S list
& data sectors.
- The verify function simply opens & then reads
a file. Actual verification occurs deep within
RWTS. As the data are read in, the disk bytes are
translated to nibbles & cummulatively EORed
together to calculate a running checksum.
If the final calculated checksum agrees
with the checksum read off the disk, the integrity
of the data is verified. Failure to verify yeilds
an I/O error.
.
.
(RTS)
============
TOERROP JMP RNGERROP ;Go handle range error.
(AB1F) ------------ ;(See dis'mbly of errors.)
* Return here after doing the VERIFY function.
* (Cause after @ function is done, use the
* stack to get back to the original caller.)
(A6AB)
AFTRFUNC BCC FMDRVRTN ;(c) = 0 = no errors.
LDA RTNCODFM ;Get error code from FM parameter list.
CMP #5 ;End-of-data error?
(A6B2) BEQ TOAPPTCH ;Yes. Got a zeroed-out T/S link or a
;zeroed-out data pair listed in a T/S list.
;(Not applicable to the verify function.)
(A6B4) JMP OTHRERR ;No. See dis'mbly of errors.
------------
(A6C3)
FMDRVRTN RTS
(A27A) JMP CMDCLOSE ;Go back into CMDCLOSE to close the
------------ ;file that was just opened via the
;verify function.
(A2EA)
CMDCLOSE .
.
(See dis'mbly of CLOSE command.)
.
.
(RTS) ;Return to the caller of the BSAVE command.
============ ;(Normally returns to AFTRCMD ($A17D)
;located in the cmd parsing and processing
;routines.)
- No Address or Length parameters were
- issued with the BSAVE comand.
(A000)
CKIFCTRL LDA BUF200 ;Is the FIRST character in the input buf
CMP DCTRLCHR ;equal to DOS'S control character?
(A006) BEQ CHKIFCR ;Yes.
- Was DOS's control character the only
- character on the line?
(A00B)
CHKIFCR LDA BUF200+1 ;Get second char in input buffer.
CMP #$8D ;Is it a carriage return?
(A010) BNE PRSYNERR ;Wasn't just DOS's ctrl char (and a <cr>) so
;go issue a syntax-error message.
(A018)
PRSYNERR JMP SYNTXERR ;Go issue a syntax-error message.
------------ ;(See dis'mbly of errors.)