     .XLIST
;******************** Version 1.19 **********************************
; This is a kluge version for Seequa Chameleon and other IBM PC
;  lookalikes which have a built in comm port at a nonstandard
;  address, but interfaced to the BIOS a la IBM (i.e., INT 14
;  works normally). It implements PCKERMIT so that the DOS calls
;  and BIOS calls are used exclusively wherever possible.
;    The program will use the supplied baud rate to set up the BIOS
;  for I/O, using 8 bit nonparity transmission (and doing software
;  parity itself) inside of
;  KERMIT itself. Another effect intended is that where PCDOS V2
;  is used and the ANSI.SYS device is loaded to implement "vt100"
;  mode, it will work with Kermit in this version. Speed is likely
;  to suffer somewhat for direct connections however due to the
;  longer I/O path.
;   Note the BIOS routine is NOT interrupt driven or buffered (arrgh)
;  and accordingly this flavor of Kermit can't go as fast as "standard"
;  PCKERMIT, which handles 9600 baud easily. - G. Everhart
;   Glenn Everhart, RCA,   11/17/1983
;******************** Version 1.18 **********************************
; [18] A NAK for the next packet is not the same as an ACK for the
;      current packet if we're in Send-Init.  Also, account for
;      wraparound when comparing packet numbers that are off by one.
;      Daphne, 7/13/83
;******************** Version 1.3A **********************************
; [17] (a) Make command to SET BELL ON/OFF when transfer is complete.
;          Changed variable name to be consistent with other flags.
;      (b) Make it more like a Heath/Zenith H19 (I/D L/C,inverse,24x80).
;      (c) Fix Telflg to be in CS so Telnet works.
;      Dave King (CMU), 7/1/83
;******************** Version 1.3 **********************************
; [16] Make adjustments to XT changes so that things that used to work
;      still do: pass along characters with the eighth bit on, and in
;      OUTCHR, don't overwrite character after setting the appropriate
;      parity.
;      Daphne, 6/17/83
; [15] Add tabs stop and clear screen support.  Don't give checksum
;      warnings.  Give keyboard input higher scheduling priority than
;      port input.  This allows users to ^S, ^O, ^C, etc. the output
;      when the port is full of characters.  Add a CMU conditional
;      to swap control-backspace (delete) with backspace since TOPS-20
;      and VMS are more delete than backspace oriented.
;      Glenn Marcy, 6/8/83
; [14] Add CMU changes that allow Kermit to work on the XT.  Plus add
;      a statement omitted previously when comparing packet numbers.
;      Daphne, 5/26/83  (changes by Dave King, CMU)
;******************** Version 1.2 **********************************
; [13] When closing received file, handle case where number of bytes is
;      divisible by 128.
;      Daphne, 5/2/83
;******************** Version 1.1 **********************************
; [12] If "SET IBM", set local echo, XON/XOFF, and default (mark) parity.
;      Daphne, 4/15/83
; [11] In RPACK, don't push packet type, but store in temp variable.
;      If push and get an error, you pick up packet type as return addr.
;      Daphne, 4/15/83
; [10] Add Set Parity Command.
;      Daphne, 4/12/83
; [9]  Allow single-character wildcard in filenames, use "=".
;      Daphne, 4/4/83
; [8]  Add Kermit server support.
;      Daphne, 3/17/83
; [7]  Allow wildcards in filename.
;      Daphne, 3/15/83
; [6]  Make format of "Set Escape" look like the other commands.
;      Daphne, 3/14/83
; [5]  Add Set "End-of-Line" (to the char used to terminate packets I send).
;      Daphne, 3/7/83
; [4]  Ring bell when done (when succeed and when fail).
;      Daphne, 2/10/83
; [3]  Match keyword if "?" is the terminator.
;      Daphne, 2/9/83
; [2]  Change "Inpkt" so ignores bare CR from any system.
;      Daphne, 2/9/83
; [1]  Add "cmer04" - print error message if run off list of commands allowed.
;      Daphne, 2/9/83

;******************** Version 1.0 **********************************
; KERMIT - KL10 Error-free Reciprocal Micro Interconnect over TTY-lines
;
;       Program Version 1.18, Kermit Protocol Version 2
;       June 13, 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.


CMU     EQU     1               ; CMU conditional assembly. [15]
IBMPC   EQU     0               ; For IBM PC conditional assembly.
; note: for the generalized IBM PC LOOKALIKE version, set
; Z100, PCEMU, and Z100X to 1, Z100N to 0
;  For the real Z100 version set Z100 and Z100N to 1, and PCEMU and
;  Z100X to 0. For both of these, set IBMPC to 0. IBMPC version has
;  IBMPC set to 1, the rest to 0 (except possibly CMU and STEVE)
;  (Wonder what "STEVE" does?) - G. Everhart
Z100    EQU     1               ; For Heath/Zenith Z-100.
PCEMU   EQU     1		; For IBM PC emulators with nonstd comm addrs
Z100X   EQU     1		; SUM OF Z100 AND PCEMU
Z100N   EQU     0		; Z100-EXCLUSIVE CODE
; note: pcemu is a subconditional of z100 and will cause use of
; INT 14 (hex) for comm i/o, allowing ANSI.SYS use for PC console.
STEVE   EQU     0               ; For Steve's homebrew assembly.

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
ASYIO   EQU     14H	; BIOS call for PCEMU version [V1.19]

DOS     EQU     21H

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

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.                  [10 start]
PARMRK  EQU     01H             ; Mark parity.
PARNON  EQU     02H             ; No parity.
PARODD  EQU     03H             ; Odd parity.
PARSPC  EQU     04H             ; Space parity.
DEFPAR  EQU     PARNON          ; Default parity (none.)
IBMPAR  EQU     PARMRK          ; IBM's parity (mark.)          [10 end]

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.   [8]

