REM Program: Hex Editor v7.7a, Module 3 of 6, PD 2007.
REM Author: Erik Jon Oredson AS. Csci
REM Release: 10/15/2007.
REM Status: Public Domain.
REM Email: eoredson@gmail.com
REM Urls: www.filegate.net www.simtel.net

REM Help/main screens for main menu and file menu.
REM Ansi/Hex Charts and Print subroutines.
REM Screen/File Dump and Print subroutines.
REM Clipboard and ViewFile subroutines.

REM File/directory sort subroutines.
REM GetInfo subroutine for Attribute, Date/Time, FileSize.
REM GetDriveInfo subroutine.
REM SearchFile subroutine.

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

REM File box main menu.

SUB FileMainMenu
 CALL HMouse
 COLORf2 White, 1
 CLS
 LOCATEf Xcoor, Ycoor, 0
 COLORf2 White, 0
 COLORf Yellow
 PRINTf CHR$(ULcorner) + STRING$(10, Hline)
 COLORf Green
 PRINTf "(<esc>=Quit,F9=Help)"
 COLORf Yellow
 PRINTf STRING$(9, Hline) + CHR$(URcorner)
 LOCATEf Xcoor + 1, Ycoor, 0
 PRINTf CHR$(Vline) + " "
 COLORf White
 PRINTf "Filename:"
 COLORf Yellow
 PRINTf SPACE$(29) + CHR$(Vline)
 LOCATEf Xcoor + 2, Ycoor, 0
 PRINTf CHR$(Vline) + SPACE$(39) + CHR$(Vline)
 LOCATEf Xcoor + 3, Ycoor, 0
 PRINTf CHR$(Vline) + " "
 COLORf White
 PRINTf "Files:          Dirs:          Drives:"
 COLORf Yellow
 PRINTf CHR$(Vline)
 LOCATEf Xcoor + 4, Ycoor, 0
 PRINTf CHR$(Vline)
 COLORf Magenta
 PRINTf " " + CHR$(ULcorner) + STRING$(12, Hline) + CHR$(URcorner) + "  "
 PRINTf CHR$(ULcorner) + STRING$(12, Hline) + CHR$(URcorner) + "  "
 PRINTf CHR$(ULcorner) + STRING$(3, Hline) + CHR$(URcorner) + " "
 COLORf Yellow
 PRINTf CHR$(Vline)
 COLORf Yellow
 LOCATEf Xcoor + 5, Ycoor, 0
 PRINTf CHR$(Vline)
 COLORf Magenta
 PRINTf " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(3) + CHR$(Vline) + " "
 COLORf Yellow
 PRINTf CHR$(Vline)
 COLORf Yellow
 LOCATEf Xcoor + 6, Ycoor, 0
 PRINTf CHR$(Vline)
 COLORf Magenta
 PRINTf " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(3) + CHR$(Vline) + " "
 COLORf Yellow
 PRINTf CHR$(Vline)
 COLORf Yellow
 LOCATEf Xcoor + 7, Ycoor, 0
 PRINTf CHR$(Vline)
 COLORf Magenta
 PRINTf " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(3) + CHR$(Vline) + " "
 COLORf Yellow
 PRINTf CHR$(Vline)
 COLORf Yellow
 LOCATEf Xcoor + 8, Ycoor, 0
 PRINTf CHR$(Vline)
 COLORf Magenta
 PRINTf " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(3) + CHR$(Vline) + " "
 COLORf Yellow
 PRINTf CHR$(Vline)
 COLORf Yellow
 LOCATEf Xcoor + 9, Ycoor, 0
 PRINTf CHR$(Vline)
 COLORf Magenta
 PRINTf " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(3) + CHR$(Vline) + " "
 COLORf Yellow
 PRINTf CHR$(Vline)
 COLORf Yellow
 LOCATEf Xcoor + 10, Ycoor, 0
 PRINTf CHR$(Vline)
 COLORf Magenta
 PRINTf " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(3) + CHR$(Vline) + " "
 COLORf Yellow
 PRINTf CHR$(Vline)
 COLORf Yellow
 LOCATEf Xcoor + 11, Ycoor, 0
 PRINTf CHR$(Vline)
 COLORf Magenta
 PRINTf " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(3) + CHR$(Vline) + " "
 COLORf Yellow
 PRINTf CHR$(Vline)
 COLORf Yellow
 LOCATEf Xcoor + 12, Ycoor, 0
 PRINTf CHR$(Vline)
 COLORf Magenta
 PRINTf " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(3) + CHR$(Vline) + " "
 COLORf Yellow
 PRINTf CHR$(Vline)
 COLORf Yellow
 LOCATEf Xcoor + 13, Ycoor, 0
 PRINTf CHR$(Vline)
 COLORf Magenta
 PRINTf " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(3) + CHR$(Vline) + " "
 COLORf Yellow
 PRINTf CHR$(Vline)
 COLORf Yellow
 LOCATEf Xcoor + 14, Ycoor, 0
 PRINTf CHR$(Vline)
 COLORf Magenta
 PRINTf " " + CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(12) + CHR$(Vline) + "  "
 PRINTf CHR$(Vline) + SPACE$(3) + CHR$(Vline) + " "
 COLORf Yellow
 PRINTf CHR$(Vline)
 COLORf Yellow
 LOCATEf Xcoor + 15, Ycoor, 0
 PRINTf CHR$(Vline)
 COLORf Magenta
 PRINTf " " + CHR$(LLcorner) + STRING$(12, Hline) + CHR$(LRcorner) + "  "
 PRINTf CHR$(LLcorner) + STRING$(12, Hline) + CHR$(LRcorner) + "  "
 PRINTf CHR$(LLcorner) + STRING$(3, Hline) + CHR$(LRcorner) + " "
 COLORf Yellow
 PRINTf CHR$(Vline)
 LOCATEf Xcoor + 16, Ycoor, 0
 PRINTf CHR$(LLcorner) + STRING$(39, Hline) + CHR$(LRcorner)
 COLORf White
 ' make file input box mouse symbols.
 LOCATEf Xcoor + 4, Ycoor + 16, 0
 PRINTf "<"
 LOCATEf Xcoor + 5, Ycoor + 16, 0
 PRINTf "|"
 LOCATEf Xcoor + 14, Ycoor + 16, 0
 PRINTf "|"
 LOCATEf Xcoor + 15, Ycoor + 16, 0
 PRINTf ">"
 ' make directory input box mouse symbols.
 LOCATEf Xcoor + 4, Ycoor + 32, 0
 PRINTf "<"
 LOCATEf Xcoor + 5, Ycoor + 32, 0
 PRINTf "|"
 LOCATEf Xcoor + 14, Ycoor + 32, 0
 PRINTf "|"
 LOCATEf Xcoor + 15, Ycoor + 32, 0
 PRINTf ">"
 ' make drive input box mouse symbols.
 LOCATEf Xcoor + 5, Ycoor + 39, 0
 PRINTf "|"
 LOCATEf Xcoor + 14, Ycoor + 39, 0
 PRINTf "|"
 ' make file menu box question symbol.
 LOCATEf Xcoor, Ycoor + 39, 0
 PRINTf "?"
 ' make file menu box exit symbol.
 LOCATEf Xcoor, Ycoor + 40, 0
 PRINTf "x"
 ' make remaining menu box areas.
 IF Xcoor - 1 > 0 THEN
    COLORf2 Green, 1
    LOCATEf Xcoor - 1, Ycoor, 0
    PRINTf "Hexedit " + Version + " For DOS & Windows PD 2007."
 END IF
 CALL BottomRow
 CALL SMouse
END SUB

REM File box bottom row menu.

SUB BottomRow
 CALL HMouse
 IF Xcoor + 17 <= 24 THEN
    COLORf2 Green, 1
    LOCATEf Xcoor + 17, Ycoor, 0
    PRINTf "Path:"
 END IF
 IF Xcoor + 18 <= 24 THEN
    COLORf2 Green, 1
    LOCATEf Xcoor + 18, Ycoor, 0
    PRINTf "File:"
 END IF
 IF Xcoor + 19 <= 24 THEN
    COLORf2 Green, 1
    LOCATEf Xcoor + 19, Ycoor, 0
    PRINTf "Size:"
 END IF
 COLORf2 Plain, 0
 CALL SMouse
END SUB

' display filename border area.
SUB DisplayScreen3X
 LOCATEf 3, 2, 0
 COLORf Magenta
 PRINTf CHR$(Vline) + " "
 COLORf Green
 PRINTf CHR$(ULcorner) + STRING$(46, Hline) + CHR$(URcorner) + " "
 PRINTf CHR$(ULcorner) + STRING$(22, Hline) + CHR$(URcorner)
 COLORf White
 PRINTf "x"
 COLORf Magenta
 PRINTf CHR$(Vline)
END SUB

REM Help screen subroutines:

' display help for file menu input box.
SUB DisplayHelp
 COLORf2 White, 1
 CLS
 LOCATEf 5, 3, 0
 PRINTf "            File Menu Box Function Keys Help Screen " + Version + " " + Release
 LOCATEf 6, 3, 0
 COLORf2 White, 0
 colorf Yellow
 PRINTf CHR$(ULcorner) + STRING$(74, Hline) + CHR$(URcorner)
 LOCATEf 7, 3, 0
 PRINTf CHR$(Vline) + " "
 colorf White
 PRINTf "                  Press <escape> To Return To Menu:                      "
 colorf Yellow
 PRINTf CHR$(Vline)
 LOCATEf 8, 3, 0
 PRINTf CHR$(Vline) + " "
 colorf White
 PRINTf "F1 - Change Drive  F8 - Attribute Specs Alt-F3 Dir Exclude List          "
 colorf Yellow
 PRINTf CHR$(Vline)
 LOCATEf 9, 3, 0
 PRINTf CHR$(Vline) + " "
 colorf White
 PRINTf "F2 - Toggle Sort   F9 - Display Help    Alt-F4 Toggle File Sort Direction"
 colorf Yellow
 PRINTf CHR$(Vline)
 LOCATEf 10, 3, 0
 colorf Yellow
 PRINTf CHR$(Vline) + " "
 colorf White
 PRINTf "F3 - Move Menu     F10 - Exit Editor    Alt-F5 Toggle Dir Sort Direction "
 colorf Yellow
 PRINTf CHR$(Vline)
 LOCATEf 11, 3, 0
 PRINTf CHR$(Vline) + " "
 colorf White
 PRINTf "F4 - Back Drive    F11 - Shell To DOS   Alt-F6 Toggle File Date/Time Info"
 colorf Yellow
 PRINTf CHR$(Vline)
 LOCATEf 12, 3, 0
 PRINTf CHR$(Vline) + " "
 colorf White
 PRINTf "F5 - Forward Drive F12 - Load FileSpec  Alt-F7 Toggle File Size Info     "
 colorf Yellow
 PRINTf CHR$(Vline)
 LOCATEf 13, 3, 0
 PRINTf CHR$(Vline) + " "
 colorf White
 PRINTf "F6 - Toggle Ambiguate  Alt-F1 Toggle Quiet   Alt-F8 Load Network Path    "
 colorf Yellow
 PRINTf CHR$(Vline)
 LOCATEf 14, 3, 0
 PRINTf CHR$(Vline) + " "
 colorf White
 PRINTf "F7 - Redraw Menu Box   Alt-F2 Exclude List   Alt-F9 Load Default Net Path"
 colorf Yellow
 PRINTf CHR$(Vline)
 LOCATEf 15, 3, 0
 PRINTf CHR$(Vline) + " "
 colorf White
 PRINTf "Alt-A to Alt-Z  Select Drive Letter   Alt-F10 Load Default Net Path Drive"
 colorf Yellow
 PRINTf CHR$(Vline)
 LOCATEf 16, 3, 0
 PRINTf CHR$(LLcorner) + STRING$(74, Hline) + CHR$(LRcorner)
 colorf White
 WHILE INKEY$ <> CHR$(27)
    R = ReleaseTime
 WEND
