REM Program: Hex Editor for DOS v2.2a
REM Author: Erik Jon Oredson AS. Csci
REM Release: 01/01/2002.
REM Status: Public Domain.
REM Email: eoredson@yahoo.com
REM Urls: www.simtel.net www.filegate.net

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

' declare error trap.
ON ERROR GOTO Error.Routine

' increase stack.
STACK 8192

' store quote.
Quote = CHR$(34)

' declare filename variables.
ConfigFile="hexedit.cfg"
DumpFile="hexedit.dmp"

' dimension undo arrays.
REDIM UndoByte(1 TO 1024) AS INTEGER
REDIM UndoPosition(1 TO 1024) AS LONG

' dimension marker array.
REDIM Markers(1 TO 1024) AS LONG

' check for screen row variable.
IF ENVIRON$("HEXSCREEN")<>Nul THEN
   ScreenRow=True
ELSE
   ScreenRow=False
END IF

' store ascii characters.
Hline=205
Vline=186
ULcorner=201
URcorner=187
LLcorner=200
LRcorner=188

' declare alternate characters.
IF ENVIRON$("HEXCHARS")<>Nul THEN
   Hline=45
   Vline=124
   ULcorner=43
   URcorner=43
   LLcorner=43
   LRcorner=43
END IF

' read config file.
GOSUB ReadConfigFile

' check command line.
IF Command$="/?" THEN
   GOTO BootUsage
END IF

' read command line.
GOSUB ReadCommandLine

' check config filename.
IF CommandLine$=Nul THEN
   IF Filename<>Nul THEN
      GOTO StartFile
   END IF
END IF

' store command line.
Filename=CommandLine$

' filename entry loop starts here.
StartFile:

' note: although the labels below are unreferenced by any GOTOs,
'  the error.routine function will jump to them using RESUME NEXT.

' check filename
IF Filename=Nul THEN
   IF Header=False THEN
      Header=True
      COLOR White
      PRINT "Hex Editor "+Version+" "+Release+"."
   END IF
   COLOR Yellow
   PRINT "Enter filename to edit";
   INPUT Filename
   IF Filename=Nul THEN
      GOTO BootUsage
   END IF
END IF
NextFile:

' init some functions
GOSUB StoreDTA
GOSUB CheckWindows
GOSUB SetDTA
NextFile2:

' trim filename.
Filename=RTRIM$(Filename)
Filename=LTRIM$(Filename)
NextFile3:

' check long filename in quotes.
IF LEFT$(Filename,1)=Quote THEN
   IF RIGHT$(Filename,1)=Quote THEN
      Filename=MID$(Filename,2)
      Filename=LEFT$(Filename,LEN(Filename)-1)
   END IF
END IF
NextFile4:

' store filename.
ASCIIZ=Filename+CHR$(0)
NextFile5:

' conanicalize filename.
GOSUB ShortFilename
NextFile6:

' open/create file.
GOSUB OpenFile
NextFile7:

' check open error.
IF ValidFile=False THEN
   IF Header=False THEN
      Header=True
      COLOR White
      PRINT "Hex Editor "+Version+" "+Release+"."
   END IF
   COLOR Green
   PRINT "File not found."
   Filename=Nul
   GOTO StartFile
END IF
NextFile8:

' check length of file.
GOSUB GetFileLength
NextFile9:

' create 1 byte file.
IF FileLength=False THEN
   GOSUB AppendFile
END IF
NextFile10:

' store startup undo variables.
CurrentUndo=0
MaxUndos=1024

' store startup marker variables.
CurrentMarker=0
MarkerCount=0
MaxMarkers=1024
NextFile11:

' store hex editing screen values.
FilePage=1
FilePosition=1
PageRow=1
PageColumn=1
NextFile12:

' initialize file buffer.
SeekPosition=1
GOSUB LseekFile
GOSUB ReadFile
FileByte=Buffer
AsciiValue=ASC(FileByte)
NextFile13:

' main program loop starts here.
TopProgram:

' setup editing screen.
Header=False
GOSUB RedrawScreen
NextFile14:

' keyboard input loop.
DO
   ' get a keypress.
   CharInput$=Nul
   DO
      CharInput$=INKEY$
      IF LEN(CharInput$) THEN
         EXIT DO
      END IF
   LOOP
   ' parse the key.
   SELECT CASE LEN(CharInput$)
   CASE 1 ' single ascii key.
      SELECT CASE ASC(CharInput$)
      CASE 9 ' Tab
         IF FileLength THEN
            GOSUB TabWindow
         END IF
      CASE 13 ' Enter
         IF FileLength THEN
            GOSUB ChangeHexValue
         END IF
      CASE 63 ' ?
         GOSUB DisplayInfo
      CASE 33 ' !
         GOSUB DisplayData
      CASE 126 ' ~
         GOSUB DisplayLengths
      CASE 49 ' 1
         IF FileLength THEN
            GOSUB AddMarker
         END IF
      CASE 50 ' 2
         IF FileLength THEN
            GOSUB AddSpecificMarker
         END IF
      CASE 51 ' 3
         IF FileLength THEN
            GOSUB DeleteMarker
         END IF
      CASE 52 ' 4
         IF FileLength THEN
            GOSUB DeleteSpecificMarker
         END IF
      CASE 53 ' 5
         IF FileLength THEN
            GOSUB JumpPreviousMarker
         END IF
      CASE 54 ' 6
         IF FileLength THEN
            GOSUB JumpCurrentMarker
         END IF
      CASE 55 ' 7
         IF FileLength THEN
            GOSUB JumpNextMarker
         END IF
      CASE 56 ' 8
         IF FileLength THEN
            GOSUB JumpSpecificMarker
         END IF
      CASE 57 ' 9
         IF FileLength THEN
            GOSUB ListAllMarkers
         END IF
      CASE 48 ' 0
         IF FileLength THEN
            GOSUB ListSpecificMarker
         END IF
      CASE 45 ' -
         IF FileLength THEN
            GOSUB ListMarkersOfValue
         END IF
      CASE 43 ' +
         IF FileLength THEN
            GOSUB ListMarkerRange
         END IF
      CASE 61 ' =
         IF FileLength THEN
            GOSUB DeleteMarkerRange
         END IF
      CASE 91 ' [
         IF FileLength THEN
            GOSUB DeleteAllMarkers
         END IF
      CASE 93 ' ]
         IF FileLength THEN
            GOSUB DeleteMarkersOfValue
         END IF
      CASE ELSE ' Unknown key.
         GOSUB HelpLine
      END SELECT
   CASE 2 ' extended ascii key.
      SELECT CASE ASC(RIGHT$(CharInput$,1))
      CASE 0 ' Control-Break
         BEEP
      CASE 15 ' Shift-tab
         IF FileLength THEN
            GOSUB TabWindow
         END IF
      CASE 30 ' Alt-A
         IF FileLength THEN
            GOSUB AppendByte
         END IF
      CASE 46 ' Alt-C
         GOSUB ANSIChart
      CASE 32 ' Alt-D
         IF FileLength THEN
            GOSUB DumpScreen
         END IF
      CASE 18 ' Alt-E
         IF FileLength THEN
            GOSUB DumpHEXFile
         END IF
      CASE 35 ' Alt-H
         GOSUB HEXChart
      CASE 36 ' Alt-J
         IF FileLength THEN
            GOSUB JumpByte
         END IF
      CASE 37 ' Alt-K
         IF FileLength THEN
            GOSUB SearchASCII
         END IF
      CASE 38 ' Alt-L
         IF FileLength THEN
            GOSUB JumpPage
         END IF
      CASE 50 ' Alt-M
         IF FileLength THEN
            GOSUB AppendASCII
         END IF
      CASE 49 ' Alt-N
         GOSUB NewFile
         GOTO StartFile
      CASE 25 ' Alt-P
         IF FileLength THEN
            GOSUB PrintScreen
         END IF
      CASE 16 ' Alt-Q
         GOSUB HelpScreen
      CASE 19 ' Alt-R
         GOSUB RedrawScreen
      CASE 31 ' Alt-S
         IF FileLength THEN
            GOSUB SearchByte
         END IF
      CASE 20 ' Alt-T
         IF FileLength THEN
            GOSUB PrintFile
         END IF
      CASE 22 ' Alt-U
         IF FileLength THEN
            GOSUB UndoByte
         END IF
      CASE 45 ' Alt-X
         EXIT DO ' exit program.
      CASE 21 ' Alt-Y
         IF FileLength THEN
            GOSUB ToggleRight
         END IF
      CASE 44 ' Alt-Z
         IF FileLength THEN
            GOSUB UndoAll
         END IF
      CASE 82 ' Insert
         IF FileLength THEN
            GOSUB ChangeASCIIValues
         END IF
      CASE 72 ' Up
         IF FileLength THEN
            GOSUB CursorUp
         END IF
      CASE 80 ' Down
         IF FileLength THEN
            GOSUB CursorDown
         END IF
      CASE 75 ' Left
         IF FileLength THEN
            GOSUB CursorLeft
         END IF
      CASE 77 ' Right
         IF FileLength THEN
            GOSUB CursorRight
         END IF
      CASE 73 ' PageUp
         IF FileLength THEN
            GOSUB PageUp
         END IF
      CASE 81 ' PageDown
         IF FileLength THEN
            GOSUB PageDown
         END IF
      CASE 79 ' End
         IF FileLength THEN
            GOSUB EndKey
         END IF
      CASE 71 ' Home
         IF FileLength THEN
            GOSUB HomeKey
         END IF
      CASE 115 ' Ctrl-Left
         IF FileLength THEN
            GOSUB CtrlLeftKey
         END IF
      CASE 116 ' Ctrl-Right
         IF FileLength THEN
            GOSUB CtrlRightKey
         END IF
      CASE 117 ' Ctrl-End
         IF FileLength THEN
            GOSUB CtrlEndKey
         END IF
      CASE 119 ' Ctrl-Home
         IF FileLength THEN
            GOSUB CtrlHomeKey
         END IF
      CASE ELSE ' Unknown key.
         GOSUB HelpLine
      END SELECT
   CASE ELSE ' Unknown key.
      BEEP
   END SELECT
LOOP

' end of program.
GOSUB CloseFile
GOSUB ResetAttribute
IF ScreenRow THEN
   LOCATE 23,1,1
ELSE
   LOCATE 25,1,1
END IF
COLOR Plain
GOTO StopProgram

