REM file: Stree.bas - QB64 Utility v1.1a PD 2016.

' default integer variables
DEFINT A-Z
REM $DYNAMIC
_TITLE "STREE"

' define boolean values
CONST True = -1
CONST TrueD = -1#
CONST False = 0
CONST FalseD = 0#
CONST FalseS = 0!
CONST NUL = ""

' define color values
CONST Black = 0
CONST Cyan = 11
CONST Green = 10
CONST Magenta = 12
CONST Plain = 7
CONST Red = 12
CONST White = 15
CONST Yellow = 14

' declare date\time variables
DIM SHARED Creation.Time AS INTEGER
DIM SHARED Access.Time AS INTEGER
DIM SHARED Modified.Time AS INTEGER

' declare work variables
DIM SHARED Search.Archive AS INTEGER, Search.Hidden AS INTEGER
DIM SHARED Search.Readonly AS INTEGER, Search.System AS INTEGER
DIM SHARED Recurse.Directories AS INTEGER, Attribute AS INTEGER
DIM SHARED Extended.List AS INTEGER, Display.Errors AS INTEGER
DIM SHARED Continuous.Display AS INTEGER, Directories.Counted AS SINGLE
DIM SHARED Display.Lines AS INTEGER, Display.Lowercase AS INTEGER
DIM SHARED Drive.Search AS STRING * 1, Current.Drive AS STRING * 1
DIM SHARED Nested.Levels AS INTEGER, Nested.Recurse AS INTEGER
DIM SHARED Short.Filenames AS INTEGER, Short.Display AS INTEGER
DIM SHARED Wide.Display AS INTEGER, Display.Length AS INTEGER
DIM SHARED Truncate.Slash AS INTEGER, Strip.Drive AS INTEGER
DIM SHARED Check.Root AS INTEGER, First.Dir AS INTEGER, Length AS INTEGER
DIM SHARED Quit.Searching AS INTEGER, More.Display AS INTEGER
DIM SHARED Append.Slash AS INTEGER, Wide.Display2 AS INTEGER

' declare command line work variables
DIM SHARED Command.Line AS STRING
DIM SHARED Command.Work AS STRING
DIM SHARED Last.Switch AS INTEGER

' declare library constants.
CONST MAX_PATH = 260
CONST INVALID_HANDLE_VALUE = -1

' declare library structures.
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 external libraries.
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)
END DECLARE

DECLARE LIBRARY
    FUNCTION GetModuleFileNameA (BYVAL Module AS LONG, FileName AS STRING, BYVAL nSize AS LONG)
END DECLARE

' declare library variables.
DIM SHARED SysTime AS SYSTEMTIME

' declare standard error trap
ON ERROR GOTO Error.Routine

' reset counters
Directories.Counted = FalseS
Display.Lines = False
Continuous.Display = False
Quit.Searching = False

' get current drive
Current.Drive = LEFT$(GetD$, 1)

' check command line
IF COMMAND$ = "/?" THEN
    GOSUB Boot.Usage
    END
END IF

' display header
GOSUB Header

' command line input loop
IF COMMAND$ = NUL THEN
    COLOR White, Black
    PRINT "Dir spec: ";
    LINE INPUT Command.Line
    DO
        COLOR White, Black
        PRINT "Switches(?=list): ";
        LINE INPUT Var$
        IF Var$ = "?" THEN
            GOSUB Boot.Usage
        ELSE
            Command.Line = Command.Line + Var$
            EXIT DO
        END IF
    LOOP
ELSE
    Command.Line = COMMAND$
END IF

' store command line
Command.Line = RTRIM$(Command.Line)

' check command line switches
Search.Archive = ParseLine("/A")
Append.Slash = ParseLine("/B")
Continuous.Display = ParseLine("/C")
Extended.List = ParseLine("/E")
Short.Display = ParseLine("/F")
Search.Hidden = ParseLine("/H")
Search.Readonly = ParseLine("/O")
Search.System = ParseLine("/S")
Display.Lowercase = ParseLine("/Y")
Strip.Drive = ParseLine("/U")
Short.Filenames = ParseLine("/V")
Wide.Display2 = ParseLine("/W1")
Wide.Display = ParseLine("/W")
Truncate.Slash = ParseLine("/X")
Display.Errors = ParseLine("/Z")

