home *** CD-ROM | disk | FTP | other *** search
/ Phoenix CD 2.0 / Phoenix_CD.cdr / 01e / msk230s1.zip / MSSSCP.ASM < prev    next >
Assembly Source File  |  1988-02-12  |  58KB  |  1,105 lines

  1.         name mssscp
  2. ; File mssscp.asm
  3. ; Edit History
  4. ; Last edit: 1 Jan 1988
  5. ; 6 Jan 1988 Fix pointer for out @con calls. [jrd]
  6. ; 1 Jan 1988 version 2.30
  7. ; 26 Dec 1987 Use no-echo reading of console for OUTPUT @CON, speedup
  8. ;  reading of host response for OUTPUT command. [jrd]
  9. ; 4 Dec 1987 Update global byte errlev when a Script command Fails
  10. ;  (timeout or output failure or manual interruption). [jrd]
  11. ; 9 Oct 1987 Allow curly braced strings, trim trailing whitespace too. [jrd]
  12. ; 4 Oct 1987 Apply Set Display 7/8 bit mask to bytes rcv'd from serial port
  13. ;  after Set Translation Input filter. Log 8-bit chars in Debug mode. [jrd]
  14. ; 26 Sept 1987 Add check for Control-C interrupt to chkkbd and ECHO,
  15. ;  make Control-C in TRANSMIT command use squit exit. [jrd]
  16. ; 18 Aug 1987 Change ESC to escape for MASM 4.5+ [jrd]
  17. ; 11 Aug 1987 Add Set Send Pause plus 3 millisec wait before doing OUTPUT.[jrd]
  18. ; 31 July 1987 Open port reading to null chars et al. Correct timeofday
  19. ;  routine, from Jack Bryans. [jrd]
  20. ; 22 July 1987 Rewrite time of day material for no ambiguities. [jrd]
  21. ; 15 July 1987 Terminate strings read as @filespec on first carriage return.
  22. ;  Change number parsing to use decimal as default and \bddd for other bases.
  23. ; 24 May 1987 Add error recovery for outchr calls. [jrd]
  24. ; 10 May 1987 Add translation of input characters, rxtable. [jrd]
  25. ; 4 April 1987 Clear Echo's old text line, from Eberhard Lisse. [jrd]
  26. ; 18 March 1987 Add requests for command confirmation. [jrd]
  27. ; 2 March 1987 Remove test of Set Input Echo from OUTPUT command. [jrd]
  28. ; 27 Oct 1986 preserve data char in al around call to outchr in Output [jrd]
  29. ; 19 Oct 1986 Add "\b" and "\B" to Output procedure as send-a-Break command
  30. ;  to serial port comms line. [jrd]
  31. ; 1 Oct 1986 Version 2.29a
  32. ; 1 Oct 1986 Add 7/8 bit display mask to displayed text. [jrd]
  33. ; 12 Sept 1986 Add changes from Frank da Cruz: one second default timeout,
  34. ;  echo chars if Local Echo is On, Input command without a pattern should
  35. ;  behave like a Pause command.
  36. ;
  37. ; MS Kermit Script routines, DEC-20 style.
  38. ; Extensively rewritten for MS Kermit 2.29a by Joe R. Doupnik 5 July 86
  39. ;;
  40. ;    Created June, 1986 a.d.    By James Sturdevant
  41. ;                                         A. C. Nielsen Co. Mpls.
  42. ;                                         8401 Wayzata Blvd.
  43. ;                                         Minneapolis, Mn. 55426
  44. ;                                         (612)546-0600
  45. ;;;;;;;;
  46. ; Kermit command level usages and this file's entry points:
  47. ; Clear - clears serial port buffers. Procedure scclr.
  48. ; Echo text - displays text on local screen. Proc scecho.
  49. ; Pause [time] - waits indicated number of seconds (default is Input
  50. ;       Default-timeout, 1 second typically). Proc scpau.
  51. ; Input [time] text - waits up to time seconds while scanning serial port
  52. ;       input for a match with text. Default value for time is Input
  53. ;       Default-timeout, 1 second typically). Spaces or tabs are separators
  54. ;       between the time and text fields. Proc scinp.
  55. ;       A carriage return typed by the local user simulates a match.
  56. ; Output text - sends the text to the serial output port. Proc scout.
  57. ; Transmit text [prompt] - raw file transfer to host. Proceeds from source
  58. ;       line to source line upon receipt of prompt from host or carriage
  59. ;       return from us. Default prompt is linefeed. A null prompt (\0)
  60. ;       causes the file to be sent with no pausing or handshaking. Note
  61. ;       that linefeeds are stripped from outgoing material. Proc scxmit.
  62. ; In the above commands "text" may be replaced by "@filespec" to cause the
  63. ;       one line of that file to be used instead. @CON obtains one line of
  64. ;       text from the keyboard. Such "indirect command files" may be nested
  65. ;       to a depth of 100. Control codes are written as decimal numbers
  66. ;       in the form "\ddd" where d is a digit between 0 and 9. Carriage
  67. ;       return is \13, linefeed is \10, bell is \7; the special code \255
  68. ;       is used to match (Input) either cr or lf or both.
  69. ; These commands can be given individually by hand or automatically
  70. ;       in a Kermit Take file; Take files may be nested.
  71. ;;;;;;;;
  72. ; These routines expect to be invoked by the Kermit command dispatcher
  73. ; and can have their default operations controlled by the Kermit Set Input
  74. ; command (implemented in file mssset.asm). They parse their own cmd lines.
  75. ; Set Input accepts arguments of
  76. ;   Case Ignore or Observe  (default is ignore case when matching strings)
  77. ;   Default-timeout seconds (default is 5 seconds)
  78. ;   Echo On or Off      controls echoing of Input cmd text (default is Off)
  79. ;   Timeout-action Quit or Proceed (default is Proceed)
  80. ; These conditions are passed via global variables incasv,indfto,inecho,
  81. ;   inactv, respectively, stored here.
  82. ;;;;;;;;;
  83.  
  84.         include mssdef.h
  85.         public  scout, scinp, scpau, scecho, scclr, scxmit
  86.  
  87. linelen         equ     134             ; length of working buffer line
  88. prtbuflen       equ     128             ; serial port local buffer length
  89. maxtry          equ     5               ; maximum number of output retries
  90. stat_unk        equ     0               ; status return codes.
  91. stat_ok         equ     1               ; have a port character
  92. stat_cc         equ     2               ; control-C typed
  93. stat_tmo        equ     4               ; timeout
  94. stat_cr         equ     8               ; carriage return typed
  95.  
  96. datas   segment public 'datas'
  97.         public  indfto, inactv, incasv, inecho
  98.         extrn   taklev:byte, takadr:word, portval:word, flags:byte
  99.         extrn   rxtable:byte, spause:byte, errlev:byte
  100.  
  101.                                         ; global (public) variables
  102. inactv  db      0                       ; input action value (default proceed)
  103. incasv  db      0dfh                    ; input case  (default ignore)
  104. indfto  dw      1                       ; input and pause timeout (def 1 sec)
  105. inecho  db      1                       ; echo Input cmd text (0 = no)
  106.                                         ; local variables
  107. line    db      linelen+1 dup (?)       ; line of output or input + terminator
  108. prtbuf  db      prtbuflen dup (?)       ; serial port storage buffer
  109. bufcnt  dw      0                       ; serial port buf byte cnt, must be 0
  110. bufrdptr dw     prtbuf                  ; serial port buf read ptr
  111. bufwtptr dw     prtbuf                  ; serial port buf write ptr
  112. temptr  dw      ?                       ; temporary pointer
  113. temptr2 dw      ?                       ; ditto, points to end of INPUT string
  114. tempd   dw      ?                       ; temp
  115. tempa   db      ?                       ; another temp
  116. retry   db      0                       ; number of output retries
  117. status  dw      ?                       ; general status word
  118. fhandle dw      ?                       ; file handle storage place
  119. parmsk  db      7fh                     ; 7/8 bit parity mask
  120. lecho   db      ?                       ; local echo of output (0 = no)
  121. timout  dw      ?                       ; work area (seconds before timeout)
  122. timhms  db      4 dup (?)               ; hhmmss.s tod buffer
  123.  
  124. crlf    db      cr,lf,'$'
  125. xfrfnf  db      cr,lf,'?Transmit file not found$'
  126. xfrrer  db      cr,lf,'?error reading Transmit file$'
  127. xfrcan  db      cr,lf,'?transmission canceled$'
  128. indmis  db      '?Indirect file not found',cr,lf,'$'
  129. inderr  db      '?error reading indirect file',cr,lf,'$'
  130. tmomsg  db      cr,lf,'?Timeout$'
  131. outhlp  db      'line of text to be sent to remote host$'
  132. inphlp  db      'time limit and line of text expected from remote host$'
  133. echhlp  db      'line of text to echo to screen$'
  134. ptshlp  db      'number of seconds to pause$'
  135. xmthlp  db      'File specification with optional path name$'
  136. pmthlp  db      'Prompt character expected as an ACK from host (\0 for none)$'
  137. datas   ends
  138.  
  139. code    segment public 'code'
  140.  
  141.         extrn   comnd:near, clrbuf:near, prtchr:near, outchr:near, sendbr:near
  142.         extrn   cptchr:near, serini:near, serrst:near, pcwait:near, katoi:near
  143.         extrn   cnvstr:near
  144.         assume  cs:code, ds:datas
  145.  
  146. ; Clear input buffer(s) of serial port
  147. ; Clear command
  148. ;
  149. SCCLR   PROC    NEAR
  150.         mov     ah,cmcfm                ; get a confirm
  151.         call    comnd
  152.          jmp r                          ; no confirm
  153.          nop
  154.         call    bufclear                ; clear our serial port circular buf
  155.         call    clrbuf                  ; clear system serial port buffer too
  156.         jmp     rskp                    ; return success
  157. SCCLR   ENDP
  158. ;
  159. ; Echo a line of text to our screen
  160. ; Echo text
  161. ;
  162. SCECHO  PROC    NEAR
  163.         mov     ah,cmtxt                ; get a whole line of asciiz text
  164.         mov     bx,offset line          ; where to store in
  165.         mov     word ptr [bx],0         ; clear line
  166.         mov     dx,offset echhlp        ; help
  167.         call    comnd
  168.          jmp    rskp                    ; ignore parse error if no text
  169.         mov     si,offset line          ; start of line
  170.         mov     di,si                   ; convert to the same place
  171.         mov     ah,incasv               ; save current case state
  172.         push    ax
  173.         mov     incasv,0ffh             ; say no case conversion
  174.         call    cnvlin                  ; convert \numbers to binary
  175.         pop     ax
  176.         mov     incasv,ah               ; recover case state
  177.         jc      echo3                   ; carry set means error
  178.         mov     al,lf                   ; start with a linefeed
  179.         call    scdisp                  ; show it
  180.         jcxz    echo2                   ; z = nothing to show
  181. echo1:  push    cx                      ; save loop counter
  182.         cld
  183.         lodsb                           ; get a source char into al
  184.         push    si
  185.         call    scdisp                  ; display the char
  186.         pop     si
  187.         pop     cx
  188.         loop    echo1                   ; get another
  189. echo2:  jmp     rskp                    ; return success
  190. echo3:  ret                             ; error
  191. SCECHO  ENDP
  192.  
  193. ; Input from port command, match input with text pattern
  194. ; Input [timeout] text
  195. ;
  196. SCINP   PROC    NEAR
  197.         mov     ah,cmtxt                ; get a whole line of asciiz text
  198.         mov     bx,offset line          ; place to put text
  199.         mov     dx,offset inphlp        ; help message
  200.         call    comnd                   ; get the pattern text
  201.          jmp    r                       ; nothing, complain
  202.         mov     ah,cmcfm                ; get a confirm
  203.         call    comnd
  204.          jmp r                          ; no confirm
  205.          nop
  206.         cmp     taklev,0                ; are we in a Take file?
  207.         je      input0                  ; e = no, display linefeed
  208.         cmp     flags.takflg,0          ; are Take commands being echoed?
  209.         je      input1                  ; e = no, skip display
  210. input0: cmp     inecho,0                ; Input echo off?
  211.         je      input1                  ; e = yes
  212.         mov     al,lf                   ; next line
  213.         call    scdisp                  ; display the char
  214. input1: call    serini                  ; initialize the system's serial port
  215.         mov     status,stat_unk         ; clear status flag
  216.         call    inptim                  ; get the timeout time, sets si
  217.         mov     di,offset line          ; put text in compare buffer
  218.         call    cnvlin                  ; convert \numbers in buf line
  219.         jnc     input2                  ; nc = no error
  220.         ret                             ; else return on error
  221. input2: mov     parmsk,0ffh             ; parity mask, assume 8 bit data
  222.         mov     di,portval
  223.         cmp     [di].parflg,parnon      ; parity is none?
  224.         je      input2a                 ; e = none
  225.         mov     parmsk,07fh             ; else strip parity (8th) bit
  226. input2a:mov     di,offset line
  227.         mov     temptr,di               ; pointer to pattern char
  228.         mov     temptr2,di              ; and we need pointer to end of string
  229.         add     temptr2,cx              ; offset of end of string
  230.         cmp     cx,0                    ; empty pattern? (cnvlin sets cx=cnt)
  231.         jne     input4                  ; ne = not empty
  232.                                         ; empty. read, display, and discard
  233. input3: call    chkkbd                  ; check keyboard
  234.         test    status,stat_cc          ; did user type control-c?
  235.         jnz     input5                  ; nz = yes, quit
  236.         test    status,stat_cr          ; did user type cr? [js]
  237.         jnz     inputx                  ; nz = yes, return success [js]
  238.         call    chktmo                  ; check timeout
  239.         test    status,stat_tmo
  240.         jnz     input5                  ; nz = timed out, quit
  241.         call    bufread                 ; read from serial port buffer into al
  242.         jmp     input3                  ; loop until timeout
  243.  
  244.                                         ; start main read and compare loop
  245. input4: mov     di,temptr               ; pointer to current pattern char
  246.         cmp     di,temptr2              ; at end of pattern?
  247.         jae     inputx                  ; ae = yes, return success
  248.         call    chkkbd                  ; check keyboard
  249.         test    status,stat_cc          ; did user type control-c?
  250.         jnz     input5                  ; nz = yes, quit
  251.         test    status,stat_cr          ; did user type cr? [js]
  252.         jnz     inputx                  ; nz = yes, return success [js]
  253.         call    chktmo                  ; check timeout
  254.         test    status,stat_tmo
  255.         jnz     input5                  ; nz = timed out, quit
  256.         call    bufread                 ; read from serial port buffer into al
  257.         jc      input4                  ; c = nothing there, keep looking
  258.         cmp     al,'a'                  ; candidate for case conversion? [js]
  259.         jb      inpu4a                  ; b = no [js]
  260.         cmp     al,'z'                  ; in lower case set? [js]
  261.         ja      inpu4a                  ; a = no [js]
  262.         and     al,incasv               ; apply case conversion mask
  263. inpu4a: mov     di,temptr
  264.         mov     ah,byte ptr [di]        ; get current pattern char again
  265.         call    matchr                  ; al=rcvd, ah=pattern, do they match?
  266.         jc      inpm                    ; c = no match, try substring
  267.         inc     temptr                  ; matched, point to next pattern char
  268.         jmp     input4
  269. input5: or      errlev,2                ; set RECEIVE failure condition
  270.         jmp     squit                   ; exit failure: timeout or control-c
  271. inputx: jmp     rskp                    ; return success
  272.  
  273. ; See if a trailing-subset of the matched chars + new port char can match
  274. ; the beginning part of the pattern. That is, if we were to simply "forget"
  275. ; the oldest of the matched chars and slide left the apparent port string
  276. ; then could we eventually find a match? Example: "Input 10 memema"
  277. ; gives the pattern of "memema"; suppose the received chars were "mememema".
  278. ; Forgetting one left-most rcv'd char at a time (two in this case) finally
  279. ; yields a match, from which we should continue to compare fresh port chars
  280. ; with successive pattern chars until either they match through all pattern
  281. ; chars or we encounter another break. If there is a later break, repeat this
  282. ; algorithm.
  283. ; Since we really have only the latest char from the port then pointers to
  284. ; the matched pattern chars are used to mimic the earlier received chars:
  285. ; they must have been identical to produce a match to date. The quick way
  286. ; to "forget" oldest received chars is to scan backward through the matched
  287. ; pattern chars looking for the current port char; if the first such find does
  288. ; not yield a matching substring then look back further.
  289.                                 ; no or partial match then break
  290.                                 ; di = temptr = pattern break char
  291.                                 ; al = port char causing break
  292.                                 ; di - offset line = # chars matched thus far
  293.                         ; avoid cpu-brand side effects with "repne scasb"
  294. inpm:   mov     tempa,al        ; save port char here
  295. inpm1:  mov     tempd,di        ; pattern break loc, where matching failed
  296.         mov     cx,di           ; char at di does not match current port char
  297.         sub     cx,offset line  ; compute count of matched bytes
  298.         jcxz    inpm4           ; z = 0 = mismatch on the initial pattern char
  299.  
  300.         mov     al,tempa        ; port char to find (in case we looped here)
  301. inpm2:  dec     di              ; back up one pattern char
  302.         mov     ah,byte ptr [di]; current pattern character to consider
  303.         call    matchr          ; is port char = earlier pattern char? [js]
  304.         jnc     inpm3           ; nc = equal values, go construct substring
  305.         loop    inpm2           ; do cx times, max. (length of match to date)
  306.         jmp     inpm4           ; get here when there are no matches [js]
  307.  
  308. inpm3:  mov     bx,tempd        ; get last break location
  309.         sub     bx,di           ; displacement = break - new find of port char
  310.         mov     tempd,di        ; remember new location of a port-like char
  311.                                 ; cx has number of chars in test substring
  312.         dec     cx              ; matched one char already [jrs]
  313.         jcxz    inpm3a          ; is there anything left? [jrs]
  314.         call    matstr          ; does this substring match the pattern?
  315.         jc      inpm1           ; c = no match, try making substring smaller
  316.  
  317. inpm3a: mov     di,tempd        ; sub-string matched. Use this shorter match
  318.         mov     temptr,di       ; set di for exit (matstr messes up di)
  319.         inc     temptr          ; matched, point to next pattern char
  320.         jmp     input4          ; continue with fresh port info.
  321.  
  322. inpm4:  mov     temptr,offset line; complete failure, restart scanning
  323.         jmp     input4          ; get something from the port.
  324.  
  325. ; worker for SCINP
  326. ; compare strings. One starts at offset line, the other starts bx bytes later.
  327. ; cx = # chars to compare. Return carry clear if match, else carry set.
  328. matstr: mov     si,offset line  ; start of pattern string
  329. matstr1:mov     ah,byte ptr [si] ; pattern char
  330.         mov     al,byte ptr [si+bx] ; "old port char" (same as pattern char)
  331.         call    matchr          ; check match of these two characters
  332.         jc      matstr2         ; c = no match (exit with carry flag set)
  333.         inc     si              ; match, consider next pair
  334.         loop    matstr1         ; consider rest of substring (cx is counter)
  335.         clc                     ; clear c bit (substrings do match)
  336. matstr2:ret                     ; preserves flags (c set = no match)
  337.  
  338. ; worker for SCINP
  339. ; compare single characters, one in ah and the other in al. Allow the 0ffh
  340. ; wild card to match CR and LF individually. Return carry clear if match,
  341. ; or carry set if they do not match. Registers preserved.
  342. matchr: cmp     ah,al           ; do these match?
  343.         je      matchr6         ; e = yes
  344.         cmp     ah,0ffh         ; the match cr/lf indicator?
  345.         je      matchr2         ; e = yes
  346.         cmp     al,0ffh         ; the match cr/lf indicator?
  347.         jne     matchr5         ; ne = no match at all.
  348. matchr2:push    ax              ; save both chars again
  349.         and     ah,al           ; make a common byte for testing
  350.         cmp     ah,cr
  351.         je      matchr4         ; e = cr matches 0ffh
  352.         cmp     ah,lf
  353.         je      matchr4         ; e = lf matches 0ffh
  354.         pop     ax              ; recover chars
  355. matchr5:stc                     ; set carry (no match)
  356.         ret
  357. matchr4:pop     ax              ; recover chars
  358. matchr6:clc                     ; clear carry (match)
  359.         ret
  360. SCINP   ENDP
  361. ;
  362. ; Pause for the specified number of seconds
  363. ; Pause [seconds]
  364. ;
  365. SCPAU   PROC    NEAR
  366.         mov     ah,cmfile               ; get a word (number)
  367.         mov     dx,offset line          ; where to store it
  368.         mov     byte ptr line,0         ; terminate line incase no text
  369.         mov     bx,offset ptshlp        ; help msg
  370.         call    comnd
  371.          nop                            ; ignore parse errors (no text)
  372.          nop                            ; must be at least 3 bytes
  373.          nop
  374.         mov     ah,cmcfm                ; get a confirm
  375.         call    comnd
  376.          jmp r                          ; no confirm
  377.          nop
  378.                                         ;
  379.         call    inptim                  ; parse pause time (or force default)
  380.         cmp     taklev,0                ; are we in a Take file
  381.         je      paus0c                  ; e = no, print linefeed
  382.         cmp     flags.takflg,0          ; are commands being echoed
  383.         je      paus0d                  ; e = no, skip this
  384. paus0c: cmp     inecho,0                ; Input echoing off?
  385.         je      paus0d                  ; e = yes
  386.         mov     al,lf                   ; next line
  387.         call    scdisp                  ; display the char
  388. paus0d: call    serini                  ; initialize the system's serial port
  389.         mov     status,stat_unk         ; clear status flag
  390.         push    si
  391.         mov     parmsk,0ffh             ; parity mask, assume 8 bit data
  392.         mov     si,portval
  393.         cmp     [si].parflg,parnon      ; parity is none?
  394.         pop     si
  395.         je      pause1                  ; e = none
  396.         mov     parmsk,07fh             ; else strip parity (8th) bit
  397. pause1: call    chkport                 ; get and show any new port char
  398.         call    chkkbd                  ; check keyboard
  399.         test    status,stat_cc          ; control-c?
  400.         jnz     pause2                  ; nz = yes, quit
  401.         call    chktmo                  ; check tod for timeout
  402.         test    status,stat_tmo         ; timeout?
  403.         jz      pause1                  ; z = no, continue to wait
  404.         jmp     rskp                    ; timeout, take successful exit
  405. pause2: or      errlev,1+2              ; set SEND and RECEIVE error condx.
  406.         jmp     squit                   ; take error exit
  407. SCPAU   ENDP
  408.  
  409. ; Output line of text to port, detect \b and \B as commands to send a Break
  410. ;  on the serial port line.
  411. ; Output text
  412.  
  413. SCOUT   PROC    NEAR
  414.         mov     ah,cmtxt                ; get a whole line of asciiz text
  415.         mov     bx,offset line          ; store text here
  416.         mov     dx,offset outhlp        ; help message
  417.         call    comnd
  418.          jmp    r                       ; bad parse (no text)
  419.          nop
  420.         mov     ah,cmcfm                ; get a confirm
  421.         call    comnd
  422.          jmp r                          ; no confirm
  423.          nop
  424.         cmp     taklev,0                ; is this being done in a Take file?
  425.         je      outpu0                  ; e = no, display linefeed
  426.         cmp     flags.takflg,0          ; are commands being echoed?
  427.         je      outp0a                  ; e = no, skip the display
  428. outpu0: cmp     inecho,0                ; Input echoing off?
  429.         je      outp0a                  ; e = yes
  430.         mov     al,lf                   ; next line
  431.         call    scdisp                  ; display the char
  432. outp0a: mov     al,spause               ; wait three millisec or more
  433.         add     al,3
  434.         xor     ah,ah
  435.         call    pcwait                  ; breathing space for HDX systems
  436.         call    serini                  ; initialize the system's serial port
  437.         mov     status,stat_unk         ; clear status flag
  438.         mov     parmsk,0ffh             ; parity mask, assume 8 bit data
  439.         mov     si,portval
  440.         cmp     [si].parflg,parnon      ; parity is none?
  441.         je      outp0b                  ; e = none
  442.         mov     parmsk,07fh             ; else strip parity (8th) bit
  443. outp0b: mov     si,portval              ; serial port structure
  444.         mov     bl,[si].ecoflg          ; Get the local echo flag.
  445.         mov     lecho,bl                ; our copy.
  446.         mov     si,offset line          ; get start of line
  447.         mov     di,offset line          ; put results in the same place
  448.         mov     ah,incasv               ; save current case state
  449.         push    ax
  450.         mov     incasv,0ffh             ; say no case conversion
  451.         call    cnvlin                  ; convert \numbers to binary
  452.         pop     ax
  453.         mov     incasv,ah               ; recover case state
  454.         jnc     outpu1                  ; nc = no error
  455.         ret                             ; return on error
  456. outpu1: mov     temptr,offset line      ; save pointer here
  457.         mov     tempd,cx                ; save byte count here
  458.         jcxz    outpu2                  ; empty string
  459.  
  460. outpu2: cmp     tempd,0                 ; are we done?
  461.         jg      outpu2a                 ; g = not done yet
  462.         jmp     rskp                    ; return success
  463. outpu2a:mov     si,temptr               ; recover pointer
  464.         cld
  465.         lodsb                           ; get the character
  466.         dec     tempd                   ; one less char to send
  467.         mov     temptr,si               ; save position on line
  468.         mov     tempa,al                ; save char here for outchr
  469.         mov     retry,0                 ; number of output retries
  470.         cmp     al,5ch                  ; backslash?
  471.         jne     outpu4d                 ; ne = no
  472.         cmp     byte ptr [si],'b'       ; "\b" for Break?
  473.         je      outpu4c                 ; e = yes
  474.         cmp     byte ptr [si],'B'       ; "\B" ?
  475.         jne     outpu4d                 ; ne = no
  476. outpu4c:inc     temptr                  ; move scan ptr beyond "\b"
  477.         dec     tempd
  478.         call    sendbr                  ; call msx send-a-break procedure
  479.         jmp     outpu5                  ; resume beyond echoing
  480.  
  481. outpu4d:inc     retry                   ; count output attempts
  482.         cmp     retry,maxtry            ; too many retries?
  483.         jle     outpu4g                 ; le = no
  484.         or      errlev,1                ; set SEND failure condition
  485.         jmp     squit                   ; return failure
  486. outpu4g:mov     ah,tempa                ; outchr gets fed from ah
  487.         call    outchr                  ; send the character to the port
  488.          jmp     outpu4d                ; failure to send char
  489.          nop                            ; ensure 3 bytes for rskp of outchr
  490.         cmp     lecho,0                 ; is Local echo active?
  491.         je      outpu5                  ; e = no
  492.         mov     al,tempa                ;
  493.         cmp     flags.capflg,0          ; is capturing active?
  494.         je      outp4b                  ; e = no
  495.         push    ax                      ; save char
  496.         call    cptchr                  ; give it captured character
  497.         pop     ax                      ; restore character and keep going
  498. outp4b: cmp     inecho,0                ; Input echo off?
  499.         je      outpu5                  ; e = yes
  500.         call    scdisp                  ; echo character to the screen
  501.                                         ;
  502. outpu5: push    cx
  503. outpu5a:mov     cx,10                   ; reset retry counter
  504. outpu5b:call    chkkbd                  ; check keyboard for interruption
  505.         test    status,stat_cc          ; control c interrupt?
  506.         jnz     outpu6                  ; nz = yes, quit now
  507.         call    chkport                 ; check for char at serial port
  508.         test    status,stat_ok          ;   and put any in buffer
  509.         jnz     outpu5a                 ; nz = have a char, look for another
  510.         mov     ax,1                    ; wait 1 millisec between rereads
  511.         call    pcwait
  512.         dec     cx                      ; count down retries
  513.         jge     outpu5b                 ; ge = keep trying
  514.         pop     cx                      ; no more input, recover register
  515.         jmp     outpu2                  ; resume command
  516. outpu6: pop     cx                      ; recover register
  517.         or      errlev,1                ; set SEND failure condition
  518.         jmp     squit                   ; quit on control c
  519. SCOUT   ENDP
  520.  
  521.  
  522. ; Raw file transfer to host (strips linefeeds)
  523. ; Transmit filespec [prompt]
  524. ; Optional prompt is the single char expected from the host to ACK each line.
  525. ; Default prompt is a linefeed (or a carriage return from us).
  526. ;
  527. SCXMIT  PROC    NEAR
  528.         mov     ah,cmfile               ; get a filename, asciiz
  529.         mov     dx,offset line          ; where to store it
  530.         mov     bx,offset xmthlp        ; help message
  531.         call    comnd
  532.          jmp    r                       ; exit on failure
  533.          nop
  534.         mov     ah,cmtxt                ; get a prompt string, asciiz
  535.         mov     bx,offset line+80       ; where to keep it (end of "line")
  536.         mov     byte ptr line+80,lf     ; store default prompt (line feed)
  537.         mov     byte ptr line+81,0      ; add terminator
  538.         mov     dx,offset pmthlp        ; Help in case user types "?".
  539.         call    comnd
  540.          nop                            ; ignore parse error if no prompt
  541.          nop
  542.          nop
  543.         mov     ah,cmcfm                ; get a confirm
  544.         call    comnd
  545.          jmp r                          ; no confirm
  546.          nop
  547.         mov     si,offset line+80       ; convert possible numeric prompt
  548.         cld
  549.         call    katoi                   ; convert number to binary, if number
  550. xmit0:  mov     tempa,al                ; save the code here
  551.         mov     dx,offset line          ; point to filename
  552.         mov     ah,open2                ; DOS 2 open file
  553.         mov     al,0                    ; open for reading
  554.         int     dos
  555.         mov     fhandle,ax              ; store file handle here
  556.         jnc     xmit1                   ; nc = successful opening
  557.  
  558.         mov     ah,prstr                ; give file not found error message
  559.         mov     dx,offset xfrfnf
  560.         int     dos
  561.         or      errlev,1                ; set SEND failure condition
  562.         jmp     squit                   ; exit failure
  563.  
  564. xmitx:  mov     ah,prstr                ; error during transfer
  565.         mov     dx,offset xfrrer
  566.         int     dos
  567. xmitx2: mov     bx,fhandle              ; file handle
  568.         mov     ah,close2               ; close file
  569.         int     dos
  570.         call    serrst                  ; reset serial port
  571.         call    bufclear                ; clear script buffer
  572.         call    clrbuf                  ; clear local serial port buffer
  573.         or      errlev,1                ; set SEND failure condition
  574.         jmp     squit                   ; exit failure
  575.                                         ;
  576. xmity:  mov     bx,fhandle              ; file handle
  577.         mov     ah,close2               ; close file
  578.         int     dos
  579.         call    serrst                  ; reset serial port
  580.         call    bufclear                ; clear buffers
  581.         call    clrbuf
  582.         jmp     rskp                    ; and return success
  583.  
  584. xmit1:  call    serini                  ; initialize serial port
  585.         call    bufclear                ; clear script input buffer
  586.         call    clrbuf                  ; clear serial port buffer
  587.         mov     status,stat_unk         ; clear status flag
  588.         mov     parmsk,0ffh             ; parity mask, assume 8 bit data
  589.         mov     si,portval
  590.         cmp     [si].parflg,parnon      ; parity is none?
  591.         je      xmit1a                  ; e = none
  592.         mov     parmsk,07fh             ; else strip parity (8th) bit
  593. xmit1a: mov     bl,[si].ecoflg          ; Get the local echo flag.
  594.         mov     lecho,bl                ; our copy
  595.         mov     dx,offset crlf          ; display cr/lf
  596.         mov     ah,prstr
  597.         int     dos
  598.  
  599. xmit2:  mov     dx,offset line          ; buffer to read into
  600.         mov     cx,linelen              ; # of bytes to read
  601.         mov     ah,readf2               ; read bytes from file
  602.         mov     bx,fhandle              ; file handle is stored here
  603.         int     dos
  604.         jc      xmitx                   ; c = failure
  605.         mov     cx,ax                   ; number of bytes read
  606.         jcxz    xmity                   ; z = none, end of file
  607.                                         ;
  608.         mov     si,offset line          ; buffer for file reads
  609. xmit3:  lodsb                           ; get a byte
  610.         push    si                      ; save position on line
  611.         push    cx                      ; and byte count
  612.         push    ax                      ; save char around outchr call
  613. xmit4:  mov     retry,0                 ; clear retry counter
  614. xmit4f: pop     ax                      ; recover saved char
  615.         push    ax                      ; and save it again
  616.         mov     ah,al                   ; outchr wants char in ah
  617.         inc     retry                   ; count number of attempts
  618.         cmp     retry,maxtry            ; too many retries?
  619.         jle     xmit4g                  ; le = no
  620.         or      status,stat_cc          ; simulate control-c abort
  621.         pop     ax                      ; clean stack
  622.         xor     al,al                   ; clear char
  623.         jmp     xmita                   ; and abort transfer
  624. xmit4g: cmp     al,lf                   ; line feed?
  625.         je      xmit4h                  ; e = yes, don't send it
  626.         call    outchr                  ; send the character to the port
  627.          jmp     xmit4f                 ; failed, try again
  628.          nop
  629. xmit4h: pop     ax                      ; recover saved char
  630.         cmp     lecho,0                 ; is local echoing active?
  631.         je      xmit5                   ; e = no
  632.         cmp     flags.capflg,0          ; capturing active?
  633.         je      xmit4a                  ; e = no
  634.         push    ax                      ; save char
  635.         call    cptchr                  ; give it the character just sent
  636.         pop     ax                      ; restore character and keep going
  637. xmit4a: call    scdisp                  ; display char on screen
  638.  
  639. xmit5:  cmp     al,cr                   ; did we send a carriage return?
  640.         je      xmit8                   ; e = yes, time to check keyboard
  641.  
  642. xmit7:  pop     cx
  643.         pop     si
  644.         loop    xmit3                   ; finish this buffer full
  645.         jmp     xmit2                   ; read next buffer
  646.  
  647. xmit8:  test    status,stat_cc          ; Control-C seen?
  648.         jnz     xmita                   ; nz = yes
  649.         call    chkkbd                  ; check keyboard (returns char in al)
  650.         test    status,stat_ok          ; have a char?
  651.         jnz     xmita                   ; nz = yes
  652.         cmp     tempa,0                 ; is prompt char a null?
  653.         jne     xmit8b                  ; ne = no
  654.         call    bufread                 ; check for char from serial port buf
  655.         jnc     xmit8                   ; nc = a char, read til none
  656.         jmp     xmit7                   ; continue transfer
  657. xmit8b: call    bufread                 ; check for char from serial port buf
  658.         jc      xmit8                   ; c = none
  659.         cmp     al,tempa                ; is port char the ack?
  660.         jne     xmit8                   ; ne = no, just ignore the char
  661.         jmp     xmit7                   ; yes, continue transfer
  662.  
  663. xmita:  test    status,stat_cc          ; control-c?
  664.         jnz     xmitc                   ; nz = yes
  665.         test    status,stat_cr          ; a local ack?
  666.         jz      xmit8                   ; no, ignore local char
  667.         mov     dx,offset crlf          ; display cr/lf
  668.         mov     ah,prstr
  669.         int     dos
  670.         jmp     xmit7                   ; continue transfer
  671. xmitc:  pop     cx                      ; Control-C, clear stack
  672.         pop     si                      ; ...
  673.         mov     dx,offset xfrcan        ; say canceling transfer
  674.         mov     ah,prstr
  675.         int     dos
  676.         jmp     xmitx2                  ; ctrl-c, quit
  677.  
  678. SCXMIT  ENDP
  679.  
  680. ;;;;;;;;;;;;;;;;;; local support procedures ;;;;;;;;;;
  681. ;
  682. ;worker: copy line from si to di, converting \nnn strings to single chars
  683. ; returns carry set if error, else carry clear. Detects leading at-sign
  684. ; as an indicator to read command file for one line of text; command files
  685. ; may be nested to a depth of 100.
  686. ; Items of the form \chars which are not numbers are copied verbatium
  687. ; to the output string (ex: \a  is copied as \a). The string is first trimmed
  688. ; of trailing spaces, then the possible curly brace delimiter pair is
  689. ; removed, and finally \numbers are converted to binary. [jrd]
  690. cnvlin  proc    near
  691.         push    si                      ; source ptr
  692.         push    di                      ; destination ptr
  693.         push    ax
  694.         mov     ax,ds
  695.         mov     es,ax                   ; use data segment for es:di
  696.         pop     ax
  697.         mov     tempd,0                 ; count indirection depth
  698. cnvln0: cmp     tempd,100               ; limit to 100 deep
  699.         jbe     cnvln0a                 ; be = not too deep yet
  700.         jmp     cnvln8                  ; too deep, quit
  701. cnvln0a:cld
  702.         xor     cx,cx                   ; initialize returned byte count
  703.         lodsb                           ; get the first character
  704.         cmp     al,40h                  ; at-sign indirection?
  705.         je      cnvln5                  ; e = yes, open the file
  706.         dec     si                      ; no, push back char just read
  707.         call    cnvstr                  ; convert string's curly braces
  708. cnvln1: xor     ah,ah                   ; clear high byte of number
  709.         call    katoi                   ; get a char into al, convert number
  710.         jnc     cnvln4                  ; nc = binary number converted
  711.         cmp     al,0ffh                 ; cr/lf wild card?
  712.         je      cnvln4                  ; e = yes, store it
  713.         cmp     al,0                    ; end of line?
  714.         jne     cnvln3                  ; ne = no
  715.         jmp     cnvlnx                  ; yes, exit now
  716. cnvln3: cmp     al,'a'                  ; candidate for conversion? [js]
  717.         jb      cnvln4                  ; b = no
  718.         cmp     al,'z'                  ; still in lower case set? [js]
  719.         ja      cnvln4                  ; a = no
  720.         and     al,incasv               ; else apply case conversion mask
  721. cnvln4: stosb                           ; save the char
  722.         inc     cx                      ; and count it
  723.         cmp     ah,0                    ; was number larger than one byte?
  724.         je      cnvln1                  ; e = no
  725.         xchg    ah,al                   ; put high byte into al
  726.         stosb                           ; store it too
  727.         inc     cx                      ; count storage
  728.         jmp     short cnvln1            ; read more
  729.  
  730. cnvln5: mov     dx,si                   ; get filename ptr from source line
  731.         push    si
  732.         inc     tempd                   ; count indirection depth
  733.         mov     cx,64                   ; max length of a filename.
  734. cnvln5a:cmp     byte ptr [si],' '       ; whitespace or control code?
  735.         jbe     cnvln5b                 ; be = yes, found termination
  736.         inc     si                      ; else look at next char
  737.         loop    cnvln5a                 ; limit search
  738. cnvln5b:mov     byte ptr [si],0         ; make asciiz
  739.         pop     si
  740.         mov     ah,open2                ; DOS 2 open file
  741.         mov     al,0                    ; open for reading
  742.         int     dos
  743.         mov     word ptr fhandle,ax     ; store file handle
  744.         jnc     cnvln7                  ; nc = open ok, read from file
  745.  
  746.         mov     ah,prstr
  747.         mov     dx,offset indmis        ; file open error msg
  748.         int     dos
  749.         xor     cx,cx                   ; say zero bytes read
  750.         pop     di                      ; destination ptr
  751.         pop     si                      ; source ptr
  752.         stc                             ; set c bit, failure
  753.         ret
  754.  
  755. cnvln7: mov     bx,word ptr fhandle     ; file handle
  756.         mov     cx,linelen              ; # of bytes to read
  757.         mov     ah,ioctl                ; ioctl, is this the console device?
  758.         mov     al,0                    ; get device info
  759.         int     dos
  760.         and     dl,81h                  ; ISDEV and ISCIN bits needed together
  761.         cmp     dl,81h                  ; Console input device?
  762.         jne     cnvln7d                 ; ne = no, use regular file i/o
  763.         push    ds
  764.         pop     es                      ; set es:di to datas segment
  765.         push    di                      ; save starting pointer
  766. cnvln7b:mov     ah,coninq               ; read console, no echo
  767.         int     dos
  768.         stosb
  769.         cmp     al,cr                   ; end of the line yet?
  770.         loopne  cnvln7b                 ; keep reading
  771. cnvln7c:mov     byte ptr [di],0         ; insert terminator
  772.         pop     di                      ; recover starting pointer
  773.         mov     dx,di                   ; simulate read file read
  774.         mov     ax,linelen
  775.         sub     ax,cx                   ; ax = number of chars read
  776.         jmp     cnvln7e                 ; close file, finish processing
  777.  
  778. cnvln7d:mov     dx,di                   ; destination ptr
  779.         mov     byte ptr [di],0         ; insert null terminator, clears line
  780.         mov     ah,readf2               ; DOS 2 read from file
  781.         int     dos
  782. cnvln7e:pushf                           ; save flags
  783.         push    ax                      ; save byte count read
  784.         mov     ah,close2               ; close file (wanted just one line)
  785.         int     dos
  786.         pop     ax
  787.         popf                            ; recover flags now
  788.         jc      cnvln8                  ; c = error
  789.         mov     cx,ax                   ; ax = number of bytes read
  790.         jcxz    cnvln8a                 ; cx = z = no bytes read
  791.         mov     al,cr                   ; look for cr as terminator
  792.         cld
  793.         repne   scasb                   ; scan while not a cr and cx not zero
  794.         jne     cnvln7a                 ; ne = no cr found
  795.         dec     di                      ; point at cr
  796. cnvln7a:mov     byte ptr [di],0         ; plant terminator on the cr
  797.                                         ;  or after last read char, if no cr.
  798.         pop     di                      ; get original destination ptr
  799.         push    di                      ; and save it again
  800.         mov     si,dx                   ; new source = this line
  801.                                         ; go convert text, as necessary, and
  802.         jmp     cnvln0                  ;  allow nested indirection
  803.  
  804. cnvln8: mov     ah,prstr
  805.         mov     dx,offset inderr        ; error reading file message
  806.         int     dos
  807. cnvln8a:xor     cx,cx                   ; say zero bytes read
  808.         pop     di
  809.         pop     si
  810.         stc                             ; set carry for failure
  811.         ret                             ; and do a real return
  812.  
  813. cnvlnx: pop     di                      ; destination ptr
  814.         pop     si                      ; source ptr
  815.         clc                             ; clear c bit, success
  816.         ret
  817. cnvlin  endp
  818. ;
  819. ; worker: read the number of seconds to pause or timeout
  820. ;    returns timeofday for timeout in timhms, and next non-space or
  821. ;    non-tab source char ptr in si.
  822. ;
  823. inptim  proc    near
  824.         push    ax
  825.         push    bx
  826.         push    cx
  827.         push    dx
  828.         cld
  829.         mov     si,offset line          ; source pointer
  830.         mov     cx,10                   ; multiplier
  831.         xor     bx,bx                   ; accumulated sum
  832.         xor     ax,ax                   ; source char holder
  833.         cmp     byte ptr [si],'9'       ; start with numeric input?
  834.         ja      inptm3                  ; a = no, use default time
  835.         cmp     byte ptr [si],'0'       ; ditto
  836.         jb      inptm3
  837. inptm1: lodsb                           ; get a byte into al
  838.         cmp     al,'9'
  839.         ja      inptm4                  ; non-numeric, exit loop
  840.         cmp     al,'0'
  841.         jb      inptm4                  ; b = non=numeric, exit loop
  842.         xchg    ax,bx                   ; put sum into ax, char in bl
  843.         mul     cx                      ; sum times ten
  844.         xchg    ax,bx                   ; put char into al, sum in bx
  845.         sub     al,'0'                  ; convert to binary
  846.         add     bx,ax                   ; add to sum
  847.         jmp     inptm1                  ; loop thru all chars
  848.  
  849. inptm3: mov     bx,indfto               ; no numbers, use default-timeout
  850.         mov     si,offset line          ; reset pointer to start of line
  851.         jmp     inptm5
  852. inptm4: dec     si                      ; back up to non-numeric terminator
  853. inptm4a:cmp     byte ptr [si],spc       ; space?
  854.         je      inptm4b                 ; e = yes, skip over it
  855.         cmp     byte ptr [si],tab       ; tab?
  856.         je      inptm4b                 ; e = yes, skip over it
  857.         jmp     inptm5                  ; neither
  858. inptm4b:inc     si                      ; look at next char
  859.         jmp     inptm4a                 ; continue scanning off white space
  860.  
  861. inptm5: push    si                      ; save ending scan position for return
  862.         mov     timout,bx               ; # seconds of timeout desired
  863.         mov     ah,gettim               ; read DOS tod clock
  864.         int     dos
  865.         mov     timhms[0],ch            ; hours
  866.         mov     timhms[1],cl            ; minutes
  867.         mov     timhms[2],dh            ; seconds
  868.         mov     timhms[3],dl            ; hundredths of seconds
  869.         mov     bx,2                    ; start with seconds field
  870. inptm6: mov     ax,timout               ; our desired timeout interval
  871.         add     al,timhms[bx]           ; add current tod digit to interval
  872.         adc     ah,0
  873.         xor     dx,dx                   ; clear high order part thereof
  874.         mov     cx,60                   ; divide by 60
  875.         div     cx                      ; compute number of minutes or hours
  876.         mov     timout,ax               ; quotient
  877.         mov     timhms[bx],dl           ; put remainder in timeout tod digit
  878.         dec     bx                      ; look at next higher order time field
  879.         cmp     bx,0                    ; done all time fields?
  880.         jge     inptm6                  ; ge = no
  881.         cmp     timhms[0],24            ; normalize hours
  882.         jl      inptm7                  ; l = not 24 hours
  883.         sub     timhms[0],24            ; discard part over 24 hours
  884. inptm7: pop     si                      ; return ptr to next source char
  885.         pop     dx
  886.         pop     cx
  887.         pop     bx
  888.         pop     ax
  889.         ret
  890. inptim  endp
  891.  
  892. ; worker: display the char in al on screen
  893. ; use caret-char notation for control codes
  894. scdisp  proc    near
  895.         push    dx
  896.         push    ax
  897.         mov     ah,conout       ; our desired function
  898.         test    flags.remflg,d8bit ; show all 8 bits?
  899.         jnz     scdisp0         ; nz = yes
  900.         and     al,7fh          ; apply 7 bit display mask
  901. scdisp0:cmp     al,0            ; null?
  902.         je      scdis2          ; e = yes, ignore
  903.         cmp     al,del          ; delete code?
  904.         je      scdis2          ; e = yes, ignore
  905.         cmp     al,spc          ; control char?
  906.         jae     scdis1          ; ae = no, display as-is
  907.         cmp     al,cr           ; carriage return?
  908.         je      scdis1          ; e = yes, display as-is
  909.         cmp     al,lf           ; line feed?
  910.         je      scdis1
  911.         cmp     al,tab          ; horizontal tab?
  912.         je      scdis1
  913.         cmp     al,bell         ; bell?
  914.         je      scdis1
  915.         cmp     al,bs           ; backspace?
  916.         je      scdis1
  917.         cmp     al,escape       ; escape?
  918.         je      scdis1
  919.         or      al,40h          ; convert control code to printable char
  920.         push    ax
  921.         mov     dl,5eh          ; display caret first
  922.         int     dos
  923.         pop     ax
  924. scdis1: mov     dl,al           ; the char to be displayed
  925.         int     dos
  926. scdis2: pop     ax
  927.         pop     dx
  928.         ret
  929. scdisp  endp
  930.  
  931. ; workers
  932. ; Circular buffer for data from serial port. Written by Joe R. Doupnik
  933. ; Entry points -
  934. ;       bufread: read serial port for latest char (invokes bufwrite, sets
  935. ;                       status), get a char into al, return carry set if none.
  936. ;       bufwrite: put a char from al into buf. If this overwrites an unread
  937. ;                       character then: we lose the old char, the read pointer
  938. ;                       is moved to the next oldest unread char, and the
  939. ;                       number of chars in the buffer is decreased by one.
  940. ;       bufclear: empties the buffer.
  941. ; The buffer is prtbuf, of size prtbuflen bytes. Internally, integer bufcnt
  942. ; holds the number of buffer locations occupied, pointer bufrdptr is the
  943. ; offset of the char to be read, pointer bufwtptr is the offset of the
  944. ; place to store the next incoming char.
  945. ;
  946. bufclear proc   near
  947.         mov     bufcnt,0                ; clear count of bytes in buffer
  948.         mov     bufrdptr,offset prtbuf  ; move read pointer to start of buf
  949.         mov     bufwtptr,offset prtbuf  ; move write pointer to start of buf
  950.         ret
  951. bufclear endp
  952.  
  953. bufread proc    near
  954.         call    chkport                 ; get any oldest char from port
  955.         cmp     bufcnt,0                ; empty buffer?
  956.         jne     bufrd1                  ; ne = no
  957.         stc                             ; yes, set carry flag (no char)
  958.         ret                             ; and quit (chkport sets status)
  959. bufrd1: push    si
  960.         mov     si,bufrdptr
  961.         mov     al,byte ptr [si]        ; extract a char into al
  962.         pop     si
  963.         inc     bufrdptr                ; move pointer to next byte
  964.         dec     bufcnt                  ; say have extracted a char
  965.         cmp     bufrdptr,offset prtbuf+prtbuflen        ; beyond end?
  966.         jb      bufrd2                  ; b = not yet, just return
  967.         mov     bufrdptr,offset prtbuf  ; reset to start of buf (wrapping)
  968. bufrd2: clc                             ; clear carry flag (have read a char)
  969.         ret                             ; chkport sets status
  970. bufread endp
  971.  
  972. bufwrite proc   near
  973.         push    si
  974.         mov     si,bufwtptr
  975.         mov     byte ptr [si],al        ; store char held in al
  976.         pop     si
  977.         inc     bufwtptr                ; move pointer to next byte
  978.         cmp     bufwtptr,offset prtbuf+prtbuflen        ; beyond end?
  979.         jb      bufwt1                  ; b = not yet
  980.         mov     bufwtptr,offset prtbuf  ; reset to start of buf (wrapping)
  981. bufwt1: inc     bufcnt                  ; say have added a char to the buf
  982.         cmp     bufcnt,prtbuflen        ; more than we can hold?
  983.         jbe     bufwt3                  ; be = not overflowing
  984.         push    bufwtptr                ; read ptr can't alias write ptr
  985.         pop     bufrdptr                ; move up read pointer
  986.         mov     bufcnt,prtbuflen        ; limit count to max buffer length
  987. bufwt3: ret
  988. bufwrite endp
  989.  
  990. ; worker: check for timeout, return status=stat_tmo if timeout, else bit
  991. ;  stat_unk is cleared.
  992. chktmo: and     status,not stat_tmo
  993.         mov     ah,gettim               ; get the time of day
  994.         int     dos
  995.         sub     ch,timhms[0]            ; hours difference, ch = (now-timeout)
  996.         je      chktmo2                 ; e = same, check mmss.s
  997.         jl      chktmox                 ; l = we are early
  998.         cmp     ch,12                   ; hours difference, large or small?
  999.         jge     chktmox                 ; ge = not that time yet
  1000.         jl      chktmo3                 ; l = beyond that time
  1001. chktmo2:cmp     cl,timhms[1]            ; minutes, hours match
  1002.         jb      chktmox                 ; b = early
  1003.         ja      chktmo3                 ; a = late
  1004.         cmp     dh,timhms[2]            ; seconds, hhmm match
  1005.         jb      chktmox                 ; b = early
  1006.         ja      chktmo3                 ; a = late
  1007.         cmp     dl,timhms[3]            ; fractions, hhmmss match
  1008.         jb      chktmox                 ; b = early
  1009. chktmo3:or      status,stat_tmo         ; say timeout
  1010. chktmox:ret
  1011. ;
  1012. ; worker: check keyboard for char. Return status = stat_cc if control-C typed,
  1013. ; stat_cr if carriage return, or stat_ok if any other char typed. Else return
  1014. ; with these status bits cleared.
  1015. chkkbd: and     status,not (stat_ok+stat_cc+stat_cr) ; clear status bits
  1016.         cmp     flags.cxzflg,'C'        ; Control-C interrupt seen?
  1017.         je      chkkbd0                 ; e = yes
  1018.         mov     ah,dconio               ; keyboard char present?
  1019.         mov     dl,0ffH
  1020.         int     dos
  1021.         je      chkkbd1                 ; e = none
  1022.         or      status,stat_ok          ; have a char, return it in al
  1023.         cmp     al,3                    ; control c?
  1024.         jne     chkkbd1                 ; ne = not control c
  1025. chkkbd0:or      status,stat_cc          ; say control c
  1026. ;;;     mov     flags.cxzflg,0          ; clear interrupt flag
  1027. chkkbd1:cmp     al,cr                   ; carriage return? [js]
  1028.         jne     chkkbd2                 ; ne = no
  1029.         or      status,stat_cr          ; say carriage return [js]
  1030. chkkbd2:ret
  1031. ;
  1032. ; worker: check serial port for received char. Return status = stat_ok if
  1033. ;  char received, otherwise stat_ok cleared. Can echo char to screen. Will
  1034. ;  write char to local circular buffer.
  1035. chkport:and     status,not stat_ok      ; clear status bit
  1036.         call    prtchr                  ; char at port (in al)?
  1037.          jmp    chkpor1                 ; yes, analyze it
  1038.          nop                            ; ensure 3 bytes for rskp of prtchr
  1039.         ret                             ; no, return
  1040. chkpor1:and     al,parmsk               ; strip parity, if any
  1041.         cmp     rxtable+256,0           ; is translation turned off?
  1042.         je      chkpor0                 ; e = yes, no translation
  1043.         push    bx                      ; translate incoming character
  1044.         mov     bx,offset rxtable       ; the translation table
  1045.         xlatb
  1046.         pop     bx
  1047. chkpor0:cmp     flags.capflg,0          ; capturing active?
  1048.         je      chkpor3                 ; e = no
  1049.         test    flags.remflg,d8bit      ; keep 8 bits for displays?
  1050.         jnz     chkpo0a                 ; nz = yes, 8 bits if possible
  1051.         cmp     flags.debug,0           ; is debug mode active?
  1052.         jne     chkpo0a                 ; ne = yes, record 8 bits
  1053.         and     al,7fh                  ; remove high bit
  1054. chkpo0a:push    ax                      ; save char
  1055.         call    cptchr                  ; give it captured character
  1056.         pop     ax                      ; restore character and keep going
  1057. chkpor3:test    flags.remflg,d8bit      ; keep 8 bits for displays?
  1058.         jnz     chkpo3a                 ; nz = yes, 8 bits if possible
  1059.         and     al,7fh                  ; remove high bit
  1060. chkpo3a:cmp     inecho,0                ; input echoing off?
  1061.         je      chkpor4                 ; e = yes
  1062.         call    scdisp                  ; display the char
  1063. chkpor4:call    bufwrite                ; put char in buffer
  1064.         or      status,stat_ok          ; say have a char (still in al)
  1065.         ret
  1066. ;
  1067. ; Squit is the script error exit pathway.
  1068. ;
  1069. squit:  test    status,stat_tmo         ; timeout?
  1070.         jz      squit2                  ; z = no, another kind of failure
  1071.         cmp     inecho,0                ; Input echo allowed?
  1072.         je      squit1                  ; e = no, so skip timeout msg
  1073.         cmp     taklev,0                ; in a Take file?
  1074.         jne     squit1                  ; ne = yes, suppress msg
  1075.         push    dx
  1076.         mov     dx,offset tmomsg        ; say timed out
  1077.         mov     ah,prstr
  1078.         int     dos                     ; display it.
  1079.         pop     dx
  1080. squit1: cmp     inactv,0                ; action to do upon timeout
  1081.         je      squit3                  ; 0 = proceed, ne = non-zero = quit
  1082. squit2: mov     flags.cxzflg,'C'        ; simulate Control-C termination
  1083.         ret                             ; return failure, pop take level
  1084. squit3: jmp     rskp                    ; return success, ignore error
  1085.  
  1086. ;
  1087. ; Jumping to this location is like retskp. It assumes the instruction
  1088. ;     after the call is a jmp addr.
  1089.  
  1090. RSKP    PROC    NEAR
  1091.         pop     bp
  1092.         add     bp,3
  1093.         push    bp
  1094.         ret
  1095. RSKP    ENDP
  1096.  
  1097. ; Jumping here is the same as a ret.
  1098.  
  1099. R       PROC    NEAR
  1100.         ret
  1101. R       ENDP
  1102.  
  1103. code    ends
  1104.         end
  1105.