REM Program: Hex Editor v5.1a, Module 5 of 5, PD 2003.
REM Author: Erik Jon Oredson AS. Csci
REM Release: 10/03/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:

REM These variables are set before a call to menu:
'   check mouse present.
' Mouse.Present = TestMouse
'   verify windows loaded.
' Windows.Detected = TestWindows

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. No leading or trailing spaces.

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

' during editing,
'   I$  -  Current keystroke.
'   F$  -  Fully qualified pathname with filename and drive letter.
'   Q$  -  Current subdirectory.
'   D1$ -  Temporary directory storage.
'   X1$ -  Temporary file entry area path/file.
'   X2$ -  Temporary filename storage.

' mouse variables,
'   IsMenu =
'     1  -  Click in file box.
'     2  -  Click in dir box.
'     3  -  Click in drive box.
'     4  -  Click in entry area.
'     5  -  Click on 'x' to exit.

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

' restore data.
RESTORE

' read Alt-<key> data.
DIM Keys(26) AS INTEGER
FOR Var = 1 TO 26
   READ Keys(Var)
NEXT

' reset flags.
Ambiguate = AmbiguateSwitch

' open structure files.
GOSUB OpenDataFiles1

' display menu screen.
GOSUB MainMenu

' get current drive/directory.
Current.Drive = False
GOSUB GetDrives
GOSUB InitDrive
GOSUB InitDir

' get current filespec.
GOSUB InitFileSpec

' get current directory spec.
GOSUB InitDirSpec

' 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

' display all drives.
GOSUB InitDrives

' check mouse.
IF Mouse.Present THEN
   ' position mouse.
   CALL MouseFunction2(1,1)

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

' reset filename attribute overrides.
RequireReadOnly = False
RequireHidden = False
RequireSystem = False
RequireArchive = False

' file entry area variables:
'ProcessEditLine - processes X$ edit line when set to True.
'Xstart     - hilights file entry area for overstrike when set to True.
'Xposition1 - left position in file entry area editing string.
'Xposition2 - position of character in file entry area editing string.

' main input loop.
Xstart = True
Xposition1 = 1
DO
   ' reset filespec.
   IF X$ = "" THEN
      X$ = "*.*"
      Xposition1 = 1
      Xposition2 = 3
   END IF

   ' display file entry area.
   GOSUB DisplayFileLine

   ' start input loop.
   DO
      ' reset input.
      I$ = ""

      ' reset edit line.
      ProcessEditLine = False

      ' process input.
      DO
         ' get keypress.
         I$ = INKEY$

         ' process keypress.
         IF LEN(I$) THEN
            IsMenu = False
            EXIT DO
         END IF

         ' call mouse subroutine.
         CALL MouseDriver

         ' check exit symbol.
         IF IsMenu = 5 THEN
            I$ = CHR$(27)
            EXIT DO
         END IF

         ' check left mouse button.
         IF Mouse.ButtonX THEN
            GOSUB MouseButton1Z
            SELECT CASE IsMenu
            CASE 1 ' file box.
               IF I$ = CHR$(13) THEN
                  E$ = RTRIM$(Filenames(Current.File))
                  GOTO EndLoop2
               ELSE
                  GOSUB FileBoxKey
               END IF
            CASE 2 ' dir box.
               IF I$ = CHR$(13) THEN
                  GOSUB GetNewPath
                  EXIT DO
               ELSE
                  GOSUB Dirboxkey
               END IF
            CASE 3 ' drive box.
               IF I$ = CHR$(13) THEN
                  GOSUB SelectDrive
                  IF Valid THEN
                     I$ = ""
                     EXIT DO
                  END IF
               ELSE
                  GOSUB Driveboxkey
               END IF
            END SELECT
         ELSE
            ' check mouse position.
            IF Mouse.Row OR Mouse.Column THEN
               GOSUB MouseOverX1
               GOSUB DisplayFileLine
            END IF
         END IF

         ' release time slice,
         ' (speeds up mouse in windows).
         Var = ReleaseTime
      LOOP

      ' ignore network slash
      IF I$ = "/" THEN
         I$ = ""
      END IF

      ' check alt-<key>
      IF LEN(I$) = 2 THEN

         ' get alt keycode.
         Var = ASC(RIGHT$(I$, 1))

         ' compare all Alt-n keys
         FOR Var2 = 1 TO 26
            ' check key.
            IF Keys(Var2) = Var THEN
               ' specify drive letter.
               X$ = CHR$(Var2 + 64) + ":\"
               I$ = ""
               ProcessEditLine = True
               EXIT DO
            END IF
         NEXT
      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 = False
               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 59 ' F1 changes drive letter.
            I$ = ""
            LOCATE Xcoor + 1, Ycoor + 2, 1
            PRINT SPACE$(38);
            LOCATE Xcoor + 1, Ycoor + 2, 1
            COLOR Yellow, Black
            PRINT "Drive letter: ";
            DO
               Z$ = INKEY$
               IF LEN(Z$) = 1 THEN
                  Z$ = UCASE$(Z$)
                  IF Z$ >= "A" AND Z$ <= "Z" THEN
                     EXIT DO
                  END IF
               END IF
            LOOP
            PRINT Z$;
            X$ = UCASE$(Z$) + ":\"
            I$ = ""
            ProcessEditLine = True
            EXIT DO
         CASE 60 ' F2 toggles heap sorting.
            I$ = ""
            HeapSortOff = NOT HeapSortOff
            LOCATE Xcoor + 1, Ycoor + 2, 1
            PRINT SPACE$(38);
            LOCATE 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 UpdateDisplay
            EXIT DO
         CASE 61 ' F3 moves file menu box.
            GOSUB HMouse
            I$ = ""
            LOCATE Xcoor + 1, Ycoor + 2, 1
            PRINT SPACE$(38);
            LOCATE Xcoor + 1, Ycoor + 2, 1
            COLOR White, Black
            PRINT "Use cursor keys. Press <esc> to quit.";
            ' move menu.
            GOSUB StoreArea
            COLOR white, blue
            CLS
            GOSUB RestoreArea
            I$ = ""
            DO
               I$ = INKEY$
               IF LEN(I$) THEN
                  IF I$ = CHR$(27) THEN
                     I$ = ""
                     EXIT DO
                  END IF
                  IF LEN(I$) = 2 THEN
                     SELECT CASE ASC(RIGHT$(I$, 1))
                     CASE 72 ' up
                        IF Xcoor - 1 >= 2 THEN
                           Xcoor = Xcoor - 1
                           COLOR white, blue
                           CLS
                           GOSUB RestoreArea
                        END IF
                     CASE 80 ' down
                        IF Xcoor + 1 <= 9 THEN
                           Xcoor = Xcoor + 1
                           COLOR white, blue
                           CLS
                           GOSUB RestoreArea
                        END IF
                     CASE 75 ' left
                        IF Ycoor - 1 >= 1 THEN
                           Ycoor = Ycoor - 1
                           COLOR white, blue
                           CLS
                           GOSUB RestoreArea
                        END IF
                     CASE 77 ' right
                        IF Ycoor + 1 <= 39 THEN
                           Ycoor = Ycoor + 1
                           COLOR white, blue
                           CLS
                           GOSUB RestoreArea
                        END IF
                     END SELECT
                  END IF
               END IF
            LOOP
            GOSUB BottomRow
            GOSUB DisplayCurrentPath
            IF Num.Files > 0 THEN
               GOSUB DisplayLongName2
            END IF
            GOSUB DisplayFilenamex
            GOSUB DisplayFileLine
            GOSUB SMouse
         CASE 62 ' F4 backward 1 drive letter.
            I$ = ""
            V = ASC(C$)
            IF V > 65 THEN
               V = V - 1
               X$ = CHR$(V) + ":\"
               ProcessEditLine = True
               EXIT DO
            END IF
         CASE 63 ' F5 forward 1 drive letter.
            I$ = ""
            V = ASC(C$) - 64
            IF V + 1 <= Last.Drive THEN
               V = V + 1
               X$ = CHR$(V + 64) + ":\"
               ProcessEditLine = True
               EXIT DO
            END IF
         CASE 64 ' F6 toggle ambiguate.
            I$ = ""
            Ambiguate = NOT Ambiguate
            LOCATE Xcoor + 1, Ycoor + 2, 1
            PRINT SPACE$(38);
            LOCATE Xcoor + 1, Ycoor + 2, 1
            COLOR White, Black
            IF Ambiguate = False THEN
               PRINT "Ambiguation Off. Press <esc>:";
            ELSE
               PRINT "Ambiguation On. Press <esc>:";
            END IF
            WHILE INKEY$<>CHR$(27)
            WEND
            GOSUB UpdateDisplay
            EXIT DO
         CASE 65 ' F7 redraw screen
            GOSUB RedrawScreen
            EXIT DO
         CASE 66 ' F8 attribute override
            I$ = ""
            LOCATE Xcoor + 1, Ycoor + 2, 1
            PRINT SPACE$(38);
            LOCATE Xcoor + 1, Ycoor + 2, 1
            COLOR White, Black
            PRINT "Require read-only bit. Press <y/n>:";
            DO
               M$ = ""
               WHILE M$ = ""
                  M$ = INKEY$
               WEND
               M$ = UCASE$(M$)
               IF M$ = "Y" THEN
                  RequireReadOnly = True
                  EXIT DO
               END IF
               IF M$ = "N" THEN
                  RequireReadOnly = False
                  EXIT DO
               END IF
            LOOP
            LOCATE Xcoor + 1, Ycoor + 2, 1
            PRINT SPACE$(38);
            LOCATE Xcoor + 1, Ycoor + 2, 1
            COLOR White, Black
            PRINT "Require hidden bit. Press <y/n>:";
            DO
               M$ = ""
               WHILE M$ = ""
                  M$ = INKEY$
               WEND
               M$ = UCASE$(M$)
               IF M$ = "Y" THEN
                  RequireHidden = True
                  EXIT DO
               END IF
               IF M$ = "N" THEN
                  RequireHidden = False
                  EXIT DO
               END IF
            LOOP
            LOCATE Xcoor + 1, Ycoor + 2, 1
            PRINT SPACE$(38);
            LOCATE Xcoor + 1, Ycoor + 2, 1
            COLOR White, Black
            PRINT "Require system bit. Press <y/n>:";
            DO
               M$ = ""
               WHILE M$ = ""
                  M$ = INKEY$
               WEND
               M$ = UCASE$(M$)
               IF M$ = "Y" THEN
                  RequireSystem = True
                  EXIT DO
               END IF
               IF M$ = "N" THEN
                  RequireSystem = False
                  EXIT DO
               END IF
            LOOP
            LOCATE Xcoor + 1, Ycoor + 2, 1
            PRINT SPACE$(38);
            LOCATE Xcoor + 1, Ycoor + 2, 1
            COLOR White, Black
            PRINT "Require archive bit. Press <y/n>:";
            DO
               M$ = ""
               WHILE M$ = ""
                  M$ = INKEY$
               WEND
               M$ = UCASE$(M$)
               IF M$ = "Y" THEN
                  RequireArchive = True
                  EXIT DO
               END IF
               IF M$ = "N" THEN
                  RequireArchive = False
                  EXIT DO
               END IF
            LOOP
            GOSUB UpdateDisplay
            EXIT DO
         CASE 133 ' F11 Drop to DOS
            COLOR Plain
            CLS
            PRINT "Type 'Exit' to return to editor.."
            SHELL
            GOSUB RedrawScreen
            EXIT DO
         CASE ELSE
            I$ = "" ' nul activity
         END SELECT
         I$ = "" ' nul keystroke
      END IF
