home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msk316src.zip / MSSSCP.ASM < prev    next >
Assembly Source File  |  1999-10-14  |  93KB  |  2,901 lines

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