REM Program: Hex Editor v3.8a, Module 5 of 5, PD 2003.
REM Author: Erik Jon Oredson AS. Csci
REM Release: 04/30/2003.
REM Status: Public Domain.
REM Email: eoredson@yahoo.com
REM Urls: www.simtel.net www.filegate.net
REM  www.winsite.com

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

' Include function for BC 7.1 compiler:
'   Comment out for VB 1.0.
Declare Function FormatD$ (byval a#,b$)
Function Format$(x#,x$)
 Format$ = FormatD$(x#,x$)
End Function

REM File menu box routine:

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 upon return:
'   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 OpenDataFiles1

' display menu screen
GOSUB MainMenu

' get current drive/directory.
GOSUB GetDrives
GOSUB InitDrive
GOSUB InitDir

' start of menu loop.
StartMenu:

' get current filespec.
IF X1$ = "" THEN
   X$ = "*.*"
ELSE
   X$ = X1$
END IF
IF D$ = "" THEN
   F$ = C$ + ":\" + X$
ELSE
   F$ = C$ + ":\" + D$ + "\" + X$
END IF

' read all filenames.
GOSUB ClearFileBox
GOSUB LoadFileSpec
GOSUB DisplayFileSpec
GOSUB DisplayCurrentPath

' display first file.
IF Num.Files > 0 THEN
   Current.File = 1
   Box.Line = 1
   GOSUB InitFiles
ELSE
   GOSUB ClearLongName2
END IF

' read all subdirectories.
GOSUB ClearDirBox
GOSUB LoadDirSpec
GOSUB DisplayDirSpec
GOSUB DisplayCurrentDir
GOSUB DisplayCurrentPath

' display first directory.
Current.Dir = 1
Dir.Box.Line = 1
GOSUB DisplayInitDir

' read all drives.
GOSUB DisplayDrives
GOSUB InitDrives

' show mouse.
IF Mouse.Present THEN
   CALL MouseFunction(ShowMouse, 0)
END IF

' main input loop
Xstart = -1
DO
   Xposition1 = 1
   Xposition2 = LEN(X$)
   GOSUB DisplayFileLine
   DO
      ' get keypress
      I$ = ""
      DO
         I$ = INKEY$
         IF LEN(I$) THEN
            IsMenu = 0
            EXIT DO
         END IF

         ' call mouse subroutine.
         CALL MouseDriver

         ' check left mouse button.
         IF Mouse.ButtonX THEN
            GOSUB MouseButton1
            SELECT CASE IsMenu
            CASE 1 ' file box
               IF I$ = CHR$(13) THEN
                  E$ = RTRIM$(Filenames(Current.File))
                  GOTO EndLoop
               ELSE
                  GOSUB FileBoxKey
               END IF
            CASE 2 ' dir box
               IF I$ = CHR$(13) THEN
                  Q$ = RTRIM$(Directories(Current.Dir))
                  GOSUB GetNewPath
                  EXIT DO
               ELSE
                  GOSUB Dirboxkey
               END IF
            CASE 3 ' drive box
               IF I$ = CHR$(13) THEN
                  GOSUB SelectDrive
                  EXIT DO
               ELSE
                  GOSUB Driveboxkey
               END IF
            END SELECT
         END IF

         ' release time slice,
         Var = ReleaseTime
      LOOP

      ' strip off network slash
      IF I$ = "/" THEN
         I$ = ""
      END IF

      ' check extended key
      IF LEN(I$) = 2 THEN
         SELECT CASE ASC(RIGHT$(I$, 1))
         CASE 71 ' Home
            IF Xposition2 > 0 THEN
               Xposition1 = 1
               Xposition2 = 0
               GOSUB DisplayFileLine
            END IF
         CASE 79 ' End
            IF Xposition2 < LEN(X$) THEN
               Xposition2 = LEN(X$)
               Xposition1 = Xposition2 - 25
               IF Xposition1 < 1 THEN
                  Xposition1 = 1
               END IF
               GOSUB DisplayFileLine
            END IF
         CASE 83 ' Delete
            IF LEN(X$) > 0 THEN
               Xstart = 0
               X$ = LEFT$(X$, Xposition2) + MID$(X$, Xposition2 + 2)
               GOSUB DisplayFileLine
            END IF
         CASE 75 ' Left
            IF LEN(X$) THEN
               IF Xposition2 > 0 THEN
                  Xposition2 = Xposition2 - 1
                  IF Xposition2 - 25 <= Xposition1 THEN
                     Xposition1 = Xposition1 - 1
                     IF Xposition1 < 1 THEN
                        Xposition1 = 1
                     END IF
                     GOSUB DisplayFileLine
                  END IF
               END IF
            END IF
         CASE 77 ' Right
            IF LEN(X$) THEN
               IF Xposition2 < LEN(X$) THEN
                  Xposition2 = Xposition2 + 1
                  IF Xposition2 > Xposition1 + 25 THEN
                     Xposition1 = Xposition1 + 1
                  END IF
                  GOSUB DisplayFileLine
               END IF
            END IF
         CASE 80 ' down
            I$ = CHR$(9)
            GOTO TabFile
         CASE 60 ' F2 toggles heap sorting.
            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 DisplayFilenamex
            COLOR Plain, Black
            GOSUB ClearFileBox
            GOSUB LoadFileSpec
            GOSUB DisplayFileSpec
            EXIT DO
         CASE ELSE
            I$ = ""
         END SELECT
         I$ = ""
      END IF
TabFile:
      ' 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
            IF I$ = CHR$(13) THEN
               IF IsMenu = 1 THEN
                  E$ = RTRIM$(Filenames(Current.File))
                  GOTO EndLoop
               END IF
               IF IsMenu = 2 THEN
                  Q$ = RTRIM$(Directories(Current.Dir))
                  GOSUB GetNewPath
                  I$ = ""
                  Current.Dir = 1
                  Dir.Box.Line = 1
                  GOSUB ClearDirBox
                  GOSUB LoadDirSpec
                  GOSUB DisplayDirSpec
                  GOSUB DisplayCurrentDir
               END IF
               IF IsMenu = 3 THEN
                  I$ = ""
                  GOSUB SelectDrive
               END IF
            END IF
         ELSE
            GOSUB DirInputLoop
            IF I$ = CHR$(13) THEN
               IF IsMenu = 1 THEN
                  E$ = RTRIM$(Filenames(Current.File))
                  GOTO EndLoop
               END IF
            END IF
            IF I$ = CHR$(13) THEN
               IF IsMenu = 2 THEN
                  I$ = ""
                  Current.Dir = 1
                  Dir.Box.Line = 1
                  GOSUB ClearDirBox
                  GOSUB LoadDirSpec
                  GOSUB DisplayDirSpec
                  GOSUB DisplayCurrentDir
               END IF
               IF IsMenu = 3 THEN
                  GOSUB SelectDrive
               END IF
            END IF
            GOSUB DisplayCurrentPath
         END IF
         EXIT DO
      END IF
      ' enter key
      IF I$ = CHR$(13) THEN
         I$ = ""
         EXIT DO
      END IF
      ' escape key
      IF I$ = CHR$(27) THEN
         EXIT DO
      END IF
      ' backspace
      IF I$ = CHR$(8) THEN
         IF LEN(X$) THEN
            IF XPosition2 > 0 THEN
               Xstart = 0
               X$ = LEFT$(X$, Xposition2 - 1) + MID$(X$, Xposition2 + 1)
               Xposition2 = Xposition2 - 1
               IF Xposition2 - 25 <= Xposition1 THEN
                  Xposition1 = Xposition1 - 1
                  IF Xposition1 < 1 THEN
                     Xposition1 = 1
                  END IF
               END IF
               GOSUB DisplayFileLine
            END IF
         END IF
      ELSE
         ' append/insert character into filename area
         IF LEN(I$) THEN
            IF Xstart THEN
               X$ = ""
               Xstart = 0
               Xposition1 = 1
               Xposition2 = 0
               GOSUB DisplayFileLine
            END IF
            X$ = LEFT$(X$, Xposition2) + I$ + MID$(X$, Xposition2 + 1)
            Xposition2 = Xposition2 + 1
            IF Xposition2 > 26 THEN
               Xposition1 = Xposition1 + 1
            END IF
            GOSUB DisplayFileLine
         END IF
      END IF
   LOOP
   ' exit menu box with no filename
   IF I$ = CHR$(27) THEN
      E$ = ""
      EXIT DO
   END IF
   ' exit menu box with filename
   IF I$ = CHR$(13) THEN
      EXIT DO
   END IF

REM Process editing line in X$

   ' change drive
   IF MID$(X$, 2, 1) = ":" THEN
      ' check drive disk space.
      Z$ = UCASE$(LEFT$(X$, 1))
      X$ = MID$(X$, 3)
      Check.Disk = True
      Disk.Ready = False
      InregsX.AX = &H3600
      InregsX.DX = ASC(Z$) - 64
      CALL InterruptX(&H21, InregsX, OutregsX)
      ' check disk not available
      Check.Disk = False
      IF Disk.Ready = True THEN
         GOSUB PromptDisk
         X$ = X1$
      ELSE
         IF OutregsX.AX = &HFFFF THEN
            GOSUB PromptDisk
            X$ = X1$
         ELSE
            ' store and change to new drive
            C$ = Z$
            D$ = ""
            GOSUB DisplayFilenamex
            ' jump to top of filename entry loop
            IF X$ = "" OR X$ = "\" THEN
               X$ = ""
               GOTO StartMenu
            END IF
            ' load directories and continue
            GOSUB LoadDirSpec
         END IF
      END IF
   END IF
   ' change filespec from X$
   IF LEFT$(X$, 1) = "\" THEN
      ' store old values
      D1$ = D$
      X2$ = X$
      ' parse off directory
      FOR Var = LEN(X$) TO 1 STEP -1
         IF MID$(X$, Var, 1) = "\" THEN
            EXIT FOR
         END IF
      NEXT
      ' check imbedded dot path
      IF INSTR(X$, "\.\") OR INSTR(X$, "\\") THEN
         D$ = D1$
         X$ = X1$
      ELSE
         ' store directory and filename
         D$ = LEFT$(X$, Var)
         X$ = MID$(X$, Var + 1)
         ' check filename has dots
         IF INSTR(X$, "..") THEN
            D$ = D1$
            X$ = X2$
         ELSE
            ' check filename is dot
            IF X$ = "." THEN
               D$ = D1$
               X$ = X2$
            ELSE
               ' process filename
               IF X$ = "" THEN
                  ' restore current filespec
                  IF X1$ = "" THEN
                     X$ = "*.*"
                  ELSE
                     X$ = X1$
                  END IF
               END IF
               ' process directory
               IF LEFT$(D$, 1) = "\" THEN
                  D$ = MID$(D$, 2)
               END IF
               IF RIGHT$(D$, 1) = "\" THEN
                  D$ = LEFT$(D$, LEN(D$) - 1)
               END IF
               IF LEFT$(D$, 1) = "\" THEN
                  D$ = ""
               END IF
               IF RIGHT$(D$, 1) = "\" THEN
                  D$ = ""
               END IF
               IF D$ = "\" THEN
                  D$ = ""
               END IF
               ' check directory contains imbedded dots
               IF INSTR(D$, "..") THEN
                  D$ = D1$
                  X$ = X2$
               END IF
            END IF
         END IF
      END IF      
   END IF
   ' reload directories
   GOSUB LoadDirSpec
   ' verify path overrides
   ValidPath = -1
   IF X$ = "." THEN ' self is nul action
      ValidPath = 0
   ELSE
      IF X$ = ".." THEN
         ' root has no parent
         IF D$ = "" THEN
            ValidPath = 0
         END IF
      ELSE
         ' multiple dots not allowed
         IF X$ = STRING$(LEN(X$), ".") THEN
            ValidPath = 0
         ELSE
            A$ = TrimSpaces(X$)
            ' multiple dots with imbedded spaces not allowed
            IF A$ = STRING$(LEN(A$), ".") THEN
               ValidPath = 0
            ELSE
               ' dots with imbedded slashes not allowed
               IF INSTR(A$, ".\.") OR INSTR(A$, ".\") OR INSTR(A$, "\.") THEN
                  ValidPath = 0
               END IF
            END IF
         END IF
      END IF
   END IF
   ' check valid path specified
   IF ValidPath = 0 THEN
      ' restore filename override
      IF X1$ = "" THEN
         X$ = "*.*"
      ELSE
         X$ = X1$
      END IF
   END IF
   ' search for directory filespec override
   IF RIGHT$(X$, 1) <> "\" THEN
      FOR Var = 1 TO Num.Dirs
         S$ = UCASE$(RTRIM$(Directories(Var)))
         ' check X$ is directory in current one
         IF UCASE$(X$) = S$ THEN
            ' check X$ is previous directory
            IF S$ = ".." THEN
               ' check if not in subdirectory
               IF INSTR(D$, "\") = 0 THEN
                  D$ = ""
               ELSE
                  ' strip to previous directory
                  FOR Var1 = LEN(D$) TO 1 STEP -1
                     IF MID$(D$, Var1, 1) = "\" THEN
                        D$ = LEFT$(D$, Var1 - 1)
                        EXIT FOR
                     END IF
                  NEXT
               END IF
            ELSE
               ' store directory
               IF D$ = "" THEN
                  D$ = S$
               ELSE
                  D$ = D$ + "\" + S$
               END IF
            END IF
            ' restore filename override
            IF X1$ = "" THEN
               X$ = "*.*"
            ELSE
               X$ = X1$
            END IF
            EXIT FOR
         END IF
      NEXT
   END IF
   ' get the directory/filenames
   IF LEN(X$) THEN
      IF INSTR(X$, "\") THEN
         IF X1$ = "" THEN
            X$ = "*.*"
         ELSE
            X$ = X1$
         END IF
      END IF
      Current.Dir = 1
      Dir.Box.Line = 1
      GOSUB ClearDirBox
      GOSUB LoadDirSpec
      GOSUB DisplayDirSpec
      GOSUB DisplayCurrentDir
      GOSUB DisplayCurrentPath
      GOSUB DisplayInitDir
      IF D$ = "" THEN
         F$ = C$ + ":\" + X$
      ELSE
         F$ = C$ + ":\" + D$ + "\" + X$
      END IF
      X1$ = X$
      GOSUB ClearFileBox
      GOSUB LoadFileSpec
      GOSUB DisplayFileSpec
      IF Num.Files > 0 THEN
         Current.File = 1
         Box.Line = 1
         GOSUB InitFiles
      ELSE
         GOSUB ClearLongName2
      END IF
      Xstart = -1
   END IF
   GOSUB DisplayDrives
   GOSUB InitDrives
LOOP
EndLoop:
IF Mouse.Present THEN
   CALL MouseFunction(HideMouse, 0)
END IF
COLOR Plain, Black
CLS
EXIT SUB

' display current filename entry area.
DisplayFileLine:
 LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
 PRINT SPACE$(26);
 IF Xstart THEN
    COLOR Black, Plain
 END IF
 LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
 PRINT MID$(X$, Xposition1, 26);
 LOCATE 2 + Xcoor - 1, 13 + Ycoor + Xposition2 - Xposition1, 1
 COLOR Plain, Black
 RETURN

' display invalid disk message.
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 DisplayFilenamex
 COLOR Plain, Black
 PRINT X$;
 RETURN

' display filename line.
DisplayFilenamex:
 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

' init filename input loop
InitFiles:
 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
 E$ = RTRIM$(Filenames(1))
 RETURN

' filename input loop.
FileInputLoop:
 I$ = ""
 DO
    IF Current.File > 0 THEN
       GOSUB DisplayLongName2
    END IF
    DO
       ' get keystroke.
       I$ = INKEY$
       IF LEN(I$) THEN
          IsMenu = 0
          EXIT DO
       END IF

       ' call mouse subroutine.
       CALL MouseDriver

       ' check left mouse button.
       IF Mouse.ButtonX THEN
          GOSUB MouseButton1
          SELECT CASE IsMenu
          CASE 1 ' file box
             IF I$ = CHR$(13) THEN
                EXIT DO
             ELSE
                GOSUB FileBoxKey
             END IF
          CASE 2 ' dir box
             IF I$ = CHR$(13) THEN
                RETURN
             ELSE
                GOSUB Dirboxkey
             END IF
          CASE 3 ' drive box
             IF I$ = CHR$(13) THEN
                RETURN
             ELSE
                GOSUB Driveboxkey
             END IF
          END SELECT
       END IF

       ' release time slice,
       Var = ReleaseTime
    LOOP

    ' up returns shift-tab
    IF LEN(I$) = 2 THEN
       IF ASC(RIGHT$(I$, 1)) = 72 THEN
          IF Current.File = 1 THEN
             IF Box.Line = 1 THEN
                I$ = CHR$(0) + CHR$(15)
             END IF
          END IF
       END IF
    END IF

    ' shift-tab returns to top
    IF LEN(I$) = 2 THEN
       IF ASC(RIGHT$(I$, 1)) = 15 THEN
          I$ = ""
          RETURN
       END IF
    END IF

    ' right returns tab
    IF LEN(I$) = 2 THEN
       IF ASC(RIGHT$(I$, 1)) = 77 THEN
          I$ = CHR$(9)
       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
          IF IsMenu = 1 THEN
             RETURN
          END IF
          IF IsMenu = 3 THEN
             RETURN
          END IF
          Q$ = RTRIM$(Directories(Current.Dir))
          GOSUB GetNewPath
          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 Box.Line < 10 THEN
                GOSUB ClearFilename
                Box.Line = Box.Line + 1
                Current.File = Current.File + 1
                GOSUB DisplayFilename
                GOSUB DisplayLongName2
             ELSE
                Current.File = Current.File + 1
                GOSUB DisplayFilename2
                GOSUB DisplayFileBox1
                GOSUB DisplayFilename3
                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
       GOSUB FileBoxKey
    END IF
 LOOP
 RETURN

' process key in file box.
FileBoxKey:
 V = ASC(RIGHT$(I$, 1))
 SELECT CASE V
 CASE 72 ' up
    IF Current.File - 1 > 0 THEN
       IF Box.Line > 1 THEN
          GOSUB ClearFilename
          Box.Line = Box.Line - 1
          Current.File = Current.File - 1
          GOSUB DisplayFilename
          GOSUB DisplayLongName2
       ELSE
          Current.File = Current.File - 1
          GOSUB DisplayFilename2
          GOSUB DisplayFileBox2
          GOSUB DisplayFilename4
          GOSUB DisplayLongName2
       END IF
    END IF
 CASE 80 ' down
    IF Current.File + 1 <= Num.Files THEN
       IF Box.Line < 10 THEN
          GOSUB ClearFilename
          Box.Line = Box.Line + 1
          Current.File = Current.File + 1
          GOSUB DisplayFilename
          GOSUB DisplayLongName2
       ELSE
          Current.File = Current.File + 1
          GOSUB DisplayFilename2
          GOSUB DisplayFileBox1
          GOSUB DisplayFilename3
          GOSUB DisplayLongName2
       END IF
    END IF
 CASE 73 ' pgup
    IF Current.File - 10 > 0 THEN
       Box.Line = 1
       Current.File = Current.File - 10
    ELSE
       Box.Line = 1
       Current.File = 1
    END IF
    GOSUB DisplayFilename2
    GOSUB DisplayFileBox2
    GOSUB DisplayFilename4
    GOSUB DisplayLongName2
 CASE 81 ' pgdn
    IF Current.File + 10 <= Num.Files THEN
       Box.Line = 10
       Current.File = Current.File + 10
       GOSUB DisplayFilename2
       GOSUB DisplayFileBox1
       GOSUB DisplayFilename3
       GOSUB DisplayLongName2
    ELSE
       IF Current.File + 1 <= Num.Files THEN
          DO UNTIL Current.File = Num.Files
             IF Box.Line < 10 THEN
                GOSUB ClearFilename
                Box.Line = Box.Line + 1
                Current.File = Current.File + 1
                GOSUB DisplayFilename
                GOSUB DisplayLongName2
             ELSE
                Current.File = Current.File + 1
                GOSUB DisplayFilename2
                GOSUB DisplayFileBox1
                GOSUB DisplayFilename3
                GOSUB DisplayLongName2
             END IF
          LOOP
       END IF
    END IF
 CASE 71 ' home
    IF Current.File > 1 THEN
       Box.Line = 1
       Current.File = 1
    END IF
    GOSUB DisplayFilename2
    GOSUB DisplayFileBox2
    GOSUB DisplayFilename4
    GOSUB DisplayLongName2
 CASE 79 ' end
    IF Current.File + 1 <= Num.Files THEN
       DO UNTIL Current.File = Num.Files
          IF Box.Line < 10 THEN
             GOSUB ClearFilename
             Box.Line = Box.Line + 1
             Current.File = Current.File + 1
             GOSUB DisplayFilename
             GOSUB DisplayLongName2
          ELSE
             Current.File = Current.File + 1
             GOSUB DisplayFilename2
             GOSUB DisplayFileBox1
             GOSUB DisplayFilename3
             GOSUB DisplayLongName2
          END IF
       LOOP
    END IF
 END SELECT
 RETURN

' clear filename.
ClearFilename:
 LOCATE Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
 COLOR Plain, Black
 PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
 RETURN

' display filename.
DisplayFilename:
 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 Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1, 1
 COLOR Black, Plain
 PRINT LEFT$(E$, 12);
 COLOR Plain, Black
 RETURN

' display filename.
DisplayFilename2:
 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
 RETURN

' display filename.
DisplayFilename3:
 COLOR Black, Plain
 LOCATE 15 + Xcoor - 1, 4 + Ycoor - 1, 1
 PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
 RETURN

' display filename.
DisplayFilename4:
 COLOR Black, Plain
 LOCATE 6 + Xcoor - 1, 4 + Ycoor - 1, 1
 PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
 RETURN

' update filename box.
DisplayFileBox1:
 FOR V = 1 TO 9
    LOCATE 15 - V + Xcoor - 1, 4 + Ycoor - 1, 1
    PRINT LEFT$(RTRIM$(Filenames(Current.File - V)), 12);
 NEXT
 RETURN

' updates filename box.
DisplayFileBox2:
 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
 RETURN

' display init directory.
DisplayInitDir:
 Q$ = RTRIM$(Directories(Current.Dir))
 LOCATE Dir.Box.Line + 5 + Xcoor - 1, 20 + Ycoor - 1, 1
 COLOR Black, Plain
 PRINT LEFT$(Q$, 12);
 COLOR Plain, Black
 RETURN

' directory input loop.
DirInputLoop:
 GOSUB ClearLongName2
 GOSUB DisplayInitDir
 GOSUB DisplayLongName1
 I$ = ""
 DO
    DO
       ' get keystroke.
       I$ = INKEY$
       IF LEN(I$) THEN
          IsMenu = 0
          EXIT DO
       END IF

       ' call mouse subroutine.
       CALL MouseDriver

       ' check left mouse button.
       IF Mouse.ButtonX THEN
          GOSUB MouseButton1
          SELECT CASE IsMenu
          CASE 1 ' file box
             IF I$ = CHR$(13) THEN
                RETURN
             ELSE
                GOSUB FileBoxKey
             END IF
          CASE 2 ' dir box
             IF I$ = CHR$(13) THEN
                RETURN
             ELSE
                GOSUB Dirboxkey
             END IF
          CASE 3 ' drive box
             IF I$ = CHR$(13) THEN
                RETURN
             ELSE
                GOSUB Driveboxkey
             END IF
          END SELECT
       END IF

       ' release time slice,
       Var = ReleaseTime
    LOOP

    ' left returns shift-tab
    IF LEN(I$) = 2 THEN
       IF ASC(RIGHT$(I$, 1)) = 75 THEN
          I$ = CHR$(0) + CHR$(15)
       END IF
    END IF

    ' shift-tab returns to file loop
    IF LEN(I$) = 2 THEN
       IF ASC(RIGHT$(I$, 1)) = 15 THEN
          I$ = ""
          ' display current filename.
          GOSUB ClearLongName2
          IF Num.Files > 0 THEN
             GOSUB DisplayLongName2
             GOSUB ClearFilename
             GOSUB DisplayFilename
          END IF
          ' display current directory.
          GOSUB ClearDirectory
          GOSUB DisplayCurrentPath
          RETURN
       END IF
    END IF

    ' right returns tab
    IF LEN(I$) = 2 THEN
       IF ASC(RIGHT$(I$, 1)) = 77 THEN
          I$ = CHR$(9)
       END IF
    END IF

    ' Tab moves to drive input loop
    IF I$ = CHR$(9) THEN
       GOSUB DriveInputLoop
       IF I$ = CHR$(13) THEN
          IF IsMenu = 1 THEN
             RETURN
          END IF
          IF IsMenu = 2 THEN
             RETURN
          END IF
       END IF
       IF I$ = CHR$(9) THEN
          GOSUB DisplayCurrentPath
          RETURN
       END IF
       IF I$ = CHR$(13) THEN
          I$ = ""
          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.Dir + 1 <= Num.Dirs THEN
             IF Dir.Box.Line < 10 THEN
                GOSUB ClearDirectory
                Dir.Box.Line = Dir.Box.Line + 1
                Current.Dir = Current.Dir + 1
                GOSUB DisplayDirectory
             ELSE
                GOSUB ClearDirBox
                Current.Dir = Current.Dir + 1
                GOSUB DisplayDirBox1
                GOSUB DisplayDirectory2
             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
       GOSUB DirBoxKey
    END IF
 LOOP
 RETURN

' clear directory.
ClearDirectory:
 LOCATE Dir.Box.Line + 5 + Xcoor - 1, 20 + Ycoor - 1, 1
 COLOR Plain, Black
 PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
 RETURN

' display directory.
DisplayDirectory:
 LOCATE Dir.Box.Line + 5 + Xcoor - 1, 20 + Ycoor - 1, 1
 COLOR Black, Plain
 PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
 COLOR Plain, Black
 RETURN

' display directory
DisplayDirectory2:
 COLOR Black, Plain
 LOCATE 15 + Xcoor - 1, 20 + Ycoor - 1, 1
 PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
 COLOR Plain, Black
 RETURN

' display directory.
DisplayDirectory3:
 COLOR Black, Plain
 LOCATE 6 + Xcoor - 1, 20 + Ycoor - 1, 1
 PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
 COLOR Plain, Black
 RETURN

' update dir box.
DisplayDirBox1:
 COLOR Plain, Black
 FOR V = 1 TO 9
    LOCATE 15 - V + Xcoor - 1, 20 + Ycoor - 1, 1
    PRINT LEFT$(RTRIM$(Directories(Current.Dir - V)), 12);
 NEXT
 RETURN

' update dir box.
DisplayDirBox2:
 COLOR Plain, Black
 FOR V = 1 TO 9
    IF Current.Dir + V <= Num.Dirs THEN
       LOCATE 6 + V + Xcoor - 1, 20 + Ycoor - 1, 1
       PRINT LEFT$(RTRIM$(Directories(Current.Dir + V)), 12);
    END IF
 NEXT
 RETURN

' construct new path from dir box selection.
GetNewPath:
 ' 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

' process dir box key.
DirBoxKey:
 V = ASC(RIGHT$(I$, 1))
 SELECT CASE V
 CASE 72 ' up
    IF Current.Dir - 1 > 0 THEN
       IF Dir.Box.Line > 1 THEN
          GOSUB ClearDirectory
          Dir.Box.Line = Dir.Box.Line - 1
          Current.Dir = Current.Dir - 1
          GOSUB DisplayDirectory
       ELSE
          GOSUB ClearDirBox
          Current.Dir = Current.Dir - 1
          GOSUB DisplayDirBox2
          GOSUB DisplayDirectory3
       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
          GOSUB ClearDirectory
          Dir.Box.Line = Dir.Box.Line + 1
          Current.Dir = Current.Dir + 1
          GOSUB DisplayDirectory
       ELSE
          GOSUB ClearDirBox
          Current.Dir = Current.Dir + 1
          GOSUB DisplayDirBox1
          GOSUB DisplayDirectory2
       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
    GOSUB DisplayDirBox2
    GOSUB DisplayDirectory3
    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
       GOSUB DisplayDirBox1
       GOSUB DisplayDirectory2
       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
                GOSUB ClearDirectory
                Dir.Box.Line = Dir.Box.Line + 1
                Current.Dir = Current.Dir + 1
                GOSUB DisplayDirectory
             ELSE
                GOSUB ClearDirBox
                Current.Dir = Current.Dir + 1
                GOSUB DisplayDirBox1
                GOSUB DisplayDirectory2
             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
    GOSUB DisplayDirBox2
    GOSUB DisplayDirectory3
    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
             GOSUB ClearDirectory
             Dir.Box.Line = Dir.Box.Line + 1
             Current.Dir = Current.Dir + 1
             GOSUB DisplayDirectory
          ELSE
             GOSUB ClearDirBox
             Current.Dir = Current.Dir + 1
             GOSUB DisplayDirBox1
             GOSUB DisplayDirectory2
          END IF
       LOOP
       Q$ = RTRIM$(Directories(Current.Dir))
       GOSUB DisplayLongName1
    END IF
 END SELECT
 RETURN

' drive input loop
DriveInputLoop:
 I$ = ""
 DO
    GOSUB DisplayDrive
    DO
       ' get keystroke.
       I$ = INKEY$
       IF LEN(I$) THEN
          IsMenu = 0
          EXIT DO
       END IF

       ' call mouse subroutine.
       CALL MouseDriver

       ' check left mouse button.
       IF Mouse.ButtonX THEN
          GOSUB MouseButton1
          SELECT CASE IsMenu
          CASE 1 ' file box
             IF I$ = CHR$(13) THEN
                RETURN
             ELSE
                GOSUB FileBoxKey
             END IF
          CASE 2 ' dir box
             IF I$ = CHR$(13) THEN
                RETURN
             ELSE
                GOSUB Dirboxkey
             END IF
          CASE 3 ' drive box
             IF I$ = CHR$(13) THEN
                EXIT DO
             ELSE
                GOSUB Driveboxkey
             END IF
          END SELECT
       END IF

       ' release time slice,
       Var = ReleaseTime
    LOOP

    ' left returns shift-tab
    IF LEN(I$) = 2 THEN
       IF ASC(RIGHT$(I$, 1)) = 75 THEN
          I$ = CHR$(0) + CHR$(15)
       END IF
    END IF

    ' shift-tab returns to directory loop
    IF LEN(I$) = 2 THEN
       IF ASC(RIGHT$(I$, 1)) = 15 THEN
          I$ = ""
          GOSUB DisplayDirectory
          RETURN
       END IF
    END IF

    ' up returns tab
    IF LEN(I$) = 2 THEN
       IF ASC(RIGHT$(I$, 1)) = 72 THEN
          IF Current.Drive = 1 THEN
             IF Drive.Box.Line = 1 THEN
                I$ = CHR$(9)
             END IF
          END IF
       END IF
    END IF

    ' Tab returns to top loop
    IF I$ = CHR$(9) THEN
       RETURN
    END IF

    ' select a drive
    IF I$ = CHR$(13) THEN
       GOSUB SelectDrive
       IF Valid THEN
          RETURN
       END IF
    END IF
    IF I$ = CHR$(27) THEN
       RETURN
    END IF
    IF LEN(I$) = 2 THEN
       GOSUB DriveBoxKey
    END IF
 LOOP
 RETURN

' select drive from box letter.
SelectDrive:
 ' check drive disk space.
 Valid = 0
 Z$ = CHR$(Current.Drive + 64)
 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
    RETURN
 END IF
 IF OutregsX.AX = &HFFFF THEN
    GOSUB PromptDisk
    RETURN
 END IF
 Valid = -1
 C$ = Z$
 D$ = ""
 GOSUB ClearDrive
 Current.Dir = 1
 Dir.Box.Line = 1
 GOSUB ClearDirBox
 GOSUB LoadDirSpec
 GOSUB DisplayDirSpec
 GOSUB DisplayCurrentDir
 GOSUB DisplayCurrentPath
 ' display first ten files
 F$ = C$ + ":\*.*"
 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$;
 ' init filenames
 GOSUB ClearFileBox
 GOSUB LoadFileSpec
 GOSUB DisplayFileSpec
 IF Num.Files > 0 THEN
    Current.File = 1
    Box.Line = 1
    GOSUB InitFiles
 END IF
 RETURN

' process drive box key.
DriveBoxKey:
 V = ASC(RIGHT$(I$, 1))
 SELECT CASE V
 CASE 72 ' up
    IF Current.Drive - 1 > 0 THEN
       IF Drive.Box.Line > 1 THEN
          GOSUB ClearDrive
          Drive.Box.Line = Drive.Box.Line - 1
          Current.Drive = Current.Drive - 1
          GOSUB DisplayDrive
       ELSE
          Current.Drive = Current.Drive - 1
          GOSUB ClearDriveBox
          COLOR Plain, Black
          FOR V = 1 TO 9
             LOCATE Xcoor + V + 5, Ycoor + 35, 1
             PRINT "[" + CHR$(Current.Drive + V + 64) + "]";
          NEXT
          Drive.Box.Line = 1
          GOSUB DisplayDrive
       END IF
       Q$ = CHR$(Current.Drive + 64)
    END IF
 CASE 80 ' down
    IF Current.Drive + 1 <= Last.Drive THEN
       IF Drive.Box.Line < 10 THEN
          GOSUB ClearDrive
          Drive.Box.Line = Drive.Box.Line + 1
          Current.Drive = Current.Drive + 1
          GOSUB DisplayDrive
       ELSE
          Current.Drive = Current.Drive + 1
          GOSUB ClearDriveBox
          COLOR Plain, Black
          FOR V = 1 TO 9
             LOCATE Xcoor + 14 - V, Ycoor + 35, 1
             PRINT "[" + CHR$(Current.Drive - V + 64) + "]";
          NEXT
          Drive.Box.Line = 10
          GOSUB DisplayDrive
       END IF
       Q$ = CHR$(Current.Drive + 64)
    END IF
 END SELECT
 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$(39, Hline) + CHR$(URcorner)
LOCATE Xcoor + 1, Ycoor
PRINT CHR$(Vline) + " ";
COLOR White
PRINT "Filename:";
COLOR Yellow
PRINT SPACE$(29) + CHR$(Vline)
LOCATE Xcoor + 2, Ycoor
PRINT CHR$(Vline) + SPACE$(39) + CHR$(Vline)
LOCATE Xcoor + 3, Ycoor
PRINT CHR$(Vline) + " ";
COLOR White
PRINT "Files:          Dirs:          Drives:";
COLOR Yellow
PRINT CHR$(Vline)
LOCATE Xcoor + 4, Ycoor
PRINT CHR$(Vline);
COLOR Magenta
PRINT " " + CHR$(ULcorner) + STRING$(12, Hline) + CHR$(URcorner) + "  ";
PRINT CHR$(ULcorner) + STRING$(12, Hline) + CHR$(URcorner) + "  ";
PRINT CHR$(ULcorner) + STRING$(3, 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) + "  ";
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  ";
PRINT CHR$(Vline) + SPACE$(3) + 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) + "  ";
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  ";
PRINT CHR$(Vline) + SPACE$(3) + 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) + "  ";
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  ";
PRINT CHR$(Vline) + SPACE$(3) + 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) + "  ";
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  ";
PRINT CHR$(Vline) + SPACE$(3) + 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) + "  ";
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  ";
PRINT CHR$(Vline) + SPACE$(3) + 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) + "  ";
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  ";
PRINT CHR$(Vline) + SPACE$(3) + 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) + "  ";
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  ";
PRINT CHR$(Vline) + SPACE$(3) + 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) + "  ";
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  ";
PRINT CHR$(Vline) + SPACE$(3) + 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) + "  ";
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  ";
PRINT CHR$(Vline) + SPACE$(3) + 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) + "  ";
PRINT CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  ";
PRINT CHR$(Vline) + SPACE$(3) + 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) + "  ";
PRINT CHR$(LLcorner) + STRING$(3, Hline) + CHR$(LRcorner) + " ";
COLOR Yellow
PRINT CHR$(Vline)
LOCATE Xcoor + 16, Ycoor
PRINT CHR$(LLcorner) + STRING$(39, Hline) + CHR$(LRcorner)
COLOR White
' make file input box mouse symbols
LOCATE Xcoor + 4, Ycoor + 16
PRINT "<";
LOCATE Xcoor + 5, Ycoor + 16
PRINT "|";
LOCATE Xcoor + 14, Ycoor + 16
PRINT "|";
LOCATE Xcoor + 15, Ycoor + 16
PRINT ">";
' make directory input box mouse symbols
LOCATE Xcoor + 4, Ycoor + 32
PRINT "<";
LOCATE Xcoor + 5, Ycoor + 32
PRINT "|";
LOCATE Xcoor + 14, Ycoor + 32
PRINT "|";
LOCATE Xcoor + 15, Ycoor + 32
PRINT ">";
' make drive input box mouse symbols
LOCATE Xcoor + 5, Ycoor + 39
PRINT "|";
LOCATE Xcoor + 14, Ycoor + 39
PRINT "|";
IF Xcoor - 1 > 0 THEN
   COLOR Green, Blue
   LOCATE Xcoor - 1, Ycoor
   PRINT "Hexedit v3.8a for DOS & Windows PD 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
