DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T m

⟦a4a7f685e⟧ TextFile

    Length: 67293 (0x106dd)
    Types: TextFile
    Names: »mszrmx.a86«

Derivation

└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
    └─⟦71044c191⟧ »EurOpenD3/misc/kermit.ms-2.32.tar.Z« 
        └─⟦31f2d420d⟧ 
            └─⟦this⟧ »mszrmx.a86« 

TextFile

        NAME    MSZRMX
true    equ     1
escbslh equ     5c1bh           ; ESC \
escbrac equ     5d1bh           ; ESC ]
$INCLUDE(mssdef.h86)

%*DEFINE(pushv(v))(%IF(%OS EQ 286)THEN(push     %v)ELSE(mov     ax,%v
        push    ax)FI)

datas   segment

        public  citok, cotok, mbox, tmbox, sigpair, sematok, bufill, ciptr
        public  cifill, cibuf1, cibuf2, combx, cimbx, termatt, oneport
        public  subpksz, trok, source, trmstr, temp, machnam

        extrn   sintok:word, srcptr:word, takadr:word, taklev:byte, comand:byte
        extrn   portval:word, savsi:word, xofsnt:byte, portatt:word
        extrn   costrt:word, coptr:word, flags:byte, pack:byte, dtrtime:word
        extrn   bdtab:byte, bddat:word

env     db      0,0             ; "environment" must be on PARA boundary
machnam db      21 dup(' ')
trmstr  db      6,':TERM:'
lp      db      4,':LP:'
bb      db      4,':BB:'
work    db      6,':WORK:'
dolsgn  db      1,'$'
rqglob  db      8,'RQGLOBAL'
dotini  db      'MSKERMIT.INI',0
kermtmp db      '$kermit$.tmp ',0       ; Kermit's DOS name for scratch file

sigpair dw      0
        db      3                       ; control C

kilpair dw      0
        db      0

setosc  db      ESCAPE,']C:T=1,E=1,R=1,O=1,C=2;T:R=1',ESCAPE,'\'
flush   db      ESCAPE,']C:T=3',ESCAPE,'\'
escapec db      ESCAPE,'c'
printer db      'PRN',0
typecmd db      'type '
delcmd  db      'del '
chkdsk  db      'chkdsk.com'
dirfree db      'dir $ free',cr

delrmx  db      'delete '               ; keep these 2 lines together
deltail db      73 dup(?)

wccmd   db      0,'WC '                 ; keep these 2 lines together
wcpath  db      80 dup(?)

pushmsg db      cr,lf,'PUSH not implemented, use RUN whatever$'
syserr  db      cr,lf,'Your version of MSKERMIT used an unsupported DOS '
        db      'function call'
crlf    db      cr,lf,'$'
cfgerr  db      cr,lf,'Configuration error',cr,lf,'$'
killmsg db      cr,lf,'Only 1st KILL accepted',cr,lf,'$'
mbmsg   db      cr,lf,'MAX-BAUD error',cr,lf,'$'
oscmsg  db      cr,lf,'OSC error',cr,lf,'$'
prmsg   db      cr,lf,'Priority error',cr,lf,'$'
nmsg    db      cr,lf,'Number > 0ffh',cr,lf,'$'
dnmsg   db      cr,lf,'Must be decimal number',cr,lf,'$'
nxtflg  db      1
oneport db      0
codone  db      ?
esc_c   db      0
trok    db      0

$SAVE NOGEN
comtab  db      13
        %mkeyw  (%('bufill'),fillbuf)
        %mkeyw  (%('cifill'),fillci)
        %mkeyw  (%('co-delay'),codel)
        %mkeyw  (%('dtr-time'),dtr)
        %mkeyw  (%('echo'),takset)
        %mkeyw  (%('escc'),esccset)
        %mkeyw  (%('kill'),kill)
        %mkeyw  (%('max-baud'),maxbd)
        %mkeyw  (%('no-modem'),nomdm)
        %mkeyw  (%('osc'),osc)
        %mkeyw  (%('priority'),prior)
        %mkeyw  (%('sub-pack'),subpack)
        %mkeyw  (%('translate'),trnslt)
$RESTORE

        even
citok   dw      ?               ; DON'T reorder citok, cotok, lptok lines
cotok   dw      3 dup (?)
lptok   dw      ?


sematok dw      ?
initok  dw      0
globtok dw      ?
doltok  dw      ?
scfitok dw      ?
rcmdtok dw      ?
mbox    dw      ?
tmbox   dw      ?
cimbx   dw      ?
combx   dw      ?
kbuf    dw      ?
cmdtok  dw      ?
xitcode dw      40ffh
savebx  dw      ?
status  dw      ?
ccstat  dw      ?
siostat dw      ?
priorty dw      254
bufill  dw      0ffffh
cifill  dw      8080h
subpksz dw      60
codelay dw      6
ciptr   dw      offset cibuf1
cistrt  dw      ?
inisize dw      ?
savspec dw      12,12,12 dup (0)
termatt dw      2,2,2 dup (?)   ; terminal port attributes for special
ignore  dw      ?
xcepinf dw      3 dup (0)

temp    dw      110 dup(?)
        org     offset temp
        db      'Copyright 1988, John Bryans.'
        db      'Permission is granted to copy and give away,'
        db      'but not to sell for profit any form of this program.'
        db      'No Warranties Whatsoever'
        org     offset temp+size temp

cibuf1  db      cibufl dup (?)
cibuf2  db      cibufl dup (?)
cobuf1  db      cobufl dup (?)
cobuf2  db      cobufl dup (?)

source  db      bufsiz dup(0)                   ; serial input buffer

PURGE   conin,conout,lstout,dconio,coninq,prstr,seldsk,gcurdsk,setdma,gettim
PURGE   dosver,gswitch,chdir,creat2,open2,close2,readf2,write2,del2,lseek,gcd
PURGE   alloc,setblk,exec,first2,next2

dosf    dw      notimp          ; DOS function call jump table
        dw      conin
        dw      conout
        dw      2 dup(notimp)
        dw      lstout
        dw      dconio
        dw      coninq
        dw      rkbd
        dw      prstr
        dw      4 dup(notimp)
        dw      seldsk
        dw      10 dup(notimp)
        dw      gcurdsk
        dw      setdma
        dw      10 dup(notimp)
        dw      setintv
        dw      6 dup(notimp)
        dw      gettim
        dw      3 dup(notimp)
        dw      dosver
        dw      4 dup(notimp)
        dw      getintv
        dw      notimp
        dw      gswitch
        dw      3 dup(notimp)
        dw      chdir
        dw      creat2
        dw      open2
        dw      close2
        dw      readf2
        dw      write2
        dw      del2
        dw      lseek
        dw      4 dup(notimp)
        dw      gcd
        dw      alloc
        dw      notimp
        dw      setblk
        dw      exec
        dw      exit
        dw      notimp
        dw      first2
        dw      next2
dosfl   equ     ($-dosf-2)/2

datas   ends
%IF (%OS EQ 86) THEN (
stack   segment stack 'stack'
        dw      750 dup(?)
stack   ends
) ELSE (
stack   stackseg 1500
)FI
code    segment
        public  dosint, crfile, opfile, special, writer, delcon, prstr, dconio
        public  aopen, aclose, awrite, aspcl, waitio, sendms, rcvmsg, delseg
        public  gfilsta, flushci

        extrn   start:near, outchr:near, takrd:near, prompt:near, comnd:near
        extrn   takset:near, atoi:near, katoi:near

        extrn   dqdecodetime:near, dqgetsystemid:near

        extrn   rqcgetchar:near, rqcgetcommandname:near
        extrn   rqccreatecommandconnection:near, rqcsendcommand:near

        extrn   rqsopen:near, rqsdeleteconnection:near, rqsattachfile:near
        extrn   rqsreadmove:near, rqsseek:near, rqsgetconnectionstatus:near
        extrn   rqscreatefile:near, rqswritemove:near, rqsspecial:near
        extrn   rqsgetfilestatus:near, rqsdeletefile:near, rqsclose:near
        extrn   rqstruncatefile:near, rqexitiojob:near

        extrn   rqaopen:near, rqaclose:near, rqaread:near, rqawrite:near
        extrn   rqwaitio:near, rqaspecial:near, rqsetdefaultprefix:near

        extrn   rqsetexceptionhandler:near, rqsetpriority:near
        extrn   rqcreatesemaphore:near, rqreceiveunits:near, rqcreatetask:near
        extrn   rqcreatemailbox:near, rqreceivemessage:near, rqsendmessage:near
        extrn   rqcreatesegment:near, rqdeletesegment:near, rqlookupobject:near