' tab key label.
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
            ' tab from drive input loop.
            IF I$ = CHR$(9) THEN
               I$ = ""
               EXIT DO
            END IF
            ' shift-tab from dir input loop.
            IF I$ = CHR$(0) + CHR$(15) THEN
               I$ = ""
               EXIT DO
            END IF
            ' click on file entry area.
            IF IsMenu = 4 THEN
               GOSUB DisplayCurrentPath
               IF Num.Files > 0 THEN
                  GOSUB DisplayLongName2
               END IF
               EXIT DO
            END IF
            IF I$ = CHR$(13) THEN
               SELECT CASE IsMenu
               CASE 1
                  E$ = RTRIM$(Filenames(Current.File))
                  GOTO EndLoop2
               CASE 2
                  GOSUB GetNewPath
               CASE 3
                  I$ = ""
                  GOSUB SelectDrive
                  GOSUB DisplayCurrentPath
                  IF Valid THEN
                     EXIT DO
                  END IF
               CASE 4
                  GOSUB DisplayCurrentPath
                  IF Num.Files > 0 THEN
                     GOSUB DisplayLongName2
                  END IF
                  EXIT DO
               CASE 5
                  I$ = CHR$(27)
                  EXIT DO
               CASE ELSE
                  E$ = RTRIM$(Filenames(Current.File))
                  GOTO EndLoop2
               END SELECT
            END IF
         ELSE
            GOSUB DirInputLoop
            ' tab from drive input loop.
            IF I$ = CHR$(9) THEN
               I$ = ""
               EXIT DO
            END IF
            ' shift-tab from drive input loop.
            IF I$ = CHR$(0) + CHR$(15) THEN
               I$ = ""
               EXIT DO
            END IF
            IF IsMenu = 4 THEN
               GOSUB DisplayCurrentPath
               IF Num.Files > 0 THEN
                  GOSUB DisplayLongName2
               END IF
               EXIT DO
            END IF
            IF I$ = CHR$(13) THEN
               SELECT CASE IsMenu
               CASE 1
                  E$ = RTRIM$(Filenames(Current.File))
                  GOTO EndLoop2
               CASE 2
                  GOSUB GetNewPath
               CASE 3
                  I$ = ""
                  GOSUB SelectDrive
                  GOSUB DisplayCurrentPath
                  IF Valid THEN
                     EXIT DO
                  END IF
               CASE 4
                  GOSUB DisplayCurrentPath
                  IF Num.Files > 0 THEN
                     GOSUB DisplayLongName2
                  END IF
                  EXIT DO
               CASE 5
                  I$ = CHR$(27)
                  EXIT DO
               CASE ELSE
                  GOSUB GetNewPath
               END SELECT
            END IF
         END IF
      END IF

      ' enter key.
      IF I$ = CHR$(13) THEN
         I$ = ""
         ProcessEditLine = True
         EXIT DO
      END IF

      ' escape key.
      IF I$ = CHR$(27) THEN
         EXIT DO ' exit box.
      END IF

      ' backspace.
      IF I$ = CHR$(8) THEN
         IF LEN(X$) THEN
            IF Xstart = True AND Xposition2 = 0 THEN
               X$ = ""
               Xstart = False
               Xposition1 = 1
               Xposition2 = 0
               GOSUB DisplayFileLine
            ELSE
               IF XPosition2 > 0 THEN
                  Xstart = False
                  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
         END IF
      ELSE
         ' append/insert character into filename area.
         IF LEN(I$) THEN
            ' error check input length.
            IF LEN(X$) >= 32767 THEN
               X$ = ""
               Xstart = False
               Xposition1 = 1
               Xposition2 = 0
               LOCATE Xcoor + 1, Ycoor + 2, 1
               PRINT SPACE$(38);
               LOCATE Xcoor + 1, Ycoor + 2, 1
               COLOR White, Black
               PRINT "Edit line error. Press <esc>:";
               WHILE INKEY$<>CHR$(27)
               WEND
            ELSE
               IF Xstart THEN
                  X$ = ""
                  Xstart = False
                  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
      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

   ' process edit line in X$.

   ' parses drive/path/filename with
   '  partial pathname override and
   '  filename ambiguation detection.

   ' also parses imbedded path retracting.
   IF ProcessEditLine THEN

      ' store values.
      D1$ = D$
      X2$ = F$

      ' 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
            GOSUB InitFileSpec
            Xstart = True
            GOTO EndLoop1
         END IF
         IF OutregsX.AX = &HFFFF THEN
            GOSUB PromptDisk
            GOSUB InitFileSpec
            Xstart = True
            GOTO EndLoop1
         END IF
         ' store new drive.
         C$ = Z$ ' new drive.
         D$ = "" ' root.
         Current.Drive = ASC(Z$) - 64 ' drive number.
      END IF

      ' parse out imbedded \.\ path.
      GOSUB PathOverride1

      ' parse out trailing \.. path with multiple dots.
      GOSUB PathOverride2

      ' parse out leading ..\ path with multiple dots.
      GOSUB PathOverride3

      ' parse out leading \..\ path with multiple dots.
      GOSUB PathOverride4

      ' parse out imbedded \..\ path with multiple dots.
      GOSUB PathOverride5

      ' parse out imbedded \\ from path.
      GOSUB PathOverride6

      ' parse off directory.
      IF INSTR(X$, "\") THEN
         FOR Var = LEN(X$) TO 1 STEP -1
            IF MID$(X$, Var, 1) = "\" THEN
               EXIT FOR
            END IF
         NEXT

         ' parse filename.
         SELECT CASE Var
         CASE 1 ' check root.
            D$ = ""
            X$ = MID$(X$, Var + 1)
         CASE LEN(X$) ' check nul filename.
            D$ = LEFT$(X$, Var - 1)
            X$ = ""
         ' parse directory/filename.
         CASE ELSE
            IF LEFT$(X$, 1) = "\" THEN
               D$ = LEFT$(X$, Var - 1)
            ELSE
               D$ = D$ + "\" + LEFT$(X$, Var - 1)
            END IF
            X$ = MID$(X$, Var + 1)
         END SELECT
      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.
      GOSUB CheckPath
      IF ValidPath = False THEN
         D$ = D1$
         X$ = X1$
         Xposition1 = 1
         Xposition2 = 0
         GOTO EndLoop1
      END IF
      GOSUB CheckPath2
      IF ValidPath = False THEN
         D$ = D1$
         X$ = X1$
         Xposition1 = 1
         Xposition2 = 0
         GOTO EndLoop1
      END IF

      ' store directory.
      D3$ = D$
      X3$ = X$

      ' prevents directory from loading twice.
      LoadedDir = False

      ' check filename.
      IF X$ = STRING$(LEN(X$), ".") THEN
         ' strip multiple dots from path.
         GOSUB PathOverride7
      END IF

      ' construct partial path.
      IF D$ = "" THEN
         D$ = X$
      ELSE
         IF X$ <> "" THEN
            D$ = D$ + "\" + X$
         END IF
      END IF

      ' check path.
      GOSUB CheckPath

      ' check path is file.
      IF OutregsX.AX = 32 THEN ' sharing violation.
         ValidPath = False
      END IF

      ' check valid path.
      IF ValidPath = False THEN
         D$ = D3$
         X$ = X3$
      END IF

      ' check valid path.
      IF ValidPath THEN
         ' check directory already loaded.
         IF D$ <> D1$ THEN
            ' load current directory.
            GOSUB LoadDirSpec
         END IF
         X$ = "" ' reset filename.
         LoadedDir = True ' set loaded flag.
      END IF

      ' check filename.
      IF X$ = "" THEN
         GOSUB InitFileSpec
      END IF

      ' search for directory spec override.
      IF LoadedDir = False THEN
         FOR Var = 1 TO Num.Dirs
            S$ = UCASE$(RTRIM$(Directories(Var)))

            ' check X$ is directory in current one.
            IF D$ = "" THEN
               ASCIIZ = "\" + S$ + CHR$(0)
            ELSE
               ASCIIZ = "\" + D$ + "\" + S$ + CHR$(0)
            END IF

            ' get conanicalized directory name.
            V4 = False
            GOSUB ShortFilenameX

            ' check both directory names.
            IF UCASE$(X$) = S$ OR UCASE$(X$) = Short.Filename$ THEN

               ' store case of directory.
               S$ = RTRIM$(Directories(Var))

               ' store directory.
               IF D$ = "" THEN
                  D$ = S$
               ELSE
                  D$ = D$ + "\" + S$
               END IF

               ' restore filename override.
               GOSUB InitFileSpec
               EXIT FOR
            END IF
         NEXT
      END IF

      ' store current filespec.
      IF X$ = "." THEN
         X$ = ""
      END IF

      ' store and load directory.
      IF LoadedDir = False THEN
         ' load directories.
         GOSUB LoadNewDir
      ELSE
         ' init directory load.
         GOSUB LoadNewDir2
      END IF

      ' store filename.
      GOSUB InitDirSpec

      ' store filename.
      X1$ = X$
      Xposition1 = 1
      Xposition2 = 0

      ' compare filespecs.
      IF UCASE$(F$) <> UCASE$(X2$) THEN
         X2$ = F$ ' store filespec.
         GOSUB LoadNewFiles ' load file box.
      END IF

      ' search for filename spec override.
      FOR Var = 1 TO Num.Files
         S$ = UCASE$(RTRIM$(Filenames(Var)))

         ' check X$ is filename in current directory.
         IF D$ = "" THEN
            ASCIIZ = "\" + S$ + CHR$(0)
         ELSE
            ASCIIZ = "\" + D$ + "\" + S$ + CHR$(0)
         END IF

         ' get conanicalized filename.
         V4 = False
         GOSUB ShortFilenameX

         ' check both filenames.
         IF UCASE$(X$) = S$ OR UCASE$(X$) = Short.Filename$ THEN
            E$ = RTRIM$(Filenames(Var)) ' select file for editing.
            EXIT DO
         END IF
      NEXT

      ' construct dir/filename.
      IF D$ = "" THEN
         V$ = "\" + X$
      ELSE
         V$ = "\" + D$ + "\" + X$
      END IF

      ' check filename characters.
      IF INSTR(V$, "?") = 0 THEN
         IF INSTR(V$, "*") = 0 THEN

            ' check filename could or does exist.
            IF TestFile(V$) THEN
               E$ = X$ ' select file for editing.
               EXIT DO
            END IF
         END IF
      END IF

      ' display all drives.
      GOSUB InitDrives
      Xstart = True
   END IF
EndLoop1:
LOOP

' exit editing loop.
EndLoop2:

' exit file menu box.
GOSUB HMouse
COLOR Plain, Black
CLS

' return to editor.
EXIT SUB

' reset file menu box.
UpdateDisplay:
 GOSUB DisplayFilenamex
 COLOR Plain, Black
 GOSUB ClearDirBox
 GOSUB LoadDirSpec
 GOSUB DisplayDirSpec
 GOSUB DisplayCurrentDir
 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
 GOSUB InitDrives
 RETURN

' init filespec.
InitFileSpec:
 ' compare stored filename.
 IF X1$ = "" THEN
    X$ = "*.*"
    Xposition1 = 1
    Xposition2 = 3
 ELSE
    ' restore filename spec.
    X$ = X1$
    Xposition1 = 1
    Xposition2 = 0
 END IF
 ' check filename.
 IF X$ = "." THEN
    X$ = ""
 END IF
 RETURN

' init current directory.
InitDirSpec:
 IF D$ = "" THEN
    F$ = C$ + ":\" + X$
 ELSE
    F$ = C$ + ":\" + D$ + "\" + X$
 END IF
 RETURN

' parse out imbedded \.\ path.
PathOverride1:
 IF LEN(X$) THEN
    DO
       V = INSTR(X$, "\.\")
       IF V THEN
          X$ = LEFT$(X$, V) + MID$(X$, V + 3)
       ELSE
          EXIT DO
       END IF
    LOOP
 END IF
 RETURN

' parse out trailing \.. path with multiple dots.
PathOverride2:
 Z$ = ""
 IF LEN(X$) THEN
    ' search for trailing path.
    DO
       Z = 0
       L = 0
       IF RIGHT$(X$, 1) = "." THEN
          FOR V = LEN(X$) TO 1 STEP -1
             IF MID$(X$, V, 1) = "." THEN
                L = L + 1
             ELSE
                IF MID$(X$, V, 1) = "\" THEN
                   Z = -1
                   EXIT FOR
                ELSE
                   EXIT FOR
                END IF
             END IF
          NEXT
       END IF
       IF Z = 0 THEN
          EXIT DO
       END IF
       Z$ = MID$(X$, V) + Z$
       X$ = LEFT$(X$, V - 1)
    LOOP
    IF Z$ = "" THEN
       ' strip trailing dots.
       IF INSTR(X$, "\") THEN
          DO
             IF RIGHT$(X$, 1) = "." THEN
                X$ = LEFT$(X$, LEN(X$) - 1)
             ELSE
                EXIT DO
             END IF
          LOOP
       END IF
       RETURN
    END IF
    DO
       ' search leading dots.
       L = 0
       FOR V = 2 TO LEN(Z$)
          IF MID$(Z$, V, 1) = "." THEN
             L = L + 1
             IF V = LEN(Z$) THEN
                Z$ = ""
                EXIT FOR
             END IF
          ELSE
             IF MID$(Z$, V, 1) = "\" THEN
                Z$ = MID$(Z$, V)
                EXIT FOR
             END IF
          END IF
       NEXT
       ' strip trailing path.
       DO
          L2 = 1
          Z = 0
          FOR V = LEN(X$) TO 1 STEP -1
             IF MID$(X$, V, 1) = "\" THEN
                L2 = L2 + 1
                IF L = L2 THEN
                   Z = -1
                   EXIT DO
                END IF
             END IF
          NEXT
          IF Z = 0 THEN
             EXIT DO
          END IF
       LOOP
       IF Z = 0 THEN
          X$ = ""
          EXIT DO
       END IF
       IF V = 1 THEN
          IF LEFT$(X$, 1) = "\" THEN
             X$ = "\"
             EXIT DO
          END IF
       END IF
       X$ = LEFT$(X$, V - 1)
       IF Z$ = "" THEN
          EXIT DO
       END IF
    LOOP
 END IF
 ' strip trailing dots.
 IF INSTR(X$, "\") THEN
    DO
       IF RIGHT$(X$, 1) = "." THEN
          X$ = LEFT$(X$, LEN(X$) - 1)
       ELSE
          EXIT DO
       END IF
    LOOP
 END IF
 RETURN

' parse out leading ..\ path with multiple dots.
PathOverride3:
 Z$ = D$
 DO
    ' search for leading dots.
    Z = 0
    L = 0
    IF LEFT$(X$, 1) = "." THEN
       FOR V = 1 TO LEN(X$)
          IF MID$(X$, V, 1) = "." THEN
             L = L + 1
          ELSE
             IF MID$(X$, V, 1) = "\" THEN
                Z = -1
                EXIT FOR
             ELSE
                EXIT FOR
             END IF
          END IF
       NEXT
    END IF
    IF Z = 0 THEN
       EXIT DO
    END IF
    X$ = MID$(X$, V + 1)
    ' parse off trailing path.
    IF L > 1 THEN
    L2 = 1
       DO
          Z = 0
          FOR V = LEN(Z$) TO 1 STEP -1
             IF MID$(Z$, V, 1) = "\" THEN
                Z$ = LEFT$(Z$, V - 1)
                L2 = L2 + 1
                Z = -1
                EXIT FOR
             END IF
          NEXT
          IF Z = 0 THEN
             Z$ = ""
             EXIT DO
          END IF
          IF L2 = L THEN
             EXIT DO
          END IF
       LOOP
    END IF
 LOOP
 D$ = Z$
 RETURN

' parse out leading \..\ path with multiple dots.
PathOverride4:
 DO
    IF LEFT$(X$, 1) = "\" THEN
       IF LEN(X$) = 1 THEN
          EXIT DO
       END IF
       L = 0
       FOR V = 2 TO LEN(X$)
          IF MID$(X$, V, 1) = "." THEN
             L = L + 1
          ELSE
             IF MID$(X$, V, 1) = "\" THEN
                IF L > 0 THEN
                   X$ = MID$(X$, V)
                   EXIT FOR
                END IF
             END IF
             EXIT DO
          END IF
       NEXT
    ELSE
       EXIT DO
    END IF
 LOOP
 RETURN

' parse out imbedded \..\ path with multiple dots.
PathOverride5:
 IF LEN(X$) THEN
    DO
       ' search for \.\
       Z = 0
       FOR V = 1 TO LEN(X$)
          IF MID$(X$, V, 1) = "\" THEN
             L = 0
             FOR V2 = V + 1 TO LEN(X$)
                IF MID$(X$, V2, 1) = "." THEN
                   L = L + 1
                ELSE
                   IF MID$(X$, V2, 1) = "\" THEN
                      IF L > 0 THEN
                         Z = -1
                      END IF
                      EXIT FOR
                   ELSE
                      EXIT FOR
                   END IF
                END IF
             NEXT
          END IF
          IF Z = -1 THEN
             EXIT FOR
          END IF
       NEXT
       IF Z = 0 THEN
          EXIT DO
       END IF
       Z$ = "\" + STRING$(L, ".") + "\"
       V4 = INSTR(X$, Z$)
       A$ = MID$(X$, V4 + L + 2)
       L2 = 1
       DO
          V4 = V4 - 1
          IF V4 = 0 THEN
             EXIT DO
          END IF
          IF MID$(X$, V4, 1) = "\" THEN
             L2 = L2 + 1
             IF L2 = L THEN
                EXIT DO
             END IF
          END IF
       LOOP
       IF V4 = 0 THEN
          X$ = A$
       ELSE
          X$ = LEFT$(X$, V4) + A$
       END IF
    LOOP
 END IF
 ' search for imbedded ..\
 DO
    V = INSTR(X$, ".\")
    IF V THEN
       L = 0
       FOR V2 = V TO 1 STEP -1
          IF MID$(X$, V2, 1) = "." THEN
             L = L + 1
          ELSE
             X$ = LEFT$(X$, V2) + MID$(X$, V + 1)
             EXIT FOR
          END IF
       NEXT
    ELSE
       EXIT DO
    END IF
 LOOP
 RETURN

' strip imbedded \\ from path.
PathOverride6:
 DO
    V = INSTR(X$, "\\")
    IF V THEN
       X$ = LEFT$(X$, V - 1) + MID$(X$, V + 1)
    ELSE
       EXIT DO
    END IF
 LOOP
 RETURN

' strip multiple dots from path.
PathOverride7:
 DO
    IF LEFT$(X$, 2) = ".." THEN
       Z = 0
       FOR Var = LEN(D$) TO 1 STEP -1
          IF MID$(D$, Var, 1) = "\" THEN
             D$ = LEFT$(D$, Var - 1)
             X$ = MID$(X$, 2)
             Z = -1
             EXIT FOR
          END IF
       NEXT
       IF Z = 0 THEN
          D$ = ""
          X$ = ""
          EXIT DO
       END IF
    ELSE
       X$ = ""
       EXIT DO
    END IF
 LOOP
 RETURN

' inits dir box with new dirspec.
LoadNewDir:
 Current.Dir = 1
 Dir.Box.Line = 1
 GOSUB ClearDirBox
 GOSUB CheckPath
 IF ValidPath = False THEN
    D$ = D1$
    X$ = X1$
    Xposition1 = 1
    Xposition2 = 0
 END IF
 GOSUB LoadDirSpec
 GOSUB DisplayDirSpec
 GOSUB DisplayCurrentDir
 GOSUB DisplayCurrentPath
 RETURN

' inits dir box without new dirspec.
LoadNewDir2:
 Current.Dir = 1
 Dir.Box.Line = 1
 GOSUB ClearDirBox
 GOSUB CheckPath
 IF ValidPath = False THEN
    D$ = D1$
    X$ = X1$
    Xposition1 = 1
    Xposition2 = 0
 END IF
 GOSUB DisplayDirSpec
 GOSUB DisplayCurrentDir
 GOSUB DisplayCurrentPath2
 RETURN

' inits file box.
LoadNewFiles:
 GOSUB ClearFileBox
 GOSUB LoadFileSpec
 GOSUB DisplayFileSpec
 IF Num.Files > 0 THEN
    Current.File = 1
    Box.Line = 1
    GOSUB InitFiles
 ELSE
    GOSUB ClearLongName2
 END IF
 RETURN

' display current filename entry area.
DisplayFileLine:
 GOSUB HMouse
 LOCATE Xcoor + 1, Ycoor + 12, 1
 PRINT SPACE$(26);
 ' check hilighting.
 IF Xstart THEN
    COLOR Black, Plain
 END IF
 ' display edit line and position cursor.
 LOCATE Xcoor + 1, Ycoor + 12, 1
 PRINT MID$(X$, Xposition1, 26);
 LOCATE Xcoor + 1, Ycoor + Xposition2 - Xposition1 + 13, 1
 COLOR Plain, Black
 GOSUB SMouse
 RETURN

' display invalid disk message.
PromptDisk:
 GOSUB HMouse
 LOCATE Xcoor + 1, Ycoor + 2, 1
 PRINT SPACE$(38);
 LOCATE 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$;
 GOSUB SMouse
 RETURN

' display filename line.
DisplayFilenamex:
 GOSUB HMouse
 LOCATE Xcoor + 1, Ycoor + 2, 1
 PRINT SPACE$(38);
 LOCATE Xcoor + 1, Ycoor + 2, 1
 COLOR White, Black
 PRINT "Filename: ";
 COLOR Plain, Black
 GOSUB SMouse
 RETURN

' init filename input loop.
InitFiles:
 E$ = RTRIM$(Filenames(1))
 GOSUB HMouse
 COLOR Black, Plain
 LOCATE Xcoor + 5, Ycoor + 3, 1
 PRINT LEFT$(E$, 12);
 COLOR Plain, Black
 GOSUB DisplayLongName2
 GOSUB SMouse
 RETURN

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

       ' call mouse subroutine.
       CALL MouseDriver

       ' check file entry area.
       IF IsMenu >= 4 THEN
          RETURN
       END IF

       ' check left mouse button.
       IF Mouse.ButtonX THEN
          GOSUB MouseButton1Z
          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
       ELSE
          ' check mouse position.
          IF Mouse.Row OR Mouse.Column THEN
             GOSUB MouseOverX1
             IF Current.File > 0 THEN
                GOSUB DisplayLongName2
                GOSUB ClearFilename
                GOSUB DisplayFilename
             END IF
          END IF
       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
          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 IsMenu >= 4 THEN
          RETURN
       END IF
       IF I$ = CHR$(9) THEN
          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:
 GOSUB HMouse
 LOCATE Box.Line + Xcoor + 4, Ycoor + 3, 1
 COLOR Plain, Black
 PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
 GOSUB SMouse
 RETURN

' display filename.
DisplayFilename:
 E$ = RTRIM$(Filenames(Current.File))
 GOSUB HMouse
 COLOR Plain, Black
 LOCATE Xcoor + 1, Ycoor + 12, 1
 PRINT SPACE$(26);
 LOCATE Xcoor + 1, Ycoor + 12, 1
 GOSUB TruncateFilename
 PRINT A$;
 LOCATE Box.Line + Xcoor + 4, Ycoor + 3, 1
 COLOR Black, Plain
 PRINT LEFT$(E$, 12);
 COLOR Plain, Black
 GOSUB SMouse
 RETURN

' display filename.
DisplayFilename2:
 E$ = RTRIM$(Filenames(Current.File))
 GOSUB HMouse
 COLOR Plain, Black
 LOCATE Xcoor + 1, Ycoor + 12, 1
 PRINT SPACE$(26);
 LOCATE Xcoor + 1, Ycoor + 12, 1
 GOSUB TruncateFilename
 PRINT A$;
 GOSUB ClearFileBox
 COLOR Plain, Black
 GOSUB SMouse
 RETURN

' display filename.
DisplayFilename3:
 GOSUB HMouse
 COLOR Black, Plain
 LOCATE Xcoor + 14, Ycoor + 3, 1
 PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
 GOSUB SMouse
 RETURN

' display filename.
DisplayFilename4:
 GOSUB HMouse
 COLOR Black, Plain
 LOCATE Xcoor + 5, Ycoor + 3, 1
 PRINT LEFT$(RTRIM$(Filenames(Current.File)), 12);
 GOSUB SMouse
 RETURN

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

' updates filename box.
DisplayFileBox2:
 GOSUB HMouse
 FOR V = 1 TO 9
    IF Current.File + V <= Num.Files THEN
       LOCATE Xcoor + V + 5, Ycoor + 3, 1
       PRINT LEFT$(RTRIM$(Filenames(Current.File + V)), 12);
    END IF
 NEXT
 GOSUB SMouse
 RETURN

' display init directory.
DisplayInitDir:
 Q$ = RTRIM$(Directories(Current.Dir))
 LOCATE Dir.Box.Line + Xcoor + 4, Ycoor + 19, 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 = False
          EXIT DO
       END IF

       ' call mouse subroutine.
       CALL MouseDriver

       ' check file entry area.
       IF IsMenu >= 4 THEN
          RETURN
       END IF

       ' check left mouse button.
       IF Mouse.ButtonX THEN
          GOSUB MouseButton1Z
          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
       ELSE
          ' check mouse position.
          IF Mouse.Row OR Mouse.Column THEN
             GOSUB MouseOverX1
             Q$ = RTRIM$(Directories(Current.Dir))
             GOSUB DisplayLongName1
          END IF
       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.Dir = 1 THEN
             IF Dir.Box.Line = 1 THEN
                I$ = CHR$(0) + CHR$(15)
             END IF
          END IF
       END IF
    END IF

    ' 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
          ' 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 IsMenu >= 3 THEN
          GOSUB DisplayCurrentPath
          IF Num.Files > 0 THEN
             GOSUB DisplayLongName2
          END IF
          RETURN
       END IF
       IF I$ = CHR$(9) THEN
          GOSUB DisplayCurrentPath
          IF Num.Files > 0 THEN
             GOSUB DisplayLongName2
          END IF
          RETURN
       END IF
    END IF
    IF I$ = CHR$(13) THEN
       IsMenu = 2
       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:
 GOSUB HMouse
 LOCATE Dir.Box.Line + Xcoor + 4, Ycoor + 19, 1
 COLOR Plain, Black
 PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
 GOSUB SMouse
 RETURN

' display directory.
DisplayDirectory:
 GOSUB HMouse
 LOCATE Dir.Box.Line + Xcoor + 4, Ycoor + 19, 1
 COLOR Black, Plain
 PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
 COLOR Plain, Black
 GOSUB SMouse
 RETURN

' display directory.
DisplayDirectory2:
 GOSUB HMouse
 COLOR Black, Plain
 LOCATE Xcoor + 14, Ycoor + 19, 1
 PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
 COLOR Plain, Black
 GOSUB SMouse
 RETURN

' display directory.
DisplayDirectory3:
 GOSUB HMouse
 COLOR Black, Plain
 LOCATE Xcoor + 5, Ycoor + 19, 1
 PRINT LEFT$(RTRIM$(Directories(Current.Dir)), 12);
 COLOR Plain, Black
 GOSUB SMouse
 RETURN

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

' update dir box.
DisplayDirBox2:
 GOSUB HMouse
 COLOR Plain, Black
 FOR V = 1 TO 9
    IF Current.Dir + V <= Num.Dirs THEN
       LOCATE Xcoor + V + 5, Ycoor + 19, 1
       PRINT LEFT$(RTRIM$(Directories(Current.Dir + V)), 12);
    END IF
 NEXT
 GOSUB SMouse
 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 = False
          EXIT DO
       END IF

       ' call mouse subroutine.
       CALL MouseDriver

       ' check file entry area.
       IF IsMenu >= 4 THEN
          RETURN
       END IF

       ' check left mouse button.
       IF Mouse.ButtonX THEN
          GOSUB MouseButton1Z
          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
       ELSE
          ' check mouse position.
          IF Mouse.Row OR Mouse.Column THEN
             GOSUB MouseOverX1
             GOSUB DisplayDrive
          END IF
       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
       IsMenu = 3
       RETURN
    END IF

    ' exit from drive box.
    IF I$ = CHR$(27) THEN
       RETURN
    END IF

    ' process drive box keystroke.
    IF LEN(I$) = 2 THEN
       GOSUB DriveBoxKey
    END IF
 LOOP
 RETURN

' select drive letter.
SelectDrive:
 ' check valid drive.
 Valid = False
 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 not ready.
 Check.Disk = False
 IF Disk.Ready = True THEN
    GOSUB PromptDisk
    RETURN
 END IF

 ' check disk not ready.
 IF OutregsX.AX = &HFFFF THEN
    GOSUB PromptDisk
    RETURN
 END IF

 ' select new drive.
 Valid = True
 C$ = Z$
 D$ = ""

 ' display directories.
 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

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

 ' reset filespec.
 X$ = "*.*"
 LOCATE Xcoor + 1, Ycoor + 12, 1
 PRINT SPACE$(26);
 LOCATE Xcoor + 1, Ycoor + 12, 1
 PRINT X$;
 Xposition1 = 1
 Xposition2 = 3
 RETURN

' process drive box key.
DriveBoxKey:
 V = ASC(RIGHT$(I$, 1))
 SELECT CASE V
 CASE 72 ' up
    GOSUB MoveDriveUp
 CASE 80 ' down
    GOSUB MoveDriveDown
 END SELECT
 RETURN

' moves up one drive letter.
MoveDriveUp:
 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
 END IF
 RETURN

' moves down one drive letter.
MoveDriveDown:
 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
 END IF
 RETURN

' draw menu.
MainMenu:
 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 "|";
 ' make file menu box question symbol.
 LOCATE Xcoor, Ycoor + 39
 PRINT "?";
 ' make file menu box exit symbol.
 LOCATE Xcoor, Ycoor + 40
 PRINT "x";
 ' make remaining menu box areas.
 IF Xcoor - 1 > 0 THEN
    COLOR Green, Blue
    LOCATE Xcoor - 1, Ycoor
    PRINT "Hexedit " + Version + " For DOS & Windows PD 2003.";
 END IF
 GOSUB BottomRow
 RETURN

' display bottom row area.
BottomRow:
 GOSUB HMouse
 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
 GOSUB SMouse
 RETURN

' display path.
DisplayCurrentPath:
 GOSUB DisplayCurrentPath3
 GOSUB DisplayLongName1
 RETURN

' display path.
DisplayCurrentPath2:
 GOSUB DisplayCurrentPath3
 GOSUB DisplayLongName3
 RETURN

' display path.
DisplayCurrentPath3:
 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
 RETURN

' display long directory.
DisplayLongName1:
 GOSUB HMouse
 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)))
 IF V > 12 THEN
    V = 12
 END IF
 LOCATE Dir.Box.Line + Xcoor + 4, Ycoor + V + 19, 1
 GOSUB SMouse
 RETURN

' display long filename.
DisplayLongName2:
 GOSUB HMouse
 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)))
 IF V > 12 THEN
    V = 12
 END IF
 LOCATE Box.Line + Xcoor + 4, Ycoor + V + 3, 1
 GOSUB SMouse
 RETURN

