

'info:
' FileNames array contains long file names without path
' ShortNames array contains short file names without path
' Directories array contains long directories names without path
' ShortNameDir array contains short directories names without path
' FUNCTION  __File$ (mask$, parameter)  - if is parameter 1, this function return SHORT filename AND PATH to this file (after is this file with Enter selected)
'                                       - if is parameter 2, return 2 arrays (STRING): first array is FilesVisible. Contains long filesnames + path. Second is FilesUsable. Contains short filesnames + path.
'                                       - in X$ = __Files$ (mask$, 2) you need NOT X$, is for call only. In this mode select more files using Enter and then go back pressing Esc.
'                                      in function __Files$ use arrow Up and Down, PageUP, PageDN, Home, End, Enter and Esc. Is possible switching drives and selecting files in more places not in 1 dir only!

' Please test it. Use UNICODE paths, UNICODE filenames, for real hard test. For me all works correctly.


'typy a zpusoby navratu: - vrati seznam souboru ze slozky formou pole  ---- v poli FileNames - dlouha jmena, ShortNameFile vraci kratka jmena
'                        - vrati seznam adresaru                       ---- v poli Directories dlouha jmena, ShortNameDir vraci kratka jmena adresaru
'                        - vrati jeden soubor po vyberu (soucasny stav)  -- __Files (mask$, 1)
'                        - vrati vice souboru po vyberu               ----- __Files (mask$, 2)

'this program in main loop contains _SNDPLAY statement, so please try selecting and then playing some your MP3 files using your national unicode names.




REM sample program to get/list/sort lists of filenames/directories v1.0a PD. Upgraded Erik's code for solving FILES statement unusuality.
' detect operating system
$IF WIN = 0 THEN
    COLOR 15, 0
    CLS
    PRINT "Sorry, this program only works in Windows.."
    END
$END IF
REM $DYNAMIC
CONST MAX_PATH = 260
CONST INVALID_HANDLE_VALUE = -1
CONST ERROR_FILE_NOT_FOUND = 2
CONST ERROR_NO_MORE_FILES = &H12





TYPE FILETIME
    dwLowDateTime AS _UNSIGNED LONG
    dwHighDateTime AS _UNSIGNED LONG
END TYPE

TYPE SYSTEMTIME
    wYear AS INTEGER
    wMonth AS INTEGER
    wDayOfWeek AS INTEGER
    wDay AS INTEGER
    wHour AS INTEGER
    wMinute AS INTEGER
    wSecond AS INTEGER
    wMilliseconds AS INTEGER
END TYPE

TYPE WIN32_FIND_DATAA
    dwFileAttributes AS _UNSIGNED LONG
    ftCreationTime AS FILETIME
    ftLastAccessTime AS FILETIME
    ftLastWriteTime AS FILETIME
    nFileSizeHigh AS _UNSIGNED LONG
    nFileSizeLow AS _UNSIGNED LONG
    dwReserved0 AS _UNSIGNED LONG
    dwReserved1 AS _UNSIGNED LONG
    cFileName AS STRING * MAX_PATH
    cAlternateFileName AS STRING * 14
END TYPE

DECLARE DYNAMIC LIBRARY "kernel32"
    FUNCTION FindFirstFileA~%& (BYVAL lpFileName~%&, BYVAL lpFindFileData~%&)
    FUNCTION FindNextFileA& (BYVAL hFindFile~%&, BYVAL lpFindFileData~%&)
    FUNCTION FindClose& (BYVAL hFindFile~%&)
    FUNCTION FileTimeToSystemTime& (lpFileTime AS FILETIME, lpSystemTime AS SYSTEMTIME)
    FUNCTION GetVolumeInformationA& (lpRootPathName$, lpVolumeNameBuffer$, BYVAL nVolumeNameSize~&, lpVolumeSerialNumber~&, lpMaximumComponentLength~&, lpFileSystemFlags~&, lpFileSystemNameBuffer$, BYVAL nFileSystemNameSize&)
    FUNCTION GetDiskFreeSpaceA& (f$, sectors&, bytes&, free&, total&)
    FUNCTION GetDiskFreeSpaceExA& (filename$, free AS _UNSIGNED _INTEGER64, total AS _UNSIGNED _INTEGER64, free2 AS _UNSIGNED _INTEGER64)
END DECLARE

DECLARE LIBRARY
    FUNCTION GetFileAttributes& (f$)
    FUNCTION SetFileAttributes& (f$, BYVAL a&)
    FUNCTION GetDriveType& (d$)
    FUNCTION GetShortPathName& (InP$, OutP$, BYVAL length&)
    FUNCTION GetModuleFileNameA (BYVAL Module AS LONG, FileName AS STRING, BYVAL nSize AS LONG)
END DECLARE

' declare library variables.
DIM SHARED finddata AS WIN32_FIND_DATAA
DIM SHARED hfind AS _UNSIGNED _OFFSET
DIM SHARED SysTime AS SYSTEMTIME
DIM SHARED Out3 AS STRING
DIM SHARED DriveType AS STRING

' declare byte divisor variable.
DIM SHARED ByteDivisor AS DOUBLE
'--------------------------------
'moje vklady
DIM SHARED Drives(1) AS STRING 'vrati pole s pismeny jednotek
DIM SHARED DriveLabels(1) AS STRING
DIM SHARED DriveSerials(1) AS STRING
DIM SHARED DriveType(1) AS STRING
DIM SHARED DiskTotalSpace(1) AS STRING
DIM SHARED DiskFreeSpace(1) AS STRING


DIM SHARED Filenames(1) AS STRING
DIM SHARED Directories(1) AS STRING

DIM SHARED FileCount AS SINGLE
DIM SHARED DirCount AS SINGLE

DIM SHARED FileSize(1) AS DOUBLE

DIM SHARED DateTimeDir(1) AS STRING * 19
DIM SHARED DateTimeFile(1) AS STRING * 19