%IF (%OS EQ 286) THEN (
        extrn   rqegetaddress:near, rqecreatedescriptor:near
        extrn   rqedeletedescriptor:near
)FI
psp:    jmp     stop            ; "program segment prefix"
        db      10h             ; combined w/previous byte makes size>65K
        db      0
        db      9ah,0f0h,0ffh,0dh,0f0h  ; beats the hell out of me
        dd      quitint         ; termination address
        dd      cctask          ; control-break address
        dd      quitint         ; critical error address
        db      (psp+2ch)-$ dup(?)
        dw      seg env         ; segment address of environment
        db      (psp+50h)-$ dup(?)
fake    proc    far
        jmp     dosint          ; DOS function dispatcher entry
fake    endp
        db      (psp+80h)-$ dup(?)
cline   db      82 dup(0)

begin   proc    far
        call    setexcp
%IF (%OS EQ 286) THEN (
        push    cs
        push    offset psp
        push    ds
        push    offset status
        call    rqegetaddress
        push    dx
        push    ax
        push    offset begin
        push    ds
        push    offset status
        call    rqecreatedescriptor
)ELSE(
        mov     ax,cs
)FI
        mov     es,ax
        mov     di,offset cline ; move command line to cline
        sub     al,al
L1:     inc     byte ptr es:cline
        stosb                   ; clears count 1st time thru
        push    es              ; save es & di
        push    di
        push    ds              ; al=call rqcgetchar(@status)
        %pushv(offset status)
        call    rqcgetchar
        pop     di              ; restore es & di
        pop     es
        test    al,al           ; end of string?
        jnz     L1              ; no
        mov     byte ptr es:[di],cr     ; stuff cr
%IF (%OS EQ 286) THEN (
        push    es              ; let's not leave this descriptor laying around
        push    ds
        push    offset status
        call    rqedeletedescriptor)FI

        call    crmbx           ; mbox=rqcreatemailbox(0,@status)
        mov     mbox,ax
        call    crmbx           ; tmbox=rqcreatemailbox(0,@status)
        mov     tmbox,ax
        call    crmbx           ; combx=rqcreatemailbox(0,@status)
        mov     combx,ax
        call    crmbx           ; cimbx=rqcreatemailbox(0,@status)
        mov     cimbx,ax

        mov     di,offset work  ; scfitok=rqscreatefile(@(6,':WORK:'),@status)
        call    crfile          ; scratch file is for wild card implementation
        mov     scfitok,ax      ; (FIRST2 & NEXT2), and :CO: redirection (EXEC)

        mov     bx,3            ; call rqsopen(scfitok,3,2,@status)
        mov     cx,2
        call    opfile

        mov     di,offset trmstr
        call    crfile
        mov     citok,ax        ; citok=rqscreatefile(@(4,':TERM:'),@status)

        mov     bx,3            ; call rqaopen(citok,3,3,0,@status)
        call    aopen

        mov     di,offset trmstr
        call    crfile
        mov     cotok,ax        ; cotok=rqscreatefile(@(4,':TERM:'),@status)
        mov     cotok+2,ax
        mov     cotok+4,ax

        mov     bx,3            ; call rqsopen(cotok,3,3,@status)
        mov     cx,bx
        call    opfile

        mov     ax,cotok        ; call rqsspecial(cotok,4,@savspec,0,@status)
        mov     bx,offset savspec
        mov     cx,4
        call    special
        test    savspec+18,8000h
        js      L2
        mov     word ptr savspec+2,7

L2:     mov     ax,citok        ; set OSCs for :CI:
        mov     bx,offset setosc
        mov     cx,size setosc
        sub     dx,dx
        call    awrite

        mov     ax,cotok        ; set OSCs for :CO:
        mov     bx,offset setosc
        mov     cx,size setosc
        call    writer

        mov     ax,citok        ; rumor has it write before read
        mov     bx,offset crlf  ; is s'posed to convince Terminal Support Code
        mov     cx,2            ; we're serious about wanting transparent input
        mov     dx,tmbox
        call    awrite

        push    ds              ; get pathname that called us
        %pushv(offset cobuf1)   ; stash @cobuf1
        %pushv(size cobuf1)     ; call rqgetcommandname
        push    ds              ;       (@cobuf1,size cobuf1,@status)
        %pushv(offset status)
        call    rqcgetcommandname

        mov     ax,citok        ; wait for TSC to settle down
        mov     bx,tmbox        ; necessary for 386's & lickety-split 286's
        call    waitio

        mov     ax,ds           ; back scan to last path separator
        mov     es,ax
        mov     bl,cobuf1
        sub     bh,bh
        lea     si,cobuf1[bx]
        call    bakscan         ; si=file name ptr, bx=its length, al=separator

; The full string @cobuf1 is used to look for .cfg & .ini in the dir from which
; Kermit was loaded.  The mid-string, @si-1, is used to look in :$:.

        mov     [bx+si],'c.'            ; catenate '.cfg'
        mov     [bx+si+2],'gf'
        dec     si                      ; byte before file name for string count
        mov     word ptr cobuf2,si      ; save ptr
        add     cobuf1,4                ; bump length of full string for .cfg
        add     bl,4                    ; bump length of mid-string
        mov     [si],bl                 ; RMX string for lookup in :$:
        mov     ah,bl                   ; ah=current byte @si, al=old char @si
        cmp     si,offset cobuf1        ; if no path, use bl for old char
        jne     L3
        mov     al,bl                   ; instead of the one from bakscan
L3:     mov     word ptr cobuf2+2,ax    ; save them

        call    cfgini                  ; look for .cfg, open, size to dx:si
        jcxz    L4                      ; OK?
        jmp     short L7                ; no, do .ini
L4:     inc     taklev
        add     takadr,size takinfo
        mov     di,takadr
        mov     [di].takhnd,ax          ; token
        mov     [di].taktyp,0feh        ; mark as take
        mov     [di].takcnt,si          ; low size
        mov     [di].takcnt+2,dx        ; high size
        call    takrd

L5:     mov     ax,ds
        mov     es,ax
        mov     dx,offset dolsgn        ; ptr for prompt
        call    prompt
        cmp     taklev,0                ; done?
        je      L7                      ; eq = yes
        mov     dx,offset comtab        ; command table ptr
        mov     bx,offset dolsgn        ; help ptr
        mov     comand.cmcr,1
        mov     ah,cmkey
        call    comnd
         jmp    short L6                ; error exit
         nop
        call    bx                      ; call cfg s/r
        jmp     L5                      ; loop

L6:     mov     dx,offset cfgerr        ; output error msg & loop
        call    prstr
        jmp     L5

L7:     mov     si,word ptr cobuf2      ; point to mid-string
        mov     ax,word ptr cobuf2+2    ; ah=mid-string count, al=path separator
        mov     [si],ah
        mov     bl,ah
        sub     bh,bh
        mov     byte ptr[bx+si],'i'     ; replace 'cfg' w/'ini'
        dec     bx
        dec     bx
        mov     [bx+si],'ni'
        call    cfgini                  ; look for .ini, open, size to dx:si
        jcxz    L8                      ; found
        jmp     short L9                ; not found

CFGINI  proc
        mov     di,si
        mov     temp,si                 ; save string pointer
        call    atfile                  ; attach from :$:
        jcxz    CGIN1                   ; z=found
        mov     si,word ptr cobuf2      ; point to mid-string
        mov     ax,word ptr cobuf2+2    ; al=path separator
        mov     [si],al                 ; put it back
        mov     di,offset cobuf1        ; point to full path
        mov     temp,di                 ; save string pointer
        call    atfile                  ; attach from full path
        jcxz    CGIN1
        ret
CGIN1:  mov     temp+100,ax             ; save token
        mov     bx,1
        mov     cx,bx
        call    opfile                  ; open for reading
        jcxz    CGIN2
        ret
CGIN2:  mov     di,temp                 ; string pointer
        call    gfilsta                 ; get file status to find size
        mov     si,ax                   ; low order file size
        mov     ax,temp+100             ; token
        ret
CFGINI  endp

