;*****************************************************************************
; TRDOS.ASM  [ Draft for Kernel TRDOS.RTS ]
; Copyright (C) 2004  Erdogan TAN  [ 17/01/2004 ]  Last Update: 06/07/2004
; ! Under Development !  Current Stage: INT 20h replacement, load&run files
; Currently, usable prompt line commands: 'CD', 'DIR', 'VER', 'EXIT', 'PROMPT'
; 'VOLUME', 'LONGNAME', 'DATE', 'TIME'
;
; (RUN command runs standalone com files with INT 20h termination, for now.)
; (RUN command is using temporary memory allocation, for now.)
; (RUN/external command will use tr-dos memory allocation procedures, later)
;
; NOTE: DOS Interrupts and INT 18h will be programmed at last.
; This stage is "embedded command.com" (simple equivalent of command.com)
; ****************************************************************************
; masm.bat -> masm trdos -> link /t trdos -> TRDOS.COM [ MASM v6.11 ]
; This is source code of TRDOS.COM file which succesfully runs in MS-DOS 7.1 
;*****************************************************************************
;
; Masterboot / Partition Table at Beginning+1BEh
ptBootable       equ 0
ptBeginHead      equ 1
ptBeginSector    equ 2
ptBeginCylinder  equ 3
ptFileSystemName equ 4
ptEndHead        equ 5
ptEndSector      equ 6
ptEndCylinder    equ 7
ptStartSector    equ 8
ptSectors        equ 12

; Boot Sector Parameters at 7C00h
DataArea1     equ -4
DataArea2     equ -2
BootStart     equ 0h
OemName       equ 03h
BytesPerSec   equ 0Bh
SecPerClust   equ 0Dh
ResSectors    equ 0Eh
FATs          equ 10h
RootDirEnts   equ 11h
Sectors       equ 13h
Media         equ 15h
FATsecs       equ 16h
SecPerTrack   equ 18h
Heads         equ 1Ah 
Hidden1       equ 1Ch
Hidden2       equ 1Eh
HugeSec1      equ 20h
HugeSec2      equ 22h
DriveNumber   equ 24h
Reserved1     equ 25h
bootsignature equ 26h                 
VolumeID      equ 27h
VolumeLabel   equ 2Bh
FileSysType   equ 36h          
Reserved2     equ 3Eh                           ; Starting cluster of P2000

; FAT32 BPB Structure
FAT32_FAT_Size equ 36
FAT32_RootFClust equ 44
FAT32_DrvNum equ 64
FAT32_Reserved1 equ 65
FAT32_BootSig equ 66
FAT32_VolID equ 67
FAT32_VolLab equ 71
FAT32_FilSysType equ 82

; BIOS Disk Parameters
DPDiskNumber  equ 0h
DPDType       equ 1h
DPReturn      equ 2h
DPHeads       equ 3h
DPCylinders   equ 4h
DPSecPerTrack equ 6h
DPDisks       equ 7h
DPTableOff    equ 8h
DPTableSeg    equ 0Ah
DPNumOfSecs   equ 0Ch

; BIOS INT 13h Extensions (LBA extensions)
; Just After DP Data (DPDiskNumber+)
DAP_PacketSize equ 10h  ; If extensions present, this byte will be >=10h
DAP_Reserved1 equ 11h   ; Reserved Byte 
DAP_NumOfBlocks equ 12h ; Value of this byte must be 0 to 127
DAP_Reserved2 equ 13h   ; Reserved Byte
DAP_Destination equ 14h ; Address of Transfer Buffer as SEGMENT:OFFSET
DAP_LBA_Address equ 18h ; LBA=(C1*H0+H1)*S0+S1-1
                        ; C1= Selected Cylinder Number
                        ; H0= Number Of Heads (Maximum Head Number + 1)
                        ; H1= Selected Head Number
                        ; S0= Maximum Sector Number
                        ; S1= Selected Sector Number
                        ; QUAD WORD
; DAP_Flat_Destination equ 20h ; 64 bit address, if value in 4h is FFFF:FFFFh
                             ; QUAD WORD (Also, value in 0h must be 18h) 
                             ; TR-DOS will not use 64 bit Flat Address

; INT 13h Function 48h "Get Enhanced Disk Drive Parameters"
; Just After DP Data (DPDiskNumber+)
GetDParams_48h equ 20h ; Word. Data Lenght, must be 26 (1Ah) for short data.
GDP_48h_InfoFlag equ 22h ; Word
; Bit 1 = 1 -> The geometry returned in bytes 4-15 is valid.
GDP_48h_NumOfPCyls equ 24h ; Double Word. Number physical cylinders.
GDP_48h_NumOfPHeads equ 28h ; Double Word. Number of physical heads.
GDP_48h_NumOfPSpT equ 2Ch ; Double word. Num of physical sectors per track.
GDP_48h_LBA_Sectors equ 30h ; 8 bytes. Number of physical/LBA sectors.
GDP_48h_BytesPerSec equ 38h ; Word. Number of bytes in a sector.

; TR-DOS Standalone Program Extensions to the DiskParams Block
; Just After DP Data (DPDiskNumber+)
TRDP_CurrentSector equ 3Ah  ; DX:AX (LBA)
TRDP_SectorCount equ 3Eh    ; CX (or Counter)

; DOS Logical Disks
LD_Name equ 0
LD_DiskType equ 1
LD_PhyDrvNo equ 2
LD_FATType equ 3
LD_FSType equ 4
LD_LBAYes equ 5
LD_BPB equ 6
LD_FATBegin equ 96
LD_ROOTBegin equ 100
LD_DATABegin equ 104
LD_StartSector equ 108
LD_TotalSectors equ 112
LD_FreeSectors equ 116
LD_Clusters equ 120
LD_PartitionEntry equ 124
LD_DParamEntry equ 125
LD_MediaChanged equ 126
LD_CDirLevel equ 127
LD_CurrentDirectory equ 128

; Valid FAT Types
FS_FAT12 equ 1
FS_FAT16_CHS equ 2
FS_FAT32_CHS equ 3
FS_FAT16_LBA equ 4
FS_FAT32_LBA equ 5

; Cursor Location
CCCpointer equ  0450h   ; BIOS data, current cursor column
; FAT Clusters EOC sign
FAT12EOC equ 0FFFh
FAT16EOC equ 0FFFFh
;FAT32EOC equ 0FFFFFFFh ; It is not direct usable for 8086 code
; BAD Cluster
FAT12BADC equ 0FF7h
FAT16BADC equ 0FFF7h
;FAT32BADC equ 0FFFFFF7h ; It is not direct usable for 8086 code
; MS-DOS FAT16 FS (Maximum Possible) Last Cluster Number= 0FFF6h 

Present segment Para 'code'

		assume CS:Present, DS:Present, ES:Present, SS:Present


;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
;±
;±              PROCEDURE proc_start
;±
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

proc_start      proc    far

                org 100h
start:                                         
                mov si, offset Starting_Msg
                call proc_printmsg

                xor dl,dl
                mov si, offset DiskParams
dparam_read:
                call proc_dparam
                mov dl, byte ptr [SI][DPDisks]
                add si, 40h
                cmp dl, 2
                jne short pass_floppy1
                dec dl
                call proc_dparam
pass_floppy1:
                mov dl, 80h
                add si, 40h
                call proc_dparam
                jnc short pass_hd_15h_error
                mov word ptr [si][DPNumOfSecs], 0
                mov word ptr [si][DPNumOfSecs]+2,0
pass_hd_15h_error:
                mov ah, byte ptr [SI][DPDisks]
                mov byte ptr [HDCounter], ah
next_hard_disk:
                dec byte ptr [HDCounter]
                cmp byte ptr [HDCounter], 0
                jna short load_hd_partition_tables
                inc dl
                add si, 40h
                call proc_dparam
                jnc short next_hard_disk
                mov word ptr [si][DPNumOfSecs], 0
                mov word ptr [si][DPNumOfSecs]+2,0
                jmp short next_hard_disk
load_hd_partition_tables:
                mov si, offset Disk_hd0
                mov di, offset PTable_hd0
                push ds
                pop es
                mov dl, 80h
                mov cx, 4
load_next_hd_partition_table:
                push cx
                push dx
                push si
                push di
                cmp byte ptr [SI]+1, 03h
                jne short pass_pt_this_hard_disk
                call proc_load_masterboot
                jc short pass_pt_this_hard_disk
                pop di
                push di
                mov si, offset PartitionTable
                mov cx, 32
                rep movsw
pass_pt_this_hard_disk:
                pop di
                pop si
                pop dx
                pop cx
                inc dl
                add si, 40h
                add di, 40h
                loop load_next_hd_partition_table
load_extended_dos_partitions:
                mov si, Offset PTable_hd0
                mov di, Offset PTable_ep0
                mov byte ptr [HDCounter], 80h
next_hd_extd_partition:
                push si
                mov cx, 4
hd_check_fs_id_05h:
                mov al, byte ptr [SI][ptFileSystemName]
                cmp al, 05h ; Is it an extended dos partition ?
                je short pass_hd_check_05h
                cmp al, 0Fh ; Is it an extended win4 (LBA mode) partition ?
                je short pass_hd_check_0Fh 
continue_to_check_ep:
                add si, 10h
                loop hd_check_fs_id_05h
continue_check_ep_next_disk:
                pop si
                add si, 40h
                add di, 40h
                inc byte ptr [HDCounter]
                cmp byte ptr [HDCounter], 83h
                jna short next_hd_extd_partition
                jmp logical_drv_init
pass_hd_check_05h:
                push cx
                mov ax, word ptr [SI][ptStartSector]
                mov dx, word ptr [SI][ptStartSector]+2
                xor bh,bh
                mov bl, byte ptr [HDCounter]
                push bx
                sub bl, 80h
                shl bl, 1
                shl bl, 1
                mov word ptr [Val_StartSector][BX],ax
                mov word ptr [Val_StartSector][BX]+2,dx
                pop dx
                mov dh, byte ptr [SI][ptBeginHead]
                mov cx, word ptr [SI][ptBeginSector]
                mov ax, 0201h    ; Read 1 sector
                mov bx, offset MasterBootBuff
                push ds
                pop es
                int 13h
                pop cx
                jc short continue_to_check_ep
                push si
                push di
                push cx
                mov si, offset PartitionTable
                mov cx, 32
                rep movsw
                pop cx
                pop di
                pop si
                jmp short continue_check_ep_next_disk
pop_di_check_next_ep:
                pop di
                jmp continue_to_check_ep
pass_hd_check_0Fh:
                mov ax, word ptr [SI][ptStartSector]
                mov dx, word ptr [SI][ptStartSector]+2
                xor bh,bh
                mov bl, byte ptr [HDCounter]
                sub bl, 80h
                push bx
                shl bl, 1
                shl bl, 1
                mov word ptr [Val_StartSector][BX],ax
                mov word ptr [Val_StartSector][BX]+2,dx
                pop ax
                push di
                mov ah, 40h
                mul ah
                mov di, offset Disk_hd0
                add di, ax
ep_mov_dap_parameters:
                push ds
                pop es
                cmp byte ptr [DI][DAP_PacketSize], 10h
                jne short pop_di_check_next_ep
                mov word ptr [DI][DAP_Destination], offset MasterBootBuff
                push ds
                pop word ptr [DI][DAP_Destination]+2
                mov byte ptr [DI][DAP_NumOfBlocks],1
                push si
                push di
                add si, ptStartSector
                add di, DAP_LBA_Address
                movsw
                movsw
                pop si  
                add si, DAP_PacketSize ; DS:SI= DAP Location
                mov ah, 42h  ; Extended Disk Read - LBA Read
                mov dl, byte ptr [HDCounter]
                int 13h
                pop si
                pop di
                jc continue_to_check_ep
                push di
                push si
                push cx
                mov si, offset PartitionTable
                mov cx, 32
                rep movsw
                pop cx
                pop si
                pop di
                jmp continue_check_ep_next_disk
logical_drv_init:
                mov byte ptr [Hard_Disk], 80h
                mov cx, 4
                xor al, al
                mov si, offset PTable_Buffer
                mov di, offset Logical_DOSDisks + 200h
                mov byte ptr [Last_DOS_DiskNo], 1
ldrv_init_next_hdp:
                push si
                push cx
                push ax
                push di
                cmp byte ptr [SI][ptFileSystemName], 06h
                jne short pass_this_is_FAT16_CHS_disk
                mov byte ptr [DI][LD_DiskType], 2
                mov dl, byte ptr [Hard_Disk]
                mov byte ptr [DI][LD_PhyDrvNo], dl
                mov byte ptr [DI][LD_FATType], 2
                mov byte ptr [DI][LD_FSType], 06
                mov bl, dl
                sub bl, 80h
                xor bh, bh
                mov ah, byte ptr [HD_LBAYes][BX]
                mov byte ptr [DI][LD_LBAYes], ah
                mov byte ptr [DI][LD_PartitionEntry],al
                mov ah, dl
                sub ah, 7Eh
                mov byte ptr [DI][LD_DParamEntry], ah
                mov dh, byte ptr [SI][ptBeginHead]
                mov cx, word ptr [SI][ptBeginSector]
                mov ax, 0201h    ; Read 1 sector
                mov bx, offset DOSBootSectorBuff
                int 13h
                jc pass_this_is_FAT32_LBA_disk
                jmp hdp_boot_validation
pass_this_is_FAT16_CHS_disk:
                cmp byte ptr [SI][ptFileSystemName], 0Eh
                jne pass_this_is_FAT16_LBA_disk
                mov byte ptr [DI][LD_DiskType], 2
                mov dl, byte ptr [Hard_Disk]
                mov byte ptr [DI][LD_PhyDrvNo], dl
                mov byte ptr [DI][LD_FATType], 2
                mov byte ptr [DI][LD_FSType], 0Eh
                mov byte ptr [DI][LD_LBAYes], 1
                mov byte ptr [DI][LD_PartitionEntry],al
                mov ah, dl
                sub ah, 7Eh
                mov byte ptr [DI][LD_DParamEntry], ah
                mov al, 40h
                mul ah
                add ax, offset Disk_fd0
                mov di, ax
                cmp byte ptr [DI][DAP_PacketSize], 10h
                jne pass_this_is_FAT32_LBA_disk
                mov word ptr [DI][DAP_Destination], offset DOSBootSectorBuff
                push ds
                pop word ptr [DI][DAP_Destination]+2
                mov byte ptr [DI][DAP_NumOfBlocks],1
                push di
                add si, ptStartSector
                add di, DAP_LBA_Address
                movsw
                movsw
                pop si  
                add si, DAP_PacketSize ; DS:SI= DAP Location
                mov ah, 42h  ; Extended Disk Read - LBA Read
                mov dl, byte ptr [Hard_Disk]
                int 13h
                jc pass_this_is_FAT32_LBA_disk
hdp_boot_validation:
                cmp word ptr [BS_Validation], 0AA55h
                jne pass_this_is_FAT32_LBA_disk
                cmp byte ptr [BPB_Media], 0F8h
                jne pass_this_is_FAT32_LBA_disk
                cmp word ptr [BPB_FATSz16], 0
                ja short pass_FAT32_BPB
                cmp byte ptr [BS_FAT32_BootSig], 29h
                jne pass_this_is_FAT32_LBA_disk
                mov cx, 45
                jmp short loc_move_hd_BPB
pass_FAT32_BPB:
                cmp byte ptr [BS_BootSig], 29h
                jne pass_this_is_FAT32_LBA_disk
                mov cx, 32
loc_move_hd_BPB:
                mov si, offset DOSBootSectorBuff
                pop di
                push di
                push di
                add di, LD_BPB
                rep movsw 
                pop si
                pop di
                add di, 100h
                push di
                inc byte ptr [Last_DOS_DiskNo]
                mov al, 'A'
                add al, byte ptr [Last_DOS_DiskNo]
                mov byte ptr [SI][LD_Name], al

                cmp byte ptr [Now_EP_Drives], 0
                jna short ld_StartSector_set1
                cmp byte ptr [SI][LD_FsType], 0Bh
                jne short ld_StartSector_set1
                mov ax, word ptr [SI][LD_StartSector]
                mov dx, word ptr [SI][LD_StartSector]+2
                jmp short ld_StartSector_set2
ld_StartSector_set1:
                mov AX,Word Ptr [SI][LD_BPB][Hidden1]
                mov DX,Word Ptr [SI][LD_BPB][Hidden2]
                mov word ptr [SI][LD_StartSector],AX
                mov word ptr [SI][LD_StartSector]+2,DX
ld_StartSector_set2:
                add AX,Word Ptr [SI][LD_BPB][ResSectors]
                adc DX,0

                mov Word Ptr [SI][LD_FATBegin], AX
                mov Word Ptr [SI][LD_FATBegin]+2, DX
                cmp byte ptr [SI][LD_FATType], 3
                jne short pass_FAT32_RootDirLoc
                mov ax, Word Ptr [SI][LD_BPB][FAT32_FAT_Size]
                mov dx, Word Ptr [SI][LD_BPB][FAT32_FAT_Size]+2
                xor bh,bh
                mov bl,Byte Ptr [SI][LD_BPB][FATs]
                call proc_mul32
                add ax, Word Ptr [SI][LD_FATBegin]
                adc dx, Word Ptr [SI][LD_FATBegin]+2
                mov Word Ptr [SI][LD_DATABegin], AX
                mov Word Ptr [SI][LD_DATABegin]+2, DX
                mov Word Ptr [SI][LD_ROOTBegin], AX
                mov Word Ptr [SI][LD_ROOTBegin]+2, DX
                jmp short pass_FAT_FS_Locations
pass_FAT32_RootDirLoc:
                mov AL,Byte Ptr [SI][LD_BPB][FATs]
                cbw                             
                mul Word Ptr [SI][LD_BPB][FATSecs]
                add AX,Word Ptr [SI][LD_FATBegin]
                adc DX,Word Ptr [SI][LD_FATBegin]+2
                mov Word Ptr [SI][LD_ROOTBegin], AX
                mov Word Ptr [SI][LD_ROOTBegin]+2, DX
                mov Word Ptr [SI][LD_DATABegin], AX 
                mov Word Ptr [SI][LD_DATABegin]+2, DX
                mov AX,20h       ; Size of a directory entry
                mul Word Ptr [SI][LD_BPB][RootDirEnts]
                add AX,511
              ; adc dx, 0
                mov cx, 512
                div cx
                add Word Ptr [SI][LD_DATABegin],AX 
                adc Word Ptr [SI][LD_DATABegin]+2,0
pass_FAT_FS_Locations:
                mov ax,Word Ptr [SI][LD_BPB][HugeSec1]
                mov Word Ptr [SI][LD_TotalSectors], AX
                mov dx,Word Ptr [SI][LD_BPB][HugeSec2]
                mov Word Ptr [SI][LD_TotalSectors]+2, dx
                add ax,Word Ptr [SI][LD_StartSector]
                adc dx,Word Ptr [SI][LD_StartSector]+2
                sub ax,Word Ptr [SI][LD_DATABegin]
                sbb dx,Word Ptr [SI][LD_DATABegin]+2
                xor ch,ch
                mov cl,Byte Ptr [SI][LD_BPB][SecPerClust]
                call Rx_Dos_Div32 
                mov word ptr [SI][LD_Clusters], AX
                mov word ptr [SI][LD_Clusters]+2, DX
                    ; Maximum Valid Cluster Number= DX:AX +1
                    ; with 2 reserved clusters= DX:AX +2
               ;mov word ptr [SI][LD_FreeSectors],0
               ;mov word ptr [SI][LD_FreeSectors]+2,0
               ;BPB has been loaded, yet
               ;LD_MediaChanged= 1 is "New Boot, FAT is not read"
                mov byte ptr [SI][LD_MediaChanged],1

                jmp pass_this_is_FAT32_LBA_disk

pass_this_is_FAT16_LBA_disk:
                cmp byte ptr [SI][ptFileSystemName], 0Bh
                jne short pass_this_is_FAT32_CHS_disk
                mov byte ptr [DI][LD_DiskType], 2
                mov bl, byte ptr [Hard_Disk]
                mov byte ptr [DI][LD_PhyDrvNo], bl
                mov byte ptr [DI][LD_FATType], 3
                mov byte ptr [DI][LD_FSType], 0Bh
                sub bl, 80h
                xor bh, bh
                mov ah, byte ptr [HD_LBAYes][BX]
                mov byte ptr [DI][LD_LBAYes],ah
                mov byte ptr [DI][LD_PartitionEntry],al
                mov ah, bl
                add ah, 2
                mov byte ptr [DI][LD_DParamEntry], ah
                mov ax, word ptr [SI][ptStartSector]
                mov dx, word ptr [SI][ptStartSector]+2
                cmp byte ptr [Now_EP_Drives],0
                jna short pass_0Bh_ext_part_start_fixup
                shl bl, 1
                shl bl, 1
                add ax, word ptr [Val_StartSector][BX]
                adc dx, word ptr [Val_StartSector][BX]+2
                mov word ptr [DI][LD_StartSector], ax
                mov word ptr [DI][LD_StartSector]+2, dx
