REM Hexed v2.8a, Module 2 of 2, PD 2003.

' get include file.
REM $INCLUDE: 'hexedit.inc'

REM Define subroutines.

' routine to read in custom config file variables.
' searchs current path, environment path, then path statement.
SUB ReadConfigFile (Var$)
 ' declare error trap.
 ON LOCAL ERROR GOTO Error.Routine

 ' search current directory.
 Config.Filename$ = ConfigFile
 IF DIR$(Config.Filename$) <> Nul THEN
    GOTO ReadFile2
 END IF
 ' search environment data file.
 File$ = ENVIRON$("HEXEDIT")
 IF LEN(File$) THEN
    File$ = RTRIM$(File$)
    File$ = LTRIM$(File$)
    IF RIGHT$(File$, 1) <> "\" THEN
       File$ = File$ + "\"
    END IF
    Config.Filename$ = File$ + ConfigFile
    IF DIR$(Config.Filename$) <> Nul THEN
       GOTO ReadFile2
    END IF
 END IF
 ' search path statement.
 Path$ = ENVIRON$("PATH")
 DO
    ' parse path.
    Parse = INSTR(Path$, ";")
    IF Parse THEN
       File$ = LEFT$(Path$, Parse - 1)
       Path$ = MID$(Path$, Parse + 1)
    ELSE
       File$ = Path$
       Path$ = Nul
    END IF
    ' store filename.
    File$ = RTRIM$(File$)
    File$ = LTRIM$(File$)
    IF LEN(File$) THEN
       IF RIGHT$(File$, 1) <> "\" THEN
          File$ = File$ + "\"
       END IF
       Config.Filename$ = File$ + ConfigFile
       IF DIR$(Config.Filename$) <> Nul THEN
          GOTO ReadFile2
       END IF
    ELSE
       EXIT DO
    END IF
 LOOP
 EXIT SUB

' read in the data file
ReadFile2:
 ' open filename.
 ErrorTrap = False
 CLOSE #1
 OPEN Config.Filename$ FOR INPUT AS #1
 IF ErrorTrap THEN
    EXIT SUB
 END IF
 ' read input lines.
 DO WHILE NOT EOF(1)
    LINE INPUT #1, FileLine$
    FileLine2$ = FileLine$
    ' remove spaces.
    FileLine$ = TrimSpaces$(FileLine$)
    ' check for comment.
    IF LEFT$(FileLine$, 1) = ";" THEN
       FileLine$ = Nul
    END IF
    ' check assignment value.
    Parse = INSTR(FileLine$, "=")
    ' parse off left/right sides.
    IF Parse THEN
       ' get left/right side values.
       Char$ = LEFT$(FileLine$, Parse - 1)
       Setting$ = MID$(FileLine$, Parse + 1)
       ' get right side value for filenames
       ' enclosed in quotes containing spaces.
       Parse = INSTR(FileLine2$, "=")
       Setting2$ = MID$(FileLine2$, Parse + 1)
       Setting2$ = RTRIM$(Setting2$)
       Setting2$ = LTRIM$(Setting2$)
       ' check length of values.
       IF LEN(Char$) > 0 AND LEN(Setting$) > 0 THEN
          SELECT CASE UCASE$(Char$)
          ' check config filenames.
          CASE "DUMPFILE"
             DumpFile = Setting$
          CASE "EDITFILE"
             Var$ = Setting2$
          ' check environment replacement variables.
          CASE "HEXSCREEN"
             SELECT CASE UCASE$(Setting$)
             CASE "OFF", "0", "FALSE"
                ScreenRow = True
             CASE "ON", "-1", "TRUE"
                ScreenRow = False
             END SELECT
          CASE "HEXSORT"
             SELECT CASE UCASE$(Setting$)
             CASE "OFF", "0", "FALSE"
                HeapSortOff = True
             CASE "ON", "-1", "TRUE"
                HeapSortOff = False
             END SELECT
          CASE ELSE
             ' check ascii value.
             NewValue = INT(VAL(Setting$))
             IF NewValue >= False AND NewValue <= 255 THEN
                SELECT CASE UCASE$(Char$)
                CASE "HLINE"
                   Hline = NewValue
                CASE "VLINE"
                   Vline = NewValue
                CASE "ULCORNER"
                   ULcorner = NewValue
                CASE "URCORNER"
                   URcorner = NewValue
                CASE "LLCORNER"
                   LLcorner = NewValue
                CASE "LRCORNER"
                   LRcorner = NewValue
                END SELECT
             END IF
          END SELECT
       END IF
    END IF
 LOOP
TopProgram:
 CLOSE #1
 EXIT SUB

' critical error trap.
Error.Routine:
 IF ScreenDrawn THEN
    CLS
 END IF
 ScreenDrawn = False
 COLOR White
 PRINT "Hex Editor ReadConfigFile " + Version + " " + Release + " critical error trap:"
 COLOR Yellow
 ErrorTrap = ERR
 SELECT CASE ERR
 CASE 5
    PRINT "Syntax error." ' should not happen.
 CASE 9
    PRINT "Subscript out of range."
 CASE 14
    PRINT "Out of string space."
 CASE 24
    PRINT "Device timeout."
 CASE 25
    PRINT "Device fault."
 CASE 27
    PRINT "Out of paper."
 CASE 52
    PRINT "Bad file name or number."
 CASE 53
    PRINT "File not found."
 CASE 54
    PRINT "Bad file mode."
 CASE 55
    PRINT "File already open."
 CASE 57
    PRINT "Device I/O error."
 CASE 58
    PRINT "File already exists."
 CASE 59
    PRINT "Bad record length."
 CASE 61
    PRINT "Disk full."
 CASE 62
    PRINT "Input past eof."
 CASE 63
    PRINT "Bad record length."
 CASE 64
    PRINT "Bad filename."
 CASE 67
    PRINT "Not enough file handles."
 CASE 68
    PRINT "Device unavailable."
 CASE 70
    PRINT "Permission denied."
 CASE 71
    PRINT "Disk not ready."
 CASE 72
    PRINT "Disk-media error."
 CASE 75
    PRINT "Path/File access error."
 CASE 76
    PRINT "Pathname not found."
 CASE 81
    PRINT "Invalid name."
 CASE ELSE
    PRINT "Untrapped error" + STR$(ERR) + "."
 END SELECT
 ' display error prompt.
 COLOR Green
 PRINT "Press R(etry), C(ontinue), Q(uit), A(bort):";
 ' get keypress.
 DO
    ErrorRespond$ = Nul
    DO
       ErrorRespond$ = INKEY$
       IF LEN(ErrorRespond$) THEN
          EXIT DO
       END IF
    LOOP
    ' parse key.
    SELECT CASE LCASE$(ErrorRespond$)
    CASE "r"
       PRINT "r"
       RESUME
    CASE "c"
       PRINT "c"
       RESUME NEXT
    CASE "q"
       PRINT "q"
       RESUME TopProgram
    CASE "a"
       PRINT "a"
       EXIT DO
    END SELECT
 LOOP
END SUB

REM Define functions.

' function to release time slice in windows.
FUNCTION ReleaseTime
 ON LOCAL ERROR RESUME NEXT
 IF SupportedCall = False THEN
    InregsX.AX = &H1680
    InregsX.BX = &H0
    CALL InterruptX(&H2F, InregsX, OutregsX)
    IF (OutregsX.AX AND &HFF) = &H80 THEN
       SupportedCall = True
    END IF
 END IF
 ReleaseTime = True
END FUNCTION

' remove spaces from variable.
FUNCTION TrimSpaces$ (Var$)
 ON LOCAL ERROR RESUME NEXT
 Var1$ = Var$
 DO
    Parse = INSTR(Var1$, " ")
    IF Parse THEN
       Var1$ = LEFT$(Var1$, Parse - 1) + MID$(Var1$, Parse + 1)
    ELSE
       EXIT DO
    END IF
 LOOP
 TrimSpaces$ = Var1$
END FUNCTION