L8:     mov     inisize,si              ; size of .ini
        mov     initok,ax               ; close KERMIT.INI,
        call    clfile                  ; but leave attached for open2

L9:     mov     ax,cotok                ; save configured attributes
        mov     bx,offset termatt       ; for ping-ponging
        mov     cx,4
        call    special

        call    crsema                  ; sematok=rqcreatesemaphore(0,1,0,@statu
        mov     sematok,ax
        mov     sigpair,ax              ; for ^C trapping

        mov     ax,citok                ; establish ^C & sematok as signal pair
        mov     cx,6
        mov     bx,offset sigpair
        call    aspcl

        mov     bx,offset cctask        ; call rqcreatetask
        call    crtsk                   ;    (0,@cctask,datas,0,300,0,@status)

        mov     bx,offset siotsk        ; call rqcreatetask
        call    crtsk                   ;    (0,@siotsk,datas,0,300,0,@status)

        mov     bx,offset citsk         ; call rqcreatetask
        call    crtsk                   ;    (0,@citsk,datas,0,300,0,@status)

        mov     bx,offset cotsk         ; call rqcreatetask
        call    crtsk                   ;    (0,@cotsk,datas,0,300,0,@status)

        mov     di,offset lp    ; lptok=rqscreatefile(@(4,':LP:'),@status)
        call    crfile
        jcxz    L10             ; jump if OK
        mov     di,offset bb    ; otherwise use :BB:
        call    crfile
L10:    mov     lptok,ax

        mov     bx,2            ; call rqsopen(lptok,2,2,@status)
        mov     cx,bx
        call    opfile

        mov     ax,citok        ; cmdtok = rqccreatecommandconnection(citok,
        mov     bx,cotok        ;                       cotok,0,@status)
        sub     cx,cx
        call    crcmdco
        mov     cmdtok,ax

        mov     ax,lptok        ; rcmdtok = rqccreatecommandconnection(lptok,
        mov     bx,scfitok      ;                       scfitok,1,@status)
        mov     cx,1            ; lptok forces error if ":CI:" gets read,
        call    crcmdco         ; scfitok is ":CO:" redirected to scratch file
        mov     rcmdtok,ax

        push    ds              ; call dqgetsystemid(@temp,@status)
        %pushv(offset temp)
        push    ds
        %pushv(offset status)
        call    dqgetsystemid
        mov     ax,ds           ; use system id for machine name
        mov     es,ax
        mov     si,offset temp+1
        mov     di,offset machnam
        mov     cl,byte ptr temp
        sub     ch,ch
        rep movsb
        mov     al,'$'          ; it's a $ terminated string
        stosb

        mov     ax,cx
        mov     bx,offset rqglob
        call    lookup          ; globtok=rqlookupobject(0,@rqglob,0,@status)
        mov     globtok,ax

        mov     bx,offset dolsgn
        call    lookup          ; doltok=rqlookupobject(globtok,@dolsgn,0,@statu
        mov     doltok,ax

        push    cx              ; call rqsetpriority(0,priorty,@status)
        push    priorty
        push    ds
        %pushv(offset status)
        call    rqsetpriority

        mov     ax,cs
        mov     ds,ax           ; point ds & es to psp
        mov     es,ax

        jmp     start           ; go to Kermit

begin   endp

; cfg subroutines.
; Number conversion routines getn & getdn return to caller's caller on error

fillbuf proc
        call    getn            ; convert backslash number
        mov     bufill,ax       ; set serial input background fill
        ret
fillbuf endp

fillci  proc
        call    getn            ; convert backslash number
        mov     cifill,ax       ; set terminal input background fill
        ret
fillci  endp

codel   proc
        call    getdn           ; convert decimal number
        mov     codelay,ax      ; set connect mode terminal output buffer time
        ret
codel   endp

dtr     proc
        call    getdn           ; convert decimal number
        mov     dtrtime,ax      ; set time to hold DTR down
        ret
dtr     endp

esccset proc
        mov     esc_c,true      ; enable sending ESC c (VT100 reset) on exit
        ret
esccset endp

kill    proc
        call    getn            ; convert backslash number
        cmp     kilpair,0       ; has task already been created?
        jne     K1              ; ne = yes
        mov     byte ptr kilpair+2,al   ; set control char to trap
        call    crsema          ; kilpair=rqcreatesemaphore(0,1,0,@status)
        mov     kilpair,ax
        mov     bx,offset kiltsk
        call    crtsk           ; create kill task
        mov     ax,citok
        mov     cx,6
        mov     bx,offset kilpair
        call    aspcl           ; establish trap char & kiltsk as signal pair
        ret
K1:     mov     dx,offset killmsg       ; don't let 'em do it twice
        call    prstr
        ret
kill    endp

maxbd   proc
        mov     dx,offset bdtab ; parse for baud rate
        sub     bx,bx
        mov     ah,cmkey
        call    comnd
         jmp    short MB1       ; NG, bitch
         nop
        mov     temp,bx         ; save baud ix
        mov     ah,cmcfm        ; proper parsing ettiqutte
        call    comnd
         jmp    short MB1       ; NG, bitch
         nop
        mov     bx,temp         ; baud ix
        inc     bx              ; next higher
        mov     cx,baudsiz      ; baudsiz - (1+baud ix) is # wds to clear
        sub     cx,bx           ; x2 is word ix
        shl     bx,1
        mov     ax,ds
        mov     es,ax
        sub     ax,ax
        mov     di,offset bddat ; point to 1st word to clear
        add     di,bx
        cld
        rep stosw               ; wipe 'em out
        ret
MB1:    mov     dx,offset mbmsg
        call    prstr
        ret
maxbd   endp

nomdm   proc
        and     portatt+6,0fff7h        ; turn off modem control bit
        ret
nomdm   endp

osc     proc
        mov     ah,cmtxt        ; parse text upto cr to temp+2
        mov     bx,offset temp+2
        mov     dx,offset dolsgn
        call    comnd
         jmp    short OSCERR    ; NG
         nop
        mov     cl,ah
        sub     ch,ch           ; cx = # bytes
        mov     di,offset temp+2        ; point to start
        mov     ax,ds
        mov     es,ax
        mov     al,' '
        cld
        repe scasb              ; discard leading blanks
        je      OSCERR          ; empty, show indignation
        xchg    bx,di           ; bx = 1st non-blank char ptr
        dec     di              ; di = last char ptr
        std
        repe scasb              ; discard trailing blanks
        cld
        add     cl,6            ; cx = total length of OSC
        inc     di
        inc     di              ; point to plant trailer
        sub     bx,3            ; point to plant lead-in
        mov     [bx],escbrac    ; insert lead-in
        mov     [di],escbslh    ; insert trailer
        mov     ax,cotok
        push    bx              ; save ptr for ci
        push    cx              ; save count for ci
        call    writer          ; write OSC to cotok
        pop     cx
        pop     bx
        mov     ax,citok        ; write OSC to citok
        sub     dx,dx
        call    awrite
        ret
OSCERR: mov     dx,offset oscmsg
        call    prstr
        ret
osc     endp

prior   proc
        call    getn            ; convert backslash number
        je      PRERR           ; getn compared to 255, reject if =
        mov     byte ptr priorty,al     ; set priority
        ret
PRERR:  mov     dx,offset prmsg
        call    prstr
        ret
prior   endp

subpack proc
        call    getdn           ; convert decimal number
        mov     subpksz,ax      ; set sub-packet size (tuning param for sending)
        ret
subpack endp

trnslt  proc
        mov     trok,true       ; enable translation during connect
        ret
trnslt  endp

getn    proc    ; bags backslash #, converts it, ensures<256, returns in ah & al
        mov     ah,cmfile       ; parse upto whitespace into temp
        mov     bx,offset dolsgn
        mov     dx,offset temp
        mov     byte ptr temp,0
        call    comnd
         jmp    short NERR      ; NG return
         nop
        mov     si,offset temp  ; point to it
        call    katoi           ; convert it
        jc      NERR            ; carry set = NG
        cmp     ax,0ffh         ; we want 255 max
        ja      NERR
        mov     ah,al           ; both bytes the same for word filling
        ret
NERR:   mov     dx,offset nmsg
        call    prstr
        pop     ax
        ret
getn    endp

getdn   proc    ; bags decimal number, converts it, returns it in ax
        mov     ah,cmtxt        ; parse upto cr into temp
        mov     bx,offset temp
        mov     dx,offset dolsgn
        mov     byte ptr[bx],0
        call    comnd
         jmp    short DNERR     ; NG return
         nop
        mov     si,offset temp  ; point to it
        call    atoi            ; convert it
         jmp    short DNERR     ; NG return
         nop
        ret                     ; got it, it's in ax
DNERR:  mov     dx,offset dnmsg
        call    prstr
        pop     ax
        ret
getdn   endp

dosint  proc                    ; DOS function call table look up
        push    ds
        push    bx
        mov     bx,datas
        mov     ds,bx
        pop     savebx
        cmp     ah,dosfl
        ja      notimp
        sub     bh,bh
        mov     bl,ah
        rol     bx,1
        call    dosf[bx]
        mov     bx,savebx
        pop     ds
        ret
dosint  endp

notimp:                         ; not implemented DOS function error routine
        mov     dx,offset syserr
        call    prstr

quitint proc    far
stop:   mov     ax,datas
        mov     ds,ax
        mov     dx,offset crlf
        call    prstr

        cmp     esc_c,true      ; is ESC c cfg'd?
        jne     ST1             ; ne = no
        mov     ax,cotok        ; give Terminal Support Code an ESC c
        mov     bx,offset escapec       ; to restore terminal to initial state
        mov     cx,size escapec
        call    writer

ST1:    mov     ax,cotok        ; close to wait for output completion
        call    clfile
        mov     ax,citok        ; restore terminal attributes
        mov     bx,offset savspec
        mov     cx,5
        call    aspcl

        mov     cx,globtok      ; restore $ directory
        mov     ax,doltok       ; call rqsetdefaultprefix(globtok,doltok,@status
        call    sdefpfx

        mov     cx,kilpair      ; was a kill kermit ctrl char established
        jcxz    ST2             ; z = no
        mov     ax,citok        ; yes, disestablish
        mov     bx,offset kilpair
        mov     word ptr[bx],0
        mov     cx,6
        call    aspcl

ST2:    mov     ax,citok        ; wait for completion before exit
        mov     cx,tmbox
        call    aclose
        mov     ax,tmbox
        mov     bx,0ffffh
        call    rcvmsg

        push    xitcode         ; call rqexitiojob(xitcode,@0,@status)
        sub     ax,ax
        push    ax
        push    ax
        push    ds
        %pushv(offset status)
        call    rqexitiojob
quitint endp

kiltsk  proc                    ; kill task
        mov     ax,kilpair      ; wait for kill char to be typed
        call    rcvun
        jmp     STOP            ; then quit
kiltsk  endp

cctask  proc    far             ; ^C task
CCT:    mov     ax,sematok      ; wait for ^C to be typed
        call    rcvun
        mov     flags.cxzflg,'C'        ; slightly adapted (mostly stolen) from
        mov     pack.state,'A'  ; MSSKER's intbrk
        jmp     CCT
cctask  endp

siotsk  proc    far             ; serial input task
        call    setexcp         ; never call exception handler
SIO1:   mov     bx,0ffffh       ; wait forever @ mbox for something to do
SIO2:   mov     ax,mbox
        call    rcvmsg
        cmp     ax,mbox         ; if it's the token for mbox,
        je      SIO6            ; it's SERINI asking us to crank up input
        dec     cx              ; otherwise it's E$TIME or an IORS
        jz      SIO3            ; it's E$TIME
        call    delseg          ; it's an IORS, so delete it
SIO3:   cmp     sintok,0        ; if the port has been reset,
        je      SIO1            ; let the interrupts expire unanswered
        cmp     xofsnt,true
        jne     SIO4
        mov     bx,50
        jmp     SIO2
SIO4:   call    sread           ; start aread & fill following buffer quadrant
        mov     ax,srcptr
        sub     ax,savsi        ; if there's at least 2 quadrants between next
        jns     SIO5            ; quadrant & current pointer,
        add     ax,bufsiz
SIO5:   cmp     ax,bufsiz/2
        jle     SIO1            ; we don't need to XOF, so wait for interrupt
        mov     bx,portval
        cmp     [bx].floflg,0   ; is flow control enabled?
        je      SIO1            ; no
        mov     ax,[bx].flowc   ; ouput whatever we're using for XOF
        mov     ah,al
        call    outchr
         nop
         nop
         nop
        mov     xofsnt,true
        jmp     SIO1
SIO6:   mov     ax,sintok               ; for aspecial to set it
        mov     bx,offset portatt
        or      word ptr[bx+4],3        ; change to flushing mode
        mov     cx,5                    ; while we're at it
        call    aspcl
SIO7:   mov     ax,sintok
        mov     bx,offset source        ; initialize
        mov     savsi,bx                ; current byte ptr
        mov     srcptr,bx               ; & next quadrant ptr
        mov     cx,bufsiz               ; in case the ports on a buffered board
        mov     dx,mbox                 ; flush it's buffer
        call    aread
        mov     ax,sintok
        mov     bx,mbox
        call    waitio
        cmp     ax,bufsiz
        je      SIO7                    ; no matter how big the damn thing is
        mov     ax,sintok
        mov     bx,offset portatt
        and     word ptr[bx+4],0fffdh   ; change back to transparent mode
        mov     cx,5
        call    aspcl
        mov     ax,ds                   ; fill 1st quadrant
        mov     es,ax
        mov     ax,bufill
        mov     cx,bufsiz/8
        mov     di,offset source
        cld
        rep stosw
        call    sread                   ; start 1st read & fill 2nd quadrant
        jmp     SIO4                    ; go do 2nd read

sread   proc
        mov     ax,sintok
        mov     bx,srcptr               ; next quadrant ptr
        mov     cx,bufsiz/4
        mov     dx,mbox
        call    aread                   ; read current quadrant
        mov     ax,ds
        mov     es,ax
        mov     ax,bufill
        mov     cx,bufsiz/4
        mov     di,srcptr
        add     di,cx
        cmp     di,bufsiz+offset source ; was it last quadrant
        jl      SRD1                    ; no
        mov     di,offset source        ; yes, point to 1st
SRD1:   mov     srcptr,di               ; set next quadrant ptr
        shr     cx,1
        cld
        rep stosw                       ; fill quadrant
        ret
sread   endp
siotsk  endp

citsk   proc    far             ; read terminal task
        call    setexcp
CIT1:   mov     bx,offset cibuf1
CIT2:   mov     cistrt,bx       ; set buffer ptr

        mov     ax,ds           ; fill it w/cifill
        mov     es,ax
        mov     di,bx
        mov     cx,(size cibuf1)/2
        mov     ax,cifill
        cld
        rep stosw

        mov     ax,citok        ; call rqaread
        mov     cx,size cibuf1  ;       (citok,@buffer,size(buffer),cimbx,@statu
        mov     dx,cimbx
        call    aread

CIT3:   mov     ax,cimbx        ; wait for completion or task restart
        mov     bx,0ffffh
        call    rcvmsg

        cmp     ax,cimbx        ; if it's the mail box token, it's task restart
        jne     CIT4            ; if, not it's an IORS
        mov     bx,offset cibuf1
        mov     ciptr,bx        ; initialize buffer & char pointers
        jmp     CIT2            ; & start over

CIT4:   mov     es,ax           ; check IORS for "flushing" status
        cmp     es:word ptr 0,2ch
        pushf
        call    delseg          ; delete IORS
        popf                    ; "flushing" means suspend task,
        je      CIT3            ; go wait for restart

        mov     bx,offset cibuf2
        cmp     bx,cistrt       ; exchange buffers
        je      CIT1
        jmp     CIT2
citsk   endp

cotsk   proc    far             ; write terminal task -- active in connect mode
        call    setexcp
COT1:   mov     ax,combx        ; wait for task start or IORS
        mov     bx,0ffffh
        call    rcvmsg

        cmp     ax,combx        ; if it's the mail box token, it's task start
        je      COT2
        call    delseg          ; otherwise it's an expiring IORS, delete it
        jmp     COT1            ; & wait for task start

COT2:   mov     ax,cotok        ; task start.  close EIOS & re-open BIOS
        call    clfile
        mov     ax,cotok
        mov     bx,2
        mov     codone,bl       ; mark write complete
        call    aopen

COT3:   mov     ax,offset cobuf1
COT4:   mov     coptr,ax        ; byte ptr
        mov     costrt,ax       ; buffer ptr

COT5:   mov     ax,combx        ; wait for timer, IORS, or suspend task request
        mov     bx,codelay      ; default = 60 milliseconds
        call    rcvmsg
        jcxz    COT6            ; 0 = IORS or suspend task
        cmp     codone,0        ; timeout.  Is write complete?
        jne     COT7            ; ne = yes
        jmp     COT5            ; no, wait for it

COT6:   cmp     ax,combx        ; if mail box token
        je      COT9            ; it's suspend task request
        mov     codone,true     ; it's IORS, mark write complete
        call    delseg          ; delete IORS

COT7:   mov     bx,costrt       ; buffer ptr
        mov     cx,coptr        ; byte prt
        sub     cx,bx           ; # bytes to write
        jcxz    COT8            ; don't write 0
        mov     ax,cotok        ; call rqawrite
        mov     dx,combx        ;       (cotok,@buffer,nbytes,combx,@status)
        call    awrite
        mov     codone,0        ; mark write not finished

COT8:   mov     ax,offset cobuf2
        cmp     ax,costrt       ; exchange buffers
        je      COT3
        jmp     COT4

COT9:   mov     ax,cotok        ; suspend task.  Close BIOS, wait for task start
        call    aclose
        jmp     COT1
cotsk   endp

conin   proc
        call    rkbd            ; read 1 from :CI: to al
        push    dx
        mov     dl,al           ; conout writes out dl
        call    conout          ; echo it to :CO:
        pop     dx
        ret
conin   endp

conout  proc
        call    save
        mov     ax,cotok        ; write dl to :CO:
CO1:    mov     cx,1
        mov     temp,dx
        mov     bx,offset temp
        call    writer
        call    rstr
        ret
conout  endp

lstout  proc
        call    save
        mov     ax,lptok        ; write dl to :LP:
        jmp     CO1
lstout  endp

dconio  proc
        cmp     dl,0ffh         ; if dl ain't ff,
        jne     conout          ; it's same as conout
        push    si
        push    cx
        call    rdci            ; read 1 from :CI: to temp, on return
        test    cx,cx           ; cx=1 if read, 0 if not, set zero flag if not
        pop     cx
        pop     si
        ret
dconio  endp

coninq  proc
        push    cx
DC1:    call    rdci            ; read 1 from :CI: to temp
        jcxz    DC1             ; 'til we get 1
        pop     cx
        ret
coninq  endp

rkbd    proc
RKBD1:  call    pollci          ; read 1 from :CI: to al
        je      RKBD1           ; 'til we get 1
        ret
rkbd    endp

rdci    proc
        sub     cx,cx
        cmp     flags.cxzflg,'C'        ; reads 1 from :CI: to temp, doesn't
        jne     RDC1                    ; wait, doesn't check ^C
        mov     flags.cxzflg,ch         ; returns cx=1 if read, 0 if not
        mov     al,3
        jmp     short RDC2
RDC1:   call    pollci
        je      RDC3
RDC2:   inc     cx
RDC3:   ret
rdci    endp

pollci  proc
        push    si
        cmp     sintok,0        ; if serial port's active
        je      PCI1
        cmp     oneport,true    ; & oneport
        je      PCI3            ; return no character

PCI1:   mov     si,ciptr        ; next byte ptr
        lodsb
        cmp     al,byte ptr cifill
        je      PCI3            ; eq = no byte
        cmp     si,offset cibuf2 + size cibuf2
        jne     PCI2
        mov     si,offset cibuf1
        test    si,si           ; clear equal
PCI2:   mov     ciptr,si        ; set ptr for next byte
PCI3:   pop     si
        ret
pollci  endp

prstr   proc
        call    save    ; call rqswritemove(cotok,ds:dx,#char,@status)
        mov     ax,ds
        mov     es,ax
        mov     di,dx
        mov     cx,0ffffh
        mov     al,'$'
        repne scasb
        neg     cx
        add     cx,0fffeh       ; cx=#characters
        jcxz    PRSTR1          ; why bother
        mov     ax,cotok
        mov     bx,dx
        call    writer
PRSTR1: call    rstr
        ret
prstr   endp

seldsk  proc
        mov     al,1            ; what the hell, say there's 1
        ret
seldsk  endp

gcurdsk proc
        sub     al,al           ; always A: -- meaningless anyway
        ret
gcurdsk endp

setdma  proc
        mov     kbuf,dx         ; save disk transfer address, DTA
        ret
setdma  endp

setintv proc
        ret                     ; if KERMIT ever does more than
setintv endp                    ; setup int 23h, we're in trouble

gettim  proc
        call    save
        sub     ax,ax           ; let dword @temp be system time
        mov     temp,ax         ; set to 0, so decodetime returns current time
        mov     temp+2,ax
        push    ds              ; call dqdecodetime(@temp,@status)
        %pushv(offset temp)
        push    ds
        %pushv(offset status)
        call    dqdecodetime
        call    rstr
        push    ax
        mov     dx,temp+12
        call    asc2bin
        mov     ch,dl           ; ch=hours
        mov     dx,temp+15
        call    asc2bin
        mov     cl,dl           ; cl=minutes
        mov     dx,temp+18
        call    asc2bin
        mov     dh,dl           ; dh=seconds
        sub     dl,dl           ; dl=0 hundredths
        pop     ax
        ret
asc2bin proc
        sub     dx,'00'
        shl     dl,1
        mov     al,dl
        shl     dl,1
        shl     dl,1
        add     dl,al
        add     dl,dh
        ret
asc2bin endp
gettim  endp

dosver  proc
        mov     al,2            ; we're simulating DOS 2.x
        ret
dosver  endp

gswitch proc
        mov     dl,'/'          ; undocumented DOS get switch character
        ret
gswitch endp

getintv proc
        ret                     ; if KERMIT ever does more than
getintv endp                    ; setup int 23h, we're in trouble

chdir   proc
        call    save
        mov     ax,ds
        mov     es,ax
        mov     si,offset temp+1
        call    z2rmx           ; copy ASCIIZ string @ds:dx to temp+1
        mov     byte ptr temp,al
        mov     di,offset temp  ; length to temp makes it RMX string
        call    atfile          ; attach file
        jcxz    CHD2            ; jump if OK
CHD1:   call    rstr
        mov     ax,3            ; return error code w/carry set
        stc
        ret
CHD2:   mov     cx,globtok      ; call rqsetdefaultprefix(globtok,ax,@status)
        push    ax
        call    sdefpfx
        pop     ax
        jcxz    CHD3
        jmp     CHD1
CHD3:   call    sdefpfx         ; call rqsetdefaultprefix(0,ax,@status)
        call    rstr
        clc
        ret
chdir   endp

creat2  proc
        call    save
        mov     ax,ds
        mov     es,ax
        mov     si,offset printer       ; is it PRN ?
        mov     di,dx
        mov     cx,size printer
        repe cmpsb
        jne     CRF1                    ; ne=no
        call    rstr
        mov     ax,lptok                ; yes, use :LP:
        clc
        ret
CRF1:   call    cropsr
        jnc     CRF2
        call    exfisr
        jmp     short OP5
CRF2:   call    crfile                  ; create file
        mov     bx,3                    ; mode for OPEN & error return code
        mov     temp+2,bx               ; error return code
        jmp     short OP4

cropsr  proc
        mov     si,dx
        mov     di,offset kermtmp       ; is it "$kermit$.tmp"?
        mov     cx,size kermtmp
        repe cmpsb
        jne     CROP1
        mov     bx,scfitok              ; yes, use token for scratch file
        mov     temp,bx                 ; save it
        stc
        ret
CROP1:  mov     si,offset temp+3
        call    z2rmx                   ; ASCIIZ string to temp+3
        mov     di,offset temp+2        ; setup di
        mov     [di],al                 ; length makes it RMX string at temp+2
        clc
        ret
cropsr  endp

creat2  endp

open2   proc
        call    save
        sub     ah,ah                   ; convert DOS mode to RMX
        inc     ax
        mov     temp,ax                 ; save mode
        mov     ax,ds
        mov     es,ax
        mov     si,dx
        mov     di,offset dotini        ; is it MSKERMIT.INI?
        mov     cx,size dotini
        repe cmpsb
        jne     OP1                     ; no
        mov     ax,initok               ; yes, initok's already attached
        jmp     short OP3
OP1:    call    cropsr
        jnc     OP2
        call    rewind
        jmp     short OP5
OP2:    call    atfile
OP3:    mov     temp+2,2                ; error return code
        mov     bx,temp                 ; get mode
OP4:    mov     temp,ax                 ; save token
        mov     cx,2                    ; call rqsopen(token,mode,2,@status)
        call    opfile
OP5:    call    rstr
        mov     ax,temp                 ; return token to caller in ax
        mov     bx,temp+2               ; get error return code
        jmp     short CRYFLG
open2   endp

close2  proc
        mov     bx,savebx               ; savebx has file token
        cmp     bx,scfitok              ; if it's the scratch file,
        je      CL1                     ; don't you dare!
        cmp     bx,lptok                ; :LP:, neither
        je      CL1
        call    save
        mov     bx,savebx
        call    delcon                  ; delete connection
        call    rstr
        mov     bx,6                    ; error flag, if necessary
        jmp     short CRYFLG
CL1:    ret
close2  endp

readf2  proc
        call    save
        mov     ax,savebx               ; savebx has file token
        mov     bx,dx           ; nbyt=rqsreadmove(token,@buf,cnt,@status)
        call    reader
RF1:    mov     temp,ax                 ; save # bytes read
        call    rstr
        mov     ax,temp                 ; return to caller in ax
        mov     bx,6                    ; error flag, if necessary
        jmp     short CRYFLG
readf2  endp

write2  proc
        call    save
        mov     bx,savebx               ; savebx has file token
        test    bx,bx                   ; is it magic token 0 (CI)?
        jz      WRT1                    ; yes, let fail gracefully
        cmp     bx,4                    ; other magic tokens?
        ja      WRT1                    ; no
        shl     bx,1                    ; yes, lookup real token
        mov     bx,citok[bx]
WRT1:   mov     ax,bx
        mov     bx,dx           ; nbyt=rqswritemove(token,@buf,cnt,@status)
        call    writer
        jmp     RF1
write2  endp

del2    proc
        call    save
        mov     ax,ds
        mov     es,ax
        mov     si,offset temp+1        ; ASCIIZ string @ds:dx to temp+1
        call    z2rmx
        mov     bx,offset temp
        mov     byte ptr[bx],al         ; length makes it RMX string at temp
        push    ds                      ; call rqsdeletefile(@temp,@status)
        push    bx
        push    ds
        %pushv(offset status)
        call    rqsdeletefile
        call    rstr
        mov     bx,2                    ; error return code
CRYFLG: clc
        cmp     status,0                ; OK?
        je      CFLG1                   ; yes
        stc
        mov     ax,bx                   ; & return error code
CFLG1:  ret
del2    endp

lseek   proc
        call    save
        mov     bx,savebx       ; savebx has file token
        push    bx              ; save for get con. status
        add     al,2            ; convert DOS mode to RMX
        cbw
        call    seek
        pop     bx
        call    gconsta         ; getconnectionstatus puts file ptr
        call    rstr            ; in temp+4 & 6
        mov     ax,temp+4       ; dx:ax are file pointer
        mov     dx,temp+6
        mov     bx,6            ; error flag, if necessary
        jmp     CRYFLG
lseek   endp

alloc   proc
        call    save
        mov     ax,savebx       ; savebx has # paragraphs
        cmp     ax,1000h        ; is it 65K?
        jl      AL2             ; <65K, it's OK
        jne     AL1             ; >65K, too much
        sub     ax,ax           ; =65K, use 0 for full segment
        jmp     short AL2
AL1:    mov     status,ax       ; force error
        jmp     short AL3
AL2:    mov     cl,4            ; convert paragraphs to bytes
        shl     ax,cl
        push    ax              ; seg_base=rqcreatesegment(#bytes,@status)
        push    ds
        %pushv(offset status)
        call    rqcreatesegment
        mov     temp,ax         ; save
AL3:    call    rstr
        mov     ax,temp         ; restore seg_base return param
        mov     bx,8            ; error return code
        jmp     CRYFLG
alloc   endp

gcd     proc
        mov     byte ptr[si],0  ; return null string @ds:si
        clc
        ret
gcd     endp

setblk  proc
        ret
setblk  endp

PUSHCMD:                                ; actually, part of exec
        mov     dx,offset pushmsg       ; for now, say "no pushing"
        call    prstr                   ; but here's the spot to implement later
        call    rstr
        mov     ax,11
        stc
        ret

exec    proc
        call    save
        mov     bx,savebx               ; saved bx
        mov     di,es:[bx+2]            ; command tail pointer to es:di
        mov     es,es:[bx+4]
        sub     cx,cx
        mov     cl,es:[di]              ; if command tail length is 0, it's PUSH
        jcxz    PUSHCMD
        inc     di
        mov     al,' '
        repne scasb                     ; scan past DOSisms
        repe scasb
        dec     di                      ; 1st non-blank char of command
        mov     bx,di
        mov     dx,cx                   ; bx is ptr, dx is count
        mov     al,'>'                  ; if '>' appears, Kermit's asking for
        repne scasb                     ; redirected output
        mov     ax,cmdtok               ; if not, use ordinary cmd token
        jne     EX1                     ; ne = no redirection
        sub     dx,cx                   ; reduce count by chars from '>' to end
        dec     dx
        push    bx
        push    dx
        push    es
        call    exfisr                  ; rewind & truncate scratch file
        pop     es
        pop     dx
        pop     bx
        mov     ax,rcmdtok              ; use redirected cmd token

EX1:    mov     temp+100,ax             ; save cmd token
        mov     si,offset typecmd       ; is it 'TYPE'?
        mov     di,bx
        mov     cx,size typecmd
        repe cmpsb
        jne     EX2                     ; ne = no
        mov     [bx],'oc'               ; replace w/'COPY'
        mov     [bx+2],'yp'
        jmp     short EX4

EX2:    mov     si,offset delcmd        ; is it 'DEL'?
        mov     di,bx
        mov     cl,size delcmd
        repe cmpsb
        jne     EX3                     ; ne = no
        sub     dx,size delcmd          ; construct RMX DELETE command @delrmx
        mov     cx,dx
        mov     al,' '
        repe scasb
        dec     di
        inc     cx
        mov     dx,cx
        add     dx,size delrmx
        push    ds
        push    es
        pop     ds
        pop     es
        mov     si,di
        mov     di,offset deltail
        rep movsb
        mov     si,offset delrmx
        jmp     short EX5

EX3:    mov     si,offset chkdsk
        mov     di,bx
        mov     cl,size chkdsk
        repe cmpsb
        jne     EX4
        mov     bx,offset dirfree       ; yes, use 'dir $ free' as command
        mov     dx,size dirfree
        mov     cx,ds
        mov     es,cx

EX4:    push    ds                      ; swap ds & es
        push    es
        pop     ds
        pop     es
        mov     si,bx
EX5:    mov     di,offset temp          ; move command to temp
        mov     ax,dx
        stosb
        mov     cx,dx
        rep movsb
        push    es                      ; restore ds
        pop     ds
        mov     ax,temp+100             ; command token
        cmp     ax,rcmdtok              ; if output's going to scratch file
        je      EX6                     ; bypass fussing w/:TERM:

        mov     ax,citok                ; shut down citsk
        call    aclose
        mov     ax,citok                ; reopen
        mov     bx,3
        call    aopen

        call    flushci                 ; wait for output to :TERM: to finish
        mov     bx,offset savspec       ; ping back to user's connection &
        push    word ptr[bx+2]          ; terminal attributes
        mov     word ptr[bx+2],2
        mov     ax,cotok
        mov     cx,5
        call    special
        mov     ax,citok
        mov     bx,offset savspec
        mov     cx,5
        call    aspcl
        pop     savspec+2

EX6:    mov     ax,temp+100             ; command token
        push    ax                      ; save it
        mov     bx,offset temp          ; call rqcsendcommand
        mov     cx,offset temp+100      ;       (token,@temp,@temp+100,@status)
        call    sendcmd
        pop     ax                      ; command token
        cmp     ax,rcmdtok              ; if it went to scratch file,
        je      EX7                     ; don't mess w/:TERM:

        push    cx                      ; save status
        call    flushci                 ; wait for completion of cmd's output
        mov     ax,cotok                ; pong attr's back to Kermit's
        mov     bx,offset termatt
        mov     cx,5
        call    special
        mov     ax,citok
        mov     bx,offset termatt
        mov     cx,5
        call    aspcl

        mov     ax,cimbx                ; restart citsk
        mov     bx,ax
        call    sendms
        pop     cx                      ; restore status

EX7:    cmp     cx,83h                  ; is it E$CONTINUED
        je      EX8                     ; yes, return w/carry clear
        or      cx,temp+100             ; sendcmd status OR status from command
        jcxz    EX8                     ; jump if OK
        call    rstr
        mov     ax,2                    ; return error code w/carry set
        stc
        ret
EX8:    call    rstr
        clc
        ret

exfisr  proc                    ; rewind & truncate scratch file
        mov     bx,scfitok
        push    bx              ; save for truncate
        call    rewind          ; rewind scratch file
        push    ds              ; call rqstruncatefile(scfitok,@status)
        %pushv(offset status)
        call    rqstruncatefile
        ret
exfisr  endp

flushci proc
        mov     ax,citok        ; this is necessary to wait for completion
        mov     bx,offset flush ; of output to :TERM: for fast systems
        mov     cx,size flush
        sub     dx,dx
        call    awrite
        mov     ax,citok
        mov     bx,offset cobuf1
        mov     cx,cobufl
        mov     dx,tmbox
        call    aread
        mov     ax,citok
        mov     bx,tmbox
        call    waitio
        ret
flushci endp
exec    endp

exit    proc
        sub     ah,ah           ; convert DOS exit code to RMX
        test    ax,ax
        jz      X1
        mov     ah,40h          ; put in user range, if non-0
X1:     mov     xitcode,ax
        jmp     stop
exit    endp

first2  proc
        call    save
        mov     si,dx                   ; ds:dx points to ASCIIZ file name
        mov     ax,ds
        mov     es,ax
        mov     di,offset kermtmp       ; is it "$kermit$.tmp"?
        mov     temp+100,di
        mov     cx,size kermtmp
        mov     temp+102,cx
        repe cmpsb
        jne     FST2
        mov     bx,scfitok              ; yes, fill in DTA.  For scratch file,
        call    gconsta                 ; getconnectionstatus to temp
        mov     ax,temp+4               ; bx:ax are file pointer,
        mov     bx,temp+6               ; which is length of scratch file
FST1:   mov     di,kbuf
        mov     [di+1ah],ax             ; lo file size to DTA
        mov     [di+1ch],bx             ; hi file size to DTA
        mov     byte ptr [di+15h],0     ; clear DTA's attribute field
        add     di,1eh                  ; point to DTA's file name field
        mov     si,temp+100
        mov     cx,temp+102
        rep movsb
        call    rstr
        mov     bx,2
        jmp     CRYFLG

FST2:   mov     si,dx
        mov     di,offset dotini        ; is it MSKERMIT.INI?
        mov     temp+100,di
        mov     cx,size dotini
        mov     temp+102,cx
        sub     bx,bx
        repe cmpsb
        mov     ax,inisize
        je      FST1                    ; yes, initok's already attached

        mov     temp+100,2
        mov     si,dx
        cmp     word ptr[si],002ch      ; is it ',',0?
        je      NXT1                    ; eq = yes, treat as next

        push    es
        push    dx
        call    exfisr                  ; rewind & truncate scratch file
        pop     dx
        pop     es

        mov     si,offset wcpath        ; move file-spec to wcpath, length to ax
        call    z2rmx
        mov     bx,ax
        add     al,3
        mov     wccmd,al                ; + 3 for 'wc ' makes RMX string
        mov     si,dx                   ; point to file-spec
        mov     cx,bx                   ; length

FST3:   lodsb                           ; scan for wc chars, if any goto FST4
        cmp     al,'*'
        je      FST4
        cmp     al,'?'
        je      FST4
        cmp     al,','
        je      FST4
        loop    FST3

        mov     si,dx                   ; no need for wc, next can handle it
        mov     di,offset wcpath+1      ; if we move it over 1 byte
        mov     cx,bx
        rep movsb
        jmp     short NXT3

FST4:   mov     si,dx
        add     si,bx                   ; point to end
        dec     si                      ; backup over zero byte
        call    bakscan                 ; find rightmost path separater
        cmp     al,'\'                  ; is it \?
        jne     FST5
        call    rstr                    ; yes, force error
        mov     ax,2                    ; it's a DOSism we can do without
        stc
        ret

FST5:   mov     ax,rcmdtok              ; call rqcsendcommand
        mov     bx,offset wccmd         ;       (rcmdtok,@wccmd,@temp,@status)
        mov     cx,offset temp
        call    sendcmd

        mov     bx,scfitok              ; rewind scratch file
        call    rewind
        mov     nxtflg,0
        jmp     short NXT1              ; let next finish up
first2  endp

next2   proc
        call    save
        mov     temp+100,18             ; error return code
        cmp     nxtflg,0                ; was next called before 1st,
        jne     NXT4                    ; or after no more?  ne = yes

NXT1:   mov     bx,offset wcpath        ; place to stash file name string
        mov     byte ptr[bx],0          ; empty
NXT2:   inc     bx                      ; bump count
        push    bx
        mov     ax,scfitok              ; read 1 from scratch
        mov     cx,1
        call    reader
        test    ax,ax
        pop     bx
        jz      NXT4                    ; 0 = EOF
        cmp     byte ptr[bx],lf
        jne     NXT2                    ; loop 'til EOL

        sub     bx,offset wcpath+2      ; bx = length file name
NXT3:   mov     di,offset wcpath
        mov     [di],bl                 ; RMX string @di
        call    gfilsta                 ; does it exist?
        jcxz    NXT5                    ; 0 = yes
NXT4:   mov     nxtflg,1                ; mark no more next w/o 1st 1st
        call    rstr
        mov     ax,temp+100             ; return error code
        stc
        ret

NXT5:   mov     di,kbuf
        mov     [di+15h],bl             ; directory attribute to DTA
        mov     [di+1ah],ax             ; low file size
        mov     [di+1ch],dx             ; high file size
        mov     bl,byte ptr wcpath
        sub     bh,bh                   ; bx = length file name stirng
        lea     si,wcpath[bx]           ; point to end
        call    bakscan                 ; separate path/file name
        mov     cx,bx                   ; cx = file name length
        add     di,1eh                  ; DTA file name field ptr
        mov     ax,ds                   ; si points to file name, move it
        mov     es,ax
        rep movsb
        mov     [di],cl                 ; make ASCIIZ
        call    rstr
        clc
        ret
next2   endp

save    proc            ; save regs
        pop     bx
        push    es
        push    si
        push    di
        push    dx
        push    cx
        push    ax
        jmp     bx
save    endp

rstr    proc            ; restore regs
        pop     bx
        pop     ax
        pop     cx
        pop     dx
        pop     di
        pop     si
        pop     es
        jmp     bx
rstr    endp

setexcp proc
        push    ds      ; call rqsetexceptionhandler(@xcepinf,@status)
        %pushv(offset xcepinf)
        push    ds
        %pushv(offset status)
        call    rqsetexceptionhandler
        ret
setexcp endp

crtsk   proc            ; ax=rqcreatetask(0,cs:bx,ds,0:0,300h,0,@status)
        sub     cx,cx   ; bx is start address
        push    cx
        push    cs
        push    bx
        push    ds
        push    cx
        push    cx
        %pushv(300h)
        push    cx
        push    ds
        %pushv(offset status)
        call    rqcreatetask
        ret
crtsk   endp

crmbx   proc            ; ax=rqcreatemailbox(0,@status)
        %pushv(0)
        push    ds
        %pushv(offset status)
        call    rqcreatemailbox
        ret
crmbx   endp

crsema  proc
        sub     ax,ax   ; ax=rqcreatesemaphore(0,1,0,@status)
        push    ax
        inc     ax
        push    ax
        dec     ax
        push    ax
        push    ds
        %pushv(offset status)
        call    rqcreatesemaphore
        ret
crsema  endp

atfile  proc            ; ax=rqsattachfile(ds:di,@status)
        push    ds      ; ds:di is path ptr
        push    di
        push    ds
        %pushv(offset status)
        call    rqsattachfile
        ret
atfile  endp

crfile  proc            ; ax=rqscreatefile(ds:di,@status)
        push    di      ; ds:di is path ptr.  save di
        push    ds
        push    di
        push    ds
        %pushv(offset status)
        call    rqscreatefile
        pop     di      ; restore di
        ret
crfile  endp

opfile  proc            ; call rqsopen(ax,bx,cx,@status)
        push    ax      ; token
        push    bx      ; mode
        push    cx      ; number of buffers
        push    ds
        %pushv(offset status)
        call    rqsopen
        ret
opfile  endp

clfile  proc            ; call rqsclose(ax,@siostat)
        push    ax      ; token
        push    ds
        %pushv(offset siostat)
        call    rqsclose
        ret
clfile  endp

delcon  proc            ; call rqsdeleteconnection(bx,@status)
        push    bx      ; token
        push    ds
        %pushv(offset status)
        call    rqsdeleteconnection
        ret
delcon  endp

special proc            ; call rqsspecial(ax,cx,ds:bx,0,@status)
        push    ax      ; token
        push    cx      ; function
        push    ds
        push    bx      ; data ptr
        sub     ax,ax
        push    ax
        push    ax
        push    ds
        %pushv(offset status)
        call    rqsspecial
        ret
special endp

reader  proc            ; ax=rqsreadmove(ax,ds:bx,cx,@status)
        push    ax      ; token
        push    ds
        push    bx      ; buffer ptr
        push    cx      ; number of bytes
        push    ds
        %pushv(offset status)
        call    rqsreadmove
        ret
reader  endp

writer  proc            ; ax=rqswritemove(ax,ds:bx,cx,@status)
        push    ax      ; token
        push    ds
        push    bx      ; buffer ptr
        push    cx      ; number of bytes
        push    ds
        %pushv(offset status)
        call    rqswritemove
        ret
writer  endp

rewind  proc
        mov     ax,2    ; setup so seek positions to BOF
        sub     cx,cx
        mov     dx,cx

seek    proc
        push    bx      ; call rqsseek(token,mode,count,@status)
        push    ax
        push    cx
        push    dx
        push    ds
        %pushv(offset status)
        call    rqsseek
        ret
seek    endp
rewind  endp

lookup  proc            ; ax=rqlookupobject(ax,ds:bx,0,@status)
        push    ax      ; job token
        push    ds      ; @name
        push    bx
        push    cx      ; time limit
        push    ds
        %pushv(offset status)
        call    rqlookupobject
        ret
lookup  endp

sdefpfx proc            ; call rqsetdefaultprefix(cx,ax,@status)
        push    cx      ; job token
        push    ax      ; prefix token
        push    ds
        %pushv(offset status)
        call    rqsetdefaultprefix
        ret
sdefpfx endp

crcmdco proc            ; ax=rqccreatecommandconnection(ax,bx,cx,@status)
        push    ax      ; input token
        push    bx      ; output token
        push    cx      ; flag
        push    ds
        %pushv(offset status)
        call    rqccreatecommandconnection      ; can you believe this shit?
        ret
crcmdco endp

sendcmd proc            ; call rqcsendcommand(ax,ds:bx,ds:cx,@status)
        push    ax      ; command connection token
        push    ds
        push    bx      ; pointer to command
        push    ds
        push    cx      ; pointer to command exception
        push    ds
        %pushv(offset status)
        call    rqcsendcommand
        push    cx      ; save status
        mov     ax,citok
        mov     bx,offset sigpair
        mov     cx,6
        call    aspcl   ; restore ^C trap
        pop     cx      ; restore status
        ret
sendcmd endp

z2rmx   proc            ; copies ASCIIZ @ds:dx to si, returns count in ax
        mov     di,dx
        mov     cx,0ffffh
        sub     ax,ax
        repne scasb
        neg     cx
        add     cx,0fffeh
        mov     ax,cx   ; ax=cx= # of bytes
        mov     di,si
        mov     si,dx
        rep movsb
        ret
z2rmx   endp

bakscan proc            ; finds path part & file name part
        std             ; bx=string size, si points to EOstring
        mov     cx,bx
BSC1:   lodsb
        cmp     al,':'
        je      BSC2
        cmp     al,'/'
        je      BSC2
        cmp     al,'^'
        je      BSC2
        loop    BSC1
        dec     si
BSC2:   inc     si
        inc     si      ; si point to file name
        cld
        sub     bx,cx   ; bx=size file name, cx=size path
        ret             ; al=separator
bakscan endp

aopen   proc            ; call rqaopen(ax,bx,3,0,@status)
        push    ax      ; token
        push    bx      ; mode
        %pushv(3)
        %pushv(0)
        push    ds
        %pushv(offset status)
        call    rqaopen
        ret
aopen endp

aclose  proc
        push    ax      ; call rqaclose(ax,cx,@siostat)
        push    cx
        push    ds
        %pushv(offset siostat)
        call    rqaclose
        ret
aclose  endp

aread   proc            ; call rqaread(ax,ds:bx,cx,dx,@siostat)
        push    ax
        push    ds
        push    bx      ; buffer ptr
        push    cx      ; count
        push    dx      ; response mailbox
        push    ds
        %pushv(offset siostat)
        call    rqaread
        ret
aread   endp

awrite  proc            ; call rqawrite(ax,ds:bx,cx,dx,@siostat)
        push    ax
        push    ds
        push    bx      ; buffer ptr
        push    cx      ; count
        push    dx      ; response mailbox
        push    ds
        %pushv(offset siostat)
        call    rqawrite
        ret
awrite  endp

aspcl   proc            ; call rqaspecial(ax,cx,ds:bx,tmbox,@siostat)
        push    ax      ; token
        push    cx      ; function
        push    ds
        push    bx      ; ioparm ptr
        push    tmbox
        push    ds
        %pushv(offset siostat)
        call    rqaspecial
        mov     ax,tmbox
        mov     bx,0ffffh
        call    rcvmsg  ; ax=rqreceivemessage(tmbox,0ffffh,@ignore,@siostat)
        call    delseg
        ret
aspcl   endp

waitio  proc            ; ax=rqwaitio(ax,bx,0ffffh,@status)
        push    ax      ; token
        push    bx      ; response mailbox
        %pushv(0ffffh)
        push    ds
        %pushv(offset status)
        call    rqwaitio
        ret
waitio  endp

sendms  proc            ; call rqsendmessage(ax,bx,0,@status)
        push    ax      ; mailbox token
        push    bx      ; object to send
        %pushv(0)
        push    ds
        %pushv(offset status)
        call    rqsendmessage
        cld
        ret
sendms  endp

rcvmsg  proc
        pop     bp      ; ax=rqreceivemessage(tmbox,0ffffh,@ignore,@siostat)
        push    ax      ; mail box token
        push    bx      ; time limit
        push    ds
        %pushv(offset ignore)
        push    ds
        %pushv(offset siostat)
        call    rqreceivemessage
        jmp     bp
rcvmsg  endp

rcvun   proc            ; call rqreceiveunits(ax,1,0ffffh,@ccstat)
        pop     bp
        push    ax      ; semaphore token
        %pushv(1)       ; units
        %pushv(0ffffh)  ; time limit
        push    ds
        %pushv(offset ccstat)
        call    rqreceiveunits
        jmp     bp
rcvun   endp

delseg  proc            ; call rqdeletesegment(ax,@status)
        push    ax
        push    ds
        %pushv(offset siostat)
        call    rqdeletesegment
        ret
delseg  endp

gconsta proc
        push    bx      ; call rqsgetconnectionstatus(token,@temp,@status)
        push    ds
        %pushv(offset temp)
        push    ds
        %pushv(offset status)
        call    rqsgetconnectionstatus
        ret
gconsta endp

gfilsta proc
        push    ds      ; call rqsgetfilestatus(ds:di,@temp,@status)
        push    di      ; path ptr
        push    ds
        %pushv(offset temp)
        push    ds
        %pushv(offset status)
        call    rqsgetfilestatus
        jcxz    GFIL1
        ret
GFIL1:  mov     bx,cx
        cmp     byte ptr temp+9,0ffh    ; is it a named file?
        je      GFIL2
        mov     ax,cx                   ; no, setup for zero length
        mov     dx,cx
        ret
GFIL2:  cmp     byte ptr temp+38,8      ; is it a directory?
        je      GFIL3                   ; eq = no
        mov     bl,10h                  ; yes, get DOS directory attribute
GFIL3:  mov     ax,temp+54              ; low file size
        mov     dx,temp+56              ; high file size
        ret
gfilsta endp

code    ends
        end     begin, ds:datas, ss:stack