pass_0Bh_ext_part_start_fixup:
                push ax
                mov ah, byte ptr [Hard_Disk]
                sub ah, 7Eh
                mov al, 40h
                mul ah
                add ax, offset Disk_fd0
                mov di, ax
                pop ax
                cmp byte ptr [DI][DAP_PacketSize], 10h
                jne pass_this_is_FAT32_LBA_disk
                mov word ptr [DI][DAP_LBA_Address], ax
                mov word ptr [DI][DAP_LBA_Address]+2, dx
                jmp short loc_fixup_8GB_CHS_to_LBA
pass_val_startsec_check:
                mov dh, byte ptr [SI][ptBeginHead]
                mov cx, word ptr [SI][ptBeginSector]
                mov ax, 0201h    ; Read 1 sector
                mov bx, offset DOSBootSectorBuff
                int 13h
                jc pass_this_is_FAT32_LBA_disk
                jmp hdp_boot_validation
pass_this_is_FAT32_CHS_disk:
                cmp byte ptr [SI][ptFileSystemName], 0Ch
                jne pass_this_is_FAT32_LBA_disk
                mov byte ptr [DI][LD_DiskType], 2
                mov ah, byte ptr [Hard_Disk]
                mov byte ptr [DI][LD_PhyDrvNo], ah
                mov byte ptr [DI][LD_FATType], 3
                mov byte ptr [DI][LD_FSType], 0Ch
                mov byte ptr [DI][LD_LBAYes], 1
                mov byte ptr [DI][LD_PartitionEntry],al
                sub ah, 7Eh
                mov byte ptr [DI][LD_DParamEntry], ah
                mov al, 40h
                mul ah
                add ax, offset Disk_fd0
                mov di, ax
                cmp byte ptr [DI][DAP_PacketSize], 10h
                jne pass_this_is_FAT32_LBA_disk
                push word ptr [SI][ptStartSector]
                pop word ptr [DI][DAP_LBA_Address]
                push word ptr [SI][ptStartSector]+2
                pop word ptr [DI][DAP_LBA_Address]+2
loc_fixup_8GB_CHS_to_LBA:
                mov word ptr [DI][DAP_Destination], offset DOSBootSectorBuff
                push ds
                pop word ptr [DI][DAP_Destination]+2
                mov byte ptr [DI][DAP_NumOfBlocks],1
                push di
                pop si  
                add si, DAP_PacketSize ; DS:SI= DAP Location
                mov ah, 42h  ; Extended Disk Read - LBA Read
                mov dl, byte ptr [Hard_Disk]
                int 13h
                jnc hdp_boot_validation
pass_this_is_FAT32_LBA_disk:
                pop di
                pop ax
                pop cx
                pop si
                add si, 10h
                inc al
                dec cx
                cmp cx, 0
                ja  ldrv_init_next_hdp
                cmp byte ptr [Hard_Disk], 83h
                jnb short pass_init_primary_dos_partitions
                mov cx, 4
                inc byte ptr [Hard_Disk]
                jmp ldrv_init_next_hdp
pass_init_primary_dos_partitions:
                cmp byte ptr [Now_EP_Drives], 0
                ja short launch_current_dos_drive
                mov byte ptr [Now_EP_Drives], 1
                mov si, offset PTable_ep0
                mov byte ptr [Hard_Disk], 80h
                mov ah, byte ptr [Last_DOS_DiskNo]
                inc ah
                xor al,al
                mov di, offset Logical_DOSDisks
                add di, ax
                mov al, 16
                mov cx, 4
                jmp ldrv_init_next_hdp
Now_EP_Drives:  db 0
Val_StartSector: dd 0
                 dd 0
                 dd 0
                 dd 0
launch_current_dos_drive:
                push ds
                xor ax, ax
                mov ds, ax
                mov ax, word ptr DS:[084h]
                push ax
                pop word ptr CS:[INT21h_Offset]
                mov ax, word ptr DS:[086h]
                push ax
                pop word ptr CS:[INT21h_Segment]
                mov word ptr DS:[084h], offset trdos_int21h_routine
                mov ax, cs
                mov word ptr DS:[086h], ax
                pop ds
trdos_mainprog:
                call proc_clear_screen
                mov al, 2 ; C:
                call proc_change_current_drive
                call proc_dos_prompt
end_of_program:
                xor ax, ax
                mov ds, ax
                push word ptr CS:[INT21h_Offset]
                pop ax
                mov word ptr DS:[084h], ax
                push word ptr CS:[INT21h_Segment]
                pop ax
                mov word ptr DS:[086h], ax

                int 20h
                    
proc_start      endp

proc_clear_screen proc near

                mov ah, 0Fh 
                int 10h
                mov ah, 0
                int 10h

                retn

proc_clear_screen endp

proc_printmsg   proc near
loc_print:          
		lodsb                           ; Load byte at DS:SI to AL
		and     AL,AL            
		je      short loc_return        ; If AL = 00h then return
		mov     AH,0Eh                  
		mov     BX,07h             
		int     10h                     ; BIOS Service func ( ah ) = 0Eh
						; Write char as TTY
						;AL-char BH-page BL-color
		jmp     short loc_print           
loc_return:
		retn

proc_printmsg   endp

;'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
; Rx_DOS  32 bit Divide                                      ;
; (Special version by Erdogan Tan)                           ;
;- - - - - - - - - - - - - - - - - - - - - - - - - -- - - - -;
;                                                            ;
; input -> DX_AX = 32 bit dividend                           ;
; input -> CX = 16 bit divisor                               ;
; output -> DX_AX = 32 bit quotient                          ;
; output -> BX = 16 bit remainder                            ;
;                                                            ;
;  This procedure divides the requested 32 bit number        ;
;  and gives the result in DX, AX and BX (remainder)         ;
;                                                            ;
; Original Procedure by Michael Podanoffsky / Real Time DOS  ;
; (c) Erdogan TAN  1999                     [ RXDOSBIO.ASM ] ;
;............................................................;

Rx_Dos_Div32    proc near

		mov  bx, dx
		xchg ax, bx
		xor  dx, dx
		div  cx         ; at first, divide DX
		xchg ax, bx     ; remainder is in DX
				; now, BX has quotient
				; save remainder
		div  cx         ; so, DX_AX divided and
				; AX has quotient
				; DX has remainder
		xchg dx, bx     ; finally, BX has remainder

		retn

Rx_Dos_Div32    endp

;'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
; From binary (byte) to hexadecimal (character) converter    ;
;                                                            ;
; input -> AL = byte (binary number) to be converted         ;
; output -> AH = First character of hexadecimal number       ;
; output -> AL = Second character of hexadecimal number      ;
;                                                            ;
; (c) Erdogan TAN  1998 - 1999                               ;
;............................................................;

; 1998

proc_hex        proc    near

		db 0D4h,10h                     ; Undocumented inst. AAM
						; AH = AL / 10h
						; AL = AL MOD 10h
		or AX,'00'                      ; Make it ZERO (ASCII) based

                xchg AH,AL 

; 1999
		cmp AL,'9'
		jna pass_cc_al
		add AL,7
pass_cc_al:
		cmp AH,'9'
		jna pass_cc_ah
		add AH,7
pass_cc_ah:

; 1998
		retn

proc_hex        endp

;'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
; 32 bit Multiply                                            ;
;- - - - - - - - - - - - - - - - - - - - - - - - - -- - - - -;
;                                                            ;
; input -> DX_AX = 32 bit multiplier                         ;
; input -> BX = 16 bit number to be multiplied by DX_AX      ;
; output -> BX_DX_AX = 48 bit (16+32 bit) result number      ;
;                                                            ;
; (c) Erdogan TAN  1999                                      ;
;............................................................;

proc_mul32    proc near

	      push cx

	      mov cx, bx
	      mov bx, dx

	      mul cx

              xchg ax, bx

	      push dx

              mul cx 

              pop cx 

              add ax, cx 
	      adc dx, 0

	      xchg bx, ax
	      xchg dx, bx

	      pop cx

	      retn

proc_mul32    endp

proc_dparam   proc near
              ; input
              ; dl = Disk Drive Number
              ; ds:si = Parameters Table Buffer
              ; output
              ; ah = error number (0 = No Error if C flag is ZERO)
              mov byte ptr [si][DPDiskNumber], dl
              mov byte ptr [si][DPDType], 0
              push dx
              mov ah, 08h
              int 13h
              mov byte ptr [si][DPReturn], ah
              jnc short dparam_no_error
              pop dx
              retn
dparam_no_error:
              mov byte ptr [si][DPDType], bl
              mov byte ptr [si][DPDisks], dl
              inc dh
              mov byte ptr [si][DPHeads], dh
              push cx
              and cl, 3Fh
              mov byte ptr [si][DPSecPerTrack], cl
              pop cx
              shr cl,1
              shr cl,1
              shr cl,1
              shr cl,1
              shr cl,1
              shr cl,1
              xchg ch,cl
              inc cx
              mov word ptr [si][DPCylinders], cx
              mov word ptr [si][DPTableOff], di
              push es
              pop word ptr [si][DPTableSeg]

              cmp byte ptr [si][DPDiskNumber], 80h
              jb short dparam_15h_return

              mov dl, byte ptr [si][DPDiskNumber]
              mov byte ptr [Hard_Disk], dl
              mov byte ptr [si][DPDType], 0
              mov ah, 15h
              int 13h
              jc short dparam_15h_return
              mov byte ptr [si][DPDType], ah
              mov word ptr [si][DPNumOfSecs], cx
              mov word ptr [si][DPNumOfSecs]+2, dx
dparam_15h_return:
              pop dx ; dl = Drive Number
              mov byte ptr [SI][DAP_PacketSize], 0 ; Reset (No DAP)
              mov ah, 41h ; Check Extensions Present
              mov bx, 55AAh
              int 13h
              jc short dparam_48h_return
              cmp bx, 0AA55h
              jne short dparam_48h_return
              test cx, 01h ; Fixed Disk Access Subset - is LBA ready ? 
              jz short dparam_48h_return
              xor bh,bh
              mov bl, byte ptr [Hard_Disk]
              sub bl, 80h
              mov byte ptr [HD_LBAYes][BX],1
              mov byte ptr [SI][DAP_PacketSize], 10h
dparam_41h_return:
              push si
              add si, GetDParams_48h
              mov word ptr [SI], 0026 ; GDP Data Lenght - Set
            ; DS:SI= Address of Result Buffer
            ; DL (Drive Number) must be not changed before here...
              mov ah, 48h  ; Get Enhanced Disk Drive Parameters
              int 13h
              pop si
              jc short dparam_48h_return
              mov word ptr [SI][GetDParams_48h], 0 ; GDP Data Lenght - Reset
dparam_48h_return:
              xor ah,ah
              retn
proc_dparam   endp

proc_load_masterboot proc near
                ; input -> dl = drive number
                xor ah,ah
                int 13h
                jnc short pass_reset_error
harddisk_error:
                retn
pass_reset_error:
                mov bx, offset MasterBootBuff
                mov ax,0201h
                mov cx,1
                xor dh,dh
                push ds
                pop es
                int 13h
                jc short harddisk_error

                cmp word ptr [MBIDCode],0AA55h
                jnz short loc_not_masterboot
                retn
loc_not_masterboot:
                stc
                retn

proc_load_masterboot endp

proc_CHS_read proc near
                push si
                ; INPUT -> DX:AX = Logical Block Address
                ; CX = Number of sectors to read
                ; DS:SI = Logical Dos Disk Table Offset (DRV)
                ; ES:BX = Destination Buffer
                ; OUTPUT -> clc or stc
                mov byte ptr [CHS_RetryCount], 4
loc_read_disk_chs:
                push    CX                      ; # of FAT/FILE/DIR sectors
                push    AX                      ; Linear sector #
                push    DX                      ; DX_AX = Linear address (sectors)
                mov     CX,Word Ptr [SI][LD_BPB][SecPerTrack]
                push    BX

                call    RX_DOS_DIV32            ; Special 32 bit divide !!!
                                                ; To fix large disk problem.
                                                ; (c) Erdogan Tan 1999
                                                ; (October 20th, 1999)

                mov     CX, BX                  ; Sector (zero based)
                inc     CX                      ; To make it 1 based
                push    CX
                mov     CX,Word Ptr [SI][LD_BPB][Heads]
                call    RX_DOS_DIV32            ; Convert track to head & cyl
                mov     DH, BL                  ; BX = Head (max. FFh)
                pop     CX
                                                ; AX=Cyl, DH=Head, CX=Sector
                pop     BX                      ; ES:BX = Buffer

                mov     DL,Byte Ptr [SI][LD_PhyDrvNo]
                mov     CH,AL                   
                ror     AH,1                    ; Rotate right
                ror     AH,1                   
                or      CL,AH                   
                mov     AX,0201h
                int     13h                     ; BIOS Service func ( ah ) = 2
                                                ; Read disk sectors
                                                ;AL-sec num CH-track CL-sec
                                                ; DH-head DL-drive ES:BX-buffer
                                                ;CF-flag AH-stat AL-sec read
                                                ; If CF = 1 then (If AH > 0)
                pop     DX
                pop     AX
                pop     CX 
                jnc     short pass_read_disk_chs_error
                                                ; error code in AH
                sub     byte ptr [CHS_RetryCount], 1
                jnb     short loc_read_disk_chs
                pop si
                retn
pass_read_disk_chs_error:
                loop    loc_read_next_sector
                pop si
                retn
loc_read_next_sector:
                add     AX,1
                adc     DX,0    
                add     BX, 512
                jmp     short loc_read_disk_chs

proc_CHS_read   endp

proc_LBA_read   proc near
                push si
                ; INPUT -> DAP_Buffer
                ; OUTPUT -> clc or stc
loc_read_disk_lba:
                mov si, offset DAP_Buffer
                ; DS:SI= DAP Location
                mov ah, 42h  ; Extended Disk Read - LBA Read
               ;mov dl, byte ptr [DAP_BuffDisk]
                int 13h
                jnc short pass_read_disk_lba_error
                dec byte ptr [DAP_RetryCount]
                cmp byte ptr [DAP_RetryCount],1
                jnb short loc_read_disk_lba
pass_read_disk_lba_error:
                pop si
                retn
proc_LBA_read   endp

proc_get_next_cluster   proc near
                ; INPUT -> AX = Cluster Number, low 16 bit
                ; INPUT -> DX = Cluster Number, high 16 bit
                ; INPUT -> DS:SI = Logical Dos Drive Parameters Table
                ; OUTPUT -> clc -> No Error
                ; OUTPUT -> CX,BX will be destroyed
                ; AX: Next Cluster Number, low 16 bit
                ; DX: Next Cluster Number, high 16 bit
                ; stc -> Error
                mov word ptr [FAT_CurrentCluster], ax
                mov word ptr [FAT_CurrentCluster]+2, dx
check_next_cluster_fat_type:
                cmp byte ptr [SI][LD_FATType], 2
                jb short get_FAT12_next_cluster
                ja short get_FAT32_next_cluster
get_FAT16_next_cluster:
                mov bx, 300h ;768
                div bx
                ; AX = Count of 3 FAT sectors
                ; DX = Sector Offset
                shl dx, 1 ; Multiply by 2
                push dx
                mov bx, 3
                mul bx  
                pop bx ; Sector Offset
                ; AX = FAT Sector
                ; DX = 0
                mov cl, byte ptr [SI][LD_Name]
                cmp byte ptr [FAT_BuffValidData], 0
                jna load_FAT_sectors0
                cmp cl, byte ptr [FAT_BuffDrvName]
                jne load_FAT_sectors0
                cmp ax, word ptr [FAT_BuffSector]
                jne load_FAT_sectors2
                mov ax, word ptr [FAT_Buffer][BX]
                xor dx, dx
                retn
get_FAT12_next_cluster:
                mov bx, 400h ;1024
                div bx
                ; AX = Count of 3 FAT sectors
                ; DX = Buffer Entry Offset
                push ax
                mov ax, 3
                mul dx    ; Multiply by 3
                shr ax, 1 ; Divide by 2
                mov dx, ax
                pop ax
                push dx
                mov bx, 3
                mul bx  
                pop bx ; Buffer Byte Offset
                ; AX = FAT Beginning Sector
                ; DX = 0
                mov cl, byte ptr [SI][LD_Name]
                cmp byte ptr [FAT_BuffValidData], 0
                jna short load_FAT_sectors0
                cmp cl, byte ptr [FAT_BuffDrvName]
                jne short load_FAT_sectors0
                cmp ax, word ptr [FAT_BuffSector]
                jne short load_FAT_sectors2

                mov cx, word ptr [FAT_CurrentCluster]
                shr cx, 1
                mov ax, word ptr [FAT_Buffer][BX]
                jnc short get_FAT12_nc_even
                shr ax, 1
                shr ax, 1
                shr ax, 1
                shr ax, 1
get_FAT12_nc_even:
                and ah,0Fh
                retn
get_FAT32_next_cluster:
                mov cx, 180h ;384
                call Rx_Dos_Div32
                ; DX:AX = Count of 3 FAT sectors
                ; BX = Sector Offset
                shl bx, 1
                shl bx, 1 ; Multiply by 4
                push bx
                mov bx, 3
                call proc_mul32
                pop bx ; Sector Offset
                ; DX:AX = FAT Sector

                mov cl, byte ptr [SI][LD_Name]
                cmp byte ptr [FAT_BuffValidData], 0
                jna short load_FAT_sectors0
                cmp cl, byte ptr [FAT_BuffDrvName]
                jne short load_FAT_sectors0
                cmp dx, word ptr [FAT_BuffSector]+2
                jne short load_FAT_sectors1
                cmp ax, word ptr [FAT_BuffSector]
                jne short load_FAT_sectors2

                mov ax, word ptr [FAT_Buffer][BX]
                mov dx, word ptr [FAT_Buffer][BX]+2
                and dh, 0Fh ; 28 bit Cluster
                
                retn

load_FAT_sectors0:
                mov byte ptr [FAT_BuffDrvName], cl
load_FAT_sectors1:
                mov word ptr [FAT_BuffSector]+2, dx
load_FAT_sectors2:
                mov word ptr [FAT_BuffSector], ax
                add ax, word ptr [SI][LD_FATbegin]
                adc dx, word ptr [SI][LD_FATbegin]+2
                cmp byte ptr [SI][LD_LBAYes], 0
                ja short loc_load_lba_fat_sectors
               ;push ds
               ;pop es

                mov bx, offset FAT_Buffer
                mov cx, 3
                call proc_CHS_read
                jnc short pass_FAT_sectors_load_error
                mov byte ptr [FAT_BuffValidData], 0
                retn

loc_load_lba_fat_sectors:
              ; mov byte ptr [DAP_BuffLBAyes], 1
                mov word ptr [DAP_BuffLBA_Address], ax
                mov word ptr [DAP_BuffLBA_Address]+2, dx
                mov byte ptr [DAP_BuffPacketSize], 10h
                mov word ptr [DAP_BuffDestination], offset FAT_Buffer
                push ds
                pop word ptr [DAP_BuffDestination]+2
                mov byte ptr [DAP_BuffNumOfBlocks], 3
                mov byte ptr [DAP_RetryCount], 4
                mov dl, byte ptr [SI][LD_PhyDrvNo]
                mov byte ptr [DAP_BuffDisk], dl
                call proc_LBA_read
return_from_fat_secs_read:
                jnc short pass_FAT_sectors_load_error
                mov byte ptr [FAT_BuffValidData], 0
                retn
pass_FAT_sectors_load_error:
                mov byte ptr [FAT_BuffValidData], 1
                mov ax, word ptr [FAT_CurrentCluster]
                mov dx, word ptr [FAT_CurrentCluster]+2
                jmp check_next_cluster_fat_type
proc_get_next_cluster endp

proc_load_root_directory proc near
               ; BL = Sector Offset
               ; BH = DRV
               mov byte ptr [DirBuff_ValidData],0
               mov byte ptr [DirBuff_SectorOffset], bl
               mov byte ptr [DirBuff_LastEntry], 15
               mov byte ptr [DirBuff_LastSector], 31
               add bl,224
               jc short ld_drv_root_failed
               xor bl,bl
               push si
               mov  si, offset Logical_DOSDisks
               add  si, bx
               cmp byte ptr [SI][LD_Name], 'A'
               jnb short pass_ld_drv_root_failed
               pop si
ld_drv_root_failed:
               retn
pass_ld_drv_root_failed:
               mov byte ptr [DirBuff_Drv], bh
               mov word ptr [DirBuff_DirCluster], 0
               mov word ptr [DirBuff_DirCluster]+2, 0
               mov word ptr [DirBuff_NextCluster], 0
               mov word ptr [DirBuff_NextCluster]+2, 0
               mov byte ptr [DirBuff_CurrentEntry],0
               mov ax, word ptr [SI][LD_ROOTbegin]
               mov dx, word ptr [SI][LD_ROOTbegin]+2
               xor bh, bh
               mov bl, byte ptr [DirBuff_SectorOffset]
               add ax, bx
               adc dx, 0
               mov word ptr [DirBuff_DirSector], ax
               mov word ptr [DirBuff_DirSector]+2, dx
               cmp byte ptr [SI][LD_LBAYes], 0
               ja  short lba_read_root_dir_sector
               ; push ds
               ; pop es
               mov bx, offset Directory_Buffer
               mov cx, 1
               call proc_CHS_read
               jnc short validate_RDirBuff_and_return
               pop si
               retn
