        TITLE   'Dir - RxDOS Command Shell Dir Function'
        PAGE 59, 132
        .LALL

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  RxDOS Command Shell Dir                                      ;
        ;...............................................................;

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Real Time Dos                                                ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  This material  was created as a published version  of a DOS  ;
        ;  equivalent product.   This program  logically  functions in  ;
        ;  the same way as  MSDOS functions and it  is  internal  data  ;
        ;  structure compliant with MSDOS 6.0                           ;
        ;                                                               ;
        ;  This product is distributed  AS IS and contains no warranty  ;
        ;  whatsoever,   including  warranty  of   merchantability  or  ;
        ;  fitness for a particular purpose.                            ;
        ;                                                               ;
        ;                                                               ;
        ;  (c) Copyright 1990, 1997. Api Software and Mike Podanoffsky  ;
        ;      All Rights Reserved Worldwide.                           ;
        ;                                                               ;
        ;  This product is protected under copyright laws and  may not  ;
        ;  be reproduced  in whole  or in part, in any form  or media,  ;
        ;  included but not limited to source listing, facsimile, data  ;
        ;  transmission, cd-rom, or  floppy disk without the expressed  ;
        ;  written consent of the author.                               ;
        ;                                                               ;
        ;  License  for  distribution  for commercial  use  or  resale  ;
        ;  required from:                                               ;
        ;                                                               ;
        ;  Api Software                                                 ;
        ;  12 South Walker Street                                       ;
        ;  Lowell,  MA   01851                                          ;
        ;                                                               ;
        ;  internet: mikep@world.std.com                                ;
        ;                                                               ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;  Compile with MASM 5.1                                        ;
        ;...............................................................;

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  RxDOS Command Shell                                          ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Programmer's Notes:                                          ;
        ;                                                               ;
        ;  Command Shell consists of  two parts bound  together into a  ;
        ;  single executable load.  There  exists  a  single  resident  ;
        ;  command shell which is accessible by an Int 2Eh.             ;
        ;                                                               ;
        ;...............................................................;

        include rxdosmac.asm
        include rxdosdef.asm
        include rxdoscin.asm

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  RxDOS Command Shell                                          ;
        ;...............................................................;

RxDOSCMD SEGMENT PARA PUBLIC 'CODE'
         assume cs:RxDOSCMD, ds:RxDOSCMD, es:RxDOSCMD, ss:RxDOSCMD

        public _Dir
        public _splitpath
        public _makePath

        extrn CheckOptOneArg                            : near
        extrn CmndError_InvalidDrive                    : near
        extrn CmndError_NoFilesFound                    : near
        extrn CRLF                                      : near
        extrn DisplayLine                               : near
        extrn DisplayErrorMessage                       : near
        extrn PreProcessCmndLine                        : near
        extrn RxDOS_AllFiles                            : near
        extrn setPagingMode                             : near
        extrn _AppendPathName                           : near
        extrn _CopyString                               : near

        extrn _DirAttribSwitch                          : near
        extrn _DirBareSwitch                            : near
        extrn _DirLowerCaseSwitch                       : near
        extrn _DirOrderSwitch                           : near
        extrn _DirPauseSwitch                           : near
        extrn _DirSubDirSwitch                          : near
        extrn _DirSwitches                              : near
        extrn _DirWideSwitch                            : near
        extrn _Dir_DirectoryOf                          : near
        extrn _Dir_DirEntry                             : near
        extrn _Dir_FileEntry                            : near
        extrn _Dir_Files                                : near
        extrn _Dir_NoVolumeLabel                        : near
        extrn _Dir_VolumeLabel                          : near
        extrn _Dir_VolumeSerialNumber                   : near

        extrn RxDOS_DTA                                 : near
        extrn _lowerCase                                : near
        extrn _lowerCaseString                          : near
        extrn _endofString                              : near
        extrn _sprintf                                  : near
        extrn returnVolumeName                          : near


        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Dir Time To Ascii (USA Format)                               ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Input:                                                       ;
        ;   ax     time value                                           ;
        ;   di     address to display time of day                       ;
        ;                                                               ;
        ;...............................................................;


