.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