lba_read_root_dir_sector:
               mov byte ptr [DAP_BuffLBAyes], 1
               mov byte ptr [DAP_BuffPacketSize], 10h
               mov word ptr [DAP_BuffDestination], offset Directory_Buffer
               push ds
               pop word ptr [DAP_BuffDestination]+2
               mov word ptr [DAP_BuffLBA_Address], ax
               mov word ptr [DAP_BuffLBA_Address]+2, dx
               mov byte ptr [DAP_BuffNumOfBlocks], 1
               mov byte ptr [DAP_RetryCount], 4
               mov dl, byte ptr [SI][LD_PhyDrvNo]
               mov byte ptr [DAP_BuffDisk], dl
               call proc_LBA_read
               jnc short validate_RDirBuff_and_return
               pop si
               retn
validate_RDirBuff_and_return:
               mov byte ptr [DirBuff_ValidData], 1
               pop si
               retn
proc_load_root_directory endp

proc_load_directory proc near
               ; DX:AX = Cluster Number
               ; BL = Sector Offset in cluster
               ; BH = DRV
                 mov byte ptr [DirBuff_ValidData],0

                 mov byte ptr [DirBuff_SectorOffset], bl
               ; mov byte ptr [DirBuff_LastEntry], 0 ;[RESET]
                 xor bl,bl
                 push si
                 mov  si, offset Logical_DOSDisks
                 add  si, bx
                 cmp byte ptr [SI][LD_Name], 'A'
                 jnb short pass_ld_drv_failed
                 pop si
                 retn
pass_ld_drv_failed:
                 cmp byte ptr [SI][LD_FATType],2
                 ja short pass_ld_reset_dx
                 xor dx,dx
pass_ld_reset_dx:
                 mov byte ptr [DirBuff_Drv], bh
                 mov word ptr [DirBuff_DirCluster], ax
                 mov word ptr [DirBuff_DirCluster]+2, dx
                 mov word ptr [DirBuff_NextCluster], 0
                 mov word ptr [DirBuff_NextCluster]+2, 0
                 mov bl, byte ptr [SI][LD_BPB][SecPerClust]
                 dec bl
                 mov byte ptr [DirBuff_LastSector], bl
                 cmp bl, byte ptr [DirBuff_SectorOffset]
                 jnb short pass_ld_drv_secoff_failed
                 pop si
                 retn
pass_ld_drv_secoff_failed:
                 mov byte ptr [DirBuff_CurrentEntry],0
                 mov byte ptr [DirBuff_LastEntry], 15
                 sub ax, 2
                 sbb dx, 0
                 xor bh, bh
                 mov bl, byte ptr [DirBuff_LastSector]
                 inc bl
                 call proc_mul32
                 add ax, word ptr [SI][LD_DATAbegin]
                 adc dx, word ptr [SI][LD_DATAbegin]+2
               ; xor bh, bh
                 mov bl, byte ptr [DirBuff_SectorOffset]
                 add ax, bx
                 adc dx, 0
loc_read_directory_sector:
                 mov word ptr [DirBuff_DirSector], ax
                 mov word ptr [DirBuff_DirSector]+2, dx
                 cmp byte ptr [SI][LD_LBAYes], 0
                 ja  short lba_read_directory_sector
               ; push ds
               ; pop es
                 mov bx, offset Directory_Buffer
                 mov cx, 1
                 call proc_CHS_read
                 jnc short validate_DirBuff_and_return
                 pop si
                 retn
lba_read_directory_sector:
                 mov byte ptr [DAP_BuffLBAyes], 1
                 mov byte ptr [DAP_BuffPacketSize], 10h
                 mov word ptr [DAP_BuffDestination], offset Directory_Buffer
                 push ds
                 pop word ptr [DAP_BuffDestination]+2
                 mov word ptr [DAP_BuffLBA_Address], ax
                 mov word ptr [DAP_BuffLBA_Address]+2, dx
                 mov byte ptr [DAP_BuffNumOfBlocks], 1
                 mov byte ptr [DAP_RetryCount], 4
                 mov dl, byte ptr [SI][LD_PhyDrvNo]
                 mov byte ptr [DAP_BuffDisk], dl
                 call proc_LBA_read
                 jnc short validate_DirBuff_and_return
                 pop si
                 retn
validate_DirBuff_and_return:
                 mov byte ptr [DirBuff_ValidData], 1
                 pop si
                 retn
proc_load_directory endp

proc_get_volume_name proc near
                mov     byte ptr [DirBuff_SectorOffset], 0FFh
loc_get_volume_next_sector:
                xor     bl,bl
                mov     bh, byte ptr [DirBuff_Drv]
                mov     byte ptr [DirBuff_CurrentEntry], 0
                mov     si, offset Logical_DOSDisks
                add     si, bx
                cmp     byte ptr [SI][LD_FATType], 2
                ja      short get_FAT32_root_cluster
loc_load_root_directory:
                inc     byte ptr [DirBuff_SectorOffset] 
                mov     bl, byte ptr [DirBuff_SectorOffset]
                call    proc_load_root_directory
                jnc     short loc_get_volume_name
                retn
get_FAT32_root_cluster:
                mov     ax, word ptr [SI][LD_BPB][FAT32_RootFClust]
                mov     dx, word ptr [SI][LD_BPB][FAT32_RootFClust]+2
                call    proc_load_directory
                jnc     short loc_get_volume_name
                retn
loc_get_volume_name:
                mov     si, offset Directory_Buffer
check_root_volume_name:
                cmp     byte ptr [SI]+0Bh, 28h
                je      short put_root_volume_name
                inc     byte ptr [DirBuff_CurrentEntry]
                cmp     byte ptr [DirBuff_CurrentEntry], 15
                ja      short pass_check_root_volume_name
                add     si, 32
                cmp     byte ptr [SI], 0
                ja      short check_root_volume_name
pass_check_root_volume_name:
                mov     byte ptr [DirBuff_CurrentEntry], 0
                mov     bl, byte ptr [DirBuff_SectorOffset]
                inc     bl
                cmp     bl, byte ptr [DirBuff_LastSector]
                ja      short pass_check_root_volume_name_2
                jmp     short loc_get_volume_next_sector
pass_check_root_volume_name_2:
                mov     si, offset Current_Path
put_root_volume_name:
                mov     al, byte ptr [DirBuff_Drv]
                add     al, 'A'
                mov     byte ptr [Dir_Drive_Name], al
                mov     di, offset Vol_Name
                mov     cx, 11
                rep     movsb

                mov al, byte ptr [Current_VolSerial1]
                call proc_hex
                mov word ptr [Vol_Serial1]+2, ax
                mov al, byte ptr [Current_VolSerial1]+1
                call proc_hex
                mov word ptr [Vol_Serial1], ax

                mov al, byte ptr [Current_VolSerial2]
                call proc_hex
                mov word ptr [Vol_Serial2]+2, ax
                mov al, byte ptr [Current_VolSerial2]+1
                call proc_hex
                mov word ptr [Vol_Serial2], ax
                clc
                retn
proc_get_volume_name endp

proc_dos_prompt proc near
                push ds
                pop  es 
loc_TRDOS_prompt: 
                mov DI, offset TextBuffer
                mov byte ptr [DI], "["
                inc di
                mov si, offset TRDOSPromptLabel
get_next_prompt_label_char:
                mov al, byte ptr [SI]
                cmp al, 20h
                jb  short pass_prompt_label
                mov byte ptr [DI], al
                inc si
                inc di
                jmp short get_next_prompt_label_char
pass_prompt_label:
                mov byte ptr [DI], "]"
                inc di
                mov byte ptr [DI], 20h
                inc di
                mov al, byte ptr [Current_DosDisk]
                add al, 'A'
                mov byte ptr [DI], al
                inc DI
                mov byte ptr [DI], ':'
                inc DI
                mov byte ptr [DI], 0
                mov si, offset TextBuffer
                call proc_printmsg
                mov SI, offset Dir_Str_Root
                call proc_printmsg

                mov al, '>'
                mov ah, 0Eh
                mov bx, 07h
                int 10h

                mov al, 20h
                mov ah, 0Eh
                mov bx, 07h
                int 10h


                mov     ah,03h
                mov     bx,07h                  
		int     10h
		mov     Byte Ptr [CursorColumn],dl
loc_rw_char_again:
                call    proc_rw_char
                mov     Byte Ptr [CommandBuffer]+79,0
loc_move_command:
                mov     CX, 8
                xor     SI, SI
                mov     byte ptr [CmdArgStart],1
		mov     DI, offset CommandBuffer
next_command_char:
		mov     al, byte ptr [SI][CommandBuffer]
		inc     si
		cmp     al, 20h
		ja      short pass_space_control
		jb      short pass_move_command
                cmp     cx, 8
		jb      short pass_move_command
                cmp     si,79
		jb      short next_command_char
		jmp     short pass_move_command
pass_space_control:
		cmp     al,61h
		jb      short pass_capitalize
		cmp     al,7Ah
		ja      short pass_capitalize
		and     al,0DFh
pass_capitalize:
		stosb   
                inc     byte ptr [CmdArgStart]
                loop    short next_command_char
pass_move_command:
                mov     byte ptr [DI],0
                call    command_interpreter
                mov     cx,79
                mov     di,offset CommandBuffer
                xor     al,al
                rep     stosb
                cmp     byte ptr [Program_Exit], 0
                ja      return_to_msdos
                mov     al,0Dh
                mov     ah, 0Eh
                int     10h
		mov     al,0Ah
		int     10h
                jmp     loc_TRDOS_prompt ; loop
return_to_msdos:
                retn
proc_dos_prompt  endp

proc_rw_char    proc    near
                push    es
                xor     cx,cx
                mov     es,cx
readnextchar:
                xor     ah,ah
		int     16h
		and     al,al
		jz      short loc_arrow    
		cmp     al,0E0h          
		jz      short loc_arrow
		cmp     al,08h             
		jnz     short char_return
loc_back:
		cmp     dl,Byte ptr [CursorColumn]
		ja      short prev_column
		jmp     short readnextchar
prev_column:
		dec     dl
set_cursor_pos:
		mov     ah,02h
		int     10h
              ; xor     bh,bh
                mov     bl,dl
                sub     bl,byte ptr [CursorColumn] 
                mov     cx,1
                mov     ah,09h
		mov     al,20h
                mov     Byte Ptr [CommandBuffer][BX],al
                mov     bl,7
loc_write_it:
		int     10h
                mov     dl,Byte Ptr ES:[CCCpointer]
                jmp     short readnextchar
loc_arrow:    
		cmp     AH,4Bh
		jz      short loc_back
		cmp     AH,53h
		jz      short loc_back
		cmp     AH,4Dh
		jnz     short readnextchar
		cmp     dl,79
		jnb     short readnextchar
		inc     dl
		jmp     short set_cursor_pos
char_return:
                mov     bl,dl
              ; xor     bh,bh 
                sub     bl,byte ptr [CursorColumn] 
                mov     ah,0Eh
                cmp     al,20h
		jb      short loc_escape
                mov     Byte Ptr [CommandBuffer][BX],al
                mov     bl,7
                cmp     dl,79
		jb      short loc_write_it
		jmp     short readnextchar
loc_escape:
		cmp     al,1Bh
                jnz     short pass_escape
                pop     es
                retn
pass_escape:
		cmp     al,0Dh
		jnz     short readnextchar
                int     10h
		mov     al,0Ah
		int     10h
                pop     es
                retn
proc_rw_char    endp

proc_print_directory proc near

                mov word ptr [Dir_Count],0
                mov word ptr [File_Count],0
                mov word ptr [Total_FSize], 0
                mov word ptr [Total_FSize]+2, 0

                call    proc_clear_screen

                mov     si, offset Dir_Drive_Str
                call    proc_printmsg

                mov     si, offset Vol_Serial_Header
                call    proc_printmsg

                mov     ah, 0Eh
                mov     bx, 07h
                mov     al,0Dh
                int     10h
                mov     al,0Ah
                int     10h
                mov     al,0Dh
                int     10h
                mov     al,0Ah
                int     10h

                call    proc_change_prompt_dir_string

                push    ds
                pop     es

                mov     byte ptr [DirBuff_CurrentEntry], 0
                mov     byte ptr [DirBuff_SectorOffset], 0
                mov     byte ptr [PrintDir_RowCounter], 16
                xor     bl,bl
                mov     bh, byte ptr [DirBuff_Drv]
                mov     si, offset Logical_DOSDisks
                add     si, bx
                cmp     byte ptr [SI][LD_FATType], 2
                ja      short print_FAT32_directory
                cmp     byte ptr [Current_DirLevel], 0
                ja      short print_sub_directory
print_FAT_root_directory:
                call    proc_load_root_directory
                jc      loc_dir_ok
                mov     word ptr [DirBuff_EntryCounter], 512
                mov     si, offset Directory_Buffer
                jmp     short check_dir_entry 
print_FAT32_directory:
print_sub_directory:
                mov     word ptr [DirBuff_EntryCounter], 0
                mov     ax, word ptr [Current_DirFCluster]
                mov     dx, word ptr [Current_DirFCluster]+2
                jmp     short loc_cont_to_load_dir_2
loc_cont_to_load_dir_1:
                mov     ax, word ptr [DirBuff_DirCluster]
                mov     dx, word ptr [DirBuff_DirCluster]+2
loc_cont_to_load_dir_2:
                call    proc_load_directory
                jc      loc_dir_ok
                mov     si, offset Directory_Buffer
check_dir_entry:
                cmp     Byte Ptr [SI],0 ; Is it never used entry?
                jna     loc_dir_ok
                cmp     Byte Ptr [SI],0E5h ; Is it a deleted file?
                je      loc_next_entry
                mov     bl,Byte Ptr [SI]+0Bh
                test    bl,08h  ; Is it a volume name or long name entry?
                jnz     loc_next_entry
                test    bl, byte ptr [DirEntryAttr]
                jz      loc_next_entry
                test    bl, byte ptr [DirEntryAttr]+1
                jnz     loc_next_entry

                push    si
                cmp     byte ptr [DirEntryFilters], 0
                jna     short loc_dfname_use_this
                mov     di, si
                mov     si, offset Dir_File_Name
                mov     cx, 8
loc_lodsb_dfname_1:
                lodsb
                cmp     al, '*'
                je      short loc_check_dfname_extension
pass_dfname_everyc_check:
                cmp     al, '?'
                je      short loc_scasb_dfname_3
pass_dfname_anyc_check:
                cmp     al, 20h
                jnb     short loc_scasb_dfname
loc_lodsb_dfname_2:
                cmp     byte ptr [DI], 20h
                jnb     short loc_dfname_next_entry
                jmp     short loc_dfname_use_this
loc_scasb_dfname:
                cmp     al, byte ptr [DI]
                jne     short loc_dfname_next_entry
loc_scasb_dfname_3:
                inc     di
                loop    loc_lodsb_dfname_1
loc_check_dfname_extension:
                cmp     byte ptr [DirEntryFilters]+1, 0
                jna     short loc_dfname_use_this

                pop     di  ; pushed si
                push    di
                mov     si, offset Dir_File_Name
                add     si, 8
                add     di, 8
                mov     cx, 3
loc_lodsb_dfname_4:
                lodsb
                cmp     al, '*'
                je      short loc_dfname_use_this
pass_dfname_everycext_check:
                cmp     al, '?'
                je      short loc_scasb_dfname_6
pass_dfname_anycext_check:
                cmp     al, 20h
                jnb     short loc_scasb_dfname_ext
loc_lodsb_dfname_5:
                cmp     byte ptr [DI], 20h
                jnb     short loc_dfname_next_entry
                jmp     short loc_dfname_use_this
loc_scasb_dfname_ext:
                cmp     al, byte ptr [DI]
                jne     short loc_dfname_next_entry
loc_scasb_dfname_6:
                inc     di
                loop    loc_lodsb_dfname_4

loc_dfname_use_this:
                pop     si

                test    bl,10h  ; Is it a directory?
                jz      short loc_not_dir

                inc     word ptr [Dir_Count]
                push    si
                mov     cx, 10
                mov     si, offset Type_Dir      ; '<DIR>      '
                mov     di, offset Dir_Or_FileSize
                rep     movsb                    ; move 10 bytes
                pop     si

                jmp     short loc_dir_attribute

loc_dfname_next_entry:
                pop     si
                jmp     loc_next_entry

loc_not_dir:
                inc     word ptr [File_Count]
                mov     ax, Word Ptr [SI]+1Ch ; File Size L
                mov     dx, Word Ptr [SI]+1Eh ; File Size H

                add     word ptr [Total_FSize], ax
                adc     word ptr [Total_FSize]+2, dx

                mov     di,9
loc_dir_rdivide:
                mov     cx,10                   ; 16 bit divisor
                call    Rx_Dos_Div32            ; 32 bit divide
                add     bl, '0'                 ; to make visible
                mov     Byte Ptr [Dir_Or_FileSize][DI],bl
                dec     di
                cmp     ax,0
                ja      short loc_dir_rdivide
                cmp     dx,0
                ja      short loc_dir_rdivide
loc_dir_fill_space:
                mov     Byte Ptr [Dir_Or_FileSize][DI],20h
                cmp     di,0
                jna     short loc_dir_attribute
                dec     di
                jmp     short loc_dir_fill_space
loc_dir_attribute:
                mov     word ptr [File_Attribute], 2020h
                mov     word ptr [File_Attribute]+2, 2020h
                mov     bl, Byte Ptr [SI]+0Bh
                cmp     bl, 20h  ; Is it an archive file?
                jb      short loc_dir_pass_arch
                mov     Byte Ptr [File_Attribute]+3,'A'
loc_dir_pass_arch:
                and     bl,7
                jz      short loc_dir_file_name
                mov     bh,bl
                and     bl,3
                cmp     bh,bl
                jna     short loc_dir_pass_s
                mov     byte ptr [File_Attribute], 'S'
loc_dir_pass_s:
                and     bl,2
                jz      short loc_dir_pass_h
                mov     byte ptr [File_Attribute]+1, 'H'
loc_dir_pass_h:
                and     bh,1
                jz      short loc_dir_file_name
                mov     byte ptr [File_Attribute]+2, 'R'
loc_dir_file_name:
                mov     bx, word ptr [SI]+18h ; Date
                mov     dx, word ptr [SI]+16h ; Time
                push    si
                mov     cx, 8
                mov     di, offset File_Name
                rep     movsb                    ; move 8 bytes
                mov     Byte Ptr [DI],20h
                inc     di
                mov     cx, 3
                rep     movsb                    ; move 3 bytes
                pop     si
Dir_Date_start:
		mov     ax, bx                   ; Date
		and     ax, 00011111b            ; Day Mask
		aam                              ; Q([AL]/10)->AH
						 ; R([AL]/10)->AL
						 ; [AL]+[AH]= Day as BCD
		or      ax, '00'                 ; Convert to ASCII
		xchg    al,ah
                mov     word ptr [File_Day],ax

		mov     ax, bx
		mov     cl, 5
		shr     ax, cl                   ; shift right 5 times
		and     ax, 00001111b            ; Month Mask
		aam
		or      ax, '00'
		xchg    ah,al
                mov     word ptr [File_Month],ax

		mov     ax, bx
		mov     cl, 9
		shr     ax, cl
		and     ax, 01111111b            ; Result = Year - 1980
		add     ax, 1980

		mov     cl, 10
		div     cl                        ; Q -> AL, R -> AH 
		or      ah, '0'
                mov     byte ptr [File_Year]+3,ah

		aam
		xchg    ah, al
		or      ah, '0'                  ; Convert to ASCII
                mov     byte ptr [File_Year]+2,ah

		aam
		xchg     al, ah
		or      ax, '00'
                mov     word ptr [File_Year],ax

Dir_Time_start:
		mov     ax, dx                   ; Time
		mov     cl, 5
		shr     ax, cl                   ; shift right 5 times
		and     ax, 0000111111b          ; Minute Mask
		aam
		or      ax, '00'
		xchg    ah,al
                mov     word ptr [File_Minute],ax

		mov     al, dh                   
		shr     al, 1
		shr     al, 1
		shr     al, 1                    ; ax = hours
		aam
		or      ax, '00'
		xchg    ah, al
                mov     word ptr [File_Hour],ax
loc_show_line:
                push    si
                mov     si, offset File_Name
                mov     cx, 46
		mov     ah, 0Eh
		mov     bx, 07h
loop_loc_dir_entry:
                lodsb                           
                int     10h                     
                loop    loop_loc_dir_entry     
                pop si

                mov     al,0Dh
                int     10h
                mov     al,0Ah
                int     10h
                sub     byte ptr [PrintDir_RowCounter], 1
                jna     Pause_dir_scroll
