; PPIP-7.Z80 ; <<7>> Console I/O module ;----------------------------------------------------------------------- ; Editor subroutine ; Entry: HL = buffer address ; BUFRECS should be preset to max. no. of records we'll accept ; Return: BC = number of records to write from buffer ; all registers used EDIT: LD C,0 ; Initialize Console line position LD B,RECSZ ; Initialize Bytes-left-in-record LD DE,1 ; Initialize recorD count ; Main edit loop EDLUP: CALL DCONIN ; Get a character EDLUP0: CP TRIGGER ; Case: trigger JP Z,CTLCHR CP BS ; Case: backspace JP Z,EDRUB CP RUB ; Case: rubout JP Z,EDRUB CP CR ; Case: carriage return JP Z,EDCRLF CP EOF ; Case: end edit JP Z,EDDUN EDLUP1: CALL EDOUT ; Default: output the character to console JP Z,EDDUN ; Quit now if end of buffer EDLUP2: CALL EDSAVE ; Save it in memory JP NZ,EDLUP ; Repeat if not end of buffer EDDUN: LD A,B ; Get pad count in Acc. EDDN1: LD (HL),EOF ; Pad one (always) INC HL ; Bump buffer pointer DEC A ; Decrement pad count JP NZ,EDDN1 ; And loop until done LD B,D ; Put record count in BC LD C,E RET ; And return ; Handle an embedded ("triggered") control character CTLCHR: CALL DCONIN ; Get another character CALL TOUPPER ; Convert to upper case CP '@' JP C,CTLNOT ; Not control if < '@' CP '_'+1 JP NC,CTLNOT ; And not control if > '_' SUB 040H ; Subtract offset to get real ctl. char JP EDLUP1 ; And back into main loop CTLNOT: CP TRIGGER ; Not control - is it the trigger again ? JP Z,EDLUP1 ; YES - ok we'll take it this time JP EDLUP0 ; Else process as a new character ; Edit output routine - expects character in Acc. ; Returns zero if end of buffer. EDOUT: PUSH DE ; Free-up a register LD E,A ; And save a copy of the character CP ' ' ; Is it a control character ? JP NC,EDOUT1 ; NO - move on PUSH AF ; Else save the control character LD A,'^' ; And send a carat CALL TYPE POP AF ; Retrieve the character INC C ; And increment console position ADD A,040H ; Make it printable EDOUT1: CALL TYPE ; Type it IF ZCPR3 LD A,(ZSWID) LD D,A DEC D ENDIF ; ZCPR3 INC C ; Increment console line pointer LD A,C ; And get it in Acc. IF NOT ZCPR3 CP SWID-1 ; Are we at or past the end of con: line? ENDIF ; NOT ZCPR3 IF ZCPR3 CP D ENDIF ; ZCPR3 JP C,EDOUT2 ; NO - then go check if we're close yet LD A,E ; Else get the character CALL EDSAVE ; Save it JP Z,EDOUT4 ; Quit now if end of buffer JP EDOUT3 ; Else force next line EDOUT2: IF NOT ZCPR3 CP SWID-10 ; Are we even close to the end of line? ENDIF ; NOT ZCPR3 IF ZCPR3 DEC D DEC D DEC D DEC D DEC D DEC D DEC D DEC D DEC D CP D ENDIF ; ZCPR3 LD A,E ; In any event, get the character back JP C,EDOUT4 ; And done if not close to end of line CP ' ' ; Else, was the character a space JP NZ,EDOUT4 ; NO - then we're done EDOUT3: LD A,CR ; Else force newline by sending a CR CALL TYPE LD C,0 ; Zero the console line position CALL EDSAVE ; Save the CR JP Z,EDOUT4 ; Quit if buffer full LD A,LF ; Then send a LF CALL TYPE ; (LF will still be in Acc. on return) EDOUT4: POP DE ; Restore caller's register RET ; And curtain ; Save a character in the buffer and check buffer limits. Returns ; with zero set if the end of the buffer has been reached. Rings bell ; if five or fewer characters remain. EDSAVE: LD (HL),A ; Put the character in buffer INC HL ; Bump buffer pointer DEC B ; Decrement bytes left in this record LD A,B ; If bytes left = 0 OR A JP NZ,EDSAV1 LD B,RECSZ ; Then bytes left = one whole record INC DE ; And bump record count up EDSAV1: PUSH DE ; Save record count PUSH HL ; And buffer pointer LD HL,(BUFRECS) ; Max. records in HL, record count in DE CALL SUB16 ; Find difference POP HL ; Restore bufptr POP DE ; Restore bytes-count RET NZ ; Return if records < > max. (non-zero) LD A,5 ; Return if more than 5 characters left CP B RET C ; (non-zero) LD A,BELL ; Else ring bell CALL TYPE LD A,1 ; More than 1 character left ? CP B RET ; (zero set if only one character left) ; Do a rubout EDRUB: CALL EDRUB0 ; Do the rubout JP EDLUP ; And re-enter the loop EDRUB0: LD A,C ; Can't move past beginning of line OR A ; So if line count = 0 RET Z ; Then return now DEC HL ; Else move buffer pointer back LD A,(HL) ; Take a look at the character there CP ' ' ; Is it a control character? JP NC,EDRUB1 ; NO - then skip this next bit CALL EDERAS ; Else erase an extra character from scrn. DEC C ; And decrement console position EDRUB1: CALL EDERAS ; Erase character from screen DEC C ; Console position goes back one INC B ; Add one more byte to record LD A,B ; Get result in Acc. CP RECSZ+1 ; Test for overflow (more than RECSZ bytes) RET C ; Return if ok LD B,1 ; Else bytes left = 1 DEC DE ; And decrement record count RET ; Do a carriage return and add a line feed EDCRLF: CALL EDCLF0 ; Do the cr/lf JP Z,EDDUN ; Quit if out of memory JP EDLUP ; Else back to top of loop EDCLF0: LD A,CR ; Get a CR CALL TYPE ; Type it LD C,0 ; Zero the line position CALL EDSAVE ; And save the CR RET Z ; Done if end of buffer LD A,LF ; Else get an LF CALL TYPE ; Type it, too JP EDSAVE ; And save it (EDSAVE: does the return) ; Erase a character from the screen (destructive backspace) EDERAS: CALL ILPRT DB BS,' ',BS,0 RET ; Direct console input - waits for character DCONIN: PUSH BC ; Save all PUSH DE PUSH HL DCNIO1: LD E,0FFH ; Get status/character LD C,DCONIO ; From bdos CALL 5 OR A JP Z,DCNIO1 ; Loop until a character arrives AND 07FH ; Then mask parity on it POP HL ; Restore all POP DE POP BC RET ; Return to caller ;----------------------------------------------------------------------- ; In-Line PRinT routine ; ; Entry: Stack: ; Return: All registers except PSW are preserved. ILPRT: EX (SP),HL ; Stack points to message so put in HL CALL PRINT ; Print it EX (SP),HL ; HL has return address so put it on stack RET ; And get old HL back, and done. ;----------------------------------------------------------------------- ; Print a string ; ; Entry: HL = pointer to ZERO TERMINATED string ; Return: HL is incremented. PSW destroyed. Rest preserved. PRINT: LD A,(HL) ; Get a character INC HL ; Point to next OR A ; Test for zero RET Z ; Return if zero CALL TYPE ; Else type the character JP PRINT ; And repeat ;----------------------------------------------------------------------- ; Type the character on the console ; ; Entry: Acc. = character ; Return: All registers are preserved. TYPE: PUSH BC ; Save all PUSH DE PUSH HL PUSH AF LD E,A ; Cp/m wants char. in E LD C,CONOUT ; Do function CALL BDOS POP AF POP HL ; Restore all POP DE POP BC RET ; Done ;----------------------------------------------------------------------- ; Query the user about file deletion. ; Entry: none ; Return: CARRY SET if file is NOT to be deleted. QDELET: CALL ILPRT ; Query user about file deletion DB ' Delete? ',0 CALL GETKEY ; Get an answer CALL TOUPPER ; Convert to upper case CP 'Y' ; Was the answer 'Y'es ? RET Z ; Return if so SCF ; Else set carry RET ; And return ;----------------------------------------------------------------------- ; Print a carriage return/line feed combination on console ; Entry: none ; Return: All registers preserved. NEWLINE: PUSH AF ; Save caller's Acc/status CALL ILPRT ; Send it DB CR,LF,0 POP AF ; Restore RET ; And that's it ;----------------------------------------------------------------------- ; Wait for and get a character from the console ; Entry: none ; Return: Acc. = character ; Other registers preserved GETKEY: PUSH BC PUSH DE PUSH HL LD C,CONIN CALL BDOS POP HL POP DE POP BC RET ;----------------------------------------------------------------------- ; Get console status ; Entry: none ; Return: ZERO flag SET if NOT ready ; All registeres except PSW are preserved ; KEYPRESS: PUSH BC PUSH DE PUSH HL LD C,CONSTAT CALL BDOS OR A POP HL POP DE POP BC RET ;----------------------------------------------------------------------- ; Output a 4-digit hex number ; Entry: HL = number to output ; Return: None ; all registers preserved DHXOUT: PUSH HL ; Save regs PUSH AF LD A,H ; Get MSB CALL HEXO ; Send it LD A,L ; Get LSB CALL HEXO ; Send it POP AF POP HL ; Restore RET ; That's it ;----------------------------------------------------------------------- ; Output one hex byte to the console ; ; Entry: Acc. = byte to output ; Return: none ; PSW destroyed, other registers unaffected HEXO: PUSH AF ; Save original digit RRA ; Roll high nybble into low nybble RRA RRA RRA CALL NYBBLE ; And send it POP AF ; Restore original (to do low part) NYBBLE: AND 0FH ; Mask out the high nybble CP 10 ; Is it < 10? JP C,DIGOUT ; YES - ready to send digit ADD A,7 ; Else, add alpha offset DIGOUT: ADD A,'0' ; Add ASCII offset CALL TYPE ; And send it to the console RET ; end of console I/O module ;-----------------------------------------------------------------------