******************************************************************
*                                                                *
*                      EXEC comand handler                       *
*                                                                *
*----------------------------------------------------------------*
*                                                                *
*      The EXEC command is one of the most powerful commands in  *
* DOS.  Its command handler (CMDEXEC, $A5C6) reads data from a   *
* text file and interprets the information contained in that     *
* file as if it was typed in from the keyboard in the immediate  *
* mode.  If a command is read, it is executed immediately.  If   *
* the data are interpreted to be a program line, the line is     *
* added to the program currently in memory.  A filename must be  *
* issued with the command.  Volume, drive, slot and relative     *
* field position parameters are optional.                        *
*      The EXECCMD routine does not do any EXECing per se.  It   *
* simply opens the file, positions the file pointer and (most    *
* importantly) SETS the EXECFLAG.  Eventually the computer       *
* returns to basic's RESTART routine ($D43C) where input is      *
* requested.  Because the input hook (CSW/+1; $36,$37) points at *
* DOS's input handler (INPTINCP, $9E81), DOS regains control.    *
* During the execution of INPTINCP, the exec flag (EXECFLAG,     *
* $AAB3) is tested and discovered to be set.  Consequently, the  *
* READEXEC routine ($A682) is used to read data from the disk.   *
* As the data are read, they are placed in the input buffer      *
* (BUFF200, $200) one byte at a time.  Each time that a carriage *
* return is encountered, the buffer is parsed.  If a DOS,        *
* Applesoft or machine language instruction is recognized, the   *
* command (instruction) is executed as if it were typed in from  *
* the keyboard (ie. immediate mode).  After the entire file is   *
* read, the file is closed and the EXECFLAG is shut off.         *
*                                                                *
******************************************************************