BIOS    EQU     10H
COMM    EQU     14H
KEYB    EQU     16H
IF ibmpc
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 PCEMU
; Note change: use control - ^ for escape so we can run other Kermits
; from this one w/o confusion. Also easier to type 1-handed.
DEFESC   EQU     '^'-100Q  ; DEFAULT ESCAPE CHARACTER
ENDIF
IF Z100N
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
IF PCEMU
B0110  EQU      0  ; 110 BAUD
B0150  EQU      1  ; 150 BAUD
B0300  EQU      2  ; 300 BAUD
B0600  EQU      3  ; 600 BAUD
B1200  EQU      4  ; 1200 BAUD
B2400  EQU      5  ; 2400 BAUD
B4800  EQU      6  ; 4800 BAUD
B9600  EQU      7  ; 9600 BAUD
; FOLLOWING ARE MISC EXTRAS
B00455  EQU     0               ; 45.5 baud
B0050   EQU     1               ; 50 baud
B0075   EQU     2               ; 75 baud
B01345  EQU     4               ; 134.5 baud
B1800   EQU     9               ; 1800 baud
B2000   EQU     10              ; 2000 baud
B19200  EQU     14              ; 19200 baud
B38400  EQU     15              ; 38400 baud
; LAST 8 NOT REALLY USED BUT FILLERS
ENDIF

STACK   SEGMENT PARA STACK 'STACK'
        DW      100 DUP(0)      ; Initialize stack to all zeros.
STK     EQU     THIS WORD
STACK   ENDS

DATAS   SEGMENT PARA PUBLIC 'DATAS'

        ; Pure storage.

versio  db      'CUCCA'
IF ibmpc
        db      ' IBM-PC'
ENDIF
IF Z100N
        db      '/Stevens Heath/Zenith Z-100'
ENDIF
IF PCEMU
        db      '/General IBM PC Lookalike'
ENDIF
        db      ' Kermit-86 - ver 1.19',cr,lf,
        db      'Field Test Version',cr,lf,'$'
kerm    db      'Kermit-86>$'
spmes   db      'Spack:  $'
rpmes   db      'Rpack:  $'
hibit   db      'Warning - Non Ascii char$'
tmp     db      ?
foo     db      '$'
crlf    db      cr,lf,'$'
ender   db      bell,bell,'$'                   ;  [4]
tmsg1   db      cr,lf,'[Connecting to host, type $'
tmsg3   db      ' C to return to PC]',cr,lf,cr,lf,'$'  ; [17b]
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      cr,lf,'?Unable to tell host that session is finished$'
erms19  db      cr,lf,'?Unable to tell host to logout$'
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-$'         ; [6]
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,'BELL'    ; [17a]
        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'                     ; [10]
;        db      cr,lf,'RECEIVE parameter'
;        db      cr,lf,'SEND parameter'
IF ibmpc
        db      cr,lf,'VT52-EMULATION$'
ENDIF
IF Z100
        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$'   ; [10]
IF ibmpc
bdhlp   db      cr,lf,'300   1200   1800   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$'   ; [5]
eolerr  db      cr,lf,'Illegal end-of-line character$'  ; [5]
inthlp  db      cr,lf,'?  This message'
        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>$'
locst   db      cr,lf,'Local echo on$'
remst   db      cr,lf,'Local echo off$'
belon   db      cr,lf,'Ring bell at end of transfer$'     ; [17a - DT]
beloff  db      cr,lf,'No bell at end of transfer$'       ; [17a - DT]
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$'                      ; [10]
poddst  db      cr,lf,'Odd parity$'                     ; [10]
pevnst  db      cr,lf,'Even parity$'                    ; [10]
pmrkst  db      cr,lf,'Mark parity$'                    ; [10]
pspcst  db      cr,lf,'Space parity$'                   ; [10]
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$'
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 ^$'     ; [5]
escmes  db      cr,lf,'Escape character is  $'          ; [6]


outlin  db      cr,lf,'                CUCCA'
IF ibmpc
        db      ' IBM-PC'
ENDIF
IF Z100N
        db      '/Stevens Heath/Zenith Z-100'
ENDIF
IF PCEMU
	db      '/General IBM PC Lookalike'
ENDIF
        db      ' Kermit-86 V1.19',
        db      '  Field Test Version',cr,lf
        db      cr,lf,'Number of packets        (hex)'
        db      cr,lf,'Number of retries        (hex)'
        db      cr,lf,'File name $'