DIM SHARED AttributesDir(1) AS INTEGER
DIM SHARED AttributesFile(1) AS INTEGER

DIM SHARED ShortNameDir(1) AS STRING
DIM SHARED ShortNameFile(1) AS STRING

DIM SHARED DateTimeType AS INTEGER
DIM SHARED LineCount AS INTEGER

REDIM SHARED FilesVisible(1) AS STRING 'pro vicenasobny vyber - dlouha jmena 'multiple select array, long names + path
REDIM SHARED FilesUsable(1) AS STRING 'pro vicenasobny vyber - kratka jmena  'multiple select array, short names + path

REDIM SHARED Attrib(1) AS STRING
REDIM SHARED Size(1) AS STRING

DateTimeType = 1
StoreSort1 = 1
StoreSort2 = -1

' ------------ start mych uprav ------------- Petr's upgrade start


rst:
Maska$ = "*.mp3" 'mask
CALL GetFiles(Maska$) '                 load files list from kernel32 to memory, Erik work
CALL SortFiles(StoreSort1, StoreSort2) 'sort files, Erik work
REDIM SHARED Adresar(0) AS STRING 'its help array, Petr work - for Dirs
REDIM SHARED Soubor(0) AS STRING ' its help array, Petr work - for files



'telo programu disk
ON ERROR GOTO Error.Routine
' declare some constants.
CONST Nul = ""
CONST True = -1
_TITLE "DRIVE INFO"

REM Start program loop.

IF INSTR(_OS$, "[WINDOWS]") THEN
    ByteDivisor = 1024
ELSE
    IF INSTR(_OS$, "[MACOSX]") THEN
        ByteDivisor = 1000
    ELSE
        ByteDivisor = 1024
    END IF
END IF


ListDrives Nul, 0
ListFiles
'telo disk konec

SCREEN _NEWIMAGE(640, 480, 256)
_FULLSCREEN
one$ = __Files$("*.*", 1) '__Files$ (function) is Petr's program full based on Erik's demo.
CLS '
PRINT "Function return this path to 1 selected file: "; one$
IF _SNDPLAYING(m&) THEN _SNDSTOP (m&): _SNDCLOSE m&
IF LCASE$(RIGHT$(one$, 4)) = ".mp3" THEN m& = _SNDOPEN(one$): _SNDPLAY m& ELSE _SCREENICON: SHELL one$
SLEEP 1
PRINT "Select more files with enter, quit with Esc"
SLEEP
e$ = __Files$("*.mp3", 2): e$ = "" 'function return with ,2 outputs in arrays FilesVisible and FilesUsable
CLS
PRINT "Selected files:"
PRINT "Long names (use with _MAPUNICODE NOT FOR ACCESS! and short system name, use for access:):"

FOR w = 0 TO UBOUND(FilesVisible)
    COLOR 15
    PRINT FilesVisible(w); CHR$(32);: COLOR 4: PRINT FilesUsable(w)
    IF w MOD 5 = 0 AND w >= 5 THEN COLOR 15: PRINT "Press any key...": SLEEP: CLS: PRINT "Long names (use with _MAPUNICODE NOT FOR ACCESS! and short system name, use for access:):"
NEXT w
PRINT "After pressing key, sound will stopped and is played selected from mode 2 (if are some MP3 selected)"
SLEEP
COLOR 15, 0

_SNDSTOP m&: _SNDCLOSE m&: CLS
FOR w = 1 TO UBOUND(FilesVisible)
    IF LCASE$(RIGHT$(FilesUsable(w), 4)) = ".mp3" THEN
        m& = _SNDOPEN(FilesUsable(w))
        _SNDPLAY m&
        DO UNTIL NOT _SNDPLAYING(m&)
            i$ = INKEY$
            IF i$ = CHR$(27) THEN END
            LOCATE 5, 1: PRINT "Playing "; FilesVisible(w)
            LOCATE 6, 1: PRINT FilesUsable(w)
            _LIMIT 10
        LOOP
        IF m& THEN _SNDCLOSE m&
        CLS
    END IF
NEXT w




END


' critical error trap
Error.Routine:
IF ERR THEN CHDIR "C:\": RESUME NEXT