_dirTimeToAscii:

        push di
        
        push ax
        mov ch, 'a'
        mov cl, 11                              ; ch = 0
        shr ax, cl                              ; hours
        cmp ax, 13                              ; 1 pm or greater ?
        jc _dirTimeToAscii_08                   ; no -->

        sub ax, 12                              ; 1 pm or greater
        mov ch, 'p'                             ; set pm flag
        
_dirTimeToAscii_08:
        mov cl, 10
        div cl
        or ax, '00'                             ; conv to ascii
        stosw

        mov al,':'
        stosb

        pop ax
        mov cl, 5
        shr ax, cl                              ; minutes
        and ax, 00111111b                       ; mask off hours
        
        mov cl, 10
        div cl
        or ax, '00'                             ; conv to ascii
        stosw

        xor ah, ah
        mov al, ch
        stosw

        pop di
        cmp byte ptr [ di ], '0'
        jnz _dirTimeToAscii_12
        mov byte ptr [ di ], ' '

_dirTimeToAscii_12:
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Dir Date To Ascii (USA Format)                               ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Input:                                                       ;
        ;   ax     date value                                           ;
        ;   di     address to display date of day                       ;
        ;                                                               ;
        ;...............................................................;

_dirDateToAscii:

        push di
        push ax
        mov cl,  5
        shr ax, cl                              ; Month
        and ax, 00001111b                       ; mask off year 

        mov cl, 10
        div cl
        or ax, '00'                             ; conv to ascii
        stosw

        mov al,'-'
        stosb

        pop ax
        push ax
        and ax, 00011111b                       ; mask off everything but day
        
        mov cl, 10
        div cl
        or ax, '00'                             ; conv to ascii
        stosw

        mov al,'-'
        stosb

        pop ax
        mov cl,  9
        shr ax, cl                              ; Year
        and ax, 01111111b                       ; mask
        add ax, 80                              ; 80 plus
        cmp ax, 100                             ; past year 2000 ?
        jc _dirDateToAscii_08                   ; no need to adjust -->

        sub ax, 100                             ; 2000 plus

_dirDateToAscii_08:
        mov cl, 10
        div cl
        or ax, '00'                             ; conv to ascii
        stosw

        xor al, al
        stosb

        pop di
        cmp byte ptr [ di ], '0'
        jnz _dirDateToAscii_12
        mov byte ptr [ di ], ' '

_dirDateToAscii_12:
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  test drive letter                                            ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Input:                                                       ;
        ;   al     drive letter or null character                       ;
        ;                                                               ;
        ;  Returned:                                                    ;
        ;   al     drive (0 = A:, 1=B:, ... )                           ;
        ;   cy     if not valid                                         ;
        ;   zr     if null or default drive                             ;
        ;                                                               ;
        ;...............................................................;

_testDriveLetter:
        or al, al                                       ; default drive ?
        jz _testDriveLetter_Return                      ; yes -->

        cmp al, 'A'                                     ; 'A' - 'Z' ?
        jc _testDriveLetter_Return                      ; no -->
        cmp al, 'Z' + 1
        jc _testDriveLetter_Valid                       ; no -->

        cmp al, 'a'                                     ; 'a' - 'z' ?
        jc _testDriveLetter_Return                      ; no -->
        cmp al, 'z' + 1
        jc _testDriveLetter_Valid                       ; no -->

        stc
        jmp short _testDriveLetter_Return

_testDriveLetter_Valid:
        dec al
        and al, 1Fh                                     ; just drive letter

_testDriveLetter_Return:
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Split Path                                                   ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   si     points to filename to split                          ;
        ;   di     points to expanded name area                         ;
        ;...............................................................;

_splitpath:

        Entry
        
        def _source, si
        def _expandedname, di
        def _extension
        def _wildchars, 0000

        clearMemory sizeExpandedName                    ; clear expand area

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  examine/ extract drive letter from path
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        cmp byte ptr [ si+1 ],':'                       ; test for drive letter
        jnz _splitpath_08                               ; no drive letter entered -->

        mov al, byte ptr [ si ]
        mov byte ptr [ expDrive ][ di ], al             ; isolate drive letter
        inc si
        inc si

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  scan string through entire path until extension, if any.
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_splitpath_08:
        xor ax, ax                                      ; prev character
        mov dx, si
        push si

_splitpath_12:
        xor cx, cx                                      ; last . separator, if any