IF Xcoor + 19 <= 24 THEN
   COLOR Green, Blue
   LOCATE Xcoor + 19, Ycoor
   PRINT "Size:";
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:
 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
 V = LEN(RTRIM$(Directories(Current.Dir)))
 LOCATE Dir.Box.Line + 5 + Xcoor - 1, 20 + Ycoor - 1 + V, 1
 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
 GOSUB DisplayFilesize
 V = LEN(RTRIM$(Filenames(Current.File)))
 LOCATE Box.Line + 5 + Xcoor - 1, 4 + Ycoor - 1 + V, 1
 RETURN

' display filesize
DisplayFilesize:
 GOSUB GetFilesize
 COLOR Green, Blue
 IF Xcoor + 19 <= 24 THEN
    Length = 80 - Ycoor - 1
    LOCATE Xcoor + 19, Ycoor
    PRINT SPACE$(Length);
    LOCATE Xcoor + 19, Ycoor
    P$ = "Size: " + Format$(Filesize, "#,##0;;0")
    PRINT P$;" ";
    GOSUB DisplayFileattr
 END IF
 COLOR Plain, Black
 RETURN

' get filesize
GetFilesize:
 ' reset filesize
 FileSize = False
 ' store dta
 GOSUB SetDTA
 ' store long filename
 IF D$ = "" THEN
    W$ = C$ + ":\" + E$
 ELSE
    W$ = C$ + ":\" + D$ + "\" + E$
 END IF
 ' store asciiz filename
 ASCIIZ3 = W$ + CHR$(0)
 ' check windows/get file info
 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
 ' check findnext error
 IF (OutregsX.Flags AND &H1) = &H1 THEN
    RETURN
 END IF
 ' store filesize
 IF Windows.Detected THEN
    FileSize = ASC(MID$(WDTAfile.FileSizeHigh, 4, 1))
    FileSize = FileSize * &H100 + ASC(MID$(WDTAfile.FileSizeHigh, 3, 1))
    FileSize = FileSize * &H100 + ASC(MID$(WDTAfile.FileSizeHigh, 2, 1))
    FileSize = FileSize * &H100 + ASC(MID$(WDTAfile.FileSizeHigh, 1, 1))
    FileSize = FileSize * &H100 + ASC(MID$(WDTAfile.FileSizeLow, 4, 1))
    FileSize = FileSize * &H100 + ASC(MID$(WDTAfile.FileSizeLow, 3, 1))
    FileSize = FileSize * &H100 + ASC(MID$(WDTAfile.FileSizeLow, 2, 1))
    FileSize = FileSize * &H100 + ASC(MID$(WDTAfile.FileSizeLow, 1, 1))
 ELSE
    FileSize = ASC(MID$(DTAfile.FileSize, 4, 1))
    FileSize = FileSize * &H100 + ASC(MID$(DTAfile.FileSize, 3, 1))
    FileSize = FileSize * &H100 + ASC(MID$(DTAfile.FileSize, 2, 1))
    FileSize = FileSize * &H100 + ASC(MID$(DTAfile.FileSize, 1, 1))
 END IF
 ' store file attribute
 IF Windows.Detected THEN
    FileAttribute = ASC(WDTAfile.FileBits)
 ELSE
    FileAttribute = ASC(DTAfile.FileBits)
 END IF
 ' 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
 ' restore dta
 GOSUB ResetDTA
 RETURN

