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

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