home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msr313src.zip / msster.asm < prev    next >
Assembly Source File  |  1993-07-12  |  45KB  |  1,566 lines

  1.      NAME    msster
  2. ; File MSSTER.ASM
  3.     include mssdef.h
  4. ;  Copyright (C) 1985, 1993, Trustees of Columbia University in the 
  5. ;  City of New York.  Permission is granted to any individual or institution
  6. ;  to use this software as long as it is not sold for profit.  This copyright
  7. ;  notice must be retained.  This software may not be included in commercial
  8. ;  products without written permission of Columbia University.
  9. ;
  10. ; Edit history
  11. ; 27 August 1992 version 3.13
  12. ; 6 Sept 1991 version 3.11
  13. ; Last edit 22 Feb 1992
  14.  
  15.     public    clscpt, defkey, clscpi, ploghnd, sloghnd, tloghnd
  16.     public  dopar, shokey, cptchr, pktcpt, targ, replay, repflg
  17.     public    kbdflg, shkadr, telnet, ttyact, write, dec2di, caplft
  18.     public    cnvlin, katoi, decout, valout, atoi, cnvstr
  19.     public    pntchr, pntflsh, pntchk, prnhand, prnopen
  20.     public    vfopen, vfread
  21.  
  22. braceop    equ    7bh            ; opening curly brace
  23. bracecl    equ    7dh            ; closing curly brace
  24.  
  25. data     segment
  26.     extrn    flags:byte, trans:byte, diskio:byte, portval:word
  27.     extrn    rdbuf:byte, dosnum:word, filtst:byte, prnname:byte
  28.     extrn    comand:byte, kstatus:word, flowon:byte, flowoff:byte
  29.  
  30. targ    termarg    <0,1,cptchr,0,parnon>
  31. crlf    db      cr,lf,'$'
  32. tmsg1    db    cr,lf,'(Connecting to host, type $' 
  33. tmsg3    db    ' C to return to PC)',cr,lf,cr,lf,cr,lf,'$'
  34. erms21    db    cr,lf,'?Cannot start the connection.$'
  35. erms25    db    cr,lf,'?Input must be numeric$' 
  36. erms22    db    cr,lf,'?No open logging file$'
  37. erms23    db    '*** Error writing session log, suspending capture ***$'
  38. erms24    db    cr,lf,'?Error writing Packet log$'
  39. erms26    db    ' *** PRINTER IS NOT READY ***  press R to retry'
  40.     db    ' or D to discard printing:  $'
  41. esctl    db    'Control-$'
  42. repflg    db    0        ; REPLAY or SET TERM REPLAY filespec flag
  43. rephlp    db    'name of file to playback$'
  44. reperr    db    cr,lf,'?File not found$'    ; for REPLAY command
  45. msgtxt    db    'text to be written$'
  46.  
  47. vfophlp    db    'Filename$'
  48. vfopbad    db    cr,lf,'?Cannot open file $'    ; filename follows
  49. vfclbad    db    cr,lf,'?Cannot close file$'
  50. vfoptwice db    cr,lf,'?File is already open$'
  51. vfnofile db    cr,lf,'?File is not open$'
  52. vfrbad    db    cr,lf,'?Error while reading file$'
  53. vfwbad    db    cr,lf,'?Error while writing file$'
  54. vfrdbad    db    cr,lf,'?more parameters are needed$'
  55. vfrdmsg    db    'name of variable  into which to read a line from file$'
  56. vfrhandle dw    -1            ; READ FILE handle (-1 = invalid)
  57. vfwhandle dw    -1            ; WRITE FILE handle
  58.  
  59. opntab    db    3            ; OPEN FILE table
  60.     mkeyw    'Read',1
  61.     mkeyw    'Write',2
  62.     mkeyw    'Append',3
  63.  
  64. inthlp db cr,lf,'  ?  This message                    F  Dump screen to file'
  65.        db cr,lf,'  C  Close the connection            P  Push to DOS'
  66.        db cr,lf,'  S  Status of the connection        Q  Quit logging'
  67.        db cr,lf,'  M  Toggle mode line                R  Resume logging'
  68.        db cr,lf,'  B  Send a Break                    0  Send a null'
  69.        db cr,lf,'  L  Send a long 1.8 s Break         H  Hangup phone'
  70.        db cr,lf,'  A  Send Telnet "Are You There"     I  Send Telnet' 
  71.        db    ' "Interrupt Process"' 
  72.        db cr,lf,'  Typing the escape character will send it to the host'
  73.        db 0          ; this short-form obscures less screen area [jrd]
  74.  
  75. intprm    db    'Command> $'
  76. intclet    db    'B','C','F','H','L'    ; single letter commands
  77.     db    'M','P','Q','R','S'    ; must parallel dispatch table intcjmp
  78.     db    '?','0','A','I'
  79. numlet    equ    $ - intclet        ; number of entries
  80.     even
  81. intcjmp    dw    intchb,intchc,intchf,intchh,intchl
  82.     dw    intchm,intchp,intchq,intchr,intchs
  83.     dw    intchu,intchn,intayt,inttip
  84.  
  85. prnhand    dw    4        ; printer file handle (4 = DOS default)
  86.  
  87.     even
  88. ploghnd    dw    -1        ; packet logging handle
  89. sloghnd    dw    -1        ; session logging handle
  90. tloghnd    dw    -1        ; transaction logging handle
  91.  
  92. clotab    db    6
  93.     mkeyw    'READ-FILE',4001h
  94.     mkeyw    'WRITE-FILE',4002h
  95.     mkeyw    'All-logs',logpkt+logses+logtrn
  96.     mkeyw    'Packets',logpkt
  97.     mkeyw    'Session',logses
  98.     mkeyw    'Transaction',logtrn
  99.  
  100. clseslog db    cr,lf,' Closing Session log$'
  101. clpktlog db    cr,lf,' Closing Packet log$'
  102. cltrnlog db    cr,lf,' Closing Transaction log$'
  103. clohlp    db    cr,lf,' READ-FILE or WRITE-FILE, or the following log files:'
  104.     db    cr,lf,' All-logs, Packets, Session, Transaction$'
  105.  
  106. writetab db    5            ; Write command log file types
  107.     mkeyw    'FILE',4002h        ; FILE
  108.     mkeyw    'Packet',logpkt
  109.     mkeyw    'Screen',80h        ; unused value, to say screen
  110.     mkeyw    'Session',logses
  111.     mkeyw    'Transaction',logtrn
  112.  
  113. sttmsg    db    cr,lf,'Press space to continue ...$'
  114. kbdflg    db    0            ; non-zero means char here from Term
  115. ttyact    db    0            ; Connect mode active, if non-zero
  116. shkadr    dw    0            ; offset of replacement Show Key cmd
  117. nbase    dw    10            ; currently active number base
  118. numset    db    '0123456789ABCDEF'    ; number conversion alphabet
  119. temp    dw    0
  120. tmp    db    0
  121. pktlft    dw    cptsiz        ; number free bytes left
  122. caplft    dw    cptsiz        ; number free bytes left
  123. data    ends
  124.  
  125. data1    segment
  126. pktbuf    db    cptsiz dup (0)    ; packet logging buffer
  127. pktbp    dw    pktbuf        ; buffer pointer to next free byte
  128. capbuf    db    cptsiz dup (0)    ; session logging buffer
  129. capbp    dw    capbuf        ; buffer pointer to next free byte
  130. prnbuf    db    cptsiz dup (0)    ; printer buffer
  131. pntptr    dw    prnbuf        ; pointer to next free byte
  132. data1    ends
  133.  
  134. code    segment
  135.     extrn     comnd:near, outchr:near, stat0:near, iseof:near
  136.     extrn    term:near, strlen:near, pcwait:near, isfile:near
  137.     extrn    beep:near, puthlp:near, serhng:near
  138.     extrn    serini:near, serrst:near, sendbr:near, putmod:near
  139.     extrn    fpush:near, dumpscr:near, sendbl:near, prtasz:near
  140.     extrn    trnmod:near, dodecom:near
  141.     assume    cs:code, ds:data, es:nothing
  142.  
  143. ; the show key command
  144. shokey    proc    near
  145.     cmp    shkadr,0        ; keyboard translator present?
  146.     je    shokey1            ; e = no, use regular routines
  147.     mov    bx,shkadr        ; get offset of replacement routine
  148.     jmp    bx            ; and execute it rather than us
  149. shokey1:clc
  150.     ret
  151. shokey    endp
  152. ; enter with ax/scan code to define, si/ pointer to definition, cx/ length
  153. ; of definition.  Defines it in definition table. Obsolete.
  154. defkey    proc    near
  155.     ret
  156. defkey    endp
  157.  
  158. ; This is the CONNECT command
  159.  
  160. TELNET     PROC    NEAR
  161.     mov    ah,cmeol
  162.     call    comnd            ; get a confirm
  163.     jnc    teln1            ; nc = success
  164.     ret
  165. teln1:    call    serini            ; ensure port is inited now
  166.     jnc    teln1a            ; nc = success
  167.     test    flags.remflg,dquiet    ; quiet display mode?
  168.     jnz    teln1b            ; nz = yes. Don't write to screen
  169.     mov    dx,offset erms21    ; say cannot start connection
  170.     mov    ah,prstr
  171.     int    dos
  172. teln1b:    or    kstatus,ksgen        ; general command failure
  173.     ret
  174. teln1a:    cmp    flags.vtflg,0        ; emulating a terminal?
  175.     jne    teln2            ; ne= yes, no wait necessary
  176.     mov    ah,prstr
  177.     mov    dx,offset crlf        ; output a crlf
  178.     int    dos
  179.     call    domsg            ; reassure user
  180.     mov    ax,2000            ; two seconds
  181.     call    pcwait            ; pause
  182. teln2:    xor    al,al            ; initial flags
  183.     mov    ttyact,1        ; say telnet is active
  184.     cmp    flags.vtflg,0        ; emulating a terminal?
  185.     je    teln3            ; e = no, say mode line is to be off
  186.     cmp    flags.modflg,0        ; mode line enabled?
  187.     jne    tel010            ; ne = yes
  188. teln3:    or    al,modoff        ; no, make sure it stays off
  189.  
  190. tel010:    test    flags.debug,logses    ; debug mode?
  191.     jz    tel0            ; z = no, keep going
  192.     or    al,trnctl        ; yes, show control chars
  193. tel0:    cmp    flags.vtflg,0        ; emulating a terminal?
  194.     je    tel1            ; e = no
  195.     or    al,emheath        ; say emulating some kind of terminal
  196. tel1:    mov    bx,portval
  197.     cmp    [bx].ecoflg,0        ; echoing?
  198.     jz    tel2            ; z = no
  199.     or    al,lclecho        ; turn on local echo
  200. tel2:    mov    targ.flgs,al        ; store flags
  201.     mov    ah,flags.comflg        ; COMs port identifier
  202.     mov    targ.prt,ah        ; Port 1 or 2, etc
  203.     mov    ah,[bx].parflg        ; parity flag
  204.     mov    targ.parity,ah
  205.     mov    ax,[bx].baud        ; baud rate identifier
  206.     mov    targ.baudb,al
  207.     xor    ah,ah
  208.     test    flags.capflg,logses    ; select session logging flag bit
  209.     jz    tel3            ; z = no logging
  210.     mov    ah,capt            ; set capture flag
  211. tel3:    or    targ.flgs,ah
  212.     jmp    short tem1
  213.  
  214. TEM:    call    serini            ; init serial port
  215.     jnc    tem1            ; nc = success
  216.     mov    ttyact,0        ; say we are no longer active
  217.     clc
  218.     ret                ; and exit Connect mode
  219.  
  220. tem1:    mov    dx,offset crlf        ; give user an indication that we are
  221.     mov    ah,prstr        ; entering terminal mode
  222.     int    dos
  223.     mov    ax,offset targ        ; point to terminal arguments
  224.     call    term            ; call the main Terminal procedure
  225.     mov    al,kbdflg        ; get the char from Term, if any
  226.     mov    kbdflg,0        ; clear    the flag
  227.     or    al,al            ; was there a char from Term?
  228.     jnz    intch2            ; nz = yes, else ask for one from kbd
  229.  
  230. intchar:call    iseof            ; stdin at eof?
  231.     jnc    intch1            ; nc = not eof, get more
  232.     mov    al,'C'            ; use C when file is empty
  233.     jmp    short intchc        ;  to provide an exit
  234. intch1:    mov    ah,0ch            ; clear Bios keyboard buffer and do
  235.     mov    al,coninq        ;  read keyboard, no echo
  236.     int    dos            ; get a char
  237.     or    al,al            ; scan code indicator?
  238.     jnz    intch2            ; nz = no, ascii
  239.     mov    ah,coninq        ; read and discard scan code
  240.     int    dos
  241.     jmp    short intch1        ; try again
  242. intch2:    mov    flags.cxzflg,0        ; prevent Control-C carryover
  243.     cmp    al,' '            ; space?
  244.     je    tem            ; e = yes, ignore it
  245.     cmp    al,cr            ; check ^M (cr) against plain ascii M
  246.     je    tem            ; exit on cr
  247.     cmp    al,trans.escchr        ; is it the escape char?
  248.     jne    intch3            ; ne = no
  249.     mov    ah,al
  250.     call    outchr
  251.     jmp    short tem        ; return, we are done here
  252. intch3:    push    es
  253.     push    ds
  254.     pop    es
  255.     mov    di,offset intclet    ; command letters
  256.     mov    cx,numlet        ; quantity of them
  257.     cmp    al,' '            ; control code?
  258.     jae    intch3a            ; ae = no
  259.     or    al,40H            ; convert control chars to printable
  260. intch3a:cmp    al,96            ; lower case?
  261.     jb    intch3b            ; b = no
  262.     and    al,not (20h)        ; move to upper case
  263. intch3b:cld
  264.     repne    scasb            ; find the matching letter
  265.     pop    es
  266.     jne    intch4            ; ne = not found, beep and get another
  267.     dec    di            ; back up to letter
  268.     sub    di,offset intclet    ; get letter number
  269.     shl    di,1            ; make it a word index
  270.     jmp    intcjmp[di]        ; dispatch to it
  271. intch4:    call    beep            ; say illegal character
  272.     jmp    intchar
  273.  
  274. intayt:    mov    ah,255            ; 'I' Telnet Are You There
  275.     call    outchr            ; send IAC (255) AYT (246)
  276.     mov    ah,246
  277.     call    outchr
  278.     jmp    tem
  279.  
  280. intchb:    call    sendbr            ; 'B' send a break
  281.     jmp    tem            ; And return
  282.  
  283. intchc:    mov    ttyact,0        ; 'C' say we are no longer active
  284.     clc                ; and exit Connect mode
  285.     ret
  286.  
  287. intchf:    call    dumpscr            ; 'F' dump screen, use msy routine
  288.     jmp    tem            ; and return
  289.  
  290. intchh:    call    serhng            ; 'H' hangup phone
  291.     call    serrst            ; turn off port
  292.     jmp    tem
  293.  
  294. intchl:    call    sendbl            ; 'L' send a long break
  295.     jmp    tem
  296.  
  297. inttip:    mov    ah,255            ; 'I' Telnet Interrrupt Process
  298.     call    outchr            ; send IAC (255) IP (244)
  299.     mov    ah,244
  300.     call    outchr
  301.     jmp    tem
  302.  
  303. intchm:    cmp    flags.modflg,1        ; 'M' toggle mode line, enabled?
  304.     jne    intchma            ; ne = no, leave it alone
  305.     xor    targ.flgs,modoff    ; enabled, toggle its state
  306. intchma:jmp    tem            ; and reconnect
  307.  
  308. intchp:    call    fpush            ; 'P' push to DOS
  309.     mov    dx,offset sttmsg    ; say we have returned
  310.     mov    ah,prstr
  311.     int    dos
  312.     jmp    short intchsb        ; wait for a space
  313.  
  314. intchq:    and    targ.flgs,not capt    ; 'Q' suspend session logging
  315.     jmp    tem            ; and resume
  316.  
  317. intchr:    test    flags.capflg,logses    ; 'R' resume logging. Can we capture?
  318.     jz    intchr1            ; z = no
  319.     or    targ.flgs,capt        ; turn on session logging flag
  320. intchr1:jmp    tem            ; and resume
  321.  
  322. intchs:    call    stat0            ; 'S' status, call stat0
  323.     mov    dx,offset sttmsg
  324.     mov    ah,prstr
  325.     int    dos
  326. intchsa:call    iseof            ; is stdin at eof?
  327.     jnc    intchsb            ; nc = not eof, get more
  328.     jmp    tem            ; resume if EOF
  329. intchsb:mov    ah,coninq        ; console input, no echo
  330.     int    dos
  331.     cmp    al,' '            ; space?
  332.     jne    intchsa
  333.     jmp    tem
  334.  
  335. intchu:    mov    ax,offset inthlp    ; '?' get help message
  336.     call    puthlp            ; write help msg
  337.     mov    dx,offset intprm
  338.     mov    ah,prstr        ; Print it
  339.     int    dos
  340.     jmp    intchar            ; Get another char
  341.  
  342. intchn:    xor    ah,ah            ; '0' send a null
  343.     call    outchr
  344.     jmp    tem
  345. TELNET  ENDP
  346.  
  347. ; Reassure user    about connection to the host. Tell him what escape sequence
  348. ; to use to return
  349.  
  350. DOMSG    PROC    NEAR
  351.     mov    ah,prstr
  352.     mov    dx,offset tmsg1
  353.     int    dos
  354.     call    escprt
  355.     mov    ah,prstr
  356.     mov    dx,offset tmsg3
  357.     int    dos
  358.     ret
  359. DOMSG    ENDP
  360.  
  361. ; print    the escape character in readable format.  
  362.  
  363. ESCPRT    PROC    NEAR
  364.     mov    dl,trans.escchr
  365.     cmp    dl,' '
  366.     jge    escpr2
  367.     push    dx
  368.     mov    ah,prstr
  369.     mov    dx,offset esctl
  370.     int    dos
  371.     pop    dx
  372.     add    dl,040H        ; Make it printable
  373. escpr2:    mov    ah,conout
  374.     int    dos
  375.     ret
  376. ESCPRT    ENDP
  377.  
  378.  
  379. ; Set parity for character in Register AL
  380.  
  381. dopar:    push    bx
  382.     mov    bx,portval
  383.     mov    bl,[bx].parflg        ; get parity flag byte
  384.     cmp    bl,parnon        ; No parity?
  385.     je    parret            ; Just return
  386.     and    al,07FH            ; Strip parity. Same as Space parity
  387.     cmp    bl,parspc        ; Space parity?
  388.     je    parret            ; e = yes, then we are done here
  389.     cmp    bl,parevn        ; Even parity?
  390.     jne    dopar0            ; ne = no
  391.     or    al,al
  392.     jpe    parret            ; pe = even parity now
  393.     xor    al,080H            ; Make it even parity
  394.     jmp    short parret
  395. dopar0:    cmp    bl,parmrk        ; Mark parity?
  396.     jne    dopar1            ; ne = no
  397.     or    al,080H            ; Turn on the parity bit
  398.     jmp    short parret
  399. dopar1:    cmp    bl,parodd        ; Odd parity?    
  400.     or    al,al
  401.     jpo    parret            ; Already odd, leave it
  402.     xor    al,080H            ; Make it odd parity
  403. parret:    pop    bx
  404.     ret
  405.  
  406. ; REPLAY filespec  through terminal emulator
  407. replay    proc    near
  408.     mov    dx,offset rdbuf        ; place for filename
  409.     mov    bx,offset rephlp    ; help
  410.     mov    repflg,0        ; clear the replay active flag
  411.     mov    ah,cmword        ; get filename
  412.     call    comnd
  413.     jc    replay2            ; c = failure
  414.     mov    ah,cmeol        ; get an EOL confirm
  415.     call    comnd
  416.     jc    replay2            ; c = failure
  417.     mov    ah,open2        ; open file
  418.     xor    al,al            ; open readonly
  419.     cmp    byte ptr dosnum+1,2    ; above DOS 2?
  420.     jna    replay1            ; na = no, so no shared access
  421.     mov    al,0+40h        ; open readonly, deny none
  422. replay1:mov    dx,offset rdbuf        ; asciiz filename
  423.     int    dos
  424.     jnc    replay3            ; nc = success
  425.     mov    ah,prstr
  426.     mov    dx,offset reperr    ; Cannot open that file
  427.     int    dos
  428.     clc
  429. replay2:ret
  430. replay3:mov    diskio.handle,ax    ; file handle
  431.     mov    repflg,1        ; set replay flag
  432.     call    telnet            ; enter Connect mode
  433.     mov    bx,diskio.handle
  434.     mov    ah,close2        ; close the file
  435.     int    dos
  436.     mov    repflg,0        ; clear the flag
  437.     clc
  438.     ret
  439. replay    endp
  440.  
  441. cptchr    proc    near            ; session capture routine, char in al
  442.     test    flags.capflg,logses    ; session logging active now?
  443.     jz    cptch1            ; z = no
  444.     push    di
  445.     push    es
  446.     mov    di,data1        ; seg of capbp and capbuf
  447.     mov    es,di
  448.     cld
  449.     mov    di,es:capbp        ; buffer pointer
  450.     stosb
  451.     inc    es:capbp
  452.     pop    es
  453.     pop    di
  454.     dec    caplft            ; decrement chars remaining
  455.     jg    cptch1            ; more room, forget this part
  456.     call    cptdmp            ; dump the info
  457. cptch1:    ret
  458. cptchr    endp
  459.  
  460. cptdmp    proc    near            ; empty the capture buffer
  461.     push    ax
  462.     push    bx
  463.     push    cx
  464.     push    dx
  465.     mov    bx,sloghnd        ; get file handle
  466.     or    bx,bx            ; is file open?
  467.     jle    cptdm1            ; le = no, skip it
  468.     mov    cx,cptsiz        ; original buffer size
  469.     sub    cx,caplft        ; minus number remaining
  470.     jl    cptdm2            ; means error
  471.     jcxz    cptdm1            ; z = nothing to do
  472.     push    ds
  473.     mov    dx,data1        ; seg of capbuf
  474.     mov    ds,dx
  475.     mov    dx,offset capbuf    ; the capture routine buffer
  476.     mov    ah,write2        ; write with filehandle
  477.     int    dos            ; write out the block
  478.     pop    ds
  479.     jc    cptdm2            ; carry set means error
  480.     cmp    ax,cx            ; wrote all?
  481.     jne    cptdm2            ; no, an error
  482.     push    es
  483.     mov    dx,data1        ; seg of capbuf and capbp
  484.     mov    es,dx
  485.     mov    es:capbp,offset capbuf
  486.     pop    es
  487.     mov    caplft,cptsiz        ; init buffer ptr & chrs left
  488.     clc
  489.     jmp    short cptdm1
  490. cptdm2:    and    targ.flgs,not capt    ; so please stop capturing
  491.     and    flags.capflg,not logses    ; deselect session logging flag bit
  492.     mov    dx,offset erms23    ; tell user the bad news
  493.     call    putmod            ; write on mode line
  494.     stc
  495. cptdm1:    pop    dx
  496.     pop    cx
  497.     pop    bx
  498.     pop    ax
  499.     ret
  500. cptdmp    endp
  501.  
  502. pktcpt    proc    near            ; packet log routine, char in al
  503.     test    flags.capflg,logpkt    ; logging packets now?
  504.     jz    pktcp1            ; z = no
  505.     push    di
  506.     push    es
  507.     mov    di,data1        ; seg of pktbuf and pktbp
  508.     mov    es,di
  509.     mov    di,es:pktbp        ; buffer pointer
  510.     cld
  511.     stosb                ; store char in buffer
  512.     inc    es:pktbp        ; move pointer to next free byte
  513.     pop    es
  514.     pop    di
  515.     dec    pktlft            ; decrement chars remaining
  516.     jg    pktcp1            ; g = more room, forget this part
  517.     call    pktdmp            ; dump the info
  518. pktcp1:    ret
  519. pktcpt    endp
  520.  
  521. pktdmp    proc    near            ; empty the capture buffer
  522.     push    ax
  523.     push    bx
  524.     push    cx
  525.     push    dx
  526.     mov    bx,ploghnd        ; get file handle
  527.     or    bx,bx            ; is file open?
  528.     jle    cptdm1            ; le = no, skip it
  529.     mov    cx,cptsiz        ; original buffer size
  530.     sub    cx,pktlft        ; minus number remaining
  531.     jl    pktdm2            ; l means error
  532.     jcxz    pktdm1            ; z = nothing to do
  533.     push    ds
  534.     mov    dx,data1        ; seg of pktbuf
  535.     mov    ds,dx
  536.     mov    dx,offset pktbuf    ; the capture routine buffer
  537.     mov    ah,write2        ; write with filehandle
  538.     int    dos            ; write out the block
  539.     pop    ds
  540.     jc    pktdm2            ; carry set means error
  541.     cmp    ax,cx            ; wrote all?
  542.     jne    pktdm2            ; ne = no, error
  543.     push    es
  544.     mov    dx,data1        ; seg of pktbuf
  545.     mov    es,dx
  546.     mov    es:pktbp,offset pktbuf
  547.     pop    es
  548.     mov    pktlft,cptsiz        ; init buffer ptr & chrs left
  549.     jmp    short pktdm1
  550. pktdm2:    and    flags.capflg,not logpkt    ; so please stop capturing
  551.     mov    dx,offset erms24    ; tell user the bad news
  552.     mov    ah,prstr
  553.     int    dos
  554.     call    clscp4            ; close the packet log
  555. pktdm1:    pop    dx
  556.     pop    cx
  557.     pop    bx
  558.     pop    ax
  559.     ret
  560. pktdmp    endp
  561.  
  562. ; CLOSE command
  563.  
  564. clscpt    proc    near
  565.     mov    ah,cmkey        ; get kind of file to close
  566.     mov    dx,offset clotab    ; close table
  567.     mov    bx,offset clohlp    ; help
  568.     call    comnd
  569.            jc    clscp2            ; c = failure
  570.     mov    temp,bx
  571.     mov    ah,cmeol
  572.     call    comnd
  573.            jc    clscp2            ; c = failure
  574.     mov    kstatus,kssuc        ; success status thus far
  575.     mov    bx,temp
  576.     cmp    bh,40h            ; READ-FILE or WRITE-FILE?
  577.     jne    clscp0            ; ne = no
  578.     mov    ax,bx
  579.     jmp    vfclose            ; close FILE, pass kind in AX
  580. clscp0:    cmp    bx,logpkt+logses+logtrn    ; close all?
  581.     je    clscpi            ; e = yes
  582.     cmp    bx,logpkt        ; just packet?
  583.     je    clscp4
  584.     cmp    bx,logses        ; just session?
  585.     je    clscp6
  586.     cmp    bx,logtrn        ; just session?
  587.     jne    clscp1            ; ne = no
  588.     jmp    clscp8
  589. clscp1:    mov    dx,offset erms22    ; say none active
  590.     mov    ah,prstr
  591.     int    dos
  592.     clc
  593.     ret
  594. clscp2:    mov    kstatus,ksgen        ; general cmd failure status
  595.     stc
  596.     ret
  597.                     ; CLSCPI called at Kermit exit
  598. CLSCPI:    mov    bx,portval
  599.     mov    [bx].flowc,0        ; set no flow control so no sending it
  600.     call    pntflsh            ; flush PRN buffer
  601.     call    clscp4            ; close packet log
  602.     call    clscp6            ; close session log
  603.     call    clscp8            ; close transaction log
  604.     mov    al,2            ; close WRITE FILE log
  605.     call    vfclose
  606.     clc                ; return success
  607.     ret
  608.  
  609. clscp4:    push    bx            ; PACKET LOG
  610.     mov    bx,ploghnd        ; packet log handle
  611.     or    bx,bx            ; is it open?
  612.     jle    clscp5            ; e = no
  613.     call    pktdmp            ; dump buffer
  614.     mov    ah,close2
  615.     int    dos
  616.     cmp    flags.takflg,0        ; ok to echo?
  617.     je    clscp5            ; e = no
  618.     mov    ah,prstr
  619.     mov    dx,offset clpktlog    ; tell what we are doing
  620.     int    dos
  621. clscp5:    mov    ploghnd,-1        ; say handle is invalid
  622.     pop    bx
  623.     and    flags.capflg,not logpkt    ; say this log is closed
  624.     ret
  625.  
  626. clscp6:    push    bx            ; SESSION LOG
  627.     mov    bx,sloghnd        ; session log handle
  628.     or    bx,bx            ; is it open?
  629.     jle    clscp7            ; e = no
  630.     call    cptdmp            ; dump buffer
  631.     mov    ah,close2
  632.     int    dos
  633.     cmp    flags.takflg,0        ; ok to echo?
  634.     je    clscp7            ; e = no
  635.     mov    ah,prstr
  636.     mov    dx,offset clseslog    ; tell what we are doing
  637.     int    dos
  638. clscp7:    mov    sloghnd,-1        ; say handle is invalid
  639.     pop    bx
  640.     and    flags.capflg,not logses    ; say this log is closed
  641.     ret
  642.  
  643. clscp8:    push    bx            ; TRANSACTION LOG
  644.     mov    bx,tloghnd        ; transaction log handle
  645.     or    bx,bx            ; is it open?
  646.     jle    clscp9            ; e = no
  647.     mov    ah,close2
  648.     int    dos
  649.     cmp    flags.takflg,0        ; ok to echo?
  650.     je    clscp9            ; e = no
  651.     mov    ah,prstr
  652.     mov    dx,offset cltrnlog    ; tell what we are doing
  653.     int    dos
  654. clscp9:    mov    tloghnd,-1        ; say handle is invalid
  655.     pop    bx
  656.     and    flags.capflg,not logtrn    ; say this log is closed
  657.     ret
  658. clscpt    endp
  659.  
  660. ; Print on PRN the char in register al. On success return with C bit clear.
  661. ; On failure do procedure pntchk and return its C bit (typically C set).
  662. ; Uses buffer dumpbuf (screen dump).
  663. pntchr    proc    near
  664.     push    es
  665.     push    ax
  666.     mov    ax,data1        ; segment of pntptr and prnbuf
  667.     mov    es,ax
  668.     cmp    es:pntptr,offset prnbuf+cptsiz ; buffer full yet?
  669.     pop    ax
  670.     pop    es
  671.     jb    pntchr1            ; b = no
  672.     call    pntflsh            ; flush buffer now
  673.     jnc    pntchr1            ; nc = success
  674.     ret                ; c = fail, discard char
  675. pntchr1:push    es
  676.     push    bx
  677.     mov    bx,data1        ; segment of pntptr and prnbuf
  678.     mov    es,bx
  679.     mov    bx,es:pntptr        ; pointer to next open slot
  680.     mov    es:[bx],al        ; store the character
  681.     inc    bx            ; update pointer
  682.     mov    es:pntptr,bx        ; save pointer
  683.     pop    bx
  684.     pop    es
  685.     clc                ; clear carry bit
  686.     ret
  687. pntchr    endp
  688.  
  689. ; Flush printer buffer. Return carry clear if success.
  690. ; On failure do procedure pntchk and return its C bit (typically C set).
  691. ; Uses buffer dumpbuf (screen dump).
  692. pntflsh    proc    near
  693.     push    es
  694.     push    ax
  695.     mov    ax,data1        ; segment of pntptr and prnbuf
  696.     mov    es,ax
  697.     cmp    es:pntptr,offset prnbuf    ; any text in buffer?
  698.     pop    ax
  699.     pop    es
  700.     ja    pntfls1            ; a = yes
  701.     clc
  702.     ret                ; else nothing to do
  703. pntfls1:cmp    prnhand,0        ; is printer handle valid?
  704.     jg    pntfls2            ; g = yes
  705.     push    es
  706.     push    ax
  707.     mov    ax,data1        ; segment of pntptr and prnbuf
  708.     mov    es,ax
  709.     mov    es:pntptr,offset prnbuf
  710.     pop    ax
  711.     pop    es
  712.     clc                ; omit printing, quietly
  713.     ret
  714. pntfls2:push    ax
  715.     push    bx
  716.     push    cx
  717.     push    dx
  718.     push    si
  719.     push    di
  720.     push    es
  721.     mov    ah,flowoff        ; get flow control char
  722.     or    ah,ah            ; flow control active?
  723.     jz    pntfls3            ; z = no, not using xoff
  724.     call    outchr            ; output xoff (ah), no echo
  725. pntfls3:mov    bx,prnhand        ; file handle for DOS printer PRN
  726.     push    DS            ; about to change DS
  727.     mov    dx,data1        ; segment of prnbuf
  728.     mov    ds,dx            ; set DS
  729.     mov    dx,offset prnbuf    ; start of buffer
  730.     mov    cx,ds:pntptr
  731.     sub    cx,dx            ; cx = current byte count
  732. pntfls4:push    cx
  733.     push    dx
  734.     mov    cx,1
  735.     mov    ah,write2
  736.     int    dos            ; write buffer to printer
  737.     pop    dx
  738.     pop    cx
  739.     jc    pntfls5            ; c = call failed
  740.     cmp    ax,1            ; did we write it?
  741.     jne    pntfls5            ; ne = no, dos critical error
  742.     inc    dx            ; point to next char
  743.     loop    pntfls4
  744.     mov    ds:pntptr,offset prnbuf    ; reset buffer pointer
  745.     pop    DS            ; restore DS
  746.     clc                ; declare success
  747.     jmp    pntfls11
  748. pntfls5:mov    si,dx            ; address of next char to be printed
  749.     mov    di,offset prnbuf    ; start of buffer
  750.     sub    dx,di            ; dx now = number successful prints
  751.     mov    cx,ds:pntptr
  752.     sub    cx,si            ; count of chars to be printed
  753.     jle    pntfls6
  754.     mov    ax,ds
  755.     mov    es,ax
  756.     cld
  757.     rep    movsb            ; copy unwritten to start of buffer
  758. pntfls6:sub    ds:pntptr,dx        ; move back printer pointer by ok's
  759.     pop    DS            ; restore DS
  760.  
  761. pntfls7:mov    dx,offset erms26    ; printer not ready, get user action
  762.     call    putmod            ; write new mode line
  763.     call    beep            ; make a noise
  764.     mov    ah,0ch            ; clear DOS typeahead buffer
  765.     mov    al,1            ; read from DOS buffer
  766.     int    dos
  767.     or    al,al            ; Special key?
  768.     jnz    pntfls8            ; nz = no, consume
  769.     mov    al,1            ; consume scan code
  770.     int    dos
  771.     jmp    short pntfls7        ; try again
  772.  
  773. pntfls8:and    al,not 20h        ; lower to upper case quickie
  774.     cmp    al,'R'            ; Retry?
  775.     jne    pntfls8a        ; ne = no
  776.     call    trnmod            ; toggle mode line
  777.     call    trnmod            ; back to same state as before
  778.     jmp    pntfls3            ; go retry
  779. pntfls8a:cmp    al,'D'            ; Discard printing?
  780.     jne    pntfls7            ; ne = no, try again
  781.     mov    bx,prnhand
  782.     cmp    bx,4            ; stdin/stdout/stderr/stdaux/stdprn?
  783.     jbe    pntfls9            ; be = yes, always available
  784.     mov    ah,close2        ; close this file
  785.     int    dos
  786. pntfls9:mov    bx,offset prnname    ; name of printer file
  787.     mov    word ptr [bx],'UN'    ; set to NUL<0>
  788.     mov    word ptr [bx+2],'L'+0
  789.     push    es
  790.     mov    ax,data1        ; seg for pntptr
  791.     mov    es,ax
  792.     mov    es:pntptr,offset prnbuf    ; reset pointer
  793.     pop    es
  794.     mov    prnhand,-1        ; declare handle invalid
  795. pntfls10:call    trnmod            ; toggle mode line
  796.     call    trnmod            ; back to same state as before
  797.     stc                ; declare failure
  798. pntfls11:pushf
  799.     mov    ah,flowon
  800.     or    ah,ah            ; flow control active?
  801.     jz    pntfls12        ; z = no, not using xon
  802.     call    outchr            ; output xon (al), no echo
  803. pntfls12:popf
  804.     pop    es
  805.     pop    di
  806.     pop    si
  807.     pop    dx
  808.     pop    cx
  809.     pop    bx
  810.     pop    ax
  811.     ret                ; nc = success
  812. pntflsh    endp
  813.  
  814. ; Check for PRN (DOS's printer) being ready. If ready, return with C clear
  815. ; Otherwise, write Not Ready msg on mode line and return with C bit set.
  816. ; N.B. DOS Critical Error will occur here if PRN is not ready.  [jrd]
  817. pntchk    proc    near
  818.     push    dx
  819.     push    cx
  820.     push    ax
  821.     mov    cx,10            ; ten retries before declaring error
  822.     cmp    prnhand,0        ; printer handle valid?
  823.     jle    pntchk2            ; le = no, invalid
  824. pntchk0:push    bx
  825.     mov    bx,prnhand        ; file handle
  826.     mov    ah,ioctl        ; get printer status, via DOS
  827.     mov    al,7            ; status for output
  828.     int    dos
  829.     pop    bx
  830.     jc    pntchk1            ; c = call failed
  831.     cmp    al,0ffh            ; code for Ready?
  832.     je    pntchk3            ; e = yes, assume printer is ready
  833. pntchk1:push    cx            ; save counter, just in case
  834.     mov    ax,100            ; wait 100 millisec
  835.     call    pcwait
  836.     pop    cx
  837.     loop    pntchk0            ; and try a few more times
  838.                     ; get here when printer is not ready
  839. pntchk2:pop    ax
  840.     pop    cx
  841.     pop    dx
  842.     stc                ; say printer not ready
  843.     ret
  844. pntchk3:pop    ax
  845.     pop    cx
  846.     pop    dx
  847.     clc                ; say printer is ready
  848.     ret
  849. pntchk    endp
  850.  
  851.  
  852. prnopen    proc    near
  853.     push    ax
  854.     push    bx
  855.     push    cx
  856.     push    dx
  857.     mov    prnhand,4        ; preset default handle
  858.     mov    dx,offset prnname    ; name of disk file, from mssset
  859.     mov    ax,dx            ; where isfile wants name ptr
  860.     call    isfile            ; what kind of file is this?
  861.     jc    prnop3            ; c = no such file, create it
  862.     test    byte ptr filtst.dta+21,1fh ; file attributes, ok to write?
  863.     jnz    prnop2            ; nz = no
  864.     mov    al,1            ; writing
  865.     mov    ah,open2        ; open existing file
  866.     int    dos
  867.     jc    prnop2            ; c = failure
  868.     mov    prnhand,ax        ; save file handle
  869.     mov    bx,ax            ; handle for DOS
  870.     mov    ah,ioctl
  871.     mov    al,0            ; get info
  872.     int    dos
  873.     or    dl,20h            ; turn on binary mode
  874.     xor    dh,dh
  875.     mov    ah,ioctl
  876.     mov    al,1            ; set info
  877.     int    dos
  878.     mov    cx,0ffffh        ; setup file pointer
  879.     mov    dx,-1            ; and offset
  880.     mov    al,2            ; move to eof minus one byte
  881.     mov    ah,lseek        ; seek the end
  882.     int    dos
  883.     pop    dx
  884.     pop    cx
  885.     pop    bx
  886.     pop    ax
  887.     clc
  888.     ret
  889. prnop2:    stc
  890.     ret
  891. prnop3:    test    filtst.fstat,80h    ; access problem?
  892.     jnz    prnop2            ; nz = yes
  893.     mov    ah,creat2        ; file did not exist
  894.     mov    cx,20h            ; attributes, archive bit
  895.     int    dos
  896.     mov    prnhand,ax        ; save file handle
  897.     pop    dx
  898.     pop    cx
  899.     pop    bx
  900.     pop    ax
  901.     ret                ; may have carry set
  902. prnopen    endp
  903.  
  904. ; worker: copy line from si to di, first removing trailing spaces, second
  905. ; parsing out curly braced strings, then third converting \{b##} in strings
  906. ; to binary numbers. Returns carry set if error; else carry clear, with byte
  907. ; count in cx. Braces are optional but must occur in pairs.
  908. ; Items which cannot be converted to legal numbers are copied verbatium
  909. ; to the output string (ex: \{c}  is copied as \{c}  but \{x0d} is hex 0dh).
  910. cnvlin    proc    near
  911.     push    ax
  912.     push    si            ; source ptr
  913.     push    di            ; destination ptr
  914.     push    es            ; end of save regs
  915.     push    ds            ; move ds into es
  916.     pop    es            ; use data segment for es:di
  917.     call    cnvstr            ; trim trailing, parse curly braces
  918.     xor    cx,cx            ; initialize returned byte count
  919. cnvln1:    cmp    byte ptr [si],0        ; at end of string?
  920.     je    cnvln2            ; e = yes, exit
  921.     call    katoi            ; read char, convert ascii to binary
  922.     cld
  923.     stosb                ; save the char
  924.     inc    cx            ; and count it
  925.     or    ah,ah            ; is returned number > 255?
  926.     jz    cnvln1            ; z = no, do more chars
  927.     push    ax
  928.     stosb                ; save high order byte next
  929.     pop    ax
  930.     inc    cx
  931.     jmp    short cnvln1        ; do more chars
  932. cnvln2:    mov    byte ptr [di],0        ; plant terminator
  933.     clc                ; clear c bit, success
  934.     pop    es            ; restore regs
  935.     pop    di            ; destination ptr
  936.     pop    si            ; source ptr
  937.     pop    ax
  938.     ret
  939. cnvlin    endp
  940.  
  941. ; Convert string by first remove trailing spaces and then removing surrounding
  942. ; curly brace delimiter pair. Converts text in place.
  943. ; Enter with source ptr in si.
  944. ; Preserves all registers, uses byte tmp. 9 Oct 1987 [jrd]
  945. cnvstr    proc    near
  946.     push    ax
  947.     push    cx
  948.     push    dx
  949.     push    si            ; save start of source string
  950.     push    di
  951.     push    es
  952.                     ; 1. Trim trailing spaces
  953.     mov    dx,si            ; source address
  954.     call    strlen            ; get current length to cx
  955.     jcxz    cnvst4            ; z = nothing there
  956.     mov    di,si            ; set di to source address
  957.     add    di,cx            ; start at end of string
  958.     dec    di            ; ignore terminator
  959.     mov    al,spc            ; scan while spaces
  960.     push    ds
  961.     pop    es            ; set es to data segment
  962.     std                ; search backward
  963.     repe    scasb            ; scan off trailing spaces
  964.     mov    byte ptr [di+2],0    ; terminate string after last text
  965.     cld
  966.     mov    di,si            ; set destination address to source
  967.                     ; 2. Parse off curly brace delimiters
  968.     cmp    byte ptr [si],braceop    ; opening brace?
  969.     jne    cnvst4            ; ne = no, ignore brace-matching code
  970.     inc    si            ; skip opening brace
  971.     mov    dl,braceop        ; opening brace (we count them up)
  972.     mov    dh,bracecl        ; closing brace (we count them down)
  973.     mov    tmp,1            ; we are at brace level 1
  974. cnvst1:    cld                ; search forward
  975.     lodsb                ; read a string char
  976.     stosb                ; store char (skips opening brace)
  977.     or    al,al            ; at end of string?
  978.     jz    cnvst4            ; z = yes, we are done
  979.     cmp    al,dl            ; an opening brace?
  980.     jne    cnvst2            ; ne = no
  981.     inc    tmp            ; yes, increment brace level
  982.     jmp    short cnvst1        ;  and continue scanning
  983.  
  984. cnvst2:    cmp    al,dh            ; closing brace?
  985.     jne    cnvst1            ; ne = no, continue scanning
  986.     dec    tmp            ; yes, decrement brace level
  987.     cmp    byte ptr [si],0        ; have we just read the last char?
  988.     jne    cnvst3            ; no, continue scanning
  989.     mov    tmp,0            ; yes, this is the closing brace
  990. cnvst3:    cmp    tmp,0            ; at level 0?
  991.     jne    cnvst1            ; ne = no, #opening > #closing braces
  992.     mov    byte ptr [di-1],0    ; plant terminator on closing brace
  993.  
  994. cnvst4:    pop    es            ; recover original registers
  995.     pop    di
  996.     pop    si
  997.     pop    dx
  998.     pop    cx
  999.     pop    ax
  1000.     ret
  1001. cnvstr    endp
  1002.  
  1003. ; Convert ascii strings of the form "\{bnnn}" to a binary word in ax.
  1004. ; The braces are optional but must occur in pairs. Numeric base indicator "b"
  1005. ; is O or o or X or x or D or d or missing, for octal, hex, or decimal (def).
  1006. ; Enter with si pointing at "\".
  1007. ; Returns binary value in ax with carry clear and si to right of "}" or at
  1008. ; terminating non-numeric char if successful; otherwise, a failure,
  1009. ; return carry set with si = entry value + 1 and first read char in al.
  1010.  
  1011. katoi    proc    near
  1012.     cld
  1013.     lodsb                ; get first char
  1014.     xor    ah,ah            ; clear high order field
  1015.     push    cx            ; save working reg
  1016.     push    si            ; save entry si+1
  1017.     push    bx
  1018.     push    ax            ; save read char
  1019.     or    al,al            ; end of text?
  1020.     jz    katoi1a            ; z = yes, exit failure
  1021.     cmp    al,'\'            ; escape char?
  1022.     je    katoi1b            ; e = yes
  1023. katoi1a:jmp    katoix            ; common jump point to exit failure
  1024. katoi1b:lodsb                ; get next char, maybe brace
  1025.     or    al,al            ; premature end?
  1026.     jz    katoi1a            ; z = yes, exit failure
  1027.     xor    bx,bx            ; no conv yet, assume no opening brace
  1028.     cmp    al,braceop        ; opening brace?
  1029.     jne    katoi2            ; ne = no, have number or base
  1030.     mov    bl,bracecl        ; remember a closing brace is needed
  1031.     lodsb                ; get number base, if any
  1032. katoi2:    xor    cx,cx            ; temporary place for binary value
  1033.     mov    nbase,10        ; assume decimal numbers
  1034.     or    al,al            ; premature end?
  1035.     jz    katoix            ; z = yes, exit failure
  1036.     cmp    al,'a'            ; lower case?
  1037.     jb    katoi3            ; b = no
  1038.     cmp    al,'z'            ; in range of lower case?
  1039.     ja    katoi3            ; a = no
  1040.     and    al,5fh            ; map to upper case
  1041. katoi3:    cmp    al,'O'            ; octal?
  1042.     jne    katoi4            ; ne = no
  1043.     mov    nbase,8            ; set number base
  1044.     jmp    short katoi6
  1045. katoi4:    cmp    al,'X'            ; hex?
  1046.     jne    katoi5            ; ne = no
  1047.     mov    nbase,16
  1048.     jmp    short katoi6
  1049. katoi5:    cmp    al,'D'            ; decimal?
  1050.     jne    katoi7            ; ne = no base char, assume decimal
  1051.     mov    nbase,10
  1052. katoi6:    lodsb                ; get a digit
  1053. katoi7:    or    al,al            ; premature end?
  1054.     jz    katoi8a            ; z = yes, use it as a normal end
  1055.     cmp    al,bl            ; closing brace?
  1056.     je    katoi9            ; e = yes
  1057.     call    cnvdig            ; convert ascii to binary digit
  1058.     jc    katoi8            ; c = cannot convert
  1059.     inc    bh            ; say we did a successful conversion
  1060.     xor    ah,ah            ; clear high order value
  1061.     push    ax            ; save this byte's value
  1062.     xchg    ax,cx            ; put binary summation in ax
  1063.     mul    nbase            ; scale up current sum
  1064.     xchg    ax,cx            ; put binary back in cx
  1065.     pop    ax            ; recover binary digit
  1066.     add    cx,ax            ; form running sum
  1067.     jc    katoix            ; c = overflow error, exit
  1068.     or    dx,dx            ; overflow?
  1069.     jnz    katoix            ; nz = yes, exit with error
  1070.     jmp    short katoi6        ; get more
  1071.  
  1072. katoi8:    or    bl,bl            ; closing brace needed?
  1073.     jnz    katoix            ; nz = yes, but not found
  1074. katoi8a:dec    si            ; backup to reread terminator
  1075. katoi9:    or    bh,bh            ; did we do any conversion?
  1076.     jz    katoix            ; z = no, exit failure
  1077.     pop    ax            ; throw away old saved ax
  1078.     pop    bx            ; restore bx
  1079.     pop    ax            ; throw away starting si, keep current
  1080.     mov    ax,cx            ; return final value in ax
  1081.     pop    cx            ; restore old cx
  1082.     clc                ; clear carry for success
  1083.     ret
  1084. katoix:    pop    ax            ; restore first read al
  1085.     pop    bx
  1086.     pop    si            ; restore start value + 1
  1087.     pop    cx            ; restore old cx
  1088.     stc                ; set carry for failure
  1089.     ret
  1090. katoi    endp
  1091.  
  1092. cnvdig    proc    near            ; convert ascii code in al to binary
  1093.     push    cx            ; return carry set if cannot
  1094.     push    es            ; nbase has numeric base
  1095.     push    di
  1096.     push    ax
  1097.     cmp    al,'a'            ; lower case?
  1098.     jb    cnvdig1            ; b = no
  1099.     cmp    al,'f'            ; highest hex digit
  1100.     ja    cnvdigx            ; a = illegal symbol
  1101.     sub    al,'a'-'A'        ; convert 'a' to 'f' to upper case
  1102. cnvdig1:mov    di,offset numset    ; set of legal number symbols
  1103.     mov    cx,nbase        ; number of legal symbols in this base
  1104.     cmp    cx,cx            ; preset z flag
  1105.     push    ds
  1106.     pop    es            ; point es at data segment
  1107.     cld                ; scan forward
  1108.     repne    scasb            ; find character in set
  1109.     jne    cnvdigx            ; ne = not found
  1110.     inc    cx            ; offset auto-dec of repne scasb above
  1111.     sub    cx,nbase        ; counted off minus length
  1112.     neg    cx            ; two's complement = final value
  1113.     pop    ax            ; saved ax
  1114.     mov    ax,cx            ; return binary in al
  1115.     clc                ; c clear for success
  1116.     jmp    short cnvdixx        ; exit
  1117. cnvdigx:stc                ; c set for failure
  1118.     pop    ax
  1119. cnvdixx:pop    di
  1120.     pop    es
  1121.     pop    cx
  1122.     ret
  1123. cnvdig    endp    
  1124.  
  1125. decout    proc    near        ; display decimal number in ax
  1126.     push    ax
  1127.     push    cx
  1128.     push    dx
  1129.     mov    cx,10        ; set the numeric base
  1130.     call    valout        ; convert and output value
  1131.     pop    dx
  1132.     pop    cx
  1133.     pop    ax
  1134.     ret
  1135. decout    endp
  1136.  
  1137. valout    proc    near        ; output number in ax using base in cx
  1138.                 ; corrupts ax and dx
  1139.     xor    dx,dx        ; clear high word of numerator
  1140.     div    cx        ; (ax / cx), remainder = dx, quotient = ax
  1141.     push    dx        ; save remainder for outputting later
  1142.     or    ax,ax        ; any quotient left?
  1143.     jz    valout1        ; z = no
  1144.     call    valout        ; yes, recurse
  1145. valout1:pop    dx        ; get remainder
  1146.     add    dl,'0'        ; make digit printable
  1147.     cmp    dl,'9'        ; above 9?
  1148.     jbe    valout2        ; be = no
  1149.     add    dl,'A'-1-'9'    ; use 'A'--'F' for values above 9
  1150. valout2:mov    ah,conout
  1151.     int    dos
  1152.     ret
  1153. valout    endp
  1154.  
  1155. ; Convert input in buffer pointed to by SI to real number which is returned
  1156. ; in DX:AX.  Enter with string size in AH.
  1157. ; Return carry set on failure, carry clear on success.
  1158. ATOI    PROC    NEAR
  1159.     xor    bx,bx        ; high order of this stays 0
  1160.     mov    tmp,bl        ; no input yet
  1161.     mov    cl,ah        ; number of chars of input
  1162.     xor    ch,ch        ; size of string
  1163.     xor    ax,ax        ; init sum
  1164.     xor    dx,dx        ; high order part of sum
  1165.     cld
  1166. atoi0:    jcxz    atoi4        ; Fail on no input
  1167.     mov    bl,[si]        ; get an input char
  1168.     inc    si
  1169.     dec    cx        ; count number remaining
  1170.     cmp    bl,' '        ; leading space?
  1171.     je    atoi0        ; e = yes, skip it
  1172.     cmp    bl,','        ; comma separator?
  1173.     je    atoi0        ; e = yes, skip it
  1174.     dec    si        ; back up source pointer for reread below
  1175.     inc    cx        ; and readjust byte counter
  1176. atoi1:    mov    bl,[si]        ; get a new char
  1177.     inc    si
  1178.     cmp    bl,'9'        ; check range for '0' to '9'
  1179.     ja    atoi2        ; above '9'
  1180.     cmp    bl,'0'
  1181.     jb    atoi2        ; below '0'
  1182.     sub    bl,'0'        ; take away ascii bias
  1183.     push    bx        ; save digit and high null
  1184.     shl    ax,1
  1185.     rcl    dx,1        ; current sum * 2
  1186.     push    dx
  1187.     push    ax        ; save it
  1188.     shl    ax,1
  1189.     rcl    dx,1
  1190.     shl    ax,1
  1191.     rcl    dx,1        ; times * 4 more
  1192.     pop    bx        ; low * 2
  1193.     add    bx,ax
  1194.     mov    ax,bx        ; low order * 10
  1195.     pop    bx
  1196.     adc    bx,dx
  1197.     mov    dx,bx        ; high order * 10
  1198.     pop    bx        ; new digit and high null
  1199.     add    ax,bx        ; plus new digit
  1200.     adc    dx,0
  1201.     mov    tmp,1        ; say have sum being computed
  1202.     loop    atoi1
  1203.     inc    si        ; inc for dec below
  1204. atoi2:    dec    si        ; point at terminator
  1205.     cmp    tmp,0        ; were any digits discovered?
  1206.     je    atoi4        ; e = no, fail
  1207.     clc            ; success
  1208.     ret
  1209. atoi4:    mov    dx,offset erms25 ; Input must be numeric
  1210.     stc            ; failure
  1211.     ret
  1212. ATOI    ENDP
  1213.  
  1214. ; Write binary number in AX as decimal asciiz to buffer pointer DI.
  1215. dec2di    proc    near        ; output number in ax using base in cx
  1216.     push    ax
  1217.     push    cx
  1218.     push    dx
  1219.     mov    cx,10
  1220.     call    dec2di1        ; recursive worker
  1221.     pop    dx
  1222.     pop    cx
  1223.     pop    ax
  1224.     ret
  1225.  
  1226. dec2di1:xor    dx,dx        ; clear high word of numerator
  1227.     div    cx        ; (ax / cx), remainder = dx, quotient = ax
  1228.     push    dx        ; save remainder for outputting later
  1229.     or    ax,ax        ; any quotient left?
  1230.     jz    dec2di2        ; z = no
  1231.     call    dec2di1        ; yes, recurse
  1232. dec2di2:pop    dx        ; get remainder
  1233.     add    dl,'0'        ; make digit printable
  1234.     mov    [di],dl        ; store char in buffer
  1235.     inc    di
  1236.     mov    byte ptr[di],0    ; add terminator
  1237.     ret
  1238. dec2di    endp
  1239.  
  1240.  
  1241. ; OPEN { READ | WRITE | APPEND } filespec
  1242. vfopen    proc    near
  1243.     mov    ah,cmkey        ; get READ/WRITE/APPEND keyword
  1244.     mov    dx,offset opntab    ; keyword table
  1245.     xor    bx,bx            ; help
  1246.     call    comnd
  1247.     jc    vfopen1            ; c = failed
  1248.     mov    temp,bx
  1249.     mov    ah,cmword        ; read filespec
  1250.     mov    dx,offset rdbuf        ; buffer for filename
  1251.     mov    bx,offset vfophlp    ; help
  1252.     call    comnd
  1253.     jc    vfopen1            ; c = failed
  1254.     mov    ah,cmeol        ; get end of line confirmation
  1255.     call    comnd
  1256.     jnc    vfopen2
  1257.     mov    kstatus,ksgen        ; general cmd failure status
  1258. vfopen1:ret                ; error return, carry set
  1259.  
  1260. vfopen2:mov    kstatus,kssuc        ; assume success status
  1261.     mov    dx,offset rdbuf        ; filename, asiiz
  1262.     mov    bx,temp            ; kind of open
  1263.     cmp    bx,1            ; open for reading?
  1264.     jne    vfopen4            ; ne = no
  1265.                     ; OPEN READ
  1266.     cmp    vfrhandle,0        ; is it open now?
  1267.     jge    vfopen8            ; ge = yes, complain
  1268.     mov    ah,open2        ; file open
  1269.     xor    al,al            ; 0 = open readonly
  1270.     cmp    dosnum,300h        ; at or above DOS 3?
  1271.     jb    vfopen3            ; b = no, so no shared access
  1272.     or    al,40h            ; open readonly, deny none
  1273. vfopen3:int    dos
  1274.     jc    vfopen9            ; c = failed to open the file
  1275.     mov    vfrhandle,ax        ; save file handle
  1276.     clc
  1277.     ret
  1278.                     ; OPEN WRITE or APPEND
  1279. vfopen4:cmp    vfwhandle,0        ; is it open now?
  1280.     jge    vfopen8            ; ge = yes, complain
  1281.     mov    ax,dx            ; filename for isfile
  1282.     call    isfile        ; check for read-only/system/vol-label/dir
  1283.     jc    vfopen7            ; c = file does not exist
  1284.     test    byte ptr filtst.dta+21,1fh    ; the no-no file attributes
  1285.     jnz    vfopen9            ; nz = do not write over one of these
  1286. vfopen5:test    filtst.fstat,80h    ; access problem?
  1287.     jnz    vfopen9            ; nz = yes, quit here
  1288.     test    byte ptr filtst.dta+21,1bh    ; r/o, hidden, volume label?
  1289.     jnz    vfopen9            ; we won't touch these
  1290.     mov    ah,open2           ; open existing file (usually a device)
  1291.     mov    al,1+1            ; open for writing
  1292.     int    dos
  1293.     jc    vfopen9            ; carry set means can't open
  1294.     mov    vfwhandle,ax        ; remember file handle
  1295.     mov    bx,ax            ; file handle for lseek
  1296.     xor    cx,cx
  1297.     xor    dx,dx            ; cx:dx = displacment
  1298.     xor    al,al            ; 0 means from start of file
  1299.     cmp    temp,2            ; WRITE? means from start of file
  1300.     je    vfopen6            ; e = yes, else APPEND
  1301.     mov    al,2            ; move to eof
  1302. vfopen6:mov    ah,lseek        ; seek the place
  1303.     int    dos
  1304.     clc
  1305.     ret
  1306.  
  1307. vfopen7:cmp    temp,1            ; READ?
  1308.     je    vfopen9            ; e = yes, should not be here
  1309.     mov    ah,creat2        ; create file
  1310.     xor    cx,cx            ; 0 = attributes bits
  1311.     int    dos
  1312.     jc    vfopen9            ; c = failed
  1313.     mov    vfwhandle,ax        ; save file handle
  1314.     clc                ; carry clear for success
  1315.     ret
  1316.  
  1317. vfopen8:mov    dx,offset vfoptwice    ; trying to reopen a file
  1318.     mov    ah,prstr
  1319.     int    dos
  1320.     mov    kstatus,kstake        ; Take file failure status
  1321.     stc
  1322.     ret
  1323. vfopen9:mov    dx,offset vfopbad    ; can't open, complain
  1324.     mov    ah,prstr
  1325.     int    dos
  1326.     mov    dx,offset rdbuf        ; filename
  1327.     call    prtasz
  1328.     mov    kstatus,kstake        ; Take file failure status
  1329.     stc
  1330.     ret
  1331. vfopen    endp
  1332.  
  1333. ; CLOSE {READ-FILE | WRITE-FILE}
  1334. vfclose    proc    near
  1335.     mov    tmp,al            ; remember kind (1=READ, 2=WRITE)
  1336.     mov    bx,vfrhandle        ; READ FILE handle
  1337.     cmp    al,1            ; READ-FILE?
  1338.     je    vfclos1            ; e = yes
  1339.     cmp    al,2            ; WRITE-FILE?
  1340.     jne    vfclos3            ; ne = no, a mistake
  1341.     mov    bx,vfwhandle        ; write handle
  1342.     or    bx,bx
  1343.     jl    vfclos3            ; l = invalid handle
  1344.     mov    dx,offset rdbuf
  1345.     xor    cx,cx            ; zero length
  1346.     push    bx            ; save handle
  1347.     mov    ah,write2        ; set file high water mark
  1348.     int    dos
  1349.     pop    bx
  1350. vfclos1:or    bx,bx
  1351.     jl    vfclos3            ; l = invalid handle
  1352.     mov    kstatus,kssuc        ; success status thus far
  1353.     mov    ah,close2        ; close file
  1354.     int    dos
  1355.     jc    vfclos4            ; c = error
  1356.     cmp    tmp,1            ; READ?
  1357.     jne    vfclos2            ; ne = no, WRITE
  1358.     mov    vfrhandle,-1        ; declare READ handle to be invalid
  1359.     clc
  1360.     ret
  1361. vfclos2:mov    vfwhandle,-1        ; declare WRITE handle to be invalid
  1362.     clc
  1363.     ret
  1364. vfclos4:mov    ah,prstr
  1365.     mov    dx,offset vfclbad    ; complain
  1366.     int    dos
  1367. vfclos3:mov    kstatus,ksgen        ; general cmd failure status
  1368.     stc
  1369.     ret
  1370. vfclose    endp
  1371.  
  1372. ; READ-FILE variable name
  1373. vfread    proc    near
  1374.     mov    comand.cmper,1        ; do not react to '\%' in macro name
  1375.     mov    ah,cmword
  1376.     mov    dx,offset rdbuf+2    ; buffer for macro name
  1377.     mov    word ptr rdbuf,0
  1378.     mov    bx,offset vfrdmsg
  1379.     call    comnd            ; get macro name
  1380.     jnc    vfread1            ; nc = success
  1381.     mov    kstatus,ksgen        ; general cmd failure status
  1382.     ret                ; failure
  1383. vfread1:or    ax,ax            ; null entry?
  1384.     jnz    vfread2            ; nz = no
  1385.     mov    dx,offset vfrdbad    ; more parameters needed
  1386.     mov    ah,prstr
  1387.     int    dos
  1388.     mov    kstatus,ksgen        ; general cmd failure status
  1389.     stc
  1390.     ret
  1391.  
  1392. vfread2:push    ax
  1393.     mov    ah,cmeol        ; get command confirmation
  1394.     call    comnd
  1395.     pop    ax            ; ax is variable length
  1396.     jc    vfreadx            ; c = failed
  1397.     mov    cx,cmdblen        ; length of rdbuf
  1398.     sub    cx,ax            ; minus macro name
  1399.     dec    cx            ; minus space separator
  1400.     mov    temp,0            ; leading whitespace and comment flgs
  1401.     mov    di,offset rdbuf+2    ; destination buffer
  1402.     add    di,ax            ; plus variable name
  1403.     mov    byte ptr [di],' '    ; space separator
  1404.     inc    di            ; put definition here
  1405.     mov    bx,vfrhandle        ; READ FILE handle
  1406.     or    bx,bx            ; check for valid handle
  1407.     jge    vfread3            ; ge = valid
  1408.     mov    ah,prstr
  1409.     mov    dx,offset vfnofile    ; say no file
  1410.     int    dos
  1411. vfreadx:mov    kstatus,ksgen        ; general cmd failure status
  1412.     stc                ; failure return
  1413.     ret
  1414. vfread3:push    cx            ; read from file
  1415.     mov    kstatus,kssuc        ; assume success status
  1416.     mov    cx,1            ; read 1 char
  1417.     mov    dx,di            ; place here
  1418.     mov    byte ptr [di],0        ; insert terminator
  1419.     mov    ah,readf2
  1420.     int    dos
  1421.     pop    cx
  1422.     jc    vfreadx            ; c = read failure
  1423.     or    ax,ax            ; count of bytes read
  1424.     jz    vfread9            ; z means end of file
  1425.     mov    al,[di]            ; get the character
  1426.     cmp    flags.takflg,0        ; echo Take files?
  1427.     je    vfread3a        ; e = no
  1428.     push    ax
  1429.     mov    ah,conout
  1430.     mov    dl,al            ; echo character
  1431.     int    dos
  1432.     pop    ax
  1433. vfread3a:cmp    al,CR            ; CR?
  1434.     je    vfread7            ; e = yes, ignore it
  1435.     cmp    al,LF            ; LF?
  1436.     je    vfread8            ; e = yes, exit
  1437.     cmp    al,';'            ; start of comment?
  1438.     jne    vfread4            ; ne = no
  1439.     mov    byte ptr temp+1,1    ; say comment has started
  1440. vfread4:cmp    byte ptr temp+1,0    ; seen comment semicolon yet?
  1441.     jne    vfread7            ; ne = yes, do not store comment
  1442.     cmp    byte ptr temp,0        ; seen non-spacing char yet?
  1443.     jne    vfread6            ; ne = yes
  1444.     cmp    al,' '            ; is this a space?
  1445.     je    vfread7            ; e = yes, skip it
  1446.     cmp    al,TAB            ; or a tab?
  1447.     je    vfread7            ; e = yes, skip it
  1448.     mov    byte ptr temp,1        ; say have seen non-spacing char
  1449.  
  1450. vfread6:inc    di            ; next storage cell
  1451. vfread7:loop    vfread3            ; loop til end of line
  1452.  
  1453. vfread8:cmp    byte ptr [di-1],'-'    ; last printable is line-continuation?
  1454.     jne    vfread10        ; ne = no, use this line as-is
  1455.     dec    di            ; point to hyphen
  1456.     mov    cx,offset rdbuf+cmdblen    ; end of rdbuf
  1457.     sub    cx,di            ; minus where we are now
  1458.     jle    vfread10        ; le = no space remaining
  1459.     mov    temp,0            ; leading whitespace and comment flgs
  1460.     jmp    vfread3            ; read another line
  1461.  
  1462. vfread9:mov    kstatus,ksgen        ; EOF, general command failure status
  1463.  
  1464. vfread10:cmp    flags.takflg,0        ; echo Take files?
  1465.     je    vfread11        ; e = no
  1466.     mov    ah,prstr
  1467.     mov    dx,offset crlf        ; for last displayed line
  1468.     int    dos
  1469.  
  1470. vfread11:mov    byte ptr [di],0        ; insert final terminator
  1471.     mov    dx,offset rdbuf+2    ; start counting from here
  1472.     push    kstatus            ; preserve status from above work
  1473.     call    strlen            ; cx becomes length
  1474.     call    dodecom            ; create the variable
  1475.     pop    kstatus            ; recover reading status
  1476.     jc    vfread12        ; c = failure
  1477.     ret
  1478. vfread12:mov    kstatus,ksgen        ; general command failure status
  1479.     mov    ah,prstr
  1480.     mov    dx,offset vfrbad    ; say error while reading
  1481.     int    dos
  1482.     stc
  1483.     ret
  1484. vfread    endp
  1485.  
  1486. ; WRITE {FILE or log} text
  1487. Write    proc    near
  1488.     mov    ah,cmkey        ; get kind of log file
  1489.     mov    dx,offset writetab    ; table of possibilities
  1490.     xor    bx,bx            ; help, when we get there
  1491.     call    comnd
  1492.     jnc    write1            ; nc = success
  1493.     mov    kstatus,ksgen        ; general cmd failure status
  1494.     ret
  1495. write1:    mov    temp,bx            ; save log file kind
  1496.     mov    ah,cmline        ; get string to be written
  1497.     mov    bx,offset rdbuf        ; where to put text
  1498.     mov    dx,offset msgtxt    ; help
  1499.     call    comnd
  1500.     mov    ah,cmeol
  1501.     call    comnd
  1502.     jnc    wpkt0
  1503.     mov    kstatus,ksgen        ; general cmd failure status
  1504.     ret                ; c = failure
  1505. wpkt0:    mov    kstatus,kssuc        ; success status thus far
  1506.     mov    si,offset rdbuf        ; start of text in buffer
  1507.     mov    di,si            ; convert in-place, to asciiz
  1508.     call    cnvlin
  1509.     mov    bx,temp            ; log file kind
  1510.     mov    si,offset rdbuf
  1511.     mov    dx,si
  1512.     call    strlen
  1513.     jcxz    wpkt2            ; z = no chars to write
  1514.     cmp    bx,logpkt        ; Packet log?
  1515.     jne    wses1            ; ne = no
  1516. wpkt1:    lodsb                ; get byte to al
  1517.     call    pktcpt            ; write to packet log
  1518.     loop    wpkt1
  1519. wpkt2:    clc                ; say success
  1520.     ret
  1521.  
  1522. wses1:    cmp    bx,logses        ; Session log?
  1523.     jne    wtrn1            ; ne = no
  1524. wses2:    lodsb                ; get byte to al
  1525.     call    cptchr            ; write to log
  1526.     loop    wses2            ; do cx chars
  1527.     clc                ; say success
  1528.     ret
  1529.  
  1530. wtrn1:    cmp    bx,logtrn        ; Transaction log?
  1531.     jne    wtrn2            ; ne = no
  1532.     mov    bx,tloghnd        ; file handle
  1533.     jmp    short wtrn4
  1534.  
  1535. wtrn2:    cmp    bx,80h            ; WRITE SCREEN?
  1536.     jne    wtrn3            ; ne = no
  1537.     xor    bx,bx            ; handle is stdout
  1538.     jmp    short wtrn4
  1539.  
  1540. wtrn3:    cmp    bx,4002h        ; WRITE FILE?
  1541.     jne    wtrn5            ; ne = no, forget this
  1542.     mov    bx,vfwhandle        ; handle
  1543.  
  1544. wtrn4:    or    bx,bx            ; is handle valid?
  1545.     jl    wtrn5            ; l = no
  1546.     mov    ah,write2        ; write to file handle in bx
  1547.     int    dos
  1548.     jc    wtrn4a            ; c = failure
  1549.     ret
  1550. wtrn4a:    mov    ah,prstr
  1551.     mov    dx,offset vfwbad    ; say error while writing
  1552.     int    dos
  1553.     mov    kstatus,ksgen
  1554.     stc
  1555.     ret
  1556. wtrn5:    mov    kstatus,ksgen        ; general cmd failure status
  1557.     mov    ah,prstr
  1558.     mov    dx,offset vfnofile    ; say no file
  1559.     int    dos
  1560.     stc
  1561.     ret
  1562. write    endp
  1563. code    ends 
  1564.     end
  1565.