' conanicalizes filename.
FUNCTION Conanicalize$ (Var$)
 ON LOCAL ERROR RESUME NEXT
 Var1$ = Var$
 ' strip drive letter.
 Var1$ = UCASE$(Var1$)
 IF MID$(Var1$, 2, 1) = ":" THEN
    Var1$ = MID$(Var1$, 3)
 END IF
 ' strip dos path.
 DO
    Path = INSTR(Var1$, "\")
    IF Path THEN
       Var1$ = MID$(Var1$, Path + 1)
    ELSE
       EXIT DO
    END IF
 LOOP
 ' strip network path.
 DO
    Path = INSTR(Var1$, "/")
    IF Path THEN
       Var1$ = MID$(Var1$, Path + 1)
    ELSE
       EXIT DO
    END IF
 LOOP
 Conanicalize$ = Var1$
END FUNCTION

' test data file exists.
' returns: function=-1 if file exists,
'   or non-existent & can be created.
FUNCTION TestFile(Var$)
 DIM TestASCIIZ AS STRING*261
 TestASCIIZ = Var$ + CHR$(0)
 InregsX.AX = &H4300
 InregsX.DS = VARSEG(TestASCIIZ)
 InregsX.DX = VARPTR(TestASCIIZ)
 CALL InterruptX(&H21, InregsX, OutregsX)
 IF (OutregsX.Flags AND &H1) = &H0 THEN
    TestFile = True
    EXIT FUNCTION
 END IF
 ' check file nonexistent.
 IF (OutregsX.AX) = 2 THEN
    TestFile = True
    EXIT FUNCTION
 END IF
 TestFile = False
END FUNCTION

REM Drop down menu subroutine:

REM Returns: variable CurrentMenu equales 1 to 7, or 0 if exit,
REM  variable CurrentMenuSelection is menu selection in CurrentMenu.

REM Note: Mouse function 'Hide' should be used before any menu write,
REM  then mouse function 'Show' after the display is updated,
REM  this allows the mouse cursor in DOS to be hilighted over any
REM  menu selection or display. Mouse 'Hide' is re-entrant, that is,
REM  multiple calls to mouse 'Hide' are counted, then the same number of
REM  mouse 'Show' functions must be called.

SUB DropDownMenu
 ' declare error trap.
 ON LOCAL ERROR GOTO Error.Routine2
 GOSUB StoreArea
 GOSUB DrawMenu
 GOSUB DrawCurrentMenuSelection

 ' keyboard/mouse input loop.
 DO
    CharInput$ = ""

    ' call mouse subroutine.
    CALL MouseDriver

    ' check left mouse button.
    IF Mouse.Button1 THEN
       GOSUB MouseButton1
    END IF
    ' check right/middle mouse button.
    IF Mouse.Button2 OR Mouse.Button3 THEN
       GOSUB RestoreArea
       CurrentMenu = False
       EXIT SUB
    END IF
    ' check mouse position.
    IF Mouse.Row OR Mouse.Column THEN
       GOSUB MoveMouse
    END IF

    ' store keyboard buffer.
    CharInput$ = INKEY$
    IF LEN(CharInput$) THEN
       SELECT CASE LEN(CharInput$)
       CASE 1
          SELECT CASE ASC(CharInput$)
          CASE 13 ' Enter
             GOSUB RestoreArea
             EXIT SUB
          CASE 27 ' Escape
             GOSUB RestoreArea
             CurrentMenu = False
             EXIT SUB
          END SELECT
       CASE 2
          SELECT CASE ASC(RIGHT$(CharInput$, 1))
          CASE 72 ' Up
             GOSUB MenuUp
          CASE 80 ' Down
             GOSUB MenuDown
          CASE 75 ' Left
             IF FileLength THEN
                GOSUB MenuLeft
             END IF
          CASE 77 ' Right
             IF FileLength THEN
                GOSUB MenuRight
             END IF
          END SELECT
       END SELECT
    END IF
    ' release time slice,
    ' (speeds up mouse in windows).
    Var = ReleaseTime
 LOOP
 EXIT SUB

' moves one menu left, wrapping.
MenuLeft:
 GOSUB RestoreArea
 IF CurrentMenu = 1 THEN
    CurrentMenu = 7
 ELSE
    CurrentMenu = CurrentMenu - 1
 END IF
 GOSUB StoreArea
 GOSUB DrawMenu
 GOSUB DrawCurrentMenuSelection
 RETURN

' moves one menu right, wrapping.
MenuRight:
 GOSUB RestoreArea
 IF CurrentMenu = 7 THEN
    CurrentMenu = 1
 ELSE
    CurrentMenu = CurrentMenu + 1
 END IF
 GOSUB StoreArea
 GOSUB DrawMenu
 GOSUB DrawCurrentMenuSelection
 RETURN

' moves menu up, wrapping.
' selects CurrentMenuSelection variable.
MenuUp:
 SELECT CASE CurrentMenu
 CASE 1
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 1 THEN
       CurrentMenuSelection = 3
    ELSE
       CurrentMenuSelection = CurrentMenuSelection - 1
    END IF
    GOSUB DrawCurrentMenuSelection
 CASE 2
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 1 THEN
       CurrentMenuSelection = 2
    ELSE
       CurrentMenuSelection = CurrentMenuSelection - 1
    END IF
    GOSUB DrawCurrentMenuSelection
 CASE 3
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 1 THEN
       CurrentMenuSelection = 2
    ELSE
       CurrentMenuSelection = CurrentMenuSelection - 1
    END IF
    GOSUB DrawCurrentMenuSelection
 CASE 4
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 1 THEN
       CurrentMenuSelection = 5
    ELSE
       CurrentMenuSelection = CurrentMenuSelection - 1
    END IF
    GOSUB DrawCurrentMenuSelection
 CASE 5
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 1 THEN
       CurrentMenuSelection = 2
    ELSE
       CurrentMenuSelection = CurrentMenuSelection - 1
    END IF
    GOSUB DrawCurrentMenuSelection
 CASE 6
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 1 THEN
       CurrentMenuSelection = 2
    ELSE
       CurrentMenuSelection = CurrentMenuSelection - 1
    END IF
    GOSUB DrawCurrentMenuSelection
 CASE 7
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 1 THEN
       CurrentMenuSelection = 2
    ELSE
       CurrentMenuSelection = CurrentMenuSelection - 1
    END IF
    GOSUB DrawCurrentMenuSelection
 END SELECT
 RETURN

' moves menu down, wrapping.
' selects CurrentMenuSelection variable.
MenuDown:
 SELECT CASE CurrentMenu
 CASE 1
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 3 THEN
       CurrentMenuSelection = 1
    ELSE
       CurrentMenuSelection = CurrentMenuSelection + 1
    END IF
    GOSUB DrawCurrentMenuSelection
 CASE 2
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 2 THEN
       CurrentMenuSelection = 1
    ELSE
       CurrentMenuSelection = CurrentMenuSelection + 1
    END IF
    GOSUB DrawCurrentMenuSelection
 CASE 3
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 2 THEN
       CurrentMenuSelection = 1
    ELSE
       CurrentMenuSelection = CurrentMenuSelection + 1
    END IF
    GOSUB DrawCurrentMenuSelection
 CASE 4
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 5 THEN
       CurrentMenuSelection = 1
    ELSE
       CurrentMenuSelection = CurrentMenuSelection + 1
    END IF
    GOSUB DrawCurrentMenuSelection
 CASE 5
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 2 THEN
       CurrentMenuSelection = 1
    ELSE
       CurrentMenuSelection = CurrentMenuSelection + 1
    END IF
    GOSUB DrawCurrentMenuSelection
 CASE 6
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 2 THEN
       CurrentMenuSelection = 1
    ELSE
       CurrentMenuSelection = CurrentMenuSelection + 1
    END IF
    GOSUB DrawCurrentMenuSelection
 CASE 7
    GOSUB EraseCurrentMenuSelection
    IF CurrentMenuSelection = 2 THEN
       CurrentMenuSelection = 1
    ELSE
       CurrentMenuSelection = CurrentMenuSelection + 1
    END IF
    GOSUB DrawCurrentMenuSelection
 END SELECT
 RETURN

' removes hilight from current menu selection.
EraseCurrentMenuSelection:
 IF Mouse.Present THEN
    CALL MouseFunction(HideMouse, 0)
 END IF
 COLOR White, Black
 GOSUB DisplayCurrentMenuSelection
 COLOR White, Black
 IF Mouse.Present THEN
    CALL MouseFunction(ShowMouse, 0)
 END IF
 RETURN

' adds hilight to current menu selection.
DrawCurrentMenuSelection:
 IF Mouse.Present THEN
    CALL MouseFunction(HideMouse, 0)
 END IF
 COLOR White, Blue
 GOSUB DisplayCurrentMenuSelection
 COLOR White, Black
 IF Mouse.Present THEN
    CALL MouseFunction(ShowMouse, 0)
 END IF
 RETURN

' draws current menu selection.
DisplayCurrentMenuSelection:
 SELECT CASE CurrentMenu
 CASE 1
    SELECT CASE CurrentMenuSelection
    CASE 1
       LOCATE 3, 7, 1
       PRINT "Load new file";
    CASE 2
       LOCATE 4, 7, 1
       PRINT "Toggle window";
    CASE 3
       LOCATE 5, 7, 1
       PRINT "Exit program ";
    END SELECT
 CASE 2
    SELECT CASE CurrentMenuSelection
    CASE 1
       LOCATE 3, 17, 1
       PRINT "ANSI Chart";
    CASE 2
       LOCATE 4, 17, 1
       PRINT "HEX Chart ";
    END SELECT
 CASE 3
    SELECT CASE CurrentMenuSelection
    CASE 1
       LOCATE 3, 27, 1
       PRINT "HEX Screen Dump";
    CASE 2
       LOCATE 4, 27, 1
       PRINT "HEX File Dump  ";
    END SELECT
 CASE 4
    SELECT CASE CurrentMenuSelection
    CASE 1
       LOCATE 3, 37, 1
       PRINT "Append Bytes       ";
    CASE 2
       LOCATE 4, 37, 1
       PRINT "Append ASCII String";
    CASE 3
       LOCATE 5, 37, 1
       PRINT "Redraw Screen      ";
    CASE 4
       LOCATE 6, 37, 1
       PRINT "Undo last byte     ";
    CASE 5
       LOCATE 7, 37, 1
       PRINT "Undo All bytes     ";
    END SELECT
 CASE 5
    SELECT CASE CurrentMenuSelection
    CASE 1
       LOCATE 3, 47, 1
       PRINT "Jump to byte";
    CASE 2
       LOCATE 4, 47, 1
       PRINT "Jump to page";
    END SELECT
 CASE 6
    SELECT CASE CurrentMenuSelection
    CASE 1
       LOCATE 3, 57, 1
       PRINT "HEX Screen Print";
    CASE 2
       LOCATE 4, 57, 1
       PRINT "HEX File Print  ";
    END SELECT
 CASE 7
    SELECT CASE CurrentMenuSelection
    CASE 1
       LOCATE 3, 65, 1
       PRINT "Search string";
    CASE 2
       LOCATE 4, 65, 1
       PRINT "Search bytes ";
    END SELECT
 END SELECT
 RETURN

' draws menu.
DrawMenu:
 CurrentMenuSelection = 1
 GOSUB BoxBorder
 BoxDrawX1 = Xstore1
 BoxDrawX2 = Xstore2
 BoxDrawY1 = Ystore1
 BoxDrawY2 = Ystore2
 SELECT CASE CurrentMenu
 CASE 1
    BoxDrawLength = 15
    GOSUB DrawBox
    COLOR White
    LOCATE 3, 7, 1
    PRINT "Load new file";
    LOCATE 4, 7, 1
    PRINT "Toggle window";
    LOCATE 5, 7, 1
    PRINT "Exit program ";
 CASE 2
    BoxDrawLength = 12
    GOSUB DrawBox
    COLOR White
    LOCATE 3, 17, 1
    PRINT "ANSI Chart";
    LOCATE 4, 17, 1
    PRINT "HEX Chart ";
 CASE 3
    BoxDrawLength = 17
    GOSUB DrawBox
    COLOR White
    LOCATE 3, 27, 1
    PRINT "HEX Screen Dump";
    LOCATE 4, 27, 1
    PRINT "HEX File Dump  ";
 CASE 4
    BoxDrawLength = 21
    GOSUB DrawBox
    COLOR White
    LOCATE 3, 37, 1
    PRINT "Append Bytes       ";
    LOCATE 4, 37, 1
    PRINT "Append ASCII String";
    LOCATE 5, 37, 1
    PRINT "Redraw Screen      ";
    LOCATE 6, 37, 1
    PRINT "Undo last byte     ";
    LOCATE 7, 37, 1
    PRINT "Undo All bytes     ";
 CASE 5
    BoxDrawLength = 14
    GOSUB DrawBox
    COLOR White
    LOCATE 3, 47, 1
    PRINT "Jump to byte";
    LOCATE 4, 47, 1
    PRINT "Jump to page";
 CASE 6
    BoxDrawLength = 18
    GOSUB DrawBox
    COLOR White
    LOCATE 3, 57, 1
    PRINT "HEX Screen Print";
    LOCATE 4, 57, 1
    PRINT "HEX File Print  ";
 CASE 7
    BoxDrawLength = 15
    GOSUB DrawBox
    COLOR White
    LOCATE 3, 65, 1
    PRINT "Search string";
    LOCATE 4, 65, 1
    PRINT "Search bytes ";
 END SELECT
 RETURN

' stores area under menu.
StoreArea:
 IF CurrentMenu = False THEN
    RETURN
 END IF
 IF Mouse.Present THEN
    CALL MouseFunction(HideMouse, 0)
 END IF
 GOSUB BoxBorder
 RowX1 = 0
 ColumnY1 = 0
 FOR RowX2 = Xstore1 TO Xstore2
    RowX1 = RowX1 + 1
    ColumnY1 = 0
    FOR ColumnY2 = Ystore1 TO Ystore2
       ColumnY1 = ColumnY1 + 1
       ' store ascii character.
       Area1(RowX1, ColumnY1) = SCREEN(RowX2, ColumnY2)
       ' store color. (undocumented: also stores background color).
       Area2(RowX1, ColumnY1) = SCREEN(RowX2, ColumnY2, 1)
    NEXT
 NEXT
 ' hilight menu tab.
 COLOR White, Blue
 GOSUB DisplayTab
 IF Mouse.Present THEN
    CALL MouseFunction(ShowMouse, 0)
 END IF
 RETURN

' restores area under menu.
RestoreArea:
 IF CurrentMenu = False THEN
    RETURN
 END IF
 IF Mouse.Present THEN
    CALL MouseFunction(HideMouse, 0)
 END IF
 GOSUB BoxBorder
 RowX1 = 0
 ColumnY1 = 0
 FOR RowX2 = Xstore1 TO Xstore2
    RowX1 = RowX1 + 1
    ColumnY1 = 0
    FOR ColumnY2 = Ystore1 TO Ystore2
       ColumnY1 = ColumnY1 + 1
       LOCATE RowX2, ColumnY2, 1
       ' restore color.
       TempZ = Area2(RowX1, ColumnY1)
       VarB = INT(TempZ / 16)
       VarF = TempZ MOD 16
       COLOR VarF, VarB
       ' restore ascii character.
       PRINT CHR$(Area1(RowX1, ColumnY1));
    NEXT
 NEXT
 ' remove hilight menu tab.
 COLOR White, Black
 GOSUB DisplayTab
 IF Mouse.Present THEN
    CALL MouseFunction(ShowMouse, 0)
 END IF
 RETURN

' returns borders of box.
BoxBorder:
 SELECT CASE CurrentMenu
 CASE 1
    Xstore1 = 2
    Xstore2 = 6
    Ystore1 = 6
    Ystore2 = 20
 CASE 2
    Xstore1 = 2
    Xstore2 = 5
    Ystore1 = 16
    Ystore2 = 27
 CASE 3
    Xstore1 = 2
    Xstore2 = 5
    Ystore1 = 26
    Ystore2 = 42
 CASE 4
    Xstore1 = 2
    Xstore2 = 8
    Ystore1 = 36
    Ystore2 = 56
 CASE 5
    Xstore1 = 2
    Xstore2 = 5
    Ystore1 = 46
    Ystore2 = 59
 CASE 6
    Xstore1 = 2
    Xstore2 = 5
    Ystore1 = 56
    Ystore2 = 73
 CASE 7
    Xstore1 = 2
    Xstore2 = 5
    Ystore1 = 64
    Ystore2 = 78
 END SELECT
 RETURN

' redraws menu tab.
DisplayTab:
 SELECT CASE CurrentMenu
 CASE 1 ' File
    LOCATE 1, 6, 1
    PRINT "File";
 CASE 2 ' Charts
    LOCATE 1, 16, 1
    PRINT "Charts";
 CASE 3 ' Dump
    LOCATE 1, 26, 1
    PRINT "Dump";
 CASE 4 ' Edit
    LOCATE 1, 36, 1
    PRINT "Edit";
 CASE 5 ' Jump
    LOCATE 1, 46, 1
    PRINT "Jump";
 CASE 6 ' Print
    LOCATE 1, 56, 1
    PRINT "Print";
 CASE 7 ' Search
    LOCATE 1, 64, 1
    PRINT "Search";
 END SELECT
 COLOR White, Black
 RETURN

' draws box from (BoxDrawX1,BoxDrawY1) To (BoxDrawX2,BoxDrawY2),
'  length of box from left to right being BoxDrawLength.
DrawBox:
 COLOR Yellow
 LOCATE BoxDrawX1, BoxDrawY1, 1
 PRINT CHR$(ULcorner);STRING$(BoxDrawLength - 2, Hline);CHR$(URcorner);
 FOR RowX1 = BoxDrawX1 + 1 TO BoxDrawX2 - 1
    LOCATE RowX1, BoxDrawY1, 1
    PRINT CHR$(Vline);
    LOCATE RowX1, BoxDRawY2, 1
    PRINT CHR$(Vline);
 NEXT
 LOCATE BoxDrawX2, BoxDrawY1, 1
 PRINT CHR$(LLcorner);STRING$(BoxDrawLength - 2, Hline);CHR$(LRcorner);
 RETURN

' process mouse move.
MoveMouse:
 ' select drop down menu.
 IF Mouse.Row = 1 THEN
    NewMenuSelection = 0
    SELECT CASE Mouse.Column
    CASE 6 TO 9 ' File
       NewMenuSelection = 1
    CASE 16 TO 21 ' Charts
       NewMenuSelection = 2
    CASE 26 TO 29 ' Dump
       NewMenuSelection = 3
    CASE 36 TO 39 ' Edit
       NewMenuSelection = 4
    CASE 46 TO 49 ' Jump
       NewMenuSelection = 5
    CASE 56 TO 60 ' Print
       NewMenuSelection = 6
    CASE 64 TO 69 ' Search
       NewMenuSelection = 7
    END SELECT
    IF NewMenuSelection > False THEN
       IF NewMenuSelection <> CurrentMenu THEN
          IF CurrentMenu > False THEN
             GOSUB RestoreArea
          END IF
          CurrentMenu = NewMenuSelection
          CurrentMenuSelection = 1
          GOSUB StoreArea
          GOSUB DrawMenu
          GOSUB DrawCurrentMenuSelection
       END IF
    END IF
    IF CurrentMenu > False THEN
       IF Mouse.Present THEN
          CALL MouseFunction(HideMouse, 0)
       END IF
       COLOR White, Blue
       GOSUB DisplayTab
       IF Mouse.Present THEN
          CALL MouseFunction(ShowMouse, 0)
       END IF
    END IF
    RETURN
 END IF
 ' check mouse selection boundaries.
 SELECT CASE CurrentMenu
 CASE 1
    IF Mouse.Row >=3 AND Mouse.Row <= 5 THEN
       IF Mouse.Column >= 7 AND Mouse.Column <= 19 THEN
          IF Mouse.Row - 2 <> CurrentMenuSelection THEN
             GOSUB EraseCurrentMenuSelection
             CurrentMenuSelection = Mouse.Row - 2
          END IF
          GOSUB DrawCurrentMenuSelection
       END IF
    END IF
 CASE 2
    IF Mouse.Row >=3 AND Mouse.Row <= 4 THEN
       IF Mouse.Column >= 17 AND Mouse.Column <= 26 THEN
          IF Mouse.Row - 2 <> CurrentMenuSelection THEN
             GOSUB EraseCurrentMenuSelection
             CurrentMenuSelection = Mouse.Row - 2
          END IF
          GOSUB DrawCurrentMenuSelection
       END IF
    END IF
 CASE 3
    IF Mouse.Row >=3 AND Mouse.Row <= 4 THEN
       IF Mouse.Column >= 27 AND Mouse.Column <= 41 THEN
          IF Mouse.Row - 2 <> CurrentMenuSelection THEN
             GOSUB EraseCurrentMenuSelection
             CurrentMenuSelection = Mouse.Row - 2
          END IF
          GOSUB DrawCurrentMenuSelection
       END IF
    END IF
 CASE 4
    IF Mouse.Row >=3 AND Mouse.Row <= 7 THEN
       IF Mouse.Column >= 37 AND Mouse.Column <= 55 THEN
          IF Mouse.Row - 2 <> CurrentMenuSelection THEN
             GOSUB EraseCurrentMenuSelection
             CurrentMenuSelection = Mouse.Row - 2
          END IF
          GOSUB DrawCurrentMenuSelection
       END IF
    END IF
 CASE 5
    IF Mouse.Row >=3 AND Mouse.Row <= 5 THEN
       IF Mouse.Column >= 47 AND Mouse.Column <= 58 THEN
          IF Mouse.Row - 2 <> CurrentMenuSelection THEN
             GOSUB EraseCurrentMenuSelection
             CurrentMenuSelection = Mouse.Row - 2
          END IF
          GOSUB DrawCurrentMenuSelection
       END IF
    END IF
 CASE 6
    IF Mouse.Row >=3 AND Mouse.Row <= 5 THEN
       IF Mouse.Column >= 57 AND Mouse.Column <= 72 THEN
          IF Mouse.Row - 2 <> CurrentMenuSelection THEN
             GOSUB EraseCurrentMenuSelection
             CurrentMenuSelection = Mouse.Row - 2
          END IF
          GOSUB DrawCurrentMenuSelection
       END IF
    END IF
 CASE 7
    IF Mouse.Row >=3 AND Mouse.Row <= 5 THEN
       IF Mouse.Column >= 65 AND Mouse.Column <= 77 THEN
          IF Mouse.Row - 2 <> CurrentMenuSelection THEN
             GOSUB EraseCurrentMenuSelection
             CurrentMenuSelection = Mouse.Row - 2
          END IF
          GOSUB DrawCurrentMenuSelection
       END IF
    END IF
 END SELECT
 RETURN

' process left mouse button.
MouseButton1:
 ExitMouse = False
 IF Mouse.Row - 2 = CurrentMenuSelection THEN
    SELECT CASE CurrentMenu
    CASE 1
       IF Mouse.Column >= 7 AND Mouse.Column <= 19 THEN
          ExitMouse = True
       END IF
    CASE 2
       IF Mouse.Column >= 17 AND Mouse.Column <= 26 THEN
          ExitMouse = True
       END IF
    CASE 3
       IF Mouse.Column >= 27 AND Mouse.Column <= 41 THEN
          ExitMouse = True
       END IF
    CASE 4
       IF Mouse.Column >= 37 AND Mouse.Column <= 55 THEN
          ExitMouse = True
       END IF
    CASE 5
       IF Mouse.Column >= 47 AND Mouse.Column <= 58 THEN
          ExitMouse = True
       END IF
    CASE 6
       IF Mouse.Column >= 57 AND Mouse.Column <= 72 THEN
          ExitMouse = True
       END IF
    CASE 7
       IF Mouse.Column >= 65 AND Mouse.Column <= 77 THEN
          ExitMouse = True
       END IF
    END SELECT

    ' exit subroutine with menu selection.
    IF ExitMouse THEN
       GOSUB RestoreArea
       EXIT SUB
    END IF
 END IF
 RETURN

TopProgram2:
 EXIT SUB

' critical error trap.
Error.Routine2:
 CurrentMenu = False
 IF ScreenDrawn THEN
    CLS
 END IF
 ScreenDrawn = False
 COLOR White
 PRINT "Hex Editor DropDownMenu " + Version + " " + Release + " critical error trap:"
 COLOR Yellow
 ErrorTrap = ERR
 SELECT CASE ERR
 CASE 5
    PRINT "Syntax error." ' should not happen.
 CASE 9
    PRINT "Subscript out of range."
 CASE 14
    PRINT "Out of string space."
 CASE 24
    PRINT "Device timeout."
 CASE 25
    PRINT "Device fault."
 CASE 27
    PRINT "Out of paper."
 CASE 52
    PRINT "Bad file name or number."
 CASE 53
    PRINT "File not found."
 CASE 54
    PRINT "Bad file mode."
 CASE 55
    PRINT "File already open."
 CASE 57
    PRINT "Device I/O error."
 CASE 58
    PRINT "File already exists."
 CASE 59
    PRINT "Bad record length."
 CASE 61
    PRINT "Disk full."
 CASE 62
    PRINT "Input past eof."
 CASE 63
    PRINT "Bad record length."
 CASE 64
    PRINT "Bad filename."
 CASE 67
    PRINT "Not enough file handles."
 CASE 68
    PRINT "Device unavailable."
 CASE 70
    PRINT "Permission denied."
 CASE 71
    PRINT "Disk not ready."
 CASE 72
    PRINT "Disk-media error."
 CASE 75
    PRINT "Path/File access error."
 CASE 76
    PRINT "Pathname not found."
 CASE 81
    PRINT "Invalid name."
 CASE ELSE
    PRINT "Untrapped error" + STR$(ERR) + "."
 END SELECT
 ' display error prompt.
 COLOR Green
 PRINT "Press R(etry), C(ontinue), Q(uit):";
 ' get keypress.
 DO
    ErrorRespond$ = Nul
    DO
       ErrorRespond$ = INKEY$
       IF LEN(ErrorRespond$) THEN
          EXIT DO
       END IF
    LOOP
    ' parse key.
    SELECT CASE LCASE$(ErrorRespond$)
    CASE "r"
       PRINT "r"
       RESUME
    CASE "c"
       PRINT "c"
       RESUME NEXT
    CASE "q"
       PRINT "q"
       RESUME TopProgram2
    END SELECT
 LOOP
END SUB

' subroutine to check mouse activity.
SUB MouseDriver
 ON LOCAL ERROR RESUME NEXT
 Mouse.Button1 = False
 Mouse.Button2 = False
 Mouse.Button3 = False
 ' check mouse present
 IF Mouse.Present = False THEN
    EXIT SUB
 END IF
 ' read middle mouse button.
 CALL MouseFunction(Button, 2)
 IF (OutregsX.AX AND 4) = 4 THEN
    IF OutregsX.BX > 0 THEN
       Mouse.Button3 = True
       Mouse.Row = OutregsX.DX / 8 + 1
       Mouse.Column = OutregsX.CX / 8 + 1
       EXIT SUB
    END IF
 END IF
 ' read right mouse button.
 CALL MouseFunction(Button, 1)
 IF (OutregsX.AX AND 2) = 2 THEN
    IF OutregsX.BX > 0 THEN
       Mouse.Button2 = True
       Mouse.Row = OutregsX.DX / 8 + 1
       Mouse.Column = OutregsX.CX / 8 + 1
       EXIT SUB
    END IF
 END IF
 ' read left mouse button.
 CALL MouseFunction(Button, 0)
 IF (OutregsX.AX AND 1) = 1 THEN
    IF OutregsX.BX > 0 THEN
       Mouse.Button1 = True
       Mouse.Row = OutregsX.DX / 8 + 1
       Mouse.Column = OutregsX.CX / 8 + 1
       EXIT SUB
    END IF
 END IF
 ' read mouse position
 Mouse.Row = False
 Mouse.Column = False
 CALL MouseFunction(Position, 0)
 Var2 = OutregsX.CX / 8 + 1
 Var3 = OutregsX.DX / 8 + 1
 IF Var3 <> Mouse.X OR Var2 <> Mouse.Y THEN
    Mouse.X = Var3
    Mouse.Y = Var2
    Mouse.Row = Mouse.X
    Mouse.Column = Mouse.Y
 END IF
END SUB

SUB MouseFunction (Var1, Var2)
 ' subroutine calls mouse bios function.
 ON LOCAL ERROR RESUME NEXT
 REM INT 33H:
 REM   AX=00 - initialize mouse.
 REM   AX=01 - show mouse cursor.
 REM   AX=02 - hide mouse cursor. (re-entrant).
 REM   AX=03 - return position and button status.
 REM   AX=05 - return button press data.
 InregsX.AX = Var1
 InregsX.BX = Var2
 CALL InterruptX(&H33, InregsX, OutregsX)
END SUB

' structure directory structure function.
FUNCTION Directories$ (Var1%)
 ON LOCAL ERROR RESUME NEXT
 IF Windows.Detected THEN
    GET 3, Var1%, WinFileStruc
    Directories$ = WinFileStruc.Name
 ELSE
    GET 3, Var1%, DosFileStruc
    Directories$ = DosFileStruc.Name
 END IF
END FUNCTION

' structure filename structure function.
FUNCTION Filenames$ (Var1%)
 ON LOCAL ERROR RESUME NEXT
 IF Windows.Detected THEN
    GET 2, Var1%, WinFileStruc
    Filenames$ = WinFileStruc.Name
 ELSE
    GET 2, Var1%, DosFileStruc
    Filenames$ = DosFileStruc.Name
 END IF
END FUNCTION

' File input menu box.
SUB Menu (C$, D$, X$, E$)

' returns:
'   C$  -  Drive letter.
'       Normally C without : or \
'   D$  -  Directory.
'       Without leading or trailing \ (can be null)
'   X$  -  Filespec.
'       Normally *.*
'   E$  -  Filename.
'       Can be long filename.

' concatenate:
'   IF D$="" THEN
'      Filename=C$+":\"+E$
'   ELSE
'      Filename=C$+":\"+D$+"\"+E$
'   END IF

' define simple error routine
ON LOCAL ERROR GOTO Error.Routine3

' test windows
GOSUB TestWindows

' open structure files
GOSUB OpenDataFiles

' display menu screen
GOSUB MainMenu

' get current drive/directory
GOSUB InitDrive
GOSUB InitDir

' read all subdirectories
StartMenu:
Current.Dir = 1
Dir.Box.Line = 1
GOSUB ClearDirBox
GOSUB LoadDirSpec
GOSUB DisplayDirSpec
GOSUB DisplayCurrentDir

' display first ten files
IF D$ = "" THEN
   F$ = C$ + ":\*.*"
ELSE
   F$ = C$ + ":\" + D$ + "\" + "*.*"
END IF
GOSUB ClearFileBox
GOSUB LoadFileSpec
GOSUB DisplayFileSpec
GOSUB DisplayCurrentPath

' main input loop
X$ = "*.*"
LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
PRINT SPACE$(12);
LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
PRINT X$;
DO
   LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
   PRINT SPACE$(12);
   LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
   PRINT X$;
   DO
      I$ = ""
      DO
         I$ = INKEY$
         IF LEN(I$) THEN
            EXIT DO
         END IF
      LOOP
      IF I$ = ":" OR I$ = "\" OR I$ = "/" THEN
         I$ = ""
      END IF
      IF LEN(I$) = 2 THEN
         SELECT CASE ASC(RIGHT$(I$, 1))
         ' F1 changes drive letter.
         CASE 59
            I$ = ""
            LOCATE 2 + Xcoor - 1, Ycoor + 2, 1
            PRINT SPACE$(28);
            LOCATE 2 + Xcoor - 1, Ycoor + 2, 1
            COLOR Yellow, Black
            PRINT "Drive letter: ";
            DO
               Z$ = INKEY$
               IF LEN(Z$) = 1 THEN
                  EXIT DO
               END IF
            LOOP
            Z$ = UCASE$(Z$)
            IF Z$ >= "A" AND Z$ <= "Z" THEN
               ' check drive disk space.
               Check.Disk = True
               Disk.Ready = False
               InregsX.AX = &H3600
               InregsX.DX = ASC(Z$) - 64
               CALL InterruptX(&H21, InregsX, OutregsX)
               Check.Disk = False
               IF Disk.Ready = True THEN
                  GOSUB PromptDisk
               ELSE
                  IF OutregsX.AX = &HFFFF THEN
                     GOSUB PromptDisk
                  ELSE
                     C$ = Z$
                     D$ = ""
                     GOSUB DisplayFilename
                     GOTO StartMenu
                  END IF
               END IF
            END IF
         ' F2 toggles heap sorting.
         CASE 60
            I$ = ""
            HeapSortOff = NOT HeapSortOff
            LOCATE 2 + Xcoor - 1, Ycoor + 2, 1
            PRINT SPACE$(12);
            LOCATE 2 + Xcoor - 1, Ycoor + 2, 1
            COLOR White, Black
            IF HeapSortOff THEN
               PRINT "Sorting Off. Press <esc>:";
            ELSE
               PRINT "Sorting On. Press <esc>:";
            END IF
            WHILE INKEY$<>CHR$(27)
            WEND
            GOSUB DisplayFilename
            COLOR Plain, Black
            PRINT X$;
         END SELECT
         I$ = ""
      END IF
      ' Tab moves to file loop, or
      '   directory loop if there are no files.
      IF I$ = CHR$(9) THEN
         IF Num.Files > 0 THEN
            GOSUB FileInputLoop
         ELSE
            GOSUB DirInputLoop
            IF I$ = CHR$(13) THEN
               I$ = ""
               Current.Dir = 1
               Dir.Box.Line = 1
               GOSUB ClearDirBox
               GOSUB LoadDirSpec
               GOSUB DisplayDirSpec
               GOSUB DisplayCurrentDir
            END IF
            GOSUB DisplayCurrentPath
         END IF
         EXIT DO
      END IF
      IF I$ = CHR$(13) THEN
         I$ = ""
         EXIT DO
      END IF
      IF I$ = CHR$(27) THEN
         EXIT DO
      END IF
      IF I$ = CHR$(8) THEN
         IF LEN(X$) > 0 THEN
            X$ = LEFT$(X$, LEN(X$) - 1)
            LOCATE CSRLIN, POS(0) - 1, 1
            PRINT " ";
            LOCATE CSRLIN, POS(0) - 1, 1
         END IF
      ELSE
         I$ = LTRIM$(I$)
         I$ = RTRIM$(I$)
         I$ = UCASE$(I$)
         IF LEN(X$) < 12 THEN
            PRINT I$;
            X$ = X$ + I$
         END IF
      END IF
   LOOP
   IF I$ = CHR$(27) THEN
      E$ = ""
      EXIT DO
   END IF
   IF I$ = CHR$(13) THEN
      EXIT DO
   END IF
   IF D$ = "" THEN
      F$ = C$ + ":\" + X$
   ELSE
      F$ = C$ + ":\" + D$ + "\" + X$
   END IF
   GOSUB ClearFileBox
   GOSUB LoadFileSpec
   GOSUB DisplayFileSpec
LOOP
COLOR Plain, Black
CLS
EXIT SUB

PromptDisk:
 LOCATE 2 + Xcoor - 1, Ycoor + 2, 1
 PRINT SPACE$(12);
 LOCATE 2 + Xcoor - 1, Ycoor + 2, 1
 COLOR White, Black
 PRINT "Disk not ready. Press <esc>:";
 WHILE INKEY$<>CHR$(27)
 WEND
 GOSUB DisplayFilename
 COLOR Plain, Black
 PRINT X$;
 RETURN

DisplayFilename:
 LOCATE 2 + Xcoor - 1, Ycoor + 2, 1
 PRINT SPACE$(28);
 LOCATE 2 + Xcoor - 1, Ycoor + 2, 1
 COLOR White, Black
 PRINT "Filename: ";
 COLOR Plain, Black
 RETURN

FileInputLoop:
 E$ = Filenames(1)
 E$ = RTRIM$(E$)
 COLOR Plain, Black
 LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
 PRINT SPACE$(12);
 LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
 PRINT LEFT$(E$, 12);
 COLOR Black, Plain
 LOCATE 6 + Xcoor - 1, 4 + Ycoor - 1, 1
 PRINT LEFT$(E$, 12);
 COLOR Plain, Black
 GOSUB DisplayLongName2
 Current.File = 1
 File.Box.Line = 1
 E$ = RTRIM$(Filenames(1))
 I$ = ""
 DO
    DO
       I$ = INKEY$
       IF LEN(I$) THEN
          EXIT DO
       END IF
    LOOP
    ' shift-tab returns to top
    IF LEN(I$) = 2 THEN
       IF ASC(RIGHT$(I$, 1)) = 15 THEN
          I$ = ""
          RETURN
       END IF
    END IF
    ' Tab moves to directory loop
    IF I$ = CHR$(9) THEN
       GOSUB DirInputLoop
       IF I$ = CHR$(9) THEN
          GOSUB DisplayCurrentPath
          RETURN
       END IF
       IF I$ = CHR$(13) THEN
          I$ = ""
          Current.Dir = 1
          Dir.Box.Line = 1
          GOSUB ClearDirBox
          GOSUB LoadDirSpec
          GOSUB DisplayDirSpec
          GOSUB DisplayCurrentDir
          GOSUB DisplayCurrentPath
          RETURN
       END IF
    END IF
    IF I$ = CHR$(13) THEN
       RETURN
    END IF
    IF I$ = CHR$(27) THEN
       RETURN
    END IF
    IF LEN(I$) = 1 THEN
       SELECT CASE I$
       CASE "A" TO "Z", "a" TO "z", "0" TO "9"
       DO
          IF Current.File + 1 <= Num.Files THEN
             IF File.Box.Line < 10 THEN
                LOCATE File.Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
                COLOR Plain, Black
                PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
                File.Box.Line = File.Box.Line + 1
                Current.File = Current.File + 1
                E$ = RTRIM$(Filenames(Current.File))
                COLOR Plain, Black
                LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                PRINT SPACE$(12);
                LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                PRINT LEFT$(E$, 12);
                LOCATE File.Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
                COLOR Black, Plain
                PRINT LEFT$(E$, 12);
                COLOR Plain, Black
                GOSUB DisplayLongName2
             ELSE
                Current.File = Current.File + 1
                E$ = RTRIM$(Filenames(Current.File))
                COLOR Plain, Black
                LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                PRINT SPACE$(12);
                LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                PRINT LEFT$(E$, 12);
                GOSUB ClearFileBox
                COLOR Plain, Black
                FOR V = 1 TO 9
                   LOCATE 15 - V + Xcoor - 1, 4 + Ycoor - 1, 1
                   PRINT LEFT$(RTRIM$(Filenames(Current.File - V)), 12);
                NEXT
                COLOR Black, Plain
                LOCATE 15 + Xcoor - 1, 4 + Ycoor - 1, 1
                PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
                GOSUB DisplayLongName2
             END IF
             IF LEFT$(E$, 1) = I$ THEN
                EXIT DO
             END IF
          ELSE
             EXIT DO
          END IF
       LOOP
       END SELECT
       I$ = ""
    END IF
    IF LEN(I$) = 2 THEN
       V = ASC(RIGHT$(I$, 1))
       SELECT CASE V
       CASE 72 ' up
          IF Current.File - 1 > 0 THEN
             IF File.Box.Line > 1 THEN
                LOCATE File.Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
                COLOR Plain, Black
                PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
                File.Box.Line = File.Box.Line - 1
                Current.File = Current.File - 1
                E$ = RTRIM$(Filenames(Current.File))
                COLOR Plain, Black
                LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                PRINT SPACE$(12);
                LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                PRINT LEFT$(E$, 12);
                LOCATE File.Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
                COLOR Black, Plain
                PRINT LEFT$(E$, 12);
                COLOR Plain, Black
                GOSUB DisplayLongName2
             ELSE
                Current.File = Current.File - 1
                E$ = RTRIM$(Filenames(Current.File))
                COLOR Plain, Black
                LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                PRINT SPACE$(12);
                LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                PRINT LEFT$(E$, 12);
                GOSUB ClearFileBox
                COLOR Plain, Black
                FOR V = 1 TO 9
                   IF Current.File + V <= Num.Files THEN
                      LOCATE 6 + V + Xcoor - 1, 4 + Ycoor - 1, 1
                      PRINT LEFT$(RTRIM$(Filenames(Current.File + V)), 12);
                   END IF
                NEXT
                COLOR Black, Plain
                LOCATE 6 + Xcoor - 1, 4 + Ycoor - 1, 1
                PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
                GOSUB DisplayLongName2
             END IF
          END IF
       CASE 80 ' down
          IF Current.File + 1 <= Num.Files THEN
             IF File.Box.Line < 10 THEN
                LOCATE File.Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
                COLOR Plain, Black
                PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
                File.Box.Line = File.Box.Line + 1
                Current.File = Current.File + 1
                E$ = RTRIM$(Filenames(Current.File))
                COLOR Plain, Black
                LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                PRINT SPACE$(12);
                LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                PRINT LEFT$(E$, 12);
                LOCATE File.Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
                COLOR Black, Plain
                PRINT LEFT$(E$, 12);
                COLOR Plain, Black
                GOSUB DisplayLongName2
             ELSE
                Current.File = Current.File + 1
                E$ = RTRIM$(Filenames(Current.File))
                COLOR Plain, Black
                LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                PRINT SPACE$(12);
                LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                PRINT LEFT$(E$, 12);
                GOSUB ClearFileBox
                COLOR Plain, Black
                FOR V = 1 TO 9
                   LOCATE 15 - V + Xcoor - 1, 4 + Ycoor - 1, 1
                   PRINT LEFT$(RTRIM$(Filenames(Current.File - V)), 12);
                NEXT
                COLOR Black, Plain
                LOCATE 15 + Xcoor - 1, 4 + Ycoor - 1, 1
                PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
                GOSUB DisplayLongName2
             END IF
          END IF
       CASE 73 ' pgup
          IF Current.File - 10 > 0 THEN
             File.Box.Line = 1
             Current.File = Current.File - 10
          ELSE
             File.Box.Line = 1
             Current.File = 1
          END IF
          E$ = RTRIM$(Filenames(Current.File))
          COLOR Plain, Black
          LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
          PRINT SPACE$(12);
          LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
          PRINT LEFT$(E$, 12);
          GOSUB ClearFileBox
          COLOR Plain, Black
          FOR V = 1 TO 9
             IF Current.File + V <= Num.Files THEN
                LOCATE 6 + V + Xcoor - 1, 4 + Ycoor - 1, 1
                PRINT LEFT$(RTRIM$(Filenames(Current.File + V)), 12);
             END IF
          NEXT
          COLOR Black, Plain
          LOCATE 6 + Xcoor - 1, 4 + Ycoor - 1, 1
          PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
          GOSUB DisplayLongName2
       CASE 81 ' pgdn
          IF Current.File + 10 <= Num.Files THEN
             File.Box.Line = 10
             Current.File = Current.File + 10
             E$ = RTRIM$(Filenames(Current.File))
             COLOR Plain, Black
             LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
             PRINT SPACE$(12);
             LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
             PRINT LEFT$(E$, 12);
             GOSUB ClearFileBox
             COLOR Plain, Black
             FOR V = 1 TO 9
                LOCATE 15 - V + Xcoor - 1, 4 + Ycoor - 1, 1
                PRINT LEFT$(RTRIM$(Filenames(Current.File - V)), 12);
             NEXT
             COLOR Black, Plain
             LOCATE 15 + Xcoor - 1, 4 + Ycoor - 1, 1
             PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
             GOSUB DisplayLongName2
          ELSE
             IF Current.File + 1 <= Num.Files THEN
                DO UNTIL Current.File = Num.Files
                   IF File.Box.Line < 10 THEN
                      LOCATE File.Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
                      COLOR Plain, Black
                      PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
                      File.Box.Line = File.Box.Line + 1
                      Current.File = Current.File + 1
                      E$ = RTRIM$(Filenames(Current.File))
                      COLOR Plain, Black
                      LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                      PRINT SPACE$(12);
                      LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                      PRINT LEFT$(E$, 12);
                      LOCATE File.Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
                      COLOR Black, Plain
                      PRINT LEFT$(E$, 12);
                      COLOR Plain, Black
                      GOSUB DisplayLongName2
                   ELSE
                      Current.File = Current.File + 1
                      E$ = RTRIM$(Filenames(Current.File))
                      COLOR Plain, Black
                      LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                      PRINT SPACE$(12);
                      LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                      PRINT LEFT$(E$, 12);
                      GOSUB ClearFileBox
                      COLOR Plain, Black
                      FOR V = 1 TO 9
                         LOCATE 15 - V + Xcoor - 1, 4 + Ycoor - 1, 1
                         PRINT LEFT$(RTRIM$(Filenames(Current.File - V)), 12);
                      NEXT
                      COLOR Black, Plain
                      LOCATE 15 + Xcoor - 1, 4 + Ycoor - 1, 1
                      PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
                      GOSUB DisplayLongName2
                   END IF
                LOOP
             END IF
          END IF
       CASE 71 ' home
          IF Current.File > 1 THEN
             File.Box.Line = 1
             Current.File = 1
          END IF
          E$ = RTRIM$(Filenames(Current.File))
          COLOR Plain, Black
          LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
          PRINT SPACE$(12);
          LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
          PRINT LEFT$(E$, 12);
          GOSUB ClearFileBox
          COLOR Plain, Black
          FOR V = 1 TO 9
             IF Current.File + V <= Num.Files THEN
                LOCATE 6 + V + Xcoor - 1, 4 + Ycoor - 1, 1
                PRINT LEFT$(RTRIM$(Filenames(Current.File + V)), 12);
             END IF
          NEXT
          COLOR Black, Plain
          LOCATE 6 + Xcoor - 1, 4 + Ycoor - 1, 1
          PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
          GOSUB DisplayLongName2
       CASE 79 ' end
          IF Current.File + 1 <= Num.Files THEN
             DO UNTIL Current.File = Num.Files
                IF File.Box.Line < 10 THEN
                   LOCATE File.Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
                   COLOR Plain, Black
                   PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
                   File.Box.Line = File.Box.Line + 1
                   Current.File = Current.File + 1
                   E$ = RTRIM$(Filenames(Current.File))
                   COLOR Plain, Black
                   LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                   PRINT SPACE$(12);
                   LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                   PRINT LEFT$(E$, 12);
                   LOCATE File.Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
                   COLOR Black, Plain
                   PRINT LEFT$(E$, 12);
                   COLOR Plain, Black
                   GOSUB DisplayLongName2
                ELSE
                   Current.File = Current.File + 1
                   E$ = RTRIM$(Filenames(Current.File))
                   COLOR Plain, Black
                   LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                   PRINT SPACE$(12);
                   LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
                   PRINT LEFT$(E$, 12);
                   GOSUB ClearFileBox
                   COLOR Plain, Black
                   FOR V = 1 TO 9
                      LOCATE 15 - V + Xcoor - 1, 4 + Ycoor - 1, 1
                      PRINT LEFT$(RTRIM$(Filenames(Current.File - V)), 12);
                   NEXT
                   COLOR Black, Plain
                   LOCATE 15 + Xcoor - 1, 4 + Ycoor - 1, 1
                   PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
                   GOSUB DisplayLongName2
                END IF
             LOOP
          END IF
       END SELECT
    END IF
 LOOP
 RETURN

DirInputLoop:
 GOSUB ClearLongName2
 Q$ = RTRIM$(Directories(Current.Dir))
 LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
 COLOR Black, Plain
 PRINT LEFT$(Q$, 12);
 COLOR Plain, Black
 GOSUB DisplayLongName1
 I$ = ""
 DO
    DO
       I$ = INKEY$
       IF LEN(I$) THEN
          EXIT DO
       END IF
    LOOP
    ' shift-tab returns to file loop
    IF LEN(I$) = 2 THEN
       IF ASC(RIGHT$(I$, 1)) = 15 THEN
          I$ = ""
          LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
          COLOR Plain, Black
          PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
          ' returns if no files.
          IF Num.Files = 0 THEN
             GOSUB ClearLongName2
             RETURN
          END IF
          ' display current filename.
          GOSUB DisplayLongName2
          E$ = Filenames(Current.File)
          E$ = RTRIM$(E$)
          COLOR Plain, Black
          LOCATE File.Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
          PRINT SPACE$(12);
          COLOR Black, Plain
          LOCATE File.Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
          PRINT LEFT$(E$, 12);
          COLOR Plain, Black
          RETURN
       END IF
    END IF
    ' Tab returns to top loop
    IF I$ = CHR$(9) THEN
       LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
       COLOR Plain, Black
       PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
       RETURN
    END IF
    IF I$ = CHR$(13) THEN
       ' check the path type
       SELECT CASE Q$
       CASE "." ' self
          ' nul
       CASE ".." ' parent
          IF INSTR(D$, "\") = 0 THEN
             D$ = ""
          ELSE
             FOR V = LEN(D$) TO 1 STEP -1
                IF MID$(D$, V, 1) = "\" THEN
                   D$ = LEFT$(D$, V - 1)
                   EXIT FOR
                END IF
             NEXT
          END IF
       CASE ELSE ' imbedded path
          IF D$ = "" THEN
             D$ = Q$
          ELSE
             D$ = D$ + "\" + Q$
          END IF
       END SELECT
       RETURN
    END IF
    IF I$ = CHR$(27) THEN
       RETURN
    END IF
    IF LEN(I$) = 1 THEN
       SELECT CASE I$
       CASE "A" TO "Z", "a" TO "z", "0" TO "9"
       DO
          IF Current.Dir + 1 <= Num.Dirs THEN
             IF Dir.Box.Line < 10 THEN
                LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
                COLOR Plain, Black
                PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                Dir.Box.Line = Dir.Box.Line + 1
                Current.Dir = Current.Dir + 1
                LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
                COLOR Black, Plain
                PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                COLOR Plain, Black
             ELSE
                GOSUB ClearDirBox
                Current.Dir = Current.Dir + 1
                COLOR Plain, Black
                FOR V = 1 TO 9
                   LOCATE 15 - V + Xcoor - 1, 21 + Ycoor - 1, 1
                   PRINT LEFT$(RTRIM$(Directories(Current.Dir - V)), 12);
                NEXT
                COLOR Black, Plain
                LOCATE 15 + Xcoor - 1, 21 + Ycoor - 1, 1
                PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                COLOR Plain, Black
             END IF
             Q$ = RTRIM$(Directories(Current.Dir))
             GOSUB DisplayLongName1
             IF LEFT$(Q$, 1) = I$ THEN
                EXIT DO
             END IF
          ELSE
             EXIT DO
          END IF
       LOOP
       END SELECT
       I$ = ""
    END IF
    IF LEN(I$) = 2 THEN
       V = ASC(RIGHT$(I$, 1))
       SELECT CASE V
       CASE 72 ' up
          IF Current.Dir - 1 > 0 THEN
             IF Dir.Box.Line > 1 THEN
                LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
                COLOR Plain, Black
                PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                Dir.Box.Line = Dir.Box.Line - 1
                Current.Dir = Current.Dir - 1
                LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
                COLOR Black, Plain
                PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                COLOR Plain, Black
             ELSE
                GOSUB ClearDirBox
                Current.Dir = Current.Dir - 1
                COLOR Plain, Black
                FOR V = 1 TO 9
                   IF Current.Dir + V <= Num.Dirs THEN
                      LOCATE 6 + V + Xcoor - 1, 21 + Ycoor - 1, 1
                      PRINT LEFT$(RTRIM$(Directories(Current.Dir + V)), 12);
                   END IF
                NEXT
                COLOR Black, Plain
                LOCATE 6 + Xcoor - 1, 21 + Ycoor - 1, 1
                PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                COLOR Plain, Black
             END IF
             Q$ = RTRIM$(Directories(Current.Dir))
             GOSUB DisplayLongName1
          END IF
       CASE 80 ' down
          IF Current.Dir + 1 <= Num.Dirs THEN
             IF Dir.Box.Line < 10 THEN
                LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
                COLOR Plain, Black
                PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                Dir.Box.Line = Dir.Box.Line + 1
                Current.Dir = Current.Dir + 1
                LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
                COLOR Black, Plain
                PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                COLOR Plain, Black
             ELSE
                GOSUB ClearDirBox
                Current.Dir = Current.Dir + 1
                COLOR Plain, Black
                FOR V = 1 TO 9
                   LOCATE 15 - V + Xcoor - 1, 21 + Ycoor - 1, 1
                   PRINT LEFT$(RTRIM$(Directories(Current.Dir - V)), 12);
                NEXT
                COLOR Black, Plain
                LOCATE 15 + Xcoor - 1, 21 + Ycoor - 1, 1
                PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                COLOR Plain, Black
             END IF
             Q$ = RTRIM$(Directories(Current.Dir))
             GOSUB DisplayLongName1
          END IF
       CASE 73 ' pgup
          IF Current.Dir - 10 > 0 THEN
             Dir.Box.Line = 1
             Current.Dir = Current.Dir - 10
          ELSE
             Dir.Box.Line = 1
             Current.Dir = 1
          END IF
          GOSUB ClearDirBox
          COLOR Plain, Black
          FOR V = 1 TO 9
             IF Current.Dir + V <= Num.Dirs THEN
                LOCATE 6 + V + Xcoor - 1, 21 + Ycoor - 1, 1
                PRINT LEFT$(RTRIM$(Directories(Current.Dir + V)), 12);
             END IF
          NEXT
          COLOR Black, Plain
          LOCATE 6 + Xcoor - 1, 21 + Ycoor - 1, 1
          PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
          COLOR Plain, Black
          Q$ = RTRIM$(Directories(Current.Dir))
          GOSUB DisplayLongName1
       CASE 81 ' pgdn
          IF Current.Dir + 10 <= Num.Dirs THEN
             GOSUB ClearDirBox
             Dir.Box.Line = 10
             Current.Dir = Current.Dir + 10
             COLOR Plain, Black
             FOR V = 1 TO 9
                LOCATE 15 - V + Xcoor - 1, 21 + Ycoor - 1, 1
                PRINT LEFT$(RTRIM$(Directories(Current.Dir - V)), 12);
             NEXT
             COLOR Black, Plain
             LOCATE 15 + Xcoor - 1, 21 + Ycoor - 1, 1
             PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
             COLOR Plain, Black
             Q$ = RTRIM$(Directories(Current.Dir))
             GOSUB DisplayLongName1
          ELSE
             IF Current.Dir + 1 <= Num.Dirs THEN
                DO UNTIL Current.Dir = Num.Dirs
                   IF Dir.Box.Line < 10 THEN
                      LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
                      COLOR Plain, Black
                      PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                      Dir.Box.Line = Dir.Box.Line + 1
                      Current.Dir = Current.Dir + 1
                      LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
                      COLOR Black, Plain
                      PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                      COLOR Plain, Black
                   ELSE
                      GOSUB ClearDirBox
                      Current.Dir = Current.Dir + 1
                      COLOR Plain, Black
                      FOR V = 1 TO 9
                         LOCATE 15 - V + Xcoor - 1, 21 + Ycoor - 1, 1
                         PRINT LEFT$(RTRIM$(Directories(Current.Dir - V)), 12);
                      NEXT
                      COLOR Black, Plain
                      LOCATE 15 + Xcoor - 1, 21 + Ycoor - 1, 1
                      PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                      COLOR Plain, Black
                   END IF
                LOOP
                Q$ = RTRIM$(Directories(Current.Dir))
                GOSUB DisplayLongName1
             END IF
          END IF
       CASE 71 ' home
          IF Current.Dir > 1 THEN
             Dir.Box.Line = 1
             Current.Dir = 1
          END IF
          GOSUB ClearDirBox
          COLOR Plain, Black
          FOR V = 1 TO 9
             IF Current.Dir + V <= Num.Dirs THEN
                LOCATE 6 + V + Xcoor - 1, 21 + Ycoor - 1, 1
                PRINT LEFT$(RTRIM$(Directories(Current.Dir + V)), 12);
             END IF
          NEXT
          COLOR Black, Plain
          LOCATE 6 + Xcoor - 1, 21 + Ycoor - 1, 1
          PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
          COLOR Plain, Black
          Q$ = RTRIM$(Directories(Current.Dir))
          GOSUB DisplayLongName1
       CASE 79 ' end
          IF Current.Dir + 1 <= Num.Dirs THEN
             DO UNTIL Current.Dir = Num.Dirs
                IF Dir.Box.Line < 10 THEN
                   LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
                   COLOR Plain, Black
                   PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                   Dir.Box.Line = Dir.Box.Line + 1
                   Current.Dir = Current.Dir + 1
                   LOCATE Dir.Box.Line + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
                   COLOR Black, Plain
                   PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                   COLOR Plain, Black
                ELSE
                   GOSUB ClearDirBox
                   Current.Dir = Current.Dir + 1
                   COLOR Plain, Black
                   FOR V = 1 TO 9
                      LOCATE 15 - V + Xcoor - 1, 21 + Ycoor - 1, 1
                      PRINT LEFT$(RTRIM$(Directories(Current.Dir - V)), 12);
                   NEXT
                   COLOR Black, Plain
                   LOCATE 15 + Xcoor - 1, 21 + Ycoor - 1, 1
                   PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
                   COLOR Plain, Black
                END IF
             LOOP
             Q$ = RTRIM$(Directories(Current.Dir))
             GOSUB DisplayLongName1
          END IF
       END SELECT
    END IF
 LOOP
 RETURN

MainMenu:
' define screen offsets,
' allows menu centering.
Xcoor = 5
Ycoor = 20
' draw menu
COLOR , 1
CLS
LOCATE Xcoor, Ycoor
COLOR , 0
COLOR Yellow
PRINT CHR$(ULcorner) + STRING$(33, Hline) + CHR$(URcorner)
LOCATE Xcoor + 1, Ycoor
PRINT CHR$(Vline) + " ";
COLOR White
PRINT "Filename:";
COLOR Yellow
PRINT "                       " + CHR$(Vline)
LOCATE Xcoor + 2, Ycoor
PRINT CHR$(Vline) + "                                 " + CHR$(Vline)
LOCATE Xcoor + 3, Ycoor
PRINT CHR$(Vline) + " ";
COLOR White
PRINT "Files:           Directories:   ";
COLOR Yellow
PRINT CHR$(Vline)
LOCATE Xcoor + 4, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(ULcorner) + STRING$(12, Hline) + CHR$(URcorner);
COLOR White
PRINT "F1=";
COLOR Magenta
PRINT CHR$(ULcorner) + STRING$(12, Hline) + CHR$(URcorner) + " ";
COLOR Yellow
PRINT CHR$(Vline)
COLOR Yellow
LOCATE Xcoor + 5, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline);
COLOR White
PRINT "<c>";
COLOR Magenta
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + " ";
COLOR Yellow
PRINT CHR$(Vline)
COLOR Yellow
LOCATE Xcoor + 6, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "   " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + " ";
COLOR Yellow
PRINT CHR$(Vline)
COLOR Yellow
LOCATE Xcoor + 7, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline);
COLOR White
PRINT "F2=";
COLOR Magenta
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + " ";
COLOR Yellow
PRINT CHR$(Vline)
COLOR Yellow
LOCATE Xcoor + 8, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline);
COLOR White
PRINT "<s>";
COLOR Magenta
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + " ";
COLOR Yellow
PRINT CHR$(Vline)
COLOR Yellow
LOCATE Xcoor + 9, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "   " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + " ";
COLOR Yellow
PRINT CHR$(Vline)
COLOR Yellow
LOCATE Xcoor + 10, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "   " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + " ";
COLOR Yellow
PRINT CHR$(Vline)
COLOR Yellow
LOCATE Xcoor + 11, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "   " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + " ";
COLOR Yellow
PRINT CHR$(Vline)
COLOR Yellow
LOCATE Xcoor + 12, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "   " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + " ";
COLOR Yellow
PRINT CHR$(Vline)
COLOR Yellow
LOCATE Xcoor + 13, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "   " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + " ";
COLOR Yellow
PRINT CHR$(Vline)
COLOR Yellow
LOCATE Xcoor + 14, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "   " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + " ";
COLOR Yellow
PRINT CHR$(Vline)
COLOR Yellow
LOCATE Xcoor + 15, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(LLcorner) + STRING$(12, Hline) + CHR$(LRcorner) + "   ";
PRINT CHR$(LLcorner) + STRING$(12, Hline) + CHR$(LRcorner) + " ";
COLOR Yellow
PRINT CHR$(Vline)
LOCATE Xcoor + 16, Ycoor
PRINT CHR$(LLcorner) + STRING$(33, Hline) + CHR$(LRcorner)
IF Xcoor - 1 > 0 THEN
   COLOR Green, Blue
   LOCATE Xcoor - 1, Ycoor
   PRINT "Hexedit v2.8a for Windows/DOS 2003.";