delstr  db      10O,' ',10O,10O,'$'     ; Delete string.
clrspc  db      ' ',10O,'$'             ; Clear space.
escspc  db      10O,' ',10O,'$'         ; Clear escape.
IF ibmpc
clrlin  db      cr,'$'                  ; Clear line (just the cr part).
ENDIF
IF Z100N
clrlin  db      cr,esc,'K$'             ; Clear line on Z-100
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
IF PCEMU
; note: for PCEMU version may have to add the ['s and O's to
; escape sequences for ANSI.SYS driver of PCDOS 2.0; Chameleon
; supports PCDOS 2.0 well enough.
clrlin  db      cr,esc,'[K$'             ; Clear line on Z-100
clreol  db      esc,'[K$'                ; Clear to end of line
clrscr  db      esc,'[H',esc,'[J$'        ; Home and clear screen
homcur  db      esc,'[1;1H$'                ; 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      curclr                  ; Clear display. [15]
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.
tn      dw      delchr                  ; Delete character. [17b]
to      dw      insmox                  ; Cancel Insert Character. [17b]
ENDIF

IF Z100N
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
IF PCEMU
scrhi   db      esc,'[3;24H',lf,'$'  ; 8th bit on in character
scrrpr  db      esc,'[7;1H','$'     ; Prompt when Kermit ends
screrr  db      esc,'[6;1H','$'     ; Error messages
scrfln  db      esc,'[5;12H','$'     ; File name
scrnrt  db      esc,'[3;25H',lf,'$'  ; Number of retries
scrnp   db      esc,'[3;25H','$'     ; Number of packets
scrfr   db      esc,'[6;1H','$'     ; Rename file
scrst   db      esc,'[3;52H','$'     ; Status
scrsp   db      esc,'[8;1H','$'     ; send packet
scrrp   db      esc,'[10;1H','$'     ; 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      0AH             ; Ten entries. [17a]
ENDIF
IF Z100
settab  db      09H             ; Nine entries.   [10]  [17a -- DT]
ENDIF
        db      04H,'BAUD$'
        dw      baudst
        db      04H,'BELL$'     ; [17a]
        dw      bellst          ; [17a]
        db      05H,'DEBUG$'
        dw      debst
        db      0BH,'END-OF-LINE$'               ;  [5]
        dw      eolset                           ;  [5]
        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$'                           ; [10]
        dw      setpar                                  ; [10]
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.                 [10 start]
        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                                          ;[10 end]

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$'     ;  [1]
cmin00  db      ' Confirm with carriage return$'
cmcrlf  db      cr,lf,'$'

cmstat  db      ?               ; What is presently being parsed.
cmaflg  db      ?               ; Non-zero when an action char has been found.
cmccnt  db      ?               ; Non-zero if a significant char is found.
cmsflg  db      ?               ; Non-zero when the last char was a space.
cmostp  dw      ?               ; Old stack pointer for reparse.
cmrprs  dw      ?               ; Address to go to on reparse.
cmprmp  dw      ?               ; Address of prompt.
cmptab  dw      ?               ; Address of present keyword table.
cmhlp   dw      ?               ; Address of present help.
cmdbuf  db      80H DUP(?)      ; Buffer for command parsing.
cmfcb   dw      ?               ; Pointer to FCB.
cmfcb2  dw      ?               ; Pointer to position in FCB.
cmcptr  dw      ?               ; Pointer for next char input.
cmdptr  dw      ?               ; Pointer into the command buffer.
cmsiz   dw      ?               ; Size info of user input.
cmkptr  dw      ?               ; Pointer to keyword.
cmsptr  dw      ?               ; Place to save a pointer.
cmchr   db      ?               ; Save char when checking ambiguity.

; Program storage.

oldstk  dw      ?               ; Storage for system stack.
oldsts  dw      ?               ; System stack segment.
ssp     dw      0               ; Save SP in Telnet.
bufhex  dw      80H
filsiz  dd      0               ; Double word for filesize (in bytes.)
eoflag  db      ?               ; EOF flag; non-zero on EOF.
wldflg  db      0               ; Assume no "*" in fn.         [7]
;telflg db      0               ; Are we acting as a terminal. [16] [17c]
belflg  db      1               ; Use bell  [17a -- DT]
incmod  db      0               ; Insert Character mode.  [17b]
debug   db      0               ; Debugging mode (default off).
hierr   db      0               ; Non-ascii char (non-zero if yes).
filflg  db      ?               ; Non-zero when nothing in DMA buffer.
ecoflg  db      0               ; Local echo flag (default off).
parflg  db      defpar          ; Parity flag (default none.)  [10]
escflg  db      0               ; Escape flag (start off).

IF ibmpc
vtflg   db      1               ; VT52 emulation flag (default on).
curatt  dw      0007H           ; Video attributes. [17b]
baud    dw      B1200           ; Use default of 1200.
ENDIF
IF Z100
curatt  dw      0007H			; mode for terminal
auxcnf  db      4 dup(?)        ; AUX port configuration info
baud    db      B1200               ; Baud rate (1200 DEFAULT)
auxcnf1 db      12 dup(?)       ; 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   dw      ?               ; Number of chars read in from port.
chrcnt  dw      ?               ; Number of chars in the file buffer.
filcnt  dw      ?               ; Number of chars left to fill.
outpnt  dw      ?               ; Position in packet.
bufpnt  dw      ?               ; Position in file buffer.
fcbptr  dw      ?               ; Position in FCB.
datptr  dw      ?               ; Position in packet data buffer.
cbfptr  dw      ?               ; Position in character buffer.
pktptr  dw      ?               ; Poistion in receive packet.
siz     dw      ?               ; 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  dw      ?               ; Packet number.
numpkt  dw      ?               ; Total number of packets sent.
numrtr  dw      ?               ; Total number of retries.
numtry  db      ?               ; Number of tries on this packet.
oldtry  db      ?               ; Number of tries on previous packet.
state   db      ?               ; Present state of the automaton.
savsci  dw      ?               ; Save for serial port interrupt vector. [14]
savscs  dw      ?               ; Ditto.  [14]
packet  db      ?,?,?,?         ; Packet (data is part of it).
data    db      5AH DUP(?)      ; Data and checksum field of packet.
recpkt  db      60H DUP(?)      ; Receive packet storage (use the following).
filbuf  db      60H DUP(?)      ; Character buffer.
fcb     db      25H DUP(?)      ; Use as our FCB.
cpfcb   db      25H DUP(?)      ; Save FCB in case of "*".   [7]
buff    db      80H DUP(?)      ; Use as our DAT.
rdbuf   db      80H DUP(?)
cnt     dw      0
temp    dw      0
temp1   dw      ?               ; Temporary storage.
temp2   dw      ?
temp3   dw      ?
temp4   dw      ?
argblk  dw      ?               ; For subroutine arguments.
argbk1  dw      ?
argbk2  dw      ?
argbk3  dw      ?

DATAS   ENDS                    ; End data segment


MAIN    SEGMENT PARA PUBLIC 'MAIN'
START   PROC  FAR
        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.

        mov ax,datas            ; Initialize DS.
        mov ds,ax
        sub ax,ax

        mov oldstk,sp           ; Save old stack pointer.

        call cmblnk             ; Clear the 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 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 Z100N
        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
IF PCEMU
	mov ah,3	; set up to read status
	mov dx,0	; zero for 1st port
	int asyio	; get status from bios
	mov auxcnf,al	; save status in 1st byte. forget rest.
; NOTE: Status won't return baud rate... use whatever is set here to
; init things. Remember however that the BIOS routine is not
; interrupt driven and can't keep up with high rates too well...
	mov	baud,al	; get user's baud rate
	shl al,1
	shl al,1
	shl al,1
	shl al,1	; shift into place
	shl al,1
	or	al,3	; set 8 bit length, 0 parity etc.
	int	asyio	; start i/o up
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 sp,oldstk
        ret

START   ENDP


; These are some utility routines.

;       Abort

ABORT   PROC    NEAR
        mov state,'A'           ; Otherwise abort.
        ret
ABORT   ENDP

;       NAK

NAK     PROC    NEAR
        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
IF ibmpc
        mov ah,2
        mov bh,0
        mov dx,screrr
        int bios
        ret
ENDIF
IF Z100
        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
IF ibmpc
        mov ah,2
        mov bh,0
        mov dx,scrnrt
        int bios
        ret
ENDIF
IF Z100
        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
        push bx
IF ibmpc
        mov ah,2
        mov bh,0
        mov dx,scrhi
        int bios
ENDIF
IF Z100
        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            ; [6 start]
        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                    ; [6 end]

;       FCB must be remembered if found "*" in filename.      [7 start]
;       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
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
        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
        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
        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
        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
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
        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

;       RECEIVE command

READ    PROC    NEAR
        mov bx,offset data      ; Where to put text (if any).  [8 start]
        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                                              ; [8 end]
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 serini             ; Initialize serial port. [14]
        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
        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
IF ibmpc
        mov ah,2
        mov dx,scrnp
        mov bh,0
        int bios
ENDIF
IF Z100
        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.
        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
        call serrst             ; Reset serial port. [14]
IF ibmpc
        mov ah,2                ; Position cursor.
        mov dx,scrst
        mov bh,0
        int bios
ENDIF
IF Z100
        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
        cmp belflg,0            ; Bell desired?  [17a]
        je readnb               ; No.  [17a]
        mov dx,offset ender     ; Ring them bells.    [4]
        int dos                 ; [4]
readnb:                         ; [17a -- new label]
IF ibmpc
        mov ah,2
        mov dx,scrrpr           ; Put prompt here.
        mov bh,0
        int bios
ENDIF
IF Z100
        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:  call serrst             ; Reset serial port. [14]
IF ibmpc
        mov ah,2                ; Position cursor.
        mov dx,scrst
        mov bh,0
        int bios
ENDIF
IF Z100
        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 dx,offset ender     ; Ring them bells.   [4]
        int dos                 ;  [4]
IF ibmpc
        mov ah,2
        mov dx,scrrpr
        mov bh,0
        int bios
ENDIF
IF Z100
        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
        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.
        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
        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.
        cmp ax,0                ; Had we wrapped around? [18 start]
        jne rfilx
        mov ax,64
rfilx:  dec ax                  ; Decrement.  [18 end -- new label]
        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.
        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.
        cmp ax,0                ; Had we wrapped around? [18 start]
        jne rfily
        mov ax,64
rfily:  dec ax                  ; Decrement.  [18 end -- new label]
        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.)
        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.)
        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).
        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
        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.  [14]
        mov ax,pktnum
        cmp ax,0                ; Had we wrapped around? [18 start]
        jne rdatx
        mov ax,64