' force recursion
Recurse.Directories = True
Var = ParseLine("/R")
IF Var THEN
    Recurse.Directories = False
END IF

' reset some display variables
IF Wide.Display THEN
    Extended.List = False
    Short.Display = True
    Short.Filenames = True
END IF

' get extended date\time switches
Creation.Time = ParseLine("/1")
Access.Time = ParseLine("/2")
Modified.Time = ParseLine("/3")
IF Creation.Time = False THEN
    IF Access.Time = False THEN
        IF Modified.Time = False THEN
            Modified.Time = True
        END IF
    END IF
END IF

' get nested switch from command line
Nested.Levels = 256%
Imbedded = INSTR(UCASE$(Command.Line), "/N")
IF Imbedded THEN
    Var = LastSwitch(Imbedded)
    Command.Line = LEFT$(Command.Line, Imbedded - 1) + MID$(Command.Line, Imbedded + 2)
    GOSUB Get.Numeric
    Nested.Recurse = Var%
END IF

' recheck command line
IF INSTR(Command.Line, "/") THEN
    GOTO Boot.Error
END IF

' check trailing command line
Command.Line = RTRIM$(Command.Line)
IF Last.Switch THEN
    IF LEN(Command.Line) > Last.Switch THEN
        GOTO Boot.Error
    END IF
END IF

' remove blanks from command line
Command.Line = RTRIM$(Command.Line)
Command.Line = LTRIM$(Command.Line)

' store entire command
Command.Work = Command.Line

' filename processing loop
DO
    ' store entire command
    Imbedded = INSTR(Command.Line, " ")
    IF Imbedded THEN
        Command.Work = LEFT$(Command.Line, Imbedded - 1)
        Command.Line = MID$(Command.Line, Imbedded + 1)
    ELSE
        Command.Work = Command.Line
        Command.Line = NUL
    END IF
    Command.Line = LTRIM$(Command.Line)
    Command.Line = RTRIM$(Command.Line)

    ' store current drive
    IF MID$(Command.Work, 2, 1) = ":" THEN
        Drive.Search = LEFT$(Command.Work, 1)
        Command.Work = MID$(Command.Work, 3)
    ELSE
        Drive.Search = Current.Drive
    END IF
    Drive.Search = UCASE$(Drive.Search)

    ' store current directory
    Directory.Search$ = MID$(GetD$, 3)
    IF Command.Work <> NUL THEN
        IF Directory.Search$ = "\" + Command.Work THEN
            Directory.Search$ = "\" + Command.Work
        ELSE
            IF LEFT$(Command.Work, 1) <> "\" THEN
                IF Directory.Search$ = "\" THEN
                    Directory.Search$ = "\" + Command.Work
                ELSE
                    Directory.Search$ = Directory.Search$ + "\" + Command.Work
                END IF
            ELSE
                Directory.Search$ = Command.Work
            END IF
        END IF
    END IF

    ' display search header
    IF Continuous.Display = False THEN
        COLOR Yellow, Black
        Display.Lines = Display.Lines + 1
        PRINT "Searching: " + Directory.Search$
    END IF

    ' call subroutine to search directories
    CALL Directories(Directory.Search$)

    ' check search filename
    IF Command.Line = NUL THEN
        EXIT DO
    END IF

    ' check quit searching
    IF Quit.Searching THEN
        EXIT DO
    END IF
LOOP
End.Stree:

' display counters
IF Continuous.Display = False THEN
    IF Wide.Display THEN
        IF Display.Length THEN
            PRINT
        END IF
    END IF
    COLOR Yellow, Black
    PRINT "Directories counted"; Directories.Counted
    COLOR White, Black
    Prompt$ = "Press any key to exit:"
    PRINT Prompt$;
    DO
        _LIMIT 50
        LOCATE , , 1
        IF INKEY$ <> NUL THEN
            COLOR Plain, Black
            SYSTEM
        END IF
    LOOP
