%TITLE          "Determine Current Directories - CHiPS bv 1997"
;**********************************************************************
;**                                                                  **
;**  Program   : DC_DIRS                                             **
;**  Purpose   : Determine Current Directories                       **
;**              Program assumes that Dir_Map table is initialized   **
;**                                                                  **
;**  Author    : B.F. Schreurs                                       **
;**              Computer High Performance Software (CHiPS) bv       **
;**  Date      : September 4th, 1997                                 **
;**                                                                  **
;**  Calls     : MEMSORT        - Sort A (Memory) File               **
;**                                                                  **
;**  Parameter : 1. Pass the address of the requested format.        **
;**                 The format specified how the data of the         **
;**                 available directories will be passed back.       **
;**                 Requested format size is 1 byte and may contain: **
;**                 "1" = Return data in format as specified in      **
;**                       DIRENTRY.STR with size DIR_ENTRY_LENGTH.   **
;**                 "2" = Return data in format                      **
;**                       "..           <DIR>      "                 **
;**                       "ATARI        <DIR>      "                 **
;**                       "MYDIR        <DIR>      "                 **
;**                       "YOURDIR      <DIR>      "                 **
;**                       "                        "                 **
;**                       "                        "                 **
;**                       "                        "                 **
;**                       etc. with size DIR_ENTRY_LENGTH            **
;**  Parameter : 2. Pass the address of the data which contains the  **
;**                 path to be searched for the directories to be    **
;**                 retrieved. Path size is PATH_LENGTH.             **
;**  Parameter : 3. Pass the address of the table where the data     **
;**                 containing the directory info will be stored.    **
;**                 Format "1": Table size: DIR_ENTRY_LENGTH *       **
;**                             number of expected libraries.        **
;**                 Format "2": Table size: DIR_ENTRY_LENGTH *       **
;**                             number of expected libraries.        **
;**                                                                  **
;**  Language  : Turbo Assembler                                     **
;**                                                                  **
;**  Returncode: 0 - No error encountered                            **
;**              1 - Drive was not ready                             **
;**                                                                  **
;**********************************************************************
        IDEAL
        JUMPS

;----------------------------------------------------------------------
;--  Functions which can be called                                   --
;----------------------------------------------------------------------
        PUBLIC  DC_DIRS

;----------------------------------------------------------------------
;--  Equates                                                         --
;----------------------------------------------------------------------
include ".\equ\attrib.equ"
include ".\equ\dos.equ"
include ".\equ\equipmnt.equ"
include ".\equ\sysdep.equ"

DIRECTORY_TEXT_LENGTH       EQU     12

;**********************************************************************
SEGMENT SSeg Para Stack 'STACK'
;**********************************************************************

        db        64 dup (0)            ; Stack

ENDS    SSeg



;**********************************************************************
SEGMENT DSeg Word Public 'DATA'
;**********************************************************************

;----------------------------------------------------------------------
;--  Structures                                                      --
;----------------------------------------------------------------------
include ".\str\direntry.str"
include ".\str\dta.str"
include ".\str\sortkeys.str"

;----------------------------------------------------------------------
;--  Working Storage                                                 --
;----------------------------------------------------------------------
GLOBAL Return_Code:Byte:1

Parm_Format_ptr_es      DW    1 dup (NULL)      ; 1 = "DIRENTRY format ..      "
                                                ;     "DIRENTRY format ATARI   "
Parm_Format_ptr_di      DW    1 dup (NULL)      ; 2 = "..           <DIR>      "
                                                ;     "ATARI        <DIR>      "
Parm_Path_Spec_ptr_es   DW    1 dup (NULL)
Parm_Path_Spec_ptr_di   DW    1 dup (NULL)

Parm_Dir_Map_ptr_es     DW    1 dup (NULL)
Parm_Dir_Map_ptr_di     DW    1 dup (NULL)

Parm_SortKeys           SortKeys<>

DOS_Find_Files_Or_Dirs  DW    1 dup (DOS_FIND_DIRECTORIES)

Requested_Format        DB    1 dup (?)
Directory_Above_Text    DB  "..           <DIR>      "
Directory_Text          DB  " <DIR>      "
Dir_Map_Entry           Dir_Entry <>
Dirs_In_Dir_Table       DW    0