END IF
IF Xcoor + 17 <= 24 THEN
   COLOR Green, Blue
   LOCATE Xcoor + 17, Ycoor
   PRINT "Path:";
END IF
IF Xcoor + 18 <= 24 THEN
   COLOR Green, Blue
   LOCATE Xcoor + 18, Ycoor
   PRINT "File:";
END IF
COLOR Plain, Black
RETURN

' display path
DisplayCurrentPath:
 Q$ = D$
 FOR Var = LEN(Q$) TO 1 STEP -1
    IF MID$(Q$, Var, 1) = "\" THEN
       Q$ = MID$(Q$, Var + 1)
       EXIT FOR
    END IF
 NEXT
 IF Q$ = "" THEN
    Q$ = "\"
 END IF
 GOSUB DisplayLongName1
 RETURN

' display long directory
DisplayLongName1:
 IF Q$ = "." THEN
    RETURN
 END IF
' IF Q$ = ".." THEN
'    GOSUB ClearLongName1
'    RETURN
' END IF
 COLOR Green, Blue
 IF Xcoor + 17 <= 24 THEN
    Length = 80 - Ycoor - 1
    LOCATE Xcoor + 17, Ycoor
    PRINT SPACE$(Length);
    LOCATE Xcoor + 17, Ycoor
    P$ = "Path: " + Q$
    IF LEN(P$) > Length THEN
       P$ = LEFT$(P$, Length - 3) + "..."
    END IF
    PRINT P$;
 END IF
 COLOR Plain, Black
 RETURN

