******************************************************************
*                                                                *
*                     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.)
