home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msvp98b1.lzh / MSSTER.ASM < prev    next >
Assembly Source File  |  1993-05-14  |  44KB  |  1,485 lines

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