_splitpath_16:
        mov ah, al                                      ; prev character
        mov al, byte ptr [ si ]
        inc si
        or al, al                                       ; end of string ?
        jz _splitpath_28                                ; if yes -->
        cmp al, '/'                                     ; path separator ?
        jz _splitpath_24                                ; if yes -->
        cmp al, '\'                                     ; path separator ?
        jz _splitpath_24                                ; if yes -->

        cmp al, '?'                                     ; wild character ?
        jz _splitpath_26                                ; if yes -->
        cmp al, '*'                                     ; wild character ?
        jz _splitpath_26                                ; if yes -->

        cmp al, '.'                                     ; extension separator ?
        jnz _splitpath_16

        cmp ah, '.'                                     ; previous also ..
        jz _splitpath_12                                ; yes, ignore -->
        mov cx, si                                      ; save location of extension
        dec cx                                          ; must save dot position
        jmp _splitpath_16                               ; continue scanning -->

_splitpath_24:
        mov dx, si
        jmp _splitpath_16

_splitpath_26:
        mov byte ptr [ _wildchars ][ bp ], 1
        jmp _splitpath_16

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  at end of scan, see if path defined
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_splitpath_28:
        pop si                                          ; start of path
        storarg _extension, cx                          ; save pointer to extension
        or dx, dx                                       ; path defined (\ in string ?)
        jz _splitpath_38                                ; no path defined -->

        mov cx, dx
        sub cx, si                                      ; length of path string
        cmp cx, size expPath                            ; greater than expPath ?
        jle _splitpath_30                               ; no -->
        mov cx, (size expPath) - 1                      ; max size

_splitpath_30:
        getarg di, _expandedname
        lea di, offset [ expPath ][ di ]
        rep movsb                                       ; copy path

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  copy filename
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_splitpath_38:
        getarg di, _expandedname
        lea di, offset [ expFilename ][ di ]
        mov cx, (size expFilename) - 1

        mov si, dx                                      ; get start of filename
        or si, si                                       ; no filename ?
        jz _splitpath_48                                ; no -->

_splitpath_40:
        lodsb                                           ; get character
        or al, al                                       ; if null, no extension -->
        jz _splitpath_60
        cmp al, '.'                                     ; if period
        jz _splitpath_48                                ; we have extension -->

        stosb
        loop _splitpath_40

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  copy extension
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_splitpath_48:
        getarg di, _expandedname
        lea di, offset [ expExtension ][ di ]
        mov cx, (size expExtension) - 1
        getarg si, _extension         
        or si, si                                       ; no filename ?
        jz _splitpath_60                                ; no -->

_splitpath_50:
        lodsb                                           ; get character
        or al, al                                       ; if null, no extension -->
        jz _splitpath_60

        stosb
        loop _splitpath_50

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  done
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_splitpath_60:
        mov al, byte ptr [ _wildchars ][ bp ]
        or al, al
        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Make Path                                                    ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   si     points to expanded name area                         ;
        ;   di     points to filename to build                          ;
        ;...............................................................;

_makePath:

        push si
        push di
        mov dx, si
        mov byte ptr [ di ], 00

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  insert drive  
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        lea bx, offset [ expDrive ][ si ]
        mov al, byte ptr [ bx ]
        or al, al                                       ; drive available ?
        jz _makePath_08                                 ; no -->

        mov ah, ':'
        stosw                                           ; store drive
        mov byte ptr [ di ], 00

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  insert path
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_makePath_08:
        lea si, offset [ expPath ][ si ]
        mov al, byte ptr [ si ]
        or al, al                                       ; path available ?
        jz _makePath_16                                 ; no -->

        call _CopyString                                ; copy path to output
        dec di                                          ; backup over null term
        cmp byte ptr [ di-1 ], '\'                      ; path ended in \ ?
        jz _makePath_16                                 ; no -->

        mov ax, '\'
        stosb                                           ; add \
        mov byte ptr [ di ], 00

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  insert filename
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_makePath_16:
        mov si, dx
        lea si, offset [ expFilename ][ si ]
        mov al, byte ptr [ si ]
        or al, al                                       ; filename available ?
        jz _makePath_24                                 ; no -->

        call _CopyString                                ; copy filename to output
        dec di                                          ; backup over null term

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  insert extension
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_makePath_24:
        mov si, dx
        lea si, offset [ expExtension ][ si ]
        mov al, byte ptr [ si ]
        or al, al                                       ; filename available ?
        jz _makePath_32                                 ; no -->

        call _CopyString                                ; copy filename to output

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  return
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_makePath_32:
        pop di
        pop si
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Directory                                                    ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   ss:di  Arg Array                                            ;
        ;   ax     Number of arguments in array                         ;
        ;...............................................................;