Old_Dta_Seg             DW    ?                 ; Old Dta Segment Address
Old_Dta_Ofs             DW    ?                 ; Old Dta Segment Offset
Own_Dta                 Dta <>

ENDS    DSeg



;**********************************************************************
SEGMENT CSeg Word Public 'CODE'
;**********************************************************************
;----------------------------------------------------------------------
;--  External Variables                                              --
;----------------------------------------------------------------------
        EXTRN   MEMSORT:proc                    ; Sort A (Memory) File

;**********************************************************************
PROC    DC_DIRS
;**********************************************************************
        ASSUME  cs:CSeg
        ASSUME  ds:DSeg
        mov     ax, DSeg                        ; Initialize DS to address
        mov     ds, ax                          ; of data segment

        mov     bx, sp

;
; Parameter Directories
;
        mov     di, [ss:bx+2]
        mov     es, [ss:bx+4]

        mov     [Parm_Dir_Map_ptr_es], es
        mov     [Parm_Dir_Map_ptr_di], di

;
; Parameter Path
;
        mov     di, [ss:bx+6]
        mov     es, [ss:bx+8]

        mov     [Parm_Path_Spec_ptr_es], es
        mov     [Parm_Path_Spec_ptr_di], di

;
; Parameter Requested Format
;
        mov     di, [ss:bx+10]
        mov     es, [ss:bx+12]


        mov     [Parm_Format_ptr_es], es
        mov     [Parm_Format_ptr_di], di
        mov     al, [byte es:di]
        mov     [Requested_Format], al

; Init return code
        mov     al, NULL
        mov     [Return_Code], al

; Save Current Dta
        mov     ah, DOS_GET_DTA             ; Get Disk Transfer Area address
        int     DOS_SERVICE 
        mov     [Old_Dta_Seg], es           ; Save old Dta Segment Address
        mov     [Old_Dta_Ofs], bx           ; Save old Dta Segment Offset

; Specify Own Dta
        mov     dx, offset Own_Dta          ; Address of Own Dta
        mov     ah, DOS_SET_DTA
        int     DOS_SERVICE 

;
; First entry in our map is always a pointer back to root = ..
;
        mov     es, [Parm_Dir_Map_ptr_es]
        mov     di, [Parm_Dir_Map_ptr_di]
        mov     si, offset Directory_Above_Text
        mov     cx, DIR_ENTRY_LENGTH
        rep     movsb

;
; The directory search is split up in 2 parts
; Skip the Files,
; Retrieve ALL Directories
;
        mov     [Dirs_In_Dir_Table], 1          ; First entry is ..

        mov     ds, [Parm_Path_Spec_ptr_es]     ; Use specified search path
        mov     dx, [Parm_Path_Spec_ptr_di]

        mov     cx, [DOS_Find_Files_Or_Dirs]    ; Is one or the other
        xor     ax, ax                          ; Reset ax
        mov     ah, DOS_FIND_FIRST_FILE         ; Find First File
        jmp     @@20

; Retrieve dir entries
@@10:
        mov     cx, [DOS_Find_Files_Or_Dirs]    ; Is one or the other
        xor     ax, ax                      ; Reset ax
        mov     ah, DOS_FIND_NEXT_FILE      ; Find Next File

; Read VTOC
@@20:
        int     DOS_SERVICE                 ; Find First/Next Entry
        jc      @@50                        ; No more Entries?

; Check for "." or ".." entry
        mov     si, offset Own_Dta.File_Name
                                            ; Load address of filename
        cmp     [byte ds:si], DOT           ; Is this a ". " Entry?
        je      @@10                        ; Retrieve next Entry

; Check Entry for being a directory entry
        mov     si, offset Own_Dta.File_Attribute
                                            ; Load address of attribute
        xor     ax, ax                      ; Reset ax
        mov     al, [byte ds:si]            ; Load attribute
        and     al, ATTRIB_FILE_DIRECTORY
        cmp     al, ATTRIB_FILE_DIRECTORY   ; Entry is a directory?
        jne     @@10                        ; No
                                            ; Yes, so
;
; Move entry to our dir entry
;

; Init dir entry first
        mov     si, offset Dir_Map_Entry
        push    ds si
        pop     di es
        mov     cx, DIR_ENTRY_LENGTH
        xor     ax, ax
        rep     stosb

