810 lines
64 KiB
Plaintext
810 lines
64 KiB
Plaintext
******************************************************************
|
|
* *
|
|
* APPEND Command Handler *
|
|
* *
|
|
*----------------------------------------------------------------*
|
|
* *
|
|
* The APPEND command is intended to help you lengthen a *
|
|
* pre-exsiting SEQUENTIAL text file. This command opens the *
|
|
* specified file and then locates the end of the file so that a *
|
|
* subsequent WRITE command can add new data contiguous to old *
|
|
* data. A file name must be issued with the command. Volume, *
|
|
* drive and slot parameters are optional. *
|
|
* Unfortunately, the append command does not always adjust *
|
|
* the file pointer correctly eventhough Apple Computer Inc. has *
|
|
* repeatedly attempted to fix this routine. Because patches *
|
|
* have been added to repair previous patches and because *
|
|
* execution fails on occassion, the append command has evolved *
|
|
* into a classic case of spaghetti programming. *
|
|
* *
|
|
* Execution pattern and bugs: *
|
|
* The APPEND command (CMDAPPND, $A298) calls the open *
|
|
* command (CMDOPEN, $A2A3) to locate the named file, read in its *
|
|
* first T/S list and aim the three-byte file pointer (FILPTSEC, *
|
|
* $B5E4; FILPTSEC+1, $B5E5; FILPTBYT, $B5E6) at the first byte *
|
|
* of the file. If the named file cannot be located, a file-not- *
|
|
* found message is generated. *
|
|
* After opening the file, the append command repeatedly *
|
|
* calls RDTXTBYT ($A68C) to read the file byte-by-byte until the *
|
|
* end of the file is located. RDTXTBYT uses the read function *
|
|
* (FNREAD, $AC58) and read-one-byte subfunction (READONE, *
|
|
* $AC8A). READONE in turn calls RDDATA ($ACA8) to do the actual *
|
|
* reading and examination of the bytes. (Only a very minor *
|
|
* portion of the RDDATA routine is shown below. See the *
|
|
* formatted disassembly titled "PSNRDONE" for more details.) *
|
|
* The first $00 byte encountered denotes the end of the *
|
|
* file. This end-of-file marker (eof) can be located in a data *
|
|
* or T/S list sector. The eof is found in the last DATA sector *
|
|
* if that sector is not completely full. However, if the file *
|
|
* ends on a sector boundary (ie. the last data sector is full), *
|
|
* then the eof marker is detected in a T/S list sector. If the *
|
|
* last T/S list of the file describes less than 122 ($7A) data *
|
|
* sectors, the RDDATA routine encounters a zero byte when it *
|
|
* looks in the T/S list for the trk/sec values of the next data *
|
|
* sector. However, if the file has a multiple of 122 data *
|
|
* sectors, the last T/S list is full of valid data pairs. In *
|
|
* this case, the end-of-file marker is detected as a zeroed-out *
|
|
* T/S link when the RDDATA routine looks for the next T/S list *
|
|
* sector. *
|
|
* The location of the eof marker dictates the subsequent *
|
|
* execution pattern. When the first $00 byte is discovered in a *
|
|
* DATA sector, the carry is cleared and the RDDATA routine is *
|
|
* exited with the filepointer and record numbers adjusted as *
|
|
* follows: *
|
|
* $XX <------ last valid data byte. *
|
|
* $00 <------ RECNMBFM points here. *
|
|
* $00 <------ RECNMBWA & filepointer aimed here. *
|
|
* Because we eventually want to enter the subsequent WRITE *
|
|
* command with the record numbers and filepointer aimed at the *
|
|
* the byte to be overwritten, RECNMBWA and the filepointer need *
|
|
* to backed up one byte. However, if an eof is located in a T/S *
|
|
* list, the RDDATA routine is eventually exited with the carry *
|
|
* clear and the record numbers and filepointer set as follows: *
|
|
* $XX <------- last valid data byte *
|
|
* & target of RECNMBFM. *
|
|
* $00 <------- RECNMBWA & filepointer aimed here. *
|
|
* RECNMBWA and the filepointer don't require adjusting before *
|
|
* doing the subsequent write because they already point to the *
|
|
* byte to be overwritten. *
|
|
* Actual adjustment of the record numbers and the file- *
|
|
* pointer occur in the CKAPFLG ($B671) and RSETPTRS ($B6B3) *
|
|
* routines. If the end-of-file marker was found in a T/S list *
|
|
* sector (and the file is not an empty file), the CKAPFLG *
|
|
* routine is entered with the append flag (APPNDFLG, $B65D) set. *
|
|
* A set append flag forces RECNMBFM ($B5BD)to be incremented. *
|
|
* By the time the RSETPTRS routine is entered, the append flag *
|
|
* has been turned off and RECNMBFM corresponds to the eof. *
|
|
* RSETPTRS copies the contents of RECNMBFM ($B5BD) into RECNMBWA *
|
|
* ($B5FA) and the lower two bytes of the filepointer (FILPTSEC, *
|
|
* $B5E4 and FILPTBYT, $B5E6). The append command is then exited *
|
|
* via GOODFMXIT ($B37F. *
|
|
* Normally, the append command is exited with the record *
|
|
* numbers and filepointer correctly aimed at the byte to be *
|
|
* overwritten. However, because RSETPTRS only adjusts the lower *
|
|
* two bytes of the filepointer, the append command can fail if *
|
|
* the high byte of the pointer (FILPTSEC+1, $B5E4) needs to be *
|
|
* backed up. This situation only occurs if a file contains *
|
|
* exactly $FFFF (65535) or 2 * $FFFF (131070) data bytes. *
|
|
* (A file 2 * $FFFF bytes long can only be created if DOS is *
|
|
* altered to free up some extra sectors.) The chances of the *
|
|
* append command failing are therefore very small indeed. No *
|
|
* wonder some bugs seem to take forever to surface! *
|
|
* *
|
|
******************************************************************
|
|
|
|
|
|
* 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.
|
|
* - a legal file name has been parsed and
|
|
* stored in the primary file name buffer
|
|
* (PRIMFNBUF, $AA75).
|
|
* - confirmation has been made that the
|
|
* computer is working in the deferred mode.
|
|
|
|
|
|
(A298)
|
|
CMDAPPND JSR CMDOPEN ;Go open the file to be appended.
|
|
|
|
(A2A3)
|
|
CMDOPEN LDA #0 ;0 = code for text file.
|
|
(A2A5) JMP OPNCKTYP ;Go open the file & chk its type.
|
|
------------
|
|
|
|
(A3D5)
|
|
OPNCKTYP STA FILTYPFM ;Put code for file type in the
|
|
(A3D8) PHA ;Fm parameter list & save it on stk.
|
|
;($00=Text, $01=Integer, $02=Applesoft,
|
|
;$04=Binary, $08=S-type, $10=Relocatable,
|
|
;$20=A-type and $40=B-type.)
|
|
(A3D9) JSR HNDLCMD ;Use FM cmd handler to open file.
|
|
|
|
* Common file manager command handler code.
|
|
(A2A8)
|
|
HNDLCMD LDA #1 ;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 ;(Note: Record length = 1 for sequential files
|
|
LDA LENPRSD+1 ;else parsed length for random access files.)
|
|
STA RECLENFM+1
|
|
CLSLOCBF JSR CMDCLOSE ;Close file if it's already open.
|
|
(A2C8)
|
|
|
|
(A2EA)
|
|
CMDCLOSE .
|
|
.
|
|
(See dis'mbly of CMDCLOSE.)
|
|
.
|
|
.
|
|
- 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 buffer
|
|
STA OPCODEFM ;and 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
|
|
|
|
* Get adr of FM work
|
|
* buf from 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 code
|
|
(AE6F) STY RTNCODFM ;in FM parm list to
|
|
;signal no errors as
|
|
(AE72) ;default condition.
|
|
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.
|
|
|
|
(AB22) .
|
|
FNOPEN .
|
|
.
|
|
(See dis'mbly of OPEN function.)
|
|
.
|
|
.
|
|
- 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 by:
|
|
(1) creates new file description entry
|
|
- copies name to 1rst available spc
|
|
in direc sec (if can't find spc, then
|
|
issues disk-full error message).
|
|
- allocates 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 buf.
|
|
.
|
|
.
|
|
(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 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 in T/S list.
|
|
;(Not applicable to the open function.)
|
|
(A6B4) JMP OTHRERR ;No - See dis'mbly of errors.
|
|
------------
|
|
|
|
(A6C3)
|
|
FMDRVRTN RTS
|
|
|
|
(A3DC) PLA ;Get file type wanted off of stack.
|
|
(A3DD) JMP CHKFTYPE ;Go check if type wanted equals type found.
|
|
------------
|
|
|
|
* Check if file type wanted = file type found.
|
|
* (If using open command to open a pre-exisiting file,
|
|
* may get a type mismatch. However, a mismatch error
|
|
* is not possible when opening 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.
|
|
;(See dis'mbly of close command.)
|
|
(A7D0) JMP TYPMISM ;See dis'mbly of errors.
|
|
------------ ;(Eventually goes into DOS's warm start routine.)
|
|
|
|
CKTYPRTN RTS
|
|
(A7D3) ========
|
|
|
|
(A29B)
|
|
READ2END JSR RDTXTBYT
|
|
|
|
(A68C)
|
|
RDTXTBYT LDA #3 ;Set read opcode.
|
|
STA OPCODEFM
|
|
LDA #1 ;Set one-byte subcode.
|
|
STA SUBCODFM
|
|
(A696) JSR FMDRIVER ;Call FM driver to read a data byte.
|
|
|
|
(A6A8)
|
|
FMDRIVER JSR FILEMGR ;Call the file manager to do the function.
|
|
|
|
(AB06)
|
|
FILEMGR TSX ;Save stk ptr so we can rtn to caller.
|
|
STX STKSAV
|
|
(AB0A) JSR RSTRFMWA ;Copy contents of FM work buffer (in DOS
|
|
;chain) to FM work area (not in chain).
|
|
|
|
(AE6A)
|
|
RSTRFMWA JSR SELWKBUF ;Find FM work buffer.
|
|
|
|
* Get address of FM
|
|
* work buf from FM
|
|
* parm list & stick
|
|
* it in the A4L/H
|
|
* pointer.
|
|
(AF08)
|
|
SELWKBUF LDA #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 rtn code in
|
|
STY RTNCODFM ;lst 2 signal no errs.
|
|
STORFMWK LDA (A4L),Y ;Copy FM work buf
|
|
STA FMWKAREA,Y ;(in chain) to FM
|
|
INY ;wrk area (not in
|
|
CPY #45 ;DOS buf chain).
|
|
BNE STORFMWK
|
|
CLC ;Why?????
|
|
(AE7D) RTS
|
|
|
|
(AB0D) LDA OPCODEFM ;Chk if opcode is legal.
|
|
CMP #13 ;(Must be less than 13.)
|
|
BCS TOERROP ;Opcode too large, got range error.
|
|
ASL ;Double val of opcode & get addr of
|
|
TAX ;appropriate function handler from tbl.
|
|
LDA FMFUNCTB+1,X ;Put the adr on stack (hi byte first)
|
|
PHA ;& then do a "stack jump" to the appropriate
|
|
LDA FMFUNCTB,X ;function handler.
|
|
PHA
|
|
(AB1E) RTS
|
|
|
|
.
|
|
.
|
|
(AC58) .
|
|
FNREAD LDA SUBCODFM ;Check if subcode is legal.
|
|
CMP #5 ;(Must be < = 5.)
|
|
(AC5D) BCS TOERRSUB ;Error - illegal subcode.
|
|
;(Not applicable to append command.)
|
|
(AC5F) ASL ;Subcode * 2, cause 2 bytes/address.
|
|
TAX ;Index table of subfunction addresses.
|
|
LDA RDSUBTBL+1,X ;Get address (minus 1) of subfuction
|
|
PHA ;entry point & stick it on the stack
|
|
LDA RDSUBTBL,X ;(hi byte first). Then do a "stack
|
|
PHA ;jump" to execute the given READ sub-
|
|
(AC69) RTS ;function. (APPEND COMMAND ALWAYS USES
|
|
;THE READ-ONE-BYTE SUBFUNCTION.)
|
|
|
|
|
|
(AB1F) ------------
|
|
TOERROP JMP RNGERROP ;Go handle range error.
|
|
------------ ;(See dis'mbly of errors.)
|
|
|
|
|
|
(AC6A) ------------
|
|
TOERRSUB JMP RNGERRSB ;Go handle range error.
|
|
------------ ;(See dis'mbly of errors.)
|
|
|
|
|
|
.
|
|
.
|
|
(AC8A) .
|
|
READONE JSR RDDATA
|
|
|
|
(ACA8)
|
|
RDDATA .
|
|
.
|
|
- Read in the file byte-by-byte by
|
|
reading in the data and T/S list
|
|
sectors as required.
|
|
- If an end-of-file marker (eof) is
|
|
detected in a T/S list, SET the carry.
|
|
An eof marker only resides in the T/S
|
|
list if the last data sector is full-
|
|
to-the-brim. The $00 byte may be
|
|
picked up as a zeroed-out data pair or
|
|
T/S list link (depending on the length
|
|
of the file).
|
|
- If a DATA sector byte is being read,
|
|
CLEAR the carry (irregardless if the data
|
|
byte is valid or an eof).
|
|
- See formatted disassembly of the read
|
|
function for more details.
|
|
.
|
|
.
|
|
(ACAB) BCS NDATERR
|
|
-----------
|
|
(ACAD) LDA (A4L),Y ;Get single byte read
|
|
;from data sector buf.
|
|
(ACAF) PHA ;Save it on the stack.
|
|
(ACB0) JSR INCREC ;Inc the record #
|
|
;or the offset into
|
|
;the record.
|
|
(ACB3) JSR INCFILPT ;Inc the file ptr.
|
|
PLA ;Get byte just read.
|
|
(ACB7) RTS
|
|
=============
|
|
|
|
(AC8D) STA ONEIOBUF ;Put byte just read in the one-byte buffer
|
|
;contained in the FM parameter list.
|
|
(AC90) JMP GOODFMXT ;Exit the file manager.
|
|
-------------
|
|
|
|
(B37F)
|
|
GOODFMXT LDA RTNCODFM
|
|
CLC ;(c) = 0 to signal good operation.
|
|
(B383) BCC FMEXIT
|
|
|
|
(B386)
|
|
FMEXIT PHP ;Save status on stack.
|
|
STA RTNCODFM ;Store return code in FM parameter list.
|
|
LDA #0 ;Avoid that infamous $48 bug.
|
|
STA STATUS
|
|
(B38E) JSR CPYFMWA
|
|
|
|
* Copy the FM work area buffer (non-chain)
|
|
* to the FM work buffer (in DOS chain).
|
|
(AE7E)
|
|
CPYFMWA JSR SELWKBUF ;Select the FM work
|
|
;buf (in DOS chain).
|
|
|
|
* Point the A4L/H ptr
|
|
* at work buffer.
|
|
(AF08)
|
|
SELWKBUF LDX #0
|
|
(AF0A) BEQ PT2FMBUF
|
|
|
|
(AF12)
|
|
PT2FMBUF LDA WRKBUFFM,X
|
|
STA A4L
|
|
LDA WRKBUFFM+1,X
|
|
STA A4L+1
|
|
(AF1C) RTS
|
|
|
|
(AE81) LDY #0 ;Initialize index.
|
|
STORWRK LDA FMWKAREA,Y ;Get byte from work
|
|
STA (A4L),Y ;area & put it in
|
|
INY ;the work buffer.
|
|
CPY #45 ;45 bytes to copy
|
|
BNE STORWRK ;(0 to 44).
|
|
(AE8D) RTS
|
|
|
|
(B391) PLP ;Retrieve status of success of operation
|
|
;back from the stack.
|
|
(B392) LDX STKSAV ;Adjust the stack pointer to force exit
|
|
TXS ;to the caller even if several subroutines
|
|
(B396) RTS ;deeper than original entry. In this
|
|
============ ;particular case, return to AFTRFUNC.
|
|
|
|
* This routine is entered only if a
|
|
* end-of-file marker was found in
|
|
* a T/S list.
|
|
(ACB8)
|
|
NDATERR JMP ENDOFDAT ;Ran out of data while
|
|
------------ ;reading or appending.
|
|
|
|
(B36F)
|
|
ENDOFDAT LDA #5 ;Out of data code.
|
|
(B371) BNE BADFMXIT ;ALWAYS.
|
|
|
|
(B385)
|
|
BADFMXIT SEC ;(c)=1=unsuccessful.
|
|
FMEXIT PHP ;Save status on stack.
|
|
STA RTNCODFM ;Save return code.
|
|
LDA #0 ;Avoid $48 bug.
|
|
STA STATUS
|
|
(B38E) JSR CPYFMWA
|
|
|
|
* Copy work area
|
|
* to work buffer.
|
|
(AE7E)
|
|
CPYFMWA JSR SELWKBUF
|
|
|
|
* Point A4L/H ptr
|
|
* at work buffer.
|
|
(AF08)
|
|
SELWKBUF LDX #0
|
|
(AF0A) BEQ PT2FMBUF
|
|
|
|
(AF12)
|
|
PT2FMBUF LDA WRKBUFFM,X
|
|
STA A4L
|
|
LDA WRKBUFFM+1,X
|
|
STA A4L+1
|
|
(AF1C) RTS
|
|
|
|
* Do the copying.
|
|
(AE81) LDY #0
|
|
STORWRK LDA FMWKAREA,Y
|
|
STA (A4L),Y
|
|
INY
|
|
CPY #45
|
|
BNE STORWRK
|
|
(AE8D) RTS
|
|
|
|
(B391) PLP ;Get success of oper-
|
|
;ation from stk.
|
|
(B392) LDX STKSAV ;Adjust stack ptr
|
|
TXS ;to force exit
|
|
(B396) RTS ;to the caller even
|
|
============ ;when several sub-
|
|
;routines deeper
|
|
;than orig entry.
|
|
;In this case,
|
|
;return to AFTRFUNC.
|
|
|
|
* Return here after doing the READ function
|
|
* (Cause after @ function is done, use stack
|
|
* to get back to original caller.)
|
|
*
|
|
* = If dealing with a byte from a data sector
|
|
* (even if that byte is a $00) enter with:
|
|
* - RECNMBFM = record # corresponding to byte just read.
|
|
* - RECNMBWA = record # associated with next potential
|
|
* byte situated after byte just read.
|
|
* (ie. RECNMBWA = 1 greater than contents
|
|
* of RECNMBFM.)
|
|
* - Filepointer aimed 1 byte past byte just read.
|
|
* (ie. lower two bytes of filepointer contain
|
|
* the same values as RECNMBWA.)
|
|
* - Carry is CLEAR.
|
|
*
|
|
* = If dealing with a $00 byte read from the T/S list
|
|
* then either got a zeroed-out T/S link or a
|
|
* zeroed out data pair . In either case, enter with:
|
|
* - RECNMBFM = record # of last valid data byte.
|
|
* - RECNMBWA = record # of next potential data byte.
|
|
* (ie. RECNMBWA is always 1 > RECNMBFM).
|
|
* - Filepointer aimed at next potential data byte
|
|
* byte position. Lowest two bytes of filpointer
|
|
* (FILPTSEC and FILPTBYT) are same as RECNMBWA and
|
|
* RECNMBWA+1.
|
|
* - Carry is SET.
|
|
|
|
(A6AB)
|
|
AFTRFUNC BCC FMDRVRTN ;Branch if dealing with byte from
|
|
;a data sector (as opposed to byte
|
|
;from a T/S list).
|
|
(A6AD) LDA RTNCODFM ;Get error code from FM parameter list.
|
|
CMP #5 ;End-of-data error?
|
|
(A6B2) BEQ TOAPPTCH ;Yes - not handled like other errors!!!.
|
|
;File ends at a full data sec and so we
|
|
;encountered a zeroed out T/S link or a
|
|
;zeroed out data pair (trk/sec vals for
|
|
;next data sec listed in T/S list).
|
|
(A6B4) JMP OTHRERR ;Only take if got an error other than
|
|
------------ ;an end-of-data error. (See dis'mbly
|
|
;of errors.)
|
|
TOAPPTCH JMP APNDPTCH
|
|
(A6B7) ------------
|
|
|
|
* Note: You are now entering an almost
|
|
* undecipherable mess of spaghetti programming.
|
|
* Parts of the following routines seem useless.
|
|
* They may just be residual (but innocuous)
|
|
* instructions that are left over from an
|
|
* earlier version of DOS.
|
|
|
|
* Check if file pointer and WASTEBYT are zeroes.
|
|
(B692)
|
|
APNDPTCH LDY #$13
|
|
CK4ZEROS LDA (A4L),Y
|
|
(B696) BNE SETAPFLG ;Unless we are dealing with a
|
|
;useless file that was previously
|
|
;opened, but never closed, this
|
|
;instruction is always taken.
|
|
(B698) INY
|
|
CPY #$17
|
|
(B69B) BNE CK4ZEROS
|
|
|
|
* The purpose of the following instructions is not
|
|
* understood. This section of code may have been
|
|
* designed to deal with useless files that were
|
|
* opened but never closed. Whatever the original
|
|
* purpose was, the following code appears to keep
|
|
* the file pointer at #$000000 when a file with no
|
|
* data is encountered.
|
|
(B69D) LDY #$19
|
|
COPYRECS LDA (A4L),Y ;Copy image of RECNMBWA/+1 and BYTOFFWA/+1
|
|
STA RECNMBFM-$19,Y ;that were just stored in the work
|
|
INY ;buffer to RECNMBFM/+1 and BYTOFFFM/+1
|
|
CPY #$1D ;in the FM parm list.
|
|
BNE COPYRECS
|
|
FMDVRTN JMP BK2FMDRV
|
|
(B6A9) ------------
|
|
|
|
* Set the append flag.
|
|
* (Never entered if dealing
|
|
* with an empty file.)
|
|
(B6AC)
|
|
SETAPFLG LDX #$FF
|
|
STX APPNDFLG ;Set the append flag.
|
|
(B6B1) BNE FMDVRTN ;ALWAYS.
|
|
------------
|
|
|
|
(A6BA) NOP
|
|
BK2FMDRV JSR CKIFAPND
|
|
(A6BB)
|
|
|
|
* Check if using APPEND command.
|
|
(BA69)
|
|
CKIFAPND LDX NDX2CMD ;Get command index.
|
|
CPX #$1C ;Are we APPENDing?
|
|
BEQ RTNCKAPN ;Yes - leave flag on.
|
|
LDX #0 ;No - turn off append flag.
|
|
STX APPNDFLG
|
|
RTNCKAPN RTS
|
|
(BA75)
|
|
|
|
(A6BE) LDX #0 ;Zero out the one-data byte parameter in FM parm list.
|
|
STX ONEIOBUF ;(Also referred to as low byte of CURIOBUF.)
|
|
FMDRVRTN RTS ;Return to caller of FMDRIVER.
|
|
(A6C3)
|
|
|
|
(A699) LDA ONEIOBUF ;Get byte just read.
|
|
(A69C) RTS
|
|
|
|
(A29E) BNE READ2END ;Take branch if dealing with a valid
|
|
;data byte. Haven't encountered an end-
|
|
;of-file marker yet, so go back to read
|
|
;rest of file.
|
|
(A2A0) JMP CKAPFLG ;Detected an end-of-file marker (a $00 byte).
|
|
------------
|
|
|
|
* Prepare to manually back up file pointer
|
|
* if necessary. Need to back it up one byte
|
|
* if a $00 byte was encountered in a data sector.
|
|
* However, if a zeroed-out data pair (listed
|
|
* in the T/S list) or a zeroed out T/S link was
|
|
* read, then the filepointer is positioned
|
|
* correctly. (P.S. At one time in the history
|
|
* of DOS 3.3, the position function was used to
|
|
* back up the file pointer.)
|
|
* Enter with append flag set if a $00 was detected
|
|
* in a (non-empty) file's T/S list.
|
|
(B671)
|
|
CKAPFLG LDA APPNDFLG ;Is append flag on?
|
|
BEQ CLRAPFLG ;No - flag is off.
|
|
INC RECNMBFM ;Yes - so increment the file manager's
|
|
BNE CLRAPFLG ;version of the record number cause
|
|
(B67B) INC RECNMBFM+1 ;RECNMBFM is pointing at the last
|
|
;valid data byte and we want it to point
|
|
;at the next potential record number.
|
|
;(P.S. Remember that RECNMBFM always lags
|
|
;RECNMBWA by one byte.)
|
|
(B67E)
|
|
CLRAPFLG LDA #0 ;Don't need append flag any more, so
|
|
STA APPNDFLG ;turn it off.
|
|
(B683) JMP RSETPTRS ;Go back up the file pointer.
|
|
------------
|
|
|
|
* Buggy routine used to back up the file pointer.
|
|
* If a file is $FFFF (65535) bytes long (or some
|
|
* some multiple thereof), the append will fail
|
|
* because this routine neglects to back up the
|
|
* hi byte of the file pointer (FILPTSEC+1).
|
|
(B6B3)
|
|
RSETPTRS LDA RECNMBFM ;Reconcile record number versions
|
|
STA FILPTBYT ;and lowest 2 bytes of file pointer.
|
|
STA RECNMBWA
|
|
LDA RECNMBFM+1
|
|
(B6BF) STA WASTEBYT ;Appears to be irrevelvant. Obviously
|
|
;has something to do with the CK4ZEROS
|
|
;routine described above.
|
|
(B6C2) STA RECNMBWA+1
|
|
STA FILPTSEC
|
|
TSX ;Reset the stack pointer so we can use the
|
|
(B6C9) STX STKSAV ;FMEXIT routine to return to the caller
|
|
;of the append command. (Note: This will
|
|
;be an exceptional exit route for FMEXIT.)
|
|
(B6CC) JMP GOODFMXT ;Exit cleanly.
|
|
------------
|
|
(B37F)
|
|
GOODFMXT LDA RTNCODFM
|
|
CLC ;(c) = 0 to signal good operation.
|
|
(B383) BCC FMEXIT ;ALWAYS.
|
|
|
|
(B386)
|
|
FMEXIT PHP ;Save status on stack.
|
|
STA RTNCODFM ;Store return code in FM parameter list.
|
|
LDA #0 ;Avoid that infamous $48 bug.
|
|
STA STATUS
|
|
(B38E) JSR CPYFMWA
|
|
|
|
* Copy the FM work area buffer (non-chain)
|
|
* to the FM work buffer (in DOS chain).
|
|
(AE7E)
|
|
CPYFMWA JSR SELWKBUF ;Select the FM work buffer (in DOS chain).
|
|
|
|
* Point the A4L/H pointer at the FM work buffer.
|
|
(AF08)
|
|
SELWKBUF LDX #0 ;Set index to selct FM work buffer.
|
|
(AF0A) BEQ PT2FMBUF ;ALWAYS.
|
|
|
|
(AF12)
|
|
PT2FMBUF LDA WRKBUFFM,X ;Get addr of selected buffer from the
|
|
STA A4L ;FM parameter list & put it in the pointer.
|
|
LDA WRKBUFFM+1,X
|
|
STA A4L+1
|
|
(AF1C) RTS
|
|
|
|
(AE81) LDY #0 ;Initialize index.
|
|
STORWRK LDA FMWKAREA,Y ;Get byte from the FM work area.
|
|
STA (A4L),Y ;Put it in the work buffer.
|
|
INY
|
|
CPY #45 ;45 bytes to copy (0 to 44).
|
|
BNE STORWRK
|
|
(AE8D) RTS
|
|
|
|
(B391) PLP ;Retrieve status of success of operation
|
|
;back from the stack.
|
|
(B392) LDX STKSAV ;NOTE: The contents of STKSAV ($B39B) were
|
|
TXS ;altered above (at $B6C9). Therefore, the
|
|
(B396) RTS ;stack is now reset to return to the caller
|
|
============ ;of the append command handler. Execution
|
|
;actually returns to AFTRCMD ($A17D) located
|
|
;in the command parsing and processing
|
|
;routines. Note that this is an exceptional
|
|
;route for FMEXIT to take.
|