' display long directory.
DisplayLongName3:
 GOSUB HMouse
 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
 GOSUB SMouse
 RETURN

' display filesize.
DisplayFilesize:
 GOSUB GetFilesize
 GOSUB HMouse
 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
 GOSUB SMouse
 RETURN

' get filesize and attribute.
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:
 GOSUB HMouse
 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
 GOSUB SMouse
 RETURN

' clear long filename area.
ClearLongName2:
 GOSUB HMouse
 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
 GOSUB SMouse
 RETURN

' construct new path.
GetNewPath:
 ' check filespec.
 IF INSTR(X$, "?") = 0 THEN
    IF INSTR(X$, "*") = 0 THEN
       X$ = "*.*"
       Xposition1 = 1
       Xposition2 = 3
    END IF
 END IF
 ' check file.
 IF X$ = "" THEN
    X$ = "*.*"
    Xposition1 = 1
    Xposition2 = 3
 END IF
 ' store new path.
 Q$ = RTRIM$(Directories(Current.Dir))
 ' store path to be parsed.
 X$ = Q$ + "\" + X$
 RETURN

' truncate filename for display.
TruncateFilename:
 A$ = RTRIM$(E$)
 IF LEN(A$) > 26 THEN
    A$ = LEFT$(A$, 23) + "..."
 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.DA" + MID$(STR$(Process.Number), 2)
 V2$ = "HEXEDIT2.DA" + MID$(STR$(Process.Number), 2)
 CALL OpenDataFiles(V1$, V2$)
 CLOSE #2, #3
 ' open data structure files.
 IF Windows.Detected THEN
    ' open filename random record structure for windows.
    OPEN V1$ FOR RANDOM AS #2 LEN = LEN(WinFileStruc)
    ' open directory random record structure for windows.
    OPEN V2$ FOR RANDOM AS #3 LEN = LEN(WinFileStruc)
 ELSE
    ' open filename random record structure for DOS.
    OPEN V1$ FOR RANDOM AS #2 LEN = LEN(DosFileStruc)
    ' open directory random record structure for DOS.
    OPEN V2$ FOR RANDOM AS #3 LEN = LEN(DosFileStruc)
 END IF
 RETURN