END IF
COLOR Plain, Black
END

' make header
Header:
IF Header.Flag THEN
    RETURN
END IF
Header.Flag = True
IF Continuous.Display = False THEN
    COLOR White, Black
    PRINT "Stree v1.1a: Directory search utility;"
END IF
RETURN

Get.Numeric:
Var% = False
DO
    Temp$ = MID$(Command.Line, Imbedded, 1)
    IF Temp$ >= "0" AND Temp$ <= "9" THEN
        Var% = Var% * 10 + VAL(Temp$)
        Command.Line = LEFT$(Command.Line, Imbedded - 1) + MID$(Command.Line, Imbedded + 1)
    ELSE
        EXIT DO
    END IF
LOOP
RETURN

' display program usage
Boot.Usage:
' make header
COLOR White, Black
PRINT "Stree v1.1a: Directory search utility;"
COLOR Yellow, Black
PRINT "Usage:"
PRINT "   Stree [d:\path\][/ahos][/bcefnruvwxyz][/123]"
PRINT "Where:"
PRINT "   /b  append slash         /c  continuous display"
PRINT "   /e  extended display     /f  short filename display"
PRINT "   /r  prevent recurse      /u  strip leading drive letter"
PRINT "   /v  use 8.3 filenames    /w  wide list display"
PRINT "   /w1 prepend slash        /x  truncate slash"
PRINT "   /y  lowercase display    /z  suppress errors"
PRINT "   /nxxx  recurse levels override"
PRINT "   display directory ranges:"
PRINT "      /1  creation, /2 accessed, /3 modified"
PRINT "   display directory attributes:"
PRINT "      /a  archive, /h  hidden, /o  read-only, /s  system"
COLOR Plain, Black
RETURN
END

Boot.Error:
COLOR White, Black
PRINT "Command line error. Type Stree /? for help."
COLOR Plain, Black
END

' critical error trap
Error.Routine:
DataError = ERR
IF Display.Errors THEN
    RESUME NEXT
END IF
IF Wide.Display THEN
    IF Display.Length THEN
        Display.Length = False
        PRINT
    END IF
END IF
COLOR Green, Black
PRINT "Critical error:"; DataError; " IDE line:"; _ERRORLINE
Prompt$ = "Press R to retry, Q to quit, C to continue:"
CALL MorePrompt(Prompt$, "rqc", Outpt$)
SELECT CASE Outpt$
    CASE "r"
        RESUME
    CASE "q"
        RESUME End.Stree
    CASE "c"
        RESUME NEXT
END SELECT
COLOR Plain, Black
END 0

' subroutine to access directories
SUB Directories (Directory.Search$)
' declare subroutine variables
'  local only to this subroutine for recursion.
DIM ASCIIZ AS STRING * 260
DIM finddata AS WIN32_FIND_DATAA
DIM Wfile.Handle AS _UNSIGNED _OFFSET

' make directory filename
Temp.Dir$ = Directory.Search$
IF RIGHT$(Temp.Dir$, 1) <> "\" THEN
    Temp.Dir$ = Temp.Dir$ + "\"
END IF
Temp.Dir$ = Temp.Dir$ + "*.*"
ASCIIZ = Temp.Dir$ + CHR$(0)

' find first long filename
Wfile.Handle = FindFirstFileA(_OFFSET(ASCIIZ), _OFFSET(finddata))