' display long filename
DisplayLongName2:
 COLOR Green, Blue
 IF Xcoor + 18 <= 24 THEN
    Length = 80 - Ycoor - 1
    LOCATE Xcoor + 18, Ycoor
    PRINT SPACE$(Length);
    LOCATE Xcoor + 18, Ycoor
    P$ = "File: " + E$
    IF LEN(P$) > Length THEN
       P$ = LEFT$(P$, Length - 3) + "..."
    END IF
    PRINT P$;
 END IF
 COLOR Plain, Black
 RETURN

' clear long directory area
ClearLongName1:
 COLOR Green, Blue
 IF Xcoor + 17 <= 24 THEN
    Length = 80 - Ycoor - 1
    LOCATE Xcoor + 17, Ycoor
    PRINT SPACE$(Length);
    LOCATE Xcoor + 17, Ycoor
    PRINT "Path: ";
 END IF
 COLOR Plain, Black
 RETURN

' clear long filename area
ClearLongName2:
 COLOR Green, Blue
 IF Xcoor + 18 <= 24 THEN
    Length = 80 - Ycoor - 1
    LOCATE Xcoor + 18, Ycoor
    PRINT SPACE$(Length);
    LOCATE Xcoor + 18, Ycoor
    PRINT "File: ";
 END IF
 COLOR Plain, Black
 RETURN