' display file attribute
DisplayFileattr:
 P$ = Nul
 IF (FileAttribute AND ReadOnlyBit) = ReadOnlyBit THEN
    P$ = P$ + "o"
 END IF
 IF (FileAttribute AND HiddenBit) = HiddenBit THEN
    P$ = P$ + "h"
 END IF
 IF (FileAttribute AND SystemBit) = SystemBit THEN
    P$ = P$ + "s"
 END IF
 IF (FileAttribute AND ArchiveBit) = ArchiveBit THEN
    P$ = P$ + "a"
 END IF
 IF LEN(P$) THEN
    PRINT "("; P$; ")";
 END IF
 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
 ' clear size area
 IF Xcoor + 19 <= 24 THEN
    Length = 80 - Ycoor - 1
    LOCATE Xcoor + 19, Ycoor
    PRINT SPACE$(Length);
    LOCATE Xcoor + 19, Ycoor
    PRINT "Size: ";
 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.
OpenDataFiles1:
 V1$ = "HEXEDIT1.DAT"
 V2$ = "HEXEDIT2.DAT"
 CALL OpenDataFiles(V1$, V2$)
 CLOSE #2, #3
 ' open data structure files.
 IF Windows.Detected THEN
    OPEN V1$ FOR RANDOM AS #2 LEN = LEN(WinFileStruc)
    OPEN V2$ FOR RANDOM AS #3 LEN = LEN(WinFileStruc)
 ELSE
    OPEN V1$ FOR RANDOM AS #2 LEN = LEN(DosFileStruc)
    OPEN V2$ 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
 LOCATE Xcoor + 3, Ycoor + 24
 PRINT SPACE$(8);
 LOCATE Xcoor + 3, Ycoor + 24
 COLOR White
 PRINT "(" + MID$(STR$(Num.Dirs), 2) + ")";
 COLOR Plain
 IF HeapSortOff THEN
    RETURN
 END IF
 IF Windows.Detected THEN
    GOSUB Win.Heap.Sort2
 ELSE
    GOSUB Dos.Heap.Sort2
 END IF
 RETURN

