TITLE 'CP/M Console Command Processor (CCP) Vers 2.2' ; Refer to CCP 1.4 disassembly listing for comments ; This current file is not completely commented. FALSE EQU 0 TRUE EQU NOT FALSE ABORT$LOC EQU 0F000H PAGE1$DRV EQU 04H BDOS EQU 05H TPA EQU 100H ACR EQU 0DH ALF EQU 0AH UC$MASK EQU 5FH BIAS EQU 40H DEF$DMA$LOC EQU 80H REC$LENGTH EQU 80H TRANS$FCB EQU 5CH SECOND$NAME EQU TRANS$FCB+10H NAME$OFFSET EQU 01 TYPE$OFFSET EQU 09 ATTR$OFFSET EQU 10 NAME$LEN EQU 08 TYPE$LEN EQU 03 CPM$EOF EQU 1AH ; The following 'REL' equates are to allow generation ; of page 0 and page 1 .HEX files, used to create ; relocation bit tables in programs like MOVCPM.COM REL EQU TRUE ; set true to generate relocatable code IF REL CCPBIAS EQU 0 ; set 0 for "0K" system ENDIF IF NOT REL MSIZE EQU 56 ; current memory configuration CCPBIAS EQU (MSIZE-20)*1024+2D00H ; starting address of CCP ENDIF ; CCP starts here ORG CCPBIAS CCP$LEN EQU 800H BDOS$START EQU $+CCP$LEN CCP: JMP START ; cold entry point to CCP JMP ALT$START ; warm entry point to CCP ; CCP command buffer MAX$LN: DB 7FH ; maximum buffer capacity CHARS$TYPED: DB 0 ; number char's typed CON$BUF: ; command buffer starts here DB ' ' DB 'COPYRIGHT (C) 1979, DIGITAL RESEARCH ' DS 4AH ; ; Next 2 labels are storage loc'ns used to ; temporarily store the loc'n of the next ; char in the console buffer to be processed. ; NXTCHR: DW CON$BUF NEXT1: DW 0000 ; ; Send character in to console output ; PUT$CON: MOV E,A MVI C,2 JMP BDOS ; ; Save and send char in to console ; PUT1$CON: PUSH B CALL PUT$CON POP B RET ; ; Send CR, LF to Console ; CRLF: MVI A,ACR CALL PUT1$CON MVI A,ALF JMP PUT1$CON ; ; Send blank to console ; SPACE: MVI A,' ' JMP PUT1$CON ; ; Precede ascii string print with crlf ; PUT$MSG: PUSH B CALL CRLF POP H ; ; Send Ascii string to console ; Address of string in ; String terminated by 0 ; PUT1$MSG: MOV A,M ORA A RZ INX H PUSH H CALL PUT$CON POP H JMP PUT1$MSG ; ; Initialize BDOS, selects drive 'A' and ; sets dma address to 80H ; Reset Disk System ; INIT$BDOS: MVI C,0DH JMP BDOS ; ; Log in and select drive no. passed in ; LOG$ACC:MOV E,A MVI C,0EH JMP BDOS ; ; Call to BDOS, =dir/err code ; BDOS$R: CALL BDOS STA DIR$ADDR ; save byte address in directory ; of fcb at location INR A ; set zero flag if 0FFH returned RET ; ; Open File =dir Code ; =fcb ; OPEN$FILE: MVI C,0FH JMP BDOS$R ; ; Routine opens file, fcb=default fcb ; of ccp ; OPEN$CCP: XRA A ; set next record.. STA CCP$FCB$NXT$REC ; .. equal to zero LXI D,CCP$FCB JMP OPEN$FILE ; ; Close File =dir Code ; =fcb ; CLOSE$FIL: MVI C,10H JMP BDOS$R ; ; Search for first =dir Code ; =fcb ; SEARCH: MVI C,11H JMP BDOS$R ; ; Search for next ; =fcb ; SEARCH$NXT: MVI C,12H JMP BDOS$R ; ; Search directory for next occurrance of ; file whose fcb address in ; FIND$CCP: LXI D,CCP$FCB JMP SEARCH ; ; Delete File =fcb ; =dir Code ; DELETE$FIL: MVI C,13H JMP BDOS ; ; Call BDOS, =return code ; BDOS$E: CALL BDOS ORA A ; set flags RET ; ; Read next record =err code ; =fcb ; READ$NXT: MVI C,14H JMP BDOS$E ; ; Read next record of file in default fcb ; READ$CCP: LXI D,CCP$FCB JMP READ$NXT ; ; Write next =err code ; =fcb ; WRITE$NXT: MVI C,15H JMP BDOS$E ; ; Make file =dir code ; =fcb ; MAKE$FILE: MVI C,16H JMP BDOS$R ; ; Rename file =dir code ; =fcb ; REN$FIL: MVI C,17H JMP BDOS ; ; Get/Set user code ; =0ffh (get) ; =user code (set) ; =current code ; GETUSR: MVI E,0FFH ; set =0FFH to get user no. SETUSR: MVI C,20H ; set =function number JMP BDOS ; ; Get current user number and shift up to high nybble, ; logically OR with current drive, and save this in ; location 4 for system use. ; SET4: CALL GETUSR ; get current user code ADD A ; *2 ADD A ; *4 ADD A ; *8 ADD A ; *16 (shift left 8 bits) LXI H,CUR$DRV ; get current drive no. ORA M ; OR with user code STA PAGE1$DRV ; and save it for system use RET ; ; Get current drive no. and save it in 4 ; INIT4: LDA CUR$DRV ; get current drive no. STA PAGE1$DRV ; store in 4 RET ; ; Convert lower case alpha character to UPPER ; UPRCASE:CPI 61H ; return if already RC ; upper case CPI 7BH RNC ANI 5FH ; make UPPER case RET ; ; If no submit is in progress, this routine will get ; a new command line from the console, convert it to ; upper case, put a null char at the end, and initialize ; next$char to point to start of console buffer. ; ; If a submit is in progress, the next record of the submit ; file is loaded into the console buffer and executed as a ; command string. ; GET$CMD: LDA STK$TOP ; get submit status flag ORA A ; set flags JZ FIL$BUF ; no submit in progress, get cmd string LDA CUR$DRV ; get current drive ORA A ; set flags MVI A,0 ; set A=0 without changing flags CNZ LOG$ACC ; make drive A if not already A LXI D,SUB$FCB ; point to $$$.SUB fcb CALL OPEN$FILE ; open the submit file JZ FIL$BUF LDA SUB$REC$CNT ; get current record count DCR A ; in current extent, decrement it STA SUB$FCB$NXT$REC ; ..save it as next record to read LXI D,SUB$FCB ; point to $$$.SUB fcb again CALL READ$NXT ; read next record JNZ FIL$BUF ; if not zero, then error, so get ; command string from console buffer LXI D,CHARS$TYPED ; point to console buffer LXI H,DEF$DMA$LOC ; source DEFAULT buffer MVI B,REC$LENGTH ; 128 bytes CALL MOV$HL2DE ; move sector just read to console ; buffer LXI H,SUB$FCB+10H MVI M,0 INX H DCR M LXI D,SUB$FCB CALL CLOSE$FIL ; CLOSE the file JZ FIL$BUF LDA CUR$DRV ; get current drive ORA A ; set status CNZ LOG$ACC ; reset if not A LXI H,CON$BUF CALL PUT1$MSG ; print the command CALL GET$IF ; check for key depression JZ CONV$BUF ; no, go execute contents of buffer CALL CLR$SUB ; abort--clear pending submit JMP PROMPT ; go sign on again ; ; Clear any submit in progress and get a command string from ; the console ; FIL$BUF: CALL CLR$SUB ; terminate any active submit file CALL SET4 MVI C,0AH ; read console buffer LXI D,MAX$LN ; point to max buffer length CALL BDOS CALL INIT4 ; ; Convert the command string into upper case ; CONV$BUF: LXI H,CHARS$TYPED ; point to number of chars typed MOV B,M ; put value in CONV1$BUF: INX H ; point to next char in buffer MOV A,B ; get count in acc ORA A ; set the flags JZ END$CONV ; if finished, then jump MOV A,M ; get next char in acc CALL UPRCASE ; convert to UC as required MOV M,A ; put it back DCR B ; bump the count JMP CONV1$BUF ; loop til finished ; ; Put a null at the end of the command string and set the ; value of NEXT$CHAR equal to the start of the buffer ; END$CONV: MOV M,A ; if we got here, acc = 0 ; put 0 into the buffer to show end LXI H,CON$BUF ; point to start of buffer SHLD NXTCHR ; save it as next character RET ; ; Get a console character if one is waiting, ; otherwise return with zero set. ; GET$IF: MVI C,0BH ; get console status CALL BDOS ORA A ; set status bits RZ ; not ready if zero MVI C,1 ; was ready, so get CALL BDOS ; a console character ORA A ; and set status bits RET ; ; Return current logged in drive number from BDOS ; GET$DRV: MVI C,19H JMP BDOS ; ; Set DMA to default buffer ; SET$DEF$DMA: LXI D,DEF$DMA$LOC ; default dma location ; ; Set DMA address =dma address ; SET$DMA: MVI C,1AH JMP BDOS ; ; Routine terminates any submit sequence ; which may be in progress ; CLR$SUB: LXI H,STK$TOP ; point to submit flag MOV A,M ; --> ORA A ; set flags RZ ; return if zero MVI M,0 ; ..else set to zero XRA A ; = 0 CALL LOG$ACC ; log in drive 0 LXI D,SUB$FCB ; point to submit fcb CALL DELETE$FIL ; delete it LDA CUR$DRV ; log on.. JMP LOG$ACC ; ..current drive ; ; Compare CCP and BDOS serial numbers ; CHK$SN: LXI D,CCP$SN ; point to CCP serial number LXI H,BDOS$START ; point to BDOS serial number MVI B,6 ; count = 6 CHK1$SN: LDAX D ; next CCP # to acc CMP M ; compare to JNZ GET$LOST ; if not the same get lost INX D ; bump CCP pointer INX H ; bump BDOS pointer DCR B ; decrement count JNZ CHK1$SN ; loop until all checked RET ; ..finished, then AOK ; ; Echo the console buffer until a space or null (end of buffer) ; is encountered, then execute the ERR$SYMB routine below ; ECHO$BUF: CALL CRLF ; get a new line LHLD NEXT1 ; point to next char ECHO1$BUF: MOV A,M ; get char in acc CPI ' ' ; if it is a space, JZ ERR$SYMB ; then exit ORA A ; set the flags JZ ERR$SYMB ; if 00, exit also PUSH H ; save pointer CALL PUT$CON ; show the character POP H ; get back pointer INX H ; bump the pointer JMP ECHO1$BUF ; loop till done ; ; Print the error symbol ("?"), clear any submit in progress, ; then re-prompt the user ; ERR$SYMB: MVI A,'?' ; get char in acc CALL PUT$CON ; display it CALL CRLF ; get new line CALL CLR$SUB ; clear any submit in progress JMP PROMPT ; go print another prompt ; ; Test char at for reserved characters 'SPACE', ; 'EQUALS', 'UNDERLINE', 'PERIOD', 'COLON', 'SEMI-COLON', ; 'LEFT-ARROW', 'RIGHT-ARROW', and return with zero set, ; if found. If the character is less than an ascii SPACE, ; and exit is made to the ECHO$BUF routine which will ; print the error prompt and echo the buffer ; TEST4RES: LDAX D ; get (DE) in acc ORA A ; set the flags RZ ; get back if null CPI ' ' ; is it less than a SPACE? JC ECHO$BUF ; yes, echo buffer and prompt RZ ; if ' ', then get back CPI '=' RZ ; if '=', get back CPI '_' RZ ; if '_', get back CPI '.' RZ ; if '.', get back CPI ':' RZ ; if ':', get back CPI ';' RZ ; if ';', get back CPI '<' RZ ; if '<', get back CPI '>' RZ ; if '>', get back RET ; ; Search the character string pointed by until ; a non-blank char or null is found. If a null is ; found, return with ZERO flag set. Otherwise return ; with the char in the acc and pointing to it. ; (null is placed at end of command string by convert ; routine) ; NON$BLNK: LDAX D ; get next char ORA A ; set flags RZ ; get back if null CPI ' ' ; is it a space? RNZ ; no, then get back INX D ; bump the pointer JMP NON$BLNK ; loop ; ; Add the contents of acc to HL ; ADD$ACC: ADD L MOV L,A RNC INR H RET ; ; Entry point to MAKE$FCB when destination is to ; be the start of CCP$FCB ; MAKE$FCB: MVI A,0 ; ; Create a FCB in CCP$FCB with the displacement in the ; accumulator. (Used to put the second name in fcb when ; acc = 10H). On return the flags are set and the acc ; contains the number of ambigious chars in the name.type. ; 'NEXT$CHAR' is saved pointing to the next character ; following the string set up as a file NAME.TYPE. ; ; For example, the SAVE command finds the ascii string ; corresponding to the number of decimal records to write ; as a file name in the first 16 bytes of the fcb, and ; the name of the file to created in the second 16 bytes ; of the fcb. ; MAKE1$FCB: LXI H,CCP$FCB ; point to ccp's fcb CALL ADD$ACC ; add displacement in acc PUSH H ; save char pointer once PUSH H ; and then again XRA A ; set acc = zero STA NEW$DRV$PLUS ; This location is set by 'YES$DRV' to ; the binary value of the drive number ; in the command buffer plus 1. ; This is so we can test for zero to ; determine if a new drive has been ; specified, even if the new drive is ; drive number zero LHLD NXTCHR ; get pointer to next char in buffer XCHG ; put buffer pointer in CALL NON$BLNK ; get next non-blank char in acc ; DE points to its location XCHG ; HL now points to next non-blank ; character in console buffer SHLD NEXT1 XCHG POP H LDAX D ORA A JZ NO$DRV SBI '@' MOV B,A INX D LDAX D CPI ':' JZ YES$DRV DCX D NO$DRV: LDA CUR$DRV MOV M,A JMP GET$NAME ; YES$DRV: MOV A,B STA NEW$DRV$PLUS MOV M,B INX D ; ; The next 8 characters in the CCP$FCB are to be a file ; name. Transfer the contents of the CON$BUF, checking ; for reserved characters and ambigious name char ('*' or '?') ; filling with blanks or '?' as required. ; GET$NAME: MVI B,8 GET1$NAME: CALL TEST4RES JZ FIL$SPC INX H CPI '*' JNZ NOT$AMB MVI M,3FH JMP KEEP$CNT ; NOT$AMB: MOV M,A INX D KEEP$CNT: DCR B JNZ GET1$NAME FIND$RES: CALL TEST4RES JZ PUT$TYPE INX D JMP FIND$RES ; FIL$SPC: INX H MVI M,' ' DCR B JNZ FIL$SPC ; ; The next three characters in the CCP$FCB are to be the ; file type. Transfer the contents of CON$BUF checking ; for reserved characters and ambigious characters ('*' or '?') ; Fill with '?'s as required. ; PUT$TYPE: MVI B,3 CPI '.' JNZ FIL2$SPC INX D PUT2$TYPE: CALL TEST4RES JZ FIL2$SPC INX H CPI '*' JNZ XFER$TYPE MVI M,'?' JMP KEEP2$CNT ; XFER$TYPE: MOV M,A INX D KEEP2$CNT: DCR B JNZ PUT2$TYPE ; ; We have a FILENAME.TYPE, so now find the next reserved ; character in the command string so we can save NEXT$CHAR ; below ; FIND1$RES: CALL TEST4RES JZ FILL$NULL INX D JMP FIND1$RES ; FIL2$SPC: INX H MVI M,' ' DCR B JNZ FIL2$SPC ; ; Set the file extent (byte 12 of fcb) and the ; unused bytes (13 and 14) of the fcb to zero ; FILL$NULL: MVI B,3 FILL1$NULL: INX H MVI M,0 DCR B JNZ FILL1$NULL ; ; We are almost finished. Save pointer of the next character ; in the console buffer, count the number of ambigious char's ; in the filename.type, and return with the count in acc and ; the flags set ; XCHG SHLD NXTCHR POP H LXI B,0BH NUM$AMB: INX H MOV A,M CPI '?' JNZ SKIP$BUMP INR B SKIP$BUMP: DCR C JNZ NUM$AMB MOV A,B ORA A RET ; ; Valid names of resident CCP commands ; CMD$NAME: DB 'DIR ' DB 'ERA ' DB 'TYPE' DB 'SAVE' DB 'REN ' DB 'USER' ; ; CCP Serial Number and Version ; CCP$SN: DB 00,00 ; type & version number DB 00,00,00,00 ; serial number ; ; Search for CP/M command ; Return =index to vector table ; LOOK$CMD: LXI H,CMD$NAME ; get addr of ccp commands MVI C,0 ; preset counter LOOK2$CMD: MOV A,C ; get counter CPI 6 ; finished? RNC ; yes, if no match after 6 bytes LXI D,CCP$FCB+1 MVI B,4 LOOK1$CMD: LDAX D CMP M JNZ FAIL INX D INX H DCR B JNZ LOOK1$CMD LDAX D CPI ' ' JNZ TRY$AGN MOV A,C RET ; FAIL: INX H DCR B JNZ FAIL TRY$AGN: INR C JMP LOOK2$CMD ; ; If entered here, set the command string length to zero ; to avoid executing whatever may be in the buffer ; ALT$START: XRA A ; set command length STA CHARS$TYPED ; to zero ; ; Normal entry point to CCP. Initialize the stack, initialize ; the BDOS, log-in the drive number which was in register C ; upon entry, go see if a submit is in progress (if INIT$BDOS ; returns 0FFH in acc and drive to log-in is zero, then a submit ; is taking place), and finally see if CHARS$TYPED is non-zero ; (if non-zero a command string waits, so go do it) ; START: LXI SP,STK$TOP ; init stack PUSH B ; save entry parm MOV A,C ; get user/drive parm RAR ; get high order nibble RAR ; moved into low nibble RAR RAR ANI 0FH ; strip off high 8 bits MOV E,A CALL SETUSR ; and set it CALL INIT$BDOS ; reset the disk system STA STK$TOP POP B ; pop entry parm MOV A,C ; get user/drive code ANI 0FH ; strip off high nibble STA CUR$DRV ; and save it in locn 4 CALL LOG$ACC ; select the drive LDA CHARS$TYPED ; check if command buffer ORA A ; has anything in it JNZ DO$CMD ; if so, goto DO$CMD ; ; Prompt the user and get a command string ; PROMPT: LXI SP,STK$TOP CALL CRLF ; new line CALL GET$DRV ADI 'A' ; add ascii bias CALL PUT$CON ; print current disk MVI A,'>' ; print arrow prompt CALL PUT$CON CALL GET$CMD ; ; Execute the command string in the console buffer ; DO$CMD: LXI D,DEF$DMA$LOC ; set default DMA address CALL SET$DMA CALL GET$DRV ; get current disk STA CUR$DRV ; store it CALL MAKE$FCB CNZ ECHO$BUF LDA NEW$DRV$PLUS ORA A JNZ USERCOMMAND CALL LOOK$CMD ; check if non-transient command LXI H,JMP$TBL ; get table address MOV E,A ; and command index MVI D,0 DAD D DAD D ; and compute position in table MOV A,M INX H MOV H,M MOV L,A PCHL ; go do it! ; ; Address table to resident CCP commands ; and to the user command routine ; JMP$TBL: DW DIRECTORY DW ERASE DW TYPE DW SAVE DW RENAME DW USER DW USERCOMMAND ; ; Write a permanent error jump at the entry ; point to the CCP and then exit ; GET$LOST: LXI H,ABORT$LOC SHLD CCP+1 LXI H,CCP PCHL ; ; Display read error message ; DO$RERR: LXI B,RERR$MSG ; get string address JMP PUT$MSG ; RERR$MSG: DB 'READ ERROR',0 ; ; Display 'NO FILE' error message ; DO$NFERR: LXI B,NFERR$MSG JMP PUT$MSG ; NFERR$MSG: DB 'NO FILE',0 ; ; Calculate binary number of records (256 bytes each) ; to be written by the SAVE command (return with the ; count in ) ; CALC$BIN$SEC: CALL MAKE$FCB LDA NEW$DRV$PLUS ORA A JNZ ECHO$BUF LXI H,CCP$FCB+1 LXI B,0BH CALC$LOOP: MOV A,M CPI ' ' JZ CONFIRM$SPC INX H SUI '0' CPI 0AH JNC ECHO$BUF MOV D,A MOV A,B ANI 0E0H JNZ ECHO$BUF MOV A,B RLC RLC RLC ADD B JC ECHO$BUF ADD B JC ECHO$BUF ADD D JC ECHO$BUF MOV B,A DCR C JNZ CALC$LOOP RET ; ; Confirm that only spaces remain following the number ; of records to be saved (the ascii number of decimal ; records was set up in the fcb by MAKE$FCB as if it ; were a filename) ; CONFIRM$SPC: MOV A,M CPI ' ' JNZ ECHO$BUF INX H DCR C JNZ CONFIRM$SPC MOV A,B RET ; ; If entered here, routine will move 3 characters from ; address in to address in ; MOV3$HL2DE: MVI B,3 ; set for 3 bytes ; ; Move routine: ; Source addr=, Destination addr= ; Number of bytes to move in ; MOV$HL2DE: MOV A,M ; get source byte STAX D ; move to dest INX H ; bump source addr INX D ; bump dest addr DCR B ; bump byte count JNZ MOV$HL2DE ; continue til finished RET ; ; Get the relative character (acc = offset) from the ; directory entry whose converted byte address is in ; the register (used by DIR command) ; CALC$DIS$GET: LXI H,80H ADD C CALL ADD$ACC MOV A,M RET ; ; Set the entry type of the CCP$FCB equal to ; zero and then execute the LOG$DRV$MYST routine ; SET$ET$DRV: XRA A STA CCP$FCB LDA NEW$DRV$PLUS ORA A RZ DCR A LXI H,CUR$DRV CMP M RZ JMP LOG$ACC ; ; If drive was specified in the command string and if ; the specified drive is different from the ; current drive, go log the current drive back in ; LOG$CUR$DRV: LDA NEW$DRV$PLUS ORA A RZ DCR A LXI H,CUR$DRV CMP M RZ LDA CUR$DRV JMP LOG$ACC ; ; DIRectory command of the Console Command Processor ; DIRECTORY: CALL MAKE$FCB CALL SET$ET$DRV LXI H,CCP$FCB+1 MOV A,M CPI ' ' JNZ FILE$NAME$N$DIR MVI B,0BH PUT$N$DIR: MVI M,'?' INX H DCR B JNZ PUT$N$DIR FILE$NAME$N$DIR: MVI E,0 PUSH D CALL FIND$CCP CZ DO$NFERR DIR$DO$LOOP: JZ FINISH$DIR$CMD LDA DIR$ADDR RRC RRC RRC ANI 60H MOV C,A MVI A,0AH ; get file attribute bit CALL CALC$DIS$GET ; which is MSB of 10th byte RAL ; rotate MSB into CY JC DIR$SKIP$ALL ; don't display if set ($SYS) ; ; Print 4 directory entries per line ; POP D ; get directory entry address MOV A,E ; move LSbyte to acc INR E ; bump the address PUSH D ; push address back on stack ANI 3 ; look at 2 LSbits PUSH PSW ; save this too JNZ PUT$FENCE ; don't print drive unless ; this is 1st filename on line CALL CRLF PUSH B CALL GET$DRV POP B ADI 'A' CALL PUT1$CON MVI A,':' CALL PUT1$CON JMP SKIP$FENCE ; don't print the fence ; ; Print 'Fence' character between filenames ; PUT$FENCE: CALL SPACE MVI A,':' CALL PUT1$CON SKIP$FENCE: CALL SPACE MVI B,1 DIR$NXT$CHAR: MOV A,B CALL CALC$DIS$GET ANI 7FH CPI ' ' JNZ DIR$CON$OUT POP PSW ; get LSbits of address again PUSH PSW ; save them back CPI 3 ; JNZ A61F7 MVI A,9 CALL CALC$DIS$GET ANI 7FH CPI ' ' JZ DIR$KEY$LOOK A61F7: MVI A,' ' DIR$CON$OUT: CALL PUT1$CON INR B MOV A,B CPI 0CH JNC DIR$KEY$LOOK CPI 9 JNZ DIR$NXT$CHAR CALL SPACE JMP DIR$NXT$CHAR ; DIR$KEY$LOOK: POP PSW DIR$SKIP$ALL: CALL GET$IF JNZ FINISH$DIR$CMD CALL SEARCH$NXT JMP DIR$DO$LOOP ; FINISH$DIR$CMD: POP D JMP CMD$END ; ; ERAse file command of the Console Command Processor ; ERASE: CALL MAKE$FCB CPI 0BH JNZ ERASE1 LXI B,ALL$MSG CALL PUT$MSG CALL GET$CMD LXI H,CHARS$TYPED DCR M JNZ PROMPT INX H MOV A,M CPI 'Y' JNZ PROMPT INX H SHLD NXTCHR ERASE1: CALL SET$ET$DRV LXI D,CCP$FCB CALL DELETE$FIL INR A CZ DO$NFERR JMP CMD$END ; ALL$MSG: DB 'ALL (Y/N)?',0 ; ; TYPE file command of the Console Command Processor ; TYPE: CALL MAKE$FCB JNZ ECHO$BUF CALL SET$ET$DRV CALL OPEN$CCP JZ CANT$TYPE CALL CRLF LXI H,REL$BUF$CNT MVI M,0FFH TYPE$DO$LOOP: LXI H,REL$BUF$CNT MOV A,M CPI 80H JC NOT$END PUSH H CALL READ$CCP POP H JNZ TYPE$DONE XRA A MOV M,A NOT$END: INR M LXI H,DEF$DMA$LOC CALL ADD$ACC MOV A,M CPI 1AH JZ CMD$END CALL PUT$CON CALL GET$IF JNZ CMD$END JMP TYPE$DO$LOOP ; TYPE$DONE: DCR A JZ CMD$END CALL DO$RERR CANT$TYPE: CALL LOG$CUR$DRV JMP ECHO$BUF ; ; SAVE file command of the Console Command Processor ; SAVE: CALL CALC$BIN$SEC PUSH PSW CALL MAKE$FCB JNZ ECHO$BUF CALL SET$ET$DRV LXI D,CCP$FCB PUSH D CALL DELETE$FIL POP D CALL MAKE$FILE JZ DISP$NSERR XRA A STA CCP$FCB$NXT$REC POP PSW MOV L,A MVI H,0 DAD H LXI D,TPA WRITE$LOOP: MOV A,H ORA L JZ CLOSE$THE$SAV DCX H PUSH H LXI H,80H DAD D PUSH H CALL SET$DMA LXI D,CCP$FCB CALL WRITE$NXT POP D POP H JNZ DISP$NSERR JMP WRITE$LOOP ; CLOSE$THE$SAV: LXI D,CCP$FCB CALL CLOSE$FIL INR A JNZ FINISH$SAVE ; ; Display the 'NO SPACE' error message, then fall ; through to the close routine and save what we can ; DISP$NSERR: LXI B,NSERR$MSG CALL PUT$MSG FINISH$SAVE: CALL SET$DEF$DMA JMP CMD$END ; NSERR$MSG: DB 'NO SPACE',0 ; ; REName file command of the Console Command Processor ; RENAME: CALL MAKE$FCB JNZ ECHO$BUF LDA NEW$DRV$PLUS PUSH PSW CALL SET$ET$DRV CALL FIND$CCP JNZ CANT$RENAME LXI H,CCP$FCB LXI D,CCP$FCB+10H MVI B,10H CALL MOV$HL2DE LHLD NXTCHR XCHG CALL NON$BLNK CPI '=' JZ RENAME1 CPI 05FH JNZ CANT1$RENAME RENAME1: XCHG INX H SHLD NXTCHR CALL MAKE$FCB JNZ CANT1$RENAME POP PSW MOV B,A LXI H,NEW$DRV$PLUS MOV A,M ORA A JZ CARRY$ON$REN CMP B MOV M,B JNZ CANT1$RENAME CARRY$ON$REN: MOV M,B XRA A STA CCP$FCB CALL FIND$CCP JZ NONE$2$RENAME LXI D,CCP$FCB CALL REN$FIL JMP CMD$END ; NONE$2$RENAME: CALL DO$NFERR JMP CMD$END ; CANT1$RENAME: CALL LOG$CUR$DRV JMP ECHO$BUF ; CANT$RENAME: LXI B,FILE$EXISTS CALL PUT$MSG JMP CMD$END ; FILE$EXISTS: DB 'FILE EXISTS',0 ; ; Load the user command ( .COM file) and ; execute it ; USER: CALL CALC$BIN$SEC CPI 10H JNC ECHO$BUF MOV E,A LDA CCP$FCB+1 CPI ' ' JZ ECHO$BUF CALL SETUSR JMP CMD1$END ; ; Process transient command ; USERCOMMAND: CALL CHK$SN LDA CCP$FCB+1 CPI ' ' JNZ USR1$COM LDA NEW$DRV$PLUS ORA A JZ CMD1$END DCR A STA CUR$DRV CALL INIT4 CALL LOG$ACC JMP CMD1$END ; USR1$COM: LXI D,CCPFCB$TYPE LDAX D CPI ' ' JNZ ECHO$BUF PUSH D CALL SET$ET$DRV POP D LXI H,COM$ASC CALL MOV3$HL2DE CALL OPEN$CCP JZ USR$CMD$EXIT LXI H,TPA GET$IT$ALL: PUSH H XCHG CALL SET$DMA LXI D,CCP$FCB CALL READ$NXT JNZ MAY$B$DONE POP H LXI D,REC$LENGTH DAD D LXI D,CCP MOV A,L SUB E MOV A,H SBB D JNC DISPL$LDERR JMP GET$IT$ALL ; MAY$B$DONE: POP H DCR A JNZ DISPL$LDERR CALL LOG$CUR$DRV CALL MAKE$FCB LXI H,NEW$DRV$PLUS PUSH H MOV A,M STA CCP$FCB MVI A,10H CALL MAKE1$FCB POP H MOV A,M STA CCP$FCB+10H XRA A STA CCP$FCB$NXT$REC ; ; Now, move the whole thing down to the user's file ; control block (He'd never look for it up here) ; LXI D,TRANS$FCB LXI H,CCP$FCB MVI B,21H CALL MOV$HL2DE LXI H,CON$BUF ; ; Now, go find any garbage the user may have typed after ; the file names and transfer it to the user's dma buffer ; FIND$USR$STR: MOV A,M ORA A JZ MOV$USR$STR CPI ' ' JZ MOV$USR$STR INX H JMP FIND$USR$STR ; MOV$USR$STR: MVI B,0 LXI D,81H KEEP$ON: MOV A,M STAX D ORA A JZ GO$DO$USR INR B INX H INX D JMP KEEP$ON ; GO$DO$USR: MOV A,B STA 80H CALL CRLF CALL SET$DEF$DMA CALL SET4 CALL TPA ; ; This is the location to which the user's program will ; return control (if he doesn't overwrite the CCP and ; do a simple re-boot) ; LXI SP,STK$TOP CALL INIT4 CALL LOG$ACC JMP PROMPT ; USR$CMD$EXIT: CALL LOG$CUR$DRV JMP ECHO$BUF ; DISPL$LDERR: LXI B,LDERR$MSG CALL PUT$MSG JMP CMD$END ; LDERR$MSG: DB 'BAD LOAD',0 ; COM$ASC: DB 'COM' ; ; All CCP commands execute this sequence when done to ; verify that the rest of the command buffer is empty ; CMD$END: CALL LOG$CUR$DRV CMD1$END: CALL MAKE$FCB LDA CCP$FCB+1 SUI 20H LXI H,NEW$DRV$PLUS ORA M JNZ ECHO$BUF JMP PROMPT ;------------------------------------------------------------ ; ; CCP stack area ; DS 10H ; STK$TOP:DB 00 ; Also 'submit-in-progress' flag ; ;------------------------------------------------------------ ; ; FCB for submit function of CCP ; SUB$FCB: DB 00 ; Redefined in version 2 as drive ; code (0 - 16) ; 0 => use default drive for file ; 1 => auto disk select drive A, ; 2 => auto disk select drive B, ; ... ; 16=> auto disk select drive P. DB '$$$ SUB' ; Name & Type DB 00 ; Current extent number, normally ; set to 0 by user, but in range ; 0 - 31 during file I/O DB 00 ; S1 - internal system use T64BA: DB 00 ; S2 - internal system use, set to ; zero on call to OPEN, MAKE, SEARCH SUB$REC$CNT: ; Record count in current extent DB 00 ; Disk Allocation Map DB 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 SUB$FCB$NXT$REC: DB 00 ; Next record to read/write ; from/to .SUB file ;------------------------------------------------------------ ; ; CCP File Control Block ; CCP$FCB: DB 00 ; Drive code DB 00,00,00,00,00,00,00,00 ; Name, padded with blanks CCPFCB$TYPE: DB 00,00,00 ; File type, padded with blanks DB 00 ; File extent DB 00 ; S1 - internal system use DB 00 ; S2 - internal system use, set to ; zero on call to OPEN, MAKE, SEARCH DB 00 ; Record count in current extent ; Disk Allocation Map DB 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 CCP$FCB$NXT$REC: DB 00 ; Next record to read/write ; ;------------------------------------------------------------ ; DIR$ADDR: DB 00 CUR$DRV: DB 0 NEW$DRV$PLUS: DB 00 REL$BUF$CNT: DB 00 ; ;------------------------------------------------------------ ; ; Unused space which can be used with caution. Other Digital ; Research software may use this area. ; DS BDOS$START - $ ; ; END