FUNCTION __Files$ (mask AS STRING, typ AS _BYTE) 'mask - use "*.*" for all files.... typ: 1 for one file select, 2 for more files (and it can be in different directories) selecting, this is ending after pressing Esc, values are then in arrays FilesVisible and FilesUsable. Visible for long names viewing, Usable for file access!  THIS MUSS WORKING ON ALL WINDOWS WORLDWIDE!

    begin:
    DirLevel = 0
    sizindex = 1
    CLS
    path$ = _CWD$
    IF _PIXELSIZE = 0 THEN LOCATE 1, 1: PRINT "Current path: "; path$

    GetFiles mask$
    SortFiles StoreSort1, StoreSort2
    REDIM Adresar(DirCount) AS STRING '             Directories
    REDIM Soubor(FileCount) AS STRING '             Files
    REDIM Vse(DirCount + FileCount) AS STRING '     Both - first directories, then files - contains long names, unussable for stable file access in other as english languages (not coded in Unicode)
    REDIM Acces(UBOUND(vse)) AS STRING '            Both - short names, usable for worldwide file / folder access
    REDIM ostatni(UBOUND(vse)) AS STRING 'date and time
    REDIM Attrib(FileCount + DirCount) AS STRING
    REDIM Size(FileCount) AS STRING
    ListDirs '                                                              modified - give dir names to array adresar$
    ListFiles '                                                             modified - give long file names to array soubor$
    akt = 1
    vklad = 1
    FOR rew0 = 1 TO DirCount
        Vse(rew0) = UCASE$(Adresar(rew0))
        ostatni(rew0) = DateTimeDir(rew0)
        IF ShortNameDir(rew0) <> "" THEN Acces(rew0) = ShortNameDir(rew0) ELSE Acces(rew0) = UCASE$(Directories(rew0))
    NEXT rew0
    FOR rew1 = 1 TO FileCount
        Vse(DirCount + rew1) = Soubor(rew1)
        ostatni(DirCount + rew1) = DateTimeFile(rew1)
        IF ShortNameFile(rew1) <> "" THEN Acces(DirCount + rew1) = ShortNameFile(rew1) ELSE Acces(DirCount + rew1) = Filenames(rew1)
    NEXT rew1

    IF LEN(path$) > 3 THEN REDIM _PRESERVE Vse(UBOUND(vse) + 1) AS STRING: Vse(UBOUND(vse)) = ".." '.. is for return up one level in directory structure

    Celkem = UBOUND(vse)
    IF Celkem < 1 THEN Celkem = 1
    ListStart = 1
    ListEnd = 15
    pul = CINT(ListEnd - ListStart) / 2
    IF ListEnd > Celkem THEN ListEnd = Celkem
    akt = 1 'what is selected. First name in list after start
    vypis = 1
    Pso = 5 ' start printing folder list. This number muss be the same as in line 177!

    REDIM _PRESERVE ostatni(UBOUND(vse)) AS STRING
    DO
        FOR vypis = ListStart TO ListEnd
            IF ListEnd > UBOUND(vse) THEN ListEnd = UBOUND(vse)
            Pso = Pso + 1
            i$ = INKEY$
            SELECT CASE i$
                CASE CHR$(0) + CHR$(72)
                    akt = akt - 1: IF akt < 1 THEN akt = 1
                    IF akt < pul + ListStart THEN ListStart = ListStart - 1: ListEnd = ListEnd - 1
                    IF ListStart < 1 THEN ListStart = 1: ListEnd = ListStart + (ListEnd - ListStart + 1)
                CASE CHR$(0) + CHR$(80)
                    akt = akt + 1: IF akt > Celkem THEN akt = Celkem
                    IF akt > pul + ListStart THEN ListEnd = ListEnd + 1: ListStart = ListStart + 1
                    IF ListEnd > UBOUND(vse) THEN ListEnd = UBOUND(vse): ListStart = ListEnd - (ListEnd - ListStart + 1)
                CASE CHR$(0) + CHR$(71): akt = 1: ListStart = 1: IF UBOUND(vse) > 15 THEN ListEnd = 15 ELSE ListEnd = UBOUND(vse) 'home
                CASE CHR$(0) + CHR$(79): akt = UBOUND(vse): ListEnd = akt: IF akt > 15 THEN ListStart = akt - 15 ELSE ListStart = 1 ' end
                CASE CHR$(0) + CHR$(73) 'pgUp
                    akt = akt - 15: IF akt < 1 THEN akt = 1
                    ListStart = ListStart - 15
                    IF ListStart < 1 THEN ListStart = 1
                    IF ListStart + 15 < UBOUND(vse) THEN ListEnd = ListStart + 15 ELSE ListEnd = UBOUND(vse)
                CASE CHR$(0) + CHR$(81)
                    akt = akt + 15: IF akt > UBOUND(vse) THEN akt = UBOUND(vse)
                    ListEnd = ListEnd + 15
                    IF ListEnd > UBOUND(vse) THEN ListEnd = UBOUND(vse)
                    IF ListEnd - 15 > 1 THEN ListStart = ListEnd - 15 ELSE ListStart = 1
                CASE CHR$(13)
                    SELECT CASE typ
                        CASE 1: EXIT DO
                        CASE 2:
                            IF Vse(akt) = ".." THEN CHDIR "..": DirLevel = DirLevel - 1: t$ = "": GOTO begin
                            IF akt <= DirCount THEN CHDIR Acces(akt): DirLevel = DirLevel + 1: t$ = "": GOTO begin ' CHDIR MUSS BE!!!!! set to Acces array for long DIRECTORIES names!!!!
                            zaznam = zaznam + 1
                            REDIM _PRESERVE FilesVisible(zaznam) AS STRING: FilesVisible(zaznam) = path$ + CHR$(92) + Vse(akt)
                            REDIM _PRESERVE FilesUsable(zaznam) AS STRING: FilesUsable(zaznam) = path$ + CHR$(92) + Acces(akt)
                    END SELECT
                CASE CHR$(27): IF typ = 2 THEN _AUTODISPLAY: EXIT FUNCTION
            END SELECT
            IF LEN(useavailable$) THEN
                FOR fr = 1 TO LEN(useavailable$)
                    IF MID$(UCASE$(useavailable$), fr, 1) = UCASE$(i$) THEN disc = fr: DriveSelect$ = i$ + LTRIM$(":\"): CHDIR DriveSelect$: GOTO begin
                NEXT fr
            END IF
            COLOR 15, 0: LOCATE Pso, 20: PRINT SPACE$(55)
            IF vypis = akt THEN COLOR 14, 9 ELSE COLOR 15, 0
            IF LEN(Vse(vypis)) > 24 THEN t$ = LEFT$(Vse(vypis), 21) + "..." ELSE t$ = Vse(vypis)
            IF vypis > UBOUND(vse) THEN
                navic$ = ""
            ELSE
                navic$ = ostatni(vypis)
            END IF

            IF t$ = ".." THEN t$ = t$ + SPC(57)

            IF typ = 2 THEN
                FOR porovnej = 0 TO UBOUND(FilesVisible)
                    IF FilesVisible(porovnej) = path$ + CHR$(92) + Vse(vypis) THEN COLOR 2 'musi byt shoda i s cestou
                    IF FilesUsable(porovnej) = path$ + CHR$(92) + Vse(vypis) THEN COLOR 2
                NEXT
            END IF
            IF vypis > DirCount AND vypis <= FileCount + DirCount THEN
                LOCATE Pso, 54: PRINT "  "; Attrib(vypis - DirCount) + SPC(14) ' atributy   [pole attrib je velke jako dircount + filecount]
                LOCATE Pso, 63: PRINT Size(vypis - DirCount)
            ELSE LOCATE Pso, 54: PRINT " <DIR> " + SPC(12)
            END IF
            LOCATE Pso, 10: PRINT t$; SPC(25 - LEN(t$)); navic$; CHR$(32)
            COLOR 15, 0
        NEXT vypis
        i3 = 0
        Pso = 5
        sizindex = 0

        IF _PIXELSIZE > 0 THEN
            LINE (30, 30)-(610, 360), 15, B
            LINE (35, 35)-(605, 355), 15, B
            LINE (35, 60)-(605, 65), 15, B
            _PRINTSTRING (40, 40), "         Select file. Use Esc in mode 2 for end. Mode: " + STR$(typ)

            IF LEN(path$) > 44 THEN pat$ = LEFT$(path$, 44) + "..." ELSE pat$ = path$
            _PRINTSTRING (70, 370), "Current path: " + pat$
            LINE (610, 360)-(30, 395), 15, B
            LINE (605, 360)-(35, 390), 15, B
            IF Available$ = "" THEN
                FOR HowDisk = 1 TO UBOUND(drives)
                    IF UCASE$(LEFT$(pat$, 1)) = UCASE$(Drives(HowDisk)) THEN disc = HowDisk
                    Available$ = Available$ + Drives(HowDisk) + " "
                    useavailable$ = useavailable$ + Drives(HowDisk)
                NEXT
            END IF
            _PRINTSTRING (30, 400), "Disk info: " + Drives(disc) + LTRIM$(":\  Total space: ") + DiskTotalSpace(disc) + " Free space: " + DiskFreeSpace(disc) + RTRIM$(" [" + DriveLabels(disc) + "]")
            _PRINTSTRING (30, 420), "Press correct key for select drive. Drives: " + Available$
        END IF
        _DISPLAY
        _LIMIT 15
    LOOP
    _AUTODISPLAY
    IF Vse(akt) = ".." THEN CHDIR "..": DirLevel = DirLevel - 1: t$ = "": GOTO begin
    IF akt <= DirCount THEN CHDIR Acces(akt): DirLevel = DirLevel + 1: GOTO begin
    IF akt <= DirCount THEN __Files$ = path$ + CHR$(92) + Acces(akt) ELSE __Files$ = path$ + CHR$(92) + Acces(akt)
END FUNCTION
SUB GetFiles (Var$)
    maska$ = Var$
    Var$ = "*.*"
    DIM Attribute AS INTEGER
    DIM ASCIIZ AS STRING * 260
    DIM finddata AS WIN32_FIND_DATAA
    DIM Wfile.Handle AS _UNSIGNED _OFFSET
    DIM SysTime AS SYSTEMTIME

    DirCount = 0!
    FileCount = 0!

    ASCIIZ = Var$ + CHR$(0)
    Wfile.Handle = FindFirstFileA(_OFFSET(ASCIIZ), _OFFSET(finddata))
    IF Wfile.Handle <> INVALID_HANDLE_VALUE THEN ' OR WDIR.Handle <> INVALID_HANDLE_VALUE THEN
        DO
            Attribute = finddata.dwFileAttributes
            Filename$ = finddata.cFileName
            Filename$ = LEFT$(Filename$, INSTR(Filename$, CHR$(0)) - 1)
            IF Filename$ <> "." AND Filename$ <> ".." THEN

                ' store date/time
                SELECT CASE DateTimeType
                    CASE 1
                        x& = FileTimeToSystemTime&(finddata.ftCreationTime, SysTime)
                    CASE 2
                        x& = FileTimeToSystemTime&(finddata.ftLastAccessTime, SysTime)
                    CASE 3
                        x& = FileTimeToSystemTime&(finddata.ftLastWriteTime, SysTime)
                END SELECT

                Var1$ = RIGHT$("00" + LTRIM$(STR$(SysTime.wMonth)), 2) + "-"
                Var1$ = Var1$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wDay)), 2) + "-"
                Var1$ = Var1$ + LTRIM$(STR$(SysTime.wYear)) + " "

                Var1$ = Var1$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wHour)), 2) + ":"
                Var1$ = Var1$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wMinute)), 2) + ":"
                Var1$ = Var1$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wSecond)), 2)
                IF (Attribute AND &H10) = &H10 THEN
                    DirCount = DirCount + 1!
                    REDIM _PRESERVE Directories(DirCount) AS STRING
                    Directories(DirCount) = Filename$

                    REDIM _PRESERVE DateTimeDir(DirCount) AS STRING * 19
                    DateTimeDir(DirCount) = Var1$

                    REDIM _PRESERVE AttributesDir(DirCount) AS INTEGER
                    AttributesDir(DirCount) = Attribute

                    Filename$ = finddata.cAlternateFileName
                    Filename$ = LEFT$(Filename$, INSTR(Filename$, CHR$(0)) - 1)
                    REDIM _PRESERVE ShortNameDir(DirCount) AS STRING
                    ShortNameDir(DirCount) = Filename$
                ELSE
                    FileCount = FileCount + 1!
                    REDIM _PRESERVE Filenames(FileCount) AS STRING
                    Filenames(FileCount) = Filename$
                    REDIM _PRESERVE FileSize(FileCount) AS DOUBLE
                    F# = finddata.nFileSizeHigh * &H100000000~&& OR finddata.nFileSizeLow
                    FileSize(FileCount) = F#

                    REDIM _PRESERVE DateTimeFile(FileCount) AS STRING * 19
                    DateTimeFile(FileCount) = Var1$

                    REDIM _PRESERVE AttributesFile(FileCount) AS INTEGER
                    AttributesFile(FileCount) = Attribute

                    Filename$ = finddata.cAlternateFileName
                    Filename$ = LEFT$(Filename$, INSTR(Filename$, CHR$(0)) - 1)
                    REDIM _PRESERVE ShortNameFile(FileCount) AS STRING
                    ShortNameFile(FileCount) = Filename$
                END IF
            END IF
        LOOP WHILE FindNextFileA(Wfile.Handle, _OFFSET(finddata))
        x = FindClose(Wfile.Handle)
    END IF
    IF maska$ <> "*.*" THEN Var$ = maska$: Filtruj maska$ 'prepise FileCount podle predimenzovaneho poctu zanamu do poli FileNames, FileSize, DateTimeFile a ShortNameFile. Zaznamy adresaru zustanou stejne!