' check findirst error
IF Wfile.Handle <> INVALID_HANDLE_VALUE THEN

    ' filename/directory loop
    DO

        ' check quit searching
        IF Quit.Searching THEN
            ' close long filename search
            x = FindClose(Wfile.Handle)
            EXIT SUB
        END IF

        ' get file attributes
        Attribute = finddata.dwFileAttributes

        ' check directory attribute
        IF (Attribute AND &H10) = &H10 THEN

            ' check to recurse directories
            IF Recurse.Directories = 0 THEN
                ' store directory name
                Directory$ = finddata.cFileName
                V = INSTR(Directory$, CHR$(0))
                IF V THEN Directory$ = LEFT$(Directory$, V - 1)

                ' display directory
                GOSUB Display.Directory
            END IF

            ' check to recurse directories
            IF Recurse.Directories THEN

                ' store directory name
                Directory$ = finddata.cFileName
                V = INSTR(Directory$, CHR$(0))
                IF V THEN Directory$ = LEFT$(Directory$, V - 1)

                ' check directory name
                Valid.Flag = -1
                IF Directory$ = "." THEN
                    Valid.Flag = 0
                END IF
                IF Directory$ = ".." THEN
                    Valid.Flag = 0
                END IF
                IF Directory$ = NUL THEN
                    Valid.Flag = 0
                END IF
                IF Valid.Flag THEN

                    ' display directory
                    GOSUB Display.Directory

                    ' check recursion levels
                    Recursion% = True
                    IF Nested.Recurse > False THEN
                        Nested.Levels = Nested.Levels + 1
                        IF Nested.Levels >= Nested.Recurse THEN
                            Recursion% = False
                        END IF
                    END IF

                    ' recursively search subdirectories
                    IF Recursion% THEN
                        CALL Directories(Next.Directory$)
                    END IF
                    IF Nested.Recurse > False THEN
                        Nested.Levels = Nested.Levels - 1
                    END IF
                END IF
            END IF
        END IF

        ' find next long filename
        IF FindNextFileA(Wfile.Handle, _OFFSET(finddata)) = 0 THEN
            ' close long filename search
            x = FindClose(Wfile.Handle)
            EXIT DO
        END IF
    LOOP
END IF
EXIT SUB

Display.Directory:
' make next search directory
IF RIGHT$(Directory.Search$, 1) <> "\" THEN
    Next.Directory$ = Directory.Search$ + "\" + Directory$
ELSE
    Next.Directory$ = Directory.Search$ + Directory$
END IF

Display.Directory2:
' store directory name
Temp.Directory$ = finddata.cFileName
V = INSTR(Temp.Directory$, CHR$(0))
IF V THEN Temp.Directory$ = LEFT$(Temp.Directory$, V - 1)

IF Temp.Directory$ = NUL THEN
    RETURN
END IF
IF Temp.Directory$ = "." THEN
    RETURN
END IF
IF Temp.Directory$ = ".." THEN
    RETURN
END IF
Temp.Directory$ = Next.Directory$

' get short filename
IF Short.Filenames THEN
    Temp.Directory$ = finddata.cAlternateFileName
    V = INSTR(Temp.Directory$, CHR$(0))
    IF V THEN Temp.Directory$ = LEFT$(Temp.Directory$, V - 1)
    IF Temp.Directory$ = NUL THEN
        Temp.Directory$ = finddata.cFileName
        V = INSTR(Temp.Directory$, CHR$(0))
        IF V THEN Temp.Directory$ = LEFT$(Temp.Directory$, V - 1)
    END IF
END IF

' check directory attribute
Valid.Attribute = True

' check for read-only file
IF Search.Readonly THEN
    IF (Attribute AND &H1) <> &H1 THEN
        Valid.Attribute = False
    END IF
END IF

' check for hidden file
IF Search.Hidden THEN
    IF (Attribute AND &H2) <> &H2 THEN
        Valid.Attribute = False
    END IF
END IF

' check for system file
IF Search.System THEN
    IF (Attribute AND &H4) <> &H4 THEN
        Valid.Attribute = False
    END IF
END IF

' check for archive file
IF Search.Archive THEN
    IF (Attribute AND &H20) <> &H20 THEN
        Valid.Attribute = False
    END IF
END IF