' check path.
CheckPath:
 GOSUB VerifyPath

 ' check carry flag error.
 IF (OutregsX.Flags AND &H1) = &H1 THEN
    ' check invalid path.
    IF (OutregsX.AX) = 3 THEN
       ValidPath = False
    END IF
    RETURN
 END IF

 ' check filename is not path.
 IF (OutregsX.CX AND &H10) <> &H10 THEN
    ValidPath = False
 END IF
 RETURN

' check path.
CheckPath2:
 GOSUB VerifyPath

 ' check carry flag error.
 IF (OutregsX.Flags AND &H1) = &H1 THEN
    ' check invalid file.
    IF (OutregsX.AX) = 2 THEN
       ValidPath = False
    END IF
 END IF
 RETURN

' get path/file attribute.
VerifyPath:
 ValidPath = True

 ' store directory.
 IF D$ = "" THEN
    ASCIIZ = C$ + ":\" + CHR$(0)
 ELSE
    IF D$ = "\" THEN
       ASCIIZ = C$ + ":\" + CHR$(0)
    ELSE
       ASCIIZ = C$ + ":\" + D$ + CHR$(0)
    END IF
 END IF

 ' conanicalize filename.
 V4 = True
 GOSUB ShortFilenameX

 ' store filename.
 ASCIIZ = RTRIM$(Short.Filename$) + CHR$(0)

 ' check windows.
 IF Windows.Detected THEN
    ' get file attribute.
    InregsX.AX = &H7143
    InregsX.BX = &H0
    InregsX.DS = VARSEG(ASCIIZ)
    InregsX.DX = VARPTR(ASCIIZ)
    CALL InterruptX(&H21, InregsX, OutregsX)
 ELSE
    ' get file attribute.
    InregsX.AX = &H4300
    InregsX.DS = VARSEG(ASCIIZ)
    InregsX.DX = VARPTR(ASCIIZ)
    CALL InterruptX(&H21, InregsX, OutregsX)
 END IF
 RETURN