rdatx:  dec ax                  ; [14] [18 end -- new label]
        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.)
        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.)
        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,0                ; Had we wrapped around? [18 start]
        jne rdaty
        mov ax,64
rdaty:  dec ax                  ; [14 Omitted accidentally - D.T.] [18 end]
        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.)
        mov ah,'Y'              ; Acknowledge packet.
        call spack              ; Send the packet.
         jmp abort
        ret
rdata3: cmp ah,'Z'              ; Is it a EOF packet?
        je rdat3x                               ; [13]
        jmp rdata4               ; Try and see if its an error. [13]
rdat3x: mov ax,pktnum           ; Get the present packet number. [13]
        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              ;   [13 start]
        jne rdat34
        call outbuf             ; Write out buffer if no room for ^Z.
         jmp abort
        mov ax,0                ;   [13 end]
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
        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.)
        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
        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
        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
        mov dx,offset crlf
        int dos
        mov ah,prstr
        mov dx,offset erms15
        int dos
        ret
send12: cmp wldflg,0            ; Any wildcards.      [7 start]
        je send16               ; Nope, so no problem.
        mov bx,offset fcb       ; Remember what FCB looked like.
        mov di,offset cpfcb
        mov cl,37               ; Size of FCB.
        call fcbcpy
        mov di,offset fcb+1     ; Copy filename from DTA to FCB.
        mov bx,offset buff+1
        mov cl,11
        call fcbcpy                                     ; [7 end]
send16: call init               ; Clear the line and initialize the buffers.
        call serini             ; Initialize serial port. [14]
        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
        mov ah,2                ; Position cursor.
        mov bh,0
        mov dx,scrst
        int bios
ENDIF
IF Z100
        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
IF ibmpc
        mov ah,2
        mov dx,scrnp
        mov bh,0
        int bios
ENDIF
IF Z100
        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
        call serrst             ; Reset serial port.  [14]
IF ibmpc
        mov ah,2                ; Position cursor.
        mov dx,scrst
        mov bh,0
        int bios
ENDIF
IF Z100
        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
        cmp belflg,0            ; Bell desired? [17a]
        je sendnb               ; [17a]
        mov dx,offset ender     ; Ring them bells.   [4]
        int dos                 ;  [4]
sendnb:                         ; [17a -- new label]
IF ibmpc
        mov ah,2
        mov dx,scrrpr
        mov bh,0
        int bios
ENDIF
IF Z100
        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:  call serrst             ; Reset serial port.  [14]
IF ibmpc
        mov ah,2                ; Position cursor.
        mov dx,scrst
        mov bh,0
        int bios
ENDIF
IF Z100
        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 dx,offset ender     ; Ring them bells.   [4]
        int dos                 ;  [4]
IF ibmpc
        mov ah,2
        mov dx,scrrpr
        mov bh,0
        int bios
ENDIF
IF Z100
        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
        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. [18 start]
;        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. [18 end]
        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
        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.

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.
        and ax,03FH             ; Account for wraparound.  [18]
        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
        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

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.
        and ax,03FH             ; Account for wraparound.  [18]
        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
        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

        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.
        and ax,03FH             ; Account for wraparound.  [18]
        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
        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.
        and ax,03FH             ; Account for wraparound.  [18]
        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

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
        jns gtch52              ; Any chars left?
        mov chrcnt,0            ; If not, say so.
        mov al,cl                       ; Return the count in A.
        mov ah,0
        jmp rskp
gtch52: mov ah,[bx]                     ; Get the next char.
        inc bx                  ; Move the pointer.
        cmp ah,('Z'-100O)               ; Is it a ^Z?
        jz gtch51               ; If so see if they rest are.

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.
inbuf0: push bx
        push cx
        mov bx,offset buff      ; Set the r/w buffer pointer.
        mov bufpnt,bx
        mov ah,readf            ; Read a record.
        mov dx,offset fcb
        int dos
        mov cx,filsiz
        cmp cx,0                ; Check for 128 chars or less left.
        jne inbuf1              ; Still have data left.
        mov ax,ds
        mov es,ax
        mov si,offset filsiz+2
        mov di,offset bufhex
        cmps filsiz+2,es:bufhex
        ja inbuf1               ; More than 128 chars.
        mov eoflag,0FFH         ; Set End-of-file.
        mov cx,filsiz+2
        mov chrcnt,cx           ; Return proper number of chars.
        mov filflg,0            ; Buffer not empty.
        pop cx
        pop bx
        jmp rskp
