💾 Archived View for mirrors.apple2.org.za › archive › www.textfiles.com › apple › ANATOMY › cmdappnd… captured on 2024-08-19 at 03:01:32.
View Raw
More Information
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
- *****************************************************************
- *
- 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.