' check for valid directory
IF Valid.Attribute THEN

    ' store directory name
    Outpt$ = RTRIM$(Temp.Directory$)
    IF Short.Display THEN
        IF RIGHT$(Outpt$, 1) = "\" THEN
            Outpt$ = LEFT$(Outpt$, LEN(Outpt$) - 1)
        END IF
        FOR Imbedded = LEN(Outpt$) TO 1 STEP -1
            IF MID$(Outpt$, Imbedded, 1) = "\" THEN
                Outpt$ = MID$(Outpt$, Imbedded + 1)
                EXIT FOR
            END IF
        NEXT
    END IF
    IF Truncate.Slash THEN
        IF Outpt$ <> "\" THEN
            IF RIGHT$(Outpt$, 1) = "\" THEN
                Outpt$ = LEFT$(Outpt$, LEN(Outpt$) - 1)
            END IF
        END IF
    END IF
    IF Short.Filenames = False OR Short.Display THEN
        IF MID$(Outpt$, 2, 1) <> ":" THEN
            IF LEFT$(Directory.Search$, 2) <> "\\" THEN
                Outpt$ = Drive.Search + ":" + Outpt$
            END IF
        END IF
    END IF
    IF LEFT$(Directory.Search$, 2) = "\\" THEN
        IF MID$(Outpt$, 2, 1) = ":" THEN
            Outpt$ = MID$(Outpt$, 3)
        END IF
    END IF
    IF Strip.Drive THEN
        IF MID$(Outpt$, 2, 1) = ":" THEN
            Outpt$ = MID$(Outpt$, 3)
        END IF
    END IF
    IF Display.Lowercase THEN
        Outpt$ = LCASE$(Outpt$)
    END IF

    ' set directory flag
    Flag = True

    ' display directory
    IF Flag THEN
        ' increment directories counted
        Directories.Counted = Directories.Counted + 1!

        ' check wide display output
        IF Wide.Display THEN
            COLOR Yellow, Black
            ' append/prepend slash
            IF Strip.Drive THEN
                IF Wide.Display2 THEN ' prepend
                    IF LEFT$(Outpt$, 1) <> "\" THEN
                        Outpt$ = "\" + Outpt$
                    END IF
                END IF
                IF Append.Slash THEN ' append
                    IF RIGHT$(Outpt$, 1) <> "\" THEN
                        Outpt$ = Outpt$ + "\"
                    END IF
                END IF
            END IF
            Outpt$ = LEFT$(Outpt$, 14)
            PRINT Outpt$;
            PRINT SPACE$(15 - LEN(Outpt$));
            ' count directories in one line
            Display.Length = Display.Length + 1
            IF Display.Length = 5 THEN
                ' reset counters
                PRINT
                Display.Length = False
                Display.Lines = Display.Lines + 1
                GOSUB Page.Prompt
                IF Quit.Searching THEN
                    EXIT SUB
                END IF
            END IF
        ELSE
            ' check slash switch
            IF Append.Slash THEN
                IF RIGHT$(Outpt$, 1) <> "\" THEN
                    Outpt$ = Outpt$ + "\"
                END IF
            END IF

            ' store length of directory name
            Length = LEN(Outpt$)
            ' calculate length variable
            GOSUB Calc.Length

            ' check for overflow past more prompt
            ' before directory displayed
            IF Continuous.Display = False THEN
                ' reset display line counter
                IF Display.Lines > 22 THEN
                    GOSUB Page.Prompt
                    IF Quit.Searching THEN
                        EXIT SUB
                    END IF
                    ' recalculate length
                    GOSUB Calc.Length
                END IF
            END IF

            ' display full directory pathname
            COLOR Yellow, Black
            PRINT Outpt$

            ' check for paginate
            ' after directory displayed
            IF Continuous.Display = False THEN
                GOSUB Page.Prompt
                IF Quit.Searching THEN
                    EXIT SUB
                END IF
            END IF

            ' check output type
            IF Extended.List THEN
                ' display extended directory attributes
                GOSUB Display.List
                ' check for paginate
                ' after extended info displayed
                IF Continuous.Display = False THEN
                    GOSUB Page.Prompt
                    IF Quit.Searching THEN
                        EXIT SUB
                    END IF
                END IF
            END IF
        END IF
    END IF