' load new file.
NewFile:
 GOSUB CloseFile
 GOSUB ResetAttribute
 GOSUB ResetDTA
 CLS
 CurrentWindow=False
 CurrentWindow2=False
 ScreenDrawn=False
 LOCATE 24,1,1
 COLOR Plain
 ' reset variables.
 FilePage=1
 FilePosition=1
 PageRow=1
 PageColumn=1
 Buffer=Chr$(0)
 FileByte=Chr$(0)
 AsciiValue=False
 Filename=Nul
 FileLength=False
 FilePosition=False
 ' redimension all arrays.
 REDIM UndoByte(1 TO 1024) AS INTEGER
 REDIM UndoPosition(1 TO 1024) AS LONG
 REDIM Markers(1 TO 1024) AS LONG
 ' reset all array variables.
 CurrentUndo=0
 MaxUndos=1024
 MaxMarkers=1024
 MarkerCount=0
 CurrentMarker=0
 RETURN

' display command line instructions.
BootUsage:
IF Header=False THEN
   COLOR White
   PRINT "Hex Editor "+Version+" "+Release+"."
END IF
COLOR Green
PRINT "Usage:"
COLOR Yellow
PRINT "   Hexedit <filename.ext>"
COLOR Green
PRINT "Where:"
COLOR Yellow
PRINT "   <filename.ext> is the file to edit."
PRINT "   may include drive/pathname.
COLOR Green
PRINT "Example:"
COLOR Yellow
PRINT "   Hexedit \dos\page.com"
COLOR Green
PRINT "Note:
COLOR Yellow
PRINT "   Hexedit supports long filenames in quotes."
COLOR Plain
GOTO StopProgram

' main program editing screen.
DisplayScreen:
CLS
COLOR Magenta
PRINT " ";CHR$(ULcorner);STRING$(75,Hline);CHR$(URcorner)
PRINT " ";CHR$(Vline);STRING$(75,32);CHR$(Vline)
PRINT " ";CHR$(Vline);" ";
COLOR Green
PRINT CHR$(ULcorner);STRING$(46,Hline);CHR$(URcorner);" ";CHR$(ULcorner);STRING$(22,Hline);CHR$(URcorner);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "0";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "1";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "2";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "3";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "4";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "5";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "6";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "7";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "8";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "9";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "A";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "B";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "C";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "D";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "E";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR White
PRINT "F";
COLOR Green
PRINT CHR$(Vline);STRING$(46,32);CHR$(Vline);" ";CHR$(Vline);STRING$(22,32);CHR$(Vline);" ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);" ";
COLOR Green
PRINT CHR$(LLcorner);STRING$(46,Hline);CHR$(LRcorner);" ";CHR$(LLcorner);STRING$(22,Hline);CHR$(LRcorner);" ";
' check to skip info line area.
IF ScreenRow THEN
   GOTO NextRow
END IF
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR Yellow
PRINT " Alt-A Append bytes, Alt-M Append string, Alt-C ANSI Chart, Alt-N New File ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR Yellow
PRINT " Alt-H HEX Chart, Alt-R Redraw, Alt-S Search bytes, Alt-U Undo, Alt-X Exit ";
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(Vline);
COLOR Yellow
PRINT " Alt-J Jump, Alt-K Search string, Alt-D Dump, Alt-P Print, Alt-Z Undo All. ";
' display last row.
NextRow:
COLOR Magenta
PRINT CHR$(Vline)
PRINT " ";CHR$(LLcorner);STRING$(75,Hline);CHR$(LRcorner);
COLOR Plain
RETURN

' display ANSI charts.
ANSIChart:
 CLS
 COLOR White
 PRINT "ASCII Chart for characters 1 to 127:"
 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)+" "
    COLOR Green
    PRINT Var1$;
    COLOR Yellow
    PRINT DisplayChar$;" ";
    ' check full screen line
    IF (Char MOD 10)=False THEN
       PRINT
    END IF
 NEXT
 PRINT
 GOSUB PressKey
 COLOR Plain
 PRINT
 CLS
 COLOR White
 PRINT "ASCII Chart for characters 128 to 255:"
 FOR Char=128 TO 255
    DisplayChar$=CHR$(Char)
    Var$=MID$(STR$(Char),2)
    Var1$=RIGHT$("00"+Var$,3)+" "
    COLOR Green
    PRINT Var1$;
    COLOR Yellow
    PRINT DisplayChar$;" ";
    ' check full screen line
    IF ((Char-7) MOD 10)=False THEN
       PRINT
    END IF
 NEXT
 PRINT
 GOSUB PressKey
 COLOR Plain
 PRINT
 GOSUB RedrawScreen
 RETURN

' display HEX charts.
HEXChart:
 CLS
 COLOR White
 PRINT "HEX Chart for characters 1 to 127:"
 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)+" "
    COLOR Green
    PRINT Var1$;
    COLOR Yellow
    PRINT DisplayChar$;" ";
    ' check full screen line
    IF (Char MOD 10)=False THEN
       PRINT
    END IF
 NEXT
 PRINT
 GOSUB PressKey
 COLOR Plain
 PRINT
 CLS
 COLOR White
 PRINT "HEX Chart for characters 128 to 255:"
 FOR Char=128 TO 255
    DisplayChar$=CHR$(Char)
    Var$=HEX$(Char)
    Var1$=RIGHT$("0"+Var$,2)+" "
    COLOR Green
    PRINT Var1$;
    COLOR Yellow
    PRINT DisplayChar$;" ";
    ' check full screen line
    IF ((Char-7) MOD 10)=False THEN
       PRINT
    END IF
 NEXT
 PRINT
 GOSUB PressKey
 COLOR Plain
 PRINT
 GOSUB RedrawScreen
 RETURN

' function for unknown key.
HelpLine:
 GOSUB ClearStatus
 PRINT "Editing file: ";Filename;
 COLOR White
 PRINT " Type Alt-Q for Help.";
 GOSUB LocateCursor
 RETURN

' display help screens.
HelpScreen:
 GOSUB DisplayHelpScreen1
 GOSUB DisplayHelpScreen2
 GOSUB DisplayHelpScreen3
 GOSUB DisplayHelpScreen4
 COLOR Plain
 GOSUB RedrawScreen
 RETURN

' help screen header.
HelpHeader:
 CLS
 COLOR White
 PRINT "Help screen: Hex Editor "+Version+" "+Release+" functions:"
 RETURN

' help screen key prompt.
PressKey:
 COLOR White
 PRINT "Press a key:";
 WHILE INKEY$=Nul:WEND
 RETURN

' help screen 1.
DisplayHelpScreen1:
 GOSUB HelpHeader
 COLOR Red
 PRINT "Function keys:                          Editing keys:"
 COLOR Yellow
 PRINT "Alt-A  Append multiple bytes to file.   Tab    -- Switch windows."
 PRINT "Alt-C  ANSI Chart.                      Enter  -- Change byte value."
 PRINT "Alt-D  HEX Screen Dump.                 Insert -- Change string value."
 PRINT "Alt-E  HEX File Dump.                   Cursor Up/Down/Left/Right."
 PRINT "Alt-H  HEX Chart.                       Page Up/Page Down, Home/End."
 PRINT "Alt-J  Jump to byte position.           Ctrl-Home/Ctrl-End."
 PRINT "Alt-K  Search for ASCII string.         Ctrl-Right/Ctrl-Left."
 PRINT "Alt-L  Jump to page position."
 PRINT "Alt-M  Append ASCII string to file.";
 COLOR Red
 PRINT "     Other keys:"
 COLOR Yellow
 PRINT "Alt-N  Load new file.                   (hex value numeral preceded)."
 PRINT "Alt-P  HEX Screen Print.                (right window unprintable chars"
 PRINT "Alt-Q  Help screen.                      are represented with a dot)."
 PRINT "Alt-R  Redraw screen.                   (ascii values precede with H"
 PRINT "Alt-S  Search for multiple bytes.        treated as hexcidecimal)."
 PRINT "Alt-T  HEX File Print.                  (escape> key exits search)."
 PRINT "Alt-U  Undo last byte change.
 PRINT "Alt-X  Exit program.
 PRINT "Alt-Y  Toggle right window.
 PRINT "Alt-Z  Undo All byte changes.
 GOSUB PressKey
 RETURN

' help screen 2.
DisplayHelpScreen2:
 GOSUB HelpHeader
 COLOR Red
 PRINT "Marker keys:"
 COLOR Yellow
 PRINT "1   add marker"
 PRINT "2   add specific marker value"
 PRINT "3   delete marker"
 PRINT "4   delete specific marker"
 PRINT "5   jump previous marker"
 PRINT "6   jump current marker"
 PRINT "7   jump next marker"
 PRINT "8   jump specific marker"
 PRINT "9   list all markers"
 PRINT "0   list specific marker"
 PRINT "-   list markers of value"
 PRINT "+   list range of markers"
 PRINT "=   delete a range"
 PRINT "[   delete all markers"
 PRINT "]   delete markers of value"
 GOSUB PressKey
 RETURN

' help screen 3.
DisplayHelpScreen3:
 GOSUB HelpHeader
 COLOR Red
 PRINT "Information keys:"
 COLOR Yellow
 PRINT "? key displays file length, and undos remaining."
 PRINT "! key displays current page, row, and column."
 PRINT "~ key displays last page and markers used."
 GOSUB PressKey
 RETURN

' help screen 4.
DisplayHelpScreen4:
 CLS
 COLOR White
 PRINT "Hexedit information: ";
 IF WindowsDetected THEN
    PRINT "(Windows loaded);"
 ELSE
    PRINT "(DOS loaded);"
 END IF
 COLOR Yellow
 PRINT "Program: "+Program+" "+Version+" "+Release+"."
 PRINT "Author: "+Author
 PRINT "Published: "+Publish
 PRINT "Status: "+Status
 PRINT "Email: "+Email
 PRINT "Urls: "+Urls
 GOSUB PressKey
 RETURN

' function for ? key.
DisplayInfo:
 GOSUB ClearStatus
 PRINT "Editing file: ";Filename;" ";
 IF FileLength=False THEN
    GOSUB LockedFile
    RETURN
 END IF
 Attr$=Nul
 IF (FileAttribute AND ReadOnlyBit)=ReadOnlyBit THEN
    Attr$=Attr$+"o"
 END IF
 IF (FileAttribute AND HiddenBit)=HiddenBit THEN
    Attr$=Attr$+"h"
 END IF
 IF (FileAttribute AND SystemBit)=SystemBit THEN
    Attr$=Attr$+"s"
 END IF
 IF (FileAttribute AND ArchiveBit)=ArchiveBit THEN
    Attr$=Attr$+"a"
 END IF
 IF LEN(Attr$) THEN
    PRINT "(";Attr$;") ";
 END IF
 IF CurrentWindow2=False THEN
    PRINT "(Length:";STR$(FileLength);") ";
 ELSE
    PRINT "(Length: ";RIGHT$("00000000"+HEX$(FileLength),8);"H) ";
 END IF
 PRINT "(Undos:";STR$(CurrentUndo);") ";
 GOSUB LocateCursor
 RETURN