' load current subdirectories.
LoadDirSpec:
 ' verify valid path.
 GOSUB CheckPath
 IF ValidPath = False THEN
    GOSUB CheckPath2
    IF ValidPath = False THEN
       D$ = ""
    END IF
 END IF
 ' reset directory counter.
 Num.Dirs = 0
 ' set dta.
 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
 ' start findfirst.
 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 findnext error.
    IF (OutregsX.Flags AND &H1) = &H1 THEN
       EXIT DO
    END IF
    ' check for directory.
    IF Windows.Detected THEN
       Attribute = ASC(WDTAfile.FileBits)
    ELSE
       Attribute = ASC(DTAfile.FileBits)
    END IF
    ' check directory attribute.
    IF (Attribute AND &H10) = &H10 THEN
       ' store directory name
       GOSUB StoreName
       IF Num.Dirs < 32767 THEN
          Num.Dirs = Num.Dirs + 1
          IF Windows.Detected THEN
             WinFileStruc.Name = L$
             PUT 3, Num.Dirs, WinFileStruc
          ELSE
             DosFileStruc.Name = L$
             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
 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
 ' restore dta.
 GOSUB ResetDTA
 ' reset number of directories.
 IF Num.Dirs = 0 THEN
    Num.Dirs = 1
    IF Windows.Detected THEN
       WinFileStruc.Name = "."
       PUT 3, 1, WinFileStruc
    ELSE
       DosFileStruc.Name = "."
       PUT 3, 1, DosFileStruc
    END IF
 END IF
 ' display number of directories.
 GOSUB Hmouse
 LOCATE Xcoor + 3, Ycoor + 24
 PRINT SPACE$(8);
 LOCATE Xcoor + 3, Ycoor + 24
 COLOR White
 PRINT MID$(STR$(Num.Dirs), 2);
 COLOR Plain
 GOSUB SMouse
 ' sort directories.
 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:
 GOSUB HMouse
 VarX = False
 DO
    VarX = VarX + 1
    IF VarX > 10 THEN
       EXIT DO
    END IF
    IF VarX > Num.Dirs THEN
       EXIT DO
    END IF
    LOCATE VarX + Xcoor + 4, Ycoor + 19, 1
    Q$ = Directories(VarX)
    Q$ = RTRIM$(Q$)
    PRINT LEFT$(Q$, 12);
 LOOP
 GOSUB SMouse
 RETURN