END SUB

' display help screens.
SUB HelpScreen
 GOSUB DisplayHelpScreen1
 GOSUB DisplayHelpScreen2
 GOSUB DisplayHelpScreen3
 GOSUB DisplayHelpScreen4
 GOSUB DisplayHelpScreen5
 EXIT SUB

' help screen header.
HelpHeader:
 CALL DisplayScreen2
 LOCATEf 2, 2, 0
 COLORf White
 PRINTf "Help screen: Hex Editor " + Version + " " + Release + " functions:"
 RETURN

' help screen 1.
DisplayHelpScreen1:
 GOSUB HelpHeader
 COLORf Red
 LOCATEf 3, 2, 0
 PRINTf "Function keys:"
 COLORf Yellow
 LOCATEf 4, 2, 0
 PRINTf "Alt-A  Append multiple bytes to file.   Alt-T  HEX File Print."
 LOCATEf 5, 2, 0
 PRINTf "Alt-B  Append multiple null bytes.      Alt-U  Undo last byte change."
 LOCATEf 6, 2, 0
 PRINTf "Alt-C  ANSI Chart.                      Alt-V  View files."
 LOCATEf 7, 2, 0
 PRINTf "Alt-D  HEX Screen Dump.                 Alt-W  Close file."
 LOCATEf 8, 2, 0
 PRINTf "Alt-E  HEX File Dump.                   Alt-X  Exit program."
 LOCATEf 9, 2, 0
 PRINTf "Alt-F  Start input menu.                Alt-Y  Toggle right window."
 LOCATEf 10, 2, 0
 PRINTf "Alt-G  Append multiple specified bytes. Alt-Z  Undo all bytes changes."
 LOCATEf 11, 2, 0
 PRINTf "Alt-H  HEX Chart.                       "
 COLORf Red
 PRINTf "Editing keys:"
 COLORf Yellow
 LOCATEf 12, 2, 0
 PRINTf "Alt-I  DOS shell.                       Tab    -- Switch windows."
 LOCATEf 13, 2, 0
 PRINTf "Alt-J  Jump to byte position.           Enter  -- Change byte value."
 LOCATEf 14, 2, 0
 PRINTf "Alt-K  Search for ASCII string.         Insert -- Change string value."
 LOCATEf 15, 2, 0
 PRINTf "Alt-L  Jump to page position.           Delete -- Change hex string."
 LOCATEf 16, 2, 0
 PRINTf "Alt-M  Append ASCII string to file.     Escape -- Input Menu."
 LOCATEf 17, 2, 0
 PRINTf "Alt-N  Open new file.                   (hex value numeral preceded)."
 LOCATEf 18, 2, 0
 PRINTf "Alt-O  Print help.                      (right window unprintable chars"
 LOCATEf 19, 2, 0
 PRINTf "Alt-P  HEX Screen Print.                are represented with a dot)."
 LOCATEf 20, 2, 0
 PRINTf "Alt-Q  Help screen.                     (ascii values preceded with H"
 LOCATEf 21, 2, 0
 PRINTf "Alt-R  Redraw screen.                   are treated as hexidecimal)."
 LOCATEf 22, 2, 0
 PRINTf "Alt-S  Search for multiple bytes.       (<escape> key exits search)."
 LOCATEf 23, 2, 0
 CALL PressKey
 RETURN

' help screen 2.
DisplayHelpScreen2:
 GOSUB HelpHeader
 COLORf Red
 LOCATEf 3, 2, 0
 PRINTf "Marker keys:"
 COLORf Yellow
 LOCATEf 4, 2, 0
 PRINTf "1   add marker."
 LOCATEf 5, 2, 0
 PRINTf "2   add specific marker value."
 LOCATEf 6, 2, 0
 PRINTf "3   delete marker."
 LOCATEf 7, 2, 0
 PRINTf "4   delete specific marker."
 LOCATEf 8, 2, 0
 PRINTf "5   jump previous marker."
 LOCATEf 9, 2, 0
 PRINTf "6   jump current marker."
 LOCATEf 10, 2, 0
 PRINTf "7   jump next marker."
 LOCATEf 11, 2, 0
 PRINTf "8   jump specific marker."
 LOCATEf 12, 2, 0
 PRINTf "9   list all markers."
 LOCATEf 13, 2, 0
 PRINTf "0   list specific marker."
 LOCATEf 14, 2, 0
 PRINTf "-   list markers of value."
 LOCATEf 15, 2, 0
 PRINTf "+   list range of markers."
 LOCATEf 16, 2, 0
 PRINTf "=   delete a range."
 LOCATEf 17, 2, 0
 PRINTf "[   delete all markers."
 LOCATEf 18, 2, 0
 PRINTf "]   delete markers of value."
 LOCATEf 19, 2, 0
 CALL PressKey
 RETURN

' help screen 3.
DisplayHelpScreen3:
 GOSUB HelpHeader
 COLORf Red
 LOCATEf 3, 2, 0
 PRINTf "Information keys:"
 COLORf Yellow
 LOCATEf 4, 2, 0
 PRINTf "? key displays file length, and undos remaining."
 LOCATEf 5, 2, 0
 PRINTf "! key displays current page, row, and column."
 LOCATEf 6, 2, 0
 PRINTf "~ key displays last page and markers used."
 LOCATEf 7, 2, 0
 PRINTf CHR$(34) + " key displays current path of file being edited."
 LOCATEf 8, 2, 0
 PRINTf "; key displays the range of the current hilighted area."
 LOCATEf 9, 2, 0
 PRINTf "{ key displays number of pasted entries stored in the undo file."
 COLORf Red
 LOCATEf 10, 2, 0
 PRINTf "Display keys:"
 COLORf Yellow
 LOCATEf 11, 2, 0
 PRINTf "F1 key toggles 64-byte filename display."
 LOCATEf 12, 2, 0
 PRINTf "F2 key toggles lower screen help key list."
 COLORf Red
 LOCATEf 13, 2, 0
 PRINTf "DOS function keys:"
 COLORf Yellow
 LOCATEf 14, 2, 0
 PRINTf "F11 key opens DOS shell in editor or file menu box."
 LOCATEf 15, 2, 0
 PRINTf "F12 key prompts for DOS command in editor."
 LOCATEf 16, 2, 0
 COLORf Red
 PRINTf "Hilight keys: "
 COLORf Yellow
 PRINTf "Shift-<key> hilights area, where <key> is:"
 LOCATEf 17, 2, 0
 PRINTf "<left>/<right>/<up>/<down>/<page up>/<page down>/<home>/<end>"
 LOCATEf 18, 2, 0
 COLORf Red
 PRINTf "Clipboard controls: "
 COLORf Yellow
 PRINTf "Control-C (copy) Control-V (paste)"
 LOCATEf 19, 2, 0
 PRINTf "Control-X (undo previous paste)  Control-Z (undo all pastes)"
 COLORf Red
 LOCATEf 20, 2, 0
 PRINTf "Calculator key:"
 COLORf Yellow
 PRINTf "  keypad '5' key, or Alt-F5"
 COLORf Red
 LOCATEf 21, 2, 0
 PRINTf "Repeat last search:"
 COLORf Yellow
 PRINTf "  Control-F3"
 LOCATEf 22, 2, 0
 CALL PressKey
 RETURN

' help screen 4.
DisplayHelpScreen4:
 GOSUB HelpHeader
 COLORf Red
 LOCATEf 3, 2, 0
 PRINTf "Multiple file keys:"
 COLORf Yellow
 LOCATEf 4, 2, 0
 PRINTf "F6 - Next File.      F9 - Close File."
 LOCATEf 5, 2, 0
 PRINTf "F7 - Previous File.  F10 - View Files."
 LOCATEf 6, 2, 0
 PRINTf "F8 - Load New File.  Alt-0  Close All Files."
 LOCATEf 7, 2, 0
 PRINTf "Alt-1 To Alt-9  -  Select Specific File."
 COLORf Red
 LOCATEf 8, 2, 0
 PRINTf "File menu box keys:"
 COLORf Yellow
 LOCATEf 9, 2, 0
 PRINTf "F1 - drive change.            F7 - redraw file menu box."
 LOCATEf 10, 2, 0
 PRINTf "F2 - toggle file sort.        F8 - attribute override."
 LOCATEf 11, 2, 0
 PRINTf "F3 - move file menu box.      F9 - display help.
 LOCATEf 12, 2, 0
 PRINTf "F4 - back 1 drive letter.     F10 - exit editor."
 LOCATEf 13, 2, 0
 PRINTf "F5 - forward 1 drive letter.  F11 - shell to DOS.
 LOCATEf 14, 2, 0
 PRINTf "F6 - toggle 8.3 ambiguation.  F12 - load filespec into Editor."
 LOCATEf 15, 2, 0
 PRINTf "Alt-A to Alt-Z - select drive letter, Alt-F1 Toggle Quiet."
 LOCATEf 16, 2, 0
 PRINTf "Alt-F2 File Exclude List.     Alt-F3 Dir Exclude List."
 LOCATEf 17, 2, 0
 PRINTf "Alt-F4 Toggle File Sort.      Alt-F5 Toggle Dir Sort."
 LOCATEf 18, 2, 0
 PRINTf "Alt-F6 Toggle File Date/Time. Alt-F7 Toggle File Size Info."
 LOCATEf 19, 2, 0
 PRINTf "Alt-F8 Load Network Path.     Alt-F9 Load Default Network Path."
 LOCATEf 20, 2, 0
 PRIntf "Alt-F10 Load Default Network Path Drive."
 COLORf Yellow
 LOCATEf 21, 2, 0
 CALL PressKey
 RETURN