END SUB

' Var1=1 filename, Var1=2 datetime, Var1=3 filesize
' Var2=-1 ascending, Var2=0 descending
SUB SortFiles (Var1, Var2)
    FOR X! = 1! TO FileCount - 1!
        FOR Y! = X! + 1! TO FileCount
            SELECT CASE Var1
                CASE 1
                    IF Var2 THEN
                        IF Filenames(X!) > Filenames(Y!) THEN
                            SWAP Filenames(X!), Filenames(Y!)
                            SWAP ShortNameFile(X!), ShortNameFile(Y!)
                            SWAP FileSize(X!), FileSize(Y!)
                            SWAP DateTimeFile(X!), DateTimeFile(Y!)
                            SWAP AttributesFile(X!), AttributesFile(Y!)
                        END IF
                    ELSE
                        IF Filenames(X!) < Filenames(Y!) THEN
                            SWAP Filenames(X!), Filenames(Y!)
                            SWAP ShortNameFile(X!), ShortNameFile(Y!)
                            SWAP FileSize(X!), FileSize(Y!)
                            SWAP DateTimeFile(X!), DateTimeFile(Y!)
                            SWAP AttributesFile(X!), AttributesFile(Y!)
                        END IF
                    END IF
                CASE 2
                    IF Var2 THEN
                        IF DateTimeFile(X!) > DateTimeFile(Y!) THEN
                            SWAP Filenames(X!), Filenames(Y!)
                            SWAP ShortNameFile(X!), ShortNameFile(Y!)
                            SWAP FileSize(X!), FileSize(Y!)
                            SWAP DateTimeFile(X!), DateTimeFile(Y!)
                            SWAP AttributesFile(X!), AttributesFile(Y!)
                        END IF
                    ELSE
                        IF DateTimeFile(X!) < DateTimeFile(Y!) THEN
                            SWAP Filenames(X!), Filenames(Y!)
                            SWAP ShortNameFile(X!), ShortNameFile(Y!)
                            SWAP FileSize(X!), FileSize(Y!)
                            SWAP DateTimeFile(X!), DateTimeFile(Y!)
                            SWAP AttributesFile(X!), AttributesFile(Y!)
                        END IF
                    END IF
                CASE 3
                    IF Var2 THEN
                        IF FileSize(X!) > FileSize(Y!) THEN
                            SWAP Filenames(X!), Filenames(Y!)
                            SWAP ShortNameFile(X!), ShortNameFile(Y!)
                            SWAP FileSize(X!), FileSize(Y!)
                            SWAP DateTimeFile(X!), DateTimeFile(Y!)
                            SWAP AttributesFile(X!), AttributesFile(Y!)
                        END IF
                    ELSE
                        IF FileSize(X!) < FileSize(Y!) THEN
                            SWAP Filenames(X!), Filenames(Y!)
                            SWAP ShortNameFile(X!), ShortNameFile(Y!)
                            SWAP FileSize(X!), FileSize(Y!)
                            SWAP DateTimeFile(X!), DateTimeFile(Y!)
                            SWAP AttributesFile(X!), AttributesFile(Y!)
                        END IF
                    END IF
            END SELECT
        NEXT
    NEXT
    IF Var1 = 3 THEN EXIT SUB
    FOR X! = 1! TO DirCount - 1!
        FOR Y! = X! + 1! TO DirCount
            SELECT CASE Var1
                CASE 1
                    IF Var2 THEN
                        IF Directories(X!) > Directories(Y!) THEN
                            SWAP Directories(X!), Directories(Y!)
                            SWAP ShortNameDir(X!), ShortNameDir(Y!)
                            SWAP DateTimeDir(X!), DateTimeDir(Y!)
                            SWAP AttributesDir(X!), AttributesDir(Y!)
                        END IF
                    ELSE
                        IF Directories(X!) < Directories(Y!) THEN
                            SWAP Directories(X!), Directories(Y!)
                            SWAP ShortNameDir(X!), ShortNameDir(Y!)
                            SWAP DateTimeDir(X!), DateTimeDir(Y!)
                            SWAP AttributesDir(X!), AttributesDir(Y!)
                        END IF
                    END IF
                CASE 2
                    IF Var2 THEN
                        IF DateTimeDir(X!) > DateTimeDir(Y!) THEN
                            SWAP Directories(X!), Directories(Y!)
                            SWAP ShortNameDir(X!), ShortNameDir(Y!)
                            SWAP DateTimeDir(X!), DateTimeDir(Y!)
                            SWAP AttributesDir(X!), AttributesDir(Y!)
                        END IF
                    ELSE
                        IF DateTimeDir(X!) < DateTimeDir(Y!) THEN
                            SWAP Directories(X!), Directories(Y!)
                            SWAP ShortNameDir(X!), ShortNameDir(Y!)
                            SWAP DateTimeDir(X!), DateTimeDir(Y!)
                            SWAP AttributesDir(X!), AttributesDir(Y!)
                        END IF
                    END IF
            END SELECT
        NEXT
    NEXT