' clear directory box.
ClearDirBox:
 GOSUB HMouse
 FOR VarX = 1 TO 10
    LOCATE VarX + Xcoor + 4, Ycoor + 19, 1
    PRINT SPACE$(12);
 NEXT
 GOSUB SMouse
 RETURN

' display directory.
DisplayCurrentDir:
 IF RIGHT$(D$, 2) = "\." THEN
    D$ = LEFT$(D$, LEN(D$) - 2)
 END IF
 GOSUB HMouse
 ASCIIZ = C$ + ":\" + D$ + CHR$(0)
 LOCATE Xcoor + 2, Ycoor + 2, 1
 PRINT SPACE$(32);
 V4 = True
 GOSUB ShortFilenameX
 IF Short.Filename$ = "" THEN
    Short.Filename$ = C$ + ":\"
 END IF
 Z$ = Short.Filename$
 CALL Deconcatenate(Z$, 32)
 LOCATE Xcoor + 2, Ycoor + 2, 1
 PRINT UCASE$(Z$);
 GOSUB SMouse
 RETURN

' load specified files.
LoadFileSpec:
 Num.Files = 0
 ' set dta.
 GOSUB SetDTA
 ' find first file.
 IF RIGHT$(F$, 1) = "\" THEN
    F$ = F$ + "*.*"
 END IF
 ASCIIZ3 = F$ + CHR$(0)
 ' start findfirst.
 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
    ' check directory attribute.
    IF (Attribute AND &H10) <> &H10 THEN
       ' reset file flag.
       Flag = True
       ' check requirements.
       IF RequireReadOnly THEN
          IF (Attribute AND ReadOnlyBit) = 0 THEN
             Flag = False
          END IF
       END IF
       IF RequireHidden THEN
          IF (Attribute AND HiddenBit) = 0 THEN
             Flag = False
          END IF
       END IF
       IF RequireSystem THEN
          IF (Attribute AND SystemBit) = 0 THEN
             Flag = False
          END IF
       END IF
       IF RequireArchive THEN
          IF (Attribute AND ArchiveBit) = 0 THEN
             Flag = False
          END IF
       END IF
       ' check flag.
       IF Flag THEN
          ' store filename.
          GOSUB StoreName
          IF Num.Files < 32767 THEN
             Num.Files = Num.Files + 1
             IF Windows.Detected THEN
                WinFileStruc.Name = L$
                PUT 2, Num.Files, WinFileStruc
             ELSE
                DosFileStruc.Name = L$
                PUT 2, Num.Files, DosFileStruc
             END IF
          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 filename.
       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
 ' restore dta.
 GOSUB ResetDTA
 ' display number of files.
 GOSUB HMouse
 LOCATE Xcoor + 3, Ycoor + 9
 PRINT SPACE$(9);
 LOCATE Xcoor + 3, Ycoor + 9
 COLOR White
 PRINT MID$(STR$(Num.Files), 2);
 COLOR Plain
 GOSUB SMouse
 ' sort files.
 IF HeapSortOff THEN
    RETURN
 END IF
 GOSUB HMouse
 COLOR White
 LOCATE Xcoor + 1, Ycoor + 12, 1
 PRINT SPACE$(26);
 LOCATE Xcoor + 1, Ycoor + 12, 1
 PRINT "Sorting..";
 COLOR Plain
 IF Windows.Detected THEN
    GOSUB Win.Heap.Sort1
 ELSE
    GOSUB Dos.Heap.Sort1
 END IF
 GOSUB SMouse
 RETURN