' help screen 5.
DisplayHelpScreen5:
 CALL DisplayScreen2
 COLORf White
 LOCATEf 2, 2, 0
 PRINTf "Hexedit information: "
 IF Windows.Detected THEN
    PRINTf "(Windows loaded) "
    PRINTf "[process #" + MID$(STR$(Process.Number + 1), 2) + "]"
 ELSE
    PRINTf "(DOS loaded)"
 END IF
 COLORf Yellow
 LOCATEf 3, 2, 0
 PRINTf "Program: " + Program + " " + Version + " " + Release + "."
 LOCATEf 4, 2, 0
 PRINTf "Author: Erik Jon Oredson"
 LOCATEf 5, 2, 0
 PRINTf "Release: 06/10/2007."
 LOCATEf 6, 2, 0
 PRINTf "Status: Public Domain"
 LOCATEf 7, 2, 0
 PRINTf "Email: eoredson@gmail.com"
 LOCATEf 8, 2, 0
 PRINTf "Urls: www.filegate.net"
 LOCATEf 9, 2, 0
 CALL PressKey
 RETURN
END SUB

' routine to print screen/file.
SUB PrintSub(Var1)
 ON LOCAL ERROR GOTO Error.Routine1
 If Var1 = 1 Then
 Column = False
 ColumnSpace = False
 HexLine$ = Nul
 HexLine2$ = Nul
 FirstByte = (FilePage - 1) * 320 + 1
 LastByte = (FilePage - 1) * 320 + 320
 DumpLine$ = DumpLineRange$
 PRINT #1, ""
 PRINT #1, DumpLine$
 Temp# = FirstByte
 FOR NextByte = FirstByte TO LastByte
    IF NextByte <= FileLength THEN
       SeekPosition = NextByte
       CALL LseekFile
       CALL ReadFile
       FileByte = Buffer
       ByteValue = ASC(FileByte)
       IF ByteValue < 32 THEN
          HexLine2$ = HexLine2$ + "."
       ELSE
          HexLine2$ = HexLine2$ + FileByte
       END IF
       HexLine$ = HexLine$ + RIGHT$("00" + HEX$(ASC(FileByte)), 2)
    ELSE
       HexLine$ = HexLine$ + "  "
       HexLine2$ = HexLine2$ + " "
    END IF
    ColumnSpace = ColumnSpace + 1
    IF ColumnSpace = 4 THEN
       HexLine$ = HexLine$ + " "
       Column = Column + 1
       ColumnSpace = False
    END IF
    Column = Column + 2
    IF Column > 44 THEN
       HexFile$ = HexLine$ + " " + HexLine2$
       HexFile$ = RTRIM$(HexFile$)
       IF LEN(HexFile$) THEN
          HexFile$ = HexFile$ + SPACE$(67 - LEN(HexFile$))
          HexFile$ = HexFile$ + "x" + RIGHT$("00000000" + HEX$(Temp# - 1#), 8)
          PRINT #1, HexFile$
       END IF
       HexLine$ = Nul
       HexLine2$ = Nul
       Temp# = NextByte + 1#
       Column = False
    END IF
 NEXT
 PRINT #1, CHR$(12);
 Else
 If Var1 = 2 Then
 Column = False
 ColumnSpace = False
 HexLine$ = Nul
 HexLine2$ = Nul

 ' calculate last page
 FirstByte = 1
 LastPage = INT((FileLength - 1) / 320) + 1
 LastByte = (LastPage - 1) * 320 + 320

 ' write to printer
 FileDumped = True
 ' display message about dumping.
 COLORf Yellow
 LOCATEf 2, 4, 0
 PRINTf SPACE$(74)
 LOCATEf 2, 4, 0
 PRINTf "Printing file: (Press <esc> to quit):"
 DumpLine$ = DumpLineRange$
 PRINT #1, ""
 PRINT #1, DumpLine$
 Temp# = FirstByte
 PercentDisplayed! = SFalse
 LOCATEf 2, 41, 0
 PRINTf " 0%"
 FOR NextByte = FirstByte TO LastByte
    IF NextByte <= FileLength THEN
       SeekPosition = NextByte
       CALL LseekFile
       CALL ReadFile
       FileByte = Buffer
       ByteValue = ASC(FileByte)
       ' skip unprintable characters
       IF ByteValue < 32 THEN
          HexLine2$ = HexLine2$ + "."
       ELSE
          HexLine2$ = HexLine2$ + FileByte
       END IF
       HexLine$ = HexLine$ + RIGHT$("00" + HEX$(ASC(FileByte)), 2)
    ELSE
       HexLine$ = HexLine$ + "  "
       HexLine2$ = HexLine2$ + " "
    END IF
    ColumnSpace = ColumnSpace + 1
    IF ColumnSpace = 4 THEN
       HexLine$ = HexLine$ + " "
       Column = Column + 1
       ColumnSpace = False
    END IF
    Column = Column + 2
    IF Column > 44 THEN
       IF INKEY$ = CHR$(27) THEN
          FileDumped = False
          EXIT FOR
       END IF
       HexFile$ = HexLine$ + " " + HexLine2$
       HexFile$ = RTRIM$(HexFile$)
       IF LEN(HexFile$) THEN
          HexFile$ = HexFile$ + SPACE$(67 - LEN(HexFile$))
          HexFile$ = HexFile$ + "x" + RIGHT$("00000000" + HEX$(Temp# - 1#), 8)
          PRINT #1, HexFile$
          PercentCopied! = INT(CSNG(NextByte / LastByte) * 100!)
          IF PercentCopied! > PercentDisplayed! THEN
             LOCATEf 2, 41, 0
             PRINTf STR$(PercentCopied!) + "%"
             PercentDisplayed! = PercentCopied!
          END IF
       END IF
       HexLine$ = Nul
       HexLine2$ = Nul
       Temp# = NextByte + 1#
       Column = False
    END IF
    R = ReleaseTime
 NEXT
 PRINT #1, CHR$(12);
 Else
 PRINT #1, "Help screen: Hex Editor " + Version + " " + Release + " functions:"
 PRINT #1, "Function keys:"
 PRINT #1, " Alt-A  Append multiple bytes to file.   Alt-T  HEX File Print."
 PRINT #1, " Alt-B  Append multiple null bytes.      Alt-U  Undo last byte change."
 PRINT #1, " Alt-C  ANSI Chart.                      Alt-V  View files."
 PRINT #1, " Alt-D  HEX Screen Dump.                 Alt-W  Close file."
 PRINT #1, " Alt-E  HEX File Dump.                   Alt-X  Exit program."
 PRINT #1, " Alt-F  Start input menu.                Alt-Y  Toggle right window."
 PRINT #1, " Alt-G  Append multiple specified bytes. Alt-Z  Undo all byte changes."
 PRINT #1, " Alt-H  HEX Chart.                       Editing keys:"
 PRINT #1, " Alt-I  DOS shell.                       Tab    -- Switch windows."
 PRINT #1, " Alt-J  Jump to byte position.           Enter  -- Change byte value."
 PRINT #1, " Alt-K  Search for ASCII string.         Insert -- Change string value."
 PRINT #1, " Alt-L  Jump to page position.           Delete -- Change hex string."
 PRINT #1, " Alt-M  Append ASCII string to file.     Escape -- Input Menu."
 PRINT #1, " Alt-N  Open new file.                   (hex value numeral preceded)."
 PRINT #1, " Alt-O  Print help.                      (ascii values preceded with H"
 PRINT #1, " Alt-P  HEX Screen Print.                treated as hexidecimal.)"
 PRINT #1, " Alt-Q  Help screen.                     (right window unprintable chars"
 PRINT #1, " Alt-R  Redraw screen.                   are represented with a dot)."
 PRINT #1, " Alt-S  Search for multiple bytes.       (<escape> key exits search)."
 PRINT #1, "Marker keys:"
 PRINT #1, " 1  -  add marker              2  -  add specific marker value"
 PRINT #1, " 3  -  delete marker           4  -  delete specific marker"
 PRINT #1, " 5  -  jump previous marker    6  -  jump current marker"
 PRINT #1, " 7  -  jump next marker        8  -  jump specific marker"
 PRINT #1, " 9  -  list all markers        0  -  list specific marker"
 PRINT #1, " -  -  list markers of value   +  -  list range of markers"
 PRINT #1, " =  -  delete a range          [  -  delete all markers"
 PRINT #1, " ]  -  delete markers of value"
 PRINT #1, "Information keys:"
 PRINT #1, " ? key displays file length, and undos remaining."
 PRINT #1, " ! key displays current page, row, and column."
 PRINT #1, " ~ key displays last page and markers used."
 PRINT #1, " " + CHR$(34) + " key displays current path of file being edited."
 PRINT #1, " ; key displays the range of the current hilighted area."
 PRINT #1, " { key displays number of pasted entries stored in the undo file."
 PRINT #1, "Calculator key:  keypad '5' key, or Alt-F5"
 PRINT #1, "Repeat last search:  Control-F3"
 PRINT #1, CHR$(12);
 PRINT #1, "Help screen: Hex Editor " + Version + " " + Release + " functions:"
 PRINT #1, "Display keys:"
 PRINT #1, " F1 key toggles 64-byte filename display."
 PRINT #1, " F2 key toggles lower screen help key list."
 PRINT #1, "DOS function keys:"
 PRINT #1, " F11 key opens DOS shell in editor or file menu box."
 PRINT #1, " F12 key prompts for DOS command in editor."
 PRINT #1, "Hilight keys:"
 PRINT #1, " Shift-<key> hilights area, where <key> is:"
 PRINT #1, " <left>/<right>/<up>/<down>/<page up>/<page down>/<home>/<end>"
 PRINT #1, "Clipboard controls:"
 PRINT #1, " Control-C (copy)                 Control-V (paste)"
 PRINT #1, " Control-X (undo previous paste)  Control-Z (undo all pastes)"
 PRINT #1, "Multiple file keys:"
 PRINT #1, " F6 - Next file.  F7 - Previous file  F8 - Load new file."
 PRINT #1, " F9 - Close file. F10 - View files.   Alt-0 - Close all files."
 PRINT #1, " Alt-1 to Alt-9  -  select specific file."
 PRINT #1, "File menu box keys:"
 PRINT #1, " F1 - Change Drive          F2 - Toggle Sort"
 PRINT #1, " F3 - Move File Box         F4 - Back Drive"
 PRINT #1, " F5 - Forward Drive         F6 - Toggle Ambiguate"
 PRINT #1, " F7 - Redraw File Menu Box  F8 - Attribute Override"
 PRINT #1, " F9 - Display Help          F10 - Exit Editor"
 PRINT #1, " F11 - Shell To DOS         F12 - Load FileSpec into Editor"
 PRINT #1, " Alt-A to Alt-Z - select drive letter"
 PRINT #1, " Alt-F1 Toggle Quiet Mode   Alt-F2 File Exclude List"
 PRINT #1, " Alt-F3 Dir Exclude List    Alt-F4 Toggle File Sort"
 PRINT #1, " Alt-F5 Toggle Dir Sort     Alt-F6 Toggle File date/time"
 PRINT #1, " Alt-F7 Toggle File Size"
 PRINT #1, "File Menu Box Network keys:"
 PRINT #1, " Alt-F8  Load Network Path"
 PRINT #1, " Alt-F9  Load Default Network Path"
 PRINT #1, " Alt-F10 Load Default Network Path Drive"
 PRINT #1, CHR$(12);
 Endif
 Endif
Error.Resume1:
 EXIT SUB
Error.Routine1:
 RESUME Error.Resume1
END SUB

' subroutine to dump screen/file contents to file.
SUB DumpSub(Var1)
 ON LOCAL ERROR GOTO Error.Routine3
 If Var1 = 1 Then
 FirstByte = (FilePage - 1) * 320 + 1
 LastByte = (FilePage - 1) * 320 + 320
 DumpLine$ = DumpLineRange$
 PRINT #1, ""
 PRINT #1, DumpLine$
 Temp# = FirstByte
 FOR NextByte = FirstByte TO LastByte
    IF NextByte <= FileLength THEN
       SeekPosition = NextByte
       CALL LseekFile
       CALL ReadFile
       FileByte = Buffer
       ByteValue = ASC(FileByte)
       ' skip unprintable characters
       IF ByteValue < 32 THEN
          HexLine2$ = HexLine2$ + "."
       ELSE
          HexLine2$ = HexLine2$ + FileByte
       END IF
       HexLine$ = HexLine$ + RIGHT$("00" + HEX$(ASC(FileByte)), 2)
    ELSE
       HexLine$ = HexLine$ + "  "
       HexLine2$ = HexLine2$ + " "
    END IF
    ColumnSpace = ColumnSpace + 1
    IF ColumnSpace = 4 THEN
       HexLine$ = HexLine$ + " "
       Column = Column + 1
       ColumnSpace = False
    END IF
    Column = Column + 2
    IF Column > 44 THEN
       HexFile$ = HexLine$ + " " + HexLine2$
       HexFile$ = RTRIM$(HexFile$)
       IF LEN(HexFile$) THEN
          HexFile$ = HexFile$ + SPACE$(67 - LEN(HexFile$))
          HexFile$ = HexFile$ + "x" + RIGHT$("00000000" + HEX$(Temp# - 1#), 8)
          PRINT #1, HexFile$
       END IF
       HexLine$ = Nul
       HexLine2$ = Nul
       Temp# = NextByte + 1#
       Column = False
    END IF
 NEXT
 Else
 ' calculate last page
 FirstByte = 1
 LastPage = INT((FileLength - 1) / 320) + 1
 LastByte = (LastPage - 1) * 320 + 320

 ' write to file
 FileDumped = True
 COLORf Yellow
 LOCATEf 2, 4, 0
 PRINTf SPACE$(74)
 LOCATEf 2, 4, 0
 PRINTf "Writing file: (Press <esc> to quit):"
 DumpLine$ = DumpLineRange$
 PRINT #1, ""
 PRINT #1, DumpLine$
 Temp# = FirstByte
 PercentDisplayed! = SFalse
 LOCATEf 2, 40, 0
 PRINTf " 0%"
 FOR NextByte = FirstByte TO LastByte
    IF NextByte <= FileLength THEN
       SeekPosition = NextByte
       CALL LseekFile
       CALL ReadFile
       FileByte = Buffer
       ByteValue = ASC(FileByte)
       ' skip unprintable characters
       IF ByteValue < 32 THEN
          HexLine2$ = HexLine2$ + "."
       ELSE
          HexLine2$ = HexLine2$ + FileByte
       END IF
       HexLine$ = HexLine$ + RIGHT$("00" + HEX$(ASC(FileByte)), 2)
    ELSE
       HexLine$ = HexLine$ + "  "
       HexLine2$ = HexLine2$ + " "
    END IF
    ColumnSpace = ColumnSpace + 1
    IF ColumnSpace = 4 THEN
       HexLine$ = HexLine$ + " "
       Column = Column + 1
       ColumnSpace = False
    END IF
    Column = Column + 2
    IF Column > 44 THEN
       IF INKEY$ = CHR$(27) THEN
          FileDumped = False
          EXIT FOR
       END IF
       HexFile$ = HexLine$ + " " + HexLine2$
       HexFile$ = RTRIM$(HexFile$)
       IF LEN(HexFile$) THEN
          HexFile$ = HexFile$ + SPACE$(67 - LEN(HexFile$))
          HexFile$ = HexFile$ + "x" + RIGHT$("00000000" + HEX$(Temp# - 1#), 8)
          PRINT #1, HexFile$
          PercentCopied! = INT(CSNG(NextByte / LastByte) * 100!)
          IF PercentCopied! > PercentDisplayed! THEN
             LOCATEf 2, 40, 0
             PRINTf STR$(PercentCopied!) + "%"
             PercentDisplayed! = PercentCopied!
          END IF
       END IF
       HexLine$ = Nul
       HexLine2$ = Nul
       Temp# = NextByte + 1#
       Column = False
    END IF
    R = ReleaseTime
 NEXT
 Endif
Error.Resume3:
 EXIT SUB
Error.Routine3:
 RESUME Error.Resume3
END SUB

' routine to display Ansi/Hex chart.
SUB DisplayChart(Var1)
 On Local Error Resume Next
 If Var1=1 Then
 CALL DisplayScreen2
 COLORf White
 LOCATEf 2, 2, 0
 PRINTf "ASCII Chart for characters 1 to 127:"
 Var2 = 3
 LOCATEf 3, 2, 0
 FOR Char = 1 TO 127
    SELECT CASE Char
    ' skip unprintable characters
    CASE 0, 7, 9 TO 13, 28 TO 32
       DisplayChar$ = " "
    ' store character
    CASE ELSE
       DisplayChar$ = CHR$(Char)
    END SELECT
    Var$ = MID$(STR$(Char), 2)
    Var1$ = RIGHT$("00" + Var$, 3) + " "
    COLORf Green
    PRINTf Var1$
    COLORf Yellow
    PRINTf DisplayChar$ + " "
    ' check full screen line
    IF (Char MOD 10) = False THEN
       Var2 = Var2 + 1
       LOCATEf Var2, 2, 0
    END IF
 NEXT
 LOCATEf 16, 2, 0
 CALL PressKey
 CALL DisplayScreen2
 COLORf White
 LOCATEf 2, 2, 0
 PRINTf "ASCII Chart for characters 128 to 255:"
 Var2 = 3
 LOCATEf 3, 2, 0
 FOR Char = 128 TO 255
    DisplayChar$ = CHR$(Char)
    Var$ = MID$(STR$(Char), 2)
    Var1$ = RIGHT$("00" + Var$, 3) + " "
    COLORf Green
    PRINTf Var1$
    COLORf Yellow
    PRINTf DisplayChar$ + " "
    ' check full screen line
    IF ((Char - 7) MOD 10) = False THEN
       Var2 = Var2 + 1
       LOCATEf Var2, 2, 0
    END IF
 NEXT
 LOCATEf 16, 2, 0
 CALL PressKey
 Else
 CALL DisplayScreen2
 COLORf White
 LOCATEf 2, 2, 0
 PRINTf "HEX Chart for characters 1 to 127:"
 Var2 = 3
 LOCATEf 3, 2, 0
 FOR Char = 1 TO 127
    SELECT CASE Char
    ' skip unprintable characters
    CASE 0, 7, 9 TO 13, 28 TO 32
       DisplayChar$ = " "
    ' store character
    CASE ELSE
       DisplayChar$ = CHR$(Char)
    END SELECT
    Var$ = HEX$(Char)
    Var1$ = RIGHT$("0" + Var$, 2) + " "
    COLORf Green
    PRINTf Var1$
    COLORf Yellow
    PRINTf DisplayChar$ + " "
    ' check full screen line
    IF (Char MOD 10) = False THEN
       Var2 = Var2 + 1
       LOCATEf Var2, 2, 0
    END IF
 NEXT
 LOCATEf 16, 2, 0
 CALL PressKey
 COLORf Plain
 CALL DisplayScreen2
 COLORf White
 LOCATEf 2, 2, 0
 PRINTf "HEX Chart for characters 128 to 255:"
 Var2 = 3
 LOCATEf 3, 2, 0
 FOR Char = 128 TO 255
    DisplayChar$ = CHR$(Char)
    Var$ = HEX$(Char)
    Var1$ = RIGHT$("0" + Var$, 2) + " "
    COLORf Green
    PRINTf Var1$
    COLORf Yellow
    PRINTf DisplayChar$ + " "
    ' check full screen line
    IF ((Char - 7) MOD 10) = False THEN
       Var2 = Var2 + 1
       LOCATEf Var2, 2, 0
    END IF
 NEXT
 LOCATEf 16, 2, 0
 CALL PressKey
 Endif
END SUB

REM Clipboard routines:

SUB Clipboard2(Var)
' declare error trap.
ON LOCAL ERROR GOTO Error.Routine5
IF Var = 1 THEN GOTO CopyToClipboard
IF Var = 2 THEN GOTO PasteFromClipboard
IF Var = 3 THEN GOTO ClipboardUndo
IF Var = 4 THEN GOTO ClipboardUndoAll
TopProgram:
EXIT SUB

' copy hilighted area to clipboard file.
CopyToClipboard:
 IF CopyPositionStart = DFalse THEN
    EXIT SUB
 END IF
 ' store clipboard length.
 ByteLength# = CopyPositionEnd - CopyPositionStart + 1#
 IF ByteLength# + 4# > 2147483647# THEN
    StatusMessage = "Copy extends beyond clipboard file length."
    CALL DisplayStatus2
    EXIT SUB
 END IF
 Call ClearStatus
 PRINTf "Editing file: " + RTRIM$(Filename) + " :"
 PRINTf " Copying bytes to clipboard.."
 CALL LocateCursor2
 Bytes$ = RIGHT$("00000000" + HEX$(ByteLength#), 8)
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 1, 2)))
 PUT #4, 1, CopyByte
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 3, 2)))
 PUT #4, 2, CopyByte
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 5, 2)))
 PUT #4, 3, CopyByte
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 7, 2)))
 PUT #4, 4, CopyByte
 ' write clipboard.
 Temp# = FilePosition
 Temp2# = 4#
 FOR NextByte = CopyPositionStart TO CopyPositionEnd
    SeekPosition = NextByte
    CALL LseekFile
    CALL ReadFile
    FileByte = Buffer
    Temp2# = Temp2# + 1#
    PUT #4, Temp2#, FileByte
 NEXT
 FilePosition = Temp#
 Call ClearStatus
 PRINTf "Editing file: " + RTRIM$(Filename) + " :"
 UndoToggle = NOT UndoToggle
 IF UndoToggle THEN
    PRINTf " (+)"
 ELSE
    PRINTf " (X)"
 END IF
 PRINTf STR$(ByteLength#) + " bytes copied to clipboard."
 CALL LocateCursor2
 EXIT SUB

' paste clipboard to current file position.
PasteFromClipboard:
 ' read clipboard length.
 IF LOF(4) = 0 THEN
    EXIT SUB
 END IF
 ' get clipboard length.
 ByteLength# = DFalse
 GET #4, 1, CopyByte
 ByteLength# = ByteLength# + ASC(CopyByte) * 16 ^ 6
 GET #4, 2, CopyByte
 ByteLength# = ByteLength# + ASC(CopyByte) * 16 ^ 4
 GET #4, 3, CopyByte
 ByteLength# = ByteLength# + ASC(CopyByte) * 16 ^ 2
 GET #4, 4, CopyByte
 ByteLength# = ByteLength# + ASC(CopyByte) 
 ' check end of file.
 IF FilePosition + ByteLength# - 1# > FileLength THEN
    StatusMessage = "Paste extends beyond file length."
    CALL DisplayStatus2
    EXIT SUB
 END IF
 ' clear hilight area.
 IF CopyPositionStart > 0# THEN
    CALL ResetHilightBytes
 END IF
 ' store paste area to undo clipboard file.
 GOSUB StoreUndoPaste
 IF ValidPaste = False THEN
    EXIT SUB
 END IF
 ' write paste bytes.
 Temp# = FilePosition
 LastPage = FilePage
 FOR NextByte = 1# TO ByteLength#
    GET #4, NextByte + 4#, FileByte
    SeekPosition = FilePosition
    CALL LseekFile
    CALL WriteFile
    CALL CalculatePosition1
    IF LastPage = FilePage THEN
       CALL ClearPageByte
    END IF
    IF NextByte < ByteLength# THEN
       FilePosition = FilePosition + 1
    END IF
 NEXT
 FilePosition = Temp#
 CALL CalculatePosition1
 CALL DisplayPageByte
 Call ClearStatus
 PRINTf "Editing file: " + RTRIM$(Filename) + " :"
 PRINTf STR$(ByteLength#) + " bytes "
 PRINTf "(entry #" + MID$(STR$(ByteEntries), 2) + ") pasted."
 CALL LocateCursor2
 EXIT SUB

' store area to be over-written into paste undo file.
'   see also: Struc.txt describes file format.
StoreUndoPaste:
 IF LEN(5) = 0 THEN
    CopyByte = CHR$(0)
    PUT #5, 1, CopyByte
    PUT #5, 2, CopyByte
 END IF
 ValidPaste = True
 ' get maximum entries.
 ByteEntries = 0
 GET #5, 1, CopyByte
 ByteEntries = ByteEntries + ASC(CopyByte) * 16 ^ 2
 GET #5, 2, CopyByte
 ByteEntries = ByteEntries + ASC(CopyByte) 
 IF ByteEntries >= 32767 THEN
    ValidPaste = False
    StatusMessage = "Paste undo entries extend beyond file length."
    CALL DisplayStatus2
    RETURN
 END IF
 ' scan to last entry position in paste undo file.
 Temp2# = 3#
 Temp3 = 1
 DO
    ' check last entry.
    IF Temp3 > ByteEntries THEN
       EXIT DO
    END IF
    ' skip file start position.
    Temp2# = Temp2# + 4#
    LengthOfRecord# = DFalse
    GET #5, Temp2#, CopyByte
    LengthOfRecord# = LengthOfRecord# + ASC(CopyByte) * 16 ^ 6
    Temp2# = Temp2# + 1#
    GET #5, Temp2#, CopyByte
    LengthOfRecord# = LengthOfRecord# + ASC(CopyByte) * 16 ^ 4
    Temp2# = Temp2# + 1#
    GET #5, Temp2#, CopyByte
    LengthOfRecord# = LengthOfRecord# + ASC(CopyByte) * 16 ^ 2
    Temp2# = Temp2# + 1#
    GET #5, Temp2#, CopyByte
    LengthOfRecord# = LengthOfRecord# + ASC(CopyByte) 
    Temp2# = Temp2# + LengthOfRecord# + 1#
    Temp3 = Temp3 + 1
 LOOP
 ' get maximum entries.
 TotalBytes# = Temp2# + ByteLength# + 8#
 IF TotalBytes# >= 2147483647# THEN
    ValidPaste = False
    StatusMessage = "Paste undo extends beyond file length."
    CALL DisplayStatus2
    RETURN
 END IF
 Call ClearStatus
 PRINTf "Editing file: " + RTRIM$(Filename) + " :"
 PRINTf " Pasting bytes from clipboard.."
 CALL LocateCursor2
 ' store new entry.
 ByteEntries = ByteEntries + 1
 Bytes$ = RIGHT$("0000" + HEX$(ByteEntries), 4)
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 1, 2)))
 PUT #5, 1, CopyByte
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 3, 2)))
 PUT #5, 2, CopyByte
 ' store file position of undo paste area.
 Bytes$ = RIGHT$("00000000" + HEX$(FilePosition), 8)
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 1, 2)))
 PUT #5, Temp2#, CopyByte
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 3, 2)))
 Temp2# = Temp2# + 1#
 PUT #5, Temp2#, CopyByte
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 5, 2)))
 Temp2# = Temp2# + 1#
 PUT #5, Temp2#, CopyByte
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 7, 2)))
 Temp2# = Temp2# + 1#
 PUT #5, Temp2#, CopyByte
 ' store length of undo paste area.
 Bytes$ = RIGHT$("00000000" + HEX$(ByteLength#), 8)
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 1, 2)))
 Temp2# = Temp2# + 1#
 PUT #5, Temp2#, CopyByte
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 3, 2)))
 Temp2# = Temp2# + 1#
 PUT #5, Temp2#, CopyByte
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 5, 2)))
 Temp2# = Temp2# + 1#
 PUT #5, Temp2#, CopyByte
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 7, 2)))
 Temp2# = Temp2# + 1#
 PUT #5, Temp2#, CopyByte
 ' write undo clipboard.
 Temp# = FilePosition
 FOR NextByte = Temp# TO Temp# + ByteLength# - 1#
    SeekPosition = NextByte
    CALL LseekFile
    CALL ReadFile
    FileByte = Buffer
    Temp2# = Temp2# + 1#
    PUT #5, Temp2#, FileByte
 NEXT
 FilePosition = Temp#
 RETURN