inbuf1: sub filsiz+2,80H        ; Sent another 128 chars.
        sbb filsiz,0            ; Account for the doubleword.
        mov al,80H              ; Use as counter for number of chars read.
        pop cx
        pop bx
        cmp filflg,0            ; Ever used DMS?
        jnz inbf21              ; Nope, then don't change count.
        dec al                  ; Fix boundary error.
inbf21: mov ah,0                ; Zero the flag (buffer not empty).
        mov chrcnt,ax           ; Number of chars read from file.
        mov filflg,0            ; Buffer not empty.
        jmp rskp

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
        mov bx,offset fcb+18    ; File size in bytes (hi order word).
        mov di,offset filsiz    ; Where to put the info.
        mov ax,[bx]
        mov [di],ax
        mov bx,offset fcb+16    ; Lo order word.
        mov ax,[bx]
        mov 2[di],ax
        sub filsiz+2,1          ; Don't count the ^Z.
        sbb filsiz,0
        jmp rskp


gtnfil: cmp wldflg,0            ; Was there a "*"?              [7 start]
        je gtn5                 ; Nope.
        mov bx,offset cpfcb     ; Get FCB from last check for file.
        mov di,offset fcb       ; Copy to FCB.
        mov cl,37               ; Size of FCB.
        call fcbcpy
gtn2:   mov ah,snext
        mov dx,offset fcb       ; More files?
        int dos
        cmp al,0FFH
        je gtn5
        mov bx,offset fcb
        mov di,offset cpfcb
        mov cl,37
        call fcbcpy             ; Copy from FCB.
        mov di,offset fcb+1     ; Get name of next file to send.
        mov bx,offset buff+1
        mov cl,11
        call fcbcpy
        call getfil             ; Initialize
         jmp r
        jmp rskp
gtn5:   mov wldflg,0            ; Reset wild card flag.
        ret                                             ;  [7 end]


;       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
        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

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
        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: call outpkt             ; Call the system dependent routine.
         jmp r
        jmp rskp

SPKT    ENDP
;       Write out a packet.

OUTPKT  PROC    NEAR
        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
IF ibmpc
outchr: sub cx,cx               ; [14 start]
        mov al,ah               ; Parity routine works on AL. [16]
        call dopar              ; Set parity appropriately.     [10]
        mov ah,al               ; Don't overwrite character with status. [16]
        mov dx,03FDH
outch1: in al,dx
        test al,20H             ; Transmitter ready?
        jnz outch2              ; Yes
        loop outch1
         jmp r                  ; Timeout
outch2: mov al,ah               ; Now send it out
        mov dx,03F8H
        out dx,al
        jmp rskp                ; [14 end]
ENDIF
IF Z100N
outchr: mov al,ah               ; Yes, get the character into al
        mov cx,0
        call dopar              ; Set parity appropriately.   [10]
outch1:
        call bios_auxout        ; Send the character
        jmp rskp
ENDIF
if pcemu
outchr: mov al,ah               ; Yes, get the character into al
        mov cx,0
        call dopar              ; Set parity appropriately.   [10]
outch1:
	mov ah,1		; set up for output of character
	push dx
	mov	dx,0		; set adapter 0
	int asyio		; let bios put it out
	pop	dx
        jmp rskp
endif

;************************System Dependent****************************
;
;       Get a char from the port and return in AH.

inchr:
IF ibmpc
        call prtchr             ; Get character if ready.  [14]
         jmp inchr3             ; Got it in AL.  [14]
ENDIF
IF Z100N
        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
IF PCEMU
        push    bx              ; Save BX
	mov ah,3		; get status function (see if anything there)
	push dx
	mov	dx,0	; adaptor 0
	int asyio		; see if anything's there
	pop	dx
	and ah,1		; look at data ready bit only
	cmp ah,1		; 1 means data ready
	jz inchr3		; if zero (equal), data there... read it
        pop bx                  ; And restore BX
ENDIF
; KEEP LOOKING HERE FOR CONSOLE OR COMM I/O
        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 Z100N
        mov ah,chr_read         ; Get the function to read
        call bios_auxfunc       ; Get a character
        pop bx                  ; Restore BX
ENDIF
IF PCEMU
	mov ah,2		; read from aux function
	push dx
	mov	dx,0		; select com 0
	int asyio		; bios read call
; CHAR RETURNS IN AL
	pop	dx
        pop bx                  ; Restore BX
ENDIF
        mov ah,al
        cmp parflg,parnon       ; Is the parity none?   [10]
        je inchr5               ; We're done.           [10]
        and ah,7FH                      ; Turn off the parity bit.
inchr5: jmp rskp

; Set parity for character in Register AL.

dopar:  cmp parflg,parnon       ; No parity?                    [10 start]
        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                                                     ; [10 end]
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
IF ibmpc
        mov ah,2
        mov dx,scrst            ; Position cursor.
        mov bh,0
        int bios
ENDIF
IF Z100
        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: 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, return bad.
        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. [11]
        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.
        ret
rpack4: mov ah,0
        mov [bx],ah             ; Put a null at the end of the data.
        mov ax,temp             ; Get the type.   [11]
        jmp rskp
RPACK   ENDP


INPKT   PROC    NEAR
        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.   [2 start]
        jne inpkt6
        mov incnt,0
        mov bx,offset recpkt
        jmp inpkt2              ;                   [2 end]
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
        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.  [8]

ERROR   PROC    NEAR
        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                                            ; [8 start]
        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
        mov numtry,0            ; Initialize count.
        call serini             ; Initialize port.  [14]
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
        call serrst             ; Reset port.  [14]
        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
        call serrst             ; Reset port.  [14]
        jmp rskp
logo4:  cmp ah,'E'              ; Error packet?
        jnz logo1               ; Try sending the packet again.
        call error1
        call serrst             ; Reset port.  [14]
        ret
LOGO    ENDP

; FINISH - tell remote KERSRV to exit.

FINISH  PROC    NEAR
        mov ah,cmcfm            ; Parse a confirm.
        call comnd
         jmp r
        mov numtry,0            ; Initialize count.
        call serini             ; Initialize port.  [14]
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
        call serrst             ; Reset port.  [14]
        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
        call serrst             ; Reset port. [14]
        jmp rskp                ; Yes, then we're done.