' display directory box.
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, 20 + Ycoor - 1, 1
    Q$ = Directories(VarX)
    Q$ = RTRIM$(Q$)
    PRINT LEFT$(Q$, 12);
 LOOP
 RETURN

' clear directory box.
ClearDirBox:
 FOR VarX = 1 TO 10
    LOCATE VarX + 5 + Xcoor - 1, 20 + Ycoor - 1, 1
    PRINT SPACE$(12);
 NEXT
 RETURN

' display directory.
DisplayCurrentDir:
 ' deconcatenate long path with \..\ characters
 Z$ = C$ + ":\" + D$
 CALL Deconcatenate(Z$, 32)
 LOCATE 3 + Xcoor - 1, 3 + Ycoor - 1, 1
 PRINT SPACE$(32);
 LOCATE 3 + Xcoor - 1, 3 + Ycoor - 1, 1
 PRINT UCASE$(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$(9);
 LOCATE Xcoor + 3, Ycoor + 9
 COLOR White
 PRINT "(" + MID$(STR$(Num.Files), 2) + ")";
 COLOR Plain
 IF HeapSortOff THEN
    RETURN
 END IF
 COLOR White
 LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
 PRINT SPACE$(26);
 LOCATE 2 + Xcoor - 1, 13 + Ycoor - 1, 1
 PRINT "Sorting..";
 COLOR Plain
 IF Windows.Detected THEN
    GOSUB Win.Heap.Sort1
 ELSE
    GOSUB Dos.Heap.Sort1
 END IF
 RETURN

' display filename box.
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
    Q$ = Filenames(VarX)
    Q$ = RTRIM$(Q$)
    PRINT LEFT$(Q$, 12);
 LOOP
 RETURN

' clear filename box.
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

' get default drives.
GetDrives:
 ' get current drive.
 InregsX.AX = &H1900
 CALL InterruptX(&H21, InregsX, OutregsX)
 Default.Drive = OutregsX.AX AND &HFF ' 0=a, 1=b,..

 ' get maximum drives.
 InregsX.AX = &H0E00
 InregsX.DX = Default.Drive
 CALL InterruptX(&H21, InregsX, OutregsX)
 Last.Drive = OutregsX.AX AND &HFF ' number of drives
 IF Last.Drive > 26 THEN
    Last.Drive = 26
 END IF
 RETURN

' clear current drive.
ClearDrive:
 COLOR Plain, Black
 LOCATE Xcoor + 4 + Drive.Box.Line, Ycoor + 35, 1
 PRINT "[" + CHR$(Current.Drive + 64) + "]";
 RETURN

' display current drive.
DisplayDrive:
 COLOR Black, Plain
 LOCATE Xcoor + 4 + Drive.Box.Line, Ycoor + 35, 1
 PRINT "[" + CHR$(Current.Drive + 64) + "]";
 COLOR Plain, Black
 RETURN

' clear drive box.
ClearDriveBox:
 FOR Var = 1 TO 10
    LOCATE Xcoor + 4 + Var, Ycoor + 35, 1
    PRINT "   ";
 NEXT
 RETURN

' display current drive.
InitDrives:
Current.Drive = 1
Drive.Box.Line = 1
V = ASC(C$) - 64
IF V <= Last.Drive THEN
   IF V > 10 THEN
      V = 10
   END IF
   Current.Drive = V
   Drive.Box.Line = V
END IF
GOSUB DisplayDrive
RETURN

' display available drives.
DisplayDrives:
 FOR Var = 1 TO Last.Drive
    IF Var > 10 THEN
       RETURN
    END IF
    LOCATE Xcoor + 4 + Var, Ycoor + 35, 1
    PRINT "[" + CHR$(Var + 64) + "]";
 NEXT
 RETURN

' process mouse button1.
MouseButton1:
 IsMenu = 0
 Mouse.Row = Mouse.RowX
 Mouse.Column = Mouse.ColumnX
 ' file box pageup
 IF Mouse.Row = Xcoor + 4 THEN
    IF Mouse.Column = Ycoor + 16 THEN
       I$ = CHR$(0) + CHR$(73)
       IsMenu = 1
       RETURN
    END IF
 END IF
 ' file box up
 IF Mouse.Row = Xcoor + 5 THEN
    IF Mouse.Column = Ycoor + 16 THEN
       I$ = CHR$(0) + CHR$(72)
       IsMenu = 1
       RETURN
    END IF
 END IF
 ' file box down
 IF Mouse.Row = Xcoor + 14 THEN
    IF Mouse.Column = Ycoor + 16 THEN
       I$ = CHR$(0) + CHR$(80)
       IsMenu = 1
       RETURN
    END IF
 END IF
 ' file box pagedown
 IF Mouse.Row = Xcoor + 15 THEN
    IF Mouse.Column = Ycoor + 16 THEN
       I$ = CHR$(0) + CHR$(81)
       IsMenu = 1
       RETURN
    END IF
 END IF
 ' directory box pageup
 IF Mouse.Row = Xcoor + 4 THEN
    IF Mouse.Column = Ycoor + 32 THEN
       I$ = CHR$(0) + CHR$(73)
       IsMenu = 2
       RETURN
    END IF
 END IF
 ' directory box up
 IF Mouse.Row = Xcoor + 5 THEN
    IF Mouse.Column = Ycoor + 32 THEN
       I$ = CHR$(0) + CHR$(72)
       IsMenu = 2
       RETURN
    END IF
 END IF
 ' directory box down
 IF Mouse.Row = Xcoor + 14 THEN
    IF Mouse.Column = Ycoor + 32 THEN
       I$ = CHR$(0) + CHR$(80)
       IsMenu = 2
       RETURN
    END IF
 END IF
 ' directory box pagedown
 IF Mouse.Row = Xcoor + 15 THEN
    IF Mouse.Column = Ycoor + 32 THEN
       I$ = CHR$(0) + CHR$(81)
       IsMenu = 2
       RETURN
    END IF
 END IF
 ' drive box up
 IF Mouse.Row = Xcoor + 5 THEN
    IF Mouse.Column = Ycoor + 39 THEN
       I$ = CHR$(0) + CHR$(72)
       IsMenu = 3
       RETURN
    END IF
 END IF
 ' drive box down
 IF Mouse.Row = Xcoor + 14 THEN
    IF Mouse.Column = Ycoor + 39 THEN
       I$ = CHR$(0) + CHR$(80)
       IsMenu = 3
       RETURN
    END IF
 END IF
 ' check mouse selection boundaries for file box.
 IF Mouse.Row >= Xcoor + 5 AND Mouse.Row <= Xcoor + 14 THEN
    IF Mouse.Column >= Ycoor + 3 AND Mouse.Column <= Ycoor + 14 THEN
       IF Num.Files > 0 THEN
          I$ = ""
          Valid = 0
          V = Mouse.Row - (Xcoor + 4)
          IF V = Box.Line THEN
             Valid = -1
          END IF
          IF V > Box.Line THEN
             IF Current.File + (V - Box.Line) <= Num.Files THEN
                Current.File = Current.File + (V - Box.Line)
                Valid = -1
             END IF
          END IF
          IF V < Box.Line THEN
             IF Current.File - (Box.Line - V) > 0 THEN
                Current.File = Current.File - (Box.Line - V)
                Valid = -1
             END IF
          END IF
          IF Valid THEN
             I$ = CHR$(13)
             IsMenu = 1
          END IF
       END IF
       RETURN
    END IF
 END IF
 ' check mouse selection boundaries for dir box.
 IF Mouse.Row >= Xcoor + 5 AND Mouse.Row <= Xcoor + 14 THEN
    IF Mouse.Column >= Ycoor + 19 AND Mouse.Column <= Ycoor + 31 THEN
       I$ = ""
       Valid = 0
       V = Mouse.Row - (Xcoor + 4)
       IF V = Dir.Box.Line THEN
          Valid = -1
       END IF
       IF V > Dir.Box.Line THEN
          IF Current.Dir + (V - Dir.Box.Line) <= Num.Dirs THEN
             Current.Dir = Current.Dir + (V - Dir.Box.Line)
             Valid = -1
          END IF
       END IF
       IF V < Dir.Box.Line THEN
          IF Current.Dir - (Dir.Box.Line - V) > 0 THEN
             Current.Dir = Current.Dir - (Dir.Box.Line - V)
             Valid = -1
          END IF
       END IF
       IF Valid THEN
          I$ = CHR$(13)
          IsMenu = 2
       END IF
       RETURN
    END IF
 END IF
 ' check mouse selection boundaries for drive box.
 IF Mouse.Row >= Xcoor + 5 AND Mouse.Row <= Xcoor + 14 THEN
    IF Mouse.Column >= Ycoor + 35 AND Mouse.Column <= Ycoor + 37 THEN
       I$ = ""
       Valid = 0
       V = Mouse.Row - (Xcoor + 4)
       IF V = Drive.Box.Line THEN
          Valid = -1
       END IF
       IF V > Drive.Box.Line THEN
          IF Current.Drive + (V - Drive.Box.Line) <= Last.Drive THEN
             Current.Drive = Current.Drive + (V - Drive.Box.Line)
             Drive.Box.Line = Drive.Box.Line + (V - Drive.Box.Line)
             Valid = -1
          END IF
       END IF
       IF V < Drive.Box.Line THEN
          IF Current.Drive - (Drive.Box.Line - V) > 0 THEN
             Current.Drive = Current.Drive - (Drive.Box.Line - V)
             Drive.Box.Line = Drive.Box.Line - (Drive.Box.Line - V)
             Valid = -1
          END IF
       END IF
       IF Valid THEN
          I$ = CHR$(13)
          IsMenu = 3
       END IF
       RETURN
    END IF
 END IF
 RETURN

' simple error routine
Error.Routine3:
 IF Check.Disk THEN
    IF ERR = 57 THEN
       Disk.Ready = True
       RESUME NEXT
    END IF
    IF ERR = 71 THEN
       Disk.Ready = True
       RESUME NEXT
    END IF
    IF ERR = 76 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, .CFG file, or DOS file handles, then restart."
 COLOR Plain
 END
END SUB