' function for ! key.
DisplayData:
 GOSUB ClearStatus
 PRINT "Editing file: ";Filename;" ";
 IF FileLength=False THEN
    GOSUB LockedFile
    RETURN
 END IF
 TempPosition3=FilePosition
 GOSUB FormatPosition1
 GOSUB LocateCursor
 RETURN

' function for ~ key.
DisplayLengths:
 GOSUB ClearStatus
 PRINT "Editing file: ";Filename;" ";
 IF FileLength=False THEN
    GOSUB LockedFile
    RETURN
 END IF
 FilePage2&=INT((FileLength-1)/320)+1
 IF CurrentWindow2=False THEN
    PRINT "(Last page:";STR$(FilePage2&);") ";
 ELSE
    PRINT "(Last page: ";RIGHT$("00000000"+HEX$(FilePage2&),8);"H) ";
 END IF
 ' count markers
 TempPosition3=0
 FOR TempPosition=1 TO MarkerCount
    IF Markers(TempPosition)>0 THEN
       TempPosition3=TempPosition3+1&
    END IF
 NEXT
 PRINT "(Markers: ";MID$(STR$(TempPosition3),2);")";
 GOSUB LocateCursor
 RETURN

' display name of file being edited.
DisplayFilename:
 GOSUB ClearStatus
 PRINT "Editing file: ";Filename;" ";
 IF FileLength=False THEN
    GOSUB LockedFile
    RETURN
 END IF
 GOSUB DisplayPosition
 RETURN

' display info on file being edited.
DisplayPosition:
 COLOR Yellow
 StringLength=LEN("Editing file: "+Filename+" ")+4
 LOCATE 2,StringLength,0
 PRINT SPACE$(76-StringLength);
 LOCATE 2,StringLength,0
 IF FileLength=False THEN
    GOSUB LockedFile
    RETURN
 END IF
 IF CurrentWindow2=False THEN
    PRINT "(Position:";STR$(FilePosition);") ";
 ELSE
    PRINT "(Position: ";RIGHT$("00000000"+HEX$(FilePosition),8);"H) ";
 END IF
 PRINT "(Ascii:";STR$(AsciiValue);") ";
 PRINT "(Hex: ";RIGHT$("00"+HEX$(AsciiValue),2);"H)";
 GOSUB LocateCursor
 RETURN

' display message for locked file.
LockedFile:
 COLOR White
 PRINT "<locked file>";
 LOCATE 1,1,0
 RETURN

' redraw editing screen
RedrawScreen:
 ScreenDrawn=True
 GOSUB DisplayScreen
 GOSUB DisplayFilename
 GOSUB DisplayHexPage
 GOSUB DisplayPageByte
 RETURN

' display screen of current page of hex/ascii values of file being edited.
DisplayHexPage:
 IF FileLength=False THEN
    LOCATE 1,1,0
    RETURN
 END IF
 COLOR White
 Row=False
 Column=False
 ColumnSpace=False
 FOR NextByte=(FilePage-1)*320+1 TO (FilePage-1)*320+320
    LOCATE Row+4,Column+6,0
    IF NextByte<=FileLength THEN
       SeekPosition=NextByte
       GOSUB LseekFile
       GOSUB ReadFile
       FileByte=Buffer
       PRINT RIGHT$("00"+HEX$(ASC(FileByte)),2);
    ELSE
       PRINT "  ";
    END IF
    ColumnSpace=ColumnSpace+1
    IF ColumnSpace=4 THEN
       PRINT " ";
       Column=Column+1
       ColumnSpace=False
    END IF
    Column=Column+2
    IF Column>44 THEN
       Row=Row+1
       Column=False
    END IF
 NEXT
 GOSUB RedrawRightWindow
 RETURN

' redraw right window.
RedrawRightWindow:
 IF CurrentWindow2=False THEN
    GOSUB RedrawWindow1
 ELSE
    GOSUB RedrawWindow2
 END IF
 RETURN

' redraw right window of ascii values.
RedrawWindow1:
 COLOR White
 Row=False
 Column=False
 FOR NextLine=0 TO 15
    LOCATE NextLine+4,54,0
    PRINT " ";
 NEXT
 FOR NextByte=(FilePage-1)*320+1 TO (FilePage-1)*320+320
    LOCATE Row+4,Column+55,0
    IF NextByte<=FileLength THEN
       SeekPosition=NextByte
       GOSUB LseekFile
       GOSUB ReadFile
       FileByte=Buffer
       ByteValue=ASC(FileByte)
       ' skip unprintable characters
       SELECT CASE ByteValue
       CASE 0, 7, 9 TO 13, 28 TO 32
          PRINT ".";
       CASE ELSE
          PRINT FileByte;
       END SELECT
    ELSE
       PRINT " ";
    END IF
    Column=Column+1
    IF Column>19 THEN
       Row=Row+1
       Column=False
    END IF
 NEXT
 RETURN

' redraw right window of hex ranges.
RedrawWindow2:
 Row=False
 FOR NextLine=(FilePage-1)*320+1 TO (FilePage-1)*320+320 STEP 20
    LOCATE Row+4,54,0
    Row=Row+1
    IF NextLine<=FileLength THEN
       IF NextLine+19<=FileLength THEN
          COLOR White
          PRINT "x";RIGHT$("00000000"+HEX$(NextLine),8);
          COLOR Yellow
          PRINT " - ";
          COLOR White
          PRINT "x";RIGHT$("00000000"+HEX$(NextLine+19),8);
       ELSE
          COLOR White
          PRINT "x";RIGHT$("00000000"+HEX$(NextLine),8);
          COLOR Yellow
          PRINT " - ";
          COLOR White
          PRINT "x";RIGHT$("00000000"+HEX$(FileLength),8);
       END IF
    ELSE
       PRINT SPACE$(22);
    END IF
 NEXT
 RETURN

' dump screen of current page of hex/ascii values to file.
DumpScreen:
 Column=False
 ColumnSpace=False
 HexLine$=Nul
 HexLine2$=Nul
 CLOSE #1
 ErrorTrap=False
 OPEN DumpFile FOR APPEND AS #1
 IF ErrorTrap THEN
    GOSUB RedrawScreen
    RETURN
 END IF
 FirstByte=(FilePage-1)*320+1
 LastByte=(FilePage-1)*320+320
 DumpLine$="File: "+Filename+", position"+STR$(FirstByte)+" to"
 IF LastByte<=FileLength THEN
    DumpLine$=DumpLine$+STR$(LastByte)
 ELSE
    DumpLine$=DumpLine$+STR$(FileLength)
 END IF
 DumpLine$=DumpLine$+"."
 PRINT #1,DumpLine$
 FOR NextByte=FirstByte TO LastByte
    IF NextByte<=FileLength THEN
       SeekPosition=NextByte
       GOSUB LseekFile
       GOSUB 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
          PRINT #1,HexFile$
       END IF
       HexLine$=Nul
       HexLine2$=Nul
       Column=False
    END IF
 NEXT
 GOSUB DisplayPageByte

 ' conanicalize filename.
 Filename2$=Conanicalize$(DumpFile)

 ' display filename.
 StatusMessage="Screen dumped to: '"+Filename2$+"'."
 GOSUB DisplayStatus1
 RETURN

' dump file of current hex/ascii values to file.
DumpHEXFile:
 Column=False
 ColumnSpace=False
 HexLine$=Nul
 HexLine2$=Nul
 CLOSE #1
 ErrorTrap=False
 OPEN DumpFile FOR APPEND AS #1
 IF ErrorTrap THEN
    GOSUB RedrawScreen
    RETURN
 END IF

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

 ' write to file
 FileDumped=True
 GOSUB DumpInfo
 DumpLine$="File: "+Filename+", position"+STR$(FirstByte)+" to"
 IF LastByte<=FileLength THEN
    DumpLine$=DumpLine$+STR$(LastByte)
 ELSE
    DumpLine$=DumpLine$+STR$(FileLength)
 END IF
 DumpLine$=DumpLine$+"."
 PRINT #1,DumpLine$
 FOR NextByte=FirstByte TO LastByte
    IF NextByte<=FileLength THEN
       SeekPosition=NextByte
       GOSUB LseekFile
       GOSUB 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
          PRINT #1,HexFile$
       END IF
       HexLine$=Nul
       HexLine2$=Nul
       Column=False
    END IF
 NEXT
 GOSUB DisplayPageByte

 ' conanicalize filename.
 Filename2$=Conanicalize$(DumpFile)

 ' display filename.
 IF FileDumped THEN
    StatusMessage="File dumped to: '"+Filename2$+"'."
 ELSE
    StatusMessage="Partial file dumped to: '"+Filename2$+"'."
 END IF
 GOSUB DisplayStatus1
 RETURN

' print screen of current page of hex/ascii values to printer.
PrintScreen:
 GOSUB ClearStatus
 PRINT "Enter printer port(1-3)";
 INPUT PortNumber
 PortNumber=INT(PortNumber)
 IF PortNumber>=1 AND PortNumber<=3 THEN
    CLOSE #1
    Filename2$="LPT"+MID$(STR$(PortNumber),2)+":"
    ErrorTrap=False
    OPEN Filename2$ FOR OUTPUT AS #1
    IF ErrorTrap THEN
       GOSUB RedrawScreen
       RETURN
    END IF
 ELSE
    StatusMessage="Invalid printer port number."
    GOSUB DisplayStatus1
    RETURN
 END IF
 Column=False
 ColumnSpace=False
 HexLine$=Nul
 HexLine2$=Nul
 FirstByte=(FilePage-1)*320+1
 LastByte=(FilePage-1)*320+320
 DumpLine$="File: "+Filename+", position"+STR$(FirstByte)+" to"
 IF LastByte<=FileLength THEN
    DumpLine$=DumpLine$+STR$(LastByte)
 ELSE
    DumpLine$=DumpLine$+STR$(FileLength)
 END IF
 DumpLine$=DumpLine$+"."
 PRINT #1,DumpLine$
 FOR NextByte=FirstByte TO LastByte
    IF NextByte<=FileLength THEN
       SeekPosition=NextByte
       GOSUB LseekFile
       GOSUB 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
          PRINT #1,HexFile$
       END IF
       HexLine$=Nul
       HexLine2$=Nul
       Column=False
    END IF
 NEXT
 PRINT #1,CHR$(12);
 GOSUB DisplayPageByte
 StatusMessage="Screen dumped to printer port:"+STR$(PortNumber)+"."
 GOSUB DisplayStatus1
 RETURN