(A5C6)
CMDEXEC  JSR CMDOPEN  ;Go open the file to be EXECed.

                      (A2A3)
                      CMDOPEN  LDA #0       ;0 = code for text file.
                      (A2A5)   JMP OPNCKTYP ;Go open the file & check its type.
                               ------------

                      (A3D5)
                      OPNCKTYP STA FILTYPFM ;Put code for file type in the FM parameter
                      (A3D8)   PHA          ;list & save it on the stack.  ($00= Text,
                                            ;$02=Applesoft, $04=Binary, $08=S-type,
                                            ;$10=Relocatable, $20=A-type and $40=B-type.)
                      (A3D9)   JSR HNDLCMD  ;Use the file manager's command handler to
                                            ;open the 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 parameter 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 is already open.
                                            (A2C8)

                                                                  (A2EA)
                                                                  CMDCLOSE .
                                                                           .
                                                                  (See dis'mbly of CMDCLOSE for details.)
                                                                           .
                                                                           .
                                                                  - 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/+1 is left pointing at the
                                                                    highest numbered (lowest in memory) FREE DOS buffer
                                                                    when CMDCLOSE 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/+1 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 NOBUFFER ;Go issue an out-of-buffers message.
                                                     ------------ ;(See dis'mbly of errors.)
                                            (A2D2)
                                            SAVFNPTR STA A3L+1    ;Reset A3L/+1 to point at the DOS buffer
                                                     LDA A5L      ;that we will use for the file name field
                                                     STA A3L      ;buffer (in chain).
                                            (A2D8)   JSR CPYFN

                                                                  * NOTE:  This routine (re)assigns a DOS buffer
                                                                  * to the file we want to open.  The buffer used
                                                                  * may or may not be the same one that was just
                                                                  * released by the CLOSE command above.  The
                                                                  * highest numbered (lowest in memory) free DOS
                                                                  * buffer is used.
                                                                  (A743)
                                                                  CPYFN    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 CPYPRIM  ;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.  Addr of next DOS filename buffer
                                                                           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 table
                                                                           LDA ADRPFNBF+1 ;and put it in the FM parm list.
                                                                           STA FNAMBUFM+1
                                                                           LDA A3L      ;Save addr of current DOS filename
                                                                           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/+1 pointer.
                                                                                                           (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.
                                                                                        (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
                                                                    first 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 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 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 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 list 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          ;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-existing 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)   ============

(A5C9)   LDA CURFNADR ;Get the addr of the current file name buf
         STA EXECBUFF ;and designate it as the Exec files name buf.
         LDA CURFNADR+1
         STA EXECBUFF+1
         LDA PRIMFNBF ;Set the exec flag to a non-zero value.
         STA EXECFLAG ;(Use first char of file name.)
(A5DB)   BNE POSNCHKR ;ALWAYS - go position file pointer if
         ------------ ;necessary.

(A5EB)
POSNCHKR LDA CUMLOPTN ;Check to see if a non-zero R-parameter
         AND #%00000100 ;was issued with the command.
(A5F0)   BEQ DONEPOSN ;R-parameter was zero, so go exit (ie. don't
                      ;move file pointer.)

* A non-zero R-parameter was issued, so
* go move the file porinter FORWARD by
* reading one-byte at a time.  When a
* <cr> is encountered, reduce the count
* of the relative field position.  When
* the count equals zero, done positioning.
(A5F2)
CKPSNDUN LDA RECPRSD  ;Check count.
         BNE POSNMORE
         LDA RECPRSD+1
(A5FA)   BEQ DONEPOSN ;R-parameter has been counted down to zero,
                      ;so we are done positioning.
(A5FC)   DEC RECPRSD+1 ;Reduce count of R-parameter (# of fields
POSNMORE DEC RECPRSD  ;moved forward) for the next time around.
PSNFIELD JSR RDTXTBYT ;Go read a text file byte.
(A602)

                      (A68C)
                      RDTXTBYT LDA #3       ;Set READ opcode.
                               STA OPCODEFM
                               LDA #1       ;Set one-byte subcode.
                               STA SUBCODFM
                      (A696)   JSR FMDRIVER ;Call the FM driver to read a data byte.

                                            * Use the file manager driver
                                            * to do the READ 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/+1 pointer.
                                                                                                           (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.
                                                                                        (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.

                                                                  (AC58)
                                                                  FNREAD   LDA SUBCODFM ;Check if subcode is legal.
                                                                           CMP #5       ;(Must be < = 5.)
                                                                  (AC5D)   BCS TOERRSUB ;Error - illegal subcode.
                                                                                        ;(Not applciable to exec command.)
                                                                  (AC5F)   ASL          ;Subcode * 2, cause 2 bytes/address.
                                                                           LDA RDSUBTBL+1,X ;Get address (minus 1) of subfunction
                                                                           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.  (Exec command ALWAYS uses
                                                                                        ;the READ-ONE-BYTE subfunction.)

                                                                  (AC8A)
                                                                  READONE  .
                                                                           .
                                                                  (See dis'mbly of the
                                                                  read-one-byte subfunction.)
                                                                           .
                                                                           .
                                                                           (RTS)
                                                                          =============

                                                                  TOERROP  JMP RNGERROP ;Go handle range error.
                                                                  (AB1F)   ------------ ;(See dis'mbly of errors.)

                                                                  TOERRSUB JMP RNGERRSB ;Go handle range error.
                                                                  (AC6A)   ------------ ;(See dis'mbly of errors.)

                                            * Return here after doing the READ function.
                                            * (Cause after @ function is done, use stack to get
                                            * back to the original caller.)  Note that (c) = 0 if a data
                                            * byte was just read (regardless of whether that data byte
                                            * was $00 or not).
                                            (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 - 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 a T/S list).
                                            (A6B4)   JMP OTHRERR  ;No.  Only take if got an error other than
                                                                  ;an end-of-data error.  (See dis'mbly of
                                            (A6B7)                ;errors.)
                                            TOAPPTCH JMP APNDPTCH ;(See dis'mbly of errors.)
                                                     NOP
                                            BK2FMDRV JSR CKIFAPND ; <----- Note:  APNDPTCH returns here.
                                            (A6BB)

                                                                  * Check if using Append command.
                                                                  (BA69)
                                                                  CKIFAPND LDX CMDINDEX ;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 buffer in FM parm list.
                                                     STX ONEIOBUF ;(Also referred to as low byte of CURIOBUF.)
                                            FMDRVRTN RTS
                                            (A6C3)

                      (A699)   LDA ONEIOBUF ;Load (a) with byte just read.
                      (A69C)   RTS

(A605)   BEQ ENDATERR ;If byte just read = $00, then ran out of data.
                      ;A zero byte can be obtained from an
                      ;incompletely filled data sector.  Or, if
                      ;a file ends on a sector boundary, a $00
                      ;byte can also be obtained from a zeroed-out
                      ;T/S link or a zeroed-out data pair (trk/sec
                      ;values of next potential data sec listed in
                      ;a T/S list).
(A607)   CMP #$8D     ;Was it a carriage return?
         BNE PSNFILED ;No - go read the next byte in the same field.
(A60B)   BEQ CKPSNDUN ;Yes - Got an end-of-field marker so branch
         ------------ ;      back to reduce field count & see if
                      ;      we are done positioning yet.
DONEPOSN RTS          ;Exit - either done positioning or else the
(A60D)   ============ ;       R-parameter was zero to start with
                      ;       and there4 no positioning is needed.

(A63F)
ENDATERR LDA #5
(A641)   JMP ERRHNDLR ;(See dis'mbly of errors.)
         ------------


*-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:*
*                                                                *
*     Note:  Actual EXECing of statements does not occur until   *
* after the computer returns to BASIC's RESTART routine ($D43C). *
*                                                                *
*          SEE DISASSEMBLY TITLED "CMDEXEC CONTINUED".           *
*                                                                *
*-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:*