loc_next_entry:
                dec     word ptr [DirBuff_EntryCounter]
                cmp     word ptr [DirBuff_EntryCounter], 0
                jna     short loc_dir_ok
                add     si, 32
                inc     byte ptr [DirBuff_CurrentEntry]
                cmp     byte ptr [DirBuff_CurrentEntry], 15
                jna     check_dir_entry
                mov     bh, byte ptr [DirBuff_Drv]
                xor     bl, bl
                mov     si, offset Logical_DOSDisks
                add     si, bx
                mov     bl, byte ptr [DirBuff_SectorOffset]
                inc     bl
                cmp     byte ptr [Current_DirLevel],0
                ja      short pass_load_next_rdir_sector
                cmp     byte ptr [SI][LD_FATType],2
                ja      short pass_load_next_rdir_sector
                cmp     bl, byte ptr [DirBuff_LastSector]
                jna     print_FAT_root_directory
                jmp     short loc_dir_ok
pass_load_next_rdir_sector:
                cmp     bl, byte ptr [DirBuff_LastSector]
                jna     loc_cont_to_load_dir_1
load_next_dir_cluster:
                mov     ax, word ptr [DirBuff_DirCluster]
                mov     dx, word ptr [DirBuff_DirCluster]+2
               ; push    si
                call    proc_get_next_cluster
               ; pop     si
                jc      short loc_dir_ok
                cmp     al, 0F6h
                jna     short put_dirbuff_cluster_values
                cmp     byte ptr [SI][LD_FATType],1
                ja      short loc_FAT16_eoc_check
                cmp     ah, 0Fh
                jb      short put_dirbuff_cluster_values
                jmp     short loc_dir_ok
loc_FAT16_eoc_check:
                cmp     byte ptr [SI][LD_FATType],2
                ja      short loc_FAT32_eoc_check
                cmp     ah, 0FFh
                jnb     short loc_dir_ok
put_dirbuff_cluster_values:
                xor     bl, bl
                mov     bh, byte ptr [DirBuff_Drv]
              ; mov     word ptr [DirBuff_NextCluster], ax
              ; mov     word ptr [DirBuff_NextCluster]+2, dx
                jmp     loc_cont_to_load_dir_2
loc_FAT32_eoc_check:
                cmp     ah, 0FFh
                jb      short put_dirbuff_cluster_values
                cmp     dx, 0FFFh
                jb      short put_dirbuff_cluster_values
loc_dir_ok:
                mov     ax, word ptr [Dir_Count]
                mov     di, offset Decimal_Dir_Count
                cmp     ax, 10
                jb      short pass_ddc
                inc     di
                cmp     ax, 100
                jb      short pass_ddc
                inc di
                cmp     ax, 1000
                jb      short pass_ddc
                inc di
                cmp     ax, 10000
                jb      short pass_ddc
                inc di
pass_ddc:
                mov     byte ptr [DI]+1, 0
loc_ddc_rediv:
                xor     dx, dx
                mov     cx, 10
                div     cx
                add     dl, "0"
                mov     byte ptr [DI], dl
                dec     DI
                cmp     ax, 0
                ja      short loc_ddc_rediv

                mov     ax, word ptr [File_Count]
                mov     di, offset Decimal_File_Count
                cmp     ax, 10
                jb      short pass_dfc
                inc     di
                cmp     ax, 100
                jb      short pass_dfc
                inc di
                cmp     ax, 1000
                jb      short pass_dfc
                inc di
                cmp     ax, 10000
                jb      short pass_dfc
                inc di
pass_dfc:
                mov     byte ptr [DI]+1, 0
loc_dfc_rediv:
                xor     dx, dx
                mov     cx, 10
                div     cx
                add     dl, "0"
                mov     byte ptr [DI], dl
                dec     DI
                cmp     ax, 0
                ja      short loc_dfc_rediv

                mov     di, offset TFS_Dec_End
                mov     byte ptr [DI], 0
                mov     ax, word ptr [Total_FSize]
                mov     dx, word ptr [Total_FSize]+2
                mov     cx, 10
rediv_tfs_hex:
                call    Rx_Dos_Div32
                add     bl, "0"
                dec     DI
                mov     byte ptr [DI], bl
                cmp     ax, 0
                ja      short rediv_tfs_hex
                cmp     dx, 0
                ja      short rediv_tfs_hex
                mov     word ptr [TFS_Dec_Begin], DI
                mov si, offset Decimal_File_Count_Header
                call proc_printmsg
                mov si, offset str_files
                call proc_printmsg
                mov si, offset str_dirs
                call proc_printmsg
                mov si, word ptr [TFS_Dec_Begin]
                call proc_printmsg
                mov si, offset str_bytes
                call proc_printmsg

                retn

Pause_dir_scroll:
                xor    ah, ah                                           
                int    16h
                cmp    al,1Bh
                je     loc_dir_ok
                mov    byte ptr [PrintDir_RowCounter], 16 ; Reset counter
                jmp    loc_next_entry

File_Count:     dw 0
Dir_Count:      dw 0
Decimal_File_Count_Header:  db 0Dh, 0Ah
Decimal_File_Count: db 6 dup(0)
str_files:      db " file(s) & "
Decimal_Dir_Count: db 6 dup(0)
str_dirs:       db " directory(s) ", 0Dh, 0Ah, 0
Total_FSize:    dd 0
TFS_Dec_Begin:  dw 0
                db 10 dup(0)
TFS_Dec_End:    db 0
str_bytes:      db " byte(s) in file(s)", 0Dh, 0Ah, 0

proc_print_directory endp

proc_change_current_drive proc near
               ; INPUT al= logical dos drive number
               cmp al, 1
               ja short loc_change_current_drv0
loc_init_drv_fd:
               mov dl, al
               call floppy_drv_init
               jnc short loc_change_current_drv1
               retn
loc_change_current_drv0:
               mov si, offset Logical_DOSdisks
               mov ah, al
               xor al, al
               add si, ax
loc_change_current_drv1:
               mov al, byte ptr [SI][LD_Name]
               sub al, 'A'
               jc  short loc_return_change_drive
               mov byte ptr [DirBuff_Drv], al
               mov byte ptr [Current_DirLevel], 0
               mov byte ptr [Dir_Str], 0
               cmp byte ptr [SI][LD_FATType], 2
               ja short loc_get_FAT32_bs_volume_name
               push word ptr [SI][LD_BPB][VolumeID]
               pop word ptr [Current_VolSerial1]
               push word ptr [SI][LD_BPB][VolumeID]+2
               pop word ptr [Current_VolSerial2]
               mov word ptr [Current_DirFCluster], 0
               mov word ptr [Current_DirFCluster]+2, 0
               mov word ptr [DirBuff_DirCluster], 0
               mov word ptr [DirBuff_DirCluster]+2, 0
               jmp short loc_init_ccd_volume
loc_get_FAT32_bs_volume_name:
               push word ptr [SI][LD_BPB][FAT32_RootFClust]
               pop word ptr [Current_DirFCluster]
               push word ptr [SI][LD_BPB][FAT32_RootFClust]+2
               pop word ptr [Current_DirFCluster]+2
               mov word ptr [DirBuff_DirCluster], 0
               mov word ptr [DirBuff_DirCluster]+2, 0
               push word ptr [SI][LD_BPB][FAT32_VolID]
               pop word ptr [Current_VolSerial1]
               push word ptr [SI][LD_BPB][FAT32_VolID]+2
               pop word ptr [Current_VolSerial2]
loc_init_ccd_volume:
               call proc_get_volume_name
               mov al, byte ptr [DirBuff_Drv]
               mov byte ptr [Current_DosDisk], al
               clc
loc_return_change_drive:
               retn
proc_change_current_drive endp

command_interpreter proc near
cmp_cmd_dir:
                mov byte ptr [Program_Exit],0
                mov cx,3
                xor si,si
                mov di, offset Cmd_Dir
get_char_dir:
                mov al, byte ptr [CommandBuffer][SI]
                inc si
		scasb
                jne cmp_cmd_cd
		loop get_char_dir
                mov al, byte ptr [CommandBuffer][SI]
                cmp al, 20h
                ja loc_cmd_failed
get_dfname_fchar:
                inc si
                mov al, byte ptr [CommandBuffer][SI]
                cmp al, 20h
                je short get_dfname_fchar
                jb loc_print_dir_call_all
                cmp al, '-'
                jne pass_dir_attr_chars
get_next_attr_char:
                mov word ptr [DirEntryFilters], 0
                inc si
                mov al, byte ptr [CommandBuffer][SI]
                cmp al, 20h
                je short get_next_attr_char
                jb loc_print_dir_call_flt
                and al, 0DFh
                cmp al, 'D'
                jne short pass_only_directories
                mov byte ptr [DirEntryAttr], 10h
                mov byte ptr [DirEntryAttr]+1, 0
                jmp loc_print_dir_call_attr
pass_only_directories:
                cmp al, 'F'
                jne short pass_only_files
                mov byte ptr [DirEntryAttr], 0FFh
                mov byte ptr [DirEntryAttr]+1, 10h
                jmp loc_print_dir_call_attr
pass_only_files:
                mov byte ptr [DirEntryAttr], 0h
                mov byte ptr [DirEntryAttr]+1, 0h
check_attr_s:
                cmp al, 'S'
                jne short pass_attr_s
                or byte ptr [DirEntryAttr], 4
                inc si
                mov al, byte ptr [CommandBuffer][SI]
                cmp al, 20h
                jna short loc_print_dir_call_attr
                and al, 0DFh
pass_attr_s:
                cmp al, 'H'
                jne short pass_attr_h
                or byte ptr [DirEntryAttr], 2
                inc si
                mov al, byte ptr [CommandBuffer][SI]
                cmp al, 20h
                jna short loc_print_dir_call_attr
                and al, 0DFh
                jmp short check_attr_s
pass_attr_h:
                cmp al, 'R'
                jne short pass_attr_r
                or byte ptr [DirEntryAttr], 1
                inc si
                mov al, byte ptr [CommandBuffer][SI]
                cmp al, 20h
                jna short loc_print_dir_call_attr
                and al, 0DFh
                jmp short check_attr_s
pass_attr_r:
                cmp al, 'A'
                jne short loc_print_dir_call_attr
                or byte ptr [DirEntryAttr], 20h
                inc si
                mov al, byte ptr [CommandBuffer][SI]
                cmp al, 20h
                jna short loc_print_dir_call_attr
                and al, 0DFh
                jmp short check_attr_s
pass_dir_attr_chars:
                mov word ptr [DirEntryFilters], 1
                add si, offset CommandBuffer
                mov di, offset Dir_File_Name
                call proc_convert_file_name
                mov byte ptr [DI], 0
                sub di, offset Dir_File_Name
                cmp di, 8
                jna short loc_print_dir_call_flt
                mov byte ptr [DirEntryFilters]+1, 1
                jmp short loc_print_dir_call_flt
loc_print_dir_call_all:
                mov word ptr [DirEntryFilters], 0
loc_print_dir_call_flt:
                mov byte ptr [DirEntryAttr], 0FFh
                mov byte ptr [DirEntryAttr]+1, 0
loc_print_dir_call_attr:
                call proc_print_directory
                jc loc_not_ready_read_err
                retn
cmp_cmd_cd:
                mov ax, word ptr [CommandBuffer]
                cmp ax, 'DC'
                jne cmp_cmd_drive
                mov si, 2
                cmp byte ptr [CommandBuffer][SI], 20h
                ja loc_cmd_failed
get_char_cd:
                inc si
                mov al, byte ptr [CommandBuffer][SI]
                cmp al, 20h
                je short get_char_cd
                jb loc_cmd_cd_return
get_next_cd_char:
                mov ah, byte ptr [CommandBuffer][SI]+1
                cmp ah, ':'
                jne short pass_drive_change
                mov ah, byte ptr [CommandBuffer][SI]+2
                cmp ah, 20h
                ja loc_cmd_failed
                and al, 0DFh
                sub al, 'A'
                jc loc_cmd_failed
                cmp al, byte ptr [Last_Dos_DiskNo]
                ja short loc_cd_drive_not_ready
                call proc_change_current_drive
                jc short loc_cd_drive_not_ready
                jmp replace_current_dir_path
loc_cd_drive_not_ready:
                mov si, offset Msg_Not_Ready_Read_Err
                call proc_printmsg
                retn
pass_drive_change:
                cmp al, "."
                jne short pass_cd_dot_check
                cmp ah,  20h
                jna short loc_cmd_cd_return
                cmp ah, "."
                jne loc_cmd_failed
                cmp byte ptr [CommandBuffer][SI]+2, 20h
                ja  loc_cmd_failed
                mov al, byte ptr [Current_DirLevel]
                cmp al, 0
                jna short loc_cmd_cd_return
                dec al
                mov byte ptr [Last_DirLevel], al
                jmp short pass_cd_parse_dir_name
pass_cd_dot_check:
                add si, offset CommandBuffer
                call proc_parse_dir_name
pass_cd_parse_dir_name:
                call proc_change_current_directory
                xor bl,bl
                mov bh, byte ptr [DirBuff_Drv]
                mov di, offset Logical_DOSdisks
                add di, bx
                mov al, byte ptr [Current_DirLevel]
                mov byte ptr [DI][LD_CDirLevel],al
                mov si, offset Current_Path
                add di, LD_CurrentDirectory
                mov cx, 64
                rep movsw
                call proc_change_prompt_dir_string
loc_cmd_cd_return:
                retn
cmp_cmd_drive:
                ; C:, D:, E: etc.
                mov ax, word ptr [CommandBuffer]
                cmp ah, ':'
                jne short cmp_cmd_ver
                mov ah, byte ptr [CommandBuffer]+2
                cmp ah, 20h
                ja loc_cmd_failed
                and al, 0DFh
                sub al, 'A'
                jc loc_cmd_failed
                cmp al, byte ptr [Last_Dos_DiskNo]
                ja short loc_cd_drive_not_ready
                call proc_change_current_drive
                jc loc_cd_drive_not_ready
replace_current_dir_path:
                xor bl, bl
                mov bh, byte ptr [DirBuff_Drv]
                mov si, offset Logical_DOSdisks
                add si, bx
                mov al, byte ptr [SI][LD_CDirLevel]
                mov byte ptr [Current_DirLevel],al
                mov byte ptr [Last_DirLevel],al
                add si, LD_CurrentDirectory
                mov di, offset Current_Path
                mov cx, 64
                rep movsw
                cmp al, 0
                jna short loc_cmd_cd_return
                jmp short pass_cd_parse_dir_name
cmp_cmd_ver:
		mov  cx,3
		xor  si,si
                mov  di, offset Cmd_Ver
get_char_ver:
                mov  al, byte ptr [CommandBuffer][SI]
		inc  si
		scasb
                jne  short cmp_cmd_exit
                loop get_char_ver
                mov  al, byte ptr [CommandBuffer][SI]
		cmp  al,20h
                ja loc_cmd_failed
                mov si, offset Program_Version
                call proc_printmsg
                retn
cmp_cmd_exit:
                mov  cx,4
		xor  si,si
                mov  di, offset Cmd_Exit
get_char_exit:
                mov  al, byte ptr [CommandBuffer][SI]
		inc  si
		scasb
                jne  short cmp_cmd_prompt
                loop get_char_exit
                mov  al, byte ptr [CommandBuffer][SI]
		cmp  al,20h
                ja loc_cmd_failed
                mov byte ptr [Program_Exit], 1
                retn
cmp_cmd_prompt:
                mov  cx,6
		xor  si,si
                mov  di, offset Cmd_Prompt
get_char_prompt:
                mov  al, byte ptr [CommandBuffer][SI]
		inc  si
		scasb
                jne  short cmp_cmd_volume
                loop get_char_prompt
                mov  al, byte ptr [CommandBuffer][SI]
		cmp  al,20h
                ja   loc_cmd_failed
get_prompt_name_fchar:
                inc si
                mov al, byte ptr [CommandBuffer][SI]
                cmp al, 20h
                je short get_prompt_name_fchar
                ja short loc_change_prompt_label
                mov si, offset TRDOSPromptLabel
                mov word ptr [SI], "RT"
                inc si
                inc si
                mov word ptr [SI], "OD"
                inc si
                inc si
                mov byte ptr [SI], "S"
                inc si
                mov byte ptr [SI], 0
loc_cmd_prompt_return:
                retn
loc_change_prompt_label:
                ; push ds
                ; pop es
                mov cx, 11
                add si, offset CommandBuffer
                mov di, offset TRDOSPromptLabel
put_char_new_prompt_label:
                lodsb
                cmp al, 20h
                jb short pass_put_new_prompt_label
                stosb
                loop put_char_new_prompt_label
pass_put_new_prompt_label:
                mov byte ptr [DI], 0
                retn
cmp_cmd_volume:
                mov  cx,6
		xor  si,si
                mov  di, offset Cmd_Volume
get_char_volume:
                mov  al, byte ptr [CommandBuffer][SI]
		inc  si
		scasb
                jne  short check_vol_str
                loop get_char_volume
                mov  al, byte ptr [CommandBuffer][SI]
                cmp  al,20h
                ja   loc_cmd_failed
get_vol_drive_name_fchar:
                inc si
get_vol_drive_name_fchar1:
                mov al, byte ptr [CommandBuffer][SI]
                cmp al, 20h
                ja short pass_vol_current_drive
                je short get_vol_drive_name_fchar
                mov al, byte ptr [DirBuff_Drv]
                jmp short loc_get_volume_size_info
check_vol_str:
                cmp SI, 4
                jne short cmp_cmd_longname
                cmp al,20h
                ja  loc_cmd_failed
                jmp short get_vol_drive_name_fchar1
pass_vol_current_drive:
                cmp al, 'A'
                jb  loc_cmd_failed
                cmp al, 'z'
                ja  loc_cmd_failed
                cmp al, 'Z'
                jna short pass_vol_drv_capitalize
                cmp al, 'a'
                jb  loc_cmd_failed
                and al, 0DFh
pass_vol_drv_capitalize:
                inc si
                mov ah, byte ptr [CommandBuffer][SI]
                cmp ah, ":"
                jne loc_cmd_failed
                sub al, 'A'
loc_get_volume_size_info:
                call proc_volume_total_free_space
                jc loc_cd_drive_not_ready
                retn
cmp_cmd_longname:
                mov  cx,8
		xor  si,si
                mov  di, offset Cmd_LongName
get_char_longname:
                mov  al, byte ptr [CommandBuffer][SI]
		inc  si
		scasb
                jne  short cmp_cmd_date
                loop get_char_longname
                mov  al, byte ptr [CommandBuffer][SI]
		cmp  al,20h
                ja   loc_cmd_failed
get_longname_fchar:
                inc si
                mov al, byte ptr [CommandBuffer][SI]
                cmp al, 20h
                je short get_longname_fchar
                jb short pass_find_longname
                add si, CommandBuffer
                call proc_find_longname
pass_find_longname:
                retn
cmp_cmd_date:
                mov  cx,4
		xor  si,si
                mov  di, offset Cmd_Date
get_char_date:
                mov  al, byte ptr [CommandBuffer][SI]
		inc  si
		scasb
                jne  short cmp_cmd_time
                loop get_char_date
                mov  al, byte ptr [CommandBuffer][SI]
		cmp  al,20h
                ja   loc_cmd_failed
                call proc_show_date
                call proc_set_date
                retn
cmp_cmd_time:
                mov  cx,4
		xor  si,si
                mov  di, offset Cmd_Time
get_char_time:
                mov  al, byte ptr [CommandBuffer][SI]
		inc  si
		scasb
                jne  short cmp_cmd_run
                loop get_char_time
                mov  al, byte ptr [CommandBuffer][SI]
		cmp  al,20h
                ja   loc_cmd_failed
                call proc_show_time
                call proc_set_time
                retn
cmp_cmd_run:
                mov  cx,3
		xor  si,si
                mov  di, offset Cmd_Run
get_char_run:
                mov  al, byte ptr [CommandBuffer][SI]
		inc  si
		scasb
                jne  loc_cmd_failed
                loop get_char_run
                mov  al, byte ptr [CommandBuffer][SI]
		cmp  al,20h
                ja   loc_cmd_failed
get_runfile_fchar:
                inc si
                mov al, byte ptr [CommandBuffer][SI]
                cmp al, 20h
                je short get_runfile_fchar
                jnb short loc_find_runfile
                retn
loc_find_runfile:
                add si, CommandBuffer
                push ds
                pop es
                mov di, offset Dir_File_Name
		call proc_convert_file_name
                cmp byte ptr [Dir_File_Name]+8, "C"
                jne short loc_check_exe_file
                cmp byte ptr [Dir_File_Name]+9, "O"
                jne short loc_check_exe_file
                cmp byte ptr [Dir_File_Name]+10, "M"
                jne loc_cmd_failed
                mov byte ptr [EXE_ID], 0
                jmp short loc_find_load_executable_file
