home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mskermit / msster.asm < prev    next >
Assembly Source File  |  2020-01-01  |  79KB  |  2,734 lines

  1.      NAME    msster
  2. ; File MSSTER.ASM
  3.     include mssdef.h
  4. ;    Copyright (C) 1982, 1997, Trustees of Columbia University in the 
  5. ;    City of New York.  The MS-DOS Kermit software may not be, in whole 
  6. ;    or in part, licensed or sold for profit as a software product itself,
  7. ;    nor may it be included in or distributed with commercial products
  8. ;    or otherwise distributed by commercial concerns to their clients 
  9. ;    or customers without written permission of the Office of Kermit 
  10. ;    Development and Distribution, Columbia University.  This copyright 
  11. ;    notice must not be removed, altered, or obscured.
  12. ;
  13. ; Edit history
  14. ; 12 Jan 1995 version 3.14
  15. ; Last edit
  16. ; 12 Jan 1995
  17.  
  18.     public    clscpt, defkey, clscpi, ploghnd, sloghnd, tloghnd
  19.     public  dopar, shokey, cptchr, pktcpt, targ, replay, repflg
  20.     public    kbdflg, shkadr, telnet, ttyact, write, dec2di, caplft
  21.     public    cnvlin,  decout, valout, cnvstr
  22.     public    pntchr, pntflsh, pntchk, prnhand, prnopen
  23.     public    vfopen, vfread, ldiv, lmul, lgcd, atoi, atoibyte
  24.     public  domath, domath_ptr, domath_cnt, domath_msg
  25.     public    atoi_cnt, atoi_err, tod2secs
  26.  
  27. braceop    equ    7bh            ; opening curly brace
  28. bracecl    equ    7dh            ; closing curly brace
  29.  
  30. data     segment
  31.     extrn    flags:byte, trans:byte, diskio:byte, portval:word
  32.     extrn    rdbuf:byte, dosnum:word, filtst:byte, prnname:byte
  33.     extrn    comand:byte, kstatus:word, flowon:byte, flowoff:byte
  34.     extrn    cardet:byte
  35. ifndef    no_terminal
  36.     extrn    anspflg:byte
  37. endif    ; no_terminal
  38.  
  39. targ    termarg    <0,1,cptchr,0,parnon>
  40. crlf    db      cr,lf,'$'
  41. tmsg1    db    cr,lf,'(Connecting to host, type $' 
  42. tmsg3    db    ' C to return to PC)',cr,lf,cr,lf,cr,lf,'$'
  43. erms21    db    cr,lf,'?Cannot start the connection.$'
  44. erms25    db    cr,lf,'?Input must be numeric$' 
  45. erms22    db    cr,lf,'?No open logging file$'
  46. erms23    db    '*** Error writing session log, suspending capture ***$'
  47. erms24    db    cr,lf,'?Error writing Packet log$'
  48. erms26    db    ' *** PRINTER IS NOT READY ***  press R to retry'
  49.     db    ' or D to discard printing:  $'
  50. erms27    db    cr,lf
  51.     db    '? Carrier signal not detected on this serial port.'
  52.     db    cr,lf
  53.     db    '  Use the DIAL command, SET CARRIER OFF, or check your modem.$'
  54.  
  55. esctl    db    'Control-$'
  56. repflg    db    0        ; REPLAY or SET TERM REPLAY filespec flag
  57. reperr    db    cr,lf,'?File not found$'    ; for REPLAY command
  58. noterm    db    cr,lf,'Connect mode is not built into this Kermit$'
  59. vfopbad    db    cr,lf,'?Cannot open file $'    ; filename follows
  60. vfclbad    db    cr,lf,'?Cannot close file$'
  61. vfoptwice db    cr,lf,'?File is already open$'
  62. vfnofile db    cr,lf,'?File is not open$'
  63. vfrbad    db    cr,lf,'?Error while reading file$'
  64. vfwbad    db    cr,lf,'?Error while writing file$'
  65. vfrdbad    db    cr,lf,'?more parameters are needed$'
  66. vfrhandle dw    -1            ; READ FILE handle (-1 = invalid)
  67. vfwhandle dw    -1            ; WRITE FILE handle
  68.  
  69. opntab    db    3            ; OPEN FILE table
  70.     mkeyw    'Read',1
  71.     mkeyw    'Write',2
  72.     mkeyw    'Append',3
  73.  
  74. inthlp db cr,lf,' ', 22 dup ('-'),' Special keys within Connect mode '
  75.        db    22 dup ('-')
  76.        db cr,lf,'                           numeric keypad keys:'
  77.        db cr,lf,'  Pg Up/Dn  roll screen vertically   Ctrl Pg Up/Dn  roll'
  78.        db    ' screen one line '
  79.        db cr,lf,'  Home/End  roll to start/end screen Ctrl End screen dump'
  80.        db cr,lf,'  - (minus) toggle status/mode line'
  81.        db cr,lf,'                           other key combinations:'
  82.        db cr,lf,'  Alt-b  send a BREAK                Alt-n  next active'
  83.        db    ' Telnet session'
  84.        db cr,lf,'  Alt-c  start Compose sequence      Alt-x  exit emulator'
  85.        db cr,lf,'  Alt-h  show this menu              Alt-z  network session'
  86.        db    ' hold'
  87.        db cr,lf,'  Alt-= or Alt-r  reset emulator     Alt--  toggle terminal'
  88.        db    ' type'
  89.        db cr,lf,'  Ctrl Prtscrn  toggle printing'
  90.        db cr,lf,'  Additional commands are escape character '
  91. inthlpc db '  '
  92.        db    ' followed by special characters.'
  93.        db cr,lf,' ',78 dup ('-')
  94.        db cr,lf,'  7n1 = SET TERM BYTE 7, SET PARITY NONE, 1 stop bit'
  95.        db cr,lf,'  8n1 = SET TERM BYTE 8, SET PARITY NONE, 1 stop bit'
  96.        db cr,lf,'  7e1 = SET PARITY EVEN, 1 stop bit   7s1 = SET PARITY SPACE'
  97.        db    ', 1 stop bit'
  98.        db cr,lf,'  7o1 = SET PARITY ODD,  1 stop bit   7m1 = SET PARITY MARK'
  99.        db    ',  1 stop bit'
  100.        db cr,lf,'  press a key to exit this menu'
  101.        db    0
  102.  
  103. intqry db cr,lf,' ',20 dup ('-'),' Single character commands active now ' 
  104.        db    20 dup ('-')
  105.        db cr,lf,'  ?  Show this menu                  F  Dump screen to file'
  106.        db cr,lf,'  C  Close the emulator              P  Push to DOS'
  107.        db cr,lf,'  S  Status of the connection        Q  Quit logging'
  108.        db cr,lf,'  M  Toggle mode line                R  Resume logging'
  109.        db cr,lf,'  B  Send a Break                    0  Send a null'
  110.        db cr,lf,'  L  Send a long 1.8 s Break         H  Hangup phone'
  111.        db cr,lf,'  A  Send Telnet "Are You There"     I  Send Telnet' 
  112.        db    ' "Interrupt Process"' 
  113.        db cr,lf,'  Typing the escape character '
  114. intqryc db '  '                    ; where escape char glyphs go
  115.        db    ' will send it to the host'
  116.        db cr,lf,'  press space bar to exit this menu'
  117.        db 0
  118.  
  119. intprm    db    'Command> $'
  120. intclet    db    'B','C','F','H','L'    ; single letter commands
  121.     db    'M','P','Q','R','S'    ; must parallel dispatch table intcjmp
  122.     db    '?','0','A','I'
  123. numlet    equ    $ - intclet        ; number of entries
  124.     even
  125. ifndef    no_terminal
  126. intcjmp    dw    intchb,intchc,intchf,intchh,intchl
  127.     dw    intchm,intchp,intchq,intchr,intchs
  128.     dw    intchu,intchn,intayt,inttip
  129. endif    ; no_terminal
  130.  
  131. prnhand    dw    4        ; printer file handle (4 = DOS default)
  132.  
  133.     even
  134. ploghnd    dw    -1        ; packet logging handle
  135. sloghnd    dw    -1        ; session logging handle
  136. tloghnd    dw    -1        ; transaction logging handle
  137.  
  138. clotab    db    6
  139.     mkeyw    'READ-FILE',4001h
  140.     mkeyw    'WRITE-FILE',4002h
  141.     mkeyw    'All-logs',logpkt+logses+logtrn
  142.     mkeyw    'Packets',logpkt
  143.     mkeyw    'Session',logses
  144.     mkeyw    'Transaction',logtrn
  145.  
  146. clseslog db    cr,lf,' Closing Session log$'
  147. clpktlog db    cr,lf,' Closing Packet log$'
  148. cltrnlog db    cr,lf,' Closing Transaction log$'
  149.  
  150. writetab db    5            ; Write command log file types
  151.     mkeyw    'FILE',4002h        ; FILE
  152.     mkeyw    'Packet',logpkt
  153.     mkeyw    'Screen',80h        ; unused value, to say screen
  154.     mkeyw    'Session',logses
  155.     mkeyw    'Transaction',logtrn
  156.  
  157. sttmsg    db    cr,lf,'Press space to continue ...$'
  158. kbdflg    db    0            ; non-zero means char here from Term
  159. ttyact    db    0            ; Connect mode active, if non-zero
  160. shkadr    dw    0            ; offset of replacement Show Key cmd
  161. nbase    dw    10            ; currently active number base
  162. temp    dw    0
  163. temp1    dw    0
  164. tmp    db    0
  165. tmp1    db    0
  166. tmpstring db    6 dup (0)        ; local string work buffer
  167. pktlft    dw    cptsiz        ; number free bytes left
  168. caplft    dw    cptsiz        ; number free bytes left
  169.  
  170. maxdepth equ    8            ; domath, parenthesis nesting depth
  171. listlen equ    6            ; domath, outstanding numbers and ops
  172. parendepth db    0            ; domath, depth of ()'s
  173. mathkind db    0            ; domath, math operator symbol, temp
  174. operators db    '()!~^*/%&+-|#@'    ; domath, math operator list
  175. operator_len equ $ - operators        ; domath, length of the list
  176. precedence db    6,6,5,4,3, 2,2,2,2,1, 1,1,1,1 ; domath, precedence of ops
  177. fevalst    struc        ; structure of demath work stacks, all on the stack
  178.   savebp    dw    0        ; where bp is pushed
  179.   numcnt    dw    0        ; count of values in numlist
  180.   numlist    dw listlen dup (0,0)    ; list of dword values
  181.   opcnt        dw    0        ; count of operators in oplist
  182.   oplist    dw  listlen dup (0)    ; list of pending operators
  183. fevalst    ends
  184. domath_ptr dw    0            ; ds:offset of domath input text
  185. domath_cnt dw    0            ; count of bytes in input text
  186. domath_msg dw    0            ; non-zero to allow error msgs
  187. matherr dw    0            ; non-zero = offset of error msg
  188. opmsg    db    '?too many math operators or too few values $'
  189. opmsg1    db    '?math operator missing or invalid $'
  190. opmsg2    db    '?unknown math symbol: $'
  191. opmsg3 db    '?math expression error $'
  192. opmsg4    db    '?parentheses nested too deeply $'
  193. atoibyte db    0            ; non-zero to say convert one char
  194. atoi_err db    0            ; atoi return error codes
  195. atoi_cnt dw    0            ; atoi, bytes supplied to/remaining
  196. data    ends
  197.  
  198. data1    segment
  199. rephlp    db    'name of file to playback$'
  200. clohlp    db    cr,lf,' READ-FILE or WRITE-FILE, or the following log files:'
  201.     db    cr,lf,' All-logs, Packets, Session, Transaction$'
  202. msgtxt    db    'text to be written$'
  203. vfophlp    db    'Filename$'
  204. vfrdmsg    db    'name of variable  into which to read a line from file$'
  205. pktbuf    db    cptsiz dup (0)    ; packet logging buffer
  206. pktbp    dw    pktbuf        ; buffer pointer to next free byte
  207. capbuf    db    cptsiz dup (0)    ; session logging buffer
  208. capbp    dw    capbuf        ; buffer pointer to next free byte
  209. prnbuf    db    cptsiz dup (0)    ; printer buffer
  210. pntptr    dw    prnbuf        ; pointer to next free byte
  211. data1    ends
  212.  
  213. code1    segment
  214.     extrn    iseof:far, strlen:far, prtasz:far, isfile:far
  215.     assume    cs:code1
  216. code1    ends
  217.  
  218. code    segment
  219.     extrn     comnd:near, outchr:near, stat0:near, pcwait:far
  220.     extrn    beep:near, puthlp:near, serhng:near, lnout:near
  221.     extrn    serini:near, serrst:near, sendbr:near, putmod:near
  222.     extrn    fpush:near,  sendbl:near, trnmod:near, dodecom:near
  223. ifndef    no_terminal
  224.     extrn    dumpscr:near,term:near
  225. endif    ; no_terminal
  226. flnout    proc    far
  227.     call    lnout
  228.     ret
  229. flnout    endp
  230.     assume    cs:code, ds:data, es:nothing
  231.  
  232. ; the show key command
  233. shokey    proc    near
  234.     cmp    shkadr,0        ; keyboard translator present?
  235.     je    shokey1            ; e = no, use regular routines
  236.     mov    bx,shkadr        ; get offset of replacement routine
  237.     jmp    bx            ; and execute it rather than us
  238. shokey1:clc
  239.     ret
  240. shokey    endp
  241. ; enter with ax/scan code to define, si/ pointer to definition, cx/ length
  242. ; of definition.  Defines it in definition table. Obsolete.
  243. defkey    proc    near
  244.     ret
  245. defkey    endp
  246.  
  247.  
  248. ; This is the CONNECT command
  249. ifdef    no_terminal
  250. TELNET     PROC    NEAR
  251.     mov    ah,cmeol
  252.     call    comnd            ; get a confirm
  253.     jnc    teln1            ; nc = success
  254.     ret
  255. teln1:    mov    ah,prstr
  256.     mov    dx,offset noterm
  257.     int    dos
  258.     clc
  259.     ret
  260. TELNET    ENDP
  261. endif    ; no_terminal
  262.  
  263. ifndef    no_terminal
  264. TELNET     PROC    NEAR
  265.     mov    ah,cmeol
  266.     call    comnd            ; get a confirm
  267.     jnc    teln1            ; nc = success
  268.     ret
  269. teln1:    cmp    repflg,0        ; REPLAY?
  270.     jne    teln1d            ; ne = yes
  271.     call    serini            ; ensure port is inited now
  272.     jnc    teln1a            ; nc = success
  273.     test    flags.remflg,dquiet    ; quiet display mode?
  274.     jnz    teln1b            ; nz = yes. Don't write to screen
  275.     mov    dx,offset erms21    ; say cannot start connection
  276.     mov    ah,prstr
  277.     int    dos
  278. teln1b:    or    kstatus,ksgen        ; general command failure
  279.     ret
  280. teln1a:    cmp    flags.comflg,'F'    ; Fossil port?
  281.     je    teln1c            ; e = yes
  282.     cmp    flags.comflg,'4'    ; using real or Bios serial ports?
  283.     ja    teln1d            ; a = no
  284. teln1c:    cmp    flags.carrier,0        ; want CD on now?
  285.     je    teln1d            ; e = no
  286.     test    cardet,80h        ; CD on?
  287.     jnz    teln1d            ; nz = yes
  288.     mov    ah,prstr        ; complain on screen
  289.     mov    dx,offset erms27
  290.     int    dos
  291.     stc                ; fail
  292.     ret
  293. teln1d:    cmp    flags.vtflg,0        ; emulating a terminal?
  294.     jne    teln2            ; ne= yes, no wait necessary
  295.     mov    ah,prstr
  296.     mov    dx,offset crlf        ; output a crlf
  297.     int    dos
  298.     call    domsg            ; reassure user
  299.     mov    ax,2000            ; two seconds
  300.     call    pcwait            ; pause
  301. teln2:    xor    al,al            ; initial flags
  302.     mov    ttyact,1        ; say telnet is active
  303.     cmp    flags.vtflg,0        ; emulating a terminal?
  304.     je    teln3            ; e = no, say mode line is to be off
  305.     cmp    flags.modflg,0        ; mode line enabled?
  306.     jne    tel010            ; ne = yes
  307. teln3:    or    al,modoff        ; no, make sure it stays off
  308.  
  309. tel010:    test    flags.debug,logses    ; debug mode?
  310.     jz    tel0            ; z = no, keep going
  311.     or    al,trnctl        ; yes, show control chars
  312. tel0:    cmp    flags.vtflg,0        ; emulating a terminal?
  313.     je    tel1            ; e = no
  314.     or    al,emheath        ; say emulating some kind of terminal
  315. tel1:    mov    bx,portval
  316.     cmp    [bx].ecoflg,0        ; echoing?
  317.     jz    tel2            ; z = no
  318.     or    al,lclecho        ; turn on local echo
  319. tel2:    mov    targ.flgs,al        ; store flags
  320.     mov    ah,flags.comflg        ; COMs port identifier
  321.     mov    targ.prt,ah        ; Port 1 or 2, etc
  322.     mov    ah,[bx].parflg        ; parity flag
  323.     mov    targ.parity,ah
  324.     mov    ax,[bx].baud        ; baud rate identifier
  325.     mov    targ.baudb,al
  326.     xor    ah,ah
  327.     test    flags.capflg,logses    ; select session logging flag bit
  328.     jz    tel3            ; z = no logging
  329.     mov    ah,capt            ; set capture flag
  330. tel3:    or    targ.flgs,ah
  331.     jmp    short tem1
  332.  
  333. TEM:    call    serini            ; init serial port
  334.     jnc    tem1            ; nc = success
  335.     mov    ttyact,0        ; say we are no longer active
  336.     clc
  337.     ret                ; and exit Connect mode
  338.  
  339. tem1:    mov    dx,offset crlf        ; give user an indication that we are
  340.     mov    ah,prstr        ; entering terminal mode
  341.     int    dos
  342.     mov    ax,offset targ        ; point to terminal arguments
  343.     call    term            ; call the main Terminal procedure
  344.     mov    al,kbdflg        ; get the char from Term, if any
  345.     mov    kbdflg,0        ; clear    the flag
  346.     or    al,al            ; was there a char from Term?
  347.     jnz    intch2            ; nz = yes, else ask for one from kbd
  348.  
  349. intchar:call    iseof            ; stdin at eof?
  350.     jnc    intch1            ; nc = not eof, get more
  351.     mov    al,'C'            ; use C when file is empty
  352.     jmp    intchc            ;  to provide an exit
  353. intch1:    cmp    al,0            ; asking for help?
  354.     jne    intch1b            ; ne = no
  355.     mov    al,' '
  356.     mov    ah,trans.escchr
  357.     cmp    ah,' '            ; printable now?
  358.     jae    intch1a            ; ae = yes
  359.     mov    al,'^'
  360.     add    ah,40h            ; make control visible
  361. intch1a:mov    word ptr intqryc,ax    ; store escape char code
  362.     mov    ax,offset intqry    ; '?' get help message
  363.     call    puthlp            ; write help msg
  364.     mov    dx,offset intprm
  365.     mov    ah,prstr        ; show prompt
  366.     int    dos
  367. intch1b:mov    ah,0ch            ; clear Bios keyboard buffer and do
  368.     mov    al,coninq        ;  read keyboard, no echo
  369.     int    dos            ; get a char
  370.     or    al,al            ; scan code indicator?
  371.     jnz    intch1c            ; nz = no, ascii
  372.     mov    ah,coninq        ; read and discard scan code
  373.     int    dos
  374.     jmp    short intch1        ; try again
  375. intch1c:cmp    al,'?'            ; want to see menu again?
  376.     jne    intch2            ; ne = no
  377.     xor    al,al            ; prep for menu display
  378.     jmp    short intchar
  379.  
  380. intch2:    mov    flags.cxzflg,0        ; prevent Control-C carryover
  381.     cmp    al,' '            ; space?
  382.     je    tem            ; e = yes, ignore it
  383.     cmp    al,cr            ; check ^M (cr) against plain ascii M
  384.     je    tem            ; exit on cr
  385.     cmp    al,trans.escchr        ; is it the escape char?
  386.     jne    intch3            ; ne = no
  387.     mov    ah,al
  388.     call    outchr
  389.     jmp    tem            ; return, we are done here
  390. intch3:    push    es
  391.     push    ds
  392.     pop    es
  393.     mov    di,offset intclet    ; command letters
  394.     mov    cx,numlet        ; quantity of them
  395.     cmp    al,' '            ; control code?
  396.     jae    intch3a            ; ae = no
  397.     or    al,40H            ; convert control chars to printable
  398. intch3a:cmp    al,96            ; lower case?
  399.     jb    intch3b            ; b = no
  400.     and    al,not (20h)        ; move to upper case
  401. intch3b:cld
  402.     repne    scasb            ; find the matching letter
  403.     pop    es
  404.     jne    intch4            ; ne = not found, beep and get another
  405.     dec    di            ; back up to letter
  406.     sub    di,offset intclet    ; get letter number
  407.     shl    di,1            ; make it a word index
  408.     jmp    intcjmp[di]        ; dispatch to it
  409. intch4:    call    beep            ; say illegal character
  410.     jmp    intchar
  411.  
  412. intayt:    mov    ah,255            ; 'I' Telnet Are You There
  413.     call    outchr            ; send IAC (255) AYT (246)
  414.     mov    ah,246
  415.     call    outchr
  416.     jmp    tem
  417.  
  418. intchb:    call    sendbr            ; 'B' send a break
  419.     jmp    tem            ; And return
  420.  
  421. intchc:    mov    ttyact,0        ; 'C' say we are no longer active
  422.     clc                ; and exit Connect mode
  423.     ret
  424.  
  425. intchf:    call    dumpscr            ; 'F' dump screen, use msy routine
  426.     jmp    tem            ; and return
  427.  
  428. intchh:    call    serhng            ; 'H' hangup phone
  429.     call    serrst            ; turn off port
  430.     jmp    tem
  431.  
  432. intchl:    call    sendbl            ; 'L' send a long break
  433.     jmp    tem
  434.  
  435. inttip:    mov    ah,255            ; 'I' Telnet Interrrupt Process
  436.     call    outchr            ; send IAC (255) IP (244)
  437.     mov    ah,244
  438.     call    outchr
  439.     jmp    tem
  440.  
  441. intchm:    cmp    flags.modflg,1        ; 'M' toggle mode line, enabled?
  442.     jne    intchma            ; ne = no, leave it alone
  443.     xor    targ.flgs,modoff    ; enabled, toggle its state
  444. intchma:jmp    tem            ; and reconnect
  445.  
  446. intchp:    call    fpush            ; 'P' push to DOS
  447.     mov    dx,offset sttmsg    ; say we have returned
  448.     mov    ah,prstr
  449.     int    dos
  450.     jmp    short intchsb        ; wait for a space
  451.  
  452. intchq:    and    targ.flgs,not capt    ; 'Q' suspend session logging
  453.     jmp    tem            ; and resume
  454.  
  455. intchr:    test    flags.capflg,logses    ; 'R' resume logging. Can we capture?
  456.     jz    intchr1            ; z = no
  457.     or    targ.flgs,capt        ; turn on session logging flag
  458. intchr1:jmp    tem            ; and resume
  459.  
  460. intchs:    call    stat0            ; 'S' status, call stat0
  461.     mov    dx,offset sttmsg
  462.     mov    ah,prstr
  463.     int    dos
  464. intchsa:call    iseof            ; is stdin at eof?
  465.     jnc    intchsb            ; nc = not eof, get more
  466.     jmp    tem            ; resume if EOF
  467. intchsb:mov    ah,coninq        ; console input, no echo
  468.     int    dos
  469.     cmp    al,' '            ; space?
  470.     jne    intchsa
  471.     jmp    tem
  472.  
  473. intchu:    mov    ah,trans.escchr
  474.     cmp    ah,' '            ; printable now?
  475.     jae    intchu1            ; ae = yes
  476.     mov    al,'^'
  477.     add    ah,40h            ; make control visible
  478. intchu1:mov    word ptr inthlpc,ax    ; store escape char code
  479.     mov    ax,offset inthlp    ; help message
  480.     call    puthlp            ; write help msg
  481.     mov    ah,0ch            ; clear Bios keyboard buffer and do
  482.     mov    al,coninq        ;  read keyboard, no echo
  483.     int    dos            ; get a char
  484.     or    al,al            ; scan code indicator?
  485.     jnz    intchu2            ; nz = no, ascii
  486.     mov    ah,coninq        ; read and discard scan code
  487.     int    dos
  488. intchu2:jmp    tem            ; try again
  489.  
  490. intchn:    xor    ah,ah            ; '0' send a null
  491.     call    outchr
  492.     jmp    tem
  493. TELNET  ENDP
  494. endif    ; no_terminal
  495. code    ends
  496.  
  497. code1    segment
  498.     assume cs:code1
  499. ; Reassure user    about connection to the host. Tell him what escape sequence
  500. ; to use to return
  501.  
  502. DOMSG    PROC    FAR
  503.     mov    ah,prstr
  504.     mov    dx,offset tmsg1
  505.     int    dos
  506.     call    escprt
  507.     mov    ah,prstr
  508.     mov    dx,offset tmsg3
  509.     int    dos
  510.     ret
  511. DOMSG    ENDP
  512.  
  513. ; print    the escape character in readable format.  
  514.  
  515. ESCPRT    PROC    NEAR
  516.     mov    dl,trans.escchr
  517.     cmp    dl,' '
  518.     jge    escpr2
  519.     push    dx
  520.     mov    ah,prstr
  521.     mov    dx,offset esctl
  522.     int    dos
  523.     pop    dx
  524.     add    dl,040H        ; Make it printable
  525. escpr2:    mov    ah,conout
  526.     int    dos
  527.     ret
  528. ESCPRT    ENDP
  529. code1    ends
  530.  
  531. code    segment
  532.     assume    cs:code 
  533.  
  534. ; Set parity for character in Register AL
  535.  
  536. dopar:    push    bx
  537.     mov    bx,portval
  538.     mov    bl,[bx].parflg        ; get parity flag byte
  539.     test    bl,PARHARDWARE        ; hardware?
  540.     jnz    parret            ; nz = yes
  541.     cmp    bl,parnon        ; No parity?
  542.     je    parret            ; Just return
  543.     and    al,07FH            ; Strip parity. Same as Space parity
  544.     cmp    bl,parspc        ; Space parity?
  545.     je    parret            ; e = yes, then we are done here
  546.     cmp    bl,parevn        ; Even parity?
  547.     jne    dopar0            ; ne = no
  548.     or    al,al
  549.     jpe    parret            ; pe = even parity now
  550.     xor    al,080H            ; Make it even parity
  551.     jmp    short parret
  552. dopar0:    cmp    bl,parmrk        ; Mark parity?
  553.     jne    dopar1            ; ne = no
  554.     or    al,080H            ; Turn on the parity bit
  555.     jmp    short parret
  556. dopar1:    cmp    bl,parodd        ; Odd parity?    
  557.     or    al,al
  558.     jpo    parret            ; Already odd, leave it
  559.     xor    al,080H            ; Make it odd parity
  560. parret:    pop    bx
  561.     ret
  562.  
  563. ; REPLAY filespec  through terminal emulator
  564. replay    proc    near
  565.     mov    bx,offset rdbuf        ; place for filename
  566.     mov    dx,offset rephlp    ; help
  567.     mov    repflg,0        ; clear the replay active flag
  568.     mov    ah,cmword        ; get filename
  569.     call    comnd
  570.     jc    replay2            ; c = failure
  571.     mov    ah,cmeol        ; get an EOL confirm
  572.     call    comnd
  573.     jc    replay2            ; c = failure
  574. ifndef    no_terminal
  575.     mov    ah,open2        ; open file
  576.     xor    al,al            ; open readonly
  577.     cmp    byte ptr dosnum+1,2    ; above DOS 2?
  578.     jna    replay1            ; na = no, so no shared access
  579.     mov    al,0+40h        ; open readonly, deny none
  580. replay1:mov    dx,offset rdbuf        ; asciiz filename
  581.     int    dos
  582.     jnc    replay3            ; nc = success
  583.     mov    ah,prstr
  584.     mov    dx,offset reperr    ; Cannot open that file
  585.     int    dos
  586.     clc
  587.     ret
  588. replay3:mov    diskio.handle,ax    ; file handle
  589.     mov    repflg,1        ; set replay flag
  590.     call    telnet            ; enter Connect mode
  591.     mov    bx,diskio.handle
  592.     mov    ah,close2        ; close the file
  593.     int    dos
  594. endif    ; no_terminal
  595.     mov    repflg,0        ; clear the flag
  596.     clc
  597. replay2:ret
  598. replay    endp
  599.  
  600. cptchr    proc    near            ; session capture routine, char in al
  601.     test    flags.capflg,logses    ; session logging active now?
  602.     jz    cptch1            ; z = no
  603.     push    di
  604.     push    es
  605.     mov    di,data1        ; seg of capbp and capbuf
  606.     mov    es,di
  607.     cld
  608.     mov    di,es:capbp        ; buffer pointer
  609.     stosb
  610.     inc    es:capbp
  611.     pop    es
  612.     pop    di
  613.     dec    caplft            ; decrement chars remaining
  614.     jg    cptch1            ; more room, forget this part
  615.     call    cptdmp            ; dump the info
  616. cptch1:    ret
  617. cptchr    endp
  618.  
  619. cptdmp    proc    near            ; empty the capture buffer
  620.     push    ax
  621.     push    bx
  622.     push    cx
  623.     push    dx
  624.     mov    bx,sloghnd        ; get file handle
  625.     or    bx,bx            ; is file open?
  626.     jle    cptdm1            ; le = no, skip it
  627.     mov    cx,cptsiz        ; original buffer size
  628.     sub    cx,caplft        ; minus number remaining
  629.     jl    cptdm2            ; means error
  630.     jcxz    cptdm1            ; z = nothing to do
  631.     push    ds
  632.     mov    dx,data1        ; seg of capbuf
  633.     mov    ds,dx
  634.     mov    dx,offset capbuf    ; the capture routine buffer
  635.     mov    ah,write2        ; write with filehandle
  636.     int    dos            ; write out the block
  637.     pop    ds
  638.     jc    cptdm2            ; carry set means error
  639.     cmp    ax,cx            ; wrote all?
  640.     jne    cptdm2            ; no, an error
  641.     push    es
  642.     mov    dx,data1        ; seg of capbuf and capbp
  643.     mov    es,dx
  644.     mov    es:capbp,offset capbuf
  645.     pop    es
  646.     mov    caplft,cptsiz        ; init buffer ptr & chrs left
  647.     clc
  648.     jmp    short cptdm1
  649. cptdm2:    and    targ.flgs,not capt    ; so please stop capturing
  650.     and    flags.capflg,not logses    ; deselect session logging flag bit
  651.     mov    dx,offset erms23    ; tell user the bad news
  652.     call    putmod            ; write on mode line
  653.     stc
  654. cptdm1:    pop    dx
  655.     pop    cx
  656.     pop    bx
  657.     pop    ax
  658.     ret
  659. cptdmp    endp
  660.  
  661. pktcpt    proc    near            ; packet log routine, char in al
  662.     test    flags.capflg,logpkt    ; logging packets now?
  663.     jz    pktcp1            ; z = no
  664.     push    di
  665.     push    es
  666.     mov    di,data1        ; seg of pktbuf and pktbp
  667.     mov    es,di
  668.     mov    di,es:pktbp        ; buffer pointer
  669.     cld
  670.     stosb                ; store char in buffer
  671.     inc    es:pktbp        ; move pointer to next free byte
  672.     pop    es
  673.     pop    di
  674.     dec    pktlft            ; decrement chars remaining
  675.     jg    pktcp1            ; g = more room, forget this part
  676.     call    pktdmp            ; dump the info
  677. pktcp1:    ret
  678. pktcpt    endp
  679.  
  680. pktdmp    proc    near            ; empty the capture buffer
  681.     push    ax
  682.     push    bx
  683.     push    cx
  684.     push    dx
  685.     mov    bx,ploghnd        ; get file handle
  686.     or    bx,bx            ; is file open?
  687.     jle    cptdm1            ; le = no, skip it
  688.     mov    cx,cptsiz        ; original buffer size
  689.     sub    cx,pktlft        ; minus number remaining
  690.     jl    pktdm2            ; l means error
  691.     jcxz    pktdm1            ; z = nothing to do
  692.     push    ds
  693.     mov    dx,data1        ; seg of pktbuf
  694.     mov    ds,dx
  695.     mov    dx,offset pktbuf    ; the capture routine buffer
  696.     mov    ah,write2        ; write with filehandle
  697.     int    dos            ; write out the block
  698.     pop    ds
  699.     jc    pktdm2            ; carry set means error
  700.     cmp    ax,cx            ; wrote all?
  701.     jne    pktdm2            ; ne = no, error
  702.     push    es
  703.     mov    dx,data1        ; seg of pktbuf
  704.     mov    es,dx
  705.     mov    es:pktbp,offset pktbuf
  706.     pop    es
  707.     mov    pktlft,cptsiz        ; init buffer ptr & chrs left
  708.     jmp    short pktdm1
  709. pktdm2:    and    flags.capflg,not logpkt    ; so please stop capturing
  710.     mov    dx,offset erms24    ; tell user the bad news
  711.     mov    ah,prstr
  712.     int    dos
  713.     call    clscp4            ; close the packet log
  714. pktdm1:    pop    dx
  715.     pop    cx
  716.     pop    bx
  717.     pop    ax
  718.     ret
  719. pktdmp    endp
  720.  
  721. ; CLOSE command
  722.  
  723. clscpt    proc    near
  724.     mov    ah,cmkey        ; get kind of file to close
  725.     mov    dx,offset clotab    ; close table
  726.     mov    bx,offset clohlp    ; help
  727.     call    comnd
  728.            jc    clscp2            ; c = failure
  729.     mov    temp,bx
  730.     mov    ah,cmeol
  731.     call    comnd
  732.            jc    clscp2            ; c = failure
  733.     mov    kstatus,kssuc        ; success status thus far
  734.     mov    bx,temp
  735.     cmp    bh,40h            ; READ-FILE or WRITE-FILE?
  736.     jne    clscp0            ; ne = no
  737.     mov    ax,bx
  738.     jmp    vfclose            ; close FILE, pass kind in AX
  739. clscp0:    cmp    bx,logpkt+logses+logtrn    ; close all?
  740.     je    clscpi            ; e = yes
  741.     cmp    bx,logpkt        ; just packet?
  742.     je    clscp4
  743.     cmp    bx,logses        ; just session?
  744.     je    clscp6
  745.     cmp    bx,logtrn        ; just session?
  746.     jne    clscp1            ; ne = no
  747.     jmp    clscp8
  748. clscp1:    mov    dx,offset erms22    ; say none active
  749.     mov    ah,prstr
  750.     int    dos
  751.     clc
  752.     ret
  753. clscp2:    mov    kstatus,ksgen        ; general cmd failure status
  754.     stc
  755.     ret
  756.                     ; CLSCPI called at Kermit exit
  757. CLSCPI:    mov    bx,portval
  758.     mov    [bx].flowc,0        ; set no flow control so no sending it
  759.     call    pntflsh            ; flush PRN buffer
  760.     call    clscp4            ; close packet log
  761.     call    clscp6            ; close session log
  762.     call    clscp8            ; close transaction log
  763.     mov    al,2            ; close WRITE FILE log
  764.     call    vfclose
  765.     clc                ; return success
  766.     ret
  767.  
  768. clscp4:    push    bx            ; PACKET LOG
  769.     mov    bx,ploghnd        ; packet log handle
  770.     or    bx,bx            ; is it open?
  771.     jle    clscp5            ; e = no
  772.     call    pktdmp            ; dump buffer
  773.     mov    ah,close2
  774.     int    dos
  775.     cmp    flags.takflg,0        ; ok to echo?
  776.     je    clscp5            ; e = no
  777.     mov    ah,prstr
  778.     mov    dx,offset clpktlog    ; tell what we are doing
  779.     int    dos
  780. clscp5:    mov    ploghnd,-1        ; say handle is invalid
  781.     pop    bx
  782.     and    flags.capflg,not logpkt    ; say this log is closed
  783.     ret
  784.  
  785. clscp6:    push    bx            ; SESSION LOG
  786.     mov    bx,sloghnd        ; session log handle
  787.     or    bx,bx            ; is it open?
  788.     jle    clscp7            ; e = no
  789.     call    cptdmp            ; dump buffer
  790.     mov    ah,close2
  791.     int    dos
  792.     cmp    flags.takflg,0        ; ok to echo?
  793.     je    clscp7            ; e = no
  794.     mov    ah,prstr
  795.     mov    dx,offset clseslog    ; tell what we are doing
  796.     int    dos
  797. clscp7:    mov    sloghnd,-1        ; say handle is invalid
  798.     pop    bx
  799.     and    flags.capflg,not logses    ; say this log is closed
  800.     ret
  801.  
  802. clscp8:    push    bx            ; TRANSACTION LOG
  803.     mov    bx,tloghnd        ; transaction log handle
  804.     or    bx,bx            ; is it open?
  805.     jle    clscp9            ; e = no
  806.     mov    ah,close2
  807.     int    dos
  808.     cmp    flags.takflg,0        ; ok to echo?
  809.     je    clscp9            ; e = no
  810.     mov    ah,prstr
  811.     mov    dx,offset cltrnlog    ; tell what we are doing
  812.     int    dos
  813. clscp9:    mov    tloghnd,-1        ; say handle is invalid
  814.     pop    bx
  815.     and    flags.capflg,not logtrn    ; say this log is closed
  816.     ret
  817. clscpt    endp
  818.  
  819. ; Print on PRN the char in register al. On success return with C bit clear.
  820. ; On failure do procedure pntchk and return its C bit (typically C set).
  821. ; Uses buffer dumpbuf (screen dump).
  822. pntchr    proc    near
  823.     push    es
  824.     push    ax
  825.     mov    ax,data1        ; segment of pntptr and prnbuf
  826.     mov    es,ax
  827.     cmp    es:pntptr,offset prnbuf+cptsiz ; buffer full yet?
  828.     pop    ax
  829.     pop    es
  830.     jb    pntchr1            ; b = no
  831.     call    pntflsh            ; flush buffer now
  832.     jnc    pntchr1            ; nc = success
  833.     ret                ; c = fail, discard char
  834. pntchr1:push    es
  835.     push    bx
  836.     mov    bx,data1        ; segment of pntptr and prnbuf
  837.     mov    es,bx
  838.     mov    bx,es:pntptr        ; pointer to next open slot
  839.     mov    es:[bx],al        ; store the character
  840.     inc    bx            ; update pointer
  841.     mov    es:pntptr,bx        ; save pointer
  842.     pop    bx
  843.     pop    es
  844.     clc                ; clear carry bit
  845.     ret
  846. pntchr    endp
  847.  
  848. ; Flush printer buffer. Return carry clear if success.
  849. ; On failure do procedure pntchk and return its C bit (typically C set).
  850. ; Uses buffer dumpbuf (screen dump).
  851. pntflsh    proc    near
  852.     push    es
  853.     push    ax
  854.     mov    ax,data1        ; segment of pntptr and prnbuf
  855.     mov    es,ax
  856.     cmp    es:pntptr,offset prnbuf    ; any text in buffer?
  857.     pop    ax
  858.     pop    es
  859.     ja    pntfls1            ; a = yes
  860.     clc
  861.     ret                ; else nothing to do
  862. pntfls1:cmp    prnhand,0        ; is printer handle valid?
  863.     jg    pntfls2            ; g = yes
  864.     push    es
  865.     push    ax
  866.     mov    ax,data1        ; segment of pntptr and prnbuf
  867.     mov    es,ax
  868.     mov    es:pntptr,offset prnbuf
  869.     pop    ax
  870.     pop    es
  871.     clc                ; omit printing, quietly
  872.     ret
  873. pntfls2:push    ax
  874.     push    bx
  875.     push    cx
  876.     push    dx
  877.     push    si
  878.     push    di
  879.     push    es
  880.     mov    ah,flowoff        ; get flow control char
  881.     or    ah,ah            ; flow control active?
  882.     jz    pntfls3            ; z = no, not using xoff
  883.     call    outchr            ; output xoff (ah), no echo
  884. pntfls3:mov    bx,prnhand        ; file handle for DOS printer PRN
  885.     push    DS            ; about to change DS
  886.     mov    dx,data1        ; segment of prnbuf
  887.     mov    ds,dx            ; set DS
  888.     mov    dx,offset prnbuf    ; start of buffer
  889.     mov    cx,ds:pntptr
  890.     sub    cx,dx            ; cx = current byte count
  891. pntfls4:push    cx
  892.     push    dx
  893.     mov    cx,1
  894.     mov    ah,write2
  895.     int    dos            ; write buffer to printer
  896.     pop    dx
  897.     pop    cx
  898.     jc    pntfls5            ; c = call failed
  899.     cmp    ax,1            ; did we write it?
  900.     jne    pntfls5            ; ne = no, dos critical error
  901.     inc    dx            ; point to next char
  902.     loop    pntfls4
  903.     mov    ds:pntptr,offset prnbuf    ; reset buffer pointer
  904.     pop    DS            ; restore DS
  905.     clc                ; declare success
  906.     jmp    pntfls11
  907. pntfls5:mov    si,dx            ; address of next char to be printed
  908.     mov    di,offset prnbuf    ; start of buffer
  909.     sub    dx,di            ; dx now = number successful prints
  910.     mov    cx,ds:pntptr
  911.     sub    cx,si            ; count of chars to be printed
  912.     jle    pntfls6
  913.     mov    ax,ds
  914.     mov    es,ax
  915.     cld
  916.     rep    movsb            ; copy unwritten to start of buffer
  917. pntfls6:sub    ds:pntptr,dx        ; move back printer pointer by ok's
  918.     pop    DS            ; restore DS
  919.  
  920. pntfls7:mov    dx,offset erms26    ; printer not ready, get user action
  921.     call    putmod            ; write new mode line
  922.     call    beep            ; make a noise
  923.     mov    ah,0ch            ; clear DOS typeahead buffer
  924.     mov    al,1            ; read from DOS buffer
  925.     int    dos
  926.     or    al,al            ; Special key?
  927.     jnz    pntfls8            ; nz = no, consume
  928.     mov    al,1            ; consume scan code
  929.     int    dos
  930.     jmp    short pntfls7        ; try again
  931.  
  932. pntfls8:and    al,not 20h        ; lower to upper case quicky
  933.     cmp    al,'R'            ; Retry?
  934.     jne    pntfls8a        ; ne = no
  935.     call    trnmod            ; toggle mode line
  936.     call    trnmod            ; back to same state as before
  937.     jmp    pntfls3            ; go retry
  938. pntfls8a:cmp    al,'D'            ; Discard printing?
  939.     jne    pntfls7            ; ne = no, try again
  940.     mov    bx,prnhand
  941.     cmp    bx,4            ; stdin/stdout/stderr/stdaux/stdprn?
  942.     jbe    pntfls9            ; be = yes, always available
  943.     mov    ah,close2        ; close this file
  944.     int    dos
  945. pntfls9:mov    bx,offset prnname    ; name of printer file
  946.     mov    word ptr [bx],'UN'    ; set to NUL<0>
  947.     mov    word ptr [bx+2],'L'+0
  948.     push    es
  949.     mov    ax,data1        ; seg for pntptr
  950.     mov    es,ax
  951.     mov    es:pntptr,offset prnbuf    ; reset pointer
  952.     pop    es
  953.     mov    prnhand,-1        ; declare handle invalid
  954. ifndef    no_terminal
  955.     mov    anspflg,0        ; mszibm/msyibm print status flag off
  956. endif    ; no_terminal
  957. pntfls10:call    trnmod            ; toggle mode line
  958.     call    trnmod            ; back to same state as before
  959.     stc                ; declare failure
  960. pntfls11:pushf
  961.     mov    ah,flowon
  962.     or    ah,ah            ; flow control active?
  963.     jz    pntfls12        ; z = no, not using xon
  964.     call    outchr            ; output xon (al), no echo
  965. pntfls12:popf
  966.     pop    es
  967.     pop    di
  968.     pop    si
  969.     pop    dx
  970.     pop    cx
  971.     pop    bx
  972.     pop    ax
  973.     ret                ; nc = success
  974. pntflsh    endp
  975.  
  976. ; Check for PRN (DOS's printer) being ready. If ready, return with C clear
  977. ; Otherwise, write Not Ready msg on mode line and return with C bit set.
  978. ; N.B. DOS Critical Error will occur here if PRN is not ready.  [jrd]
  979. pntchk    proc    near
  980.     push    dx
  981.     push    cx
  982.     push    ax
  983.     mov    cx,10            ; ten retries before declaring error
  984.     cmp    prnhand,0        ; printer handle valid?
  985.     jle    pntchk2            ; le = no, invalid
  986. pntchk0:push    bx
  987.     mov    bx,prnhand        ; file handle
  988.     mov    ah,ioctl        ; get printer status, via DOS
  989.     mov    al,7            ; status for output
  990.     int    dos
  991.     pop    bx
  992.     jc    pntchk1            ; c = call failed
  993.     cmp    al,0ffh            ; code for Ready?
  994.     je    pntchk3            ; e = yes, assume printer is ready
  995. pntchk1:push    cx            ; save counter, just in case
  996.     mov    ax,100            ; wait 100 millisec
  997.     call    pcwait
  998.     pop    cx
  999.     loop    pntchk0            ; and try a few more times
  1000.                     ; get here when printer is not ready
  1001. pntchk2:pop    ax
  1002.     pop    cx
  1003.     pop    dx
  1004.     stc                ; say printer not ready
  1005.     ret
  1006. pntchk3:pop    ax
  1007.     pop    cx
  1008.     pop    dx
  1009.     clc                ; say printer is ready
  1010.     ret
  1011. pntchk    endp
  1012.  
  1013.  
  1014. prnopen    proc    near
  1015.     push    ax
  1016.     push    bx
  1017.     push    cx
  1018.     push    dx
  1019.     mov    prnhand,4        ; preset default handle
  1020.     mov    dx,offset prnname    ; name of disk file, from msssho
  1021.     mov    ax,dx            ; where isfile wants name ptr
  1022.     call    isfile            ; what kind of file is this?
  1023.     jc    prnop3            ; c = no such file, create it
  1024.     test    byte ptr filtst.dta+21,1fh ; file attributes, ok to write?
  1025.     jnz    prnop2            ; nz = no
  1026.     mov    al,1            ; writing
  1027.     mov    ah,open2        ; open existing file
  1028.     int    dos
  1029.     jc    prnop2            ; c = failure
  1030.     mov    prnhand,ax        ; save file handle
  1031.     mov    bx,ax            ; handle for DOS
  1032.     mov    ah,ioctl
  1033.     mov    al,0            ; get info
  1034.     int    dos
  1035.     or    dl,20h            ; turn on binary mode
  1036.     xor    dh,dh
  1037.     mov    ah,ioctl
  1038.     mov    al,1            ; set info
  1039.     int    dos
  1040.     mov    cx,0ffffh        ; setup file pointer
  1041.     mov    dx,-1            ; and offset
  1042.     mov    al,2            ; move to eof minus one byte
  1043.     mov    ah,lseek        ; seek the end
  1044.     int    dos
  1045.     pop    dx
  1046.     pop    cx
  1047.     pop    bx
  1048.     pop    ax
  1049.     clc
  1050.     ret
  1051. prnop2:    pop    dx
  1052.     pop    cx
  1053.     pop    bx
  1054.     pop    ax
  1055.     stc
  1056.     ret
  1057. prnop3:    test    filtst.fstat,80h    ; access problem?
  1058.     jnz    prnop2            ; nz = yes
  1059.     mov    ah,creat2        ; file did not exist
  1060.     mov    cx,20h            ; attributes, archive bit
  1061.     int    dos
  1062.     mov    prnhand,ax        ; save file handle
  1063.     pop    dx
  1064.     pop    cx
  1065.     pop    bx
  1066.     pop    ax
  1067.     ret                ; may have carry set
  1068. prnopen    endp
  1069.  
  1070. ; worker: copy line from si to di, first removing trailing spaces, second
  1071. ; parsing out curly braced strings, then third converting \{b##} in strings
  1072. ; to binary numbers. Returns carry set if error; else carry clear, with byte
  1073. ; count in cx. Braces are optional but must occur in pairs.
  1074. ; Items which cannot be converted to legal numbers are copied verbatium
  1075. ; to the output string (ex: \{c}  is copied as \{c}  but \{x0d} is hex 0dh).
  1076. ; '\\' is written as '\'
  1077. ; Requires byte count in CX to handle embedded \0 bytes.
  1078. cnvlin    proc    near
  1079.     push    ax
  1080.     push    si            ; source ptr
  1081.     push    di            ; destination ptr
  1082.     push    bp            ; end of string marker
  1083.     push    temp            ; output length counter
  1084.     push    es            ; end of save regs
  1085.     push    ds            ; move ds into es
  1086.     pop    es            ; use data segment for es:di
  1087.     mov    temp,di            ; initial output position
  1088.     call    cnvstr            ; parse curly braces
  1089.     xor    dx,dx            ; initialize returned byte count
  1090.     cld
  1091.     mov    bp,si
  1092.     add    bp,cx            ; point to last byte + 1 of string
  1093. cnvln1:    cmp    si,bp            ; at end of string?
  1094.     jae    cnvlnx            ; ae = yes, exit
  1095.     mov    al,[si]            ; look at starting byte
  1096.     cmp    al,'\'            ; numeric intro?
  1097.     jne    cnvln3            ; ne = no
  1098.     mov    atoi_cnt,cx        ; length for atoi
  1099.     mov    atoibyte,1        ; convert only one character
  1100.     call    atoi            ; deal with \numbers
  1101.     jnc    cnvln4            ; nc = success, converted number
  1102. cnvln3:    lodsb                ; reread from string literally
  1103.     xor    ah,ah            ; only one byte of output
  1104. cnvln4:    cld
  1105.     stosb                ; save the char
  1106.     or    ah,ah            ; is returned number > 255?
  1107.     jz    cnvln1            ; z = no, do more chars
  1108. cnvln5:    stosb                ; save high order byte next
  1109.     jmp    short cnvln1        ; do more chars
  1110. cnvlnx:    mov    byte ptr [di],0        ; plant terminator
  1111.     clc                ; clear c bit, success
  1112.     sub    di,temp            ; current - inital output position
  1113.     mov    cx,di            ; returned byte count to CX
  1114.     pop    es            ; restore regs
  1115.     pop    temp
  1116.     pop    bp
  1117.     pop    di            ; destination ptr
  1118.     pop    si            ; source ptr
  1119.     pop    ax
  1120.     ret
  1121. cnvlin    endp
  1122.  
  1123. ; Convert string by removing surrounding curly brace delimiter pair. 
  1124. ; Converts text in place.
  1125. ; Enter with source ptr in si.
  1126. ; Preserves all registers, uses byte tmp. 9 Oct 1987 [jrd]
  1127. cnvstr    proc    near
  1128.     push    ax
  1129.     push    bx
  1130.     push    dx
  1131.     push    si            ; save start of source string
  1132.     push    di
  1133.     push    es
  1134.     xor    bx,bx             ; output count, assume none
  1135.     mov    dx,si            ; source address
  1136.     jcxz    cnvst4            ; z = nothing there
  1137.     push    ds
  1138.     pop    es            ; set es to data segment
  1139.     cld
  1140.     mov    di,si            ; set destination address to source
  1141.                     ; 2. Parse off curly brace delimiters
  1142.     mov    bx,cx            ; assume no changes to byte count
  1143.     cmp    byte ptr [si],braceop    ; opening brace?
  1144.     jne    cnvst4            ; ne = no, ignore brace-matching code
  1145.     xor    bx,bx            ; count up output bytes
  1146.     inc    si            ; skip opening brace
  1147.     mov    dl,braceop        ; opening brace (we count them up)
  1148.     mov    dh,bracecl        ; closing brace (we count them down)
  1149.     mov    tmp,1            ; we are at brace level 1
  1150. cnvst1:    cld                ; search forward
  1151.     lodsb                ; read a string char
  1152.     stosb                ; store char (skips opening brace)
  1153.     dec    cx
  1154.     inc    bx            ; count bytes read and written
  1155.     or    cx,cx            ; at end of string?
  1156.     jle    cnvst4            ; le = yes, we are done
  1157.     cmp    al,dl            ; an opening brace?
  1158.     jne    cnvst2            ; ne = no
  1159.     inc    tmp            ; yes, increment brace level
  1160.     jmp    short cnvst1        ;  and continue scanning
  1161.  
  1162. cnvst2:    cmp    al,dh            ; closing brace?
  1163.     jne    cnvst1            ; ne = no, continue scanning
  1164.     dec    tmp            ; yes, decrement brace level
  1165.     or    cx,cx            ; have we just read the last char?
  1166.     jnz    cnvst3            ; nz = no, continue scanning
  1167.     mov    tmp,0            ; yes, this is the closing brace
  1168. cnvst3:    cmp    tmp,0            ; at level 0?
  1169.     jne    cnvst1            ; ne = no, #opening > #closing braces
  1170.     dec    bx            ; don't count terminating brace
  1171.     mov    byte ptr [di-1],0    ; plant terminator on closing brace
  1172.  
  1173. cnvst4:    pop    es            ; recover original registers
  1174.     pop    di
  1175.     pop    si
  1176.     pop    dx
  1177.     mov    cx,bx            ; return count in cx
  1178.     pop    bx
  1179.     pop    ax
  1180.     ret
  1181. cnvstr    endp
  1182.  
  1183. ; OPEN { READ | WRITE | APPEND } filespec
  1184. vfopen    proc    near
  1185.     mov    ah,cmkey        ; get READ/WRITE/APPEND keyword
  1186.     mov    dx,offset opntab    ; keyword table
  1187.     xor    bx,bx            ; help
  1188.     call    comnd
  1189.     jc    vfopen1            ; c = failed
  1190.     mov    temp,bx
  1191.     mov    ah,cmword        ; read filespec
  1192.     mov    bx,offset rdbuf        ; buffer for filename
  1193.     mov    dx,offset vfophlp    ; help
  1194.     call    comnd
  1195.     jc    vfopen1            ; c = failed
  1196.     mov    ah,cmeol        ; get end of line confirmation
  1197.     call    comnd
  1198.     jnc    vfopen2
  1199.     mov    kstatus,ksgen        ; general cmd failure status
  1200. vfopen1:ret                ; error return, carry set
  1201.  
  1202. vfopen2:mov    kstatus,kssuc        ; assume success status
  1203.     mov    dx,offset rdbuf        ; filename, asiiz
  1204.     mov    bx,temp            ; kind of open
  1205.     cmp    bx,1            ; open for reading?
  1206.     jne    vfopen4            ; ne = no
  1207.                     ; OPEN READ
  1208.     cmp    vfrhandle,0        ; is it open now?
  1209.     jge    vfopen8            ; ge = yes, complain
  1210.     mov    ah,open2        ; file open
  1211.     xor    al,al            ; 0 = open readonly
  1212.     cmp    dosnum,300h        ; at or above DOS 3?
  1213.     jb    vfopen3            ; b = no, so no shared access
  1214.     or    al,40h            ; open readonly, deny none
  1215. vfopen3:int    dos
  1216.     jc    vfopen9            ; c = failed to open the file
  1217.     mov    vfrhandle,ax        ; save file handle
  1218.     clc
  1219.     ret
  1220.                     ; OPEN WRITE or APPEND
  1221. vfopen4:cmp    vfwhandle,0        ; is it open now?
  1222.     jge    vfopen8            ; ge = yes, complain
  1223.     mov    ax,dx            ; filename for isfile
  1224.     call    isfile        ; check for read-only/system/vol-label/dir
  1225.     jc    vfopen7            ; c = file does not exist
  1226.     test    byte ptr filtst.dta+21,1fh    ; the no-no file attributes
  1227.     jnz    vfopen9            ; nz = do not write over one of these
  1228. vfopen5:test    filtst.fstat,80h    ; access problem?
  1229.     jnz    vfopen9            ; nz = yes, quit here
  1230.     test    byte ptr filtst.dta+21,1bh    ; r/o, hidden, volume label?
  1231.     jnz    vfopen9            ; we won't touch these
  1232.     mov    ah,open2           ; open existing file (usually a device)
  1233.     mov    al,1+1            ; open for writing
  1234.     int    dos
  1235.     jc    vfopen9            ; carry set means can't open
  1236.     mov    vfwhandle,ax        ; remember file handle
  1237.     mov    bx,ax            ; file handle for lseek
  1238.     xor    cx,cx
  1239.     xor    dx,dx            ; cx:dx = displacment
  1240.     xor    al,al            ; 0 means from start of file
  1241.     cmp    temp,2            ; WRITE? means from start of file
  1242.     je    vfopen6            ; e = yes, else APPEND
  1243.     mov    al,2            ; move to eof
  1244. vfopen6:mov    ah,lseek        ; seek the place
  1245.     int    dos
  1246.     clc
  1247.     ret
  1248.  
  1249. vfopen7:cmp    temp,1            ; READ?
  1250.     je    vfopen9            ; e = yes, should not be here
  1251.     mov    ah,creat2        ; create file
  1252.     xor    cx,cx            ; 0 = attributes bits
  1253.     int    dos
  1254.     jc    vfopen9            ; c = failed
  1255.     mov    vfwhandle,ax        ; save file handle
  1256.     clc                ; carry clear for success
  1257.     ret
  1258.  
  1259. vfopen8:mov    dx,offset vfoptwice    ; trying to reopen a file
  1260.     mov    ah,prstr
  1261.     int    dos
  1262.     mov    kstatus,kstake        ; Take file failure status
  1263.     stc
  1264.     ret
  1265. vfopen9:mov    dx,offset vfopbad    ; can't open, complain
  1266.     mov    ah,prstr
  1267.     int    dos
  1268.     mov    dx,offset rdbuf        ; filename
  1269.     call    prtasz
  1270.     mov    kstatus,kstake        ; Take file failure status
  1271.     stc
  1272.     ret
  1273. vfopen    endp
  1274.  
  1275. ; CLOSE {READ-FILE | WRITE-FILE}
  1276. vfclose    proc    near
  1277.     mov    tmp,al            ; remember kind (1=READ, 2=WRITE)
  1278.     mov    bx,vfrhandle        ; READ FILE handle
  1279.     cmp    al,1            ; READ-FILE?
  1280.     je    vfclos1            ; e = yes
  1281.     cmp    al,2            ; WRITE-FILE?
  1282.     jne    vfclos3            ; ne = no, a mistake
  1283.     mov    bx,vfwhandle        ; write handle
  1284.     or    bx,bx
  1285.     jl    vfclos3            ; l = invalid handle
  1286.     mov    dx,offset rdbuf
  1287.     xor    cx,cx            ; zero length
  1288.     push    bx            ; save handle
  1289.     mov    ah,write2        ; set file high water mark
  1290.     int    dos
  1291.     pop    bx
  1292. vfclos1:or    bx,bx
  1293.     jl    vfclos3            ; l = invalid handle
  1294.     mov    kstatus,kssuc        ; success status thus far
  1295.     mov    ah,close2        ; close file
  1296.     int    dos
  1297.     jc    vfclos4            ; c = error
  1298.     cmp    tmp,1            ; READ?
  1299.     jne    vfclos2            ; ne = no, WRITE
  1300.     mov    vfrhandle,-1        ; declare READ handle to be invalid
  1301.     clc
  1302.     ret
  1303. vfclos2:mov    vfwhandle,-1        ; declare WRITE handle to be invalid
  1304.     clc
  1305.     ret
  1306. vfclos4:mov    ah,prstr
  1307.     mov    dx,offset vfclbad    ; complain
  1308.     int    dos
  1309. vfclos3:mov    kstatus,ksgen        ; general cmd failure status
  1310.     stc
  1311.     ret
  1312. vfclose    endp
  1313.  
  1314. ; READ-FILE variable name
  1315. vfread    proc    near
  1316.     mov    comand.cmper,1        ; do not react to '\%' in macro name
  1317.     mov    comand.cmarray,1    ; allow sub in [..] of \&<char> arrays
  1318.     mov    ah,cmword
  1319.     mov    bx,offset rdbuf+2    ; buffer for macro name
  1320.     mov    word ptr rdbuf,0
  1321.     mov    dx,offset vfrdmsg
  1322.     call    comnd            ; get macro name
  1323.     jnc    vfread1            ; nc = success
  1324.     mov    kstatus,ksgen        ; general cmd failure status
  1325.     ret                ; failure
  1326. vfread1:or    ax,ax            ; null entry?
  1327.     jnz    vfread2            ; nz = no
  1328.     mov    dx,offset vfrdbad    ; more parameters needed
  1329.     mov    ah,prstr
  1330.     int    dos
  1331.     mov    kstatus,ksgen        ; general cmd failure status
  1332.     stc
  1333.     ret
  1334.  
  1335. vfread2:push    ax
  1336.     mov    ah,cmeol        ; get command confirmation
  1337.     call    comnd
  1338.     pop    ax            ; ax is variable length
  1339.     jc    vfreadx            ; c = failed
  1340.     mov    cx,cmdblen        ; length of rdbuf
  1341.     sub    cx,ax            ; minus macro name
  1342.     dec    cx            ; minus space separator
  1343.     mov    temp,0            ; leading whitespace and comment flgs
  1344.     mov    di,offset rdbuf+2    ; destination buffer
  1345.     add    di,ax            ; plus variable name
  1346.     mov    byte ptr [di],' '    ; space separator
  1347.     inc    di            ; put definition here
  1348.     mov    bx,vfrhandle        ; READ FILE handle
  1349.     or    bx,bx            ; check for valid handle
  1350.     jge    vfread3            ; ge = valid
  1351.     mov    ah,prstr
  1352.     mov    dx,offset vfnofile    ; say no file
  1353.     int    dos
  1354. vfreadx:mov    kstatus,ksgen        ; general cmd failure status
  1355.     stc                ; failure return
  1356.     ret
  1357. vfread3:push    cx            ; read from file
  1358.     mov    kstatus,kssuc        ; assume success status
  1359.     mov    cx,1            ; read 1 char
  1360.     mov    dx,di            ; place here
  1361.     mov    byte ptr [di],0        ; insert terminator
  1362.     mov    ah,readf2
  1363.     int    dos
  1364.     pop    cx
  1365.     jc    vfreadx            ; c = read failure
  1366.     or    ax,ax            ; count of bytes read
  1367.     jz    vfread9            ; z means end of file
  1368.     mov    al,[di]            ; get the character
  1369.     cmp    flags.takflg,0        ; echo Take files?
  1370.     je    vfread3a        ; e = no
  1371.     push    ax
  1372.     mov    ah,conout
  1373.     mov    dl,al            ; echo character
  1374.     int    dos
  1375.     pop    ax
  1376. vfread3a:cmp    al,CR            ; CR?
  1377.     je    vfread7            ; e = yes, ignore it
  1378.     cmp    al,LF            ; LF?
  1379.     je    vfread8            ; e = yes, exit
  1380.     cmp    byte ptr temp,0        ; seen non-spacing char yet?
  1381.     jne    vfread6            ; ne = yes
  1382.     cmp    al,' '            ; is this a space?
  1383.     je    vfread7            ; e = yes, skip it
  1384.     cmp    al,TAB            ; or a tab?
  1385.     je    vfread7            ; e = yes, skip it
  1386.     mov    byte ptr temp,1        ; say have seen non-spacing char
  1387.  
  1388. vfread6:inc    di            ; next storage cell
  1389. vfread7:loop    vfread3            ; loop til end of line
  1390.  
  1391. vfread8:cmp    byte ptr [di-1],'-'    ; last printable is line-continuation?
  1392.     jne    vfread10        ; ne = no, use this line as-is
  1393.     dec    di            ; point to hyphen
  1394.     mov    cx,offset rdbuf+cmdblen    ; end of rdbuf
  1395.     sub    cx,di            ; minus where we are now
  1396.     jle    vfread10        ; le = no space remaining
  1397.     mov    temp,0            ; leading whitespace and comment flgs
  1398.     jmp    vfread3            ; read another line
  1399.  
  1400. vfread9:mov    kstatus,ksgen        ; EOF, general command failure status
  1401.  
  1402. vfread10:cmp    flags.takflg,0        ; echo Take files?
  1403.     je    vfread11        ; e = no
  1404.     mov    ah,prstr
  1405.     mov    dx,offset crlf        ; for last displayed line
  1406.     int    dos
  1407.  
  1408. vfread11:mov    byte ptr [di],0        ; insert final terminator
  1409.     mov    dx,offset rdbuf+2    ; start counting from here
  1410.     push    kstatus            ; preserve status from above work
  1411.     call    strlen            ; cx becomes length
  1412.     call    dodecom            ; create the variable
  1413.     pop    kstatus            ; recover reading status
  1414.     jc    vfread12        ; c = failure
  1415.     ret
  1416. vfread12:mov    kstatus,ksgen        ; general command failure status
  1417.     mov    ah,prstr
  1418.     mov    dx,offset vfrbad    ; say error while reading
  1419.     int    dos
  1420.     stc
  1421.     ret
  1422. vfread    endp
  1423.  
  1424. ; WRITE {FILE or log} text
  1425. Write    proc    near
  1426.     mov    ah,cmkey        ; get kind of log file
  1427.     mov    dx,offset writetab    ; table of possibilities
  1428.     xor    bx,bx            ; help, when we get there
  1429.     call    comnd
  1430.     jnc    write1            ; nc = success
  1431.     mov    kstatus,ksgen        ; general cmd failure status
  1432.     ret
  1433. write1:    mov    temp,bx            ; save log file kind
  1434.     mov    comand.cmdonum,1    ; \number conversion allowed
  1435.     mov    comand.cmblen,cmdblen    ; use full length
  1436.     mov    ah,cmline        ; get string to be written
  1437.     mov    bx,offset rdbuf        ; where to put text
  1438.     mov    dx,offset msgtxt    ; help
  1439.     call    comnd
  1440.     jnc    wpkt0
  1441.     mov    kstatus,ksgen        ; general cmd failure status
  1442.     ret                ; c = failure
  1443. wpkt0:    mov    kstatus,kssuc        ; success status thus far
  1444.     mov    si,offset rdbuf        ; start of text in buffer
  1445.     mov    di,si            ; convert in-place, to asciiz
  1446.     mov    cx,ax            ; length for cnvlin
  1447.     call    cnvlin
  1448.     mov    bx,temp            ; log file kind
  1449.     jcxz    wpkt2            ; z = no chars to write
  1450.     mov    si,offset rdbuf
  1451.     cmp    bx,logpkt        ; Packet log?
  1452.     jne    wses1            ; ne = no
  1453. wpkt1:    lodsb                ; get byte to al
  1454.     call    pktcpt            ; write to packet log
  1455.     loop    wpkt1
  1456. wpkt2:    clc                ; say success
  1457.     ret
  1458.  
  1459. wses1:    cmp    bx,logses        ; Session log?
  1460.     jne    wtrn1            ; ne = no
  1461. wses2:    lodsb                ; get byte to al
  1462.     call    cptchr            ; write to log
  1463.     loop    wses2            ; do cx chars
  1464.     clc                ; say success
  1465.     ret
  1466.  
  1467. wtrn1:    cmp    bx,logtrn        ; Transaction log?
  1468.     jne    wtrn2            ; ne = no
  1469.     mov    bx,tloghnd        ; file handle
  1470.     jmp    short wtrn4
  1471.  
  1472. wtrn2:    cmp    bx,80h            ; WRITE SCREEN?
  1473.     jne    wtrn3            ; ne = no
  1474.     xor    bx,bx            ; handle is stdout
  1475.     jmp    short wtrn4
  1476.  
  1477. wtrn3:    cmp    bx,4002h        ; WRITE FILE?
  1478.     jne    wtrn5            ; ne = no, forget this
  1479.     mov    bx,vfwhandle        ; handle
  1480.  
  1481. wtrn4:    or    bx,bx            ; is handle valid?
  1482.     jl    wtrn5            ; l = no
  1483.     mov    dx,offset rdbuf
  1484.     mov    ah,write2        ; write to file handle in bx
  1485.     int    dos
  1486.     jc    wtrn4a            ; c = failure
  1487.     ret
  1488. wtrn4a:    mov    ah,prstr
  1489.     mov    dx,offset vfwbad    ; say error while writing
  1490.     int    dos
  1491.     mov    kstatus,ksgen
  1492.     stc
  1493.     ret
  1494. wtrn5:    mov    kstatus,ksgen        ; general cmd failure status
  1495.     mov    ah,prstr
  1496.     mov    dx,offset vfnofile    ; say no file
  1497.     int    dos
  1498.     stc
  1499.     ret
  1500. write    endp
  1501. code    ends
  1502.  
  1503. code1    segment
  1504.     assume    cs:code1
  1505.  
  1506. ; Convert ascii strings of the form "\{bnnn}" to a binary dword in dx:ax.
  1507. ; The braces are optional but must occur in pairs. Numeric base indicator "b"
  1508. ; is O or o or X or x or D or d or missing, for octal, hex, or decimal (def).
  1509. ; Enter with si pointing at "\".
  1510. ; Returns binary value in ax with carry clear and si to right of "}" or at
  1511. ; terminating non-numeric char if successful; otherwise, a failure,
  1512. ; return carry set with si = entry value and first read char in al.
  1513. ; Public byte  atoibyte  is used to control conversion of one character, if
  1514. ;  non-zero, or as many as can be parsed if zero. This routine always clears
  1515. ;  atoibyte upon exiting.
  1516. ; atoi_err byte values, carry bit state, meaning
  1517. ; 0 nc    successfully converted, can accept more data
  1518. ; 1 nc    successfully converted and string is terminated
  1519. ; 2 nc    successfully converted with break char pointed to by SI
  1520. ; 4 c    insufficient bytes to resolve
  1521. ; 8 c    syntax error in expression, cannot convert
  1522. atoi    proc    far
  1523.     push    temp
  1524.     push    temp1
  1525.     push    cx            ; save working reg
  1526.     push    si            ; save entry si
  1527.     push    bx
  1528.     push    ax            ; save read char
  1529.     xor    ax,ax
  1530.     mov    temp,ax
  1531.     mov    temp1,ax
  1532.     mov    atoi_err,al        ; assume success and can read more
  1533.     xor    bx,bx            ; assume no opening brace
  1534.     cld
  1535.     mov    cx,atoi_cnt        ; bytes available to examine
  1536.     or    cx,cx
  1537.     jnz    atoi1
  1538.     mov    atoi_cnt,16        ; safety
  1539. atoi1:    call    atoi_read        ; read a byte or fail
  1540.     jnc    atoi1a
  1541.     jmp    atoix            ; fail
  1542.  
  1543. atoi1a:    cmp    al,' '            ; leading space?
  1544.     je    atoi1            ; e = yes, read again, for do_math
  1545.     cmp    al,'\'            ; number introducer?
  1546.     jne    atoi1b            ; ne = no
  1547.     call    atoi_read        ; get next byte
  1548.     jnc    atoi1b
  1549.     jmp    atoix
  1550.  
  1551. atoi1b:    cmp    al,braceop        ; opening brace?
  1552.     jne    atoi1c            ; ne = no
  1553.     mov    bl,bracecl        ; remember a closing brace is needed
  1554.     call    atoi_read        ; get next byte
  1555.     jnc    atoi1c
  1556.     jmp    atoix
  1557.  
  1558. atoi1c:    call    isnumbase        ; number base introducer?
  1559.     jc    atoi1d            ; c = no
  1560.     call    atoi_read        ; get next byte
  1561.     jnc    atoi2            ; nc = got a byte
  1562.     jmp    atoix
  1563. atoi1d:    mov    nbase,10        ; assume base 10
  1564.     mov    cx,3            ; and three digits per char
  1565.  
  1566. atoi2:    call    cnvdig            ; do we have a digit now?
  1567.     jnc    atoi2a            ; nc = yes
  1568.     mov    atoi_err,8        ; syntax error, digit required
  1569.     jmp    atoix
  1570. atoi2a:    dec    si            ; back over it for read below
  1571.     inc    atoi_cnt
  1572.     mov    ax,cx            ; number base byte count
  1573.     mov    cx,atoi_cnt        ; available bytes
  1574.     cmp    atoibyte,0        ; read as many bytes as possible?
  1575.     je    atoi3            ; e = yes
  1576.     cmp    ax,cx            ; number base wants more than we have?
  1577.     ja    atoi3            ; a = yes, use available bytes
  1578.     mov    cx,ax            ; limit loop to num base requirements
  1579.     mov    atoi_err,1        ; presume successful and terminated
  1580.  
  1581. atoi3:    call    atoi_read        ; get a byte
  1582.     jc    atoix            ; c = failed
  1583.     call    cnvdig            ; convert ascii to binary digit
  1584.     jc    atoi4            ; c = cannot convert, SI-1 is break
  1585.     xor    ah,ah            ; clear high order value
  1586.     cmp    atoibyte,0        ; read as many bytes as possible?
  1587.     je    atoi3b            ; e = yes
  1588.     push    ax            ; test for fitting into byte result
  1589.     mov    ax,temp            ; current low order value
  1590.     mul    nbase            ; times number base
  1591.     add    dx,ax            ; to dx, plus any overflow
  1592.     pop    ax
  1593.     add    dx,ax            ; next result would be in dx
  1594.     or    dh,dh            ; overflow beyond one byte
  1595.     jnz    atoi4            ; nz = cannot accept this byte
  1596.     cmp    cx,1            ; reading last byte?
  1597.     ja    atoi3b            ; a = no
  1598.     
  1599. atoi3b:    inc    bh            ; say we did a successful conversion
  1600.     push    ax            ; save this byte's value
  1601.     mov    ax,temp1
  1602.     mul    nbase            ; high order
  1603.     mov    temp1,ax        ; keep low order part of product
  1604.     mov    ax,temp
  1605.     mul    nbase            ; low order
  1606.     add    temp1,dx        ; high order carry
  1607.     mov    temp,ax            ; low order
  1608.     pop    ax            ; recover binary digit
  1609.     add    temp,ax
  1610.     adc    temp1,0
  1611.     loop    atoi3            ; get more
  1612.     jmp    short atoi4a        ; out of data, don't backup
  1613.                     ; here on break char in al
  1614.  
  1615. atoi4:    dec    si            ; backup to reread terminator
  1616.     inc    atoi_cnt
  1617.     mov    atoi_err,2        ; terminated on break char
  1618. atoi4a:    or    bl,bl            ; closing brace needed?
  1619.     jz    atoi6            ; z = no, success so far
  1620. atoi5:    call    atoi_read        ; get a byte for brace
  1621.     jnc    atoi5a
  1622.     cmp    atoi_cnt,0        ; out of counts?
  1623.     je    atoix            ; e = yes
  1624. atoi5a:    cmp    al,bl            ; the closing brace?
  1625.     jne    atoi5b            ; ne = no
  1626.     mov    atoi_err,1        ; success, terminator seen (brace)
  1627.     jmp    atoi6
  1628. atoi5b:    cmp    al,' '            ; space padding?
  1629.     je    atoi5            ; e = yes, skip it
  1630. atoi5c:    mov    atoi_err,8        ; syntax error (failed to get brace)
  1631.     jmp    atoix
  1632.  
  1633. atoi6:    or    bh,bh            ; did we do any conversion?
  1634.     jz    atoix            ; z = no
  1635.     pop    ax            ; throw away old saved ax
  1636.     pop    bx            ; restore bx
  1637.     pop    ax            ; throw away starting si, keep current
  1638.     pop    cx            ; restore old cx
  1639.     mov    dx,temp1
  1640.     mov    ax,temp
  1641.     pop    temp1
  1642.     pop    temp
  1643.     mov    atoibyte,0
  1644.     mov    atoi_cnt,0
  1645.     clc                ; clear carry for success
  1646.     ret
  1647. atoix:    pop    ax            ; restore first read al
  1648.     pop    bx
  1649.     pop    si            ; restore start value
  1650.     pop    cx            ; restore old cx
  1651.     pop    temp1
  1652.     pop    temp
  1653.     xor    dx,dx
  1654.     mov    atoibyte,0
  1655.     mov    atoi_cnt,0
  1656.     stc                ; set carry for failure
  1657.     ret
  1658. atoi    endp
  1659.  
  1660. ; Examine char in AL for being a number base indicator, O, X, D, in
  1661. ; either case.
  1662. ; If matched return carry clear, number base nbase set, and cx holding
  1663. ; the qty of bytes in a single character result value.
  1664. ; If not matched return carry set.
  1665. ; AL is preserved.
  1666. isnumbase proc    near
  1667.     push    ax            ; try for number bases
  1668.     cmp    al,'a'            ; lower case?
  1669.     jb    isnum1            ; b = no
  1670.     cmp    al,'z'            ; in range of lower case?
  1671.     ja    isnum1            ; a = no
  1672.     and    al,5fh            ; map to upper case
  1673. isnum1:    cmp    al,'O'            ; octal?
  1674.     jne    isnum2            ; ne = no
  1675.     mov    nbase,8            ; set number base
  1676.     cmp    atoibyte,0        ; all bytes?
  1677.     je    isnum4            ; e = yes
  1678.     mov    cx,3            ; three octal chars per final char
  1679.     jmp    short isnum4
  1680. isnum2:    cmp    al,'X'            ; hex?
  1681.     jne    isnum3            ; ne = no
  1682.     mov    nbase,16
  1683.     cmp    atoibyte,0        ; all bytes?
  1684.     je    isnum4            ; e = yes
  1685.     mov    cx,2            ; two hex chars per final char
  1686.     jmp    short isnum4
  1687. isnum3:    cmp    al,'D'            ; decimal?
  1688.     jne    isnum5            ; ne = no, syntax error
  1689.     mov    nbase,10
  1690.     cmp    atoibyte,0        ; all bytes?
  1691.     je    isnum4            ; e = yes
  1692.     mov    cx,3
  1693. isnum4:    pop    ax            ; successful result
  1694.     clc
  1695.     ret
  1696. isnum5:    pop    ax
  1697.     stc                ; carry set for failure
  1698.     ret
  1699. isnumbase endp
  1700.  
  1701. ; Read a byte from ds:si.
  1702. ; If success decrement byte atoi_cnt, inc si, return byte in AL, carry clear.
  1703. ; If failure return carry set, no change to atoi_cnt, AL unchanged.
  1704. atoi_read proc    near
  1705.     cmp    atoi_cnt,0        ; any bytes left?
  1706.     jg    atoi_read1        ; g = yes
  1707.     mov    atoi_err,4        ; c = insufficient bytes to resolve
  1708.     stc                ; return failure
  1709.     ret
  1710. atoi_read1:
  1711.     cld
  1712.     lodsb                ; get first char
  1713.     dec    atoi_cnt        ; one less byte availble
  1714.     clc
  1715.     ret
  1716. atoi_read endp
  1717.  
  1718.                     ; worker for atoi
  1719. cnvdig    proc    near            ; convert ascii code in al to binary
  1720.     push    ax            ; return carry set if cannot
  1721.     cmp    al,'a'            ; lower case hexadecimal candidate?
  1722.     jb    cnvdig1            ; b = no
  1723.     sub    al,20h            ; lower case hex to upper
  1724. cnvdig1:cmp    al,'A'            ; uppercase hex
  1725.     jb    cnvdig2
  1726.     sub    al,'A'-10-'0'        ; 'A' becomes '10'
  1727. cnvdig2:sub    al,'0'            ; remove ASCII bias
  1728.     jc    cnvdigx            ; c = out of range
  1729.     cmp    al,byte ptr nbase    ; out of range?
  1730.     jae    cnvdigx            ; ae = yes, out of range
  1731.     add    sp,2            ; pop saved ax
  1732.     clc                ; success, binary value is in al
  1733.     ret
  1734. cnvdigx:pop    ax            ; return ax unchanged
  1735.     stc                ; c set for failure
  1736.     ret
  1737. cnvdig    endp    
  1738.  
  1739. decout    proc    far        ; display decimal number in ax
  1740.     push    ax
  1741.     push    cx
  1742.     push    dx
  1743.     mov    cx,10        ; set the numeric base
  1744.     call    mvalout        ; convert and output value
  1745.     pop    dx
  1746.     pop    cx
  1747.     pop    ax
  1748.     ret
  1749. decout    endp
  1750.  
  1751. mvalout    proc    near        ; output number in ax using base in cx
  1752.                 ; corrupts ax and dx
  1753.     xor    dx,dx        ; clear high word of numerator
  1754.     div    cx        ; (ax / cx), remainder = dx, quotient = ax
  1755.     push    dx        ; save remainder for outputting later
  1756.     or    ax,ax        ; any quotient left?
  1757.     jz    mvalout1    ; z = no
  1758.     call    mvalout        ; yes, recurse
  1759. mvalout1:pop    dx        ; get remainder
  1760.     add    dl,'0'        ; make digit printable
  1761.     cmp    dl,'9'        ; above 9?
  1762.     jbe    mvalout2    ; be = no
  1763.     add    dl,'A'-1-'9'    ; use 'A'--'F' for values above 9
  1764. mvalout2:mov    ah,conout
  1765.     int    dos
  1766.     ret
  1767. mvalout    endp
  1768.  
  1769.  
  1770. valout    proc    far        ; output number in ax using base in cx
  1771.                 ; corrupts ax and dx
  1772.     xor    dx,dx        ; clear high word of numerator
  1773.     div    cx        ; (ax / cx), remainder = dx, quotient = ax
  1774.     push    dx        ; save remainder for outputting later
  1775.     or    ax,ax        ; any quotient left?
  1776.     jz    valout1        ; z = no
  1777.     call    valout        ; yes, recurse
  1778. valout1:pop    dx        ; get remainder
  1779.     add    dl,'0'        ; make digit printable
  1780.     cmp    dl,'9'        ; above 9?
  1781.     jbe    valout2        ; be = no
  1782.     add    dl,'A'-1-'9'    ; use 'A'--'F' for values above 9
  1783. valout2:mov    ah,conout
  1784.     int    dos
  1785.     ret
  1786. valout    endp
  1787.  
  1788. ; Write binary number in AX as decimal asciiz to buffer pointer DS:DI.
  1789. dec2di    proc    far        ; output number in ax using base in cx
  1790.     push    ax
  1791.     push    cx
  1792.     push    dx
  1793.     mov    cx,10
  1794.     call    dec2di1        ; recursive worker
  1795.     pop    dx
  1796.     pop    cx
  1797.     pop    ax
  1798.     ret
  1799.  
  1800. dec2di1    proc    near        ; worker of dec2di
  1801.     xor    dx,dx        ; clear high word of numerator
  1802.     div    cx        ; (ax / cx), remainder = dx, quotient = ax
  1803.     push    dx        ; save remainder for outputting later
  1804.     or    ax,ax        ; any quotient left?
  1805.     jz    dec2di2        ; z = no
  1806.     call    dec2di1        ; yes, recurse
  1807. dec2di2:pop    dx        ; get remainder
  1808.     add    dl,'0'        ; make digit printable
  1809.     mov    [di],dl        ; store char in buffer
  1810.     inc    di
  1811.     mov    byte ptr[di],0    ; add terminator
  1812.     ret
  1813. dec2di1    endp
  1814. dec2di    endp
  1815.  
  1816. ; Perform math. Reads argptr string, returns binary value in DX:AX.
  1817. ; Expects pointer to string to be in domath_ptr and its length in domath_cnt.
  1818. ; Note that value and operator lists are stored on the stack in positive
  1819. ; order (increasing array values are at increasing addresses, not in push
  1820. ; order).
  1821. ; Returns carry set if error.
  1822. domath    proc    far
  1823.     push    bx
  1824.     push    cx
  1825.     push    si
  1826.     push    di
  1827.     mov    si,domath_ptr
  1828.     mov    di,domath_cnt
  1829.     mov    parendepth,0        ; parenthesis nesting depth
  1830.     call    domath_main
  1831.     mov    domath_msg,0        ; re-enable domath error messages
  1832.     jnc    domathx1
  1833.     mov    domath_ptr,si
  1834.     mov    domath_cnt,di
  1835. domathx1:    
  1836.     pop    di
  1837.     pop    si
  1838.     pop    cx
  1839.     pop    bx
  1840.     ret
  1841. domath    endp
  1842.  
  1843. domath_main proc near
  1844.     push    si
  1845.     push    bp
  1846.     sub    sp,size fevalst        ; counters and lists
  1847.     mov    bp,sp            ; remember base of lists
  1848.     mov    [bp].numcnt,0        ; no numbers in list
  1849.     mov    [bp].opcnt,0        ; no operators in list
  1850.     mov    [bp].numlist,0        ; returned value
  1851.     mov    [bp].numlist[2],0    ; high order returned value
  1852.     inc    parendepth        ; recursion limit counter
  1853.     cmp    parendepth,maxdepth    ; called too many times?
  1854.     jbe    domath0            ; be = no
  1855.     mov    matherr,offset opmsg4
  1856.     jmp    domath_error        ; a = too many parentheses
  1857.  
  1858. domath0:call    gettoken        ; read a token from string
  1859.     jc    domath_exit        ; c = nothing present
  1860.     cmp    bl,'O'            ; operator?
  1861.     je    domath1            ; e = yes
  1862.     cmp    [bp].numcnt,2        ; have two numbers (num num)?
  1863.     jb    domath0            ; b = no, get an operator
  1864.     mov    matherr,offset opmsg1    ; missing operator
  1865.     jmp    domath_error        ; exit with grammar error
  1866.  
  1867.     ; have initial operator in AX, decide in/pre/post-fix style
  1868. domath1:cmp    al,'!'            ; postfix? (number is on stack)
  1869.     jne    domath2            ; ne = no
  1870.     call    domath_calc1        ; do math on one arg, result on stack
  1871.     jc    domath_error        ; failure, exit
  1872.     jmp    short domath0        ; done here, get next tokens
  1873.  
  1874.                     ; prefix or infix?
  1875. domath2:call    gettoken        ; get expected following number
  1876.     jc    domath_error        ; c = eof, unexpected, error
  1877.     cmp    bl,'N'            ; got the number?
  1878.     jne    domath4            ; ne = no, operator
  1879. domath3:call    domath_la        ; call lookahead proc
  1880.     ; c clear, bl = N for use current number on stack
  1881.     ; c clear, bl = O for have higher prec operator on stack & ax, delay
  1882.     ; c clear, bl = F for read end of file, no next operator
  1883.     ; c set,   bl = F for math failure, best to exit
  1884.     jc    domath_error        ; failure on math
  1885.     cmp    bl,'F'            ; end of file?
  1886.     je    domath_end        ; e = eof, do remaining math
  1887.     cmp    bl,'O'            ; found higher prec op (delay)?
  1888.     je    domath1            ; e = yes, do newest operator
  1889.     call    domath_calc2        ; bl = 'N', number ready, do math
  1890.     jc    domath_error        ; c = failure
  1891.     cmp    [bp].opcnt,0        ; any ops backlogged?
  1892.     jne    short domath3        ; be = try again to reduce back math
  1893.     jmp    domath0            ; start over
  1894.  
  1895.             ; Have op op. Is second op a prefix operator?
  1896. domath4:cmp    al,'~'            ; prefix?
  1897.     je    domath5            ; e = yes
  1898.     cmp    al,'-'            ; prefix, overload?
  1899.     je    domath5            ; e = yes
  1900.     cmp    al,'+'            ; prefix, overload?
  1901.     jne    domath_error        ; ne = no, inconsistent syntax
  1902.         ; could be  op number postfix  so look at next token to see
  1903.         ; and if so reduce <number postfix> before applying prefix.
  1904. domath5:call    gettoken        ; get expected number following prefix
  1905.     jc    domath_end        ; c = eof, do remaining math
  1906.     cmp    bl,'O'            ; operator?
  1907.     je    domath_error        ; e = yes, that makes op op op
  1908.     call    domath_la        ; do lookahead for postfix
  1909.     jc    domath_error        ; c = failure on math
  1910.     call    domath_calc1        ; do prefix calculation now
  1911.     jc    domath_error        ; c = failure
  1912.     call    popop            ; get first operator to ax
  1913.     call    pushop            ; put it back as if just read
  1914.     mov    bl,'O'            ; mark as operator
  1915.     jmp    short domath3        ; reanalyze from new operator
  1916.  
  1917.                     ; end of data, finish up math & exit
  1918. domath_end:                ; do calcs remaining on stack
  1919.     cmp    [bp].opcnt,0        ; operators remaining to be done?
  1920.     je    domath_exit        ; e = no
  1921.     call    domath_calc2        ; finish math
  1922.     jc    domath_error        ; c = failure
  1923.     jmp    short domath_end    ; keep trying til no more operators
  1924.  
  1925. domath_error:                ; math errors seen, exit in error
  1926.     mov    cx,1            ; set carry for error
  1927.     jmp    short domath_exit1
  1928.  
  1929. domath_exit:                ; only way out, restore stack
  1930.     xor    cx,cx            ; assume success, cx = error counter
  1931. domath_exit1:
  1932.     dec    parendepth        ; nesting depth
  1933.     cmp    [bp].numcnt,1        ; only one value remaning?
  1934.     je    domath_exit2        ; e = yes, that's good
  1935.     jb    domath_exit2a        ; b = no numbers, empty arg
  1936.     jcxz    domath_exit2        ; z = no error
  1937.  
  1938.     cmp    domath_msg,0        ; msgs permitted?
  1939.     jnz    domath_exit2a        ; nz = no
  1940.     mov    matherr,offset opmsg1    ; missing operator
  1941. domath_exit2a:
  1942.     inc    cx            ; say error
  1943. domath_exit2:
  1944.     cmp    [bp].opcnt,0        ; used all operators?
  1945.     je    domath_exit3        ; e = yes
  1946.     mov    matherr,offset opmsg    ; too many operators
  1947.     inc    cx            ; say error
  1948.  
  1949. domath_exit3:                ; all returns
  1950.     mov    ax,[bp].numlist        ; returned value
  1951.     mov    dx,[bp].numlist[2]    ; high order part
  1952.     mov    sp,bp            ; base of lists
  1953.     add    sp,size fevalst        ; counters and lists
  1954.     or    cx,cx            ; any errors?
  1955.     jz    domath_exit4        ; z = no (clears carry bit)
  1956.     cmp    domath_msg,0        ; ok to complain?
  1957.     jne    domath_exit3a        ; ne = no, keep quiet
  1958.     mov    ah,prstr
  1959.     mov    dx,matherr        ; math error pointer
  1960.     or    dx,dx            ; if any
  1961.     jz    domath_exit3a        ; z = none
  1962.     push    dx
  1963.     mov    dx,offset crlf
  1964.     int    dos
  1965.     pop    dx
  1966.     int    dos            ; display error message
  1967. domath_exit3a:
  1968.     xor    ax,ax            ; return zero on errors
  1969.     xor    dx,dx
  1970.     stc                ; set carry for fail
  1971. domath_exit4:
  1972.     mov    matherr,0
  1973.     pop    bp
  1974.     pop    si
  1975.     ret                ; all done. Result in DX:AX
  1976. domath_main endp
  1977.  
  1978. ; Worker for domath. Reads argptr, inc's it, dec's arglen. Recognizes
  1979. ; numbers (with or without leading \), recognizes math operators and ().
  1980. ; Returns numbers as binary in DX:AX and BL = 'N',
  1981. ; returns operator and precedence in AL and AH with BL = 'O'. 
  1982. ; Returns Carry set and BL = 'F' if neither kind of token.
  1983. ; Tolerates leading whitespace.
  1984. ; Uses domath_ptr as source pointer, domath_cnt as source count.
  1985. ; Array domath_tmp is owned by this routine as private space.
  1986. gettoken proc    near
  1987.     xor    ax,ax            ; no operator, lowest precedence
  1988.     xor    dx,dx
  1989.  
  1990. gettok0:cmp    domath_cnt,0        ; anything to read?
  1991.     jg    gettok1            ; g = yes
  1992.     mov    bl,'F'            ; F for end of file, failure
  1993.     stc
  1994.     ret
  1995.  
  1996. gettok1:mov    si,domath_ptr
  1997.     mov    al,byte ptr [si]
  1998.     cmp    al,' '            ; leading whitepace?
  1999.     jne    gettok1a        ; ne = no
  2000.     inc    domath_ptr
  2001.     dec    domath_cnt
  2002.     jmp    short gettok0
  2003.  
  2004. gettok1a:jb    gettok1b        ; b = non-printable
  2005.     cmp    al,127
  2006.     jb    gettok2            ; b = printable
  2007. gettok1b:mov    bl,'F'            ; declare F for end of file, failure
  2008.     mov    domath_cnt,0        ; truncate string
  2009.     clc
  2010.     ret
  2011.  
  2012. gettok2:mov    cx,domath_cnt
  2013.     mov    atoi_cnt,cx
  2014.     call    atoi            ; convert DS:SI to number in DX:AX
  2015.     jc    gettok5            ; c = failed to convert number
  2016.     mov    cx,si
  2017.     sub    cx,domath_ptr        ; amount read
  2018.     sub    domath_cnt,cx        ; deduct that read
  2019.     mov    domath_ptr,si        ; break char
  2020.     call    pushval            ; push onto number stack
  2021.     mov    bl,'N'            ; say returning number
  2022.     ret                ; may have carry bit set
  2023.  
  2024. gettok5:mov    si,domath_ptr
  2025.     lodsb                ; reread non-numeric
  2026.     inc    domath_ptr
  2027.     dec    domath_cnt
  2028.     push    di            ; look for operators
  2029.     push    es
  2030.     mov    di,seg operators    ; list of math operators
  2031.     mov    es,di
  2032.     mov    di,offset operators
  2033.     mov    cx,operator_len        ; length of list
  2034.     cld
  2035.     repne    scasb            ; look for match
  2036.     pop    es
  2037.     je    gettok6            ; e = found a match
  2038.     pop    di
  2039.     cmp    domath_msg,0        ; allowed to display messages?
  2040.     jne    gettok5a        ; ne = no
  2041.     push    ax
  2042.     mov    ah,prstr
  2043.     mov    dx,offset crlf
  2044.     int    dos
  2045.     mov    dx,offset opmsg2    ; unknown symbol
  2046.     int    dos
  2047.     pop    ax
  2048.     mov    dl,al            ; unknown op
  2049.     mov    ah,conout
  2050.     int    dos
  2051.     mov    ah,prstr
  2052.     mov    dx,offset crlf
  2053.     int    dos
  2054. gettok5a:
  2055.     dec    domath_ptr        ; set to read on this symbol
  2056.     inc    domath_cnt
  2057.     mov    bl,'F'            ; say returning parse failure
  2058.     stc                ; fail
  2059.     ret
  2060. gettok6:sub    di,offset operators + 1    ; index into list
  2061.     mov    ah,precedence[di]    ; precedence to return
  2062.     pop    di
  2063.     mov    bl,'O'            ; say returning operator
  2064.     cmp    al,'('            ; start recursion?
  2065.     je    gettok7
  2066.     cmp    al,')'            ; closure?
  2067.     je    gettok9            ; e = yes, it's an EOF here
  2068.     call    pushop            ; push operator on op stack
  2069.     clc
  2070.     ret
  2071.  
  2072. gettok7:call    domath_main        ; '(', invoke new scan
  2073.     jnc    gettok8            ; nc = succeeded
  2074.     ret                ; c = return failure
  2075. gettok8:call    pushval            ; push returned DX:AX
  2076.     mov    bl,'N'            ; report number
  2077.     ret                ; may have carry bit set
  2078.  
  2079. gettok9:mov    bl,'O'
  2080.     stc                ; ')' returns EOF
  2081.     ret
  2082. gettoken endp
  2083.  
  2084. ; Lookahead processor. Have ...<op><number> on stack
  2085. ; Return bl = N for return number present on stack, carry clear
  2086. ; Return bl = O for return higher prec operator on stack, carry clear
  2087. ; Return bl = F and carry clear for end of file
  2088. ; Return bl = F and carry set for math failure (errors)
  2089.  
  2090. domath_la proc near
  2091.     call    gettoken        ; expect operator or end of file
  2092.     jnc    domath_la1        ; nc = success
  2093.     mov    bl,'F'            ; say eof
  2094.     clc                ; carry clear for eof
  2095.     ret
  2096.  
  2097. domath_la1:
  2098.     cmp    bl,'O'            ; lookahead operator?
  2099.     je    domath_la2        ; e = yes
  2100.     mov    bl,'F'            ; fail, case of number number
  2101.     stc                ; syntax error, signal quit
  2102.     ret
  2103.  
  2104. domath_la2:
  2105.     mov    si,[bp].opcnt        ; get size of op list
  2106.     dec    si            ; zero based index
  2107.     or    si,si            ; sanity check, should be > 0
  2108.     jnz    domath_la2a        ; nz = have current op available
  2109.     mov    bl,'F'            ; signal total failure
  2110.     stc
  2111.     ret
  2112. domath_la2a:
  2113.     shl    si,1            ; index words
  2114.     mov    ax,[bp].oplist[si]    ; lookahead operator
  2115.     mov    cx,[bp].oplist[si-2]    ; currently active operator
  2116.     cmp    ah,ch            ; lookahead versus current op
  2117.     ja    domath_la3        ; a = lookahead is higher, delay
  2118.     call    popop            ; remove lookahead operator from stack
  2119.     dec    domath_ptr        ; set to reread operator
  2120.     inc    domath_cnt
  2121.     mov    bl,'N'            ; signal number ready on stack
  2122.     clc
  2123.     ret
  2124.  
  2125. domath_la3:                ; delay
  2126.     cmp    al,'!'            ; postfix on number?
  2127.     jne    domath_la5        ; ne = no, another operator, delay
  2128.     call    domath_calc1        ; combine number!, report number
  2129.     jnc    domath_la4        ; nc = success, use number on stack
  2130.     mov    bl,'F'            ; report failed
  2131.     ret                ; carry set
  2132.  
  2133. domath_la4:mov    bl,'N'            ; report number is on stack
  2134.     clc                ; say success
  2135.     ret
  2136.  
  2137. domath_la5:mov    bl,'O'        ; lookahead (delayed op) is on stack and ax
  2138.     clc            ; bl = 'O', signal delay and lookahead op
  2139.     ret            ; is on the stack
  2140. domath_la endp
  2141.  
  2142. ; Calculate results of top operator and one top value.
  2143. ; Return value on top of the value stack.
  2144. ; Returns carry set if failure
  2145. ; Pops one operator, and zero (failure) or one value from stack before
  2146. ; starting.
  2147. domath_calc1    proc    near
  2148.     mov    si,[bp].opcnt        ; count of operators
  2149.     cmp    si,0            ; any?
  2150.     jg    dom_c1_1a        ; g = yes
  2151.     mov    matherr,offset opmsg3
  2152.     stc                ; fail
  2153.     ret
  2154. dom_c1_1a:
  2155.     cmp    [bp].numcnt,0        ; one or more values?
  2156.     jne    dom_c1_1b        ; ne = yes
  2157.     mov    matherr,offset opmsg    ; too few values
  2158.     stc
  2159.     ret
  2160. dom_c1_1b:
  2161.     call    popop            ; get top operator from list to AX
  2162.     mov    mathkind,al        ; operation to do
  2163.     call    popval            ; get first value from list to DX:AX
  2164.  
  2165.     cmp    mathkind,'!'        ; factorial?
  2166.     jne    dom_c1c            ; ne = no
  2167.     mov    bx,ax            ; save argument
  2168.     mov    cx,ax
  2169.     mov    ax,-1            ; default for too large an arg
  2170.     mov    dx,ax
  2171.     cmp    cx,10            ; largest within 32 bits?
  2172.     ja    dom_c1b            ; a = too large, report -1
  2173.     mov    ax,1            ; default for 0! and 1!
  2174.     xor    dx,dx
  2175.     sub    cx,ax
  2176.     jle    dom_c1b            ; le = special cases of 0 and 1
  2177.     mov    ax,bx            ; recover argument
  2178. dom_c1a:mul    cx
  2179.     loop    dom_c1a
  2180. dom_c1b:jmp    dom_c1_1x
  2181.  
  2182. dom_c1c:cmp    mathkind,'~'        ; logical not?
  2183.     jne    dom_c1d            ; ne = no
  2184.     not    ax            ; 1's complement
  2185.     not    dx
  2186.     jmp    dom_c1_1x
  2187.  
  2188. dom_c1d:cmp    mathkind,'-'        ; negate?
  2189.     jne    dom_c1e            ; ne = no
  2190.     neg    dx
  2191.     neg    ax            ; change sign
  2192.     sbb    dx,0
  2193.     jmp    dom_c1_1x
  2194.  
  2195. dom_c1e:cmp    mathkind,'+'        ; unary '+'?
  2196.     je    dom_c1_1x        ; e = yes
  2197.  
  2198. dom_c1f:stc                ; unknown operator
  2199.     mov    matherr,offset opmsg2
  2200.     ret
  2201. dom_c1_1x:
  2202.     call    pushval
  2203.     ret                ; may have carry bit set
  2204. domath_calc1 endp
  2205.  
  2206. ; Calculate results of top operator and two top values.
  2207. ; Return value on top of the value stack.
  2208. ; Returns carry set if failure
  2209. ; Pops one operator, and one (failure) or two values from stack before
  2210. ; starting.
  2211. domath_calc2 proc near
  2212.     cmp    [bp].numcnt,2        ; two or more args?
  2213.     jb    domath_calc1        ; b = no, do 1 arg math
  2214.  
  2215.     call    popop            ; get top operator from list to AX
  2216.     jnc    dom_c2_2a        ; nc = success
  2217.     mov    matherr,offset opmsg3
  2218.     ret                ; fail
  2219. dom_c2_2a:
  2220.     mov    mathkind,al        ; operation to do
  2221.     call    popval            ; get first value from list to DX:AX
  2222.     mov    bx,ax            ; right side, low order
  2223.     mov    cx,dx            ; right side, high order
  2224.     call    popval            ; first (left side) to dx:ax
  2225.     cmp    mathkind,'^'        ; raise arg1 to power of arg2?
  2226.     jne    dom_c2_6        ; ne = no
  2227.     mov    cx,bx            ; use low order of exponent
  2228.     dec    cx            ;
  2229.     cmp    cx,31            ; largest exponent we allow
  2230.     jbe    dom_c2_1        ; be = ok
  2231.     mov    ax,-1            ; report -1 as overflow result
  2232.     cwd
  2233.     jc    dom_c2_2y        ; c = overflow error
  2234. dom_c2_1:or    cl,cl            ; zero power?
  2235.     jne    dom_c2_2        ; ne = no
  2236.     mov    ax,1            ; report 1
  2237.     xor    dx,dx
  2238.     jmp    dom_c2_2x
  2239. dom_c2_2:push    si
  2240.     push    di
  2241.     mov    si,ax            ; original number
  2242.     mov    di,dx
  2243. dom_c2_3:push    cx            ; save loop counter
  2244.     mov    cx,di
  2245.     mov    bx,si            ; original number
  2246.     call    lmul            ; use long multiply
  2247.     pop    cx
  2248.     jc    dom_c2_4        ; c = overflow
  2249.     loop    dom_c2_3
  2250.     pop    di
  2251.     pop    si
  2252.     jmp    dom_c2_2x
  2253. dom_c2_4:pop    di
  2254.     pop    si
  2255.     stc
  2256.     jmp    dom_c2_2y        ; failure from overflow
  2257.  
  2258. dom_c2_6:cmp    mathkind,'*'        ; times?
  2259.     jne    dom_c2_7        ; ne = no
  2260.     call    lmul            ; do 32 bit signed multiply
  2261.     jc    dom_c2_2y        ; c = overflow error
  2262.     jmp    dom_c2_2x
  2263.  
  2264. dom_c2_7:cmp    mathkind,'/'        ; divide?
  2265.     jne    dom_c2_8        ; ne = no
  2266.     call    ldiv
  2267.     jc    dom_c2_2y        ; c = overflow error
  2268.     jmp    dom_c2_2x
  2269.  
  2270. dom_c2_8:cmp    mathkind,'%'        ; modulo?
  2271.     jne    dom_c2_9        ; ne = no
  2272.     call    ldiv            ; divide
  2273.     jc    dom_c2_2y        ; c = overflow error
  2274.     xchg    cx,dx            ; get remainder to dx:ax
  2275.     xchg    bx,ax
  2276.     jmp    dom_c2_2x
  2277.  
  2278. dom_c2_9:cmp    mathkind,'&'        ; logical AND?
  2279.     jne    dom_c2_11        ; ne = no
  2280.     and    ax,bx
  2281.     and    dx,cx
  2282.     jmp    dom_c2_2x
  2283.  
  2284. dom_c2_11:cmp    mathkind,'+'        ; addition?
  2285.     jne    dom_c2_12        ; ne = no
  2286. dom_c2_11a:
  2287.     push    si
  2288.     mov    si,dx            ; get sign bit
  2289.     xor    si,cx            ; different? if so then 1
  2290.     add    ax,bx
  2291.     adc    dx,cx
  2292.     test    si,8000h        ; check for case of same start signs
  2293.     jnz    dom_c2_11b        ; nz = different signs, no overflow
  2294.     mov    si,dx
  2295.     xor    si,cx            ; different
  2296.     test    si,8000h        ; different signs now?
  2297.     pop    si
  2298.     jnz    dom_c2_2y        ; nz = yes, overflow
  2299.     jmp    dom_c2_2x
  2300. dom_c2_11b:pop    si
  2301.     jmp    dom_c2_2x
  2302.  
  2303. dom_c2_12:cmp    mathkind,'-'        ; subtraction?
  2304.     jne    dom_c2_13        ; ne = no
  2305.     neg    cx
  2306.     neg    bx            ; change sign of right side number
  2307.     sbb    cx,0
  2308.     jmp    short dom_c2_11a    ; now do addition with bounds check
  2309.  
  2310. dom_c2_13:cmp    mathkind,'|'        ; logical OR?
  2311.     jne    dom_c2_14        ; ne = no
  2312.     or    ax,bx
  2313.     or    dx,cx
  2314.     jmp    dom_c2_2x
  2315.  
  2316. dom_c2_14:cmp    mathkind,'#'        ; exclusive OR?
  2317.     jne    dom_c2_15        ; ne = no
  2318.     xor    ax,bx
  2319.     xor    dx,cx
  2320.     jmp    dom_c2_2x
  2321.  
  2322. dom_c2_15:cmp    mathkind,'@'        ; GCD?
  2323.     jne    dom_c2_16        ; ne = no
  2324.     call    lgcd            ; call the gcd routine
  2325.     jc    dom_c2_2y        ; c = overflow error
  2326.     jmp    dom_c2_2x
  2327. dom_c2_16:stc
  2328.     ret                ; unknown operator
  2329.  
  2330. dom_c2_2x:
  2331.     call    pushval            ; store result
  2332.     ret
  2333. dom_c2_2y:
  2334.     call    pushval            ; store result (typically -1)
  2335.     mov    matherr,offset opmsg3
  2336.     stc                ; say failure of math
  2337.     ret
  2338. domath_calc2 endp
  2339.  
  2340. ; Push operator (AL) and precedence (AH) onto the operator stack.
  2341. ; Increments [bp].opcnt.
  2342. ; Return carry set if no room.
  2343. pushop    proc    near
  2344.     mov    si,[bp].opcnt        ; count of operators
  2345.     cmp    si,listlen        ; list full?
  2346.     jae    pushop1            ; ae = yes, fail
  2347.     shl    si,1            ; words
  2348.     mov    [bp].oplist[si],ax    ; save operator (AL) and preced (AH)
  2349.     inc    [bp].opcnt        ; one more operator in the list
  2350.     clc                ; success
  2351.     ret
  2352. pushop1:mov    matherr,offset opmsg1
  2353.     stc                ; fail
  2354.     ret
  2355. pushop    endp
  2356.  
  2357. ; Pop current opcode from op stack to AX. Decrements [bp].opcnt.
  2358. ; Returns carry set if no operators are available
  2359. popop    proc    near
  2360.     mov    si,[bp].opcnt        ; count of operators in list
  2361.     or    si,si            ; any?
  2362.     jz    popop1            ; z = no, exit
  2363.     dec    si            ; index from zero
  2364.     shl    si,1            ; words
  2365.     mov    ax,[bp].oplist[si]    ; get lookahead (last) operator
  2366.     dec    [bp].opcnt
  2367.     clc                ; success
  2368.     ret
  2369. popop1:    mov    matherr,offset opmsg1
  2370.     stc                ; failed to op (empty list)
  2371.     ret
  2372. popop    endp
  2373.  
  2374. ; Push value in DX:AX onto value stack. Increments [bp].numcnt.
  2375. ; Returns carry set if not enough space.
  2376. pushval    proc    near
  2377.     mov    si,[bp].numcnt
  2378.     cmp    si,listlen        ; at limit of list?
  2379.     ja    pushval1        ; a = exceeded list length, fail
  2380.     shl    si,1            ; address dwords
  2381.     shl    si,1
  2382.     mov    [bp].numlist[si],ax    ; push dx:ax onto value stack
  2383.     mov    [bp].numlist[si+2],dx    ; high order part
  2384.     inc    [bp].numcnt        ; occupancy is one greater
  2385.     clc                ; succeed
  2386.     ret
  2387. pushval1:stc                ; fail
  2388.     ret
  2389. pushval    endp
  2390.  
  2391. ; Pop top value from value stack into DX:AX. Decrements [bp].numcnt.
  2392. ; Returns carry set if no value were available.
  2393. popval    proc    near
  2394.     mov    si,[bp].numcnt        ; count of values in list
  2395.     or    si,si            ; count
  2396.     jz    popval1            ; z = none
  2397.     dec    si            ; index from 0
  2398.     shl    si,1            ; address dwords
  2399.     shl    si,1
  2400.     mov    ax,[bp].numlist[si]    ; pop top value to dx:ax
  2401.     mov    dx,[bp].numlist[si+2]    ; high order part
  2402.     dec    [bp].numcnt        ; occupancy is one less
  2403.     clc                ; success
  2404.     ret
  2405. popval1:stc                ; fail
  2406.     ret
  2407. popval    endp
  2408.                     ; end of domath procedures
  2409.  
  2410. ; Perform 32 bit division. Numerator is in DX:AX, denominator in CX:BX.
  2411. ; Returns quotient in DX:AX, remainder in CX:BX. Carry set and -1 on
  2412. ; divide by zero.
  2413. ldiv    proc    far
  2414.     push    temp
  2415.     push    temp1
  2416.     push    si
  2417.     push    di
  2418.     mov    tmp,0            ; holds final sign (0=positive)
  2419.     or    dx,dx            ; numerator is negative?
  2420.     jge    ldiv1            ; ge = no
  2421.     neg    dx
  2422.     neg    ax
  2423.     sbb    dx,0            ; change sign
  2424.     xor    tmp,1            ; remember to change sign later
  2425. ldiv1:    or    cx,cx            ; denominator is negative?
  2426.     jge    ldiv2            ; ge = no
  2427.     neg    cx
  2428.     neg    bx
  2429.     sbb    cx,0            ; change sign
  2430.     xor    tmp,1            ; remember to change sign later
  2431. ldiv2:    mov    di,cx            ; denominator, hold here
  2432.     mov    si,bx
  2433.     cmp    dx,cx            ; is numerator larger than denom?
  2434.     jne    ldiv10            ; ne = yes, and 32 bits too
  2435.     or    dx,dx            ; 32 bit number?
  2436.     jnz    ldiv10            ; nz = yes
  2437.                 ; only 16 bit numbers here
  2438.     or    bx,bx            ; denominator zero?
  2439.     jnz    ldiv3            ; nz = no
  2440.     jmp    ldivf            ; overflow, report failure
  2441.  
  2442. ldiv3:    div    bx            ; regular signed division
  2443.     mov    bx,dx            ; remainder
  2444.     xor    dx,dx            ; high quotient
  2445.     xor    cx,cx            ; high remainder
  2446.     jmp    ldivx            ; exit success
  2447.  
  2448.                 ; 32 bit numbers here
  2449. ldiv10:    mov    tmp1,0            ; shift counter
  2450.     mov    temp,0            ; shift accumulator, low part
  2451.     mov    temp1,0            ; shift accumulator, high part
  2452.     or    cx,cx            ; check for zero denominator
  2453.     jnz    ldiv11            ; nz = not zero
  2454.     or    bx,bx
  2455.     jz    ldivf            ; zero, exit failure
  2456.  
  2457. ldiv11:    cmp    dx,di            ; top vs bottom high order words
  2458.     jb    ldiv13            ; b = top smaller than bottom
  2459.     ja    ldiv12            ; a = top larger than bottom
  2460.                     ; high order words are the same
  2461.     cmp    ax,si            ; top vs bottom low order words
  2462.     jb    ldiv13            ; b = top eq or larger than bottom
  2463.     je    ldiv15            ; e = top equals bottom
  2464.                 ; top is larger than bottom
  2465. ldiv12:    or    di,di            ; can shift left further?
  2466.     js    ldiv14            ; s = no, accumulate and back down
  2467.     inc    tmp1            ; remember doing left shift
  2468.     shl    si,1            ; shift denominator left one bit
  2469.     rcl    di,1            ; include carry-out from low half
  2470.     jmp    short ldiv11        ; compare again til top < bot
  2471.  
  2472. ; either we start with top < bottom (tmp1 = 0), or we have left shifted
  2473. ; the bottom enough (tmp1 > 0) to create that condition.
  2474.  
  2475.                        ; top is smaller than or equal to bottom
  2476. ldiv13:    cmp    tmp1,0            ; any shifts remaining?
  2477.     je    ldiv16            ; e = no
  2478. ; If tmp1 is 0 then we are done, no further adjustments can be made.
  2479. ; Else back off tmp1 by one position
  2480.     dec    tmp1            ; shift right by 1 to get top >= bot
  2481.     shr    di,1
  2482.     rcr    si,1
  2483.  
  2484. ldiv14:    cmp    dx,di            ; is top less than bottom?
  2485.     jb    ldiv13            ; b = yes, shift again
  2486.     ja    ldiv15            ; a = no, greater than
  2487.     cmp    ax,si            ; low order part
  2488.     jb    ldiv13            ; b = top is less than bottom
  2489. ldiv15:    sub    ax,si            ; (top - bottom) to get remainder
  2490.     sbb    dx,di
  2491.     call    ldiv_acc        ; accumulate shifted success
  2492.     jmp    short ldiv14        ; try again til top < bot
  2493.  
  2494. ldiv16:    mov    bx,ax            ; remainder to cx:bx
  2495.     mov    cx,dx            ; quotient to dx:ax
  2496.     mov    ax,temp            ; extract accumlated shifts
  2497.     mov    dx,temp1        ; and exit success
  2498.  
  2499.                     ; successful exit, update signs
  2500. ldivx:    cmp    tmp,0            ; need to adjust signs?
  2501.     je    ldivx1            ; e = no
  2502.     neg    dx
  2503.     neg    ax            ; change sign of quotient
  2504.     sbb    dx,0
  2505.     neg    cx
  2506.     neg    bx            ; change sign of remainder
  2507.     sbb    cx,0
  2508. ldivx1:    pop    di
  2509.     pop    si
  2510.     pop    temp1
  2511.     pop    temp
  2512.     clc                ; success
  2513.     ret
  2514.  
  2515. ldivf:    mov    ax,-1            ; failure
  2516.     cwd                ; report -1
  2517.     mov    bx,ax
  2518.     mov    cx,ax
  2519.     pop    di            ; failure exit
  2520.     pop    si
  2521.     pop    temp1
  2522.     pop    temp
  2523.     stc                ; say failure
  2524.     ret
  2525.  
  2526. ldiv_acc proc    near            ; add current shift to accumulator
  2527.     push    cx
  2528.     push    ax
  2529.     push    dx
  2530.     mov    cl,tmp1            ; shift bit count
  2531.     xor    ch,ch
  2532.     mov    ax,1            ; value = 2 ** temp1
  2533.     xor    dx,dx
  2534.     jcxz    ldiv_acc2        ; z = nothing to do
  2535. ldiv_acc1:shl    ax,1
  2536.     rcl    dx,1
  2537.     loop    ldiv_acc1
  2538. ldiv_acc2:add    temp,ax            ; accumulate shifts
  2539.     adc    temp1,dx
  2540.     pop    dx
  2541.     pop    ax
  2542.     pop    cx
  2543.     ret
  2544. ldiv_acc endp
  2545. ldiv    endp
  2546.  
  2547. ; Multiplies 32 bit values in DX:AX by CX:BX and returns the result in
  2548. ; DX:AX. Overflows result in carry set and -1 as the answer. Signed
  2549. ; arithmetic is used here, beware.
  2550. lmul    proc    far
  2551.     push    si
  2552.     push    di
  2553.     push    bx
  2554.     push    cx
  2555.     push    temp
  2556.     mov    temp,0            ; zero means no sign change at end
  2557.     or    dx,dx            ; negative?
  2558.     jns    lmul1            ; ns = no
  2559.     neg    ax            ; make positive
  2560.     neg    dx
  2561.     sbb    dx,0
  2562.     xor    temp,1            ; sign change needed
  2563. lmul1:    or    cx,cx            ; ditto for cx:bx
  2564.     jns    lmul2
  2565.     neg    bx
  2566.     neg    cx
  2567.     sbb    cx,0
  2568.     xor    temp,1
  2569. lmul2:    or    cx,cx            ; check for high word in both numbers
  2570.     jz    lmul3            ; z = bottom does not have it
  2571.     or    dx,dx
  2572.     jnz    lmul4            ; nz = both have parts too large
  2573.  
  2574. lmul3:    push    dx
  2575.     push    ax
  2576.     mul    bx            ; low bottom time whole top
  2577.     mov    di,dx
  2578.     mov    si,ax            ; regular product to di:si
  2579.     pop    ax
  2580.     pop    dx            ; recover normal top
  2581.     push    dx
  2582.     push    ax
  2583.     mov    ax,dx
  2584.     mul    bx
  2585.     add    di,ax
  2586.     pop    ax
  2587.     pop    dx            ; recover normal top
  2588.     js    lmul4            ; s = overflow in high accumlator
  2589.     mul    cx            ; high bottom times regular top
  2590.     add    di,ax            ; high reg product plus new product
  2591.     jns    lmul5            ; ns = no overflow in high accumulator
  2592.  
  2593. lmul4:    mov    ax,-1            ; overflow, yield minus one as answer
  2594.     cwd                ; extend sign to dx
  2595.     mov    temp,0            ; no sign change
  2596.     stc                ; carry set for problem
  2597.     jmp    short lmul6
  2598. lmul5:    mov    dx,di            ; results to dx:ax
  2599.     mov    ax,si
  2600.     cmp    temp,0            ; sign change needed?
  2601.     je    lmul6            ; e = no
  2602.     neg    dx            ; flip output sign
  2603.     neg    ax
  2604.     sbb    dx,0
  2605.     clc                ; carry clear for no problem
  2606. lmul6:    pop    temp
  2607.     pop    cx
  2608.     pop    bx
  2609.     pop    di
  2610.     pop    si
  2611.     ret
  2612. lmul    endp
  2613.  
  2614. ; Greatest common divisor, 32 bit (removes signs). Inputs are DX:AX and
  2615. ; CX:BX. Results are in DX:AX. Carry bit set and -1 returned if error.
  2616. lgcd    proc    far
  2617.     push    bx
  2618.     push    cx
  2619.     or    dx,dx            ; negative?
  2620.     jns    lgcd1            ; ns = no
  2621.     neg    ax            ; make positive
  2622.     neg    dx
  2623.     sbb    dx,0
  2624. lgcd1:    or    cx,cx            ; negative?
  2625.     jns    lgcd2            ; ns = no
  2626.     neg    bx
  2627.     neg    cx            ; make positive
  2628.     sbb    cx,0
  2629. lgcd2:    cmp    dx,cx            ; first arg same/larger than second?
  2630.     ja    lgcd4            ; a = yes
  2631.     jb    lgcd3            ; b = smaller
  2632.     cmp    ax,bx            ; low order parts
  2633.     jae    lgcd4            ; ae = larger
  2634. lgcd3:    xchg    dx,cx            ; make largest the top number dx:ax
  2635.     xchg    ax,bx
  2636. lgcd4:    push    bx            ; preserve smaller number
  2637.     push    cx
  2638.     call    ldiv            ; large / small
  2639.     jc    lgcd6            ; c = divide by zero
  2640.     mov    dx,cx            ; temp spot
  2641.     or    dx,bx            ; remainder?
  2642.     jz    lgcd5            ; z = no, small is the answer
  2643.     pop    dx            ; new values, new top is old bot
  2644.     pop    ax            ; bottom is new remainder
  2645.     jmp    short lgcd2        ; repeat calculation
  2646. lgcd5:    pop    dx            ; recover smaller number from stack
  2647.     pop    ax            ; result in dx:ax
  2648.     pop    dx
  2649.     pop    cx
  2650.     clc
  2651.     ret                ; success
  2652. lgcd6:    pop    ax
  2653.     pop    ax            ; clean stack
  2654.     pop    dx
  2655.     pop    cx
  2656.     mov    ax,-1            ; dx:ax = -1 on error
  2657.     cwd
  2658.     stc
  2659.     ret
  2660. lgcd    endp
  2661.  
  2662. ; Convert ASCIIZ string in DS:SI of form hh:mm:ss to ASCIIZ string seconds
  2663. ; in ES:DI.
  2664. tod2secs proc    far
  2665.     mov    temp,0
  2666.     mov    temp1,0
  2667.     xor    dx,dx            ; dh=field counter, dl=read byte
  2668.     xor    bx,bx            ; three groups possible
  2669. tod2s1:    mov    dl,[si]            ; get a char
  2670.     inc    si            ; next char
  2671.     inc    dh            ; count char in field
  2672.     or    dl,dl            ; null terminator?
  2673.     jz    tod2s3            ; z = yes, wrap calculations and quit
  2674.     cmp    dl,':'            ; field separator?
  2675.     je    tod2s3            ; e = a separator, step fields
  2676.     sub    dl,'0'            ; remove ascii bias
  2677.     cmp    dl,9
  2678.     ja    short tod2s6        ; a = failure to get expected digit
  2679.     cmp    dh,2            ; more than two bytes in this field
  2680.     ja    tod2s6            ; a = yes, fail translation
  2681.     mov    al,bh            ; get sum to al
  2682.     mov    ah,10
  2683.     mul    ah            ; sum times ten
  2684.     add    al,dl            ; sum = 10 * previous + current
  2685.     mov    bh,al            ; current sum
  2686.     mov    ah,60
  2687.     or    bl,bl            ; doing hours?
  2688.     jne    tod2s2            ; ne = no, min, sec
  2689.     mov    ah,24            ; max for hours field
  2690. tod2s2:    cmp    bh,ah            ; more than legal?
  2691.     jae    tod2s6            ; ae = illegal
  2692.     jmp    short tod2s1        ; continue analysis
  2693.  
  2694. tod2s3:    mov    al,bh            ; current sum
  2695.     xor    ah,ah
  2696.     mov    cx,1
  2697.     cmp    bl,2            ; seconds?
  2698.     je    tod2s4            ; e = yes
  2699.     mov    cx,60
  2700.     or    bl,bl            ; hours?
  2701.     jne    tod2s4            ; ne = no
  2702.     mov    cx,60*60        ; seconds per hour
  2703. tod2s4:    mul    cx
  2704.     add    temp,ax
  2705.     adc    temp1,dx
  2706.     xor    bh,bh            ; bh = current field sum
  2707.     xor    dh,dh            ; dh = counter of bytes in field
  2708.     cmp    byte ptr [si-1],0    ; ended on null?
  2709.     je    tod2s5            ; e = yes, end of conversion
  2710.     inc    bl            ; point to next field
  2711.     cmp    bl,2            ; last field to use (secs)
  2712.     jbe    tod2s1            ; be = get more text
  2713. tod2s5:    mov    ax,temp
  2714.     mov    dx,temp1
  2715.     push    di
  2716.     mov    di,offset tmpstring    ; build ASCII in this buffer
  2717.     call    flnout
  2718.     pop    di
  2719.     mov    dx,offset tmpstring
  2720.     mov    si,dx
  2721.     call    strlen
  2722.     cld
  2723.     rep    movsb            ; copy string to es:di area
  2724.     mov    byte ptr es:[di],0    ; and null terminator
  2725.     clc                ; carry clear for success
  2726.     ret
  2727. tod2s6:    mov    byte ptr es:[di],0
  2728.     stc                ; carry set for illegal value    
  2729.     ret
  2730. tod2secs endp
  2731. code1    ends 
  2732.     end
  2733.