' display filename box.
DisplayFileSpec:
 GOSUB HMouse
 VarX = False
 DO
    VarX = VarX + 1
    IF VarX > 10 THEN
       EXIT DO
    END IF
    IF VarX > Num.Files THEN
       EXIT DO
    END IF
    LOCATE VarX + Xcoor + 4, Ycoor + 3, 1
    Q$ = Filenames(VarX)
    Q$ = RTRIM$(Q$)
    PRINT LEFT$(Q$, 12);
 LOOP
 GOSUB SMouse
 RETURN

' clear filename box.
ClearFileBox:
 GOSUB HMouse
 FOR VarX = 1 TO 10
    LOCATE VarX + Xcoor + 4, Ycoor + 3, 1
    PRINT SPACE$(12);
 NEXT
 GOSUB SMouse
 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

' store asciiz name.
StoreName:
 IF Windows.Detected THEN
    IF Ambiguate = False THEN
       L$ = WDTAfile.ASCIIZfull
    ELSE
       L$ = WDTAfile.ASCIIZshort
       GOSUB StripAsciiz
       IF RTRIM$(L$) = "" THEN
          L$ = WDTAfile.ASCIIZfull
       END IF
    END IF
 ELSE
    L$ = DTAfile.ASCIIZfilename
 END IF
 GOSUB StripAsciiz
 RETURN

' strip ascii 0 from asciiz.
StripAsciiz:
 IF INSTR(L$, CHR$(0)) THEN
    L$ = LEFT$(L$, INSTR(L$, CHR$(0)) - 1)
 END IF
 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

' format filename for display and search purposes.
ShortFilenameX:
 ' read ambiguated 8.3 filename.
 IF Windows.Detected THEN
    InregsX.AX = &H7160
    InregsX.CX = &H8001
    InregsX.DS = VARSEG(ASCIIZ)
    InregsX.SI = VARPTR(ASCIIZ)
    InregsX.ES = VARSEG(ASCIIZ2)
    InregsX.DI = VARPTR(ASCIIZ2)
    CALL InterruptX(&H21, InregsX, OutregsX)
 ELSE
    InregsX.AX = &H6000
    InregsX.DS = VARSEG(ASCIIZ)
    InregsX.SI = VARPTR(ASCIIZ)
    InregsX.ES = VARSEG(ASCIIZ2)
    InregsX.DI = VARPTR(ASCIIZ2)
    CALL InterruptX(&H21, InregsX, OutregsX)
 END IF
 ' check carry flag error.
 IF (OutregsX.Flags AND &H1) = &H1 THEN
    Short.Filename$ = ""
    RETURN
 END IF
 IF (OutregsX.Flags AND &H1) = &H0 THEN
    ' store conanicalized 8.3 filename.
    Short.Filename$ = ASCIIZ2
    Imbedded = INSTR(Short.Filename$, CHR$(0))
    IF Imbedded THEN
       Short.Filename$ = LEFT$(Short.Filename$, Imbedded - 1)
    END IF
    Short.Filename$ = UCASE$(RTRIM$(Short.Filename$))
    ' store 8.3 filename.
    IF V4 = False THEN ' variable to strip filename from path.
       FOR V = LEN(Short.Filename$) TO 1 STEP -1
          IF MID$(Short.Filename$, V, 1) = "\" THEN
             Short.Filename$ = MID$(Short.Filename$, V + 1)
             EXIT FOR
          END IF
       NEXT
    END IF
 END IF
 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

 ' some old DOS functions return 0 - 63.
 IF Last.Drive > 26 THEN
    Last.Drive = 26
 END IF
 RETURN

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

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

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

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

' display drive box.
InitDrives:
' init drive letter.
IF Current.Drive = 0 THEN
   Current.Drive = Drive.Number + 1
END IF
' display drives.
V3 = Current.Drive
IF V3 > Last.Drive THEN
   V3 = Last.Drive
END IF
GOSUB ClearDriveBox
Drive.Box.Line = 1
Current.Drive = 1
GOSUB DisplayDrives
GOSUB DisplayDrive
' scroll to drive.
DO UNTIL Current.Drive >= V3
   GOSUB MoveDriveDown
LOOP
RETURN

' hide mouse.
HMouse:
 IF Mouse.Present THEN
    CALL MouseFunction(HideMouse, 0)
 END IF
 RETURN

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

' process left mouse button single-click.
MouseButton1Z:
 ' store mouse variables.
 IsMenu = False
 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 = False
          V = Mouse.Row - (Xcoor + 4)
          IF V = Box.Line THEN
             Valid = True
          END IF
          IF V > Box.Line THEN
             IF Current.File + (V - Box.Line) <= Num.Files THEN
                Current.File = Current.File + (V - Box.Line)
                Valid = True
             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 = True
             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 = False
       V = Mouse.Row - (Xcoor + 4)
       IF V = Dir.Box.Line THEN
          Valid = True
       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 = True
          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 = True
          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 = False
       V = Mouse.Row - (Xcoor + 4)
       IF V = Drive.Box.Line THEN
          Valid = True
       END IF
       IF V > Drive.Box.Line THEN
          IF Current.Drive + (V - Drive.Box.Line) <= Last.Drive THEN
             GOSUB ClearDrive
             Current.Drive = Current.Drive + (V - Drive.Box.Line)
             Drive.Box.Line = Drive.Box.Line + (V - Drive.Box.Line)
             GOSUB DisplayDrive
             Valid = True
          END IF
       END IF
       IF V < Drive.Box.Line THEN
          IF Current.Drive - (Drive.Box.Line - V) > 0 THEN
             GOSUB ClearDrive
             Current.Drive = Current.Drive - (Drive.Box.Line - V)
             Drive.Box.Line = Drive.Box.Line - (Drive.Box.Line - V)
             GOSUB DisplayDrive
             Valid = True
          END IF
       END IF
       IF Valid THEN
          I$ = CHR$(13)
          IsMenu = 3
       END IF
       RETURN
    END IF
 END IF
 ' check mouse selection boundaries for file entry area.
 IF Mouse.Row = Xcoor + 1 THEN
    IF Mouse.Column >= Ycoor + 2 AND Mouse.Column <= Ycoor + 39 THEN
       I$ = ""
       IsMenu = 4
       RETURN
    END IF
 END IF
 ' check mouse selection boundaries for file box question.
 IF Mouse.Row = Xcoor THEN
    IF Mouse.Column = Ycoor + 39 THEN
       I$ = ""
       GOSUB DisplayHelp
       RETURN
    END IF
 END IF
 ' check mouse selection boundaries for file box exit.
 IF Mouse.Row = Xcoor THEN
    IF Mouse.Column = Ycoor + 40 THEN
       I$ = ""
       IsMenu = 5
       RETURN
    END IF
 END IF
 RETURN