' check windows dos
TestWindows:
 InregsX.AX = &H160A
 CALL InterruptX(&H2F, InregsX, OutregsX)
 IF OutregsX.AX = False THEN
    Temp = (OutregsX.BX AND &HFF00) / 256
    IF Temp >= 4 THEN
       Windows.Detected = True
    END IF
 END IF
 RETURN

' return current drive.
InitDrive:
 InregsX.AX = &H1900
 CALL InterruptX(&H21, InregsX, OutregsX)
 Drive.Number = OutregsX.AX AND &HFF
 C$ = CHR$(Drive.Number + 65)
 RETURN

' return current directory.
InitDir:
 ' check windows dos
 IF Windows.Detected THEN
    ' get current directory
    InregsX.AX = &H7147
    InregsX.DX = Drive.Number + 1
    InregsX.DS = VARSEG(ASCIIZ3)
    InregsX.SI = VARPTR(ASCIIZ3)
    CALL InterruptX(&H21, InregsX, OutregsX)
 ELSE
    ' get current directory
    InregsX.AX = &H4700
    InregsX.DX = Drive.Number + 1
    InregsX.DS = VARSEG(ASCIIZ3)
    InregsX.SI = VARPTR(ASCIIZ3)
    CALL InterruptX(&H21, InregsX, OutregsX)
 END IF
 D$ = LEFT$(ASCIIZ3, INSTR(ASCIIZ3, CHR$(0)) - 1)
 RETURN