' print file of current hex/ascii values to printer.
PrintFile:
 GOSUB ClearStatus
 PRINT "Enter printer port(1-3)";
 INPUT PortNumber
 PortNumber=INT(PortNumber)
 IF PortNumber>=1 AND PortNumber<=3 THEN
    CLOSE #1
    Filename2$="LPT"+MID$(STR$(PortNumber),2)+":"
    ErrorTrap=False
    OPEN Filename2$ FOR OUTPUT AS #1
    IF ErrorTrap THEN
       GOSUB RedrawScreen
       RETURN
    END IF
 ELSE
    StatusMessage="Invalid printer port number."
    GOSUB DisplayStatus1
    RETURN
 END IF
 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
 GOSUB DumpInfo
 DumpLine$="File: "+Filename+", position"+STR$(FirstByte)+" to"
 IF LastByte<=FileLength THEN
    DumpLine$=DumpLine$+STR$(LastByte)
 ELSE
    DumpLine$=DumpLine$+STR$(FileLength)
 END IF
 DumpLine$=DumpLine$+"."
 PRINT #1,DumpLine$
 FOR NextByte=FirstByte TO LastByte
    IF NextByte<=FileLength THEN
       SeekPosition=NextByte
       GOSUB LseekFile
       GOSUB 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
       IF INKEY$=CHR$(27) THEN
          FileDumped=False
          EXIT FOR
       END IF
       HexFile$=HexLine$+" "+HexLine2$
       HexFile$=RTRIM$(HexFile$)
       IF LEN(HexFile$) THEN
          PRINT #1,HexFile$
       END IF
       HexLine$=Nul
       HexLine2$=Nul
       Column=False
    END IF
 NEXT
 PRINT #1,CHR$(12);
 GOSUB DisplayPageByte
 IF FileDumped THEN
    StatusMessage="File dumped to printer port:"+STR$(PortNumber)+"."
 ELSE
    StatusMessage="Partial file dumped to printer port:"+STR$(PortNumber)+"."
 END IF
 GOSUB DisplayStatus1
 RETURN

' clear hilight of current byte on screen.
ClearPageByte:
 COLOR White
 GOSUB DisplayByte
 RETURN

' reset hilight of current byte being edited.
DisplayPageByte:
 COLOR Yellow
 GOSUB DisplayByte
 ' store the current byte value being edited.
 AsciiValue=ASC(FileByte)
 GOSUB DisplayPosition
 RETURN

' display a byte on the screen.
DisplayByte:
 IF FileLength=False THEN
    LOCATE 1,1,0
    RETURN
 END IF
 SeekPosition=FilePosition
 GOSUB LseekFile
 GOSUB ReadFile
 FileByte=Buffer
 ByteValue=ASC(FileByte)
 GOSUB CalculateColumn
 ' display hex byte.
 LOCATE PageRow+3,Column+5,0
 PRINT RIGHT$("00"+HEX$(ByteValue),2);
 ' check right window toggled.
 IF CurrentWindow2=False THEN
    ' display ascii byte.
    LOCATE PageRow+3,PageColumn+54,0
    ' skip unprintable characters.
    SELECT CASE ByteValue
    CASE 0, 7, 9 TO 13, 28 TO 32
       PRINT ".";
    CASE ELSE
       PRINT FileByte;
    END SELECT
 END IF
 RETURN

' calculate the spaces between hex value groups.
CalculateColumn:
 SELECT CASE PageColumn
 CASE 1 TO 4
    Column=(PageColumn-1)*2+1
 CASE 5 TO 8
    Column=(PageColumn-1)*2+2
 CASE 9 TO 12
    Column=(PageColumn-1)*2+3
 CASE 13 TO 16
    Column=(PageColumn-1)*2+4
 CASE 17 TO 20
    Column=(PageColumn-1)*2+5
 END SELECT
 RETURN

' determine which window on screen cursor is.
LocateCursor:
 IF FileLength=False THEN
    LOCATE 1,1,0
    RETURN
 END IF
 IF CurrentWindow=False THEN
    LOCATE PageRow+3,Column+5,1
 ELSE
    LOCATE PageRow+3,PageColumn+54,1
 END IF
 RETURN

' clear top status area
ClearStatus:
 COLOR Yellow
 LOCATE 2,4
 PRINT SPACE$(74);
 LOCATE 2,4
 RETURN

' display status line message and prompt type 1.
DisplayStatus1:
 StatusMessage=StatusMessage+" Press <esc>:"
 GOTO DisplayStatusLine

' display status line message and prompt type 2.
DisplayStatus2:
 StatusMessage=StatusMessage+" Press <esc> to continue:"

' display the status line message and prompt for key.
DisplayStatusLine:
 GOSUB ClearStatus
 PRINT StatusMessage;
 GOSUB LocateCursor
 WHILE INKEY$<>CHR$(27):WEND
 GOSUB DisplayFilename
 RETURN

' add multiple bytes of an ASCII string to file and locate there.
AppendASCII:
 GOSUB ClearStatus
 PRINT "Enter ASCII string";
 INPUT ByteString$
 IF LEN(ByteString$)=False THEN
    StatusMessage="Invalid append string."
    GOSUB DisplayStatus2
    RETURN
 END IF
 NumBytes=LEN(ByteString$)
 GOSUB AsciiToHex2
 GOTO StartAppend
' add multiple bytes to file and locate there.
' left window adds space-separated hex byte pairs,
' right window adds space-separated 3-byte ascii pairs.
AppendByte:
 GOSUB ClearStatus
 IF CurrentWindow=False THEN
    PRINT "Enter hex byte(s)";
    INPUT ByteString$
    IF LEFT$(ByteString$,1)="+" THEN
       ByteString$=MID$(ByteString$,2)
       GOSUB CheckAsciiBytes
    ELSE
       AllowWildcard=False
       GOSUB CheckHexBytes
    END IF
 ELSE
    PRINT "Enter ascii byte(s)";
    INPUT ByteString$
    IF UCASE$(LEFT$(ByteString$,1))="H" THEN
       ByteString$=MID$(ByteString$,2)
       AllowWildcard=False
       GOSUB CheckHexBytes
    ELSE
       GOSUB CheckAsciiBytes
    END IF
 END IF
 IF ValidByteString=False THEN
    StatusMessage="Invalid append string."
    GOSUB DisplayStatus2
    RETURN
 END IF
 ' append the byte string
StartAppend:
 LastPage=FilePage
 FOR Byte1=1 TO NumBytes
    GOSUB ClearPageByte
    Byte$=MID$(ByteString$,(Byte1-1)*2+1,2)
    Byte2=VAL("&H"+Byte$)
    FileByte=CHR$(Byte2)
    FileLength=FileLength+1&
    SeekPosition=FileLength
    GOSUB LseekFile
    GOSUB WriteFile
    FilePosition=FileLength
    GOSUB CalculatePosition1
    IF LastPage<>FilePage THEN
       LastPage=FilePage
       GOSUB DisplayHexPage
    END IF
    GOSUB DisplayPageByte
 NEXT
 GOSUB DisplayFilename
 RETURN

' search multiple bytes of an ASCII string in file and locate there.
SearchASCII:
 GOSUB ClearStatus
 PRINT "Enter ASCII string";
 INPUT ByteString$
 IF LEN(ByteString$)=False THEN
    StatusMessage="Invalid search string."
    GOSUB DisplayStatus2
    RETURN
 END IF
 NumBytes=LEN(ByteString$)
 GOSUB AsciiToHex2
 GOTO StartSearch
' search multiple bytes in file and locate there.
' left window adds space-separated hex byte pairs,
' right window adds space-separated 3-byte ascii pairs.
SearchByte:
 GOSUB ClearStatus
 IF CurrentWindow=False THEN
    PRINT "Enter hex byte(s)";
    INPUT ByteString$
    IF LEFT$(ByteString$,1)="+" THEN
       ByteString$=MID$(ByteString$,2)
       GOSUB CheckAsciiBytes
    ELSE
       AllowWildcard=True
       GOSUB CheckHexBytes
    END IF
 ELSE
    PRINT "Enter ascii byte(s)";
    INPUT ByteString$
    IF UCASE$(LEFT$(ByteString$,1))="H" THEN
       ByteString$=MID$(ByteString$,2)
       AllowWildcard=True
       GOSUB CheckHexBytes
    ELSE
       GOSUB CheckAsciiBytes
    END IF
 END IF
 IF ValidByteString=False THEN
    StatusMessage="Invalid search string."
    GOSUB DisplayStatus2
    RETURN
 END IF
StartSearch:
 ' search for the byte string
 FoundString=False
 GOSUB ClearPageByte
 LastPage=FilePage
 GOSUB SearchInfo
 FOR FileBytePosition=FilePosition TO FileLength
    ' check to break search
    IF INKEY$=CHR$(27) THEN
       EXIT FOR
    END IF
    ' store next byte string
    TotalByte$=Nul
    FOR TotalBytes=1 TO NumBytes
       NextByte=FileBytePosition+TotalBytes
       IF NextByte>FileLength THEN
          TotalByte$=Nul
          EXIT FOR
       END IF
       SeekPosition=NextByte
       GOSUB LseekFile
       GOSUB ReadFile
       FileByte=Buffer
       Byte$=HEX$(ASC(FileByte))
       Byte$=RIGHT$("00"+Byte$,2)
       TotalByte$=TotalByte$+Byte$
    NEXT
    ' compare byte strings
    IF LEN(TotalByte$) THEN
       FoundString=True
       FOR TotalBytes=1 TO NumBytes*2
          Byte1$=MID$(ByteString$,TotalBytes,1)
          Byte2$=MID$(TotalByte$,TotalBytes,1)
          IF Byte1$<>"?" THEN
             IF Byte1$<>Byte2$ THEN
                FoundString=False
                EXIT FOR
             END IF
          END IF
       NEXT
    END IF
    ' check byte comparison
    IF FoundString THEN
       FilePosition=FileBytePosition+1
       GOSUB CalculatePosition1
       IF LastPage<>FilePage THEN
          GOSUB DisplayHexPage
       END IF
       EXIT FOR
    END IF
 NEXT
 GOSUB DisplayPageByte
 IF FoundString=False THEN
    StatusMessage="String not found."
    GOSUB DisplayStatus2
    RETURN
 END IF
 GOSUB DisplayFilename
 RETURN

' checks hex byte string.
'   input: AllowWildcard true to allow ? character.
'     ByteString$ is space-separated hex byte pair string.
'   returns: ValidByteString equals true if string is valid,
'     NumBytes is number of hex byte pairs,
'     ByteString$ is concatenated hex byte string.
CheckHexBytes:
 ByteString$=LTRIM$(ByteString$)
 ByteString$=RTRIM$(ByteString$)
 IF LEN(ByteString$)=False THEN
    ValidByteString=False
    RETURN
 END IF
 NumBytes=1
 ValidByteString=True
 FOR StringPosition=1 TO LEN(ByteString$)
    Byte$=MID$(ByteString$,StringPosition,1)
    IF (StringPosition MOD 3)=False THEN
       IF Byte$<>" " THEN
          ValidByteString=False
          RETURN
       END IF
       NumBytes=NumBytes+1
    ELSE
       SELECT CASE Byte$
       CASE "0" TO "9", "A" TO "F", "a" TO "f", "?"
          IF Byte$="?" THEN
             IF AllowWildcard=False THEN
                ValidByteString=False
                RETURN
             END IF
          END IF
          MID$(ByteString$,StringPosition,1)=UCASE$(Byte$)
       CASE ELSE
          ValidByteString=False
          RETURN
       END SELECT
    END IF
 NEXT
 ByteString$=TrimSpaces$(ByteString$)
 RETURN

