home *** CD-ROM | disk | FTP | other *** search
/ Phoenix CD 2.0 / Phoenix_CD.cdr / 01e / msk230s1.zip / MSSFIL.ASM < prev    next >
Assembly Source File  |  1988-02-12  |  95KB  |  1,975 lines

  1.         NAME    mssfil
  2. ; File MSSFIL.ASM
  3. ; Edit history:
  4. ; Last edit 1 Jan 1988
  5. ; 1 Jan 1988 version 2.30
  6. ; Add packet length display, from Frank da Cruz. [jrd]
  7. ; 13 Dec 1987 minor cleanups. [jrd]
  8. ; 26 July 1987 Add test for formatted file display, fmtdsp, for cursor
  9. ;  positioning control. [jrd]
  10. ; 12 July 1987 Separate disk full and writing errors in outbuf. Tnx to
  11. ;  Jack Bryans. [jrd]
  12. ; 16 April 1987 Fix possible trashed error packet at gofi14, from Jack Bryans
  13. ; 5 April 1987 Move reprompt cursor to bottom screen line. [jrd]
  14. ; 15 March 87 Force procedure decode to flush its output buffer upon exit,
  15. ;  and correct outbuf to use buffer decbuf rather than buff. [jrd]
  16. ; 9 March 1987 Add statistics gathering per file and per session. [jrd]
  17. ; 5 March 1987 Add more bullet proofing wrt es: & cld usage. [jrd]
  18. ; 22 Feb 1987 Change output in prtscr to file i/o for speed, from
  19. ;  Jack Bryans. [jrd]
  20. ; 19 Oct 1986 Add special check for file names like "A:" in proc gofil. [jrd]
  21. ; 1 Oct 1986 Version 2.29a
  22. ; 25 July 1986 Reverse order of control-Z test, for speed, under encod3: [jrd]
  23. ; 26 May 1986 Revise code to permit serial display. [jrd]
  24. ; [2.29] code frozen on 6 May 1986 [jrd]
  25.  
  26.         public  bufpnt, buff, cptio, chrcnt, init
  27.         public  gofil, outbuf, ptchr, gtchr, gtnfil, getfil, filbuf
  28.         public  encode, decode, nulref, nulr, decbuf, errpack, rptq
  29.         public  origr, rptct, rptval, clrfln, cxmsg, biterr, intmsg
  30.         public  rtpos, erpos, rppos, stpos, nppos, rprpos, nrtpos, sppos
  31.         public  kbpos, perpos, frpos, prtasz, prtscr, prtfn, fmtdsp
  32.         public  diskio, locfil, strlen, strcat, strcpy, fparse, pktsize
  33.         public  shosta, begtim, endtim, fsta    ; statistics procedures
  34.  
  35.         include mssdef.h
  36.  
  37. rptmin  equ     3               ; At least 3 of same char in a row.
  38.                                 ; equates for screen positioning
  39. scrfln  equ     0316H           ; Place for file name.
  40. scrkb   equ     0416H           ; Place for percent transferred.
  41. scrper  equ     0516H           ; Place for Kbytes transferred.
  42. scrst   equ     0616H           ; Place for status.
  43. scrnp   equ     0816H           ; Place for number of packets.
  44. scrsz   equ     0916h           ; packet size
  45. scrnrt  equ     0A16H           ; Place for number of retries.
  46. screrr  equ     0B16H           ; Place for error msgs.
  47. scrhi   equ     0C16H           ; Err when 8th bit is on.
  48. scrfr   equ     0C16H           ; Rename file.
  49. scrint  equ     0C16H           ; Acknowledge interrupt
  50. scrsp   equ     0D00H           ; Place for send packet.
  51. scrrp   equ     0F00H           ; Place for receive packet.
  52. scrrpr  equ     1700H           ; Prompt when Kermit ends (does cr/lf).
  53.  
  54. datas   segment public 'datas'
  55.         extrn   data:byte, flags:byte, trans:byte, pack:byte, hierr:byte
  56.         extrn   filtst:byte
  57.  
  58. outlin  db      cr,lf,10 dup (' ')
  59.         verdef                                          ; version ident
  60.         db      cr,lf
  61.         db      cr,lf,'           File name:'
  62.         db      cr,lf,'  KBytes transferred:'
  63.         db      cr,lf
  64.         db      cr,lf
  65.         db      cr,lf
  66.         db      cr,lf,'   Number of packets:'
  67.         db      cr,lf,'       Packet length:'
  68.         db      cr,lf,'   Number of retries:'
  69.         db      cr,lf,'          Last error: None'
  70.         db      cr,lf,'        Last warning: None'
  71.         db      cr,lf,'$'
  72.  
  73. ermes4  db      '?Unable to make unique name$'
  74. ermes9  db      '?Printer not ready$'
  75. erms10  db      '?Unable to receive data$'
  76. erms11  db      '?Disk full$'
  77. erms12  db      '?Unable to create file $'
  78. erms13  db      '?Error writing file$'
  79. infms5  db      'Renaming file to $'
  80. infms7  db      'File interrupt',cr,lf,'$'
  81. infms8  db      'File group interrupt',cr,lf,'$'
  82. infms9  db      'User ',5eh,'  interrupt',cr,lf,'$'
  83. hibit   db      'Warning - Non Ascii char',cr,lf,'$'
  84. asmsg   db      '  as  $'
  85. crlf    db      cr,lf,'$'
  86. printer db      'PRN',0
  87.                                 ; DOS special chars allowed in filenames
  88. spchar2 db      '$', 26h, 23h, 40h, 21h, 25h, 27H, '(', ')', '-', 7bh,7dh
  89.         db      5fh, 5eh, 7eh, 60h
  90. spc2len equ     $-spchar2
  91. rptval  db      0               ; Repeated character.
  92. rptct   db      1               ; Number of times it's repeated.
  93. rptq    db      drpt            ; Repeat prefix.
  94. origr   db      drpt            ; Original repeat prefix.
  95. chrcnt  dw      0               ; Number of chars in the file buffer.
  96. outpnt  dw      0               ; Position in packet.
  97. bufpnt  dw      0               ; Position in file buffer.
  98. ofilsz  dw      0               ; Double word original file size (in bytes.)
  99.         dw      0
  100. tfilsz  dw      0               ; Bytes transferred.
  101.         dw      0
  102. oldper  dw      0               ; old percentage
  103. oldkbt  dw      0               ; old KB transferred.
  104. wrpmsg  db      0               ; non-zero if we wrote percent message
  105. fmtdsp  db      0               ; non-zero if formatted display in use
  106.                                 ; Statistics data storage area
  107. fsta    statinfo <>             ; for last operation values
  108. ssta    statinfo <>             ; for session values
  109. sflag   dw      0               ; flag for send (1) or receive (0)
  110.                                 ;   80h = begtim started
  111.  
  112. lastmsg db      cr,lf,lf,' Totals for the last transfer    ($'
  113. sessmsg db      cr,lf,lf,' Totals since Kermit was started ($'
  114. pinmsg  db      ' sec)'
  115.         db      cr,lf,'  Serial port characters received $'
  116. poutmsg db      cr,lf,'  Serial port characters sent     $'
  117. finmsg  db      cr,lf,'  File characters received        $'
  118. foutmsg db      cr,lf,'  File characters sent            $'
  119. pkimsg  db      cr,lf,'  Packets received                $'
  120. pkomsg  db      cr,lf,'  Packets sent                    $'
  121. nakimsg db      cr,lf,'  NAKs received                   $'
  122. nakomsg db      cr,lf,'  NAKs sent                       $'
  123. baudmsg db      cr,lf,'  Effective baud rate             $'
  124. tens    dd      1,10,100,1000,10000,100000,1000000,10000000,100000000
  125.         dd      1000000000
  126. tenslen equ     ($-tens) / 4    ; number of double words in array tens.
  127.                                 ; end statistics data area
  128. onek    dw      1024
  129. onehun  dw      100
  130. sixty   dw      60
  131. ten     dw      10
  132. denom   dw      0
  133. permsg  db      cr,' Percent transferred:$'
  134. cxzhlp  db      '^X cancels file, ^Z cancels batch'
  135.         db      ', ^E quits protocol'
  136.         db      ', ^C quits'
  137.         db      ', Return retries'
  138.         db      '$'
  139. erword  db      cr,lf,'Error $'
  140. rtword  db      cr,lf,'Retry $'
  141. cxzser  db   cr,lf,'Type Control X to cancel file, Control Z to cancel batch,'
  142.         db      cr,lf,' Control E to quit protocol, Control C to quit '
  143.         db      'abruptly,',cr,lf,' or Return to retry',cr,lf,'$'
  144. templp  db      65 dup (?)      ; temp for local path part
  145. templf  db      14 dup (?)      ; temp for local filename part
  146. temprp  db      65 dup (?)      ; temp for remote path part
  147. temprf  db      14 dup (?)      ; temp for remote filename part
  148. locfil  db      65 dup (?)      ; local filename for receive and get
  149. cptio   filest  <>              ; DOS 2.0 file structure for logging
  150. diskio  filest  <>              ; ditto, for ordinary file transfers
  151.  
  152. buff    db      buffsz dup (?)  ; Use as our Disk Transfer Area.
  153. filbuf  equ     this byte       ; make filbuf and decbuf the same address
  154. decbuf  db      maxpack+10 dup (?) ; For decoding incoming data (+guard).
  155. unum    dw      ?               ; unique filename generation number
  156. havdot  db      ?               ; dot-found status in verify
  157. prepksz dw      0               ; previous packet size
  158. datas   ends
  159.  
  160. code    segment public 'code'
  161.         extrn   spack:near, cmblnk:near, locate:near, decout:near, comnd:near
  162.         extrn   putmod:near, poscur:near, clearl:near, isfile:near
  163.         assume  cs:code, ds:datas
  164.  
  165. ; Position cursor for an error message.
  166.  
  167. ERPOS   PROC    NEAR
  168.         test    flags.remflg,dquiet     ; quiet screen?
  169.         jnz     erpx                    ; nz = yes
  170.         push    dx              ; save any preexisting message pointer
  171.         test    flags.remflg,dserial    ; serial mode display?
  172.         jnz     erpo1                   ; nz = yes
  173.         test    flags.remflg,dserver    ; are we a server
  174.         jnz     erp0                    ; nz = yes, and display is regular
  175.         cmp     flags.xflg,1            ; Packet header seen?
  176.         jne     erp0                    ; No, do as normal.
  177. erpo1:  mov     dx,offset crlf
  178.         mov     ah,prstr
  179.         int     dos
  180.         mov     dx,offset erword        ; put out word Error
  181.         int     dos
  182.         pop     dx                      ; restore old pointer
  183.         ret
  184. erp0:   mov     dx,screrr
  185.         call    poscur
  186.         pop     dx                      ; restore old pointer
  187. erpx:   ret
  188. ERPOS   ENDP
  189.  
  190. ; Position cursor for number of retries message.
  191.  
  192. RTPOS   PROC    NEAR
  193.         test    flags.remflg,dquiet     ; quiet display mode?
  194.         jnz     rtpx                    ; nz = yes
  195.         test    flags.remflg,dserver    ; in server mode?
  196.         jnz     rtp0                    ; nz = yes
  197.         cmp     flags.xflg,1            ; Packet header seen?
  198.         jne     rtp0                    ; No, do as normal.
  199.         ret
  200. rtp0:   test    flags.remflg,dserial    ; serial mode display?
  201.         jnz     rtp1                    ; nz = yes
  202.         mov     dx,scrnrt
  203.         call    poscur
  204.         jmp     clearl
  205. rtp1:   mov     dx,offset rtword        ; display word Retry
  206.         mov     ah,prstr
  207.         int     dos
  208. rtpx:   ret
  209. RTPOS   ENDP
  210.  
  211. ; Reassure user that we acknowledge his ^X/^Z.
  212.  
  213. INTMSG  PROC    NEAR
  214.         cmp     fmtdsp,0                ; non-formatted screen?
  215.         je      int5                    ; e = yes
  216.         test    flags.remflg,dserver    ; server mode?
  217.         jnz     int4                    ; nz = yes
  218.         cmp     flags.xflg,0            ; Writing to screen?
  219.         jne     int1                    ; Yes. Don't do anything.
  220. int4:   test    flags.remflg,dquiet     ; quiet screen?
  221.         jnz     int1                    ; yes, supress msg
  222.         test    flags.remflg,dserial    ; serial mode display?
  223.         jz      int2                    ; ne = no
  224. int5:   mov     dx,offset crlf          ; yes. output initial cr/lf
  225.         mov     ah,prstr
  226.         int     dos
  227.         jmp     int3                    ; display the message
  228. int2:   mov     dx,scrint
  229.         call    poscur
  230.         call    clearl
  231. int3:   mov     dx,offset infms7        ; File interrupted?
  232.         cmp     flags.cxzflg,'X'        ; Yes.
  233.         je      int0
  234.         mov     dx,offset infms8        ; File group interrupted?.
  235.         cmp     flags.cxzflg,'Z'
  236.         je      int0
  237.         cmp     flags.cxzflg,'C'        ; just a control-C?
  238.         je      int1                    ; e = yes, suppress msg
  239.         mov     dl,flags.cxzflg
  240.         mov     infms9+6,dl             ; store interrupt code letter
  241.         mov     dx,offset infms9
  242. int0:   mov     ah,prstr
  243.         int     dos
  244. int1:   ret
  245. INTMSG  ENDP
  246.  
  247. ; Print error message that a high bit set char was found in the file.
  248.  
  249. BITERR  PROC    NEAR
  250.         test    flags.remflg,dquiet     ; remote mode?
  251.         jnz     biter1                  ; nz = yes, no printing.
  252.         push    bx
  253.         cmp     fmtdsp,0                ; non-formatted display?
  254.         je      biter3                  ; e = yes
  255.         test    flags.remflg,dserial    ; serial mode display?
  256.         jz      biter2                  ; z = no
  257.         mov     ah,prstr                ; display an initial cr/lf
  258.         mov     dx,offset crlf
  259.         int     dos
  260.         jmp     biter3
  261. biter2: mov     dx,scrhi
  262.         call    poscur
  263.         call    clearl
  264. biter3: mov     ah,prstr
  265.         mov     dx,offset hibit
  266.         int     dos
  267.         pop     bx
  268. biter1: ret
  269. BITERR  ENDP
  270.  
  271. ;  Clear out message about interrupted file.
  272.  
  273. CXMSG   PROC    NEAR
  274.         test    flags.remflg,dserver    ; server mode?
  275.         jnz     cxm1                    ; nz = yes
  276.         cmp     flags.xflg,0            ; Writing to screen?
  277.         jne     cxm0                    ; Yes. Don't do anything.
  278. cxm1:   test    flags.remflg,dquiet+dserial ; quiet or serial display?
  279.         jnz     cxm0                    ; nz = yes
  280.         mov     dx,scrint
  281.         call    poscur
  282.         call    clearl
  283. cxm0:   ret
  284. CXMSG   ENDP
  285.  
  286. ;  Clear out the old filename on the screen.
  287.  
  288. CLRFLN  PROC    NEAR
  289.         test    flags.remflg,dquiet     ; quiet display?
  290.         jnz     clrflnx                 ; nz = yes
  291.         test    flags.remflg,dserial    ; serial display mode?
  292.         jnz     clrfln1                 ; nz = yes, use just cr/lf
  293.         mov     dx,scrfln
  294.         call    poscur
  295.         call    clearl                  ; Clear to end of line
  296.         ret
  297. clrfln1:push    ax                      ; for serial display, does cr/lf
  298.         mov     ah,prstr
  299.         mov     dx,offset crlf
  300.         int     dos
  301.         pop     ax
  302. clrflnx:ret
  303. CLRFLN  ENDP
  304.  
  305. PKTSIZE PROC    NEAR                    ; display packet size
  306.         cmp     fmtdsp,0                ; formatted display?
  307.         je      pktsiz3                 ; e = no, no display
  308.         push    ax
  309.         push    dx
  310.         mov     ax,pack.argbk1          ; packet size (data part)
  311.         add     al,trans.chklen         ; plus checksum
  312.         adc     ax,3                    ; plus LEN, SEQ, TYPE
  313.         cmp     ax,94                   ; larger than Regular?
  314.         jbe     pktsiz1                 ; be = no
  315.         add     ax,3                    ; add Long Packet len and chksum
  316. pktsiz1:cmp     ax,prepksz              ; same as previous packet?
  317.         je      pktsiz2                 ; e = yes, skip display
  318.         mov     prepksz,ax              ; remember new value
  319.         push    ax
  320.         mov     dx,scrsz                ; position cursor
  321.         call    poscur
  322.         call    clearl                  ; clear to end of line
  323.         pop     ax
  324.         call    decout                  ; show packet length
  325. pktsiz2:pop     dx
  326.         pop     ax
  327. pktsiz3:ret
  328. PKTSIZE ENDP
  329.  
  330. ; some random screen positioning functions
  331. kbpos:  mov     dx,scrkb                ; KBytes transferred.
  332.         test    flags.remflg,dquiet+dserial ; quiet or serial display mode?
  333.         jz      setup2                  ; z = no
  334.         ret                             ; else ignore postioning request
  335. perpos: mov     dx,scrper               ; Percent transferred.
  336.         test    flags.remflg,dquiet+dserial ; quiet or serial display mode?
  337.         jz      setup2                  ; z = no
  338.         ret                             ; else ignore postioning request
  339. frpos:  mov     dx,scrfr                ; Say renamed file.
  340.         jmp     setup2
  341. stpos:  mov     dx,scrst                ; Print status of file transfer.
  342.         jmp     setup2
  343. nppos:  mov     dx,scrnp                ; Number of packets sent.
  344.         test    flags.remflg,dquiet+dserial ; quiet or serial display mode?
  345.         jz      setup1                  ; z = no
  346.         ret
  347. rprpos: mov     dx,scrrpr               ; Reprompt position.
  348.         call    setup1                  ; position cursor
  349.         mov     fmtdsp,0                ; turn off formatted display flag
  350.         ret
  351. nrtpos: mov     dx,scrnrt               ; Number of retries.
  352.         jmp     short setup2
  353. sppos:  mov     dx,scrsp                ; Send packet location.
  354.         jmp     short setup1
  355. rppos:  mov     dx,scrrp                ; Receive packet location.
  356.         jmp     short setup1
  357.                                 ; common service routines for positioning.
  358. setup1: test    flags.remflg,dquiet+dserial; quiet or serial display mode?
  359.         jnz     setupa                  ; nz = yes
  360.         cmp     fmtdsp,0                ; non-formatted display?
  361.         je      setupa                  ; e = yes
  362.         jmp     poscur
  363. setup2: test    flags.remflg,dquiet+dserial; quiet or serial display mode?
  364.         jnz     setupa                  ; nz = yes
  365.         cmp     fmtdsp,0                ; non-formatted display?
  366.         je      setupa                  ; e = yes
  367.         call    poscur                  ; no
  368.         jmp     clearl
  369. setupa: test    flags.remflg,dquiet     ; quiet mode?
  370.         jnz     setupx                  ; nz = yes, do nothing
  371.         push    ax                      ; display cr/lf and return
  372.         push    dx
  373.         mov     dx,offset crlf
  374.         mov     ah,prstr
  375.         int     dos
  376.         pop     dx
  377.         pop     ax
  378. setupx: ret
  379.  
  380. ; Start recording of statistics for this operation. [jrd]
  381. begtim  proc    near
  382.         test    sflag,80h               ; is this a duplicate call?
  383.         jz      begtim1                 ; z = no
  384.         ret                             ; else just return
  385. begtim1:
  386.         push    ax
  387.         push    cx
  388.         push    dx
  389.         xor     ax,ax           ; clear statistics counters for this file
  390.         mov     fsta.prbyte,ax          ; bytes received from serial port
  391.         mov     fsta.prbyte+2,ax
  392.         mov     fsta.psbyte,ax          ; bytes sent out serial port
  393.         mov     fsta.psbyte+2,ax
  394.         mov     fsta.frbyte,ax          ; bytes received for this file
  395.         mov     fsta.frbyte+2,ax
  396.         mov     fsta.fsbyte,ax          ; bytes sent for this file
  397.         mov     fsta.fsbyte+2,ax
  398.         mov     fsta.prpkt,ax           ; packets received for this file
  399.         mov     fsta.prpkt+2,ax
  400.         mov     fsta.pspkt,ax           ; packets sent for this file
  401.         mov     fsta.pspkt+2,ax
  402.         mov     fsta.nakrcnt,ax         ; NAKs received for this file
  403.         mov     fsta.nakscnt,ax         ; NAKs sent for this file
  404.  
  405.         mov     ah,gettim               ; get DOS time of day
  406.         int     dos
  407.         xor     dl,dl                   ; clear .s part
  408.         xchg    dh,dl                   ; work with just seconds
  409.         mov     fsta.btime,dx           ; store ss
  410.         mov     al,ch                   ; get hours
  411.         and     al,3fh                  ; trim possible junk
  412.         xor     ah,ah
  413.         mul     sixty                   ; hours to min
  414.         add     al,cl                   ; add current minutes field
  415.         adc     ah,0                    ; number of minutes in hhmm
  416.         mul     sixty                   ; convert to minutes to seconds
  417.         add     ax,fsta.btime           ; add seconds field
  418.         adc     dx,0                    ; add carry out to high word
  419.         mov     fsta.btime,ax           ; store low word of seconds
  420.         mov     fsta.btime+2,dx         ; store high word of seconds
  421.         mov     sflag,80h               ; say begtim has been run
  422.         pop     dx
  423.         pop     cx
  424.         pop     ax
  425.         ret
  426. begtim  endp
  427.  
  428. ; Take snapshot of statistics counters at end of an operation.
  429. ; Enter with ax = 0 for a receive operation, ax = 1 for a send. [jrd]
  430. endtim  proc    near
  431.         test    sflag,80h       ; called more than once without calling begtim?
  432.         jnz     endtim1                 ; ne = no, so do statistics snapshot
  433.         ret                             ; yes, do nothing
  434. endtim1:and     sflag,not (1)           ; assume receive operation
  435.         or      ax,ax                   ; send (ax > 0), receive (ax = 0) flag
  436.         jz      endtim2                 ; z = receive opeation
  437.         or      sflag,1                 ; say send operation
  438. endtim2:
  439.         push    ax
  440.         push    cx
  441.         push    dx
  442.         mov     ah,gettim               ; get DOS time of day
  443.         int     dos
  444.         xor     dl,dl                   ; clear .s part
  445.         xchg    dh,dl                   ; work with just seconds
  446.         mov     fsta.etime,dx           ; store ss
  447.         mov     al,ch                   ; get hours
  448.         and     al,3fh                  ; trim possible junk
  449.         xor     ah,ah
  450.         mul     sixty                   ; hours to min
  451.         add     al,cl                   ; add current minutes field
  452.         adc     ah,0                    ; number of minutes in hhmm
  453.         mul     sixty                   ; convert to minutes to seconds
  454.         add     ax,fsta.etime           ; add seconds field
  455.         adc     dx,0                    ; add carry out to high word
  456.         mov     fsta.etime,ax           ; store low word of seconds
  457.         mov     fsta.etime+2,dx         ; store high word of seconds
  458.                                         ;
  459.         cmp     dx,fsta.btime+2         ; end time less than start time?
  460.         ja      endtim2a        ; a = above (no need to test low order word)
  461.         cmp     ax,fsta.btime           ; be. How about low order word
  462.         jae     endtim2a                ; ae = no wrap around of time
  463.         add     ax,20864        ; add 86400 sec. 20864 sec in lower 16 bits
  464.         adc     dx,1            ;   plus another 65536 to make one day.
  465. endtim2a:sub    ax,fsta.btime   ; subtract starting seconds from ending secs
  466.         sbb     dx,fsta.btime+2         ; high order word too
  467.         mov     fsta.etime,ax           ; store elapsed time, seconds, low wd
  468.         mov     fsta.etime+2,dx         ; high word
  469.         add     ssta.etime,ax           ; add to session time, low word
  470.         adc     ssta.etime+2,dx         ; add to session time, high word
  471.         mov     ax,fsta.prbyte          ; port bytes received for this file
  472.         add     ssta.prbyte,ax          ; port bytes received for this session
  473.         mov     ax,fsta.prbyte+2        ; high word
  474.         adc     ssta.prbyte+2,ax
  475.         mov     ax,fsta.psbyte  ; port bytes sent for this file, low word
  476.         add     ssta.psbyte,ax  ; port bytes sent for this session, low word
  477.         mov     ax,fsta.psbyte+2        ; high word
  478.         adc     ssta.psbyte+2,ax
  479.         test    sflag,1                 ; completing a receive operation?
  480.         jnz     endtim3                 ; nz = no, a send operation
  481.  
  482.         mov     ax,tfilsz+2             ; file bytes received, low word
  483.         mov     fsta.frbyte,ax
  484.         add     ssta.frbyte,ax          ; session received file bytes, low word
  485.         mov     ax,tfilsz               ; high word
  486.         mov     fsta.frbyte+2,ax
  487.         adc     ssta.frbyte+2,ax
  488.         jmp     short endtim4
  489.  
  490. endtim3:mov     ax,tfilsz+2             ; file bytes sent, low word
  491.         mov     fsta.fsbyte,ax          ; file bytes sent
  492.         add     ssta.fsbyte,ax          ; session sent file bytes, low word
  493.         mov     ax,tfilsz               ; high word
  494.         mov     fsta.fsbyte+2,ax
  495.         adc     ssta.fsbyte+2,ax
  496.  
  497. endtim4:mov     tfilsz,0                ; clear file size area
  498.         mov     tfilsz+2,0
  499.         mov     ax,fsta.prpkt           ; packets received for this file
  500.         add     ssta.prpkt,ax           ; session received packets
  501.         mov     ax,fsta.prpkt+2
  502.         adc     ssta.prpkt+2,ax
  503.         mov     ax,fsta.pspkt           ; packets sent for this file
  504.         add     ssta.pspkt,ax           ; session sent packets
  505.         mov     ax,fsta.pspkt+2
  506.         adc     ssta.pspkt+2,ax
  507.         mov     ax,fsta.nakrcnt         ; NAKs received for this file
  508.         add     ssta.nakrcnt,ax         ; session received NAKs
  509.         mov     ax,fsta.nakscnt         ; NAKs sent for this file
  510.         add     ssta.nakscnt,ax         ; session sent NAKs
  511.         mov     sflag,0                 ; say have done ending once already
  512.         pop     dx
  513.         pop     cx
  514.         pop     ax
  515.         ret
  516. endtim  endp
  517.  
  518. ; SHOW STATISTICS command. Displays last operation and session statistics.
  519. ; 9 March 1987 [jrd]
  520. shosta  proc    near                    ; show file transfer statistics
  521.         mov     ah,cmcfm                ; confirm with carriage return
  522.         call    comnd
  523.          jmp    r                       ; not confirmed
  524.          nop
  525.         call    endtim                  ; update statistics, just in case
  526.         push    ax
  527.         push    bx
  528.         push    cx
  529.         push    dx
  530.         mov     bx,offset fsta          ; pointer to file (Last op) statistics
  531.         mov     dx,offset lastmsg       ; totals for last transfer
  532.         mov     cx,2                    ; two sets to display
  533. shosta0:push    cx                      ; save loop counter
  534.         cmp     cx,2                    ; doing Last operation set?
  535.         je      shosta1                 ; e = yes
  536.         mov     bx,offset ssta          ; point to Session statistics area
  537.         mov     dx,offset sessmsg       ; totals for whole session
  538. shosta1:
  539.         mov     ah,prstr                ; display title line (dx is ptr)
  540.         int     dos
  541.         mov     ax,[bx].etime           ; elapsed time of operation
  542.         mov     dx,[bx].etime+2
  543.         call    lnout                   ; show elapsed time
  544.         mov     ah,prstr
  545.         mov     dx,offset pinmsg        ; port bytes received
  546.         int     dos
  547.         mov     ax,[bx].prbyte
  548.         mov     dx,[bx].prbyte+2
  549.         call    lnout                   ; convert and display long value
  550.         mov     ah,prstr
  551.         mov     dx,offset poutmsg       ; port bytes sent
  552.         int     dos
  553.         mov     ax,[bx].psbyte
  554.         mov     dx,[bx].psbyte+2
  555.         call    lnout
  556.         mov     ah,prstr
  557.         mov     dx,offset finmsg        ; file bytes received
  558.         int     dos
  559.         mov     ax,[bx].frbyte
  560.         mov     dx,[bx].frbyte+2
  561.         call    lnout
  562.         mov     ah,prstr
  563.         mov     dx,offset foutmsg       ; file bytes sent
  564.         int     dos
  565.         mov     ax,[bx].fsbyte
  566.         mov     dx,[bx].fsbyte+2
  567.         call    lnout
  568.         mov     ah,prstr
  569.         mov     dx,offset pkimsg        ; packets received
  570.         int     dos
  571.         mov     ax,[bx].prpkt
  572.         mov     dx,[bx].prpkt+2
  573.         call    lnout
  574.         mov     ah,prstr
  575.         mov     dx,offset pkomsg        ; packets sent
  576.         int     dos
  577.         mov     ax,[bx].pspkt
  578.         mov     dx,[bx].pspkt+2
  579.         call    lnout
  580.         mov     ah,prstr
  581.         mov     dx,offset nakimsg       ; naks received
  582.         int     dos
  583.         mov     ax,[bx].nakrcnt
  584.         xor     dx,dx
  585.         call    lnout
  586.         mov     ah,prstr
  587.         mov     dx,offset nakomsg       ; naks sent
  588.         int     dos
  589.         mov     ax,[bx].nakscnt
  590.         xor     dx,dx
  591.         call    lnout
  592.                 ; compute baud rate as  10 * total port bytes / elapsed time
  593.         mov     ah,prstr
  594.         mov     dx,offset baudmsg       ; effective baud rate
  595.         int     dos
  596.         mov     ax,[bx].prbyte          ; port bytes received, low
  597.         mov     dx,[bx].prbyte+2        ; port bytes received, high
  598.         add     ax,[bx].psbyte          ; port bytes sent, low
  599.         adc     dx,[bx].psbyte+2        ;  high. [dx,ax] = total port bytes
  600.  
  601.         mov     cx,[bx].etime           ; low word of sec in cx
  602.         cmp     [bx].etime+2,0  ; is high word of sec zero (e.t. < 65536 sec)?
  603.         jz      shosta3                 ; z = yes, ready for arithmetic
  604.         push    ax                      ; else scale values, save byte count
  605.         push    dx
  606.         mov     ax,[bx].etime           ; elapsed time for file, low word
  607.         mov     dx,[bx].etime+2         ;  high word
  608.         shr     ax,1                    ; divide seconds by two, low word
  609.         ror     dx,1                    ; get low bit of high word
  610.         and     dx,8000                 ; pick out just that bit
  611.         or      ax,dx           ; mask in that bit, new time in ax (dx = 0)
  612.         mov     cx,ax                   ; save elapsed time (double-seconds)
  613.         pop     dx                      ; get byte count again
  614.         pop     ax
  615.         shr     ax,1                    ; divide byte count by two also
  616.         push    dx
  617.         ror     dx,1                    ; rotate low bit to high position
  618.         and     dx,8000h                ; get low bit of high word
  619.         or      ax,dx                   ; byte count divided by two, low word
  620.         pop     dx
  621.         shr     dx,1                    ; and high word
  622. shosta3:or      cx,cx                  ; is elapsed time (in cx) zero seconds?
  623.         jnz     shosta4                 ; nz = no
  624.         inc     cx                      ; set time to one second (no div by 0)
  625. shosta4:div     cx                     ; bytes div seconds, ax = quo, dx = rem
  626.         push    dx                      ; save remainder of bytes/second
  627.         mul     ten                     ; quotient times ten to dx,ax
  628.         pop     dx                      ; discard overflow, recover remainder
  629.         push    ax                      ; save partial baud rate
  630.         xchg    ax,dx                   ; remainder to ax
  631.         xor     dx,dx                   ; clear extension
  632.         mul     ten             ; remainder times ten too (keep only overflow)
  633.         pop     ax                      ; recover main partial result
  634.         add     ax,dx                   ; add two partial results
  635.         xor     dx,dx                   ; clear extension ( < 65536 baud )
  636.         call    lnout
  637.         pop     cx                      ; recover loop counter
  638.         dec     cx
  639.         jcxz    shostax                 ; cx = 0 means we are done
  640.         jmp     shosta0         ; do next set of statistics (session stuff)
  641. shostax:
  642.         pop     dx
  643.         pop     cx
  644.         pop     bx
  645.         pop     ax
  646.         jmp     rskp
  647. shosta  endp
  648.  
  649. ; LNOUT - Table driven unsigned long integer (32 bit) display.
  650. ; Register dx holds high order word and ax holds low order word of unsigned
  651. ; long integer to be displayed in decimal.
  652. ; Table TENS holds set of double word values of ten raised to powers 0 to 9.
  653. ; TENSLEN holds the number of these double words.
  654. ; All registers preserved.      8 March 1987 [jrd]
  655. lnout   proc    near
  656.         push    ax
  657.         push    bx
  658.         push    cx
  659.         push    dx
  660.         push    di
  661.         xor     di,di           ; flag to say start printing (no leading 0's)
  662.         mov     cx,tenslen      ; number of table entries
  663. lnout1: push    cx              ; save loop counter
  664.         mov     bx,cx           ; index into tens double word table
  665.         dec     bx              ; index starts at zero
  666.         add     bx,bx
  667.         add     bx,bx           ; bx times four (double words to bytes)
  668.         xor     cx,cx           ; cx is now a counter of subtractions
  669.  
  670. lnout2: cmp     dx,word ptr tens[bx+2]  ; pattern 10**(bx/4), high order part
  671.         jb      lnout4          ; b = present number is less than pattern
  672.         ja      lnout3          ; a = present number is larger than pattern
  673.         cmp     ax,word ptr tens[bx] ; high words match, how about lows
  674.         jb      lnout4          ; b = present number is smaller than pattern
  675. lnout3: sub     ax,word ptr tens[bx]    ; subtract low order words
  676.         sbb     dx,word ptr tens[bx+2]  ; subtract high order words, w/borrow
  677.         inc     cx                      ; count number of subtractions
  678.         inc     di              ; flag to indicate printing needed
  679.         jmp     lnout2          ; try again to deduct present test pattern
  680.  
  681. lnout4: or      bx,bx           ; doing least significant digit?
  682.         jz      lnout5          ; z = yes, always print this one
  683.         or      di,di           ; should we print?
  684.         jz      lnout6          ; z = no, not yet
  685. lnout5: push    ax
  686.         push    dx
  687.         mov     ah,conout       ; put on console
  688.         mov     dl,cl           ; get number of subtractions
  689.         add     dl,'0'
  690.         int     dos             ; display it
  691.         pop     dx
  692.         pop     ax
  693. lnout6: pop     cx              ; recover loop counter
  694.         loop    lnout1
  695.         pop     di
  696.         pop     dx
  697.         pop     cx
  698.         pop     bx
  699.         pop     ax
  700.         ret
  701. lnout   endp
  702.  
  703. ;       Initialize buffers and clear line.
  704.  
  705. INIT    PROC    NEAR
  706.         mov     hierr,0                 ; clear high-bit-seen flag
  707.         test    flags.remflg,dquiet     ; quiet display mode?
  708.         jnz     init3                   ; nz = yes
  709.         test    flags.remflg,dserial    ; serial mode display?
  710.         jnz     init2                   ; nz = yes
  711.         call    cmblnk
  712.         mov     dx,offset cxzhlp
  713.         call    putmod                  ; write mode line
  714.         call    locate
  715.         mov     fmtdsp,1                ; say doing formatted display
  716.         mov     ah,prstr                ; Put statistics headers on the screen
  717.         mov     dx,offset outlin
  718.         int     dos
  719.         mov     wrpmsg,0                ; haven't printed the messsage yet.
  720.         mov     prepksz,0               ; set previous packet size to zero
  721.         ret
  722. init2:  mov     ah,prstr                ; print string
  723.         mov     dx,offset cxzser        ; status line as a text string
  724.         int     dos
  725. init3:  mov     wrpmsg,1                ; supress display of percentage message
  726.         mov     fmtdsp,0                ; say doing unformatted display
  727.         ret
  728. INIT    ENDP
  729.  
  730.  
  731. ;       Output the chars in a packet.
  732.  
  733. ; Called with AX = size of the data, BX = address of source.
  734.  
  735. FILEIO  PROC    NEAR
  736.  
  737. ptchr:  mov     cx,ax
  738.         mov     ax,offset outbuf       ; routine to call when buffer gets full
  739.         mov     chrcnt,maxpack          ; size of buffer Data
  740.         mov     bufpnt,offset decbuf ; decoded data placed here pending output
  741.         mov     bx,offset data          ; source of data
  742.         jmp     short decode
  743.  
  744.  
  745. ; CX = Size of data, BX = Address of data, AX = Routine to call to
  746. ; dump data.
  747.  
  748. decode: push    si
  749.         push    di
  750.         push    es
  751.         push    dx
  752.         push    ax
  753.         mov     ax,ds
  754.         mov     es,ax
  755.         pop     ax
  756.         mov     si,bx                   ; Source of data.
  757.         mov     bx,ax                   ; Coroutine to call.
  758.         mov     di,bufpnt               ; Destination of data.
  759.         mov     dh,0                    ; assume no quote char
  760.         cmp     trans.ebquot,'N'        ; no quoting?
  761.         je      decod1                  ; yes, keep going
  762.         cmp     trans.ebquot,'Y'        ; or not doing it?
  763.         je      decod1                  ; yes, keep going
  764.         mov     dh,trans.ebquot         ; otherwise use quote char
  765.  
  766. decod1: mov     rptct,0                 ; Reset.
  767.         mov     rptval,0                ; Ditto.
  768.         cmp     cx,0                    ; any more chars in source?
  769.         jg      dcod11                  ; g = yes
  770.         jmp     decod6                  ; Else, we're through.
  771. dcod11: cmp     chrcnt,0                ; any space left in output buffer?
  772.         jg      decod2                  ; g = yes, continue filling
  773.         push    cx
  774.         push    dx
  775.         push    bx
  776.         call    bx                      ; Output it if full.
  777.          jmp    decod5                  ;  Error return if disk is full.
  778.          nop
  779.         pop     bx
  780.         pop     dx
  781.         pop     cx
  782.         mov     di,bufpnt
  783. decod2: cmp     rptct,0                 ; Doing a repeat?
  784.         je      dcod20                  ; No, so go get a character.
  785.         mov     ah,0
  786.         mov     al,rptval               ; Get the character we're repeating.
  787.         jmp     decod4                  ; And write it out to the file.
  788. dcod20: cld                             ; forward direction
  789.         lodsb                           ; Pick up a char.
  790.         dec     cx                      ; count number left
  791.         cmp     rptq,0                  ; Doing repeat quoting?
  792.         je      dcod21                  ; Nope, skip this part.
  793.         cmp     al,rptq                 ; Did we pick up the repeat quote char?
  794.         jne     dcod21                  ; No, continue processing it.
  795.         lodsb                           ; Get the size.
  796.         dec     cx                      ; Modify buffer count.
  797.         sub     al,20H                  ; Was made printable.
  798.         mov     rptct,al                ; Remember how many repetitions.
  799.         lodsb                           ; Get the char to repeat.
  800.         dec     cx                      ; Modify buffer count.
  801. dcod21: mov     ah,00H                  ; Assume no 8-bit quote char.
  802.         cmp     al,dh                   ; This the 8-bit quot char?
  803.         jne     decod3
  804.         lodsb                           ; Get the real character.
  805.         dec     cx                      ; Decrement # chars in packet
  806.         mov     ah,80H                  ; Turn on 8-bit quot char flag.
  807. decod3: cmp     al,trans.squote         ; Is it the quote char?
  808.         jne     decod4                  ; If not proceed.
  809.         lodsb                           ; Get the quoted character
  810.         dec     cx                      ; Decrement # of chars in packet.
  811.         or      ah,al                   ; save parity (combine with prefix)
  812.         and     ah,80h                  ; only parity
  813.         and     al,7FH                  ; Turn off the parity bit.
  814.         cmp     al,trans.squote         ; Is it the quote char?
  815.         je      decod4                  ; If so just go write it out.
  816.         cmp     al,dh                   ; This the 8-bit quot char?
  817.         je      decod4                  ; If so, just go write it out
  818.         cmp     al,rptq                 ; Is is the repeat quote character?
  819.         je      decod4                  ; If so, just write it out.
  820.                                         ; fix bug in unquoting chars
  821.         cmp     al,3fh                  ; char less than '?' ?
  822.         jl      decod4                  ; l = yes; leave it intact
  823.         cmp     al,5fh                  ; char greater than '_' ?
  824.         jg      decod4                  ; g = yes; leave it alone
  825.         add     al,40H                  ; Make it a control char again.
  826.         and     al,7FH                  ; Modulo 128.
  827. decod4: or      al,ah                   ; or in parity
  828.         stosb                           ; store the character
  829.         dec     chrcnt                  ; Decrement number of chars in dta.
  830.         dec     rptct                   ; Repeat counter.
  831.         cmp     rptct,0                 ; Write out char again?
  832.         jg      dcod41
  833.         jmp     decod1                  ; No, get next char.
  834. dcod41: mov     rptval,al               ; Save the char.
  835.         jmp     dcod11                  ; and loop to next char.
  836. decod5: pop     bx
  837.         pop     dx                      ; dx is pushed twice (really)
  838.         pop     cx
  839.         pop     dx
  840.         pop     es
  841.         pop     di
  842.         pop     si
  843.         ret
  844. decod6: mov     bufpnt,di               ; store address for next output char
  845.         push    cx
  846.         push    dx
  847.         push    bx
  848.         call    bx                      ; flush output buffer before final ret
  849.          jmp    decod5                  ;  Error return if disk is full.
  850.          nop
  851.         pop     bx
  852.         pop     dx
  853.         pop     cx
  854.  
  855.         pop     dx
  856.         pop     es
  857.         pop     di
  858.         pop     si
  859.         jmp     rskp                    ; Return successfully if done.
  860.  
  861.                                 ; output the buffer, reset bufpnt and chrcnt
  862.  
  863. outbuf: cmp     flags.xflg,1            ; Writing to screen?
  864.         jne     outbu0
  865.         jmp     outbf2                  ; Yes, handle specially
  866. outbu0:
  867.         mov     cx,maxpack              ; get full size of buffer
  868.         sub     cx,chrcnt               ; minus space remaining = # to write
  869.         jc      outbf0                  ; c = bad buffer pointers
  870.         jcxz    outb11                  ; cx = 0 means nothing to do
  871.         push    bx
  872.         mov     dx,offset decbuf        ; address of buffer
  873.         mov     bx,diskio.handle        ; file handle
  874.         mov     ah,write2               ; DOS 2.0 write
  875.         int     dos                     ; Write the record.
  876.         pop     bx
  877.         jc      outbf0                  ; c set means disk writing error
  878.         cmp     ax,cx                   ; did we write all the bytes?
  879.         je      outbf1                  ; e = yes
  880.         call    erpos                   ; no
  881.         mov     ah,prstr                ; Tell about it.
  882.         mov     dx,offset erms11        ; Disk full error.
  883.         cmp     flags.destflg,0         ; writing to printer?
  884.         jne     outbu0a                 ; ne = no
  885.         mov     dx,offset ermes9        ; Printer not ready message
  886. outbu0a:int     dos
  887.         jmp     abfil                   ; Fix things up before aborting
  888.  
  889. outbf0: call    erpos
  890.         mov     ah,prstr                ; Tell about it.
  891.         mov     dx,offset erms13        ; Disk writing error.
  892.         cmp     flags.destflg,0         ; writing to printer?
  893.         jne     outbf0a                 ; ne = no
  894.         mov     dx,offset ermes9        ; Printer not ready message
  895. outbf0a:int     dos
  896.         jmp     abfil                   ; Fix things up before aborting
  897.  
  898. outbf1: add     tfilsz+2,cx             ; count received chars
  899.         adc     tfilsz,0
  900.         test    flags.remflg,dserial    ; serial mode display?
  901.         jnz     outb11          ; nz = yes, skip kbyte and % displays
  902.         call    kbpr                    ; Print the kilobytes received.
  903.         call    perpr                   ; Print the percent
  904. outb11: mov     bufpnt,offset decbuf    ; Addr for beginning.
  905.         mov     chrcnt,maxpack          ; size of empty buffer
  906.         jmp     rskp
  907.  
  908. outbf2:                                 ; writing to screen
  909.         mov     cx,maxpack              ; size of full buffer
  910.         sub     cx,chrcnt               ; minus # of unused in buffer
  911.         jle     outb11                  ; none to print, don't try
  912.         mov     di,offset decbuf        ; Where they are.
  913.         call    prtscr                  ; Output buffer to screen
  914.         jmp     outb11                  ; Reset counter & pointer
  915.  
  916. ;  Tidy up before aborting. Retidied by [jrd]
  917. ABFIL   PROC    NEAR
  918.         cmp     flags.xflg,1            ; Writing to screen?
  919.         je      abfil1                  ; Yes don't delete "file".
  920.         mov     bx,diskio.handle        ; get file handle
  921.         mov     ah,close2               ; DOS 2.0 file close
  922.         int     dos
  923.         cmp     flags.abfflg,1          ; Delete what got across or keep it?
  924.         jne     abfil1                  ; Nope, keep it.
  925.         push    dx
  926.         mov     dx,offset diskio.string ; the full file name
  927.         mov     ah,del2                 ; DOS 2.0 file delete
  928.         int     dos
  929.         pop     dx
  930. abfil1: mov     bx,offset erms10        ; Text of message to send.
  931.         call    errpack                 ; Send an error packet.
  932.         ret
  933. ABFIL   ENDP
  934.  
  935. ; General routine for sending an error packet.  Register BX should
  936. ; point to the text of the message being sent in the packet.
  937.  
  938. ERRPACK PROC    NEAR
  939.         push    di
  940.         mov     di,offset data          ; Where to put the message.
  941.         mov     al,0
  942. errp1:  mov     ah,[bx]
  943.         cmp     ah,'$'                  ; At end of message?
  944.         je      errp2
  945.         inc     al                      ; Remember number of chars in msg.
  946.         mov     [di],ah
  947.         inc     bx
  948.         inc     di
  949.         jmp     errp1
  950. errp2:  pop     di
  951.         mov     ah,0
  952.         mov     pack.argbk1,ax
  953.         mov     ah,'E'                  ; And send an error packet.
  954.         call    spack
  955.          nop                            ; Return if succeed or fail.
  956.          nop
  957.          nop
  958.         ret
  959. ERRPACK ENDP
  960.  
  961. ;       Get the chars from the file.
  962.  
  963. gtchr:  cmp     flags.filflg,0          ; Is there anything in the DMA?
  964.         jz      gtchr0                  ; Yup, proceed.
  965.         mov     ah,rptq
  966.         mov     origr,ah                ; Save repeat prefix here.
  967.         mov     rptct,1                 ; Number of times char is repeated.
  968.         mov     rptval,0                ; Value of repeated char.
  969.         call    inbuf
  970.          jmp    gtchr1                  ; No more chars, go return EOF.
  971.          nop                            ; Make  three bytes long.
  972. gtchr0: mov     bx,offset inbuf
  973.         jmp     encode
  974. gtchr1: mov     ax,0ffffh
  975.         ret
  976.  
  977. ; encode - writes data portion of kermit packet into filbuf.
  978. ; expects BX to contain the address of a routine to refill the buffer,
  979. ; chrcnt to be the # of chars in the buffer, trans.maxdat to contain
  980. ; the maximum size of the data packet, bufpnt to contain a pointer to
  981. ; the source of the characters.
  982. ; Returns: AX/ the number of characters actually written to the buffer.
  983.  
  984. encode: mov     cx,trans.maxdat         ; Maximum packet size
  985.         push    ds
  986.         pop     es                      ; make es:di point to datas segment
  987.         mov     di,offset filbuf        ; Where to put the data.
  988.         mov     si,bufpnt               ; pointer into source buffer
  989.         mov     dl,trans.rquote         ; send quote char
  990.         mov     dh,0                    ; assume no 8-bit quoting
  991.         cmp     trans.ebquot,'N'        ; not doing 8-bit quoting
  992.         je      encod1
  993.         cmp     trans.ebquot,'Y'        ; or can but won't?
  994.         je      encod1
  995.         mov     dh,0ffh                 ; remember we have to do it
  996. encod1: cmp     cx,0                    ; any space left in output buffer?
  997.         jg      encod2                  ; g = yes
  998.         sub     di,offset filbuf
  999.         mov     ax,di
  1000.         mov     bufpnt,si               ; update pointer into DMA.
  1001.         jmp     rskp
  1002. encod2: cmp     chrcnt,0                ; Any data in buffer?
  1003.         jg      encod3                  ; yes, skip over buffer refill.
  1004.         call    bx                      ; Get another buffer full.
  1005.          jmp    encod8
  1006.         mov     si,bufpnt               ; update position in DMA.
  1007.         cmp     chrcnt,0                ; no characters returned?
  1008.         jne     encod3                  ; Got some, keep going.
  1009.         jmp     encod8                  ; none, assume eof.
  1010. encod3: dec     chrcnt                  ; Decrement input count.
  1011.         cld                             ; forward direction
  1012.         lodsb
  1013.         cmp     flags.eofcz,0           ; Is a control-z an end of file?
  1014.         je      encd30                  ; No, don't have to look for one.
  1015.         cmp     al,'Z'-40H              ; Is this a control-Z?
  1016.         jne     encd30                  ; No, skip eof-processing
  1017.         mov     flags.eoflag,0FFH       ; Yes, set eof flag
  1018.         mov     flags.filflg,0FFH       ; No more input in buffer
  1019.         mov     chrcnt,0                ; Ditto
  1020.         jmp     encod8                  ; Go set character count and return
  1021. encd30: cmp     rptq,0                  ; Are we doing repeat prefixing?
  1022.         je      encd3x                  ; Nope, skip next part.
  1023.         cmp     chrcnt,0                ; Are we on the last character?
  1024.         jle     encd31                  ; Yes, so there's no next character.
  1025.         cmp     rptct,94                ; Max number that we can put in a byte.
  1026.         je      encd31                  ; Then that's it.
  1027.         mov     ah,[si]                 ; Get the next character.
  1028.         cmp     al,ah                   ; Is current char == next char?
  1029.         jne     encd31
  1030.         inc     rptct                   ; Number of times char appears.
  1031.         mov     rptval,al               ; Remember the character.
  1032.         jmp     encod1                  ; Keep checking for more.
  1033. encd31: cmp     rptct,1                 ; Were previous characters repeats?
  1034.         je      encd3x                  ; No, so just add this char.
  1035.         cmp     rptct,rptmin    ; Are we within bounds for repeat prefixing?
  1036.         jge     encd32                  ; Yes, use repeat prefixing.
  1037.         mov     al,rptct
  1038.         mov     ah,0
  1039.         sub     si,ax                   ; Not enough characters to warrant it.
  1040.         mov     rptval,0                ; Clear out this value.
  1041.         mov     al,rptq
  1042.         mov     origr,al                ; Save original repeat prefix.
  1043.         mov     rptq,0                  ; Pretend we're not doing prefixing
  1044.         mov     al,rptct
  1045.         mov     ah,0
  1046.         add     chrcnt,ax               ; Adjust input buffer pointer.
  1047.         jmp     encod1                  ; Reprocess those characters.
  1048. encd32: push    ax                      ; Do repeat prefixing - save data.
  1049.         mov     al,rptq                 ; Add repeat prefix char.
  1050.         stosb
  1051.         dec     cx                      ; Account for it in buffer size.
  1052.         mov     al,rptct                ; Get the repeat count.
  1053.         add     al,20H                  ; Make it printable.
  1054.         stosb                           ; Add to buffer.
  1055.         dec     cx
  1056.         pop     ax                      ; Get back the actual character.
  1057.         mov     rptct,1                 ; Reset repeat count.
  1058.         mov     rptval,0                ; And this.
  1059. encd3x: cmp     dh,0                    ; are we doing 8-bit quoting?
  1060.         je      encod4                  ; no, forget this.
  1061.         test    al,80h                  ; parity on?
  1062.         je      encod4                  ; no, don't bother with this
  1063.         and     al,7fh                  ; turn off parity
  1064.         push    ax                      ; save original char for a bit
  1065.         dec     cx                      ; decrement # of chars left
  1066.         mov     al,trans.ebquot         ; get quote char
  1067.         stosb                           ; save  in buffer
  1068.         pop     ax                      ; restore character
  1069. encod4: mov     ah,al                   ; save character
  1070.         and     ah,80h                  ; only parity
  1071.         and     al,7fh                  ; turn off parity in character
  1072.         cmp     al,' '                  ; Compare to a space.
  1073.         jl      encod5                  ; If less then its a control char.
  1074.         cmp     al,del                  ; Is the char a delete?
  1075.         jz      encod5                  ; Go quote it.
  1076.         cmp     al,dl                   ; Is it the quote char?
  1077.         je      encod6                  ; Yes - go add it
  1078.         cmp     dh,0                    ; are we doing 8-bit quoting?
  1079.         je      encd41                  ; no, don't translate it
  1080.         cmp     al,trans.ebquot         ; Is it the 8-bit quote char?
  1081.         je      encod6                  ; Yes, just output with quote
  1082. encd41: cmp     origr,0                 ; Doing repeat prefixing?
  1083.         je      encod7                  ; No, don't check for quote char.
  1084.         cmp     al,origr                ; Is this the repeat quote character.
  1085.         je      encod6                  ; Yes, then quote it.
  1086.         jmp     short encod7            ; else don't quote it.
  1087. encod5: add     al,40h                  ; control char, uncontrollify
  1088.         and     al,7fh
  1089. encod6: push    ax                      ; save the char
  1090.         dec     cx
  1091.         mov     al,dl
  1092.         stosb
  1093.         pop     ax
  1094. encod7: or      al,ah                   ; put parity back
  1095.         stosb
  1096.         dec     cx                      ; Decrement output buffer counter.
  1097.         cmp     rptct,1                 ; One occurence of this char?
  1098.         jne     encd7x
  1099.         mov     al,origr
  1100.         mov     rptq,al                 ; Restore repeat quote char.
  1101.         jmp     encod1                  ; Yes, so loop around for some more.
  1102. encd7x: dec     rptct                   ; Add another entry of this char.
  1103.         jmp     encod1                  ; With quoting and all.
  1104.  
  1105. encod8: sub     di,offset filbuf
  1106.         or      di,di
  1107.         je      encod9                  ; Nope.
  1108.         mov     ax,di
  1109.         jmp     rskp
  1110. encod9: mov     ax,0FFFFH               ; Get a minus one.
  1111.         ret
  1112.  
  1113.  
  1114. inbuf:  cmp     flags.eoflag,0          ; Have we reached the end?
  1115.         jz      inbuf0
  1116.         ret                             ; Return if set.
  1117. inbuf0: push    si
  1118.         push    di
  1119.         push    dx
  1120.         push    bx
  1121.         push    cx
  1122.         mov     bx,offset buff          ; Set the r/w buffer pointer.
  1123.         mov     bufpnt,bx
  1124.         mov     bx,diskio.handle        ; get file handle
  1125.         mov     cx,buffsz               ; record size
  1126.         mov     dx,bufpnt               ; buffer address
  1127.         mov     ah,readf2               ; DOS 2.0 read a record
  1128.         int     dos
  1129.         jc      inbuf1                  ; c = error, ie file not open
  1130.         or      ax,ax                   ; any bytes read?
  1131.         jne     inbuf2                  ; ne = yes (the number read)
  1132. inbuf1: mov     flags.eoflag,0FFH       ; Set End-of-file
  1133.         mov     flags.filflg,0ffh       ; Buffer empty
  1134.         mov     chrcnt,0                ; zero bytes left in buffer
  1135.         pop     cx
  1136.         pop     bx
  1137.         pop     dx
  1138.         pop     di
  1139.         pop     si
  1140.         ret
  1141. inbuf2: add     tfilsz+2,ax             ; total the # bytes transferred so far
  1142.         adc     tfilsz,0                ; it's a double word
  1143.         mov     chrcnt,ax               ; Number of chars read from file.
  1144.         mov     flags.filflg,0          ; Buffer not empty.
  1145.         test    flags.remflg,dserial    ; serial display mode?
  1146.         jnz     inbuf3                  ; nz = yes, skip kbyte and % display
  1147.         push    ax
  1148.         call    kbpr                    ; Print the kilobytes sent.
  1149.         call    perpr                   ; Print the percent sent.
  1150.         pop     ax
  1151. inbuf3: pop     cx
  1152.         pop     bx
  1153.         pop     dx
  1154.         pop     di
  1155.         pop     si
  1156.         jmp     rskp
  1157.  
  1158. nulref: mov     chrcnt,0                ; No data to return.
  1159.         jmp     rskp
  1160.  
  1161. nulr:   ret                             ; dummy buffer emptier
  1162.  
  1163. ; Print the number of Kilobytes transferred.
  1164.  
  1165. kbpr:   test    flags.remflg,dquiet     ; quiet display mode?
  1166.         jnz     kbpr1                   ; nz = yes, no printing.
  1167.         push    bx
  1168.         mov     ax,tfilsz+2             ; low order word
  1169.         mov     bx,tfilsz               ; high order word
  1170.         mov     al,ah                   ; divide double word by 1024, in steps
  1171.         mov     ah,bl
  1172.         shr     ax,1
  1173.         shr     ax,1
  1174.         ror     bh,1
  1175.         ror     bh,1
  1176.         and     bh,not (3fh)
  1177.         or      ah,bh                   ; ax has the result
  1178.         pop     bx
  1179.         cmp     ax,oldkbt               ; is it the same?
  1180.         je      kbpr1                   ; yes, skip printing
  1181.         mov     oldkbt,ax               ; save new # of kb
  1182.         push    ax
  1183.         call    kbpos                   ; Postion the cursor.
  1184.         pop     ax
  1185.         call    decout                  ; Print number of KBytes transferred
  1186. kbpr1:  ret
  1187.  
  1188.  
  1189. ; Print the percent transferred.
  1190.  
  1191. perpr:  test    flags.remflg,dquiet     ; quiet display mode?
  1192.         jz      perpr1                  ; z = no. allow printing.
  1193.         ret                             ; skip printing in remote mode
  1194. perpr1: cmp     ofilsz,0                ; high word of original file size > 0 ?
  1195.         jne     perpr3                  ; ne = yes, use big file code.
  1196.         cmp     ofilsz+2,0              ; anything here at all?
  1197.         jne     perpr2                  ; ne = yes, use small file code.
  1198.         ret                             ; otherwise, quit now.
  1199. perpr2: push    dx                      ; case for files < 64 Kb.
  1200.         mov     ax,ofilsz+2             ; original size (low word)
  1201.         mov     denom,ax
  1202.         mov     dx,tfilsz               ;transferred size times 256 in [dx,ax]
  1203.         mov     ax,tfilsz+2
  1204.         mov     dh,dl                   ; whole value multiplied by 256
  1205.         mov     dl,ah
  1206.         mov     ah,al
  1207.         mov     al,0
  1208.         div     denom                   ; (256*xfer)/orig. ax = quo, dx = rem
  1209.         mul     onehun                  ; multiply quotient above by 100
  1210.         mov     al,ah                   ; divide result (ax) by 256
  1211.         mov     ah,0                    ; percentage is in ax
  1212.         jmp     perpr4                  ; finish in common code
  1213. perpr3: push    dx                      ; case for file size > 64 KB.
  1214.         mov     ax,ofilsz+2             ; original file size low order word
  1215.         shr     ax,1                    ; divide by 2
  1216.         mov     al,ah                   ; divide again by 256 for total of 512
  1217.         mov     ah,0                    ; clear ah
  1218.         mov     dx,ofilsz               ; high order word
  1219.         xchg    dh,dl                   ; do shl dx,cl=7
  1220.         ror     dx,1                    ; old low bit of dh to high bit of dh
  1221.         and     dl,80h                  ; clear lower bits. divided by two
  1222.         or      ax,dx                   ; paste together the two parts into ax
  1223.         mov     denom,ax                ; denom = original size divided by 512
  1224.         mov     dx,tfilsz               ; high order word of transferred size
  1225.         mov     ax,tfilsz+2             ; low order word
  1226.         div     denom                   ; xfer/(512*orig). ax=quot, dx=rem
  1227.         mul     onehun                  ; times 100 for 512*percentage, in ax
  1228.         mov     al,ah                   ; divide ax by 512
  1229.         mov     ah,0
  1230.         shr     ax,1                    ; final percentage, in ax
  1231. perpr4: pop     dx
  1232.         cmp     ax,oldper               ; same as it was before?
  1233.         je      perpr7                  ; yes, don't bother printing.
  1234.         mov     oldper,ax               ; remember this for next time
  1235.         cmp     wrpmsg,0                ; did we write the percentage message?
  1236.         jne     perpr5                  ; yes, skip this part
  1237.         push    ax
  1238.         call    perpos                  ; position cursor
  1239.         mov     dx,offset permsg
  1240.         mov     ah,prstr
  1241.         int     dos                     ; write out message
  1242.         pop     ax
  1243.         mov     wrpmsg,1                ; init flag so we don't do it again
  1244. perpr5: push    ax
  1245.         call    perpos                  ; Position the cursor.
  1246.         pop     ax
  1247.         cmp     ax,onehun               ; > 100% ?
  1248.         jle     perpr6                  ; no, accept it
  1249.         mov     ax,onehun               ; else just use 100
  1250. perpr6: call    decout
  1251.         mov     dl,25h                  ; Load a percent sign.
  1252.         mov     ah,conout               ; Print the character.
  1253.         int     dos
  1254. perpr7: ret
  1255.                                 ; GETFIL, called only by send code
  1256. getfil: mov     flags.filflg,0ffh       ; Say nothing is in the buffer.
  1257.         mov     flags.eoflag,0          ; Not the end of file.
  1258.         mov     dx,offset diskio.dta    ; data transfer address
  1259.         mov     ah,setdma               ; set disk transfer address
  1260.         int     dos                     ; do it
  1261.         mov     cx,0                    ; attributes: find only normal files
  1262.         mov     dx,offset diskio.string ; filename string (may have wild cards)
  1263.         mov     ah,first2               ; DOS 2.0 search for first
  1264.         int     dos                     ; get file's characteristics
  1265.         pushf                           ; save c flag
  1266.         mov     ah,setdma               ; reset dta address
  1267.         mov     dx,offset buff          ; restore dta
  1268.         int     dos
  1269.         popf                            ; restore status of search for first
  1270.         jnc     getfi1                  ; nc = ok so far
  1271.         ret                             ; else take error exit
  1272. getfi1:
  1273.         mov     dx,offset diskio.string ; original file spec (may be wild)
  1274.         mov     di,offset templp        ; place for path part
  1275.         mov     si,offset templf        ; place for filename part
  1276.         call    fparse                  ; split them
  1277.         mov     si,offset diskio.fname  ; current filename from DOS
  1278.         call    strcat                  ; local path + diskio.fname
  1279.         mov     si,di                   ; make it a source
  1280.         mov     di,offset diskio.string ; new destination
  1281.         call    strcpy                ; new string = old path + DOS's filename
  1282.         mov     ah,open2                ; DOS 2.0 file open
  1283.         mov     al,0                    ; open readonly
  1284.         mov     dx,offset diskio.string ; filename string
  1285.         int     dos
  1286.         jnc     getfi2                  ; nc = opened the file
  1287.         ret                             ; else take error return
  1288. getfi2: mov     diskio.handle,ax        ; save file handle
  1289.         mov     ax,diskio.sizehi        ; get file size (high order word)
  1290.         mov     ofilsz,ax               ; new form
  1291.         mov     ax,diskio.sizelo        ; low order word
  1292.         mov     ofilsz+2,ax             ; new form
  1293.         mov     tfilsz,0                ; Set bytes sent to zero.
  1294.         mov     tfilsz+2,0
  1295.         mov     oldkbt,-1
  1296.         mov     oldper,-1
  1297.         cmp     ofilsz,0                ; Null file?
  1298.         jne     getfl0                  ; Nope.
  1299.         cmp     ofilsz+2,0              ; Null file?
  1300.         jne     getfl0                  ; Nope.
  1301.         mov     flags.eoflag,0FFH       ; yes. Set EOF.
  1302. getfl0: jmp     rskp
  1303.  
  1304. ; GTNFIL called by send code to get next file. Rewritten by [jrd]
  1305.  
  1306. gtnfil: cmp     flags.cxzflg,'Z'        ; Did we have a ^Z?
  1307.         jne     gtn1                    ; ne = no, else done sending files
  1308.         ret                             ; take failure exit
  1309.  
  1310. gtn1:   mov     flags.filflg,0ffh       ; Nothing in the DMA.
  1311.         mov     flags.eoflag,0          ; Not the end of file.
  1312.         mov     dx,offset diskio.dta    ; point at dta
  1313.         mov     ah,setdma               ; set the dta address
  1314.         int     dos
  1315.         mov     ah,next2                ; DOS 2.0 search for next
  1316.         int     dos
  1317.         pushf                           ; save carry flag
  1318.         mov     ah,setdma               ; restore dta
  1319.         mov     dx,offset buff
  1320.         int     dos
  1321.         popf                            ; recover carry flag
  1322.         jc  gtn4                        ; carry set means no more files found
  1323.         mov     di,offset templp        ; place for path part
  1324.         mov     si,offset templf        ; place for filename part
  1325.         mov     dx,offset diskio.string ; current full filename
  1326.         call    fparse                  ; split them
  1327.         mov     si,offset diskio.fname  ; new filename part from DOS
  1328.         call    strcat                  ; rejoin path and new filename
  1329.         mov     si,di                   ; new source
  1330.         mov     di,offset diskio.string ; place for whole new name
  1331.         call    strcpy                  ; copy new string
  1332.         mov     dx,offset diskio.string ; address of new string
  1333.         mov     ah,open2                ; DOS 2.0 file open
  1334.         mov     al,0                    ; open readonly
  1335.         int     dos
  1336.         jc      gtn4                    ; c = could not open the file
  1337.  
  1338.         mov     diskio.handle,ax        ; save file handle
  1339.         mov     ax,diskio.sizehi        ; get file size (high order word)
  1340.         mov     ofilsz,ax               ; save as original file size
  1341.         mov     ax,diskio.sizelo        ; low order word
  1342.         mov     ofilsz+2,ax
  1343.         mov     tfilsz,0                ; Set bytes sent to zero.
  1344.         mov     tfilsz+2,0
  1345.         mov     oldkbt,-1
  1346.         mov     oldper,-1
  1347.         cmp     ofilsz,0                ; Null file?
  1348.         jne     gtn2                    ; Nope.
  1349.         cmp     ofilsz+2,0              ; Null file?
  1350.         jne     gtn2                    ; Nope.
  1351.         mov     flags.eoflag,0FFH       ; Set EOF.
  1352. gtn2:   jmp     rskp                    ; set success condition
  1353. gtn4:   ret                             ; set failure condition
  1354.  
  1355.  
  1356. ; Get the file name from the data portion of the F packet or from locally
  1357. ; specified override filename (in locfil).
  1358. ; prints the filename, handles any manipulation of the filename
  1359. ; necessary, including changing the name to prevent collisions.
  1360. ; Called by READ (receive a file, at rfil32).
  1361.  
  1362. gofil:  cmp     flags.xflg,0    ; Receiving to screen? (X rather than F)
  1363.         je      gofil1                  ; e = no
  1364.         jmp     gofi20                  ; Yes. so skip this stuff.
  1365. gofil0: cmp     flags.destflg,2         ; file destination = screen?
  1366.         jne     gofil1                  ; ne = no
  1367.         jmp     gofi20                  ; yes
  1368. gofil1: mov     byte ptr diskio.string,0 ; clear final filename
  1369.         test    flags.remflg,dquiet     ; quiet display mode?
  1370.         jnz     gofi1c                  ; nz = yes, don't display filename
  1371.         call    prtfn                   ; display the packet's filename
  1372. gofi1c: cmp     flags.destflg,0         ; writing to printer?
  1373.         jne     gofi1a                  ; ne = no, go on
  1374.         mov     ax,offset printer       ; this is filename now
  1375.         jmp     gofi17                  ; and do it directly
  1376. gofi1a: mov     flags.nmoflg,0          ; assume no override name
  1377.         cmp     byte ptr locfil,0       ; overriding name from other side?
  1378.         jne     gofi1e                  ; ne = yes.
  1379.         jmp     gofil4                  ; e = No. get the other end's filename
  1380. gofi1e: mov     flags.nmoflg,0ffh       ; say using an override name
  1381.         mov     ax,offset locfil        ; get local override filename
  1382.         cmp     word ptr locfil+1,003ah ; colon+null?(primative drive spec A:)
  1383.         je      gofil3          ; e = yes, skip screwy DOS response (No Path)
  1384. gofi1e1:call    isfile                  ; does it exist?
  1385.         jnc     gofi1f                  ; nc = file exists
  1386.         test    filtst.fstat,80h        ; serious error?
  1387.         jz      gofil3                  ; z = no, just no such file
  1388.         jmp     gofi18a                 ; else quit here.
  1389. gofi1f: test    byte ptr filtst.dta+21,10H      ; subdirectory name?
  1390.         jnz     gofi1b                  ; nz = yes
  1391.         cmp     byte ptr locfil+2,5ch ; could it be a root directory like b:\?
  1392.         jne     gofi1d              ; ne = no. (DOS is not helpful with roots)
  1393.         cmp     byte ptr locfil+3,0     ; and is it terminated in a null?
  1394.         je      gofi1b                  ; e = yes, so it is a root spec.
  1395. gofi1d: test    byte ptr filtst.dta+21,0fh   ; r/o, hidden, system, vol label?
  1396.         jz      gofil3                  ; z = no
  1397.         jmp     gofi18a                ; yes. Complain and don't transfer file
  1398. gofi1b: mov     dx,offset locfil        ; locfil is a subdirectory name
  1399.         call    strlen                  ; get its length w/o terminator
  1400.         jcxz    gofil2                  ; zero length
  1401.         dec     cx                      ; examine last char
  1402.         push    bx                      ; save bx
  1403.         mov     bx,cx
  1404.         add     bx,dx
  1405.         cmp     byte ptr [bx],5ch       ; ends in backslash?
  1406.         je      gofil2                  ; e = yes
  1407.         cmp     byte ptr [bx],2fh       ; maybe forward slash?
  1408.         je      gofil2                  ; e = yes
  1409.         mov     byte ptr [bx + 1],5ch   ; no slash yet. use backslash
  1410.         mov     byte ptr [bx + 2],0     ; plant new terminator
  1411. gofil2: pop     bx
  1412.  
  1413. gofil3: mov     di,offset templp        ; local path
  1414.         mov     si,offset templf        ; local filename
  1415.         mov     dx,offset locfil        ; local string
  1416.         call    fparse                  ; split local string
  1417.         mov     di,offset temprp        ; remote path
  1418.         mov     si,offset temprf        ; remote file
  1419.         mov     dx,offset data          ; remote string
  1420.         push    bx                      ; guard against long filenames
  1421.         mov     bx,offset data
  1422.         mov     byte ptr [bx+64],0     ; force filename to be <= 64 text chars
  1423.         pop     bx
  1424.         call    fparse                  ; split remote string
  1425.         mov     si,offset templp        ; copy local path to
  1426.         mov     di,offset data          ; final filename
  1427.         call    strcpy                  ; do the copy
  1428. gofi3a: mov     si,offset templf        ; assume using local file name
  1429.         cmp     byte ptr templf,0       ; local file name given?
  1430.         jne     gofi3b                  ; ne = yes
  1431.         mov     si,offset temprf        ; else use remote file name
  1432. gofi3b: call    strcat                  ; do the append
  1433.                                 ; now offset data holds the new filename
  1434.                                         ;
  1435. gofil4: mov     ax,offset data          ; assume we're writing to disk
  1436.         push    bx                      ; guard against long filenames
  1437.         mov     bx,offset data
  1438.         mov     byte ptr [bx+64],0      ; force filename to be <= 64 text char
  1439.         pop     bx
  1440.                                 ; recheck legality of filename in 'data'
  1441. gofil5: mov     di,offset temprp        ; remote path
  1442.         mov     si,offset temprf        ; remote file
  1443.         mov     dx,offset data          ; remote string
  1444.         call    strlen                  ; get original size
  1445.         push    cx                      ; remember it
  1446.         call    fparse                  ; further massage filename
  1447.         push    si                      ; put pieces back together
  1448.         call    verfil                  ; verify each char in temprf string
  1449.         mov     si,di                   ; get path part first
  1450.         mov     di,dx                   ; set destination
  1451.         call    strcpy                  ; copy in path part
  1452.         pop     si                      ; recover (new) filename
  1453.         cmp     byte ptr [si],'.'       ; does filename part start with a dot?
  1454.         jne     gofil5a                 ; ne = no
  1455.         push    di                      ; save regs
  1456.         push    si
  1457.         mov     di,offset filbuf        ; a work area
  1458.         mov     byte ptr [di],'X'       ; start name with letter X
  1459.         inc     di
  1460.         call    strcpy                  ; copy rest of filename
  1461.         mov     di,si
  1462.         mov     si,offset filbuf     ; copy new name back to original location
  1463.         call    strcpy
  1464.         pop     si                      ; restore regs
  1465.         pop     di
  1466. gofil5a:call    strcat                  ; append it.
  1467.         call    strlen                  ; see if we chopped out something
  1468.         pop     si                  ; get original length (from push cx above)
  1469.         cmp     cx,si                   ; same size?
  1470.         je      gofil9                  ; e = yes
  1471.         mov     flags.nmoflg,0ffh       ; say that we have a replacement name
  1472.                                 ; filename is now in 'data', all converted
  1473. gofil9: test    flags.remflg,dquiet     ; quiet display mode?
  1474.         jnz     gofi10                  ; nz = yes, don't print it.
  1475.         cmp     flags.nmoflg,0          ; using local override name?
  1476.         je      gofi10                  ; e = no
  1477.         mov     ah,prstr
  1478.         mov     dx,offset asmsg         ; print " as "
  1479.         int     dos
  1480.         mov     dx,offset data          ; plus the local filename
  1481.         call    strlen                  ; computes length in cx for prtscr
  1482.         mov     di,dx
  1483.         call    prtscr
  1484.  
  1485. gofi10: mov     ax,offset data          ; point to name
  1486.         cmp     flags.flwflg,0          ; Is file warning on?
  1487.         je      gofi16                  ; e = no, just proceed
  1488.         call    isfile                  ; does it exist?
  1489.         mov     ax,offset data          ; reload ptr in case...
  1490.         jc      gofi16                  ; carry set = no, just proceed
  1491.         call    unique                  ; generate unique name
  1492.         jc      gofi14                  ; could not generate a unique name
  1493.         test    flags.remflg,dquiet     ; quiet display mode?
  1494.         jnz     gofi13                  ; nz = yes, skip printing
  1495.         push    ax                      ; save unique name again
  1496.         call    frpos                   ; Position cursor.
  1497.         mov     ah,prstr           ; Inform the user we are renaming the file
  1498.         mov     dx,offset infms5
  1499.         int     dos
  1500.         pop     ax                      ; get name back into ax again
  1501.         push    ax                      ; save around these calls
  1502.         mov     dx,ax                   ; print current filename
  1503.         call    strlen                  ; get cx = byte count
  1504.         mov     di,dx                   ; pointer for prtscr
  1505.         call    prtscr                  ; display filename
  1506.         pop     ax                      ; pointer to name, again
  1507. gofi13: jmp     gofi16                  ; and go handle file
  1508.  
  1509. gofi14: mov     dx,offset ermes4
  1510.         test    flags.remflg,dquiet     ; quiet display mode?
  1511.         jnz     gofi15                  ; nz = yes, no printing
  1512.         call    erpos                   ; Position cursor.
  1513.         mov     ah,prstr                ; Tell the user we can't rename it
  1514.         int     dos
  1515. gofi15: mov     bx,dx                   ; Tell host can't rename
  1516.         call    errpack                 ; Send error packet before abort
  1517.         ret
  1518.  
  1519. gofi16: mov     si,ax                   ; pointer to (maybe new) name
  1520.         mov     di,offset diskio.string ; filename, used in open
  1521.         call    strcpy                  ; copy name to diskio.string
  1522.         mov     dx,offset diskio.string ; filename
  1523.         call    isfile          ; check for read-only/system/vol-label/dir
  1524.         jc      gofi16a                 ; c = file does not exist.
  1525.         test    byte ptr filtst.dta+21,1fh      ; the no-no file attributes
  1526.         jnz     gofi18          ; nz = shouldn't write over one of these
  1527. gofi16a:test    filtst.fstat,80h        ; access problem?
  1528.         jnz     gofi18                  ; nz = yes, quit here
  1529.         mov     ofilsz,0                ; original file size is unknown.
  1530.         mov     ofilsz+2,0              ; double word
  1531.         mov     tfilsz,0                ; Set bytes received to zero.
  1532.         mov     tfilsz+2,0
  1533.         mov     oldkbt,-1
  1534.         mov     oldper,-1
  1535.         mov     diskio.handle,0         ; clear handle of previous usage.
  1536.         mov     ah,creat2               ; DOS 2.0 create file
  1537.         mov     cx,0                    ; attributes bits
  1538.         int     dos
  1539.         jc      gofi16b                 ; try regular open
  1540.         mov     diskio.handle,ax        ; save file handle here
  1541.         jmp     rskp
  1542. gofi16b:test    byte ptr filtst.dta+21,1bh      ; r/o, hidden, volume label?
  1543.         jnz     gofi18                  ; we won't touch these
  1544.         mov     ah,open2               ; open existing file (usually a device)
  1545.         mov     al,1                    ; open for writing
  1546.         int     dos
  1547.         jc      gofi18                  ; carry set means can't open
  1548.         mov     diskio.handle,ax        ; file handle
  1549.         jmp     rskp
  1550. gofi17: mov     dx,ax                   ; pointer to filename string (PRN)
  1551.         mov     si,ax                   ; pointer to system filename (PRN)
  1552.         mov     di,offset diskio.string ; destination
  1553.         call    strcpy                  ; copy it for the display
  1554.         jmp     gofi16a                 ; clear counters and open file
  1555.  
  1556. gofi18a:mov     si,ax                   ; pointer to local override name
  1557.         mov     di,offset diskio.string ; filename, used in open
  1558.         call    strcpy                  ; copy name to diskio.string
  1559.         mov     dx,offset diskio.string ; filename
  1560.                                         ; fall  through to gofi18
  1561. gofi18: test    flags.remflg,dquiet     ; quiet display mode?
  1562.         jnz     gofi19                  ; nz = yes, don't try printing
  1563.         call    erpos                   ; Position cursor.
  1564.         mov     ah,prstr                ; tell the user.
  1565.         mov     dx,offset erms12
  1566.         int     dos
  1567.         mov     dx,offset diskio.string ; print offending name
  1568.         call    strlen                  ; get cx = byte count
  1569.         mov     di,dx                   ; pointer for prtscr
  1570.         call    prtscr                  ; display filename
  1571. gofi19: mov     dx,offset erms12        ; reset error message for packet
  1572.         mov     bx,dx
  1573.         call    errpack                 ; Send an error packet.
  1574.         ret
  1575. gofi20: cmp     pack.argbk1,0           ; Any data in "X" packet?
  1576.         je      gofi21                  ; Nothing to print.
  1577.         mov     ah,prstr
  1578.         mov     dx,offset crlf
  1579.         int     dos
  1580.         int     dos                     ; Print another crlf.
  1581.         mov     di,offset data          ; Where data is.
  1582.         mov     cx,pack.argbk1          ; How much data we have.
  1583.         call    prtscr                  ; Print it on the screen.
  1584.         mov     ah,prstr
  1585.         mov     dx,offset crlf
  1586.         int     dos
  1587. gofi21: jmp     rskp                    ; And done.
  1588.  
  1589. FILEIO  ENDP
  1590.  
  1591. ; Given incoming filename in 'data'.  Verify that each char is legal
  1592. ; (if not change it to an "X"), force max of three chars after a period (dot).
  1593. ; Source is at ds:si (si is changed here). [jrd]
  1594.  
  1595. VERFIL  PROC    NEAR
  1596.         push    es                      ; verify each char in 'data'
  1597.         push    cx
  1598.         mov     ax,ds
  1599.         mov     es,ax
  1600.         mov     havdot,0                ; say no dot found in name yet
  1601.         cld
  1602. verfi1: lodsb                           ; get a byte of name from si
  1603.         and     al,7fH                  ; strip any eight bit
  1604.         cmp     al,0                    ; end of name?
  1605.         je      verfi5                  ; e = yes
  1606.         cmp     al,'.'                  ; a dot?
  1607.         jne     verfi2                  ; ne = no.
  1608.         cmp     havdot,0                ; have one dot already?
  1609.         jne     verfi3                  ; ne = yes, change to X
  1610.         mov     byte ptr [si+3],0    ; forceably end filename after 3 char ext
  1611.         mov     havdot,1                ; say have a dot now.
  1612.         jmp     verfi4                  ; continue
  1613. verfi2: cmp     al,3ah                  ; colon?
  1614.         je      verfi4
  1615.         cmp     al,5ch                  ; backslash path separator?
  1616.         je      verfi4
  1617.         cmp     al,2fh                  ; or forward slash?
  1618.         je      verfi4
  1619.         cmp     al,'0'
  1620.         jb      verfi3                  ; See if it's a legal char < '0'.
  1621.         cmp     al,'9'
  1622.         jbe     verfi4                  ; It's between 0-9 so it's OK.
  1623.         cmp     al,'A'
  1624.         jb      verfi3                  ; Check for a legal punctuation char
  1625.         cmp     al,'Z'
  1626.         jbe     verfi4                  ; It's A-Z so it's OK.
  1627.         cmp     al,'a'
  1628.         jb      verfi3                  ; Check for a legal punctuation char
  1629.         cmp     al,'z'
  1630.         ja      verfi3
  1631.         and     al,5FH                  ; It's a-z, capitalize.
  1632.         jmp     verfi4                  ; continue with no change
  1633.  
  1634. verfi3: push    di                      ; special char. Is it on the list?
  1635.         mov     di,offset spchar2       ; list of acceptable special chars
  1636.         mov     cx,spc2len
  1637.         cld
  1638.         repne   scasb                   ; Search string for input char.
  1639.         pop     di
  1640.         je      verfi4                  ; e = in table, return it
  1641.         mov     al,'X'                  ; else illegal, replace with "X".
  1642.         mov     flags.nmoflg,0FFH       ; say we have a replacement filename
  1643. verfi4: mov     [si-1],al               ; update name
  1644.         jmp     verfi1                  ; loop thru rest of name
  1645. verfi5: mov     byte ptr[si-1],0        ; make sure it's null terminated
  1646.         pop     cx
  1647.         pop     es
  1648.         ret
  1649. VERFIL  ENDP
  1650.  
  1651. ; find a unique filename...     Upgraded by [jrd]
  1652. ; Enter with a pointer to a (null-terminated) filename in ax.
  1653. ; Return with same pointer but with a new name (or old if failure).
  1654. ; Success = carry clear; failure = carry set.
  1655. ; The idea is to pad out the main name part (8 chars) with ascii zeros and
  1656. ; then change the last chars successively to a 1, 2, etc. until
  1657. ; a unique name is found. All registers are preserved.
  1658. ; Add patch to make empty main name fields start with letter X, not digit 0.
  1659. ; 23 March 1986 [jrd]
  1660. unique  proc    near
  1661.         push    bx
  1662.         push    cx
  1663.         push    dx
  1664.         push    si
  1665.         push    di
  1666.         push    es
  1667.         push    ax                      ; save address of source string
  1668.         mov     dx,ds                   ; make es use ds segment
  1669.         mov     es,dx
  1670.         mov     dx,ax                   ; point at original filename string
  1671.         mov     di,offset templp        ; place for path
  1672.         mov     si,offset templf        ; place for filename
  1673.         call    fparse                  ; separate path (di) and filename (si)
  1674.         mov     dx,di                   ; point at path part
  1675.         call    strlen                  ; put length in cx
  1676.         mov     si,ax                   ; point to original string
  1677.         add     si,cx                   ; point to filename part
  1678.         mov     di,offset templf        ; destination is temporary location
  1679.         mov     cx,0                    ; a counter
  1680.         cld                             ; set direction to be forward
  1681. uniq1:  lodsb                           ; get a byte
  1682.         cmp     al,'.'                  ; have a dot?
  1683.         je      uniq2                   ; e = yes.
  1684.         cmp     al,0                    ; maybe null at end?
  1685.         jne     uniq3                   ; ne = no. continue loop
  1686.  
  1687. uniq2:  cmp     cl,8                    ; have we copied any chars before dot?
  1688.         jge     uniq3                   ; ge = all 8
  1689.         mov     byte ptr [di],'0'       ; avoid clobbers; pad with 0's
  1690.         cmp     cl,0                    ; first char of filename?
  1691.         jne     uniq2a                  ; ne = no
  1692.         mov     byte ptr [di],'X'       ; start name with letter X, not 0
  1693. uniq2a: inc     di                      ; and count the output chars
  1694.         inc     cl                      ; and this counter too
  1695.         jmp     uniq2                   ; continue until filled 8 slots
  1696. uniq3:  inc     cl                      ; cl = # char in destination
  1697.         stosb                           ; store the char
  1698.         cmp     al,0                    ; null at end?
  1699.         jne     uniq1                   ; ne = no, continue copying
  1700.  
  1701.         mov     di,offset templf
  1702.         add     di,7                    ; address of last name char
  1703.         mov     byte ptr [di],'1'       ; put '1' in last name char
  1704.         mov     unum,1                  ; start with this generation digit
  1705.  
  1706. uniq4:  mov     di,offset filbuf        ; build a temporary full filename
  1707.         mov     si,offset templp        ; path part
  1708.         call    strcpy                  ; copy that much
  1709.         mov     si,offset templf        ; get rebuilt filename part
  1710.         call    strcat                  ; paste that to the end
  1711.         mov     ax,offset filbuf        ; point to full name
  1712.         call    isfile                  ; does it exist?
  1713.         jc      uniq6                   ; c = no, succeed now
  1714.  
  1715.         inc     unum                    ; move to next generation
  1716.         mov     di,offset templf        ; position for characters
  1717.         add     di,7                    ; point to last name char
  1718.         mov     cx,7                    ; max # of digits to play with
  1719.         mov     bx,10                   ; divisor (16 bits)
  1720.         mov     ax,unum                 ; low order part of generation #
  1721. uniq5:  mov     dx,0                    ; high order part of generation #
  1722.         div     bx                      ; compute digit (unum / 10)
  1723.         add     dl,'0'                  ; make remainder part printable
  1724.         mov     byte ptr [di],dl        ; put into right place
  1725.         cmp     ax,0                    ; any more to do? (quotient nonzero)
  1726.         jz      uniq4                   ; z = no, try this name
  1727.         dec     di                      ; else decrement char position
  1728.         loop    uniq5                   ;   and keep making a number
  1729.         stc                             ; failure: set carry, keep old name
  1730.         jmp     short uniq7             ;   and exit
  1731.  
  1732. uniq6:  pop     di                      ; address of original filename
  1733.         push    ax                      ; save for exit clean up
  1734.         mov     si,offset filbuf
  1735.         call    strcpy                  ; copy new filename over old
  1736.         clc                             ; success: clear carry flag
  1737. uniq7:  pop     ax
  1738.         pop     es
  1739.         pop     di
  1740.         pop     si
  1741.         pop     dx
  1742.         pop     cx
  1743.         pop     bx
  1744.         ret
  1745. unique  endp
  1746.  
  1747.  
  1748. ;       [jrd]
  1749. ; strlen -- computes the length, excluding the terminator, of an asciiz
  1750. ;       string. Input: dx = offset of the string.
  1751. ;               Output: cx = the byte count.
  1752. ;       Normal 'ret' return. All registers except cx are preserved.
  1753. ;
  1754. STRLEN  PROC    NEAR
  1755.         push    di
  1756.         push    es
  1757.         push    ax
  1758.         mov     ax,ds                   ; use proper segment address
  1759.         mov     es,ax
  1760.         mov     di,dx
  1761.         mov     cx,0ffffh               ; large byte count
  1762.         cld                             ; set direction to be forward
  1763.         mov     al,0                    ; item sought is a null
  1764.         repne   scasb                   ; search for it
  1765.         add     cx,2                    ; add for -1 and auto dec in scasb
  1766.         neg     cx                    ; convert to count, excluding terminator
  1767.         pop     ax
  1768.         pop     es
  1769.         pop     di
  1770.         ret
  1771. STRLEN  ENDP
  1772.  
  1773. ;       [jrd]
  1774. ; strcat -- concatenates asciiz string 2 to the end of asciiz string 1.
  1775. ;       offset of string 1 is expected to be in ds:di. input & output
  1776. ;       offset of string 2 is expected to be in ds:si. input only (unchanged)
  1777. ;       Preserves all registers. No error returns, returns normally via ret.
  1778. ;
  1779. STRCAT  PROC    NEAR
  1780.         push    di                      ; save work registers
  1781.         push    si
  1782.         push    es
  1783.         push    dx
  1784.         push    cx
  1785.         push    ax
  1786.         mov     ax,ds                   ; get data segment value
  1787.         mov     es,ax                   ; set es to ds for implied es:di usage
  1788.         mov     dx,di
  1789.         call    strlen          ; get length (w/o terminator) of dest string
  1790.         add     di,cx                   ; address of first terminator
  1791.         mov     dx,si                   ; start offset of source string
  1792.         call    strlen                  ; find its length too (in cx)
  1793.         inc     cx                      ; include its terminator in the count
  1794.         rep     movsb           ; copy source string to end of output string
  1795.         pop     ax
  1796.         pop     cx
  1797.         pop     dx
  1798.         pop     es
  1799.         pop     si
  1800.         pop     di
  1801.         ret
  1802. STRCAT  ENDP
  1803.  
  1804. ;       [jrd]
  1805. ; strcpy -- copies asciiz string pointed to by ds:si into area pointed to by
  1806. ;       ds:di. Returns via ret. All registers are preserved.
  1807. ;
  1808. STRCPY  PROC    NEAR
  1809.         mov     byte ptr [di],0         ; clear destination string
  1810.         call    strcat                  ; let strcat do the real work
  1811.         ret
  1812. STRCPY  ENDP
  1813.  
  1814. ;       [jrd]
  1815. ; fparse -- separate the drive:path part from the filename.ext part of an
  1816. ;       asciiz string. Characters separating parts are  \ or / or :
  1817. ;       Inputs: asciiz input full filename string offset in ds:dx
  1818. ;               asciiz path offset in ds:di
  1819. ;               asciiz filename offset in ds:si
  1820. ;       Outputs: the above strings in the indicated spots.
  1821. ;       Strategy is simple. Reverse scan input string until one of the
  1822. ;       three separators is encountered and then cleave at that point.
  1823. ;       Simple filename construction restrictions added 30 Dec 1985;
  1824. ;       to wit: mainname limited to 8 chars or less,
  1825. ;       extension field limited to 3 chars or less and is found by searching
  1826. ;       for first occurence of a dot in the filename field. Thus the whole
  1827. ;       filename part is restricted to 12 (8+dot+3) chars plus a null.
  1828. ;       All registers are preserved. Return is always via ret.
  1829. ;       (Microsoft should have written this for DOS 2.x et seq.)
  1830.  
  1831. FPARSE  PROC    NEAR
  1832.         push    cx                      ; local counter
  1833.         push    ax                      ; local work area
  1834.         push    es                      ; implied segment register for di
  1835.         push    di                      ; offset of path part of output
  1836.         push    si                      ; offset of file name part of output
  1837.         mov     ax,ds                   ; get data segment value
  1838.         mov     es,ax                   ; set es to ds for implied es:di usage
  1839.         mov     byte ptr [si],0         ; clear outputs
  1840.         mov     byte ptr [di],0
  1841.  
  1842.         push    si                      ; save original file name address
  1843.         mov     si,dx                   ; get original string address
  1844.         call    strcpy                  ; copy string to original di
  1845.         call    strlen                  ; find length (w/o terminator), in cx
  1846.         mov     si,di                   ; address of string start
  1847.         add     si,cx
  1848.         dec     si                      ; si = address of last non-null char
  1849.         jcxz    fpars5                  ; if null skip the path scan
  1850.                                         ; now find last path char, if any.
  1851.                                         ; start at the end of input string
  1852.         std                             ; set direction to be backward
  1853. fpars4: lodsb                           ; get a byte (dec's si afterward)
  1854.         cmp     al,5ch                  ; is it a backslash ('\')?
  1855.         je      fpars6                  ; e = yes
  1856.         cmp     al,2fh                  ; or forward slash ('/')?
  1857.         je      fpars6                  ; e = yes
  1858.         cmp     al,3ah                  ; or even the drive terminator colon?
  1859.         je      fpars6                  ; e = yes
  1860.         loop    fpars4                  ; else keep looking until cx == 0
  1861.                                         ; si is at beginning of file name
  1862. fpars5: dec     si                      ; dec for inc below
  1863. fpars6: inc     si
  1864.         inc     si                      ; si now points at first filename char
  1865.                                         ; cx holds number of path chars
  1866.                                         ; get original file name address (si)
  1867.         pop     di                      ; and make it place to copy filename.
  1868.         cld                             ; reset direction to be forward
  1869.         mov     ax,si                   ; ax holds filename address for awhile
  1870.         push    dx
  1871.         mov     dx,si                   ; strlen wants string pointer in dx
  1872.         call    strlen                  ; get length of filename part into cx
  1873.         pop     dx
  1874.         jcxz    fpar7a                  ; any chars to look at? z = no
  1875. fpars7: cmp     byte ptr [si],'.'       ; look for a dot in filename
  1876.         je      fpars8                  ; e = found one
  1877.         inc     si                      ; look at next filename char
  1878.         loop    fpars7                  ; keep looking until cx = zero
  1879. fpar7a: mov     si,ax                   ; no dot. recover starting address
  1880.         mov     byte ptr [si+8],0       ; forcably truncate mainname to 8 char
  1881.         call    strcpy                  ; copy this part to filename field
  1882.         jmp     fparsx                  ;  and exit.
  1883. fpars8: mov     byte ptr [si+4],0   ; plant terminator after dot + 3 ext chars
  1884.         mov     cx,si
  1885.         sub     cx,ax           ; cx now = number of chars in mainname field
  1886.         cmp     cx,9                    ; more than 8?
  1887.         jb      fpars9                  ; b = no, we're safe.
  1888.         mov     cx,8                 ; limit ourselves to 8 chars in mainname
  1889. fpars9: push    si                   ; remember address of dot and extension
  1890.         mov     si,ax                   ; point to start of input filename
  1891.         rep     movsb                   ; copy cx chars from si to di (output)
  1892.         mov     byte ptr [di],0         ; plant terminator where dot goes
  1893.         pop     si                      ; source = dot and extension address
  1894.         call    strcat          ; append the dot & ext to the filename field.
  1895. fparsx: mov     si,ax           ; recover start of filename in input string.
  1896.         mov     byte ptr [si],0         ; terminate path field
  1897.         pop     si
  1898.         pop     di
  1899.         pop     es
  1900.         pop     ax
  1901.         pop     cx
  1902.         ret
  1903. FPARSE  ENDP
  1904.  
  1905. ; Print filename in offset data. Shortened by [jrd].
  1906. PRTFN   PROC    NEAR
  1907.         push    ax                      ; saves for messy clrfln routine
  1908.         push    bx
  1909.         push    cx
  1910.         push    dx
  1911.         push    di
  1912.         call    clrfln                  ; Position cursor & blank out the line
  1913.         mov     dx,offset data
  1914.         call    strlen                 ; compute length of asciiz string in cx
  1915.         mov     di,dx                   ; where prtscr wants its string
  1916.         call    prtscr
  1917.         pop     di
  1918.         pop     dx
  1919.         pop     cx
  1920.         pop     bx
  1921.         pop     ax
  1922.         ret
  1923. PRTFN   ENDP
  1924.  
  1925.  
  1926. ; Print string to screen from offset ds:di for # bytes given in cx,
  1927. ; regardless of $'s.  All registers are preserved.              [jrd]
  1928.  
  1929. PRTSCR  PROC    NEAR
  1930.         push    ax
  1931.         push    bx
  1932.         push    dx
  1933.         mov     dx,di                   ; source ptr for DOS
  1934.         mov     bx,1                    ; stdout file handle
  1935.         mov     ah,write2
  1936.         int     dos
  1937.         pop     dx
  1938.         pop     bx
  1939.         pop     ax
  1940.         ret
  1941.         ret
  1942. PRTSCR  ENDP
  1943.  
  1944. ; Print to screen asciiz string given in ds:dx. Everything preserved. [jrd]
  1945. PRTASZ  PROC    NEAR
  1946.         push    cx
  1947.         push    di
  1948.         call    strlen                  ; get length of asciiz string
  1949.         mov     di,dx                   ; where prtscr looks
  1950.         call    prtscr                  ; print counted string
  1951.         pop     di
  1952.         pop     cx
  1953.         ret
  1954. PRTASZ  ENDP
  1955.  
  1956.  
  1957. ; Jumping to this location is like retskp.  It assumes the instruction
  1958. ;   after the call is a jmp addr.
  1959.  
  1960. RSKP    PROC    NEAR
  1961.         pop     bp
  1962.         add     bp,3
  1963.         push    bp
  1964.         ret
  1965. RSKP    ENDP
  1966.  
  1967. ; Jumping here is the same as a ret.
  1968.  
  1969. R       PROC    NEAR
  1970.         ret
  1971. R       ENDP
  1972.  
  1973. code    ends
  1974.         end
  1975.