' undo last paste clipboard.
ClipboardUndo:
 IF LEN(5) = 0 THEN
    CopyByte = CHR$(0)
    PUT #5, 1, CopyByte
    PUT #5, 2, CopyByte
    ValidPaste = False
 ELSE
    Call ClearStatus
    PRINTf "Editing file: " + RTRIM$(Filename) + " :"
    PRINTf " Undoing bytes from pastefile.."
    CALL LocateCursor2
    GOSUB UndoClipboard
 END IF
 Call ClearStatus
 PRINTf "Editing file: " + RTRIM$(Filename) + " :"
 IF ValidPaste = False THEN
    PRINTf " 0 bytes paste undo."
 ELSE
    PRINTf STR$(ByteLength#) + " bytes "
    PRINTf "(entry #" + MID$(STR$(ByteEntries + 1), 2) + ") paste undo."
 END IF
 CALL LocateCursor2
 EXIT SUB

' undo all paste clipboard.
ClipboardUndoAll:
 TotalEntries = 0
 IF LEN(5) = 0 THEN
    CopyByte = CHR$(0)
    PUT #5, 1, CopyByte
    PUT #5, 2, CopyByte
 ELSE
    ByteEntries = 0
    GET #5, 1, CopyByte
    ByteEntries = ByteEntries + ASC(CopyByte) * 16 ^ 2
    GET #5, 2, CopyByte
    ByteEntries = ByteEntries + ASC(CopyByte)
    IF ByteEntries > 0 THEN
       TotalEntries = ByteEntries
       Call ClearStatus
       PRINTf "Editing file: " + RTRIM$(Filename) + " :"
       PRINTf " Undoing all entries from paste file.."
       CALL LocateCursor2
       DO
          GOSUB UndoClipboard
          IF ValidPaste = False THEN
             EXIT DO
          END IF
       LOOP
    END IF
 END IF
 Call ClearStatus
 PRINTf "Editing file: " + RTRIM$(Filename) + " :"
 PRINTf " Total" + STR$(TotalEntries) + " entries in paste undos."
 CALL LocateCursor2
 EXIT SUB

' copy last undo paste entry.
UndoClipboard:
 ' get last entry.
 ByteEntries = 0
 GET #5, 1, CopyByte
 ByteEntries = ByteEntries + ASC(CopyByte) * 16 ^ 2
 GET #5, 2, CopyByte
 ByteEntries = ByteEntries + ASC(CopyByte) 
 ValidPaste = True
 IF ByteEntries = 0 THEN
    ValidPaste = False
    RETURN
 END IF
 ' scan to last entry position in paste undo file.
 Temp# = FilePosition
 Temp2# = 3#
 Temp3 = 1
 DO
    ' check last entry.
    IF Temp3 = ByteEntries THEN
       EXIT DO
    END IF
    ' skip file start position.
    Temp2# = Temp2# + 4#
    LengthOfRecord# = DFalse
    GET #5, Temp2#, CopyByte
    LengthOfRecord# = LengthOfRecord# + ASC(CopyByte) * 16 ^ 6
    Temp2# = Temp2# + 1#
    GET #5, Temp2#, CopyByte
    LengthOfRecord# = LengthOfRecord# + ASC(CopyByte) * 16 ^ 4
    Temp2# = Temp2# + 1#
    GET #5, Temp2#, CopyByte
    LengthOfRecord# = LengthOfRecord# + ASC(CopyByte) * 16 ^ 2
    Temp2# = Temp2# + 1#
    GET #5, Temp2#, CopyByte
    LengthOfRecord# = LengthOfRecord# + ASC(CopyByte) 
    Temp2# = Temp2# + LengthOfRecord# + 1#
    Temp3 = Temp3 + 1
 LOOP
 ' restore last entry.
 ByteEntries = ByteEntries - 1
 Bytes$ = RIGHT$("0000" + HEX$(ByteEntries), 4)
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 1, 2)))
 PUT #5, 1, CopyByte
 CopyByte = CHR$(VAL("&H" + MID$(Bytes$, 3, 2)))
 PUT #5, 2, CopyByte
 ' restore file position of undo paste area.
 NextByte = DFalse
 GET #5, Temp2#, CopyByte
 NextByte = NextByte + ASC(CopyByte) * 16 ^ 6
 Temp2# = Temp2# + 1#
 GET #5, Temp2#, CopyByte
 NextByte = NextByte + ASC(CopyByte) * 16 ^ 4
 Temp2# = Temp2# + 1#
 GET #5, Temp2#, CopyByte
 NextByte = NextByte + ASC(CopyByte) * 16 ^ 2
 Temp2# = Temp2# + 1#
 GET #5, Temp2#, CopyByte
 NextByte = NextByte + ASC(CopyByte) 
 ' restore length of undo paste area.
 ByteLength# = DFalse
 Temp2# = Temp2# + 1#
 GET #5, Temp2#, CopyByte
 ByteLength# = ByteLength# + ASC(CopyByte) * 16 ^ 6
 Temp2# = Temp2# + 1#
 GET #5, Temp2#, CopyByte
 ByteLength# = ByteLength# + ASC(CopyByte) * 16 ^ 4
 Temp2# = Temp2# + 1#
 GET #5, Temp2#, CopyByte
 ByteLength# = ByteLength# + ASC(CopyByte) * 16 ^ 2
 Temp2# = Temp2# + 1#
 GET #5, Temp2#, CopyByte
 ByteLength# = ByteLength# + ASC(CopyByte) 
 ' undo paste area.
 Temp# = FilePosition
 Temp3# = NextByte
 LastPage = FilePage
 FOR FilePosition = Temp3# TO Temp3# + ByteLength# - 1#
    Temp2# = Temp2# + 1#
    GET #5, Temp2#, FileByte
    SeekPosition = FilePosition
    CALL LseekFile
    CALL WriteFile
    CALL CalculatePosition1
    IF LastPage = FilePage THEN
       CALL ClearPageByte
    END IF
 NEXT
 FilePosition = Temp#
 CALL CalculatePosition1
 CALL DisplayPageByte
 RETURN