' initialize directory/filename record.
OpenDataFiles:
 CLOSE #2, #3
 V$ = ENVIRON$("TMP")
 IF V$ = "" THEN
    V$ = ENVIRON$("TEMP")
 END IF
 IF LEN(V$) THEN
    IF RIGHT$(V$, 1) = "\" THEN
       F1$ = V$ + "HEXEDIT1.DAT"
    ELSE
       F1$ = V$ + "\HEXEDIT1.DAT"
    END IF
    IF RIGHT$(V$, 1) = "\" THEN
       F2$ = V$ + "HEXEDIT2.DAT"
    ELSE
       F2$ = V$ + "\HEXEDIT2.DAT"
    END IF
    IF TestFile(F1$) THEN
       GOTO OpenDataFilename
    END IF
 END IF
 F1$ = "C:\TEMP\HEXEDIT1.DAT"
 F2$ = "C:\TEMP\HEXEDIT2.DAT"
 IF TestFile(F1$) THEN
    GOTO OpenDataFilename
 END IF
 F1$ = "C:\HEXEDIT1.DAT"
 F2$ = "C:\HEXEDIT2.DAT"
 IF TestFile(F1$) THEN
    GOTO OpenDataFilename
 END IF
 F1$ = "HEXEDIT1.DAT"
 F2$ = "HEXEDIT2.DAT"
 IF TestFile(F1$) THEN
    GOTO OpenDataFilename
 END IF
 ERROR 76
 END