fin4:   cmp ah,'E'              ; Error packet?
        jnz fin1                ; Try sending it again.
        call error1
        call serrst             ; Reset port.  [14]
        jmp rskp
FINISH  ENDP

; BYE command - tell remote KERSRV to logout & exits to DOS.

BYE     PROC    NEAR
        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                                        ; [8 end]
BYE     ENDP

; This is the 'exit' command.  It leaves KERMIT and returns to DOS.

EXIT    PROC    NEAR
        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
        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.
telflg  db      0               ; Are we acting as a terminal. [16] [17c]
ENDIF
IF Z100
telflg  db      0               ; Are we acting as a terminal. [16] [17c]
ENDIF

;       This is the CONNECT command.

TELNET  PROC    NEAR
        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 dx,offset tmsg1
        int dos
        call escprt
        mov ah,prstr
        mov dx,offset tmsg3
        int dos
        mov ah,3                ; Get cursor position.  [17b start]
        mov bh,0
        int bios
        dec dh                  ; Decrement ROW attribute. (DT)
        mov ah,2
        int bios                ; [17b end]
        mov cs:telflg,0FFH      ; Turn on Telnet flag.  [16] [17c]
        call serini             ; Initialize serial port. [14]
IF ibmpc
        xor ax,ax
        mov cx,ds               ; Save DS in CX.
        mov ds,ax               ; Use low core.
        mov bx,6CH              ; "break" interrupt vector.
        push [bx]
        mov bx,6EH
        push [bx]
        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.
ENDIF
IF Z100
        mov ssp,sp              ; Save current stack pointer.
ENDIF
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: cmp al,TAB              ; Tab ? [15]
        jne notab               ; No, skip the jump [15]
        call dotab              ; Yes, handle the tab [15]
        jmp telnoe              ; And get the next character [15]
notab:  call dotty              ; Use our own TTY I/O.  [17b]
        jmp telnoe
ENDIF
IF Z100
        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

; Put character in AL to the screen.  [17b start]

DOTTY   PROC NEAR
        push ax
        mov ah,3                ;Get cursor
        mov bh,0
        int bios
        pop ax
        cmp al,8                ;Backspace?
        je dotty3
        cmp al,0DH              ;CR?
        je dotty4
        cmp al,0AH              ;LF?
        je dotty5
        cmp incmod,0            ;I/C?
        jne dotty7
        mov ah,9                ;Ordinary character
        mov bx,curatt
        mov cx,1
        int bios
        mov ah,2
        mov bh,0
        inc dl                  ;Step cursor
        cmp dl,80               ;Overflow?
        jne dotty2
        ret
dotty1: inc dh
dotty6: mov ah,2
dotty2: int bios
        ret
dotty3: dec dl                  ;BS
        jge dotty6
        ret
dotty4: mov dl,0                ;CR
        jmp dotty6
dotty5: cmp dh,23               ;LF
        jl dotty1
        mov ah,8                ;Get attribute of last line
        int bios
        mov bh,ah
        mov ax,0601H            ;Scroll
        sub cx,cx
        mov dx,174FH
        jmp dotty2
dotty7: mov temp,ax             ;DK6 Save the character
        mov temp1,dx            ;Save the cursor
        mov dl,78               ;Start shift at end of line
        mov temp2,dx
        mov ah,1                ;Turn off cursor
        mov ch,20H
        int bios
dotty8: mov ah,2                ;Position to col M
        mov bh,0
        mov dx,temp2
        int bios
        mov ah,8                ;Read char/attr
        int bios
        mov cx,ax               ;Save it
        mov ah,2                ;Position to col M+1
        inc dx
        int bios
        mov ah,9                ;Write char/attr
        mov al,cl
        mov bl,ch
        mov cx,1
        int bios
        dec dx
        dec temp2
        cmp dx,temp1
        jne dotty8
        mov ah,2                ;Position
        mov bh,0
        int bios
        mov ax,temp             ;Write the char
        mov ah,9
        mov bx,curatt           ;In the current video mode
        mov cx,1
        int bios
        mov ah,2                ;Step to next column
        inc dl
        int bios
        mov ah,1                ;Turn on cursor
        mov cx,0B0CH
        int bios
        ret                     ; [17b end]
DOTTY   ENDP

EXTLN   PROC    NEAR
IF ibmpc
        call serrst             ; Reset serial port. [14]
        mov sp,ssp
        xor bx,bx
        mov cx,ds               ; Save DS register.
        mov ds,bx               ; Address low memory.
        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
        mov sp,ssp
ENDIF
        mov ah,prstr
        mov dx,offset tmsg2
        int dos
        mov cs:telflg,0         ; Not acting as terminal anymore. [16] [17c]
        jmp rskp
EXTLN   ENDP

;[14 start]       Common initialization for using serial port.

SERINI  PROC    NEAR
IF ibmpc
        cli                     ; Disable interrupts
        cld                     ; Do increments in string operations
        xor ax,ax               ; Address low memory
        mov es,ax
        mov bx,30H              ; Save serial card interrupt vector
        mov ax,es:[bx]
        mov savsci,ax
        mov ax,offset serint    ; And point it to my routine
        mov es:[bx],ax
        mov bx,32H
        mov ax,es:[bx]
        mov savscs,ax
        mov es:[bx],cs
        lea ax,cs:source        ; Initialize the pointers
        mov cs:srcpnt,ax
        mov cs:savesi,ax
        mov cs:count,0
        mov di,cs:srcpnt        ; Where to store bytes
        mov ax,cs               ; Ready ES for string operations
        mov es,ax
        mov si,0                ; Where to fetch bytes
        in al,21H               ; Set up 8259 interrupt controller
        and al,0EFH             ; Enable INT4
        out 21H,al
        mov dx,03FBH            ; Set up the serial card
        mov al,3
        out dx,al
        mov dx,03F9H
        mov al,1                ; Set up interrupt enable register
        out dx,al
        mov dl,0FCH             ; Enable interrupts from serial card
        mov al,0BH
        out dx,al
        sti                     ; Allow interrupts
        mov dl,0F8H
        in al,dx
ENDIF
        ret
SERINI  ENDP