' critical error trap.
Error.Routine5:
 ErrorTrap = ERR
 IF ScreenDrawn THEN
    CLS
 END IF
 ScreenDrawn = False
 COLORf White
 LOCATEf Csrlin, 1, 0
 PRINTf "Hex Editor Clipboard " + Version + " " + Release + " critical error trap:"
 COLORf Yellow
 LOCATEf Csrlin+1, 1, 0
 CALL DisplayCriticalError(ErrorTrap)
 ' display error prompt.
 COLORf Green
 LOCATEf Csrlin+1, 1, 0
 PRINTf "Press R(etry), C(ontinue), Q(uit):"
 LOCATEf Csrlin, 35, 1
 ' get keypress.
 DO
    ErrorRespond$ = Nul
    DO
       ErrorRespond$ = INKEY$
       IF LEN(ErrorRespond$) THEN
          EXIT DO
       END IF
    LOOP
    ' parse key.
    SELECT CASE LCASE$(ErrorRespond$)
    CASE "r"
       PRINTf "r"
       LOCATEf Csrlin+1, 1, 0
       RESUME TopProgram
    CASE "c"
       PRINTf "c"
       LOCATEf Csrlin+1, 1, 0
       RESUME TopProgram
    CASE "q"
       PRINTf "q"
       LOCATEf Csrlin+1, 1, 0
       RESUME TopProgram
    END SELECT
    R = ReleaseTime
 LOOP