; Search the null terminator
        mov     si, offset Own_Dta.File_Name
        push    ds si
        pop     di es
        mov     cx, DIR_NAME_LENGTH         ; Search length
        inc     cx
        xor     ax, ax                      ; Search for null character
        repne   scasb                       ; Search uses es:di
        mov     bx, cx

; File_Name
        mov     si, offset Dir_Map_Entry.File_Name
        push    ds si
        pop     di es
        mov     si, offset Own_Dta.File_Name
        mov     cx, DIR_NAME_LENGTH
        sub     cx, bx
        rep     movsb

        cmp     [Requested_Format], "1"         ; DIRENTRY format?
        je      @@30                            ; Yes
                                                ; No, so
;
; Replace remaining nulls from VTOC read by spaces
;
        mov     cx, bx
        mov     al, SPACE
        rep     stosb

;
;
; Format is "..                      "
;           "ATARI        <DIR>      "
;           etc.
;
        mov     si, offset Directory_Text
        mov     cx, DIRECTORY_TEXT_LENGTH
        rep     movsb
        jmp     @@40

@@30:
; File_Size
        mov     si, offset Dir_Map_Entry.File_Size
        push    ds si
        pop     di es
        mov     si, offset Own_Dta.File_Size
        mov     cx, 4
        rep     movsb

; File_Date
        mov     si, offset Dir_Map_Entry.File_Date
        push    ds si
        pop     di es
        mov     si, offset Own_Dta.File_Date
        mov     cx, 2
        rep     movsb

; File_Time
        mov     si, offset Dir_Map_Entry.File_Time
        push    ds si
        pop     di es
        mov     si, offset Own_Dta.File_Time
        mov     cx, 2
        rep     movsb

; File_Attribute
        mov     al, offset Own_Dta.File_Attribute
        mov     [offset Dir_Map_Entry.File_Attribute], al

@@40:
; Calculate location where to store the entry
        mov     ax, DIR_ENTRY_LENGTH
        xor     bx, bx
        mov     cx, [Dirs_In_Dir_Table]
        xor     dx, dx
        mul     cx
 
; Store Entry       
        mov     cx, ax

        mov     es, [Parm_Dir_Map_ptr_es]
        mov     di, [Parm_Dir_Map_ptr_di]
        add     di, cx

        mov     si, offset Dir_Map_Entry
        mov     cx, DIR_ENTRY_LENGTH
        rep     movsb

; Increase Entry count
        inc     [Dirs_In_Dir_Table]

        cmp     [Dirs_In_Dir_Table], MAX_DIRS
                                            ; Max nr of Entries reached?
        jne     @@10                        ; No
                                            ; Yes, so
@@50:
        mov     es, [Old_Dta_Seg]           ; Restore old Dta Address
        mov     dx, [Old_Dta_Ofs]
        mov     ah, DOS_SET_DTA
        int     DOS_SERVICE 

        cmp     [Dirs_In_Dir_Table], 0      ; Files found?
        je      @@90                        ; No
                                            ; Yes, so
        cmp     [Dirs_In_Dir_Table], 1      ; Do we need to sort?
        je      @@99                        ; No
                                            ; Yes, so
;
; Set up sort keys
;
        mov     si, offset Parm_SortKeys
        push    ds si
        pop     di es

        mov     ax, [Parm_Dir_Map_ptr_es]
        mov     bx, [Parm_Dir_Map_ptr_di]

        mov     [(SortKeys ptr di).Memory_Address_Hi], ax
        mov     [(SortKeys ptr di).Memory_Address_Lo], bx
        mov     ax, [Dirs_In_Dir_Table]
        mov     [(SortKeys ptr di).Record_Count], ax
        mov     [(SortKeys ptr di).Record_Size], DIR_ENTRY_LENGTH
        mov     [(SortKeys ptr di).Key_Count], 1
        mov     [(SortKeys ptr di).Key_1_Position], 1
        mov     [(SortKeys ptr di).Key_1_Size], DIR_NAME_LENGTH
        mov     [(SortKeys ptr di).Key_1_A_D], SORT_ASCENDING

;
; Bubble Sort Directories in alphabetic order
;
        push    es di

        call    MEMSORT

        pop     bx bx

@@90:
        mov     al, 1
        mov     [Return_Code], al

@@99:
        ret

ENDP    DC_DIRS



ENDS    CSeg                                ; End of Code segment

END                                         ; End of Program