loc_check_exe_file:
                cmp word ptr [Dir_File_Name]+8, "XE"
                jne loc_cmd_failed
                cmp byte ptr [Dir_File_Name]+10, "E"
                jne loc_cmd_failed
                mov byte ptr [EXE_ID], 'E'
loc_find_load_executable_file:
                xor bl, bl
                mov bh, byte ptr [DirBuff_Drv]
                cmp byte ptr [Current_DirLevel], 0
                ja short loc_find_runfile_next_sec1
                cmp byte ptr [Current_FS], 2
                ja short loc_find_runfile_next_sec1
                call proc_load_root_directory
                jc loc_runfile_notfound
                jmp short loc_find_runfile_cont
loc_find_runfile_next_sec1:
                mov ax, word ptr [Current_DirFCluster]
                mov dx, word ptr [Current_DirFCluster]+2
loc_find_runfile_next_sec2:
                call proc_load_directory
                jc loc_runfile_notfound
loc_find_runfile_cont:
                mov si, offset Dir_File_Name
                xor ax, ax
                xor cx, cx
                mov bx, 1800h ; Except volume label and dirs
                call proc_find_direntry
                jnc loc_runfile_found

                xor bl, bl
                mov bh, byte ptr [DirBuff_Drv]
                cmp byte ptr [Current_DirLevel], 0
                ja short pass_loc_rf_load_next_root_sector
                cmp byte ptr [Current_FS], 2
                ja short pass_loc_rf_load_next_root_sector
                mov bl, byte ptr [DirBuff_SectorOffset]
                inc bl
                cmp bl, byte ptr [DirBuff_LastSector]
                ja short loc_runfile_notfound
                call proc_load_root_directory
                jc short loc_runfile_notfound
                jmp short loc_find_runfile_cont
pass_loc_rf_load_next_root_sector:
                mov ax, word ptr [DirBuff_DirCluster]
                mov dx, word ptr [DirBuff_DirCluster]+2
                mov bl, byte ptr [DirBuff_SectorOffset]
                inc bl
                cmp bl, byte ptr [DirBuff_LastSector]
                jna short loc_find_runfile_next_sec2
                xor bl, bl
                call proc_get_next_cluster
                jc short loc_runfile_notfound

                cmp al, 0F6h
                jna short loc_find_runfile_next_sec2
                cmp byte ptr [Current_FS], 1
                ja short find_runfile_FAT16_eoc_check
                cmp ah, 0Fh
                jb short loc_find_runfile_next_sec2
                jmp short loc_runfile_notfound
find_runfile_FAT16_eoc_check:
                cmp byte ptr [Current_FS], 2
                ja short find_runfile_FAT32_eoc_check
                cmp ah, 0FFh
                jnb short loc_runfile_notfound
                jmp loc_cd_find_dir_next_sec2
find_runfile_FAT32_eoc_check:
                cmp ah, 0FFh
                jb loc_find_runfile_next_sec2
                cmp dx, 0FFFh
                jb loc_find_runfile_next_sec2
loc_runfile_notfound:
                mov si, offset Msg_File_Not_Found
                call proc_printmsg
                stc
                retn
loc_runfile_found:
                mov al, 32
                mul cl
                mov si, ax
                add si, offset Directory_Buffer
                mov ax, word ptr [SI]+28 ; FileSize Low Word
                mov dx, word ptr [SI]+30 ; FileSize High Word
                cmp dx, 0
                ja  loc_cmd_failed
                cmp ax, 0
                jna loc_cmd_failed
                mov word ptr [Program_Size], ax
                mov word ptr [Program_Size]+2, dx
                mov ax, word ptr [SI]+26 ; First Cluster Low Word
                mov dx, word ptr [SI]+20 ; First Cluster High Word
                cmp dx, 0
                ja short pass_runfile_fc_check
                cmp ax, 2
                jb  loc_cmd_failed
pass_runfile_fc_check:
                push ax
                push dx
                xor dx, dx
                mov ax, offset RunFile_Buffer
                mov bx, 16
                div bx
                mov bx, ds
                add ax, bx
                mov word ptr [Run_Segment], ax
                mov word ptr [Run_Offset], 100h
                pop dx
                pop ax
                xor bl,bl
                mov bh, byte ptr [DirBuff_Drv]
                mov di, word ptr [Run_Offset]
                push word ptr [Run_Segment]
                pop es
                call proc_load_file
                jc loc_not_ready_read_err

		xor bx, bx
		mov es, bx

		mov bx, word ptr ES:[80h]   ; Int 20h Offset
		mov word ptr [INT20h_Offset], bx
		mov bx, word ptr ES:[82h]   ; Int 20h Segment
		mov word ptr [INT20h_segment], bx

		mov si, offset Run_Com_INT20h_Handler

		mov di, 80h
		mov word ptr ES:[DI], si      ; Temporary INT20h handler

		mov si, ds

		mov word ptr ES:[DI]+2, si    ; Temporary INT20h handler

                mov es, word ptr [Run_Segment]  ; Program segment to run
                mov word ptr [StackPointer], sp
                mov word ptr [BasePointer], bp
                xor bx,bx
                mov word ptr ES:[BX], 20CDh ; INT 20h (CD20h) for "RET"
                cmp byte ptr [EXE_ID], 0
                jna short far_jump_to_com_file

loc_relocate_exe_items:
                ; This code written by Erdogan Tan
                ; by using "Dissecting DOS" book by
                ; Michael Podanoffsky (Rx_DOS)
                ; and source code by
                ; Alexei A. Frounze (OS for Dummies Loader)
                mov ax, word ptr [Run_Segment]
                add ax, 10h
                mov es, ax
                add ax, word ptr ES:[08h] ;Size of header, in paragraphs
                mov cx, word ptr ES:[06h] ;Number of relocation items
                mov bx, word ptr ES:[18h] ;Relocation table offset
                jcxz short exe_hdr_relocation_done
exe_hdr_relocation_cycle:
                mov di, word ptr ES:[BX]   ;Item Offset
                mov dx, word ptr ES:[BX+2] ;Item Segment (Relative]
                add dx, ax                 ;Item Segment (Absolute)
                push es
                mov es, dx
                add word ptr ES:[DI], ax ;Fixup
                pop es
                add bx, 4
                loop exe_hdr_relocation_cycle
exe_hdr_relocation_done:
                mov bx, ax
                add bx, word ptr ES:[0Eh] ;Initial SS Value
                mov ss, bx
                mov sp, word ptr ES:[10h] ;Initial SP Value
                add ax, word ptr ES:[16h] ;Initial CS Value
                mov bx, word ptr [Run_Segment]
                mov word ptr [Run_Segment], ax
                mov ax, word ptr ES:[14h] ;Intial IP Value
                mov word ptr [Run_Offset], ax
                jmp short far_jump_to_exe_file
far_jump_to_com_file:
                mov bx, word ptr [Run_Segment]
                mov ss, bx
                mov sp, 0FFFEh
far_jump_to_exe_file:
                mov ds, bx
                mov es, bx
                push bx
                xor ax, ax
                push ax
                mov cx, word ptr [Program_Size]
                mov bx, word ptr [Program_Size]+2
                xor si, si
                xor di, di
                jmp dword ptr CS:[Run_Offset]

Run_Com_INT20h_Handler:
                ; CPU comes here via INT 20h
               ; pop ax ; IP
               ; pop ax ; CS 
               ; pop ax ; Flags

                push cs
		pop  ds
                push ds
		pop  ss
                mov sp, word ptr [StackPointer]
                mov bp, word ptr [BasePointer]
                xor ax, ax
                mov es, ax
                push word ptr [INT20h_Offset]
                pop word ptr ES:[80h]
                push word ptr [INT20h_Segment]
                pop word ptr ES:[82h]
                push ds
		pop  es
                sti
                retn

Program_Size: dd 0
EXE_ID: db 0
StackPointer: dw 0
BasePointer: dw 0
INT20h_Offset: dw 0
INT20h_Segment: dw 0
Run_Offset: dw 0
Run_Segment: dw 0

loc_cmd_failed:
                cmp byte ptr [CommandBuffer], 20h
                jna short loc_cmd_return
                mov si, offset Msg_Bad_Command
                call proc_printmsg
loc_cmd_return:
                retn

loc_not_ready_read_err:
                mov si, offset Msg_Not_Ready_Read_err
                call proc_printmsg

                retn

command_interpreter endp

floppy_drv_init proc near
                mov si, offset Disk_fd0
                mov di, offset Logical_DOSDisks
                xor dh, dh
                cmp dl, 0
                jna short pass_drv_init_fd1
                add si, 40h
                add di, 100h
pass_drv_init_fd1:
                mov byte ptr [DI][LD_MediaChanged],0
             ;  cmp byte ptr [SI][DPDType], 0
             ;  jna short pass_fd_read_boot_sector0
read_fd_boot_sector:
                push ds
                pop es
                push dx
                mov cx, 4 ; Retry Count
read_fd_boot_sector_again:
                push cx
                mov cx, 1
                mov ax, 0201h    ; Read 1 sector
                mov bx, offset DOSBootSectorBuff
                int 13h
                pop cx
                jnc short use_fd_boot_sector_params
                loop read_fd_boot_sector_again
pass_fd_read_boot_sector0:
                stc
pass_fd_read_boot_sector1:
                pop dx
                retn
use_fd_boot_sector_params:
                cmp word ptr [BS_Validation], 0AA55h
                jne short pass_fd_read_boot_sector0
              ; cmp byte ptr [BS_BootSig], 29h
              ; jne short pass_fd_read_boot_sector0
                cmp byte ptr [BPB_Media], 0F0h
                jb short pass_fd_read_boot_sector1
                mov si, offset DOSBootSectorBuff
                push di
                add di, LD_BPB
                mov cx, 32
                rep movsw 
                pop si
                xor ax, ax
                mov Word Ptr [SI][LD_StartSector], AX
                mov Word Ptr [SI][LD_StartSector]+2,0
                add AX,Word Ptr [SI][LD_BPB][ResSectors]
                mov Word Ptr [SI][LD_FATBegin], AX
                mov Word Ptr [SI][LD_FATBegin]+2, 0
                mov AL,Byte Ptr [SI][LD_BPB][FATs] 
                cbw                             
                mul Word Ptr [SI][LD_BPB][FATSecs]
                add AX,Word Ptr [SI][LD_FATBegin]
                mov Word Ptr [SI][LD_ROOTBegin], AX
                mov Word Ptr [SI][LD_ROOTBegin]+2, 0
                mov Word Ptr [SI][LD_DATABegin], AX 
                mov Word Ptr [SI][LD_DATABegin]+2, 0
                mov AX,20h   ; Size of a directory entry
                mul Word Ptr [SI][LD_BPB][RootDirEnts]
                add AX,511
                mov cx,512
                div cx
                add Word Ptr [SI][LD_DATABegin], AX 
                adc Word Ptr [SI][LD_DATABegin]+2, 0 
                mov AX,Word Ptr [SI][LD_BPB][Sectors]
                mov Word Ptr [SI][LD_TotalSectors], AX
                mov Word Ptr [SI][LD_TotalSectors]+2,0
                sub ax,Word Ptr [SI][LD_DATABegin]
                xor dx,dx
                xor ch,ch
                mov cl,Byte Ptr [SI][LD_BPB][SecPerClust]
                div cx 
                mov word ptr [SI][LD_Clusters], AX
                mov byte ptr [SI][LD_FATType], 1
                mov byte ptr [SI][LD_FSType], 0
                mov word ptr [SI][LD_Clusters]+2, 0
                    ; Maximum Valid Cluster Number= AX +1
                    ; with 2 reserved clusters= AX +2
                pop ax
                mov byte ptr [SI][LD_DParamEntry], al
                mov byte ptr [SI][LD_PhyDrvNo], al
                add al, 'A'
                mov byte ptr [SI][LD_Name], al
                mov byte ptr [SI][LD_DiskType], 1
                mov byte ptr [SI][LD_LBAYes], 0
                mov byte ptr [SI][LD_PartitionEntry], 0
                mov byte ptr [SI][LD_MediaChanged], 1
                retn

floppy_drv_init endp
   
proc_parse_dir_name proc near
                ; DS:SI = Directory String
                cmp byte ptr [SI], "/"
                jne short pass_reset_parse_sd_levels
                xor ah, ah
                mov byte ptr [Last_DirLevel],0
                mov byte ptr [Current_DirLevel],0
                jmp short repeat_parse_sd_name0
pass_reset_parse_sd_levels:
                mov ah, byte ptr [Current_DirLevel]
                mov byte ptr [Last_DirLevel],ah
                jmp short repeat_parse_sd_name2
repeat_parse_sd_name0:
                inc si
repeat_parse_sd_name1:
                cmp byte ptr [SI], "/"
                je short repeat_parse_sd_name0
repeat_parse_sd_name2:
                cmp byte ptr [SI], 20h
                ja short pass_reset_dir_level
                jb short end_of_parse_dir_name
                jmp short repeat_parse_sd_name0
pass_reset_dir_level:
                inc ah 
                cmp ah, 7
                ja short end_of_parse_dir_name
                mov byte ptr [Last_DirLevel],ah
                mov cx, 12
                mov di, offset Dir_File_Name
loc_get_subdir_name:
                lodsb
                mov byte ptr [DI], al
                cmp al, 20h
                jna short end_of_subdir_name
                cmp al, "/"
                je short end_of_subdir_name
                inc di
                loop loc_get_subdir_name
end_of_subdir_name:
                mov byte ptr [DI], 0
                push ax
                push si
                mov si, offset Dir_File_Name
                mov al, byte ptr [Last_DirLevel]
                mov ah, 16
                mul ah
                mov di, offset Current_Path
                add di, ax
                mov word ptr [DI]+12, 0
                mov word ptr [DI]+14, 0
                call proc_convert_file_name
                pop si
                pop ax
                cmp al, 0Dh
                jna short end_of_parse_dir_name
                mov ah, byte ptr [Last_DirLevel]
                jmp short repeat_parse_sd_name1
end_of_parse_dir_name:
                retn
proc_parse_dir_name endp

proc_convert_file_name proc near
     ; INPUT -> DS:SI = Dot File Name Location
     ; INPUT -> ES:DI = Dir Entry Format File Name Location
     push di
     mov cx, 11
     mov al, 20h
     rep stosb
     pop di
     mov cx, 12
     mov al, 2Eh
     cmp byte ptr [SI], 2Eh
     je short pass_dot_space
loc_get_fchar:
     mov al, byte ptr [SI]
     cmp al, 61h
     jb  short pass_name_capitalize
     cmp al, 7Ah
     ja  short pass_name_capitalize
     and al, 0DFh
     mov byte ptr [SI], al
pass_name_capitalize:
     cmp al, 21h
     jb  short stop_convert_file
     cmp al, 2Eh
     jne short pass_dot_space
add_space:
     cmp cx, 4
     jna short inc_and_loop
     mov byte ptr [DI], 20h
     inc di
     dec cx
     jmp short add_space
pass_dot_space:
     mov byte ptr [DI], al
     inc di
inc_and_loop:
     inc si
     loop loc_get_fchar
stop_convert_file:
     retn
proc_convert_file_name endp

Last_DirLevel: db 0
Dir_File_Name: db 13 dup(0)

proc_change_current_directory proc near
               xor bl, bl
               mov bh, byte ptr [DirBuff_Drv]
               mov di, offset Logical_DOSDisks
               add di, bx
               mov ah, byte ptr [DI][LD_FATType]
               mov byte ptr [Current_FS], ah
               cmp ah, 2
               jna short pass_fat32_fs_rdfc
               push word ptr [DI][LD_BPB][FAT32_RootFClust]
               pop word ptr [Current_FS_RDFC]
               push word ptr [DI][LD_BPB][FAT32_RootFClust]+2
               pop word ptr [Current_FS_RDFC]+2
               jmp short pass_fat_fs_rdfc
check_fat32_root_dir0:
               mov ax, word ptr [Current_FS_RDFC]
               mov dx, word ptr [Current_FS_RDFC]+2
               call proc_load_directory
               jc short retn_find_sub_dir0
               push word ptr [Current_FS_RDFC]
               pop word ptr [Current_DirFCluster]
               push word ptr [Current_FS_RDFC]+2
               pop word ptr [Current_DirFCluster]+2
               jmp short pass_fat16_root_dir_loading
pass_fat32_fs_rdfc:
               mov word ptr [Current_FS_RDFC], 0
               mov word ptr [Current_FS_RDFC]+2, 0
pass_fat_fs_rdfc:
               mov al, byte ptr [Current_DirLevel]
               cmp al, 0
               ja short pass_cd_root_dir_fixup
check_fat32_root_dir1:
               cmp byte ptr [Current_FS], 2
               ja short check_fat32_root_dir0
check_fat16_root_dir:
               call proc_load_root_directory
               jc short retn_find_sub_dir0
               mov word ptr [Current_DirFCluster], 0
               mov word ptr [Current_DirFCluster]+2, 0
pass_fat16_root_dir_loading:
               mov si, offset Current_Path
               add si, 16
               cmp byte ptr [Last_DirLevel], 0
               ja short loc_cd_find_directory
               mov byte ptr [Dir_Str],0
               retn
pass_cd_root_dir_fixup:
               cmp byte ptr [Last_DirLevel], 0
               ja short pass_return_to_root_dir
               mov byte ptr [Current_DirLevel], 0
               jmp short check_fat32_root_dir1
retn_find_sub_dir0:
               mov si, offset Msg_dir_not_found
               call proc_printmsg
               stc
retn_find_sub_dir1:
               retn
pass_return_to_root_dir:
               cmp al, byte ptr [Last_DirLevel]
               jb short locate_next_level_dir
               je short reload_current_dir
               mov al, byte ptr [Last_Dirlevel]
               mov byte ptr [Current_DirLevel], al
reload_current_dir:
               mov ah, 16
               mul ah
               mov si, offset Current_Path
               add si, ax
               mov ax, word ptr [SI]+12
               mov dx, word ptr [SI]+14
               jmp update_cdir_fclust_exit
locate_next_level_dir:
               mov ah, 16
               mul ah
               mov si, offset Current_Path
               add si, ax
               cmp byte ptr [SI]+16, 20h
               jna stc_retn_find_sub_dir
             ; mov ax, word ptr [SI]+12
             ; mov dx, word ptr [SI]+14
               add si, 16
loc_cd_find_dir_next_sec0:
               mov ax, word ptr [Current_DirFCluster]
               mov dx, word ptr [Current_DirFCluster]+2
loc_cd_find_dir_next_sec1:
               xor bl, bl
loc_cd_find_dir_next_sec2:
               push si
               mov bh, byte ptr [DirBuff_Drv]
               call proc_load_directory
               pop si
               jc short retn_find_sub_dir0
loc_cd_find_directory:
               xor ax, ax ; No Filters
               mov bx, 0810h ; Directory
               xor cx, cx
               call proc_find_direntry
               jnc loc_directory_found
               cmp byte ptr [Current_DirLevel], 0
               ja short pass_loc_cd_load_next_root_sec1
               push si
               xor bl, bl
               mov bh, byte ptr [DirBuff_Drv]
               mov si, offset Logical_DOSdisks
               add si, bx
               cmp byte ptr [SI][LD_FATType], 2
               ja short pass_loc_cd_load_next_root_sec0
               mov bl, byte ptr [DirBuff_SectorOffset]
               inc bl
               pop si
               cmp bl, byte ptr [DirBuff_LastSector]
               ja short pass_loc_cd_load_next_root_sec2
               jmp check_fat16_root_dir
pass_loc_cd_load_next_root_sec0:
               pop si
pass_loc_cd_load_next_root_sec1:
               mov ax, word ptr [DirBuff_DirCluster]
               mov dx, word ptr [DirBuff_DirCluster]+2
               mov bl, byte ptr [DirBuff_SectorOffset]
               inc bl
               cmp bl, byte ptr [DirBuff_LastSector]
               jna short loc_cd_find_dir_next_sec2
pass_loc_cd_load_next_root_sec2:
               push    si
               xor     bl, bl
               mov     bh, byte ptr [DirBuff_Drv]
               mov     si, Offset Logical_DOSdisks
               add     si, bx
               call    proc_get_next_cluster
               pop     si
               jc      short retn_find_sub_dir

               cmp     al, 0F6h
               jna     short loc_cd_find_dir_next_sec1
               cmp     byte ptr [Current_FS], 1
               ja      short find_dir_FAT16_eoc_check
               cmp     ah, 0Fh
               jb      short loc_cd_find_dir_next_sec1
               jmp     short stc_retn_find_sub_dir
find_dir_FAT16_eoc_check:
               cmp     byte ptr [Current_FS], 2
               ja      short find_dir_FAT32_eoc_check
               cmp     ah, 0FFh
               jnb     short stc_retn_find_sub_dir
               jmp     loc_cd_find_dir_next_sec1
find_dir_FAT32_eoc_check:
               cmp     ah, 0FFh
               jb      loc_cd_find_dir_next_sec1
               cmp     dx, 0FFFh
               jb      loc_cd_find_dir_next_sec1
