* * ENHANCED CP/M CONSOLE COMMAND PROCESSOR (CCP) for CP/M REV. 2.2 * * Origianl CCP disassembled by ???? * Original CCP disassembled further by RLC * Original CCP commented by RLC * Modified and generalized by John Thomas (6/20/81) * Macros expanded and condtional for terminals which * use form feeds to clear the screen added by * Bo McCormick (6/27/81) * ***** ASSEMBLING THIS CCP FOR CP/M 2.2 ***** * You must be using a Z-80 processor to run this * program. You do not need MAC or any macro library. * If you add further modifications to the program * the total size of the program must not exceed * 2K in order to fit under the BDOS. Set the CCPLOC equate * to the memory location of the CCP in your system. * Once assembled, the hex file of this CCP program can be * "patched" into your sytem using DDT as outlined in the * CP/M 2 Alteration Guide. * Code must be added to use the Clear Screen command with * your terminal. Equates exist for the Hazeltine 1500, * the Heath/Zenith H19/H89, and any terminal which uses * a form feed to clear the screen. * Also, there is a provision for a boot-up command. Place * the command to be executed on cold and warm starts at * location CBUFF. * ***** NON-STANDARD FEATURES ***** * The non-standard features incorporated into this CCP are: * A. The Command-Search Hierarchy, as follows -- * 1. Scan for a CCP-resident command and execute it if * found * 2. If not CCP-resident, look for a .COM file on disk * 3. If the .COM file is not found in the current user * area and the current user area is not USER 0, * USER 0 is selected and scanned for the file * 4. If the .COM file is not found on the current * logged-in disk drive, drive A: is selected * and scanned for the file * B. The DIR Command no longer prints the current drive spec * at the beginning of each line * C. The TYPE Command pages its output * D. A LIST Command now exists which is like TYPE but does not * page and sends its output to the LST: device * E. A CLS (Clear Screen) Command now exists which clears the * screen of the terminal * F. The user number is printed as part of the command prompt; * the prompt is now du>, such as A0> and A15> * G. Z80-code is used throughout to reduce the size of the CCP * and give room to implement the additional functions * H. The input line buffer has been reduced in size to 100 bytes * I. The ERA Command displays the names of the files it is to * erase * J. The DIR Command has an additional special form of "DIR @" * which displays all files (both non-system and system), * while "DIR" displays just the non-system files * K. The Directory Display no longer displays the disk name at * the beginning of each line and it now includes a '.' between * the file name and file type (FILENAME.TYP) * L. The SUBMIT File Facility now expects the $$$.SUB file to be * on the currently logged-in disk (as opposed to always A:) * M. The Command Line Prompt is now '$' if the command comes from * a $$$.SUB file and '>' if the command comes from the user; * also, the '>' is not printed until all preprocessing is * completed * N. The TYPE and LIST Commands mask the MSB of each byte, so that * files created by editors such as EDIT80 are "printable" * FALSE EQU 0 TRUE EQU NOT FALSE CCPLOC EQU 3400H+1400H ; START OF CCP IN MEMORY ; REPLACE WITH VALUE ; FOR YOUR SYSTEM NLINES EQU 16 ; NUMBER OF LINES ON CRT SCREEN H19 EQU FALSE ; USING HEATH H19/H89 TERMINAL HAZE EQU FALSE ; USING HAZELTINE 1500 TERMINAL FFTERM EQU TRUE ; USING TERMINAL THAT RESPONDS TO 0CH ; OR ANY CHARACTER IF YOU CHANGE THE ; VALUE OF FF BELOW CR EQU 0DH LF EQU 0AH TAB EQU 09H FF EQU 0CH ;<==== CHANGE THIS BYTE IF TERMINAL ESC EQU 1BH ; NEEDS A DIFFERENT CHARACTER ; TO CLEAR THE SCREEN WBOOT EQU 0000H ; CP/M WARM BOOT ADDRESS UDFLAG EQU 0004H ; USER NUMBER IS IN HIGH NYBBLE, DISK IN LOW BDOS EQU 0005H ; BDOS FUNCTION CALL ENTRY PT TBUFF EQU 0080H ; DEFAULT DISK I/O BUFFER TFCB EQU 005CH ; DEFAULT FCB BUFFER TPA EQU 0100H ; BASE OF TPA ORG CCPLOC ; START OF CCP IN MEMEORY IN YOUR SYSTEM ENTRY: JMP CCP JMP CCP1 * INPUT COMMAND LINE AND DEFAULT COMMAND BUFLEN EQU 100 ; MAXIMUM BUFFER LENGTH MBUFF: DB BUFLEN ; MAXIMUM BUFFER LENGTH CBUFF: DB 3 ;<== NUMBER OF VALID CHARS IN COMMAND LINE CIBUFF: DB 'DIR ' ;<== DEFAULT (COLD BOOT) COMMAND DB ' ' DB ' ' DB ' ' CIBUF: DS 85 ; TOTAL IS 100 BYTES DS 20 ; STACK AREA STACK EQU $ ; TOP OF STACK CIBPTR: DW CIBUFF ;POINTER TO CMD INPUT BUFF CIPTR: DW CIBUF ;CURRENT PNTR * * I/O UTILITIES * * OUTPUT SPACER: MVI A,' ' ; FALL THRU TO CONOUT * OUTPUT CHAR IN REG A TO CONSOLE AND DON'T CHANGE BC CONOUT: PUSH B PUSH H MVI C,02H OUTPUT: MOV E,A CALL BDOS POP H POP B RET * CALL BDOS AND SAVE BC BDOSB: PUSH B CALL BDOS POP B RET * OUTPUT CHAR IN REG A TO LIST DEVICE LSTOUT: PUSH B PUSH H MVI C,05H DB 18H DB OUTPUT-$-1 AND 0FFH * OUTPUT CRLF: MVI A,CR CALL CONOUT MVI A,LF DB 18H DB CONOUT-$-1 AND 0FFH * PRINT STRING (ENDING IN 0) PTED TO BY RET ADR; START WITH PRINT: XTHL ; GET PTR TO STRING PUSH PSW ; SAVE FLAGS CALL CRLF ; NEW LINE CALL PRIN1 POP PSW ; GET FLAGS XTHL ; RESTORE HL AND RET ADR RET * PRINT STRING (ENDING IN 0) PTED TO BY HL PRIN1: MOV A,M ; GET NEXT BYTE INX H ; PT TO NEXT BYTE ORA A ; DONE IF 0 RZ CALL CONOUT ; PRINT CHAR DB 18H DB PRIN1-$-1 AND 0FFH * * BDOS FUNCTION ROUTINES * RESET: MVI C,0DH JMP BDOS ; LOGIN: MOV E,A MVI C,0EH JMP BDOS ; OPENF: XRA A STA FCBCR LXI D,FCBDN ; FALL THRU TO OPEN ; OPEN: MVI C,0FH ; FALL THRU TO GRBDOS ; GRBDOS: CALL BDOS INR A ; SET ZERO FLAG FOR ERROR RETURN RET ; CLOSE: MVI C,10H DB 18H DB GRBDOS-$-1 AND 0FFH ; SEARF: LXI D,FCBDN ; SPECIFY FCB SEAR1: MVI C,11H DB 18H DB GRBDOS-$-1 AND 0FFH ; SEARN: MVI C,12H DB 18H DB GRBDOS-$-1 AND 0FFH ; DELETE: MVI C,13H JMP BDOS ; READF: LXI D,FCBDN ; FALL THRU TO READ ; READ: MVI C,14H ; FALL THRU TO GOBDOS ; GOBDOS: CALL BDOSB ; PRESERVE B ORA A RET ; WRITE: MVI C,15H DB 18H DB GOBDOS-$-1 AND 0FFH ; CREATE: MVI C,16H DB 18H DB GRBDOS-$-1 AND 0FFH ; GETUSR: MVI E,0FFH ;GET CURRENT USER NUMBER SETUSR: MVI C,20H ;SET USER NUMBER TO VALUE IN E (GET IF E=FFH) JMP BDOS * * END OF BDOS FUNCTIONS * * * CCP UTILITIES * * SET USER/DISK FLAG TO CURRENT USER AND DEFAULT DISK SETUD: CALL GETUSR ; GET NUMBER OF CURRENT USER ADD A ; PLACE IT IN HIGH NYBBLE ADD A ADD A ADD A LXI H,TDRIVE ; MASK IN DEFAULT DRIVE NUMBER (LOW NYBBLE) ORA M ; MASK IN STA UDFLAG ; SET USER/DISK NUMBER RET * SET USER/DISK FLAG TO USER 0 AND DEFAULT DISK SETU0D: LDA TDRIVE ; SET USER 0/DEFAULT DISK STA UDFLAG ; SET USER/DISK NUMBER RET * CONVERT CHAR IN A TO UPPER CASE UCASE: CPI 61H ; LOWER-CASE A RC CPI 7BH ; GREATER THAN LOWER-CASE Z? RNC ANI 5FH ; CAPITALIZE RET * INPUT NEXT COMMAND TO CCP REDBUF: LDA RNGSUB ; SUBMIT FILE CURRENTLY IN EXECUTION? ORA A ; 0=NO DB 28H DB RB1-$-1 AND 0FFH ; GET LINE FROM CONSOLE IF NOT LXI D,SUBFCB ; OPEN $$$.SUB CALL OPEN DB 28H DB RB1-$-1 AND 0FFH ; ERASE $$$.SUB IF END OF FILE AND GET CMND LDA SUBFRC ; GET VALUE OF LAST RECORD IN FILE DCR A ; PT TO NEXT TO LAST RECORD STA SUBFCR ; SAVE NEW VALUE OF LAST RECORD IN $$$.SUB LXI D,SUBFCB ; READ LAST RECORD OF SUBMIT FILE CALL READ DB 20H DB RB1-$-1 AND 0FFH ; ABORT $$$.SUB IF ERROR IN READING LAST REC LXI D,CBUFF ; COPY LAST RECORD (NEXT SUBMIT CMND) TO CBUFF LXI H,TBUFF ; FROM TBUFF MVI B,BUFLEN ; NUMBER OF BYTES CALL MOVEHD LXI H,SUBFS2 ; PT TO S2 OF $$$.SUB FCB MVI M,0 ; SET S2 TO ZERO INX H ; PT TO RECORD COUNT DCR M ; DECREMENT RECORD COUNT OF $$$.SUB LXI D,SUBFCB ; CLOSE $$$.SUB CALL CLOSE DB 28H DB RB1-$-1 AND 0FFH ; ABORT $$$.SUB IF ERROR MVI A,'$' ; PRINT SUBMIT PROMPT CALL CONOUT LXI H,CIBUFF ; PRINT COMMAND LINE FROM $$$.SUB CALL PRIN1 CALL BREAK ; CHECK FOR ABORT (ANY CHAR) DB 28H DB CNVBUF-$-1 AND 0FFH ; IF (NO ABORT), CAP COMMAND AND RUN CALL SUBKIL ; KILL $$$.SUB IF ABORT JMP RESTRT ; RESTART CCP * INPUT COMMAND LINE FROM USER CONSOLE RB1: CALL SUBKIL ; ERASE $$$.SUB IF PRESENT CALL SETUD ; SET USER AND DISK MVI A,'>' ; PRINT PROMPT CALL CONOUT MVI C,0AH ; READ COMMAND LINE FROM USER LXI D,MBUFF CALL BDOS CALL SETU0D ; SET CURRENT DISK NUMBER IN LOWER PARAMS * CAPITALIZE STRING (ENDING IN 0) IN CBUFF CNVBUF: LXI H,CBUFF ; PT TO USER'S COMMAND MOV B,M ; CHAR COUNT IN B CB1: INX H ; PT TO 1ST VALID CHAR MOV A,B ; DONE WHEN ENCOUNTERED ORA A DB 28H DB CB2-$-1 AND 0FFH MOV A,M ; CAPITALIZE COMMAND CHAR CALL UCASE MOV M,A DCR B ; CONTINUE UNTIL END OF COMMAND LINE DB 18H DB CB1-$-1 AND 0FFH CB2: MOV M,A ; STORE ENDING LXI H,CIBUFF ; SET COMMAND LINE PTR TO 1ST CHAR SHLD CIBPTR RET * CHECK FOR ANY CHAR FROM USER CONSOLE; RET W/ZERO SET IF NONE BREAK: PUSH D ; SAVE DE MVI E,0FFH ; GET STATUS MVI C,6 ; DIRECT CONSOLE I/O CALL BDOSB POP D ANI 7FH ; MASK MSB AND SET ZERO FLAG RET * RETURN NUMBER OF CURRENT DISK IN A GETDRV: MVI C,19H JMP BDOS * SET 80H AS DMA ADDRESS DEFDMA: LXI D,TBUFF ; 80H=TBUFF DMASET: MVI C,1AH JMP BDOS * CHECK FOR SUBMIT FILE IN EXECUTION AND ABORT IT IF SO SUBKIL: LXI H,RNGSUB ; CHECK FOR SUBMIT FILE IN EXECUTION MOV A,M ORA A ; 0=NO RZ MVI M,0 ; ABORT SUBMIT FILE LXI D,SUBFCB ; DELETE $$$.SUB JMP DELETE * INVALID COMMAND -- PRINT IT ERROR: CALL CRLF ; NEW LINE LHLD CIPTR ; PT TO BEGINNING OF COMMAND LINE ERR2: MOV A,M ; GET CHAR CPI ' ' ; SIMPLE '?' IF DB 28H DB ERR1-$-1 AND 0FFH ORA A ; SIMPLE '?' IF DB 28H DB ERR1-$-1 AND 0FFH PUSH H ; SAVE PTR TO ERROR COMMAND CHAR CALL CONOUT ; PRINT COMMAND CHAR POP H ; GET PTR INX H ; PT TO NEXT DB 18H DB ERR2-$-1 AND 0FFH ; CONTINUE ERR1: MVI A,'?' ; PRINT '?' CALL CONOUT CALL SUBKIL ; TERMINATE ACTIVE $$$.SUB IF ANY JMP RESTRT ; RESTART CCP * CHECK TO SEE IF DE PTS TO DELIMITER; IF SO, RET W/ZERO FLAG SET SDELM: LDAX D ORA A ; 0=DELIMITER RZ CPI ' ' ; ERROR IF < JC ERROR RZ ; =DELIMITER CPI '=' ; '='=DELIMITER RZ CPI 5FH ; UNDERSCORE=DELIMITER RZ CPI '.' ; '.'=DELIMITER RZ CPI ':' ; ':'=DELIMITER RZ CPI ';' ; ';'=DELIMITER RZ CPI '<' ; '<'=DELIMITER RZ CPI '>' ; '>'=DELIMITER RET * SKIP STRING PTED TO BY DE (STRING ENDS IN 0) UNTIL END OF STRING * OR NON-BLANK ENCOUNTERED (BEGINNING OF TOKEN) SBLANK: LDAX D ORA A RZ CPI ' ' RNZ INX D DB 18H DB SBLANK-$-1 AND 0FFH * ADD A TO HL (HL=HL+A) ADDAH: ADD L MOV L,A RNC INR H RET * EXTRACT TOKEN FROM COMMAND LINE AND PLACE IT INTO FCBDN; FORMAT FCBDN * IF TOKEN RESEMBLES FILE NAME AND TYPE (FILENAME.TYP); * ON INPUT, CIBPTR PTS TO CHAR AT WHICH TO START SCAN * ON OUTPUT, CIBPTR PTS TO CHAR AT WHICH TO CONTINUE AND ZERO FLAG IS SET * IF '?' IS IN TOKEN SCANER: MVI A,0 ; START AT DRIVE SPECIFICATION BYTE SCAN1: LXI H,FCBDN ; POINT TO FCBDN CALL ADDAH ; OFFSET INTO FCB PUSH H PUSH H XRA A ; SET TEMPORARY DRIVE NUMBER TO DEFAULT STA TEMPDR LHLD CIBPTR ; GET PTR TO NEXT CHAR IN COMMAND LINE XCHG ; PTR IN DE CALL SBLANK ; SKIP TO NON-BLANK OR END OF LINE XCHG SHLD CIPTR ; SET PTR TO NON-BLANK OR END OF LINE XCHG ; DE PTS TO NEXT NON-BLANK OR END OF LINE CHAR POP H ; GET PTR TO NEXT BYTE IN FCBDN LDAX D ; END OF LINE? ORA A ; 0=YES DB 28H DB SCAN2-$-1 AND 0FFH SBI 'A'-1 ; CONVERT POSSIBLE DRIVE SPEC TO NUMBER MOV B,A ; STORE NUMBER (A:=0, B:=1, ETC) IN B INX D ; PT TO NEXT CHAR LDAX D ; SEE IF IT IS A COLON (:) CPI ':' DB 28H DB SCAN3-$-1 AND 0FFH ; YES^ WE HAVE A DRIVE SPEC DCX D ; NO^ BACK UP PTR TO FIRST NON-BLANK CHAR SCAN2: LDA TDRIVE ; SET 1ST BYTE OF FCBDN AS DEFAULT DRIVE MOV M,A DB 18H DB SCAN4-$-1 AND 0FFH SCAN3: MOV A,B ; WE HAVE A DRIVE SPEC^ STA TEMPDR ; SET TEMPORARY DRIVE MOV M,B ; SET 1ST BYTE OF FCBDN AS SPECIFIED DRIVE INX D ; PT TO BYTE AFTER ':' * EXTRACT FILENAME FROM POSSIBLE FILENAME.TYP SCAN4: MVI B,08H ; MAX OF 8 CHARS IN FILE NAME SCAN5: CALL SDELM ; DONE IF DELIMITER ENCOUNTERED - FILL DB 28H DB SCAN9-$-1 AND 0FFH INX H ; PT TO NEXT BYTE IN FCBDN CPI '*' ; IS (DE) A WILD CARD? DB 20H DB SCAN6-$-1 AND 0FFH ; CONTINUE IF NOT MVI M,'?' ; PLACE '?' IN FCBDN AND DON'T ADVANCE DE IF SO DB 18H DB SCAN7-$-1 AND 0FFH SCAN6: MOV M,A ; STORE FILENAME CHAR IN FCBDN INX D ; PT TO NEXT CHAR IN COMMAND LINE SCAN7: DB 10H DB SCAN5-$-1 AND 0FFH ; DECREMENT CHAR COUNT UNTIL 8 ELAPSED SCAN8: CALL SDELM ; 8 CHARS OR MORE - SKIP UNTIL DELIMITER DB 28H DB SCAN10-$-1 AND 0FFH ; ZERO FLAG SET IF DELIMITER FOUND INX D ; PT TO NEXT CHAR IN COMMAND LINE DB 18H DB SCAN8-$-1 AND 0FFH SCAN9: INX H ; PT TO NEXT BYTE IN FCBDN MVI M,' ' ; FILL FILENAME PART WITH DB 10H DB SCAN9-$-1 AND 0FFH * EXTRACT FILE TYPE FROM POSSIBLE FILENAME.TYP SCAN10: MVI B,03H ; PREPARE TO EXTRACT TYPE CPI '.' ; IF (DE) DELIMITER IS A '.', WE HAVE A TYPE DB 20H DB SCAN15-$-1 AND 0FFH ; FILL FILE TYPE BYTES WITH INX D ; PT TO CHAR IN COMMAND LINE AFTER '.' SCAN11: CALL SDELM ; CHECK FOR DELIMITER DB 28H DB SCAN15-$-1 AND 0FFH ; FILL REST OF TYPE IF IT IS A DELIMITER INX H ; PT TO NEXT BYTE IN FCBDN CPI '*' ; WILD? DB 20H DB SCAN12-$-1 AND 0FFH ; STORE CHAR IF NOT WILD MVI M,'?' ; STORE '?' AND DON'T ADVANCE COMMAND LINE PTR DB 18H DB SCAN13-$-1 AND 0FFH SCAN12: MOV M,A ; STORE CHAR IN FCBDN INX D ; PT TO NEXT CHAR IN COMMAND LINE SCAN13: DB 10H DB SCAN11-$-1 AND 0FFH ; COUNT DOWN CHARS IN FILE TYPE (3 MAX) SCAN14: CALL SDELM ; SKIP REST OF CHARS AFTER 3-CHAR TYPE TO DB 28H DB SCAN16-$-1 AND 0FFH ; DELIMITER INX D DB 18H DB SCAN14-$-1 AND 0FFH SCAN15: INX H ; FILL IN REST OF TYP WITH MVI M,' ' DB 10H DB SCAN15-$-1 AND 0FFH * FILL IN EX, S1, S2, AND RC WITH ZEROES SCAN16: MVI B,4 ; 4 BYTES SCAN17: INX H ; PT TO NEXT BYTE IN FCBDN MVI M,0 DB 10H DB SCAN17-$-1 AND 0FFH * SCAN COMPLETE -- DE PTS TO DELIMITER BYTE AFTER TOKEN XCHG ; STORE PTR TO NEXT BYTE IN COMMAND LINE SHLD CIBPTR * SET ZERO FLAG TO INDICATE PRESENCE OF '?' IN FILENAME.TYP POP H ; GET PTR TO FCBDN IN HL LXI B,11 ; SCAN FOR '?' IN FILENAME.TYP (C=11 BYTES) SCAN18: INX H ; PT TO NEXT BYTE IN FCBDN MOV A,M CPI '?' DB 20H DB SCAN19-$-1 AND 0FFH INR B ; B<>0 TO INDICATE '?' ENCOUNTERED SCAN19: DCR C ; COUNT DOWN DB 20H DB SCAN18-$-1 AND 0FFH MOV A,B ; A=B=NUMBER OF '?' IN FILENAME.TYP ORA A ; SET ZERO FLAG TO INDICATE ANY '?' RET * * CCP BUILT-IN COMMAND TABLE AND COMMAND PROCESSOR * NCMNDS EQU 8 ; NUMBER OF CCP COMMANDS NCHARS EQU 4 ; NUMBER OF CHARS/COMMAND * CCP COMMAND NAME TABLE CMDTBL: DB 'DIR ' DB 'ERA ' DB 'LIST' DB 'TYPE' DB 'SAVE' DB 'REN ' DB 'USER' DB 'CLS ' * CCP COMMAND ADDRESS TABLE REQTBL: DW DIR DW ERA DW LIST DW TYPE DW SAVE DW REN DW USER DW CLS DW COM ;MUST BE A COM FILE * CMDTBL (COMMAND TABLE) SCANNER * ON RETURN, A=TABLE ENTRY # (0-5) OR 6 IF NOT FOUND (COM FILE) CMDSER: LXI H,CMDTBL ; PT TO COMMAND TABLE MVI C,0 ; SET COMMAND COUNTER CMS1: MOV A,C ; CHECK FOR DONE CPI NCMNDS ; NUMBER OF COMMANDS RNC LXI D,FCBFN ; PT TO STORED COMMAND NAME MVI B,NCHARS ; NUMBER OF CHARS/COMMAND (8 MAX) CMS2: LDAX D ; COMPARE AGAINST TABLE ENTRY CMP M DB 20H DB CMS3-$-1 AND 0FFH ; NO MATCH INX D ; PT TO NEXT CHAR INX H DB 10H DB CMS2-$-1 AND 0FFH ; COUNT DOWN LDAX D ; NEXT CHAR IN INPUT COMMAND MUST BE CPI ' ' DB 20H DB CMS4-$-1 AND 0FFH MOV A,C ; TABLE ENTRY NUMBER IN A RET CMS3: INX H ; SKIP TO NEXT COMMAND TABLE ENTRY DB 10H DB CMS3-$-1 AND 0FFH CMS4: INR C ; INCREMENT TABLE ENTRY NUMBER DB 18H DB CMS1-$-1 AND 0FFH * * CCP STARTING POINTS * * START CCP AND DON'T PROCESS DEFAULT COMMAND STORED CCP1: XRA A ; SET NO DEFAULT COMMAND STA CBUFF * START CCP AND POSSIBLY PROCESS DEFAULT COMMAND CCP: LXI SP,STACK ; RESET STACK PUSH B MOV A,C ; C=USER/DISK NUMBER (SEE LOC 4) RAR ; EXTRACT USER NUMBER RAR RAR RAR ANI 0FH MOV E,A ; SET USER NUMBER CALL SETUSR CALL RESET ; RESET DISK SYSTEM POP B MOV A,C ; C=USER/DISK NUMBER (SEE LOC 4) ANI 0FH ; EXTRACT DEFAULT DISK DRIVE STA TDRIVE ; SET IT CALL LOGIN ; LOG IN DEFAULT DISK LXI D,SUBFCB ; CHECK FOR $$$.SUB ON CURRENT DISK CALL SEAR1 CMA ; 0FFH IS RETURNED IF NO $$$.SUB, SO COMPLEMENT STA RNGSUB ; SET FLAG (0=NO $$$.SUB) LDA CBUFF ; EXECUTE DEFAULT COMMAND? ORA A ; 0=NO DB 20H DB RS1-$-1 AND 0FFH * PROMPT USER AND INPUT COMMAND LINE FROM HIM RESTRT: LXI SP,STACK ; RESET STACK * PRINT PROMPT (DU>) CALL CRLF ; PRINT PROMPT CALL GETDRV ; CURRENT DRIVE IS PART OF PROMPT ADI 'A' ; CONVERT TO ASCII A-P CALL CONOUT CALL GETUSR ; GET USER NUMBER CPI 10 ; USER < 10? DB 38H DB RS00-$-1 AND 0FFH SUI 10 ; SUBTRACT 10 FROM IT PUSH PSW ; SAVE IT MVI A,'1' ; OUTPUT 10'S DIGIT CALL CONOUT POP PSW RS00: ADI '0' ; OUTPUT 1'S DIGIT (CONVERT TO ASCII) CALL CONOUT * READ INPUT LINE FROM USER OR $$$.SUB CALL REDBUF ; INPUT COMMAND LINE FROM USER (OR $$$.SUB) * PROCESS INPUT LINE RS1: LXI D,TBUFF ; PT TO INPUT COMMAND LINE (IN TBUFF) CALL DMASET ; SET TBUFF TO DMA ADDRESS CALL GETDRV ; GET DEFAULT DRIVE NUMBER STA TDRIVE ; SET IT CALL SCANER ; PARSE COMMAND NAME FROM COMMAND LINE CNZ ERROR ; ERROR IF COMMAND NAME CONTAINS A '?' LDA TEMPDR ; IS COMMAND OF FORM 'D:COMMAND'? ORA A ; NZ=YES JNZ COM ; PROCESS AS COM FILE IMMEDIATELY CALL CMDSER ; SCAN FOR CCP-RESIDENT COMMAND LXI H,REQTBL ; EXECUTE COMMAND (CCP-RESIDENT OR COM) MOV E,A ; COMPUTE OFFSET INTO ADDRESS TABLE MVI D,0 DAD D DAD D MOV A,M ; GET ADDRESS IN HL INX H MOV H,M ; ADDRESS HIGH MOV L,A ; ADDRESS LOW PCHL ; EXECUTE CCP ROUTINE * * ERROR MESSAGES * PRNNF: CALL PRINT ; NO FILE MESSAGE DB 'No Files',0 RET * * MORE CCP UTILITIES * * EXTRACT NUMBER FROM COMMAND LINE NUMBER: CALL SCANER ; PARSE NUMBER AND PLACE IN FCBFN LDA TEMPDR ; TOKEN BEGIN WITH DRIVE SPEC (D:)? ORA A ; ERROR IF SO JNZ ERROR LXI H,FCBFN ; PT TO TOKEN FOR CONVERSION LXI B,11 ; B=ACCUMULATED VALUE, C=CHAR COUNT NUM1: MOV A,M ; GET CHAR CPI ' ' ; DONE IF DB 28H DB NUM2-$-1 AND 0FFH INX H ; PT TO NEXT CHAR SUI '0' ; CONVERT TO BINARY (ASCII 0-9 TO BINARY) CPI 10 ; ERROR IF >= 10 JNC ERROR MOV D,A ; DIGIT IN D MOV A,B ; GET ACCUMULATED VALUE ANI 0E0H ; CHECK FOR RANGE ERROR (>255) JNZ ERROR MOV A,B ; NEW VALUE = OLD VALUE * 10 RLC RLC RLC ADD B ; CHECK FOR RANGE ERROR JC ERROR ADD B ; CHECK FOR RANGE ERROR JC ERROR ADD D ; NEW VALUE = OLD VALUE * 10 + DIGIT JC ERROR ; CHECK FOR RANGE ERROR MOV B,A ; SET NEW VALUE DCR C ; COUNT DOWN DB 20H DB NUM1-$-1 AND 0FFH RET * REST OF TOKEN BUFFER MUST BE NUM2: MOV A,M ; CHECK FOR CPI ' ' JNZ ERROR INX H ; PT TO NEXT DCR C ; COUNT DOWN CHARS DB 20H DB NUM2-$-1 AND 0FFH MOV A,B ; GET ACCUMULATED VALUE RET * MOVE 3 BYTES FROM HL TO DE MOVHD3: MVI B,3 ; MOVE 3 CHARS MOVEHD: MOV A,M ; GET IT STAX D ; PUT IT INX H ; PT TO NEXT INX D DB 10H DB MOVEHD-$-1 AND 0FFH RET * PT TO DIRECTORY ENTRY IN TBUFF WHOSE OFFSET IS SPECIFIED BY A AND C DIRPTR: LXI H,TBUFF ; PT TO TEMP BUFFER ADD C ; PT TO 1ST BYTE OF DIR ENTRY CALL ADDAH ; PT TO DESIRED BYTE IN DIR ENTRY MOV A,M ; GET DESIRED BYTE RET * CHECK FOR SPECIFIED DRIVE AND LOG IT IN IF NOT DEFAULT SLOGIN: XRA A ; SET FCBDN FOR DEFAULT DRIVE STA FCBDN CALL COMLOG ; CHECK DRIVE RZ JMP LOGIN ; DO LOGIN OTHERWISE * CHECK FOR SPECIFIED DRIVE AND LOG IN DEFAULT DRIVE IF SPECIFIED<>DEFAULT DLOGIN: CALL COMLOG ; CHECK DRIVE RZ ; ABORT IF SAME LDA TDRIVE ; LOG IN DEFAULT DRIVE JMP LOGIN * ROUTINE COMMON TO BOTH LOGIN ROUTINES; ON EXIT, Z SET MEANS ABORT COMLOG: LDA TEMPDR ; DRIVE SPECIFIED? ORA A ; 0=NO RZ DCR A ; COMPARE IT AGAINST DEFAULT LXI H,TDRIVE CMP M RET ; ABORT IF SAME * * CCP DIRECTORY DISPLAY FUNCTION (DIR) * DIR: MVI A,80H ; SET SYSTEM BIT EXAMINATION PUSH PSW CALL SCANER ; EXTRACT POSSIBLE D:FILENAME.TYP TOKEN CALL SLOGIN ; LOG IN DRIVE IF NECESSARY LXI H,FCBFN ; MAKE FCB WILD (ALL '?') IF NO FILENAME.TYP MOV A,M ; GET FIRST CHAR OF FILENAME.TYP CPI ' ' ; IF , ALL WILD DB 28H DB DIR0-$-1 AND 0FFH CPI '@' ; SYSTEM FILES? DB 20H DB DIR2-$-1 AND 0FFH INX H ; JUST '@'? MUST FOLLOW MOV A,M DCX H ; BACK UP CPI ' ' ; JUST '@' IF FOLLOWS DB 20H DB DIR2-$-1 AND 0FFH POP PSW ; GET FLAG XRA A ; SET NO SYSTEM BIT EXAMINATION PUSH PSW DIR0: MVI B,11 ; NUMBER OF CHARS IN FN & FT DIR1: MVI M,'?' ; STORE '?' INX H DB 10H DB DIR1-$-1 AND 0FFH DIR2: POP PSW ; GET FLAG CALL DIRPR ; PRINT DIRECTORY JMP RSTCCP ; RESTART CCP * DIRECTORY PRINT ROUTINE; ON ENTRY, MSB OF A IS 1 (80H) IF SYSTEM FILES EXCL DIRPR: MOV D,A ; STORE SYSTEM FLAG IN D MVI E,0 ; SET COLUMN COUNTER TO ZERO PUSH D ; SAVE COLUMN COUNTER (E) AND SYSTEM FLAG (D) CALL SEARF ; SEARCH FOR SPECIFIED FILE (FIRST OCCURRANCE) CZ PRNNF ; PRINT NO FILE MSG; REG A NOT CHANGED * ENTRY SELECTION LOOP; ON ENTRY, A=OFFSET FROM SEARF OR SEARN DIR3: DB 28H DB DIR11-$-1 AND 0FFH ; DONE IF ZERO FLAG SET DCR A ; ADJUST TO RETURNED VALUE RRC ; CONVERT NUMBER TO OFFSET INTO TBUFF RRC RRC ANI 60H MOV C,A ; OFFSET INTO TBUFF IN C (C=OFFSET TO ENTRY) MVI A,10 ; ADD 10 TO PT TO SYSTEM FILE ATTRIBUTE BIT CALL DIRPTR POP D ; GET SYSTEM BIT MASK FROM D PUSH D ANA D ; MASK FOR SYSTEM BIT DB 20H DB DIR10-$-1 AND 0FFH ; SKIP ENTRY IF BIT IS SET POP D ; GET ENTRY COUNT (= COUNTER) MOV A,E ; ADD 1 TO IT INR E PUSH D ; SAVE IT ANI 03H ; OUTPUT IF 4 ENTRIES PRINTED IN LINE PUSH PSW DB 20H DB DIR4-$-1 AND 0FFH CALL CRLF ; NEW LINE DB 18H DB DIR5-$-1 AND 0FFH DIR4: CALL SPACER ; PRINT : BETWEEN ENTRIES MVI A,':' CALL CONOUT CALL SPACER DIR5: MVI B,01H ; PT TO 1ST BYTE OF FILE NAME DIR6: MOV A,B ; A=OFFSET CALL DIRPTR ; HL NOW PTS TO 1ST BYTE OF FILE NAME ANI 7FH ; MASK OUT MSB CPI ' ' ; NO FILE NAME? DB 20H DB DIR8-$-1 AND 0FFH ; PRINT FILE NAME IF PRESENT POP PSW PUSH PSW CPI 03H DB 20H DB DIR7-$-1 AND 0FFH MVI A,09H ; PT TO 1ST BYTE OF FILE TYPE CALL DIRPTR ; HL NOW PTS TO 1ST BYTE OF FILE TYPE ANI 7FH ; MASK OUT MSB CPI ' ' ; NO FILE TYPE? DB 28H DB DIR9-$-1 AND 0FFH ; CONTINUE IF SO DIR7: MVI A,' ' ; OUTPUT DIR8: CALL CONOUT ; PRINT CHAR INR B ; INCR CHAR COUNT MOV A,B CPI 12 ; END OF FILENAME.TYP? DB 30H DB DIR9-$-1 AND 0FFH ; CONTINUE IF SO CPI 09H ; END IF FILENAME ONLY? DB 20H DB DIR6-$-1 AND 0FFH ; PRINT TYP IF SO MVI A,'.' ; PRINT DOT BETWEEN FILE NAME AND TYPE CALL CONOUT DB 18H DB DIR6-$-1 AND 0FFH DIR9: POP PSW DIR10: CALL BREAK ; CHECK FOR ABORT DB 20H DB DIR11-$-1 AND 0FFH CALL SEARN ; SEARCH FOR NEXT FILE DB 18H DB DIR3-$-1 AND 0FFH ; CONTINUE DIR11: POP D ; RESTORE STACK RET * * CCP FILE ERASE FUNCTION (ERA) * ERA: CALL SCANER ; PARSE FILE SPECIFICATION CPI 0BH ; ALL WILD (ALL FILES = 11 '?')? DB 20H DB ERA1-$-1 AND 0FFH ; IF NOT, THEN DO ERASES CALL PRINT DB 'All (Y/N)?',0 CALL REDBUF ; GET REPLY LXI H,CBUFF ; CHECK FOR DCR M JNZ RESTRT ; RESTART CCP IF JUST INX H ; PT TO RESPONSE BYTE MOV A,M ; GET IT CPI 'Y' ; YES? JNZ RESTRT ; RESTART CCP IF NOT INX H ; PT TO CHAR AFTER 'Y' SHLD CIBPTR ; SET PTR TO IT ERA1: CALL SLOGIN ; LOG IN SELECTED DISK IF ANY MVI A,80H ; SKIP SYSTEM FILES (EXAMINE SYSTEM BIT) CALL DIRPR ; PRINT DIRECTORY OF ERASED FILES LXI D,FCBDN ; DELETE FILE SPECIFIED CALL DELETE JMP RSTCCP ; REENTER CCP * * CCP LIST FUNCTION (LIST) * LIST: MVI A,0FFH ; TURN ON PRINTER FLAG DB 18H DB TYPE0-$-1 AND 0FFH * * CCP TYPE FUNCTION (TYPE) * TYPE: XRA A ; TURN OFF PRINTER FLAG * ENTRY POINT FOR CCP LIST FUNCTION (LIST) TYPE0: STA PRFLG ; SET FLAG CALL SCANER ; EXTRACT FILENAME.TYP TOKEN JNZ ERROR ; ERROR IF ANY QUESTION MARKS CALL SLOGIN ; LOG IN SELECTED DISK IF ANY CALL OPENF ; OPEN SELECTED FILE JZ TYPE4 ; ABORT IF ERROR CALL CRLF ; NEW LINE CALL PAGSET ; SET LINE COUNT LXI H,CHRCNT ; SET CHAR POSITION/COUNT MVI M,0FFH ; EMPTY LINE MVI B,0 ; SET TAB CHAR COUNTER TYPE1: LXI H,CHRCNT ; PT TO CHAR POSITION/COUNT MOV A,M ; END OF BUFFER? CPI 80H DB 38H DB TYPE2-$-1 AND 0FFH PUSH H ; READ NEXT BLOCK CALL READF POP H DB 20H DB TYPE3-$-1 AND 0FFH ; ERROR? XRA A ; RESET COUNT MOV M,A TYPE2: INR M ; INCREMENT CHAR COUNT LXI H,TBUFF ; PT TO BUFFER CALL ADDAH ; COMPUTE ADDRESS OF NEXT CHAR FROM OFFSET MOV A,M ; GET NEXT CHAR ANI 7FH ; MASK OUT MSB CPI 1AH ; END OF FILE (^Z)? JZ RSTCCP ; RESTART CCP IF SO PUSH PSW ; SAVE CHAR LDA PRFLG ; TYPE OR LIST? ORA A ; 0=TYPE DB 28H DB TYPE2T-$-1 AND 0FFH * OUTPUT CHAR TO LST: DEVICE WITH TABULATION POP PSW ; GET CHAR CPI CR ; RESET TAB COUNT? DB 28H DB TABRST-$-1 AND 0FFH CPI LF ; RESET TAB COUNT? DB 28H DB TABRST-$-1 AND 0FFH CPI TAB ; TAB? DB 28H DB LTAB-$-1 AND 0FFH CALL LSTOUT ; LIST CHAR INR B ; INCREMENT CHAR COUNT DB 18H DB TYPE2L-$-1 AND 0FFH TABRST: CALL LSTOUT ; OUTPUT MVI B,0 ; RESET TAB COUNTER DB 18H DB TYPE2L-$-1 AND 0FFH LTAB: MVI A,' ' ; CALL LSTOUT INR B ; INCR POS COUNT MOV A,B ANI 7 DB 20H DB LTAB-$-1 AND 0FFH DB 18H DB TYPE2L-$-1 AND 0FFH * OUTPUT CHAR TO CON: WITH TABULATION TYPE2T: POP PSW ; GET CHAR PUSH PSW ; SAVE CHAR CALL CONOUT ; TYPE CHAR POP PSW CPI LF ; PAGE ON CZ PAGER ; COUNT LINES AND PAGE * CONTINUE PROCESSING TYPE2L: CALL BREAK ; CHECK FOR ABORT DB 28H DB TYPE1-$-1 AND 0FFH ; CONTINUE IF NO CHAR CPI 'C'-'@' ; ^C? JZ RSTCCP ; RESTART IF SO DB 18H DB TYPE1-$-1 AND 0FFH TYPE3: DCR A ; NO ERROR? JZ RSTCCP ; RESTART CCP CALL PRINT ; PRINT READ ERROR MSG DB 'Read Error',0 TYPE4: CALL DLOGIN ; LOG IN DEFAULT DRIVE JMP ERROR * * PAGING ROUTINES * PAGER COUNTS DOWN LINES AND PAUSES FOR INPUT (DIRECT) IF COUNT EXPIRES * PAGSET SETS LINES/PAGE COUNT * PAGER: LDA PAGCNT ; COUNT DOWN DCR A STA PAGCNT RNZ PUSH H ; SAVE HL PAGER1: MVI C,6 ; DIRECT CONSOLE I/O MVI E,0FFH ; INPUT CALL BDOSB ORA A ; CHAR READY? DB 28H DB PAGER1-$-1 AND 0FFH ; WAIT FOR CHAR CPI 'C'-'@' ; ^C JZ RSTCCP ; RESTART CCP POP H ; RESTORE HL PAGSET: MVI A,NLINES-2 ; GET LINE COUNT STA PAGCNT RET * * CCP SAVE FUNCTION (SAVE) * SAVE: CALL NUMBER ; EXTRACT NUMBER FROM COMMAND LINE PUSH PSW ; SAVE IT CALL SCANER ; EXTRACT FILENAME.TYPE JNZ ERROR ; MUST BE NO '?' IN IT CALL SLOGIN ; LOG IN SELECTED DISK LXI D,FCBDN ; DELETE FILE IN CASE IT ALREADY EXISTS PUSH D CALL DELETE POP D CALL CREATE ; MAKE NEW FILE DB 28H DB SAVE3-$-1 AND 0FFH ; ERROR? XRA A ; SET RECORD COUNT FIELD OF NEW FILE'S FCB STA FCBCR POP PSW ; GET PAGE COUNT MOV L,A ; HL=PAGE COUNT MVI H,0 DAD H ; DOUBLE IT FOR HL=SECTOR (128 BYTES) COUNT LXI D,TPA ; PT TO START OF SAVE AREA (TPA) SAVE1: MOV A,H ; DONE WITH SAVE? ORA L ; HL=0 IF SO DB 28H DB SAVE2-$-1 AND 0FFH DCX H ; COUNT DOWN ON SECTORS PUSH H ; SAVE PTR TO BLOCK TO SAVE LXI H,128 ; 128 BYTES PER SECTOR DAD D ; PT TO NEXT SECTOR PUSH H ; SAVE ON STACK CALL DMASET ; SET DMA ADDRESS FOR WRITE (ADDRESS IN DE) LXI D,FCBDN ; WRITE SECTOR CALL WRITE POP D ; GET PTR TO NEXT SECTOR IN DE POP H ; GET SECTOR COUNT DB 20H DB SAVE3-$-1 AND 0FFH ; WRITE ERROR? DB 18H DB SAVE1-$-1 AND 0FFH ; CONTINUE SAVE2: LXI D,FCBDN ; CLOSE SAVED FILE CALL CLOSE INR A ; ERROR? DB 20H DB SAVE4-$-1 AND 0FFH SAVE3: CALL PRINT DB 'No Space',0 SAVE4: CALL DEFDMA ; SET DMA TO 0080 JMP RSTCCP ; RESTART CCP * * CCP RENAME FILE FUNCTION (REN) * REN: CALL SCANER ; EXTRACT FILE NAME JNZ ERROR ; ERROR IF ANY '?' IN IT LDA TEMPDR ; SAVE CURRENT DEFAULT DISK PUSH PSW CALL SLOGIN ; LOG IN SELECTED DISK CALL SEARF ; LOOK FOR SPECIFIED FILE DB 28H DB REN0-$-1 AND 0FFH ; CONTINUE IF NOT FOUND CALL PRINT DB 'File Exists',0 JMP RENRET REN0: LXI H,FCBDN ; SAVE NEW FILE NAME LXI D,FCBDM MVI B,16 ; 16 BYTES CALL MOVEHD LHLD CIBPTR ; GET PTR TO NEXT CHAR IN COMMAND LINE XCHG ; ... IN DE CALL SBLANK ; SKIP TO NON-BLANK CPI '=' ; '=' OR UNDERSCORE OK DB 28H DB REN1-$-1 AND 0FFH CPI 5FH DB 20H DB REN4-$-1 AND 0FFH REN1: XCHG ; PT TO CHAR AFTER '=' OR UNDERSCORE IN HL INX H SHLD CIBPTR ; SAVE PTR TO OLD FILE NAME CALL SCANER ; EXTRACT FILENAME.TYP TOKEN DB 20H DB REN4-$-1 AND 0FFH ; ERROR IF ANY '?' POP PSW ; GET OLD DEFAULT DRIVE MOV B,A ; SAVE IT LXI H,TEMPDR ; COMPARE IT AGAINST CURRENT DEFAULT DRIVE MOV A,M ; MATCH? ORA A DB 28H DB REN2-$-1 AND 0FFH CMP B ; CHECK FOR DRIVE ERROR MOV M,B DB 20H DB REN4-$-1 AND 0FFH REN2: MOV M,B XRA A STA FCBDN ; SET DEFAULT DRIVE LXI D,FCBDN ; RENAME FILE MVI C,17H ; BDOS RENAME FCT CALL BDOS INR A ; ERROR? -- FILE NOT FOUND IF SO DB 20H DB RENRET-$-1 AND 0FFH REN3: CALL PRNNF ; PRINT NO FILE MSG RENRET: JMP RSTCCP ; RESTART CCP REN4: CALL DLOGIN ; LOG IN DEFAULT DRIVE JMP ERROR * * CCP SET USER NUMBER FUNCTION * MAXUSR EQU 15 ; MAXIMUM USER AREA ACCESSABLE USER: CALL NUMBER ; EXTRACT USER NUMBER FROM COMMAND LINE CPI MAXUSR+1 ; ERROR IF >= MAXUSR JNC ERROR MOV E,A ; PLACE USER NUMBER IN E LDA FCBFN ; CHECK FOR PARSE ERROR CPI ' ' ; =ERROR JZ ERROR CALL SETUSR ; SET SPECIFIED USER JMP RCCPNL ; RESTART CCP (NO DEFAULT LOGIN) * * CLEAR SCREEN ROUTINE FOR CRT TERMINAL * CLS: IF H19 ; CLEAR H19/H89 CRT SCREEN MVI A,ESC ; GET ESCAPE CHAR CALL CONOUT MVI A,'E' ; CLEAR SCREEN CALL CONOUT ENDIF IF HAZE ; CLEAR HAZELTINE 1500 SCREEN MVI A,7EH ; TILDA PREFIX CALL CONOUT MVI A,28 ; CLEAR SCREEN CALL CONOUT ENDIF IF FFTERM MVI A,FF CALL CONOUT ENDIF JMP RCCPNL ; RESTART CCP (NO DEFAULT LOGIN) * * NOT CCP-RESIDENT COMMAND -- PROCESS AS TRANSCIENT * COM: CALL GETUSR ; GET CURRENT USER NUMBER STA TMPUSR ; SAVE IT FOR LATER STA TSELUSR ; TEMP USER TO SELECT LDA FCBFN ; ANY COMMAND? CPI ' ' ; ' ' MEANS COMMAND WAS 'D:' TO SWITCH DB 20H DB COM1-$-1 AND 0FFH ; NOT , SO MUST BE TRANSCIENT OR ERROR LDA TEMPDR ; LOOK FOR DRIVE SPEC ORA A ; IF ZERO, JUST BLANK JZ RCCPNL DCR A ; ADJUST FOR LOG IN STA TDRIVE ; SET DEFAULT DRIVE CALL SETU0D ; SET DRIVE WITH USER 0 CALL LOGIN ; LOG IN DRIVE JMP RCCPNL ; RESTART CCP COM1: LDA FCBFT ; CHECK FOR ERROR IN FCB CPI ' ' ; ERROR IF SO JNZ ERROR * * COMA IS A REENTRY POINT FOR A NON-STANDARD CP/M MODIFICATION * THIS IS THE RETURN POINT FOR WHEN THE .COM FILE IS NOT FOUND THE * FIRST TIME, DRIVE A: IS SELECTED FOR A SECOND STTEMPT * COMA: CALL SLOGIN ; LOG IN SPECIFIED DRIVE IF ANY LXI H,COMMSG ; PLACE 'COM' IN FCB LXI D,FCBFT ; PT TO FILE TYPE CALL MOVHD3 ; MOVE 3 CHARS CALL OPENF ; OPEN COMMAND.COM FILE DB 20H DB COMA1-$-1 AND 0FFH ; ERROR? * ERROR ROUTINE TO SELECT USER 0 IF ALL ELSE FAILS LDA TSELUSR ; GET USER FLAG ORA A ; SET FLAGS DB 28H DB COMA0-$-1 AND 0FFH ; TRY DISK A: IF ALREADY USER 0 XRA A ; SELECT USER 0 MOV E,A STA TSELUSR ; RESET TEMPORARY USER NUMBER CALL SETUSR DB 18H DB COMA-$-1 AND 0FFH ; TRY AGAIN * ERROR ROUTINE TO SELECT DRIVE A: IF DEFAULT WAS ORIGINALLY SELECTED COMA0: LXI H,TEMPDR ; GET DRIVE FROM CURRENT COMMAND XRA A ; A=0 ORA M JNZ COM8 ; ERROR IF ALREADY DISK A: MVI M,1 ; SELECT DRIVE A: DB 18H DB COMA-$-1 AND 0FFH * FILE FOUND -- PROCEED WITH LOAD COMA1: LXI H,TPA ; SET START ADDRESS OF MEMORY LOAD COM2: PUSH H ; SAVE ADDRESS OF NEXT SECTOR XCHG ; ... IN DE CALL DMASET ; SET DMA ADDRESS FOR LOAD LXI D,FCBDN ; READ NEXT SECTOR CALL READ DB 20H DB COM3-$-1 AND 0FFH ; READ ERROR OR EOF? POP H ; GET ADDRESS OF NEXT SECTOR LXI D,128 ; MOVE 128 BYTES PER SECTOR DAD D ; PT TO NEXT SECTOR IN HL LXI D,ENTRY-128 ; ARE WE GOING TO WRITE OVER CCP? MOV A,L ; COMPARE ADDRESS OF NEXT SECTOR (HL) SUB E ; TO START OF CCP (DE) MOV A,H SBB D DB 30H DB PRNLE-$-1 AND 0FFH ; ERROR IF SAME DB 18H DB COM2-$-1 AND 0FFH ; OTHERWISE CONTINUE * LOAD ERROR PRNLE: CALL PRINT DB 'Bad Load',0 JMP RSTCCP COM3: POP H ; LOAD COMPLETE! DCR A DB 20H DB PRNLE-$-1 AND 0FFH CALL RESETUSR ; RESET CURRENT USER NUMBER ; USER MUST BE SET BEFORE LOGIN IS DONE CALL DLOGIN ; LOG IN DEFAULT DRIVE CALL SCANER ; SEARCH COMMAND LINE FOR NEXT TOKEN LXI H,TEMPDR ; SAVE PTR TO DRIVE SPEC PUSH H MOV A,M ; SET DRIVE SPEC STA FCBDN MVI A,10H ; OFFSET FOR 2ND FILE SPEC CALL SCAN1 ; SCAN FOR IT AND LOAD IT INTO FCBDN+16 POP H ; SET UP DRIVE SPECS MOV A,M STA FCBDM XRA A STA FCBCR LXI D,TFCB ; COPY TO DEFAULT FCB LXI H,FCBDN ; FROM FCBDN MVI B,33 ; SET UP DEFAULT FCB CALL MOVEHD LXI H,CIBUFF COM4: MOV A,M ; SKIP TO END OF 2ND FILE NAME ORA A ; END OF LINE? DB 28H DB COM5-$-1 AND 0FFH CPI ' ' ; END OF TOKEN? DB 28H DB COM5-$-1 AND 0FFH INX H DB 18H DB COM4-$-1 AND 0FFH * LOAD COMMAND LINE INTO TBUFF COM5: MVI B,0 ; SET CHAR COUNT LXI D,TBUFF+1 ; PT TO CHAR POS COM6: MOV A,M ; COPY COMMAND LINE TO TBUFF STAX D ORA A ; DONE IF ZERO DB 28H DB COM7-$-1 AND 0FFH INR B ; INCR CHAR COUNT INX H ; PT TO NEXT INX D DB 18H DB COM6-$-1 AND 0FFH * RUN LOADED TRANSCIENT PROGRAM COM7: MOV A,B ; SAVE CHAR COUNT STA TBUFF CALL CRLF ; NEW LINE CALL DEFDMA ; SET DMA TO 0080 CALL SETUD ; SET USER/DISK CALL TPA ; RUN TRANSCIENT CALL SETU0D ; SET USER 0/DISK CALL LOGIN ; LOGIN DISK JMP RESTRT ; RESTART CCP * TRANSCIENT LOAD ERROR COM8: CALL RESETUSR ; RESET CURRENT USER NUMBER ; RESET MUST BE DONE BEFORE LOGIN CALL DLOGIN ; LOG IN DEFAULT DISK JMP ERROR * RESET SELECTED USER NUMBER IF CHANGED RESETUSR: LDA TMPUSR ; GET OLD USER NUMBER MOV E,A ; PLACE IN E JMP SETUSR ; RESET * FILE TYPE FOR COMMAND COMMSG: DB 'COM' * ENTRY POINT FOR RESTARTING CCP AND LOGGING IN DEFAULT DRIVE RSTCCP: CALL DLOGIN ; LOG IN DEFAULT DRIVE * ENTRY POINT FOR RESTARTING CCP WITHOUT LOGGING IN DEFAULT DRIVE RCCPNL: CALL SCANER ; EXTRACT NEXT TOKEN FROM COMMAND LINE LDA FCBFN ; GET FIRST CHAR OF TOKEN SUI ' ' ; ANY CHAR? LXI H,TEMPDR ORA M JNZ ERROR JMP RESTRT RNGSUB: DB 0 ;0=$$$.SUB NOT PRESENT, ELSE $$$.SUB PRESENT * * FILE CONTROL BLOCK (FCB), ONE * SUBFCB: DB 0 ;DISK NAME DB '$$$' ;FILE NAME DB ' ' DB 'SUB' ;FILE TYPE DB 0 ;EXTENT NUMBER DB 0 ;S1 SUBFS2: DS 1 ;S2 SUBFRC: DS 1 ;RECORD COUNT DS 16 ;DISK GROUP MAP SUBFCR: DS 1 ;CURRENT RECORD NUMBER * * FILE CONTROL BLOCK * FCBDN: DS 1 ;DISK NAME FCBFN: DS 8 ;FILE NAME FCBFT: DS 3 ;FILE TYPE DS 1 ;EXTENT NUMBER DS 2 ;S1 AND S2 DS 1 ;RECORD COUNT FCBDM: DS 16 ;DISK GROUP MAP FCBCR: DS 1 ;CURRENT RECORD NUMBER * OTHER BUFFERS PRFLG: DB 0 ;PRINTER FLAG (0=NO, 0FFH=YES) PAGCNT: DB NLINES-2 ;LINES LEFT ON PAGE IORESL: DB 0 ;I/O RESULTS TDRIVE: DB 1 ;TEMP DRIVE NUMBER TEMPDR: DB 0 CHRCNT: DB 0 ;CHAR COUNT FOR TYPE TMPUSR: DB 0 ;TEMPORARY USER NUMBER FOR COM TSELUSR: DB 0 ;TEMPORARY SELECTED USER NUMBER END OK