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

  1.     NAME    mssscp
  2. ; File MSSSCP.ASM
  3.     include mssdef.h
  4. ;    Copyright (C) 1982, 1997, Trustees of Columbia University in the 
  5. ;    City of New York.  The MS-DOS Kermit software may not be, in whole 
  6. ;    or in part, licensed or sold for profit as a software product itself,
  7. ;    nor may it be included in or distributed with commercial products
  8. ;    or otherwise distributed by commercial concerns to their clients 
  9. ;    or customers without written permission of the Office of Kermit 
  10. ;    Development and Distribution, Columbia University.  This copyright 
  11. ;    notice must not be removed, altered, or obscured.
  12. ;
  13. ; Edit history
  14. ; 12 Jan 1995 version 3.14
  15. ; Last edit
  16. ; 12 Jan 1995
  17. ;       
  18. ; MS Kermit Script routines, DEC-20 style.
  19. ; Extensively rewritten for MS Kermit 2.29a by Joe R. Doupnik 5 July 86
  20. ;;
  21. ;    Created June, 1986 a.d.    By James Sturdevant
  22. ;                      A. C. Nielsen Co. Mpls.
  23. ;                      8401 Wayzata Blvd.
  24. ;                      Minneapolis, Mn. 55426
  25. ;                      (612)546-0600
  26. ;;;;;;;;
  27. ; Kermit command level usages and this file's entry points:
  28. ; Clear - clears serial port buffers. Procedure scclr.
  29. ; Echo text - displays text on local screen. Proc scecho.
  30. ; Pause [time] - waits indicated number of seconds (default is Input
  31. ;    Default-timeout, 1 second typically). Proc scpau.
  32. ; IF condtion command - tests condition (SUCCESS or FAILURE just now) and
  33. ;       if the condition is met executes the main-line Kermit command.
  34. ; GOTO label - rewinds Take file or Macro, locates the :label, transfers
  35. ;       parsing control to the next line.
  36. ; Input [time] text - waits up to time seconds while scanning serial port
  37. ;    input for a match with text. Default value for time is Input
  38. ;    Default-timeout, 1 second typically). Spaces or tabs are separators
  39. ;    between the time and text fields. Proc scinp.
  40. ;    A carriage return typed by the local user simulates a match.
  41. ; Reinput [time] text - like INPUT but non-destructively rereads the 128 byte
  42. ;       script buffer. Buffer can be added to, until full, if necessary.
  43. ; Output text - sends the text to the serial output port. Proc scout.
  44. ; Transmit text [prompt] - raw file transfer to host. Proceeds from source
  45. ;    line to source line upon receipt of prompt from host or carriage
  46. ;    return from us. Default prompt is linefeed. A null prompt (\0)
  47. ;    causes the file to be sent with no pausing or handshaking. Note
  48. ;    that linefeeds are stripped from outgoing material. Proc scxmit.
  49. ; In the above commands "text" may be replaced by "@filespec" to cause the
  50. ;    one line of that file to be used instead. @CON obtains one line of
  51. ;    text from the keyboard. Such "indirect command files" may be nested
  52. ;    to a depth of 100. Control codes are written as decimal numbers
  53. ;    in the form "\ddd" where d is a digit between 0 and 9. Carriage
  54. ;    return is \13, linefeed is \10, bell is \7; the special code \255
  55. ;    is used to match (Input) either cr or lf or both.
  56. ; These commands can be given individually by hand or automatically
  57. ;    in a Kermit Take file; Take files may be nested.
  58. ;;;;;;;;
  59. ; These routines expect to be invoked by the Kermit command dispatcher
  60. ; and can have their default operations controlled by the Kermit Set Input
  61. ; command (implemented in file mssset.asm). They parse their own cmd lines.
  62. ; Set Input accepts arguments of
  63. ;   Case Ignore or Observe  (default is ignore case when matching strings)
  64. ;   Default-timeout seconds (default is 5 seconds)
  65. ;   Echo On or Off    controls echoing of Input cmd text (default is Off)
  66. ;   Timeout-action Quit or Proceed (default is Proceed)
  67. ; These conditions are passed via global variables script.incasv, .indfto,
  68. ;   .inecho, .inactv, respectively, stored here in structure script.
  69. ;;;;;;;;;                    
  70.  
  71.     public    script, scout, scinp, scpau, scecho, scclr, scxmit, scwait
  72.         public    sgoto, screinp, ifcmd, setalrm, inptim, chktmo, alrhms
  73.     public    buflog, scpini, scpbuflen, decvar, incvar, scmpause, outpace
  74.     public    scsleep, scapc, inpath_seg, sforward, scminput, xecho
  75.     public    input_status, xifcmd, whilecmd, minpcnt, switch
  76.  
  77. linelen         equ    134        ; length of working buffer line
  78. maxtry        equ    5        ; maximum number of output retries
  79. stat_unk     equ    0          ; status return codes.
  80. stat_ok        equ    1        ; have a port character
  81. stat_cc        equ    2        ; control-C typed
  82. stat_tmo    equ    4        ; timeout
  83. stat_cr        equ    8        ; carriage return typed
  84.  
  85. ifsuc        equ    0+0        ; indicators for IF conditions
  86. iffail        equ    1+0100h        ; plus high byte = number of args
  87. ifext        equ    2+0100h
  88. iferr        equ    3+0100h
  89. ifnot        equ    4+0
  90. ifctr        equ    5+0
  91. ifmdf        equ    6+0100h
  92. ifalarm        equ    7+0100h
  93. ifequal        equ    8+0200h
  94. ifless        equ    9+0200h
  95. ifsame        equ    10+0200h
  96. ifmore        equ    11+0200h
  97. ifllt        equ    12+0200h
  98. iflgt        equ    13+0200h
  99. ifpath        equ    14+0100h
  100. ifdir        equ    15+0100h
  101. ifnewer        equ    16+0100h
  102. iftrue        equ    17+0
  103. ifemulation    equ    18+0
  104.  
  105. braceop    equ    7bh        ; opening curly brace
  106. bracecl    equ    7dh        ; closing curly brace
  107.  
  108. data    segment
  109.     extrn    taklev:byte, takadr:word, portval:word, flags:byte
  110.     extrn    rxtable:byte, spause:byte, errlev:byte, fsta:word
  111.     extrn    kstatus:word, mcctab:byte, comand:byte, ttyact:byte
  112.     extrn    keyboard:word, rdbuf:byte, apctrap:byte, filtst:byte
  113.     extrn    diskio:byte, buff:byte, domath_ptr:word, domath_cnt:word
  114.     extrn    domath_msg:word, pardone:word, parfail:word, ifelse:byte
  115.     extrn    domacptr:word
  116.  
  117.                     ; global (public) variables     
  118. script    scptinfo <>            ; global structure, containing:
  119. ;;inactv    db    0        ; input action value (default proceed)
  120. ;;incasv    db    0        ; input case  (default ignore)
  121. ;;indfto    dw    1        ; input and pause timeout (def 1 sec)
  122. ;;inecho    db    1        ; echo Input cmd text (0 = no)
  123. ;;infilter    db    1    ; filer control sequences from screen (0=no)
  124. ;;xmitfill    db    0        ; non-zero to TRANSMIT filler
  125. ;;xmitlf    db    0        ; non-zero to TRANSMIT LF's
  126. ;;xmitpmt    db    lf        ; prompt between lines
  127.  
  128.                     ; local variables
  129. line    db    linelen+1 dup (0)    ; line of output or input + terminator
  130.         even
  131. scpbuflen dw    128            ; serial port local buffer def length
  132. minpcnt dw    0            ; minput successful match pattern
  133. bufcnt    dw    0            ; serial port buf byte cnt, must be 0
  134. bufseg    dw    0            ; segment of buffer
  135. bufrptr dw    0            ; input buffer read-next pointer
  136. inpath_seg dw    0            ; segment of inpath string (0=none)
  137. reinflg    db    0            ; 0=INPUT, 1=REINPUT, 2=MINPUT
  138. notflag    db    0            ; IF NOT flag
  139. slablen    dw    0            ; label length, for GOTO
  140. forward    db    0            ; 0=goto, else use Forward form
  141. status    dw    0            ; general status word
  142. disp_state dw    0            ; scdisp state machine state
  143. fhandle    dw    0            ; file handle storage place
  144. temptr    dw    0            ; temporary pointer
  145. temptr2    dw    0            ; ditto, points to end of INPUT string
  146. tempd    dw    0            ; temp
  147. temp    dw    0            ; a temp
  148. temp1    dw    0            ; high order part of temp
  149. tempa    dw    0            ; another temp
  150. wtemp    db    0            ; temp for WAIT
  151. ltype    dw    0            ; lex type for IF statements
  152. retry    db    0            ; number of output retries
  153. parmsk    db    7fh            ; 7/8 bit parity mask
  154. lecho    db    0            ; local echo of output (0 = no)
  155. timout    dw    0            ; work area (seconds before timeout)
  156. timhms    db    4 dup (0)        ; hhmmss.s time of day buffer
  157. alrhms    db    4 dup (0)        ; hhmmss.s time of day alarm buffer
  158. outpace    dw    0            ; OUTPUT pacing, millisec
  159. input_status dw 0ffffh            ; INPUT status for v(instatus)
  160. deflabel db    'default',0        ; label :default, asciiz
  161.  
  162. crlf    db    cr,lf,'$'
  163. xfrfnf    db    cr,lf,'?Transmit file not found$'
  164. xfrrer    db    cr,lf,'?error reading Transmit file$'
  165. xfrcan    db    cr,lf,'?Transmission canceled$'
  166. indmis    db    '?Indirect file not found',cr,lf,'$'
  167. inderr    db    '?error reading indirect file',cr,lf,'$'
  168. laberr    db    cr,lf,'?Label ":$'
  169. laberr2    db    '" was not found.',cr,lf,'$'
  170. tmomsg    db    cr,lf,'?Timeout',cr,'$'
  171. wtbad    db    cr,lf,'?Command not understood, improper syntax $'
  172. mpbad    db    cr,lf,'?Bad number$'
  173.  
  174. ifkind    db    0        ; 0 = IF, 1 = XIF, 2 = WHILE
  175.  
  176. clrtable db    4
  177.     mkeyw    "input-buffer",1
  178.     mkeyw    "device-buffer",2
  179.     mkeyw    "both",3
  180.     mkeyw    'APC',4
  181.  
  182. iftable    db    20            ; IF command dispatch table
  183.     mkeyw    'Not',ifnot
  184.     mkeyw    '<',ifless
  185.     mkeyw    '=',ifsame
  186.     mkeyw    '>',ifmore
  187.     mkeyw    'Alarm',ifalarm
  188.     mkeyw    'Count',ifctr
  189.     mkeyw    'Defined',ifmdf
  190.     mkeyw    'Directory',ifdir
  191.     mkeyw    'Emulation',ifemulation
  192.     mkeyw    'Errorlevel',iferr
  193.     mkeyw    'Equal',ifequal
  194.     mkeyw    'Exist',ifext
  195.     mkeyw    'Inpath',ifpath
  196.     mkeyw    'LGT',iflgt
  197.     mkeyw    'LLT',ifllt
  198.     mkeyw    'Newer',ifnewer
  199.     mkeyw    'Numeric',ifnumeric
  200.     mkeyw    'Failure',iffail
  201.     mkeyw    'Success',ifsuc
  202.     mkeyw    'True',iftrue
  203. data    ends
  204.  
  205. data1    segment
  206. outhlp    db    'line of text to be sent to remote host$'
  207. apchlp    db    'Applications Program Commands to send to remote host$'
  208. inphlp    db    'time-limit and line of text expected from remote host'
  209.     db    cr,lf,' Time is number of seconds or until a specific'
  210.     db    ' hh:mm:ss (24 hour clock)$'
  211. echhlp    db    'line of text to be Echoed to screen$'
  212. ptshlp    db    'amount of time to pause/wait'
  213.     db    cr,lf,' Time is number of seconds or until a specific'
  214.     db    ' hh:mm:ss (24 hour clock)$'
  215. wthlp    db    cr,lf,' Optional modem status signals CD, CTS, DSR, RI which'
  216.     db    ' if asserted',cr,lf,'  will terminate waiting$'
  217. xmthlp    db    ' Name of file to be Transmitted$'
  218. pmthlp    db    cr,lf
  219.     db     ' Prompt character expected as an ACK from host (\0 for none)$'
  220. ifdfhlp    db    cr,lf,' Name of macro or variable$'
  221. alrmhlp    db    cr,lf,' Seconds from now or time of day (HH:MM:SS) for alarm,'
  222.     db    ' < 12H from present$'
  223. mphlp    db    cr,lf,' Number of milliseconds to pause (0..65535)$'
  224. ifmhlp    db    cr,lf,' Number, ARGC (1+argument count), COUNT, ERRORLEVEL,'
  225.     db    ' KEYBOARD, VERSION$'
  226. ifnhlp    db    cr,lf,' Number which errorlevel should match or exceed$'
  227. ifehlp    db    cr,lf,' word or variable to be compared$'
  228. ifnewhlp db    ' filename$'
  229. whilehlp db    cr,lf,' While if-condition {command, command,...}'
  230. chgvarhlp db    'name of variable$'
  231. ssizehlp db    'amount, default is 1$'
  232. clrhelp    db    cr,lf,' INPUT-BUFFER (script string matching buffer), or'
  233.     db    cr,lf,' DEVICE-BUFFER (comms receive), or BOTH (buffers)'
  234.     db    cr,lf,' APC (to not return to Connect mode after APC cmd)$'
  235. mskcmd    db      ' Kermit command$'
  236.     db    cr,lf,' "IF" condition is false, command will be ignored.$'
  237. sleephlp db    cr,lf,' Wait seconds or time of day (HH:MM:SS), does not'
  238.     db    ' touch comms port.$'
  239. switchhlp1 db    cr,lf,' index'
  240. switchhlp2 db    ' {body of Switch statement}$'
  241.  
  242. ; ifkind    0 1 2     3    4 5 6        7 8       9      10
  243. ifhlplst dw 0,0,ifnewhlp,ifnhlp,0,0,ifdfhlp,0,ifehlp,ifmhlp,ifmhlp
  244. ;       11      12     13    14     15      16
  245.     dw ifmhlp,ifehlp,ifehlp,ifnewhlp,ifnewhlp,ifnewhlp
  246. data1    ends
  247.  
  248. code1    segment
  249.     extrn    isdev:far, tolowr:far, prtasz:far, strlen:far, domath:far
  250.     extrn    isfile:far, malloc:far, atpclr:near, atparse:near
  251.     extrn    strcpy:far, prtscr:far, dec2di:far, strcat:far, docnv:far
  252.     extrn    takrd:far, toupr:far, poplevel:far
  253. extrn decout:far,valout:far
  254.     assume    cs:code1
  255. code1    ends
  256.  
  257. code    segment
  258.      
  259.     extrn    comnd:near, clrbuf:near, prtchr:near, outchr:near
  260.     extrn    cptchr:near, serini:near, pcwait:far, spath:near
  261.     extrn    getmodem:near, sendbr:near, takclos:far
  262.     extrn    sendbl:near, lnout:near, dopar:near, dodecom:near
  263.     extrn    takopen_macro:far, cnvlin:near
  264.     assume    cs:code, ds:data, es:nothing
  265.  
  266. fcptchr    proc    far
  267.     call    cptchr
  268.     ret
  269. fcptchr    endp
  270.  
  271. fprtchr    proc    far
  272.     call    prtchr
  273.     ret
  274. fprtchr    endp
  275.  
  276. ; Initialize script routines before use, called as Kermit initializes.
  277.  
  278. SCPINI    PROC    NEAR
  279.     mov    cx,scpbuflen        ; (RE)INPUT buffer length
  280.     mov    bx,cx            ; string length, in bytes
  281.     add    bx,15            ; round up
  282.     jnc    scpini1            ; nc = under max size
  283. scpini3:mov    bx,0ffffh        ; 64KB-16 bytes, max buffer
  284. scpini1:mov    cl,4
  285.     shr    bx,cl            ; convert to paragraphs (divide by 16)
  286. scpini2:mov    cx,bx            ; remember desired paragraphs
  287.     mov    ah,alloc        ; allocate a memory block
  288.     int    dos
  289.     jc    scpini4            ; error, not enough memory
  290.     mov    bufseg,ax        ; store new segment
  291.     mov    cl,4
  292.     shl    bx,cl            ; convert paragraphs to bytes
  293.     mov    scpbuflen,bx        ; new length
  294.     mov    bufcnt,0        ; clear the buffer (say is empty)
  295.     mov    bufrptr,0        ; buffer read-next pointer
  296.     clc                ; return success
  297.     ret
  298. scpini4:mov    scpbuflen,0
  299.     stc                ; carry set for failure to initialize
  300.     ret
  301. SCPINI    ENDP
  302.  
  303. ; Clear input buffer(s) of serial port
  304. ; Clear command
  305. ;     
  306. SCCLR    PROC    NEAR
  307.     mov    comand.cmcr,1        ; permit empty line
  308.     mov    ah,cmkey
  309.     mov    dx,offset clrtable
  310.     mov    bx,offset clrhelp
  311.     call    comnd
  312.     mov    comand.cmcr,0
  313.     mov    kstatus,kssuc        ; global status
  314.     push    bx            ; cmd return
  315.     mov    ah,cmeol        ; get a confirm
  316.     call    comnd
  317.     pop    bx
  318.     jnc    scclr1            ; nc = success
  319.     ret                ; failure
  320. scclr1:    xor    ax,ax
  321.     mov    disp_state,ax        ; reinit escape parser
  322.     cmp    bx,1
  323.     jne    scclr2
  324.     mov    bufcnt,ax        ; clear INPUT buffer (say is empty)
  325.     mov    bufrptr,ax        ; buffer read-next pointer
  326.     clc
  327.     ret
  328. scclr2:    cmp    bx,2
  329.     jne    scclr3            ; default, gibberish bx
  330.     call    clrbuf
  331.     clc
  332.     ret
  333. scclr3:    cmp    bx,3            ; BOTH?
  334.     jne    scclr4            ; ne = no
  335.     mov    bufcnt,ax        ; clear INPUT buffer (say is empty)
  336.     mov    bufrptr,ax        ; buffer read-next pointer
  337.     call    clrbuf            ; clear system serial port buffer too
  338.     clc
  339.     ret
  340. scclr4:    cmp    bx,4            ; APC?
  341.     jne    scclr7
  342. scclr5:    call    poplevel        ; pop macro/take level
  343.     ret
  344. scclr7:    stc                ; fail
  345.     ret
  346. SCCLR    ENDP
  347.  
  348. XECHO    proc    near
  349.     mov    temp,1            ; say want no leading cr/lf
  350.     jmp    short echo1
  351. XECHO    endp
  352.  
  353. ;
  354. ; Echo a line of text to our screen
  355. ; Echo text
  356. ;
  357. SCECHO    PROC    NEAR
  358.     mov    temp,0            ; say do cr/lf before text
  359. echo1:    mov    ah,cmline        ; get a whole line of asciiz text
  360.     mov    bx,offset rdbuf        ; where to store in
  361.     mov    comand.cmdonum,1    ; \number conversion allowed
  362.     mov    comand.cmblen,cmdblen    ; set line capacity (length of rdbuf)
  363.     mov    dx,offset echhlp    ; help
  364.     call    comnd
  365.     jnc    echo2
  366.     ret
  367. echo2:    push    ax            ; returned byte count
  368.     cmp    temp,0            ; perform leading cr/lf?
  369.     jne    echo3            ; ne = no
  370.     mov    ah,prstr
  371.     mov    dx,offset crlf
  372.     int    dos
  373. echo3:    pop    cx            ; recover byte count
  374.     mov    di,offset rdbuf        ; start of line
  375.     call    prtscr            ; print all bytes in ds:di, cx = count
  376.     clc                ; return success
  377.     ret                ; error
  378. SCECHO    ENDP
  379.  
  380. ; Extract label from command line. Store in LINE, length in slablen.
  381. ; Jump to line in Take or Macro following that label.
  382. SGOTO    PROC    NEAR
  383.     mov    forward,0        ; assume goto, not forward
  384. goto0:    mov    kstatus,kssuc        ; global status
  385.     mov    ah,cmword        ; get label (leaves ending CR unread)
  386.     mov    bx,offset line        ; buffer to hold label
  387.     xor    dx,dx            ; no help (non-interactive command)
  388.     mov    slablen,dx        ; clear label holding buffer
  389.     call    comnd
  390.     jnc    goto1            ; nc = success
  391.     ret                ; failure
  392. goto1:    mov    slablen,ax        ; save count here
  393.     cmp    slablen,0        ; need contents
  394.     jz    goto2            ; empty, fail
  395.     cmp    flags.cxzflg,'C'    ; check for Control-C breakout
  396.     je    goto2            ; e = yes, fail
  397.     cmp    taklev,0        ; in a Take file or Macro?
  398.     jne    goto3            ; ne = yes, find the label
  399.     clc                ; ignore interactive command
  400.     ret
  401. goto2:    stc
  402.     ret
  403. goto3:    call    getto            ; far call the label finding worker
  404.     mov    comand.cmkeep,0        ; do not keep open the macro after EOF
  405.     ret
  406. SGOTO    ENDP
  407.  
  408. ; Like GOTO but searches only forward from the current point.
  409. ; Forward cascades upward during searches of surrounding Take files/macros.
  410. SFORWARD proc    near
  411.     mov    forward,1        ; say search only forward
  412.     jmp    goto0
  413. SFORWARD endp
  414.  
  415. ; SWITCH variable {:label,commands,:label,commands,...}
  416. ; Have label :default present for unmatched labels.
  417. SWITCH    proc    near
  418.     mov    ah,cmword        ; get variable
  419.     mov    bx,offset line        ; where to store it
  420.     mov    comand.cmdonum,0    ; \number conversion NOT allowed
  421.     mov    dx,offset switchhlp1    ; help
  422.     call    comnd
  423.     jnc    swit1
  424.     ret
  425. swit1:    mov    slablen,ax        ; length of label
  426.     mov    ah,cmline
  427.     mov    bx,offset rdbuf+2    ; buffer for switch body
  428.     mov    dx,offset switchhlp2    ; help
  429.     mov    comand.cmdonum,1    ; \number conversion is allowed
  430.     mov    comand.cmper,1        ; do not react to '\%' in macro name
  431.     mov    comand.cmcnvkind,cmcnv_crprot ; allow CR within {..}
  432.     mov    comand.cmblen,cmdblen    ; set line capacity (length of rdbuf)
  433.     call    comnd
  434.     jnc    swit2
  435.     ret
  436. swit2:    mov    word ptr rdbuf,ax    ; length to start of string
  437.     mov    si,ds
  438.     mov    es,si
  439.     mov    si,offset rdbuf        ; es:si is source of string
  440.     call    docnv            ; convert macro string in-place
  441.     call    takopen_macro        ; open macro
  442.     jnc    swit3            ; nc = succeeded
  443.     ret
  444. swit3:    mov    ax,word ptr rdbuf    ; string length
  445.     add    ax,2            ; plus count word
  446.     call    malloc            ; ax has size of buffer
  447.     jnc    swit4            ; nc = success
  448.     ret                ; fail
  449.  
  450. swit4:    mov    bx,takadr        ; point to current macro structure
  451.     mov    [bx].takbuf,ax        ; segment of definition string struc
  452.     mov    cx,word ptr rdbuf    ; string length
  453.     mov    [bx].takcnt,cx        ; number of chars in definition
  454.     mov    [bx].takptr,2        ; where to read first string byte
  455.     or    [bx].takattr,take_malloc; say have buffer to be removed
  456.     or    [bx].takattr,take_while    ; so Break/Continue work
  457.     mov    si,offset rdbuf        ; switch body string
  458.     push    es
  459.     mov    es,ax            ; new memory segment
  460.     xor    di,di            ; follow with string
  461.     add    cx,2            ; copy count word too
  462.     cld
  463.     rep    movsb            ; copy string to malloc'd buffer
  464.     pop    es
  465.     mov    forward,2        ; identify SWITCH operation
  466.     call    getto            ; find line after label or fail
  467.     jc    swit5            ; c = failed, try label :default
  468.     ret                ; found, execute
  469. swit5:    mov    si,offset deflabel    ; label :default
  470.     mov    di,offset line
  471.     call    strcpy
  472.     mov    dx,offset line
  473.     call    strlen
  474.     mov    slablen,cx
  475.     mov    bx,takadr        ; rewind the macro
  476.     mov    [bx].takptr,2        ; where to read next time
  477.     mov    ax,[bx].takbuf        ; segment of string
  478.     mov    es,ax
  479.     mov    ax,es:[0]        ; get string length from string
  480.     mov    [bx].takcnt,ax        ; quantity unread
  481.     call    getto            ; dispatch to label :default
  482.     jc    swit6            ; failed to find :default
  483.     ret                ; success, do :default commands
  484. swit6:    call    takclos            ; close switch macro
  485.     stc                ; fail
  486.     ret
  487. SWITCH    endp
  488.  
  489. ; IF [NOT] {< }| = | > | ALARM | COUNT | FAILURE | SUCCESS | INPATH filespec
  490. ;    | ERRORLEVEL \number | EQUAL string string | EXIST filespec |
  491. ;    NUMBER } command
  492.  
  493. IFCMD    PROC    NEAR
  494.     xor    ax,ax
  495.     mov    ifkind,al        ; say doing IF, not XIF or WHILE
  496.     mov    notflag,al        ; assume NOT keyword is absent
  497.     mov    ifelse,al        ; say ELSE if not yet permitted
  498.  
  499. ifcmd1:    mov    ah,cmkey        ; parse keyword
  500.     mov    dx,offset iftable    ; table of keywords
  501.     xor    bx,bx            ; help is the table
  502.     call    comnd
  503.     jnc    ifcmd1a            ; nc = success
  504.     ret                ; failure
  505. ifcmd1a:cmp    bx,ifnot        ; NOT keyword?
  506.     jne    ifcmd2            ; ne = no
  507.     xor    notflag,1        ; toggle not flag
  508.     jmp    short ifcmd1        ; and get next keyword
  509.  
  510. ifcmd2:    cmp    bx,ifsuc        ; IF SUCCESS?
  511.     jne    ifcmd4            ; ne = no
  512.     cmp    kstatus,kssuc        ; do we have success?
  513.     je    ifcmd2a            ; e = yes
  514.     jmp    ifcmdf            ; ne = no, no jump
  515. ifcmd2a:jmp    ifcmdp            ; yes
  516.  
  517. ifcmd4:    cmp    bx,iferr        ; IF ERRORLEVEL?
  518.     jne    ifcmd5            ; ne = no
  519.     jmp    ifnum            ; parse number to binary in line
  520.  
  521. ifcmd5:    cmp    bx,ifext        ; IF EXIST filespec?
  522.     je    ifcmd5a            ; e = yes
  523.     cmp    bx,ifpath        ; IF INPATH filespec?
  524.     je    ifcmd5a            ; e = yes
  525.     cmp    bx,ifdir        ; IF DIR filespec?
  526.     jne    ifcmd6            ; ne = no
  527. ifcmd5a:mov    ah,cmword        ; read a filespec
  528.     mov    dx,offset ifnewhlp    ; help
  529.     mov    comand.cmblen,cmdblen    ; long for long paths
  530.     push    bx
  531.     mov    bx,offset rdbuf        ; buffer for filespec
  532.     mov    word ptr [bx],0
  533.     call    comnd
  534.     pop    bx
  535.     jnc    ifcmd5k            ; nc = success
  536.     ret                ; failure
  537. ifcmd5k:or    ax,ax            ; any text?
  538.     jnz    ifcmd5b            ; nz = yes
  539.     jmp    ifcmdf            ; fail
  540.  
  541. ifcmd5b:mov    si,offset rdbuf        ; file spec, top of loop
  542.     mov    dx,si
  543.     call    strlen
  544.     add    si,cx            ; look at last char
  545.     or    cx,cx            ; if any bytes
  546.     jz    ifcmd5d            ; z = none
  547.     cmp    byte ptr [si-1],':'    ; ends on ":"?
  548.     je    ifcmd5f            ; e = yes, just a drive letter
  549.     cmp    byte ptr [si-1],'\'    ; ends on backslash?
  550.     je    ifcmd5e            ; e = yes
  551.     cmp    byte ptr [si-1],'.'    ; ends on dot?
  552.     jne    ifcmd5d            ; ne = no
  553. ifcmd5e:mov    byte ptr [si-1],0    ; trim trailing backslash
  554.     jmp    short ifcmd5b        ; keep trimming
  555.  
  556. ifcmd5f:cmp    bx,ifdir        ; IF DIRECTORY?
  557.     jne    ifcmd5d            ; ne = no
  558.     mov    ah,gcurdsk        ; get current disk
  559.     int    dos
  560.     push    ax            ; save current disk in al
  561.     xor    dl,dl
  562.     xchg    dl,rdbuf        ; get drive letter, set rdbuf=0 fail
  563.     or    dl,40h            ; to lower
  564.     sub    dl,'a'            ; 'a' is 0
  565.     mov    ah,seldsk        ; select disk
  566.     int    dos
  567.     jc    ifcmd5g            ; c = fail
  568.     cmp    ah,0ffh            ; 0ffh is failure too
  569.     je    ifcmd5g            ; e = failure
  570.     inc    rdbuf            ; 1 is success
  571. ifcmd5g:pop    ax
  572.     mov    dl,al            ; current disk
  573.     mov    ah,seldsk        ; reset to current directory
  574.     int    dos
  575.     cmp    rdbuf,0            ; fail?
  576.     je    ifcmdf            ; e = yes
  577.     jmp    ifcmdp            ; pass
  578.  
  579. ifcmd5d:cmp    bx,ifpath        ; IF INPATH?
  580.     je    ifcmd5c            ; e = yes
  581.     mov    ax,offset rdbuf        ; isfile wants pointer in ds:ax
  582.     push    bx
  583.     call    isfile            ; see if file EXISTS
  584.     pop    bx
  585.     jc    ifcmdf            ; c = no, fail
  586.     cmp    bx,ifdir        ; IF DIRECTORY?
  587.     jne    ifcmdp            ; ne = no, Exists so succeed
  588.     test    byte ptr filtst.dta+21,10H ; subdirectory name?
  589.     jnz    ifcmdp            ; nz = yes
  590.     cmp    filtst.fname,2eh    ; directory name?
  591.     je    ifcmdp            ; e = yes
  592.     jmp    ifcmdf            ; else fail
  593. ifcmd5c:push    es
  594.     mov    ax,inpath_seg        ; preexisting inpath_seg?
  595.     or    ax,ax
  596.     jz    ifcmd5h            ; z = no buffer yet
  597.     mov    es,ax            ; free it now
  598.     mov    ah,freemem
  599.     int    dos
  600.     mov    inpath_seg,0        ; say no segment
  601. ifcmd5h:pop    es
  602.     mov    ax,offset rdbuf        ; file pointer
  603.     call    spath            ; search path
  604.     jc    ifcmdf            ; c = no such file
  605.     push    es
  606.     push    ax
  607.     mov    dx,ax            ; offset of local copy of ds:string
  608.     call    strlen
  609.     mov    si,ax            ; start of string
  610.     add    si,cx            ; end of string + 1
  611. ifcmd5i:dec    si
  612.     cmp    byte ptr [si],'\'    ; path/filename separator?
  613.     je    ifcmd5j            ; e = yes
  614.     cmp    byte ptr [si],':'    ; drive separator?
  615.     je    ifcmd5j            ; e = yes
  616.     loop    ifcmd5i
  617. ifcmd5j:inc    si
  618.     inc    cx
  619.     mov    byte ptr [si],0        ; stuff a terminator
  620.     mov    ax,cx            ; length needed
  621.     add    ax,2            ; plus length word
  622.     call    malloc            ; create a buffer
  623.     mov    inpath_seg,ax        ; segment of string
  624.     mov    es,ax
  625.     xor    di,di
  626.     mov    ax,cx
  627.     cld
  628.     stosw                ; store count
  629.     pop    si            ; ds:offset of path string (was AX)
  630.     rep    movsb            ; copy string to buffer
  631.     pop    es
  632.     jmp    ifcmdp            ; succeed, do the succeed stuff
  633.     
  634. ifcmd6:    cmp    bx,iffail        ; IF FAIL?
  635.     jne    ifcmd7
  636.     test    kstatus,not (kssuc)    ; check all bits
  637.     jz    ifcmdf            ; z = not that condition, no jump 
  638.     jmp    ifcmdp
  639.  
  640. ifcmd7:    cmp    bx,ifctr        ; IF COUNT?
  641.     jne    ifcmd8            ; ne = no
  642.     cmp    taklev,0        ; in a Take file?
  643.     je    ifcmdf            ; e = no, fail
  644.     push    bx
  645.     mov    bx,takadr        ; current Take structure
  646.     cmp    [bx].takctr,0        ; exhausted count?
  647.     je    ifcmd7a            ; e = yes, dec no more ye counter
  648.     dec    [bx].takctr        ; dec COUNT if non-zero
  649.     jz    ifcmd7a            ; z = exhausted
  650.     pop    bx
  651.     jmp    ifcmdp            ; COUNT > 0 at entry, execute command
  652. ifcmd7a:pop    bx
  653.     jmp    ifcmdf            ; do not execute command
  654.  
  655. ifcmd8:    cmp    bx,ifmdf        ; IF DEF?
  656.     jne    ifcmd9            ; ne = no
  657.     jmp    ifmdef            ; do further parsing below
  658.  
  659. ifcmd9:    cmp    bx,ifalarm        ; IF ALARM?
  660.     jne    ifcmd10            ; ne = no
  661.     jmp    ifalrm            ; do further parsing below
  662.  
  663. ifcmd10:cmp    bx,ifequal        ; IF EQUAL?
  664.     jne    ifcmd10a        ; ne = no
  665.     jmp    ifequ            ; do further parsing below
  666. ifcmd10a:cmp    bx,iflgt        ; IF LGT?
  667.     jne    ifcmd10b        ; ne = no
  668.     jmp    ifequ
  669. ifcmd10b:cmp    bx,ifllt        ; IF LLT?
  670.     jne    ifcmd11            ; ne = no
  671.     jmp    ifequ
  672.  
  673. ifcmd11:cmp    bx,ifless        ; IF <?
  674.     je    ifcmd12            ; e = yes
  675.     cmp    bx,ifsame        ; IF =?
  676.     je    ifcmd12
  677.     cmp    bx,ifmore        ; IF > ?
  678.     jne    ifcmd13            ; ne = no
  679. ifcmd12:jmp    ifmath
  680.  
  681. ifcmd13:cmp    bx,ifnumeric        ; IF NUMBER?
  682.     jne    ifcmd14            ; ne = no
  683.     jmp    ifnumeric
  684.  
  685. ifcmd14:cmp    bx,ifnewer        ; IF NEWER?
  686.     jne    ifcmd17
  687.     jmp    tstnewer        ; do file newer test
  688.  
  689. ifcmd17:cmp    bx,iftrue        ; IF TRUE?
  690.     jne    ifcmd18            ; ne = no
  691.     jmp    ifcmdp            ; jump to test passed code
  692.  
  693. ifcmd18:cmp    bx,ifemulation        ; IF EMULATION?
  694.     jne    ifcmdf            ; ne = no
  695.     jmp    ifcmdf            ; always evaluates as False
  696.  
  697.                     ; Jump points for worker routines
  698.                     ; failure
  699. ifcmdf:    cmp    notflag,0        ; need to apply not condition?
  700.     jne    ifcmdp2            ; ne = yes, take other exit
  701. ifcmdf2:cmp    ifkind,1        ; doing XIF command, and failed?
  702.     jne    ifcmdf3            ; ne = no
  703.     mov    bx,offset rdbuf
  704.     xor    dx,dx            ; help
  705.     mov    comand.cmper,1        ; don't expand variables at this time
  706.     mov    comand.cmblen,cmdblen
  707.     mov    comand.cmcnvkind,cmcnv_crprot ; allow CR within {..}
  708.     mov    ah,cmword        ; read the success word
  709.     call    comnd
  710.     jc    ifcmdf3
  711.     mov    bx,offset rdbuf        ; now read ELSE
  712.     xor    dx,dx            ; help
  713.     mov    comand.cmper,1        ; don't expand variables at this time
  714.     mov    comand.cmblen,cmdblen
  715.     mov    ah,cmword
  716.     call    comnd
  717.     jc    ifcmdf3
  718.     cmp    ax,4            ; four bytes for ELSE?
  719.     jne    ifcmdf3            ; ne = no, fail outright
  720.     mov    ax,word ptr rdbuf    ; check spelling
  721.     or    ax,2020h        ; quick to lower case
  722.     cmp    ax,'le'
  723.     jne    ifcmdf3            ; ne = spelling failure
  724.     mov    ax,word ptr rdbuf+2
  725.     or    ax,2020h
  726.     cmp    ax,'es'
  727.     jne    ifcmdf3            ; ne = not present, use failure case
  728.     jmp    ifcmdp2            ; make macro of rest of line    
  729.  
  730. ifcmdf3:mov    ifelse,1        ; say permit following ELSE command
  731.     cmp    taklev,0        ; in a macro/take file?
  732.     je    ifcmdf4a        ; e = not in macro/take file
  733.     mov    bx,takadr
  734.     test    [bx].takattr,take_while    ; is this a for/while macro?
  735.     jz    ifcmdf4a        ; z = no
  736.     mov    [bx].takcnt,0        ; read nothing more from While macro
  737.     mov    ifelse,0        ; no following ELSE command
  738.  
  739. ifcmdf4a:mov    bx,offset rdbuf+2    ; soak line with no echo
  740.     xor    dx,dx            ; no help
  741.     mov    comand.cmblen,cmdblen
  742.     mov    comand.cmkeep,0
  743.     mov    comand.cmcnvkind,cmcnv_crprot ; allow CR within {..}
  744.     mov    ah,cmline        ; soak up rest of line
  745.     call    comnd
  746. ifcmdf5:clc                ; force success on discard of line
  747.     ret
  748.  
  749.                     ; success (pass)
  750. ifcmdp:    cmp    notflag,0        ; need to apply not condition?
  751.     jne    ifcmdf2            ; ne = yes, take other exit
  752. ifcmdp2:mov    bx,offset rdbuf+2
  753.     xor    dx,dx            ; help
  754.     mov    comand.cmper,1        ; don't expand variables at this time
  755.     mov    comand.cmblen,cmdblen
  756.     mov    comand.cmcnvkind,cmcnv_crprot ; allow CR within {..}
  757.     mov    ah,cmword        ; read word into buffer
  758.     cmp    ifkind,1        ; xif?
  759.     je    ifcmdp2a        ; e = yes, read word
  760.     mov    ah,cmline        ; read line for non-XIF's
  761.     cmp    taklev,0        ; in a takefile/macro?
  762.     je    ifcmdp2a        ; e = no
  763.     push    bx
  764.     mov    bx,takadr
  765.     test    [bx].takattr,take_while    ; for/while?
  766.     pop    bx
  767.     jz    ifcmdp2a        ; z = no
  768.     mov    comand.cmkeep,1        ; keep for/while open after read
  769. ifcmdp2a:call    comnd
  770.     jnc    ifcmdp3            ; nc = success
  771.     ret
  772.  
  773. ifcmdp3:mov    word ptr rdbuf,ax    ; store response length in buffer
  774.     cmp    ifkind,1        ; xif
  775.     je    ifcmdp3d        ; e = yes, no rewinding
  776.     cmp    taklev,0        ; still in a take file?
  777.     je    ifcmdp3d        ; e = no
  778.     push    bx
  779.     mov    al,taklev
  780.     mov    bx,takadr
  781.     test    [bx].takattr,take_while    ; is a for/while macro active?
  782.     jz    ifcmdp3b        ; z = no
  783.     mov    ax,[bx].takbuf        ; rewind the macro,  seg of buffer
  784.     mov    es,ax
  785.     mov    ax,es:[0]        ; get original filling qty
  786.     mov    [bx].takcnt,ax        ; set as unread qty
  787.     mov    [bx].takptr,2        ; from offset 2
  788. ifcmdp3b:pop    bx
  789.  
  790. ifcmdp3d:cmp    ifkind,1        ; xif?
  791.     jne    ifcmdp3a        ; ne = no, have read line
  792.     mov    ah,cmline        ; read and discard rest of line
  793.     mov    comand.cmblen,cmdblen    ; discards the else <cmds> part
  794.     inc    bx
  795.     mov    dx,offset mskcmd    ; enter any command
  796.     mov    comand.cmcnvkind,cmcnv_crprot ; allow CR within {..}
  797.     mov    comand.cmper,1        ; don't expand variables at this time
  798.     call    comnd
  799.  
  800. ifcmdp3a:mov    dx,offset rdbuf+2
  801.     call    strlen            ; docnv cmds which permit {,..,}
  802.     mov    word ptr rdbuf,cx    ; plant count word for docnv
  803.     mov    ax,ds
  804.     mov    es,ax
  805.     mov    si,offset rdbuf        ; need count word here
  806.     cmp    ifkind,1        ; XIF?
  807.     je    ifcmdp3c        ; e = yes
  808.     mov    bx,takadr
  809.     test    [bx].takattr,take_while    ; is a for/while macro active?
  810.     jz    ifcmdp3e        ; z = no
  811. ifcmdp3c:call    docnv            ; convert macro string in place
  812. ifcmdp3e:mov    ax,cx
  813.     add    ax,2            ; plus count word
  814.     call    malloc            ; grab memory
  815.     mov    es,ax            ; segment
  816.     mov    di,2            ; start two bytes in
  817.     mov    si,offset rdbuf+2
  818.     push    cx
  819.     cld
  820.     rep    movsb            ; copy to malloc'd area
  821.     pop    cx
  822.     call    takopen_macro        ; open a macro
  823.     mov    bx,takadr        ; point to current macro structure
  824.     mov    ax,es            ; segment of definition
  825.     mov    [bx].takbuf,ax        ; segment of definition string struc
  826.     mov    [bx].takcnt,cx        ; number of chars in definition
  827.     mov    es:[0],cx        ; original amount in buffer
  828.     mov    [bx].takargc,0        ; our argument count
  829.     mov    [bx].takptr,2        ; offset to read next command char
  830.     or    [bx].takattr,take_malloc ; free buffer when done
  831.     cmp    taklev,1        ; at least second macro level?
  832.     jbe    ifcmd3f            ; be = ne, skip caller-testing
  833.     push    bx
  834.     sub    bx,size takinfo        ; backup to main macro
  835.     test    [bx].takattr,take_while    ; was it a for/while loop?
  836.     pop    bx
  837.     jz    ifcmd3f            ; z = no
  838.     or    [bx].takattr,take_subwhile ; mark this macro as part of it
  839. ifcmd3f:clc
  840.     ret
  841. IFCMD    ENDP
  842.  
  843.  
  844. XIFCMD    proc near
  845.     mov    ifkind,1        ; say doing XIF command
  846.     mov    notflag,0        ; assume NOT keyword is absent
  847.     jmp    ifcmd1            ; do common code
  848. XIFCMD    endp
  849.  
  850. ; While if-condition {command, command,...}
  851. WHILECMD proc    near
  852.     mov    di,offset rdbuf+2
  853.     mov    word ptr [di],'FI'
  854.     mov    byte ptr [di+2],' '    ; 'IF ' prefix
  855.     add    di,3            ; append line to prefix
  856.  
  857. while1:    mov    ah,cmkey        ; parse keyword
  858.     mov    dx,offset iftable    ; table of keywords
  859.     push    di            ; save built-up string
  860.     xor    bx,bx            ; help is the table
  861.     call    comnd
  862.     pop    di
  863.     jnc    while2            ; nc = success
  864. whilex:    ret                ; failure
  865. while2:    mov    temp,bx            ; save keyword value
  866.     cmp    bx,ifnot        ; NOT keyword?
  867.     jne    while3            ; ne = no
  868.     mov    word ptr [di],'ON'    ; insert 'NOT '
  869.     mov    word ptr [di+2],' T'
  870.     add    di,4
  871.     jmp    short while1        ; and get next keyword
  872. while3:    mov    dx,offset iftable    ; table of keywords
  873.     call    revlookup        ; get cx,si for keyword text
  874.     jc    whilex            ; c = fail, should never happen
  875.     mov    ax,ds
  876.     mov    es,ax
  877.     cld
  878.     rep    movsb            ; copy keyword text
  879.     mov    al,' '            ; plus a space
  880.     stosb
  881.     mov    bx,di            ; work with bx as destination now
  882.     xor    ch,ch    
  883.     mov    cl,byte ptr [si+1]    ; number of following arguments
  884.     jcxz    while6            ; z = none, get command
  885.  
  886. while4:    mov    comand.cmper,1        ; don't expand variables here
  887.     mov    al,byte ptr temp    ; keyword value
  888.     xor    ah,ah
  889.     mov    si,ax
  890.     shl    si,1
  891.     mov    ax,seg ifhlplst        ; where help text lives
  892.     mov    es,ax
  893.     mov    dx,es:ifhlplst[si]    ; get help msg pointer
  894.     mov    ah,cmword        ; read argument word
  895.     push    cx            ; save loop counter
  896.     call    comnd
  897.     pop    cx
  898.     jnc    while5
  899.     ret
  900. while5:    mov    byte ptr [bx],' '    ; space
  901.     inc    bx            ; ready for next phrase
  902.     loop    while4
  903.  
  904. while6:    mov    comand.cmper,1        ; don't expand variables here
  905.     mov    comand.cmblen,cmdblen
  906.     mov    comand.cmcnvkind,cmcnv_crprot ; allow CR within {..}
  907.     mov    dx,offset mskcmd
  908.     mov    ah,cmline        ; read whole line as command
  909.     call    comnd
  910.     jnc    while7
  911.     ret
  912. while7:    mov    ifkind,2        ; say doing WHILE command
  913.     mov    si,offset rdbuf+2
  914.     mov    dx,si
  915.     call    strlen            ; length of final string
  916.     mov    ax,cx
  917.     add    ax,2+1            ; plus count word plus safety
  918.     call    malloc
  919.     mov    es,ax            ; seg
  920.     mov    di,2            ; start two bytes in
  921.     push    cx
  922.     cld
  923.     rep    movsb            ; copy to malloc'd area
  924.     pop    cx
  925.     call    takopen_macro        ; open a macro
  926.     mov    bx,takadr        ; point to current macro structure
  927.     mov    ax,es            ; segment of definition
  928.     mov    [bx].takbuf,ax        ; segment of definition string struc
  929.     mov    [bx].takcnt,cx        ; number of chars in definition
  930.     mov    es:[0],cx        ; count for goto's
  931.     mov    [bx].takargc,0        ; our argument count
  932.     mov    [bx].takptr,2        ; offset to read next command char
  933.     or    [bx].takattr,take_malloc ; free buffer when done
  934.     or    [bx].takattr,take_while    ; mark as our While loop
  935.     clc
  936.     ret
  937. WHILECMD endp
  938.  
  939. ; Compare errlev against user number. Jump successfully if errlev >= number.
  940. ; Worker for IF [NOT] ERRORLEVEL number <command>
  941. ifnum    proc    near
  942.     mov    ah,cmword        ; get following number
  943.     mov    bx,offset rdbuf
  944.     mov    comand.cmblen,cmdblen
  945.     mov    dx,offset ifnhlp    ; help
  946.     call    comnd
  947.     jnc    ifnum1            ; nc = success
  948.     ret                ; failure
  949. ifnum1:    mov    domath_ptr,offset rdbuf    ; text in compare buffer
  950.     mov    domath_cnt,ax
  951.     mov    domath_msg,1        ; no error message
  952.     call    domath            ; convert to number in dx:ax
  953.     cmp    domath_cnt,0        ; converted whole word?
  954.     je    ifnum2            ; e = yes
  955.     mov    notflag,0        ; fail completely
  956.     jmp    ifcmdf
  957. ifnum2:    cmp    errlev,al        ; at or above this level?
  958.     jae    ifnum3            ; ae = yes, succeed
  959.     jmp    ifcmdf            ; else fail
  960. ifnum3:    jmp    ifcmdp            ; jump to main command Success exit
  961. ifnum    endp
  962.  
  963. ; Compare text as number. Jump successfully if number.
  964. ifnumeric proc    near
  965.     mov    ah,cmword        ; get following number
  966.     mov    bx,offset rdbuf
  967.     mov    comand.cmblen,cmdblen
  968.     mov    dx,offset ifnhlp    ; help
  969.     call    comnd
  970.     jnc    ifnumer1        ; nc = success
  971.     ret                ; failure
  972. ifnumer1:mov    cx,ax            ; length of string
  973.     mov    si,offset rdbuf        ; where string starts
  974.     cmp    cx,1            ; more than one char?
  975.     je    ifnumer2        ; e = no
  976.     jb    ifnumer3        ; b = no chars
  977.     lodsb                ; could be +/- digits
  978.     dec    cx
  979.     cmp    al,'+'            ; leading sign?
  980.     je    ifnumer2        ; e = acceptable
  981.     cmp    al,'-'
  982.     je    ifnumer2        ; e = acceptable
  983.     inc    cx            ; back up to first byte
  984.     dec    si
  985. ifnumer2:lodsb
  986.     cmp    al,'0'            ; check for '0'..'9' as numeric
  987.     jb    ifnumer3        ; b = non-numeric
  988.     cmp    al,'9'
  989.     ja    ifnumer3        ; a = non-numeric
  990.     loop    ifnumer2
  991.     jmp    ifcmdp            ; jump to main command Success exit
  992. ifnumer3:jmp    ifcmdf            ; jump to main command Failure exit
  993. ifnumeric endp
  994.  
  995. ; Process IF [NOT] DEF <macro name> <command>
  996. ifmdef    proc    near
  997.     mov    bx,offset rdbuf+2    ; point to work buffer
  998.     mov    dx,offset ifdfhlp    ; help
  999.     mov    comand.cmblen,cmdblen
  1000.     mov    ah,cmword        ; get macro name
  1001.     mov    comand.cmper,1        ; do not react to \%x
  1002.     call    comnd
  1003.     jnc    ifmde1            ; nc = success
  1004.     ret                ; failure
  1005. ifmde1:    mov    word ptr rdbuf,ax    ; store length in buffer
  1006.     mov    bx,offset mcctab+1    ; table of macro keywords
  1007.     mov    tempd,0            ; tempd = current keyword
  1008.     cmp    byte ptr [bx-1],0    ; any macros defined?
  1009.     je    ifmde9            ; e = no, failure, exit now
  1010.                     ; match table keyword and user word
  1011. ifmde3:    mov    si,offset rdbuf        ; pointer to user's cnt+name
  1012.     mov    cx,[si]            ; length of user's macro name
  1013.     add    si,2            ; point to macro name
  1014.     cmp    cx,[bx]            ; compare length vs table keyword
  1015.     jne    ifmde7            ; ne = not equal lengths, try another
  1016.     push    si            ; lengths match, how about spelling?
  1017.     push    bx
  1018.     add    bx,2            ; point at start of keyword
  1019. ifmde4:    mov    ah,[bx]            ; keyword char
  1020.     mov    al,[si]            ; new text char
  1021.     cmp    al,'a'            ; map lower case to upper
  1022.     jb    ifmde5
  1023.     cmp    al,'z'
  1024.     ja    ifmde5
  1025.     sub    al,'a'-'A'
  1026. ifmde5:    cmp    al,ah            ; test characters
  1027.     jne    ifmde6            ; ne = no match
  1028.     inc     si            ; move to next char
  1029.     inc    bx
  1030.     loop    ifmde4            ; loop through entire length
  1031. ifmde6:    pop    bx
  1032.     pop    si
  1033.     jcxz    ifmde10            ; z: cx = 0, found the name
  1034.                     ; select next keyword
  1035. ifmde7:    inc    tempd            ; number of keyword to test next
  1036.     mov    cx,tempd
  1037.     cmp    cl,mcctab        ; all done? Recall, tempd starts at 0
  1038.     jae    ifmde9            ; ae = yes, no match
  1039.     mov    ax,[bx]            ; cnt (keyword length from macro)
  1040.     add    ax,4            ; skip over '$' and two byte value
  1041.     add    bx,ax            ; bx = start of next keyword slot
  1042.     jmp    short ifmde3        ; do another comparison
  1043. ifmde9:    jmp    ifcmdf            ; jump to main command Failure exit
  1044. ifmde10:jmp    ifcmdp            ; jump to main command Success exit
  1045. ifmdef    endp
  1046.  
  1047. ; IF [not] ALARM hh:mm:ss command
  1048. ifalrm    proc    near
  1049.     call    chkkbd            ; check keyboard for override
  1050.     test    status,stat_cc        ; Control-C?
  1051.     jz    ifalr1            ; z = no
  1052.     stc
  1053.     ret                ; yes, return failure now
  1054. ifalr1:    push    word ptr timhms
  1055.     push    word ptr timhms+2    ; save working timeouts
  1056.     mov    ax,word ptr alrhms
  1057.     mov    word ptr timhms,ax
  1058.     mov    ax,word ptr alrhms+2
  1059.     mov    word ptr timhms+2,ax    ; set alarm value
  1060.     call    chktmo            ; check for timeout
  1061.     pop    word ptr timhms+2    ; restore working timeouts
  1062.     pop    word ptr timhms
  1063.     test    status,stat_tmo        ; tod past user time (alarm sounded)?
  1064.     jnz    ifalr2            ; nz = yes, succeed
  1065.                     ; failure (not at alarm time yet)
  1066.     jmp    ifcmdf            ; main fail exit
  1067.                     ; success (at or past alarm time)
  1068. ifalr2:    jmp    ifcmdp            ; main pass exit
  1069. ifalrm    endp
  1070.  
  1071. ; IF [NOT] {LLT, EQUAL, LGT} word word command
  1072. ; Permits use of \number, {string}, @filespec
  1073. ifequ    proc    near
  1074.     mov    ltype,bx        ; remember kind of lex test
  1075.     mov    comand.cmblen,cmdblen
  1076.     mov    comand.cmdonum,1    ; \number conversion allowed
  1077.     mov    ah,cmword        ; get a word
  1078.     mov    bx,offset rdbuf        ; where to store
  1079.     mov    dx,offset ifehlp    ; help
  1080.     call    comnd            ; ignore parse error if no text
  1081.     jc    ifequ9            ; carry set means error
  1082.     or    ax,ax            ; byte count
  1083.     jz    ifequ3            ; z = empty word
  1084.      mov    tempd,ax
  1085.     mov    si,offset rdbuf        ; start of line
  1086.     add    si,ax
  1087.     inc    si            ; skip null terminator
  1088.     mov    temptr,si        ; place to start second part
  1089.     mov    bx,si
  1090.     mov    ah,cmword        ; get a word of text
  1091.     mov    dx,offset ifehlp    ; help
  1092.     mov    comand.cmblen,cmdblen
  1093.     mov    comand.cmdonum,1    ; \number conversion allowed
  1094.     call    comnd            ; ignore parse error if no text
  1095.     jc    ifequ9            ; c = failure
  1096.     mov    si,temptr        ; start of second line
  1097.     cmp    tempd,ax        ; first longer than second?
  1098.     jae    ifequ3            ; ae = yes
  1099.     xchg    tempd,ax        ; use length of shorter word
  1100. ifequ3:    or    ax,ax
  1101.     jz    ifequ9            ; z = empty word
  1102.     inc    ax            ; include null terminator in count
  1103.     mov    cx,ax
  1104.     mov    si,offset rdbuf        ; first word
  1105.     mov    di,temptr        ; second word
  1106.     push    es
  1107.     mov    ax,ds
  1108.     mov    es,ax
  1109.     cld
  1110. ifequ4:    lodsb
  1111.     mov    ah,[di]
  1112.     inc    di
  1113.     cmp    script.incasv,0        ; case insensitive?
  1114.     jne    ifequ5            ; ne = no
  1115.     call    toupr            ; to upper case
  1116. ifequ5:    cmp    al,ah
  1117.     loope    ifequ4
  1118.     pop    es
  1119.     jb    ifequ6            ; exited on before condition
  1120.     ja    ifequ7            ; exited on above condition
  1121.  
  1122.     cmp    ltype,ifequal        ; wanted EQUAL condition?
  1123.     jne    ifequ9            ; ne = no, fail
  1124.     jmp    ifcmdp            ; else success
  1125.  
  1126. ifequ6:    cmp    ltype,ifllt        ; LLT test?
  1127.     jne    ifequ9            ; ne = no, failed
  1128.     jmp    ifcmdp            ; do IF cmd success
  1129.  
  1130. ifequ7:    cmp    ltype,iflgt        ; LGT test?
  1131.     jne    ifequ9            ; ne = no, failed
  1132.     jmp    ifcmdp            ; do IF cmd success
  1133.  
  1134. ifequ9:    jmp    ifcmdf            ; do IF cmd failure
  1135. ifequ    endp
  1136.  
  1137. ; Worker for IF [NOT] < = > var var <command>
  1138. ; var is ARGC, COUNT, ERRORLEVEL, VERSION, or a 16 bit number
  1139. ifmath    proc    near
  1140.     mov    tempa,bx        ; save kind of math test here
  1141.     xor    ax,ax
  1142.     mov    temp,ax            ; place to store first value
  1143.     mov    temp1,ax        ; place to store high word of value
  1144.     mov    tempd,ax        ; count times around this loop
  1145. ifmath1:mov    bx,offset rdbuf
  1146.     mov    dx,offset ifmhlp    ; help
  1147.     mov    comand.cmblen,cmdblen
  1148.     mov    ah,cmword        ; get following number
  1149.     call    comnd
  1150.     jnc    ifmath2            ; nc = success
  1151.     ret                ; failure
  1152. ifmath2:mov    si,offset rdbuf        ; put text in compare buffer
  1153.     mov    ax,[si]            ; get first two user chars
  1154.     or    ax,2020h        ; lowercase both bytes
  1155.     xor    dx,dx            ; high word of apparent value
  1156.     cmp    ax,'ra'            ; ARGC?
  1157.     jne    ifmath3            ; ne = no
  1158.     xor    ax,ax
  1159.     cmp    taklev,0        ; in a Take/macro?
  1160.     je    ifmath8            ; e = no, report ARGC as 0
  1161.     mov    bx,takadr        ; current Take structure
  1162.     mov    ax,[bx].takargc        ; get argument count
  1163.     jmp    short ifmath8
  1164. ifmath3:cmp    ax,'re'            ; ERRORLEVEL?
  1165.     jne    ifmath4            ; ne = no
  1166.     mov    al,errlev        ; get errorlevel
  1167.     xor    ah,ah
  1168.     jmp    short ifmath8
  1169. ifmath4:cmp    ax,'oc'            ; COUNT?
  1170.     jne    ifmath5            ; ne = no
  1171.     xor    ax,ax
  1172.     cmp    taklev,0        ; in a Take/macro?
  1173.     je    ifmath8            ; e = no, report COUNT as 0
  1174.     mov    bx,takadr        ; current Take structure
  1175.     mov    ax,[bx].takctr        ; get COUNT
  1176.     jmp    short ifmath8
  1177. ifmath5:cmp    ax,'ev'            ; VERSION?
  1178.     jne    ifmath5a        ; ne = no
  1179.     mov    ax,version        ; get version such as 300
  1180.     jmp    short ifmath8
  1181. ifmath5a:cmp    ax,'ek'            ; KEYBOARD?
  1182.     jne    ifmath6            ; ne = no
  1183.     mov    ax,keyboard        ; get 88 or 101 for keys on keyboard
  1184.     jmp    short ifmath8
  1185. ifmath6:mov    dx,offset rdbuf        ; text in compare buffer
  1186.     call    strlen
  1187.     mov    domath_cnt,cx
  1188.     mov    domath_ptr,dx        ; text in compare buffer
  1189.     call    domath            ; convert to number in dx:ax
  1190.     cmp    domath_cnt,0        ; converted whole word?
  1191.     je    ifmath8            ; e = yes
  1192.     mov    notflag,0        ; fail completely
  1193.     jmp    short ifmathf
  1194. ifmath8:cmp    tempd,0            ; have second value yet?
  1195.     ja    ifmath9            ; a = yes, it is in ax
  1196.     mov    temp,ax            ; save first value
  1197.     mov    temp1,dx        ; high order part
  1198.     inc    tempd            ; say we have been here
  1199.     jmp    ifmath1            ; do second argument
  1200.  
  1201. ifmath9:mov    bx,tempa        ; kind of math test
  1202.     cmp    bx,ifless        ; "<"?
  1203.     jne    ifmath10        ; ne = no
  1204.     cmp    temp1,dx        ; val1 < val2?
  1205.     jl    ifmathp            ; b = pass
  1206.     jg    ifmathf            ; a = fail
  1207.     cmp    temp,ax            ; val1 < val2?
  1208.     jl    ifmathp            ; b = pass
  1209.     jmp    short ifmathf        ; fail
  1210. ifmath10:cmp    bx,ifsame        ; "="?
  1211.     jne    ifmath11        ; ne = no
  1212.     cmp    temp1,dx        ; val1 = val2?
  1213.     jne    ifmathf            ; ne = no, fail
  1214.     cmp    temp,ax            ; val1 = val2?
  1215.     je    ifmathp            ; e = yes, pass
  1216.     jmp    short ifmathf        ; fail
  1217. ifmath11:cmp    temp1,dx        ; val2 > val1?
  1218.     jg    ifmathp            ; a = yes, pass
  1219.     jl    ifcmdf            ; b = no, fail
  1220.     cmp    temp,ax            ; val2 > val1?
  1221.     jg    ifmathp            ; a = yes, pass
  1222. ifmathf:jmp    ifcmdf            ; else fail
  1223. ifmathp:jmp    ifcmdp            ; jump to main command Success exit
  1224. ifmath    endp
  1225.  
  1226. ; IF NEWER file1 file2 
  1227. tstnewer proc    near
  1228.     mov    ah,cmword        ; get first filename
  1229.     mov    bx,offset rdbuf
  1230.     mov    comand.cmblen,cmdblen
  1231.     mov    dx,offset ifnewhlp    ; help
  1232.     call    comnd
  1233.     jnc    tstnew1            ; nc = success
  1234.     jmp    tstnewf            ; failure
  1235. tstnew1:mov    ah,cmword        ; get following number
  1236.     mov    bx,offset rdbuf+65    ; second file name
  1237.     mov    comand.cmblen,cmdblen
  1238.     mov    dx,offset ifnewhlp    ; help
  1239.     call    comnd
  1240.     jnc    tstnew2            ; nc = success
  1241.     jmp    tstnewf                ; failure
  1242. tstnew2:mov    bx,offset rdbuf        ; first file
  1243.     call    getfdate        ; filedate to dx:ax
  1244.     jc    tstnewf            ; c = fail
  1245.     mov    word ptr rdbuf,ax    ; save low part
  1246.     mov    word ptr rdbuf+2,dx    ; higher
  1247.     mov    bx,offset rdbuf+65    ; second file
  1248.     call    getfdate        ; filedate to dx:ax
  1249.     jc    tstnewf            ; c = fail
  1250.     cmp    word ptr rdbuf+2,dx    ; first vs second, high word
  1251.     ja    tstnewp            ; a = newer, pass
  1252.     jb    tstnewf            ; b = older, fail
  1253.     cmp    word ptr rdbuf,ax    ; first vs second, low word
  1254.     jbe    tstnewf            ; be = older, fail
  1255. tstnewp:jmp    ifcmdp            ; pass
  1256. tstnewf:jmp    ifcmdf            ; fail
  1257. tstnewer endp
  1258.  
  1259. ; Return file date/time stamp in dx:ax, given ASCIIZ filename in bx
  1260. getfdate proc    near
  1261.     push    di
  1262.     push    es
  1263.     mov    dx,offset diskio.dta    ; data transfer address
  1264.     mov    ah,setdma        ; set disk transfer address
  1265.     int    dos
  1266.     mov    dx,bx            ; for file open
  1267.     xor    cx,cx            ; attributes: find only normal files
  1268.     mov    ah,first2        ; DOS 2.0 search for first
  1269.     int    dos            ; get file's characteristics
  1270.     pushf                ; save status
  1271.     mov    ah,setdma        ; restore dta
  1272.     mov    dx,offset buff
  1273.     int    dos
  1274.     popf                ; get status
  1275.     pop    es
  1276.     pop    di
  1277.     jnc    getfdat1        ; nc = success
  1278.     ret                ; fail
  1279. getfdat1:                ; time/date stamp yyyymmdd hh:mm:ss
  1280.     mov    dl,diskio.dta+25    ; yyyyyyym from DOS via file open
  1281.     xor    dh,dh
  1282.     shr    dx,1            ; get year
  1283.     add    dx,1980            ; add bias
  1284.     mov    ax,word ptr diskio.dta+24 ; yyyyyyyym mmmddddd  year+month+day
  1285.     clc
  1286.     ret
  1287. getfdate endp
  1288.  
  1289. ; DECREMENT/INCREMENT variable size (default size 1)
  1290. ; Permits variable to be \%<char> or a macro name. Non-negative results.
  1291. decvar    proc    near
  1292.     mov    temp,'--'        ; marker to say dec
  1293.     jmp    short incvar1
  1294. decvar    endp
  1295.  
  1296. incvar    proc    near
  1297.     mov    temp,'++'        ; marker to say inc
  1298. incvar1:mov    kstatus,ksgen        ; general command failure
  1299.     mov    ah,cmword        ; read variable name
  1300.     mov    bx,offset rdbuf+2    ; reserve word 0 for entry count
  1301.     mov    word ptr rdbuf+2,0
  1302.     mov    dx,offset chgvarhlp
  1303.     mov    comand.cmper,1        ; don't react to \%x variables
  1304.     call    comnd
  1305.     jnc    incvar2            ; nc = success
  1306.     ret                ; failure
  1307. incvar2:or    ax,ax            ; necessary macro name?
  1308.     jnz    incvar3            ; nz = yes
  1309. incvar2a:stc                ; no, fail
  1310.     ret
  1311. incvar3:mov    word ptr rdbuf,ax    ; save length of macro name
  1312.     mov    si,offset mcctab    ; table of macro names
  1313.     cld
  1314.     lodsb
  1315.     mov    cl,al            ; number of macro entries
  1316.     xor    ch,ch
  1317.     jcxz    incvar2a        ; z = none
  1318.                     ; find variable
  1319. incvar4:push    cx            ; save loop counter
  1320.     lodsw                ; length of macro name to ax
  1321.     mov    cx,word ptr rdbuf    ; length of user's string
  1322.     cmp    ax,cx            ; variable name same as user spec?
  1323.     jne    incvar6            ; ne = no, no match
  1324.     push    ax
  1325.     push    si            ; save these around match test
  1326.     mov    di,offset rdbuf+2    ; user's string
  1327. incvar5:mov    ah,[di]
  1328.     inc    di
  1329.     lodsb                ; al = mac name char, ah = user char
  1330.     and    ax,not 2020h        ; clear bits (uppercase chars)
  1331.     cmp    ah,al            ; same?
  1332.     loope    incvar5            ; while equal, do more
  1333.     pop    si            ; restore regs
  1334.     pop    ax
  1335.     jne    incvar6            ; ne = no match
  1336.     pop    cx            ; remove loop counter
  1337.     jmp    short incvar7        ; e = match
  1338. incvar6:add    si,ax            ; point to next name, add name length
  1339.     add    si,2            ;  and string pointer
  1340.     pop    cx            ; recover loop counter
  1341.     loop    incvar4            ; one less macro to examine
  1342.     xor    ax,ax
  1343.     mov    temp,ax            ; indicate failure
  1344.     jmp    incvar13        ; go do command confirmation
  1345.  
  1346. incvar7:mov    ax,[si-2]        ; get length of variable string
  1347.     add    si,ax            ; point to segment of definition
  1348.     mov    si,[si]            ; seg of definition
  1349.     push    es
  1350.     mov    es,si
  1351.     mov    cx,es:[0]        ; length of definition
  1352.     mov    di,offset rdbuf+2    ; variable name from user
  1353.     add    di,[di-2]        ; plus length of variable name
  1354.     mov    byte ptr [di],' '    ; <count><varname><space>
  1355.     inc    di
  1356.     mov    si,2            ; skip over definition count word
  1357. incvar9:mov    al,es:[si]        ; copy string to regular data segment
  1358.     mov    [di],al
  1359.     inc    si
  1360.     inc    di
  1361.     loop    incvar9
  1362.     pop    es
  1363.     mov    ax,temp            ; get inc/dec +/- sign and a 1
  1364.     mov    [di],ax
  1365.     inc    di            ; leave the '1' present
  1366.     push    di            ; save place after '+/-'
  1367.     mov    bx,di            ; optional step goes here
  1368.     mov    ah,cmword        ; get step size, if any
  1369.     mov    dx,offset ssizehlp
  1370.     call    comnd
  1371.     pop    di
  1372.     jnc    incvar13
  1373.     ret
  1374. incvar13:push    di
  1375.     push    ax            ; save step size string length
  1376.     mov    ah,cmeol
  1377.     call    comnd
  1378.     pop    ax
  1379.     pop    di
  1380.     jnc    incvar14        ; nc = success
  1381.     ret
  1382.                     ; now convert step size, if any
  1383. incvar14:or    ax,ax            ; is length zero?
  1384.     jnz    incvar15        ; nz = no, convert number to binary
  1385.     mov    word ptr [di],'1'    ; put '1' where optional is missing
  1386.  
  1387. incvar15:mov    di,offset rdbuf+2    ; user's variable name
  1388.     add    di,[di-2]        ; its length
  1389.     inc    di            ; skip space separator
  1390.     push    di            ; save for place to write result
  1391.     mov    dx,di
  1392.     call    strlen            ; get string length
  1393.     mov    domath_cnt,cx
  1394.     mov    domath_ptr,dx
  1395.     call    domath            ; convert to number in dx:ax
  1396.     cmp    domath_cnt,0        ; converted whole word?
  1397.     pop    di            ; clean stack
  1398.     je    incvar17        ; e = yes
  1399.     stc
  1400.     ret                ; fail
  1401.                     ; step size is in ax
  1402. incvar17:or    dx,dx            ; is result negative?
  1403.     jns    incvar18        ; ns = no, positive or zero
  1404.     neg    dx            ; flip sign
  1405.     neg    ax
  1406.     sbb    dx,0
  1407.     mov    byte ptr [di],'-'    ; show minus sign
  1408.     inc    di
  1409. incvar18:call    lnout            ; binary to ascii decimal in ds:di
  1410.     mov    dx,offset rdbuf+2    ; place of <var><space><value>
  1411.     call    strlen            ; length to cx for dodecom
  1412.     call    dodecom            ; re-define variable
  1413.     mov    kstatus,kssuc        ; say success
  1414.     clc
  1415.     ret
  1416. incvar    endp
  1417.  
  1418. ; SET ALARM <time, sec from now or HH:MM:SS>
  1419. SETALRM    PROC    NEAR
  1420.     mov    bx,offset line        ; point to work buffer
  1421.     mov    word ptr line+2,0
  1422.     mov    dx,offset alrmhlp    ; help
  1423.     mov    ah,cmword        ; get macro name
  1424.     call    comnd
  1425.     jc    setal1            ; c = failure
  1426.     mov    ah,cmeol        ; get a confirm
  1427.     call    comnd
  1428.     jc    setal1            ; c = failure
  1429.     push    word ptr timhms
  1430.     push    word ptr timhms+2    ; save working timeouts
  1431.     mov    si,offset line        ; source pointer
  1432.     call    inptim            ; get the timeout time, sets si
  1433.     mov    ax,word ptr timhms    ; save time in alarm area
  1434.     mov    word ptr alrhms,ax
  1435.     mov    ax,word ptr timhms+2
  1436.     mov    word ptr alrhms+2,ax
  1437.     pop    word ptr timhms+2    ; restore working timeouts
  1438.     pop    word ptr timhms
  1439.     clc
  1440. setal1:    ret
  1441. SETALRM    ENDP
  1442.  
  1443. ; MINPUT <timeout> <match text> <match text> ...<match text>
  1444. SCMINPUT PROC    NEAR
  1445.     mov    minpcnt,0        ; matched pattern count
  1446.     mov    reinflg,2        ; say doing MINPUT
  1447.     jmp    short input100
  1448. SCMINPUT ENDP
  1449.  
  1450. ; REINPUT <timeout> <match text>
  1451. ; Reread material in serial port buffer, seeking a match with user's text
  1452. ; pattern. If user's pattern is longer than material in buffer then read
  1453. ; additional characters from the serial port. Use SCINP to do the main work.
  1454.  
  1455. SCREINP    PROC    NEAR
  1456.     mov    reinflg,1        ; say doing REINPUT, not INPUT
  1457.     jmp    short input100
  1458. SCREINP    ENDP
  1459.  
  1460. ; Input from port command, match input with text pattern
  1461. ; Input [timeout] text
  1462. ;     
  1463. SCINP    PROC    NEAR
  1464.     mov    reinflg,0        ; say doing INPUT, not REINPUT
  1465.  
  1466. input100:
  1467.     mov    kstatus,kssuc
  1468.     mov    bx,offset line+2    ; place to put text
  1469.     mov    ah,cmword        ; get pattern match word
  1470.     mov    dx,offset inphlp    ; help message
  1471.     mov    comand.cmdonum,1    ; \number conversion allowed
  1472.     cmp    reinflg,2        ; MINPUT?
  1473.     je    input101        ; e = yes, else INPUT or REINPUT
  1474.     mov    ah,cmline        ; get time + pattern match string
  1475. input101:call    comnd            ; get the pattern text
  1476.     jnc    input20            ; nothing, complain
  1477.     ret                ; failure
  1478. input20:mov    word ptr line,ax    ; store length in preceeding word
  1479.     mov    bx,offset line+2+2    ; leave a full word empty
  1480.     add    bx,ax            ; skip current material
  1481.     mov    word ptr [bx-2],0    ; clear for next count
  1482.     or    ax,ax            ; any text?
  1483.     jnz    input21            ; nz = yes
  1484.     stc                ; fail
  1485.     ret
  1486. input21:mov    si,offset line+2    ; source pointer
  1487.     call    inptim            ; get the timeout time, sets si
  1488.     mov    bx,offset line+2    ; basic line again, omitting count
  1489.     jnc    input22            ; nc = got timeout, now get pattern
  1490.                     ; c = not legal time, must be pattern
  1491.     mov    ax,word ptr line    ; get byte count
  1492.     add    bx,ax            ; move bx to end + 1
  1493.     jmp    short input12        ; simulate skipping inptim call
  1494.  
  1495. input22:cmp    reinflg,2        ; MINPUT?
  1496.     je    input10            ; e = yes, else INPUT or REINPUT
  1497.     push    di
  1498.     mov    di,offset line+2    ; where results go
  1499.     mov    bx,si            ; break char (text pattern)
  1500.     sub    bx,offset line+2    ; length of time field
  1501.     mov    cx,word ptr line    ; length of time + pattern
  1502.     sub    cx,bx            ; cx = length of pattern
  1503.     call    cnvlin            ; remove curly braces, cnv \numbers
  1504.     mov    word ptr line,cx    ; length of final result
  1505.     add    di,cx            ; step to end of line
  1506.     mov    word ptr [di],0        ; zero count of next pattern
  1507.     pop    di
  1508.     jmp    short input13
  1509.  
  1510. input10:mov    kstatus,kssuc        ; MINPUT, REINPUT
  1511.     mov    ah,cmword        ; get pattern match word
  1512.     mov    dx,offset inphlp    ; help message
  1513.     mov    comand.cmdonum,1    ; \number conversion allowed
  1514.     call    comnd            ; get the pattern text
  1515.     jnc    input12            ; nothing, complain
  1516.     ret                ; failure
  1517. input12:mov    si,bx            ; terminating null
  1518.     sub    si,ax            ; minus length
  1519.     mov    [si-2],ax        ; store length in preceeding word
  1520.     add    bx,2            ; leave a full word empty
  1521.     mov    word ptr [bx-2],0    ; clear count of next element
  1522.     cmp    reinflg,2        ; MINPUT?
  1523.     jne    input13            ; ne = no
  1524.     or    ax,ax            ; any text?
  1525.     jnz    input10            ; nz = got text, get more
  1526.     mov    ah,cmeol
  1527.     call    comnd
  1528.     jnc    input13
  1529.     ret
  1530.  
  1531. input13:cmp    reinflg,1        ; reinput command?
  1532.     je    input1a            ; e = yes, don't reecho
  1533.     cmp    taklev,0        ; are we in a Take file?
  1534.     je    input0            ; e = no, display linefeed
  1535.     cmp    flags.takflg,0        ; are Take commands being echoed?
  1536.     je    input1            ; e = no, skip display
  1537. input0:    cmp    script.inecho,0        ; Input echo off?
  1538.     je    input1            ; e = yes
  1539.     mov    al,lf            ; next line
  1540.     call    scdisp            ; display the char
  1541. input1: call    serini            ; initialize the system's serial port
  1542.     jnc    input1a            ; nc = success
  1543.     ret
  1544. input1a:mov    status,stat_unk        ; clear status flag
  1545.                     ; start main read and compare loop
  1546. input4:    mov    si,offset line        ; <count word><pattern> sequence
  1547.     cmp    reinflg,2        ; MINPUT?
  1548.     jne    input4a            ; ne = no
  1549.     mov    minpcnt,0        ; minput pattern match number
  1550. input4a:mov    cx,[si]            ; length of pattern
  1551.     jcxz    input4d            ; z = no pattern
  1552.     inc    minpcnt            ; count minput pattern number
  1553. input4g:add    si,2            ; point at pattern
  1554. input4c:call    inmat            ; match strings
  1555.     jnc    input6            ; nc = success
  1556.     add    si,cx            ; skip to next pattern
  1557.     jmp    short input4a        ; try again
  1558.  
  1559. input4d:mov    minpcnt,0        ; clear \v(minput) match counter
  1560.     call    chkkbd            ; check keyboard
  1561.     test    status,stat_cc        ; did user type Control-C?
  1562.     jnz    input5            ; nz = yes, quit
  1563.     test    status,stat_cr        ; did user type cr? [js]
  1564.     jz    input4e            ; z = no
  1565.     or    status,stat_tmo        ; force timeout status too
  1566.     mov    input_status,1        ; \v(instatus), timed out
  1567.     jmp    short input5
  1568. input4e:test    status,stat_tmo+stat_ok ; user override/timeout on last read
  1569.     jnz    input5            ; nz = timed out, quit
  1570.     cmp    reinflg,1        ; Reinput command?
  1571.     jne    input4f            ; ne = no
  1572.     mov    ax,scpbuflen        ; total buffer length
  1573.     cmp    bufcnt,ax        ; full?
  1574.     jae    input5            ; ae = yes, reinput fails
  1575. input4f:call    bufread            ; read from serial port to buffer
  1576.     jmp    input4            ; analyze character
  1577.  
  1578. input5:    or    errlev,ksrecv        ; set RECEIVE failure condition
  1579.     or    fsta.xstatus,ksrecv    ; set status
  1580.     or    kstatus,ksrecv
  1581. input6:    mov    input_status,0        ; INPUT \v(instatus), assume success
  1582.     cmp    reinflg,2        ; MINPUT?
  1583.     je    input6a            ; e = yes
  1584.     mov    minpcnt,0        ; clear \v(minput) match counter
  1585. input6a:test    status,stat_tmo        ; timeout?
  1586.     jz    input7            ; z = no
  1587.     mov    input_status,1        ; \v(instatus), timed out
  1588. input7:    test    status,stat_cr+stat_cc    ; user CR or Control-C?
  1589.     jz    input7a            ; z = no
  1590.     mov    input_status,2        ; \v(instatus), user Control-C
  1591. input7a:cmp    reinflg,2        ; MINPUT?
  1592.     je    input7c            ; e = yes
  1593. input7b:push    bx
  1594.     mov    bx,portval
  1595.     cmp    [bx].portrdy,0        ; is port not-ready?
  1596.     pop    bx
  1597.     jne    input7c            ; ne = no, port is ready
  1598.     mov    input_status,4        ; connection lost
  1599. input7c:cmp    kstatus,kssuc        ; success?
  1600.     je    input8            ; e = yes
  1601.     mov    minpcnt,0        ; clear \v(minput) match counter
  1602.     jmp    squit            ; exit failure: timeout or Control-C
  1603. input8:    jmp    squit1            ; skip timeout message, if any
  1604. inputx:    clc                ; return success
  1605.     ret
  1606. SCINP    ENDP
  1607.  
  1608. ; Match input buffer and cx string bytes at ds:si
  1609. ; Strategy: scan INPUT buffer from beginning looking for match of first
  1610. ; byte of pattern. If found try to match rest of pattern. Upon failure
  1611. ; select next INPUT buffer byte and try to match with pattern.
  1612. inmat    proc    near
  1613.     push    cx
  1614.     push    es
  1615.     push    si
  1616.     push    di
  1617.     push    temp
  1618.     push    temp1            ; buffer bytes to read
  1619.     mov    temp,cx            ; retain count of pattern bytes
  1620.     mov    di,bufseg        ; get buffer segment
  1621.     mov    es,di
  1622.     mov    di,bufcnt        ; bytes in buffer
  1623.     cmp    reinflg,1        ; Reinput command?
  1624.     je    inmat1            ; e = yes, use start of buffer
  1625.     sub    di,bufrptr        ; where to read-next, yields unread
  1626.     mov    temp1,di        ; retain count of buffer bytes to read
  1627.     mov    di,bufrptr        ; es:di is oldest unread byte
  1628.     jmp    short inmat2
  1629. inmat1:    mov    temp1,di        ; retain count of bytes to read here
  1630.     xor    di,di            ; reinput uses start of buffer
  1631.         ; work on first pattern byte
  1632. inmat2:    cmp    temp1,cx        ; unread bytes vs pattern bytes
  1633.     jb    inmatx            ; b = insufficient, fail
  1634.     cld                ; match first pattern byte
  1635.     mov    al,[si]            ; read pattern byte into AL
  1636.     mov    cx,temp1        ; buffer byte count
  1637. inmat10:mov    ah,es:[di]        ; extract buffer char into AH
  1638.     inc    di
  1639.     cmp    script.incasv,0        ; case ignore?
  1640.     jne    inmat13            ; ne = no
  1641.     call    toupr            ; upper case ax
  1642. inmat13:call    matchr            ; chars match?
  1643.     jnc    inmat14            ; nc = yes, first bytes match
  1644.     loop    inmat10            ; continue matching
  1645.     jmp    inmatx            ; failed
  1646.  
  1647. inmat14:    ; have matched first pattern byte, now consider the rest
  1648.     push    di            ; save position of to-be matched
  1649.     push    si            ; save first pattern position
  1650.     inc    si            ; point at second pattern byte
  1651.     mov    cx,temp            ; count of pattern 
  1652.     dec    cx            ; count of remaining pattern 
  1653.     jcxz    inmat17            ; z = none, success
  1654. inmat15:lodsb                ; pattern byte to AL
  1655.     mov    ah,es:[di]        ; extract buffer char into AH
  1656.     inc    di            ; point to next buffer byte
  1657.     cmp    script.incasv,0        ; case ignore?
  1658.     jne    inmat16            ; ne = no
  1659.     call    toupr            ; upper case ax
  1660. inmat16:call    matchr            ; chars match?
  1661.     jc    inmat18            ; c = no
  1662.     loop    inmat15            ; consider rest of pattern bytes
  1663. inmat17:cmp    reinflg,1        ; Reinput command?
  1664.     je    inmat19            ; e = yes, do not adjust bufrptr
  1665.     mov    bufrptr,di        ; remember last read byte plus one
  1666. inmat19:pop    si
  1667.     pop    di            ; success
  1668.     pop    temp1
  1669.     pop    temp
  1670.     pop    di
  1671.     pop    si
  1672.     pop    es
  1673.     pop    cx
  1674.     clc                ; here match
  1675.     ret
  1676.  
  1677. inmat18:pop    si            ; failed to match second etc bytes
  1678.     pop    di            ; step along buffer stream
  1679.     mov    cx,bufcnt        ; buffer count
  1680.     sub    cx,di            ; minus bytes examined in buffer
  1681.     jle    inmatx            ; le = none left, fail
  1682.     mov    temp1,cx        ; bytes in buffer
  1683.     mov    cx,temp            ; pattern bytes
  1684.     jmp    inmat2            ; rescan buffer from last di
  1685.  
  1686. inmatx:    pop    temp1            ; failure exit
  1687.     pop    temp
  1688.     pop    di
  1689.     pop    si
  1690.     pop    es
  1691.     pop    cx
  1692.     stc                ; no match
  1693.     ret
  1694. inmat    endp
  1695.  
  1696. ; worker for SCINP
  1697. ; compare single characters, one in ah and the other in al. Allow the 0ffh
  1698. ; wild card to match CR and LF individually. Return carry clear if match,
  1699. ; or carry set if they do not match. Registers preserved.
  1700. matchr    proc    near
  1701.     cmp    ah,al        ; do these match?
  1702.     je    matchr6        ; e = yes
  1703.     cmp    ah,0ffh        ; the match cr/lf indicator?
  1704.     je    matchr2        ; e = yes    
  1705.     cmp    al,0ffh        ; the match cr/lf indicator?
  1706.     jne    matchr5        ; ne = no match at all.
  1707. matchr2:push    ax        ; save both chars again
  1708.     and    ah,al        ; make a common byte for testing
  1709.     cmp    ah,cr
  1710.     je    matchr4        ; e = cr matches 0ffh
  1711.     cmp    ah,lf
  1712.     je    matchr4        ; e = lf matches 0ffh
  1713.     pop    ax        ; recover chars
  1714. matchr5:stc            ; set carry (no match)
  1715.     ret
  1716. matchr4:pop    ax        ; recover chars
  1717. matchr6:clc            ; clear carry (match)
  1718.     ret
  1719. matchr    endp
  1720.  
  1721. ; Pause for the indicated number of milliseconds, do not access comms channel
  1722. SCMPAUSE PROC    NEAR
  1723.     mov    kstatus,kssuc
  1724.     mov    ah,cmword        ; get a word (number)
  1725.     mov    bx,offset line        ; where to store it
  1726.     mov    dx,offset mphlp        ; help msg
  1727.     call    comnd
  1728.     jnc    scmpau1            ; nc = success
  1729.     ret
  1730. scmpau1:mov    dx,offset line        ; text in compare buffer
  1731.     call    strlen
  1732.     mov    domath_cnt,cx
  1733.     mov    domath_ptr,dx
  1734.     call    domath            ; convert to number in dx:ax
  1735.     jc    scmpau3            ; c = failed to convert a number
  1736.     call    pcwait            ; delay number of millisec in AX
  1737.     clc
  1738.     ret
  1739. scmpau3:mov    ah,prstr
  1740.     mov    dx,offset mpbad        ; complain about bad number
  1741.     int    dos
  1742.     mov    kstatus,ksgen        ; command status, failure
  1743.     stc
  1744.     ret
  1745. SCMPAUSE ENDP
  1746.  
  1747. ; Pause for the specified number of seconds or until a time of day
  1748. ; Pause [seconds or hh:mm:ss]
  1749. ;
  1750. SCPAU    PROC    NEAR
  1751.     mov    kstatus,kssuc
  1752.     mov    ah,cmword        ; get a word (number)
  1753.     mov    bx,offset line        ; where to store it
  1754.     mov    dx,offset ptshlp    ; help msg
  1755.     call    comnd
  1756.     jc    scpau1            ; c = failure
  1757.     mov    si,offset line        ; source pointer
  1758.     call    inptim            ; parse pause time (or force default)
  1759.     jc    scpau1            ; c = bad time value
  1760.     mov    wtemp,0            ; no modem status to detect
  1761.     jmp    swait4            ; finish in common code
  1762. scpau1:    ret                ; return command failure
  1763. SCPAU    ENDP
  1764.  
  1765. ;
  1766. ; Wait for the indicated signal for the specified number of seconds or tod
  1767. ; WAIT [seconds] \signal   where \signal is \cd, \dsr, \ri modem status lines.
  1768. ; Use INPUT-TIMEOUT ACTION for failures.
  1769. ;
  1770. SCWAIT    PROC    NEAR
  1771.     mov    kstatus,kssuc
  1772.     mov    ah,cmword        ; get a word (number)
  1773.     mov    bx,offset line        ; where to store it
  1774.     mov    dx,offset ptshlp    ; time help msg
  1775.     call    comnd
  1776.     jnc    swait0            ; nc = success
  1777.     ret
  1778. swait0:    mov    wtemp,0            ; clear modem status test byte
  1779.     mov    si,offset line        ; source pointer
  1780.     push    ax            ; save length count
  1781.     call    inptim            ; parse pause time (or force default)
  1782.     pop    ax
  1783.     jnc    swait0a            ; nc = good time value
  1784.     ret
  1785. swait0a:cmp    si,offset line        ; was a number parsed?
  1786.     je    swait1c            ; e = no, reparse as modem signal
  1787.  
  1788. swait1:    mov    ah,cmword        ; get optional modem signal word(s)
  1789.     mov    bx,offset line
  1790.     mov    dx,offset wthlp        ; modem signal help
  1791.     call    comnd
  1792.     jnc    swait1c            ; nc = success
  1793.     ret
  1794. swait1c:mov    si,offset line
  1795.     mov    cx,ax            ; returned byte count
  1796.     or    cx,cx            ; number of chars to examine
  1797.     jle    swait4            ; le = none
  1798.     cld
  1799. swait1d:lodsb                ; get a character
  1800.     dec    cx            ; reduce count remaining
  1801.     cmp    al,'\'            ; backslash signal introducer?
  1802.     je    swait1d            ; e = yes, skip it
  1803.     cmp    cx,1            ; at least two chars in signal?
  1804.     jl    swait3a            ; l = no, bad syntax
  1805.     mov    ax,[si-1]        ; get first two characters
  1806.     or    ax,2020h        ; upper case to lower, two chars
  1807.     cmp    ax,'dc'            ; carrier detect?
  1808.     jne    swait2            ; ne = no, try next signal
  1809.     or    wtemp,modcd        ; look for the CD bit
  1810.     inc    si            ; skip this field and separator
  1811.     dec    cx            ; two less chars left in the line
  1812.     jmp    short swait1        ; continue the scan
  1813. swait2:    cmp    ax,'sd'            ; data set ready?
  1814.     jne    swait3            ; ne = no
  1815.     mov    al,[si+1]        ; third letter
  1816.     or    al,20h            ; to lower case
  1817.     cmp    al,'r'            ; r for dsr?
  1818.     jne    swait3b            ; ne = no
  1819.     or    wtemp,moddsr        ; look for the DSR bit
  1820.     add    si,2            ; skip this field and separator
  1821.     sub    cx,2            ; three less chars left in the line
  1822.     jmp    short swait1
  1823. swait3:    cmp    ax,'tc'            ; clear to send?
  1824.     jne    swait3a            ; ne = no
  1825.     mov    al,[si+1]        ; third letter
  1826.     or    al,20h            ; to lower case
  1827.     cmp    al,'s'            ; r for dsr?
  1828.     jne    swait3b            ; ne = no
  1829.     or    wtemp,modcts        ; look for the CTS bit
  1830.     add    si,2            ; skip this field and separator
  1831.     sub    cx,2            ; three less chars left in the line
  1832.     jmp    short swait1        ; continue the scan
  1833. swait3a:cmp    ax,'ir'            ; ring indicator
  1834.     jne    swait3b            ; ne = no, try next signal
  1835.     or    wtemp,modri        ; look for the RI bit
  1836.     inc    si            ; skip this field and separator
  1837.     dec    cx            ; two less chars left in the line
  1838.     jmp    short swait1        ; continue the scan
  1839. swait3b:or    al,al            ; null terminator?
  1840.     je    swait4            ; e = yes, no more text
  1841.     mov    ah,prstr
  1842.     mov    dx,offset wtbad        ; say bad syntax
  1843.     int    dos
  1844.     or    errlev,ksuser        ; set user intervention error condx
  1845.     or    fsta.xstatus,ksuser    ; set status
  1846.     or    kstatus,ksuser
  1847.     stc                ; failure
  1848.     ret
  1849.                     ; SWAIT4 is used by PAUSE command
  1850. SWAIT4:    mov    ah,cmeol        ; get command confirmation
  1851.     call    comnd
  1852.     jnc    swait4a
  1853.     ret                ; c set is failure
  1854. swait4a:cmp    taklev,0        ; are we in a Take file
  1855.     je    swait5            ; e = no, print linefeed
  1856.     cmp    flags.takflg,0        ; are commands being echoed
  1857.     je    swait6            ; e = no, skip this
  1858. swait5:    cmp    script.inecho,0        ; Input echoing off?
  1859.     je    swait6            ; e = yes
  1860.     mov    al,lf            ; next line
  1861.     call    scdisp            ; display the char
  1862. swait6: call    serini            ; initialize the system's serial port
  1863.     jc    swait9            ; c = failure
  1864.     mov    status,stat_unk        ; clear status flag
  1865.     push    si
  1866.     mov    parmsk,0ffh          ; parity mask, assume 8 bit data
  1867.     mov    si,portval
  1868.     cmp    [si].parflg,parnon    ; parity is none?
  1869.     pop    si
  1870.     je    swait7            ; e = none
  1871.     mov    parmsk,07fh        ; else strip parity (8th) bit
  1872. swait7:    cmp    wtemp,0            ; anything to be tested?
  1873.     je    swait8            ; e = no, just do the wait part
  1874.     call    getmodem        ; modem handshake status to AL
  1875.     and    al,wtemp        ; keep only bits to be tested
  1876.     cmp    al,wtemp        ; check selected status bits
  1877.     jne    swait8            ; ne = not all selected bits match    
  1878.     clc                ; all match. take successful exit
  1879.     ret
  1880. swait8:    call    chkport            ; get and show any new port char
  1881.     call    chkkbd            ; check keyboard
  1882.     test    status,stat_cc        ; control-c?
  1883.     jnz    swait9            ; nz = yes, quit    
  1884.     call    chktmo            ; check tod for timeout
  1885.     test    status,stat_tmo+stat_ok    ; timeout or user override?
  1886.     jz    swait7            ; z = no, continue to wait
  1887.     cmp    wtemp,0            ; were we waiting on anything?
  1888.     jne    swait9            ; ne = yes, timeout = failure
  1889.     test    status,stat_ok        ; user intervention?
  1890.     jnz    swait9            ; nz = yes, failure
  1891.     clc                ;  else timeout = success
  1892.     ret
  1893. swait9:    or    errlev,ksuser        ; set user intervention error condx
  1894.     or    fsta.xstatus,ksuser    ; set status
  1895.     or    kstatus,ksuser
  1896.     jmp    squit            ; take error exit
  1897. SCWAIT    ENDP
  1898.  
  1899. ; SLEEP <number of sec or time of day>
  1900. ; Does not access comms channels
  1901. SCSLEEP    PROC    NEAR
  1902.     mov    kstatus,kssuc
  1903.     mov    ah,cmword        ; get a word (number)
  1904.     mov    bx,offset line        ; where to store it
  1905.     mov    dx,offset sleephlp    ; help msg
  1906.     call    comnd
  1907.     jc    scslee1            ; c = failure
  1908.     mov    si,offset line        ; source pointer
  1909.     call    inptim            ; parse pause time (or force default)
  1910.     jnc    scslee2            ; nc = good time value
  1911. scslee1:ret                ; return command failure
  1912. scslee2:call    chkkbd            ; check keyboard
  1913.     test    status,stat_cc        ; control-c?
  1914.     jnz    scslee3            ; nz = yes, quit    
  1915.     call    chktmo            ; check tod for timeout
  1916.     test    status,stat_tmo+stat_ok    ; timeout or user override?
  1917.     jz    scslee2            ; z = no, continue to wait
  1918.     test    status,stat_ok        ; user intervention?
  1919.     jnz    scslee3            ; nz = yes, failure
  1920.     clc                ;  else timeout = success
  1921.     ret
  1922. scslee3:or    errlev,ksuser        ; set user intervention error condx
  1923.     or    fsta.xstatus,ksuser    ; set status
  1924.     or    kstatus,ksuser
  1925.     jmp    squit            ; take error exit
  1926. SCSLEEP    ENDP
  1927.  
  1928. ; Output line of text to port, detect \b and \B as commands to send a Break
  1929. ;  and \l and \L as a Long Break on the serial port line.
  1930. ; Output text, display up to 100 received chars while doing so.
  1931.      
  1932. SCOUT    PROC    NEAR
  1933.     mov    kstatus,kssuc
  1934.     mov    ah,cmline        ; get a whole line of asciiz text
  1935.     mov    bx,offset line        ; store text here
  1936.     mov    dx,offset outhlp    ; help message
  1937.     mov    comand.cmdonum,1    ; \number conversion allowed
  1938.     call    comnd
  1939.     jnc    outp0d            ; nc = success
  1940.     ret                ; failure
  1941. outp0d:    mov    tempd,ax        ; save byte count here
  1942.     cmp    apctrap,0        ; disable from APC?
  1943.     je    outp0e            ; e = no
  1944.     stc                ; fail
  1945.     ret
  1946. outp0e:    cmp    taklev,0        ; is this being done in a Take file?
  1947.     je    outpu0            ; e = no, display linefeed
  1948.     cmp    flags.takflg,0        ; are commands being echoed?
  1949.     je    outp0a            ; e = no, skip the display
  1950. outpu0:    cmp    script.inecho,0        ; Input echoing off?
  1951.     je    outp0a            ; e = yes
  1952.     mov    al,lf            ; next line
  1953.     call    scdisp            ; display the char
  1954. outp0a:    mov    al,spause        ; wait three millisec or more
  1955.     add    al,3
  1956.     xor    ah,ah
  1957.     call    pcwait            ; breathing space for HDX systems
  1958.     call    serini            ; initialize the system's serial port
  1959.     jnc    outp0c            ; nc = success
  1960.     or    errlev,kssend        ; set SEND failure condition
  1961.     or    fsta.xstatus,kssend    ; set status
  1962.     or    kstatus,kssend
  1963.     jmp    squit
  1964.  
  1965. outp0c:    mov    status,stat_unk        ; clear status flag
  1966.     mov    parmsk,0ffh          ; parity mask, assume 8 bit data
  1967.     mov    si,portval
  1968.     cmp    [si].parflg,parnon    ; parity is none?
  1969.     je    outp0b            ; e = none
  1970.     mov    parmsk,07fh        ; else strip parity (8th) bit
  1971. outp0b:    mov    si,portval        ; serial port structure
  1972.     mov    bl,[si].ecoflg        ; Get the local echo flag
  1973.     mov    lecho,bl        ; our copy
  1974.     mov    temptr,offset line    ; save pointer here
  1975.     mov    ttyact,1        ; say interactive style output
  1976.  
  1977. outpu2:    cmp    tempd,0            ; are we done?
  1978.     jg    outpu2a            ; g = not done yet
  1979.     mov    ttyact,0        ; reset interactive output flag
  1980.     clc                ; return success
  1981.     ret
  1982. outpu2a:mov    si,temptr        ; recover pointer
  1983.     cld
  1984.     lodsb                ; get the character
  1985.     dec    tempd            ; one less char to send
  1986.     mov    temptr,si        ; save position on line
  1987.     mov    byte ptr tempa,al    ; save char here for outchr
  1988.     mov    retry,0            ; number of output retries
  1989.     cmp    al,5ch            ; backslash?
  1990.     jne    outpu4d            ; ne = no
  1991.     mov    al,[si]
  1992.     and    al,not 20h        ; to upper case
  1993.     cmp    al,'B'            ; "\B" for BREAK?
  1994.     jne    outpu4l            ; ne = no
  1995. outpu4c:inc    temptr            ; move scan ptr beyond "\b"
  1996.     dec    tempd
  1997.     call    sendbr            ; call msx send-a-break procedure
  1998.     jmp    short outpu5        ; resume beyond echoing
  1999. outpu4l:cmp    al,'L'            ; "\L" for Long BREAK?
  2000.     jne    outpu4g            ; ne = no
  2001.     inc    temptr
  2002.     dec    tempd
  2003.     call    sendbl            ; send a Long BREAK
  2004.     jmp    short outpu5        ; resume beyond echoing
  2005.  
  2006. outpu4d:inc    retry            ; count output attempts
  2007.     cmp    retry,maxtry        ; too many retries?
  2008.     jle    outpu4g            ; le = no
  2009.     or    errlev,kssend        ; set SEND failure condition
  2010.     or    fsta.xstatus,kssend    ; set status
  2011.     or    kstatus,kssend
  2012.     jmp    squit            ; return failure
  2013. outpu4g:
  2014.     mov    ax,outpace        ; millisecs pacing delay
  2015.     inc    ax            ; at least 1 ms
  2016.     call    pcwait
  2017.     mov    ah,byte ptr tempa    ; outchr gets fed from ah
  2018.     call    outchr            ; send the character to the port
  2019.     jc    outpu4d            ; failure to send char
  2020.     cmp    lecho,0            ; is Local echo active?
  2021.     je    outpu5            ; e = no
  2022.     mov    al,byte ptr tempa
  2023.     test    flags.capflg,logses    ; is capturing active?
  2024.     jz    outp4b            ; z = no
  2025.     push    ax            ; save char
  2026.     call    cptchr            ; give it captured character
  2027.     pop    ax            ; restore character and keep going
  2028. outp4b:    cmp    script.inecho,0        ; Input echo off?
  2029.     je    outpu5            ; e = yes
  2030.     call    scdisp            ; echo character to the screen
  2031.                     ;
  2032. outpu5:    mov    tempa,100+1        ; wait for max 100 chars in/out [dan]
  2033. outpu5a:mov    cx,10            ; reset retry counter
  2034. outpu5b:push    cx
  2035.     call    chkkbd            ; check keyboard for interruption
  2036.     pop    cx
  2037.     test    status,stat_cc        ; control c interrupt?
  2038.     jnz    outpu6            ; nz = yes, quit now
  2039.     cmp    script.inecho,0        ; Input echo off?
  2040.     je    outpu5c            ; e = yes, skip port reading/display
  2041.     dec    tempa            ; reached maximum chars in yet? [dan]
  2042.     jz    outpu5c            ; z = yes, send character anyway [dan]
  2043.     push    cx
  2044.     call    chkport            ; check for char at serial port
  2045.     pop    cx
  2046.     test    status,stat_ok        ;   and put any in buffer
  2047.     jnz    outpu5a            ; nz = have a char, look for another
  2048.     mov    ax,1            ; wait 1 millisec between rereads
  2049.     push    cx            ; protect counter
  2050.     call    pcwait
  2051.     pop    cx
  2052.     dec    cx            ; count down retries
  2053.     jge    outpu5b            ; ge = keep trying
  2054. outpu5c:jmp    outpu2            ; no more input, resume command
  2055. outpu6:    or    errlev,kssend        ; set SEND failure condition
  2056.     or    fsta.xstatus,kssend    ; set status
  2057.     or    kstatus,kssend
  2058.     mov    ttyact,0        ; reset interactive output flag
  2059.     jmp    squit            ; quit on control c
  2060. SCOUT    ENDP
  2061.  
  2062. ; OUTPUT  ESC _ usertext ESC \   as APC command
  2063. SCAPC    PROC    NEAR
  2064.     mov    kstatus,kssuc
  2065.     mov    ah,cmline        ; get a whole line of asciiz text
  2066.     mov    bx,offset line+2    ; store text here
  2067.     mov    byte ptr[bx-2],ESCAPE    ; ESC _ (APC)
  2068.     mov    byte ptr [bx-1],'_'
  2069.     mov    dx,offset apchlp    ; help message
  2070.     call    comnd
  2071.     jnc    spapc1            ; nc = success
  2072.     ret                ; failure
  2073. spapc1:    mov    bx,ax            ; user text
  2074.     add    bx,2            ; prefix
  2075.     mov    line [bx],ESCAPE    ; ESC \ (ST)
  2076.     mov    line [bx+1],'\'
  2077.     mov    line [bx+2],0        ; terminator
  2078.     mov    al,script.inecho    ; preserve echo status
  2079.     mov    ah,flags.takflg
  2080.     push    ax
  2081.     mov    script.inecho,0        ; off
  2082.     mov    flags.takflg,0        ; off
  2083. scapc2:    call    outp0a            ; do work via OUTPUT
  2084.     pop    ax
  2085.     mov    script.inecho,al    ; restore
  2086.     mov    flags.takflg,ah
  2087.     ret
  2088. SCAPC    ENDP
  2089.      
  2090. ; Raw file transfer to host (strips linefeeds)
  2091. ; Transmit filespec [prompt]
  2092. ; Optional prompt is the single char expected from the host to ACK each line.
  2093. ; Default prompt is a script.xmitpmt (linefeed) or a carriage return from us.
  2094. ;     
  2095. SCXMIT    PROC    NEAR
  2096.     mov    kstatus,kssuc
  2097.     mov    ah,cmword        ; get a filename, asciiz
  2098.     mov    bx,offset line        ; where to store it
  2099.     mov    dx,offset xmthlp    ; help message
  2100.     call    comnd
  2101.     jnc    xmit0c            ; nc = success
  2102.     ret                ; failure
  2103. xmit0c:    mov    ah,cmword        ; get a prompt string, asciiz
  2104.     mov    bx,offset line+81    ; where to keep it (end of "line")
  2105.     mov    dx,offset pmthlp    ; Help in case user types "?".
  2106.     mov    comand.cmdonum,1    ; convert \number
  2107.     call    comnd
  2108.     jnc    xmit0d            ; nc = success
  2109.     ret                ; failure
  2110. xmit0d:    mov    line+80,al        ; length of user's string
  2111.     mov    ah,cmeol        ; confirm
  2112.     call    comnd
  2113.     jnc    xmit0e
  2114.     ret
  2115. xmit0e:    cmp    line,0            ; filename given?
  2116.     je    xmit0a            ; e = no
  2117.     cmp    line+80,0        ; anything given?
  2118.     jz    xmit0            ; z = no, use default
  2119.     mov    al,line+81        ; get ascii char from user's prompt
  2120. xmit0b:    mov    script.xmitpmt,al    ; set prompt
  2121. xmit0:    mov    dx,offset line        ; point to filename
  2122.     mov    ah,open2        ; DOS 2 open file
  2123.     xor    al,al            ; open for reading
  2124.     int    dos
  2125.     mov    fhandle,ax        ; store file handle here
  2126.     mov    temp,0            ; counts chars/line
  2127.     jnc    xmit1            ; nc = successful opening
  2128.  
  2129. xmit0a:    mov    ah,prstr        ; give file not found error message
  2130.     mov    dx,offset xfrfnf
  2131.     int    dos
  2132.     or    errlev,kssend        ; set SEND failure condition
  2133.     or    fsta.xstatus,kssend    ; set status
  2134.     or    kstatus,kssend
  2135.     jmp    squit            ; exit failure
  2136.  
  2137. xmitx:    mov    ah,prstr        ; error during transfer
  2138.     mov    dx,offset xfrrer
  2139.     int    dos
  2140. xmitx2:    mov    bx,fhandle        ; file handle
  2141.     mov    ah,close2        ; close file
  2142.     int    dos
  2143.     mov    bufcnt,0        ; clear INPUT buffer (say is empty)
  2144.     call    clrbuf            ; clear local serial port buffer
  2145.     or    errlev,kssend        ; set SEND failure condition
  2146.     or    fsta.xstatus,kssend    ; set status
  2147.     or    kstatus,kssend
  2148.     jmp    squit            ; exit failure
  2149.                     ;
  2150. xmity:    mov    bx,fhandle        ; file handle
  2151.     mov    ah,close2        ; close file
  2152.     int    dos
  2153.     mov    bufcnt,0        ; clear INPUT buffer (say is empty)
  2154.     call    clrbuf
  2155.     clc                ; and return success
  2156.     ret
  2157. xmit1:    call    serini            ; initialize serial port
  2158.     jnc    xmit1b            ; nc = success
  2159.     or    errlev,kssend        ; set SEND failure condition
  2160.     or    fsta.xstatus,kssend    ; set status
  2161.     or    kstatus,kssend
  2162.     jmp    squit
  2163.  
  2164. xmit1b:    mov    bufcnt,0        ; clear INPUT buffer (say is empty)
  2165.     mov    bufrptr,0
  2166.     call    clrbuf            ; clear serial port buffer
  2167.     mov    status,stat_unk        ; clear status flag
  2168.     mov    parmsk,0ffh          ; parity mask, assume 8 bit data
  2169.     mov    si,portval
  2170.     cmp    [si].parflg,parnon    ; parity is none?
  2171.     je    xmit1a            ; e = none
  2172.     mov    parmsk,07fh        ; else strip parity (8th) bit
  2173. xmit1a:    mov    bl,[si].ecoflg        ; get the local echo flag
  2174.     mov    lecho,bl        ; our copy
  2175.     mov    dx,offset crlf        ; display cr/lf
  2176.     mov    ah,prstr
  2177.     int    dos
  2178.  
  2179. xmit2:    mov    dx,offset line        ; buffer to read into
  2180.     mov    cx,linelen        ; # of bytes to read
  2181.     mov    ah,readf2        ; read bytes from file
  2182.     mov    bx,fhandle        ; file handle is stored here
  2183.     int    dos
  2184.     jnc    xmit2a            ; nc = success
  2185.     jmp    xmitx            ; exit failure
  2186. xmit2a:    mov    cx,ax            ; number of bytes read
  2187.     jcxz    xmity            ; z = none, end of file
  2188.     mov    si,offset line        ; buffer for file reads
  2189.     cld
  2190. xmit3:    lodsb                ; get a byte
  2191.     cmp    al,ctlz            ; is this a Control-Z?
  2192.     jne    xmit3a            ; ne = no
  2193.     cmp    flags.eofcz,0        ; ignore Control-Z as EOF?
  2194.     je    xmit3a            ; e = yes
  2195.     jmp    xmity            ; ne = no, we are at EOF
  2196. xmit3a:    push    si            ; save position on line
  2197.     push    cx            ; and byte count
  2198.     cmp    al,cr            ; CR, end of line?
  2199.     jne    xmit3b            ; ne = no
  2200.     cmp    temp,0            ; chars sent in this line, any?
  2201.     ja    xmit3c            ; a = sent some
  2202.     cmp    script.xmitfill,0    ; fill empty lines?
  2203.     je    xmit3c            ; e = no, send the cr
  2204.     mov    al,script.xmitfill    ; empty line fill char
  2205.     pop    cx
  2206.     pop    si
  2207.     dec    si            ; backup read pointer to CR again
  2208.     inc    cx            ; count filler as line information
  2209.     push    si
  2210.     push    cx
  2211.     jmp    short xmit3c
  2212. xmit3b:    cmp    al,lf            ; line feed?
  2213.     jne    xmit3c            ; ne = no
  2214.     cmp    script.xmitlf,0        ; send LF's?
  2215.     je    xmit7            ; e = no, don't send it
  2216.     mov    temp,-1            ; -1 so inc returns 0 after send
  2217. xmit3c:    push    ax            ; save char around outchr call
  2218.     mov    retry,0            ; clear retry counter
  2219. xmit4f:    pop    ax            ; recover saved char
  2220.     push    ax            ; and save it again
  2221.     mov    ah,al            ; outchr wants char in ah
  2222.     inc    retry            ; count number of attempts
  2223.     cmp    retry,maxtry        ; too many retries?
  2224.     jle    xmit4g            ; le = no
  2225.     or    status,stat_cc        ; simulate control-c abort
  2226.     pop    ax            ; clean stack
  2227.     xor    al,al            ; clear char
  2228.     jmp    xmita            ; and abort transfer
  2229. xmit4g:    push    ax            ; save char
  2230.     call    outchr            ; send the character to the port
  2231.     pop    ax            ; recover char
  2232.     pushf                ; save carry flag
  2233.     cmp    flags.comflg,'t'    ; using internal TCP/IP stack?
  2234.     jne    xmit4j            ; ne = no
  2235.     mov    al,ah            ; ah is the output byte
  2236.     call    dopar            ; apply parity to al, if any
  2237.     cmp    al,0ffh            ; IAC now?
  2238.     jne    xmit4j            ; ne = no
  2239.     call    outchr            ; double the IAC byte
  2240. xmit4j:    inc    temp            ; count chars sent in this line
  2241.     popf                ; recover carry flag
  2242.     jc    xmit4f            ; c failed, try again
  2243. xmit4h:    pop    ax            ; recover saved char
  2244.     cmp    lecho,0            ; is local echoing active?
  2245.     je    xmit5            ; e = no
  2246.     test    flags.capflg,logses    ; capturing active?
  2247.     jz    xmit4a            ; z = no
  2248.     call    cptchr            ; give it the character just sent
  2249. xmit4a:    call    scdisp            ; display char on screen
  2250.  
  2251. xmit5:    cmp    al,cr            ; did we send a carriage return?
  2252.     je    xmit8            ; e = yes, time to check keyboard
  2253.  
  2254. xmit7:    pop    cx
  2255.     pop    si
  2256.     dec    cx
  2257.     or    cx,cx
  2258.     jle    xmit7a            ; le = finished this line
  2259.     jmp    xmit3            ; finish this buffer full
  2260. xmit7a:    jmp    xmit2            ; read next buffer
  2261.  
  2262. xmit8:    test    status,stat_cc        ; Control-C seen?
  2263.     jnz    xmita            ; nz = yes
  2264.     mov    temp,0            ; say starting new char/line count
  2265.     call    chkkbd            ; check keyboard (returns char in al)
  2266.     test    status,stat_ok        ; have a char?
  2267.     jnz    xmita            ; nz = yes
  2268.     cmp    script.xmitpmt,0    ; is prompt char a null?
  2269.     jne    xmit8b            ; ne = no
  2270.     mov    bufcnt,0        ; clear serial port buf
  2271.     call    bufread            ; check for char from serial port buf
  2272.     jnc    xmit8            ; nc = a char, read til none
  2273.     jmp    short xmit8c        ; continue transfer
  2274. xmit8b:    mov    bufcnt,0        ; clear serial port buf
  2275.     call    bufread            ; check for char from serial port buf
  2276.     jc    xmit8            ; c = none
  2277.     cmp    al,script.xmitpmt    ; is port char the ack?
  2278.     jne    xmit8            ; ne = no, just ignore the char
  2279. xmit8c:    mov    ax,script.xmitpause    ; get millisecs to pause
  2280.     or    ax,ax            ; any time?
  2281.     jz    xmit7            ; z = none
  2282.     call    pcwait            ; wait this long
  2283.     jmp    short xmit7        ; yes, continue transfer
  2284.  
  2285. xmita:    test    status,stat_cc        ; Control-C?
  2286.     jnz    xmitc            ; nz = yes
  2287.     test    status,stat_cr        ; a local ack?
  2288.     jz    xmit8            ; z = no, ignore local char
  2289.     mov    dx,offset crlf        ; display cr/lf
  2290.     mov    ah,prstr
  2291.     int    dos
  2292.     jmp    xmit8c            ; continue transfer
  2293. xmitc:    pop    cx            ; Control-C, clear stack
  2294.     pop    si            ; ...
  2295.     mov    dx,offset xfrcan    ; say canceling transfer
  2296.     mov    ah,prstr
  2297.     int    dos
  2298.     mov    flags.cxzflg,0        ; clear Control-C flag
  2299.     jmp    xmitx2            ; ctrl-c, quit
  2300.  
  2301. SCXMIT    ENDP
  2302.  
  2303. ;
  2304. ; Squit is the script error exit pathway.
  2305. ;
  2306. squit:    cmp    flags.cxzflg,'C'    ; Control-C interrupt seen?
  2307.     je    squit5            ; e = yes
  2308.     test    status,stat_tmo        ; timeout?
  2309.     jz    squit2            ; z = no, another kind of failure
  2310.     cmp    taklev,0        ; in a Take/macro?
  2311.     jne    squit1            ; ne = yes, skip timeout message
  2312.     push    dx
  2313.     mov    dx,offset tmomsg    ; say timed out
  2314.     mov    ah,prstr
  2315.     int    dos            ; display it
  2316.     pop    dx
  2317. squit1:    cmp    script.inactv,0        ; action to do upon timeout
  2318.     je    squit4            ; 0 = proceed, ne = non-zero = quit
  2319. squit5:    call    takclos            ; close Take file or macro
  2320. squit2:    call    isdev            ; stdin is a device (vs file)?
  2321.     jc    squit3            ; c = device, not a file
  2322.     mov    flags.extflg,1        ; set Kermit exit flag
  2323. squit3:    cmp    flags.cxzflg,'C'    ; Control-C interrupt seen?
  2324.     jne    squit6            ; ne = no
  2325.     or    kstatus,ksuser        ; say user intervention
  2326. squit6:    stc
  2327.     ret                ; return failure
  2328. squit4:    clc                ; return success, ignore error
  2329.     ret
  2330.  
  2331. code    ends
  2332. code1    segment
  2333.     assume    cs:code1
  2334.  
  2335. ;;;;;;;;;;;;;;;;;; local support procedures ;;;;;;;;;;
  2336. ; Find line starting just after ":label". Label is in variable LINE
  2337. ; (length in slablen). Readjust Take read pointer to start of that line.
  2338. ; Performs file search from beginning of file, popping up levels if req'd.
  2339. ; Exit carry clear if success, carry set otherwise. Local worker routine.
  2340. ; Leaves  command.cmkeep,1 persistent, so be careful.
  2341. getto    proc    FAR
  2342.     push    bx            ; global save of bx
  2343. gett0:    mov    comand.cmkeep,1        ; keep Take file open after this call
  2344.     mov    bx,takadr
  2345.     cmp    [bx].taktyp,take_file    ; get type of take (a file?)
  2346.     jne    gett2            ; ne = no, a macro
  2347.     cmp    forward,0        ; GOTO?
  2348.     jne    gett1            ; ne = no, FORWARD, do not rewind
  2349.                     ; scan from start of Take file
  2350.     mov    word ptr [bx].takseek,0
  2351.     mov    word ptr [bx].takseek+2,0 ; seek distance, bytes
  2352. gett1:    call    takrd            ; get a line
  2353.     mov    bx,takadr        ; restore bx to working value
  2354.     jmp    short gett4
  2355.                     ; Take a Macro
  2356. gett2:    mov    cx,[bx].takbuf        ; segment of macro definition
  2357.     push    es
  2358.     mov    es,cx
  2359.     mov    cx,es:[0]        ; get string length byte
  2360.     pop    es
  2361.     mov    [bx].takcnt,cx        ; set unread to full buffer (rewind)
  2362.     mov    [bx].takptr,2        ; set read pointer to start of text
  2363.  
  2364. gett4:    call    getch            ; get a character
  2365.     jc    gett14            ; c = end of file, no char
  2366.     cmp    al,' '            ; leading white space?
  2367.     je    gett4            ; e = yes, read again
  2368.     cmp    al,TAB            ; this kind of whitespace?
  2369.     je    gett4            ; e = yes
  2370.     cmp    al,':'            ; start of label?
  2371.     je    gett8            ; e = yes
  2372. gett6:    cmp    al,CR            ; end of line?
  2373.     je    gett4            ; e = yes, seek colon for label
  2374.     call    getch            ; get a character
  2375.     jc    gett14            ; c = end of file, no char
  2376.     jmp    short gett6        ; read until end of line
  2377.  
  2378. gett8:    mov    si,offset line        ; label to search for
  2379.     mov    cx,slablen        ; its length
  2380.     jcxz    gett12            ; no chars to match
  2381.     cmp    byte ptr[si],':'    ; user label starts with colon
  2382.     jne    gett10            ; ne = no
  2383.     inc    si            ; skip user's colon
  2384.     dec    cx
  2385.     jcxz    gett12            ; no chars to match
  2386. gett10:    call    getch            ; read file char into al
  2387.     jc    gett14            ; c = end of file
  2388.     mov    ah,al
  2389.     cld
  2390.     lodsb
  2391.     call    tolowr            ; convert al and ah to lower case
  2392.     cmp    al,ah            ; match?
  2393.     jne    gett6            ; ne = no, goto end of line
  2394.     loop    gett10            ; continue matching
  2395.                     ; match obtained
  2396.     call    getch            ; read next file character
  2397.     jc    gett13            ; c = end of file, no char
  2398.     cmp    al,' '            ; separator?
  2399.     je    gett12            ; e = yes, unique label found
  2400.     cmp    al,TAB            ; this kind of separator?
  2401.     je    gett12            ; e = yes
  2402.     cmp    al,CR            ; or end of line?
  2403.     je    gett13            ; e = yes
  2404.     jmp    gett6            ; not correct label, keep reading
  2405.  
  2406. gett12:    call    getch            ; read past end of line
  2407.     jc    gett13            ; c = end of file, no char
  2408.     cmp    al,CR            ; end of line character?        
  2409.     jne    gett12            ; ne = no, keep reading
  2410. gett13: pop    bx
  2411.     clc                ; return carry clear
  2412.     ret                ; Take pointers are ready to read line
  2413.                     ; failed to find label, pop a level
  2414. gett14:    cmp    forward,2        ; SWITCH?
  2415.     jne    gett14a            ; ne = no
  2416.     pop    bx
  2417.     stc                ; set carry for failure
  2418.     ret
  2419. gett14a:call    takclos            ; close this macro/take file
  2420.     cmp    taklev,0        ; still in macro/take?
  2421.     je    gett15            ; e = no, quit
  2422.     jmp    gett0            ; try next level up
  2423. gett15:mov    ah,prstr        ; say label not found
  2424.     mov    dx,offset laberr    ; first part of error message
  2425.     int    dos
  2426.     mov    dx,offset line
  2427.     cmp    line,':'        ; label starts with ":"?
  2428.     jne    gett16            ; ne = no
  2429.     inc    dx            ; yes, skip it
  2430. gett16:    call    prtasz            ; print asciiz string
  2431.     mov    ah,prstr
  2432.     mov    dx,offset laberr2    ; trailer of error message
  2433.     int    dos
  2434. gett20:    pop    bx
  2435.     mov    kstatus,ksgen        ; command status, failure
  2436.     stc                ; set carry for failure
  2437.     ret
  2438. getto    endp
  2439.  
  2440. ; Read char from Take buffer. Returns carry clear and char in al, or if end
  2441. ; of file returns carry set. Enter with BX holding takadr. Local worker.
  2442. getch    proc    near
  2443.     cmp    [bx].takcnt,0        ; buffer empty?
  2444.     jg    getch2            ; g = no
  2445.     cmp    [bx].taktyp,take_file    ; file?
  2446.     jne    getch1            ; ne = no, a macro
  2447.     call    takrd            ; read another buffer
  2448.     cmp    [bx].takcnt,0        ; end of file?
  2449.     jne    getch2            ; ne = no
  2450. getch1:    stc                ; e = yes, exit error
  2451.     ret
  2452. getch2:    push    si
  2453.     push    es
  2454.     mov    es,[bx].takbuf        ; segment of buffer
  2455.     mov    si,[bx].takptr        ; read a char from Take buffer
  2456.     mov    al,es:[si]
  2457.     inc    si
  2458.     mov    [bx].takptr,si        ; move buffer pointer
  2459.     dec    [bx].takcnt        ; decrease number of bytes remaining
  2460.     pop    es
  2461.     pop    si
  2462.     clc                ; return carry clear
  2463.     ret
  2464. getch    endp
  2465.  
  2466. ; worker: read the number of seconds to pause or timeout
  2467. ;    returns time of day for timeout in timhms, and next non-space or
  2468. ;    non-tab source char ptr in si. Time is either elapsed seconds or
  2469. ;    a specific hh:mm:ss, determined from context of colons being present.
  2470. ;    Last form can be abbreviated as hh:[mm[:ss]]. Returns carry set if
  2471. ;    hh:mm:ss form has bad construction (invalid time).
  2472. inptim    proc    far
  2473.     push    ax
  2474.     push    bx
  2475.     push    cx
  2476.     push    dx
  2477.     push    di
  2478.     cld                ; decode pure seconds construction
  2479.     mov    di,si            ; remember source pointer
  2480.     mov    cx,10            ; multiplier
  2481.     mov    bx,script.indfto    ; no numbers yet, use default-timeout
  2482.     mov    al,byte ptr[si]
  2483.     cmp    al,':'            ; stray hh:mm:ss separator?
  2484.     je    inptm8            ; e = yes
  2485.     cmp    al,'9'            ; start with numeric input?
  2486.     ja    inptm4            ; a = no, use default time
  2487.     cmp    al,'0'            ; ditto
  2488.     jb    inptm4
  2489.     xor    ah,ah            ; source char holder
  2490.     xor    bx,bx            ; accumulated sum
  2491. inptm1:    mov    al,byte ptr[si]        ; get a byte into al
  2492.     cmp    al,':'            ; hh:mm:ss construction?
  2493.     je    inptm8            ; e = yes
  2494.     sub    al,'0'            ; remove ascii bias
  2495.     cmp    al,9            ; numeric?
  2496.     ja    inptm4            ; a = non-numeric, exit loop, bx = sum
  2497.     xchg    ax,bx            ; put sum into ax, char in bl
  2498.     mul    cx            ; sum times ten 
  2499.     xchg    ax,bx            ; put char into al, sum in bx
  2500.     add    bx,ax            ; add to sum
  2501.     inc    si            ; next char
  2502.     jmp    short inptm1        ; loop thru all chars
  2503.  
  2504. inptm4:    cmp    bx,12*60*60        ; half a day, in seconds
  2505.     jb    inptm5            ; b = less than
  2506.     jmp    inptm13            ; more than, error
  2507. inptm5:    push    si            ; save ending scan position for return
  2508.     mov    timout,bx        ; # seconds of timeout desired
  2509.     mov    ah,gettim        ; read DOS tod clock
  2510.     int    dos
  2511.     mov    timhms[0],ch        ; hours
  2512.     mov    timhms[1],cl        ; minutes
  2513.     mov    timhms[2],dh        ; seconds
  2514.     mov    timhms[3],dl        ; hundredths of seconds
  2515.     mov    bx,2            ; start with seconds field
  2516. inptm6: mov    ax,timout        ; our desired timeout interval
  2517.     add    al,timhms[bx]        ; add current tod digit to interval
  2518.     adc    ah,0
  2519.     xor    dx,dx            ; clear high order part thereof
  2520.     mov    cx,60            ; divide by 60
  2521.     div    cx            ; compute number of minutes or hours
  2522.     mov    timout,ax        ; quotient
  2523.     mov    timhms[bx],dl        ; put remainder in timeout tod digit
  2524.     dec    bx            ; look at next higher order time field
  2525.     or    bx,bx            ; done all time fields?
  2526.     jge    inptm6            ; ge = no
  2527.     cmp    timhms[0],24        ; normalize hours
  2528.     jl    inptm7            ; l = not 24 hours
  2529.     sub    timhms[0],24        ; discard part over 24 hours
  2530. inptm7:    pop    si            ; return ptr to next source char
  2531.     jmp    short inptm11        ; trim trailing whitespace
  2532.  
  2533. inptm8:                    ; decode hh:[mm[:ss]] to timhms
  2534.     mov    si,di            ; recall starting source pointer
  2535.     mov    word ptr timhms[0],0    ; clear time out tod
  2536.     mov    word ptr timhms[2],0
  2537.     xor    bx,bx            ; three groups possible
  2538. inptm9:    mov    dl,byte ptr[si]        ; get a char
  2539.     cmp    dl,':'            ; field separator?
  2540.     je    inptm10            ; e = a separator, step fields
  2541.     sub    dl,'0'            ; remove ascii bias
  2542.     cmp    dl,9
  2543.     ja    short inptm11        ; a = failure to get expected digit
  2544.     mov    al,timhms[bx]        ; get sum to al
  2545.     mov    ah,10
  2546.     mul    ah            ; sum times ten
  2547.     add    al,dl            ; sum = 10 * previous + current
  2548.     mov    timhms[bx],al        ; current sum
  2549.     cmp    timhms[bx],60        ; more than legal?
  2550.     jae    inptm13            ; ae = illegal
  2551.     or    bx,bx            ; doing hours?
  2552.     jnz    inptm9a            ; nz = no, min or sec
  2553.     cmp    timhms[bx],24        ; more than legal?
  2554.     jae    inptm13            ; ae = illegal
  2555. inptm9a:inc    si            ; next char
  2556.     jmp    short inptm9        ; continue analysis
  2557. inptm10:inc    bx            ; point to next field
  2558.     inc    si            ; next char
  2559.     cmp    bx,2            ; last subscript to use (secs)
  2560.     jbe    inptm9            ; be = get more text
  2561.  
  2562. inptm11:cmp    byte ptr [si],spc    ; examine break char, remove spaces
  2563.     jne    inptm12            ; ne = no, stay at this char
  2564.     inc    si            ; look at next char
  2565.     jmp    short inptm11        ; continue scanning off white space
  2566. inptm12:clc                ; carry clear for success    
  2567.     jnc    inptm14
  2568. inptm13:stc                ; carry set for illegal value    
  2569. inptm14:pop    di            ; return with si beyond our text
  2570.     pop    dx
  2571.     pop    cx
  2572.     pop    bx
  2573.     pop    ax
  2574.     ret
  2575. inptim    endp
  2576.  
  2577. ; Read comms line, put most recent byte into buffer, 
  2578. ; and into reg AL as a side effect used by scxmit.
  2579. bufread    proc    far
  2580.     call    chkport            ; get any oldest char from port
  2581.     call    chktmo            ; check tod for timeout
  2582.     cmp    bufcnt,0        ; empty buffer?
  2583.     jne    bufrd1            ; ne = no
  2584.     stc                ; yes, set carry flag (no char)
  2585.     ret                ; and quit (chkport sets status)
  2586.  
  2587. bufrd1:    clc                ; clear carry flag (have a char)
  2588.     ret                ; chkport sets status
  2589. bufread    endp
  2590.  
  2591. ; Write byte AL to buffer. Manipulates bufcnt and bufrptr. Buffer is linear.
  2592. bufwrite proc    far
  2593.     push    ax
  2594.     push    si
  2595.     push    di
  2596.     push    es
  2597.     mov    si,bufseg        ; segment of buffer
  2598.     mov    es,si
  2599.     mov    si,bufcnt        ; buffer count
  2600.     cmp    si,scpbuflen        ; filled?
  2601.     jb    bufwt2            ; b = no
  2602.     push    ds            ; save DS
  2603.     mov    di,bufseg
  2604.     mov    ds,di
  2605.     mov    cx,si            ; count of bytes to be moved
  2606.     dec    cx            ; leave a hole
  2607.     xor    di,di            ; destination is at beginning
  2608.     mov    si,di
  2609.     inc    si            ; source is one forward
  2610.     cld                ; copy forward
  2611.     rep    movsb            ; copy down the buffer contents
  2612.     pop    ds
  2613.     dec    bufcnt            ; one hole left
  2614.     cmp    bufrptr,0        ; is read pointer at start?
  2615.     je    bufwt1            ; e = yes
  2616.     dec    bufrptr            ; move it down too
  2617. bufwt1:    mov    si,bufcnt
  2618. bufwt2:    mov    es:[si],al        ; store char held in al
  2619.     inc    bufcnt            ; say have added a char to the buf
  2620.     pop    es
  2621.     pop    di
  2622.     pop    si
  2623.     pop    ax
  2624.     ret
  2625. bufwrite endp
  2626.  
  2627. ; Report buffer status for dumping buffer to a log file.
  2628. ; Yield ax, cx, es, si as indicated below.
  2629. buflog    proc    far
  2630.     mov    si,bufseg            ; segment of buffer
  2631.     mov    es,si
  2632.     xor    si,si                ; start of buffer
  2633.     mov    cx,bufcnt            ; number of chars in buffer
  2634.     cmp    cx,cmdblen-1            ; longer than command buffer?
  2635.     ja    buflog1                ; a = yes, trim
  2636.     ret                    ; return these registers
  2637. buflog1:mov    si,cx                ; ending offset
  2638.     mov    cx,cmdblen-1
  2639.     sub    si,cx                ; starting offset
  2640.     ret
  2641. buflog    endp
  2642.  
  2643. ; worker: check for timeout, return status=stat_tmo if timeout, else bit
  2644. ;  stat_tmo is cleared.
  2645. chktmo    proc    far
  2646.     push    ax
  2647.     push    cx
  2648.     push    dx
  2649.     and    status,not stat_tmo
  2650.     mov    ah,gettim        ; get the time of day
  2651.     int    dos
  2652.     sub    ch,timhms[0]        ; hours difference, ch = (now-timeout)
  2653.     je    chktmo2            ; e = same, check mmss.s
  2654.     jg    chktmo1            ; g = past target hour
  2655.     add    ch,24            ; we are early, see by how much
  2656. chktmo1:cmp    ch,12            ; hours difference, large or small?
  2657.     jge    chktmox            ; ge = not that time yet
  2658.     jl    chktmo3            ; l = beyond that time
  2659. chktmo2:cmp    cl,timhms[1]        ; minutes, hours match
  2660.     jb    chktmox            ; b = early
  2661.     ja    chktmo3            ; a = late
  2662.     cmp    dh,timhms[2]        ; seconds, hhmm match
  2663.     jb    chktmox            ; b = early
  2664.     ja    chktmo3            ; a = late
  2665.     cmp    dl,timhms[3]        ; fractions, hhmmss match
  2666.     jb    chktmox            ; b = early
  2667. chktmo3:or    status,stat_tmo        ; say timeout
  2668.     pop    dx
  2669.     pop    cx
  2670.     pop    ax
  2671.     stc
  2672.     ret
  2673. chktmox:pop    dx
  2674.     pop    cx
  2675.     pop    ax
  2676.     clc
  2677.     ret
  2678. chktmo    endp
  2679. ;
  2680. ; worker: check keyboard for char. Return status = stat_cc if control-C typed,
  2681. ; stat_cr if carriage return, or stat_ok if any other char typed. Else return
  2682. ; with these status bits cleared.
  2683. chkkbd    proc    far
  2684.     and    status,not (stat_ok+stat_cc+stat_cr) ; clear status bits
  2685.     xor    al,al
  2686.     cmp    flags.cxzflg,'C'    ; Control-C interrupt seen?
  2687.     je    chkkbd0            ; e = yes
  2688.     call    isdev            ; is stdin a device, not disk file?
  2689.     jnc    chkkbd2            ; nc = not device so do not read here
  2690.     mov    ah,dconio        ; keyboard char present?
  2691.     mov    dl,0ffH
  2692.     int    dos
  2693.     je    chkkbd1            ; e = none
  2694.     or    status,stat_ok        ; have a char, return it in al
  2695.     cmp    al,3            ; control c?
  2696.     jne    chkkbd1            ; ne = not control c
  2697. chkkbd0:or    status,stat_cc        ; say control c         
  2698. chkkbd1:cmp    al,cr            ; carriage return? [js]
  2699.     jne    chkkbd2            ; ne = no
  2700.     or    status,stat_cr        ; say carriage return [js]
  2701. chkkbd2:ret
  2702. chkkbd    endp
  2703.  
  2704. ;
  2705. ; worker: check serial port for received char. Return status = stat_ok if
  2706. ;  char received, otherwise stat_ok cleared. Can echo char to screen. Will
  2707. ;  write char to local circular buffer.
  2708. chkport    proc    far
  2709.     and    status,not stat_ok    ; clear status bit
  2710.     call    fprtchr            ; char at port (in al)?
  2711.     jnc    chkpor1            ; nc = yes, analyze it
  2712.     push    bx
  2713.     mov    bx,portval
  2714.     cmp    [bx].portrdy,0        ; is port not-ready?
  2715.     pop    bx
  2716.     jne    chkpor5            ; ne = no, port is ready, just no char
  2717.     or    status,stat_cc        ; Control-C for port not ready
  2718. chkpor5:stc
  2719.     ret                ; no, return
  2720. chkpor1:and    al,parmsk        ; strip parity, if any
  2721.     cmp    rxtable+256,0        ; is translation turned off?
  2722.     je    chkpor0            ; e = yes, no translation
  2723.     push    bx            ; translate incoming character
  2724.     mov    bx,offset rxtable    ; the translation table
  2725.     xlatb
  2726.     pop    bx
  2727. chkpor0:test    flags.capflg,logses    ; capturing active?
  2728.     jz    chkpor3            ; z = no
  2729.     test    flags.remflg,d8bit    ; keep 8 bits for displays?
  2730.     jnz    chkpo0a            ; nz = yes, 8 bits if possible
  2731.     cmp    flags.debug,0        ; is debug mode active?
  2732.     jne    chkpo0a            ; ne = yes, record 8 bits
  2733.     and    al,7fh            ; remove high bit
  2734. chkpo0a:push    ax            ; save char
  2735.     call    fcptchr            ; give it captured character
  2736.     pop    ax            ; restore character and keep going
  2737. chkpor3:test    flags.remflg,d8bit    ; keep 8 bits for displays?
  2738.     jnz    chkpo3a            ; nz = yes, 8 bits if possible
  2739.     and    al,7fh            ; remove high bit
  2740. chkpo3a:cmp    script.inecho,0        ; input echoing off?
  2741.     je    chkpor4            ; e = yes
  2742.     call    scdisp            ; display the char
  2743. chkpor4:call    bufwrite        ; put char in buffer
  2744.     or    status,stat_ok        ; say have a char (still in al)
  2745.     ret
  2746. chkport    endp
  2747.  
  2748. ; Given a keyword table value in BX find the keyword text and length.
  2749. ; Offset of table is in DX.
  2750. ; Returns CX = length and SI pointing to text string, and carry clear.
  2751. ; Failure returns carry set
  2752. revlookup proc    far
  2753.     push    ax
  2754.     push    di
  2755.     mov    si,dx            ; offset of table
  2756.     xor    ch,ch
  2757.     mov    cl,byte ptr [si]    ; number of table entires
  2758.     inc    si            ; start of entries
  2759.     cld
  2760.     jcxz    revloo2            ; z = no entries, fail
  2761. revloo1:lodsw                ; length of this entry's keyword
  2762.     mov    di,si            ; point at keyword
  2763.     add    di,ax            ; point at value
  2764.     cmp    [di],bx            ; a match?
  2765.     je    revloo3            ; e = yes
  2766.     add    di,2            ; step over value to next entry
  2767.     mov    si,di            ; next entry
  2768.     loop    revloo1            ; keep looking
  2769. revloo2:pop    di
  2770.     pop    ax
  2771.     stc                ; no match, report failure
  2772.     ret
  2773. revloo3:mov    cx,ax            ; length of keyword, si has ptr
  2774.     pop    di
  2775.     pop    ax
  2776.     clc                ; success
  2777.     ret
  2778. revlookup endp
  2779.  
  2780. ; worker: display the char in al on screen
  2781. ; use caret-char notation for control codes
  2782. ; parse out escape and control sequences
  2783. scdisp    proc    far
  2784. scdisp0:cmp    disp_state,0        ; inited yet?
  2785.     jne    scdisp0a        ; ne = yes
  2786.     mov    disp_state,offset scdisp1 ; init now
  2787. scdisp0a:push    ax
  2788.     push    bx
  2789.     push    cx            ; used by atparse
  2790.     push    dx
  2791.     call    word ptr disp_state
  2792.     pop    dx
  2793.     pop    cx
  2794.     pop    bx
  2795.     pop    ax
  2796.     ret                ; keep near/far calls straight
  2797. scdisp    endp
  2798.  
  2799. scdisp1 proc    near            ; worker for above
  2800.     mov    ah,conout        ; our desired function
  2801.     test    flags.remflg,d8bit    ; show all 8 bits?
  2802.     jnz    scdisp1a        ; nz = yes
  2803.     and    al,7fh            ; apply 7 bit display mask
  2804. scdisp1a:or    al,al            ; null?
  2805.     jz    scdisp3            ; z = yes, ignore
  2806.     cmp    al,del            ; delete code?
  2807.     je    scdisp3            ; e = yes, ignore
  2808.     cmp    script.infilter,0    ; filter echos?
  2809.     je    scdisp2            ; e = no, display as-is
  2810.     test    al,not 9fh        ; C0/C1 control char?
  2811.     jnz    scdisp2            ; ae = no, display as-is
  2812.     cmp    al,CSI            ; CSI?
  2813.     je    scdisp6            ; e = yes
  2814.     test    al,80h            ; other C1?
  2815.     jnz    scdisp3            ; nz = yes, ignore
  2816.     cmp    al,cr            ; carriage return?
  2817.     je    scdisp2            ; e = yes, display as-is
  2818.     cmp    al,lf            ; line feed?
  2819.     je    scdisp2
  2820.     cmp    al,tab            ; horizontal tab?
  2821.     je    scdisp2
  2822.     cmp    al,bell            ; bell?
  2823.     je    scdisp2
  2824.     cmp    al,bs            ; backspace?
  2825.     je    scdisp2
  2826.     cmp    al,escape        ; escape?
  2827.     je    scdisp4
  2828.     or    al,40h            ; control code to printable char
  2829.     push    ax
  2830.     mov    dl,5eh            ; display caret first
  2831.     int    dos
  2832.     pop    ax
  2833. scdisp2:mov    dl,al            ; the char to be displayed
  2834.     int    dos
  2835. scdisp3:ret
  2836.  
  2837. scdisp4:mov    disp_state,offset scdisp5    ; here on ESC
  2838.     ret
  2839. scdisp5:cmp    al,'['            ; ESC [?
  2840.     jne    scdisp7            ; ne = no, consider to be terminator
  2841. scdisp6:call    atpclr            ; clear parser
  2842.     mov    parfail,offset scdisp7    ; next state upon failure
  2843.     mov    pardone,offset scdisp7    ; next state upon success
  2844.     mov    disp_state,offset atparse ; parse sequences
  2845.     ret
  2846. scdisp7:mov    disp_state,offset scdisp1 ; normal display
  2847.     ret
  2848. scdisp1    endp
  2849.  
  2850. code1    ends
  2851.     end
  2852.