home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / ccdos / ccsscp.asm < prev    next >
Assembly Source File  |  2020-01-01  |  84KB  |  1,687 lines

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