stc_retn_find_sub_dir:
               mov si, offset Msg_Dir_Not_Found
               call proc_printmsg
               stc
               retn
loc_directory_found:
               push ax
               push dx
               mov al, byte ptr [Current_DirLevel]
               inc al
               mov byte ptr [Current_DirLevel], al
               mov ah, 16
               mul ah
               mov si, offset Current_Path
               add si, ax
               pop dx
               pop ax
               mov word ptr [SI]+12, ax
               mov word ptr [SI]+14, dx
update_cdir_fclust_exit:
               mov word ptr [Current_DirFCluster], ax
               mov word ptr [Current_DirFCluster]+2,dx
               xor bl,bl
               mov bh, byte ptr [DirBuff_Drv]
               call proc_load_directory
               jc short retn_find_sub_dir
               mov al, byte ptr [Current_DirLevel]
               cmp al, byte ptr [Last_DirLevel]
               jb locate_next_level_dir
retn_find_sub_dir:
               retn
proc_change_current_directory endp

proc_find_direntry proc near
                ; SI = Sub Dir or File Name Offset
                ; BL = Attributes (AND)
                ; BH = Negative Attributes (NAND)
                ; CL = Current Entry
                ; CH = 0
                ; AL > 0 -> Use Name Filters
                ; AH > 0 -> Use Extension Filters
                ; * = Every Chars
                ; ? = Any One Char
                ; Return -> CLC -> BX= Attributes
                ; BL= Attribute
                ; BH= 0
                ; CL= CurrentDirEntry (16=Invalid)
                ; CH= 0
                mov word ptr [DirEntryAttr], bx
                mov word ptr [DirEntryFilters], ax
                ; push ds
                ; pop es
                mov     byte ptr [DirBuff_CurrentEntry], cl
                mov     di, offset Directory_Buffer
                cmp     cl, 0
                jna     short check_find_dir_entry
                push    ax
                mov     al, 32
                mul     cl
                add     di, ax
                pop     ax

check_find_dir_entry:
                xor     bl,bl
                push    si
                cmp     Byte Ptr [DI],0 ; Is it never used entry?
                jna     pop_si_loc_find_dir_ok
                cmp     Byte Ptr [DI],0E5h ; Is it a deleted file?
                je      loc_find_dir_next_entry

                mov     bl, byte ptr [DI]+0Bh
                test    bl, byte ptr [DirEntryAttr]
                jnz     short pass_check_attr_Zero
                cmp     byte ptr [DirEntryAttr], 0
                ja      loc_find_dir_next_entry
pass_check_attr_zero:
                test    bl, byte ptr [DirEntryAttr]+1
                jnz     loc_find_dir_next_entry

                cmp     bl, 0Fh
                jne     short loc_direntry_not_longname
                pop     si
                xor     ax, ax
                xor     dx, dx
                xor     bh, bh
                xor     ch, ch
                mov     cl, byte ptr [DirBuff_CurrentEntry]
                retn
loc_direntry_not_longname:
                mov     bx, di
                mov     cx, 8
loc_lodsb_find_dir_1:
                lodsb
                cmp     al, '*'
                jne     short pass_everychar_check
                cmp     byte ptr [DirEntryFilters], 0
                ja      short loc_check_dirent_extension
                jmp     short loc_scasb_find_dir
pass_everychar_check:
                cmp     al, '?'
                jne     short pass_anychar_check
                cmp     byte ptr [DirEntryFilters], 0
                ja      short loc_scasb_find_dir_3
                jmp     short loc_scasb_find_dir
pass_anychar_check:
                cmp     al, 20h
                jnb     short loc_scasb_find_dir
loc_lodsb_find_dir_2:
                cmp     byte ptr [BX], 20h
                jnb     short loc_find_dir_next_entry
                jmp     short loc_find_dir_use_clusters
loc_scasb_find_dir:
                cmp     al, byte ptr [BX]
                jne     short loc_find_dir_next_entry
loc_scasb_find_dir_3:
                inc     bx
                loop    loc_lodsb_find_dir_1
loc_check_dirent_extension:
                pop     si
                push    si
                add     si, 8
                mov     bx, di
                add     bx, 8
                mov     cx, 3
loc_lodsb_find_dir_4:
                lodsb
                cmp     al, '*'
                jne     short pass_everycharext_check
                cmp     byte ptr [DirEntryFilters]+1, 0
                ja      short loc_find_dir_use_clusters
                jmp     short loc_scasb_find_dir_ext
pass_everycharext_check:
                cmp     al, '?'
                jne     short pass_anycharext_check
                cmp     byte ptr [DirEntryFilters]+1, 0
                ja      short loc_scasb_find_dir_6
                jmp     short loc_scasb_find_dir_ext
pass_anycharext_check:
                cmp     al, 20h
                jnb     short loc_scasb_find_dir_ext
loc_lodsb_find_dir_5:
                cmp     byte ptr [BX], 20h
                jnb     short loc_find_dir_next_entry
                jmp     short loc_find_dir_use_clusters
loc_scasb_find_dir_ext:
                cmp     al, byte ptr [BX]
                jne     short loc_find_dir_next_entry
loc_scasb_find_dir_6:
                inc     bx
                loop    loc_lodsb_find_dir_4

loc_find_dir_use_clusters:
                pop     si
                mov     ax, word ptr [DI]+1Ah
                mov     dx, word ptr [DI]+14h
                and     dh, 0Fh
                mov     bl, byte ptr [DI]+0Bh
                xor     bh, bh
                xor     ch, ch
                mov     cl, byte ptr [DirBuff_CurrentEntry]
                clc
                retn
loc_find_dir_next_entry:
                mov     byte ptr [PreviousAttr], bl ; LongName check 
                pop     si
                inc     byte ptr [DirBuff_CurrentEntry]
                cmp     byte ptr [DirBuff_CurrentEntry], 15
                ja      short loc_find_dir_ok
                add     di, 32
                jmp     check_find_dir_entry
pop_si_loc_find_dir_ok:
                pop     si
loc_find_dir_ok:
                xor bx, bx
                mov cl, 16
                stc
                retn

DirEntryAttr: dw 0
DirEntryFilters: dw 0
PreviousAttr: db 0

proc_find_direntry endp

proc_change_prompt_dir_string proc near

                mov     di, offset Dir_Str
                cmp     byte ptr [Current_DirLevel],0
                jna     short pass_write_path
                mov     al, byte ptr [Current_DirLevel]
                mov     byte ptr [DirLevel_Count], al
                mov     si, offset Current_Path
                mov     di, offset Dir_Str
                add     si, 16
                mov     bx, si
loc_write_path:
                mov     cx, 8
path_write_dirname1:
                lodsb
                cmp     al, 20h
                jna     short pass_write_dirname1
                mov     byte ptr [DI], al
                inc     di
                cmp     di, offset End_Of_Dir_Str
                jnb     short pass_write_path
                loop    path_write_dirname1
                cmp     byte ptr [SI], 20h
                jna     short pass_write_dirname2
                jmp     short loc_put_dot_cont_ext
pass_write_dirname1:
                cmp     al, 0Dh
                jna     short pass_write_dirname2
                mov     si, bx
                add     si, 8
                cmp     byte ptr [SI], 20h
                jna     short pass_write_dirname2
loc_put_dot_cont_ext:
                mov     byte ptr [DI],"."
                mov     cx, 3
loc_check_dir_name_ext:
                lodsb
                inc     di
                cmp     al, 20h
                jna     short pass_write_dirname2
                mov     byte ptr [DI], al
                cmp     di, offset End_Of_Dir_Str
                jnb     short pass_write_path
                loop    loc_check_dir_name_ext
                inc     di
pass_write_dirname2:
                dec     byte ptr [DirLevel_Count]
                cmp     byte ptr [DirLevel_Count], 0
                jna     short pass_write_path
                add     bx, 16
                mov     si, bx
                mov     byte ptr [DI],"/"
                inc     di
                jmp     short loc_write_path
pass_write_path:
                mov     byte ptr [DI],0
                retn
DirLevel_Count: db 0

proc_change_prompt_dir_string endp

proc_volume_total_free_space proc near
                ; INPUT AL = DOS Drive Number
                mov word ptr [FreeClusterCount], 0
                mov word ptr [FreeClusterCount]+2, 0
                xor bl, bl
                mov bh, al
                mov si, offset Logical_DOSDisks
                add si, bx
                add al, 'A'
                cmp al, byte ptr [SI]  
                je short pass_vol_drv_name_check
                stc
                retn
pass_vol_drv_name_check:
                push si
                push bx
                mov byte ptr [Vol_Drv_Name], al
                cmp byte ptr [SI][LD_FATType],2
                ja short loc_vol_get_FAT32_vol_name
                cmp byte ptr [SI][LD_BPB][BootSignature], 29h
                jne short loc_start_calc_vol_space
                add si, LD_BPB+VolumeLabel
                mov di, offset Vol_Vol_Name
                mov cx, 11
                rep movsb
                mov si, offset Volume_in_drive
                call proc_printmsg
                jmp short loc_start_calc_vol_space
loc_vol_get_FAT32_vol_name:
              ; cmp byte ptr [SI][LD_BPB][FAT32_Bootsig], 29h
              ; jne short loc_start_calc_vol_space
                add si, LD_BPB+FAT32_VolLab
                mov di, offset Vol_Vol_Name
                mov cx, 11
                rep movsb
                mov si, offset Volume_in_drive
                call proc_printmsg
loc_start_calc_vol_space:
                pop bx
                pop si
                mov ax, word ptr [SI][LD_TotalSectors]
                mov dx, word ptr [SI][LD_TotalSectors]+2
                push bx
                mov bx, word ptr [SI][LD_BPB][BytesPerSec]
                cmp byte ptr [SI][LD_FATType],2
                ja short pass_vol_size_bytes_calc
                push word ptr [SI][LD_Clusters]
                pop word ptr [LastCluster]
                inc word ptr [LastCluster]
              ; cmp dx, 127
              ; ja short pass_vol_size_bytes_calc
                call proc_mul32
                jmp short pass_volsize_overflow
pass_vol_size_bytes_calc:
                cmp bx, 1024
                jnb short loc_vol_ax_div_bx
                push ax
                push dx
                xor dx, dx
                mov ax, 1024
                div bx
                mov cx, ax
                pop dx
                pop ax
                call Rx_Dos_Div32
                jmp short pass_volsize_overflow
loc_vol_ax_div_bx:
                push ax
                push dx
                xor dx, dx
                mov ax, 1024
                xchg ax, bx
                div bx
                mov bx, ax
                pop dx
                pop ax
                call Proc_Mul32
pass_volsize_overflow:
                pop bx
                mov di, offset Vol_Tot_Sec_Str_End
              ; mov byte ptr [DI], 0
                mov cx, 10
loc_vol_div32_1_again:
                call Rx_Dos_Div32
                add bl, '0'
                dec di
                mov byte ptr [DI], bl
                cmp ax, 0
                ja short loc_vol_div32_1_again
                cmp dx, 0
                ja short loc_vol_div32_1_again

                mov word ptr [Vol_Tot_Sec_Str_Start], DI

                cmp byte ptr [SI][LD_FATType], 2
                jna loc_get_FAT_freespace

                mov ax, word ptr [SI][LD_StartSector]
                mov dx, word ptr [SI][LD_StartSector]+2
                cmp byte ptr [SI][LD_LBAYes], 0
                jna short pass_load_fat32_fsinfo_sec_lba

                push ax
                push dx

              ; mov byte ptr [DAP_BuffLBAyes], 1
                mov word ptr [DAP_BuffLBA_Address], ax
                mov word ptr [DAP_BuffLBA_Address]+2, dx
                mov byte ptr [DAP_BuffPacketSize], 10h
                mov word ptr [DAP_BuffDestination], offset DosBootSectorBuff
                push ds
                pop word ptr [DAP_BuffDestination]+2
                mov byte ptr [DAP_BuffNumOfBlocks], 1
                mov byte ptr [DAP_RetryCount], 4
                mov dl, byte ptr [SI][LD_PhyDrvNo]
                mov byte ptr [DAP_BuffDisk], dl

                call proc_LBA_read
                pop dx
                pop ax
                jc short retn_get_lba_fs_info_sec

loc_get_lba_fs_info_sec:
                cmp word ptr [BS_Validation], 0AA55h
                jne short retn_get_lba_fs_info_stc
                add ax, word ptr [BPB_FSinfo]
                adc dx, 0

              ; mov byte ptr [DAP_BuffLBAyes], 1
                mov word ptr [DAP_BuffLBA_Address], ax
                mov word ptr [DAP_BuffLBA_Address]+2, dx
                mov byte ptr [DAP_BuffPacketSize], 10h
                mov word ptr [DAP_BuffDestination], offset DosBootSectorBuff
                push ds
                pop word ptr [DAP_BuffDestination]+2
                mov byte ptr [DAP_BuffNumOfBlocks], 1
                mov byte ptr [DAP_RetryCount], 4
                mov dl, byte ptr [SI][LD_PhyDrvNo]
                mov byte ptr [DAP_BuffDisk], dl

                call proc_lba_read
                jnc short loc_check_fsinfo_signs

retn_get_lba_fs_info_sec:
                retn
retn_get_lba_fs_info_stc:
                stc
                retn

pass_load_fat32_fsinfo_sec_lba:
                mov bx, offset DOSBootSectorBuff
                push ax
                push dx
                mov cx, 1
                call proc_chs_read
                pop dx
                pop ax
                jc short retn_get_lba_fs_info_sec
pass_get_chs_fs_info_sec:
                cmp word ptr [BS_Validation], 0AA55h
                jne short retn_get_lba_fs_info_stc
                add ax, word ptr [BPB_FSinfo]
                adc dx, 0
                mov bx, offset DOSBootSectorBuff
                mov cx, 1
                call proc_chs_read
                jc short retn_get_lba_fs_info_sec
loc_check_FSINFO_signs:
                cmp word ptr [DOSBootSectorBuff], 5252h
                jne short retn_get_lba_fs_info_stc
                mov word ptr [DOSBootSectorBuff]+2, 4161h
                jne short retn_get_lba_fs_info_stc
                mov bx, offset DOSBootSectorBuff
                add bx, 484
                cmp word ptr [BX], 7272h
                jne short retn_get_lba_fs_info_stc
                mov word ptr [BX]+2, 6141h
                jne short retn_get_lba_fs_info_stc
                add bx, 4
                push word ptr [BX]
                pop word ptr [FreeClusterCount]
                push word ptr [BX]+2
                pop word ptr [FreeClusterCount]+2

                xor ah, ah
                mov al, byte ptr [SI][LD_BPB][SecPerClust]
                mov dx, [SI][LD_BPB][BytesPerSec]
                mul dx
              ; cmp dx, 0
              ; ja short retn_get_lba_fs_info_stc
                mov bx, 1024
                cmp ax, bx
                jb short pass_fsinfo_freesize_div_1024
                div bx
                mov bx, ax
                mov ax, word ptr [FreeClusterCount]
                mov dx, word ptr [FreeClusterCount]+2
                call Proc_Mul32
                jmp short loc_vol_decimal_fat32_freesize
pass_fsinfo_freesize_div_1024:
                xchg ax, bx
                div bx
                mov cx, ax
                mov ax, word ptr [FreeClusterCount]
                mov dx, word ptr [FreeClusterCount]+2
                call Rx_Dos_Div32
loc_vol_decimal_fat32_freesize:
                mov di, offset Vol_Free_Clust_Str_End
              ; mov byte ptr [DI], 0
                mov cx, 10
loc_vol_div32_3_again:
                call Rx_Dos_Div32
                add bl, '0'
                dec di
                mov byte ptr [DI], bl
                cmp ax, 0
                ja short loc_vol_div32_3_again
                cmp dx, 0
                ja short loc_vol_div32_3_again

                mov word ptr [Vol_Free_Clust_Str_Start], DI

                mov si, offset Vol_Total_Sector_Header
                call proc_printmsg
                mov si, word ptr [Vol_Tot_Sec_Str_Start]
                call proc_printmsg
                mov si, offset VolSize_KiloBytes
                call proc_printmsg
                mov si, offset Vol_Free_Clusters_Header
                call proc_printmsg
                mov si, word ptr [Vol_Free_Clust_Str_Start]
                call proc_printmsg
                mov si, offset VolSize_KiloBytes
                call proc_printmsg

pass_write_fat32_free_clusters_calc:
                retn

loc_get_fat_freespace:
                mov ax, 2
                mov dx, 0
loc_get_fcc_next_cluster:
                push ax
                push dx
                call proc_get_next_cluster
                jnc short loc_calc_free_fat_clusters
                pop dx
                pop ax
                retn

loc_calc_free_fat_clusters:
                cmp ax, 0
                ja short pass_inc_free_cluster_count
                inc word ptr [FreeClusterCount]
pass_inc_free_cluster_count:
                pop dx
                pop ax
                inc ax
                cmp ax, word ptr [LastCluster]
                jna short loc_get_fcc_next_cluster
                xor ah, ah
                mov al, byte ptr [SI][LD_BPB][SecPerClust]
                mov dx, word ptr [SI][LD_BPB][BytesPerSec]
                mul dx
              ; cmp dx, 0
              ; ja retn_get_lba_fs_info_stc
                mov dx, word ptr [FreeClusterCount]
                mul dx

                mov di, offset Vol_Free_Clust_Str_End
              ; mov byte ptr [DI], 0
                mov cx, 10
loc_vol_div32_2_again:
                call Rx_Dos_Div32
                add bl, '0'
                dec di
                mov byte ptr [DI], bl
                cmp ax, 0
                ja short loc_vol_div32_2_again
                cmp dx, 0
                ja short loc_vol_div32_2_again

                mov word ptr [Vol_Free_Clust_Str_Start], DI

                mov si, offset Vol_Total_Sector_Header
                call proc_printmsg
                mov si, word ptr [Vol_Tot_Sec_Str_Start]
                call proc_printmsg
                mov si, offset VolSize_Bytes
                call proc_printmsg

                mov si, offset Vol_Free_Clusters_Header
                call proc_printmsg
                mov si, word ptr [Vol_Free_Clust_Str_Start]
                call proc_printmsg
                mov si, offset VolSize_Bytes
                call proc_printmsg

                retn

LastCluster: dw 0
FreeClusterCount: dd 0
Vol_Free_Clust_Str_Start: dw 0
Vol_Free_Clust_Str: db 10 dup(0)
Vol_Free_Clust_Str_End: db 0
Vol_Free_Clusters_Header:
                db "Free Space : ", 0
Vol_Tot_Sec_Str_Start: dw 0
Vol_Tot_Sec_Str: db 10 dup(0)
Vol_Tot_Sec_Str_End: db 0
Vol_Total_Sector_Header:
                db 0Dh, 0Ah, "Volume Size : ", 0
VolSize_Unit:   dw 0
VolSize_KiloBytes: db " kilobytes", 0Dh, 0Ah, 0
VolSize_Bytes:  db " bytes", 0Dh, 0Ah, 0
Volume_in_drive:
                db 0Dh, 0Ah, "Volume in drive "
Vol_Drv_Name:   db 30h
                db ":"
                db " is "
Vol_Vol_Name:   db 11 dup (30h)
                db 0Dh, 0Ah, 0

proc_volume_total_free_space endp

proc_find_longname proc near

                ; INPUT DS:SI = DOS short file name input
                ; for example: "filename.ext"

                mov cx, 33
                mov di, Offset LongFileName
                mov ax, 0
                rep stosw

                mov byte ptr [LongNameFound],0

              ; mov byte ptr [PreviousAttr], 0 ; Reset LongName Flag
              ; above instruction is for: "find file
              ; and check if it has long name" (? PreviousAttr= 0Fh)
              ; It is not needed during long name search but
              ; it is useful for short name search for delete/rename

                mov di, offset Dir_File_Name
                call proc_convert_file_name
                mov si, offset Dir_File_Name
                call proc_calculate_checksum
                mov byte ptr [LFN_Checksum], al

                xor bl, bl
                mov bh, byte ptr [DirBuff_Drv]
                mov di, offset Logical_DOSDisks
                add di, bx
                mov ah, byte ptr [DI][LD_FATType]
                mov byte ptr [Current_FS], ah
                cmp ah, 2
                jna short pass_ln_fat32_fs
check_ln_sub_dir:
                mov ax, word ptr [Current_DirFCluster]
                mov dx, word ptr [Current_DirFCluster]+2
loc_load_ln_next_sector:
                call proc_load_directory
                jc short retn_find_longname_stc
                jmp short loc_find_longname_next
pass_ln_fat32_fs:
                mov al, byte ptr [Current_DirLevel]
                cmp al, 0
                ja short check_ln_sub_dir
loc_load_ln_fat_next_root_sector:
                call proc_load_root_directory
                jc short retn_find_longname_stc
                jmp short loc_find_longname_next
retn_find_longname_stc:
                mov si, offset Msg_Not_Ready_Read_Err
                call proc_printmsg
                stc
                retn
loc_find_longname_next:
                mov     cl, 0