_Dir:

        Entry
        def  _currdisk
        def  _maxdisk
        def  _filesread
        def _extensionFlag
        ddef _freespace
        ddef _totalfilespace
        def __argarray, di                              ; arg array

        defbytes _asciiFileTime, 20
        defbytes _asciiFileDate, 20
        defbytes _pathname, 128                         ; search pathname
        defbytes _filename, 128                         ; search filename
        defbytes _expandedname, sizeExpandedName
        defbytes _printbuffer, 128

        xor ax, ax
        mov word ptr [ _filesread ][ bp ], ax
        mov word ptr [ _totalfilespace. _low  ][ bp ], ax
        mov word ptr [ _totalfilespace. _high ][ bp ], ax

        mov cx, 0000                                    ; min args
        mov dx, 0001                                    ; max args
        mov bx, offset _DirSwitches                     ; dir switches
        call PreProcessCmndLine                         ; process switches and args
        ifc _dir_Exit                                   ; if error -->

        mov ax, word ptr [ _DirPauseSwitch. swFlags ]
        call setPagingMode

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  get current, max disks
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        Int21 CurrentDisk                               ; get current disk
        mov dl, al
        inc al                                          ; a=1, ...
        storarg _currdisk, ax                           ; save disk letter

        Int21 SelectDisk                                ; use select disk to get max
        storarg _maxdisk, ax                            ; save max disk letter

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  if no args, create a *.* arg
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        mov di, word ptr [ __argarray ][ bp ]
        mov si, word ptr [ di ]                         ; locate dir argument
        or si, si                                       ; no name provided ?
        jnz _dir_06                                     ; name provided -->
        mov si, offset RxDOS_AllFiles                   ; dummy path 

_dir_06:
        lea di, offset [ _pathname ][ bp ]
        call _CopyString                                ; copy whatever was entered

_dir_08:
        dec di                                          ; backup over null
        cmp byte ptr [ di-1 ], ' '                      ; only entered drive and colon ?
        jz _dir_08                                      ; no -->
        cmp byte ptr [ di-1 ], ':'                      ; only entered drive and colon ?
        jnz _dir_10                                     ; no -->

        mov si, offset RxDOS_AllFiles                   ; dummy path 
        call _CopyString                                ; append all files

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  is name a directory ?
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dir_10:
        lea si, offset [ _pathname ][ bp ]
        lea di, offset [ _expandedname ][ bp ]
        call _splitpath

        mov al, byte ptr [ _expandedname. expDrive ][ bp ]
        or al, al                                       ; if no drive specified 
        jz _dir_14                                      ; continue -->

        call _testDriveLetter                           ; is drive letter 'a' - 'z' ?
        ifc _dir_DriveError                             ; no, bad drive -->

        cmp al, byte ptr [ _maxdisk ][ bp ]             ; is it greater than max drive ?
        jc _dir_14                                      ; if valid drive
        jmp _dir_DriveError                             ; yes, bad drive -->

_dir_14:
        mov al, byte ptr [ _expandedname. expExtension ][ bp ]
        mov byte ptr [ _extensionFlag ][ bp ], al       ; save whether extension was ever present

        lea si, offset [ _pathname ][ bp ]
        lea di, offset [ _filename ][ bp ]
        mov word ptr [ di ], '\'                        ; init area
        Int21 GetActualFileName                         ; expand name
        jnc _dir_16                                     ; if valid -->
        call _CopyString                                ; if error, pass original for further processing