' open data structure files.
OpenDataFilename:
 IF Windows.Detected THEN
    OPEN F1$ FOR RANDOM AS #2 LEN = LEN(WinFileStruc)
    OPEN F2$ FOR RANDOM AS #3 LEN = LEN(WinFileStruc)
 ELSE
    OPEN F1$ FOR RANDOM AS #2 LEN = LEN(DosFileStruc)
    OPEN F2$ FOR RANDOM AS #3 LEN = LEN(DosFileStruc)
 END IF
 RETURN

' load current subdirectories.
LoadDirSpec:
 Num.Dirs = 0
 GOSUB SetDTA
 ' find first directory
 IF D$ = "" THEN
    ASCIIZ3 = C$ + ":\*.*" + CHR$(0)
 ELSE
    IF D$ = "\" THEN
       ASCIIZ3 = C$ + ":\*.*" + CHR$(0)
    ELSE
       ASCIIZ3 = C$ + ":\" + D$ + "\*.*" + CHR$(0)
    END IF
 END IF
 IF Windows.Detected THEN
    InregsX.AX = &H714E
    InregsX.CX = &H37
    InregsX.SI = &H1
    InregsX.DS = VARSEG(ASCIIZ3)
    InregsX.DX = VARPTR(ASCIIZ3)
    InregsX.ES = VARSEG(WDTAfile)
    InregsX.DI = VARPTR(WDTAfile)
    CALL InterruptX(&H21, InregsX, OutregsX)
    Wfile.Handle = OutregsX.AX
 ELSE
    InregsX.AX = &H4E00
    InregsX.CX = &H37
    InregsX.DS = VARSEG(ASCIIZ3)
    InregsX.DX = VARPTR(ASCIIZ3)
    CALL InterruptX(&H21, InregsX, OutregsX)
 END IF
 ' store directories
 DO
    ' check for directory
    IF Windows.Detected THEN
       Attribute = ASC(WDTAfile.FileBits)
    ELSE
       Attribute = ASC(DTAfile.FileBits)
    END IF
    IF (Attribute AND &H10) = &H10 THEN
       ' store directory name
       IF Windows.Detected THEN
          E$ = WDTAfile.ASCIIZfull
       ELSE
          E$ = DTAfile.ASCIIZfilename
       END IF
       IF INSTR(E$, CHR$(0)) THEN
          E$ = LEFT$(E$, INSTR(E$, CHR$(0)) - 1)
       END IF
       IF Num.Dirs < 32767 THEN
          Num.Dirs = Num.Dirs + 1
          IF Windows.Detected THEN
             WinFileStruc.Name = E$
             PUT 3, Num.Dirs, WinFileStruc
          ELSE
             DosFileStruc.Name = E$
             PUT 3, Num.Dirs, DosFileStruc
          END IF
       END IF
    END IF
    ' find next directory
    IF Windows.Detected THEN
       ' find next long filename
       InregsX.AX = &H714F
       InregsX.BX = Wfile.Handle
       InregsX.SI = &H1
       InregsX.ES = VARSEG(WDTAfile)
       InregsX.DI = VARPTR(WDTAfile)
       CALL InterruptX(&H21, InregsX, OutregsX)
    ELSE
       ' find next directory
       InregsX.AX = &H4F00
       CALL InterruptX(&H21, InregsX, OutregsX)
    END IF
    ' check findnext error
    IF (OutregsX.Flags AND &H1) = &H1 THEN
       EXIT DO
    END IF
 LOOP
 ' check windows dos
 IF Windows.Detected THEN
    ' close long filename search
    InregsX.AX = &H71A1
    InregsX.BX = Wfile.Handle
    CALL InterruptX(&H21, InregsX, OutregsX)
 END IF
 IF Num.Dirs = 0 THEN
    IF Windows.Detected THEN
       WinFileStruc.Name = "."
       PUT 3, 1, WinFileStruc
    ELSE
       DosFileStruc.Name = "."
       PUT 3, 1, DosFileStruc
    END IF
    Num.Dirs = 1
 END IF
 GOSUB ResetDTA
 IF HeapSortOff THEN
    RETURN
 END IF
 IF Windows.Detected THEN
    GOSUB Win.Heap.Sort2
 ELSE
    GOSUB Dos.Heap.Sort2
 END IF
 RETURN

DisplayDirSpec:
 VarX = 0
 DO
    VarX = VarX + 1
    IF VarX > 10 THEN
       EXIT DO
    END IF
    IF VarX > Num.Dirs THEN
       EXIT DO
    END IF
    LOCATE VarX + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
    E$ = Directories(VarX)
    E$ = RTRIM$(E$)
    PRINT LEFT$(E$, 12);
 LOOP
 RETURN

ClearDirBox:
 FOR VarX = 1 TO 10
    LOCATE VarX + 5 + Xcoor - 1, 21 + Ycoor - 1, 1
    PRINT SPACE$(12);
 NEXT
 RETURN

