;************************** Version 1.1 ******************************* ; ; [3] Fix wildcard handling. ; Assume first ^Z in last buffer from file is the end-of-file. ; Barry Devlin. 25-November-83. ; ; [2] Trim port reading routines to minimum to allow fastest possible ; looping. Move ES set-up out of tightest loops. ; Barry Devlin. 17-August-83. ; ; [1] CP/M-86 Version. ; Remove assembler directives incompatible with ASM-86. ; MS-DOS expects DOS function number in ah; CP/M-86 in cl. ; To overcome this,define a new interrupt DOS at 40H which ; saves cx,dx and transfers ah to cl and calls BDOS at 224. ; Barry Devlin. 14-July-83. ; ;*********************************************************************** ; CP/M-86 Version 1.0 ;*********************************************************************** ; [1] Initial changes for Sirius, try non-interrupt and VT52 built-in ; sequences. Barry Devlin 3-June-1983. ; ;***************************************************************************** ; ; SIRIUS I / VICTOR-9000 KERMIT ; ; Barry Devlin ; Computer Centre ; University College Dublin ; Belfield ; Dublin 4 ; Republic of Ireland. ; ;***************************************************************************** ; KERMIT - KL10 Error-free Reciprocal Micro Interconnect over TTY-lines ; ; Program Version 1.1, Kermit Protocol Version 2 ; April 4, 1983 ; ; Based on the KERMIT Protocol. ; ; Copyright (C) 1982,1983 Trustees of Columbia University ; ; Daphne Tzoar ; Columbia University Computer Center ; 612 W. 115th St. ; New York City, NY 10025 ; ; Special thanks to Frank da Cruz, Bill Catchings, Steve Jensen, ; Vace Kundakci, and Bernie Eiben for their help and contributions. ; This file is the global data area for all the Kermit modules. SIRIUS EQU 1 ; For Sirius I conditional assembly. IBMPC EQU 0 ; For IBM PC conditional assembly. Z100 EQU 0 ; For Heath/Zenith Z-100. [*] STEVE EQU 0 ; For Steve's homebrew assembly. BPGSTK EQU 015H ; BASE PAGE STACK SEGMENT STORAGE. BELL EQU 07Q TAB EQU 11Q LF EQU 12Q FF EQU 14Q CR EQU 15Q XON EQU 21Q XOFF EQU 23Q ESC EQU 33Q DEL EQU 177Q BS EQU 08H DOS EQU 40H BDOS EQU 224 CONIN EQU 01H CONOUT EQU 02H RDRIN EQU 03H PUNOUT EQU 04H LSTOUT EQU 05H DCONIO EQU 06H GTIOB EQU 07H PRSTR EQU 09H CONSTAT EQU 0BH OPENF EQU 0FH CLOSF EQU 10H SFIRST EQU 11H SNEXT EQU 12H DELF EQU 13H READF EQU 14H ; Read from the file. WRITEF EQU 15H MAKEF EQU 16H SETDMA EQU 1AH CFLSZ EQU 23H MAXFIL EQU 10 ; Maximum number of filenames in wildcard. MAXPKT EQU '~'-' '+2Q ; Maximum size of a packet. MAXTRY EQU 05Q ; Default number of retries on a packet. IMXTRY EQU 20Q ; Default number of retries send initiate. DRPSIZ EQU 5EH ; Default receive packet size. DSPSIZ EQU 20H ; Default send packet size. DSTIME EQU 08H ; Default send time out interval. DRTIME EQU 05H ; Default receive time out interval. DSPAD EQU 00H ; Default send padding. DRPAD EQU 00H ; Default receive padding. DSPADC EQU 00H ; Default send padding char. DRPADC EQU 00H ; Default receive padding char. DSEOL EQU CR ; Default send EOL char. DREOL EQU CR ; Default receive EOL char. DSQUOT EQU '#' ; Default send quote char. DRQUOT EQU '#' ; Default receive quote char. PAREVN EQU 00H ; Even parity. PARMRK EQU 01H ; Mark parity. PARNON EQU 02H ; No parity. PARODD EQU 03H ; Odd parity. PARSPC EQU 04H ; Space parity. DEFPAR EQU PAREVN ; Default parity (none.) IBMPAR EQU PARMRK ; IBM's parity (mark.) SOH EQU 01H ; Start of header char. BUFSIZ EQU 80H ; Size of DMA. DIASW EQU 01H ; Default is diagnostics on. CMKEY EQU 01H ; Parse a keyword. CMIFI EQU 02H ; Parse an input file spec (can be wild). CMOFI EQU 03H ; Parse an output file spec. CMCFM EQU 04H ; Parse a confirm. CMTXT EQU 05H ; Parse arbitrary text up to CR. IF SIRIUS HWARE EQU 0E000H ;I/O ADDRESS BASE DEFESC EQU ']'-100Q ;Default escape char. MPDATA EQU 040H ;Main Port data addr. offset. MPSTAT EQU 042H ;Main Port status addr. offset. MPINP EQU 1 ;Input Ready Bit MPOVR EQU 20H ;Input Buffer Over-run MPTBE EQU 4 ;Transmit buffer empty bit CRST EQU 018H ;Channel reset NVND EQU 00H ;Non-vectored,non-dma mode A1SNP EQU 044H ;Asynchronous,1 stop bit,no parity RE8B EQU 0C1H ;Receive enable,8 bits/word TE8B EQU 0EAH ;Transmit enable,8 bits/word BTIMER EQU 023H ;Baud rate timer control port BRATE EQU 020H ;Baud rate timer data port BSET EQU 036H ;Baud rate set word B0300 EQU 0001H ; Baud rates. B0600 EQU 8000H B1200 EQU 4000H B2400 EQU 2000H B4800 EQU 1000H B9600 EQU 0800H ENDIF IF ibmpc BIOS EQU 10H COMM EQU 14H KEYB EQU 16H DEFESC EQU ']'-100Q ; The default escape character. MDMDAT EQU 03F8H ; Address of modem port (data). MDMSTS EQU 03FDH ; Address of modem port status. MDMCOM EQU 03FBH ; Address of modem port command. MDMINP EQU 1 ; Input ready bit. MDMINTV EQU 0030H ; Address of modem port interrupt vector. MDMINTO EQU 0EFH ; Mask to enable interrupt for modem port. MDMINTC EQU 010H ; Bit to set to disable interrupts for modem. INTCONT EQU 0021H ; Address of 8259 interrupt controller ICW2-3. INTCON1 EQU 0020H ; Address of 8259 ICW1. EOICOM EQU 0064H ; End of interrupt. TIMER EQU 40H ; Use to issue short beep. PORT_B EQU 61H ; Port B address. B0300 EQU 180H ; Variables for 300 baud, 1200, etc. B1200 EQU 60H B1800 EQU 40H B2400 EQU 30H B4800 EQU 18H B9600 EQU 0CH ENDIF IF Z100 DEFESC EQU '\'-100Q ; The default escape character. ; BIOS entry points BIOS_SEG SEGMENT AT 40H ; Define segment where BIOS really is ORG 6*3 BIOS_AUXOUT LABEL FAR ; AUX output routine ORG 26*3 BIOS_AUXFUNC LABEL FAR ; AUX: function BIOS_SEG ENDS ; End of BIOS segment defs ; Function codes for BIOS_AUXFUNC CHR_READ EQU 1 ; Read character CHR_STATUS EQU 2 ; Get status CHR_SFGS EQU 0 ; Get status subfunction CHR_SFGC EQU 1 ; Get config subfunction CHR_CONTROL EQU 3 ; Control function CHR_CFSU EQU 0 ; Set new configuration parameters B00455 EQU 0 ; 45.5 baud B0050 EQU 1 ; 50 baud B0075 EQU 2 ; 75 baud B0110 EQU 3 ; 110 baud B01345 EQU 4 ; 134.5 baud B0150 EQU 5 ; 150 baud B0300 EQU 6 ; 300 baud B0600 EQU 7 ; 600 baud B1200 EQU 8 ; 1200 baud B1800 EQU 9 ; 1800 baud B2000 EQU 10 ; 2000 baud B2400 EQU 11 ; 2400 baud B4800 EQU 12 ; 4800 baud B9600 EQU 13 ; 9600 baud B19200 EQU 14 ; 19200 baud B38400 EQU 15 ; 38400 baud ENDIF SSEG STACK: RW 100 ; INITIALIZE STACK. STK DW $ DSEG ; Pure storage. ORG 100H DATAS EQU $ versio db 'CUCCA' IF SIRIUS db ' Sirius I' ENDIF IF ibmpc db ' IBM-PC' ENDIF IF Z100 db '/Stevens Heath/Zenith Z-100' ENDIF db ' Kermit-86 - CP/M-86 ver 1.1 ',cr,lf,'$' kerm db 'Kermit-86>$' spmes db 'Spack: $' rpmes db 'Rpack: $' hibit db 'Warning - Non Ascii char$' tmp rb 1 foo db '$' crlf db cr,lf,'$' ender db bell,bell,'$' tmsg1 db cr,lf,'[Connecting to host, type $' tmsg3 db ' C to return to PC]',cr,lf,'$' tmsg2 db cr,lf,'[Back at micro]',cr,lf,'$' ermes1 db cr,lf,'?Unregonized command$' ermes2 db cr,lf,'?Illegal character$' ermes3 db cr,lf,'?Not confirmed$' ermes4 db 'Unable to rename file$' ermes7 db '?Unable to receive initiate$' ermes8 db '?Unable to receive file name$' ermes9 db '?Unable to receive end of file$' erms10 db '?Unable to receive data$' erms11 db '?Disk full$' erms14 db '?Unable to receive an acknowledgement from the host$' erms15 db '?Unable to find file$' erms17 db 'Record length exceeds size of buffer$' erms18 db '?Unable to tell host that session is finished$' erms19 db '?Unable to tell host to logout$' erms20 db '?Too many files satisfy wildcard, 10 sent$' ermszz db ' $' dimsg1 db '%Bad checksum$' infms0 db 'Waiting .....$' infms1 db 'Receiving ...$' infms2 db 'Sending .....$' infms3 db 'Completed $' infms4 db 'Failed $' infms5 db 'Renaming file to $' cfrmes db ' Confirm with carriage return $' filhlp db ' Input file spec (possibly wild) $' esctl db 'Control-$' spchar db 24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH db 3CH,3EH,7BH,7DH,5FH,5CH,5EH,7EH,7CH,60H eschlp db cr,lf,'Enter literal value (ex: Cntrl ]) $' tophlp db cr,lf,'BYE to host (LOGOUT) and exit to DOS' db cr,lf,'CONNECT to host on selected port' db cr,lf,'EXIT to DOS' db cr,lf,'FINISH running Kermit on the host' db cr,lf,'HELP by giving this message' db cr,lf,'LOGOUT the host' db cr,lf,'RECEIVE file from host' db cr,lf,'SEND file to host' db cr,lf,'SET a parameter' ; db cr,lf,'SHOW the parameters' db cr,lf,'STATUS of Kermit$' sethlp db cr,lf,'BAUD rate' db cr,lf,'DEBUG' db cr,lf,'END-OF-LINE character' db cr,lf,'ESCAPE character change' db cr,lf,'FILE-WARNING' db cr,lf,'IBM' db cr,lf,'LOCAL-ECHO echoing (half-duplex)' db cr,lf,'PARITY type' ; db cr,lf,'RECEIVE parameter' ; db cr,lf,'SEND parameter' IF ibmpc db cr,lf,'VT52-EMULATION$' ENDIF IF Z100 OR SIRIUS db '$' ENDIF stshlp db cr,lf,'PAD-CHAR' db cr,lf,'PADDING$' onhlp db cr,lf,'OFF ON$' yeshlp db cr,lf,'NO YES$' parhlp db cr,lf,'None Mark Odd Even Space$' IF ibmpc bdhlp db cr,lf,'300 1200 1800 2400 4800 9600$' ENDIF IF SIRIUS bdhlp db cr,lf,'300 600 1200 2400 4800 9600$' ENDIF IF Z100 bdhlp db cr,lf,'45.5 50 75 110 134.5 150 300' db ' 600 1200 1800' db cr,lf,' 2000 2400 4800 9600 19200 38400' ENDIF eolhlp db cr,lf,'Decimal digit between 0 and 31$' eolerr db cr,lf,'Illegal end-of-line character$' inthlp db cr,lf,'? This message' db cr,lf,'B BREAK signal sent' db cr,lf,'C Close the connection' db cr,lf,'S Status of the connection' db cr,lf,'Typing the escape character will send it to the host' db cr,lf,cr,lf,'Command>$' rechlp db cr,lf,'Carriage return or file name & carriage return$' locst db cr,lf,'Local echo on$' remst db cr,lf,'Local echo off$' IF ibmpc vtemst db cr,lf,'VT52 emulation on$' novtst db cr,lf,'VT52 emulation off$' ENDIF ibmst db cr,lf,'IBM on$' noibm db cr,lf,'IBM off$' pnonst db cr,lf,'No parity$' poddst db cr,lf,'Odd parity$' pevnst db cr,lf,'Even parity$' pmrkst db cr,lf,'Mark parity$' pspcst db cr,lf,'Space parity$' IF Z100 b04st db cr,lf,'Baud rate is 45.5$' b05st db cr,lf,'Baud rate is 50$' b07st db cr,lf,'Baud rate is 75$' b11st db cr,lf,'Baud rate is 110$' b13st db cr,lf,'Baud rate is 134.5$' b15st db cr,lf,'Baud rate is 150$' b06st db cr,lf,'Baud rate is 600$' b20st db cr,lf,'Baud rate is 2000$' b19st db cr,lf,'Baud rate is 19200$' b38st db cr,lf,'Baud rate is 38400$' ENDIF b03st db cr,lf,'Baud rate is 300$' b06st db cr,lf,'Baud rate is 600$' b12st db cr,lf,'Baud rate is 1200$' b18st db cr,lf,'Baud rate is 1800$' b24st db cr,lf,'Baud rate is 2400$' b48st db cr,lf,'Baud rate is 4800$' b96st db cr,lf,'Baud rate is 9600$' debon db cr,lf,'Debug mode on$' deboff db cr,lf,'Debug mode off$' flwon db cr,lf,'File Warning on$' flwoff db cr,lf,'File Warning off$' eolst db cr,lf,'End-of-line character is ^$' escmes db cr,lf,'Escape character is $' outlin db cr,lf,' CUCCA' IF ibmpc db ' IBM-PC' ENDIF IF SIRIUS db ' Sirius I' ENDIF IF Z100 db '/Stevens Heath/Zenith Z-100' ENDIF db ' Kermit-86 CP/M-86 V1.1 ',cr,lf db cr,lf,'Number of packets (hex)' db cr,lf,'Number of retries (hex)' db cr,lf,'File name $' IF IBMPC OR Z100 delstr db 10O,' ',10O,10O,'$' ; Delete string. clrspc db ' ',10O,'$' ; Clear space. escspc db 10O,' ',10O,'$' ; Clear escape. ENDIF IF SIRIUS delstr db 10Q,'$' ; Delete string. clrspc db ' ',10Q,'$' ; Clear space. escspc db ' ',10Q,'$' ; Clear escape. ENDIF IF ibmpc clrlin db cr,'$' ; Clear line (just the cr part). ENDIF IF Z100 OR SIRIUS clrlin db cr,esc,'K$' ; Clear line clreol db esc,'K$' ; Clear to end of line clrscr db esc,'H',esc,'J$' ; Home and clear screen homcur db esc,'H$' ; Home cursor ENDIF prsp db ' $' ; Print a space. ; Cursor addressing items. IF ibmpc scrhi dw 0434H ; Err when 8th bit is on. scrrpr dw 0700H ; Prompt when Kermit ends. screrr dw 0600H ; Place for error msgs. scrfln dw 050CH ; Place for file name. scrnrt dw 0415H ; Place for number of retries. scrnp dw 0315H ; Place for number of packets. scrfr dw 0600H ; Rename file. scrst dw 0334H ; Place for status. scrsp dw 0800H ; Place for send packet. scrrp dw 0A00H ; Place for receive packet. ttab label word ; Table for cursor movement. ta dw curup ; Cursor up. tb dw curdwn ; Cursor down. tc dw currt ; Cursor right. td dw curlft ; Cursor left. te dw curskp ; Clear display. tf dw curskp ; Enter graphics mode. tg dw curskp ; Exit graphics mode. th dw curhm ; Cursor home. ti dw curup ; Reverse line feed. tj dw curscr ; Clear to end of screen. tk dw curln ; Clear to end of line. tl dw inslin ; Insert line. tm dw dellin ; Delete line. ENDIF IF Z100 OR SIRIUS scrhi db esc,'Y',23H,54H,lf,'$' ; 8th bit on in character scrrpr db esc,'Y',27H,20H,'$' ; Prompt when Kermit ends screrr db esc,'Y',26H,20H,'$' ; Error messages scrfln db esc,'Y',25H,2CH,'$' ; File name scrnrt db esc,'Y',23H,35H,lf,'$' ; Number of retries scrnp db esc,'Y',23H,35H,'$' ; Number of packets scrfr db esc,'Y',26H,20H,'$' ; Rename file scrst db esc,'Y',23H,54H,'$' ; Status scrsp db esc,'Y',28H,20H,'$' ; send packet scrrp db esc,'Y',2AH,20H,'$' ; Receive packet ENDIF ; COMND tables comtab db 0AH ; Ten entries. db 03H,'BYE$' dw bye db 07H,'CONNECT$' dw telnet db 04H,'EXIT$' dw exit db 06H,'FINISH$' dw finish db 04H,'HELP$' dw help db 06H,'LOGOUT$' dw logout db 07H,'RECEIVE$' dw read db 04H,'SEND$' dw send db 03H,'SET$' dw setcom db 06H,'STATUS$' dw status IF ibmpc settab db 09H ; Nine entries. ENDIF IF Z100 OR SIRIUS settab db 08H ; Eight entries. ENDIF db 04H,'BAUD$' dw baudst db 05H,'DEBUG$' dw debst db 0BH,'END-OF-LINE$' dw eolset db 06H,'ESCAPE$' dw escape db 0CH,'FILE-WARNING$' dw filwar db 03H,'IBM$' dw ibmset db 0AH,'LOCAL-ECHO$' dw lcal db 06H,'PARITY$' dw setpar IF ibmpc db 0EH,'VT52-EMULATION$' dw vt52em ENDIF ontab db 02H ; Two entries. db 02H,'ON$' dw 01H db 03H,'OFF$' dw 00H yestab db 02H ; Two entries. db 02H,'NO$' dw 00H db 03H,'YES$' dw 01H partab db 05H ; Five entries. db 04H,'EVEN$' dw PAREVN db 04H,'MARK$' dw PARMRK db 04H,'NONE$' dw PARNON db 03H,'ODD$' dw PARODD db 05H,'SPACE$' dw PARSPC IF SIRIUS bdtab db 06H ;Six entries. db 04H,'1200$' dw b1200 db 04H,'2400$' dw b2400 db 03H,'300$' dw b0300 db 04H,'4800$' dw b4800 db 03H,'600$' dw b0600 db 04H,'9600$' dw b9600 ENDIF IF ibmpc bdtab db 06H ; Six entries. db 04H,'1200$' dw B1200 db 04H,'1800$' dw B1800 db 04H,'2400$' dw B2400 db 03H,'300$' dw B0300 db 04H,'4800$' dw B4800 db 04H,'9600$' dw B9600 ENDIF IF Z100 bdtab db 010H ; 16 entries db 03H,'110$' dw b0110 db 04H,'1200$' dw b1200 db 03H,'134$' dw b01345 db 03H,'150$' dw b0150 db 04H,'1800$' dw b1800 db 05H,'19200$' dw b19200 db 04H,'2000$' dw b2000 db 04H,'2400$' dw b2400 db 03H,'300$' dw b0300 db 05H,'38400$' db b38400 db 02H,'45$' dw b00455 db 04H,'4800$' dw b4800 db 02H,'50$' dw b0050 db 03H,'600$' dw b0600 db 02H,'75$' dw b0075 db 04H,'9600$' dw b9600 ENDIF ; COMND storage cmer00 db cr,lf,'?Program error Invalid COMND call$' cmer01 db cr,lf,'?Ambiguous$' cmer02 db cr,lf,'?Illegal input file spec$' cmer03 db cr,lf,'?Unrecognized instruction$' cmer04 db cr,lf,'?Invalid command or operand$' cmin00 db ' Confirm with carriage return$' cmcrlf db cr,lf,'$' cmstat rb 1 ; What is presently being parsed. cmaflg rb 1 ; Non-zero when an action char has been found. cmccnt rb 1 ; Non-zero if a significant char is found. cmsflg rb 1 ; Non-zero when the last char was a space. cmostp rw 1 ; Old stack pointer for reparse. cmrprs rw 1 ; Address to go to on reparse. cmprmp rw 1 ; Address of prompt. cmptab rw 1 ; Address of present keyword table. cmhlp rw 1 ; Address of present help. cmdbuf rb 80H ; Buffer for command parsing. cmfcb rw 1 ; Pointer to FCB. cmfcb2 rw 1 ; Pointer to position in FCB. cmcptr rw 1 ; Pointer for next char input. cmdptr rw 1 ; Pointer into the command buffer. cmsiz rw 1 ; Size info of user input. cmkptr rw 1 ; Pointer to keyword. cmsptr rw 1 ; Place to save a pointer. cmchr rb 1 ; Save char when checking ambiguity. ; Program storage. oldstk rw 1 ; Storage for system stack. oldsts rw 1 ; System stack segment. ssp dw 0 ; Save SP in Telnet. bufhex dw 80H fcbnum db 0 ; No. of files found for wildcard. [3] fcbblk rb maxfil*40H ; Storage for FCBs during wildcard. [3] filsiz dw 0 ; Double word for filesize (in bytes.) dw 0 filerc db 0 ; File record count. fileex db 0 ; File extent count. eoflag rb 1 ; EOF flag; non-zero on EOF. wldflg db 0 ; Assume no "*" in fn. debug db 0 ; Debugging mode (default off). hierr db 0 ; Non-ascii char (non-zero if yes). filflg rb 1 ; Non-zero when nothing in DMA buffer. ecoflg db 0 ; Local echo flag (default off). parflg db defpar ; Parity flag (default none.) escflg db 0 ; Escape flag (start off). IF ibmpc vtflg db 1 ; VT52 emulation flag (default on). baud dw B4800 ; Use default of 4800. ENDIF IF SIRIUS baud dw B1200 ;Default baud rate 1200 ENDIF IF Z100 auxcnf rb 4 ; AUX port configuration info baud rb 1 ; Baud rate auxcnf1 rb 12 ; Rest of configuration info ENDIF flwflg db 0 ; File warning flag (default off). ibmflg db 0 ; IBM flag (default off). extflg db 0 ; Exit flag (default off). escchr db defesc ; Storage for the escape character. incnt rw 1 ; Number of chars read in from port. chrcnt rw 1 ; Number of chars in the file buffer. filcnt rw 1 ; Number of chars left to fill. outpnt rw 1 ; Position in packet. bufpnt rw 1 ; Position in file buffer. fcbptr rw 1 ; Position in FCB. datptr rw 1 ; Position in packet data buffer. cbfptr rw 1 ; Position in character buffer. pktptr rw 1 ; Poistion in receive packet. siz rw 1 ; Size of data from gtchr. spsiz db dspsiz ; Send packet size. rpsiz db drpsiz ; Receive packet size. stime db dstime ; Send time out. rtime db drtime ; Receive time out. spad db dspad ; Send padding. rpad db drpad ; Receive padding. spadch db dspadc ; Send padding char. rpadch db drpadc ; Receive padding char. seol db dseol ; Send EOL char. reol db dreol ; Receive EOL char. squote db dsquot ; Send quote char. rquote db drquot ; Receive quote char. pktnum rw 1 ; Packet number. numpkt rw 1 ; Total number of packets sent. numrtr rw 1 ; Total number of retries. numtry rb 1 ; Number of tries on this packet. oldtry rb 1 ; Number of tries on previous packet. state rb 1 ; Present state of the automaton. packet rb 4 ; Packet (data is part of it). data rb 5AH ; Data and checksum field of packet. recpkt rb 60H ; Receive packet storage (use the following). filbuf rb 60H ; Character buffer. fcb rb 25H ; Use as our FCB. cpfcb rb 25H ; Save FCB in case of "*". buff rb 80H ; Use as our DAT. rrbuf db 80H cnt dw 0 temp dw 0 temp1 rw 1 ; Temporary storage. temp2 rw 1 temp3 rw 1 temp4 rw 1 argblk rw 1 ; For subroutine arguments. argbk1 rw 1 argbk2 rw 1 argbk3 rw 1 CSEG ;START PROC FAR START: ; ASSUME CS:MAIN,DS:DATAS,SS:STACK,ES:NOTHING push ds ; Save system data area. sub ax,ax ; Get a zero. push ax ; Put zero return addr on stack. ; lds ax,word ptr datas ; Initialize DS. sub ax,ax mov oldstk,sp ; Save old stack pointer. mov ax,ss ; Save old SS. mov oldsts,ax mov bx,offset bpgstk ; Initialize SS. mov ax,[bx] mov ss,ax mov sp,ss:offset stk ; Initialize SP. sub ax,ax sub bx,bx ; Set DOS interrupt vector. push bx pop es mov es:word ptr .100h,offset int100 mov es:word ptr .102h,cs ; ; call cmblnk ; Clear screen. call locate mov ah,prstr ; Print the version header. mov dx,offset versio int dos mov ah,setdma ; Set disk transfer address. mov dx,offset buff int dos IF SIRIUS push bx mov bx,hware push bx pop es mov bl,bset mov es:byte ptr .btimer,bl mov bx,B1200 mov es:byte ptr .brate,bh mov es:byte ptr .brate,bl ; Initial baud rate is 1200. mov es:byte ptr .mpstat,crst ; Initialize port. mov es:byte ptr .mpstat,02h mov es:byte ptr .mpstat,nvnd mov es:byte ptr .mpstat,04h mov es:byte ptr .mpstat,a1snp mov es:byte ptr .mpstat,03h mov es:byte ptr .mpstat,re8b mov es:byte ptr .mpstat,05h mov es:byte ptr .mpstat,te8b pop bx ENDIF IF ibmpc mov dx,mdmcom ; LCR -- Initialize baud rate. in al,dx mov bl,al or ax,80H out dx,al mov dx,mdmdat mov ax,baud out dx,al inc dx mov al,ah out dx,al mov dx,mdmcom mov al,bl out dx,al ENDIF IF Z100 mov bx,ds ; Set up pointer to config info mov es,bx ; . . . mov bx,offset auxcnf ; . . . mov ah,chr_status ; Get the function code mov al,chr_sfgc ; And the subfunction to get config call bios_auxfunc ; Get the block ENDIF ; This is the main KERMIT loop. It prompts for and gets the users commands. kermit: mov dx,offset kerm call prompt ; Prompt the user. mov dx,offset comtab mov bx,offset tophlp mov ah,cmkey call comnd jmp kermt2 call bx ; Call the routine returned. jmp kermt3 cmp extflg,0 ; Check if the exit flag is set. jne krmend ; If so jump to KRMEND. jmp kermit ; Do it again. kermt2: mov ah,prstr mov dx,offset ermes1 ; Give an error. int dos jmp kermit kermt3: mov ah,prstr mov dx,offset ermes3 ; Give an error. int dos jmp kermit krmend: mov ax,oldsts ; Restore the old stack. mov ss,ax mov sp,oldstk mov dl,0 ; System reset mov ah,0 int dos ;START ENDP ; These are some utility routines. ; ; Interrupt 40h. Points at BDOS with correct registers. ; Save register values to simulate MS-DOS calls. ; Only works for subset of DOS calls. *********************** ; int100: push cx push bx push es mov cl,ah int bdos pop es pop bx pop cx iret ; Abort ;ABORT PROC NEAR ABORT: mov state,'A' ; Otherwise abort. ret ;ABORT ENDP ; NAK ;NAK PROC NEAR NAK: mov ax,pktnum ; Get the packet number we're waiting for. mov argblk,ax mov argbk1,0 mov ah,'N' ; NAK that packet. call spack jmp abort ret ; Go around again. ;NAK ENDP ; Position cursor for an error message. ;ERPOS PROC NEAR ERPOS: IF ibmpc mov ah,2 mov bh,0 mov dx,screrr int bios ret ENDIF IF Z100 OR SIRIUS mov dx,offset screrr ; Get address of string to position cursor mov ah,prstr ; Get the function code int dos ; Print the addressing string ret ; And return ENDIF ;ERPOS ENDP ; Position cursor for number of retries message. ;RTPOS PROC NEAR RTPOS: IF ibmpc mov ah,2 mov bh,0 mov dx,scrnrt int bios ret ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get the function to print string mov dx,offset scrnrt ; Get the address of the string int dos ; Print the string ret ; And return ENDIF ;RTPOS ENDP ; Print err message that found a non-standard-Ascii char in the file. ;BITERR PROC NEAR BITERR: push bx IF ibmpc mov ah,2 mov bh,0 mov dx,scrhi int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get the function to print string mov dx,offset scrhi ; Get the address of the string int dos ; Print the string ENDIF mov ah,prstr mov dx,offset hibit int dos pop bx ret ;BITERR ENDP ; This routine prints out the escape character in readable format. ;ESCPRT PROC NEAR ESCPRT: mov dl,escchr cmp dl,' ' jge escpr2 push dx mov ah,prstr mov dx,offset esctl int dos pop dx add dl,040H ; Make it printable. escpr2: mov ah,conout int dos ret ;ESCPRT ENDP ; FCB must be remembered if found "*" in filename. ; Copy from place addressed by BX to place addressed by DI. ; Also use to get the filename to the FCB from the DTA. ;FCBCPY PROC NEAR FCBCPY: fcbcp1: cmp cl,0 je fcbcp2 mov ah,[bx] mov [di],ah dec cl inc bx inc di jmp fcbcp1 fcbcp2: ret ;FCBCPY ENDP ; This routine sets up the data for init packet (either the ; Send_init or ACK packet). ;RPAR PROC NEAR RPAR: mov ah,rpsiz ; Get the receive packet size. add ah,' ' ; Add a space to make it printable. mov [bx],ah ; Put it in the packet. mov ah,rtime ; Get the receive packet time out. add ah,' ' ; Add a space. mov 1[bx],ah ; Put it in the packet. mov ah,rpad ; Get the number of padding chars. add ah,' ' mov 2[bx],ah ; Put it in the packet. mov ah,rpadch ; Get the padding char. add ah,100O ; Uncontrol it. and ah,7FH mov 3[bx],ah ; Put it in the packet. mov ah,reol ; Get the EOL char. add ah,' ' mov 4[bx],ah ; Put it in the packet. mov ah,rquote ; Get the quote char. mov 5[bx],ah ; Put it in the packet. mov ah,06H ; Six pieces of data. ret ;RPAR ENDP ; This routine reads in all the send_init packet information. ;SPAR PROC NEAR SPAR: mov temp4,ax ; Save the number of arguments. mov ah,[bx] ; Get the max packet size. sub ah,' ' ; Subtract a space. mov spsiz,ah ; Save it. mov ax,temp4 cmp al,3 ; Fewer than three pieces? jge spar1 ret ; If so we are done. spar1: mov ah,2[bx] ; Get the number of padding chars. sub ah,' ' mov spad,ah mov ax,temp4 cmp al,4 ; Fewer than four pieces? jge spar2 ret ; If so we are done. spar2: mov ah,3[bx] ; Get the padding char. add ah,100O ; Re-controlify it. and ah,7FH mov spadch,ah mov ax,temp4 cmp al,5 ; Fewer than five pieces? jge spar3 ret ; If so we are done. spar3: mov ah,4[bx] ; Get the EOL char. sub ah,' ' mov seol,ah mov ax,temp4 cmp al,6 ; Fewer than six pieces? jge spar4 ret ; If so we are done. spar4: mov ah,5[bx] ; Get the quote char. mov squote,ah ret ;SPAR ENDP ; Initialize buffers and clear line. ;INIT PROC NEAR INIT: call cmblnk call locate mov ah,prstr ; Put statistics headers on the screen. mov dx,offset outlin int dos call init1 ret ;INIT ENDP ;INIT1 PROC NEAR INIT1: mov chrcnt,bufsiz ;* Number of chars left. mov bufpnt,offset buff ; Addr for beginning. ret ;INIT1 ENDP ; Clear out the old filename on the screen. ;CLRFLN PROC NEAR CLRFLN: IF ibmpc mov ah,2 mov bh,0 mov dx,scrfln int bios mov ax,0920H ; Clear out the old filename. mov bx,7 mov cx,12 int bios ret ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrfln ; and string to move cursor int dos ; Print the string mov ah,prstr ; Get the function again mov dx,offset clreol ; And the sequence to clear to EOL int dos ; Do it ret ; And return ENDIF ;CLRFLN ENDP ; Put received packet number on screen. [2] ; PNSCR: IF ibmpc mov ah,2 mov dx,scrnp mov bh,0 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrnp ; and string to move cursor int dos ; Print the string ENDIF mov ax,numpkt call nout ; Write the number of packets. ret ; RECEIVE command ;READ PROC NEAR READ: mov bx,offset data ; Where to put text (if any). mov dx,offset rechlp ; Help message. mov ah,cmtxt call comnd ; Get text or confirm. jmp kermt3 cmp ah,0 ; Read in any chars? je read1 ; A regular receive. mov al,ah mov ah,0 mov argbk1,ax ; Remember number of chars we read. mov ah,'$' ; Use for printing. mov [bx],ah call init ; Clear line and initialize buffers. call clrfln ; Prepare to print filename. mov ah,prstr mov dx,offset data ; Print file name. int dos mov argblk,0 ; Start at packet zero. mov ah,'R' ; Receive init packet. call spack ; Send the packet. jmp kermt3 jmp read12 read1: call init ; Clear the line and initialize the buffers. read12: mov numpkt,0 ; Set the number of packets to zero. mov numrtr,0 ; Set the number of retries to zero. mov pktnum,0 ; Set the packet number to zero. mov numtry,0 ; Set the number of tries to zero. call pnscr ; Print packet no. call rtpos ; Position cursor. mov ax,numrtr call nout ; Write the number of retries. mov state,'R' ; Set the state to receive initiate. read2: ;IF ibmpc ; mov ah,2 ; Position cursor. ; mov dx,scrst ; mov bh,0 ; int bios ;ENDIF ;IF Z100 OR SIRIUS ; [2 start] Don't print status. ; mov ah,prstr ; Get print string function ; mov dx,offset scrst ; and string to move cursor ; int dos ; Print the string ;ENDIF ; mov ah,prstr ; Be informative. ; mov dx,offset infms1 ; int dos ; [2 end] mov ah,state ; Get the state. cmp ah,'D' ; Are we in the data send state? jne read3 call rdata jmp read2 read3: cmp ah,'F' ; Are we in the file receive state? jne read4 call rfile ; Call receive file. jmp read2 read4: cmp ah,'R' ; Are we in the receive initiate state? jne read5 call rinit jmp read2 read5: cmp ah,'C' ; Are we in the receive complete state? jne read6 IF ibmpc mov ah,2 ; Position cursor. mov dx,scrst mov bh,0 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrst ; and string to move cursor int dos ; Print the string ENDIF mov ah,prstr mov dx,offset infms3 ; Plus a little cuteness. int dos mov ah,prstr mov dx,offset ender ; Ring them bells. int dos IF ibmpc mov ah,2 mov dx,scrrpr ; Put prompt here. mov bh,0 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrrpr ; and string to move cursor int dos ; Print the string ENDIF jmp rskp read6: IF ibmpc mov ah,2 ; Position cursor. mov dx,scrst mov bh,0 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrst ; and string to move cursor int dos ; Print the string ENDIF mov ah,prstr mov dx,offset infms4 ; Plus a little cuteness. int dos mov ah,prstr mov dx,offset ender ; Ring them bells. int dos IF ibmpc mov ah,2 mov dx,scrrpr mov bh,0 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrrpr ; and string to move cursor int dos ; Print the string ENDIF jmp rskp ;READ ENDP ; Receive routines ; Receive init ;RINIT PROC NEAR RINIT: mov ah,numtry ; Get the number of tries. cmp ah,imxtry ; Have we reached the maximum number of tries? jl rinit2 call erpos ; Position cursor. mov dx,offset ermes7 mov ah,prstr int dos ; Print an error message. jmp abort ; Change the state to abort. rinit2: inc ah ; Increment it. mov numtry,ah ; Save the updated number of tries. call rpack ; Get a packet. jmp nak ; Trashed packet: nak, retry. cmp ah,'S' ; Is it a send initiate packet? jne rinit3 ; If not see if its an error. mov ah,numtry ; Get the number of tries. mov oldtry,ah ; Save it. mov numtry,0 ; Reset the number of tries. mov ax,argblk ; Returned packet number. (Synchronize them.) inc ax ; Increment it. and ax,3FH ; Turn off the two high order bits. mov pktnum,ax ; Save modulo 64 of the number. mov bx,numpkt inc bx ; Increment the number of packets. mov numpkt,bx mov ax,argbk1 ; Get the number of arguments received. mov bx,offset data ; Get a pointer to the data. call spar ; Get the data into the proper variables. mov bx,offset data ; Get a pointer to our data block. call rpar ; Set up the receive parameters. xchg ah,al mov ah,0 mov argbk1,ax ; Store the returned number of arguments. call pnscr ; [2] B.D. Print packet no. mov ah,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort mov ah,'F' ; Set the state to file send. mov state,ah ret rinit3: cmp ah,'E' ; Is it an error packet? jne rinit4 call error rinit4: jmp abort ;RINIT ENDP ; Receive file ;RFILE PROC NEAR RFILE: cmp numtry,maxtry ; Have we reached the maximum number of tries? jl rfile1 call erpos ; Position cursor. mov dx,offset ermes8 mov ah,prstr int dos ; Print an error message. jmp abort ; Change the state to abort. rfile1: inc numtry ; Save the updated number of tries. call rpack ; Get a packet. jmp nak ; Trashed packet: nak, retry. cmp ah,'S' ; Is it a send initiate packet? jne rfile2 ; No, try next type. cmp oldtry,imxtry ; Have we reached the maximum number of tries? jl rfil12 ; If not proceed. call erpos ; Position cursor. mov dx,offset ermes7 mov ah,prstr int dos ; Print an error message. jmp abort ; Change the state to abort. rfil12: inc oldtry ; Save the updated number of tries. mov ax,pktnum ; Get the present packet number. dec ax ; Decrement. cmp ax,argblk ; Is the packet's number one less than now? je rfil13 jmp nak ; No, NAK and try again. rfil13: call rtpos ; Position cursor. inc numrtr ; Increment the number of retries. mov ax,numrtr call nout ; Write the number of retries. mov numtry,0 ; Reset the number of tries. mov bx,offset data ; Get a pointer to our data block. call rpar ; Set up the parameter information. xchg ah,al mov ah,0 mov argbk1,ax ; Save the number of arguments. call pnscr ; [2] B.D. Print packet no. mov ah,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort ret rfile2: cmp ah,'Z' ; Is it an EOF packet? jne rfile3 ; No, try next type. cmp oldtry,maxtry ; Have we reached the maximum number of tries? jl rfil21 ; If not proceed. call erpos ; Position cursor. mov dx,offset ermes9 mov ah,prstr int dos ; Print an error message. jmp abort ; Change the state to abort. rfil21: inc oldtry ; Increment it. mov ax,pktnum ; Get the present packet number. dec ax ; Decrement. cmp ax,argblk ; Is the packet's number one less than now? je rfil24 jmp nak ; No, NAK and try again. rfil24: call rtpos ; Position cursor. inc numrtr ; Increment the number of retries mov ax,numrtr call nout ; Write the number of retries. mov numtry,0 mov argbk1,0 ; No data. (The packet number is in argblk.) call pnscr ; [2] B.D. Print packet no. mov ah,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort ret rfile3: cmp ah,'F' ; Start of file? jne rfile4 mov ax,argblk ; Get the packet number. cmp ax,pktnum ; Is it the right packet number? je rfil32 jmp nak ; No, NAK it and try again. rfil32: inc ax ; Increment the packet number. and ax,3FH ; Turn off the two high order bits. mov pktnum,ax ; Save modulo 64 of the number. inc numpkt ; Increment the number of packets. call gofil ; Get a file to write to. jmp abort call init1 ; Initialize all the buffers. mov ah,numtry ; Get the number of tries. mov oldtry,ah ; Save it. mov numtry,0 ; Reset the number of tries. mov argbk1,0 ; No data. (The packet number is in argblk.) call pnscr ; [2] B.D. Print packet no. mov ah,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort mov state,'D' ; Set the state to data receive. ret rfile4: cmp ah,'B' ; End of transmission. jne rfile5 mov ax,pktnum cmp ax,argblk ; Do we match? je rfil41 jmp nak ; No, NAK it and try again. rfil41: mov argbk1,0 ; No data. (Packet number already in argblk). call pnscr ; [2] B.D. Print packet no. mov ah,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort mov state,'C' ; Set the state to complete. ret rfile5: cmp ah,'E' ; Is it an error packet. jne rfile6 call error rfile6: jmp abort ;RFILE ENDP ; Receive data ;RDATA PROC NEAR RDATA: cmp numtry,maxtry ; Get the number of tries. jl rdata1 call erpos ; Position cursor. mov dx,offset erms10 mov ah,prstr int dos ; Print an error message. jmp abort ; Change the state to abort. rdata1: inc numtry ; Save the updated number of tries. call rpack ; Get a packet. jmp nak ; Trashed packet: nak, retry. cmp ah,'D' ; Is it a data packet? je rdat11 jmp rdata2 ; No, try next type. rdat11: mov ax,pktnum ; Get the present packet number. cmp ax,argblk ; Is the packet's number correct? jz rdat14 cmp oldtry,maxtry ; Have we reached the maximum number of tries? jl rdat12 ; If not proceed. call erpos ; Position cursor. mov dx,offset erms10 mov ah,prstr int dos ; Print an error message. jmp abort ; Change the state to abort. rdat12: inc oldtry ; Save the updated number of tries. dec pktnum ; Decrement present packet number. mov ax,pktnum cmp ax,argblk ; Is the packet's number one less than now? je rdat13 jmp nak ; No, NAK it and try again. rdat13: call rtpos ; Position cursor. inc numrtr ; Increment the number of retries mov ax,numrtr call nout ; Write the number of retries. mov numtry,0 ; Reset number of tries. mov argbk1,0 ; No data. (The packet number is in argblk.) call pnscr ; [2] B.D. Print packet no. mov ah,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort ret rdat14: inc ax ; Increment the packet number. and ax,3FH ; Turn off the two high order bits. mov pktnum,ax ; Save modulo 64 of the number. inc numpkt ; Increment the number of packets. mov ah,numtry ; Get the number of tries. mov oldtry,ah ; Save it. mov ax,argbk1 ; Get the length of the data. call ptchr jmp abort ; Unable to write out chars; abort. mov numtry,0 ; Reset the number of tries. mov argbk1,0 ; No data. (Packet number still in argblk.) call pnscr ; [2] B.D. Print packet no. mov ah,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort ret rdata2: cmp ah,'F' ; Start of file? jne rdata3 ; No, try next type. cmp oldtry,maxtry ; Have we reached the maximum number of tries? jl rdat21 ; If not proceed. call erpos ; Position cursor. mov dx,offset ermes8 mov ah,prstr int dos ; Print an error message. jmp abort ; Change the state to abort. rdat21: inc oldtry ; Save the updated number of tries. mov ax,pktnum cmp ax,argblk ; Is the packet's number one less than now? je rdat22 jmp nak ; No, NAK it and try again. rdat22: call rtpos ; Position cursor. inc numrtr ; Increment the number of retries mov ax,numrtr call nout ; Write the number of retries. mov numtry,0 ; Reset number of tries. mov argbk1,0 ; No data. (The packet number is in argblk.) call pnscr ; [2] B.D. Print packet no. mov ah,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort ret rdata3: cmp ah,'Z' ; Is it a EOF packet? je rdat3x jmp rdata4 ; Try and see if its an error. rdat3x: mov ax,pktnum ; Get the present packet number. cmp ax,argblk ; Is the packet's number correct? je rdat32 jmp nak ; No, NAK it and try again. rdat32: inc ax ; Increment the packet number. and ax,3FH ; Turn off the two high order bits. mov pktnum,ax ; Save modulo 64 of the number. inc numpkt rdat33: mov bx,bufpnt ; Get the dma pointer. mov ax,80H sub ax,chrcnt ; Get the number of chars left in the DMA. cmp ax,80H jne rdat34 call outbuf ; Write out buffer if no room for ^Z. jmp abort mov ax,0 rdat34: mov cl,'Z'-100O ; Put in a ^Z for EOF. mov [bx],cl inc ax dec chrcnt mov cx,chrcnt mov temp,cx inc bx rdt3: inc ax cmp ax,80H jg rdat35 ; Pad till full. mov cl,0 ; Use nulls. mov [bx],cl inc bx jmp rdt3 rdat35: call outbuf ; Output the last buffer. jmp abort ; Give up if the disk is full. ; call fixfcb ; *** MS-DOS only *** mov ah,closf ; Close up the file. mov dx,offset fcb int dos mov ah,numtry ; Get the number of tries. mov oldtry,ah ; Save it. mov numtry,0 ; Reset the number of tries. mov argbk1,0 ; No data. (The packet number is in argblk.) call pnscr ; [2] B.D. Print packet no. mov ah,'Y' ; Acknowledge packet. call spack ; Send the packet. jmp abort mov state,'F' ret rdata4: cmp ah,'E' ; Is it an error packet. jne rdata5 call error rdata5: jmp abort ;RDATA ENDP ;FIXFCB PROC NEAR FIXFCB: mov bx,offset fcb+18 mov di,offset filsiz mov ax,[bx] mov [di],ax mov bx,offset fcb+16 mov ax,[bx] mov 2[di],ax mov ax,temp ; Get number of chars in last buffer full. sub filsiz+2,ax ; Get real file size. sbb filsiz,0 mov bx,offset fcb+18 mov di,offset filsiz mov ax,[di] mov [bx],ax mov bx,offset fcb+16 mov ax,2[di] mov [bx],ax ret ;FIXFCB ENDP ; Send command ;SEND PROC NEAR SEND: mov ah,cmifi ; Parse an input file spec. mov dx,offset fcb ; Give the address for the FCB. call comnd jmp r ; Give up on bad parse. send1: mov ah,cmcfm call comnd ; Get a confirm. jmp r ; Didn't get a confirm. send11: mov ah,sfirst ; Get the first file. mov dx,offset fcb int dos cmp al,0FFH ; Any found? jne send12 mov ah,prstr ; Complain about no files found mov dx,offset crlf int dos mov ah,prstr mov dx,offset erms15 int dos ret send14: call erpos ; Tell that too many files match [3 start] mov ah,prstr ; wildcard spec. mov dx,offset erms20 int dos jmp send15 send12: cmp wldflg,0 ; Wildcard? je send16 send13: rol al,1 ; Get offset into DMA buffer rol al,1 rol al,1 rol al,1 rol al,1 mov bx,ax add bx,offset buff mov si,offset fcb mov al,[si] mov [bx],al ; Copy in disk name given in command. mov al,fcbnum cmp al,maxfil ; Have we reached the max. number of files? jg send14 mov cl,6 ; If not, copy from DMA buffer into rol al,cl ; next slot in FCB storage area. mov di,offset fcbblk add di,ax mov cl,24H call fcbcpy inc fcbnum mov ah,snext ; Get the next FCB mov dx,offset fcb int dos cmp al,0ffH ; Any more files match wildcard? jne send13 ; If so, get next [3 end] send15: dec fcbnum ; We are ready to process first file, mov bx,offset fcbblk ; so fetch it's FCB from storage. mov al,fcbnum mov cl,6 rol al,cl mov ah,0 add bx,ax mov di,offset fcb mov cl,24H call fcbcpy send16: call init ; Clear the line and initialize the buffers. mov pktnum,0 ; Set the packet number to zero. mov numtry,0 ; Set the number of tries to zero. mov numpkt,0 ; Set the number of packets to zero. mov numrtr,0 ; Set the number of retries to zero. call rtpos ; Position cursor. mov ax,0 call nout ; Write the number of retries. mov state,'S' ; Set the state to receive initiate. send2: ;IF ibmpc ; [2 start] B.D. ; mov ah,2 ; Position cursor. ; mov bh,0 ; mov dx,scrst ; int bios ;ENDIF ;IF Z100 OR SIRIUS ; mov ah,prstr ; Get print string function ; mov dx,offset scrst ; and string to move cursor ; int dos ; Print the string ;ENDIF ; mov ah,prstr ; Be informative. ; mov dx,offset infms2 ; int dos ; [2 end] B.D. IF ibmpc mov ah,2 mov dx,scrnp mov bh,0 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrnp ; and string to move cursor int dos ; Print the string ENDIF mov ax,numpkt call nout ; Write the packet number. cmp state,'D' ; Are we in the data send state? jne send3 call sdata jmp send2 send3: cmp state,'F' ; Are we in the file send state? jne send4 call sfile ; Call send file. jmp send2 send4: cmp state,'Z' ; Are we in the EOF state? jne send5 call seof jmp send2 send5: cmp state,'S' ; Are we in the send initiate state? jne send6 call sinit jmp send2 send6: cmp state,'B' ; Are we in the eot state? jne send7 call seot jmp send2 send7: cmp state,'C' ; Are we in the send complete state? jne send8 IF ibmpc mov ah,2 ; Position cursor. mov dx,scrst mov bh,0 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrst ; and string to move cursor int dos ; Print the string ENDIF mov ah,prstr mov dx,offset infms3 ; Plus a little cuteness. int dos mov ah,prstr mov dx,offset ender ; Ring them bells. int dos IF ibmpc mov ah,2 mov dx,scrrpr mov bh,0 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrrpr ; and string to move cursor int dos ; Print the string ENDIF jmp rskp send8: IF ibmpc mov ah,2 ; Position cursor. mov dx,scrst mov bh,0 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrst ; and string to move cursor int dos ; Print the string ENDIF mov ah,prstr mov dx,offset infms4 ; Plus a little cuteness. int dos mov ah,prstr mov dx,offset ender ; Ring them bells. int dos IF ibmpc mov ah,2 mov dx,scrrpr mov bh,0 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrrpr ; and string to move cursor int dos ; Print the string ENDIF jmp rskp ;SEND ENDP ; Send routines ; Send initiate ;SINIT PROC NEAR SINIT: cmp numtry,imxtry ; Have we reached the maximum number of tries? jl sinit2 call erpos mov dx,offset erms14 mov ah,prstr int dos ; Print an error message. jmp abort ; Change the state to abort. sinit2: inc numtry ; Save the updated number of tries. mov bx,offset data ; Get a pointer to our data block. call rpar ; Set up the parameter information. xchg ah,al mov ah,0 mov argbk1,ax ; Save the number of arguments. mov ax,numpkt ; Get the packet number. mov argblk,ax mov ah,'S' ; Send initiate packet. call spack ; Send the packet. jmp abort call rpack ; Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah,'Y' ; ACK? jne sinit3 ; If not try next. mov ax,pktnum ; Get the packet number. cmp ax,argblk ; Is it the right packet number? je sini22 ret ; If not try again. sini22: inc ax ; Increment the packet number. and ax,3FH ; Turn off the two high order bits. mov pktnum,ax ; Save modulo 64 of the number. inc numpkt ; Increment the number of packets. mov ax,argbk1 ; Get the number of pieces of data. mov bx,offset data ; Pointer to the data. call spar ; Read in the data. mov ah,numtry ; Get the number of tries. mov oldtry,ah ; Save it. mov numtry,0 ; Reset the number of tries. mov state,'F' ; Set the state to file send. call getfil ; Open the file. jmp abort ; Something is wrong, die. ret sinit3: cmp ah,'N' ; NAK? jne sinit4 ; If not see if its an error. call rtpos ; Position cursor. inc numrtr ; Increment the number of retries mov ax,numrtr call nout ; Write the number of retries. mov ax,pktnum ; Get the present packet number. inc ax ; Increment. cmp ax,argblk ; Get the packet's number. je sini32 ret ; If not assume its for this packet, go again. sini32: mov numtry,0 ; Reset number of tries. mov state,'F' ; Set the state to file send. ret sinit4: cmp ah,'E' ; Is it an error packet. jne sinit5 call error sinit5: jmp abort ;SINIT ENDP ; Send file header ;SFILE PROC NEAR SFILE: cmp numtry,maxtry ; Have we reached the maximum number of tries? jl sfile1 call erpos mov dx,offset erms14 mov ah,prstr int dos ; Print an error message. jmp abort ; Change the state to abort. sfile1: inc numtry ; Increment it. mov datptr,offset data ; Get a pointer to our data block. mov bx,offset fcb+1 ; Pointer to file name in FCB. mov fcbptr,bx ; Save position in FCB. mov cl,0 ; Counter for chars in file name. mov ch,0 ; Counter for number of chars in FCB. sfil11: cmp ch,8H ; Ninth char? jne sfil12 mov ah,'.' mov bx,datptr mov [bx],ah ; Put dot in data packet. inc bx mov datptr,bx ; Save new position in data packet. inc cl sfil12: inc ch cmp ch,0CH ; Twelve? jns sfil13 mov bx,fcbptr mov ah,[bx] ; Get char of filename. inc bx mov fcbptr,bx ; Save position in FCB. cmp ah,'!' ; Is it a good char? jl sfil11 ; If not, get the next. mov bx,datptr mov [bx],ah ; Put char in data buffer. inc cl ; Increment counter. inc bx mov datptr,bx ; Save new position. jmp sfil11 ; Get another char. sfil13: mov ch,0 mov argbk1,cx ; Save number of char in filename. mov bx,datptr mov ah,'$' mov [bx],ah ; Put dollar sign for printing. call clrfln mov ah,prstr mov dx,offset data ; Print file name. int dos mov ax,pktnum ; Get the packet number. mov argblk,ax mov ah,'F' ; File header packet. call spack ; Send the packet. jmp abort call rpack ; Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah,'Y' ; ACK? jne sfile2 ; If not try next. mov ax,pktnum ; Get the packet number. cmp ax,argblk je sfil14 ret ; If not hold out for the right one. sfil14: inc ax ; Increment the packet number. and ax,3FH ; Turn off the two high order bits. mov pktnum,ax ; Save modulo 64 of the number. inc numpkt ; Increment the number of packets. mov ah,numtry ; Get the number of tries. mov oldtry,ah ; Save it. mov numtry,0 ; Reset the number of tries. ;* More file I/O. Anything to do with the CP/M FCB must be checked for MS-DOS. sfil15: mov ah,0 ; Get a zero. mov bx,offset fcb add bx,20H mov [bx],ah ; Set the record number to zero. mov eoflag,ah ; Indicate not EOF. mov ah,0FFH mov filflg,ah ; Indicate file buffer empty. call gtchr jmp sfil16 ; Error go see if its EOF. jmp sfil17 ; Got the chars, proceed. sfil16: cmp ah,0FFH ; Is it EOF? je sfl161 jmp abort ; If not give up. sfl161: mov ah,'Z' ; Set the state to EOF. mov state,ah ret sfil17: mov siz,ax ;* mov state,'D' ; Set the state to data send. ret sfile2: cmp ah,'N' ; NAK? jne sfile3 ; Try if error packet. call rtpos ; Position cursor. inc numrtr ; Increment the number of retries mov ax,numrtr call nout ; Write the number of retries. mov ax,pktnum ; Get the present packet number. inc ax ; Increment. cmp ax,argblk ; Is the packet's number one more than now? jz sfil14 ; Just as good as a ACK; go to the ACK code. ret ; If not go try again. sfile3: cmp ah,'E' ; Is it an error packet. jne sfile4 call error sfile4: jmp abort ;SFILE ENDP ; Send data ;SDATA PROC NEAR SDATA: cmp numtry,maxtry ; Have we reached the maximum number of tries? jl sdata1 call erpos mov dx,offset erms14 mov ah,prstr int dos ; Print an error message. jmp abort ; Change the state to abort. sdata1: inc numtry ; Increment it. mov datptr,offset data ; Get a pointer to our data block. mov cbfptr,offset filbuf ; Pointer to chars to be sent. mov cx,1 ; First char. sdat11: mov bx,cbfptr mov ah,[bx] inc cbfptr mov bx,datptr mov [bx],ah ; Put the char in the data packet. inc datptr ; Save position in data packet. inc cx ; Increment the count. cmp cx,siz ; Have we transfered that many? jle sdat11 ; If not get another. mov ax,siz ; Number of char in char buffer. mov argbk1,ax mov ax,pktnum ; Get the packet number. mov argblk,ax mov ah,'D' ; Data packet. call spack ; Send the packet. jmp abort call rpack ; Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah,'Y' ; ACK? jne sdata2 ; If not try next. mov ax,pktnum ; Get the packet number. cmp ax,argblk ; Is it the right packet number? jz sdat12 ret ; If not hold out for the right one. sdat12: inc ax ; Increment the packet number. and ax,3FH ; Turn off the two high order bits. mov pktnum,ax ; Save modulo 64 of the number. inc numpkt ; Increment the number of packets. mov ah,numtry ; Get the number of tries. mov oldtry,ah ; Save it. mov numtry,0 ; Reset the number of tries. call gtchr jmp sdat13 ; Error go see if its EOF. mov siz,ax ; Save the size of the data gotten. ret ;* File I/O. sdat13: cmp ah,0FFH ; Is it EOF? je sdt131 jmp abort ; If not give up. ;* sdt131: mov state,'Z' ; Set the state to EOF. ret sdata2: cmp ah,'N' ; NAK? jne sdata3 ; See if is an error packet. call rtpos ; Position cursor. inc numrtr ; Increment the number of retries mov ax,numrtr call nout ; Write the number of retries. mov ax,pktnum ; Get the present packet number. inc ax ; Increment. cmp ax,argblk ; Is the packet's number one more than now? jz sdat12 ; Just as good as ACK; goto ACK code. ret ; If not go try again. sdata3: cmp ah,'E' ; Is it an error packet. jne sdata4 call error sdata4: jmp abort ;SDATA ENDP ; Send EOF ;SEOF PROC NEAR SEOF: cmp numtry,maxtry ; Have we reached the maximum number of tries? jl seof1 call erpos ; Position cursor. mov dx,offset erms14 mov ah,prstr int dos ; Print an error message. jmp abort ; Change the state to abort. seof1: inc numtry ; Increment it. mov ax,pktnum ; Get the packet number. mov argblk,ax mov argbk1,0 ; No data. mov ah,'Z' ; EOF packet. call spack ; Send the packet. jmp abort call rpack ; Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah,'Y' ; ACK? jne seof2 ; If not try next. mov ax,pktnum ; Get the packet number. cmp ax,argblk ; Is it the right packet number? jz seof12 ret ; If not hold out for the right one. seof12: inc ax ; Increment the packet number. and ax,3FH ; Turn off the two high order bits. mov pktnum,ax ; Save modulo 64 of the number. inc numpkt ; Increment the number of packets. mov ah,numtry ; Get the number of tries. mov oldtry,ah ; Save it. mov numtry,0 ; Reset the number of tries. mov ah,closf ; Close the file. mov dx,offset fcb int dos ;* Check if successful call gtnfil ; Get the next file. jmp seof13 ; No more. mov state,'F' ; Set the state to file send. ret seof13: mov state,'B' ; Set the state to EOT. ret seof2: cmp ah,'N' ; NAK? jne seof3 ; Try and see if its an error packet. call rtpos ; Position cursor. inc numrtr ; Increment the number of retries mov ax,numrtr call nout ; Write the number of retries. mov ax,pktnum ; Get the present packet number. inc ax ; Increment. cmp ax,argblk ; Is the packet's number one more than now? jz seof12 ; Just as good as a ACK; go to the ACK code. ret ; If not go try again. seof3: cmp ah,'E' ; Is it an error packet? jne seof4 call error seof4: jmp abort ;SEOF ENDP ; Send EOT ;SEOT PROC NEAR SEOT: cmp numtry,maxtry ; Have we reached the maximum number of tries? jl seot1 call erpos ; Position cursor. mov dx,offset erms14 mov ah,prstr int dos ; Print an error message. jmp abort ; Change the state to abort. seot1: inc numtry ; Increment it. mov ax,pktnum ; Get the packet number. mov argblk,ax mov argbk1,0 ; No data. mov ah,'B' ; EOF packet. call spack ; Send the packet. jmp abort call rpack ; Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah,'Y' ; ACK? jne seot2 ; If not try next. mov ax,pktnum ; Get the packet number. cmp ax,argblk ; Is it the right packet number? jz seot12 ret ; If not hold out for the right one. seot12: inc ax ; Increment the packet number. and ax,3FH ; Turn off the two high order bits. mov pktnum,ax ; Save modulo 64 of the number. inc numpkt ; Increment the number of packets. mov ah,numtry ; Get the number of tries. mov oldtry,ah ; Save it. mov numtry,0 ; Reset the number of tries. mov state,'C' ; Set the state to file send. ret seot2: cmp ah,'N' ; NAK? jne seot3 ; Is it error. call rtpos ; Position cursor. inc numrtr ; Increment the number of retries mov ax,numrtr call nout ; Write the number of retries. mov ax,pktnum ; Get the present packet number. inc ax ; Increment. cmp ax,argblk ; Is the packet's number one more than now? jz seot12 ; Just as good as a ACK; go to the ACK code. ret ; If not go try again. seot3: cmp ah,'E' ; Is it an error packet. jne seot4 call error seot4: jmp abort ;SEOT ENDP ;* Here is the bulk of the file I/O. Good luck. ; File routines ; Output the chars in a packet. ;FILEIO PROC NEAR FILEIO: ptchr: mov temp1,ax ; Save the size. mov bx,offset data ; Beginning of received packet data. mov outpnt,bx ; Remember where we are. mov ch,rquote ; Quote char. ptchr1: dec temp1 ; Decrement # of chars in packet. jnl pt1 jmp rskp ; Return successfully if done. pt1: dec chrcnt ; Decrement number of chars in dta. jns ptchr2 ; Continue if space left. call outbuf ; Output it if full. jmp r ; Error return if disk is full. ptchr2: mov bx,outpnt ; Get position in output buffer. mov ah,[bx] ; Grab a char. inc bx mov outpnt,bx ; and bump pointer. cmp ah,ch ; Is it the quote char? jne ptchr4 ; If not proceed. mov ah,[bx] ; Get the quoted character inc bx mov outpnt,bx ; and bump pointer. dec temp1 ; Decrement # of chars in packet. mov dh,ah ; Save the char. and ah,80H ; Turn off all but the parity bit. mov dl,ah ; Save the parity bit. mov ah,dh ; Get the char. and ah,7FH ; Turn off the parity bit. cmp ah,ch ; Is it the quote char? jz ptchr3 ; If so just go write it out. mov ah,dh ; Get the char. add ah,40H ; Make it a control char again. and ah,7FH ; Modulo 128. ptchr3: or ah,dl ; Or in the parity bit. ptchr4: mov bx,bufpnt ; Destination buffer. mov [bx],ah ; Store it. inc bx mov bufpnt,bx ; Update the pointer jmp ptchr1 ; and loop to next char. ; output the buffer, reset bufpnt and chrcnt outbuf: push bx mov ah,writef ; The write code. mov dx,offset fcb int dos ; Write the record. pop bx cmp al,0 ; Successful. jz outbf1 cmp al,01 jz outbf0 call erpos mov ah,prstr mov dx,offset erms17 ; Record length exceeds dta. int dos ret outbf0: call erpos mov ah,prstr ; Tell about it. mov dx,offset erms11 ; Disk full error. int dos ret outbf1: mov bx,offset buff ; Addr for beginning. mov bufpnt,bx ; Store addr for beginning. mov ax,bufsiz-1 ; Buffer size. mov chrcnt,ax ; Number of chars left. jmp rskp ; Get the chars from the file. gtchr: mov ch,squote ; Keep quote char in c. mov ah,filflg ; Get the file flag. cmp ah,0 ; Is there anything in the DMA? jz gtchr0 ; Yup, proceed. mov cl,0 ; No chars yet. call inbuf jmp gtceof ; No more chars, go return EOF. gtchr0: mov al,spsiz ; Get the maximum packet size. sub al,5 ; Subtract the overhead. mov ah,0 mov temp1,ax ; Number of chars we're to get. mov bx,offset filbuf ; Where to put the data. mov cbfptr,bx ; Remember where we are. mov cl,0 ; No chars. gtchr1: dec temp1 ; Decrement the number of chars left. jns gtchr2 ; Go on if there is more than one left. mov al,cl ; Return the count in A. mov ah,0 jmp rskp gtchr2: mov ax,chrcnt dec ax jl gtchr3 mov chrcnt,ax jmp gtchr4 gtchr3: call inbuf ; Get another buffer full. jmp gtceof cmp chrcnt,0 jne gtchr4 sub cl,2 ; Don't count controllified Z. mov al,cl mov ah,0 jmp rskp gtchr4: mov bx,bufpnt ; Position in DMA. mov ah,[bx] ; Get a char from the file. inc bx mov bufpnt,bx mov dh,ah ; Save the char. and ah,80H ; Turn off all but parity. mov dl,ah ; Save the parity bit. mov ah,dh ; Restore the char. and ah,7FH ; Turn off the parity. cmp ah,' ' ; Compare to a space. jl gtchr5 ; If less then its a control char, handle it. cmp ah,del ; Is the char a delete? jz gtchr5 ; Go quote it. cmp ah,ch ; Is it the quote char? jne gtchr8 ; If not proceed. dec temp1 ; Decrement the char total remaining. mov bx,cbfptr ; Position in character buffer. mov [bx],ah ; Put the char in the buffer. inc bx mov cbfptr,bx inc cl ; Increment the char count. jmp gtchr8 gtchr5: or ah,dl ; Turn on the parity bit. cmp ah,('Z'-100O) ; Is it a ^Z? jne gtchr7 ; If not just proceed. mov ah,eoflag ; EOF flag set? cmp ah,0 jz gtchr6 ; If not just go on. mov bx,bufpnt mov ax,chrcnt mov dh,al ; Get number of chars left in DMA. gtch51: dec dh mov ah,dh mov chrcnt,0 ; Assume end-of-file at ^Z. [2]**************** mov al,cl ; Return the count in A. mov ah,0 jmp rskp gtchr6: mov ah,('Z'-100O) ; Restore the ^Z. gtchr7: xchg ah,al mov ah,0 mov temp2,ax ; Save the char. dec temp1 ; Decrement char counter. mov bx,cbfptr ; Position in character buffer. mov [bx],ch ; Put the quote in the buffer. inc bx mov cbfptr,bx inc cl ; Increment the char count. mov ax,temp2 ; Get the control char back. xchg al,ah add ah,40H ; Make the non-control. and ah,7fH ; Modulo 200 octal. gtchr8: mov bx,cbfptr ; Position in character buffer. or ah,dl ; Or in the parity bit. mov [bx],ah ; Put the char in the buffer. inc bx mov cbfptr,bx inc cl ; Increment the char count. jmp gtchr1 ; Go around again. gtceof: cmp cl,0 ; Had we gotten any data? je gteof0 ; Nope. mov al,cl mov ah,0 jmp rskp gteof0: mov ah,0FFH ; Get a minus one. ret inbuf: mov ah,eoflag ; Have we reached the end? cmp ah,0 jz inbuf0 ret ; Return if set. ;****** CP/M-86 rewrite ********* B.D. inbuf0: push bx push cx cmp filflg,0 ; Ever used DMA? jz inbuf1 ; Yes, then go fix buffer size. mov filflg,0 ; Otherwise, zero flag and mov chrcnt,bufsiz ; set character count to 80H. jmp inbuf2 inbuf1: mov chrcnt,bufsiz-1 ; Boundary error fixed. inbuf2: mov bx,offset buff mov bufpnt,bx mov ah,readf ; Read the record. mov dx,offset fcb int dos pop cx pop bx dec filerc ; Another 128 chars. sent. jz inbf21 ; Is this the last record in the extent? jmp rskp ; No. inbf21: cmp fileex,0 ; Any more extents? jz inbuf3 ; No more, go set EOF flag. dec fileex mov filerc,bufsiz ; Reset record count to 128 records. jmp rskp inbuf3: mov eoflag,0ffh ; Set EOF flag. jmp rskp ;****** CP/M-86 rewrite end. ******* getfil: mov ah,0FFH mov filflg,ah ; Nothing in the DMA. mov ax,0 mov eoflag,ah ; Not the end of file. mov bx,offset fcb+0CH mov [bx],ax ; Zero the current block number. mov bx,offset fcb+0EH mov [bx],ax ; Ditto for Lrecl. mov bx,offset fcb+20H mov [bx],ah ; Zero the current record (of block). inc bx mov [bx],ax ; Same for record (of file). mov bx,offset fcb+23H mov [bx],ax mov ah,openf ; Open the file. mov dx,offset fcb int dos ;****** CP/M-86 rewrite ****** B.D. mov ah,cflsz ; Calculate file-size. mov dx, offset fcb int dos mov bx,offset fcb+21h ; Get R0 mov al,[bx] cmp al,0 jl getfi1 mov ah,0 jmp getfi2 getfi1: mov ah,1 getfi2: and al,07fh mov filerc,al mov bx,offset fcb+22h ; Get R1 mov al,[bx] rcl al,1 or al,ah mov fileex,al jmp rskp ;****** CP/M-86 rewrite end. (Taken from CP/M-80 version) ****** gtnfil: cmp wldflg,0 ; Was there a "*"? [3 start] je gtn5 ; Nope. mov di,offset fcb ; Fetch next FCB from storage. mov bx,offset fcbblk dec fcbnum mov al,fcbnum cmp al,0 jl gtn5 mov cl,6 rol al,cl mov ah,0 add bx,ax mov cl,24H call fcbcpy ; [3 end] call getfil ; Initialize jmp r jmp rskp gtn5: mov wldflg,0 ; Reset wild card flag. ret ; Get the file name (including host to micro translation) gofil: mov bx,offset data ; Get the address of the file name. mov datptr,bx ; Store the address. mov bx,offset fcb+1 ; Address of the FCB. mov fcbptr,bx ; Save it. mov ax,0 mov temp1,ax ; Initialize the char count. mov temp2,ax mov si,offset fcb mov [si],ah ; Set the drive to default to current. mov ch,' ' gofil1: mov [bx],ch ; Blank the FCB. inc bx inc ah cmp ah,0BH ; Twelve? jl gofil1 gofil2: mov bx,datptr ; Get the NAME field. mov ah,[bx] inc bx mov datptr,bx cmp ah,'.' ; Seperator? jne gofil3 mov bx,offset fcb+9H mov fcbptr,bx mov ax,temp1 mov temp2,ax mov temp1,9H jmp gofil6 gofil3: cmp ah,0 ; Trailing null? jz gofil7 ; Then we're done. mov bx,fcbptr mov [bx],ah inc bx mov fcbptr,bx mov ax,temp1 ; Get the char count. inc ax mov temp1,ax cmp ax,8H ; Are we finished with this field? jl gofil2 gofil4: mov temp2,ax mov bx,datptr mov ah,[bx] inc bx mov datptr,bx cmp ah,0 jz gofil7 cmp ah,'.' ; Is this the terminator? jne gofil4 ; Go until we find it. gofil6: mov bx,datptr ; Get the TYPE field. mov ah,[bx] inc bx mov datptr,bx cmp ah,0 ; Trailing null? jz gofil7 ; Then we're done. mov bx,fcbptr mov [bx],ah inc bx mov fcbptr,bx inc temp1 ; Increment char count. cmp temp1,0CH ; Are we finished with this field? jl gofil6 gofil7: mov bx,datptr mov ah,'$' mov [bx],ah ; Put in a dollar sign for printing. call clrfln mov ah,prstr ; Print the file name. mov dx,offset data int dos mov ah,flwflg ; Is file warning on? cmp ah,0 jnz gf7x jmp gofil9 ; If not, just proceed. gf7x: mov ah,openf ; See if the file exists. mov dx,offset fcb int dos cmp al,0FFH ; Does it exist? jnz gf8x jmp gofil9 ; If not create it. gf8x: IF ibmpc mov ah,2 ; Position cursor. mov dx,scrfr mov bh,0 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrfr ; and string to move cursor int dos ; Print the string ENDIF mov ah,prstr ; Inform the user we are renaming the file. mov dx,offset infms5 int dos mov ax,temp2 ; Get the number of chars in the file name. cmp ax,0 jne gofil8 mov ax,temp1 mov temp2,ax gofil8: mov ch,0 mov cl,al mov al,0 ; Says if first field is full. cmp cl,9H ; Is the first field full? jne gofl81 mov al,0FFH ; Set a flag saying so. dec cl gofl81: mov bx,offset fcb ; Get the FCB. add bx,cx ; Add in the character number. mov ah,'&' mov [bx],ah ; Replace the char with an ampersand. push ax push bx mov ah,openf ; See if the file exists. mov dx,offset fcb int dos pop bx cmp al,0FFH ; Does it exist? pop ax jz gofl89 ; If not create it. cmp al,0 ; Get the flag. jz gofl83 dec cl ; Decrement the number of chars. cmp cl,0 jz gofl88 ; If no more, die. jmp gofl81 gofl83: inc cl ; Increment the number of chars. cmp cl,9H ; Are we to the end? jl gofl81 ; If not try again ; else fail. gofl88: call erpos ; Position cursor. mov ah,prstr ; Tell the user that we can't rename it. mov dx,offset ermes4 int dos ret gofl89: mov bx,offset fcb+0CH ; Point past the end of the file name. mov dh,[bx] ; Save the present contents. mov ah,'$' mov [bx],ah ; Put in a dollar sign. push dx mov ah,prstr ; Print the file name. mov dx,offset fcb+1 int dos pop dx mov bx,offset fcb+0CH ; Restore over the dollar sign. mov [bx],dh gofil9: mov ah,delf ; Delete the file if it exists. mov dx,offset fcb int dos mov ax,0 mov si,offset fcb+0CH mov [si],ax ; Zero current block. mov si,offset fcb+0EH mov [si],ax ; Same for Lrecl. mov si,offset fcb+20H mov [si],ah ; Zero the current record (within block). inc si mov [si],ax ; Zero record (within file). mov si,offset fcb+23H mov [si],ax mov ah,makef ; Now create it. mov dx,offset fcb int dos cmp al,0FFH ; Is the disk full? je gf9x jmp rskp gf9x: call erpos ; Position cursor. mov ah,prstr ; If so tell the user. mov dx,offset erms11 int dos ret ;FILEIO ENDP ;* ; Packet routines ; Send_Packet ; This routine assembles a packet from the arguments given and sends it ; to the host. ; ; Expects the following: ; AH - Type of packet (D,Y,N,S,R,E,F,Z,T) ; ARGBLK - Packet sequence number ; ARGBK1 - Number of data characters ; Returns: +1 always ;SPKT PROC NEAR SPKT: spack: push ax ; Save the packet type. mov bx,offset packet ; Get address of the send packet. mov ah,soh ; Get the start of header char. mov [bx],ah ; Put in the packet. inc bx ; Point to next char. mov ax,argbk1 ; Get the number of data chars. xchg ah,al add ah,' '+3 ; Real packet character count made printable. mov [bx],ah ; Put in the packet. inc bx ; Point to next char. mov cl,ah ; Start the checksum. mov ax,argblk ; Get the packet number. xchg ah,al add ah,' ' ; Add a space so the number is printable. mov [bx],ah ; Put in the packet. inc bx ; Point to next char. add cl,ah ; Add the packet number to the checksum. pop ax ; Get the packet type. mov [bx],ah ; Put in the packet. inc bx ; Point to next char. add cl,ah ; Add the type to the checksum. mov dx,argbk1 ; Get the packet size. spack2: cmp dx,0 ; Are there any chars of data? jz spack3 ; No, finish up. dec dx ; Decrement the char count. mov ah,[bx] ; Get the next char. inc bx ; Point to next char. add cl,ah ; Add the char to the checksum. cmp ah,0 jns spack2 mov hierr,0FFH ; set err flag. jmp spack2 ; Go try again. spack3: cmp hierr,0 je sp3x ; Nothing special to do. call biterr mov hierr,0 ; Reset. sp3x: mov ah,cl ; Get the character total. mov ch,cl ; Save here too (need 'cl' for shift). and ah,0C0H ; Turn off all but the two high order bits. mov cl,6 shr ah,cl ; Shift them into the low order position. mov cl,ch add ah,cl ; Add it to the old bits. and ah,3FH ; Turn off the two high order bits. (MOD 64) add ah,' ' ; Add a space so the number is printable. mov [bx],ah ; Put in the packet. inc bx ; Point to next char. mov ah,seol ; Get the EOL the other host wants. mov [bx],ah ; Put in the packet. inc bx ; Point to next char. mov ah,0 ; Get a null. mov [bx],ah ; Put in the packet. cmp debug,0 ; debug mode. je spack4 inc bx mov ah,'$' mov [bx],ah IF ibmpc mov ah,2 mov dx,scrsp mov bh,0 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get print string function mov dx,offset scrsp ; and string to move cursor int dos ; Print the string ENDIF mov ah,prstr mov dx,offset spmes int dos mov dx,offset packet mov ah,prstr int dos ; debug end. spack4: IF SIRIUS ; [3 start] B.D. mov dx,hware push dx pop es ; Set up ES pointing to PORT. sp4x: mov al,es:byte ptr .mpstat ; Input port status. and al,mpinp ; Character ready? jz sp4y ; No. mov al,es:byte ptr .mpdata ; Otherwise, go get it. jmp sp4x ; Try for another. sp4y: mov al,es:byte ptr .mpstat and al,mpovr ; Overflow set? jz sp4z ; No, then go for output. mov es:byte ptr .mpstat,30h ; Error reset. call erpos ; Position cursor. mov ah,prstr ; Tell the world. mov dx,offset erms20 int dos ; No action on overflow for now. sp4z: ENDIF ; [3 end] B.D. call outpkt ; Call the system dependent routine. jmp r jmp rskp ;SPKT ENDP ; Write out a packet. ;OUTPKT PROC NEAR OUTPKT: IF SIRIUS ; [2 start] B.D. mov dx,hware push dx pop es ; Set up ES once for packet. ENDIF ; [2 end] mov dh,spad ; Get the number of padding chars. outpk2: dec dh cmp dh,0 jl outpk3 ; If none left proceed. mov ah,spadch ; Get the padding char. call outchr ; Output it. jmp outpk2 outpk3: mov bx,offset packet ; Point to the packet. outlup: mov ah,[bx] ; Get the next character. cmp ah,0 ; Is it a null? jnz outlp2 jmp rskp outlp2: call outchr ; Output the character. jmp r inc bx ; Increment the char pointer. jmp outlup ;OUTPKT ENDP ;************************System Dependent**************************** ; Put a char in AH to the port. ;PORT PROC NEAR PORT: IF SIRIUS outchr: mov al,ah ;Char in al. mov cx,0 call dopar ;Set parity. outch1: mov dl,es:byte ptr .mpstat ;Port status and dl,mptbe ;Ready to transmit? jz outch1 ;no - loop mov es:byte ptr .mpdata,al ;ok - transmit it jmp rskp ENDIF IF ibmpc outchr: mov al,ah ; Char must be in al. mov cx,0 call dopar ; Set parity appropriately. outch1: mov ah,1 ; Output it. mov dx,0 int comm cmp ah,00H je outch3 loop outch1 jmp r outch3: jmp rskp ENDIF IF Z100 outchr: mov al,ah ; Yes, get the character into al mov cx,0 call dopar ; Set parity appropriately. outch1: call bios_auxout ; Send the character jmp rskp ENDIF ;************************System Dependent**************************** ; ; Get a char from the port and return in AH. inchr: IF SIRIUS mov al,es:byte ptr .mpstat ; Port status. and al,mpinp ;input char. ready? jnz inchr3 ;yes - get it. ENDIF IF ibmpc mov dx,mdmsts ; Get port status. in al,dx test al,mdminp ; Data available? jnz inchr3 ; Read char ok. ENDIF IF Z100 push bx ; Save BX mov ah,chr_status ; Get the function mov al,chr_sfgs ; And the subfunction call bios_auxfunc ; Determine if anything to input cmp bl,0 ; Is there? jnz inchr3 ; Yes, go get it pop bx ; And restore BX ENDIF mov ah,constat ; Is a char on the console? int dos cmp al,0 jz inchr ; If not go look for another char. mov ah,conin ; Get the char. int dos mov ah,al cmp ah,cr ; Is it a carriage return? je inchr4 ; If not go look for another char. jmp inchr ; Wait for some kind of input. inchr4: ret inchr3: IF SIRIUS mov al,es:byte ptr .mpdata ; Read in the character. ENDIF IF ibmpc mov dx,mdmdat ; Read in the char. in al,dx ENDIF IF Z100 mov ah,chr_read ; Get the function to read call bios_auxfunc ; Get a character pop bx ; Restore BX ENDIF mov ah,al cmp parflg,parnon ; Is the parity none? je inchr5 ; We're done. and ah,7FH ; Turn off the parity bit. inchr5: jmp rskp ; Set parity for character in Register AL. dopar: cmp parflg,parnon ; No parity? je parret ; Just return cmp parflg,parevn ; Even parity? jne dopar0 and al,07FH ; Strip parity. jpe parret ; Already even, leave it. or al,080H ; Make it even parity. jmp parret dopar0: cmp parflg,parmrk ; Mark parity? jne dopar1 or al,080H ; Turn on the parity bit. jmp parret dopar1: cmp parflg,parodd ; Odd parity? jne dopar2 and al,07FH ; Strip parity. jpo parret ; Already odd, leave it. or al,080H ; Make it odd parity. jmp parret dopar2: and al,07FH ; Space parity - turn off parity bit. parret: ret ;PORT ENDP ;* ; Receive_Packet ; This routine waits for a packet arrive from the host. It reads ; chars until it finds a SOH. ;RPACK PROC NEAR RPACK: IF ibmpc mov ah,2 mov dx,scrst ; Position cursor. mov bh,0 int bios ENDIF ;IF Z100 OR SIRIUS ; [2 start] Don't print status. ; mov ah,prstr ; Get the function to print string ; mov dx,offset scrst ; Get the string address ; int dos ; Position the cursor ;ENDIF ; mov ah,prstr ; mov dx,offset infms0 ; int dos rpack5: IF SIRIUS mov dx,hware push dx ; Set up ES only once. pop es ; [2 end] B.D. 17-8-83. ENDIF call inpkt ; Read up to a carriage return. jmp r ; Return bad. rpack0: call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cmp ah,soh ; Is the char the start of header char? jne rpack0 ; No, go until it is. rpack1: call getchr ; Get a character. jmp r ; Hit the carriage return, retuset infms0 cmp ah,soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. mov cl,ah ; Start the checksum. sub ah,' '+3 ; Get the real data count. mov dh,ah ; Save it for later. mov al,ah ; Swap halves. mov ah,0 mov argbk1,ax ; Save the data count. call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cmp ah,soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. add cl,ah ; Add it to the checksum. sub ah,' ' ; Get the real packet number. mov al,ah ; Swap halves. mov ah,0 mov argblk,ax ; Save the packet number. call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cmp ah,soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. mov temp,ax ; Save the message type. add cl,ah ; Add it to the checksum. mov bx,offset data ; Point to the data buffer. rpack2: dec dh ; Any data characters? js rpack3 ; If not go get the checksum. call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cmp ah,soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. mov [bx],ah ; Put the char into the packet. inc bx ; Point to the next character. add cl,ah ; Add it to the checksum. jmp rpack2 ; Go get another. rpack3: call getchr ; Get a character. jmp r ; Hit the carriage return, return bad. cmp ah,soh ; Is the char the start of header char? jz rpack1 ; Yes, then go start over. sub ah,' ' ; Turn the char back into a number. mov dh,cl ; Get the character total. and dh,0C0H ; Turn off all but the two high order bits. mov ch,cl mov cl,6 shr dh,cl ; Shift them into the low order position. mov cl,ch add dh,cl ; Add it to the old bits. and dh,3FH ; Turn off the two high order bits. (MOD 64) cmp dh,ah ; Are they equal? jz rpack4 ; If so finish up. mov dx,offset dimsg1 mov ah,prstr int dos ; Print a diagnostic message. ret rpack4: mov ah,0 mov [bx],ah ; Put a null at the end of the data. mov ax,temp ; Get the type. jmp rskp ;RPACK ENDP ;INPKT PROC NEAR INPKT: mov bx,offset recpkt ; Point to the beginning of the packet. mov incnt,0 inpkt2: call inchr ; Get a character. jmp r ; Return failure. mov [bx],ah ; Put the char in the packet. inc bx inc incnt cmp ah,reol ; Is it the EOL char? jne inpkt2 ; If not loop for another. cmp incnt,1 ; Ignore bare CR. jne inpkt6 mov incnt,0 mov bx,offset recpkt jmp inpkt2 inpkt6: cmp ibmflg,0 ; Is this the (dumb) IBM mainframe? jz inpkt4 ; If not then proceed. inpkt5: cmp state,'S' ; Check if this is the Send-Init packet. jz inpkt4 ; If so don't wait for the XON. inpkt3: call inchr ; Wait for the turn around char. jmp inpkt4 cmp ah,xon ; Is it the IBM turn around character? jne inpkt3 ; If not, go until it is. inpkt4: mov bx,offset recpkt mov pktptr,bx ; Save the packet pointer. jmp rskp ; If so we are done. ;INPKT ENDP ;GETCHR PROC NEAR GETCHR: push bx mov bx,pktptr ; Get the packet pointer. mov ah,[bx] ; Get the char. inc bx mov pktptr,bx pop bx ; Restore BX. cmp ah,reol ; Is it the EOL char? jne getcr2 ; If not return retskp. ret ; If so return failure. getcr2: jmp rskp ;GETCHR ENDP ; This is where we go if we get an error packet. A call to ERROR ; positions the cursor and prints the message. A call to ERROR1 ; just prints a CRLF and then the message. ;ERROR PROC NEAR ERROR: mov state,'A' ; Set the state to abort. call erpos ; Position the cursor. jmp error2 error1: mov ah,prstr mov dx,offset crlf int dos error2: mov bx,argbk1 ; Get the length of the data. add bx,offset data ; Get to the end of the string. mov ah,'$' ; Put a dollar sign at the end. mov [bx],ah mov ah,prstr ; Print the error message. mov dx,offset data int dos ret ;ERROR ENDP ; LOGOUT - tell remote KERSRV to logout. ;LOGOUT PROC NEAR LOGOUT: mov ah,cmcfm call comnd ; Get a confirm. jmp r call logo jmp rskp ; Go get another command whether we .... jmp rskp ; .... succeed or fail. ;LOGOUT ENDP ;LOGO PROC NEAR LOGO: mov numtry,0 ; Initialize count. logo1: mov ah,numtry cmp ah,maxtry ; Too many times? js logo3 ; No, try it. logo2: mov ah,prstr mov dx,offset erms19 int dos ret logo3: inc numtry ; Increment number of tries. mov argblk,0 ; Packet number zero. mov argbk1,1 ; One piece of data. mov bx,offset data mov ah,'L' mov [bx],ah ; Logout the remote host. mov ah,'G' ; Generic command packet. call spack jmp logo2 ; Tell user and die. nop call rpack5 ; Get ACK (w/o screen msgs.) jmp logo1 ; Go try again. nop cmp ah,'Y' ; ACK? jne logo4 jmp rskp logo4: cmp ah,'E' ; Error packet? jnz logo1 ; Try sending the packet again. call error1 ret ;LOGO ENDP ; FINISH - tell remote KERSRV to exit. ;FINISH PROC NEAR FINISH: mov ah,cmcfm ; Parse a confirm. call comnd jmp r mov numtry,0 ; Initialize count. fin1: mov ah,numtry cmp ah,maxtry ; Too many times? js fin3 ; Nope, try it. fin2: mov ah,prstr mov dx,offset erms18 int dos jmp rskp ; Go home. fin3: inc numtry ; Increment number of tries. mov argblk,0 ; Packet number zero. mov argbk1,1 ; One piece of data. mov bx,offset data mov ah,'F' mov [bx],ah ; Finish running Kermit. mov ah,'G' ; Generic command packet. call spack jmp fin2 ; Tell user and die. nop call rpack5 ; Get ACK (w/o screen stuff). jmp fin1 ; Go try again. nop cmp ah,'Y' ; Got an ACK? jnz fin4 jmp rskp ; Yes, then we're done. fin4: cmp ah,'E' ; Error packet? jnz fin1 ; Try sending it again. call error1 jmp rskp ;FINISH ENDP ; BYE command - tell remote KERSRV to logout & exits to DOS. ;BYE PROC NEAR BYE: mov ah,cmcfm ; Parse a confirm. call comnd jmp r call logo ; Tell the mainframe to logout. jmp rskp ; Failed - don't exit. mov extflg,1 ; Set exit flag. jmp rskp ;BYE ENDP ; This is the 'exit' command. It leaves KERMIT and returns to DOS. ;EXIT PROC NEAR EXIT: mov ah,cmcfm call comnd ; Get a confirm. jmp r mov extflg,1 ; Set the exit flag. jmp rskp ; Then return to system. ;EXIT ENDP ; This is the 'help' command. It gives a list of the commands. ;HELP PROC NEAR HELP: mov ah,cmcfm call comnd ; Get a confirm. jmp r mov ah,prstr ; Print a string to the console. mov dx,offset tophlp ; The address of the help message. int dos jmp rskp ;HELP ENDP IF ibmpc source db 2048 DUP(?) ; Buffer for data from port. srcpnt dw 0 ; Pointer in buffer (DI). count dw 0 ; Number of chars in int buffer. savesi dw 0 ; Save SI register here. ENDIF ; This is the CONNECT command. ;TELNET PROC NEAR TELNET: mov ah,cmcfm call comnd ; Get a confirm. jmp r ; Didn't get a confirm. mov ah,prstr ; Output mov dx,offset crlf ; a crlf. int dos mov ah,prstr mov dx,offset tmsg1 int dos call escprt mov ah,prstr mov dx,offset tmsg3 int dos cld ; Do increment in string operations. IF ibmpc cli ; Disable interrupts. xor ax,ax mov cx,ds ; Save DS in CX. mov ds,ax ; Use low core. mov bx,mdmintv push [bx] ; Serial Card Interrupt vector. mov bx,mdmintv+2 push [bx] mov bx,6CH ; "break" interrupt vector. push [bx] mov bx,6EH push [bx] mov bx,mdmintv mov ax,offset serint mov es,ax mov [bx],es ; Setup int addr. mov bx,mdmintv+2 mov [bx],cs mov bx,6CH mov ax,offset intret mov es,ax mov [bx],es ; ignore break int's (pt to "iret"). mov bx,6EH mov [bx],cs mov ds,cx mov ssp,sp ; Save SP to make an easy return. lea ax,cs:source mov cs:srcpnt,ax mov cs:savesi,ax ; Source of data starts at buffer head. mov cs:count,0 mov di,cs:srcpnt ; Address (for int) to put chars. mov ax,cs mov es,ax mov si,0 ; Place to get chars from. in al,intcont ; Set up 8259 interrupt controller. and al,mdminto ; Enable INT4. out intcont,al mov dx,mdmcom ; Set up baud, parity, etc. mov al,3 ; (baud set independently) out dx,al mov dx,03F9H ; Interrupt enable register. mov al,1 out dx,al mov dl,0FCH ; Enable int's from serial card. mov al,0BH out dx,al sti ; Enable interrupts. mov dl,0F8H in al,dx ENDIF IF Z100 OR SIRIUS mov ssp,sp ; Save current stack pointer. ENDIF IF SIRIUS ; [2 start] mov dx,hware push dx pop es ; Set ES only once. ENDIF ; [2 end] B.D. telnoe: call plup ; Char at port (type to console) ? IF ibmpc cmp al,ESC jne telx jmp telesc ENDIF telx: cmp al,DEL ; Don't bother with deletes. je telnoe cmp al,XOFF ; Skip all the following too. je telnoe cmp al,XON je telnoe cmp al,00H ; Null. je telnoe IF ibmpc cmp al,BELL jne nobell call beep jmp telnoe nobell: mov ah,14 mov bx,0 int bios jmp telnoe ENDIF IF Z100 OR SIRIUS mov dl,al ; Get the character mov ah,dconio ; and the function int dos ; type the character jmp telnoe ; Get next character ENDIF ;TELNET ENDP ;EXTLN PROC NEAR EXTLN: IF ibmpc cli ; Disable interrupts. ; push ax mov dx,03FCH mov al,3 ; Disable modem interrupts. out dx,al in al,intcont ; Interrupt control. or al,mdmintc ; Inhibit IRQ4. out intcont,al mov sp,ssp xor bx,bx mov cx,ds ; Save DS register. mov ds,bx ; Address low memory. ; pop ax mov bx,6EH pop [bx] mov bx,6CH pop [bx] mov bx,mdmintv+2 ; Restore old interrupt vectors. pop [bx] mov bx,mdmintv pop [bx] mov ds,cx ; Restore DS. xor bx,bx sti ENDIF IF Z100 OR SIRIUS mov sp,ssp ENDIF mov ah,prstr mov dx,offset tmsg2 int dos jmp rskp ;EXTLN ENDP ; *********** serial port interrupt routine ******** IF ibmpc ;SERINT PROC NEAR SERINT: push dx push ax push es push di cld mov di,cs:srcpnt ; Registers for storing data. mov ax,cs mov es,ax mov dx,mdmsts ; Asynch status port. in al,dx test al,mdminp ; Data available? jz retint ; Nope. mov dx,mdmdat in al,dx and al,7FH ; Only want 7 bits. jz retint ; Ignore nulls. cmp al,7FH ; Ignore rubouts, too. jz retint stosb ; Store char in buffer. lea ax,cs:source sub di,ax and di,7FFH ; Truncate buffer here. add di,ax inc cs:count retint: mov cs:srcpnt,di sti mov al,eoicom out intcon1,al ;Send End-of-Interrupt to 8259. pop di pop es pop ax pop dx intret: iret ;SERINT ENDP; ENDIF ;PLUP PROC NEAR PLUP: call prtchr ret ; Got a char. nop ; Use up three bytes. nop call conchr ; See if char at cons (type to port). jmp extln ; Go back to Kermit on micro. IF Z100 OR SIRIUS nop ; Make sure we have 3 bytes. ENDIF jmp plup ;PLUP ENDP ;************************System Dependent**************************** ;* These I/O routines are similar to those just above. ;PRTCHR PROC NEAR PRTCHR: IF SIRIUS mov al,es:byte ptr .mpstat ;Get port status and al,mpinp ;Character ready? jnz prtch1 ;yes - go get it jmp rskp ;no - give skip return prtch1: mov al,es:byte ptr .mpdata ; Get character. and al,07FH ;Strip parity ret ENDIF IF ibmpc cmp cs:count,0 jnz prtch2 jmp rskp ; No data - check console. prtch2: cli ; Disable int's. mov cx,ds mov ax,cs mov ds,ax mov si,cs:savesi lodsb ; Get char from buffer. lea dx,cs:source sub si,dx and si,7FFH ; Truncate buffer after here. add si,dx dec cs:count mov cs:savesi,si mov ds,cx sti ; Renable int's. ret ENDIF IF Z100 push bx ; Save BX mov ah,chr_status ; Get the function we want mov al,chr_sfgs ; Get the subfunction to get status call bios_auxfunc ; Perform the function cmp bl,0 ; Anything in queue? jne prtch1 ; Yes, go get it pop bx ; Restore BX jmp rskp ; No, give skip return prtch1: mov ah,chr_read ; Want to read character call bios_auxfunc ; Do it and al,07FH ; Strip off parity bit pop bx ; And restore BX ret ENDIF ;PRTCHR ENDP ; Generate a short beep. IF ibmpc ;BEEP PROC NEAR BEEP: mov al,10110110B ; Gen a short beep (long one losses data.) out timer+3,al ; Code snarfed from Technical Reference. mov ax,533H out timer+2,al mov al,ah out timer+2,al in al,port_b mov ah,al or al,03 out port_b,al sub cx,cx mov bl,1 beep0: loop beep0 dec bl jnz beep0 mov al,ah out port_b,al ret ;BEEP ENDP ENDIF ;CONCHR PROC NEAR CONCHR: IF ibmpc mov ah,1 ; Get keyboard status. int keyb jnz cnc0x jmp rskp cnc0x: mov ah,0 ; Read a char. int keyb cmp al,0 ; Special char (cntrl-break)? jnz nobrk ; Nope. cmp ah,3 ; 3 in ah means nul code. jz cnc1y ; Skip nulls. cmp ah,0 ; Cntrl-Break? jne cnc1y xor cx,cx mov dx,03fbH in al,dx or al,40H ; Set send-break bit out dx,al pause: loop pause xor al,40H out dx,al cnc1y: jmp rskp ENDIF IF Z100 OR SIRIUS mov ah,dconio ; Determine if character present mov dl,0ffH ; Want input int dos ; Get status cmp al,00H ; Any characters there? jne nobrk ; if not, forget it jmp rskp ; Give skip return ENDIF nobrk: mov dl,al ; Store char here. mov ah,escchr ; Get the escape char. cmp ah,dl ; Is it an escape char? jz intchr ; If so go process it. call dopar ; Set parity (if any). mov dx,ax push dx call prtout ; Output the char to the port. pop dx mov ah,ecoflg ; Get the echo flag. cmp ah,0 ; Is it turned on? jnz cnc1x jmp rskp ; If not we're done here. cnc1x: and dl,7FH cmp dl,BS ; Backspace? je cnc2x cmp dl,CR ; Carriage return? je cnc2x IF ibmpc cmp dl,BELL jne cnc2y call beep jmp rskp ENDIF cnc2y: cmp dl,20H ; Is it a control char? jge cnc2x jmp rskp cnc2x: mov ah,dconio ; Direct console output. int dos ; Echo the char. jmp rskp ;CONCHR ENDP ;CONN PROC NEAR CONN: intchr: mov ah,dconio ; Direct console I/O. mov dl,0FFH ; Input. int dos ; Get a char. mov ah,al cmp ah,0 ; Is the char a null? jz intchr ; If so, go until we get a char. mov bh,ah ; Save the actual char. and ah,137O ; Convert to upper case. cmp ah,'C' ; Is it close? jne intch0 ret intch0: IF SIRIUS cmp ah,'B' ; Is it BREAK? jne inc00x ; Not BREAK. push bx ; O/P BREAK signal. mov bx,hware push bx pop es mov es:byte ptr .mpstat, 5 ; Control reg 5 of port. mov es:byte ptr .mpstat, 0fah ; Set BREAK. mov bx,0ffffh ; Delay loop. break0: dec bx jnz break0 mov es:byte ptr .mpstat, 5 ; Now turn off BREAK. mov es:byte ptr .mpstat, 0eah pop bx jmp rskp inc00x: ENDIF cmp ah,'S' ; Is it status? jnz inc0x jmp stat01 ; If so, jump to stat01 (it will return). inc0x: mov ah,bh ; Get the char. cmp ah,'?' ; Is it help? jne intch1 ; If not, go to the next check. mov dx,offset inthlp ; If so, get the address of the help message. mov ah,prstr ; Print it. int dos jmp intchr ; Get another char. intch1: mov ch,ah ; Put the char into another reg. mov ah,escchr ; Get the escape char. cmp ah,ch ; Is it the escape char? jne intch2 ; If not, go send a beep to the user. mov al,ch call dopar ; Set parity. intc11: mov dl,al call prtout ; Output it. jmp rskp ; Return, we are done here. intch2: mov dl,'G'-100O ; Otherwise send a beep. mov ah,dconio int dos jmp rskp ;* Another similar I/O routine. ;************************System Dependent**************************** prtout: mov al,dl ; Char must be in al. IF SIRIUS mov es:byte ptr .mpdata,al ;Output character ENDIF IF ibmpc mov dx,mdmdat out dx,al ENDIF IF Z100 call bios_auxout ; Send the character ENDIF ret ;CONN ENDP ;* ;TELESC PROC NEAR TELESC: IF ibmpc cmp vtflg,0 ; Is vt52 flag on? jne vt0 jmp telnoe ; Don't do escape stuff if it's off. vt0: call plup mov ah,al ; Get the char. cmp ah,'Y' ; Special char - move cursor. jne vt1 jmp movcur vt1: cmp ah,'A' ; Less than an 'A'? jl vtig ; Yes - ignore. cmp ah,'M'+1 ; Greater than 'M'? jns vtig ; Yes - ignore. mov al,'A' sub ah,al ; Else make into index. shl ah,1 mov bx,offset ttab ; Load base addr of table. mov cl,ah ; Move a into cx. mov ch,00H ; Zero out high byte. add bx,cx ; Double add index+offset. mov bx,[bx] ; Get address of routine to call. jmp bx vtig: ; Ignore escape sequence. push ax ; Push the char to be output. mov dl,esc ; Load an escape. mov ah,conout ; The function code int dos ; and the syscal. pop ax ; Restore the character mov dl,ah ; and move to output register. mov ah,conout ; The function int dos ; and the syscall. ENDIF jmp telnoe ; Return home. ;TELESC ENDP IF ibmpc ;TEL PROC NEAR TEL: movcur: call plup sub al,32 mov dh,al mov temp,dx ; Save row position here. call plup mov dx,temp ; Restore sub al,32 ; Comes with 37Q added on (& starts at 1). mov dl,al mov bh,0 mov ah,2 int bios jmp telnoe curup: mov ah,3 ; Cursor up function. mov bh,0 int bios cmp dh,0 je cup0 sub dh,1 mov ah,2 int bios cup0: jmp telnoe curdwn: mov ah,3 ; Cursor down. mov bh,0 int bios cmp dh,24 je cdn0 add dh,1 mov ah,2 int bios cdn0: jmp telnoe currt: mov ah,3 ; Cursor right. mov bh,0 int bios cmp dl,79 je crt0 add dl,1 mov ah,2 int bios crt0: jmp telnoe curlft: mov ah,3 ; Cursor left. mov bh,0 int bios cmp dl,0 je clt0 sub dl,1 mov ah,2 int bios clt0: jmp telnoe curskp: jmp vtig ; Ignore for now. curhm: call locate jmp telnoe curscr: mov ah,3 ; Clear to end of screen. mov bh,0 int bios cmp dx,0 jne csr0 call cmblnk jmp telnoe csr0: cmp dl,0 je csr1 push dx call curln pop dx add dh,1 mov dl,0 csr1: mov cx,dx mov dx,184FH mov bh,7 ; mov al,25 ; sub al,ch mov al,0 mov ah,7 int bios jmp telnoe curln: mov ah,3 ; Clear to end of line. mov bh,0 int bios ; Get current cursor position mov cx,dx mov dl,79 mov ah,7 mov al,0 mov bh,7 int bios jmp telnoe inslin: mov ah,3 ; Get cursor position. mov bh,0 int bios mov temp,dx ; Save here. mov cx,dx mov cl,0 ; Start at beginning of row. mov dx,184FH ; End at lower corner of screen. mov ax,0701H mov bh,7 int bios ; Scroll down one line. mov dx,temp ; Get back where we were. mov dl,0 mov ah,2 mov bh,0 int bios jmp telnoe dellin: mov ah,3 mov bh,0 int bios ; Get current cursor position. mov temp,dx ; Remember the place. mov ax,0601H ; Scroll up one line. mov cx,dx mov cl,0 ; Start at beginning of row. mov dx,184FH mov bh,7 int bios mov dx,temp mov dl,0 mov ah,2 mov bh,0 int bios jmp telnoe ;TEL ENDP ENDIF ;* ; This is the SET command. ;SETCOM PROC NEAR SETCOM: mov dx,offset settab ; Parse a keyword from the set table. mov bx,offset sethlp mov ah,cmkey call comnd jmp r call bx jmp rskp ;SETCOM ENDP ; This is the ESCAPE character SET subcommand. ;ESCAPE PROC NEAR ESCAPE: call cmgtch ; Get a char. cmp ah,0 jns es1 ; Terminator or no? and ah,7FH ; Turn off minus bit. cmp ah,'?' jne es0 mov dx,offset eschlp mov ah,prstr int dos mov ah,prstr mov dx,offset crlf int dos mov ah,prstr mov dx,offset kerm int dos mov bx,cmdptr mov al,'$' mov [bx],al mov dx,offset cmdbuf int dos dec cmcptr ; Ignore dollar sign. dec cmccnt mov cmaflg,0 jmp repars es0: mov ah,prstr mov dx,offset ermes3 int dos ret es1: mov temp,ax call cmcfrm jmp es0 nop ; Take up 3 bytes. mov ax,temp mov escchr,ah ; Save new value. ret ;ESCAPE ENDP ; This is the End-of-line character SET subcommand. ;EOLSET PROC NEAR EOLSET: call cmgtch ; Get the first char into AH. cmp ah,0 jns eol1 cmp ah,0BFH ; Question mark? je eol4 jmp eol3 eol1: sub ah,030H ; Digit --> real number. mov temp,ax ; Save the input. call cmcfrm jmp eol0 ; Got a char. mov ax,0 mov bx,temp jmp eol2 eol0: sub ah,030H ; Digit --> real number. mov temp1,ax call cmcfrm jmp eol3 ; Too many chars. mov bx,temp1 mov ax,temp xchg al,ah mov ah,0 eol2: mov temp,ax ; Save our registers. mov temp1,bx call cmcfrm jmp eol3 mov bx,temp1 mov ax,temp mov temp2,10 ; Get numerical value of char. mul temp2 add al,bh mov ah,0 cmp al,0 jl eol3 cmp al,1FH jg eol3 mov seol,al ; Use new eol char. ret eol3: mov ah,prstr mov dx,offset eolerr ; Bad end-of-line char int dos jmp prserr eol4: mov ah,prstr mov dx,offset eolhlp int dos mov ah,prstr mov dx,offset crlf int dos mov ah,prstr mov dx,offset kerm int dos mov bx,cmdptr mov al,'$' mov [bx],al mov ah,prstr mov dx,offset cmdbuf int dos dec cmcptr ; Don't count the dollar sign. dec cmccnt ; Or the question mark. mov cmaflg,0 ; Check for more input. jmp repars ;EOLSET ENDP ; This is the LOCAL echo SET subcommand. ;LCAL PROC NEAR LCAL: mov dx,offset ontab mov bx,offset onhlp mov ah,cmkey call comnd jmp r push bx ; Save the parsed value. mov ah,cmcfm call comnd ; Get a confirm. jmp r ; Didn't get a confirm. pop bx mov ecoflg,bl ; Set the local echo flag. ret ;LCAL ENDP ; This is the VT52 emulation SET subcommand. IF ibmpc ;VT52EM PROC NEAR VT52EM: mov dx,offset ontab mov bx,offset onhlp mov ah,cmkey call comnd jmp r push bx mov ah,cmcfm call comnd ; Get a confirm. jmp r ; Didn't get a confirm. pop bx mov vtflg,bl ; Set the VT52 emulation flag. ret ;VT52EM ENDP ENDIF ; This is the SET IBM command. ;IBMSET PROC NEAR IBMSET: mov dx,offset ontab mov bx,offset onhlp mov ah,cmkey call comnd jmp r push bx mov ah,cmcfm call comnd ; Get a confirm. jmp r ; Didn't get a confirm. pop bx mov ibmflg,bl ; Set the IBM flag. cmp bl,0 ; Turning on or off? je ibmst1 ; If off, set parity & local echo to defaults. mov ah,ibmpar ; Set IBM parity. mov al,1 ; Set local echo on. jmp ibmst2 ibmst1: mov ah,defpar ; Reset parity to default. mov al,0 ; Turn off local echo. ibmst2: mov parflg,ah ; Set parity. mov ecoflg,al ; And local echo. ret ;IBMSET ENDP ; This is the SET File-Warning command. ;FILWAR PROC NEAR FILWAR: mov dx,offset ontab mov bx,offset onhlp mov ah,cmkey call comnd jmp r push bx mov ah,cmcfm call comnd ; Get a confirm. jmp r ; Didn't get a confirm. pop bx mov flwflg,bl ; Set the IBM flag. ret ;FILWAR ENDP ; This is the SET Parity command. ;SETPAR PROC NEAR SETPAR: mov dx,offset partab mov bx,offset parhlp mov ah,cmkey call comnd jmp r push bx mov ah,cmcfm call comnd ; Get a confirm. jmp r ; Didn't get a confirm. pop bx mov parflg,bl ; Set the parity flag. ret ;SETPAR ENDP ; Sets debugging mode on and off. ;DEBST PROC NEAR DEBST: mov dx,offset ontab mov bx,offset onhlp mov ah,cmkey call comnd jmp r push bx mov ah,cmcfm call comnd ; Get a confirm. jmp r ; Didn't get a confirm. pop bx mov debug,bl ; Set the IBM flag. ret ;DEBST ENDP ; This function sets the baud rate. ;BAUDST PROC NEAR BAUDST: mov dx,offset bdtab mov bx,offset bdhlp mov ah,cmkey call comnd jmp r push bx mov ah,cmcfm call comnd ; Get a confirm. jmp r ; Didn't get one. pop bx mov baud,bx ; Set the IBM flag. IF SIRIUS push bx mov bx,hware push bx pop es mov bl,bset mov es:byte ptr .btimer,bl mov bx,baud mov es:byte ptr .brate,bh mov es:byte ptr .brate,bl pop bx ENDIF IF ibmpc mov dx,03FBH ; LCR in al,dx mov bl,al or ax,80H out dx,al mov dx,03F8H mov ax,baud out dx,al inc dx mov al,ah out dx,al mov dx,03FBH mov al,bl out dx,al ENDIF IF Z100 mov bx,ds ; Set up pointer to config info mov es,bx ; . . . mov bx,offset auxcnf ; . . . mov ah,chr_control ; Function is control mov al,chr_cfsu ; Subfunction is set new config call bios_auxfunc ; Set the configuration ENDIF ret ;BAUDST ENDP ; This is the STATUS command. ;STATUS PROC NEAR STATUS: call stat0 jmp r jmp rskp ;STATUS ENDP ;STAT0 PROC NEAR STAT0: mov ah,cmcfm call comnd ; Get a confirm. jmp r ; Didn't get a confirm. stat01: mov dx,offset locst ; Assume local echo on. cmp ecoflg,0 ; Is the local echo flag on? jnz stat1 mov dx,offset remst ; If not say so. stat1: mov ah,prstr ; Print it. int dos IF ibmpc mov dx,offset vtemst ; Get address of the VT52 emulation string. cmp vtflg,0 ; Is the VT52 emulation flag on? jnz stat2 mov dx,offset novtst ; If not say so. stat2: mov ah,prstr ; Print it. int dos ENDIF mov dx,offset ibmst ; Is IBM flag on? cmp ibmflg,0 jnz stat3 mov dx,offset noibm ; Say it's not. stat3: mov ah,prstr int dos mov dx,offset deboff ; Assume debug mode is off. cmp debug,0 je stat4 mov dx,offset debon stat4: mov ah,prstr int dos mov dx,offset flwon ; Assume file-warning on. cmp flwflg,0 jne stat5 mov dx,offset flwoff stat5: mov ah,prstr int dos mov dx,offset pnonst ; Assume no parity. cmp parflg,parnon je stat6 mov dx,offset pmrkst ; Mark parity? cmp parflg,parmrk je stat6 mov dx,offset pevnst ; Maybe it's even parity. cmp parflg,parevn je stat6 mov dx,offset poddst ; Odd parity? cmp parflg,parodd je stat6 mov dx,offset pspcst stat6: mov ah,prstr int dos mov dx,offset eolst ; Tell the end-of-line char used. mov ah,prstr int dos mov ah,conout mov dl,seol add dl,40H int dos mov ah,prstr mov dx,offset escmes ; Print escape character. int dos call escprt mov dx,offset b48st ; Assume 4800 baud. cmp baud,B4800 jnz stat9a jmp stat9 stat9a: mov dx,offset b12st cmp baud,B1200 jz stat9 IF SIRIUS jmp stat9c ENDIF IF IBMPC OR Z100 mov dx,offset b18st cmp baud,B1800 jz stat9 ENDIF stat9c: mov dx,offset b24st cmp baud,B2400 jz stat9 mov dx,offset b96st cmp baud,B9600 jz stat9 mov dx,offset b03st IF ibmpc jmp stat9 ENDIF cmp baud,B0300 jz stat9 IF SIRIUS jmp stat9d ENDIF IF Z100 mov dx,offset b04st cmp baud,B00455 jz stat9 mov dx,offset b05st cmp baud,B0050 jz stat9 mov dx,offset b07st cmp baud,b0075 jz stat9 mov dx,offset b11st cmp baud,B0110 jz stat9 mov dx,offset b13st cmp baud,B01345 jz stat9 mov dx,offset b15st cmp baud,B0150 jz stat9 ENDIF IF SIRIUS OR Z100 stat9d: mov dx,offset b06st cmp baud,B0600 jz stat9 ENDIF IF Z100 mov dx,offset b20st jmp stat9 cmp baud,B2000 jz stat9 mov dx,offset b19st cmp baud,B19200 jz stat9 mov dx,offset b38st ENDIF stat9: mov ah,prstr int dos mov dx,offset cmcrlf ; Get the address of a crlf. mov ah,prstr ; Print it. int dos jmp rskp ;STAT0 ENDP ; Utility routines ; Jumping to this location is like retskp. It assumes the instruction ; after the call is a jmp addr. ;RSKP PROC NEAR RSKP: pop bp add bp,3 push bp ret ;RSKP ENDP ; Jumping here is the same as a ret. ;R PROC NEAR R: ret ;R ENDP ; This routine prints the number in AX on the screen. ; (Thanks to Jeff Damens) ;NOUT PROC NEAR NOUT: push bx ; Save some stuff. push cx push dx push ax mov bh,0 ; Don't print leading zeros. and ah,0F0H ; Only want high order nibble. mov cl,4 shr ah,cl call pdig ; Print the digit. pop ax ; Restore argument. and ah,0FH ; Just the low order nibble. call pdig mov ah,al and ah,0F0H ; Only want high order nibble. mov cl,4 shr ah,cl call pdig ; Print the digit. mov ah,al and ah,0FH ; Just the low order nibble. mov bh,0FFH ; Make sure at least one zero is printed. call pdig pop dx ; Restore some stuff. pop cx pop bx ret ;NOUT ENDP ; print the digit in register AH ;PDIG PROC NEAR PDIG: push ax ; Save it. cmp ah,0 jne pdig2 cmp bh,0 jne pdig2 pop ax ret pdig2: mov bh,0FFH ; Set the print zero flag. cmp ah,10 ; Do we use digits or a-f? jl usedig ; Digit. add ah,'A'-10 ; Compute digit jmp havdig ; and proceed. usedig: add ah,'0' ; Convert to digit havdig: mov dl,ah mov ah,conout int dos pop ax ret ;PDIG ENDP ; This set of routines provides a user oriented way of parsing ; commands. It is similar to that of the COMND JSYS in TOPS-20. ; This routine prints the prompt in DE and specifies the reparse ; address. ;PROMPT PROC NEAR PROMPT: pop bx ; Get the return address. push bx ; Put it on the stack again. mov cmrprs,bx ; Save as addr to go to on reparse. mov bx,0 ; Clear out register. add bx,sp ; Get the present stack pointer. mov cmostp,bx ; Save for later restoral. mov cmprmp,dx ; Save pointer to the prompt. mov bx,offset cmdbuf mov cmcptr,bx ; Initialize the command pointer. mov cmdptr,bx mov ah,0 mov cmaflg,ah ; Zero the flags. mov cmccnt,ah mov cmsflg,0FFH mov ah,prstr mov dx,offset cmcrlf int dos mov ah,prstr ; Print the prompt. mov dx,cmprmp int dos ret ;PROMPT ENDP ; This address is jumped to on reparse. ;PARSE PROC NEAR PARSE: repars: mov sp,cmostp ; new sp <-- old sp mov bx,offset cmdbuf mov cmdptr,bx mov ah,0FFH mov cmsflg,ah mov bx,cmrprs ; Get the reparse address. call bx ; Go there. ; This address can be jumped to on a parsing error. prserr: mov sp,cmostp ; Set new sp to old one. mov bx,offset cmdbuf mov cmcptr,bx ; Initialize the command pointer. mov cmdptr,bx mov ah,0 mov cmaflg,ah ; Zero the flags. mov cmccnt,ah mov cmsflg,0FFH mov ah,prstr mov dx,offset cmcrlf int dos mov ah,prstr ; Print the prompt. mov dx,cmprmp ; Get the prompt. int dos ;* Instead return to before the prompt call. mov bx,cmrprs call bx ;PARSE ENDP ; This routine parses the specified function in AH. Any additional ; information is in DX and BX. ; Returns +1 on success ; +4 on failure (assumes a JMP follows the call) ;CMND PROC NEAR CMND: comnd: mov cmstat,ah ; Save what we are presently parsing. call cminbf ; Get chars until an action or a erase char. mov ah,cmstat ; Restore 'ah' for upcoming checks. cmp ah,cmcfm ; Parse a confirm? jz cmcfrm ; Go get one. cmp ah,cmkey ; Parse a keyword? jnz cm1 jmp cmkeyw ; Try and get one. cm1: cmp ah,cmifi ; Parse an input file spec? jnz cm2 jmp cmifil ; Go get one. cm2: cmp ah,cmofi ; Output file spec? jnz cm3 jmp cmofil ; Go get one. cm3: cmp ah,cmtxt ; Parse arbitrary text. jnz cm4 jmp cmtext cm4: mov ah,prstr ; Else give error. mov dx,offset cmer00 ; "?Unrecognized COMND call" int dos ret ; This routine gets a confirm. cmcfrm: call cmgtch ; Get a char. cmp ah,0 ; Is it negative (a terminator; a space or ; a tab will not be returned here as they ; will be seen as leading white space.) js cmcfr0 ret ; If not, return failure. cmcfr0: and ah,7FH ; Turn off the minus bit. cmp ah,esc ; Is it an escape? jne cmcfr2 mov ah,conout mov dl,bell ; Get a bell. int dos mov ah,0 mov cmaflg,ah ; Turn off the action flag. mov bx,cmcptr ; Move the pointer to before thee scape. dec bx mov cmcptr,bx mov cmdptr,bx dec cmccnt ; Decremrnt the char count. jmp cmcfrm ; Try again. cmcfr2: cmp ah,'?' ; Curious? jne cmcfr3 mov ah,prstr ; Print something useful. mov dx,offset cmin00 int dos mov ah,prstr mov dx,offset cmcrlf ; Print a crlf. int dos mov ah,prstr mov dx,cmprmp ; Reprint the prompt. int dos mov bx,cmdptr ; Get the pointer into the buffer. mov ah,'$' ; Put a $ there for printing. mov [bx],ah mov bx,cmcptr dec bx ; Decrement & save the buffer pointer. mov cmcptr,bx mov ah,prstr mov dx,offset cmdbuf int dos mov ah,0 ; Turn off the action flag. mov cmaflg,ah jmp repars ; Reparse everything. cmcfr3: cmp ah,ff ; Is it a form feed? jne cmcfr4 call cmblnk ; If so blank the screen. cmcfr4: jmp rskp ; This routine parses a keyword from the table pointed ; to in DX. The format of the table is as follows: ; ; addr: db n ; Where n is the # of entries in the table. ; db m ; M is the size of the keyword. ; db 'string$' ; Where string is the keyword. ; dw ab ; Where ab is data to be returned. ; ; The keywords must be in alphabetical order. cmkeyw: mov cmhlp,bx ; Save the help. mov cmptab,dx ; Save the beginning of keyword table. mov bx,dx mov ch,[bx] ; Get number of entries in table. inc bx mov dx,cmdptr ; Save command pointer. mov cmsptr,dx ; Save pointer's here. cmky1: cmp ch,0 ; Any commands left to check? jne cmky2 mov ah,prstr mov dx,offset cmer04 ; Complain. int dos ret ; Fail if not. cmky2: dec ch mov cl,0 ; Keep track of how many chars read in so far. call cmgtch ; Get a char. cmp ah,0 ; Do we have a terminator? jns cmky2x jmp cmky4 ; Negative number means we do. cmky2x: inc bx ; Point to first letter of keyword. inc cl ; Read in another char. mov al,[bx] cmp ah,'a' ; Less than a? jl cmky21 ; If so, don't capitalize. cmp ah,'z'+1 ; More than z? jns cmky21 and ah,137O ; Capitalize the letter. cmky21: cmp ah,al je cmky3 jg cmky2y jmp cmky41 ; Fail if ah preceeds al alphabetically. cmky2y: jmp cmky6 ; Not this keyword - try the next. cmky3: inc bx ; We match here, how 'bout next char? mov al,[bx] cmp al,'$' ; End of keyword? jne cmky3x jmp cmky7 ; Succeed. cmky3x: mov dl,al ; Save al's char here. call cmgtch inc cl ; Read in another char. mov al,dl cmp ah,'a' jl cmky31 cmp ah,'z'+1 jns cmky31 and ah,137O cmky31: cmp ah,9BH ; Escape Recognition (escape w/minus bit on)? je cmky3y cmp ah,0BFH ; A question mark? je cmky3y cmp ah,0A0H ; A space? je cmky3y cmp ah,8DH ; Carriage return? je cmky3y jmp cmky38 cmky3y: mov cmkptr,bx ; Save bx here. mov cmsiz,cx ; Save size info. mov cmchr,ah ; Save char for latter. call cmambg ; See if input is ambiguous or not. jmp cmky32 ; Succeeded (not ambiguous). mov ah,cmchr cmp ah,9BH ; Escape? je cmky3z jmp cmky41 ; Fail. cmky3z: mov ah,conout ; Else, ring a bell. mov dl,bell int dos mov bx,cmcptr ; Move pointer to before the escape. dec bx mov cmcptr,bx mov cmdptr,bx dec cmccnt ; Decrement char count. mov bx,cmkptr ; Failed - pretend user never typed .... mov cx,cmsiz ; ... in a char. dec cl ; Don't count the escape. dec bx mov cmaflg,0 ; Reset the action flag. jmp cmky3 ; Keep checking. cmky32: mov cx,cmsiz ; Restore info. mov bx,cmkptr ; Our place in the keyword table. cmp cmchr,0A0H ; Space? je cmky35 cmp cmchr,0BFH ; Question mark? je cmky35 cmp cmchr,8DH ; Carriage return? je cmky35 dec cmcptr ; Pointer into buffer of input. mov dx,cmcptr cmky33: mov ah,[bx] ; Get next char in keyword. cmp ah,'$' ; Are we done yet? jz cmky34 mov di,dx mov [di],ah inc bx inc dx inc cmccnt jmp cmky33 cmky34: mov ah,' ' mov di,dx mov [di],ah ; Put a blank in the buffer. inc dx mov cx,cmcptr ; Remember where we were (for printing below). mov cmcptr,dx ; Update our pointers. mov cmdptr,dx mov ah,'$' mov di,dx mov [di],ah ; Add '$' for printing. mov ah,prstr mov dx,cx ; Point to beginning of filled in data. int dos inc bx ; Point to address we'll need. mov bx,[bx] mov cmaflg,0 ; Turn off action flag. jmp rskp cmky35: inc bx mov ah,[bx] ; Find end of keyword. cmp ah,'$' jne cmky35 inc bx mov bx,[bx] ; Address of next routine to call. ; mov cmaflg,0 ; Zero the action flag. jmp rskp cmky38: cmp ah,al jne cmky39 ; Go to end of keyword and try next. jmp cmky3 cmky39: jmp cmky6 cmky4: and ah,7FH ; Turn off minus bit. cmp ah,'?' ; Need help? je cmky5 cmp ah,' ' ; Just a space - no error. je cmky51 cmp ah,cr je cmky51 cmp ah,tab je cmky51 cmp ah,esc ; Ignore escape? je cmky43 cmky41: mov ah,prstr mov dx,offset cmer03 int dos jmp prserr ; Parse error - give up. cmky43: mov ah,conout ; Ring a bell. mov dl,bell int dos mov bx,cmcptr dec bx mov cmcptr,bx mov cmdptr,bx dec cmccnt ; Don't count the escape. mov cmaflg,0 ; Reset action flag. inc ch ; Account for a previous 'dec'. jmp cmky1 ; Start over. cmky5: mov ah,prstr mov dx,cmhlp ; Print the help text. int dos mov ah,prstr mov dx,offset crlf int dos mov ah,prstr mov dx,offset kerm int dos mov bx,cmdptr ; Get pointer into buffer. mov al,'$' mov [bx],al ; Add dollar sign for printing. mov ah,prstr mov dx,offset cmdbuf int dos dec cmcptr ; Don't keep it in the buffer. dec cmccnt ; Don't conut it. mov cmaflg,0 ; Turn off the action flag. jmp repars cmky51: jmp prserr cmky6: inc bx ; Find end of keyword. mov al,[bx] cmp al,'$' jne cmky6 inc bx ; Beginning of next command. inc bx inc bx mov dx,cmsptr ; Get old cmdptr. mov cmdptr,dx ; Restore. mov cmsflg,0FFH jmp cmky1 ; Keep trying. cmky7: call cmgtch ; Get char. cmp ah,0 js cmky71 ; Ok if a terminator. dec bx jmp cmky6 ; No match - try next keyword. cmky71: inc bx ; Get necessary data. mov bx,[bx] cmp ah,9BH ; An escape? jne cmky72 mov ah,prstr mov dx,offset prsp ; Print a space. int dos mov di,cmcptr dec di mov ah,20H mov [di],ah ; Replace escape char with space. mov cmaflg,0 mov cmsflg,0FFH ; Pretend they typed a space. cmky72: jmp rskp ; See if keyword is unambiguous or not from what the user has typed in. cmambg: cmp ch,0 ; Any keywords left to check? jne cmamb0 ret ; If not then not ambiguous. cmamb0: inc bx ; Go to end of keyword ... mov al,[bx] ; So we can check the next one. cmp al,'$' jne cmamb0 add bx,4 ; Point to start of next keyword. dec cl ; Don't count escape. mov dx,cmsptr ; Buffer with input typed by user. cmamb1: mov ah,[bx] ; Keyword char. mov di,dx mov al,[di] ; Input char. cmp al,'a' ; Do capitalizing. jl cmam11 cmp al,'z'+1 jns cmam11 and al,137O cmam11: cmp ah,al ; Keyword bigger than input (alphabetically)? jle cmamb2 ; No - keep checking. ret ; Yes - not ambiguous. cmamb2: inc bx ; Advance one char. inc dx dec cl jnz cmamb1 jmp rskp ; Fail - it's ambiguous. cmifil: mov bx,dx ; Get the fcb address in bx. mov cmfcb,bx ; Save it. mov ch,0 ; Initialize char count. mov ah,0 mov [bx],ah ; Set the drive to default to current. inc bx mov cmfcb2,bx mov cl,' ' cmifi0: mov [bx],cl ; Blank the FCB. inc bx inc ah cmp ah,0BH ; Twelve? jl cmifi0 cmifi1: call cmgtch ; Get another char. cmp ah,0 ; Is it an action character. jns cmifi2 and ah,7FH ; Turn off the action bit. cmp ah,'?' ; A question mark? jne cmif12 mov al,0 mov cmaflg,al ; Blank the action flag. dec cmcptr ; Decrement the buffer pointer. dec cmccnt ; Decrement count. ; jmp cmifi8 ; Treat like any other character. mov ah,prstr mov dx,offset filhlp ; Help message. int dos mov ah,prstr mov dx,offset crlf int dos mov ah,prstr mov dx,offset kerm int dos mov bx,cmdptr mov al,'$' mov [bx],al ; Put in dollar sign for printing. mov ah,prstr mov dx,offset cmdbuf int dos jmp repars cmif12: cmp ah,esc ; An escape? jne cmif13 mov ah,0 mov cmaflg,ah ; Turn off the action flag. mov ah,conout mov dl,bell int dos ; Ring the bell. mov bx,cmcptr ; Move the pointer to before the escape. dec bx mov cmcptr,bx mov cmdptr,bx dec cmccnt ; Decrement char count. jmp repars cmif13: mov ah,ch ; It must be a terminator. cmp ah,0 ; Test the length of the file name. jnz cmf3x jmp cmifi9 ; If zero complain. cmf3x: cmp ah,0DH js cmf3y jmp cmifi9 ; If too long complain. cmf3y: jmp rskp ; Otherwise we have succeeded. cmifi2: cmp ah,'.' jne cmifi3 inc ch mov ah,ch cmp ah,1H ; Any chars yet? jnz cmf2x jmp cmifi9 ; No, give error. cmf2x: cmp ah,0AH ; Tenth char? js cmf2y jmp cmifi9 ; Past it, give an error. cmf2y: mov dl,9H mov dh,0 mov bx,cmfcb add bx,dx ; Point to file type field. mov cmfcb2,bx mov ch,9H ; Say we've gotten nine. jmp cmifi1 ; Get the next char. cmifi3: cmp ah,':' jne cmifi4 inc ch cmp ch,2H ; Is it in right place for a drive? je cmif3x jmp cmifi9 ; If not, complain. cmif3x: mov ch,0 ; Reset char count. mov bx,cmfcb2 sub bx,1 mov ah,[bx] ; Get the drive name. sub ah,'@' ; Get the drive number. mov cmfcb2,bx mov bx,cmfcb mov [bx],ah ; Put it in the fcb. jmp cmifi1 cmifi4: cmp ah,'*' jne cmifi7 mov ah,ch cmp ah,8H ; Is this in the name or type field? jz cmifi9 ; If its where the dot should be give up. jns cmifi5 ; Type. mov cl,8H ; Eight chars. jmp cmifi6 cmifi5: mov cl,0CH ; Three chars. cmifi6: mov wldflg,0FFH ; Remember we had a wildcard. mov bx,cmfcb2 ; Get a pointer into the FCB. mov ah,'?' mov [bx],ah ; Put a question mark in. inc bx mov cmfcb2,bx inc ch mov ah,ch cmp ah,cl jl cmifi6 ; Go fill in another. jmp cmifi1 ; Get the next char. cmifi7: cmp ah,03DH ; Equals sign (wildcard)? jne cmif7x mov ah,'?' mov wldflg,0FFH ; Say we have a wildcard. jmp cmifi8 ; Put into FCB. cmif7x: cmp ah,'0' jl cmif8x cmp ah,'z'+1 jns cmif8x cmp ah,'A' ; Don't capitalize non-alphabetics. jl cmifi8 and ah,137O ; Capitalize. cmifi8: mov bx,cmfcb2 ; Get the pointer into the FCB. mov [bx],ah ; Put the char there. inc bx mov cmfcb2,bx inc ch jmp cmifi1 cmif8x: push es mov cx,ds mov es,cx ; Scan uses ES register. mov di,offset spchar ; Special chars. mov cx,20 ; Twenty of them. mov al,ah ; Char is in al. repnz scasb ; Search string for input char. cmp cx,0 ; Was it there? pop es jnz cmifi8 cmifi9: mov ah,prstr mov dx,offset cmer02 int dos ret cmofil: jmp cmifil ; For now, the same as CMIFI. ; Parse arbitrary text up to a CR. Put chars into data buffer sent to ; the host (pointed to by BX). Return updated pointer in BX and ; input size in AH. ; Expects pointeer to help message in DX. cmtext: mov cmptab,bx ; Save pointer to data buffer. mov cmhlp,dx ; Save pointer to help. mov cl,0 ; Init the char count. cmtxt1: call cmgtch ; Get a char. cmp ah,0 ; Terminator? jns cmtxt5 ; Nope, put into the buffer. and ah,07FH cmp ah,esc ; An escape? jne cmtxt2 mov ah,conout mov dl,bell ; Ring a bell. int dos mov cmaflg,0 ; Reset action flag. dec cmcptr ; Move pointer to before the escape. dec cmdptr dec cmccnt ; Decrement count. jmp cmtxt1 ; Try again. cmtxt2: cmp ah,'?' ; Asking a question? jz cmtxt3 cmp ah,ff ; Formfeed? jne cmtx2x call cmblnk cmtx2x: mov ah,cl ; Return count in AH. mov bx,cmptab ; Return updated pointer. jmp rskp cmtxt3: mov cmaflg,0 ; Reset action flag to zero. dec cmcptr dec cmccnt mov ah,prstr mov dx,cmhlp ; Help message. int dos mov ah,prstr mov dx,offset crlf int dos mov ah,prstr mov dx,offset kerm int dos mov bx,cmdptr mov al,'$' ; Retype command line. mov [bx],al mov ah,prstr mov dx,offset cmdbuf int dos jmp repars cmtxt5: inc cl ; Increment the count. mov bx,cmptab ; Pointer into destination array. mov [bx],ah ; Put char into the buffer. inc bx mov cmptab,bx jmp cmtxt1 cminbf: push dx push bx mov cx,dx ; Save value here too. mov ah,cmaflg ; Is the action char flag set? cmp ah,0 je cminb1 jmp cminb9 ; If so get no more chars. cminb1: inc cmccnt ; Increment the char count. mov ah,conin ; Get a char. int dos mov ah,al ; Keep char in 'ah'. mov bx,cmcptr ; Get the pointer into the buffer. mov [bx],ah ; Put it in the buffer. inc bx mov cmcptr,bx cmp ah,25O ; Is it a ^U? jne cminb2 cmnb12: mov ah,prstr mov dx,offset clrlin int dos IF ibmpc mov ax,0920H ; Write spaces. mov bx,7 ; Clear the line. mov cx,80 int bios ENDIF mov ah,prstr mov dx,cmprmp ; Print the prompt. int dos mov bx,offset cmdbuf mov cmcptr,bx ; Reset the point to the start. mov cmccnt,0 ; Zero the count. mov dx,cx ; Preserve original value of dx. jmp repars ; Go start over. cminb2: cmp ah,10O ; Or backspace? jz cminb3 cmp ah,del ; Delete? jne cminb4 mov ah,prstr ; Print the delete string. mov dx,offset delstr int dos cminb3: mov ah,cmccnt ; Decrement the char count by two. dec ah dec ah cmp ah,0 ; Have we gone too far? jns cmnb32 ; If not proceed. mov ah,conout ; Ring the bell. mov dl,bell int dos jmp cmnb12 ; Go reprint prompt and reparse. cmnb32: mov cmccnt,ah ; Save the new char count. mov ah,prstr ; Erase the character. mov dx,offset clrspc int dos mov bx,cmcptr ; Get the pointer into the buffer. dec bx ; Back up in the buffer. dec bx mov cmcptr,bx jmp repars ; Go reparse everything. cminb4: cmp ah,'?' ; Is it a question mark. jz cminb6 cmp ah,esc ; Is it an escape? jz cminb8 cmp ah,cr ; Is it a carriage return? jz cminb5 cmp ah,lf ; Is it a line feed? jz cminb5 cmp ah,ff ; Is it a formfeed? jne cminb7 call cmblnk call locate cminb5: mov ah,cmccnt ; Have we parsed any chars yet? cmp ah,1 jnz cminb6 jmp prserr ; If not, just start over. cminb6: mov ah,0FFH ; Set the action flag. mov cmaflg,ah jmp cminb9 cminb7: jmp cminb1 ; Get another char. cminb8: mov ah,prstr ; Don't print the escape char. mov dx,offset escspc int dos jmp cminb6 cminb9: pop bx pop dx ret cmgtch: push cx push bx push dx cmgtc1: mov ah,cmaflg cmp ah,0 ; Is it set. jne cmgt10 call cminbf ; If the action char flag is not set get more. cmgt10: mov bx,cmdptr ; Get a pointer into the buffer. mov ah,[bx] ; Get the next char. inc bx mov cmdptr,bx cmp ah,' ' ; Is it a space? jz cmgtc2 cmp ah,tab ; Or a tab? jne cmgtc3 cmgtc2: mov ah,cmsflg ; Get the space flag. cmp ah,0 ; Was the last char a space? jne cmgtc1 ; Yes, get another char. mov ah,0FFH ; Set the space flag. mov cmsflg,ah mov ah,' ' pop dx pop bx jmp cmgtc5 cmgtc3: mov al,0 mov cmsflg,al ; Zero the space flag. pop dx pop bx cmp ah,esc jz cmgtc5 cmp ah,'?' ; Is the user curious? jz cmgtc4 cmp ah,cr jz cmgtc4 cmp ah,lf jz cmgtc4 cmp ah,ff je cmgtc4 pop cx ret ; Not an action char, just return. cmgtc4: dec cmdptr cmgtc5: or ah,80H ; Make the char negative to indicate pop cx ret ; it is a terminator. ;CMND ENDP ; This routine blanks the screen. ;CMBLNK PROC NEAR ; This is stolen from the IBM example. CMBLNK: IF ibmpc mov cx,0 mov dx,184FH mov bh,7 mov ax,600H int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Get the function code mov dx,offset clrscr ; Want to clear the screen int dos ; Do it ENDIF ret ;CMBLNK ENDP ; Cursor control. ;LOCATE PROC NEAR LOCATE: IF ibmpc mov dx,0 ; Go to top left corner of screen. mov bh,0 mov ah,2 int bios ENDIF IF Z100 OR SIRIUS mov ah,prstr ; Function is print string mov dx,offset homcur ; Home cursor int dos ; do it ENDIF ret ;LOCATE ENDP