; UKM7(EIN2 replaces UKM7EIN1.COM/HEX/ZSM/DOC) ;This program was originally written in 1977 by Ward ;Christensen. ;Ward's comments were removed, Terminal File, Batch Mode ;and a lot of bugs were added in 1980 by Mark Zeiger and ;James Mills. The CRC checks were added by Paul Hansknecht ;in June 1981. ;Improved terminal file facilities, menus and a general tidy ;up of a very untidy program, removal of all modem dependent ;features, many bugs and adaptation for the UK CP/M Users ;Group Library by David Back. 4 May 1983. ; ;The file exchange protocols have not been altered and are ;generally compatible with the MODEMX series of programs in ;the US CP/M UG Library. ;UKM7 is compatible with CP/M 1.4 and CP/M 2.2. ;as it stands it will only run correctly on TATUNG EINSTEIN ;EINSTEIN dependant routines added 10/5/87 Dave West/Neil Imrie ; Baud rate setting routine intended to include modem control in future ; FALSE: EQU 0 TRUE: EQU 0FFH DBUFSIZ:EQU 2 ;S & R BUFFER SIZE IN KBYTES MODCTLP:EQU 11H ;MODEM CONTROL PORT :EINSTEIN (Comart=3) MODDATP:EQU 10H ;MODEM DATA PORT :EINSTEIN (Comart=2) MSNDB: EQU 1 ;MODEM SEND BIT (XMIT BUFF EMPTY) MSNDR: EQU 1 ;MODEM SEND READY MRCVB: EQU 2 ;MODEM RECEIVE BIT (DAV) MRCVR: EQU 2 ;MODEM RECEIVE READY BAUD: EQU 2 ;enter 1 for 1X, or 2 for 16X, or 3 for 64X ERRLIM: EQU 10 ;NUMBER OF TIMES TO RETRY ;SEND/RECEIVE ERRORS BEFORE QUIT EXITCHR:EQU 'E'-40H ; ^E = EXIT TRANCHR:EQU 'T'-40H ; ^T = TRANSFER CHARACTER CAN: EQU 'X'-40H ; ^X = CANCEL SEND/RECEIVE EOFCHAR:EQU 'Z'-40H ; ^Z = END OF FILE SAVECHR:EQU 'Y'-40H ; ^Y = SAVE CHARACTER XOFF: EQU 'S'-40H ; ^S = XOFF CHARACTER XON: EQU 'Q'-40H ; ^Q = XON CHARACTER EXTCHR: EQU 1BH ;SEND NEXT CHAR LITERALLY ENQ: EQU 5 ;^E Auto ID SAVON: EQU 12H ;^R Terminal filesave on SAVOFF: EQU 14H ;^T Terminal filesave off SOH: EQU 1 ; START OF HEADER EOT: EQU 4 ; END OF TEXT ACK: EQU 6 ; ACKNOWLEDGE NAK: EQU 15H ; NOT ACKNOWLEDGE CRC: EQU 'C' ;USED TO RQST CRC INSTEAD OF CKSUM BDNMCH: EQU 75H ; BAD NAME MATCH OKNMCH: EQU ACK ; OKAY NAME MATCH LF: EQU 10 ; LINEFEED CR: EQU 13 ; CARRIAGE RETURN BELL: EQU 7 ; BELL CHARACTER WRCON: EQU 2 PRINT: EQU 9 OPEN: EQU 15 CLOSE: EQU 16 SRCHF: EQU 17 SRCHN: EQU 18 ERASE: EQU 19 READ: EQU 20 WRITE: EQU 21 MAKE: EQU 22 REN: EQU 23 STDMA: EQU 26 FILSIZ: EQU 35 BDOS: EQU 5 FCB: EQU 5CH FCBEXT: EQU FCB+12 FCBRNO: EQU FCB+32 CLEAR: EQU 'L'-64 ORG 100H JP START ;THESE SYSTEM DEPENDENT ROUTINES ARE AT THE BEGINNING OF THE ;PROGRAM SO THEY CAN BE PATCHED WITH A MONITOR FASTCLK:DEFB TRUE ;4 MHz or greater BAKUPBYTE:DEFB TRUE ;true=make .BAK file XPRFLG: DEFB TRUE ;true=menu initially off SAVCCP: DEFB TRUE ;true=do not overwrite CCP SAVEFLG:DEFB TRUE ;true=terminal filesave initially on ECHOFLG:DEFB FALSE ;true=terminal echo initially on INITFLG:DEFB FALSE ;true=modem port already initialised ANSBAK: DEFB TRUE ;true=answerback on ^E ; INMODCTLP:IN A,(MODCTLP) ;get port status RET OUTCTLP:OUT (MODCTLP),A ;control RET OUTMODDATP:OUT (MODDATP),A ;send data RET ANISND: AND MSNDB ;bit to test for send ready RET CPISND: CP MSNDR ;value of send bit when ready RET INMODDATP:IN A,(MODDATP) ;get data RET ANIRCV: AND MRCVB ;bit to test for receive ready RET CPIRCV: CP MRCVR ;value of receive bit when ready RET LOGMSSG:DEFB 'FRED;BLOGGS',CR,LF,0 LOGMSSE: DEFS 40 ; ; This section added to give ability to manipulate 8251 USART in ; Tatung Einstein - Very machine dependant; ; Variables for USART parm command ; USAMODE: DEFB 4EH ; USART mode byte - 8 bits no parity 1 stop + *16 USACMD: DEFB 17H ; TxD RxD enabled,CTS DTR low,ER reset (modem off) USABAUD: DEFB 33H ; Baud rate default 300/300 Mflg: DEFB 0 Mrate: DEFB 0 ; Holds No of modem Baud rate steps ; USTBL: DEFB 'B' DEFW BAUDSET DEFB 'D' DEFW BITSET DEFB 'P' DEFW PARSET DEFB 'S' DEFW STOPSET DEFB 'X' DEFW USEXIT DEFB 0 ; End of table marker ; USASET: PUSH HL PUSH DE PUSH BC PUSH IX PUSH IY USASET1: CALL ILPRT ; Do menu DEFB CR,LF,' ** SET UP USART **',CR,LF,CR,LF DEFB 'B - Set Baud rate',CR,LF DEFB 'D - No of data bits',CR,LF DEFB 'P - Parity',CR,LF DEFB 'S - Number of stop bits',CR,LF DEFB 'X - Exit',CR,LF,CR,LF DEFB ' Enter required option ',0 RST 8H ; Get the option DEFB 9CH AND 5FH ; Convert to UPPER case LD D,A ; Put key in D LD HL,USTBL ; Make HL point to jump table USASET2: LD A,(HL) OR A JP Z,USASET1 ; End of table? CP D JR NZ,USASET3 INC HL LD E,(HL) INC HL LD D,(HL) PUSH DE ; = JP (DE) RET USASET3: INC HL INC HL INC HL JR USASET2 USEXIT: CALL SETUSA CALL ILPRT DEFB CR,LF,CR,LF,'*** USART SET ***',CR,LF,0 POP IY ; All leave here POP IX POP BC POP DE POP HL JP XPRT ; ; Baud Rate Set ; BAUDTBL: DEFB 33H,3 ;(3 RTS pulses) DEFB 33H,2 ;(2 RTS pulses) DEFB 05H,0 DEFB 44H,0 DEFB 55H,0 DEFB 66H,0 DEFB 77H,0 DEFB 88H,0 ; BAUDSET: CALL ILPRT ; Do menu DEFB CR,LF DEFB ' ** SET BAUD RATE **',CR,LF,CR,LF DEFB '0 - 300 TX / 300 RX ORIGINATE ',CR,LF DEFB '1 - 300 TX / 300 RX ANSWER',CR,LF DEFB '2 - 75 TX / 1200 RX',CR,LF DEFB '3 - 600 TX / 600 RX',CR,LF DEFB '4 - 1200 TX / 1200 RX',CR,LF DEFB '5 - 2400 TX / 2400 RX',CR,LF DEFB '6 - 4800 TX / 4800 RX',CR,LF DEFB '7 - 9600 TX / 9600 RX',CR,LF,CR,LF DEFB 'Enter required option ',0 BAUDSET1: RST 8H ; Get the option DEFB 9CH CP '0' ; Check if between 0 and 7 and if not JR C,BAUDSET1 ; go wait for a kosher answer CP '8' JR NC,BAUDSET1 SUB '0' ; Convert to an offset SLA A ; a two byte offset LD E,A ; add it to the origin of LD D,0 ; the baud table LD HL,BAUDTBL ADD HL,DE LD A,(HL) ; and place the Baud rate value in USABAUD LD (USABAUD),A INC HL LD A,(HL) LD (Mrate),A JP USASET1 ; ; Number of data bits Set ; DBTBL: DEFB 0 DEFB 04H DEFB 08H DEFB 0CH ; BITSET: CALL ILPRT ; Do menu DEFB CR,LF DEFB ' ** SET DATA BITS **',CR,LF,CR,LF DEFB ' 5 - 5 data bits',CR,LF DEFB ' 6 - 6 data bits',CR,LF DEFB ' 7 - 7 data bits',CR,LF DEFB ' 8 - 8 data bits',CR,LF,CR,LF DEFB 'Enter required option ',0 BITSET1: RST 8H ; Get the option DEFB 9CH CP '5' ; Check if between 5 and 8 if not JR C,BITSET1 ; go wait for a kosher answer CP '9' JR NC,BITSET1 SUB '5' ; Convert to an offset LD E,A ; add it to the origin of LD D,0 ; the data bit table LD HL,DBTBL ADD HL,DE LD A,(USAMODE) AND 0F3H OR (HL) ; and set bits as appropriate LD (USAMODE),A JP USASET1 ; ; Parity Set ; PARTBL: DEFB 0 DEFB 10H DEFB 30H ; PARSET: CALL ILPRT ; Do menu DEFB CR,LF DEFB ' ** SET PARITY **',CR,LF,CR,LF DEFB ' 0 - None',CR,LF DEFB ' 1 - Odd',CR,LF DEFB ' 2 - Even',CR,LF,CR,LF DEFB 'Enter required option ',0 PARSET1: RST 8H ; Get the option DEFB 9CH CP '0' ; Check if between 0 and 2 if not JR C,PARSET1 ; go wait for a kosher answer CP '3' JR NC,PARSET1 SUB '0' ; Convert to an offset LD E,A ; add it to the origin of LD D,0 ; the parity bit table LD HL,PARTBL ADD HL,DE LD A,(USAMODE) AND 0CFH OR (HL) ; and set bits as appropriate LD (USAMODE),A JP USASET1 ; ; Stop bit set ; STOPTBL: DEFB 40H DEFB 80H DEFB 0C0H ; STOPSET: CALL ILPRT ; Do menu DEFB CR,LF DEFB ' ** SET STOP BIT/S **',CR,LF,CR,LF DEFB ' 0 - 1 stop bit',CR,LF DEFB ' 1 - 1.5 stop bits',CR,LF DEFB ' 2 - 2 stop bits',CR,LF,CR,LF DEFB 'Enter required option ',0 STOPSET1: RST 8H ; Get the option DEFB 9CH CP '0' ; Check if between 0 and 2 if not JR C,STOPSET1 ; go wait for a kosher answer CP '3' JR NC,STOPSET1 SUB '0' ; Convert to an offset LD E,A ; add it to the origin of LD D,0 ; the stop bit table LD HL,STOPTBL ADD HL,DE LD A,(USAMODE) AND 3FH OR (HL) ; and set bits as appropriate LD (USAMODE),A JP USASET1 ; Mtog: LD A,(Mflg) CP 1 JP Z,Moff CALL Mon LD A,(Mrate) CP 0 JP Z,XPRT LD C,A Mloop: LD A,17H ;OFF OUT (MODCTLP),A LD B,29 DJNZ $ LD A,37H ;ON OUT (MODCTLP),A LD B,23 DJNZ $ DEC C JP NZ,Mloop JP XPRT ; Mon: LD A,37H LD (USACMD),A CALL OUTCTLP LD A,1 LD (Mflg),A CALL ILPRT DEFB 'ON line',CR,LF,0 RET ; Moff: LD A,17H LD (USACMD),A CALL OUTCTLP LD A,0 LD (Mflg),A CALL ILPRT DEFB 'OFF line',CR,LF,0 JP XPRT ; ; up to here (mainly) added 10/5/87 ; ;The routine below should work in most systems which use an 8251 USART INITMOD:LD A,(INITFLG) OR A RET NZ ;Return if INITFLG=TRUE CALL SETUSA CALL INMODDATP CALL INMODDATP ;clear buffers RET ; ;SETUSA - Sets up USART *** ; SETUSA: ;*** PUSH HL PUSH DE LD A,64 CALL OUTCTLP ;Reset USART for mode instruction LD A,(USAMODE) ;*** CALL OUTCTLP ;Set up USART protocol LD A,(USACMD) ;*** CALL OUTCTLP ;Set up interface spec LD A, (USABAUD) ;*** LD L,A ;*** LD H,0 ; This bit uses Einstein MOS LD DE,0 ; Tatung's equivalent of an RST 8H ; adventure game! DEFB 81H ; Set up baud rate POP DE POP HL RET ;PROGRAM FOLLOWING BELOW IS NOT SYSTEM DEPENDENT except *** START: LD HL,0 ADD HL,SP ;GET CP/M'S STACK LD (STAK),HL ;SAVE IT LD SP,STAK ;LOCAL STACK CALL INITADR ;INITIALIZE BIOS ADDRESSES CALL INITMOD ;INITIALISE MODEM PORTS CALL ILPRT DEFB CLEAR,'Einstein UKM7 V1.0',CR,LF ;*** DEFB 'Control port=0',0 LD A,(INMODCTLP+1) CALL HEXO CALL ILPRT DEFB 'H Data port=0',0 LD A,(OUTMODDATP+1) CALL HEXO CALL ILPRT DEFB 'H',CR,LF,' 300/300 orig 8/0/1 ',0 ;*** LD HL,80H LD DE,CMDBUF+1 LD B,80H CALL MOVE ;default buffer to cmdbuf LD A,TRUE LD (NFILFLG),A CALL PROCOPT ;PROCESS CONTROL OPTIONS RESTART:LD A,(OPTION) ;GET MAIN OPTION CP ' ' ;NO OPTION SPEC'D? JP Z,MENU CP 'M' ;MENU JP Z,MENU2 CALL MOVEFCB ;MOVE 2ND HALF FCB TO FIRST HALF CALL INMODDATP ;GOBBLE UP GARBAGE.. CALL INMODDATP ;..CHARACTERS ON LINE LD A,(OPTION) ;PROCESS MAIN OPTION CP 'T' ;TERMINAL MODE? JP Z,DSKSAVE CP 'S' ;SEND A FILE? JP Z,SENDFIL CP 'R' ;RECEIVE A FILE? JP Z,RCVFIL MENU: LD SP,STAK ;RESTORE STACK LD HL,RESTSN ;RESTORE SECTOR NUMBERS.. LD DE,SECNOB ;..FOR NEW FILE TRANSFER. LD B,SECNOE-SECNOB CALL MOVE LD HL,RESTROPT ;RESTORE OPTION TABLE LD DE,OPTBL LD B,OPTBE-OPTBL CALL MOVE LD A,0 LD (MFFLG1),A ;RESET MFACCESS ROUTINE.. CPL ;..AND MULTI TRANS IN CASE.. LD (FSTFLG),A ;..OF ABORT. MENU1: LD A,(XPRFLG) ;TEST IF MENU SHOULD BE SHOWN OR A JP NZ,XPRT MENU2: CALL ILPRT DEFB CR,LF DEFB 'SYNTAX:',CR,LF DEFB 'Command < afn>' DEFB CR,LF,CR,LF DEFB ' COMMANDS:',CR,LF DEFB ' S Send binary files, afn list',CR,LF DEFB ' R Receive binary files, drive:',CR,LF DEFB ' T Terminal mode. ',CR,LF DEFB ' DEL Delete Terminal file',CR,LF DEFB ' DIR Directory list, afn optional',CR,LF DEFB ' DOS Exit to DOS.',CR,LF DEFB ' X Expert, toggle menus on/off',CR,LF DEFB ' P Set up USART parameters',CR,LF ;*** DEFB ' O On/Off line toggle',CR,LF ;*** DEFB ' M Menu display',CR,LF,CR,LF DEFB ' SWITCHES: (S and R only)' DEFB CR,LF DEFB ' N Non batch mode. (XMODEM)' DEFB CR,LF DEFB ' Q Quiet mode.',CR,LF DEFB 'S,R Monitor data Sent or Received',CR,LF DEFB ' V View file',CR,LF DEFB ' T Terminal mode on completion',CR,LF,0 XPRT: CALL ILPRT DEFB CR,LF,0 LD C,25 ;CURRENT DISK FUNCTION CALL BDOS ADD 30H ;MAKE ASCII CALL CTYPE CALL ILPRT DEFB '>>',0 LD DE,CMDBUF ;ENTER COMMAND CALL INBUFF CALL CRLF LD DE,CMDBUF+2 ;POINT TO COMMAND CALL ILCOMP DEFB 'DOS',0 JP NC,EXIT CALL ILCOMP DEFB 'DIR',0 JP NC,DIR CALL ILCOMP DEFB 'DEL',0 JP NC,NEWFILE CALL ILCOMP ; DEFB 'P',0 ;*** JP NC,USASET ;*** CALL ILCOMP ;*** DEFB 'O',0 ;*** JP NC,Mtog ;*** LD DE,CMDBUF LD HL,FCB CALL CPMLINE ;LOAD FCB CALL PROCOPT JP RESTART DIR: CALL DIRLST JP XPRT EXIT: LD A,(NFILFLG) CP TRUE CALL NZ,TFILWR ;write and close terminal file LD DE,80H LD C,STDMA CALL BDOS LD HL,(STAK) LD SP,HL LD A,(SAVCCP) OR A JP Z,0 ;WARM BOOT RET ;to CCP NEWFILE:LD A,(NFILFLG) CP TRUE JP Z,MENU1 ;IF NO FILE, DON'T ERASE LD DE,FCB3 LD C,ERASE CALL BDOSRT LD A,TRUE ;DO NOT ALLOW TERMINAL.. LD (NFILFLG),A ;..SAVE SINCE NO FILE.. JP MENU1 ;====================================== ;TERMINAL ROUTINE ALLOWING MEMORY SAVE DSKSAVE:LD A,(FCB+1) ;FIRST CHAR OF FILENAME CP ' ' ;FILE SPEC'D LD HL,(HLSAVE) JP Z,TERM1 LD A,(NFILFLG) CP TRUE CALL NZ,TFILWR ;write & close existing file CALL TFLERAS CALL MOVE2 ;move FCB to FCB3 LD DE,FCB3 LD C,MAKE CALL BDOS INC A JP NZ,TERM0 CALL ILPRT DEFB '< Unable to open file >',CR,LF,0 JP TERM1 TERM0: LD HL,BOTTRAM LD (HLSAVE),HL LD A,FALSE LD (NFILFLG),A LD (CTRLR),A ;cancel any previous ^R TERM1: LD A,(XPRFLG) OR A JP NZ,TERM3 TERM2: LD A,(NFILFLG) CP TRUE JP Z,NOTFIL PUSH HL LD HL,FCB3 LD DE,TFILE LD A,(HL) OR A JP NZ,PUTDRV LD A,' ' LD (DE),A INC DE JP NAME1 PUTDRV: ADD 2FH LD (DE),A INC DE LD A,':' NAME1: LD (DE),A INC DE INC HL LD B,8 CALL MOVE INC DE LD B,3 CALL MOVE POP HL CALL ILPRT DEFB CR,LF,' ^Y Terminal file ' TFILE: DEFB ' toggle save on/off '':'' =on',0 NOTFIL: CALL ILPRT DEFB CR,LF DEFB ' ^T Transfer (Send) ASCII file.',CR,LF DEFB ' ^X Abort transfer initiated above',CR,LF DEFB ' ^C Computer mode, toggle echo ',CR,LF DEFB ' ESC Quote control character',CR,LF DEFB ' ^E Exit to command menu',CR,LF DEFB ' ^D Display terminal menu',CR,LF,0 TERM3: LD A,(NFILFLG) OR A JP NZ,TERM LD A,(SAVEFLG) OR A JP Z,TERM LD A,':' ;indicate filesave is on CALL CTYPE TERM: CALL STAT ;KEYPRESS? JP Z,TERML ;NO, CHECK LINE CALL KEYIN ;GET CHAR FROM KBD LD B,A LD A,(EXACFL) OR A LD A,FALSE LD (EXACFL),A LD A,B JP NZ,NOTOG CP EXITCHR ;^E? JP Z,MENU ;YES, RETURN TO MENU CP 3 ;^C Computer mode with echo JP NZ,NOECH LD A,(ECHOFLG) CPL LD (ECHOFLG),A JP TERML NOECH: CP 4 ;^D display terminal menu JP Z,TERM2 CP EXTCHR ;literal JP Z,EXTFLG CP TRANCHR ;TEST FOR TRANSFER REQUEST (^T) CALL Z,TRANSFER ;SEND-A-FILE (BLIND SEND) JP Z,TERM3 ;LOOP CP SAVECHR JP NZ,NOTOG LD A,(NFILFLG) ;DO NOT ALLOW SAVE IF.. CP TRUE ;..THIS FLAG IS SET. JP Z,TERML LD A,(SAVEFLG) CPL LD (SAVEFLG),A JP TERM3 EXTFLG: LD A,TRUE LD (EXACFL),A JP TERML NOTOG: CALL OUTMODDATP LD B,A LD A,(ECHOFLG) OR A LD A,B JP Z,TERML CP LF JP Z,TERML ;ignore LF CALL CTYPE ;local echo PUSH AF CALL MSAVE ;local save in terminal file POP AF CP CR JP NZ,TERML LD A,LF CALL CHRSND ;send to remote CALL CTYPE ;append LF CALL MSAVE TERML: CALL INMODCTLP CALL ANIRCV CALL CPIRCV JP NZ,TERM CALL INMODDATP AND 7FH ;strip parity JP Z,TERM ;ignore null CP ENQ ;auto logon JP NZ,NOLOG LD A,(ANSBAK) OR A JP Z,TERM LD DE,LOGMSSG NXCHAR: LD A,(DE) INC DE OR A JP Z,TERM CALL CHRSND ;send to remote LD B,A LD A,(ECHOFLG) OR A LD A,B JP NZ,CHRSAV PUSH DE LD D,0 ;init count CALL INMODEM ;wait 100ms for echo AND 7FH DEC D POP DE JP NZ,NXCHAR CHRSAV: CALL CTYPE CALL MSAVE JP NXCHAR NOLOG: CP SAVON ;auto filesave on JP NZ,TRYT LD A,(SAVEFLG) OR A JP NZ,TERM ;save already on LD A,TRUE LD (SAVEFLG),A ;turn on save LD (CTRLR),A ;remember JP TERM3 TRYT: CP SAVOFF ;auto save off JP NZ,ONWRD LD A,(CTRLR) OR A JP Z,TERM ;turn save off only LD A,FALSE ;if it was turned on LD (SAVEFLG),A ;by ^R from remote LD (CTRLR),A JP TERM ONWRD: LD B,A LD A,(ECHOFLG) OR A LD A,B JP Z,TERM5 CP LF JP Z,TERM ;ignore LF CALL OUTMODDATP ;echo to distant terminal CP CR JP NZ,TERM5 CALL CTYPE CALL MSAVE ;save in terminal file LD A,LF CALL CHRSND ;send LF TERM5: CALL CTYPE CALL MSAVE ;save in terminal file JP TERM CTRLR: DEFB FALSE LASTB1: DEFB 0 LASTB2: DEFB 0 ;========================================= ;SEND A CP/M FILE SENDFIL:LD A,(BATCHFLG) ;CHECK IF MULTIPLE FILE.. OR A ;..MODE IS SET. JP Z,SENDC1 LD A,TRUE ;INDICATE BATCH SEND LD (SENDFLG),A LD A,(FSTFLG) ;IF FIRST TIME THRU.. OR A ;..SCAN THE COMMAND LINE.. CALL NZ,TNMBUF ;..FOR MULTIPLE NAMES. CALL SENDFN ;SENDS FILE NAME TO RECEIVER JP NC,SENDC2 ;CARRY SET MEANS NO MORE FILES. LD A,0 ;STOP BATCH.. LD (BATCHFLG),A ;..MODE OPTION. LD A,EOT ;FINAL XFER END CALL SEND JP DONE SENDC1: LD A,(FCB+1) CP ' ' JP Z,BLKFILE CALL AMBGTS ;test for ambiguous filename SENDC2: CALL CNREC ;GET NUMBER OF RECORDS CALL OPENFIL LD E,80 CALL WAITNAK ;if a 'C' is received instead of NAK SENDLP: CALL RDSECT ;then CRC mode is enabled JP C,SENDEOF CALL INCRSNO XOR A LD (ERRCT),A SENDRPT:CALL SENDHDR CALL SENDSEC LD A,(CRCFLG) OR A CALL Z,SENDCRC CALL NZ,SENDCKS CALL GETACK JP C,SENDRPT JP SENDLP SENDEOF:LD A,EOT CALL SEND CALL GETACK JP C,SENDEOF JP DONE ;=============================== ;RECEIVE A FILE RCVFIL: XOR A ;default to CRC mode LD (CRCFLG),A RCV1FIL:LD A,(BATCHFLG) ;CHECK IF MULT.. OR A ;..FILE MODE. JP Z,RCVC1 LD A,FALSE ;FLAG WHERE TO RETURN.. LD (SENDFLG),A ;..FOR NEXT FILE TRANS. CALL GETFN ;GET THE FILE NAME. JP NC,RCVC2 ;CARRY SET MEANS NO MORE FILES. LD A,0 ;STOP BATCH.. LD (BATCHFLG),A ;..MODE OPTION. JP DONE RCVC1: LD A,(FCB+1) ;MAKE SURE FILE IS NAMED CP ' ' JP Z,BLKFILE JP RCVC3 RCVC2: CALL CKCPM2 CALL CKBAKUP RCVC3: CALL ERASFIL CALL MAKEFIL LD A,(BATCHFLG) OR A ;DON'T PRINT MSSG IF.. JP Z,RCVC4 ;..IN MULTI AND QUIET. LD A,(QFLG) OR A JP Z,RCVFST RCVC4: CALL ILPRT DEFB 'File open, ready to receive',CR,LF,0 RCVFST: LD A,(CRCFLG) OR A LD A,NAK JP NZ,RCV2FIL LD A,CRC ;indicate to Tx that CRC is wanted RCV2FIL:CALL SEND ;by sending a 'C' instead of NAK LD A,(CRCFLG) OR A JP NZ,RCVNAKM ;if in CRC mode CALL ILPRT ;then say so DEFB 'CRC in effect',CR,LF,0 JP RCVLP RCVNAKM:CALL ILPRT ;else say checksum mode DEFB 'Checksum in effect',CR,LF,0 RCVLP: CALL RCVSECT JP C,RCVEOT CALL WRSECT ;sends CAN if error CALL INCRSNO CALL SENDACK JP RCVLP RCVEOT: CALL WRBLOCK ;sends CAN if error CALL SENDACK CALL CLOSFIL JP DONE ;=================================== BLKFILE:CALL ILPRT ;ROUTINE IF NO FILE IS NAMED FOR "SEND" OR "RECEIVE" DEFB CR,LF,'< No file specified > ',CR,LF,BELL,0 JP MENU ;=============================== DONE: LD A,(BATCHFLG) OR A JP Z,DONETB LD A,(QFLG) OR A JP Z,NMSTRNS LD HL,FCB+1 ;PUT FILE NAME IN.. LD DE,FTRNMSG ;..SPACES IN MESSAGE.. LD B,8 ;..BELOW. CALL MOVE INC DE ;PUT FILE TYPE AFTER.. LD B,3 ;..SKIPPING ONE SPACE.. CALL MOVE ;..BELOW. CALL ILPRT DEFB CR,LF FTRNMSG:DEFB ' transferred',CR,LF,CR,LF,0;13 SPACES NMSTRNS:LD A,(FCB) ;SAVE DRIVE NO. LD (DISKNO),A LD HL,FCB ;BLANK OUT FILE CONTROL BLOCKS CALL INITFCBS LD A,(DISKNO) ;PUT DRIVE NUMBER BACK LD (FCB),A LD HL,RESTSN ;RESTORE SECTOR NUMBERS.. LD DE,SECNOB ;..FOR NEW FILE TRANSFER. LD B,SECNOE-SECNOB;ROUTINE ALSO DONE IN MENU. CALL MOVE LD A,(SENDFLG) ;GOES TO EITHER SEND OR.. OR A ;..RECEIVE FILE, DEPENDING.. JP NZ,SENDFIL ;..UPON WHICH ROUTINE SET.. JP RCV1FIL ;..THE FLAG IN MULTI-FILE MODE. DONETB: LD A,TRUE ;INDICATE NO FILES BEING.. LD (FSTFLG),A ;RESET MULTIFILE TRANS LD A,(VSEEFLG) OR A JP Z,DONETC LD A,(QFLG) OR A JP Z,DONETA DONETC: CALL ILPRT DEFB CR,LF,'All transfers completed' DEFB CR,LF,BELL,0 DONETA: LD SP,STAK ;restore stack LD A,CRC LD (CRCFLG),A ;turn off CRC option LD A,0FFH LD (FIRSTME),A ;set first-time flag LD A,(TERMFLG) ;SEE IF RETURN TO.. OR A ;..TERMINAL MODE.. JP NZ,MENU ;..AFTER X'FER. CALL CRLF JP TERM ;============================= SUBROUTINES =============== MSAVE: PUSH AF LD A,(NFILFLG) CP TRUE JP Z,NOSAVE ;CANT SAVE IF NO FILE LD A,(SAVEFLG) CP FALSE JP Z,NOSAVE POP AF LD (HL),A INC HL LD (HLSAVE),HL ;MENU COMMAND DESTROYS HL-REG.. CP LF JP NZ,NOCOLON ;TYPE ":" AFTER EACH LINE FEED.. LD A,':' ;..WHEN MEMORY SAVE ACTIVE. CALL TYPE ;dont increment col count NOCOLON:LD A,(SAVCCP) OR A JP Z,SUB1 LD A,(7) SBC 8 ;..PAGE BELOW CCP .. JP SUB1A SUB1: LD A,(7) SUB1A: DEC A ;..OR BDOS HAS BEEN.. CP H ;..REACHED AND DISKSAVE IS NEEDED. CALL Z,INTDSKSV RET NOSAVE: POP AF RET ;================================== PROCOPT:LD DE,FCB+1 LD A,(DE) LD (OPTION),A OPTLP: INC DE LD A,(DE) CP ' ' JP Z,ENDOPT LD HL,OPTBL LD B,OPTBE-OPTBL OPTCK: CP (HL) JP NZ,OPTNO LD (HL),0 ;INSERT SECONDARY OPTION JP OPTLP OPTNO: INC HL DEC B JP NZ,OPTCK JP BDOPT ENDOPT: LD A,(VSEEFLG) OR A JP NZ,CKPRI LD (QFLG),A ;IF(VFLAG.EQ.0)THEN QFLAG=0 CKPRI: LD A,(FCB+1) ;CHECK ON THE PRIMARY OPTION CP 'X' JP Z,EXPRT CP ' ' RET Z CP 'M' RET Z CP 'T' RET Z CP 'S' JP Z,CKFILE CP 'R' JP NZ,BDOPT LD A,(BATCHFLG) ;IF MULT FILE MODE, THEN.. OR A ;..RECV OPT MUST NOT BE NAMED JP Z,CKFILE LD A,(FCB+17) CP ' ' RET Z BDOPT: CALL ILPRT DEFB '< Bad Syntax >',CR,LF,0 JP MENU EXPRT: LD A,(XPRFLG) CPL LD (XPRFLG),A JP MENU CKFILE: LD A,(FCB+17) ;IF OPTION THAT NEEDS FILE NAME,.. CP ' ' ;..THEN CHECK TO SEE IF NAME.. RET NZ ;..EXISTS. JP BDOPT ;================================== TFILWR: LD HL,(HLSAVE) CALL NUMRECS ;DISK WRITE ROUTINE AS USED IN.. CALL WRTDSK ;..IN THE INTDSKSV ROUTINE. LD DE,FCB3 LD C,CLOSE CALL BDOS LD A,TRUE LD (NFILFLG),A RET ;================================ INTDSKSV: LD A,XOFF ;SEND A CTRL-S TO STOP.. CALL OUTMODDATP ;..REMOTE COMPUTER OUTPUT. LD D,0 ;D IS THE BUFFER COUNT CALL INMODEM ;GET LAST BYTES SENT.. LD (LASTB1),A ;..AFTER CTRL-S. CALL INMODEM ;ADD MORE CALLS TO INMODEM.. LD (LASTB2),A ;..AND STA LASTBYT# IF YOU ARE.. ;..LOSING BYTES WHEN MEMORY IS FULL. PUSH DE CALL NUM1REC CALL WRTDSK ;WRITE THE RECORDS POP DE LD HL,BOTTRAM INC D DEC D ;TEST BUFFER COUNT FOR ZERO JP Z,CTRLQ LD A,(LASTB1) ;GET THE LAST BYTES THAT WERE.. LD (HL),A ;..SAVED AND PUT THEM IN.. INC HL ;..BOTTRAM. CALL CTYPE DEC D JP Z,CTRLQ LD A,(LASTB2) LD (HL),A INC HL CALL CTYPE CTRLQ: LD A,XON ;SEND START CHARACTER.. CALL OUTMODDATP ;..TO REMOTE COMPUTER. RET ;====================================== ;SUBROUTINE LOOPS UNTIL THE MODEM RECEIVES A CHARACTER OR 100ms INMODEM:LD A,(FASTCLK) OR A LD BC,1250 JP Z,TIMERL LD BC,2500 TIMERL: CALL INMODCTLP CALL ANIRCV CALL CPIRCV JP Z,GETBYTE DEC BC LD A,B OR C JP NZ,TIMERL RET GETBYTE:CALL INMODDATP INC D RET ;================================ NUMRECS:LD (HL),EOFCHAR INC HL LD DE,127 ADD HL,DE NUM1REC:LD DE,(0-BOTTRAM) ADD HL,DE LD A,L ;DIVIDE HL BY 128.. OR A RLA ;..TO GET THE.. LD L,H ;..NUMBER OF SECTORS LD H,0 PUSH AF ADD HL,HL POP AF LD A,0 ADC L LD L,A ;RETNS WITH NUMBER OF.. RET ;..128 BYTE RECORDS IN HL. ;====================================== WRTDSK: LD DE,BOTTRAM NEXTWRT:LD C,STDMA CALL BDOSRT PUSH DE LD DE,FCB3 LD C,WRITE CALL BDOSRT POP DE INC A JP Z,WRTERR EX DE,HL PUSH DE LD DE,128 ADD HL,DE POP DE EX DE,HL DEC HL LD A,H OR L JP NZ,NEXTWRT CALL RSDMA ;for CP/M 1.4 RET WRTERR: CALL ILPRT DEFB '< Terminal file write error > ',CR,LF,0 RET ;========================== BDOSRT: PUSH BC PUSH DE PUSH HL CALL BDOS POP HL POP DE POP BC RET ;============================ MOVE2: LD HL,FCB3 CALL INITFCBS LD HL,FCB LD DE,FCB3 LD B,12 CALL MOVE RET ;============================= ;FILE TRANSFER ROUTINE - CALLED WITH ;CONTROL-T FROM TERMINAL ROUTINE. ;TRANSFER MAY BE CANCELLED WHILE SENDING BY USING CONTROL-X. TRANSFER: PUSH HL PUSH DE PUSH BC PUSH AF LD HL,FCB4 CALL INITFCBS ;INITIALIZES FCBS POINTED.. LD HL,FCB+16 ;..TO BY HL REG. CALL INITFCBS GET: CALL GETNAME LD A,(CMDBUF+2) ;WAS FILE ENTERED CP 20H JP Z,TRANCAN LD DE,CMDBUF LD HL,FCB4 CALL CPMLINE LD DE,FCB4 LD C,OPEN CALL BDOS CP 0FFH ;RETURN WITH 0FFH MEANS JP NZ,CONTIN ;FILE DOES NOT EXIST CALL ILPRT DEFB '< File does not exist >',CR,LF,0 TRANS2L:CALL ILPRT DEFB 'Type "^X" to cancel transfer',CR,LF DEFB 'Type "R" to re-enter name: ',BELL,0 CALL KEYIN CALL UCASE CALL CTYPE ;ECHO RESPONSE CALL CRLF CP 'R' JP Z,GET CP CAN JP Z,TRANCAN JP TRANS2L CONTIN: LD DE,80H LD C,STDMA CALL BDOS LD A,SAVON CALL CHRSND ;activate remote save READMR: LD DE,FCB4 LD C,READ CALL BDOS OR A JP NZ,RETNS CALL SEND80C CP EOFCHAR ;END OF FILE - OMIT IF OBJECT.. JP Z,RETNS ;..CODE IS TO BE SENT. CP CAN ;CANCELLATION? JP Z,TRANC1 JP READMR RETNS: LD A,SAVOFF CALL CHRSND ;deactivate remote save CALL ILPRT DEFB CR,LF,'File transfer completed',CR,LF,BELL,0 JP RETURN TRANC1: LD A,SAVOFF CALL CHRSND ;deactivate remote save TRANCAN:CALL ILPRT DEFB CR,LF,'< Transfer cancelled >',CR,LF,BELL,0 RETURN: POP AF POP BC POP DE POP HL RET ;============================= INITFCBS:;ENTRY AT +2 WILL LEAVE.. LD (HL),0 ;..DRIVE NO. INTACT. INC HL ;WILL INITIALIZE AN FCB.. LD B,11 ;..POINTED TO BY HL-REG. FILLS 1ST POS LOOP10: LD (HL),' ' ;..WITH 0, NEXT 11 WITH.. INC HL ;..WITH BLANKS, AND LAST.. DEC B ;..21 WITH NULLS. JP NZ,LOOP10 LD B,21 LOOP11: LD (HL),0 INC HL DEC B JP NZ,LOOP11 RET ;================================ GETNAME:CALL ILPRT DEFB CR,LF,'Enter filename - C/R TO QUIT: ',0 LD DE,CMDBUF CALL INBUFF CALL CRLF RET ;=========================== CHRSND: PUSH AF REDY: CALL INMODCTLP CALL ANISND CALL CPISND JP NZ,REDY POP AF CALL OUTMODDATP RET ;=============================== SEND80C:LD B,80H LD HL,80H SENDCH1:LD A,(HL) CALL CHRSND ;send to remote LD C,A LD A,(ECHOFLG) OR A LD A,C ;local echo if computer mode JP NZ,SEND2 PUSH BC LD D,0 CALL INMODEM ;wait 100ms for echo AND 7FH DEC D POP BC JP NZ,SENDC3 SEND2: CALL CTYPE ;echo with tab expansion CP EOFCHAR RET Z SENDC3: CALL STAT ;TEST TO SEE IF OR A ;CANCELLATION REQUESTED JP Z,SKIP12 CALL KEYIN CP CAN RET Z SKIP12: INC HL DEC B JP NZ,SENDCH1 RET FCB4: DEFS 33 ;=================================- SENDFN: LD A,(QFLG) OR A JP Z,SWNAK CALL ILPRT DEFB 'Awaiting name NAK',CR,LF,0 SWNAK: LD E,80 CALL WAITNLP LD A,ACK ;GOT NAK, SEND ACK CALL SEND LD HL,FILECT DEC (HL) JP M,NOMRNM LD HL,(NBSAVE) ;GET FILE NAME.. LD DE,FCB ;..IN FCB LD B,12 CALL MOVE LD (NBSAVE),HL CALL SENDNM ;SEND IT OR A ;CLEAR CARRY RET NOMRNM: LD A,EOT CALL SEND SCF RET ;====================================== SENDNM: PUSH HL SEND1NM:LD D,11 ;COUNT CHARS IN NAME LD C,0 ;INIT CHECKSUM LD HL,FCB+1 ;ADDRESS NAME NAMLPS: LD A,(HL) ;SEND NAME AND 7FH ;STRIP HIGH ORDER BIT SO CP/M 2.. CALL SEND ;..WON'T SEND R/O FILE DESIGNATION. LD A,(SSEEFLG) OR A JP Z,ACKLP ;already typed by SEND LD A,(QFLG) ;SHOW NAME IF.. OR A ;..QFLG NOT SET. LD A,(HL) CALL NZ,TYPE ACKLP: PUSH BC ;SAVE CKSUM LD B,1 ;WAIT FOR RECEIVER.. CALL RECV ;..TO ACKNOWLEDGE.. POP BC ;..GETTING LETTER. JP C,SCKSER CP ACK JP NZ,ACKLP INC HL ;NEXT CHAR DEC D JP NZ,NAMLPS LD A,EOFCHAR ;TELL RECEIVER END OF NAME CALL SEND LD A,(QFLG) OR A CALL NZ,CRLF LD D,C ;SAVE CHECKSUM LD B,1 CALL RECV ;GET CHECKSUM.. CP D ;..FROM RECEIVER. JP Z,NAMEOK SCKSER: LD A,BDNMCH ;BAD NAME-TELL RECEIVER CALL SEND LD A,(QFLG) OR A JP Z,SKCSER1 CALL ILPRT DEFB '< Checksum error > ',CR,LF,0 SKCSER1:LD E,80 ;DO HANDSHAKING OVER CALL WAITNLP ;DON'T PRINT "AWAITING NAK" MSG LD A,ACK CALL SEND JP SEND1NM NAMEOK: LD A,OKNMCH ;GOOD NAME-TELL RECEIVER CALL SEND POP HL RET ;============================ GETFN: LD HL,FCB CALL INITFCBS+2 ;DOES NOT INITIALIZE DRIVE LD A,(QFLG) OR A JP Z,GNAMELP CALL ILPRT DEFB 'Awaiting file name',CR,LF,0 GNAMELP:CALL HSNAK JP C,GNAMELP CALL GETNM ;GET THE NAME CP EOT ;IF EOT, THEN NO MORE FILES JP Z,NOMRNG OR A ;CLEAR CARRY RET NOMRNG: SCF RET ;================================ GETNM: PUSH HL GETNM1: LD C,0 ;INIT CHECKSUM LD HL,FCB+1 NAMELPG:LD B,5 CALL RECV ;GET CHAR JP NC,GETNM3 LD A,(QFLG) OR A JP Z,GETNM2 CALL ILPRT DEFB '< Time out receiving filename > ',CR,LF,0 GETNM2: JP GCKSER GETNM3: CP EOT ;IF EOT, THEN NO MORE FILES JP Z,GNRET CP EOFCHAR ;GOT END OF NAME JP Z,ENDNAME LD (HL),A ;PUT NAME IN FCB LD A,(RSEEFLG) OR A JP Z,GETNM4 ;already typed by RECV LD A,(QFLG) ;TYPE IT IF NO QFLG OR A LD A,(HL) CALL NZ,CTYPE GETNM4: PUSH BC ;SAVE CKSUM LD A,ACK ;ACK GETTING LETTER CALL SEND POP BC INC HL ;GET NEXT CHAR LD A,L ;DON'T LET NOISE... CP 7FH ;..CAUSE OVERFLOW.. JP Z,GCKSER ;..INTO PROGRAM AREA. JP NAMELPG ENDNAME:LD A,(QFLG) OR A CALL NZ,CRLF LD A,C ;SEND CHECKSUM CALL SEND LD B,1 CALL RECV ;CHECKSUM GOOD? CP OKNMCH ;YES IF OKNMCH SENT.. JP Z,GNRET ;..ELSE DO OVER. GCKSER: LD HL,FCB ;CLEAR FCB (EXCEPT DRIVE).. CALL INITFCBS+2 ;..SINCE IT MIGHT BE DAMAGED.. LD A,(QFLG) ;..BY TOO MANY CHARS. OR A JP Z,GCK1SER CALL ILPRT DEFB '< Checksum error > ',CR,LF,0 GCK1SER:CALL HSNAK ;DO HANDSHAKING OVER JP C,GCK1SER JP GETNM1 GNRET: POP HL RET ;============================== HSNAK: LD A,NAK ;SEND NAK UNTIL.. CALL SEND ;..RECEIVING ACK. CALL CKABORT ;DON'T GET HUNG UP HERE LD B,2 ;WAIT 2 SECONDS.. CALL RECV ;..IN RECEIVE. CP ACK ;IF ACK,RETURN WITH.. RET Z ;..CARRY CLEAR. SCF RET ;============================ TNMBUF: LD A,FALSE ;CALL FROM SENDFIL ONLY ONCE. LD (FSTFLG),A LD (FILECT),A CALL SCAN LD HL,NAMEBUF LD (NBSAVE),HL ;SAVE ADDR OF 1ST NAME TNLP1: CALL TRTOBUF LD HL,FCB LD DE,FCBBUF CALL CPMLINE ;PARSE NAME TO CP/M FORMAT TNLP2: CALL MFNAME ;SEARCH FOR NAMES (* FORMAT) JP C,NEXTNM LD A,(FCB+10) ;IF CP/M 2 $SYS FILE.. AND 80H ;..DON'T SEND JP NZ,TNLP2 LD HL,(NBSAVE) ;GET NAME LD DE,FCB ;MOVE IT TO FCB EX DE,HL LD B,12 CALL MOVE EX DE,HL LD (NBSAVE),HL ;ADDR OF NEXT NAME LD HL,FILECT ;COUNT FILES FOUND INC (HL) JP TNLP2 ; NEXTNM: LD HL,NAMECT ;COUNT NAMES FOUND DEC (HL) JP NZ,TNLP1 LD HL,NAMEBUF ;SAVE START OF BUFFER LD (NBSAVE),HL LD A,(FILECT) OR A JP Z,NOBFILE CP 65 ;NO MORE THAN 64 TRANSFERS RET C LD A,64 ;ONLY X'FER FIRST 64 LD (FILECT),A RET NOBFILE:CALL ILPRT DEFB '< No file > ',CR,LF,0 JP MENU ;==============================================- ;SCANS CMDBUF COUNTING NAMES AND PUTTING DELIMITER (SPACE) ;AFTER LAST NAME SCAN: PUSH HL LD HL,NAMECT LD (HL),0 LD HL,CMDBUF+1 ;FIND END OF CMD LINE.. LD C,(HL) ;..AND PUT SPACE THERE. LD B,0 LD HL,CMDBUF+2 ADD HL,BC LD (HL),20H LD HL,CMDBUF+1 LD B,(HL) INC B INC B CALL EAT ;eat spaces JP Z,DNSCAN SCAN1LP:INC HL DEC B JP Z,DNSCAN LD A,(HL) CP 20H JP NZ,SCAN1LP CALL EAT JP Z,DNSCAN LD (BGNMS),HL ;SAVE START OF NAMES IN CMDBUF INC B DEC HL SCAN3LP:INC HL DEC B JP Z,DNSCAN LD A,(HL) CP 20H JP NZ,SCAN3LP LD A,(NAMECT) ;COUNTS NAMES INC A LD (NAMECT),A CALL EAT JP Z,DNSCAN JP SCAN3LP ; DNSCAN: LD (HL),20H ;SPACE AFTER LAST CHAR POP HL RET ;================================== ;Space eater EAT: INC HL DEC B RET Z LD A,(HL) CP ' ' JP Z,EAT RET ;========================================== ;PLACES NEXT NAME IN BUFFER SO CPMLINE MAY PARSE IT TRTOBUF:LD HL,(BGNMS) LD B,0 LD DE,FCBBUF+2 TBLP: LD A,(HL) CP 20H JP Z,TRBFEND LD (DE),A INC HL INC DE INC B ;COUNT CHARS IN NAME JP TBLP ; TRBFEND:INC HL LD A,(HL) ;EAT EXTRA SPACES CP 20H JP Z,TRBFEND LD (BGNMS),HL LD HL,FCBBUF+1 ;PUT # CHARS BEFORE NAME LD (HL),B RET ;==================================== ;IN CP/M V.2, IF FILE IS R/O OR SYS, IT IS CHANGED TO 'BAK'. CKCPM2: LD C,12 CALL BDOS OR A ;RETURN 0 MEANS CP/M 1 RET Z LD C,STDMA LD DE,80H CALL BDOS LD C,SRCHF ;SEARCH FOR FILE LD DE,FCB CALL BDOS CP 0FFH RET Z ADD A ADD A ;MULT A-REG BY.. ADD A ADD A ;..32 TO FIND.. ADD A ;..NAME IN DMA. LD HL,80H ADD L LD L,A ;HL POINTS TO DIR NAME LD DE,9 ADD HL,DE ;POINT TO R/O ATTRIB BYTE LD A,(HL) AND 80H ;TEST MSB JP NZ,MKCHG ;IF SET, MAKE CHANGE INC HL ;CHECK SYSTEM ATTRIB BYTE LD A,(HL) AND 80H RET Z ;NOT $SYS OR $R/O DEC HL MKCHG: LD DE,0-8 ADD HL,DE ;POINT HL TO FILENAME + 1 LD DE,FCB+1 ;MOVE DIR NAME TO FCB.. LD B,11 ;..WITHOUT CHANGING DRIVE. CALL MOVE LD HL,FCB+9 ;R/O ATTRIB LD A,(HL) AND 7FH ;STRIP R/O ATTRIB LD (HL),A INC HL ;SYS ATTRIB LD A,(HL) AND 7FH LD (HL),A LD DE,FCB LD C,30 ;SET NEW ATTRIBS IN DIR CALL BDOS ;MAY BE CALLED BY CKBAKUP BELOW. ITS RETURN DONE HERE PLANCHG:LD HL,FCB ;CHANGE NAME TO TYPE "BAK" LD DE,6CH LD B,9 ;MOVE DRIVE AND NAME (NOT TYPE) CALL MOVE LD HL,75H ;START OF TYPE IN FCB2 LD (HL),'B' INC HL LD (HL),'A' INC HL LD (HL),'K' LD DE,6CH LD C,ERASE ;ERASE ANY PREV BACKUPS CALL BDOS LD HL,6CH ;FCB2 DR FIELD SHOULD.. LD (HL),0 ;..0 FOR RENAME. LD DE,FCB LD C,REN CALL BDOS RET CKBAKUP:LD A,(BAKUPBYTE) OR A RET Z LD C,SRCHF LD DE,FCB CALL BDOS INC A RET Z ;FILE NOT FOUND JP PLANCHG ;IN "CKCPM2" - RET DONE THERE ;==================================== RCVSECT:XOR A LD (ERRCT),A RCVRPT: LD A,(QFLG) OR A JP Z,RCVSQ CALL ILPRT DEFB CR,LF,'Awaiting number ',0 PUSH HL ;SAVE IT LD HL,(SECNO) ;GET SECTOR NUMBER INC HL ;BUMP IT CALL DECOUT ;PRINT SECTOR NUMBER IN DECIMAL CALL ILPRT DEFB ' (', 0 CALL DHXOUT ;16 BIT HEX CONVERSION & OUTPUT CALL ILPRT DEFB 'H)',0 POP HL ;RESTORE IT ; If CRC is in effect, there is only a 7 second wait ; for the first SOH. If the SOH is not received within ; this time, then a NAK is sent which tells the sender ; to use checksum checking instead of CRC. This allows ; automatic compatability with versions of MODEM that ; do not implement Cyclic Redundancy Checking(CRC). RCVSQ: LD A,(FIRSTME) ;first SOH... OR A ;...been received? JP Z,RCVSQ2 ;yes, go get next SOH XOR A ;turn off... LD (FIRSTME),A ;...first soh recvd switch LD A,(CRCFLG) ;CRC in... OR A ;...effect? JP NZ,RCVSQ2 ;no, do long wait for first SOH LD B,7 ;wait for upto 7 seconds CALL RECV ;get a character from modem JP NC,RCVSQ3 ;got a char, go see if SOH CALL ILPRT DEFB CR,LF,'Switching to Checksum Mode',CR,LF,0 LD A,'C' ;turn off... LD (CRCFLG),A ;...CRC mode. LD A,NAK ;send NAK to tell sender checksum CALL SEND ;...is in effect & to start sending. JP RCVSECT ;go start receiving sector ; RCVSQ2: LD B,7 ;10 IN ORIG PROG CALL RECV JP C,RCVSTOT RCVSQ3: CP SOH JP Z,RCVSOH OR A ;IGNORE NULLS JP Z,RCVSQ CP EOT SCF RET Z LD B,A LD A,(VSEEFLG) OR A JP Z,RCVSEH LD A,(QFLG) OR A JP Z,RCVSERR RCVSEH: LD A,B CALL CRLF CALL ILPRT ; KMQ001 DEFB '< ',0 ; KMQ001 CALL HEXO CALL ILPRT DEFB 'H received, not SOH > ',CR,LF,0 RCVSERR:LD B,1 CALL RECV JP NC,RCVSERR LD A,NAK CALL SEND LD A,(ERRCT) INC A LD (ERRCT),A CP ERRLIM JP C,RCVRPT LD A,(VSEEFLG) OR A JP Z,RCVCKQ LD A,(QFLG) OR A JP Z,RCVSABT RCVCKQ: CALL CKQUIT JP Z,RCVSECT RCVSABT:CALL CLOSFIL CALL ERXIT DEFB CR,LF,'< Unable to receive block - Aborting >$' RCVSTOT:LD A,(VSEEFLG) OR A JP Z,RCVSPT LD A,(QFLG) OR A JP Z,RCVSERR RCVSPT: CALL ILPRT DEFB CR,LF,'< Timeout > ',0 RCVPRN: LD A,(ERRCT) CALL HEXO CALL CRLF JP RCVSERR RCVSOH: LD B,1 CALL RECV JP C,RCVSTOT LD D,A LD B,1 CALL RECV JP C,RCVSTOT CPL CP D JP Z,RCVDATA LD A,(VSEEFLG) OR A JP Z,RCVBSE LD A,(QFLG) OR A JP Z,RCVSERR RCVBSE: CALL ILPRT DEFB CR,LF,'< Bad sector number in header > ',CR,LF,0 JP RCVSERR RCVDATA:LD A,D LD (RCVSNO),A LD A,1 LD (DATAFLG),A LD C,0 CALL CLRCRC ;clear crc counter LD HL,80H RCVCHR: LD B,1 CALL RECV JP C,RCVSTOT LD (HL),A INC L JP NZ,RCVCHR XOR A LD (DATAFLG),A LD A,(CRCFLG) OR A JP Z,RCVCRC LD D,C LD B,1 CALL RECV JP C,RCVSTOT CP D JP NZ,RCVCERR CHKSNUM:LD A,(RCVSNO) LD B,A LD A,(SECNO) CP B JP Z,RECVACK INC A CP B JP NZ,ABORT RET RCVCRC: LD E,2 ;nr of crc bytes RCV2CRC:LD B,1 CALL RECV JP C,RCVSTOT DEC E JP NZ,RCV2CRC CALL CHKCRC OR A JP Z,CHKSNUM LD A,(VSEEFLG) OR A JP Z,RCVCRER LD A,(QFLG) OR A JP Z,RCVSERR RCVCRER:CALL ILPRT DEFB CR,LF,'< CRC error >',0 JP RCVPRN RCVCERR:LD A,(VSEEFLG) OR A JP Z,RCVCPR LD A,(QFLG) OR A JP Z,RCVSERR RCVCPR: CALL ILPRT DEFB '< Checksum error > ',0 JP RCVPRN RECVACK:CALL SENDACK JP RCVSECT ;=============================== SENDACK:LD A,ACK CALL SEND RET ;=========================== SENDHDR:LD A,(QFLG) OR A JP Z,SENDHNM CALL ILPRT DEFB CR,LF,'Send number ',0 PUSH HL LD HL,(SECNO) ;GET SECTOR NUMBER CALL DECOUT ;PRINT IT IN DECIMAL CALL ILPRT DEFB ' (',0 CALL DHXOUT ;16 BIT HEX CONVERSION & OUTPUT CALL ILPRT DEFB 'H)',0 POP HL SENDHNM:LD A,SOH CALL SEND LD A,(SECNO) CALL SEND LD A,(SECNO) CPL CALL SEND RET ;======================== SENDSEC:LD A,1 LD (DATAFLG),A LD C,0 CALL CLRCRC LD HL,80H SENDC: LD A,(HL) CALL SEND INC L JP NZ,SENDC XOR A LD (DATAFLG),A RET ;=============================== SENDCKS:LD A,C CALL SEND RET ;============================== SENDCRC:CALL FINCRC LD A,D CALL SEND LD A,E CALL SEND XOR A RET ;=============================== GETACK: LD B,7 ;10 IN ORIG PROG CALL RECVDG JP C,GETATOT CP ACK RET Z LD B,A LD A,(QFLG) OR A JP Z,ACKERR LD A,B CALL CRLF CALL ILPRT ; KMQ001 DEFB '< ',0 ; KMQ001 CALL HEXO CALL ILPRT DEFB 'H Received, not ACK > ',CR,LF,0 ACKERR: LD A,(ERRCT) INC A LD (ERRCT),A CP ERRLIM RET C LD A,(VSEEFLG) OR A JP Z,GACKV LD A,(QFLG) OR A JP Z,CSABORT GACKV: CALL CKQUIT SCF RET Z CSABORT:CALL ERXIT DEFB CR,LF,'< Unable to send sector -- Aborting > $' GETATOT:LD A,(QFLG) OR A JP Z,ACKERR CALL ILPRT DEFB CR,LF,'< Timeout on ACK > ',CR,LF,0 JP ACKERR ;================================ CKABORT:LD A,(VSEEFLG) OR A JP Z,CKABGO LD A,(QFLG) OR A RET Z CKABGO: CALL STAT RET Z CALL KEYIN CP CAN JP Z,ABORT RET ERXIT: POP DE LD C,PRINT CALL BDOS ;does not update col count CALL ILPRT DEFB CR,LF,BELL,0 ;reset col count LD A,(BATCHFLG) OR A JP Z,DONETA LD A,'Q' ;RESET QFLG LD (QFLG),A ABORT: LD SP,STAK ABORTL: LD B,1 CALL RECV ;wait until sender finishes JP NC,ABORTL LD A,CAN CALL SEND ABORTW: LD B,1 CALL RECV ;wait until sender finishes JP NC,ABORTW LD A,' ' ;send a space to clear out ^X CALL SEND CALL ILPRT DEFB CR,LF,'< Routine cancelled > ',CR,LF,BELL,0 LD A,0 ;TURN MULTI-FILE MODE.. LD (BATCHFLG),A ;..OFF SO ROUTINE ENDS. JP DONETA ;=================================== INCRSNO:PUSH HL LD HL,(SECNO) ;GET SECTOR NUMBER INC HL ;BUMP IT LD (SECNO),HL ;STORE IT POP HL RET ;=============================== AMBGTS: LD HL,FCB+1 LD C,11 AMBIG: LD A,(HL) INC HL CP '?' ;test for ambiguous name JP NZ,NOTAMB CALL ILPRT DEFB '< Ambiguous filename not allowed > ',CR,LF,0 JP MENU NOTAMB: DEC C JP NZ,AMBIG RET ;============================= ERASFIL:LD A,(BATCHFLG) ;DON'T ASK FOR ERASE.. OR A ;..IN MULTI-FILE MODE,.. JP NZ,NOASK TFLERAS:CALL AMBGTS ;ambiguous name ? LD DE,FCB LD C,SRCHF CALL BDOS INC A RET Z CALL ILPRT DEFB 'File exists -- Type ''Y'' to erase: ',BELL,0 CALL KEYIN PUSH AF CALL CTYPE POP AF CALL UCASE CP 'Y' CALL CRLF JP NZ,MENU NOASK: LD DE,FCB LD C,ERASE CALL BDOS RET ;=========================== MAKEFIL:LD DE,FCB LD C,MAKE CALL BDOS INC A RET NZ CALL ERXIT DEFB '< File open error - Directory Full? > $' ;================================== CNREC: LD C,12 CALL BDOS OR A ;0 means CP/M 1 JP Z,CNREC14 LD C,FILSIZ ;COMPUTE FILE SIZE FUNCTION IN CP/M 2.x LD DE,FCB ;POINT TO FILE CONTROL BLOCK CALL BDOS LD HL,(FCB+33) ;GET RECORD COUNT LD (RCNT),HL ;STORE IT LD HL,0 ;ZERO HL LD (FCB+33),HL ;RESET RANDOM RECORD IN FCB RET CNREC14:LD A,'?' ;MATCH ALL EXTENTS LD (FCBEXT),A LD A,0FFH LD (MAXEXT),A ;INIT MAX EXT NO. LD C,SRCHF ;GET 'SEARCH FIRST' FNC LD DE,FCB CALL BDOS ;READ FIRST INC A ;WERE THERE ANY? JP NZ,SOME ;GOT SOME CALL ERXIT DEFB '< File not found >$' ;POINT TO DIRECTORY ENTRY SOME: DEC A ;UNDO PREV 'INR A' AND 3 ;MAKE MODULUS 4 ADD A ;MULTIPLY... ADD A ;..BY 32 BECAUSE ADD A ;..EACH DIRECTORY ADD A ;..ENTRY IS 32 ADD A ;..BYTES LONG LD HL,80H ;POINT TO BUFFER ADD L ;POINT TO ENTRY ADD 15 ;OFFSET TO RECORD COUNT LD L,A ;HL NOW POINTS TO REC COUNT LD B,(HL) ;GET RECORD COUNT DEC HL DEC HL ;BACK DOWN TO EXTENT NUMBER DEC HL LD A,(MAXEXT) ;COMPARE WITH CURRENT MAX. OR A ;IF NO MAX YET JP M,BIGGER ;THEN SAVE RECORD COUNT ANYWAY CP (HL) JP NC,MOREDIR BIGGER: LD A,B ;SAVE NEW RECORD COUNT LD (RCNT),A LD A,(HL) ;SAVE NEW MAX. EXTENT NO. LD (MAXEXT),A MOREDIR:LD C,SRCHN ;SEARCH NEXT LD DE,FCB CALL BDOS ;READ DIR ENTRY INC A ;CHECK FOR END (0FFH) JP NZ,SOME ;NOT END OF DIR...PROCESS EXTENT LD A,(MAXEXT) ;HIT END...GET HIGHEST EXTENT NO. SEEN LD L,A ;WHICH GIVES EXTENT COUNT -1 LD H,0 LD D,H LD A,(RCNT) ;GET RECORD COUNT OF MAX EXTENT SEEN LD E,A ;SAVE IT IN DE ADD HL,HL ADD HL,HL ;MULTIPLY # OF EXTENTS -1 ADD HL,HL ; TIMES 128 ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,DE ;ADD IN SIZE OF LAST EXTENT LD (RCNT),HL ;SAVE TOTAL RECORD COUNT RET ;================================== OPENFIL:XOR A LD (FCBEXT),A LD DE,FCB LD C,OPEN CALL BDOS INC A JP NZ,OPENOK CALL ERXIT DEFB '< Unable to open file > $' OPENOK: LD A,(BATCHFLG) OR A JP Z,OPEN1OK LD A,(QFLG) OR A RET Z OPEN1OK:CALL ILPRT DEFB 'File open, size: ',0 LD HL,(RCNT) ;GET RECORD COUNT CALL DECOUT ;PRINT NUMBER OF SECTORS IN DECIMAL CALL ILPRT ;PRINT DEFB ' (',0 CALL DHXOUT CALL ILPRT DEFB 'H) sectors ',CR,LF,0 RET ;============================= CLOSFIL:LD DE,FCB LD C,CLOSE CALL BDOS INC A RET NZ CALL ERXIT DEFB '< Unable to close file >$' ;================================ RDSECT: LD A,(SECINBF) DEC A LD (SECINBF),A JP M,RDBLOCK LD HL,(SECPTR) LD DE,80H CALL MOVE128 LD (SECPTR),HL RET RDBLOCK:LD A,(EOFLG) CP 1 SCF RET Z LD C,0 LD DE,DBUF RDSECLP:PUSH BC PUSH DE LD C,STDMA CALL BDOS LD DE,FCB LD C,READ CALL BDOS POP DE POP BC OR A JP NZ,REOF LD HL,80H ADD HL,DE EX DE,HL INC C LD A,C CP DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE SECTORS JP Z,RDBFULL JP RDSECLP REOF: LD A,1 LD (EOFLG),A LD A,C RDBFULL:LD (SECINBF),A LD HL,DBUF LD (SECPTR),HL LD DE,80H LD C,STDMA CALL BDOS JP RDSECT ;================================== WRSECT: LD HL,(SECPTR) EX DE,HL LD HL,80H CALL MOVE128 EX DE,HL LD (SECPTR),HL LD A,(SECINBF) INC A LD (SECINBF),A CP DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE SECTORS RET NZ WRBLOCK:LD A,(SECINBF) OR A RET Z LD C,A LD DE,DBUF DKWRLP: PUSH HL PUSH DE PUSH BC LD C,STDMA CALL BDOS LD DE,FCB LD C,WRITE CALL BDOS POP BC POP DE POP HL OR A JP NZ,WRERR LD HL,80H ADD HL,DE EX DE,HL DEC C JP NZ,DKWRLP XOR A LD (SECINBF),A LD HL,DBUF LD (SECPTR),HL RSDMA: LD DE,80H ;required by CP/M 1.4 LD C,STDMA CALL BDOS RET WRERR: CALL RSDMA LD A,CAN CALL SEND CALL ERXIT DEFB '< Error writing file >$' ;=========================================== ;RECV: Receive a character ;Timeout time is in B, in seconds. Entry via 'RECVDG' deletes garbage ;characters on the line. For example, having just sent a sector, calling ;RECVDG will delete any line noise induced characters LONG before the ;ACK/NAK would be received. RECVDG: CALL INMODDATP CALL INMODDATP RECV: PUSH DE LD A,(FASTCLK) OR A JP Z,MSEC LD A,B ADD A LD B,A MSEC: LD DE,15000 ;60% OF ORIG 50000 CALL CKABORT MWTI: CALL INMODCTLP CALL ANIRCV CALL CPIRCV JP Z,MCHAR DEC E JP NZ,MWTI DEC D JP NZ,MWTI DEC B JP NZ,MSEC POP DE SCF RET MCHAR: CALL INMODDATP POP DE PUSH AF CALL UPDCRC ;calc crc ADD C LD C,A LD A,(RSEEFLG) OR A JP Z,MONIN LD A,(VSEEFLG) OR A JP NZ,NOMONIN LD A,(DATAFLG) OR A JP Z,NOMONIN MONIN: POP AF PUSH AF CALL SHOW NOMONIN:POP AF OR A RET ;================================= SEND: PUSH AF LD A,(SSEEFLG) OR A JP Z,MONOUT LD A,(VSEEFLG) OR A JP NZ,NOMONOT LD A,(DATAFLG) OR A JP Z,NOMONOT MONOUT: POP AF PUSH AF CALL SHOW NOMONOT:POP AF PUSH AF CALL UPDCRC ;calc crc ADD C LD C,A POP AF CALL CHRSND ;send to remote RET ;================================== WAITNAK:LD A,(VSEEFLG) OR A JP Z,WAITNPR LD A,(QFLG) OR A JP Z,WAITNLP WAITNPR:CALL ILPRT DEFB 'Awaiting initial NAK',CR,LF,0 WAITNLP:CALL CKABORT LD B,1 CALL RECV CP NAK RET Z CP CRC ;crc request? JP Z,WAITCRC ;yes, go set crc flag DEC E JP Z,ABORT JP WAITNLP WAITCRC:CALL ILPRT DEFB 'CRC request received',CR,LF,0 XOR A LD (CRCFLG),A RET ;================================== INITADR:LD HL,(1) LD DE,3 ADD HL,DE LD (VSTAT+1),HL ADD HL,DE LD (VKEYIN+1),HL ADD HL,DE LD (VTYPE+1),HL RET ;================================= MOVEFCB:LD HL,FCB+16 LD DE,FCB LD B,16 CALL MOVE XOR A LD (FCBRNO),A LD (FCBEXT),A RET ;============================= CONO: LD C,A CP 9 JP NZ,CONSOP TAB: LD A,' ' CALL CONSOP LD A,(COLCNT) AND 7 JP NZ,TAB RET CONSOP: CALL TYPE LD C,A LD HL,COLCNT CP 7FH RET Z INC (HL) CP ' ' RET NC DEC (HL) LD A,(HL) OR A RET Z LD A,C CP 8 JP NZ,TRYCR DEC (HL) RET TRYCR: CP CR RET NZ LD (HL),0 RET ;============================= SHOW: CP LF JP Z,CTYPE CP CR JP Z,CTYPE PUSH AF LD A,(COLCNT) CP 70 CALL NC,CRLF ;force cr,lf POP AF CP 9 JP Z,CTYPE CP ' ' JP C,SHOWHEX CP 7FH JP C,CTYPE SHOWHEX:PUSH AF LD A,'(' CALL CTYPE POP AF CALL HEXO LD A,')' CTYPE: PUSH AF PUSH BC PUSH DE PUSH HL AND 7FH ;ensure parity bits are suppressed CALL CONO ;type with tabs expanded POP HL POP DE POP BC POP AF RET ;============================= CRLF: PUSH AF LD A,CR CALL CTYPE LD A,LF CALL CTYPE POP AF RET ;========================== TYPE: PUSH AF PUSH BC PUSH DE PUSH HL AND 7FH ;ensure parity bits are suppressed LD C,A VTYPE: CALL $-$ POP HL POP DE POP BC POP AF RET ;========================= STAT: PUSH BC PUSH DE PUSH HL VSTAT: CALL $-$ POP HL POP DE POP BC OR A RET ;=============================== KEYIN: PUSH BC PUSH DE PUSH HL VKEYIN: CALL $-$ POP HL POP DE POP BC RET ;=========================== UCASE: CP 61H ;CHANGES LOWER CASE CHARACTER.. RET C ;..IN A-REG TO UPPER CASE. CP 7BH RET NC AND 5FH RET ;============================ DECOUT: PUSH AF PUSH BC PUSH DE PUSH HL LD BC,0-10 LD DE,0-1 DECOU2: ADD HL,BC INC DE JP C,DECOU2 LD BC,10 ADD HL,BC EX DE,HL LD A,H OR L CALL NZ,DECOUT LD A,E ADD '0' CALL CTYPE POP HL POP DE POP BC POP AF RET ;====================================== ; - double precision hex output routine. DHXOUT: PUSH HL PUSH AF LD A,H ;GET MS BYTE CALL HEXO ;OUTPUT HIGH ORDER BYTE LD A,L ;GET LS BYTE CALL HEXO ;OUTPUT LOW ORDER BYTE POP AF POP HL RET ;=============================== HEXO: PUSH AF RRA RRA RRA RRA CALL NIBBL POP AF NIBBL: AND 0FH CP 10 JP C,ISNUM ADD 7 ISNUM: ADD '0' JP CTYPE ;===================================== ;RETNS W/ ZERO SET IF RETRY ASKED. IF MULTI-FILE MODE, THEN ;NO QUESTIONS ASKED, JUST QUIT CKQUIT: LD A,(BATCHFLG) OR A JP Z,CKQTASK ;ASK FOR RETRY INC A ;RESET ZERO FLG RET CKQTASK:XOR A LD (ERRCT),A CALL ILPRT DEFB '< Multiple errors encountered. >',CR,LF DEFB ' Type Q to quit, R to retry: ',BELL,0 CALL KEYIN PUSH AF CALL CTYPE CALL CRLF POP AF CALL UCASE CP 'R' RET Z CP 'Q' JP NZ,CKQUIT OR A RET ;============================== ILPRT: EX (SP),HL ILPLP: LD A,(HL) OR A JP Z,ILPRET CALL CTYPE INC HL JP ILPLP ILPRET: EX (SP),HL RET ;========================= MOVE128:LD B,128 MOVE: LD A,(HL) LD (DE),A INC HL INC DE DEC B JP NZ,MOVE RET ;================================== ; Cyclic Redundancy Code Subroutines. Version 1.20 ; These subroutines will compute and check a true 16-bit ; Cyclic Redundancy Code for a message of arbitrary length. ; The use of this scheme will guarantee detection of all ; single and double bit errors, all errors with an odd ; number of error bits, all burst errors of length 16 or ; less, 99.9969% of all 17-bit error bursts, and 99.9984% ; of all possible longer error bursts. (Ref: Computer ; Networks, Andrew S. Tanenbaum, Prentiss-Hall, 1981) ; ;Reset CRC Accumulator for a new message. CLRCRC: PUSH HL LD HL,0 LD (CRCVAL),HL POP HL RET ;==================================== ;Update CRC Accumulator using byte in (A). UPDCRC: PUSH AF PUSH BC PUSH HL LD B,8 LD C,A LD HL,(CRCVAL) UPDLOOP:LD A,C RLCA LD C,A LD A,L RLA LD L,A LD A,H RLA LD H,A JP NC,SKIPIT LD A,H ;The generator is X^16 + X^12 + X^5 + 1 XOR 10H ;as recommended by CCITT. LD H,A LD A,L XOR 21H LD L,A SKIPIT: DEC B JP NZ,UPDLOOP LD (CRCVAL),HL POP HL POP BC POP AF RET ;================================== ; Finish CRC calc for outbound message. FINCRC: PUSH AF XOR A CALL UPDCRC CALL UPDCRC PUSH HL LD HL,(CRCVAL) LD D,H LD E,L POP HL POP AF RET ;================================= ; Check CRC bytes of received message. CHKCRC: PUSH HL LD HL,(CRCVAL) LD A,H OR L POP HL RET Z LD A,0FFH RET ; CRCVAL: DEFW 0 ;====================================== ;INBUFF - DUPLICATES READ BUFFER ROUTINE ;SAME AS CP/M FUNCTION 10, BUT DOES ;NOT USE CTRL-C (REASON FOR ROUTINE). ;DOES ALLOW CONTROLS U, R, E, AND H (BACKSPACE). INBUFF: PUSH AF PUSH HL PUSH BC PUSH DE ;DE REGISTERS MUST BE PUSHED LAST ISTART: CALL ICLEAR ;CLEAR THE BUFFER AREA POP DE ;GET ADDRESS OF BUFFER ON RETRIES PUSH DE ;RESTORE STACK XOR A INC DE ;ADDRESS COUNT FIELD LD (DE),A ;INITIALIZE WITH A ZERO IN COUNT BYTE INC DE EX DE,HL ;ADDRESS FIRST BUFFER BYTE WITH HL INBUFA: CALL CONIN CP 0DH ;IS IT A RETURN? JP Z,INBUFR ;IF SO, THEN RETURN CP 7FH ;IS IT A DELETE? JP Z,DELETE CP 8 ;CTRL-H WILL BACKSPACE.. JP Z,DELETE ;..OVER DELETED CHAR. CP 'U'-40H ;IS IT A CTRL-U JP Z,INBUFO ;OUTPUT # CR LF AND START OVER CP 'R'-40H ;CTRL-R RETYPES LINE JP Z,RETYPE CP 'E'-40H JP Z,PCRLF CP 20H ;NO CONTROL CHARACTERS OTHER.. JP C,INBUFA ;..THAN ABOVE ALLOWED. LD B,A ;SAVE INPUTTED CHARACTER EX DE,HL ;SAVE HL IN DE POP HL ;GET ADDRESS OF BUFFER IN HL PUSH HL ;RESTORE STACK INC HL ;ADDRESS COUNT BYTE INC (HL) ;INCREASE COUNT BYTE DEC HL ;ADDRESS MAXIMUM LD A,(HL) ;PUT MAXIMUM IN A INC HL ;ADDRESS COUNT CP (HL) ;COMPARE COUNT TO MAXIMUM JP C,ALERT ;IF MAXIMUM, RING BELL AND WAIT FOR CR EX DE,HL ;RESTORE BUFFER POINTER TO HL LD (HL),B ;PUT INPUTTED CHARACTER IN BUFFER LD A,B ;OUTPUT IT CALL TYPE INC HL ;BUMP POINTER JP INBUFA ;GET NEXT CHARACTER DELETE: EX DE,HL ;SAVE BUFFER POINTER IN DE POP HL ;ADDRESS BEGINNING OF BUFFER PUSH HL ;RESTORE STACK INC HL ;ADDRESS COUNT FIELD LD B,A ;SAVE DELETE CHAR - 7FH OR 08H LD A,(HL) SUB 1 ;DECREASE COUNT LD (HL),A JP C,NODEL ;DON'T DELETE PAST BEGINING OF BUFFER. EX DE,HL ;RESTORE BUFFER POINTER TO HL DEC HL ;POINT TO LAST BYTE INPUTTED LD A,B ;GET BACK EITHER 7FH OR 08H LD B,(HL) ;GET CHARACTER BEING DELETED LD (HL),20H ;RESTORE BLANK CP 8 JP Z,BKSPC CP 7FH JP Z,BKSPC0 JP INBUFA ;GET NEXT CHARACTER NODEL: INC (HL) ;DON'T LEAVE COUNT NEGATIVE EX DE,HL ;RESTORE POINTER TO HL JP INBUFA BKSPC0: LD A,08H BKSPC: CALL TYPE ;TRUE ERASE IF 08H LD A,20H CALL TYPE LD A,8 CALL TYPE JP INBUFA INBUFO: LD A,'#' CALL TYPE CALL CRLF JP ISTART RETYPE: POP DE PUSH DE INC DE ;POINT TO CURRENT NUMBER.. LD A,(DE) ;..OF CHARACTERS. LD B,A LD A,'#' CALL TYPE CALL CRLF LD A,B ;TEST IF ZERO INPUT OR A JP Z,INBUFA CTLRLP: INC DE LD A,(DE) CALL TYPE DEC B JP NZ,CTLRLP JP INBUFA ALERT: LD A,7 CALL TYPE DEC (HL) EX DE,HL JP INBUFA PCRLF: CALL CRLF JP INBUFA INBUFR: CALL CRLF POP DE POP BC POP HL POP AF RET ICLEAR: POP DE ;ACCOUNTS FOR CALL POP HL ;ADDRESS BUFFER IN HL PUSH HL ;RESTORE.. PUSH DE ;..STACK LD B,(HL) ;SAVE MAXIMUM IN B INC HL ;POINT TO FIRST.. INC HL ;..BUFFER BYTE. LD A,20H CLEARL: LD (HL),A INC HL DEC B JP NZ,CLEARL RET CONIN: PUSH HL PUSH DE PUSH BC CONINLP:CALL STAT JP Z,CONINLP CALL KEYIN CALL UCASE POP BC POP DE POP HL RET ;========================================== ;LOADS A COMMAND LINE ADDRESSED BY DE REGISTERS (MAX # CHARACTERS IN LINE ;IN DE, NUMBER OF CHARS IN LINE IN DE+1, LINE STARTS IN DE+2) INTO FCB ;ADDRESSED BY HL REGISTERS. THE FCB SHOULD BE AT LEAST 33 BYTES IN LENGTH. ;THE COMMAND LINE BUFFER MUST HAVE A MAXIMUM LENGTH OF AT LEAST ONE MORE ;THAN THE GREATEST NUMBER OF CHARACTERS THAT WILL BE NEEDED. CPMLINE:PUSH AF PUSH BC PUSH DE PUSH HL CALL INIT ;FILLS FCBS WITH BLANKS AND NULLS EX DE,HL ;GET START OF COMMAND LINE IN HL. INC HL ;ADDRESS # BYTES IN CMD LINE. LD E,(HL) ;LOAD DE PAIR WITH # BYTES. LD D,0 INC HL ADD HL,DE ;POINT TO BYTE AFTER LAST CHAR.. LD (HL),0DH ;..IN CMD LINE AND STORE DELIMITER. POP HL ;RESTORE HL AND DE. POP DE PUSH DE PUSH HL INC DE ;ADDRESS START OF COMMAND. INC DE CALL CDRIVE LD C,8 ;TRANSFER FIRST FILENAME TO FCB. CALL TRANS CP 0DH JP Z,CDONE CP 20H ;IF SPACE, THEN START OF.. JP Z,NAME2 ;..SECOND FILENAME. POP HL ;FILETYPE MUST BE AFTER.. PUSH HL ;..EIGHTH BYTE OF NAME. LD BC,9 ADD HL,BC LD C,3 ;TRANSFER TYPE OF FIRST FILE CALL TRANS CP 0DH JP Z,CDONE NAME2: LD A,(DE) ;EAT MULTIPLE SPACES.. CP 20H ;..BETWEEN NAMES. JP NZ,NAME2C INC DE JP NAME2 LD A,(DE) CP 0DH ;TEST IF FIRST NAME.. JP Z,CDONE ;..ONLY AND THEN SPACE. NAME2C: POP HL ;SECOND NAME STARTS IN 16TH BYTE. PUSH HL ;POINT HL TO THIS BYTE. LD BC,16 ADD HL,BC CALL CDRIVE LD C,8 CALL TRANS CP 0DH JP Z,CDONE POP HL ;SECOND TYPE STARTS IN 25TH BYTE. PUSH HL LD BC,25 ADD HL,BC LD C,3 CALL TRANS CDONE: POP HL PUSH HL INC HL ;POINT TO FIRST CHAR OF FIRST NAME IN FCB. CALL CSCAN ;CHECK FOR * (AMBIGUOUS NAMES). POP HL PUSH HL LD BC,17 ;POINT TO FIRST CHAR OF SECOND NAME IN FCB. ADD HL,BC CALL CSCAN POP HL POP DE POP BC POP AF RET INIT: PUSH HL ;INITIALIZES FCB WITH 1 NULL (FOR FIRST DRIVE),.. PUSH BC ;..11 BLANKS, 4 NULLS, 1 NULL (FOR 2ND DRIVE),.. LD (HL),0 ;..11 BLANKS, AND 4 NULLS. INC HL LD B,11 LD A,20H CALL INITFILL LD B,5 LD A,0 CALL INITFILL LD B,11 LD A,20H CALL INITFILL LD B,4 LD A,0 CALL INITFILL POP BC POP HL RET INITFILL: LD (HL),A INC HL DEC B JP NZ,INITFILL RET CDRIVE: INC DE ;CHECK 2ND BYTE OF FILENAME. IF IT.. LD A,(DE) ;..IS A ":", THEN DRIVE WAS SPECIFIED. DEC DE CP ':' JP NZ,DEFDR ;ELSE ZERO FOR DEFAULT DRIVE ('INIT' PUT ZERO) LD A,(DE) ; ANI 5FH SUB 2FH ;CALCULATE DRIVE (A=1, B=2,...).. LD (HL),A ;..AND PLACE IT IN FCB. INC DE ;ADDRESS FIRST BYTE OF.. INC DE ;..IN CMD LINE,.. DEFDR: INC HL ;..AND NAME FIELD IN FCB. RET TRANS: LD A,(DE) ;TRANSFER FROM CMD LINE TO FCB.. INC DE ;..UP TO NUMBER OF CHARS SPECIFIED.. CP 0DH ;..BY C-REG. KEEP SCANNING FIELD.. RET Z ;..WITHOUT TRANSFER UNTIL A DELIMITING.. CP '.' ;..FIELD CHAR SUCH AS '.', BLANK, OR.. RET Z ;..C/R (FOR END OF CMD LINE). CP 20H RET Z DEC C JP M,TRANS ;ONCE C-REG IS LESS THAN ZERO, KEEP READING.. LD (HL),A ;..CMD LINE BUT DO NOT TRANSFER TO FCB. INC HL JP TRANS CSCAN: LD B,8 ;SCAN FILE NAME ADDRESSED BY HL. TSTNAM: LD A,(HL) CP '*' ;IF '*' FOUND, FILL IN REST OF FIELD.. JP Z,FILL1 ;..WITH '?' FOR AMBIGUOUS NAME. INC HL DEC B JP NZ,TSTNAM JP TSTTYP FILL1: CALL FILL TSTTYP: LD B,3 ;SCAN AND FILL TYPE FIELD FOR NAME.. TSTLTYP:LD A,(HL) ;..SPECIFIED ABOVE. CP '*' JP Z,FILL2 INC HL DEC B RET Z JP TSTLTYP FILL2: CALL FILL RET FILL: LD (HL),'?' ;ROUTINE TRANSFERS '?'. INC HL DEC B JP NZ,FILL RET ;====================================== ;IN-LINE COMPARE. COMPARES STRING ADDRESSED BY DE-REG TO STRING ;AFTER CALL (ENDS WITH ZERO). RETURN WITH CARRY SET MEANS STRINGS ;NOT THE SAME. ALL REGISTERS EXCEPT A-REG ARE UNAFFECTED. ILCOMP: EX (SP),HL ;POINT HL TO 1ST CHAR. PUSH DE ILCMPL: LD A,(HL) ;HL POINTS TO IN-LINE STRING. OR A ;END OF STRING IF ZERO. JP Z,SAME LD A,(DE) CP (HL) JP NZ,NOTSAME INC HL INC DE JP ILCMPL NOTSAME:LD A,0 ;IF NOT SAME, FINISH THRU.. NSLP: INC HL ;..STRING SO RETURN WILL.. CP (HL) ;..GO TO INSTRUCTION AFTER.. JP NZ,NSLP ;..STRING AND NOT REMAINDER OF STRING. SCF SAME: POP DE INC HL ;AVOIDS A NOP INSTRUCTION.. EX (SP),HL ;..WHEN RETURNING. RET ;================================== ;MULTI-FILE ACCESS SUBROUTINE. ALLOWS PROCESSING ;OF MULTIPLE FILES (E.G. *.ASM) FROM DISK. THIS ;ROUTINE BUILDS THE PROPER NAME IN THE FCB EACH ;TIME IT IS CALLED. ;THE FCB WILL BE SET UP WITH THE NEXT NAME, READY TO ;DO NORMAL PROCESSING (OPEN, READ, ETC.) WHEN ROUTINE IS CALLED. ;CARRY IS SET IF NO MORE NAMES CAN BE FOUND MFNAME: PUSH BC PUSH DE PUSH HL LD C,STDMA LD DE,80H CALL BDOS POP HL POP DE POP BC XOR A LD (FCBEXT),A LD A,(MFFLG1) OR A JP NZ,MFN01 LD A,1 LD (MFFLG1),A LD HL,FCB LD DE,MFREQ LD BC,12 CALL MOVER LD A,(FCB) LD (MFCUR),A ;SAVE DISK IN CURR FCB LD HL,MFREQ LD DE,FCB LD BC,12 CALL MOVER PUSH BC PUSH DE PUSH HL LD C,SRCHF LD DE,FCB CALL BDOS POP HL POP DE POP BC JP MFN02 MFN01: LD HL,MFCUR LD DE,FCB LD BC,12 CALL MOVER PUSH BC PUSH DE PUSH HL LD C,SRCHF LD DE,FCB CALL BDOS POP HL POP DE POP BC LD HL,MFREQ LD DE,FCB LD BC,12 CALL MOVER PUSH BC PUSH DE PUSH HL LD C,SRCHN LD DE,FCB CALL BDOS POP HL POP DE POP BC MFN02: INC A SCF JP NZ,MFFIX1 LD (MFFLG1),A RET MFFIX1: DEC A AND 3 ADD A ADD A ADD A ADD A ADD A ADD 81H LD L,A LD H,0 PUSH HL ;SAVE NAME POINTER LD DE,MFCUR+1 LD BC,11 CALL MOVER POP HL LD DE,FCB+1 LD BC,11 CALL MOVER XOR A LD (FCBEXT),A LD (FCBRNO),A RET ; ;MULTI-FILE ACCESS WORK AREA ; MFFLG1: DEFB 0 ;1ST TIME SW MFREQ: DEFS 12 ;REQ NAME MFCUR: DEFS 12 ;CURR NAME ;===================================== ;MOVE SUBROUTINE MOVER: LD A,(HL) LD (DE),A INC HL INC DE DEC BC LD A,B OR C JP NZ,MOVER RET ;================================ DIRLST: LD DE,CMDBUF ;PUT COMMAND LINE IN FCB LD HL,5CH CALL CPMLINE LD HL,SRCHFCB CALL INITFCBS LD A,(6CH) ;GET DRIVE # LD (SRCHFCB),A LD A,(6DH) CP 20H ;IF BLANK GET ALL NAMES PUSH AF CALL Z,QSTMARK POP AF CALL NZ,MOVENAME ;ELSE MOVE NAME INTO FCB CALL DRIVE LD DE,80H LD C,STDMA CALL BDOS XOR A LD (DNAMECT),A ;CR AFTER 2 NAMES FOR 40 COLS LD DE,SRCHFCB LD C,SRCHF ;DO FIRST SEARCH CALL BDOS CP 0FFH JP Z,NOFILE DIRLP: CALL GETADD LD DE,15 ;OFFSET FOR RECORD COUNT ADD HL,DE LD A,(HL) OR A JP Z,NEXTSR ;NO LIST IF FILE IS ZERO LENGTH LD DE,0-5 ADD HL,DE ;POINT TO $SYS ATTRIB BYTE LD A,(HL) AND 80H JP NZ,NEXTSR ;NO LIST IF $SYS FILE LD DE,0-10 ADD HL,DE ;POINT TO BEGINNING OF NAME INC HL ;POINT TO FIRST LETTER LD DE,PRNTNAME LD B,8 CALL MOVE INC DE LD B,3 CALL MOVE CALL ILPRT PRNTNAME: DEFB ' ',' : ',0;12 SPACES LD A,(DNAMECT) INC A LD (DNAMECT),A AND 01H ;CALC NAMES BEFORE CRLF OR A CALL Z,CRLF NEXTSR: LD DE,SRCHFCB LD C,SRCHN ;DO NEXT SEARCH CALL BDOS CP 0FFH JP Z,DIRDONE JP DIRLP NOFILE: CALL ILPRT DEFB '< File not found >',0 DIRDONE:CALL CRLF RET QSTMARK:LD A,'?' ;IF BLANK IN FCB, PUT IN 11 ?'s LD B,11 LD HL,SRCHFCB+1 QSTLP: LD (HL),A INC HL DEC B JP NZ,QSTLP RET MOVENAME: LD HL,6DH LD DE,SRCHFCB+1 LD B,11 CALL MOVE ;MOVE IN CP/M PROGRAM RET GETADD: AND 03H ;GET MOD4 FOR CP/M 1.4 ADD A ADD A ADD A ;ADD 32 ADD A ADD A LD E,A LD D,0 LD HL,80H ;ADD DMA OFFSET ADD HL,DE RET DRIVE: LD A,(SRCHFCB) ;IF NO DRIVE, CAL OR A ;LOGGED IN DRIVE JP Z,CALCDR ADD 2FH JP PRNTHD CALCDR: LD C,25 CALL BDOS ADD 30H PRNTHD: LD (DRNAME),A CALL ILPRT DEFB CR,LF,'DRIVE ' DRNAME: DEFB ' ',CR,LF,0 RET SRCHFCB:DEFS 33 DNAMECT:DEFS 1 ;================================ NFILFLG:DEFB FALSE ;Terminal file open flag OPTION: DEFB 0 OPTBL: EQU $ QFLG: DEFB 'Q' RSEEFLG:DEFB 'R' SSEEFLG:DEFB 'S' VSEEFLG:DEFB 'V' TERMFLG:DEFB 'T' BATCHFLG:DEFB 'N' ;0=Non-batch OPTBE: EQU $ RESTROPT:;MUST BE IN SAME ORDER AS TABLE ABOVE DEFB 'Q','R','S','V','T','N' CRCFLG: DEFB 'C' ;use CRC instead of cksum RESTSN: DEFB 0,0,0,0,0 DEFW DBUF DEFB 0,0,0,0,0,0,0 SECNOB: EQU $ RCVSNO: DEFB 0 SECNO: DEFW 0 ERRCT: DEFB 0 EOFLG: DEFB 0 SECPTR: DEFW DBUF SECINBF:DEFB 0 MAXEXT: DEFB 0 RCNT: DEFW 0 DATAFLG:DEFB 0 EXACFL: DEFB 0 ;literalise next char flag COLCNT: DEFB 0 ;column counter SECNOE: EQU $ FSTFLG: DEFB TRUE FIRSTME: DEFB 0FFH ;first SOH received switch(it is zero after 1rst SOH) CMDBUF: DEFB 80H,0 DEFS 80H HLSAVE: DEFS 2 DISKNO: DEFS 1 SENDFLG:DEFS 1 NBSAVE: DEFS 2 BGNMS: DEFS 2 FILECT: DEFS 1 NAMECT: DEFS 1 DEFS 64 STAK: DEFS 2 FCB3: DEFS 33 FCBBUF: DEFS 15 DBUF: DEFS DBUFSIZ*1024 ;FILE BUFFER FOR SEND & RECIEVE MODES NAMEBUF:DEFS 64*12 ;BUFFER FOR FILE NAMES IN BATCH MODE. ORG $ + 100H AND 0FF00H;must be on page boundary BOTTRAM:DEFS 1 ;MEMORY BUFFER FOR TERMINAL FILE END 100H