SERRST  PROC    NEAR
IF ibmpc
        cli                     ; Disable interrupts
        mov dx,03FCH            ; Disable modem interrupts
        mov al,3
        out dx,al
        in al,21H               ; Interrupt controller
        or al,10H               ; Inhibit IRQ4
        out 21H,al
        xor bx,bx               ; Address low memory
        mov es,bx
        mov bx,30H              ; Restore the serial card interrupt vector
        mov ax,savsci
        mov es:[bx],ax
        mov bx,32H
        mov ax,savscs
        mov es:[bx],ax
        sti
ENDIF
        ret
SERRST  ENDP                                    ; [14 end]

; *********** serial port interrupt routine ********

IF ibmpc
SERINT  PROC  NEAR
        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
        mov ah,0FFH             ; Assume X-fer mode. [16 start]
        cmp cs:telflg,0         ; File transfer or terminal mode? [17c]
        jz srint0
        mov ah,7FH              ; Terminal mode (7 bits only).
srint0: and al,ah               ; Fiddle with input. [16 end]
        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
        call conchr             ; Check keyboard.   [15 begin]
         jmp extln              ; Exit from Telnet
         nop                    ; In case it is a short jump (Z100)
        call prtchr             ; Check serial port
         ret                    ; Got a character
         nop                    ; Use up three bytes.  [15 end]
         nop
        jmp plup
PLUP    ENDP

;************************System Dependent****************************

; These I/O routines are similar to those just above.

PRTCHR  PROC    NEAR
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 Z100N
        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
IF PCEMU
        push bx                 ; Save BX
	mov ah,3		; examine status function
	push	dx
	mov	dx,0
	int asyio		; bios aux i/o call
	pop	dx
	and ah,1		; LOOK AT DATA READY BIT
	cmp ah,1		; data ready?
	jz prtch1		; if zero compare, yes, go get it
        pop bx                  ; Restore BX
        jmp rskp                ; No, give skip return
prtch1: mov ah,2                ; Want to read character
	push	dx
	mov	dx,0		; must select com0
	int asyio
	pop	dx
        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
        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
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 nobrk                ; Pass nulls.  [14]
        cmp ah,83               ; Del Key?  [14]
        je cnc1r                ; Yes - send a rubout. [14]
        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
        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

cnc1r:
IF CMU                          ; [15]
        mov al,BS               ; BS (will be converted to DEL) [15]
        jmp nobrk
ENDIF                           ; [15]
        mov al,07FH             ; ASCII rubout.  [14]
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.
IF CMU                          ; [15 begin]
        cmp dl,BS               ; Is it a backspace ?
        jnz cch0                ; No, check for delete
        mov dl,DEL              ; Yes, get a delete
        jmp cch1                ; And send that instead
cch0:   cmp dl,DEL              ; Is it a delete ?
        jnz cch1                ; No, done checking then
        mov dl,BS               ; Yes, use a backspace
cch1:   mov ax,dx               ; Copy character back to AX
ENDIF                           ; [15 end]
        call dopar              ; Set parity (if any).   [10]
        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
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: 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.     [10]
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 ibmpc
        mov dx,mdmdat
        out dx,al
ENDIF
IF Z100N
        call bios_auxout        ; Send the character
ENDIF
IF PCEMU
	mov ah,1   ; send function
	push	dx
	mov	dx,0		; send out character on com 0
	int asyio
	pop	dx
ENDIF
        ret
CONN    ENDP

; [15 begin]
DOTAB   PROC NEAR
        mov ah,3                ; Read current cursor position.
        mov bh,0                ; This screen
        int bios                ; From bios
        cmp dl,72               ; Are we at the last tab stop ?
        jl dotab0               ; No, move to the next
        cmp dl,79               ; Are we at the end ?
        je dotab2               ; Yes, just return
        add dl,1                ; No, move forward one position
        jmp dotab1              ; Set the cursor position
dotab0: mov al,dl               ; Get the column into al
        push dx                 ; Save the current cursor position
        xor ah,ah               ; Zero the high end of ax
        mov bl,8                ; Get an eight
        xor bh,bh               ; Zero high byte
        div bl                  ; Divide by 8
        mov al,ah               ; Put the remainder in the low end
        xor ah,ah               ; Zero the high end
        mov cl,8                ; Get an 8 into cl
        xor ch,ch               ; Zero high byte
        sub cl,al               ; Subtract al from cl
        xor ch,ch               ; Zero high end
        pop dx                  ; Restore the current cursor position
        add dl,cl               ; And subtract column mod 8
dotab1: mov ah,2                ; Set cursor position
        mov bh,0                ; This screen
        int bios                ; Bios call
dotab2: ret                     ; Return
DOTAB   ENDP

; [15 end]

TELESC  PROC    NEAR
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,'<'              ; Start-ANSI?  [17b start]
        je vtexit               ; Yes, ignore
        cmp ah,'['              ; An ANSI command?
        je vtansi               ; Yes, do it
        cmp ah,'@'              ; Insert characters?
        jne vtnins
        mov incmod,1
        jmp telnoe
vtnins: cmp ah,'p'              ; Inverse?
        jne vtninv
        jmp vtinvi
vtninv: cmp ah,'q'              ; Normal?
        jne vtnino
        jmp vtinvo              ; [17b end]
vtnino: cmp ah,'A'              ; Less than an 'A'?
        jl vtig                 ; Yes - ignore.
        cmp ah,'O'+1            ; Greater than 'O'?   [17b]
        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
vtexit: jmp telnoe              ; Return home. [17b]

; ANSI Insert/Delete Line.  [17b start]
vtansi: call plup
        cmp al,'?'
        je vtanso
        sub al,30H
        mov temp,ax
        call plup
        cmp al,"9"
        jg vtans1
        sub al,30H
        mov temp2,ax
        mov ax,temp
        mov dl,10
        mul dl
        add ax,temp2
        mov temp,ax
        call plup
vtans1: cmp al,'L'
        jne vtans2
        mov ah,3                ; Get cursor position
        mov bh,0
        int bios
        mov temp1,dx
        mov cx,dx               ; Do a N-line scroll
        mov cl,0
        mov dx,184FH
        mov ax,temp
        mov ah,7
        mov bh,7
        int bios
        jmp vtans3
vtans2: cmp al,'M'
        jne vtans4
        mov ah,3
        mov bh,0
        int bios
        mov temp1,dx
        mov ax,temp
        mov ah,6
        mov cx,dx
        mov dx,184FH
        mov bh,7
        int bios