check_ln_dirbuff_next_entry:
                cmp     byte ptr [LongNameFound], 0
                jna     short pass_check_ln_short_name
                mov     si, offset Directory_Buffer
                mov     al, 32
                mul     cl
                add     si, ax
                mov     di, offset Dir_File_Name
                push    cx
                mov     cx, 11
loc_ln_sn_comp:
                cmpsb
                jne     short pass_loop_ln_sn_comp
                loop    loc_ln_sn_comp
pass_loop_ln_sn_comp:
                cmp     cl, 0
                jna     short loc_longname_found
                mov     byte ptr [LongNameFound], 0
                pop     cx
                jmp     short pass_check_ln_short_name
loc_longname_found:
                pop cx
                mov si, offset Msg_LongName
                call proc_printmsg
                mov si, offset nextline
                call proc_printmsg

                retn

pass_check_ln_short_name:
              ; xor ch, ch 
              ; mov si, offset LFN_NameFlt
                mov bl, 0Fh ; LFN Attr
                mov bh, 30h ; Not Dir or Archive Attr
              ; mov ax, 0101h ; Use name and ext filters
                call proc_find_direntry
                jc short pass_longname_found_1
                cmp bl, 0Fh
                jne short pass_longname_found_0
                ; Output DI = DirEntry Location

                mov ch, byte ptr [DI]+0Dh ; Checksum
                cmp ch, byte ptr [LFN_Checksum]
                jne short pass_longname_found_0

                mov ah, byte ptr [DI]
                cmp ah, 41h
                jb short pass_longname_lastpart
                cmp ah, 45h
                ja short pass_longname_found_0
                sub ah, 40h
pass_longname_lastpart:
                dec ah
                mov al, 13
                mul ah
                mov cx, 5
                mov si, di
                inc si
                push di
                mov di, offset LongFileName
                add di, ax
get_lfn_first_5_chars:
                lodsw
                stosb
                loop get_lfn_first_5_chars
                pop si
                push si
                add si, 14
                mov cx, 6
get_lfn_middle_6_chars:
                lodsw
                stosb
                loop get_lfn_middle_6_chars
                pop si
                add si, 28
                lodsw
                stosb
                lodsw
                stosb

                cmp byte ptr [LongFileName], 0
                jna short pass_longname_found_2
                mov byte ptr [LongNameFound], 1

pass_longname_found_2:
                mov cl, byte ptr [DirBuff_CurrentEntry]
pass_longname_found_0:
              ; xor ch, ch
                inc cl
                cmp cl, 16
                jb check_ln_dirbuff_next_entry
pass_longname_found_1:
                mov bh, byte ptr [DirBuff_Drv]
                mov bl, byte ptr [DirBuff_SectorOffset]
                inc bl
                cmp byte ptr [Current_DirLevel], 0
                ja short pass_loc_ln_load_next_root_sec1
                cmp bl, byte ptr [DirBuff_LastSector]
                jna loc_load_ln_fat_next_root_sector
                cmp byte ptr [Current_FS], 2
                ja short pass_loc_ln_load_next_root_sec2
                jmp short retn_find_longname_notfound
pass_loc_ln_load_next_root_sec1:
                mov ax, word ptr [DirBuff_DirCluster]
                mov dx, word ptr [DirBuff_DirCluster]+2
                cmp bl, byte ptr [DirBuff_LastSector]
                ja short pass_loc_ln_load_next_root_sec3
                jmp loc_load_ln_next_sector
pass_loc_ln_load_next_root_sec2:
                mov ax, word ptr [DirBuff_DirCluster]
                mov dx, word ptr [DirBuff_DirCluster]+2
pass_loc_ln_load_next_root_sec3:
                push    si
                xor     bl, bl
                mov     si, Offset Logical_DOSdisks
                add     si, bx
                call    proc_get_next_cluster
                pop     si
                jc      short retn_find_longname_notfound

                cmp     al, 0F6h
                jna     loc_load_ln_next_sector
                cmp     byte ptr [Current_FS], 1
                ja      short find_ln_FAT16_eoc_check
                cmp     ah, 0Fh
                jb      loc_load_ln_next_sector
                jmp     short retn_find_longname_notfound
find_ln_FAT16_eoc_check:
                cmp     byte ptr [Current_FS], 2
                ja      short find_ln_FAT32_eoc_check
                cmp     ah, 0FFh
                jnb     short retn_find_longname_notfound
                jmp     loc_load_ln_next_sector
find_ln_FAT32_eoc_check:
                cmp     ah, 0FFh
                jb      loc_load_ln_next_sector
                cmp     dx, 0FFFh
                jb      loc_load_ln_next_sector
retn_find_longname_notfound:
                mov     si, offset Msg_LongNameNotFound
                call    proc_printmsg
                retn

LFN_Checksum:   db 0
Msg_LongName:  
LongFileName:   db 66 dup(0)
LongNameFound:  db 0
Msg_LongNameNotFound: db "Long name not found!"
NextLine:       db 0Dh, 0Ah, 0

proc_find_longname endp

proc_calculate_checksum proc near

               ; INPUT DS:SI = 11 byte Dos File Name location
               ; (in DOS Directory Entry Format)

               ; © Erdogan Tan [ 20-6-2004 ]
               ; This 8086 assembly code is an original code
               ; which is adapted from C code in
               ; Microsoft FAT32 File System Specification
               ; Version 1.03, December 6, 2000
               ; Page 28

               xor al, al
               mov cx, 11
loc_next_sum:
               xor ah, ah
               test al, 1
               jz short pass_ah_80h
               mov ah, 80h
pass_ah_80h:
               shr al, 1
               add al, byte ptr [si]
               inc si
               add al, ah
               loop loc_next_sum

               ; al= 8 bit checksum (CRC) value

               retn

proc_calculate_checksum endp

proc_show_date  proc    near

                mov ah, 04h
                int 1Ah

                mov al, dl
                call proc_hex
                mov word ptr [Day], ax

                mov al, dh
                call proc_hex
                mov word ptr [Month], ax

                mov al, ch
                call proc_hex
                mov word ptr [Century], ax

                mov al, cl
                call proc_hex
                mov word ptr [Year], ax
                
                mov si, offset Msg_Show_Date
                call proc_printmsg

                retn
Msg_Show_Date:
                db   'Current date is '
Day:            db   '0'
		db   '0'
                db   '/'
Month:          db   '0'
		db   '0'
                db   '/'
Century:        db   '0'
                db   '0'
Year:           db   '0'
		db   '0'
                db   0Dh, 0Ah, 0

proc_show_date  endp

proc_set_date   proc near

                mov si, offset Msg_Enter_Date
                call proc_printmsg
loc_enter_day_1:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 13
                je loc_set_date_retn
                cmp al, 27
                je loc_set_date_retn
                mov byte ptr [Day], al
                cmp al, '0'
                jb loc_set_date_stc_0
                cmp al, '3'
                ja loc_set_date_stc_0
                mov ah, 0Eh
                int 10h
loc_enter_day_2:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 27
                je loc_set_date_retn
                mov byte ptr [Day]+1, al
                cmp al, '0'
                jb loc_set_date_stc_1
                cmp al, '9'
                ja loc_set_date_stc_1
                cmp byte ptr [Day], '3'
                jb  short pass_set_day_31
                cmp al, '1'
                ja  loc_set_date_stc_1
pass_set_day_31:
                mov ah, 0Eh
                int 10h
loc_enter_separator_1:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 27
                je  loc_set_date_retn
                cmp al, '-'
                je  short pass_set_date_separator_1
                cmp al, '/'
                jne loc_set_date_stc_2
pass_set_date_separator_1:
                mov ah, 0Eh
                int 10h
loc_enter_month_1:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 27
                je  loc_set_date_retn
                mov byte ptr [Month], al
                cmp al, '0'
                jb  loc_set_date_stc_3
                cmp al, '1'
                ja  loc_set_date_stc_3
                mov ah, 0Eh
                int 10h
loc_enter_month_2:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 27
                je loc_set_date_retn
                mov byte ptr [Month]+1, al
                cmp al, '0'
                jb  loc_set_date_stc_4
                cmp al, '9'
                ja  loc_set_date_stc_4
                cmp byte ptr [Month], '1'
                jb  short pass_set_month_12
                cmp al, '2'
                ja  loc_set_date_stc_4
pass_set_month_12:
                mov ah, 0Eh
                int 10h
loc_enter_separator_2:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 27
                je  loc_set_date_retn
                cmp al, '-'
                je  short pass_set_date_separator_2
                cmp al, '/'
                jne loc_set_date_stc_5
pass_set_date_separator_2:
                mov ah, 0Eh
                int 10h
loc_enter_year_1:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 27
                je  loc_set_date_retn
                mov byte ptr [Year], al
                cmp al, '0'
                jb  loc_set_date_stc_6
                cmp al, '9'
                ja  loc_set_date_stc_6
                mov ah, 0Eh
                int 10h
loc_enter_year_2:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 27
                je  loc_set_date_retn
                mov byte ptr [Year]+1, al
                cmp al, '0'
                jb  loc_set_date_stc_7
                cmp al, '9'
                ja  loc_set_date_stc_7
                mov ah, 0Eh
                int 10h

loc_set_date_get_lchar_again:
                xor ah, ah
                int 16h

                cmp al, 13
                je short loc_set_date_progress
                cmp al, 27
                je short loc_set_date_retn

                cmp ax, 0E08h
                je short loc_set_date_bs_8
                cmp ax, 4BE0h
                je short loc_set_date_bs_8
                cmp ax, 4B00h
                je short loc_set_date_bs_8
                cmp ax, 53E0h
                je short loc_set_date_bs_8

                jmp short loc_set_date_get_lchar_again
                
loc_set_date_bs_8:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_year_2

loc_set_date_progress:
                ; Get Current Date
                mov ah, 04h
                int 1Ah

                mov ah, byte ptr [Year]
                sub ah, '0'
                mov al, 16
                mul ah
                mov cl, al
                mov al, byte ptr [Year]+1
                sub al, '0'
                add cl, al

                mov ah, byte ptr [Month]
                sub ah, '0'
                mov al, 16
                mul ah
                mov dh, al
                mov al, byte ptr [Month]+1
                sub al, '0'
                add dh, al

                mov ah, byte ptr [Day]
                sub ah, '0'
                mov al, 16
                mul ah
                mov dl, al
                mov al, byte ptr [Day]+1
                sub al, '0'
                add dl, al

                mov ah, 05h
                int 1Ah

loc_set_date_retn:
                mov si, offset nextline
                call proc_printmsg
                retn

loc_set_date_stc_0:
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_day_1
loc_set_date_stc_1:
                cmp ax, 0E08h
                je short loc_set_date_bs_1
                cmp ax, 4BE0h
                je short loc_set_date_bs_1
                cmp ax, 4B00h
                je short loc_set_date_bs_1
                cmp ax, 53E0h
                je short loc_set_date_bs_1
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_day_2
loc_set_date_bs_1:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_day_1
loc_set_date_stc_2:
                cmp ax, 0E08h
                je short loc_set_date_bs_2
                cmp ax, 4BE0h
                je short loc_set_date_bs_2
                cmp ax, 4B00h
                je short loc_set_date_bs_2
                cmp ax, 53E0h
                je short loc_set_date_bs_2
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_separator_1
loc_set_date_bs_2:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_day_2
loc_set_date_stc_3:
                cmp ax, 0E08h
                je short loc_set_date_bs_3
                cmp ax, 4BE0h
                je short loc_set_date_bs_3
                cmp ax, 4B00h
                je short loc_set_date_bs_3
                cmp ax, 53E0h
                je short loc_set_date_bs_3
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_month_1
loc_set_date_bs_3:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_separator_1
loc_set_date_stc_4:
                cmp ax, 0E08h
                je short loc_set_date_bs_4
                cmp ax, 4BE0h
                je short loc_set_date_bs_4
                cmp ax, 4B00h
                je short loc_set_date_bs_4
                cmp ax, 53E0h
                je short loc_set_date_bs_4
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_month_2
loc_set_date_bs_4:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_month_1
loc_set_date_stc_5:
                cmp ax, 0E08h
                je short loc_set_date_bs_5
                cmp ax, 4BE0h
                je short loc_set_date_bs_5
                cmp ax, 4B00h
                je short loc_set_date_bs_5
                cmp ax, 53E0h
                je short loc_set_date_bs_5
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_separator_2
loc_set_date_bs_5:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_month_2
loc_set_date_stc_6:
                cmp ax, 0E08h
                je short loc_set_date_bs_6
                cmp ax, 4BE0h
                je short loc_set_date_bs_6
                cmp ax, 4B00h
                je short loc_set_date_bs_6
                cmp ax, 53E0h
                je short loc_set_date_bs_6
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_year_1
loc_set_date_bs_6:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_separator_2
loc_set_date_stc_7:
                cmp ax, 0E08h
                je short loc_set_date_bs_7
                cmp ax, 4BE0h
                je short loc_set_date_bs_7
                cmp ax, 4B00h
                je short loc_set_date_bs_7
                cmp ax, 53E0h
                je short loc_set_date_bs_7
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_year_2
loc_set_date_bs_7:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_year_1
Msg_Enter_Date:
                db 'Enter new date (dd-mm-yy): '
                db 0

proc_set_date   endp

proc_show_time  proc    near

                mov ah, 02h
                int 1Ah

                mov al, ch
                call proc_hex
                mov word ptr [Hour], ax

                mov al, cl
                call proc_hex
                mov word ptr [Minute], ax

                mov al, dh
                call proc_hex
                mov word ptr [Second], ax

                mov si, offset Msg_Show_Time
                call proc_printmsg

                retn
Msg_Show_Time:
                db   'Current time is '
Hour:           db   '0'
		db   '0'
                db   ':'
Minute:         db   '0'
		db   '0'
                db   ':'
Second:         db   '0'
                db   '0'
                db   0Dh, 0Ah, 0

proc_show_time  endp

proc_set_time   proc near
                mov si, offset Msg_Enter_Time
                call proc_printmsg

loc_enter_hour_1:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 13
                je loc_set_time_retn
                cmp al, 27
                je loc_set_time_retn
                mov byte ptr [Hour], al
                cmp al, '0'
                jb loc_set_time_stc_0
                cmp al, '2'
                ja loc_set_time_stc_0
                mov ah, 0Eh
                int 10h
loc_enter_hour_2:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 27
                je loc_set_time_retn
                mov byte ptr [Hour]+1, al
                cmp al, '0'
                jb loc_set_time_stc_1
                cmp al, '9'
                ja loc_set_time_stc_1
                cmp byte ptr [Hour], '2'
                jb  short pass_set_time_24
                cmp al, '4'
                ja  loc_set_time_stc_1
pass_set_time_24:
                mov ah, 0Eh
                int 10h
loc_enter_time_separator_1:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 27
                je  loc_set_time_retn
                cmp al, ':'
                jne loc_set_time_stc_2
                mov ah, 0Eh
                int 10h
loc_enter_minute_1:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 27
                je  loc_set_time_retn
                mov byte ptr [Minute], al
                cmp al, '0'
                jb  loc_set_time_stc_3
                cmp al, '5'
                ja  loc_set_time_stc_3
                mov ah, 0Eh
                int 10h
loc_enter_minute_2:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 27
                je  loc_set_time_retn
                mov byte ptr [Minute]+1, al
                cmp al, '0'
                jb  loc_set_time_stc_4
                cmp al, '9'
                ja  loc_set_time_stc_4
                mov ah, 0Eh
                int 10h
loc_enter_time_separator_2:
                mov word ptr [Second], 3030h
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 13
                je  loc_set_time_progress
                cmp al, 27
                je  loc_set_time_retn
                cmp al, ':'
                jne loc_set_time_stc_5
                mov ah, 0Eh
                int 10h
loc_enter_second_1:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 13
                je  loc_set_time_progress
                cmp al, 27
                je  loc_set_time_retn
                mov byte ptr [Second], al
                cmp al, '0'
                jb  loc_set_time_stc_6
                cmp al, '5'
                ja  loc_set_time_stc_6
                mov ah, 0Eh
                int 10h
loc_enter_second_2:
                xor ah, ah
                int 16h
                ; al = ASCII Code of the Character
                cmp al, 27
                je  loc_set_time_retn
                mov byte ptr [Second]+1, al
                cmp al, '0'
                jb  loc_set_time_stc_7
                cmp al, '9'
                ja  loc_set_time_stc_7
                mov ah, 0Eh
                int 10h

loc_set_time_get_lchar_again:
                xor ah, ah
                int 16h

                cmp al, 13
                je short loc_set_time_progress
                cmp al, 27
                je short loc_set_time_retn

                cmp ax, 0E08h
                je short loc_set_time_bs_8
                cmp ax, 4BE0h
                je short loc_set_time_bs_8
                cmp ax, 4B00h
                je short loc_set_time_bs_8
                cmp ax, 53E0h
                je short loc_set_time_bs_8

                jmp short loc_set_time_get_lchar_again
                
loc_set_time_bs_8:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_second_2

loc_set_time_progress:
                ; Get Current Time
                mov ah, 02h
                int 1Ah

                mov ah, byte ptr [Hour]
                sub ah, '0'
                mov al, 16
                mul ah
                mov ch, al
                mov al, byte ptr [Hour]+1
                sub al, '0'
                add ch, al

                mov ah, byte ptr [Minute]
                sub ah, '0'
                mov al, 16
                mul ah
                mov cl, al
                mov al, byte ptr [Minute]+1
                sub al, '0'
                add cl, al

                mov ah, byte ptr [Second]
                sub ah, '0'
                mov al, 16
                mul ah
                mov dh, al
                mov al, byte ptr [Second]+1
                sub al, '0'
                add dh, al

                mov ah, 03h
                int 1Ah

loc_set_time_retn:
                mov si, offset nextline
                call proc_printmsg
                retn

loc_set_time_stc_0:
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_hour_1
loc_set_time_stc_1:
                cmp ax, 0E08h
                je short loc_set_time_bs_1
                cmp ax, 4BE0h
                je short loc_set_time_bs_1
                cmp ax, 4B00h
                je short loc_set_time_bs_1
                cmp ax, 53E0h
                je short loc_set_time_bs_1
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_hour_2
loc_set_time_bs_1:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_hour_1
loc_set_time_stc_2:
                cmp ax, 0E08h
                je short loc_set_time_bs_2
                cmp ax, 4BE0h
                je short loc_set_time_bs_2
                cmp ax, 4B00h
                je short loc_set_time_bs_2
                cmp ax, 53E0h
                je short loc_set_time_bs_2
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_time_separator_1
loc_set_time_bs_2:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_hour_2
loc_set_time_stc_3:
                cmp ax, 0E08h
                je short loc_set_time_bs_3
                cmp ax, 4BE0h
                je short loc_set_time_bs_3
                cmp ax, 4B00h
                je short loc_set_time_bs_3
                cmp ax, 53E0h
                je short loc_set_time_bs_3
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_minute_1
loc_set_time_bs_3:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_time_separator_1
loc_set_time_stc_4:
                cmp ax, 0E08h
                je short loc_set_time_bs_4
                cmp ax, 4BE0h
                je short loc_set_time_bs_4
                cmp ax, 4B00h
                je short loc_set_time_bs_4
                cmp ax, 53E0h
                je short loc_set_time_bs_4
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_minute_2
loc_set_time_bs_4:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_minute_1
loc_set_time_stc_5:
                cmp ax, 0E08h
                je short loc_set_time_bs_5
                cmp ax, 4BE0h
                je short loc_set_time_bs_5
                cmp ax, 4B00h
                je short loc_set_time_bs_5
                cmp ax, 53E0h
                je short loc_set_time_bs_5
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_time_separator_2
loc_set_time_bs_5:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_minute_2
loc_set_time_stc_6:
                cmp ax, 0E08h
                je short loc_set_time_bs_6
                cmp ax, 4BE0h
                je short loc_set_time_bs_6
                cmp ax, 4B00h
                je short loc_set_time_bs_6
                cmp ax, 53E0h
                je short loc_set_time_bs_6
                mov al, 07h
                mov ah, 0Eh
                int 10h
                mov word ptr [Second], 3030h
                jmp loc_enter_second_1
loc_set_time_bs_6:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_time_separator_2
loc_set_time_stc_7:
                cmp ax, 0E08h
                je short loc_set_time_bs_7
                cmp ax, 4BE0h
                je short loc_set_time_bs_7
                cmp ax, 4B00h
                je short loc_set_time_bs_7
                cmp ax, 53E0h
                je short loc_set_time_bs_7
                mov al, 07h
                mov ah, 0Eh
                int 10h
                jmp loc_enter_second_2
loc_set_time_bs_7:
                mov al, 08h
                mov ah, 0Eh
                int 10h
                mov al, 20h
                mov ah, 09h
                int 10h
                jmp loc_enter_second_1
Msg_Enter_Time:
                db 'Enter new time: '
                db 0

proc_set_time   endp

