home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / extra / nyenhuis3.arc / MSSSCP.ASM < prev    next >
Assembly Source File  |  1990-01-16  |  69KB  |  1,976 lines

  1.     NAME    mssscp
  2. ; File MSSSCP.ASM
  3.     include mssdef.h
  4. ; Edit History
  5. ; Last edit 16 Jan 1990
  6. ; 6 June 1989 Limit echoing of received chars by OUTPUT to 100, to quench
  7. ;  verbose hosts. From Dan Norstedt.
  8. ; 4 May 1989 Make input/reinput scan buffer be allocated dynamically. Allow
  9. ;  for that size to be set via Environment as Kermit initializes.
  10. ;       
  11. ; MS Kermit Script routines, DEC-20 style.
  12. ; Extensively rewritten for MS Kermit 2.29a by Joe R. Doupnik 5 July 86
  13. ;;
  14. ;    Created June, 1986 a.d.    By James Sturdevant
  15. ;                      A. C. Nielsen Co. Mpls.
  16. ;                      8401 Wayzata Blvd.
  17. ;                      Minneapolis, Mn. 55426
  18. ;                      (612)546-0600
  19. ;;;;;;;;
  20. ; Kermit command level usages and this file's entry points:
  21. ; Clear - clears serial port buffers. Procedure scclr.
  22. ; Echo text - displays text on local screen. Proc scecho.
  23. ; Pause [time] - waits indicated number of seconds (default is Input
  24. ;    Default-timeout, 1 second typically). Proc scpau.
  25. ; IF condtion command - tests condition (SUCCESS or FAILURE just now) and
  26. ;       if the condition is met executes the main-line Kermit command.
  27. ; GOTO label - rewinds Take file or Macro, locates the :label, transfers
  28. ;       parsing control to the next line.
  29. ; Input [time] text - waits up to time seconds while scanning serial port
  30. ;    input for a match with text. Default value for time is Input
  31. ;    Default-timeout, 1 second typically). Spaces or tabs are separators
  32. ;    between the time and text fields. Proc scinp.
  33. ;    A carriage return typed by the local user simulates a match.
  34. ; Reinput [time] text - like INPUT but non-destructively rereads the 128 byte
  35. ;       script buffer. Buffer can be added to, until full, if necessary.
  36. ; Output text - sends the text to the serial output port. Proc scout.
  37. ; Transmit text [prompt] - raw file transfer to host. Proceeds from source
  38. ;    line to source line upon receipt of prompt from host or carriage
  39. ;    return from us. Default prompt is linefeed. A null prompt (\0)
  40. ;    causes the file to be sent with no pausing or handshaking. Note
  41. ;    that linefeeds are stripped from outgoing material. Proc scxmit.
  42. ; In the above commands "text" may be replaced by "@filespec" to cause the
  43. ;    one line of that file to be used instead. @CON obtains one line of
  44. ;    text from the keyboard. Such "indirect command files" may be nested
  45. ;    to a depth of 100. Control codes are written as decimal numbers
  46. ;    in the form "\ddd" where d is a digit between 0 and 9. Carriage
  47. ;    return is \13, linefeed is \10, bell is \7; the special code \255
  48. ;    is used to match (Input) either cr or lf or both.
  49. ; These commands can be given individually by hand or automatically
  50. ;    in a Kermit Take file; Take files may be nested.
  51. ;;;;;;;;
  52. ; These routines expect to be invoked by the Kermit command dispatcher
  53. ; and can have their default operations controlled by the Kermit Set Input
  54. ; command (implemented in file mssset.asm). They parse their own cmd lines.
  55. ; Set Input accepts arguments of
  56. ;   Case Ignore or Observe  (default is ignore case when matching strings)
  57. ;   Default-timeout seconds (default is 5 seconds)
  58. ;   Echo On or Off    controls echoing of Input cmd text (default is Off)
  59. ;   Timeout-action Quit or Proceed (default is Proceed)
  60. ; These conditions are passed via global variables script.incasv, .indfto,
  61. ;   .inecho, .inactv, respectively, stored here in structure script.
  62. ;;;;;;;;;
  63.  
  64.     public    script, scout, scinp, scpau, scecho, scclr, scxmit, scwait
  65.         public    goto, screinp, ifcmd, setalrm, inptim, chktmo, alrhms
  66.     public    buflog, scpini, scpbuflen
  67.  
  68. linelen         equ    134        ; length of working buffer line
  69. maxtry        equ    5        ; maximum number of output retries
  70. stat_unk     equ    0          ; status return codes.
  71. stat_ok        equ    1        ; have a port character
  72. stat_cc        equ    2        ; control-C typed
  73. stat_tmo    equ    4        ; timeout
  74. stat_cr        equ    8        ; carriage return typed
  75.  
  76. ifsuc        equ    0        ; indicators for IF conditions
  77. iffail        equ    1
  78. ifext        equ    2
  79. iferr        equ    3
  80. ifnot        equ    4
  81. ifctr        equ    5
  82. ifmdf        equ    6
  83. ifalarm        equ    7
  84. ifequal        equ    8
  85. ifless        equ    9
  86. ifsame        equ    10
  87. ifmore        equ    11
  88.  
  89. data    segment public 'data'
  90.     extrn    taklev:byte, takadr:word, portval:word, flags:byte
  91.     extrn    rxtable:byte, spause:byte, errlev:byte, fsta:word
  92.     extrn    kstatus:word, mcctab:byte, comand:byte, ttyact:byte
  93.  
  94.                     ; global (public) variables     
  95. script    scptinfo <>            ; global structure, containing:
  96. ;;inactv    db    0        ; input action value (default proceed)
  97. ;;incasv    db    0dfh        ; input case  (default ignore)
  98. ;;indfto    dw    1        ; input and pause timeout (def 1 sec)
  99. ;;inecho    db    1        ; echo Input cmd text (0 = no)
  100. ;;xmitfill    db    0        ; non-zero to TRANSMIT filler
  101. ;;xmitlf    db    0        ; non-zero to TRANSMIT LF's
  102. ;;xmitpmt    db    lf        ; prompt between lines
  103.  
  104.                     ; local variables
  105. line    db    linelen+1 dup (0)    ; line of output or input + terminator
  106.         even
  107. scpbuflen dw    128            ; serial port local buffer def length
  108. bufcnt    dw    0            ; serial port buf byte cnt, must be 0
  109. bufseg    dw    0            ; segment of buffer
  110. bufrdptr dw    0            ; serial port buf read ptr
  111. bufwtptr dw    0            ; serial port buf write ptr
  112. bufpkptr dw    0            ; peek-read pointer
  113. bufpkcnt dw    0            ; peek-read byte count remaining
  114. inplen    dw    0            ; length of input match string
  115. reinflg    db    0            ; 0 = INPUT, else REINPUT command
  116. notflag    db    0            ; IF NOT flag
  117. slablen    dw    0            ; label length, for GOTO
  118. status    dw    0            ; general status word
  119. fhandle    dw    0            ; file handle storage place
  120. temptr    dw    0            ; temporary pointer
  121. temptr2    dw    0            ; ditto, points to end of INPUT string
  122. tempd    dw    0            ; temp
  123. temp    dw    0            ; a temp
  124. tempa    db    0            ; another temp
  125. retry    db    0            ; number of output retries
  126. parmsk    db    7fh            ; 7/8 bit parity mask
  127. lecho    db    0            ; local echo of output (0 = no)
  128. timout    dw    0            ; work area (seconds before timeout)
  129. timhms    db    4 dup (0)        ; hhmmss.s time of day buffer
  130. alrhms    db    4 dup (0)        ; hhmmss.s time of day alarm buffer
  131. eolchr    db    LF            ; end of line character
  132.  
  133. crlf    db    cr,lf,'$'
  134. xfrfnf    db    cr,lf,'?Transmit file not found$'
  135. xfrrer    db    cr,lf,'?error reading Transmit file$'
  136. xfrcan    db    cr,lf,'?Transmission canceled$'
  137. indmis    db    '?Indirect file not found',cr,lf,'$'
  138. inderr    db    '?error reading indirect file',cr,lf,'$'
  139. laberr    db    cr,lf,'?Label ":$'
  140. laberr2    db    '" was not found.',cr,lf,'$'
  141. tmomsg    db    cr,lf,'?Timeout',cr,'$'
  142. outhlp    db    'line of text to be sent to remote host$'
  143. inphlp    db    'time-limit and line of text expected from remote host'
  144.     db    cr,lf,' Time is number of seconds or until a specific'
  145.     db    ' hh:mm:ss (24 hour clock)$'
  146. echhlp    db    'line of text to be Echoed to screen$'
  147. ptshlp    db    'amount of time to pause'
  148.     db    cr,lf,' Time is number of seconds or until a specific'
  149.     db    ' hh:mm:ss (24 hour clock)$'
  150. wthlp    db    'time-limit and modem status signals \CD, \CTS, and \DSR'
  151.     db    cr,lf,' Time is number of seconds or until a specific'
  152.     db    ' hh:mm:ss (24 hour clock)$'
  153. xmthlp    db    ' Name of file to be Transmitted$'
  154. pmthlp    db    cr,lf
  155.     db     ' Prompt character expected as an ACK from host (\0 for none)$'
  156. ifdfhlp    db    cr,lf,' Name of macro or variable  then a command$'
  157. alrmhlp    db    cr,lf,' Seconds from now or time of day (HH:MM:SS) for alarm,'
  158.     db    ' < 12H from present$'
  159. ifmhlp    db    cr,lf,' Number, ARGC (1+argument count), COUNT, ERRORLEVEL,'
  160.     db    ' VERSION$'
  161. ifnhlp    db    cr,lf,' Number which errorlevel should match or exceed$'
  162. ifnmsg    db    cr,lf,'?Number expected, ignoring "$'
  163. ifnmsg2    db    '"$'
  164. discard    db      ' Kermit command'
  165.     db    cr,lf,' "IF" condition is false, command will be ignored.$'
  166. ifehlp1    db    cr,lf,'?pair of words or variables to be compared$'
  167. ifehlp2    db    cr,lf,'?second word or variable to be compared$'
  168.  
  169. iftable    db    12            ; IF command dispatch table
  170.     mkeyw    'Not',ifnot
  171.     mkeyw    '<',ifless
  172.     mkeyw    '=',ifsame
  173.     mkeyw    '>',ifmore
  174.     mkeyw    'Alarm',ifalarm
  175.     mkeyw    'Count',ifctr
  176.     mkeyw    'Defined',ifmdf
  177.     mkeyw    'Errorlevel',iferr
  178.     mkeyw    'Equal',ifequal
  179.     mkeyw    'Exist',ifext
  180.     mkeyw    'Failure',iffail
  181.     mkeyw    'Success',ifsuc
  182. data    ends
  183.      
  184. code    segment public 'code'
  185.      
  186.     extrn    comnd:near, clrbuf:near, prtchr:near, outchr:near, sendbr:near
  187.     extrn    cptchr:near, serini:near, pcwait:near, katoi:near
  188.     extrn    cnvstr:near, getmodem:near, isdev:near, isfile:near
  189.     extrn    takrd:near, takclos:near, tolowr:near, prtasz:near,strlen:near
  190.  
  191.     assume    cs:code, ds:data, es:nothing
  192.  
  193. ; Initialize script routines before use, called as Kermit initializes.
  194.  
  195. SCPINI    PROC    NEAR
  196.     mov    cx,scpbuflen        ; (RE)INPUT buffer length
  197.     mov    bx,cx            ; string length, in bytes
  198.     add    bx,15            ; round up
  199.     jnc    scpini1            ; nc = no overflow
  200.     mov    bx,1000h        ; 64KB, if overflow
  201.     jmp    short scpini2
  202. scpini1:mov    cl,4
  203.     shr    bx,cl            ; convert to paragraphs (divide by 16)
  204. scpini2:mov    cx,bx            ; remember desired paragraphs
  205.     mov    ah,alloc        ; allocate a memory block
  206.     int    dos
  207.     jc    scpini4            ; error, not enough memory
  208.     mov    bufseg,ax        ; store new segment
  209.      cmp    bx,cx            ; obtained vs wanted paragraphs
  210.     je    scpini3            ; e = got what we asked for
  211.     mov    cl,4
  212.     shl    bx,cl            ; convert paragraphs to bytes
  213.     mov    scpbuflen,bx        ; new length
  214. scpini3:clc                ; return success
  215.     ret
  216. scpini4:mov    scpbuflen,0
  217.     stc                ; carry set for failure to initialize
  218.     ret
  219. SCPINI    ENDP
  220.  
  221. ; Clear input buffer(s) of serial port
  222. ; Clear command
  223. ;     
  224. SCCLR    PROC    NEAR
  225.     mov    kstatus,0        ; global status
  226.     mov    ah,cmeol        ; get a confirm
  227.     call    comnd
  228.     jnc    scclr1            ; nc = success
  229.     ret                ; failure
  230. scclr1:    call    bufclear        ; clear our serial port circular buf
  231.     call    clrbuf            ; clear system serial port buffer too
  232.     clc
  233.     ret
  234. SCCLR    ENDP
  235.  
  236. ;
  237. ; Echo a line of text to our screen
  238. ; Echo text
  239. ;
  240. SCECHO    PROC    NEAR
  241.     mov    ah,cmline        ; get a whole line of asciiz text
  242.     mov    bx,offset line        ; where to store in
  243.     mov    word ptr [bx],0        ; clear line
  244.     mov    dx,offset echhlp    ; help
  245.     call    comnd            ; ignore parse error if no text
  246.     mov    si,offset line        ; start of line
  247.     mov    di,si            ; convert to the same place
  248.     mov    ah,script.incasv    ; save current case state
  249.     push    ax
  250.     mov    script.incasv,0ffh    ; say no case conversion
  251.     call    cnvlin            ; convert \numbers to binary
  252.     pop    ax
  253.     mov    script.incasv,ah    ; recover case state
  254.     jc    echo3            ; carry set means error
  255.     mov    ah,conout
  256.     mov    dl,LF            ; start with a linefeed
  257.     int    dos            ; show it
  258.     jcxz    echo2            ; z = nothing to show
  259. echo1:    cld
  260.     lodsb                ; get a source char into al
  261.     mov    dl,al
  262.     int    dos
  263.     loop    echo1            ; get another
  264. echo2:    clc                ; return success
  265. echo3:    ret                ; error
  266. SCECHO    ENDP
  267.  
  268. ; Extract label from command line. Store in LINE, length in slablen.
  269. ; Jump to line in Take or Macro following that label.
  270. GOTO    PROC    NEAR
  271.     mov    kstatus,0        ; global status
  272.     mov    ah,cmword        ; get a word
  273.     mov    dx,offset line        ; buffer to hold label
  274.     mov    bx,0            ; no help (non-interactive command)
  275.     mov    slablen,bx        ; clear label holding buffer
  276.     mov    comand.cmkeep,1        ; keep Take/macro open after EOF
  277.     call    comnd
  278.     jnc    goto1            ; nc = success
  279.     ret                ; failure
  280. goto1:    mov    al,ah            ; byte count
  281.     mov    ah,0
  282.     mov    slablen,ax        ; save count here
  283.     mov    comand.cmkeep,1        ; keep Take file open after this call
  284.     mov    ah,cmeol
  285.     call    comnd
  286.     jnc    goto2            ; nc = success
  287.     ret                ; failure
  288. goto2:    cmp    taklev,0        ; in a Take file or Macro?
  289.     jne    GETTO            ; ne = yes, find the label
  290.     clc                ; ignore interactive command
  291.     ret
  292.  
  293. ; Find line starting just after ":label". Label is in variable LINE
  294. ; (length in slablen). Readjust Take read pointer to start of that line.
  295. ; Performs file search from beginning of file.
  296. ; Exit carry clear if success, carry set otherwise. Local worker routine.
  297. getto    proc    near
  298.     push    bx            ; global save of bx
  299.     mov    bx,takadr
  300.     cmp    [bx].taktyp,0ffh    ; get type of take (a Macro?)
  301.     je    gett2            ; e = yes, a macro
  302.                     ; scan from start of Take file
  303.     mov    eolchr,LF        ; file lines end on LF
  304.     mov    bx,[bx].takhnd        ; rewind the file
  305.     mov    cx,0
  306.     mov    dx,0
  307.     mov    al,0            ; zero displacement from start of file
  308.     mov    ah,lseek
  309.     int    dos
  310.     jnc    gett1
  311.     jmp    gett20            ; c = failure
  312. gett1:    call    takrd            ; get a buffer of data
  313.     mov    bx,takadr        ; restore bx to working value
  314.     jmp    short gett4
  315.                     ; Take a Macro
  316. gett2:    mov    eolchr,CR        ; Macro lines end on CR
  317.     mov    ax,[bx].takptr        ; offset of next char to be read
  318.     dec    ax            ; omit count byte at start of buffer
  319.     add    [bx].takcnt,ax        ; original length of text in buffer
  320.     mov    [bx].takptr,1        ; set read pointer to start of text
  321.  
  322. gett4:    call    getch            ; get a character
  323.     jc    gett14            ; c = end of file, no char
  324.     cmp    al,':'            ; start of label?
  325.     je    gett8            ; e = yes
  326. gett6:    cmp    al,eolchr        ; end of line?
  327.     je    gett4            ; e = yes, seek colon for label
  328.     call    getch            ; get a character
  329.     jc    gett14            ; c = end of file, no char
  330.     jmp    short gett6        ; read until end of line
  331. gett8:    mov    si,offset line        ; label to search for
  332.     mov    cx,slablen        ; its length
  333.     jcxz    gett12            ; no chars to match
  334.     cmp    byte ptr[si],':'    ; user label starts with colon
  335.     jne    gett10            ; ne = no
  336.     inc    si            ; skip user's colon
  337.     dec    cx
  338.     jcxz    gett12            ; no chars to match
  339. gett10:    call    getch            ; read file char into al
  340.     jc    gett14            ; c = end of file
  341.     mov    ah,al
  342.     cld
  343.     lodsb
  344.     call    tolowr            ; convert al and ah to lower case
  345.     cmp    al,ah            ; match?
  346.     jne    gett6            ; ne = no, goto end of line
  347.     loop    gett10            ; continue matching
  348.                     ; match obtained
  349.     call    getch            ; read next file character
  350.     jc    gett13            ; c = end of file, no char
  351.     cmp    al,' '            ; separator?
  352.     je    gett12            ; e = yes, unique label found
  353.     cmp    al,TAB            ; this kind of separator?
  354.     je    gett12            ; e = yes
  355.     cmp    al,eolchr        ; or end of line?
  356.     je    gett13            ; e = yes
  357.     cmp    al,CR            ; macro eol, also file start eol pair
  358.     je    gett12            ; e = found match
  359.     jmp    gett6            ; longer label than target
  360.  
  361. gett12:    call    getch            ; read past end of line
  362.     jc    gett13            ; c = end of file, no char
  363.     cmp    al,eolchr        ; end of line character?        
  364.     jne    gett12            ; ne = no, keep reading
  365. gett13: pop    bx
  366.     clc                ; return carry clear
  367.     ret                ; Take pointers are ready to read line
  368.  
  369. gett14:    mov    ah,prstr        ; say label not found
  370.     mov    dx,offset laberr    ; first part of error message
  371.     int    dos
  372.     mov    dx,offset line
  373.     cmp    line,':'        ; label starts with ":"?
  374.     jne    gett15            ; ne = no
  375.     inc    dx            ; yes, skip it
  376. gett15:    call    prtasz            ; print asciiz string
  377.     mov    ah,prstr
  378.     mov    dx,offset laberr2    ; trailer of error message
  379.     int    dos
  380. gett20:    pop    bx
  381.     mov    kstatus,1        ; command status, failure
  382.     stc                ; set carry for failure
  383.     ret
  384. getto    endp
  385. GOTO    ENDP
  386.  
  387. ; Read char from Take buffer. Returns carry clear and char in al, or if end
  388. ; of file returns carry set. Enter with BX holding takadr. Local worker.
  389. getch    proc    near
  390.     cmp    [bx].takcnt,0        ; buffer empty?
  391.     jg    getch2            ; g = no
  392.     cmp    [bx].taktyp,0ffh    ; macro?
  393.     je    getch1            ; e = yes, that's the end
  394.     call    takrd            ; read another buffer
  395.     cmp    [bx].takcnt,0        ; end of file?
  396.     jne    getch2            ; ne = no
  397. getch1:    stc                ; e = yes, exit error
  398.     ret
  399. getch2:    push    si
  400.     push    es
  401.     mov    es,[bx].takbuf        ; segment of buffer
  402.     mov    si,[bx].takptr        ; read a char from Take buffer
  403.     mov    al,es:[si]
  404.     inc    si
  405.     mov    [bx].takptr,si        ; move buffer pointer
  406.     dec    [bx].takcnt        ; decrease number of bytes remaining
  407.     pop    es
  408.     pop    si
  409.     clc                ; return carry clear
  410.     ret
  411. getch    endp
  412.  
  413. ; IF [NOT] {< }| = | > | ALARM | COUNT | FAILURE | SUCCESS 
  414. ;    | ERRORLEVEL \number | EQUAL string string | EXIST filespec} command
  415.  
  416. IFCMD    PROC    NEAR
  417.     mov    notflag,0        ; assume NOT keyword is absent
  418. ifcmd1:    mov    ah,cmkey        ; parse keyword
  419.     mov    dx,offset iftable    ; table of keywords
  420.     mov    bx,0            ; help is the table
  421.     call    comnd
  422.     jnc    ifcmd1a            ; nc = success
  423.     ret                ; failure
  424. ifcmd1a:cmp    bx,ifnot        ; NOT keyword?
  425.     jne    ifcmd2            ; ne = no
  426.     xor    notflag,1        ; toggle not flag
  427.     jmp    short ifcmd1        ; and get next keyword
  428.  
  429. ifcmd2:    cmp    bx,ifsuc        ; IF SUCCESS?
  430.     jne    ifcmd4            ; ne = no
  431.     cmp    kstatus,0        ; do we have success?
  432.     je    ifcmd2a            ; e = yes
  433.     jmp    ifcmdf            ; ne = no, no jump
  434. ifcmd2a:jmp    ifcmdp            ; yes
  435.  
  436. ifcmd4:    cmp    bx,iferr        ; IF ERRORLEVEL?
  437.     jne    ifcmd5            ; ne = no
  438.     jmp    ifnum            ; parse number to binary in line
  439.  
  440. ifcmd5:    cmp    bx,ifext        ; IF EXIST filespec?
  441.     jne    ifcmd6            ; ne = no
  442.     mov    ah,cmword        ; read a filespec
  443.     mov    dx,offset line        ; buffer for filespec
  444.     mov    bx,0
  445.     call    comnd
  446.     jnc    ifcmd5a            ; nc = success
  447.     ret                ; failure
  448. ifcmd5a:mov    ax,offset line        ; isfile wants pointer in ds:ax
  449.     call    isfile            ; see if file exists
  450.     jc    ifcmdf            ; c = no
  451.     jmp    short ifcmdp        ; yes, do following command
  452.  
  453. ifcmd6:    cmp    bx,iffail        ; IF FAIL?
  454.     jne    ifcmd7
  455.     test    kstatus,not (0)        ; check all bits
  456.     jz    ifcmdf            ; z = not that condition, no jump 
  457.     jmp    short ifcmdp
  458.  
  459. ifcmd7:    cmp    bx,ifctr        ; IF COUNT?
  460.     jne    ifcmd8            ; ne = no
  461.     cmp    taklev,0        ; in a Take file?
  462.     je    ifcmdf            ; e = no, fail
  463.     push    bx
  464.     mov    bx,takadr        ; current Take structure
  465.     cmp    [bx].takctr,0        ; exhausted count?
  466.     je    ifcmd7a            ; e = yes, dec no more ye counter
  467.     dec    [bx].takctr        ; dec COUNT if non-zero
  468.     cmp    [bx].takctr,0        ; exhausted now?
  469.     je    ifcmd7a            ; e = yes
  470.     pop    bx
  471.     jmp    short ifcmdp        ; COUNT > 0 at entry, execute command
  472. ifcmd7a:pop    bx
  473.     jmp    short ifcmdf        ; do not execute command
  474.  
  475. ifcmd8:    cmp    bx,ifmdf        ; IF DEF?
  476.     jne    ifcmd9            ; ne = no
  477.     jmp    ifmdef            ; do further parsing below
  478.  
  479. ifcmd9:    cmp    bx,ifalarm        ; IF ALARM?
  480.     jne    ifcmd10            ; ne = no
  481.     jmp    ifalrm            ; do further parsing below
  482.  
  483. ifcmd10:cmp    bx,ifequal        ; IF EQUAL?
  484.     jne    ifcmd11            ; ne = no
  485.     jmp    ifequ            ; do further parsing below
  486.  
  487. ifcmd11:cmp    bx,ifless
  488.     je    ifcmd12
  489.     cmp    bx,ifsame
  490.     je    ifcmd12
  491.     cmp    bx,ifmore
  492.     jne    ifcmdf
  493. ifcmd12:jmp    ifmath
  494.                     ; Jump points for worker routines
  495.                     ; failure
  496. ifcmdf:    cmp    notflag,0        ; need to apply not condition?
  497.     jne    ifcmdp2            ; ne = yes, take other exit
  498. ifcmdf2:mov    ah,cmline        ; fail, read and discard rest of line
  499.     mov    bx,offset line
  500.     mov    dx,offset discard    ; say not doing anything
  501.     call    comnd
  502.     clc                ; force success on discard of line
  503.     ret
  504.                     ; success (pass)
  505. ifcmdp:    cmp    notflag,0        ; need to apply not condition?
  506.     jne    ifcmdf2            ; ne = yes, take other exit
  507. ifcmdp2:clc                ; do command
  508.     ret
  509. IFCMD    ENDP
  510.  
  511. ; Compare errlev against user number. Jump successfully if errlev >= number.
  512. ; Worker for IF [NOT] ERRORLEVEL number <command>
  513. ifnum    proc    near
  514.     mov    ah,cmword        ; get following number
  515.     mov    dx,offset line+1
  516.     mov    line,'\'        ; in case user forgets backslash
  517.     mov    word ptr line+1,0    ; clear buffer
  518.     mov    bx,offset ifnhlp    ; help
  519.     call    comnd
  520.     jnc    ifnum1            ; nc = success
  521.     ret                ; failure
  522. ifnum1:    mov    si,offset line        ; put text in compare buffer
  523.     cmp    line+1,'\'        ; did user include backslash?
  524.     jne    ifnum2            ; ne = no
  525.     inc    si            ; yes, skip our helpful backslash
  526. ifnum2:    call    katoi            ; convert number to binary in ax
  527.     jc    ifnum4            ; c = failed to convert a number
  528.     cmp    errlev,al        ; at or above this level?
  529.     jae    ifnum3            ; ae = yes, succeed
  530.     jmp    ifcmdf            ; else fail
  531. ifnum3:    jmp    ifcmdp            ; jump to main command Success exit
  532.  
  533. ifnum4:    mov    dx,offset line+1    ; pointer to bad word
  534.     mov    tempd,dx        ; remember starting place for text
  535.     call    strlen            ; get its length
  536.     add    dx,cx            ; skip over current word
  537.     mov    bx,dx
  538.     mov    byte ptr [bx],' '    ; space, chopped by parser
  539.     inc    bx            ; new text goes here
  540.     mov    dx,0            ; help
  541.     mov    ah,cmline        ; read rest of line
  542.     call    comnd
  543.     jnc    ifnum4a            ; nc = success
  544.     ret                ; failure
  545. ifnum4a:cmp    ah,0            ; returned byte count
  546.     ja    ifnum5            ; a = got some
  547.     mov    byte ptr[bx-1],0    ; remove space separator from above
  548. ifnum5:    mov    ah,prstr
  549.     mov    dx,offset ifnmsg    ; error message header
  550.     int    dos
  551.     mov    dx,offset line+1    ; start of user text
  552.     call    prtasz            ; display asciiz string
  553.     mov    ah,prstr
  554.     mov    dx,offset ifnmsg2    ; trailer of message
  555.     int    dos
  556.     jmp    ifcmdf            ; jump to main command Failure exit
  557. ifnum    endp
  558.  
  559. ; Process IF [NOT] DEF <macro name> <command>
  560. ifmdef    proc    near
  561.     mov    dx,offset line+1    ; point to work buffer
  562.     mov    bx,offset ifdfhlp    ; help
  563.     mov    ah,cmword        ; get macro name
  564.     mov    comand.cmper,1        ; do not react to \%x
  565.     call    comnd
  566.     jnc    ifmde1            ; nc = success
  567.     ret                ; failure
  568. ifmde1:    mov    line,ah            ; store length in buffer
  569.     mov    bx,offset mcctab+1    ; table of macro keywords
  570.     mov    tempd,0            ; tempd = current keyword
  571.     cmp    byte ptr [bx-1],0    ; any macros defined?
  572.     je    ifmde9            ; e = no, failure, exit now
  573.                     ; match table keyword and user word
  574. ifmde3:    mov    si,offset line        ; pointer to user's cnt+name
  575.     mov    cl,[si]            ; length of user's macro name
  576.     xor    ch,ch
  577.     inc    si            ; point to macro name
  578.     cmp    cl,[bx]            ; compare length vs table keyword
  579.     jne    ifmde7            ; ne = not equal lengths, try another
  580.     push    si            ; lengths match, how about spelling?
  581.     push    bx
  582.     inc    bx            ; point at start of keyword
  583. ifmde4:    mov    ah,[bx]            ; keyword char
  584.     mov    al,[si]            ; new text char
  585.     cmp    al,'a'            ; map lower case to upper
  586.     jb    ifmde5
  587.     cmp    al,'z'
  588.     ja    ifmde5
  589.     sub    al,'a'-'A'
  590. ifmde5:    cmp    al,ah            ; test characters
  591.     jne    ifmde6            ; ne = no match
  592.     inc     si            ; move to next char
  593.     inc    bx
  594.     loop    ifmde4            ; loop through entire length
  595. ifmde6:    pop    bx
  596.     pop    si
  597.     jcxz    ifmde10            ; z: cx = 0, found the name
  598.                     ; select next keyword
  599. ifmde7:    inc    tempd            ; number of keyword to test next
  600.     mov    cx,tempd
  601.     cmp    cl,mcctab        ; all done? Recall, tempd starts at 0
  602.     jae    ifmde9            ; ae = yes, no match
  603.     mov    al,[bx]            ; cnt (keyword length from macro)
  604.     xor    ah,ah
  605.     add    ax,4            ; skip over '$' and two byte value
  606.     add    bx,ax            ; bx = start of next keyword slot
  607.     jmp    short ifmde3        ; do another comparison
  608. ifmde9:    jmp    ifcmdf            ; jump to main command Failure exit
  609. ifmde10:jmp    ifcmdp            ; jump to main command Success exit
  610. ifmdef    endp
  611.  
  612. ; IF [not] ALARM hh:mm:ss command
  613. ifalrm    proc    near
  614.     call    chkkbd            ; check keyboard for override
  615.     test    status,stat_cc        ; Control-C?
  616.     jz    ifalr1            ; z = no
  617.     stc
  618.     ret                ; yes, return failure now
  619. ifalr1:    push    word ptr timhms
  620.     push    word ptr timhms+2    ; save working timeouts
  621.     mov    ax,word ptr alrhms
  622.     mov    word ptr timhms,ax
  623.     mov    ax,word ptr alrhms+2
  624.     mov    word ptr timhms+2,ax    ; set alarm value
  625.     call    chktmo            ; check for timeout
  626.     pop    word ptr timhms+2    ; restore working timeouts
  627.     pop    word ptr timhms
  628.     test    status,stat_tmo        ; tod past user time (alarm sounded)?
  629.     jnz    ifalr4            ; nz = yes, succeed
  630.                     ; failure (not at alarm time yet)
  631.     cmp    notflag,0        ; need to apply NOT condition?
  632.     jne    ifalr5            ; ne = yes, take other exit
  633. ifalr3:    mov    ah,cmline        ; fail, read and discard rest of line
  634.     mov    bx,offset line
  635.     mov    dx,0
  636.     call    comnd
  637.     clc                ; set command parse success
  638.     ret
  639.                     ; success (at or past alarm time)
  640. ifalr4:    cmp    notflag,0        ; need to apply not condition?
  641.     jne    ifalr3            ; ne = yes, take other exit
  642. ifalr5:    clc                ; pass, do command
  643.     ret
  644. ifalrm    endp
  645.  
  646. ; IF [NOT] EQUAL word word command
  647. ; Permits use of \number, {string}, @filespec
  648. ifequ    proc    near
  649.     mov    ah,cmword        ; get a word
  650.     mov    dx,offset line        ; where to store
  651.     mov    line,0            ; clear first entry
  652.     mov    bx,offset ifehlp1    ; help
  653.     call    comnd            ; ignore parse error if no text
  654.     mov    si,offset line        ; start of line
  655.     mov    di,si            ; convert to the same place
  656.     call    cnvlin            ; convert \numbers to binary
  657.     jc    ifequ9            ; carry set means error
  658.     jcxz    ifequ9            ; z = empty word 
  659.     mov    tempa,0            ; line length, so far
  660.     cld
  661. ifequ1:    lodsb
  662.     cmp    al,' '            ; space or control code?
  663.     jbe    ifequ2            ; be = yes, end of word
  664.     inc    tempa            ; count char in word
  665.     loop    ifequ1            ; continue
  666. ifequ2:    mov    byte ptr[si],0        ; plant terminator
  667.     inc    si            ; skip null terminator
  668.     mov    temptr,si        ; place to start second part
  669.     mov    dx,si
  670.     mov    word ptr[si],0        ; clear second part
  671.     mov    ah,cmword        ; get a word of text
  672.     mov    bx,offset ifehlp2    ; help
  673.     call    comnd            ; ignore parse error if no text
  674.     mov    si,temptr        ; start of second line
  675.     mov    di,si            ; convert to the same place
  676.     call    cnvlin            ; convert \numbers to binary
  677.     jc    ifequ9            ; carry set means error
  678.     jcxz    ifequ9            ; z = empty word
  679.     mov    si,temptr        ; point at second word
  680.     mov    dx,0            ; word length so far
  681.     cld
  682. ifequ3:    lodsb
  683.     cmp    al,' '            ; space or control code?
  684.     jbe    ifequ4            ; be = yes, end of word
  685.     inc    dx            ; count char in word
  686.     loop    ifequ3            ; continue
  687. ifequ4:    mov    byte ptr[si],0        ; plant terminator
  688.     mov    cx,dx            ; length of second word
  689.     cmp    tempa,dl        ; same lengths?
  690.     jne    ifequ9            ; ne = no
  691.     jcxz    ifequ9            ; both are null
  692.     push    es
  693.     push    ds
  694.     pop    es
  695.     mov    si,offset line        ; first word
  696.     mov    di,temptr        ; second word
  697.     cld
  698.     repe    cmpsb            ; see if they are the same
  699.     pop    es
  700.     jne    ifequ9            ; ne = not the same, fail
  701.     jmp    ifcmdp            ; do IF cmd success
  702. ifequ9:    jmp    ifcmdf            ; do IF cmd failure
  703. ifequ    endp
  704.  
  705. ; Worker for IF [NOT] < = > var var <command>
  706. ; var is ARGC, COUNT, ERRORLEVEL, VERSION, or a 16 bit number
  707. ifmath    proc    near
  708.     mov    tempa,bl        ; save kind of math test here
  709.     mov    temp,0            ; place to store first value
  710.     mov    tempd,0            ; count times around this loop
  711. ifmath1:mov    dx,offset line+1
  712.     mov    line,'\'        ; in case user forgets backslash
  713.     mov    word ptr line+1,0    ; clear buffer
  714.     mov    bx,offset ifmhlp    ; help
  715.     mov    ah,cmword        ; get following number
  716.     call    comnd
  717.     jnc    ifmath2            ; nc = success
  718.     ret                ; failure
  719. ifmath2:mov    si,offset line+1    ; put text in compare buffer
  720.     mov    ax,[si]            ; get first two user chars
  721.     or    ax,2020h        ; lowercase both bytes
  722.     cmp    ax,'ra'            ; ARGC?
  723.     jne    ifmath3            ; ne = no
  724.     xor    ax,ax
  725.     cmp    taklev,0        ; in a Take/macro?
  726.     je    ifmath8            ; e = no, report ARGC as 0
  727.     mov    bx,takadr        ; current Take structure
  728.     mov    ax,[bx].takargc        ; get argument count
  729.     jmp    short ifmath8
  730. ifmath3:cmp    ax,'re'            ; ERRORLEVEL?
  731.     jne    ifmath4            ; ne = no
  732.     mov    al,errlev        ; get errorlevel
  733.     xor    ah,ah
  734.     jmp    short ifmath8
  735. ifmath4:cmp    ax,'oc'            ; COUNT?
  736.     jne    ifmath5            ; ne = no
  737.     xor    ax,ax
  738.     cmp    taklev,0        ; in a Take/macro?
  739.     je    ifmath8            ; e = no, report COUNT as 0
  740.     mov    bx,takadr        ; current Take structure
  741.     mov    ax,[bx].takctr        ; get COUNT
  742.     jmp    short ifmath7
  743. ifmath5:cmp    ax,'ev'            ; VERSION?
  744.     jne    ifmath6            ; ne = no
  745.     mov    ax,version        ; get version such as 300
  746.     jmp    short ifmath8
  747. ifmath6:cmp    line+1,'\'        ; did user include backslash?
  748.     je    ifmath7            ; e = yes
  749.     dec    si            ; no, employ our helpful backslash
  750. ifmath7:call    katoi            ; convert number to binary in ax
  751.     jc    ifmathb            ; c = failed to convert a number
  752. ifmath8:cmp    tempd,0            ; gotten second value yet?
  753.     ja    ifmath9            ; a = yes, it is in ax
  754.     mov    temp,ax            ; save first value
  755.     inc    tempd            ; say we have been here
  756.     jmp    ifmath1            ; do second argument
  757.  
  758. ifmath9:mov    bl,tempa        ; kind of math test
  759.     cmp    bl,ifless        ; "<"?
  760.     jne    ifmath10        ; ne = no
  761.     cmp    temp,ax            ; val1 < val2?
  762.     jl    ifmathp            ; l = pass
  763.     jmp    short ifmathf        ; fail
  764. ifmath10:cmp    bl,ifsame        ; "="?
  765.     jne    ifmath11        ; ne = no
  766.     cmp    temp,ax            ; val1 = val2?
  767.     je    ifmathp            ; e = yes, pass
  768.     jmp    short ifmathf        ; fail
  769. ifmath11:cmp    temp,ax            ; val2 > val1?
  770.     ja    ifmathp            ; a = yes, pass
  771. ifmathf:jmp    ifcmdf            ; else fail
  772. ifmathp:jmp    ifcmdp            ; jump to main command Success exit
  773.  
  774. ifmathb:jmp    ifnum4            ; do common error complaint
  775. ifmath    endp
  776.  
  777. ; SET ALARM <time, sec from now or HH:MM:SS>
  778. SETALRM    PROC    NEAR
  779.     mov    dx,offset line        ; point to work buffer
  780.     mov    word ptr line,0
  781.     mov    word ptr line+2,0
  782.     mov    bx,offset alrmhlp    ; help
  783.     mov    ah,cmword        ; get macro name
  784.     call    comnd
  785.     jc    setal1            ; c = failure
  786.     mov    ah,cmeol        ; get a confirm
  787.     call    comnd
  788.     jc    setal1            ; c = failure
  789.     push    word ptr timhms
  790.     push    word ptr timhms+2    ; save working timeouts
  791.     mov    si,offset line        ; source pointer
  792.     call    inptim            ; get the timeout time, sets si
  793.     mov    ax,word ptr timhms    ; save time in alarm area
  794.     mov    word ptr alrhms,ax
  795.     mov    ax,word ptr timhms+2
  796.     mov    word ptr alrhms+2,ax
  797.     pop    word ptr timhms+2    ; restore working timeouts
  798.     pop    word ptr timhms
  799.     clc
  800. setal1:    ret
  801. SETALRM    ENDP
  802.  
  803. ; REINPUT <timeout> <match text>
  804. ; Reread material in serial port buffer, seeking a match with user's text
  805. ; pattern. If user's pattern is longer than material in buffer then read
  806. ; additional characters from the serial port. Use SCINP to do the main work.
  807.  
  808. SCREINP    PROC    NEAR
  809.     mov    reinflg,1        ; say doing REINPUT, not INPUT
  810.     jmp    short input10
  811. SCREINP    ENDP
  812.  
  813. ; Input from port command, match input with text pattern
  814. ; Input [timeout] text
  815. ;     
  816. SCINP    PROC    NEAR
  817.     mov    reinflg,0        ; say doing INPUT, not REINPUT
  818.     jmp    short input10
  819.  
  820. input10:mov    kstatus,0
  821.     mov    ah,cmline        ; get a whole line of asciiz text
  822.     mov    bx,offset line        ; place to put text
  823.     mov    dx,offset inphlp    ; help message
  824.     call    comnd            ; get the pattern text
  825.     jnc    input11            ; nothing, complain
  826.     ret                ; failure
  827. input11:cmp    reinflg,0        ; Input command?
  828.     jne    input1            ; ne = no, Reinput
  829.     cmp    taklev,0        ; are we in a Take file?
  830.     je    input0            ; e = no, display linefeed
  831.     cmp    flags.takflg,0        ; are Take commands being echoed?
  832.     je    input1            ; e = no, skip display
  833. input0:    cmp    script.inecho,0        ; Input echo off?
  834.     je    input1            ; e = yes
  835.     mov    al,lf            ; next line
  836.     call    scdisp            ; display the char
  837. input1: call    serini            ; initialize the system's serial port
  838.     jc    input1a            ; c = failure
  839.     mov    status,stat_unk        ; clear status flag
  840.     mov    si,offset line        ; source pointer
  841.     call    inptim            ; get the timeout time, sets si
  842.     jnc    input1b            ; nc = legal time value or none
  843. input1a:jmp    input5            ; else fail on error
  844. input1b:mov    di,offset line        ; put text in compare buffer
  845.     call    cnvlin            ; convert \numbers in buf line
  846.     mov    inplen,cx        ; cx = number of bytes in final string
  847.     mov    parmsk,0ffh          ; parity mask, assume 8 bit data
  848.     mov    di,portval
  849.     cmp    [di].parflg,parnon    ; parity is none?
  850.     je    input1c            ; e = none
  851.     mov    parmsk,07fh        ; else strip parity (8th) bit
  852. input1c:mov    di,offset line
  853.     mov    temptr,di        ; pointer to pattern char
  854.     mov    temptr2,di        ; and we need pointer to end of string
  855.     add    temptr2,cx        ; offset of end of string
  856.                     ; setup reinput read pointer & count
  857.     mov    ax,bufwtptr        ; where next new char goes
  858.     mov    bufpkptr,ax        ; set peek-read pointer at oldest char
  859.     mov    ax,scpbuflen        ; length of the buffer
  860.     mov    bufpkcnt,ax        ; always look back one full buffer
  861.                      ; see if a pattern needs matching
  862.     cmp    inplen,0        ; empty pattern? (cnvlin sets cx=cnt)
  863.     jne    input4            ; ne = not empty
  864.     cmp    reinflg,0        ; Input command?
  865.     je    input3            ; e = yes, read and discard chars
  866.     jmp    input5            ;  reinput, just exit timeout
  867.  
  868.                     ; empty. read, display, and discard
  869. input3:    call    chkkbd            ; check keyboard
  870.     test    status,stat_cc        ; did user type control-c?
  871.     jnz    input5            ; nz = yes, quit
  872.     test    status,stat_cr        ; did user type cr? [js]
  873.     jz    input3a            ; z = no
  874.     jmp    inputx            ; nz = yes, return success [js]
  875. input3a:call    chktmo            ; check timeout
  876.     test    status,stat_tmo
  877.     jnz    input5            ; nz = timed out, quit
  878.     call    bufread            ; read from serial port buffer into al
  879.     jmp    input3            ; loop until timeout, exit timeout
  880.  
  881.                     ; start main read and compare loop
  882. input4:    mov    di,temptr        ; pointer to current pattern char
  883.     cmp    di,temptr2        ; at end of pattern?
  884.     jae    inputx            ; ae = yes, return success
  885.     call    chkkbd            ; check keyboard
  886.     test    status,stat_cc        ; did user type control-c?
  887.     jnz    input5            ; nz = yes, quit
  888.     test    status,stat_cr        ; did user type cr? [js]
  889.     jz    input4a            ; z = no
  890.     jmp    inputx            ; nz = yes, return success [js]
  891. input4a:call    chktmo            ; check timeout
  892.     test    status,stat_tmo+stat_ok ; timeout or user override
  893.     jnz    input5            ; nz = timed out, quit
  894.     cmp    reinflg,0        ; Input command?
  895.     jne    input4b            ; ne = no, a reinput cmd
  896.     call    bufread            ; read from serial port buffer into al
  897.     jc    input4            ; c = nothing there, keep looking
  898.     jmp    short input4c        ; analyze character
  899. input4b:call    peekbuf            ; reinput: peek-read from buffer
  900.     jc    input4            ; c = failed to get a character
  901.                     ; got a char from buffer/port
  902. input4c:cmp    al,'a'            ; candidate for case conversion? [js]
  903.     jb    input4d            ; b = no [js]
  904.     cmp    al,'z'            ; in lower case set? [js]
  905.     ja    input4d            ; a = no [js]
  906.     and    al,script.incasv    ; apply case conversion mask
  907. input4d:mov    di,temptr
  908.     mov    ah,byte ptr [di]    ; get current pattern char again
  909.     call    matchr            ; al=rcvd, ah=pattern, do they match?
  910.     jc    inpm            ; c = no match, try substring
  911.     inc    temptr            ; matched, point to next pattern char
  912.     jmp    input4
  913. input5:    or    errlev,2        ; set RECEIVE failure condition
  914.     or    fsta.xstatus,2        ; set status
  915.     cmp    reinflg,0        ; Input command?
  916.     jne    input6            ; ne = no
  917.     jmp    squit            ; exit failure: timeout or control-c
  918. input6:    mov    kstatus,2        ; failure
  919.     jmp    squit1            ; skip timeout message, if any
  920. inputx:    clc                ; return success
  921.     ret
  922. ; See if a trailing-subset of the matched chars + new port char can match
  923. ; the beginning part of the pattern. That is, if we were to simply "forget"
  924. ; the oldest of the matched chars and slide left the apparent port string
  925. ; then could we eventually find a match? Example: "Input 10 memema"
  926. ; gives the pattern of "memema"; suppose the received chars were "mememema".
  927. ; Forgetting one left-most rcv'd char at a time (two in this case) finally
  928. ; yields a match, from which we should continue to compare fresh port chars 
  929. ; with successive pattern chars until either they match through all pattern
  930. ; chars or we encounter another break. If there is a later break, repeat this
  931. ; algorithm.
  932. ; Since we really have only the latest char from the port then pointers to
  933. ; the matched pattern chars are used to mimic the earlier received chars:
  934. ; they must have been identical to produce a match to date. The quick way
  935. ; to "forget" oldest received chars is to scan backward through the matched
  936. ; pattern chars looking for the current port char; if the first such find does
  937. ; not yield a matching substring then look back further.
  938.                 ; no or partial match then break
  939.                 ; di = temptr = pattern break char
  940.                 ; al = port char causing break
  941.                 ; di - offset line = # chars matched thus far
  942.             ; avoid cpu-brand side effects with "repne scasb"
  943. inpm:    mov    tempa,al    ; save port char here 
  944. inpm1:    mov    tempd,di    ; pattern break loc, where matching failed
  945.     mov    cx,di        ; char at di does not match current port char
  946.     sub    cx,offset line    ; compute count of matched bytes
  947.     jcxz    inpm4        ; z = 0 = mismatch on the initial pattern char
  948.  
  949.     mov    al,tempa    ; port char to find (in case we looped here)
  950. inpm2:    dec    di        ; back up one pattern char
  951.     mov    ah,byte ptr [di]; current pattern character to consider
  952.     call    matchr        ; is port char = earlier pattern char? [js]
  953.     jnc    inpm3        ; nc = equal values, go construct substring
  954.     loop    inpm2        ; do cx times, max. (length of match to date)
  955.     jmp    inpm4        ; get here when there are no matches [js]
  956.  
  957. inpm3:    mov    bx,tempd    ; get last break location
  958.     sub    bx,di        ; displacement = break - new find of port char
  959.     mov    tempd,di    ; remember new location of a port-like char 
  960.                 ; cx has number of chars in test substring
  961.     dec    cx        ; matched one char already [jrs]
  962.     jcxz    inpm3a        ; is there anything left? [jrs]
  963.     call    matstr        ; does this substring match the pattern?
  964.     jc    inpm1        ; c = no match, try making substring smaller
  965.  
  966. inpm3a:    mov    di,tempd    ; sub-string matched. Use this shorter match
  967.     mov    temptr,di    ; set di for exit (matstr messes up di)
  968.     inc    temptr        ; matched, point to next pattern char
  969.     jmp    input4        ; continue with fresh port info
  970.  
  971. inpm4:    mov    temptr,offset line; complete failure, restart scanning
  972.     jmp    input4        ; get something from the port
  973.  
  974. ; worker for SCINP
  975. ; compare strings. One starts at offset line, the other starts bx bytes later.
  976. ; cx = # chars to compare. Return carry clear if match, else carry set.
  977. matstr:    mov    si,offset line    ; start of pattern string
  978. matstr1:mov    ah,byte ptr [si] ; pattern char
  979.     mov    al,byte ptr [si+bx] ; "old port char" (same as pattern char)
  980.     call    matchr        ; check match of these two characters
  981.     jc    matstr2        ; c = no match (exit with carry flag set)
  982.     inc    si        ; match, consider next pair
  983.     loop    matstr1        ; consider rest of substring (cx is counter)
  984.     clc            ; clear c bit (substrings do match)
  985. matstr2:ret            ; preserves flags (c set = no match)
  986.  
  987. ; worker for SCINP
  988. ; compare single characters, one in ah and the other in al. Allow the 0ffh
  989. ; wild card to match CR and LF individually. Return carry clear if match,
  990. ; or carry set if they do not match. Registers preserved.
  991. matchr:    cmp    ah,al        ; do these match?
  992.     je    matchr6        ; e = yes
  993.     cmp    ah,0ffh        ; the match cr/lf indicator?
  994.     je    matchr2        ; e = yes    
  995.     cmp    al,0ffh        ; the match cr/lf indicator?
  996.     jne    matchr5        ; ne = no match at all.
  997. matchr2:push    ax        ; save both chars again
  998.     and    ah,al        ; make a common byte for testing
  999.     cmp    ah,cr
  1000.     je    matchr4        ; e = cr matches 0ffh
  1001.     cmp    ah,lf
  1002.     je    matchr4        ; e = lf matches 0ffh
  1003.     pop    ax        ; recover chars
  1004. matchr5:stc            ; set carry (no match)
  1005.     ret
  1006. matchr4:pop    ax        ; recover chars
  1007. matchr6:clc            ; clear carry (match)
  1008.     ret
  1009. SCINP    ENDP
  1010. ;
  1011. ; Pause for the specified number of seconds or until a time of day
  1012. ; Pause [seconds or hh:mm:ss]
  1013. ;
  1014. SCPAU    PROC    NEAR
  1015.     mov    kstatus,0
  1016.     mov    ah,cmword        ; get a word (number)
  1017.     mov    dx,offset line        ; where to store it
  1018.     mov    byte ptr line,0        ; terminate line incase no text
  1019.     mov    bx,offset ptshlp    ; help msg
  1020.     call    comnd
  1021.     jc    scpau1            ; c = failure
  1022.     mov    si,offset line        ; source pointer
  1023.     call    inptim            ; parse pause time (or force default)
  1024.     jc    scpau1            ; c = bad time value
  1025.     mov    tempa,0            ; no modem status to detect
  1026.     jmp    swait4            ; finish in common code
  1027. scpau1:    ret                ; return command failure
  1028. SCPAU    ENDP
  1029.  
  1030. ;
  1031. ; Wait for the indicated signal for the specified number of seconds or tod
  1032. ; WAIT [seconds] \signal   where \signal is \cd, \dsr modem status lines.
  1033. ; Use INPUT-TIMEOUT ACTION for failures.
  1034. ;
  1035. SCWAIT    PROC    NEAR
  1036.     mov    kstatus,0
  1037.     mov    ah,cmline        ; get a word (number)
  1038.     mov    bx,offset line        ; where to store it
  1039.     mov    byte ptr line,0        ; terminate line incase no text
  1040.     mov    dx,offset wthlp        ; help msg
  1041.     call    comnd
  1042.     jc    swait1a            ; c = failure
  1043.     mov    tempa,0            ; clear modem status test byte
  1044.     mov    si,offset line        ; source pointer
  1045.     call    inptim            ; parse pause time (or force default)
  1046.     jc    swait1a            ; c = bad time value
  1047.     mov    di,offset line        ; put text in compare buffer
  1048.     call    cnvlin            ; convert \numbers in buf line
  1049.     mov    si,di            ; code below uses si
  1050.     jnc    swait1            ; nc = no error
  1051. swait1a:ret                ; else return on error
  1052. swait1:    cmp    cx,0            ; number of chars to examine
  1053.     jle    swait4            ; le = none
  1054.     cld
  1055.     lodsb                ; get a character
  1056.     dec    cx            ; reduce count remaining
  1057.     cmp    al,' '            ; white space?
  1058.     jbe    swait1            ; be = yes, skip over it
  1059.     cmp    al,'\'            ; backslash signal introducer?
  1060.     jne    swait1            ; ne = no, keep searching
  1061.     cmp    cx,2            ; at least two chars in signal?
  1062.     jl    swait3            ; l = no
  1063.     mov    ax,[si]
  1064.     or    ax,2020h        ; upper case to lower, two chars
  1065.     cmp    ax,'dc'            ; carrier detect?
  1066.     jne    swait2            ; ne = no, try next signal
  1067.     or    tempa,modcd        ; look for the CD bit
  1068.     add    si,2            ; skip this field
  1069.     sub    cx,2            ; three less chars left in the line
  1070.     jmp    short swait1        ; continue the scan
  1071. swait2:    cmp    ax,'sd'            ; data set ready?
  1072.     jne    swait3            ; ne = no
  1073.     mov    al,[si+2]        ; third letter
  1074.     or    al,20h            ; to lower case
  1075.     cmp    al,'r'            ; r for dsr?
  1076.     jne    swait3            ; ne = no
  1077.     or    tempa,moddsr        ; look for the DSR bit
  1078.     add    si,3            ; skip this field
  1079.     sub    cx,3            ; four less chars left in the line
  1080. swait3:    cmp    ax,'tc'            ; clear to send?
  1081.     jne    swait3a            ; ne = no
  1082.     mov    al,[si+2]        ; third letter
  1083.     or    al,20h            ; to lower case
  1084.     cmp    al,'s'            ; r for dsr?
  1085.     jne    swait3a            ; ne = no
  1086.     or    tempa,modcts        ; look for the CTS bit
  1087.     add    si,3            ; skip this field
  1088.     sub    cx,3            ; four less chars left in the line
  1089. swait3a:jmp    short swait1        ; continue the scan
  1090.                     ; SWAIT4 is used by PAUSE command
  1091. SWAIT4:    cmp    taklev,0        ; are we in a Take file
  1092.     je    swait5            ; e = no, print linefeed
  1093.     cmp    flags.takflg,0        ; are commands being echoed
  1094.     je    swait6            ; e = no, skip this
  1095. swait5:    cmp    script.inecho,0        ; Input echoing off?
  1096.     je    swait6            ; e = yes
  1097.     mov    al,lf            ; next line
  1098.     call    scdisp            ; display the char
  1099. swait6: call    serini            ; initialize the system's serial port
  1100.     jc    swait9            ; c = failure
  1101.     mov    status,stat_unk        ; clear status flag
  1102.     push    si
  1103.     mov    parmsk,0ffh          ; parity mask, assume 8 bit data
  1104.     mov    si,portval
  1105.     cmp    [si].parflg,parnon    ; parity is none?
  1106.     pop    si
  1107.     je    swait7            ; e = none
  1108.     mov    parmsk,07fh        ; else strip parity (8th) bit
  1109. swait7:    call    getmodem        ; modem handshake status to AL
  1110.     and    al,tempa        ; keep only bits to be tested
  1111.     cmp    tempa,0            ; anything to be tested?
  1112.     je    swait7a            ; e = no, just do the wait part
  1113.     cmp    al,tempa        ; check selected status bits
  1114.     jne    swait7a            ; ne = not all selected bits match    
  1115.     clc                ; all match. take successful exit
  1116.     ret
  1117. swait7a:call    chkport            ; get and show any new port char
  1118.     call    chkkbd            ; check keyboard
  1119.     test    status,stat_cc        ; control-c?
  1120.     jnz    swait9            ; nz = yes, quit    
  1121.     call    chktmo            ; check tod for timeout
  1122.     test    status,stat_tmo+stat_ok    ; timeout or user override?
  1123.     jz    swait7            ; z = no, continue to wait
  1124.     cmp    tempa,0            ; were we waiting on anything?
  1125.     jne    swait9            ; ne = yes, timeout = failure
  1126.     clc                ;  else timeout = success
  1127.     ret
  1128. swait9:    or    errlev,2        ; set RECEIVE error condx
  1129.     or    fsta.xstatus,2        ; set status
  1130.     jmp    squit            ; take error exit
  1131. SCWAIT    ENDP
  1132.  
  1133.  
  1134. ; Output line of text to port, detect \b and \B as commands to send a Break
  1135. ;  on the serial port line.
  1136. ; Output text, display up to 100 received chars while doing so.
  1137.      
  1138. SCOUT    PROC    NEAR
  1139.     mov    kstatus,0
  1140.     mov    ah,cmline        ; get a whole line of asciiz text
  1141.     mov    bx,offset line        ; store text here
  1142.     mov    dx,offset outhlp    ; help message
  1143.     call    comnd
  1144.     jnc    outp0d            ; nc = success
  1145.     ret                ; failure
  1146. outp0d:    cmp    taklev,0        ; is this being done in a Take file?
  1147.     je    outpu0            ; e = no, display linefeed
  1148.     cmp    flags.takflg,0        ; are commands being echoed?
  1149.     je    outp0a            ; e = no, skip the display
  1150. outpu0:    cmp    script.inecho,0        ; Input echoing off?
  1151.     je    outp0a            ; e = yes
  1152.     mov    al,lf            ; next line
  1153.     call    scdisp            ; display the char
  1154. outp0a:    mov    al,spause        ; wait three millisec or more
  1155.     add    al,3
  1156.     xor    ah,ah
  1157.     call    pcwait            ; breathing space for HDX systems
  1158.     call    serini            ; initialize the system's serial port
  1159.     jnc    outp0c            ; nc = success
  1160.     or    errlev,1        ; set SEND failure condition
  1161.     or    fsta.xstatus,1        ; set status
  1162.     jmp    squit
  1163.  
  1164. outp0c:    mov    status,stat_unk        ; clear status flag
  1165.     mov    parmsk,0ffh          ; parity mask, assume 8 bit data
  1166.     mov    si,portval
  1167.     cmp    [si].parflg,parnon    ; parity is none?
  1168.     je    outp0b            ; e = none
  1169.     mov    parmsk,07fh        ; else strip parity (8th) bit
  1170. outp0b:    mov    si,portval        ; serial port structure
  1171.     mov    bl,[si].ecoflg        ; Get the local echo flag
  1172.     mov    lecho,bl        ; our copy
  1173.     mov    si,offset line        ; get start of line
  1174.     mov    di,offset line        ; put results in the same place
  1175.     mov    ah,script.incasv    ; save current case state
  1176.     push    ax
  1177.     mov    script.incasv,0ffh    ; say no case conversion
  1178.     call    cnvlin            ; convert \numbers to binary
  1179.     pop    ax
  1180.     mov    script.incasv,ah    ; recover case state
  1181.     jnc    outpu1            ; nc = no error
  1182.     ret                ; return on error
  1183. outpu1:    mov    temptr,offset line    ; save pointer here
  1184.     mov    tempd,cx        ; save byte count here
  1185.     mov    ttyact,1        ; say interactive style output
  1186.  
  1187. outpu2:    cmp    tempd,0            ; are we done?
  1188.     jg    outpu2a            ; g = not done yet
  1189.     mov    ttyact,0        ; reset interactive output flag
  1190.     clc                ; return success
  1191.     ret
  1192. outpu2a:mov    si,temptr        ; recover pointer
  1193.     cld
  1194.     lodsb                ; get the character
  1195.     dec    tempd            ; one less char to send
  1196.     mov    temptr,si        ; save position on line
  1197.     mov    tempa,al        ; save char here for outchr
  1198.     mov    retry,0            ; number of output retries
  1199.     cmp    al,5ch            ; backslash?
  1200.     jne    outpu4d            ; ne = no
  1201.     cmp    byte ptr [si],'b'    ; "\b" for Break?
  1202.     je    outpu4c            ; e = yes
  1203.     cmp    byte ptr [si],'B'    ; "\B" ?
  1204.     jne    outpu4d            ; ne = no
  1205. outpu4c:inc    temptr            ; move scan ptr beyond "\b"
  1206.     dec    tempd
  1207.     call    sendbr            ; call msx send-a-break procedure
  1208.     jmp    outpu5            ; resume beyond echoing
  1209.  
  1210. outpu4d:inc    retry            ; count output attempts
  1211.     cmp    retry,maxtry        ; too many retries?
  1212.     jle    outpu4g            ; le = no
  1213.     or    errlev,1        ; set SEND failure condition
  1214.     or    fsta.xstatus,1        ; set status
  1215.     jmp    squit            ; return failure
  1216. outpu4g:mov    ah,tempa        ; outchr gets fed from ah
  1217.     call    outchr            ; send the character to the port
  1218.     jc    outpu4d            ; failure to send char
  1219.     cmp    lecho,0            ; is Local echo active?
  1220.     je    outpu5            ; e = no
  1221.     mov    al,tempa        ;
  1222.     test    flags.capflg,logses    ; is capturing active?
  1223.     jz    outp4b            ; z = no
  1224.     push    ax            ; save char
  1225.     call    cptchr            ; give it captured character
  1226.     pop    ax            ; restore character and keep going
  1227. outp4b:    cmp    script.inecho,0        ; Input echo off?
  1228.     je    outpu5            ; e = yes
  1229.     call    scdisp            ; echo character to the screen
  1230.                     ;
  1231. outpu5:    mov    tempa,100+1        ; wait for max 100 chars in/out [dan]
  1232. outpu5a:mov    cx,10            ; reset retry counter
  1233. outpu5b:push    cx
  1234.     call    chkkbd            ; check keyboard for interruption
  1235.     pop    cx
  1236.     test    status,stat_cc        ; control c interrupt?
  1237.     jnz    outpu6            ; nz = yes, quit now
  1238.     cmp    script.inecho,0        ; Input echo off?
  1239.     je    outpu5c            ; e = yes, skip port reading/display
  1240.     dec    tempa            ; reached maximum chars in yet? [dan]
  1241.     jz    outpu5c            ; z = yes, send character anyway [dan]
  1242.     push    cx
  1243.     call    chkport            ; check for char at serial port
  1244.     pop    cx
  1245.     test    status,stat_ok        ;   and put any in buffer
  1246.     jnz    outpu5a            ; nz = have a char, look for another
  1247.     mov    ax,1            ; wait 1 millisec between rereads
  1248.     push    cx            ; protect counter
  1249.     call    pcwait
  1250.     pop    cx
  1251.     dec    cx            ; count down retries
  1252.     jge    outpu5b            ; ge = keep trying
  1253. outpu5c:jmp    outpu2            ; no more input, resume command
  1254. outpu6:    or    errlev,1        ; set SEND failure condition
  1255.     or    fsta.xstatus,1        ; set status
  1256.     mov    ttyact,0        ; reset interactive output flag
  1257.     jmp    squit            ; quit on control c
  1258. SCOUT    ENDP
  1259.  
  1260.      
  1261. ; Raw file transfer to host (strips linefeeds)
  1262. ; Transmit filespec [prompt]
  1263. ; Optional prompt is the single char expected from the host to ACK each line.
  1264. ; Default prompt is a script.xmitpmt (linefeed) or a carriage return from us.
  1265. ;     
  1266. SCXMIT    PROC    NEAR
  1267.     mov    kstatus,0
  1268.     mov    ah,cmword        ; get a filename, asciiz
  1269.     mov    dx,offset line        ; where to store it
  1270.     mov    bx,offset xmthlp    ; help message
  1271.     call    comnd
  1272.     jnc    xmit0c            ; nc = success
  1273.     ret                ; failure
  1274. xmit0c:    mov    ah,cmline        ; get a prompt string, asciiz
  1275.     mov    bx,offset line+80    ; where to keep it (end of "line")
  1276.     mov    word ptr [bx],0        ; clear and add terminator
  1277.     mov    dx,offset pmthlp    ; Help in case user types "?".
  1278.     call    comnd
  1279.     jnc    xmit0d            ; nc = success
  1280.     ret                ; failure
  1281. xmit0d:    cmp    line,0            ; filename given?
  1282.     je    xmit0a            ; e = no
  1283.     or    ah,ah            ; prompt given?
  1284.     jz    xmit0            ; z = no, use default
  1285.     mov    si,offset line+80    ; convert possible numeric prompt
  1286.     call    katoi            ; convert number to binary, if number
  1287.     jnc    xmit0b            ; nc = got number
  1288.     mov    al,line+80        ; get ascii char from user's prompt
  1289. xmit0b:    mov    script.xmitpmt,al    ; default prompt
  1290. xmit0:    mov    dx,offset line        ; point to filename
  1291.     mov    ah,open2        ; DOS 2 open file
  1292.     mov    al,0            ; open for reading
  1293.     int    dos
  1294.     mov    fhandle,ax        ; store file handle here
  1295.     mov    temp,0            ; counts chars/line
  1296.     jnc    xmit1            ; nc = successful opening
  1297.  
  1298. xmit0a:    mov    ah,prstr        ; give file not found error message
  1299.     mov    dx,offset xfrfnf
  1300.     int    dos
  1301.     or    errlev,1        ; set SEND failure condition
  1302.     or    fsta.xstatus,1        ; set status
  1303.     jmp    squit            ; exit failure
  1304.  
  1305. xmitx:    mov    ah,prstr        ; error during transfer
  1306.     mov    dx,offset xfrrer
  1307.     int    dos
  1308. xmitx2:    mov    bx,fhandle        ; file handle
  1309.     mov    ah,close2        ; close file
  1310.     int    dos
  1311.     call    bufclear        ; clear script buffer
  1312.     call    clrbuf            ; clear local serial port buffer
  1313.     or    errlev,1        ; set SEND failure condition
  1314.     or    fsta.xstatus,1        ; set status
  1315.     jmp    squit            ; exit failure
  1316.                     ;
  1317. xmity:    mov    bx,fhandle        ; file handle
  1318.     mov    ah,close2        ; close file
  1319.     int    dos
  1320.     call    bufclear        ; clear buffers
  1321.     call    clrbuf
  1322.     clc                ; and return success
  1323.     ret
  1324. xmit1:    call    serini            ; initialize serial port
  1325.     jnc    xmit1b            ; nc = success
  1326.     or    errlev,1        ; set SEND failure condition
  1327.     or    fsta.xstatus,1        ; set status
  1328.     jmp    squit
  1329.  
  1330. xmit1b:    call    bufclear        ; clear script input buffer
  1331.     call    clrbuf            ; clear serial port buffer
  1332.     mov    status,stat_unk        ; clear status flag
  1333.     mov    parmsk,0ffh          ; parity mask, assume 8 bit data
  1334.     mov    si,portval
  1335.     cmp    [si].parflg,parnon    ; parity is none?
  1336.     je    xmit1a            ; e = none
  1337.     mov    parmsk,07fh        ; else strip parity (8th) bit
  1338. xmit1a:    mov    bl,[si].ecoflg        ; Get the local echo flag.
  1339.     mov    lecho,bl        ; our copy
  1340.     mov    dx,offset crlf        ; display cr/lf
  1341.     mov    ah,prstr
  1342.     int    dos
  1343.  
  1344. xmit2:    mov    dx,offset line        ; buffer to read into
  1345.     mov    cx,linelen        ; # of bytes to read
  1346.     mov    ah,readf2        ; read bytes from file
  1347.     mov    bx,fhandle        ; file handle is stored here
  1348.     int    dos
  1349.     jnc    xmit2a            ; nc = success
  1350.     jmp    xmitx            ; exit failure
  1351. xmit2a:    mov    cx,ax            ; number of bytes read
  1352.     jcxz    xmity            ; z = none, end of file
  1353.                     ;
  1354.     mov    si,offset line        ; buffer for file reads
  1355.     cld
  1356. xmit3:    lodsb                ; get a byte
  1357.     cmp    al,ctlz            ; is this a Control-Z?
  1358.     jne    xmit3a            ; ne = no
  1359.     cmp    flags.eofcz,0        ; ignore Control-Z as EOF?
  1360.     jne    xmity            ; ne = no, we are at EOF
  1361. xmit3a:    push    si            ; save position on line
  1362.     push    cx            ; and byte count
  1363.     cmp    al,cr            ; CR, end of line?
  1364.     jne    xmit3b            ; ne = no
  1365.     cmp    temp,0            ; chars sent in this line, any?
  1366.     ja    xmit3c            ; a = sent some
  1367.     cmp    script.xmitfill,0    ; fill empty lines?
  1368.     je    xmit3c            ; e = no, send the cr
  1369.     mov    al,script.xmitfill    ; empty line fill char
  1370.     pop    cx
  1371.     pop    si
  1372.     dec    si            ; backup read pointer to CR again
  1373.     inc    cx            ; count filler as line information
  1374.     push    si
  1375.     push    cx
  1376.     jmp    short xmit3c
  1377. xmit3b:    cmp    al,lf            ; line feed?
  1378.     jne    xmit3c            ; ne = no
  1379.     cmp    script.xmitlf,0        ; send LF's?
  1380.     je    xmit7            ; e = no, don't send it
  1381.     mov    temp,-1            ; -1 so inc returns 0 after send
  1382. xmit3c:    push    ax            ; save char around outchr call
  1383.     mov    retry,0            ; clear retry counter
  1384. xmit4f:    pop    ax            ; recover saved char
  1385.     push    ax            ; and save it again
  1386.     mov    ah,al            ; outchr wants char in ah
  1387.     inc    retry            ; count number of attempts
  1388.     cmp    retry,maxtry        ; too many retries?
  1389.     jle    xmit4g            ; le = no
  1390.     or    status,stat_cc        ; simulate control-c abort
  1391.     pop    ax            ; clean stack
  1392.     xor    al,al            ; clear char
  1393.     jmp    xmita            ; and abort transfer
  1394. xmit4g:    call    outchr            ; send the character to the port
  1395.     inc    temp            ; count chars sent in this line
  1396.     jc    xmit4f            ; c failed, try again
  1397. xmit4h:    pop    ax            ; recover saved char
  1398.     cmp    lecho,0            ; is local echoing active?
  1399.     je    xmit5            ; e = no
  1400.     test    flags.capflg,logses    ; capturing active?
  1401.     jz    xmit4a            ; z = no
  1402.     call    cptchr            ; give it the character just sent
  1403. xmit4a:    call    scdisp            ; display char on screen
  1404.  
  1405. xmit5:    cmp    al,cr            ; did we send a carriage return?
  1406.     je    xmit8            ; e = yes, time to check keyboard
  1407.  
  1408. xmit7:    pop    cx
  1409.     pop    si
  1410.     dec    cx
  1411.     cmp    cx,0
  1412.     jle    xmit7a            ; le = finished this line
  1413.     jmp    xmit3            ; finish this buffer full
  1414. xmit7a:    jmp    xmit2            ; read next buffer
  1415.  
  1416. xmit8:    test    status,stat_cc        ; Control-C seen?
  1417.     jnz    xmita            ; nz = yes
  1418.     mov    temp,0            ; say starting new char/line count
  1419.     call    chkkbd            ; check keyboard (returns char in al)
  1420.     test    status,stat_ok        ; have a char?
  1421.     jnz    xmita            ; nz = yes
  1422.     cmp    script.xmitpmt,0    ; is prompt char a null?
  1423.     jne    xmit8b            ; ne = no
  1424.     call    bufread            ; check for char from serial port buf
  1425.     jnc    xmit8            ; nc = a char, read til none
  1426.     jmp    xmit7            ; continue transfer
  1427. xmit8b:    call    bufread            ; check for char from serial port buf
  1428.     jc    xmit8            ; c = none
  1429.     cmp    al,script.xmitpmt    ; is port char the ack?
  1430.     jne    xmit8            ; ne = no, just ignore the char
  1431.     jmp    xmit7            ; yes, continue transfer
  1432.  
  1433. xmita:    test    status,stat_cc        ; control-c?
  1434.     jnz    xmitc            ; nz = yes
  1435.     test    status,stat_cr        ; a local ack?
  1436.     jz    xmit8            ; no, ignore local char
  1437.     mov    dx,offset crlf        ; display cr/lf
  1438.     mov    ah,prstr
  1439.     int    dos
  1440.     jmp    xmit7            ; continue transfer
  1441. xmitc:    pop    cx            ; Control-C, clear stack
  1442.     pop    si            ; ...
  1443.     mov    dx,offset xfrcan    ; say canceling transfer
  1444.     mov    ah,prstr
  1445.     int    dos
  1446.     mov    flags.cxzflg,0        ; clear Control-C flag
  1447.     jmp    xmitx2            ; ctrl-c, quit
  1448.  
  1449. SCXMIT    ENDP
  1450.  
  1451. ;;;;;;;;;;;;;;;;;; local support procedures ;;;;;;;;;;
  1452. ;
  1453. ;worker: copy line from si to di, converting \nnn strings to single chars
  1454. ; returns carry set if error, else carry clear. Detects leading at-sign
  1455. ; as an indicator to read command file for one line of text; command files
  1456. ; may be nested to a depth of 100.
  1457. ; Items of the form \chars which are not numbers are copied verbatium
  1458. ; to the output string (ex: \a  is copied as \a). The string is first trimmed
  1459. ; of trailing spaces, then the possible curly brace delimiter pair is
  1460. ; removed, and finally \numbers are converted to binary. [jrd]
  1461. cnvlin    proc    near
  1462.     push    si            ; source ptr
  1463.     push    di            ; destination ptr
  1464.     push    ax
  1465.     mov    ax,ds
  1466.     mov    es,ax            ; use data segment for es:di
  1467.     pop    ax
  1468.     mov    tempd,0            ; count indirection depth
  1469. cnvln0:    cmp    tempd,100        ; limit to 100 deep
  1470.     jbe    cnvln0a            ; be = not too deep yet
  1471.     jmp    cnvln8            ; too deep, quit
  1472. cnvln0a:cld
  1473.     xor    cx,cx            ; initialize returned byte count
  1474.     lodsb                ; get the first character
  1475.     cmp    al,40h            ; at-sign indirection?
  1476.     je    cnvln5            ; e = yes, open the file
  1477.     dec    si            ; no, push back char just read
  1478.     call    cnvstr            ; convert string's curly braces
  1479. cnvln1:    xor    ah,ah            ; clear high byte of number
  1480.     call    katoi            ; get a char into al, convert number
  1481.     jnc    cnvln4            ; nc = binary number converted
  1482.     cmp    al,0ffh            ; cr/lf wild card?
  1483.     je    cnvln4            ; e = yes, store it
  1484.     cmp    al,0            ; end of line?
  1485.     jne    cnvln3            ; ne = no
  1486.     jmp    cnvlnx            ; yes, exit now
  1487. cnvln3:    cmp    al,'a'            ; candidate for conversion? [js]
  1488.     jb    cnvln4            ; b = no
  1489.     cmp    al,'z'            ; still in lower case set? [js]
  1490.     ja    cnvln4            ; a = no
  1491.     and    al,script.incasv    ; else apply case conversion mask
  1492. cnvln4: stosb                ; save the char
  1493.     inc    cx            ; and count it
  1494.     cmp    ah,0            ; was number larger than one byte?
  1495.     je    cnvln1            ; e = no
  1496.     xchg    ah,al            ; put high byte into al
  1497.     stosb                ; store it too
  1498.     inc    cx            ; count storage
  1499.     jmp    short cnvln1        ; read more
  1500.  
  1501. cnvln5:    mov    dx,si            ; get filename ptr from source line
  1502.     push    si
  1503.     inc    tempd            ; count indirection depth
  1504.     mov    cx,64            ; max length of a filename.
  1505. cnvln5a:cmp    byte ptr [si],' '    ; whitespace or control code?
  1506.     jbe    cnvln5b            ; be = yes, found termination
  1507.     inc    si            ; else look at next char
  1508.     loop    cnvln5a            ; limit search
  1509. cnvln5b:mov    byte ptr [si],0        ; make asciiz
  1510.     pop    si    
  1511.     mov    ah,open2        ; DOS 2 open file
  1512.     mov    al,0            ; open for reading
  1513.     int    dos
  1514.     mov    word ptr fhandle,ax    ; store file handle
  1515.     jnc    cnvln7            ; nc = open ok, read from file
  1516.  
  1517.     mov    ah,prstr
  1518.     mov    dx,offset indmis    ; file open error msg
  1519.     int    dos
  1520.     xor    cx,cx            ; say zero bytes read
  1521.     pop    di            ; destination ptr
  1522.     pop    si            ; source ptr
  1523.     stc                ; set c bit, failure
  1524.     ret
  1525.  
  1526. cnvln7:    mov    bx,word ptr fhandle    ; file handle
  1527.     mov    cx,linelen        ; # of bytes to read
  1528.     mov    ah,ioctl        ; ioctl, is this the console device?
  1529.     mov    al,0            ; get device info
  1530.     int    dos
  1531.     and    dl,81h            ; ISDEV and ISCIN bits needed together
  1532.     cmp    dl,81h            ; Console input device?
  1533.     jne    cnvln7d            ; ne = no, use regular file i/o
  1534.     push    ds
  1535.     pop    es            ; set es:di to data segment
  1536.     push    di            ; save starting pointer
  1537. cnvln7b:mov    ah,coninq        ; read console, no echo
  1538.     int    dos
  1539.     stosb
  1540.     cmp    al,cr            ; end of the line yet?
  1541.     loopne    cnvln7b            ; keep reading
  1542.     mov    byte ptr [di],0        ; insert terminator
  1543.     pop    di            ; recover starting pointer
  1544.     mov    dx,di            ; simulate read file read
  1545.     mov    ax,linelen
  1546.     sub    ax,cx            ; ax = number of chars read
  1547.     jmp    cnvln7e            ; close file, finish processing
  1548.  
  1549. cnvln7d:mov    dx,di            ; destination ptr
  1550.     mov    byte ptr [di],0        ; insert null terminator, clears line
  1551.     mov    ah,readf2        ; DOS 2 read from file
  1552.     int    dos
  1553. cnvln7e:pushf                ; save flags
  1554.     push    ax            ; save byte count read
  1555.     mov    ah,close2        ; close file (wanted just one line)
  1556.     int    dos
  1557.     pop    ax
  1558.     popf                ; recover flags now
  1559.     jc    cnvln8            ; c = error
  1560.     mov    cx,ax            ; ax = number of bytes read
  1561.     jcxz    cnvln8a            ; cx = z = no bytes read
  1562.     mov    al,cr            ; look for cr as terminator
  1563.     cld
  1564.     repne    scasb            ; scan while not a cr and cx not zero
  1565.     jne    cnvln7a            ; ne = no cr found
  1566.     dec    di            ; point at cr
  1567. cnvln7a:mov    byte ptr [di],0        ; plant terminator on the cr
  1568.                     ;  or after last read char, if no cr.
  1569.     pop    di            ; get original destination ptr
  1570.     push    di            ; and save it again
  1571.     mov    si,dx            ; new source = this line
  1572.                     ; go convert text, as necessary, and
  1573.     jmp    cnvln0            ;  allow nested indirection
  1574.  
  1575. cnvln8: mov    ah,prstr
  1576.     mov    dx,offset inderr    ; error reading file message
  1577.     int    dos
  1578. cnvln8a:xor    cx,cx            ; say zero bytes read
  1579.     pop    di
  1580.     pop    si
  1581.     stc                ; set carry for failure
  1582.     ret                ; and do a real return
  1583.  
  1584. cnvlnx:    pop    di            ; destination ptr
  1585.     pop    si            ; source ptr
  1586.     clc                ; clear c bit, success
  1587.     ret
  1588. cnvlin    endp
  1589. ;
  1590. ; worker: read the number of seconds to pause or timeout
  1591. ;    returns time of day for timeout in timhms, and next non-space or
  1592. ;    non-tab source char ptr in si. Time is either elapsed seconds or
  1593. ;    a specific hh:mm:ss, determined from context of colons being present.
  1594. ;    Last form can be abbreviated as hh:[mm[:ss]]. Returns carry set if
  1595. ;    hh:mm:ss form has bad construction (invalid time).
  1596. inptim    proc    near
  1597.     push    ax
  1598.     push    bx
  1599.     push    cx
  1600.     push    dx
  1601.     push    di
  1602.     cld                ; decode pure seconds construction
  1603.     mov    di,si            ; remember source pointer
  1604.     mov    cx,10            ; multiplier
  1605.     mov    bx,script.indfto    ; no numbers yet, use default-timeout
  1606.     mov    al,byte ptr[si]
  1607.     cmp    al,':'            ; stray hh:mm:ss separator?
  1608.     je    inptm8            ; e = yes
  1609.     cmp    al,'9'            ; start with numeric input?
  1610.     ja    inptm4            ; a = no, use default time
  1611.     cmp    al,'0'            ; ditto
  1612.     jb    inptm4
  1613.     xor    ah,ah            ; source char holder
  1614.     xor    bx,bx            ; accumulated sum
  1615. inptm1:    mov    al,byte ptr[si]        ; get a byte into al
  1616.     cmp    al,':'            ; hh:mm:ss construction?
  1617.     je    inptm8            ; e = yes
  1618.     sub    al,'0'            ; remove ascii bias
  1619.     cmp    al,9            ; numeric?
  1620.     ja    inptm4            ; a = non-numeric, exit loop, bx = sum
  1621.     xchg    ax,bx            ; put sum into ax, char in bl
  1622.     mul    cx            ; sum times ten 
  1623.     xchg    ax,bx            ; put char into al, sum in bx
  1624.     add    bx,ax            ; add to sum
  1625.     inc    si            ; next char
  1626.     jmp    short inptm1        ; loop thru all chars
  1627.  
  1628. inptm4:    cmp    bx,12*60*60        ; half a day, in seconds
  1629.     jb    inptm5            ; b = less than
  1630.     jmp    inptm13            ; more than, error
  1631. inptm5:    push    si            ; save ending scan position for return
  1632.     mov    timout,bx        ; # seconds of timeout desired
  1633.     mov    ah,gettim        ; read DOS tod clock
  1634.     int    dos
  1635.     mov    timhms[0],ch        ; hours
  1636.     mov    timhms[1],cl        ; minutes
  1637.     mov    timhms[2],dh        ; seconds
  1638.     mov    timhms[3],dl        ; hundredths of seconds
  1639.     mov    bx,2            ; start with seconds field
  1640. inptm6: mov    ax,timout        ; our desired timeout interval
  1641.     add    al,timhms[bx]        ; add current tod digit to interval
  1642.     adc    ah,0
  1643.     xor    dx,dx            ; clear high order part thereof
  1644.     mov    cx,60            ; divide by 60
  1645.     div    cx            ; compute number of minutes or hours
  1646.     mov    timout,ax        ; quotient
  1647.     mov    timhms[bx],dl        ; put remainder in timeout tod digit
  1648.     dec    bx            ; look at next higher order time field
  1649.     cmp    bx,0            ; done all time fields?
  1650.     jge    inptm6            ; ge = no
  1651.     cmp    timhms[0],24        ; normalize hours
  1652.     jl    inptm7            ; l = not 24 hours
  1653.     sub    timhms[0],24        ; discard part over 24 hours
  1654. inptm7:    pop    si            ; return ptr to next source char
  1655.     jmp    inptm11            ; trim trailing whitespace
  1656.  
  1657. inptm8:                    ; decode hh:[mm[:ss]] to timhms
  1658.     mov    si,di            ; recall starting source pointer
  1659.     mov    word ptr timhms[0],0    ; clear time out tod
  1660.     mov    word ptr timhms[2],0
  1661.     mov    bx,0            ; three groups possible
  1662. inptm9:    mov    dl,byte ptr[si]        ; get a char
  1663.     cmp    dl,':'            ; field separator?
  1664.     je    inptm10            ; e = a separator, step fields
  1665.     sub    dl,'0'            ; remove ascii bias
  1666.     cmp    dl,9
  1667.     ja    short inptm11        ; a = failure to get expected digit
  1668.     mov    al,timhms[bx]        ; get sum to al
  1669.     mov    ah,10
  1670.     mul    ah            ; sum times ten
  1671.     add    al,dl            ; sum = 10 * previous + current
  1672.     mov    timhms[bx],al        ; current sum
  1673.     cmp    timhms[bx],60        ; more than legal?
  1674.     jae    inptm13            ; ae = illegal
  1675.     cmp    bx,0            ; doing hours?
  1676.     ja    inptm9a            ; a = no, min or sec
  1677.     cmp    timhms[bx],24        ; more than legal?
  1678.     jae    inptm13            ; ae = illegal
  1679. inptm9a:inc    si            ; next char
  1680.     jmp    short inptm9        ; continue analysis
  1681. inptm10:inc    bx            ; point to next field
  1682.     inc    si            ; next char
  1683.     cmp    bx,2            ; last subscript to use (secs)
  1684.     jbe    inptm9            ; be = get more text
  1685.  
  1686. inptm11:cmp    byte ptr [si],spc    ; examine break char, remove spaces
  1687.     jne    inptm12            ; ne = no, stay at this char
  1688.     inc    si            ; look at next char
  1689.     jmp    short inptm11        ; continue scanning off white space
  1690. inptm12:clc                ; carry clear for success    
  1691.     jnc    inptm14
  1692. inptm13:stc                ; carry set for illegal value    
  1693. inptm14:pop    di            ; return with si beyond our text
  1694.     pop    dx
  1695.     pop    cx
  1696.     pop    bx
  1697.     pop    ax
  1698.     ret
  1699. inptim    endp
  1700.  
  1701. ; worker: display the char in al on screen
  1702. ; use caret-char notation for control codes
  1703. scdisp    proc    near
  1704.     push    dx
  1705.     push    ax
  1706.     mov    ah,conout        ; our desired function
  1707.     test    flags.remflg,d8bit    ; show all 8 bits?
  1708.     jnz    scdisp0            ; nz = yes
  1709.     and    al,7fh            ; apply 7 bit display mask
  1710. scdisp0:cmp    al,0            ; null?
  1711.     je    scdis2            ; e = yes, ignore
  1712.     cmp    al,del            ; delete code?
  1713.     je    scdis2            ; e = yes, ignore
  1714.     cmp    al,spc            ; control char?
  1715.     jae    scdis1            ; ae = no, display as-is
  1716.     cmp    al,cr            ; carriage return?
  1717.     je    scdis1            ; e = yes, display as-is
  1718.     cmp    al,lf            ; line feed?
  1719.     je    scdis1
  1720.     cmp    al,tab            ; horizontal tab?
  1721.     je    scdis1
  1722.     cmp    al,bell            ; bell?
  1723.     je    scdis1
  1724.     cmp    al,bs            ; backspace?
  1725.     je    scdis1
  1726.     cmp    al,escape        ; escape?
  1727.     je    scdis1
  1728.     or    al,40h            ; control code to printable char
  1729.     push    ax
  1730.     mov    dl,5eh            ; display caret first
  1731.     int    dos
  1732.     pop    ax
  1733. scdis1:    mov    dl,al            ; the char to be displayed
  1734.     int    dos
  1735. scdis2:    pop    ax
  1736.     pop    dx
  1737.     ret
  1738. scdisp    endp
  1739.  
  1740. ; workers
  1741. ; Circular buffer for data from serial port. Written by Joe R. Doupnik
  1742. ; Entry points -
  1743. ;    bufread: read serial port for latest char (invokes bufwrite, sets
  1744. ;            status), get a char into al, return carry set if none.
  1745. ;    bufwrite: put a char from al into buf. If this overwrites an unread
  1746. ;            character then: we lose the old char, the read pointer
  1747. ;            is moved to the next oldest unread char, and the
  1748. ;            number of chars in the buffer is decreased by one.
  1749. ;    bufclear: empties the buffer.
  1750. ; The buffer is prtbuf, of size scpbuflen bytes. Internally, integer bufcnt
  1751. ; holds the number of buffer locations occupied, pointer bufrdptr is the
  1752. ; offset of the char to be read, pointer bufwtptr is the offset of the
  1753. ; place to store the next incoming char.
  1754. ;
  1755. bufclear proc    near
  1756.     xor    ax,ax            ; create a zero
  1757.     mov    bufcnt,ax        ; clear count of bytes in buffer
  1758.     mov    bufrdptr,ax        ; move read pointer to start of buf
  1759.     mov    bufwtptr,ax        ; move write pointer to start of buf
  1760.     mov    cx,scpbuflen
  1761.     push    es            ; physically clear the buffer
  1762.     push    di
  1763.     mov    ax,bufseg        ; segment of port buffer
  1764.     mov    es,ax
  1765.     mov    al,0            ; write scpbuflen nulls
  1766.     mov    di,0
  1767.     cld
  1768.     shr    cx,1            ; do an odd byte now
  1769.     jnc    bufcle1            ; nc = no odd byte
  1770.     stosb
  1771. bufcle1:rep    stosw            ; do double bytes (words)
  1772.     pop    di
  1773.     pop    es
  1774.     ret
  1775. bufclear endp
  1776.  
  1777. bufread    proc    near
  1778.     call    chkport            ; get any oldest char from port
  1779.     cmp    bufcnt,0        ; empty buffer?
  1780.     jne    bufrd1            ; ne = no
  1781.     stc                ; yes, set carry flag (no char)
  1782.     ret                ; and quit (chkport sets status)
  1783. bufrd1: push    si
  1784.     push    es
  1785.     mov    si,bufseg        ; get buffer segment
  1786.     mov    es,si
  1787.     mov    si,bufrdptr
  1788.     mov    al,es:[si]        ; extract a char into al
  1789.     inc    bufrdptr        ; move pointer to next byte
  1790.     dec    bufcnt            ; say have extracted a char
  1791.     mov    si,scpbuflen
  1792.     cmp    bufrdptr,si        ; beyond end?
  1793.     jb    bufrd2            ; b = not yet, just return
  1794.     mov    bufrdptr,0        ; reset to start of buf (wrapping)
  1795. bufrd2:    pop    es
  1796.     pop    si
  1797.     clc                ; clear carry flag (have read a char)
  1798.     ret                ; chkport sets status
  1799. bufread    endp
  1800.  
  1801. ; Non-destructive read of serial port circular buffer. Requires external
  1802. ; initialization of peek read pointer bufpkptr and count remaining bufpkcnt.
  1803. ; Returns character in register al.
  1804. peekbuf    proc    near
  1805.     cmp    bufpkcnt,0        ; peek counter, empty buffer?
  1806.     jne    peekbu2            ; ne = no, so look in buffer
  1807.     push    si
  1808.     mov    si,scpbuflen
  1809.     cmp    bufcnt,si        ; is real buffer full?
  1810.     pop    si
  1811.     jae    peekbu1            ; ae = yes, have examined everything
  1812.     call    chkport            ; get a char from port
  1813.     cmp    bufcnt,0        ; still nothing from port?
  1814.     je    peekbu1            ; e = no char, report fact
  1815.     inc    bufpkcnt        ; got one, increase peek counter
  1816.     jmp    peekbu2            ; go extract it
  1817. peekbu1:stc                ; return nothing to see
  1818.     ret
  1819. peekbu2:push    si
  1820.     push    es
  1821.     mov    si,bufseg        ; segment of port buffer
  1822.     mov    es,si
  1823.     mov    si,bufpkptr        ; buffer peek pointer
  1824.     mov    al,es:[si]        ; extract a char into al
  1825.     inc    bufpkptr        ; move pointer to next byte
  1826.     dec    bufpkcnt        ; say have extracted a char
  1827.     mov    si,scpbuflen
  1828.     cmp    bufpkptr,si        ; beyond end?
  1829.     jb    peekbu3            ; b = not yet, just return
  1830.     mov    bufpkptr,0        ; reset to start of buf (wrapping)
  1831. peekbu3:pop    es
  1832.     pop    si
  1833.     clc                ; clear carry flag (have read a char)
  1834.     ret
  1835. peekbuf    endp
  1836.  
  1837. bufwrite proc    near
  1838.     push    si
  1839.     push    es
  1840.     mov    si,bufseg        ; segment of buffer
  1841.     mov    es,si
  1842.     mov    si,bufwtptr
  1843.     mov    es:[si],al        ; store char held in al
  1844.     inc    bufwtptr        ; move pointer to next byte
  1845.     mov    si,scpbuflen        ; length of buffer
  1846.     cmp    bufwtptr,si        ; beyond end?
  1847.     jb    bufwt1            ; b = not yet
  1848.     mov    bufwtptr,0        ; reset to start of buf (wrapping)
  1849. bufwt1:    inc    bufcnt            ; say have added a char to the buf
  1850.     cmp    bufcnt,si        ; more than we can hold?
  1851.     jbe    bufwt3            ; be = not overflowing
  1852.     push    bufwtptr        ; read ptr can't alias write ptr
  1853.     pop    bufrdptr        ; move up read pointer
  1854.     mov    bufcnt,si        ; limit count to max buffer length
  1855. bufwt3:    pop    es
  1856.     pop    si
  1857.     ret
  1858. bufwrite endp
  1859.  
  1860. ; Report buffer status for dumping buffer to a log file.
  1861. ; Yield ax, cx, es, si as indicated below.
  1862. buflog    proc    near
  1863.     mov    ax,bufcnt            ; number of unread chars
  1864.     mov    cx,scpbuflen            ; length of buffer
  1865.     mov    si,bufseg            ; segment of buffer
  1866.     mov    es,si
  1867.     mov    si,bufrdptr            ; where to read next char
  1868.     ret                    ; return these registers
  1869. buflog    endp
  1870.  
  1871. ; worker: check for timeout, return status=stat_tmo if timeout, else bit
  1872. ;  stat_tmo is cleared.
  1873. chktmo:    and    status,not stat_tmo
  1874.     mov    ah,gettim        ; get the time of day
  1875.     int    dos
  1876.     sub    ch,timhms[0]        ; hours difference, ch = (now-timeout)
  1877.     je    chktmo2            ; e = same, check mmss.s
  1878.     jg    chktmo1            ; g = past target hour
  1879.     add    ch,24            ; we are early, see by how much
  1880. chktmo1:cmp    ch,12            ; hours difference, large or small?
  1881.     jge    chktmox            ; ge = not that time yet
  1882.     jl    chktmo3            ; l = beyond that time
  1883. chktmo2:cmp    cl,timhms[1]        ; minutes, hours match
  1884.     jb    chktmox            ; b = early
  1885.     ja    chktmo3            ; a = late
  1886.     cmp    dh,timhms[2]        ; seconds, hhmm match
  1887.     jb    chktmox            ; b = early
  1888.     ja    chktmo3            ; a = late
  1889.     cmp    dl,timhms[3]        ; fractions, hhmmss match
  1890.     jb    chktmox            ; b = early
  1891. chktmo3:or    status,stat_tmo        ; say timeout
  1892.     stc
  1893.     ret
  1894. chktmox:clc
  1895.     ret
  1896. ;
  1897. ; worker: check keyboard for char. Return status = stat_cc if control-C typed,
  1898. ; stat_cr if carriage return, or stat_ok if any other char typed. Else return
  1899. ; with these status bits cleared.
  1900. chkkbd:    and    status,not (stat_ok+stat_cc+stat_cr) ; clear status bits
  1901.     cmp    flags.cxzflg,'C'    ; Control-C interrupt seen?
  1902.     je    chkkbd0            ; e = yes
  1903.     call    isdev            ; is stdin a device, not disk file?
  1904.     jnc    chkkbd2            ; nc = not device so do not read here
  1905.     mov    ah,dconio        ; keyboard char present?
  1906.     mov    dl,0ffH
  1907.     int    dos
  1908.     je    chkkbd1            ; e = none
  1909.     or    status,stat_ok        ; have a char, return it in al
  1910.     cmp    al,3            ; control c?
  1911.     jne    chkkbd1            ; ne = not control c
  1912. chkkbd0:or    status,stat_cc        ; say control c         
  1913. chkkbd1:cmp    al,cr            ; carriage return? [js]
  1914.     jne    chkkbd2            ; ne = no
  1915.     or    status,stat_cr        ; say carriage return [js]
  1916. chkkbd2:ret
  1917. ;
  1918. ; worker: check serial port for received char. Return status = stat_ok if
  1919. ;  char received, otherwise stat_ok cleared. Can echo char to screen. Will
  1920. ;  write char to local circular buffer.
  1921. chkport:and    status,not stat_ok    ; clear status bit
  1922.     call    prtchr            ; char at port (in al)?
  1923.     jnc    chkpor1            ; nc = yes, analyze it
  1924.     ret                ; no, return
  1925. chkpor1:and    al,parmsk        ; strip parity, if any
  1926.     cmp    rxtable+256,0        ; is translation turned off?
  1927.     je    chkpor0            ; e = yes, no translation
  1928.     push    bx            ; translate incoming character
  1929.     mov    bx,offset rxtable    ; the translation table
  1930.     xlatb
  1931.     pop    bx
  1932. chkpor0:test    flags.capflg,logses    ; capturing active?
  1933.     jz    chkpor3            ; z = no
  1934.     test    flags.remflg,d8bit    ; keep 8 bits for displays?
  1935.     jnz    chkpo0a            ; nz = yes, 8 bits if possible
  1936.     cmp    flags.debug,0        ; is debug mode active?
  1937.     jne    chkpo0a            ; ne = yes, record 8 bits
  1938.     and    al,7fh            ; remove high bit
  1939. chkpo0a:push    ax            ; save char
  1940.     call    cptchr            ; give it captured character
  1941.     pop    ax            ; restore character and keep going
  1942. chkpor3:test    flags.remflg,d8bit    ; keep 8 bits for displays?
  1943.     jnz    chkpo3a            ; nz = yes, 8 bits if possible
  1944.     and    al,7fh            ; remove high bit
  1945. chkpo3a:cmp    script.inecho,0        ; input echoing off?
  1946.     je    chkpor4            ; e = yes
  1947.     call    scdisp            ; display the char
  1948. chkpor4:call    bufwrite        ; put char in buffer
  1949.     or    status,stat_ok        ; say have a char (still in al)
  1950.     ret
  1951. ;
  1952. ; Squit is the script error exit pathway.
  1953. ;
  1954. squit:    mov    kstatus,2        ; general command status, failure
  1955.     test    status,stat_tmo        ; timeout?
  1956.     jz    squit2            ; z = no, another kind of failure
  1957.     cmp    taklev,0        ; in a Take/macro?
  1958.     jne    squit1            ; ne = yes, skip timeout message
  1959.     push    dx
  1960.     mov    dx,offset tmomsg    ; say timed out
  1961.     mov    ah,prstr
  1962.     int    dos            ; display it
  1963.     pop    dx
  1964. squit1:    cmp    script.inactv,0        ; action to do upon timeout
  1965.     je    squit4            ; 0 = proceed, ne = non-zero = quit
  1966.     call    takclos            ; close Take file or macro
  1967. squit2:    call    isdev            ; stdin is a device (vs file)?
  1968.     jc    squit3            ; c = device, not a file
  1969.     mov    flags.extflg,1        ; set Kermit exit flag
  1970. squit3:    stc
  1971.     ret                ; return failure
  1972. squit4:    clc                ; return success, ignore error
  1973.     ret
  1974. code    ends
  1975.     end
  1976.