vtans3: mov dx,temp1            ; Restore cursor position
        mov dl,0
        mov ah,2
        mov bh,0
        int bios
vtans4: jmp telnoe
vtanso: call plup
        call plup
        jmp telnoe

vtinvi: mov curatt,0070H        ; Reverse video
        jmp telnoe
vtinvo: mov curatt,0007H        ; Normal video
        jmp telnoe              ;  [17b end]
TELESC  ENDP

IF ibmpc
TEL     PROC    NEAR
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.

curclr: call locate             ; Home the cursor [15]
        jmp curscr              ; And clear the screen [15]

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

; Delete character.  [17b start]
delchr: mov ah,3                ; Get cursor position
        mov bh,0
        int bios
        mov temp,dx
        mov ah,1                ; Turn off cursor
        mov ch,20H
        int bios
delch1: mov ah,2                ; Position to col M+1
        inc dl
        int bios
        mov ah,8                ; Get char/attr
        int bios
        mov cx,ax               ; Save it
        dec dl                  ; Position to col M
        mov ah,2
        int bios
        mov ah,9                ; Write char/attr
        mov al,cl
        mov bl,ch
        mov cx,1
        int bios
        inc dl                  ; Next column
        cmp dl,79               ; About to write to col 80?
        jne delch1              ; No
        mov ah,2                ; Position to col 80
        int bios
        mov ah,9                ; Write char/attr
        mov al,' '
        int bios
        mov ah,2                ; Reset cursor
        mov dx,temp
        int bios
        mov ah,1
        mov cx,0B0CH
        int bios
        jmp telnoe

; Cancel Insert Character mode
insmox: mov incmod,0
        jmp telnoe              ; [17b end]
TEL     ENDP
ENDIF


; This is the SET command.

SETCOM  PROC    NEAR
        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.     [6 start]

ESCAPE  PROC    NEAR
        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 dx,offset crlf
        int dos
        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                    ; [6 end]

;       This is the End-of-line character SET subcommand.       [5 start]

EOLSET  PROC    NEAR
        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 dx,offset crlf
        int dos
        mov dx,offset kerm
        int dos
        mov bx,cmdptr
        mov al,'$'
        mov [bx],al
        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                                                 ;  [5 end]

;       This is the LOCAL echo SET subcommand.

LCAL    PROC    NEAR
        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
        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
        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?    [12 start]
        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.       [12 end]
        ret
IBMSET  ENDP

;       This is the SET File-Warning command.

FILWAR  PROC    NEAR
        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.                         [10 start]

SETPAR  PROC    NEAR
        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                                                    ; [10 end]

; Sets debugging mode on and off.

DEBST   PROC    NEAR
        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

; Turn bell on or off.    [17a start]

BELLST  PROC    NEAR
        mov dx,offset ontab
        mov bx,offset onhlp
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd
         jmp r
        pop bx
        mov belflg,bl
        ret
BELLST  ENDP                      ;  [17a end]

;  This function sets the baud rate.

BAUDST  PROC    NEAR
        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
IF ibmpc
        mov baud,bx           ; Set the IBM flag.
        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 PCEMU
        mov bx,ds               ; Set up pointer to config info
        mov es,bx               ;  .  .  .
        mov bx,offset auxcnf    ;  .  .  .
	push	dx
	mov	dx,0		; select 1st port
	mov	al,baud		; get baud rate desired
	shl al,1
	shl al,1
	shl al,1
	shl al,1	; shift into place
	shl al,1
	and	al,0e0h		; mask for double safety
	or	al,3		; set 8 bit characters, no paroity
	mov ah,0		; setup control
	int asyio
	pop	dx
ENDIF
IF Z100N
        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
        call stat0
         jmp r
        jmp rskp
STATUS  ENDP

STAT0   PROC    NEAR
        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.             [10 start]
        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                                                 ;[10 end]
        mov dx,offset belon     ; Tell if bells ring at end.  [17a start - DT]
        cmp belflg,0
        jne stat7
        mov dx,offset beloff    ; No bells.
stat7:  mov ah,prstr
        int dos                 ; That's it.  [17a end - DT]
        mov dx,offset eolst     ; Tell the end-of-line char used.  [5 start]
        mov ah,prstr
        int dos
        mov ah,conout
        mov dl,seol
        add dl,40H
        int dos                                                  ; [5 end]
        mov ah,prstr
        mov dx,offset escmes                    ; Print escape character.  [6]
        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
        jnz stat9b
        jmp stat9
stat9b: mov dx,offset b18st
        cmp baud,B1800
        jz stat9
        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
IF Z100
        cmp baud,B0300
        jz stat9
        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
        mov dx,offset b06st
        cmp baud,B0600
        je stat9
        mov dx,offset b20st
        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
        pop bp
        add bp,3
        push bp
        ret
RSKP    ENDP

; Jumping here is the same as a ret.

R       PROC    NEAR
        ret
R       ENDP

; This routine prints the number in AX on the screen.
;       (Thanks to Jeff Damens)

NOUT    PROC    NEAR
        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
        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
        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
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
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.   [8]
        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.   [1]
        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?    [3]
        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?     [3]
        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 cmky6               ; Go to end of keyword and try next.
        jmp cmky3

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 dx,offset crlf
        int dos
        mov dx,offset kerm
        int dos
        mov bx,cmdptr           ; Get pointer into buffer.
        mov al,'$'
        mov [bx],al             ; Add dollar sign for printing.
        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 dx,offset crlf
        int dos
        mov dx,offset kerm
        int dos
        mov bx,cmdptr
        mov al,'$'
        mov [bx],al             ; Put in dollar sign for printing.
        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.

cmtext: mov cmptab,bx           ; Save pointer to data buffer.   [8 start]
        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.
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                                      ; [8 end]

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.
IF ibmpc
        mov cx,0
        mov dx,184FH
        mov bh,7
        mov ax,600H
        int bios
ENDIF
IF Z100
        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
IF ibmpc
        mov dx,0                ; Go to top left corner of screen.
        mov bh,0
        mov ah,2
        int bios
ENDIF
IF Z100
        mov ah,prstr            ; Function is print string
        mov dx,offset homcur    ; Home cursor
        int dos                 ; do it
ENDIF
        ret
LOCATE  ENDP


MAIN    ENDS                    ; End of code section.
        END     START