END IF
RETURN

' check for page length
Page.Prompt:
IF Display.Lines >= 22 THEN
    Display.Lines = False
    IF Continuous.Display = False THEN
        IF More.Display = False THEN
            Prompt$ = "More (y)es/(n)o/(c)ontinuous?"
            CALL MorePrompt(Prompt$, "ync", Outpt2$)
            SELECT CASE Outpt2$
                CASE "c"
                    More.Display = True
                CASE "n"
                    Quit.Searching = True
            END SELECT
        END IF
    END IF
END IF
RETURN

' calculates line length,
' increments total lines displayed
Calc.Length:
IF Length > 240 THEN
    Display.Lines = Display.Lines + 4
ELSE
    IF Length > 160 THEN
        Display.Lines = Display.Lines + 3
    ELSE
        IF Length > 80 THEN
            Display.Lines = Display.Lines + 2
        ELSE
            Display.Lines = Display.Lines + 1
        END IF
    END IF
END IF
RETURN

' routine to display extended directory attributes
Display.List:
Length = False
' store file creation date\time
IF Creation.Time THEN
    x& = FileTimeToSystemTime&(finddata.ftCreationTime, SysTime)
    GOSUB Convert.Date
    GOSUB Convert.Time
    Outpt$ = File.Date$ + " " + File.Time$
    Length = Length + LEN(Outpt$)
    GOSUB Line.Check
    COLOR Red, Black
    PRINT Outpt$;
END IF
IF Access.Time THEN
    x& = FileTimeToSystemTime&(finddata.ftLastAccessTime, SysTime)
    GOSUB Convert.Date
    GOSUB Convert.Time
    IF Creation.Time THEN
        Length = Length + 1
        GOSUB Line.Check
        COLOR White, Black
        PRINT "\";
    END IF
    Outpt$ = File.Date$ + " " + File.Time$
    Length = Length + LEN(Outpt$)
    GOSUB Line.Check
    COLOR Red, Black
    PRINT Outpt$;
END IF
IF Modified.Time THEN
    x& = FileTimeToSystemTime&(finddata.ftLastWriteTime, SysTime)
    GOSUB Convert.Date
    GOSUB Convert.Time
    IF Creation.Time OR Access.Time THEN
        Length = Length + 1
        GOSUB Line.Check
        COLOR White, Black
        PRINT "\";
    END IF
    Outpt$ = File.Date$ + " " + File.Time$
    Length = Length + LEN(Outpt$)
    GOSUB Line.Check
    COLOR Red, Black
    PRINT Outpt$;
END IF

' display file attributes
IF (Attribute AND &H1) = &H1 THEN
    Outpt$ = " Read-only"
    Length = Length + LEN(Outpt$)
    GOSUB Line.Check
    COLOR White, Black
    PRINT Outpt$;
END IF
IF (Attribute AND &H2) = &H2 THEN
    Outpt$ = " Hidden"
    Length = Length + LEN(Outpt$)
    GOSUB Line.Check
    COLOR White, Black
    PRINT Outpt$;
END IF
IF (Attribute AND &H4) = &H4 THEN
    Outpt$ = " System"
    Length = Length + LEN(Outpt$)
    GOSUB Line.Check
    COLOR White, Black
    PRINT Outpt$;
END IF
IF (Attribute AND &H20) = &H20 THEN
    Outpt$ = " Archive"
    Length = Length + LEN(Outpt$)
    GOSUB Line.Check
    COLOR White, Black
    PRINT Outpt$;
END IF
IF Length THEN
    PRINT
END IF
Display.Lines = Display.Lines + Temp.Lines
RETURN

Convert.Date:
File.Date$ = RIGHT$("00" + LTRIM$(STR$(SysTime.wMonth)), 2) + "-"
File.Date$ = File.Date$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wDay)), 2) + "-"
File.Date$ = File.Date$ + LTRIM$(STR$(SysTime.wYear))
RETURN