END SUB

REM Viewfile routine:

' returns Var=1 to 9 of file number.
SUB Viewfiles(Var)
' declare error trap.
ON LOCAL ERROR GOTO Error.Routine6
 GOSUB StoreArea
 GOSUB DrawMenu
 MenuSelect = 1
 GOSUB DrawCurrentMenuSelection
 CALL SMouse

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

    ' call mouse subroutine.
    CALL MouseDriver

    ' check left mouse button.
    IF Mouse.ButtonX THEN
       Mouse.Row = Mouse.RowX
       Mouse.Column = Mouse.ColumnX
       GOSUB MouseButton1Y
    ELSE
       ' check right/middle mouse button.
       IF Mouse.Button2 OR Mouse.Button3 THEN
          GOSUB RestoreArea
          Var = False
          EXIT SUB
       ELSE
          ' check mouse position.
          IF Mouse.Row OR Mouse.Column THEN
             GOSUB MoveMouse
          END IF
       END IF
    END IF
    ' store keyboard buffer.
    CharInput$ = INKEY$
    IF LEN(CharInput$) THEN
       SELECT CASE LEN(CharInput$)
       CASE 1
          SELECT CASE ASC(CharInput$)
          CASE 13 ' Enter
             GOSUB RestoreArea
             IF MenuSelect > NumberFiles THEN
                Var = False
             ELSE
                Var = MenuSelect
             END IF
             EXIT SUB
          CASE 27 ' Escape
             GOSUB RestoreArea
             Var = False
             EXIT SUB
          CASE 49 TO 57 ' 1 to 9
             GOSUB EraseCurrentMenuSelection
             MenuSelect = ASC(CharInput$) - 48
             GOSUB DrawCurrentMenuSelection
          END SELECT
       CASE 2
          SELECT CASE ASC(RIGHT$(CharInput$, 1))
          CASE 72 ' Up
             GOSUB MenuUp
          CASE 80 ' Down
             GOSUB MenuDown
          END SELECT
       END SELECT
    END IF
    ' release time slice,
    R = ReleaseTime
 LOOP
 EXIT SUB

' draws menu.
DrawMenu:
 CALL HMouse
 BoxDrawX1 = 4
 BoxDrawX2 = 14
 BoxDrawY1 = 6
 BoxDrawY2 = 21
 BoxDrawLength = 16
 GOSUB DrawBox
 COLORf2 White, 0
 FOR Var2 = 1 TO 9
    LOCATEf 4 + Var2, 7, 0
    PRINTf MID$(STR$(Var2), 2) + " "
    IF Var2 > NumberFiles THEN
       PRINTf "<none>      "
    ELSE
       PRINTf File(Var2).Filename
    END IF
 NEXT
 CALL SMouse
 RETURN

' draws box from (BoxDrawX1,BoxDrawY1) To (BoxDrawX2,BoxDrawY2),
'  length of box from left to right being BoxDrawLength.
DrawBox:
 COLORf Yellow
 LOCATEf BoxDrawX1, BoxDrawY1, 0
 PRINTf CHR$(ULcorner) + STRING$(BoxDrawLength - 2, Hline) + CHR$(URcorner)
 FOR RowX1 = BoxDrawX1 + 1 TO BoxDrawX2 - 1
    LOCATEf RowX1, BoxDrawY1, 0
    PRINTf CHR$(Vline)
    LOCATEf RowX1, BoxDRawY2, 0
    PRINTf CHR$(Vline)
 NEXT
 LOCATEf BoxDrawX2, BoxDrawY1, 0
 PRINTf CHR$(LLcorner) + STRING$(BoxDrawLength - 2, Hline) + CHR$(LRcorner)
 COLORf2 0, 7
 LOCATEf 4, 9, 0
 PRINTf "View Files"
 COLORf Yellow
 RETURN

' stores area under menu.
StoreArea:
 CALL HMouse
 RowX1 = False
 ColumnY1 = False
 FOR RowX2 = 4 TO 14
    RowX1 = RowX1 + 1
    ColumnY1 = False
    FOR ColumnY2 = 6 TO 21
       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
 CALL SMouse
 RETURN

' restores area under menu.
RestoreArea:
 CALL HMouse
 RowX1 = False
 ColumnY1 = False
 FOR RowX2 = 4 TO 14
    RowX1 = RowX1 + 1
    ColumnY1 = False
    FOR ColumnY2 = 6 TO 21
       ColumnY1 = ColumnY1 + 1
       LOCATEf RowX2, ColumnY2, 1
       ' restore color.
       TempZ = Area2(RowX1, ColumnY1)
       ' undocumented: also stores background color.
       VarB = INT(TempZ / 16)
       VarF = TempZ MOD 16
       COLORf2 VarF, VarB
       ' restore ascii character.
       PRINTf CHR$(Area1(RowX1, ColumnY1))
    NEXT
 NEXT
 CALL SMouse
 RETURN

' moves menu up, wrapping.
MenuUp:
 GOSUB EraseCurrentMenuSelection
 IF MenuSelect = 1 THEN
    MenuSelect = 9
 ELSE
    MenuSelect = MenuSelect - 1
 END IF
 GOSUB DrawCurrentMenuSelection
 RETURN

' moves menu down, wrapping.
MenuDown:
 GOSUB EraseCurrentMenuSelection
 IF MenuSelect = 9 THEN
    MenuSelect = 1
 ELSE
    MenuSelect = MenuSelect + 1
 END IF
 GOSUB DrawCurrentMenuSelection
 RETURN

' removes hilight from current menu selection.
EraseCurrentMenuSelection:
 CALL HMouse
 COLORf2 White, 0
 GOSUB DisplayCurrentMenuSelection
 COLORf2 White, 0
 CALL SMouse
 RETURN

' adds hilight to current menu selection.
DrawCurrentMenuSelection:
 CALL HMouse
 COLORf2 White, 1
 GOSUB DisplayCurrentMenuSelection
 COLORf2 White, 0
 CALL SMouse
 RETURN

' draws current menu selection.
DisplayCurrentMenuSelection:
 LOCATEf 4 + MenuSelect, 7, 0
 PRINTf MID$(STR$(MenuSelect), 2) + " "
 IF MenuSelect > NumberFiles THEN
    PRINTf "<none>      "
    Call ClearStatus
    PRINTf "View file" + STR$(MenuSelect) + ": <none>"
 ELSE
    PRINTf File(MenuSelect).Filename
    GOSUB DisplayPath
 END IF
 RETURN

' display path of file being edited.
DisplayPath:
 Call ClearStatus
 Z$ = RTRIM$(File(MenuSelect).ShortFilename)
 N$ = RTRIM$(File(MenuSelect).Netpath)
 IF N$ <> Nul THEN
    IF MID$(Z$, 2, 1) = ":" THEN
       Z$ = MID$(Z$, 3)
    END IF
 END IF
 CALL Deconcatenate(N$, Z$, 64)
 Var = LEN(Z$)
 DO
    Var = Var - 1
    IF Var = False THEN
       Z$ = Nul
       EXIT DO
    END IF
    IF MID$(Z$, Var, 1) = "\" THEN
       Z$ = LEFT$(Z$, Var)
       EXIT DO
    END IF
 LOOP
 IF Z$ = Nul THEN
    Z$ = "\"
 END IF
 PRINTf "Viewing path: " + Z$ + " "
 FileDisplay2 = True
 RETURN

' process left mouse button.
MouseButton1Y:
 IF Mouse.Row >= 5 AND Mouse.Row <= 13 THEN
    IF Mouse.Column >= 7 AND Mouse.Column <= 20 THEN
       Var = Mouse.Row - 4
       GOSUB RestoreArea
       EXIT SUB
    END IF
 END IF
 RETURN

' process mouse move.
MoveMouse:
 ' check mouse selection boundaries.
 IF Mouse.Row >=5 AND Mouse.Row <= 13 THEN
    IF Mouse.Column >= 7 AND Mouse.Column <= 20 THEN
       IF Mouse.Row - 4 <> MenuSelect THEN
          GOSUB EraseCurrentMenuSelection
          MenuSelect = Mouse.Row - 4
       END IF
       GOSUB DrawCurrentMenuSelection
    END IF
 END IF
 RETURN

TopProgram1:
 EXIT SUB