' checks ascii byte string.
'   input: ByteString$ is space-separated 3-byte ascii pair string.
'   returns: ValidByteString equals true if string is valid,
'     NumBytes is number of ascii byte pairs,
'     ByteString$ is concatenated hex byte string.
CheckAsciiBytes:
 AsciiByte$=Nul
 ByteString$=LTRIM$(ByteString$)
 ByteString$=RTRIM$(ByteString$)
 IF LEN(ByteString$)=False THEN
    ValidByteString=False
    RETURN
 END IF
 NumBytes=1
 ValidByteString=True
 FOR StringPosition=1 TO LEN(ByteString$)
    Byte$=MID$(ByteString$,StringPosition,1)
    IF (StringPosition MOD 4)=False THEN
       IF Byte$<>" " THEN
          ValidByteString=False
          RETURN
       END IF
       NumBytes=NumBytes+1
    ELSE
       SELECT CASE Byte$
       CASE "0" TO "9"
          AsciiByte$=AsciiByte$+Byte$
          IF LEN(AsciiByte$)=3 THEN
             ByteValue=VAL(AsciiByte$)
             IF ByteValue>=False AND ByteValue<=255 THEN
                AsciiByte$=Nul
             ELSE
                ValidByteString=False
                RETURN
             END IF
          END IF
       CASE ELSE
          ValidByteString=False
          RETURN
       END SELECT
    END IF
 NEXT
 ByteString$=TrimSpaces$(ByteString$)
 GOSUB AsciiToHex1
 RETURN

' converts a 3-digit packed ascii string to a hex string.
AsciiToHex1:
 Byte$=Nul
 NewString$=Nul
 FOR StringPosition=1 TO LEN(ByteString$)
    Byte$=Byte$+MID$(ByteString$,StringPosition,1)
    IF LEN(Byte$)=3 THEN
       NewString$=NewString$+RIGHT$("00"+HEX$(VAL(Byte$)),2)
       Byte$=Nul
    END IF
 NEXT
 ByteString$=NewString$
 RETURN

' converts a 1-digit packed ascii string to a hex string.
AsciiToHex2:
 Byte$=Nul
 NewString$=Nul
 FOR StringPosition=1 TO LEN(ByteString$)
    Byte$=MID$(ByteString$,StringPosition,1)
    NewString$=NewString$+RIGHT$("00"+HEX$(ASC(Byte$)),2)
 NEXT
 ByteString$=NewString$
 RETURN

' display message about searching.
SearchInfo:
 GOSUB ClearStatus
 DisplayLength=LEN(ByteString$)
 IF DisplayLength>32 THEN
    PRINT "Searching for "+LEFT$(ByteString$,32)+"...";
 ELSE
    PRINT "Searching for "+ByteString$+":";
 END IF
 PRINT " (Press <esc> to quit)";
 RETURN

' display message about dumping.
DumpInfo:
 GOSUB ClearStatus
 PRINT "Writing file: (Press <esc> to quit):";
 RETURN

' jump to page position in file.
JumpPage:
 GOSUB ClearStatus
 PRINT "Enter page position";
 INPUT ByteString$
 IF UCASE$(LEFT$(ByteString$,1))="H" THEN
    ByteString$="&"+ByteString$
 END IF
 NewPage=INT(VAL(ByteString$))
 ' check the new page is there to jump to.
 TempPosition3=(NewPage-1)*320+1
 IF TempPosition3>=1 AND TempPosition3<=FileLength THEN
    GOSUB ClearPageByte
    LastPage=FilePage
    ' preserve current row, column.
    FilePosition=TempPosition3
    TempPosition2=FilePosition+(PageRow-1)*20+PageColumn-1
    IF TempPosition2<=FileLength THEN
       FilePosition=TempPosition2
    ELSE
       FilePosition=FileLength
    END IF
    GOSUB CalculatePosition1
    IF LastPage<>FilePage THEN
       GOSUB DisplayHexPage
    END IF
    GOSUB DisplayPageByte
    GOSUB DisplayFilename
    RETURN
 END IF
 StatusMessage="Invalid page."
 GOSUB DisplayStatus2
 RETURN

' jump to a byte position in file.
JumpByte:
 GOSUB ClearStatus
 PRINT "Enter file position";
 INPUT ByteString$
 IF UCASE$(LEFT$(ByteString$,1))="H" THEN
    ByteString$="&"+ByteString$
 END IF
 NewByte=INT(VAL(ByteString$))
 IF NewByte>=1 AND NewByte<=FileLength THEN
    IF NewByte<>FilePosition THEN
       GOSUB ClearPageByte
       LastPage=FilePage
       FilePosition=NewByte
       GOSUB CalculatePosition1
       IF LastPage<>FilePage THEN
          GOSUB DisplayHexPage
       END IF
       GOSUB DisplayPageByte
    END IF
    GOSUB DisplayFilename
    RETURN
 END IF
 StatusMessage="Invalid byte."
 GOSUB DisplayStatus2
 RETURN

' undo a byte from stored arrays of previous position/byte value.
UndoByte:
 IF CurrentUndo>0 THEN
    GOSUB ClearPageByte
    LastPage=FilePage
    FileByte=CHR$(UndoByte(CurrentUndo))
    FilePosition=UndoPosition(CurrentUndo)
    CurrentUndo=CurrentUndo-1
    SeekPosition=FilePosition
    GOSUB LseekFile
    GOSUB WriteFile
    GOSUB CalculatePosition1
    IF LastPage<>FilePage THEN
       GOSUB DisplayHexPage
    END IF
    GOSUB DisplayPageByte
 END IF
 RETURN

' undo all bytes from stored arrays of previous position/byte value.
UndoAll:
 IF CurrentUndo>0 THEN
    TotalUndos=CurrentUndo
    FOR NextUndo=TotalUndos TO 1 STEP -1
       GOSUB ClearPageByte
       LastPage=FilePage
       FileByte=CHR$(UndoByte(NextUndo))
       FilePosition=UndoPosition(NextUndo)
       CurrentUndo=CurrentUndo-1
       SeekPosition=FilePosition
       GOSUB LseekFile
       GOSUB WriteFile
       GOSUB CalculatePosition1
       IF LastPage<>FilePage THEN
          LastPage=FilePage
          GOSUB DisplayHexPage
       END IF
       GOSUB DisplayPageByte
    NEXT
 END IF
 RETURN

' move cursor up.
CursorUp:
 IF PageRow-1>=1 THEN
    GOSUB ClearPageByte
    PageRow=PageRow-1
    FilePosition=FilePosition-20
    GOSUB DisplayPageByte
 END IF
 RETURN

' move cursor down.
CursorDown:
 IF PageRow+1<=16 THEN
    IF FilePosition+20<=FileLength THEN
       GOSUB ClearPageByte
       PageRow=PageRow+1
       FilePosition=FilePosition+20
       GOSUB DisplayPageByte
    END IF
 END IF
 RETURN

' move cursor left.
CursorLeft:
 IF PageColumn-1>=1 THEN
    GOSUB ClearPageByte
    PageColumn=PageColumn-1
    FilePosition=FilePosition-1
    GOSUB DisplayPageByte
 END IF
 RETURN

' move cursor right.
CursorRight:
 IF PageColumn+1<=20 THEN
    IF FilePosition+1<=FileLength THEN
       GOSUB ClearPageByte
       PageColumn=PageColumn+1
       FilePosition=FilePosition+1
       GOSUB DisplayPageByte
    END IF
 END IF
 RETURN

' end key
EndKey:
 ' set to column 20
 IF PageColumn<20 THEN
    ' check column 20 is positioned before end of file
    IF FilePosition-PageColumn+20<=FileLength THEN
       GOSUB ClearPageByte
       FilePosition=FilePosition-PageColumn+20
       PageColumn=20
       GOSUB DisplayPageByte
    ELSE
       ' position end of file
       GOSUB ClearPageByte
       FilePosition=FileLength
       GOSUB CalculatePosition1
       GOSUB DisplayPageByte
    END IF
 END IF
 RETURN

' home key
HomeKey:
 IF PageColumn>1 THEN
    GOSUB ClearPageByte
    FilePosition=FilePosition-PageColumn+1
    PageColumn=1
    GOSUB DisplayPageByte
 END IF
 RETURN

' control-left key
CtrlLeftKey:
 NewColumn=0
 SELECT CASE PageColumn
 CASE 2,3,4
    NewColumn=1
 CASE 5
    NewColumn=4
 CASE 6,7,8
    NewColumn=5
 CASE 9
    NewColumn=8
 CASE 10,11,12
    NewColumn=9
 CASE 13
    NewColumn=12
 CASE 14,15,16
    NewColumn=13
 CASE 17
    NewColumn=16
 CASE 18,19,20
    NewColumn=17
 END SELECT
 IF NewColumn>0 THEN
    GOSUB ClearPageByte
    FilePosition=FilePosition-PageColumn+NewColumn
    PageColumn=NewColumn
    GOSUB DisplayPageByte
 END IF
 RETURN

' control-right key
CtrlRightKey:
 NewColumn=0
 SELECT CASE PageColumn
 CASE 1,2,3
    NewColumn=4
 CASE 4
    NewColumn=5
 CASE 5,6,7
    NewColumn=8
 CASE 8
    NewColumn=9
 CASE 9,10,11
    NewColumn=12
 CASE 12
    NewColumn=13
 CASE 13,14,15
    NewColumn=16
 CASE 16
    NewColumn=17
 CASE 17,18,19
    NewColumn=20
 END SELECT
 IF NewColumn THEN
    ' check new column is positioned before end of file
    IF FilePosition-PageColumn+NewColumn<=FileLength THEN
       GOSUB ClearPageByte
       FilePosition=FilePosition-PageColumn+NewColumn
       PageColumn=NewColumn
       GOSUB DisplayPageByte
    ELSE
       ' position end of file
       GOSUB ClearPageByte
       FilePosition=FileLength
       GOSUB CalculatePosition1
       GOSUB DisplayPageByte
    END IF
 END IF
 RETURN

' control-end key
CtrlEndKey:
 IF FilePosition<>FileLength THEN
    LastPage=FilePage
    GOSUB ClearPageByte
    FilePosition=FileLength
    GOSUB CalculatePosition1
    IF LastPage<>FilePage THEN
       GOSUB DisplayHexPage
    END IF
    GOSUB DisplayPageByte
 END IF
 RETURN