' mouseover for file/dir/drive boxes.
MouseOverX1:
 ' 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
          B1 = Mouse.Row - (Xcoor + 4)
          IF B1 > Box.Line THEN
             B2 = B1 - Box.Line
             IF B2 <= Num.Files THEN
                FOR B3 = 1 TO B2
                   I$ = CHR$(0) + CHR$(80) ' down
                   GOSUB FileBoxKey
                   I$ = ""
                NEXT
             END IF
          ELSE
             IF B1 < Box.Line THEN
                B2 = Box.Line - B1
                IF B2 > 0 THEN
                   FOR B3 = 1 TO B2
                      I$ = CHR$(0) + CHR$(72) ' up
                      GOSUB FileBoxKey
                      I$ = ""
                   NEXT
                END IF
             END IF
          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
       IF Num.Dirs > 0 THEN
          D1 = Mouse.Row - (Xcoor + 4)
          IF D1 = Dir.Box.Line THEN
             IF D1 = 1 THEN ' top
                GOSUB ClearDirectory
                Dir.Box.Line = 1
                Current.Dir = 1
                GOSUB DisplayDirectory
             END IF
          ELSE
             IF D1 > Dir.Box.Line THEN
                D2 = D1 - Dir.Box.Line
                IF D2 <= Num.Dirs THEN
                   FOR D3 = 1 TO D2 ' down
                      IF Current.Dir + 1 <= Num.Dirs THEN
                         GOSUB ClearDirectory
                         Dir.Box.Line = Dir.Box.Line + 1
                         Current.Dir = Current.Dir + 1
                         GOSUB DisplayDirectory
                      END IF
                   NEXT
                END IF
             ELSE
                IF D1 < Dir.Box.Line THEN
                   D2 = Dir.Box.Line - D1
                   IF D2 > 0 THEN
                      FOR D3 = 1 TO D2 ' up
                         IF Current.Dir - 1 > 0 THEN
                            GOSUB ClearDirectory
                            Dir.Box.Line = Dir.Box.Line - 1
                            Current.Dir = Current.Dir - 1
                            GOSUB DisplayDirectory
                         END IF
                      NEXT
                   END IF
                END IF
             END IF
          END IF
       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
       X0 = Mouse.Row - (Xcoor + 4)
       IF X0 > Drive.Box.Line THEN
          X1 = Current.Drive + (X0 - Drive.Box.Line)
          IF X1 <= Last.Drive THEN
             GOSUB ClearDrive
             Current.Drive = Current.Drive + (X0 - Drive.Box.Line)
             Drive.Box.Line = Drive.Box.Line + (X0 - Drive.Box.Line)
             GOSUB DisplayDrive
          END IF
       ELSE
          IF X0 < Drive.Box.Line THEN
             X1 = Current.Drive - (Drive.Box.Line - X0)
             IF X1 > 0 THEN
                GOSUB ClearDrive
                Current.Drive = Current.Drive - (Drive.Box.Line - X0)
                Drive.Box.Line = Drive.Box.Line - (Drive.Box.Line - X0)
                GOSUB DisplayDrive
             END IF
          END IF
       END IF
       I$ = ""
    END IF
 END IF
 RETURN

' display function keys.
DisplayHelp:
 GOSUB HMouse
 COLOR White, Blue
 CLS
 GOSUB HelpScreen
 WHILE INKEY$<>CHR$(27)
 WEND
 LOCATE ,,1
 GOSUB RedrawScreen
 GOSUB SMouse
 RETURN

' display help screen.
HelpScreen:
 LOCATE 8, 16
 PRINT "File Menu Box Function Keys Help Screen " + Version;
 LOCATE 9, 16
 COLOR , 0
 COLOR Yellow
 PRINT CHR$(ULcorner) + STRING$(44, Hline) + CHR$(URcorner)
 LOCATE 10, 16
 PRINT CHR$(Vline) + " ";
 COLOR White
 PRINT "Press <escape> To Return To Menu:          ";
 COLOR Yellow
 PRINT CHR$(Vline)
 LOCATE 11, 16
 PRINT CHR$(Vline); " ";
 PRINT "Function keys:                             ";
 COLOR Yellow
 PRINT CHR$(Vline)
 LOCATE 12, 16
 PRINT CHR$(Vline); " ";
 COLOR White
 PRINT "Alt-A to Alt-Z  Select Drive Letter        ";
 COLOR Yellow
 PRINT CHR$(Vline)
 LOCATE 13, 16
 PRINT CHR$(Vline); " ";
 COLOR White
 PRINT "F1 - Change Drive     F4 - Back Drive      ";
 COLOR Yellow
 PRINT CHR$(Vline)
 LOCATE 14, 16
 COLOR Yellow
 PRINT CHR$(Vline); " ";
 COLOR White
 PRINT "F2 - Toggle Sort      F5 - Forward Drive   ";
 COLOR Yellow
 PRINT CHR$(Vline)
 LOCATE 15, 16
 PRINT CHR$(Vline); " ";
 COLOR White
 PRINT "F3 - Move File Box    F6 - Toggle Ambiguate";
 COLOR Yellow
 PRINT CHR$(Vline)
 LOCATE 16, 16
 PRINT CHR$(Vline); " ";
 COLOR White
 PRINT "F7 - Redraw File Menu Box                  ";
 COLOR Yellow
 PRINT CHR$(Vline)
 LOCATE 17, 16
 PRINT CHR$(Vline); " ";
 COLOR White
 PRINT "F8 - Specify Filename Attribute Override   ";
 COLOR Yellow
 PRINT CHR$(Vline)
 COLOR Yellow
 LOCATE 18, 16
 PRINT CHR$(LLcorner) + STRING$(44, Hline) + CHR$(LRcorner);
 COLOR White
 LOCATE ,,0
 RETURN

' redraws editing screen.
RedrawScreen:
 COLOR white, blue
 CLS
 GOSUB MainMenu
 GOSUB UpdateDisplay
 GOSUB BottomRow
 GOSUB DisplayCurrentPath
 IF Num.Files > 0 THEN
    GOSUB DisplayLongName2
 END IF
 GOSUB DisplayFilenamex
 GOSUB DisplayFileLine
 RETURN

' store area.
StoreArea:
 RowX1 = 0
 ColumnY1 = 0
 FOR RowX2 = Xcoor - 1 TO Xcoor + 16
    RowX1 = RowX1 + 1
    ColumnY1 = 0
    FOR ColumnY2 = Ycoor TO Ycoor + 41
       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
 RETURN

' restore area.
RestoreArea:
 RowX1 = 0
 ColumnY1 = 0
 FOR RowX2 = Xcoor - 1 TO Xcoor + 16
    RowX1 = RowX1 + 1
    ColumnY1 = 0
    FOR ColumnY2 = Ycoor TO Ycoor + 41
       ColumnY1 = ColumnY1 + 1
       LOCATE RowX2, ColumnY2, 1
       ' restore color.
       TempZ = Area2(RowX1, ColumnY1)
       ' undocumented: also stores background color.
       VarB = INT(TempZ / 16)
       VarF = TempZ MOD 16
       COLOR VarF, VarB
       ' restore ascii character.
       PRINT CHR$(Area1(RowX1, ColumnY1));
    NEXT
 NEXT
 RETURN

' scancodes for Alt-A to Alt-Z.
DATA  30, 48, 46, 32, 18, 33, 34, 35, 23, 36 
DATA  37, 38, 50, 49, 24, 25, 16, 19, 31, 20 
DATA  22, 47, 17, 45, 21, 44 

' simple error routine
Error.Routine3:
 ErrorTrap = ERR
 ' verify disk letter.
 IF Check.Disk THEN
    ' device i/o error.
    IF ERR = 57 THEN
       Disk.Ready = True
       RESUME NEXT
    END IF
    ' disk not ready.
    IF ERR = 71 THEN
       Disk.Ready = True
       RESUME NEXT
    END IF
    ' path not found.
    IF ERR = 76 THEN
       Disk.Ready = True
       RESUME NEXT
    END IF
 END IF
 ' display error.
 COLOR White, Black
 CLS
 PRINT "Hex Editor Menu " + Version + " " + Release + " critical error trap:"
 COLOR Yellow
 SELECT CASE Error.Trap
 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 and exit.
 COLOR Green
 PRINT "Check TEMP variables, .CFG file, or DOS file handles, then restart."
 COLOR Plain
 END
END SUB