END SUB

SUB ListFiles
    LineCount = 3
    c = 0
    q = 0
    t = 0
    F! = 0!
    FOR VarQ = 1 TO FileCount
        F! = F! + 1!
        q = -1
        Var% = AttributesFile(VarQ)
        Attr$ = SPACE$(5)
        IF (Var% AND &H20) = &H20 THEN Attrib(VarQ) = "A"
        IF (Var% AND &H4) = &H4 THEN Attrib(VarQ) = "S"
        IF (Var% AND &H2) = &H2 THEN Attrib(VarQ) = "H"
        IF (Var% AND &H1) = &H1 THEN Attrib(VarQ) = "R"
        ' print filesize
        Var# = FileSize(VarQ)
        VarX# = VarX# + Var# ' add bytes
        CALL Suffix(Var#, z$) ' 1,024.0 KB
        z$ = LEFT$(z$, 10)
        z$ = SPACE$(10 - LEN(z$)) + z$ 'suffix
        Size(VarQ) = z$
        ' print longfilename
        z$ = Filenames(VarQ)
        z$ = RTRIM$(z$)
        IF LEN(z$) THEN
            Soubor$(VarQ) = z$
        END IF
    NEXT
    IF q = 0 THEN
        COLOR 14
        PRINT "  No files found."
    END IF
    CALL Suffix(VarX#, z$) ' 1,024.0 KB
END SUB

SUB ListDirs
    LineCount = 3
    c = 0
    q = 0
    t = 0
    F! = 0!
    FOR VarQ = 1 TO DirCount
        F! = F! + 1!
        q = -1
        z$ = ShortNameDir(VarQ)
        z$ = RTRIM$(z$)
        IF z$ = "" THEN
            z$ = Directories(VarQ)
        END IF
        IF LEN(z$) > 12 THEN
            z$ = LEFT$(z$, 12)
        END IF
        Var% = AttributesDir(VarQ)
        Attr$ = SPACE$(5)
        IF (Var% AND &H20) = &H20 THEN Attrib(VarQ) = "A"
        IF (Var% AND &H4) = &H4 THEN Attrib(VarQ) = "S"
        IF (Var% AND &H2) = &H2 THEN Attrib(VarQ) = "H"
        IF (Var% AND &H1) = &H1 THEN Attrib(VarQ) = "R"

        z$ = Directories(VarQ)
        z$ = RTRIM$(z$)
        IF LEN(z$) THEN Adresar$(VarQ) = z$
    NEXT
    IF q = 0 THEN Adresar$(0) = "None"
END SUB

' formats a double numeric string
FUNCTION FormatString$ (s#)
    x$ = ""
    s$ = STR$(s#)
    IF INSTR(s$, "D") THEN ' return string
        FormatString$ = s$
        EXIT FUNCTION
    END IF
    IF LEFT$(s$, 1) = "-" THEN ' store sign
        e$ = "-"
        s$ = MID$(s$, 2)
    END IF
    s$ = LTRIM$(s$) ' format string
    IF INSTR(s$, ".") THEN
        q$ = MID$(s$, INSTR(s$, "."))
        s$ = LEFT$(s$, INSTR(s$, ".") - 1)
    END IF
    FOR l = LEN(s$) TO 3 STEP -3
        x$ = MID$(s$, l - 2, 3) + "," + x$
    NEXT
    IF l > 0 THEN
        x$ = MID$(s$, 1, l) + "," + x$
    END IF
    IF LEN(s$) < 3 THEN
        x$ = s$
    END IF
    IF RIGHT$(x$, 1) = "," THEN
        x$ = LEFT$(x$, LEN(x$) - 1)
    END IF
    x$ = e$ + x$ + q$ ' construct string
    FormatString$ = x$
END FUNCTION

' calculate byte suffix
SUB Suffix (Var#, Var3$)
    REM B  (Byte) = 00x - 0FFx (hexidecimal zero-based)
    REM KB (Kilobyte) = 1024 B
    REM MB (Megabyte) = 1024 KB (1 MB B)
    REM GB (Gigabyte) = 1024 MB
    REM TB (Terabyte) = 1024 GB (1 MB MB)
    REM PB (Petabyte) = 1024 TB
    REM EB (Exabyte) = 1024 PB (1 MB TB)

    ' check double
    VarX# = Var#
    s$ = STR$(VarX#)
    IF INSTR(s$, "D") THEN
        Var3$ = s$
        EXIT SUB
    END IF

    ' get sign
    IF VarX# < 0# THEN
        Sign = True
        VarX# = ABS(VarX#)
    END IF

    ' calculate bytes
    TempA = False
    DO
        IF VarX# >= 1024 THEN
            VarX# = VarX# / 1024
            TempA = TempA + 1
            IF TempA = 6 THEN
                EXIT DO
            END IF
        ELSE
            EXIT DO
        END IF
    LOOP

    ' calculate byte string
    Var3$ = FormatString$(VarX#)
    IF INSTR(Var3$, ".") THEN
        Var3$ = LEFT$(Var3$, INSTR(Var3$, ".") + 1)
    ELSE
        Var3$ = Var3$ + ".0"
    END IF

    ' calculate byte suffix
    Var$ = ""
    IF TempA > 0 THEN
        Var$ = MID$("KMGTPE", TempA, 1)
    END IF
    Var3$ = Var3$ + " " + Var$ + "B"

    ' calculate byte sign
    IF Sign THEN
        Var3$ = "-" + Var3$
    END IF
END SUB




SUB MorePrompt (Input.String$, Input.Mask$, Output.String$)
    COLOR White, Black
    PRINT Input.String$ + " ";
    Input.Char$ = Nul
    DO
        LOCATE , , 1
        _LIMIT 100
        Input.Char$ = INKEY$
        IF LEN(Input.Char$) THEN
            Input.Char$ = LCASE$(Input.Char$)
            IF INSTR(Input.Mask$, Input.Char$) THEN
                PRINT Input.Char$
                Output.String$ = Input.Char$
                EXIT DO
            END IF
        END IF
    LOOP
END SUB

' lists specified drives.
SUB ListDrives (Var$, VarQ)
    ' Var$ = "x..." only list drives in string,
    ' otherwise,
    '   VarQ = 0 list all drives.
    '   VarQ = -1 except A: and B:
    CLS
    l = 0
    FOR c = 1 TO 26
        IF Var$ <> Nul THEN ' display specific drives.
            x$ = UCASE$(Var$)
            IF INSTR(x$, CHR$(c + 64)) THEN
                x = INSTR(x$, CHR$(c + 64))
                x = ASC(MID$(x$, x, 1))
                IF x >= 65 AND x <= 90 THEN
                    x = x - 64
                    IF c = x THEN

                        GOSUB DisplayDrive
                    END IF
                END IF
            END IF
        ELSE
            IF VarQ = 0 THEN ' list all drives
                GOSUB DisplayDrive
            ELSE
                ' except A: or B:
                IF c >= 3 THEN
                    GOSUB DisplayDrive
                END IF
            END IF
        END IF
        IF h = 20 THEN
            h = 0
            PRINT "-more-";
            DO
                _LIMIT 50
                I$ = INKEY$
                IF LEN(I$) THEN
                    EXIT DO
                END IF
            LOOP
        END IF
    NEXT
    EXIT SUB

    DisplayDrive:
    c$ = CHR$(c + 64)
    Out3 = c$
    IF DRIVEEXISTS(c) = 0 THEN
        h = h + 1
        l = l + 1
        q = -1
        REDIM _PRESERVE Drives(l) AS STRING
        Drives(l) = c$

        ' display volume label
        Out3 = c$
        CALL Vlabel(Out3)
        IF RTRIM$(Out3) = Nul THEN
            z$ = DriveType
        ELSE
            z$ = LEFT$(Out3, 12)
        END IF
        z$ = z$ + SPACE$(13 - LEN(z$))

        REDIM _PRESERVE DriveLabels(l) AS STRING
        DriveLabels(l) = z$

        ' display volume serial number
        Out3 = c$
        CALL Vserial(Out3)
        z$ = LEFT$(Out3, 12)
        z$ = z$ + SPACE$(13 - LEN(z$))

        REDIM _PRESERVE DriveSerials(l) AS STRING
        DriveSerials(l) = z$

        ' display volume file system type
        Out3 = c$
        CALL Vtype(Out3)
        z$ = LEFT$(Out3, 8)
        z$ = z$ + SPACE$(9 - LEN(z$))

        REDIM _PRESERVE DriveType(l) AS STRING
        DriveType(l) = z$

        ' display volume total disk space
        COLOR 11, 0
        CALL TotalSpace(Out3)
        x# = INT(VAL(Out3))
        x1# = x#


        REDIM _PRESERVE DiskTotalSpace(l) AS STRING
        IF x# > 0# THEN
            CALL Suffix(x#, S$) ' 1,024.0 KB
            DiskTotalSpace(l) = S$
        ELSE
            DiskTotalSpace(l) = "<n/a>"
        END IF

        ' display volume free disk space
        Out3 = c$
        CALL FreeSpace(Out3)
        y# = INT(VAL(Out3))
        y1# = y#

        REDIM _PRESERVE DiskFreeSpace(l) AS STRING
        IF y# > 0# THEN
            CALL Suffix(y#, S$) ' 1,024.0 KB
            DiskFreeSpace(l) = S$
        ELSE
            DiskFreeSpace(l) = "<n/a>"
        END IF

        ' display volume used disk space
        REDIM _PRESERVE DiskUsedSpace(l) AS STRING
        IF x1# > 0# OR y1# > 0# THEN
            z# = x1# - y1#
            CALL Suffix(z#, S$) ' 1,024.0 KB
            DiskUsedSpace(l) = S$
        ELSE
            DiskUsedSpace(l) = "<n/a>"
        END IF
    END IF
    RETURN

    '    DriveHeader:
    '    h = 2
    '   RETURN
END SUB

' calculate byte suffix

' formats a double numeric string

' check drive exists.
'  returns -1 if drive not detected.
FUNCTION DRIVEEXISTS (V)
    VarX$ = CHR$(V + 64) + ":\" + CHR$(0)
    VarX = GetDriveType(VarX$)
    DriveType = Nul
    SELECT CASE VarX
        CASE 0
            DriveType = "[UNKNOWN]"
        CASE 1
            DriveType = "[BADROOT]"
        CASE 2
            DriveType = "[REMOVABLE]"
        CASE 3
            DriveType = "[FIXED]"
        CASE 4
            DriveType = "[REMOTE]"
        CASE 5
            DriveType = "[CDROM]"
        CASE 6
            DriveType = "[RAMDISK]"
    END SELECT
    IF VarX > 1 THEN
        DRIVEEXISTS = False
    ELSE
        DRIVEEXISTS = True
    END IF
END FUNCTION

' get drive freespace
SUB FreeSpace (Var$)
    VarX$ = Var$ + ":\" + CHR$(0)
    Var$ = Nul
    IF DriveType = "[CDROM]" THEN
        EXIT SUB
    END IF
    IF DriveType = "[REMOVABLE]" THEN
        EXIT SUB
    END IF
    r = GetDiskFreeSpaceExA(VarX$, free~&&, total~&&, free2~&&)
    IF r THEN
        Var$ = LTRIM$(STR$(free~&&))
    END IF
    EXIT SUB

    r = GetDiskFreeSpaceA(VarX$, sectors&, bytes&, free&, total&)
    IF r THEN
        ' sectors per cluster * bytes per sector * free clusters
        x1# = CDBL(sectors&) * CDBL(bytes&) * CDBL(free&)
        Var$ = LTRIM$(STR$(x1#))
    END IF
END SUB

' get drive totalspace
SUB TotalSpace (Var$)
    VarX$ = Var$ + ":\" + CHR$(0)
    Var$ = Nul
    IF DriveType = "[CDROM]" THEN
        EXIT SUB
    END IF
    IF DriveType = "[REMOVABLE]" THEN
        EXIT SUB
    END IF
    r = GetDiskFreeSpaceExA(VarX$, free~&&, total~&&, free2~&&)
    IF r THEN
        Var$ = LTRIM$(STR$(total~&&))
    END IF
    EXIT SUB

    r = GetDiskFreeSpaceA(VarX$, sectors&, bytes&, free&, total&)
    IF r THEN
        ' sectors per cluster * bytes per sector * total clusters
        x1# = CDBL(sectors&) * CDBL(bytes&) * CDBL(total&)
        Var$ = LTRIM$(STR$(x1#))
    END IF
END SUB

' get volume label
SUB Vlabel (Var$)
    ' Note: in DOS the volume label was 8.3 format,
    '  however, in windows XP+ it is 32 char.

    ' get drive info.
    VarX$ = Var$ + ":\" + CHR$(0)
    Var$ = Nul
    Vname$ = SPACE$(MAX_PATH)
    Fname$ = SPACE$(MAX_PATH)
    R = GetVolumeInformationA(VarX$, Vname$, MAX_PATH, serial~&, empty1~&, empty2~&, Fname$, MAX_PATH)
    IF R THEN
        ' get volume label.
        Var$ = RTRIM$(Vname$)
        v = INSTR(Var$, CHR$(0))
        IF v THEN Var$ = LEFT$(Var$, v - 1)
    END IF
END SUB

' get volume serial number
SUB Vserial (Var$)

    ' get drive info.
    VarX$ = Var$ + ":\" + CHR$(0)
    Var$ = Nul
    Vname$ = SPACE$(MAX_PATH)
    Fname$ = SPACE$(MAX_PATH)
    R = GetVolumeInformationA(VarX$, Vname$, MAX_PATH, serial~&, empty1~&, empty2~&, Fname$, MAX_PATH)
    IF R THEN
        ' serial number.
        Var$ = LEFT$(HEX$(serial~&), 4) + "-" + RIGHT$(HEX$(serial~&), 4)
    END IF
END SUB

' get volume system type
SUB Vtype (Var$)

    ' get drive info.
    VarX$ = Var$ + ":\" + CHR$(0)
    Var$ = Nul
    Vname$ = SPACE$(MAX_PATH)
    Fname$ = SPACE$(MAX_PATH)
    R = GetVolumeInformationA(VarX$, Vname$, MAX_PATH, serial~&, empty1~&, empty2~&, Fname$, MAX_PATH)
    IF R THEN
        ' get volume system type.
        Var$ = RTRIM$(Fname$)
        v = INSTR(Var$, CHR$(0))
        IF v THEN Var$ = LEFT$(Var$, v - 1)
    END IF
END SUB

SUB Filtruj (maska AS STRING) 'prepise FileCount podle predimenzovaneho poctu zanamu do poli FileNames, FileSize, DateTimeFile a ShortNameFile. Zaznamy adresaru zustanou stejne!
    DIM NewFileNames(1) AS STRING 'is for mask using. There was problem if is mask used directly, so this SUB is filtering all records in arrays for correct mask if is used.
    DIM NewFileSize(1) AS DOUBLE
    DIM NewDateTimeFile(1) AS STRING * 19
    DIM NewShortNameFile(1) AS STRING
    DIM NewAttrib(1) AS STRING
    '    new = 1

    F$ = RIGHT$(maska$, 4): IF LEFT$(F$, 1) <> "." THEN BEEP: EXIT SUB 'invalid mask
    FOR test = 1 TO FileCount
        FileMask$ = RIGHT$(Filenames(test), 4)
        IF FileMask$ = F$ THEN
            New = New + 1
            REDIM _PRESERVE NewFileNames(New) AS STRING
            REDIM _PRESERVE NewFileSize(New) AS DOUBLE
            REDIM _PRESERVE NewDateTimeFile(New) AS STRING * 19
            REDIM _PRESERVE NewShortNameFile(New) AS STRING
            REDIM _PRESERVE NewAttrib(New) AS STRING
            NewFileNames(New) = Filenames(test)
            NewFileSize(New) = FileSize(test)
            NewDateTimeFile(New) = DateTimeFile(test)
            NewShortNameFile(New) = ShortNameFile(test)

            'PRINT UBOUND(attrib), UBOUND(newattrib): SLEEP
            'NewAttrib(New) = Attrib(DirCount + New)

        END IF
    NEXT test
    FileCount = New
    REDIM Filenames(1) AS STRING
    REDIM FileSize(1) AS DOUBLE
    REDIM DateTimeFile(1) AS STRING * 19
    REDIM ShortNameFile(1) AS STRING
    '    REDIM Attrib(1) AS STRING

    ' REDIM _PRESERVE NewAttrib(UBOUND(newattrib) + DirCount) AS STRING
    '   FOR DirAttrib = 1 TO DirCount
    ' NewAttrib(DirAttrib) = Attrib(DirAttrib)
    ' NEXT

    FOR ReWrite = 1 TO New

        REDIM _PRESERVE Filenames(ReWrite) AS STRING
        REDIM _PRESERVE FileSize(ReWrite) AS DOUBLE
        REDIM _PRESERVE DateTimeFile(ReWrite) AS STRING * 19
        REDIM _PRESERVE ShortNameFile(ReWrite) AS STRING
        REDIM _PRESERVE Attrib(DirCount + ReWrite) AS STRING

        Filenames(ReWrite) = NewFileNames(ReWrite)
        FileSize(ReWrite) = NewFileSize(ReWrite)
        DateTimeFile(ReWrite) = NewDateTimeFile(ReWrite)
        ShortNameFile(ReWrite) = NewShortNameFile(ReWrite)
        Attrib(ReWrite) = NewAttrib(ReWrite)
    NEXT ReWrite
END SUB