' control-home key
CtrlHomeKey:
 IF FilePosition<>1 THEN
    LastPage=FilePage
    GOSUB ClearPageByte
    FilePosition=1
    GOSUB CalculatePosition1
    IF LastPage<>FilePage THEN
       GOSUB DisplayHexPage
    END IF
    GOSUB DisplayPageByte
 END IF
 RETURN

' move one page up.
PageUp:
 ' check there is a page to move up.
 IF FilePosition-320>=1 THEN
    FilePage=FilePage-1
    FilePosition=FilePosition-320
    GOSUB DisplayHexPage
    GOSUB DisplayPageByte
 ELSE
    ' check to move to 1,1 of current top page.
    IF FilePosition>1 THEN
       GOSUB ClearPageByte
       PageRow=1
       PageColumn=1
       FilePosition=1
       GOSUB DisplayPageByte
    END IF
 END IF
 RETURN

' move one page down.
PageDown:
 ' check there is a page to move down.
 IF FilePosition+320<=FileLength THEN
    FilePage=FilePage+1
    FilePosition=FilePosition+320
    GOSUB DisplayHexPage
    GOSUB DisplayPageByte
 ELSE
    ' check the last page is there to move down to.
    IF FilePage*320<=FileLength THEN
       PageRow=1
       PageColumn=1
       FilePage=FilePage+1
       FilePosition=(FilePage-1)*320+1
       GOSUB DisplayHexPage
       GOSUB DisplayPageByte
    ELSE
       ' check there is a last position on the last page to move down to.
       IF FilePosition<FileLength THEN
          GOSUB ClearPageByte
          FilePosition=FileLength
          GOSUB CalculatePosition1
          GOSUB DisplayPageByte
       END IF
    END IF
 END IF
 RETURN

' switch editing windows.
TabWindow:
 IF CurrentWindow2=False THEN
    CurrentWindow=NOT CurrentWindow
    GOSUB LocateCursor
 ENDIF
 RETURN

' switch editing windows.
ToggleRight:
 CurrentWindow=False
 CurrentWindow2=NOT CurrentWindow2
 GOSUB RedrawRightWindow
 GOSUB DisplayPageByte
 RETURN

' change the byte value at the current position.
'   change by hex value in left window,
'   by ascii value in right window.
ChangeHexValue:
 GOSUB ClearStatus
 FileByte=Nul
 ValidByteString=False
 IF CurrentWindow=False THEN
    PRINT "Enter hex byte value";
    INPUT ByteString$
    IF LEFT$(ByteString$,1)="+" THEN
       ByteString$=MID$(ByteString$,2)
       NewValue=INT(VAL(ByteString$))
       IF NewValue>=False AND NewValue<=255 THEN
          ValidByteString=True
          FileByte=CHR$(NewValue)
       END IF
    ELSE
       IF LEN(ByteString$)=2 THEN
          AllowWildcard=False
          GOSUB CheckHexBytes
          IF ValidByteString THEN
             NewValue=VAL("&H"+ByteString$)
             FileByte=CHR$(NewValue)
          END IF
       END IF
    END IF
 ELSE
    PRINT "Enter ascii byte value";
    INPUT ByteString$
    IF UCASE$(LEFT$(ByteString$,1))="H" THEN
       ByteString$=MID$(ByteString$,2)
       IF LEN(ByteString$)=2 THEN
          AllowWildcard=False
          GOSUB CheckHexBytes
          IF ValidByteString THEN
             NewValue=VAL("&H"+ByteString$)
             FileByte=CHR$(NewValue)
          END IF
       END IF
    ELSE
       NewValue=INT(VAL(ByteString$))
       IF NewValue>=False AND NewValue<=255 THEN
          ValidByteString=True
          FileByte=CHR$(NewValue)
       END IF
    END IF
 END IF
 IF ValidByteString=False THEN
    StatusMessage="Invalid byte."
    GOSUB DisplayStatus2
    RETURN
 END IF
 GOSUB StoreUndo
 SeekPosition=FilePosition
 GOSUB LseekFile
 GOSUB WriteFile
 GOSUB DisplayPageByte
 GOSUB DisplayFilename
 RETURN

' change the ascii values with string starting at the current position.
ChangeASCIIValues:
 GOSUB ClearStatus
 PRINT "Enter ascii value(s)? ";
 LINE INPUT ByteString$
 IF LEN(ByteString$)=False THEN
    StatusMessage="Invalid ascii string."
    GOSUB DisplayStatus2
    RETURN
 END IF
 ' store all current ascii values.
 GOSUB ClearPageByte
 StorePosition=FilePosition
 FOR NumberBytes=1 TO LEN(ByteString$)
    SeekPosition=FilePosition
    GOSUB LseekFile
    GOSUB ReadFile
    FileByte=Buffer
    AsciiValue=ASC(FileByte)
    GOSUB StoreUndo
    IF FilePosition=FileLength THEN
       EXIT FOR
    END IF
    FilePosition=FilePosition+1
 NEXT
 ' write ascii string.
 FilePosition=StorePosition
 FOR NumberBytes=1 TO LEN(ByteString$)
    FileByte=MID$(ByteString$,NumberBytes,1)
    SeekPosition=FilePosition
    GOSUB LseekFile
    GOSUB WriteFile
    GOSUB DisplayPageByte
    IF FilePosition=FileLength THEN
       EXIT FOR
    END IF
    GOSUB ClearPageByte
    FilePosition=FilePosition+1
    GOSUB CalculatePosition1
    IF LastPage<>FilePage THEN
       LastPage=FilePage
       GOSUB DisplayHexPage
    END IF
 NEXT
 GOSUB DisplayPageByte
 GOSUB DisplayFilename
 RETURN

' record the current byte position and value.
' increment the number of undos in array.
StoreUndo:
 ' increase array dimensions.
 IF CurrentUndo+1>MaxUndos THEN
    MaxUndos=MaxUndos+1024
    REDIM PRESERVE UndoByte(1 TO MaxUndos) AS INTEGER
    REDIM PRESERVE UndoPosition(1 TO MaxUndos) AS LONG
 END IF
 CurrentUndo=CurrentUndo+1
 UndoByte(CurrentUndo)=AsciiValue
 UndoPosition(CurrentUndo)=FilePosition
 RETURN

' critical error trap.
Error.Routine:
 IF ScreenDrawn THEN
    CLS
 END IF
 ScreenDrawn=False
 COLOR White
 PRINT "Hex Editor "+Version+" "+Release+" critical error trap:"
 COLOR Yellow
 ErrorTrap=Err
 SELECT CASE Err
 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 "Media error."
 CASE 58
    PRINT "File already exists."
 CASE 59
    PRINT "Bad record length."
 CASE 61
    PRINT "Disk full."
 CASE 62
    PRINT "Input past eof."
 CASE 63
    PRINT "Bad record length."
 CASE 64
    PRINT "Bad filename."
 CASE 67
    PRINT "Not enough file handles."
 CASE 68
    PRINT "Device unavailable."
 CASE 70
    PRINT "Permission denied."
 CASE 71
    PRINT "Disk not ready."
 CASE 72
    PRINT "Disk-media error."
 CASE 75
    PRINT "Path/File access error."
 CASE 76
    PRINT "Pathname not found."
 CASE 81
    PRINT "Invalid name."
 CASE ELSE
    PRINT "Untrapped error" + STR$(Err) + "."
 END SELECT
 ' display error prompt.
 COLOR Green
 PRINT "Press R(etry), C(ontinue), Q(uit), A(bort):";
 ' get keypress.
 DO
    ErrorRespond$=Nul
    DO
       ErrorRespond$=INKEY$
       IF LEN(ErrorRespond$) THEN
          EXIT DO
       END IF
    LOOP
    ' parse key.
    SELECT CASE LCASE$(ErrorRespond$)
    CASE "r"
       PRINT "r"
       RESUME
    CASE "c"
       PRINT "c"
       RESUME NEXT
    CASE "q"
       PRINT "q"
       RESUME TopProgram
    CASE "a"
       PRINT "a"
       EXIT DO
    END SELECT
 LOOP
' anything goes here stops program.
StopProgram:
 GOSUB ResetDTA
 COLOR Plain
 END

REM Marker routines follow:

AddMarker:
 TempPosition3=FilePosition

AddMarkerValue:
 IF MarkerCount+1>MaxMarkers THEN
    MaxMarkers=MaxMarkers+1024
    REDIM PRESERVE Markers(1 TO MaxMarkers) AS LONG
 END IF
 MarkerCount=MarkerCount+1
 Markers(MarkerCount)=TempPosition3
 CurrentMarker=MarkerCount
 RETURN

AddSpecificMarker:
 GOSUB ClearStatus
 PRINT "Enter file position";
 INPUT ByteString$
 IF LEN(ByteString$) THEN
    IF UCASE$(LEFT$(ByteString$,1))="H" THEN
       ByteString$="&"+ByteString$
    END IF
    TempPosition3=INT(VAL(ByteString$))
    IF TempPosition3>=1 AND TempPosition3<=FileLength THEN
       GOSUB AddMarkerValue
       GOSUB LocateCursor
       GOSUB DisplayFilename
       RETURN
    END IF
 END IF
 StatusMessage="Invalid file position."
 GOSUB DisplayStatus2
 RETURN

DeleteMarker:
 IF CurrentMarker>=1 AND CurrentMarker<=MarkerCount THEN
    Markers(CurrentMarker)=False
 END IF
 RETURN

DeleteSpecificMarker:
 GOSUB ClearStatus
 PRINT "Enter marker number";
 INPUT ByteString$
 IF LEN(ByteString$) THEN
    IF UCASE$(LEFT$(ByteString$,1))="H" THEN
       ByteString$="&"+ByteString$
    END IF
    TempPosition=INT(VAL(ByteString$))
    IF TempPosition>=1 AND TempPosition<=MarkerCount THEN
       Markers(TempPosition)=False
       GOSUB LocateCursor
       GOSUB DisplayFilename
       RETURN
    END IF
 END IF
 StatusMessage="Invalid marker number."
 GOSUB DisplayStatus2
 RETURN

JumpPreviousMarker:
 NewMarker&=CurrentMarker
 DO
    IF NewMarker&<=1& THEN
       RETURN
    END IF
    NewMarker&=NewMarker&-1&
    IF Markers(NewMarker&)>0 THEN
       CurrentMarker=NewMarker&
       EXIT DO
    END IF
 LOOP
 GOSUB JumpCurrentMarker
 RETURN

JumpNextMarker:
 NewMarker&=CurrentMarker
 DO
    IF NewMarker&>=MarkerCount THEN
       RETURN
    END IF
    NewMarker&=NewMarker&+1&
    IF Markers(NewMarker&)>0 THEN
       CurrentMarker=NewMarker&
       EXIT DO
    END IF
 LOOP
 GOSUB JumpCurrentMarker
 RETURN