DisplayCurrentDir:
 ' deconcatenate long path with \..\ characters
 Z$ = C$ + ":\" + D$
 DO
    IF LEN(Z$) > 32 THEN
       V1 = INSTR(Z$, "\")
       IF V1 > 0 THEN
          DO
             IF MID$(Z$, V1, 4) = "\..\" THEN
                V1 = INSTR(V1 + 1, Z$, "\")
             ELSE
                EXIT DO
             END IF
          LOOP
          V2 = INSTR(V1 + 1, Z$, "\")
          IF V2 > 0 THEN
             Z$ = LEFT$(Z$, V1) + ".." + MID$(Z$, V2)
          ELSE
             EXIT DO
          END IF
       END IF
    ELSE
       EXIT DO
    END IF
 LOOP
 DO
    V = INSTR(Z$, "\..\..\")
    IF V > 0 THEN
       Z$ = LEFT$(Z$, V - 1) + "\..\" + MID$(Z$, V + 7)
    ELSE
       EXIT DO
    END IF
 LOOP
 IF LEN(Z$) > 32 THEN
    Z$ = LEFT$(Z$, 32)
 END IF
 LOCATE 3 + Xcoor - 1, 3 + Ycoor - 1, 1
 PRINT SPACE$(32);
 LOCATE 3 + Xcoor - 1, 3 + Ycoor - 1, 1
 PRINT Z$;
 RETURN

' load specified files.
LoadFileSpec:
 Num.Files = 0
 GOSUB SetDTA
 ' find first file
 ASCIIZ3 = F$ + CHR$(0)
 IF Windows.Detected THEN
    InregsX.AX = &H714E
    InregsX.CX = &H27
    InregsX.SI = &H1
    InregsX.DS = VARSEG(ASCIIZ3)
    InregsX.DX = VARPTR(ASCIIZ3)
    InregsX.ES = VARSEG(WDTAfile)
    InregsX.DI = VARPTR(WDTAfile)
    CALL InterruptX(&H21, InregsX, OutregsX)
    Wfile.Handle = OutregsX.AX
 ELSE
    InregsX.AX = &H4E00
    InregsX.CX = &H27
    InregsX.DS = VARSEG(ASCIIZ3)
    InregsX.DX = VARPTR(ASCIIZ3)
    CALL InterruptX(&H21, InregsX, OutregsX)
 END IF
 ' store files
 DO
    ' check findnext error
    IF (OutregsX.Flags AND &H1) = &H1 THEN
       EXIT DO
    END IF
    ' check for file
    IF Windows.Detected THEN
       Attribute = ASC(WDTAfile.FileBits)
    ELSE
       Attribute = ASC(DTAfile.FileBits)
    END IF
    IF (Attribute AND &H10) <> &H10 THEN
       ' store directory name
       IF Windows.Detected THEN
          E$ = WDTAfile.ASCIIZfull
       ELSE
          E$ = DTAfile.ASCIIZfilename
       END IF
       IF INSTR(E$, CHR$(0)) THEN
          E$ = LEFT$(E$, INSTR(E$, CHR$(0)) - 1)
       END IF
       IF Num.Files < 32767 THEN
          Num.Files = Num.Files + 1
          IF Windows.Detected THEN
             WinFileStruc.Name = E$
             PUT 2, Num.Files, WinFileStruc
          ELSE
             DosFileStruc.Name = E$
             PUT 2, Num.Files, DosFileStruc
          END IF
       END IF
    END IF
    ' find next file
    IF Windows.Detected THEN
       ' find next long filename
       InregsX.AX = &H714F
       InregsX.BX = Wfile.Handle
       InregsX.SI = &H1
       InregsX.ES = VARSEG(WDTAfile)
       InregsX.DI = VARPTR(WDTAfile)
       CALL InterruptX(&H21, InregsX, OutregsX)
    ELSE
       ' find next directory
       InregsX.AX = &H4F00
       CALL InterruptX(&H21, InregsX, OutregsX)
    END IF
 LOOP
 ' check windows dos
 IF Windows.Detected THEN
    ' close long filename search
    InregsX.AX = &H71A1
    InregsX.BX = Wfile.Handle
    CALL InterruptX(&H21, InregsX, OutregsX)
 END IF
 GOSUB ResetDTA
 LOCATE Xcoor + 3, Ycoor + 9
 PRINT SPACE$(10);
 LOCATE Xcoor + 3, Ycoor + 9
 COLOR White
 PRINT "(" + MID$(STR$(Num.Files), 2) + ")";
 COLOR 7
 IF HeapSortOff THEN
    RETURN
 END IF
 COLOR White
 LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
 PRINT SPACE$(12);
 LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
 PRINT "Sorting..";
 COLOR 7
 IF Windows.Detected THEN
    GOSUB Win.Heap.Sort1
 ELSE
    GOSUB Dos.Heap.Sort1
 END IF
 RETURN

DisplayFileSpec:
 VarX = 0
 DO
    VarX = VarX + 1
    IF VarX > 10 THEN
       EXIT DO
    END IF
    IF VarX > Num.Files THEN
       EXIT DO
    END IF
    LOCATE VarX + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
    E$ = Filenames(VarX)
    E$ = RTRIM$(E$)
    PRINT LEFT$(E$, 12);
 LOOP
 RETURN

ClearFileBox:
 FOR VarX = 1 TO 10
    LOCATE VarX + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
    PRINT SPACE$(12);
 NEXT
 RETURN

' assign program dta.
SetDTA:
 InregsX.AX = &H1A00
 InregsX.DS = VARSEG(DTAfile)
 InregsX.DX = VARPTR(DTAfile)
 CALL InterruptX(&H21, InregsX, OutregsX)
 RETURN

' restore basic dta.
ResetDTA:
 InregsX.AX = &H1A00
 InregsX.DS = BASIC.DTA.SEG
 InregsX.DX = BASIC.DTA.OFF
 CALL InterruptX(&H21, InregsX, OutregsX)
 RETURN

' sorts windows hexedit1.dat file.
Win.Heap.Sort1:
 IF Num.Files < 2 THEN
    RETURN
 END IF
 Num = Num.Files
 FOR I = 2 TO Num
    J = I
    DO UNTIL J = 1
       P = J \ 2
       I1$ = Filenames(J)
       I2$ = Filenames(P)
       IF I1$ > I2$ THEN
          WinFileStruc.Name = I2$
          PUT 2, J, WinFileStruc
          WinFileStruc.Name = I1$
          PUT 2, P, WinFileStruc
          J = P
       ELSE
          EXIT DO
       END IF
    LOOP
 NEXT
 FOR I = Num TO 2 STEP -1
    I1$ = Filenames(1)
    I2$ = Filenames(I)
    WinFileStruc.Name = I2$
    PUT 2, 1, WinFileStruc
    WinFileStruc.Name = I1$
    PUT 2, I, WinFileStruc
    J = 1
    DO
       IF 2! * CSNG(J) > CSNG(I) - 1! THEN
          EXIT DO
       END IF
       C = 2 * J
       IF C + 1 <= I - 1 THEN
          IF Filenames(C + 1) > Filenames(C) THEN
             C = C + 1
          END IF
       END IF
       I1$ = Filenames(J)
       I2$ = Filenames(C)
       IF I1$ < I2$ THEN
          WinFileStruc.Name = I2$
          PUT 2, J, WinFileStruc
          WinFileStruc.Name = I1$
          PUT 2, C, WinFileStruc
          J = C
       ELSE
          EXIT DO
       END IF
    LOOP
 NEXT
 RETURN

' sorts dos hexedit1.dat file.
Dos.Heap.Sort1:
 IF Num.Files < 2 THEN
    RETURN
 END IF
 Num = Num.Files
 FOR I = 2 TO Num
    J = I
    DO UNTIL J = 1
       P = J \ 2
       I1$ = Filenames(J)
       I2$ = Filenames(P)
       IF I1$ > I2$ THEN
          DosFileStruc.Name = I2$
          PUT 2, J, DosFileStruc
          DosFileStruc.Name = I1$
          PUT 2, P, DosFileStruc
          J = P
       ELSE
          EXIT DO
       END IF
    LOOP
 NEXT
 FOR I = Num TO 2 STEP -1
    I1$ = Filenames(1)
    I2$ = Filenames(I)
    DosFileStruc.Name = I2$
    PUT 2, 1, DosFileStruc
    DosFileStruc.Name = I1$
    PUT 2, I, DosFileStruc
    J = 1
    DO
       IF 2! * CSNG(J) > CSNG(I) - 1! THEN
          EXIT DO
       END IF
       C = 2 * J
       IF C + 1 <= I - 1 THEN
          IF Filenames(C + 1) > Filenames(C) THEN
             C = C + 1
          END IF
       END IF
       I1$ = Filenames(J)
       I2$ = Filenames(C)
       IF I1$ < I2$ THEN
          DosFileStruc.Name = I2$
          PUT 2, J, DosFileStruc
          DosFileStruc.Name = I1$
          PUT 2, C, DosFileStruc
          J = C
       ELSE
          EXIT DO
       END IF
    LOOP
 NEXT
 RETURN

' sorts windows hexedit2.dat file.
Win.Heap.Sort2:
 IF Num.Dirs < 2 THEN
    RETURN
 END IF
 Num = Num.Dirs
 FOR I = 2 TO Num
    J = I
    DO UNTIL J = 1
       P = J \ 2
       I1$ = Directories(J)
       I2$ = Directories(P)
       IF I1$ > I2$ THEN
          WinFileStruc.Name = I2$
          PUT 3, J, WinFileStruc
          WinFileStruc.Name = I1$
          PUT 3, P, WinFileStruc
          J = P
       ELSE
          EXIT DO
       END IF
    LOOP
 NEXT
 FOR I = Num TO 2 STEP -1
    I1$ = Directories(1)
    I2$ = Directories(I)
    WinFileStruc.Name = I2$
    PUT 3, 1, WinFileStruc
    WinFileStruc.Name = I1$
    PUT 3, I, WinFileStruc
    J = 1
    DO
       IF 2! * CSNG(J) > CSNG(I) - 1! THEN
          EXIT DO
       END IF
       C = 2 * J
       IF C + 1 <= I - 1 THEN
          IF Directories(C + 1) > Directories(C) THEN
             C = C + 1
          END IF
       END IF
       I1$ = Directories(J)
       I2$ = Directories(C)
       IF I1$ < I2$ THEN
          WinFileStruc.Name = I2$
          PUT 3, J, WinFileStruc
          WinFileStruc.Name = I1$
          PUT 3, C, WinFileStruc
          J = C
       ELSE
          EXIT DO
       END IF
    LOOP
 NEXT
 RETURN

' sorts dos hexedit2.dat file.
Dos.Heap.Sort2:
 IF Num.Dirs < 2 THEN
    RETURN
 END IF
 Num = Num.Dirs
 FOR I = 2 TO Num
    J = I
    DO UNTIL J = 1
       P = J \ 2
       I1$ = Directories(J)
       I2$ = Directories(P)
       IF I1$ > I2$ THEN
          DosFileStruc.Name = I2$
          PUT 3, J, DosFileStruc
          DosFileStruc.Name = I1$
          PUT 3, P, DosFileStruc
          J = P
       ELSE
          EXIT DO
       END IF
    LOOP
 NEXT
 FOR I = Num TO 2 STEP -1
    I1$ = Directories(1)
    I2$ = Directories(I)
    DosFileStruc.Name = I2$
    PUT 3, 1, DosFileStruc
    DosFileStruc.Name = I1$
    PUT 3, I, DosFileStruc
    J = 1
    DO
       IF 2! * CSNG(J) > CSNG(I) - 1! THEN
          EXIT DO
       END IF
       C = 2 * J
       IF C + 1 <= I - 1 THEN
          IF Directories(C + 1) > Directories(C) THEN
             C = C + 1
          END IF
       END IF
       I1$ = Directories(J)
       I2$ = Directories(C)
       IF I1$ < I2$ THEN
          DosFileStruc.Name = I2$
          PUT 3, J, DosFileStruc
          DosFileStruc.Name = I1$
          PUT 3, C, DosFileStruc
          J = C
       ELSE
          EXIT DO
       END IF
    LOOP
 NEXT
 RETURN

' simple error routine
Error.Routine3:
 IF Check.Disk THEN
    IF ERR = 71 THEN
       Disk.Ready = True
       RESUME NEXT
    END IF
    IF ERR = 57 THEN
       Disk.Ready = True
       RESUME NEXT
    END IF
 END IF
 CLS
 COLOR White
 PRINT "Hex Editor Menu " + Version + " " + Release + " critical error trap:"
 COLOR Yellow
 ErrorTrap = ERR
 SELECT CASE ERR
 CASE 5
    PRINT "Syntax error." ' should not happen.
 CASE 9
    PRINT "Subscript out of range."
 CASE 14
    PRINT "Out of string space."
 CASE 24
    PRINT "Device timeout."
 CASE 25
    PRINT "Device fault."
 CASE 27
    PRINT "Out of paper."
 CASE 52
    PRINT "Bad file name or number."
 CASE 53
    PRINT "File not found."
 CASE 54
    PRINT "Bad file mode."
 CASE 55
    PRINT "File already open."
 CASE 57
    PRINT "Device I/O error."
 CASE 58
    PRINT "File already exists."
 CASE 59
    PRINT "Bad record length."
 CASE 61
    PRINT "Disk full."
 CASE 62
    PRINT "Input past eof."
 CASE 63
    PRINT "Bad record length."
 CASE 64
    PRINT "Bad filename."
 CASE 67
    PRINT "Not enough file handles."
 CASE 68
    PRINT "Device unavailable."
 CASE 70
    PRINT "Permission denied."
 CASE 71
    PRINT "Disk not ready."
 CASE 72
    PRINT "Disk-media error."
 CASE 75
    PRINT "Path/File access error."
 CASE 76
    PRINT "Pathname not found."
 CASE 81
    PRINT "Invalid name."
 CASE ELSE
    PRINT "Untrapped error" + STR$(ERR) + "."
 END SELECT
 ' display error prompt.
 COLOR Green
 PRINT "Check temp variables, or DOS file handles, then restart."
 COLOR Plain
 END
END SUB