' critical error trap.
Error.Routine6:
 ErrorTrap = ERR
 IF ScreenDrawn THEN
    CLS
 END IF
 ScreenDrawn = False
 COLORf White
 LOCATEf Csrlin, 1, 0
 PRINTf "Hex Editor Viewfile " + Version + " " + Release + " critical error trap:"
 COLORf Yellow
 LOCATEf Csrlin+1, 1, 0
 CALL DisplayCriticalError(ErrorTrap)
 ' display error prompt.
 COLORf Green
 LOCATEf Csrlin+1, 1, 0
 PRINTf "Press R(etry), C(ontinue), Q(uit):"
 LOCATEf Csrlin, 35, 1
 ' get keypress.
 DO
    ErrorRespond$ = Nul
    DO
       ErrorRespond$ = INKEY$
       IF LEN(ErrorRespond$) THEN
          EXIT DO
       END IF
    LOOP
    ' parse key.
    SELECT CASE LCASE$(ErrorRespond$)
    CASE "r"
       PRINTf "r"
       LOCATEf Csrlin+1, 1, 0
       RESUME TopProgram1
    CASE "c"
       PRINTf "c"
       LOCATEf Csrlin+1, 1, 0
       RESUME TopProgram1
    CASE "q"
       PRINTf "q"
       LOCATEf Csrlin+1, 1, 0
       RESUME TopProgram1
    END SELECT
    R = ReleaseTime
 LOOP
END SUB