JumpSpecificMarker:
 GOSUB ClearStatus
 PRINT "Enter marker number";
 INPUT ByteString$
 IF LEN(ByteString$) THEN
    IF UCASE$(LEFT$(ByteString$,1))="H" THEN
       ByteString$="&"+ByteString$
    END IF
    TempPosition=INT(VAL(ByteString$))
    IF TempPosition>=1 AND TempPosition<=MarkerCount THEN
       IF Markers(TempPosition)>0 THEN
          CurrentMarker=TempPosition
          GOSUB JumpCurrentMarker
          RETURN
       END IF
    END IF
 END IF
 StatusMessage="Invalid marker number."
 GOSUB DisplayStatus2
 RETURN

JumpCurrentMarker:
 IF CurrentMarker>=1 AND CurrentMarker<=MarkerCount THEN
    TempPosition=Markers(CurrentMarker)
    IF TempPosition>=1 AND TempPosition<=FileLength THEN
       IF TempPosition<>FilePosition THEN
          GOSUB ClearPageByte
          LastPage=FilePage
          FilePosition=TempPosition
          GOSUB CalculatePosition1
          IF LastPage<>FilePage THEN
             GOSUB DisplayHexPage
          END IF
          GOSUB DisplayPageByte
       END IF
    END IF
 END IF
 GOSUB DisplayFilename
 RETURN

ListAllMarkers:
 CLS
 COLOR White
 PRINT "Marker list:"
 PageCount=False
 CountFlag=False
 FOR TempPosition=1 TO MarkerCount
    IF Markers(TempPosition)>0 THEN
       PageCount=PageCount+1
       CountFlag=True
       COLOR Yellow
       GOSUB FormatPosition3
       PRINT
       IF PageCount>=22 THEN
          PageCount=False
          GOSUB PressKey
          CLS
          COLOR White
          PRINT "Marker list:"
       END IF
    END IF
 NEXT
 IF CountFlag=False THEN
    COLOR Yellow
    PRINT "No markers stored."
 END IF
 GOSUB PressKey
 GOSUB RedrawScreen
 RETURN

ListSpecificMarker:
 GOSUB ClearStatus
 PRINT "Enter marker number";
 INPUT ByteString$
 IF LEN(ByteString$) THEN
    IF UCASE$(LEFT$(ByteString$,1))="H" THEN
       ByteString$="&"+ByteString$
    END IF
    TempPosition=INT(VAL(ByteString$))
    IF TempPosition>=1 AND TempPosition<=MarkerCount THEN
       GOSUB ClearStatus
       GOSUB FormatPosition2
       GOSUB LocateCursor
       WHILE INKEY$<>CHR$(27):WEND
       GOSUB DisplayFilename
       RETURN
    END IF
 END IF
 StatusMessage="Invalid marker number."
 GOSUB DisplayStatus2
 RETURN

ListMarkersOfValue:
 CLS
 COLOR White
 PRINT "Enter marker value";
 INPUT ByteString$
 IF UCASE$(LEFT$(ByteString$,1))="H" THEN
    ByteString$="&"+ByteString$
 END IF
 TempPosition1=INT(VAL(ByteString$))
 CLS
 COLOR White
 PRINT "Marker list:"
 PageCount=False
 CountFlag=False
 FOR TempPosition=1 TO MarkerCount
    IF Markers(TempPosition)=TempPosition1 THEN
       PageCount=PageCount+1
       CountFlag=True
       COLOR Yellow
       GOSUB FormatPosition3
       PRINT
       IF PageCount>=22 THEN
          PageCount=False
          GOSUB PressKey
          CLS
          COLOR White
          PRINT "Marker list:"
       END IF
    END IF
 NEXT
 IF CountFlag=False THEN
    COLOR Yellow
    PRINT "No markers of value stored."
 END IF
 GOSUB PressKey
 GOSUB RedrawScreen
 RETURN

ListMarkerRange:
 GOSUB ClearStatus
 PRINT "Enter beginning marker number";
 INPUT ByteString$
 IF LEN(ByteString$) THEN
    IF UCASE$(LEFT$(ByteString$,1))="H" THEN
       ByteString$="&"+ByteString$
    END IF
    TempPosition1=INT(VAL(ByteString$))
    IF TempPosition1>=1 AND TempPosition1<=MarkerCount THEN
       GOSUB ClearStatus
       PRINT "Enter ending marker number";
       INPUT ByteString$
       IF LEN(ByteString$) THEN
          IF UCASE$(LEFT$(ByteString$,1))="H" THEN
             ByteString$="&"+ByteString$
          END IF
          TempPosition2=INT(VAL(ByteString$))
          IF TempPosition2>=1 AND TempPosition2<=MarkerCount THEN
             CLS
             COLOR White
             PRINT "Marker list:"
             PageCount=False
             CountFlag=False
             FOR TempPosition=TempPosition1 TO TempPosition2
                IF Markers(TempPosition)>0 THEN
                   PageCount=PageCount+1
                   CountFlag=True
                   COLOR Yellow
                   GOSUB FormatPosition3
                   PRINT
                   IF PageCount>=22 THEN
                      PageCount=False
                      GOSUB PressKey
                      CLS
                      COLOR White
                      PRINT "Marker list:"
                   END IF
                END IF
             NEXT
             IF CountFlag=False THEN
                COLOR Yellow
                PRINT "No markers stored."
             END IF
             GOSUB PressKey
             GOSUB RedrawScreen
             RETURN
          END IF
       END IF
    END IF
 END IF
 StatusMessage="Invalid marker range."
 GOSUB DisplayStatus2
 RETURN



DeleteMarkerRange:
 GOSUB ClearStatus
 PRINT "Enter beginning marker number";
 INPUT ByteString$
 IF LEN(ByteString$) THEN
    IF UCASE$(LEFT$(ByteString$,1))="H" THEN
       ByteString$="&"+ByteString$
    END IF
    TempPosition1=INT(VAL(ByteString$))
    IF TempPosition1>=1 AND TempPosition1<=MarkerCount THEN
       GOSUB ClearStatus
       PRINT "Enter ending marker number";
       INPUT ByteString$
       IF LEN(ByteString$) THEN
          IF UCASE$(LEFT$(ByteString$,1))="H" THEN
             ByteString$="&"+ByteString$
          END IF
          TempPosition2=INT(VAL(ByteString$))
          IF TempPosition2>=1 AND TempPosition2<=MarkerCount THEN
             FOR TempPosition=TempPosition1 TO TempPosition2
                Markers(TempPosition)=False
             NEXT
             StatusMessage="Range of markers deleted."
             GOSUB DisplayStatus2
             RETURN
          END IF
       END IF
    END IF
 END IF
 StatusMessage="Invalid marker range."
 GOSUB DisplayStatus2
 RETURN

DeleteAllMarkers:
 CurrentMarker=0
 MarkerCount=0
 MaxMarkers=1024
 REDIM Markers(1 TO 1024) AS LONG
 StatusMessage="All markers deleted."
 GOSUB DisplayStatus2
 RETURN

DeleteMarkersOfValue:
 GOSUB ClearStatus
 PRINT "Enter marker value";
 INPUT ByteString$
 IF LEN(ByteString$) THEN
    IF UCASE$(LEFT$(ByteString$,1))="H" THEN
       ByteString$="&"+ByteString$
    END IF
    TempPosition1=INT(VAL(ByteString$))
    FOR TempPosition=1 TO MarkerCount
       IF Markers(TempPosition)=TempPosition1 THEN
          Markers(TempPosition)=False
       END IF
    NEXT
 END IF
 StatusMessage="All markers of value deleted."
 GOSUB DisplayStatus2
 RETURN

REM Position calculation routines follow:

' displays cell position in string format type 1.
FormatPosition1:
 GOSUB CalculatePosition2
 IF CurrentWindow2=False THEN
    PRINT "(page:";MID$(STR$(FilePage2&),2);",";
 ELSE
    PRINT "(page:";RIGHT$("00000000"+HEX$(FilePage2&),8);"H,";
 END IF
 PRINT "row:";MID$(STR$(PageRow2&),2);",";
 PRINT "column:";MID$(STR$(PageColumn2&),2);")";
 RETURN

' displays cell position in string format type 2.
FormatPosition2:
 PRINT "Marker#";MID$(STR$(TempPosition),2);":";
 TempPosition3=Markers(TempPosition)
 IF CurrentWindow2=False THEN
    PRINT MID$(STR$(TempPosition3),2);" ";
 ELSE
    PRINT RIGHT$("00000000"+HEX$(TempPosition3),8);"H ";
 END IF
 GOSUB CalculatePosition2
 IF CurrentWindow2=False THEN
    PRINT "(page:";MID$(STR$(FilePage2&),2);",";
 ELSE
    PRINT "(page:";RIGHT$("00000000"+HEX$(FilePage2&),8);"H,";
 END IF
 PRINT "row:";MID$(STR$(PageRow2&),2);",";
 PRINT "column:";MID$(STR$(PageColumn2&),2);")";
 PRINT " Press <esc>:";
 RETURN

' displays cell position in string format type 3.
FormatPosition3:
 PRINT "Marker#";MID$(STR$(TempPosition),2);" Position:";
 TempPosition3=Markers(TempPosition)
 IF CurrentWindow2=False THEN
    PRINT MID$(STR$(TempPosition3),2);" ";
 ELSE
    PRINT RIGHT$("00000000"+HEX$(TempPosition3),8);"H ";
 END IF
 GOSUB CalculatePosition2
 IF CurrentWindow2=False THEN
    PRINT "(page:";MID$(STR$(FilePage2&),2);",";
 ELSE
    PRINT "(page:";RIGHT$("00000000"+HEX$(FilePage2&),8);"H,";
 END IF
 PRINT "row:";MID$(STR$(PageRow2&),2);",";
 PRINT "column:";MID$(STR$(PageColumn2&),2);")";
 RETURN

' calculate current screen page number, row, and column, given file position.
CalculatePosition1:
 FilePage=INT((FilePosition-1)/320)+1
 PageRow=INT((FilePosition-(FilePage-1)*320-1)/20)+1
 PageColumn=INT((FilePosition-(FilePage-1)*320)-(PageRow-1)*20)
 RETURN

' calculate screen page number, row, and column, given variable.
CalculatePosition2:
 IF TempPosition3=0 THEN
    FilePage2&=0
    PageRow2&=0
    PageColumn2&=0
 ELSE
    FilePage2&=INT((TempPosition3-1)/320)+1
    PageRow2&=INT((TempPosition3-(FilePage2&-1)*320-1)/20)+1
    PageColumn2&=INT((TempPosition3-(FilePage2&-1)*320)-(PageRow2&-1)*20)
 END IF
 RETURN

