You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1264 lines
30 KiB

.title "Digital Research CCP, Version 2.2"
.page 49
MON .EQU 1 ;ADD THE CCP MON COMMAND
USRDSP .EQU 1 ;SHOW THE USER NUMBER
CHKU0B .EQU 0 ;CHECK FOR TRANSIENTS ON USER 0 TOO
ENDFIL .EQU 1 ;FILE FULL CCP SIZE
;
;**************************************************************
;*
;* C C P - C O N S O L E C O M M A N D P R O C E S S O R
;*
;**************************************************************
;*
IOBYTE: .EQU 3 ; I/O DEFINITION BYTE.
TDRIVE: .EQU 4 ; CURRENT DRIVE NAME AND USER NUMBER.
ENTRY: .EQU 5 ; ENTRY POINT FOR THE CP/M BDOS.
TFCB: .EQU 5CH ; DEFAULT FILE CONTROL BLOCK.
TBUFF: .EQU 80H ; I/O BUFFER AND COMMAND LINE STORAGE.
TBASE: .EQU 100H ; TRANSIANT PROGRAM STORAGE AREA.
;
; SET CONTROL CHARACTER .EQUATES.
;
CNTRLC: .EQU 03H ; CONTROL-C
CNTRLE: .EQU 05H ; CONTROL-E
BS: .EQU 08H ; BACKSPACE
TAB: .EQU 09H ; TAB
LF: .EQU 0AH ; LINE FEED
FF: .EQU 0CH ; FORM FEED
CR: .EQU 0DH ; CARRIAGE RETURN
CNTRLP: .EQU 10H ; CONTROL-P
CNTRLR: .EQU 12H ; CONTROL-R
CNTRLS: .EQU 13H ; CONTROL-S
CNTRLU: .EQU 15H ; CONTROL-U
CNTRLX: .EQU 18H ; CONTROL-X
CNTRLZ: .EQU 1AH ; CONTROL-Z (END-OF-FILE MARK)
DEL: .EQU 7FH ; RUBOUT
;
; SET ORIGIN FOR CP/M
;
NK .EQU 59 ;SYSTEM SIZE
BASE .EQU (NK*1024)-5000H
CCPO .EQU BASE+3400H ;CCP ORIGIN
BDOSO .EQU BASE+3C00H ;BDOS ORIGIN
BIOSO .EQU BASE+4A00H ;BIOS ORIGIN
.ORG CCPO
;
CBASE: JP COMMAND ; EXECUTE COMMAND PROCESSOR (CCP).
JP CLEARBUF ; ENTRY TO EMPTY INPUT BUFFER BEFORE STARTING CCP.
;
; STANDARD CP/M CCP INPUT BUFFER. FORMAT IS (MAX LENGTH),
; (ACTUAL LENGTH), (CHAR #1), (CHAR #2), (CHAR #3), ETC.
;
INBUFF: .DB 127 ; LENGTH OF INPUT BUFFER.
; N8VEM - if add any text after this point, change .DB 0 below to length
; and put a 0 after the text, and delete the same number of zeros after the dig
; so that inpoint ends up at the same spot
; INBUFF+1 is cleared on the next warm boot, so only runs once.
.DB 0 ;CURRENT LENGTH OF CONTENTS.
; .DB 17 ; Autoboot length of string
; .DB "SUPERSUB AUTOEXEC"
; .DB 0 ; zero at end
.DB "COPYRIGHT"
.DB " 1979 (C) BY "
.DB "DIGITAL RESEARCH "
.FILL ((INBUFF + 128) - $),055H
INPOINT:.DW INBUFF+2 ; INPUT LINE POINTER
NAMEPNT:.DW 0 ; INPUT LINE POINTER USED FOR ERROR MESSAGE. POINTS TO
; ;START OF NAME IN ERROR.
;
; ROUTINE TO PRINT (A) ON THE CONSOLE. ALL REGISTERS USED.
;
PRINT: LD E,A ; SETUP BDOS CALL.
LD C,2
JP ENTRY
;
; ROUTINE TO PRINT (A) ON THE CONSOLE AND TO SAVE (BC).
;
PRINTB: PUSH BC
CALL PRINT
POP BC
RET
;
; ROUTINE TO SEND A CARRIAGE RETURN, LINE FEED COMBINATION
; TO THE CONSOLE.
;
CRLF: LD A,CR
CALL PRINTB
LD A,LF
JP PRINTB
;
; ROUTINE TO SEND ONE SPACE TO THE CONSOLE AND SAVE (BC).
;
SPACE: LD A,' '
JP PRINTB
;
; ROUTINE TO PRINT CHARACTER STRING POINTED TO BE (BC) ON THE
; CONSOLE. IT MUST TERMINATE WITH A NULL BYTE.
;
PLINE: PUSH BC
CALL CRLF
POP HL
PLINE2: LD A,(HL)
OR A
RET Z
INC HL
PUSH HL
CALL PRINT
POP HL
JP PLINE2
;
; ROUTINE TO RESET THE DISK SYSTEM.
;
RESDSK: LD C,13
JP ENTRY
;
; ROUTINE TO SELECT DISK (A).
;
DSKSEL: LD E,A
LD C,14
JP ENTRY
;
; ROUTINE TO CALL BDOS AND SAVE THE RETURN CODE. THE ZERO
; FLAG IS SET ON A RETURN OF 0FFH.
;
ENTRY1: CALL ENTRY
LD (RTNCODE),A ; SAVE RETURN CODE.
INC A ; SET ZERO IF 0FFH RETURNED.
RET
;
; ROUTINE TO OPEN A FILE. (DE) MUST POINT TO THE FCB.
;
OPEN: LD C,15
JP ENTRY1
;
; ROUTINE TO OPEN FILE AT (FCB).
;
OPENFCB:XOR A ; CLEAR THE RECORD NUMBER BYTE AT FCB+32
LD (FCB+32),A
LD DE,FCB
JP OPEN
;
; ROUTINE TO CLOSE A FILE. (DE) POINTS TO FCB.
;
CLOSE: LD C,16
JP ENTRY1
;
; ROUTINE TO SEARCH FOR THE FIRST FILE WITH AMBIGUEOUS NAME
; (DE).
;
SRCHFST:LD C,17
JP ENTRY1
;
; SEARCH FOR THE NEXT AMBIGEOUS FILE NAME.
;
SRCHNXT:LD C,18
JP ENTRY1
;
; SEARCH FOR FILE AT (FCB).
;
SRCHFCB:LD DE,FCB
JP SRCHFST
;
; ROUTINE TO DELETE A FILE POINTED TO BY (DE).
;
DELETE: LD C,19
JP ENTRY
;
; ROUTINE TO CALL THE BDOS AND SET THE ZERO FLAG IF A ZERO
; STATUS IS RETURNED.
;
ENTRY2: CALL ENTRY
OR A ; SET ZERO FLAG IF APPROPRIATE.
RET
;
; ROUTINE TO READ THE NEXT RECORD FROM A S.EQUENTIAL FILE.
; (DE) POINTS TO THE FCB.
;
RDREC: LD C,20
JP ENTRY2
;
; ROUTINE TO READ FILE AT (FCB).
;
READFCB:LD DE,FCB
JP RDREC
;
; ROUTINE TO WRITE THE NEXT RECORD OF A S.EQUENTIAL FILE.
; (DE) POINTS TO THE FCB.
;
WRTREC: LD C,21
JP ENTRY2
;
; ROUTINE TO CREATE THE FILE POINTED TO BY (DE).
;
CREATE: LD C,22
JP ENTRY1
;
; ROUTINE TO RENAME THE FILE POINTED TO BY (DE). NOTE THAT
; THE NEW NAME STARTS AT (DE+16).
;
RENAM: LD C,23
JP ENTRY
;
; GET THE CURRENT USER CODE.
;
GETUSR: LD E,0FFH
;
; ROUTNE TO GET OR SET THE CURRENT USER CODE.
; IF (E) IS FF THEN THIS IS A GET, ELSE IT IS A SET.
;
GETSETUC:
LD C,32
JP ENTRY
;
; ROUTINE TO SET THE CURRENT DRIVE BYTE AT (TDRIVE).
;
SETCDRV:CALL GETUSR ; GET USER NUMBER
ADD A,A ; AND SHIFT INTO THE UPPER 4 BITS.
ADD A,A
ADD A,A
ADD A,A
LD HL,CDRIVE ; NOW ADD IN THE CURRENT DRIVE NUMBER.
OR (HL)
LD (TDRIVE),A ; AND SAVE.
RET
;
; MOVE CURRENTLY ACTIVE DRIVE DOWN TO (TDRIVE).
;
MOVECD: LD A,(CDRIVE)
LD (TDRIVE),A
RET
;
; ROUTINE TO CONVERT (A) INTO UPPER CASE ASCII. ONLY LETTERS
; ARE AFFECTED.
;
UPPER: CP 'A' ; CHECK FOR LETTERS IN THE RANGE OF 'A' TO 'Z'.
RET C
CP '{'
RET NC
AND 5FH ; CONVERT IT IF FOUND.
RET
;
; ROUTINE TO GET A LINE OF INPUT. WE MUST CHECK TO SEE IF THE
; USER IS IN (BATCH) MODE. IF SO, THEN READ THE INPUT FROM FILE
; ($$$.SUB). AT THE END, RESET TO CONSOLE INPUT.
;
GETINP: LD A,(BATCH) ; IF =0, THEN USE CONSOLE INPUT.
OR A
JP Z,GETINP1
;
; USE THE SUBMIT FILE ($$$.SUB) WHICH IS PREPARED BY A
; SUBMIT RUN. IT MUST BE ON DRIVE (A) AND IT WILL BE DELETED
; IF AND ERROR OCCURES (LIKE EOF).
;
LD A,(CDRIVE) ; SELECT DRIVE 0 IF NEED BE.
OR A
LD A,0 ; ALWAYS USE DRIVE A FOR SUBMIT.
CALL NZ,DSKSEL ; SELECT IT IF REQUIRED.
LD DE,BATCHFCB
CALL OPEN ; LOOK FOR IT.
JP Z,GETINP1 ; IF NOT THERE, USE NORMAL INPUT.
LD A,(BATCHFCB+15) ; GET LAST RECORD NUMBER+1.
DEC A
LD (BATCHFCB+32),A
LD DE,BATCHFCB
CALL RDREC ; READ LAST RECORD.
JP NZ,GETINP1 ; QUIT ON END OF FILE.
;
; MOVE THIS RECORD INTO INPUT BUFFER.
;
LD DE,INBUFF+1
LD HL,TBUFF ; DATA WAS READ INTO BUFFER HERE.
LD B,128 ; ALL 128 CHARACTERS MAY BE USED.
CALL HL2DE ; (HL) TO (DE), (B) BYTES.
LD HL,BATCHFCB+14
LD (HL),0 ; ZERO OUT THE 'S2' BYTE.
INC HL ; AND DECREMENT THE RECORD COUNT.
DEC (HL)
LD DE,BATCHFCB ; CLOSE THE BATCH FILE NOW.
CALL CLOSE
JP Z,GETINP1 ; QUIT ON AN ERROR.
LD A,(CDRIVE) ; RE-SELECT PREVIOUS DRIVE IF NEED BE.
OR A
CALL NZ,DSKSEL ; DON'T DO NEEDLESS SELECTS.
;
; PRINT LINE JUST READ ON CONSOLE.
;
LD HL,INBUFF+2
CALL PLINE2
CALL CHKCON ; CHECK CONSOLE, QUIT ON A KEY.
JP Z,GETINP2 ; JUMP IF NO KEY IS PRESSED.
;
; TERMINATE THE SUBMIT JOB ON ANY KEYBOARD INPUT. DELETE THIS
; FILE SUCH THAT IT IS NOT RE-STARTED AND JUMP TO NORMAL KEYBOARD
; INPUT SECTION.
;
CALL DELBATCH ; DELETE THE BATCH FILE.
JP CMMND1 ; AND RESTART COMMAND INPUT.
;
; GET HERE FOR NORMAL KEYBOARD INPUT. DELETE THE SUBMIT FILE
; INCASE THERE WAS ONE.
;
GETINP1:CALL DELBATCH ; DELETE FILE ($$$.SUB).
CALL SETCDRV ; RESET ACTIVE DISK.
LD C,10 ; GET LINE FROM CONSOLE DEVICE.
LD DE,INBUFF
CALL ENTRY
CALL MOVECD ; RESET CURRENT DRIVE (AGAIN).
;
; CONVERT INPUT LINE TO UPPER CASE.
;
GETINP2:LD HL,INBUFF+1
LD B,(HL) ; (B)=CHARACTER COUNTER.
GETINP3:INC HL
LD A,B ; END OF THE LINE?
OR A
JP Z,GETINP4
LD A,(HL) ; CONVERT TO UPPER CASE.
CALL UPPER
LD (HL),A
DEC B ; ADJUST CHARACTER COUNT.
JP GETINP3
GETINP4:LD (HL),A ; ADD TRAILING NULL.
LD HL,INBUFF+2
LD (INPOINT),HL ; RESET INPUT LINE POINTER.
RET
;
; ROUTINE TO CHECK THE CONSOLE FOR A KEY PRESSED. THE ZERO
; FLAG IS SET IS NONE, ELSE THE CHARACTER IS RETURNED IN (A).
;
CHKCON: LD C,11 ; CHECK CONSOLE.
CALL ENTRY
OR A
RET Z ; RETURN IF NOTHING.
LD C,1 ; ELSE GET CHARACTER.
CALL ENTRY
OR A ; CLEAR ZERO FLAG AND RETURN.
RET
;
; ROUTINE TO GET THE CURRENTLY ACTIVE DRIVE NUMBER.
;
GETDSK: LD C,25
JP ENTRY
;
; SET THE STABDARD DMA ADDRESS.
;
STDDMA: LD DE,TBUFF
;
; ROUTINE TO SET THE DMA ADDRESS TO (DE).
;
DMASET: LD C,26
JP ENTRY
;
; DELETE THE BATCH FILE CREATED BY SUBMIT.
;
DELBATCH:
LD HL,BATCH ; IS BATCH ACTIVE?
LD A,(HL)
OR A
RET Z
LD (HL),0 ; YES, DE-ACTIVATE IT.
XOR A
CALL DSKSEL ; SELECT DRIVE 0 FOR SURE.
LD DE,BATCHFCB ; AND DELETE THIS FILE.
CALL DELETE
LD A,(CDRIVE) ; RESET CURRENT DRIVE.
JP DSKSEL
;
; PRINT BACK FILE NAME WITH A '?' TO INDICATE A SYNTAX ERROR.
;
SYNERR: CALL CRLF ; END CURRENT LINE.
LD HL,(NAMEPNT) ; THIS POINTS TO NAME IN ERROR.
SYNERR1:LD A,(HL) ; PRINT IT UNTIL A SPACE OR NULL IS FOUND.
CP ' '
JP Z,SYNERR2
OR A
JP Z,SYNERR2
PUSH HL
CALL PRINT
POP HL
INC HL
JP SYNERR1
SYNERR2:LD A,'?' ; ADD TRAILING '?'.
CALL PRINT
CALL CRLF
CALL DELBATCH ; DELETE ANY BATCH FILE.
JP CMMND1 ; AND RESTART FROM CONSOLE INPUT.
;
; CHECK CHARACTER AT (DE) FOR LEGAL COMMAND INPUT. NOTE THAT THE
; ZERO FLAG IS SET IF THE CHARACTER IS A DELIMITER.
;
CHECK: LD A,(DE)
OR A
RET Z
CP ' ' ; CONTROL CHARACTERS ARE NOT LEGAL HERE.
JP C,SYNERR
RET Z ; CHECK FOR VALID DELIMITER.
CP '='
RET Z
CP '_'
RET Z
CP '.'
RET Z
CP ':'
RET Z
CP $3B
RET Z
CP '<'
RET Z
CP '>'
RET Z
RET
;
; GET THE NEXT NON-BLANK CHARACTER FROM (DE).
;
NONBLANK:
LD A,(DE)
OR A ; STRING ENDS WITH A NULL.
RET Z
CP ' '
RET NZ
INC DE
JP NONBLANK
;
; ADD (HL)=(HL)+(A)
;
ADDHL: ADD A,L
LD L,A
RET NC ; TAKE CARE OF ANY CARRY.
INC H
RET
;
; CONVERT THE FIRST NAME IN (FCB).
;
CONVFST:LD A,0
;
; FORMAT A FILE NAME (CONVERT * TO '?', ETC.). ON RETURN,
; (A)=0 IS AN UNAMBIGEOUS NAME WAS SPECIFIED. ENTER WITH (A) .EQUAL TO
; THE POSITION WITHIN THE FCB FOR THE NAME (EITHER 0 OR 16).
;
CONVERT:LD HL,FCB
CALL ADDHL
PUSH HL
PUSH HL
XOR A
LD (CHGDRV),A ; INITIALIZE DRIVE CHANGE FLAG.
LD HL,(INPOINT) ; SET (HL) AS POINTER INTO INPUT LINE.
EX DE,HL
CALL NONBLANK ; GET NEXT NON-BLANK CHARACTER.
EX DE,HL
LD (NAMEPNT),HL ; SAVE POINTER HERE FOR ANY ERROR MESSAGE.
EX DE,HL
POP HL
LD A,(DE) ; GET FIRST CHARACTER.
OR A
JP Z,CONVRT1
SBC A,'A'-1 ; MIGHT BE A DRIVE NAME, CONVERT TO BINARY.
LD B,A ; AND SAVE.
INC DE ; CHECK NEXT CHARACTER FOR A ':'.
LD A,(DE)
CP ':'
JP Z,CONVRT2
DEC DE ; NOPE, MOVE POINTER BACK TO THE START OF THE LINE.
CONVRT1:LD A,(CDRIVE)
LD (HL),A
JP CONVRT3
CONVRT2:LD A,B
LD (CHGDRV),A ; SET CHANGE IN DRIVES FLAG.
LD (HL),B
INC DE
;
; CONVERT THE BASIC FILE NAME.
;
CONVRT3:LD B,08H
CONVRT4:CALL CHECK
JP Z,CONVRT8
INC HL
CP '*' ; NOTE THAT AN '*' WILL FILL THE REMAINING
JP NZ,CONVRT5 ; FIELD WITH '?'.
LD (HL),'?'
JP CONVRT6
CONVRT5:LD (HL),A
INC DE
CONVRT6:DEC B
JP NZ,CONVRT4
CONVRT7:CALL CHECK ; GET NEXT DELIMITER.
JP Z,GETEXT
INC DE
JP CONVRT7
CONVRT8:INC HL ; BLANK FILL THE FILE NAME.
LD (HL),' '
DEC B
JP NZ,CONVRT8
;
; GET THE EXTENSION AND CONVERT IT.
;
GETEXT: LD B,03H
CP '.'
JP NZ,GETEXT5
INC DE
GETEXT1:CALL CHECK
JP Z,GETEXT5
INC HL
CP '*'
JP NZ,GETEXT2
LD (HL),'?'
JP GETEXT3
GETEXT2:LD (HL),A
INC DE
GETEXT3:DEC B
JP NZ,GETEXT1
GETEXT4:CALL CHECK
JP Z,GETEXT6
INC DE
JP GETEXT4
GETEXT5:INC HL
LD (HL),' '
DEC B
JP NZ,GETEXT5
GETEXT6:LD B,3
GETEXT7:INC HL
LD (HL),0
DEC B
JP NZ,GETEXT7
EX DE,HL
LD (INPOINT),HL ; SAVE INPUT LINE POINTER.
POP HL
;
; CHECK TO SEE IF THIS IS AN AMBIGEOUS FILE NAME SPECIFICATION.
; SET THE (A) REGISTER TO NON ZERO IF IT IS.
;
LD BC,11 ; SET NAME LENGTH.
GETEXT8:INC HL
LD A,(HL)
CP '?' ; ANY QUESTION MARKS?
JP NZ,GETEXT9
INC B ; COUNT THEM.
GETEXT9:DEC C
JP NZ,GETEXT8
LD A,B
OR A
RET
;
; CP/M COMMAND TABLE. NOTE COMMANDS CAN BE EITHER 3 OR 4 CHARACTERS LONG.
;
.IF MON
NUMCMDS:.EQU 7 ; NUMBER OF COMMANDS
.ELSE
NUMCMDS:.EQU 6 ; NUMBER OF COMMANDS
.ENDIF
CMDTBL: .DB "DIR "
.DB "ERA "
.DB "TYPE"
.DB "SAVE"
.DB "REN "
.DB "USER"
.IF MON
.DB "MON "
.ENDIF
CMDADR: .DW DIRECT
.DW ERASE
.DW TYPE
.DW SAVE
.DW RENAME
.DW USER
.IF MON
.DW MONITOR
.ENDIF
.DW UNKNOWN
;
; SEARCH THE COMMAND TABLE FOR A MATCH WITH WHAT HAS JUST
; BEEN ENTERED. IF A MATCH IS FOUND, THEN WE JUMP TO THE
; PROPER SECTION. ELSE JUMP TO (UNKNOWN).
; ON RETURN, THE (C) REGISTER IS SET TO THE COMMAND NUMBER
; THAT MATCHED (OR NUMCMDS+1 IF NO MATCH).
;
SEARCH: LD HL,CMDTBL
LD C,0
SEARCH1:LD A,C
CP NUMCMDS ; THIS COMMANDS EXISTS.
RET NC
LD DE,FCB+1 ; CHECK THIS ONE.
LD B,4 ; MAX COMMAND LENGTH.
SEARCH2:LD A,(DE)
CP (HL)
JP NZ,SEARCH3 ; NOT A MATCH.
INC DE
INC HL
DEC B
JP NZ,SEARCH2
LD A,(DE) ; ALLOW A 3 CHARACTER COMMAND TO MATCH.
CP ' '
JP NZ,SEARCH4
LD A,C ; SET RETURN REGISTER FOR THIS COMMAND.
RET
SEARCH3:INC HL
DEC B
JP NZ,SEARCH3
SEARCH4:INC C
JP SEARCH1
;
; SET THE INPUT BUFFER TO EMPTY AND THEN START THE COMMAND
; PROCESSOR (CCP).
;
CLEARBUF:
XOR A
LD (INBUFF+1),A ; SECOND BYTE IS ACTUAL LENGTH.
COMMAND:LD SP,CCPSTACK ; SETUP STACK AREA.
PUSH BC ; NOTE THAT (C) SHOULD BE .EQUAL TO:
LD A,C ; (UUUUDDDD) WHERE 'UUUU' IS THE USER NUMBER
RRA ; AND 'DDDD' IS THE DRIVE NUMBER.
RRA
RRA
RRA
AND 0FH ; ISOLATE THE USER NUMBER.
LD E,A
CALL GETSETUC ; AND SET IT.
CALL RESDSK ; RESET THE DISK SYSTEM.
LD (BATCH),A ; CLEAR BATCH MODE FLAG.
POP BC
LD A,C
AND 0FH ; ISOLATE THE DRIVE NUMBER.
LD (CDRIVE),A ; AND SAVE.
CALL DSKSEL ; ...AND SELECT.
LD A,(INBUFF+1)
OR A ; ANYTHING IN INPUT BUFFER ALREADY?
JP NZ,CMMND2 ; YES, WE JUST PROCESS IT.
;
; ENTRY POINT TO GET A COMMAND LINE FROM THE CONSOLE.
;
CMMND1: LD SP,CCPSTACK ; SET STACK STRAIGHT.
CALL CRLF ; START A NEW LINE ON THE SCREEN.
CALL GETDSK ; GET CURRENT DRIVE.
ADD A,'A'
CALL PRINT ; PRINT CURRENT DRIVE.
.IF USRDSP
CALL GETUSR ;GET CURRENT USER NUMBER
CP 10 ;TWO DIGITS?
JR C,CMMND3 ;NO
LD A,'1' ;PRINT LEADING '1'
CALL PRINT
CALL GETUSR ;GET CURRENT USER NUMBER
SUB 10 ;SUBTRACT 10
CMMND3: ADD A,'0'
CALL PRINT
.ENDIF
LD A,'>'
CALL PRINT ; AND ADD PROMPT.
CALL GETINP ; GET LINE FROM USER.
;
; PROCESS COMMAND LINE HERE.
;
CMMND2: LD DE,TBUFF
CALL DMASET ; SET STANDARD DMA ADDRESS.
CALL GETDSK
LD (CDRIVE),A ; SET CURRENT DRIVE.
CALL CONVFST ; CONVERT NAME TYPED IN.
CALL NZ,SYNERR ; WILD CARDS ARE NOT ALLOWED.
LD A,(CHGDRV) ; IF A CHANGE IN DRIVES WAS INDICATED,
OR A ; THEN TREAT THIS AS AN UNKNOWN COMMAND
JP NZ,UNKNOWN ; WHICH GETS EXECUTED.
CALL SEARCH ; ELSE SEARCH COMMAND TABLE FOR A MATCH.
;
; NOTE THAT AN UNKNOWN COMMAND RETURNS
; WITH (A) POINTING TO THE LAST ADDRESS
; IN OUR TABLE WHICH IS (UNKNOWN).
;
LD HL,CMDADR ; NOW, LOOK THRU OUR ADDRESS TABLE FOR COMMAND (A).
LD E,A ; SET (DE) TO COMMAND NUMBER.
LD D,0
ADD HL,DE
ADD HL,DE ; (HL)=(CMDADR)+2*(COMMAND NUMBER).
LD A,(HL) ; NOW PICK OUT THIS ADDRESS.
INC HL
LD H,(HL)
LD L,A
JP (HL) ; NOW EXECUTE IT.
;
; READ ERROR WHILE TYPEING A FILE.
;
RDERROR:LD BC,RDERR
JP PLINE
RDERR: .DB "Read Error",0
;
; REQUIRED FILE WAS NOT LOCATED.
;
NONE: LD BC,NOFILE
JP PLINE
NOFILE: .DB "No File",0
;
; DECODE A COMMAND OF THE FORM 'A>FILENAME NUMBER{ FILENAME}.
; NOTE THAT A DRIVE SPECIFIER IS NOT ALLOWED ON THE FIRST FILE
; NAME. ON RETURN, THE NUMBER IS IN REGISTER (A). ANY ERROR
; CAUSES 'FILENAME?' TO BE PRINTED AND THE COMMAND IS ABORTED.
;
DECODE: CALL CONVFST ; CONVERT FILENAME.
LD A,(CHGDRV) ; DO NOT ALLOW A DRIVE TO BE SPECIFIED.
OR A
JP NZ,SYNERR
LD HL,FCB+1 ; CONVERT NUMBER NOW.
LD BC,11 ; (B)=SUM REGISTER, (C)=MAX DIGIT COUNT.
DECODE1:LD A,(HL)
CP ' ' ; A SPACE TERMINATES THE NUMERAL.
JP Z,DECODE3
INC HL
SUB '0' ; MAKE BINARY FROM ASCII.
CP 10 ; LEGAL DIGIT?
JP NC,SYNERR
LD D,A ; YES, SAVE IT IN (D).
LD A,B ; COMPUTE (B)=(B)*10 AND CHECK FOR OVERFLOW.
AND 0E0H
JP NZ,SYNERR
LD A,B
RLCA
RLCA
RLCA ; (A)=(B)*8
ADD A,B ; .......*9
JP C,SYNERR
ADD A,B ; .......*10
JP C,SYNERR
ADD A,D ; ADD IN NEW DIGIT NOW.
DECODE2:JP C,SYNERR
LD B,A ; AND SAVE RESULT.
DEC C ; ONLY LOOK AT 11 DIGITS.
JP NZ,DECODE1
RET
DECODE3:LD A,(HL) ; SPACES MUST FOLLOW (WHY?).
CP ' '
JP NZ,SYNERR
INC HL
DECODE4:DEC C
JP NZ,DECODE3
LD A,B ; SET (A)=THE NUMERIC VALUE ENTERED.
RET
;
; MOVE 3 BYTES FROM (HL) TO (DE). NOTE THAT THERE IS ONLY
; ONE REFERENCE TO THIS AT (A2D5H).
;
MOVE3: LD B,3
;
; MOVE (B) BYTES FROM (HL) TO (DE).
;
HL2DE: LD A,(HL)
LD (DE),A
INC HL
INC DE
DEC B
JP NZ,HL2DE
RET
;
; COMPUTE (HL)=(TBUFF)+(A)+(C) AND GET THE BYTE THAT'S HERE.
;
EXTRACT:LD HL,TBUFF
ADD A,C
CALL ADDHL
LD A,(HL)
RET
;
; CHECK DRIVE SPECIFIED. IF IT MEANS A CHANGE, THEN THE NEW
; DRIVE WILL BE SELECTED. IN ANY CASE, THE DRIVE BYTE OF THE
; FCB WILL BE SET TO NULL (MEANS USE CURRENT DRIVE).
;
DSELECT:XOR A ; NULL OUT FIRST BYTE OF FCB.
LD (FCB),A
LD A,(CHGDRV) ; A DRIVE CHANGE INDICATED?
OR A
RET Z
DEC A ; YES, IS IT THE SAME AS THE CURRENT DRIVE?
LD HL,CDRIVE
CP (HL)
RET Z
JP DSKSEL ; NO. SELECT IT THEN.
;
; CHECK THE DRIVE SELECTION AND RESET IT TO THE PREVIOUS
; DRIVE IF IT WAS CHANGED FOR THE PRECEEDING COMMAND.
;
RESETDR:LD A,(CHGDRV) ; DRIVE CHANGE INDICATED?
OR A
RET Z
DEC A ; YES, WAS IT A DIFFERENT DRIVE?
LD HL,CDRIVE
CP (HL)
RET Z
LD A,(CDRIVE) ; YES, RE-SELECT OUR OLD DRIVE.
JP DSKSEL
;
;**************************************************************
;*
;* M O N I T O R C O M M A N D
;*
;**************************************************************
;
.IF MON
MONITOR:RST 38H
.ENDIF
;
;**************************************************************
;*
;* D I R E C T O R Y C O M M A N D
;*
;**************************************************************
;
DIRECT: CALL CONVFST ; CONVERT FILE NAME.
CALL DSELECT ; SELECT INDICATED DRIVE.
LD HL,FCB+1 ; WAS ANY FILE INDICATED?
LD A,(HL)
CP ' '
JP NZ,DIRECT2
LD B,11 ; NO. FILL FIELD WITH '?' - SAME AS *.*.
DIRECT1:LD (HL),'?'
INC HL
DEC B
JP NZ,DIRECT1
DIRECT2:LD E,0 ; SET INITIAL CURSOR POSITION.
PUSH DE
CALL SRCHFCB ; GET FIRST FILE NAME.
CALL Z,NONE ; NONE FOUND AT ALL?
DIRECT3:JP Z,DIRECT9 ; TERMINATE IF NO MORE NAMES.
LD A,(RTNCODE) ; GET FILE'S POSITION IN SEGMENT (0-3).
RRCA
RRCA
RRCA
AND 60H ; (A)=POSITION*32
LD C,A
LD A,10
CALL EXTRACT ; EXTRACT THE TENTH ENTRY IN FCB.
RLA ; CHECK SYSTEM FILE STATUS BIT.
JP C,DIRECT8 ; WE DON'T LIST THEM.
POP DE
LD A,E ; BUMP NAME COUNT.
INC E
PUSH DE
AND 03H ; AT END OF LINE?
PUSH AF
JP NZ,DIRECT4
CALL CRLF ; YES, END THIS LINE AND START ANOTHER.
PUSH BC
CALL GETDSK ; START LINE WITH ('A:').
POP BC
ADD A,'A'
CALL PRINTB
LD A,':'
CALL PRINTB
JP DIRECT5
DIRECT4:CALL SPACE ; ADD SEPERATOR BETWEEN FILE NAMES.
LD A,':'
CALL PRINTB
DIRECT5:CALL SPACE
LD B,1 ; 'EXTRACT' EACH FILE NAME CHARACTER AT A TIME.
DIRECT6:LD A,B
CALL EXTRACT
AND 7FH ; STRIP BIT 7 (STATUS BIT).
CP ' ' ; ARE WE AT THE END OF THE NAME?
JP NZ,DRECT65
POP AF ; YES, DON'T PRINT SPACES AT THE END OF A LINE.
PUSH AF
CP 3
JP NZ,DRECT63
LD A,9 ; FIRST CHECK FOR NO EXTENSION.
CALL EXTRACT
AND 7FH
CP ' '
JP Z,DIRECT7 ; DON'T PRINT SPACES.
DRECT63:LD A,' ' ; ELSE PRINT THEM.
DRECT65:CALL PRINTB
INC B ; BUMP TO NEXT CHARACTER PSOITION.
LD A,B
CP 12 ; END OF THE NAME?
JP NC,DIRECT7
CP 9 ; NOPE, STARTING EXTENSION?
JP NZ,DIRECT6
CALL SPACE ; YES, ADD SEPERATING SPACE.
JP DIRECT6
DIRECT7:POP AF ; GET THE NEXT FILE NAME.
DIRECT8:CALL CHKCON ; FIRST CHECK CONSOLE, QUIT ON ANYTHING.
JP NZ,DIRECT9
CALL SRCHNXT ; GET NEXT NAME.
JP DIRECT3 ; AND CONTINUE WITH OUR LIST.
DIRECT9:POP DE ; RESTORE THE STACK AND RETURN TO COMMAND LEVEL.
JP GETBACK
;
;**************************************************************
;*
;* E R A S E C O M M A N D
;*
;**************************************************************
;
ERASE: CALL CONVFST ; CONVERT FILE NAME.
CP 11 ; WAS '*.*' ENTERED?
JP NZ,ERASE1
LD BC,YESNO ; YES, ASK FOR CONFIRMATION.
CALL PLINE
CALL GETINP
LD HL,INBUFF+1
DEC (HL) ; MUST BE EXACTLY 'Y'.
JP NZ,CMMND1
INC HL
LD A,(HL)
CP 'Y'
JP NZ,CMMND1
INC HL
LD (INPOINT),HL ; SAVE INPUT LINE POINTER.
ERASE1: CALL DSELECT ; SELECT DESIRED DISK.
LD DE,FCB
CALL DELETE ; DELETE THE FILE.
INC A
CALL Z,NONE ; NOT THERE?
JP GETBACK ; RETURN TO COMMAND LEVEL NOW.
YESNO: .DB "All (Y/N)?",0
;
;**************************************************************
;*
;* T Y P E C O M M A N D
;*
;**************************************************************
;
TYPE: CALL CONVFST ; CONVERT FILE NAME.
JP NZ,SYNERR ; WILD CARDS NOT ALLOWED.
CALL DSELECT ; SELECT INDICATED DRIVE.
CALL OPENFCB ; OPEN THE FILE.
JP Z,TYPE5 ; NOT THERE?
CALL CRLF ; OK, START A NEW LINE ON THE SCREEN.
LD HL,NBYTES ; INITIALIZE BYTE COUNTER.
LD (HL),0FFH ; SET TO READ FIRST SECTOR.
TYPE1: LD HL,NBYTES
TYPE2: LD A,(HL) ; HAVE WE WRITTEN THE ENTIRE SECTOR?
CP 128
JP C,TYPE3
PUSH HL ; YES, READ IN THE NEXT ONE.
CALL READFCB
POP HL
JP NZ,TYPE4 ; END OR ERROR?
XOR A ; OK, CLEAR BYTE COUNTER.
LD (HL),A
TYPE3: INC (HL) ; COUNT THIS BYTE.
LD HL,TBUFF ; AND GET THE (A)TH ONE FROM THE BUFFER (TBUFF).
CALL ADDHL
LD A,(HL)
CP CNTRLZ ; END OF FILE MARK?
JP Z,GETBACK
CALL PRINT ; NO, PRINT IT.
CALL CHKCON ; CHECK CONSOLE, QUIT IF ANYTHING READY.
JP NZ,GETBACK
JP TYPE1
;
; GET HERE ON AN END OF FILE OR READ ERROR.
;
TYPE4: DEC A ; READ ERROR?
JP Z,GETBACK
CALL RDERROR ; YES, PRINT MESSAGE.
TYPE5: CALL RESETDR ; AND RESET PROPER DRIVE
JP SYNERR ; NOW PRINT FILE NAME WITH PROBLEM.
;
;**************************************************************
;*
;* S A V E C O M M A N D
;*
;**************************************************************
;
SAVE: CALL DECODE ; GET NUMERIC NUMBER THAT FOLLOWS SAVE.
PUSH AF ; SAVE NUMBER OF PAGES TO WRITE.
CALL CONVFST ; CONVERT FILE NAME.
JP NZ,SYNERR ; WILD CARDS NOT ALLOWED.
CALL DSELECT ; SELECT SPECIFIED DRIVE.
LD DE,FCB ; NOW DELETE THIS FILE.
PUSH DE
CALL DELETE
POP DE
CALL CREATE ; AND CREATE IT AGAIN.
JP Z,SAVE3 ; CAN'T CREATE?
XOR A ; CLEAR RECORD NUMBER BYTE.
LD (FCB+32),A
POP AF ; CONVERT PAGES TO SECTORS.
LD L,A
LD H,0
ADD HL,HL ; (HL)=NUMBER OF SECTORS TO WRITE.
LD DE,TBASE ; AND WE START FROM HERE.
SAVE1: LD A,H ; DONE YET?
OR L
JP Z,SAVE2
DEC HL ; NOPE, COUNT THIS AND COMPUTE THE START
PUSH HL ; OF THE NEXT 128 BYTE SECTOR.
LD HL,128
ADD HL,DE
PUSH HL ; SAVE IT AND SET THE TRANSFER ADDRESS.
CALL DMASET
LD DE,FCB ; WRITE OUT THIS SECTOR NOW.
CALL WRTREC
POP DE ; RESET (DE) TO THE START OF THE LAST SECTOR.
POP HL ; RESTORE SECTOR COUNT.
JP NZ,SAVE3 ; WRITE ERROR?
JP SAVE1
;
; GET HERE AFTER WRITING ALL OF THE FILE.
;
SAVE2: LD DE,FCB ; NOW CLOSE THE FILE.
CALL CLOSE
INC A ; DID IT CLOSE OK?
JP NZ,SAVE4
;
; PRINT OUT ERROR MESSAGE (NO SPACE).
;
SAVE3: LD BC,NOSPACE
CALL PLINE
SAVE4: CALL STDDMA ; RESET THE STANDARD DMA ADDRESS.
JP GETBACK
NOSPACE:.DB "No Space",0
;
;**************************************************************
;*
;* R E N A M E C O M M A N D
;*
;**************************************************************
;
RENAME: CALL CONVFST ; CONVERT FIRST FILE NAME.
JP NZ,SYNERR ; WILD CARDS NOT ALLOWED.
LD A,(CHGDRV) ; REMEMBER ANY CHANGE IN DRIVES SPECIFIED.
PUSH AF
CALL DSELECT ; AND SELECT THIS DRIVE.
CALL SRCHFCB ; IS THIS FILE PRESENT?
JP NZ,RENAME6 ; YES, PRINT ERROR MESSAGE.
LD HL,FCB ; YES, MOVE THIS NAME INTO SECOND SLOT.
LD DE,FCB+16
LD B,16
CALL HL2DE
LD HL,(INPOINT) ; GET INPUT POINTER.
EX DE,HL
CALL NONBLANK ; GET NEXT NON BLANK CHARACTER.
CP '=' ; ONLY ALLOW AN '=' OR '_' SEPERATOR.
JP Z,RENAME1
CP '_'
JP NZ,RENAME5
RENAME1:EX DE,HL
INC HL ; OK, SKIP SEPERATOR.
LD (INPOINT),HL ; SAVE INPUT LINE POINTER.
CALL CONVFST ; CONVERT THIS SECOND FILE NAME NOW.
JP NZ,RENAME5 ; AGAIN, NO WILD CARDS.
POP AF ; IF A DRIVE WAS SPECIFIED, THEN IT
LD B,A ; MUST BE THE SAME AS BEFORE.
LD HL,CHGDRV
LD A,(HL)
OR A
JP Z,RENAME2
CP B
LD (HL),B
JP NZ,RENAME5 ; THEY WERE DIFFERENT, ERROR.
RENAME2:LD (HL),B ; RESET AS PER THE FIRST FILE SPECIFICATION.
XOR A
LD (FCB),A ; CLEAR THE DRIVE BYTE OF THE FCB.
RENAME3:CALL SRCHFCB ; AND GO LOOK FOR SECOND FILE.
JP Z,RENAME4 ; DOESN'T EXIST?
LD DE,FCB
CALL RENAM ; OK, RENAME THE FILE.
JP GETBACK
;
; PROCESS RENAME ERRORS HERE.
;
RENAME4:CALL NONE ; FILE NOT THERE.
JP GETBACK
RENAME5:CALL RESETDR ; BAD COMMAND FORMAT.
JP SYNERR
RENAME6:LD BC,EXISTS ; DESTINATION FILE ALREADY EXISTS.
CALL PLINE
JP GETBACK
EXISTS: .DB "File Exists",0
;
;**************************************************************
;*
;* U S E R C O M M A N D
;*
;**************************************************************
;
USER: CALL DECODE ; GET NUMERIC VALUE FOLLOWING COMMAND.
CP 16 ; LEGAL USER NUMBER?
JP NC,SYNERR
LD E,A ; YES BUT IS THERE ANYTHING ELSE?
LD A,(FCB+1)
CP ' '
JP Z,SYNERR ; YES, THAT IS NOT ALLOWED.
CALL GETSETUC ; OK, SET USER CODE.
JP GETBACK1
;
;**************************************************************
;*
;* T R A N S I A N T P R O G R A M C O M M A N D
;*
;**************************************************************
;
UNKNOWN:LD A,(FCB+1) ; ANYTHING TO EXECUTE?
CP ' '
JP NZ,UNKWN1
LD A,(CHGDRV) ; NOPE, ONLY A DRIVE CHANGE?
OR A
JP Z,GETBACK1 ; NEITHER???
DEC A
LD (CDRIVE),A ; OK, STORE NEW DRIVE.
CALL MOVECD ; SET (TDRIVE) ALSO.
CALL DSKSEL ; AND SELECT THIS DRIVE.
JP GETBACK1 ; THEN RETURN.
;
; HERE A FILE NAME WAS TYPED. PREPARE TO EXECUTE IT.
;
UNKWN1: LD DE,FCB+9 ; AN EXTENSION SPECIFIED?
LD A,(DE)
CP ' '
JP NZ,SYNERR ; YES, NOT ALLOWED.
UNKWN2: PUSH DE
CALL DSELECT ; SELECT SPECIFIED DRIVE.
POP DE
LD HL,COMFILE ; SET THE EXTENSION TO 'COM'. LD HL,COMFILE
CALL MOVE3 ; MOVE 3 BYTES FROM (HL) TO (DE) TO ADD .COM
CALL OPENFCB ; AND OPEN THIS FILE.
.IF CHKU0B
JP NZ,UNKWNA ; GOT IT
LD E,0 ; TRY USER 0, THIS DRIVE
CALL GETSETUC ; OK, SET USER CODE.
CALL OPENFCB
JP NZ,UNKWNA ; GOT IT
LD HL,FCB ; SEE IF ON DRIVE B, USER 0
LD (HL),2
CALL OPENFCB
.ENDIF
JP Z,UNKWN9 ; NOPE
;
; LOAD IN THE PROGRAM.
;
UNKWNA: LD HL,TBASE ; STORE THE PROGRAM STARTING HERE.
UNKWN3: PUSH HL
EX DE,HL
CALL DMASET ; SET TRANSFER ADDRESS.
LD DE,FCB ; AND READ THE NEXT RECORD.
CALL RDREC
JP NZ,UNKWN4 ; END OF FILE OR READ ERROR?
POP HL ; NOPE, BUMP POINTER FOR NEXT SECTOR.
LD DE,128
ADD HL,DE
LD DE,CBASE ; ENOUGH ROOM FOR THE WHOLE FILE?
LD A,L
SUB E
LD A,H
SBC A,D
JP NC,UNKWN0 ; NO, IT CAN'T FIT.
JP UNKWN3
;
; GET HERE AFTER FINISHED READING.
;
UNKWN4: POP HL
DEC A ; NORMAL END OF FILE?
JP NZ,UNKWN0
CALL RESETDR ; YES, RESET PREVIOUS DRIVE.
CALL CONVFST ; CONVERT THE FIRST FILE NAME THAT FOLLOWS
LD HL,CHGDRV ; COMMAND NAME.
PUSH HL
LD A,(HL) ; SET DRIVE CODE IN DEFAULT FCB.
LD (FCB),A
LD A,16 ; PUT SECOND NAME 16 BYTES LATER.
CALL CONVERT ; CONVERT SECOND FILE NAME.
POP HL
LD A,(HL) ; AND SET THE DRIVE FOR THIS SECOND FILE.
LD (FCB+16),A
XOR A ; CLEAR RECORD BYTE IN FCB.
LD (FCB+32),A
LD DE,TFCB ; MOVE IT INTO PLACE AT(005CH).
LD HL,FCB
LD B,33
CALL HL2DE
LD HL,INBUFF+2 ; NOW MOVE THE REMAINDER OF THE INPUT
UNKWN5: LD A,(HL) ; LINE DOWN TO (0080H). LOOK FOR A NON BLANK.
OR A ; OR A NULL.
JP Z,UNKWN6
CP ' '
JP Z,UNKWN6
INC HL
JP UNKWN5
;
; DO THE LINE MOVE NOW. IT ENDS IN A NULL BYTE.
;
UNKWN6: LD B,0 ; KEEP A CHARACTER COUNT.
LD DE,TBUFF+1 ; DATA GETS PUT HERE.
UNKWN7: LD A,(HL) ; MOVE IT NOW.
LD (DE),A
OR A
JP Z,UNKWN8
INC B
INC HL
INC DE
JP UNKWN7
UNKWN8: LD A,B ; NOW STORE THE CHARACTER COUNT.
LD (TBUFF),A
CALL CRLF ; CLEAN UP THE SCREEN.
CALL STDDMA ; SET STANDARD TRANSFER ADDRESS.
CALL SETCDRV ; RESET CURRENT DRIVE.
CALL TBASE ; AND EXECUTE THE PROGRAM.
;
; TRANSIANT PROGRAMS RETURN HERE (OR REBOOT).
;
LD SP,BATCH ; SET STACK FIRST OFF.
CALL MOVECD ; MOVE CURRENT DRIVE INTO PLACE (TDRIVE).
CALL DSKSEL ; AND RESELECT IT.
JP CMMND1 ; BACK TO COMAND MODE.
;
; GET HERE IF SOME ERROR OCCURED.
;
UNKWN9: CALL RESETDR ; INPROPER FORMAT.
JP SYNERR
UNKWN0: LD BC,BADLOAD ; READ ERROR OR WON'T FIT.
CALL PLINE
JP GETBACK
BADLOAD:.DB "Bad Load",0
COMFILE:.DB "COM" ; COMMAND FILE EXTENSION.
;
; GET HERE TO RETURN TO COMMAND LEVEL. WE WILL RESET THE
; PREVIOUS ACTIVE DRIVE AND THEN EITHER RETURN TO COMMAND
; LEVEL DIRECTLY OR PRINT ERROR MESSAGE AND THEN RETURN.
;
GETBACK:CALL RESETDR ; RESET PREVIOUS DRIVE.
GETBACK1:
CALL CONVFST ; CONVERT FIRST NAME IN (FCB).
LD A,(FCB+1) ; IF THIS WAS JUST A DRIVE CHANGE REQUEST,
SUB ' ' ; MAKE SURE IT WAS VALID.
LD HL,CHGDRV
OR (HL)
JP NZ,SYNERR
JP CMMND1 ; OK, RETURN TO COMMAND LEVEL.
;
; CCP STACK AREA.
;
.DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
CCPSTACK: .EQU $ ;END OF CCP STACK AREA.
;
; BATCH (OR SUBMIT) PROCESSING INFORMATION STORAGE.
;
BATCH: .DB 0 ; BATCH MODE FLAG (0=NOT ACTIVE).
BATCHFCB:.DB 0,"$$$ SUB"
.DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;
; FILE CONTROL BLOCK SETUP BY THE CCP.
;
FCB: .DB 0," ",0,0,0,0,0
.DB " ",0,0,0,0,0
RTNCODE:.DB 0 ; STATUS RETURNED FROM BDOS CALL.
CDRIVE: .DB 0 ; CURRENTLY ACTIVE DRIVE.
CHGDRV: .DB 0 ; CHANGE IN DRIVES FLAG (0=NO CHANGE).
NBYTES: .DW 0 ; BYTE COUNTER USED BY TYPE.
.IF ENDFIL
.FILL ((CCPO + 0800H) - $),055H
.ENDIF
.END