' sorts DOS/Windows directories/filenames in
'   hexedit1.dat, hexedit2.dat files.
SUB SortFiles(Var1)
 On Local Error Goto Error.Routine7
 Dim I1 As String, I2 As String
 If Windows.Detected Then
    ' sort windows filenames.
    If Var1 = 1 Then
       Num! = Num.Files
       ' perform heap sort.
       IF FileSort THEN
          ' descending.
          FOR I! = 2! TO Num!
             J! = I!
             DO UNTIL J! = 1!
                P! = J! \ 2!
                I1 = Rtrim$(Filenames(J!))
                I2 = Rtrim$(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 = Rtrim$(Filenames(1!))
             I2 = Rtrim$(Filenames(I!))
             WinFileStruc.Name = I2
             PUT 2, 1!, WinFileStruc
             WinFileStruc.Name = I1
             PUT 2, I!, WinFileStruc
             J! = 1!
             DO
                IF 2! * J! > 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 = Rtrim$(Filenames(J!))
                I2 = Rtrim$(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
       ELSE
          ' ascending.
          FOR I! = 2! TO Num!
             J! = I!
             DO UNTIL J! = 1!
                P! = J! \ 2!
                I1 = Rtrim$(Filenames(J!))
                I2 = Rtrim$(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 = Rtrim$(Filenames(1!))
             I2 = Rtrim$(Filenames(I!))
             WinFileStruc.Name = I2
             PUT 2, 1!, WinFileStruc
             WinFileStruc.Name = I1
             PUT 2, I!, WinFileStruc
             J! = 1!
             DO
                IF 2! * J! > 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 = Rtrim$(Filenames(J!))
                I2 = Rtrim$(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
       END IF
    ' sort windows directories.
    Else
       Num! = Num.Dirs
       Start! = 0!
       IF RTRIM$(Directories(1)) = "." THEN
          Start! = 1!
       END IF
       IF RTRIM$(Directories(2)) = ".." THEN
          Start! = 2!
       END IF
       IF Start! >= Num! THEN
          EXIT SUB
       END IF
       ' perform insertion sort.
       FOR R! = 2! + Start! TO Num!
          I1 = Rtrim$(Directories(R!))
          FOR J! = R! TO 2! + Start! STEP -1!
             I2 = Rtrim$(Directories(J! - 1!))
             ' descending.
             IF DirSort THEN
                IF I2 < I1 THEN
                   WinFileStruc.Name = I2
                   PUT 3, J!, WinFileStruc
                ELSE
                   EXIT FOR
                END IF
             ELSE
                ' ascending.
                IF I2 > I1 THEN
                   WinFileStruc.Name = I2
                   PUT 3, J!, WinFileStruc
                ELSE
                   EXIT FOR
                END IF
             END IF
          NEXT
          WinFileStruc.Name = I1
          PUT 3, J!, WinFileStruc
       NEXT
    Endif
 Else
    ' sort dos filenames.
    If Var1 = 1 Then
       Num! = Num.Files
       ' perform heap sort.
       IF FileSort THEN
          ' descending.
          FOR I! = 2! TO Num!
             J! = I!
             DO UNTIL J! = 1!
                P! = J! \ 2!
                I1 = Rtrim$(Filenames(J!))
                I2 = Rtrim$(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 = Rtrim$(Filenames(1!))
             I2 = Rtrim$(Filenames(I!))
             DosFileStruc.Name = I2
             PUT 2, 1!, DosFileStruc
             DosFileStruc.Name = I1
             PUT 2, I!, DosFileStruc
             J! = 1!
             DO
                IF 2! * J! > 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 = Rtrim$(Filenames(J!))
                I2 = Rtrim$(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
       ELSE
          ' ascending.
          FOR I! = 2! TO Num!
             J! = I!
             DO UNTIL J! = 1!
                P! = J! \ 2!
                I1 = Rtrim$(Filenames(J!))
                I2 = Rtrim$(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 = Rtrim$(Filenames(1!))
             I2 = Rtrim$(Filenames(I!))
             DosFileStruc.Name = I2
             PUT 2, 1!, DosFileStruc
             DosFileStruc.Name = I1
             PUT 2, I!, DosFileStruc
             J! = 1!
             DO
                IF 2! * J! > 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 = Rtrim$(Filenames(J!))
                I2 = Rtrim$(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
       END IF
    Else
       ' sort dos directories.
       Num! = Num.Dirs
       Start! = 0!
       IF RTRIM$(Directories(1)) = "." THEN
          Start! = 1!
       END IF
       IF RTRIM$(Directories(2)) = ".." THEN
          Start! = 2!
       END IF
       IF Start! >= Num! THEN
          EXIT SUB
       END IF
       ' perform insertion sort.
       FOR R! = 2! + Start! TO Num!
          I1 = Rtrim$(Directories(R!))
          FOR J! = R! TO 2! + Start! STEP -1!
             I2 = Rtrim$(Directories(J! - 1!))
             ' descending.
             IF DirSort THEN
                IF I2 < I1 THEN
                   DosFileStruc.Name = I2
                   PUT 3, J!, DosFileStruc
                ELSE
                   EXIT FOR
                END IF
             ELSE
                ' ascending.
                IF I2 > I1 THEN
                   DosFileStruc.Name = I2
                   PUT 3, J!, DosFileStruc
                ELSE
                   EXIT FOR
                END IF
             END IF
          NEXT
          DosFileStruc.Name = I1
          PUT 3, J!, DosFileStruc
       NEXT
    Endif
 Endif
Error.Resume7:
 Exit Sub
Error.Routine7:
 Resume Error.Resume7
END SUB

SUB GetInfo(VarZ, VarZ$)
 On Local Error Goto Error.Routine11
 If VarZ=0 Then
    X$ = Nul
    IF (FileAttribute AND 1) = 1 THEN
       X$ = X$ + "o"
    END IF
    IF (FileAttribute AND 2) = 2 THEN
       X$ = X$ + "h"
    END IF
    IF (FileAttribute AND 4) = 4 THEN
       X$ = X$ + "s"
    END IF
    IF (FileAttribute AND 32) = 32 THEN
       X$ = X$ + "a"
    END IF
    IF X$ <> Nul THEN
       X$ = "(" + X$ + ")"
    END IF
    VarZ$=X$
    Exit Sub
 Endif
 ' construct file date and time for display.
 FileDateTime = Nul
 ' store file date and time.
 IF Windows.Detected THEN
    SELECT CASE FileSwitch
    CASE 0
       FileDate! = ASC(MID$(WDTAfile.ModTime, 4, 1))
       FileDate! = FileDate! * &H100 + ASC(MID$(WDTAfile.ModTime, 3, 1))
       FileTime! = ASC(MID$(WDTAfile.ModTime, 2, 1))
       FileTime! = FileTime! * &H100 + ASC(MID$(WDTAfile.ModTime, 1, 1))
    CASE 1
       FileDate! = ASC(MID$(WDTAfile.CreateTime, 4, 1))
       FileDate! = FileDate! * &H100 + ASC(MID$(WDTAfile.CreateTime, 3, 1))
       FileTime! = ASC(MID$(WDTAfile.CreateTime, 2, 1))
       FileTime! = FileTime! * &H100 + ASC(MID$(WDTAfile.CreateTime, 1, 1))
    CASE 2
       FileDate! = ASC(MID$(WDTAfile.AccessTime, 4, 1))
       FileDate! = FileDate! * &H100 + ASC(MID$(WDTAfile.AccessTime, 3, 1))
       FileTime! = ASC(MID$(WDTAfile.AccessTime, 2, 1))
       FileTime! = FileTime! * &H100 + ASC(MID$(WDTAfile.AccessTime, 1, 1))
    END SELECT
 ELSE
    FileDate! = ASC(MID$(DTAfile.FileDate, 2, 1))
    FileDate! = FileDate! * &H100 + ASC(MID$(DTAfile.FileDate, 1, 1))
    FileTime! = ASC(MID$(DTAfile.FileTime, 2, 1))
    FileTime! = FileTime! * &H100 + ASC(MID$(DTAfile.FileTime, 1, 1))
 END IF
 ' construct date.
 YearTemp! = INT(FileDate! / 512)
 MonthTemp! = INT((FileDate! AND &H1E0) / 32)
 DayTemp! = INT(FileDate! AND &H1F)
 YearTemp! = YearTemp! + 1980
 Var1$ = RIGHT$(STR$(MonthTemp! + 100), 2) + "-"
 Var1$ = Var1$ + RIGHT$(STR$(DayTemp! + 100), 2) + "-"
 Var1$ = Var1$ + MID$(STR$(YearTemp!), 2)
 ' construct time.
 HourTemp! = INT(FileTime! / 2048)
 MinuteTemp! = INT((FileTime! AND &H7E0) / 32)
 SecondsTemp! = INT((FileTime! AND &H1F) * 2)
 ' add one second.
 IF Windows.Detected THEN
    IF FileSwitch = 1 THEN
       IF Millisecond >= 100 THEN
          SecondsTemp! = SecondsTemp! + 1!
       END IF
    END IF
 END IF
 Var2$ = RIGHT$(STR$(HourTemp! + 100), 2) + ":"
 Var2$ = Var2$ + RIGHT$(STR$(MinuteTemp! + 100), 2) + ":"
 Var2$ = Var2$ + RIGHT$(STR$(SecondsTemp! + 100), 2)
 ' construct output value.
 IF Windows.Detected THEN
    SELECT CASE FileSwitch
    CASE 0 ' last modified (write) date\time
       FileDateTime = "[" + Var1$ + " " + LEFT$(Var2$, 5) + "]"
    CASE 1 ' creation date\time
       FileDateTime = "[" + Var1$ + " " + Var2$ + "]"
    CASE 2 ' last access date
       FileDateTime = "[" + Var1$ + "]"
    CASE ELSE ' last modified (write) date\time
       FileDateTime = "[" + Var1$ + "]"
    END SELECT
 ELSE ' last modified (write) date\time
    FileDateTime = "[" + Var1$ + " " + LEFT$(Var2$, 5) + "]"
 END IF
 ' get filesize.
 FileSize = False
 ' 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
 ' get file attribute.
 FileAttribute = False
 IF Windows.Detected THEN
    FileAttribute = ASC(WDTAfile.FileBits)
 ELSE
    FileAttribute = ASC(DTAfile.FileBits)
 END IF
Error.Resume11:
 Exit Sub
Error.Routine11:
 Resume Error.Resume11
END SUB

' search file subroutine.
'   input:
'     Var = 0 search with ascii string input.
'     Var = 1 search with hex string input.
'     Var = 2 continue search from previous input.
'   output:
'     FoundString = 1 invalid search string input.
'     FoundString = 0 search string not found.
'     FoundString = -1 search string found.
'     SearchBytePosition = location of start of search string in file.
SUB SearchFile(Var, FoundString)
 On Local Error Goto Error.Routine14
 FoundString = False
 ' check to continue search.
 IF Var = 2 THEN
    ByteString$ = RTRIM$(StoreSearchString)
    NumBytes = StoreNumBytes
    GOTO StartSearch
 END IF
 ' search multiple bytes of an ASCII string in file and locate there.
 IF Var = 0 THEN
    Call ClearStatus
    PRINTf "Enter ASCII string?"
    ByteString$ = lineinput$(2, 24, 54)
    IF LEN(ByteString$) = False THEN
       StatusMessage = "Invalid search string."
       CALL DisplayStatus2
       FoundString = 1
       EXIT SUB
    END IF
    NumBytes = LEN(ByteString$)
    CALL AsciiToHex2(ByteString$)
 ELSE
    ' search multiple bytes in file and locate there.
    '   left window specifies space-separated hex byte pairs,
    '   right window specifies space-separated 3-byte ascii pairs.
    Call ClearStatus
    IF CurrentWindow = False THEN
       PRINTf "Enter hex byte(s)?"
       ByteString$ = lineinput$(2, 23, 55)
       IF LEFT$(ByteString$, 1) = "+" THEN
          ByteString$ = MID$(ByteString$, 2)
          CALL CheckAsciiBytes(ByteString$)
       ELSE
          AllowWildcard = True
          CALL CheckHexBytes(ByteString$)
       END IF
    ELSE
       PRINTf "Enter ascii byte(s)?"
       ByteString$ = lineinput$(2, 25, 53)
       IF UCASE$(LEFT$(ByteString$, 1)) = "H" THEN
          ByteString$ = MID$(ByteString$, 2)
          AllowWildcard = True
          CALL CheckHexBytes(ByteString$)
       ELSE
          CALL CheckAsciiBytes(ByteString$)
       END IF
    END IF
    IF ValidByteString = False THEN
       StatusMessage = "Invalid search string."
       CALL DisplayStatus2
       FoundString = 1
       EXIT SUB
    END IF
 END IF
StartSearch:
 ' display searching message.
 Call ClearStatus
 DisplayLength = LEN(ByteString$)
 IF DisplayLength > 28 THEN
    Var$ = "Searching for " + LEFT$(ByteString$, 28) + "..."
 ELSE
    Var$ = "Searching for " + ByteString$ + ":"
 END IF
 Var$ = Var$ + " (Press <esc> to quit)"
 CursorLocation = LEN(Var$) + 4
 PRINTf Var$

 ' store search variables.
 FoundString = False
 CALL ClearPageByte
 LastPage = FilePage
 OriginalString$ = ByteString$
 StoreSearchString = ByteString$
 StoreNumBytes = NumBytes
 ByteSearch1 = INSTR(ByteString$, "?")
 StoreSearchPosition = FilePosition
 TotalByte$ = Nul

 ' check continue search.
 IF Var = 2 THEN
    ' check continue from last position.
    IF StoreSearchPosition = FilePosition THEN
       IF FilePosition + 1 > FileLength THEN
          EXIT SUB
       END IF
       ' reset search type.
       Var = 3
       ' increment from previous search position.
       FilePosition = FilePosition + 1
    END IF
 END IF

 ' store initial byte string.
 SearchBytePosition = FilePosition
 FOR FileBytePosition = FilePosition TO FilePosition + NumBytes - 1
    IF FileBytePosition > FileLength THEN
       If Var = 3 Then
          FilePosition = FilePosition - 1
       Endif
       FoundString = False
       EXIT SUB
    END IF
    SeekPosition = FileBytePosition
    CALL LseekFile
    CALL ReadFile
    FileByte = Buffer
    Byte$ = HEX$(ASC(FileByte))
    Byte$ = RIGHT$("00" + Byte$, 2)
    TotalByte$ = TotalByte$ + Byte$
 NEXT

 ' reset search variables.
 Byte1# = 1#
 RemainingBytes# = FileLength - FilePosition + 1
 FileBytePosition = FilePosition + NumBytes - 1
 PercentDisplayed! = SFalse
 LOCATEf 2, CursorLocation, 0
 PRINTf " 0%"

 ' continue search.
 DO
    ' fill in ? character
    IF ByteSearch1 THEN
       ByteString$ = OriginalString$
       FOR TotalBytes = 1 TO NumBytes * 2
          Byte1$ = MID$(ByteString$, TotalBytes, 1)
          Byte2$ = MID$(TotalByte$, TotalBytes, 1)
          IF Byte1$ = "?" THEN
             MID$(ByteString$, TotalBytes, 1) = Byte2$
          END IF
       NEXT
    END IF

    ' compare byte strings
    IF ByteString$ = TotalByte$ THEN
       StoreSearchPosition = SearchBytePosition
       FoundString = True
       EXIT DO
    END IF

    ' get next byte
    FileBytePosition = FileBytePosition + 1
    IF FileBytePosition > FileLength THEN
       If Var = 3 Then
          FilePosition = FilePosition - 1
       Endif
       FoundString = False
       EXIT DO
    END IF

    ' increment byte search variables.
    Byte1# = Byte1# + 1#
    SearchBytePosition = SearchBytePosition + 1#
    SeekPosition = FileBytePosition
    CALL LseekFile
    CALL ReadFile
    FileByte = Buffer
    Byte$ = HEX$(ASC(FileByte))
    Byte$ = RIGHT$("00" + Byte$, 2)
    TotalByte$ = MID$(TotalByte$, 3) + Byte$

    ' display percent remaining
    PercentCopied! = INT(CSNG(Byte1# / RemainingBytes#) * 100!)
    IF PercentCopied! > PercentDisplayed! THEN
       LOCATEf 2, CursorLocation, 0
       PRINTf STR$(PercentCopied!) + "%"
       PercentDisplayed! = PercentCopied!
    END IF

    ' check to break search
    IF INKEY$ = CHR$(27) THEN
       EXIT DO
    END IF
    R = ReleaseTime
 LOOP
EndSearch:
 EXIT SUB
Error.Routine14:
 Resume EndSearch
END SUB

' get drive information.
SUB GetDriveInfo(DriveAttribute$)
 On Local Error Goto Error.Routine15
 ' reset drive info.
 DriveAttribute$ = Nul

 ' skip drive A: and B:
 IF Current.Drive <= 2 THEN
    EXIT SUB
 END IF

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

 ' store long filename.
 W$ = CHR$(Current.Drive + 64) + ":\*.*"

 ' store asciiz filename.
 ASCIIZ3 = W$ + CHR$(0)
 Disk.Ready = False

 ' start findfirst.
 InregsX.AX = &H4E00
 InregsX.CX = &H08
 InregsX.DS = VARSEG(ASCIIZ3)
 InregsX.DX = VARPTR(ASCIIZ3)
 CALL InterruptX(&H21, InregsX, OutregsX)
 DriveVolume$ = Nul

 ' check findnext error.
 IF (OutregsX.Flags AND &H1) = &H0 THEN
    ' store drive volume label.
    DriveVolume$ = DTAfile.ASCIIZfilename
    Var = INSTR(DriveVolume$, CHR$(0))
    IF Var Then
       DriveVolume$ = LEFT$(DriveVolume$, Var - 1)
    END IF
 END IF

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

 ' check disk flag.
 IF Disk.Ready THEN
    EXIT SUB
 END IF

 ' store volume label.
 DriveAttribute$ = DriveVolume$

 ' check quiet switch.
 SELECT CASE QuietSwitch
 CASE -1, 4, 5, 6
    EXIT SUB
 END SELECT

 ' (1) BPB call does not produce critical error for invalid disk.
 '   test for it anyway:
 Disk.Ready = False

 ' (2) BPB call does not fill fields with blanks or nulls for invalid disk:

 ' preload fields.
 BPBfile.Serial = CHR$(0) + CHR$(0) + CHR$(0) + CHR$(0)
 BPBfile.System = SPACE$(8)

 ' start bpb storage function.
 InregsX.AX = &H6900
 InregsX.BX = Current.Drive
 InregsX.DS = VARSEG(BPBfile)
 InregsX.DX = VARPTR(BPBfile)
 CALL InterruptX(&H21, InregsX, OutregsX)

 ' check disk ready error.
 IF Disk.Ready THEN
    EXIT SUB
 END IF

 ' (3) BPB call does not set flag error for errors other than
 '   AX=5 (access denied).

 ' check flag error.
 IF (OutregsX.Flags AND &H1) = &H0 THEN
    ' check prestored field.
    IF RTRIM$(BPBfile.System) <> Nul THEN
       ' store volume serial number.
       DriveAttribute$ = DriveAttribute$ + "("
       ' assume serial exists if fat type exists.
       FOR Serial.Digit = 4 TO 1 STEP -1 ' reversed
          IF Serial.Digit = 2 THEN
             DriveAttribute$ = DriveAttribute$ + "-"
          END IF
          Digit = ASC(MID$(BPBfile.Serial, Serial.Digit, 1))
          Digit$ = RIGHT$(HEX$(Digit + &H100), 2)
          DriveAttribute$ = DriveAttribute$ + Digit$
       NEXT
       DriveAttribute$ = DriveAttribute$ + ")"
       ' store volume fat type.
       DriveFat$ = RTRIM$(BPBfile.System)
       Var = INSTR(DriveFat$, CHR$(0))
       IF Var Then
          DriveFat$ = LEFT$(DriveFat$, Var - 1)
       END IF
       DriveFat$ = RTRIM$(DriveFat$)
       DriveAttribute$ = DriveAttribute$ +  "[" + DriveFat$ + "]"
    END IF
 END IF
 EXIT SUB

' error routine.
Error.Routine15:
 Disk.Ready = True
 RESUME NEXT
END SUB

REM End-of-subprogram. All the source you see here was written overnight.