Convert.Time:
File.Time$ = RIGHT$("00" + LTRIM$(STR$(SysTime.wHour)), 2) + ":"
File.Time$ = File.Time$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wMinute)), 2) + ":"
File.Time$ = File.Time$ + RIGHT$("00" + LTRIM$(STR$(SysTime.wSecond)), 2)
RETURN

' check for page length
Line.Check:
' calculate lines past current line display counter
IF Length THEN
    Temp.Lines = 1
    IF Length > 80 THEN
        Temp.Lines = 2
    END IF
END IF
' check overflow past line 22
IF Display.Lines + Temp.Lines > 22 THEN
    ' page break
    IF Length THEN
        IF Continuous.Display = False THEN
            PRINT
        END IF
    END IF
    ' reset counters
    Length = False
    Display.Lines = False
    IF Continuous.Display = False THEN
        IF More.Display = False THEN
            ' prompt for more
            Prompt$ = "More (y)es/(n)o/(c)ontinuous?"
            CALL MorePrompt(Prompt$, "ync", Outpt2$)
            SELECT CASE Outpt2$
                CASE "c"
                    More.Display = True
                CASE "n"
                    Quit.Searching = True
            END SELECT
        END IF
    END IF
END IF
RETURN
END SUB

SUB MorePrompt (Input.String$, Input.Mask$, Output.String$)
COLOR White, Black
PRINT Input.String$ + " ";
Input.Char$ = NUL
DO
    DO
        _LIMIT 50
        LOCATE , , 1
        Input.Char$ = INKEY$
        IF LEN(Input.Char$) THEN
            EXIT DO
        END IF
    LOOP
    Input.Char$ = LCASE$(Input.Char$)
    IF INSTR(Input.Mask$, Input.Char$) THEN
        PRINT Input.Char$
        Output.String$ = Input.Char$
        EXIT DO
    END IF
LOOP
END SUB

' command line switch position function.
FUNCTION LastSwitch (Var)
IF Last.Switch = 0 THEN
    Last.Switch = Var - 1
ELSE
    IF Var < Last.Switch THEN
        Last.Switch = Var - 1
    END IF
END IF
END FUNCTION

' command line parser
FUNCTION ParseLine (X$)
Imbedded = INSTR(Command.Line, LCASE$(X$))
IF Imbedded THEN
    Command.Line = LEFT$(Command.Line, Imbedded - 1) + MID$(Command.Line, Imbedded + LEN(X$))
    Last.Switch = Imbedded - 1
    ParseLine = True
ELSE
    Imbedded = INSTR(Command.Line, UCASE$(X$))
    IF Imbedded THEN
        Command.Line = LEFT$(Command.Line, Imbedded - 1) + MID$(Command.Line, Imbedded + LEN(X$))
        Last.Switch = Imbedded - 1
        ParseLine = True
    ELSE
        ParseLine = False
    END IF
END IF
END FUNCTION

' get current directory.
FUNCTION GetD$
F$ = SPACE$(MAX_PATH)
R = GetModuleFileNameA(0, F$, LEN(F$))
IF R THEN
    F$ = LEFT$(F$, R)
    IF INSTR(F$, CHR$(0)) THEN
        F$ = LEFT$(F$, INSTR(F$, CHR$(0)) - 1)
    END IF
    GetD$ = RTRIM$(F$)
    FOR s = LEN(GetD$) TO 1 STEP -1
        IF MID$(GetD$, s, 1) = "\" THEN
            GetD$ = LEFT$(GetD$, s - 1)
            EXIT FOR
        END IF
    NEXT
    IF RIGHT$(GetD$, 1) <> "\" THEN
        IF LEN(GetD$) = 2 THEN
            GetD$ = GetD$ + "\"
        END IF
    END IF
    EXIT FUNCTION
END IF
GetD$ = "C:\"
END FUNCTION