proc_load_file  proc near
              ; ES:DI = File Buffer
              ; DX:AX = First Cluster Number
              ; BL = 0
              ; BH = DRV
                mov  si, offset Logical_DOSDisks
                add  si, bx
                cmp byte ptr [SI][LD_Name], 'A'
                jnb short pass_lf_drv_failed
                retn
pass_lf_drv_failed:
                cmp byte ptr [SI][LD_FATType],2
                ja short pass_lf_reset_dx
                xor dx,dx
pass_lf_reset_dx:
                mov byte ptr [SourceFile_Drv], bh
                mov word ptr [SourceFile_BufferOff], di
                push es
                pop word ptr  [SourceFile_BufferSeg]
loc_load_file_next_cluster:
                mov word ptr [SourceFile_Cluster], ax
                mov word ptr [SourceFile_Cluster]+2, dx
                mov bl, byte ptr [SI][LD_BPB][SecPerClust]
                sub ax, 2
                sbb dx, 0
                xor bh, bh
                mov cx, bx
                call proc_mul32
                add ax, word ptr [SI][LD_DATAbegin]
                adc dx, word ptr [SI][LD_DATAbegin]+2
               ; xor bh, bh
                cmp byte ptr [SI][LD_LBAYes], 0
                ja  short lba_read_file_sectors
                call proc_CHS_read
                jnc short loc_cont_load_file
                retn
lba_read_file_sectors:
                mov byte ptr [DAP_BuffLBAyes], 1
                mov byte ptr [DAP_BuffPacketSize], 10h
                push word ptr [SourceFile_BufferOff]
                pop word ptr [DAP_BuffDestination]
                push word ptr [SourceFile_BufferSeg]
                pop word ptr [DAP_BuffDestination]+2
                mov word ptr [DAP_BuffLBA_Address], ax
                mov word ptr [DAP_BuffLBA_Address]+2, dx
                mov byte ptr [DAP_BuffNumOfBlocks], cl
                mov byte ptr [DAP_RetryCount], 4
                mov dl, byte ptr [SI][LD_PhyDrvNo]
                mov byte ptr [DAP_BuffDisk], dl
                call proc_LBA_read
                jnc short loc_cont_load_file
loc_load_file_retn:
                retn
loc_cont_load_file:
                mov ax, word ptr [SourceFile_Cluster]
                mov dx, word ptr [SourceFile_Cluster]+2
                call proc_get_next_cluster
                jc short loc_load_file_retn
                push ax
                push dx
                xor bh, bh
                mov bl, byte ptr [SI][LD_BPB][SecPerClust]
                mov ax, 512
                mul bx
                add word ptr [SourceFile_BufferOff], ax
                pop dx
                pop ax
                jnc short pass_load_file_es_change
                mov bx, es
                add bx, 1000h
                mov es, bx
pass_load_file_es_change:
                cmp al, 0F6h
                jna loc_load_file_next_cluster
                cmp byte ptr [SI][LD_FATType],1
                ja  short loc_lf_FAT16_eoc_check
                cmp ah, 0Fh
                jb  loc_load_file_next_cluster
                retn
loc_lf_FAT16_eoc_check:
                cmp byte ptr [SI][LD_FATType],2
                ja  short loc_lf_FAT32_eoc_check
                cmp ah, 0FFh
                jb  loc_load_file_next_cluster
                retn
loc_lf_FAT32_eoc_check:
                cmp ah, 0FFh
                jb  loc_load_file_next_cluster
                cmp dx, 0FFFh
                jb  loc_load_file_next_cluster
                retn

proc_load_file  endp

; TRDOS Function Calls

trdos_int21h_routine:
                cmp ah, 9
                jne short pass_int21h_printstr
loc_print_$:          
                mov     BX, DX
                mov     AL, byte ptr DS:[BX]
                cmp     AL,'$'            
                je      short loc_int21_9h_return ; AL = $ : end of string
		mov     AH,0Eh                  
		mov     BX,07h             
		int     10h                     ; BIOS Service func ( ah ) = 0Eh
						; Write char as TTY
						;AL-char BH-page BL-color
                inc     DX
                jmp     short loc_print_$
loc_int21_9h_return:
                sti
                iret

pass_int21h_printstr:
                cmp ah, 0
                je terminate_process
                cmp ah, 4Ch
                je terminate_process

                cmp ah, 35h
                ja short loc_invalid_function_calll
                jmp dword ptr CS:[INT21h_Offset]

                ; Other Functions (invalid)
loc_invalid_function_calll:
                pop word ptr CS:[INT_IP]
                pop word ptr CS:[INT_CS]
                pop word ptr CS:[INT_Flags]
                
                push sp
                push bp
                push ss
                push es
                push ds

                push cs
                pop ds

                push di
                push si
                push dx
                push cx
                push bx
                push ax
                call proc_hex
                mov word ptr [ValStr_AX]+2, ax
                pop ax
                mov al, ah
                call proc_hex
                mov word ptr [ValStr_AX], ax
                mov word ptr [ValStr_AH], ax
                mov al, 21h
                call proc_hex
                mov word ptr [ValStr_INT], ax

                mov al, byte ptr [INT_IP]+1
                call proc_hex
                mov word ptr [ValStr_IP], ax
                mov al, byte ptr [INT_IP]
                call proc_hex
                mov word ptr [ValStr_IP]+2, ax

                mov al, byte ptr [INT_CS]+1
                call proc_hex
                mov word ptr [ValStr_CS], ax
                mov al, byte ptr [INT_CS]
                call proc_hex
                mov word ptr [ValStr_CS]+2, ax

                mov al, byte ptr [INT_Flags]+1
                call proc_hex
                mov word ptr [ValStr_Flags], ax
                mov al, byte ptr [INT_Flags]
                call proc_hex
                mov word ptr [ValStr_Flags]+2, ax

                pop bx
                mov al, bh
                call proc_hex
                mov word ptr [ValStr_BX], ax
                mov al, bl
                call proc_hex
                mov word ptr [ValStr_BX]+2, ax

                pop cx
                mov al, ch
                call proc_hex
                mov word ptr [ValStr_CX], ax
                mov al, cl
                call proc_hex
                mov word ptr [ValStr_CX]+2, ax

                pop dx
                mov al, dh
                call proc_hex
                mov word ptr [ValStr_DX], ax
                mov al, dl
                call proc_hex
                mov word ptr [ValStr_DX]+2, ax

                pop dx ; si
                mov al, dh
                call proc_hex
                mov word ptr [ValStr_SI], ax
                mov al, dl
                call proc_hex
                mov word ptr [ValStr_SI]+2, ax

                pop dx ; di
                mov al, dh
                call proc_hex
                mov word ptr [ValStr_DI], ax
                mov al, dl
                call proc_hex
                mov word ptr [ValStr_DI]+2, ax

                pop dx ; ds
                mov al, dh
                call proc_hex
                mov word ptr [ValStr_DS], ax
                mov al, dl
                call proc_hex
                mov word ptr [ValStr_DS]+2, ax

                pop dx ; es
                mov al, dh
                call proc_hex
                mov word ptr [ValStr_ES], ax
                mov al, dl
                call proc_hex
                mov word ptr [ValStr_ES]+2, ax

                pop dx ; ss
                mov al, dh
                call proc_hex
                mov word ptr [ValStr_SS], ax
                mov al, dl
                call proc_hex
                mov word ptr [ValStr_SS]+2, ax

                pop dx ; bp
                mov al, dh
                call proc_hex
                mov word ptr [ValStr_BP], ax
                mov al, dl
                call proc_hex
                mov word ptr [ValStr_BP]+2, ax

                pop dx ; sp
                mov al, dh
                call proc_hex
                mov word ptr [ValStr_SP], ax
                mov al, dl
                call proc_hex
                mov word ptr [ValStr_SP]+2, ax

                mov si, offset msg_invalid_function_call
                call proc_printmsg
                mov si, offset msg_function_registers
                call proc_printmsg
                
                jmp short terminate_process

terminate_process:
                jmp run_com_int20h_handler

INT21h_Offset:  dw 0
INT21h_Segment: dw 0
INT_IP: dw 0
INT_CS: dw 0
INT_FLAGS: dw 0

msg_invalid_function_call:
                db 7
                db 0Dh, 0Ah, 0Dh, 0Ah
                db "*** Invalid function call for TRDOS ! ***"
                db 0Dh, 0Ah, 0
msg_function_registers:
                db 0Dh, 0Ah
                db "INT "
ValStr_INT:     dw 3030h
                db "h"
                db "    "
                db "Function AH = "
ValStr_AH:      dw 3030h
                db "h"
                db 0Dh, 0Ah, 0Dh,0Ah
                db "Registers: ", 0Dh, 0Ah
                db "AX = "
ValStr_AX:      dd 30303030h
                db "h    "
                db "BX = "
ValStr_BX:      dd 30303030h
                db "h    "
                db "CX = "
ValStr_CX:      dd 30303030h
                db "h    "
                db "DX = "
ValStr_DX:      dd 30303030h
                db "h", 0Dh, 0Ah
                db "CS = "
ValStr_CS:      dd 30303030h
                db "h    "
                db "IP = "
ValStr_IP:      dd 30303030h
                db "h    "
                db "Flags = "
ValStr_Flags:   dd 30303030h
                db "h", 0Dh, 0Ah
                db "DS = "
ValStr_DS:      dd 30303030h
                db "h    "
                db "ES = "
ValStr_ES:      dd 30303030h
                db "h    "
                db "SI = "
ValStr_SI:      dd 30303030h
                db "h    "
                db "DI = "
ValStr_DI:      dd 30303030h
                db "h", 0Dh, 0Ah
                db "SS = "
ValStr_SS:      dd 30303030h
                db "h    "
                db "SP = "
ValStr_SP:      dd 30303030h
                db "h    "
                db "BP = "
ValStr_BP:      dd 30303030h
                db "h", 0Dh, 0Ah, 0Dh, 0Ah, 0

; End Of TRDOS Function Calls

; INTERNAL COMMANDS
Cmd_Dir: db "DIR"
; Cmd_Cd: db "CD"
; Cmd_Drive: db "C:" ; D:, E: etc.
Cmd_Ver: db "VER"
Cmd_Exit: db "EXIT"
Cmd_Prompt: db "PROMPT"
Cmd_Volume: db "VOLUME"
Cmd_LongName: db "LONGNAME"
Cmd_Date: db "DATE"
Cmd_Time: db "TIME"
Cmd_Run: db "RUN"

SourceFile_Drv: db 0
SourceFile_Cluster: dd 0
SourceFile_BufferOff: dw 0
SourceFile_BufferSeg: dw 0

HDCounter:     db 1
Partition:     db 0
              
FileSys_Names: ; 2003 (Valid FileSystems for TR-DOS Project in 2003)
               db "           "
               db "TrDos FS1  "  ; 01h (16 bit, 512 bytes per sec)
                                 ; Reserved for future TRDOS versions
               db "TrDos FS2  "  ; 02h (32 bit, 512 bytes per sec)
                                 ; Reserved for future TRDOS versions
               db "TrDos FS3  "  ; 03h (32 bit, 2048 bytes per sec)
                                 ; Reserved for future TRDOS versions
               db "DOS FAT16  "  ; 04h = FAT16 < 32MB
                                 ; TRDOS doesn't use this FS for hard disks
               db "DOS EXT    "  ; 05h = Extended DOS Partition
                                 ; TRDOS uses DOS extended partitions
               db "DOS FAT16  "  ; 06h = FAT16 > 32MB, CHS Mode
                                 ; TRDOS uses FAT16 Big CHS mode FS
FS_NTFS:       db "WINDOWS NT "  ; 07h , WINDOWS 2000/XP NTFS Partition
                                 ; TRDOS doesn't use NTFS
FS_WIN_32:     db "WIN4 FAT32 "  ; OBh = FAT32 CHS, 0Ch = FAT32 LBA
                                 ; TRDOS uses FAT32 CHS and LBA modes
FS_WIN_P:      db "WIN4 FAT16 "  ; 0Eh = FAT16, LBA Mode
                                 ; TRDOS uses FAT16 LBA mode FS
FS_WIN_EXT:    db "WIN4 EXT   "  ; 0Fh = Extented Partition, LBA Mode
                                 ; TRDOS uses WINDOWS extended partitions
FS_SCO:        db "SCO Unix   "  ; 63h , SCO UNIX, UNIXWARE, OPENSERVER
                                 ; TR-MULTIX ATAPI device LBA FS
RS_DATARANGER: db "DataRanger "  ; A0h , (DataRanger Random Data Disk) LBA
                                 ; TR-DATARANGER Ranged Data Record System
FS_Others:     db "Non-DOS    "  ; Non DOS, Another or Unknown File Systems

MasterBootBuff:
MasterBootCode: db 1BEh dup (?)
PartitionTable: db 64 dup (?)
MBIDCode: dw ?

PTable_Buffer:
PTable_hd0: db 64 dup (0)
PTable_hd1: db 64 dup (0)
PTable_hd2: db 64 dup (0)
PTable_hd3: db 64 dup (0)
PTable_ep0: db 64 dup (0)
PTable_ep1: db 64 dup (0)
PTable_ep2: db 64 dup (0)
PTable_ep3: db 64 dup (0)

DiskParams:
Disk_fd0: db 16 dup (0)
DAP_fd0: db 16 dup(0)
GDP_fd0: db 26 dup(0)
TRDP_fd0: db 6 dup(0)
Disk_fd1: db 16 dup (0)
DAP_fd1: db 16 dup(0)
GDP_fd1: db 26 dup(0)
TRDP_fd1: db 6 dup(0)
Disk_hd0: db 16 dup (0)
DAP_hd0: db 16 dup(0)
GDP_hd0: db 26 dup(0)
TRDP_hd0: db 6 dup(0)
Disk_hd1: db 16 dup (0)
DAP_hd1: db 16 dup(0)
GDP_hd1: db 26 dup(0)
TRDP_hd1: db 6 dup(0)
Disk_hd2: db 16 dup (0)
DAP_hd2: db 16 dup(0)
GDP_hd2: db 26 dup(0)
TRDP_hd2: db 6 dup(0)
Disk_hd3: db 16 dup (0)
DAP_hd3: db 16 dup(0)
GDP_hd3: db 26 dup(0)
TRDP_hd3: db 6 dup(0)
end_of_dparams_buff:

DOSBootSectorBuff:
BS_JmpBoot: db 3 dup (0)
BS_OEMName: db 8 dup (0)
BPB_BytsPerSec: dw 0
BPB_SecPerClust: db 0
BPB_RsvdSecCnt: dw 0
BPB_NumFATs: db 0
BPB_RootEntCnt: dw 0
BPB_TotalSec16: dw 0
BPB_Media: db 0
BPB_FATSz16: dw 0
BPB_SecPerTrk: dw 0
BPB_NumHeads: dw 0
BPB_HiddSec: dd 0
BPB_TotalSec32: dd 0
BPB_FATSz32: ; FAT32, 4 bytes
BS_DrvNum: db 0
BS_Reserved1: db 0
BS_BootSig: db 0
BS_VolID: db 0
BPB_ExtFlags: ; FAT32, 2 bytes
          dw 0
BPB_FSVer: ; FAT32, 2 bytes
          db 0
BS_VolLab: db 0
BPB_RootClus: ; FAT32, 4 bytes
           dd 0
BPB_FSInfo: ; FAT 32, 2 bytes 
           dw 0
BPB_BkBootSec: ; FAT32, 2 bytes
           dw 0
BPB_Reserved: ; FAT32, 12 bytes
           dw 0
BS_FilSysType:
           db 8 dup (0)
BS_BootCode:
           dw 0
BS_FAT32_DrvNum: ; FAT32, 1 byte
           db 0
BS_FAT32_Reserved1: ; FAT32, 1 byte
           db 0
BS_FAT32_BootSig: ; FAT32, 1 byte
           db 0
BS_FAT32_VolID: ; FAT32, 4 bytes
           dd 0
BS_FAT32_VolLab: ; FAT32, 11 bytes
           db 11 dup (0)
BS_FAT32_FilSysType: ; FAT32, 8 bytes
           db 8 dup (0)
BS_FAT32_BootCode:
           db 420 dup (0)
BS_Validation: dw 0

CHS_RetryCount: db 0
PrintDir_RowCounter: db 0

; Disk Read Procedure Parameters
DAP_RetryCount: db 4
DAP_BuffCDRV_BPB: dw 0
DAP_BuffDisk: db 0
DAP_BuffLBAyes: db 0
DAP_Buffer:
DAP_BuffPacketSize: db 0
DAP_BuffReservd1: db 0
DAP_BuffNumOfBlocks: db 0
DAP_BuffReservd2: db 0
DAP_BuffDestination: dd 0
DAP_BuffLBA_Address: dd 0
DAP_BuffLBA_Addressq: dd 0

FAT_BuffDescriptor:
FAT_CurrentCluster: dd 0
FAT_BuffValidData: db 0
FAT_BuffDrvName: db 0
FAT_BuffSector: dd 0
FAT_Buffer: db 1536 dup (0FFh)

Directory_BuffDescriptor:
DirBuff_ValidData: db 0
DirBuff_Drv: db 0
DirBuff_DirCluster: dd 0
DirBuff_NextCluster: dd 0
DirBuff_EntryCounter: dw 0
DirBuff_SectorOffset: db 0
DirBuff_LastSector: db 0
DirBuff_CurrentEntry: db 0
DirBuff_LastEntry: db 0
DirBuff_DirSector: dd 0
Directory_Buffer: db 512 dup (0)
                             
Current_DrvDescriptor:
Current_Media: db 0
Current_PhyDisk: db 0
Current_VolSerial1: dw 0
Current_VolSerial2: dw 0
Current_DosDisk: db 0
Current_DirLevel: db 0
Current_DirFCluster: dd 0
Current_Path: db 11  dup(0)
Current_FS: db 0  ; Byte Ptr [Current_Path]+11
Current_FS_RDFC: dd 0
Current_Path_L1_L7: db 112 dup(0)
Current_File: db 11 dup(0)
Current_File_FCluster: dd 0
Current_ClusterCount: dd 0

SectorBuffDescriptor:
SectorBuff_BeginSector: dd 0
SectorBuff_LastSector: dd 0
SectorBuff_CurrentSector: dd 0
SectorBuff_CurrentByte: dw 0
SectorBuff_BytesPerSec: dw 0
SectorBuffer: db 2048 dup(0)

TRDOSPromptLabel: db "TRDOS"
                  db 0
                  db 5 dup(0)
                  db 0
TextBuffer:  db 80 dup(0)
CommandBuffer: db 80 dup(0)
CmdArgStart: db 0
CursorColumn: db 0
Program_Exit: db 0

File_Name:
		db  12 dup(20h)
		db  20h
Dir_Or_FileSize:
		db  10 dup(20h)
		db  20h
File_Attribute:
		db  4 dup(20h)
		db  20h
File_Day:
		db  2 dup('0')
		db  '/'
File_Month:
		db  2 dup('0')
		db  '/'
File_Year:
		db  4 dup('0')
		db  20h
File_Hour:
		db  2 dup('0')
		db  ':'
File_Minute:
		db  2 dup('0')
		db  0

Type_Dir:       db '<DIR>      '

Dir_Drive_Str:
                db "TR-DOS Drive "
Dir_Drive_Name:
                db "0:"
                db  0Dh, 0Ah
Vol_Str_Header:
                db "Volume Name: "
Vol_Name:       db 11 dup(0)
                db 0
Vol_Serial_Header:
                db 0Dh, 0Ah
                db "Volume Serial No: "
Vol_Serial2:    db "0000"
                db "-"
Vol_Serial1:    db "0000"
                db 0Dh, 0Ah
Dir_Str_Header:
                db "Directory: "
Dir_Str_Root:   db "/"
Dir_Str:        db 64 dup (0)
End_of_Dir_Str: db " ..."
                db 0
Starting_Msg:
                db 0Dh, 0Ah 
                db "Starting TRDOS ..."
                db 0Dh, 0Ah, 0
Msg_Bad_Command:
                db "Bad command or file name!"
                db 0Dh, 0Ah, 0
Msg_Not_Ready_Read_Err:
                db "Drive not ready or read error!"
                db 0Dh, 0Ah, 0
Msg_Dir_Not_Found:
                db "Directory not found!"
                db 0Dh, 0Ah, 0

Msg_File_Name0: db 34
Msg_File_Name1: db 11 dup (20h)
                db 34, 0
Msg_File_Not_Found:
                db "File"
Msg_Not_Found:
                db " not found!"
                db 0Dh, 0Ah, 0
Magic_Bytes:
                   db 4
                   db 1
Program_Version:
                   db 7
                   db "[TRDOS] Main Program v1.0"
                   db 0Dh, 0Ah
                   db "(c) Erdogan Tan 2004"
                   db 0Dh, 0Ah, 0
HD_LBAYes:         dd 0
Hard_Disk:         db 80h
Last_DOS_DiskNo:   db 0
Logical_DOSDisks:  dw 3328 dup(0)

RunFile_BuffPrefix:db 16 dup (0)
RunFile_Buffer:    db 16384 dup(0)
End_Of_Run_Buffer: db 0

Present            ends

                   end  start