REM Long filename routines follow:

' read lowercase command line.
ReadCommandLine:
 CommandLine$=Nul
 InregsX.AX=&H6200
 CALL InterruptX(&H21,InregsX,OutregsX)
 PSPsegment=OutregsX.BX
 PSPoffset=128
 DEF SEG=PSPsegment
 FOR Count=1 TO 127
    CommandChar=PEEK(PSPoffset+Count)
    SELECT CASE CommandChar
    CASE 0, 10, 13
       EXIT FOR
    CASE ELSE
       CommandLine$=CommandLine$+CHR$(CommandChar)
    END SELECT
 NEXT
 DEF SEG
 RETURN

' store basic dta.
StoreDTA:
 InregsX.AX=&H2F00
 CALL InterruptX(&H21,InregsX,OutregsX)
 BASIC.DTA.SEG=OutregsX.ES
 BASIC.DTA.OFF=OutregsX.BX
 RETURN

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

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

' verify windows loaded.
CheckWindows:
 InregsX.AX=&H160A
 CALL InterruptX(&H2F,InregsX,OutregsX)
 IF OutregsX.AX=False THEN
    Temp=(OutregsX.BX AND &HFF00)/256
    IF Temp>=4 THEN
       WindowsDetected=True
    END IF
 END IF
 RETURN

' determine length of file.
GetFileLength:
 FileLength=False
 InregsX.AX=&H4202
 InregsX.BX=Handle
 InregsX.CX=&H0
 InregsX.DX=&H0
 CALL InterruptX(&H21,InregsX,OutregsX)
 IF (OutregsX.Flags AND &H1)=&H1 THEN
    DisplayError$="reading filelength"
    GOSUB LongFileError
    RETURN
 END IF
 IF OutregsX.AX<0 THEN
    Low&=CLNG(OutregsX.AX+65536)
 ELSE
    Low&=CLNG(OutregsX.AX)
 END IF
 IF OutregsX.DX<0 THEN
    High&=CLNG(OutregsX.DX+65536)
 ELSE
    High&=CLNG(OutregsX.DX)
 END IF
 FileLength=High&*&H10000+Low&
 RETURN

' close file.
CloseFile:
 InregsX.AX=&H3E00
 InregsX.BX=Handle
 CALL InterruptX(&H21,InregsX,OutregsX)
 IF (OutregsX.Flags AND &H1)=&H1 THEN
    DisplayError$="closing file"
    GOSUB LongFileError
 END IF
 RETURN

' open file based on windows or dos loaded.
'   create file if nonexistent,
'   append nul byte to new file,
'   reopen file.
' return ValidFile true if open successful.
OpenFile:
 ValidFile=True
 IF WindowsDetected THEN
    GOSUB OpenWinFile
    IF (OutregsX.Flags AND &H1)=&H1 THEN
       GOSUB CreateWinFile
       IF (OutregsX.Flags AND &H1)=&H1 THEN
          ValidFile=False
       ELSE
          GOSUB AppendFile
          IF (OutregsX.Flags AND &H1)=&H1 THEN
             ValidFile=False
          ELSE
             GOSUB CloseFile
             GOSUB OpenWinFile
          END IF
       END IF
    END IF
 ELSE
    GOSUB OpenDOSFile
    IF (OutregsX.Flags AND &H1)=&H1 THEN
       GOSUB CreateDOSFile
       IF (OutregsX.Flags AND &H1)=&H1 THEN
          ValidFile=False
       ELSE
          GOSUB AppendFile
          IF (OutregsX.Flags AND &H1)=&H1 THEN
             ValidFile=False
          ELSE
             GOSUB CloseFile
             GOSUB OpenDOSFile
          END IF
       END IF
    END IF
 END IF
 RETURN

' open file in windows.
'   store/reset read-only bit.
OpenWinFile:
 ' reset file attributes.
 FileAttribute=False
 ' get file attributes.
 InregsX.AX=&H7143
 InregsX.BX=&H0
 InregsX.DS=VARSEG(ASCIIZ)
 InregsX.DX=VARPTR(ASCIIZ)
 CALL InterruptX(&H21,InregsX,OutregsX)
 ' store file attributes.
 IF (OutregsX.Flags AND &H1)=&H0 THEN
    FileAttribute=OutregsX.CX
 END IF
 ' clear read-only bit for opening file for write.
 IF (FileAttribute AND ReadOnlyBit)=ReadOnlyBit THEN
    Attribute=(FileAttribute AND NOT ReadOnlyBit)
    ' reset file attribute
    InregsX.AX=&H7143
    InregsX.BX=&H1
    InregsX.CX=Attribute
    InregsX.DS=VARSEG(ASCIIZ)
    InregsX.DX=VARPTR(ASCIIZ)
    CALL InterruptX(&H21,InregsX,OutregsX)
 END IF
 ' open file for read/write.
 InregsX.AX=&H716C
 InregsX.BX=&H2
 InregsX.CX=FileAttribute
 InregsX.DX=&H1
 InregsX.DS=VARSEG(ASCIIZ)
 InregsX.SI=VARPTR(ASCIIZ)
 InregsX.DI=&H1
 CALL InterruptX(&H21,InregsX,OutregsX)
 Handle=OutregsX.AX
 RETURN

' open file in dos.
'   store/reset read-only bit.
OpenDOSFile:
 ' reset file attributes.
 FileAttribute=False
 ' get file attributes.
 InregsX.AX=&H4300
 InregsX.DS=VARSEG(ASCIIZ)
 InregsX.DX=VARPTR(ASCIIZ)
 CALL InterruptX(&H21,InregsX,OutregsX)
 ' store file attributes.
 IF (OutregsX.Flags AND &H1)=&H0 THEN
    FileAttribute=OutregsX.CX
 END IF
 ' clear read-only bit for opening file for write.
 IF (FileAttribute AND ReadOnlyBit)=ReadOnlyBit THEN
    Attribute=(FileAttribute AND NOT ReadOnlyBit)
    ' reset source attribute
    InregsX.AX=&H4301
    InregsX.CX=Attribute
    InregsX.DS=VARSEG(ASCIIZ)
    InregsX.DX=VARPTR(ASCIIZ)
    CALL InterruptX(&H21,InregsX,OutregsX)
 END IF
 ' open file for read/write.
 InregsX.AX=&H6C00
 InregsX.BX=&H2
 InregsX.CX=FileAttribute
 InregsX.DX=&H1
 InregsX.DS=VARSEG(ASCIIZ)
 InregsX.SI=VARPTR(ASCIIZ)
 CALL InterruptX(&H21,InregsX,OutregsX)
 Handle=OutregsX.AX
 RETURN

' create new file in windows.
CreateWinFile:
 InregsX.AX=&H716C
 InregsX.BX=&H1
 InregsX.CX=&H0
 InregsX.DX=&H10
 InregsX.DS=VARSEG(ASCIIZ)
 InregsX.SI=VARPTR(ASCIIZ)
 InregsX.DI=&H1
 CALL InterruptX(&H21,InregsX,OutregsX)
 Handle=OutregsX.AX
 RETURN

' create new file in dos.
CreateDOSFile:
 InregsX.AX=&H6C00
 InregsX.BX=&H1
 InregsX.CX=&H0
 InregsX.DX=&H10
 InregsX.DS=VARSEG(ASCIIZ)
 InregsX.SI=VARPTR(ASCIIZ)
 CALL InterruptX(&H21,InregsX,OutregsX)
 Handle=OutregsX.AX
 RETURN

' write a nul byte to file.
AppendFile:
 FileByte=CHR$(0)
 GOSUB WriteFile
 RETURN

' read 1 byte from file.
ReadFile:
 InregsX.AX=&H3F00
 InregsX.BX=Handle
 InregsX.CX=1
 InregsX.DS=VARSEG(Buffer)
 InregsX.DX=VARPTR(Buffer)
 CALL InterruptX(&H21,InregsX,OutregsX)
 IF (OutregsX.Flags AND &H1)=&H1 THEN
    DisplayError$="reading file"
    GOSUB LongFileError
 END IF
 RETURN

' write 1 byte to file.
WriteFile:
 Buffer=FileByte
 InregsX.AX=&H4000
 InregsX.BX=Handle
 InregsX.CX=1
 InregsX.DS=VARSEG(Buffer)
 InregsX.DX=VARPTR(Buffer)
 CALL InterruptX(&H21,InregsX,OutregsX)
 IF (OutregsX.Flags AND &H1)=&H1 THEN
    DisplayError$="writing file"
    GOSUB LongFileError
 END IF
 RETURN

' position pointer in file.
LseekFile:
 ' calculate high/low seek position.
 High&=INT(SeekPosition/65536)
 Low&=(SeekPosition AND 65535)-1
 ' seek position in file.
 InregsX.AX=&H4200
 InregsX.BX=Handle
 InregsX.CX=INT(VAL("&H"+HEX$(High&)))
 InregsX.DX=INT(VAL("&H"+HEX$(Low&)))
 CALL InterruptX(&H21,InregsX,OutregsX)
 IF (OutregsX.Flags AND &H1)=&H1 THEN
    DisplayError$="seeking file"
    GOSUB LongFileError
 END IF
 RETURN

' conanicalize filename for display purposes.
ShortFilename:
 ' read 8.3 filename.
 IF WindowsDetected 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

 ' store 8.3 filename.
 IF (OutregsX.Flags AND &H1)=&H0 THEN
    Filename=ASCIIZ2
    Imbedded=INSTR(Filename,CHR$(0))
    IF Imbedded THEN
       Filename=LEFT$(Filename,Imbedded-1)
    END IF
 END IF

 ' conanicalize filename.
 Filename=Conanicalize$(Filename)
 RETURN

' restore read-only attribute.
ResetAttribute:
 IF (FileAttribute AND ReadOnlyBit)=ReadOnlyBit THEN
    IF WindowsDetected THEN
       InregsX.AX=&H7143
       InregsX.BX=&H1
       InregsX.CX=FileAttribute
       InregsX.DS=VARSEG(ASCIIZ)
       InregsX.DX=VARPTR(ASCIIZ)
       CALL InterruptX(&H21,InregsX,OutregsX)
    ELSE
       InregsX.AX=&H4301
       InregsX.CX=FileAttribute
       InregsX.DS=VARSEG(ASCIIZ)
       InregsX.DX=VARPTR(ASCIIZ)
       CALL InterruptX(&H21,InregsX,OutregsX)
    END IF
 END IF
 RETURN

' display message about long filename access error.
LongFileError:
 GOSUB ClearStatus
 PRINT "Error ";DisplayError$;".";
 RETURN

REM Define functions.

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

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

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

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

 ' This program is worth three cookies, two colas, and a cat!