_dir_16:
        lea si, offset [ _filename ][ bp ]
        lea di, offset [ _expandedname ][ bp ]
        call _splitpath
        jnz _dir_28                                     ; if wild characters found -->

        mov cx, ATTR_DIRECTORY
        lea dx, offset [ _filename ][ bp ]
        Int21 FindFirstFile                             ; locate file

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  if . or .. handle special
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dir_20:
        jc _dir_28                                      ; not found, try expanding -->

        test byte ptr [ RxDOS_DTA. findFileAttribute ], ATTR_DIRECTORY
        jz _dir_28                                      ; if a directory, add \*.*  -->

        cmp byte ptr [ RxDOS_DTA. findFileName ], '.'
        jnz _dir_22  

        Int21 FindNextFile                              ; locate next file
        jmp _dir_20                                     ; see if also a dir -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  if a directory name, change to include *.* for all files
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dir_22:
        lea si, offset [ _expandedname. expFilename ][ bp ]
        lea di, offset [ _expandedname. expPath     ][ bp ]
        call _AppendPathName                            ; append path name

        lea si, offset [ _expandedname. expExtension ][ bp ]
        call _CopyString                                ; append to path name

        mov byte ptr [ _expandedname. expExtension ][ bp ], 00

        mov si, offset [ RxDOS_AllFiles ]
        lea di, offset [ _expandedname. expFilename ][ bp ]
        call _CopyString
        jmp _dir_36                                     ; if none, ok to makepath

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  is name is not a directory
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dir_28:
        lea di, offset [ _expandedname. expFilename ][ bp ]
        cmp byte ptr [ di ], 00
        jnz _dir_32
        mov word ptr [ di ], '*'

_dir_32:
        lea di, offset [ _expandedname. expExtension ][ bp ]
        mov al, byte ptr [ _extensionFlag ][ bp ]       ; extension required 
        or al, byte ptr [ di ]                          ; or extension provided
        jnz _dir_36                                     ; if either -->
        mov word ptr [ di ], '*.'
        mov byte ptr [ di+2 ], 0

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  rebuild and edit name
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dir_36:
        lea si, offset [ _expandedname ][ bp ]
        lea di, offset [ _pathname ][ bp ]
        call _makePath

        lea si, offset [ _pathname ][ bp ]
        lea di, offset [ _filename ][ bp ]
        mov word ptr [ di ], '\'                        ; init area
        Int21 GetActualFileName                         ; expand name to get real display name
        jnc _dir_38                                     ; if ok -->

        lea si, offset [ _pathname ][ bp ]
        lea di, offset [ _filename ][ bp ]
        call _CopyString

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  extract drive letter
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dir_38:
        lea di, offset [ _filename ][ bp ]
        cmp byte ptr [ di+1 ], ':'
        jnz _dir_42

        xor ah, ah
        mov al, byte ptr [ di ]
        mov word ptr [ _currdisk ][ bp ], ax            ; save current disk

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  display header
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dir_42:
        test word ptr [ _DirBareSwitch. swFlags ], SW_SWITCHSET
        jnz _dir_52                                     ; skip header  -->

        mov bx, offset _Dir_NoVolumeLabel               ; assume no volume label
        mov al, byte ptr [ _currdisk ][ bp ]            ; get current disk value
        call returnVolumeName                           ; get volume for drive
        ifc _dir_DriveError                             ; cannot open drive -->
        jnz _dir_44                                     ; if no volume name -->

        push di                                         ; save vol label pointer
        mov bx, offset _Dir_VolumeLabel                 ; print statement format

_dir_44:
        lea di, offset [ _currdisk ][ bp ]              ; pointer to current disk
        push di                                         ; current disk
        push bx                                         ; format
        lea di, offset [ _printbuffer ][ bp ]
        push di
        call _sprintf
        add sp, ax                                      ; # args passed
        call DisplayLine

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  display drive: path
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        lea si, offset [ _filename ][ bp ]
        lea di, offset [ _pathname ][ bp ]
        call _copyString                                ; copy to pathname

_dir_48:
        dec di                  
        cmp byte ptr [ di ], '\'                        ; isolate path
        jnz _dir_48

        mov byte ptr [ di ], 0

        lea di, offset [ _pathname ][ bp ]
        push di                                         ; first arg encountered

        mov di, offset _Dir_DirectoryOf
        push di
        lea di, offset [ _printbuffer ][ bp ]
        push di
        call _sprintf
        add sp, ax                                      ; # args passed
        call DisplayLine

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  scan through files
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dir_52:
        mov cx, ATTR_DIRECTORY
        lea dx, offset [ _filename ][ bp ]              ; pointer to search filename
        Int21 FindFirstFile                             ; locate file
        ifc _dir_72                                     ; if none located -->

