489 lines
38 KiB
Plaintext
489 lines
38 KiB
Plaintext
******************************************************************
|
|
* *
|
|
* 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". *
|
|
* *
|
|
*-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:-:*
|