home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / DIR / DIRM13.ZIP / DIRM13.ASM < prev    next >
Encoding:
Assembly Source File  |  1990-11-01  |  46.9 KB  |  1,272 lines

  1. ;-----------------------------------------------------------------------;
  2. ; This is the main source code for DIRM v1.3, a FAST! directory lister. ;
  3. ; It is the copyrighted property of Michael P. Rice. (c) 1990.          ;
  4. ; This source code is NOT in the public domain and cannot be used       ;
  5. ; commercially without permission.  Completed 2-November-1990.          ;                                               ;
  6. ;-----------------------------------------------------------------------;
  7. .model small
  8.  
  9. .data
  10. ;-----------------------------------------------------------------------;
  11. ; The following table is used in the write_time procedure.  The bits    ;
  12. ; are used as follows:  Bits     6,7   Unused                           ;
  13. ;                                  5   Space flag 0=off 1=on            ;
  14. ;                                  4   Am\Pm flag 0=am 1=pm             ;
  15. ;                            3,2,1,0   Hour to print                    ;
  16. ;-----------------------------------------------------------------------;
  17. time_table      db      0ch,21h,22h,23h,24h,25h,26h,27h,28h,29h,0ah,0bh
  18.                 db      1ch,31h,32h,33h,34h,35h,36h,37h,38h,39h,1ah,1bh
  19.  
  20. ;-----------------------------------------------------------------------;
  21. ; This is a simple table to determine AM/PM for write_time.             ;
  22. ;-----------------------------------------------------------------------;
  23. am_pm_table     db      'a','p'
  24.  
  25. def_filespec    db      '*.*',0
  26. volumespec      db      '*.*',0
  27. filespec        db      13 dup (0)
  28. filespec2       db      13 dup (0)      ; SS
  29.  
  30. ;-----------------------------------------------------------------------;
  31. ; These are used for attribute processing.  Default is attributes will  ;
  32. ; not be printed.  File mask 31h means hidden and system files are not  ;
  33. ; show in the directory.  When attributes are on, system and hidden     ;
  34. ; files are shown with mask=37h                                         ;
  35. ;-----------------------------------------------------------------------;
  36. attrib_on       db      0
  37. attrib_mask     dw      0031h
  38.  
  39. ;-----------------------------------------------------------------------;
  40. ; These are the ASCIIZ string data messages used in the program.        ;
  41. ;-----------------------------------------------------------------------;
  42. volumemess1     db      'Volume in Drive ',0
  43. volumemess2     db      ' is ',0
  44. volumemess3     db      ' has no label.',0
  45. colon           db      ':',0                           ;SS
  46. dirmess1        db      "DIRM v1.3  Directory of ",0
  47. dirmess2        db      '      Filespec: ',0
  48. dir_braces      db      ' <DIR>       ',0
  49. moremessage     db      'Press any key to continue',0
  50. trailermess0    db      ' bytes in ',0
  51. trailermess1    db      ' File(s)',0
  52. trailermess2    db      ' bytes free. ',0
  53. illegalswitch   db      'Usage: dirm [d:][path specification] [/switches]',0
  54. legalswitches   db      ' /w wide mode  /p page at a time  /a show attribs',0
  55. nofoundpath     db      'Unknown Path | ',0
  56. nofoundswitch   db      'Illegal Switch | ',0
  57.  
  58. ;-----------------------------------------------------------------------;
  59. ; Flags used to indicate the use of a switches /p /w /r.                ;
  60. ;-----------------------------------------------------------------------;
  61. page_flag       db      0
  62. recursive_flag  db      0
  63. wide_flag       db      0
  64.  
  65. ;-----------------------------------------------------------------------;
  66. ; Flags used in PSP processing to detect the need for default params.   ;
  67. ;-----------------------------------------------------------------------;
  68. drive_set       db      0
  69. directory_set   db      0
  70.  
  71. ;-----------------------------------------------------------------------;
  72. ; This is used to keep a count of the files in the directory, not       ;
  73. ; including directory entries.                                          ;
  74. ;-----------------------------------------------------------------------;
  75. files           dw      0
  76.  
  77. ;-----------------------------------------------------------------------;
  78. ; This keeps track of lines printed for the /p page switch. It is set   ;
  79. ; initially to 3 to keep the header on the screen.                      ;
  80. ;-----------------------------------------------------------------------;
  81. filecount       db      3
  82.  
  83. ;-----------------------------------------------------------------------;
  84. ; These are where the drive numbers are stored when a change is needed. ;
  85. ;-----------------------------------------------------------------------;
  86. startdrive      db      0
  87. tempdrive       db      0
  88.  
  89. ;-----------------------------------------------------------------------;
  90. ; These are directory specifications used with INT 21h BIOS calls.      ;
  91. ;-----------------------------------------------------------------------;
  92. root            db      '\',0
  93. directory       db      '\'
  94.                 db      64 dup (?)
  95. tempdir         db      '\'
  96.                 db      64 dup (?)
  97.  
  98. ;-----------------------------------------------------------------------;
  99. ; This is where the filesizes of matching files are accumulated.        ;
  100. ;-----------------------------------------------------------------------;
  101. accum_filesize  dd      00000000h
  102.  
  103. ;-----------------------------------------------------------------------;
  104. ; This is the field to add commas to the filesize, bytes free numbers   ;
  105. ;-----------------------------------------------------------------------;
  106. p_field         db      '   ,   ,   ,   ',0
  107.  
  108.  
  109. .data?
  110.  
  111. ;-----------------------------------------------------------------------;
  112. ; This is the data area used for the disk DTA - Disk Transfer Area.     ;
  113. ;-----------------------------------------------------------------------;
  114. Reserved        db      21 dup (?)      ;Reserved
  115. FAttrib         db       1 dup (?)      ;file's Attribute
  116. FTime           db       2 dup (?)      ;file's time stamp
  117. FDate           db       2 dup (?)      ;file's date stamp
  118. FSize           db       4 dup (?)      ;file's size
  119. FName        db    13 dup (?)    ;ASCIIZ file name
  120.  
  121. ;-----------------------------------------------------------------------;
  122. ; Area to move the command line PSP area switches, directory specs, etc ;
  123. ;-----------------------------------------------------------------------;
  124. PSPBytes        db        1 dup (?)
  125. PSPSpace        db        1 dup (?)
  126. PSPArea         db      7Eh dup (?)
  127.  
  128. ;-----------------------------------------------------------------------;
  129. ; Just what it says: holds the current filesize that will be added to   ;
  130. ; the accumulated file size.                                            ;
  131. ;-----------------------------------------------------------------------;
  132. current_filesize  db    4 dup (?)
  133.  
  134. .stack
  135.  
  136. .code
  137.  
  138.     EXTRN    send_crlf:proc, write_string:proc, write_char:proc
  139.     EXTRN    goto_xy:proc, init_write_char:proc
  140.     EXTRN    SCREEN_X:byte, goto_col:proc
  141.     PUBLIC disk_dir
  142. ;-----------------------------------------------------------------------;
  143. ; This is a C callable function to display a disk directory.            ;
  144. ;-----------------------------------------------------------------------;
  145. disk_dir        PROC
  146.         mov dx,ds
  147.         mov ax,@data
  148.         mov ds,dx                       ;Both DS and ES point to the data
  149.     mov es,ax
  150.         
  151.         mov si,80h                      ;Move the PSP into Memory
  152.         mov di,OFFSET PSPBytes
  153.         mov cx,80h
  154.         rep movsb
  155.         mov ds,ax
  156.  
  157.     call init_write_char        ;Determine screen memory    
  158.  
  159.         mov ah,19h
  160.         int 21h                         ;Get current drive
  161.         mov startdrive,al               ;Save current drive
  162.         mov tempdrive,al
  163.  
  164.         call process_psp                ;Process command switches
  165.         call adjust_filespec            ;Make filespec = filespec.*
  166.  
  167.         mov ah,47h                      ;Save the new temporary directory
  168.         mov si,OFFSET tempdir+1
  169.         mov dl,0
  170.         int 21h
  171.  
  172.         call send_crlf
  173.  
  174.         mov dx,OFFSET Reserved          ;Set up a DTA
  175.     mov ah,1ah
  176.     int 21h
  177.  
  178.     call write_volume        ;Write Volume Message/Volume
  179.     call send_crlf
  180.         
  181.         mov dx,OFFSET filespec          ;Load in the currentfilespec
  182.         mov cx,attrib_mask              ;Search for normal files
  183.     mov ah,4eh
  184.     int 21h                ;Get first filename
  185.         mov di,0
  186.         jae printf                      ;Print the entry
  187.         jmp exit_disk_dir               ;No entries on DISK!
  188.     
  189. printf:
  190.  
  191.         cmp wide_flag,0                 ;Is wide flag being used?
  192.         jne wide_files                  ;If so, go process in wide mode
  193.         cmp page_flag,0                 ;If page flag isn't set we skip
  194.         je skip_page_stuff              ; over the page processing
  195.  
  196.         cmp filecount,24                ;Otherwise, Do we have 24 lines yet?
  197.         jne increment_filecount         ;If not, increment lines
  198.         call process_endpage            ;If so, do hold processing
  199.         jmp skip_page_stuff             ; and don't increment
  200. increment_filecount:
  201.         inc filecount                   ;Increment lines=files
  202. skip_page_stuff:
  203.         mov bx,OFFSET FAttrib           ;Check for directories
  204.         mov cx,[bx]                     ;Move the attrib into CX
  205.         and cx,0010h                    ;Check for directory
  206.         mov dx,OFFSET FName             ;Write name from DTA
  207.         cmp cx,0
  208.         jnz just_write_dir
  209.         call write_first                ;Write first part of file name
  210.                                         ; i.e. part before the '.'
  211.         push dx                         ;Save offset returned by write_first
  212.         mov dl,9                        ;Goto column 10 for extension printing
  213.         call goto_col
  214.         pop dx                          ;Get back the extension's OFFSET
  215. just_write_dir:
  216.         call write_string               ;Write the extension or if
  217.                                         ; it is a directory write it all
  218.               
  219.     mov dl,12
  220.     call goto_col            ;Move to column 13
  221.         cmp cx,0                        ;If CX is 0, it is not a directory
  222.         jz fsize_stuff                  ;So want to print the filesize info
  223.  
  224.         mov dx,OFFSET dir_braces        ;Otherwise print a <DIR> message
  225.         call write_string               ;instead of a filesize
  226.         jmp date_stuff                  ;Do date stuff, skip wide stuff
  227.  
  228. wide_files:
  229.         mov bx,OFFSET FAttrib           ;Check for director so we don't
  230.         mov cx,[bx]                     ;include it in the file count
  231.         and cx,0010h
  232.         cmp cx,0                        ;If CX is 0, it is not a directory
  233.         jnz no_inc                      ;So don't increment the file count
  234.         inc files                       ;Add one to file count
  235. no_inc:
  236.         cmp di,80                       ;If we are at col 64 want to do a CRLF
  237.         je newline
  238.         mov dx,di                       ;Move to the right column
  239.         call goto_col                   ;which is 16 more than the last column
  240.         jmp write_it                    ;write the file or directory name
  241. newline:
  242.         call send_crlf                  ;Send a carriage return/linefeed and
  243.         inc filecount                   ;Increment lines count=file*5
  244.         cmp page_flag,0                 ;If not in wide and page modes
  245.         je no_more_prompt               ; don't check for number of lines
  246.         cmp filecount,24                ;Do we have 24 lines yet?
  247.         jne no_more_prompt              ;If not, don't do hold processing
  248.         call process_endpage            ;If so, do hold processing
  249. no_more_prompt:
  250.         mov di,0                        ;Set current column to 0
  251. write_it:
  252.         mov dx,OFFSET FName             ;Write the name
  253.         call write_string
  254.         add di,16                       ;Add 16 to column counter
  255.         jmp more_files                  ;Go see if there are more files
  256.  
  257. printf_link:
  258.         jmp printf                      ;Too large routines cause this noise
  259.  
  260. fsize_stuff:
  261.         inc files                       ;Increment number of files
  262.         mov bx,OFFSET FSize             ;Get Offset in file size area
  263.     mov si,[bx]            ;Get LSBs of file size
  264.     mov di,[bx+2]            ;Get MSBs of file size
  265.         call tally_files                ;Add to file byte accumulator
  266.  
  267.         call bin_to_ascii               ;Convert and print in decimal
  268.  
  269.     mov dl,' '            ;Move one column forward
  270.     call write_char
  271. date_stuff:
  272.         mov dx,OFFSET FDate             ;Set to date in DTA
  273.     call write_date            ;Write the date out
  274.  
  275.         mov dl,' '                      ;Move one column forward
  276.         call write_char
  277.  
  278.         mov dx,OFFSET FTime
  279.         call write_time                 ;Write the time out
  280.  
  281.         mov dl,' '                      ;Write the space
  282.         call write_char
  283.  
  284.         cmp attrib_on,0                 ;Was the attrib '/a' switch used?
  285.         je no_attribs                   ;If not, skip this code
  286.         mov dx,OFFSET FAttrib
  287.         call write_attributes           ;Write the attributes after the time
  288. no_attribs:
  289.         call send_crlf
  290.     
  291. more_files:
  292.     mov ah,4fh            ;Get next filename
  293.     int 21h
  294.         jae printf_link                 ;Print entry if exists
  295.                     ;Or exit, if done
  296.  
  297. exit_disk_dir:
  298.         cmp wide_flag,0                 ;If wide mode is active no CRLF
  299.         je no_crlf                      ;is needed after each filename
  300.         call send_crlf
  301.         mov dl,8                        ;Goto column 9 for wide mode trailer
  302.         call goto_col
  303. no_crlf:
  304.         call write_trailer              ;Write # files, etc
  305.  
  306.         mov dl,startdrive
  307.         mov ah,0eh                      ;Restore correct drive
  308.         int 21h
  309.  
  310.         mov dx,OFFSET directory         ;Restore correct subdirectory
  311.         mov ah,3bh
  312.         int 21h
  313.  
  314.         call send_crlf
  315.  
  316.         mov ah,4ch
  317.     int 21h                ;Exit to DOS
  318.  
  319. disk_dir    ENDP
  320.  
  321.         public adjust_filespec
  322. ;-----------------------------------------------------------------------;
  323. ; This procedure makes filespec match all filespec.* files.  If you     ;
  324. ; don't want this for some reason you can remove this procedure and its ;
  325. ; call without harm.  It was added in version 1.1 for COMMAND.COM com-  ;
  326. ; patibility.                                                           ;
  327. ;-----------------------------------------------------------------------;
  328. adjust_filespec PROC
  329.         push ax                         ;Save registers
  330.         push cx
  331.         push di
  332.         push si
  333.  
  334.         mov si,OFFSET filespec          ;Find beginning of set filespec
  335.         lodsb                           ;Load a byte                    SS
  336.         cmp al,'.'                      ;See if it is a period          SS
  337.         je first_period                 ; If it is go to first_period   SS
  338.         dec si                          ;Go back to start of filespec   SS
  339.  
  340. loopback:
  341.         lodsb                           ;Get a byte
  342.         cmp al,'.'                      ;Check if it has an extension
  343.         je ext_found                    ; If it does branch out
  344.         cmp al,0                        ; If end, no extension found
  345.         je no_ext_found
  346.         jmp loopback                    ;Keep trying
  347.  
  348. first_period:                           ;                               SS
  349.         mov di,OFFSET filespec2         ;Builds new specs in filespec2  SS
  350.         mov si,OFFSET def_filespec      ;Only if filespec given starts  SS
  351.         mov cx,1                        ;With a period '.'              SS
  352.         rep movsb                       ;Basically just adds an '*'     SS
  353.         mov si,OFFSET filespec          ;Before the specs given         SS
  354.         mov di,OFFSET filespec2+1       ;                               SS
  355.         mov cx,4                        ;                               SS
  356.         rep movsb                       ;                               SS
  357.         mov si,OFFSET filespec2         ;Puts filespec2 into            SS
  358.         mov cx,5                        ; filespec                      SS
  359.         call set_filespec               ;                               SS
  360.         jmp loopback                    ;Goes to loopback               SS
  361.  
  362. ext_found:
  363.         lodsb                           ;See if it is just a .
  364.         cmp al,0
  365.         dec si                          ;Set si for no_ext_found
  366.         je no_ext_found
  367.         jmp exit_adjust_filespec
  368.  
  369. no_ext_found:
  370.         dec si
  371.         mov di,si                      ;Move ".*",0 into filespec
  372.         mov si,OFFSET def_filespec+1
  373.         mov cx,3
  374.         rep movsb
  375.  
  376. exit_adjust_filespec:
  377.         pop si                          ;Restore registers and exit
  378.         pop di
  379.         pop cx
  380.         pop ax
  381.         ret
  382.  
  383. adjust_filespec ENDP
  384.                     
  385.         public process_endpage
  386.         extrn clear_to_end_of_line:proc
  387. ;-----------------------------------------------------------------------;
  388. ; This procedure initializes the filecount and prints the MORE message  ;
  389. ; then waits for a keypress and sends a carriage return and returns.    ;
  390. ;-----------------------------------------------------------------------;
  391. process_endpage PROC
  392.         mov filecount,0                 ;Initialize the file count
  393.         mov dx,OFFSET moremessage       ; 'Press any key to continue'
  394.         call write_string
  395.         mov ah,02h                      ;Move cursor to correct position
  396.         mov bh,0                        ;Page 0
  397.         mov dx,1819h                    ;Row 24, Col 25
  398.         int 10h
  399.         mov ah,07h                      ;Wait for keypress, don't echo it
  400.         int 21h
  401.         mov dl,0                        ;Go back to column zero
  402.         call goto_col
  403.         call clear_to_end_of_line       ;Erase 'Press any key' message
  404.         ret                             ; and return
  405. process_endpage ENDP
  406.  
  407.  
  408.         public write_first
  409. ;-----------------------------------------------------------------------;
  410. ; This procedure is used to print the first part of a file name.  It    ;
  411. ; expects DS:DX to point to the filename.  For example if a filename is ;
  412. ; defined as   NAME db 'FIRST.EXT',0 this will print FIRST and leave    ;
  413. ; DX pointing to the first letter after the .  So the extension can be  ;
  414. ; printed with a normal ASCIIZ print routine with DX the OFFSET.        ;
  415. ;-----------------------------------------------------------------------;
  416. write_first  proc
  417.         push ax                         ;Save registers and Flags
  418.         push si
  419.         pushf
  420.  
  421.         cld                             ;Increment of LODS,STOS
  422.         mov si,dx                       ;Get OFFSET
  423.  
  424. first_loop:
  425.         lodsb                           ;Get a byte
  426.         cmp al,'.'                      ;Is it the extension divider?
  427.         jz end_of_first                 ;If yes, we've found the end
  428.         cmp al,0                        ;Is it the end of the filename?
  429.         jz end_of_first1                ;If yes, there is no extension
  430.         mov dl,al                       ;Otherwise, write the character
  431.         call write_char
  432.         jmp first_loop
  433. end_of_first1:
  434.         dec si                          ;Move back if end (May not be needed)
  435. end_of_first:
  436.         mov dx,si                       ;Save the OFFSET
  437.         popf                            ;Restore flags and registers
  438.         pop si
  439.         pop ax
  440.         ret
  441. write_first     ENDP
  442.  
  443.  
  444.         public process_psp
  445. ;-----------------------------------------------------------------------;
  446. ; This procedure takes care of the DOS command line switches.           ;
  447. ;-----------------------------------------------------------------------;
  448. process_psp     proc
  449.         push ax                         ;Save the friggin' registers
  450.         push bx
  451.         push cx
  452.         push dx
  453.         push di
  454.         push si
  455.         push bp
  456.  
  457.         mov bx,OFFSET PSPBytes
  458.         mov cl,[bx]                     ;Get number of characters of info
  459.  
  460.         and cx,00ffh                    ;Make sure CL is zero
  461.         jcxz exit_default_link          ;If there are no characters
  462.  
  463.         dec cl                          ;Remove leading space
  464.  
  465.         mov bx,cx                       ;Place a zero after last
  466.         add bx,OFFSET PSPArea           ;byte in PSP header
  467.         xor al,al
  468.         mov [bx],al
  469.  
  470.         cld                             ;Increment on LODS commands
  471.         mov si,OFFSET PSPArea
  472.  
  473. loop1:
  474.         jcxz exit_check_link
  475.         dec cl
  476.         lodsb                           ;Loop through any leading spaces
  477.         cmp al,' '
  478.         je loop1
  479.         cmp al,'/'                      ;Check for switch characters
  480.         je process_switches
  481.         cmp al,'\'                      ;Check for full path indicator
  482.         je process_full_path
  483.         jmp process_rel_path            ;Must be relative path or drivespec
  484.  
  485. ;-----------------------------------------------------------------------------
  486. exit_default_link:
  487.         jmp exit_default
  488. exit_check_link:
  489.         jmp exit_check
  490.  
  491. process_switches:
  492.         lodsb
  493.         dec cl
  494.         cmp al,'a'                      ;Check for ATTRIBUTE switch
  495.         je a_switch
  496.         cmp al,'A'
  497.         je a_switch
  498.         cmp al,'r'                      ;Check for RECURSIVE switch
  499.         je r_switch
  500.         cmp al,'R'
  501.         je r_switch
  502.         cmp al,'p'                      ;Check for PAGE switch
  503.         je p_switch
  504.         cmp al,'P'
  505.         je p_switch
  506.         cmp al,'w'                      ;Check for WIDE switch
  507.         je w_switch
  508.         cmp al,'W'
  509.         je w_switch
  510.         jmp error                       ;Illegal damn switch
  511.  
  512. a_switch:
  513.         mov attrib_mask,37h             ;Look also for hidden and system files
  514.         mov attrib_on,1                 ;Set attrib flag on
  515.         jmp loop1
  516. r_switch:
  517.         mov recursive_flag,1            ;Set recursive flag on
  518.         jmp loop1
  519. p_switch:
  520.         mov page_flag,1                 ;Set page flag on
  521.         jmp loop1
  522. w_switch:
  523.         mov wide_flag,1                 ;Set wide flag on
  524.         jmp loop1
  525.  
  526. ;-----------------------------------------------------------------------------
  527. process_full_path:
  528.         mov bx,si
  529.         dec bx                                  ;BX points to last '\'
  530.         mov di,bx
  531. common_stuff:
  532.         call slashscan                          ;Set BX to last '\'
  533.                                                 ;Set DI to beginning of path
  534.                                                 ;Set SI to end of path
  535.         call save_cur_dir
  536.         call change_drive
  537.         call change_dir                         ;Change to specified directory
  538.         mov directory_set,1
  539.         jmp loop1
  540.  
  541. ;-----------------------------------------------------------------------------
  542. process_rel_path:
  543.         cmp drive_set,0                 ;Has the drive been set yet?
  544.         jnz do_path_spec                ;If it has, we must have a pathspec
  545.         call checkdrive                 ;If not see if it is a drive..
  546.         jmp loop1                       ; and go back and loop through rest
  547. do_path_spec:
  548.         mov di,si                       ;Set DI to beginning of relative path
  549.         dec di
  550.         xor bx,bx                       ;Set BX to 0, there is no last '\'
  551.         jmp common_stuff                ;Go do normal path processing
  552.  
  553. error:
  554.         mov dx,OFFSET nofoundswitch     ;Print Illegal switch message
  555.         call write_string
  556.         mov dx,OFFSET illegalswitch     ;Print Usage statement
  557.         call write_string
  558.         call send_crlf
  559.         mov dl,16
  560.         call goto_col
  561.         mov dx,OFFSET legalswitches     ;Print all legal switches
  562.         call write_string
  563.         call send_crlf
  564.  
  565.         mov ah,4ch                      ;Exit to DOS
  566.         int 21h
  567.  
  568. exit_check:
  569.         cmp directory_set,0             ;Has the directory been set yet?
  570.         jne exit_process_psp            ;If yes, we can exit
  571.  
  572.  
  573. exit_default:                           ;If not
  574.         call save_cur_dir               ;Save the current directory
  575.         mov cx,3                        ;Move *.* to the filespec area
  576.         mov si,OFFSET def_filespec
  577.         call set_filespec
  578.         cmp drive_set,0                 ;Has the drive been set yet?
  579.         je exit_process_psp             ;If not, we can exit
  580.         call change_drive               ;If so, change to correct drive
  581.                                         ; and exit
  582.  
  583. exit_process_psp:
  584.         pop bp                          ;Restore registers and leave
  585.         pop si
  586.         pop di
  587.         pop dx
  588.         pop cx
  589.         pop bx
  590.         pop ax
  591.         ret
  592.  
  593. process_psp     ENDP
  594.  
  595.         public checkdrive
  596. ;-----------------------------------------------------------------------;
  597. ; This procedure checks if the 2 characters pointed to by DS:SI are a   ;
  598. ; drive specification.  If it is a legal drivespec the drive number     ;
  599. ; will be put into tempdrive, and CL and SI are set as needed.          ;
  600. ; If they are not legal, CL and SI are set back over these characters   ;
  601. ; for further scanning.                                                 ;
  602. ;-----------------------------------------------------------------------;
  603. checkdrive      PROC
  604.  
  605.         push ax
  606.  
  607.  
  608.         dec si                          ;When alpha is found move back
  609.         lodsw                           ; and get a whole word to test
  610.         cmp ah,':'                      ;Do we have a drive specification?
  611.         je setdrive                     ;If yes, go set it
  612.         jmp exit_no
  613.  
  614. setdrive:
  615.         cmp al,'A'                      ;Check if under legal range
  616.         jl exit_no
  617.         cmp al,'z'                      ;Check if over legal range
  618.         jg exit_no
  619.         cmp al,'a'                      ;Check the case
  620.         jl lowercase                    ;If less than 'a' it is lowercase
  621.         sub al,'a'
  622.         jmp ok
  623. lowercase:
  624.         sub al,'A'                      ;Adjust from ASCII to drive number
  625. ok:
  626.         dec cl
  627.         mov tempdrive,al                ;Store the drive number in memory
  628.         jmp exit_checkdrive
  629. exit_no:
  630.         inc cl
  631.         sub si,2                        ;Backup if no drive was selected
  632. exit_checkdrive:
  633.         mov drive_set,1
  634.         pop ax
  635.         ret
  636.  
  637. checkdrive      ENDP
  638.  
  639.         public  slashscan
  640. ;-----------------------------------------------------------------------;
  641. ; This procedure will scan a path specification and mark the end of it  ;
  642. ; with a zero byte, and point SI to this zero byte, point BX to the     ;
  643. ; backslash character.                                                  ;
  644. ;-----------------------------------------------------------------------;
  645. slashscan       PROC
  646.  
  647. loop2:
  648.         jcxz exit_slashscan             ;When count is zero, we're done
  649.         dec cl                          ;Decrement count
  650.         lodsb                           ;Get a byte
  651.         cmp al,' '                      ;If a space, path is complete
  652.         je space_exit
  653.         cmp al,0
  654.         je space_exit
  655.         cmp al,'\'                      ;This is what we are looking for!
  656.         jne loop2
  657.         mov bx,si
  658.         dec bx                          ;Move BX to this '\'
  659.         jmp loop2
  660.  
  661. space_exit:
  662.         inc cl                          ;Move back to the space
  663.         dec si
  664.         xchg si,bx                      ;End the patch with a ZERO
  665.         xor al,al
  666.         mov [bx],al
  667.         xchg bx,si                      ;Move BX back to where it belongs
  668.  
  669. exit_slashscan:
  670.         ret
  671.  
  672. slashscan       ENDP
  673.  
  674.  
  675.         public save_cur_dir
  676. ;-----------------------------------------------------------------------;
  677. ; This procedure gets the current directory and saves it in memory.     ;
  678. ;-----------------------------------------------------------------------;
  679. save_cur_dir    PROC
  680.  
  681.         push si
  682.         mov si,OFFSET directory+1       ;Get OFFSET one past a '\'
  683.         mov ah,47h
  684.         mov dl,0
  685.         int 21h                         ;Get current directory
  686.         pop si
  687.         ret
  688.  
  689. save_cur_dir    ENDP
  690.  
  691.  
  692.         public change_drive
  693. ;-----------------------------------------------------------------------;
  694. ; This procedure changes to the drive number in tempdrive if necessary. ;
  695. ;-----------------------------------------------------------------------;
  696. change_drive  PROC   
  697.  
  698.         mov al,tempdrive
  699.         cmp startdrive,al               ;If a drive change was indicated
  700.         je exit_change_drive            ;call BIOS to change to it
  701.         mov dl,tempdrive
  702.         mov ah,0eh
  703.         int 21h
  704. exit_change_drive:
  705.         ret
  706.  
  707. change_drive    ENDP
  708.  
  709.  
  710.         public change_dir
  711. ;-----------------------------------------------------------------------;
  712. ; This procedure tries to change to a specified directory.  It assumes  ;
  713. ; DI points to the beginning of a full path specification.  BX points   ;
  714. ; to the last '\' before the end.  SI points to the byte after the last ;
  715. ; character in path specification.                                      ;
  716. ;-----------------------------------------------------------------------;
  717. change_dir      PROC
  718.  
  719.         push si
  720.         push cx
  721.         mov dx,di                       ;Assume whole thing is directory
  722.         mov ah,3bh
  723.         int 21h
  724.         jnc default                     ;Is a legal directory
  725.         cmp bx,0
  726.         je pre_set_filespec
  727.         xor ah,ah
  728.         mov [bx],ah                     ;Separate filespec and path with a zero
  729.         cmp di,bx                       ;Is the last '\' also the first '\'?
  730.         je root_dir                     ;If so, we want to use just '\' as path
  731.         mov ah,3bh                      ;Try this new directory
  732.         int 21h
  733.         jc error_change_dir             ;Neither is legal directory
  734.         jmp setfilespec
  735.  
  736. root_dir:
  737.         mov dx,OFFSET root              ;Set for the '\' path
  738.         mov ah,3bh                      ;Change to the '\' path
  739.         int 21h
  740.         jmp setfilespec
  741.  
  742. default:
  743.         mov cx,3
  744.         mov si,OFFSET def_filespec      ;Move *.* in as filespec
  745.         call set_filespec
  746.         jmp exit_change_dir
  747.  
  748. pre_set_filespec:
  749.         mov bx,di                       ;If BX was 0, we need to set it
  750.         dec bx                          ;
  751. setfilespec:
  752.         inc bx
  753.         mov cx,si
  754.         sub cx,bx
  755.         mov si,bx                       ;DS:SI is source filespec
  756.         call set_filespec
  757.         jmp exit_change_dir
  758.  
  759. error_change_dir:
  760.         mov dx,OFFSET nofoundpath
  761.         call write_string
  762.         mov dx,OFFSET illegalswitch
  763.         call write_string
  764.         call send_crlf
  765.  
  766.         mov ah,4ch                      ;Return to DOS
  767.         int 21h
  768.  
  769.  
  770. exit_change_dir:
  771.         pop cx
  772.         pop si
  773.         mov bx,si
  774.         mov al,20h
  775.         mov [bx],al                     ;Move a space back over the ZERO
  776.         ret
  777.  
  778. change_dir      ENDP
  779.  
  780.  
  781.         public set_filespec
  782. ;-----------------------------------------------------------------------;
  783. ; This procedure will set the filespec to the desired pattern.          ;
  784. ; On ENTRY: CX=number of characters to move, SI source for move.        ;
  785. ;-----------------------------------------------------------------------;
  786. set_filespec     PROC
  787.  
  788.         mov di,OFFSET filespec          ;ES:DI is destination of filespec
  789.         rep movsb                       ;Do the move
  790.         ret
  791.  
  792. set_filespec     ENDP
  793.  
  794.  
  795.         public write_date
  796.     extrn write_decimal:proc, write_char:proc
  797. ;-----------------------------------------------------------------------;
  798. ; Prints a file's date when given the date stamp from the DTA        ;
  799. ;                                    ;
  800. ; Expects address of date to be DS:DX                    ;
  801. ;-----------------------------------------------------------------------;
  802. write_date      proc
  803.     push ax            ;Save those registers!
  804.     push bx
  805.         push cx
  806.         push dx
  807.     
  808.     
  809.     mov bx,dx        ;Move offset into BX 
  810.     mov ax,[bx]        ;Move date into AX
  811.     push ax            ;Save it!
  812.     
  813.     and ax,01e0h        ;Save only month bits(8-5)
  814.     mov cl,5        ;Shift to get actual value in AX
  815.     shr ax,cl
  816.     cmp ax,9        
  817.     jg just_print1        ;If greater than 9 just print
  818.         mov dl,'0'              ;Otherwise, print a leading zero
  819.         call write_char
  820. just_print1:
  821.     mov dx,ax
  822.     call write_decimal
  823.     mov dl,'-'
  824.     call write_char
  825.     
  826.         pop ax                  ;Get the correct date back
  827.         push ax                 ;Save it again
  828.     and ax,001fh        ;Save only day bits (4-0)
  829.     cmp ax,9
  830.     jg just_print2        ;If greater than 9 just print
  831.         mov dl,'0'              ;Otherwise, add a leading zero
  832.         call write_char
  833. just_print2:
  834.     mov dx,ax
  835.     call write_decimal
  836.     mov dl,'-'
  837.     call write_char
  838.     
  839.         pop ax                  ;Get back the date one more time
  840.     and ax,0fe00h        ;Save only the year bits (15-9)            
  841.     mov cl,9
  842.     shr ax,cl        ;Shift to get actual value
  843.         add ax,80               ;Date is relative to 1980
  844.         mov dx,ax
  845.     call write_decimal
  846.  
  847.     pop dx
  848.         pop cx
  849.         pop bx
  850.     pop ax
  851.     ret
  852.  
  853. write_date endp
  854.  
  855.  
  856.         public write_time
  857. ;-----------------------------------------------------------------------;
  858. ; This procedure prints the time stamp associated with a file on the    ;
  859. ; screen at the current cursor position.                                ;
  860. ; Expects DS:DX to be the date in the DTA.                              ;
  861. ;-----------------------------------------------------------------------;
  862. write_time      PROC
  863.         push ax                         ;Save registers of course
  864.         push bx
  865.         push cx
  866.         push dx
  867.         
  868.         mov bx,dx
  869.         mov ax,[bx]                     ;Get the time word into AX
  870.         push ax                         ;Save the time for later
  871.  
  872.         and ax,0f800h                   ;Save only the hour bits(15-11)
  873.         mov cl,11                       ;Shift to get correct value is AX
  874.         shr ax,cl
  875.         mov bx,OFFSET time_table        ;Get offset of date translation table
  876.         xlat                            ;Get translated byte into AL
  877.         mov bl,al                       ;Save AL for later use
  878.         and bl,10h                      ;Save only AM/PM flag in BL
  879.         mov cl,4                        ;Shift for correct value in BL
  880.         shr bl,cl
  881.         test al,20h                     ;Test for the space bit
  882.         jnz write_a_space               ;If space bit on, write a space
  883.         jmp continue                    ; otherwise, continue
  884. write_a_space:
  885.         mov dl,' '
  886.         call write_char
  887. continue:
  888.         and al,0fh                      ;Now just save the hour number
  889.         mov dx,ax                       ;Write the hour
  890.         call write_decimal
  891.         mov dl,':'                      ;Write time separator
  892.         call write_char
  893.  
  894.         pop ax                          ;Get the date back
  895.         and ax,07e0h                    ;Save only the minutes
  896.         mov cl,5                        ;Shift for correct value in AL
  897.         shr ax,cl
  898.         cmp ax,9                        ;If min. > 9 no leading zero needed
  899.         jg just_write
  900.         mov dl,'0'                      ;Write the leading zero
  901.         call write_char
  902. just_write:
  903.         mov dx,ax
  904.         call write_decimal              ;Write the minutes
  905.         mov al,bl                       ;Translate 0 into 'a' and 1 into 'p'
  906.         mov bx,OFFSET am_pm_table
  907.         xlat
  908.         mov dl,al                       ;Write the 'a' or 'p'
  909.         call write_char
  910.  
  911.  
  912.         pop dx                          ;Restore registers and exit
  913.         pop cx
  914.         pop bx
  915.         pop ax
  916.         ret
  917.  
  918. write_time      ENDP
  919.         public bin_to_ascii
  920. ;-----------------------------------------------------------------------;
  921. ; This procedure will take a 2 word (32 bit) number stored at DI:SI,     ;
  922. ; where DI contains the most significant part and SI the least         ;
  923. ; significant part, and convert it into a ASCII string and print it on    ;
  924. ; the screen at the current cursor location.                ;
  925. ;-----------------------------------------------------------------------;
  926. bin_to_ascii  PROC
  927.     push ax                ;Save registers
  928.     push bx
  929.     push cx
  930.     push dx
  931.     push bp
  932.     push si
  933.     push di
  934.  
  935.     xor ax,ax            ;Initialize to zero AX,BX,BP
  936.     mov bx,ax
  937.     mov bp,ax
  938.     mov cx,32            ;32 bits to convert
  939. next_bit:
  940.     shl si,1            ;Shift DI:SI left maintaining    
  941.     rcl di,1            ;the carry out
  942.     xchg ax,bp            ;Start work on BP
  943.     call func4            ;Add to accumulator
  944.     xchg ax,bp            ;Put back BP
  945.     xchg ax,bx            ;Start work on BX
  946.     call func4            ;Add to BX any carry caused by BP 
  947.     xchg ax,bx            ;Put back BX
  948.     call func4            ;Now do AX, adding any carry
  949.     loop next_bit            ;Continue for 32 bits
  950.  
  951. ;-----------------------------------------------------------------------;
  952. ; At this point we have AX:BX:BP equal to the decimal number we want to    ;
  953. ; print.  AX=MSBs BP=LSBs                        ;
  954. ;-----------------------------------------------------------------------;    
  955.  
  956.         cld                             ;Forward increments
  957.         mov di,OFFSET p_field           ;Destination is print field
  958.         call form_reg                   ;Process AX digits
  959.         mov ax,bx
  960.         call form_reg                   ;Process BX digits
  961.         mov ax,bp
  962.         call form_reg                   ;Process CX digits
  963.  
  964.         mov bx,OFFSET p_field           ;Now Remove excess digits and
  965.         mov cx,14                       ; commas.
  966.         xor ax,ax
  967. form_loop:
  968.         cmp BYTE PTR [bx],30h           ;If a digit start printing here
  969.         jg set_dx
  970.         inc bx                          ;Try next char
  971.         inc ax                          ;Increment counter of removed chars
  972.         loop form_loop
  973. set_dx:
  974.         sub ax,3                        ;Calculate number of pad chars
  975.         mov cx,ax                       ;Use this a loop amount
  976. spaces_add:
  977.         mov dl,' '                      ;Pad with spaces
  978.         call write_char
  979.         loop spaces_add
  980.  
  981.         mov dx,bx                       ;Print the comma'ed number
  982.         call write_string
  983.  
  984.         pop di                          ;Restore registers
  985.         pop si
  986.         pop bp
  987.         pop dx
  988.         pop cx
  989.         pop bx
  990.         pop ax
  991.  
  992.         ret
  993. bin_to_ascii  ENDP
  994.  
  995.         public form_reg
  996. ;-----------------------------------------------------------------------;
  997. ; This procedure will process the 4 BCD digits in the p_field to put    ;
  998. ; commas in the number.  It converts from BCD to ASCII.                 ;
  999. ;-----------------------------------------------------------------------;
  1000. form_reg        PROC
  1001.  
  1002.         push ax                         ;Save AX
  1003.         xchg al,ah                      ;Move the high bits to the low bits
  1004.         shr al,1                        ;shift right 4 times
  1005.         shr al,1
  1006.         shr al,1
  1007.         shr al,1
  1008.         and al,0fh                      ;Convert to ASCII
  1009.         or al,030h
  1010.         cmp BytE PTR ES:[DI],','        ;If it is a comma skip it
  1011.         jne over1
  1012.         inc di
  1013. over1:
  1014.         stosb                           ;Put char in print field
  1015.         pop ax                          ;Get back AX
  1016.         push ax                         ;Resave it
  1017.         xchg al,ah                      ;Move high bits to low bits
  1018.         and al,0fh                      ;Convert to ASCII
  1019.         or al,030h
  1020.         cmp BYTE PTR ES:[DI],','        ;Skip if comma
  1021.         jne over2
  1022.         inc di
  1023. over2:
  1024.         stosb                           ;Store the byte in print field
  1025.         pop ax                          ;Get back AX
  1026.         mov ah,al                       ;Save low bits in high bits
  1027.         shr al,1                        ;Shift low bits 4 times
  1028.         shr al,1
  1029.         shr al,1
  1030.         shr al,1
  1031.         and al,0fh                      ;Convert to ASCII
  1032.         or al,030h
  1033.         cmp BYTE PTR ES:[DI],','        ;Skip if comma
  1034.         jne over3
  1035.         inc di
  1036. over3:
  1037.         stosb                           ;Store the byte
  1038.         xchg al,ah                      ;Get low bits back
  1039.         and al,0fh                      ;Convert to ASCII
  1040.         or al,030h
  1041.         cmp BYTE PTR ES:[DI],','        ;Skip if comma
  1042.         jne over4
  1043.         inc di
  1044. over4:
  1045.         stosb                           ;Store in print field
  1046.  
  1047.         ret                             ;Return!
  1048.  
  1049. form_reg ENDP
  1050.  
  1051. ;-----------------------------------------------------------------------;
  1052. ; This procedure takes a 2 byte value and accumulates a BCD value in    ;
  1053. ; it, taking into account the carry from the last operation whether it    ;
  1054. ; be a shift or a ADC.  On exit there may also be a carry active for    ;
  1055. ; use in the next 2 byte register. Entry is in AX.            ;
  1056. ;-----------------------------------------------------------------------;
  1057.  
  1058. func4   PROC
  1059.     adc al,al            ;Mult by 2 and add carry
  1060.     daa                ;Adjust to BCD
  1061.     xchg al,ah            ;Now work on other digit
  1062.     
  1063.     adc al,al            ;Mult by 2 and add carry        
  1064.     daa                ;Adjust to BCD
  1065.     xchg al,ah            ;Return AX to correct position
  1066.     ret
  1067. func4    ENDP
  1068.  
  1069.     public write_volume
  1070. ;-----------------------------------------------------------------------;
  1071. ; This procedure will write out a volume name message for the current    ;
  1072. ; drive.                                ;
  1073. ;-----------------------------------------------------------------------;
  1074. write_volume    PROC
  1075.     mov ah,2fh
  1076.     int 21h                ;Get the current DTA
  1077.  
  1078.         mov dx,OFFSET volumespec        ;Get the *.* filespec
  1079.     mov cx,08h            ;8 is volume attrib.
  1080.     mov ah,4eh            ;Find file
  1081.     int 21h
  1082.         jnc no_carry
  1083.         jmp carry_set
  1084. no_carry:
  1085.         xor cx,cx
  1086. carry_set:
  1087.         mov dx,OFFSET volumemess1       ;"Volume in Drive "
  1088.     call write_string
  1089.         mov dl,tempdrive                ;Get specified drive
  1090.         add dl,'A'                      ;Adjust to ASCII
  1091.         call write_char
  1092.         cmp cx,0
  1093.         jnz no_volume
  1094.         mov dx,OFFSET volumemess2       ;" is "
  1095.         call write_string
  1096.  
  1097.     mov dx,OFFSET FName        ;Get offset of volume name
  1098.     mov bx,dx            ;Put in BX for addressing
  1099.         jmp next_byte
  1100.  
  1101. no_volume:
  1102.         mov dx,OFFSET volumemess3       ;" has no label. "
  1103.         jmp done_no_ext
  1104.  
  1105.  
  1106. next_byte:
  1107.     xor al,al            ;Clear for compare
  1108.     cmp al,[bx]            ;If we see a zero, were are done
  1109.     je done_no_ext
  1110.     mov ax,'.'            ;Now see if it is a '.'
  1111.     cmp al,[bx]
  1112.     je squish            ;If so, then take the '.' out
  1113.     inc bx                ;Otherwise, try next character
  1114.     jmp next_byte
  1115. squish:
  1116.     mov ah,[bx+1]            ;Move 4 bytes to a position
  1117.     mov al,[bx+2]            ;One less than their previous
  1118.     mov ch,[bx+3]            ;positions
  1119.     mov cl,[bx+4]
  1120.     mov [bx],ah
  1121.     mov [bx+1],al
  1122.     mov [bx+2],ch
  1123.     mov [bx+3],cl
  1124. done_no_ext:        
  1125.     call write_string        ;Write the volume name 
  1126.         call send_crlf
  1127.         mov dx,OFFSET dirmess1          ;"Directory of "
  1128.         call write_string
  1129.         mov dl,tempdrive                ;Put the drive letter in front   SS
  1130.         add dl,'A'                      ; of the path listing of dir     SS
  1131.         call write_char                 ;Puts colon after drive letter   SS
  1132.         mov dx,OFFSET colon             ;                                SS
  1133.         call write_string               ;                                SS
  1134.         mov dx,OFFSET tempdir           ;Write the specified directory
  1135.         call write_string
  1136.         mov dx,OFFSET dirmess2          ;"     Filespec:  "
  1137.         call write_string
  1138.         mov dx,OFFSET filespec          ;Write current file specification
  1139.         call write_string
  1140.         call send_crlf
  1141.         ret
  1142. write_volume    ENDP
  1143.  
  1144.     public    write_trailer
  1145.     EXTRN     goto_col:proc
  1146. ;-----------------------------------------------------------------------;
  1147. ; This will print the number of files specified, byte count in these    ;
  1148. ; files and bytes left on current drive.                                ;
  1149. ;-----------------------------------------------------------------------;
  1150. write_trailer   PROC
  1151.         cmp wide_flag,0
  1152.         jne wide_entry
  1153.         mov si,WORD PTR accum_filesize
  1154.         mov di,WORD PTR accum_filesize[2]
  1155.         call bin_to_ascii
  1156.         mov dx,OFFSET trailermess0
  1157.         call write_string
  1158. wide_entry:
  1159.         mov dx,files                            ;Write number of files
  1160.     call write_decimal
  1161.         mov dx,OFFSET trailermess1              ;Write "File(s)   "
  1162.     call write_string
  1163.     mov dl,0                ;Set for current drive
  1164.     mov ah,36h                ;Get free clusters
  1165.     int 21h
  1166.     xor dx,dx
  1167.         mul cx                                  ;Calculate free bytes
  1168.         mul bx
  1169.         mov si,ax                               ;Write the ASCII number
  1170.         mov di,dx
  1171.         call bin_to_ascii
  1172.     mov dx,OFFSET trailermess2        ;Write " bytes free. "
  1173.     call write_string
  1174.     ret
  1175. write_trailer    ENDP
  1176.  
  1177.         public write_attributes
  1178. ;-----------------------------------------------------------------------;
  1179. ; This procedure will print the attribute of each file as it is listed  ;
  1180. ; in the directory.  DS:DX should point to the Attrib section in DTA.   ;
  1181. ;-----------------------------------------------------------------------;
  1182. write_attributes        PROC
  1183.         push ax
  1184.         push bx
  1185.         push dx
  1186.  
  1187.         mov bx,dx                       ;Move offset into BX
  1188.         mov ax,[bx]                     ;Get attribute into AX
  1189.  
  1190.         test ax,0001h                   ;Is the file read only?
  1191.         jnz write_R
  1192.         mov dl,'.'                      ;If not write a DOT
  1193.         call write_char
  1194. R_return:
  1195.         test ax,0002h                   ;Is the file hidden?
  1196.         jnz write_H
  1197.         mov dl,'.'
  1198.         call write_char
  1199. H_return:
  1200.         test ax,0004h                   ;Is the file a system file?
  1201.         jnz write_S
  1202.         mov dl,'.'
  1203.         call write_char
  1204. S_return:
  1205.         test ax,0010h                   ;Is the file a directory?
  1206.         jnz write_D
  1207.         mov dl,'.'
  1208.         call write_char
  1209. D_return:
  1210.         test ax,0020h                   ;Is the file an archive file?
  1211.         jnz write_A
  1212.         mov dl,'.'
  1213.         call write_char
  1214.         jmp done_write_attributes
  1215.  
  1216. write_R:
  1217.         mov dl,'R'                      ;Write the characters
  1218.         call write_char
  1219.         jmp R_return
  1220. write_H:
  1221.         mov dl,'H'
  1222.         call write_char
  1223.         jmp H_return
  1224. write_S:
  1225.         mov dl,'S'
  1226.         call write_char
  1227.         jmp S_return
  1228. write_D:
  1229.         mov dl,'D'
  1230.         call write_char
  1231.         jmp D_return
  1232. write_A:
  1233.         mov dl,'A'
  1234.         call write_char
  1235.  
  1236. done_write_attributes:
  1237.         pop dx                          ;Restore the registers and return
  1238.         pop bx
  1239.         pop ax
  1240.         ret
  1241.  
  1242. write_attributes        ENDP
  1243.  
  1244.         public tally_files
  1245. ;-----------------------------------------------------------------------;
  1246. ; This procedure adds the 32bit number currently in DI:SI               ;
  1247. ; to the 32bit number in accum_filesize.                                ;
  1248. ;-----------------------------------------------------------------------;
  1249. tally_files PROC
  1250.         push ax
  1251.         push dx
  1252.         push di
  1253.  
  1254.         mov ax,WORD PTR accum_filesize          ;Add least significant bytes
  1255.         add ax,si
  1256.         mov dx,WORD PTR accum_filesize[2]       ;Add most significant bytes
  1257.         adc dx,di                               ; with carry
  1258.         cld
  1259.         mov di,OFFSET accum_filesize            ;Store the result in memory
  1260.         stosw
  1261.         mov ax,dx
  1262.         stosw
  1263.  
  1264.         pop di
  1265.         pop dx
  1266.         pop ax
  1267.         ret
  1268. tally_files     ENDP
  1269.  
  1270.  
  1271.         END     disk_dir
  1272.