_dir_54:
        inc word ptr [ _filesread ][ bp ]               ; files read

        mov ax, word ptr [ RxDOS_DTA. findFileTime ]
        lea di, offset [ _asciiFileTime ][ bp ]
        call _dirTimeToAscii
        push di

        mov ax, word ptr [ RxDOS_DTA. findFileDate ]
        lea di, offset [ _asciiFileDate ][ bp ]
        call _dirDateToAscii
        push di

        test byte ptr [ RxDOS_DTA. findFileAttribute ], ATTR_DIRECTORY
        ifnz _dir_60                                    ; if a directory -->

        mov di, offset [ RxDOS_DTA. findFileSize ]
        mov ax, word ptr [ _low  ][ di ]
        mov dx, word ptr [ _high ][ di ]
        add word ptr [ _totalfilespace. _low  ][ bp ], ax
        adc word ptr [ _totalfilespace. _high ][ bp ], dx

        push di                                         ; third arg: file size

_dir_60:
        mov di, offset [ RxDOS_DTA. findFileName ]      ; locate extension
        mov al, byte ptr [ di ]                         ; start of filename
        call _endofString                               ; point to null terminator

        push di                                         ; terminator, in case no extension
        cmp al, '.'                                     ; filename either . or .. ?
        jz _dir_64                                      ; yes, no need to find extension -->

        mov al, '.'
        mov cx, offset [ RxDOS_DTA. findFileName ]      ; search length
        xchg di, cx                                     ; determine search length
        sub cx, di                                      ; search length
        repnz scasb                                     ; else scan for extension
        jnz _dir_64                                     ; if found, di points to extension
        mov byte ptr [ di-1 ], 0                        ; else, di will point to a null (no extension)
        pop ax
        push di                                         ; extension address, if found

_dir_64:
        mov di, offset [ RxDOS_DTA. findFileName ]
        push di                                         ; pointer to filename

        mov di, offset _Dir_FileEntry
        test byte ptr [ RxDOS_DTA. findFileAttribute ], ATTR_DIRECTORY
        ifz _dir_66                                     ; if not a directory -->

        mov di, offset _Dir_DirEntry

_dir_66:
        push di
        lea di, offset [ _printbuffer ][ bp ]
        push di
        call _sprintf
        add sp, ax                                      ; # args passed

        test word ptr [ _DirLowerCaseSwitch. swFlags ], SW_SWITCHSET
        jz _dir_68                                      ; not lower case option ->
        push ss
        push si                                         ; where string
        call _lowerCaseString                           ; lowercase string

_dir_68:
        call DisplayLine                                ; print line
        jc _dir_Exit                                    ; control C abort -->

        Int21 FindNextFile                              ; locate next file
        ifnc _dir_54                                    ; if none located -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  print number of files 
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dir_72:
        cmp word ptr [ _filesread ][ bp ], 0000         ; any files read ?
        jnz _dir_76                                     ; yes -->

        mov dx, offset CmndError_NoFilesFound
        call DisplayLine                                ; file not found
        jmp short _dir_Exit

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  display files, space used, space free
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dir_76:
        mov dl, byte ptr [ _expandedName. expDrive ][ bp ]
        and dl, 15                                      ; drive
        Int21 GetFreeDiskSpace

        mul cx                                          ; total space
        mul bx
        stordarg _freespace, dx, ax

        lea di, offset [ _freespace ][ bp ]
        push di
        lea di, offset [ _totalfilespace ][ bp ]
        push di
        lea di, offset [ _filesread ][ bp ]
        push di

        mov di, offset _Dir_Files
        push di
        lea di, offset [ _printbuffer ][ bp ]
        push di
        call _sprintf
        add sp, ax                                      ; # args passed
        call DisplayLine                                ; print line

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  done
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dir_Exit:
        Return

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  if error
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_dir_DriveError:
        mov dx, offset CmndError_InvalidDrive
        call DisplayErrorMessage                        ; display message
        Return

RxDOSCMD                        ENDS
                                END
