Rem File: Helpedit v1.4a for Dndbbs Version v5.0a Release r2.0

REM compile:
REM bc helpedit/x/o;
REM link helpedit,,,vbdos/e;

REM $INCLUDE: 'io9.inc'

Common Shared VarX As String*1
Common Shared VarY As String*1
Common Shared Debug.Mode As Integer
Common Shared Max.Row As Integer
Common Shared TempX2 As Integer
Common Shared Temp.ArrayY() As Long
Common Shared Temp.ArrayZ() As Double
Common Shared Linux As Integer

HelpRecLen = LEN(HelpRecord)

' define clock display function
Function FClock$
 FClock$=Format$(Now,"ddd dd mmm yyyy\, hh:mma/p")
End Function

' define formatting function
FUNCTION Form$ (Var#)
 Form$ = Format$(Var#, "#,##0;;" + CHR$(34) + "zero" + CHR$(34))
END FUNCTION

' checks keyboard buffer
FUNCTION KeyIS
 InregsX.AX = &H0100
 CALL InterruptX(&H16, InregsX, OutregsX)
 IF (OutregsX.Flags AND &H40) = &H40 THEN
    KeyIS = False
 ELSE
    KeyIS = True
 END IF
 CALL Release.Time(1)
END FUNCTION

' reads character directly from keyboard including extended keys.
FUNCTION KeyboardChar$
 InregsX.AX = &H0000
 CALL InterruptX(&H16, InregsX, OutregsX)
 Key1 = (OutregsX.AX AND &HFF)
 IF Key1 = False THEN ' extended key
    Key2 = (OutregsX.AX AND &HFF00) / 256
    KeyboardChar$ = CHR$(0) + CHR$(Key2)
 ELSE
    KeyboardChar$ = CHR$(Key1)
 END IF
 CALL Release.Time(1)
END FUNCTION

' uses direct keyboard input to get an input line during redirected input.
FUNCTION KeyboardLine$
 Var$ = Nul
 DO
    LOCATE ,,1
    IF KeyIS THEN ' check keyboard
       Var2$ = KeyboardChar$ ' get character
       SELECT CASE Var2$
       CASE CHR$(13) ' return
          EXIT DO
       CASE CHR$(27) ' escape
          FOR V% = LEN(Var$) TO 1 STEP -1
             IF POS(0) > 1 THEN ' check cursor location
                LOCATE CSRLIN, POS(0) - 1, 0
                PRINT " ";
                LOCATE CSRLIN, POS(0) - 1, 1
             ELSE ' line-wrap
                LOCATE CSRLIN - 1, 80, 0
                PRINT " ";
                LOCATE CSRLIN - 1, 80, 1
             END IF
          NEXT   
          Var$ = Nul
       CASE CHR$(8) ' backspace
          IF LEN(Var$) > 0 THEN
             Var$ = LEFT$(Var$, LEN(Var$) - 1)
             IF POS(0) > 1 THEN ' check cursor location
                LOCATE CSRLIN, POS(0) - 1, 0
                PRINT " ";
                LOCATE CSRLIN, POS(0) - 1, 1
             ELSE ' line-wrap
                LOCATE CSRLIN - 1, 80, 0
                PRINT " ";
                LOCATE CSRLIN - 1, 80, 1
             END IF
          END IF
       CASE ELSE ' store input
          PRINT Var2$;
          LOCATE , , 1
          Var$ = Var$ + Var2$
       END SELECT
    END IF

    ' release time slice for tight loop
    CALL Release.Time(1)
 LOOP

 ' return input line
 KeyboardLine$ = Var$
END FUNCTION

' declare help array structure
REDIM HelpStruc(1 TO 1024) AS HelpType2

' declare command error routine
ON ERROR GOTO MainError

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

' start helpedit
Call Read.Rows(Var)
Max.Row=Var
MaxHelp = 1024
CurrentHelp = 0
Current.Dir$ = CURDIR$
CALL Get.Config(Filename$)
CLOSE

Call Save.Screen(0)

' create temp directory
VarZ$ = "C:\TEMP" + NodeX
ON ERROR RESUME NEXT
IF DIR$(VarZ$)<>"" THEN
   KILL VarZ$
END IF
CHDIR VarZ$
IF ERR THEN
   MKDIR VarZ$
END IF
ON ERROR GOTO MainError
CHDIR Current.Dir$

' check files already exist
Filenamex$ = VarZ$ + "\CONTENTD.HLP"
If Dir$(Filenamex$)<>"" Then
   Goto MainError2
Endif
Filenamex$ = VarZ$ + "\CONTENTS.HLP"
If Dir$(Filenamex$)<>"" Then
   Goto MainError2
Endif

' disassemble help file
COLOR 15,0
PRINT "Writing temporary help data files.."
CLOSE
OPEN Filename$ FOR RANDOM SHARED AS #1 LEN = HelpRecLen
FOR Rec! = 2 TO LOF(1) / HelpRecLen
   GET 1, Rec!, HelpRecord
   Text$ = RTRIM$(HelpRecord.CommandName)
   IF Text$ <> Prev$ THEN
      Prev$ = Text$
      CurrentHelp = CurrentHelp + 1
      IF CurrentHelp > MaxHelp THEN
	 MaxHelp = MaxHelp + 16
	 REDIM PRESERVE HelpStruc(1 TO MaxHelp) AS HelpType2
      END IF
      HelpStruc(CurrentHelp).CName = Text$
      HelpStruc(CurrentHelp).Filename = "DND" + RIGHT$("00000" + MID$(STR$(CurrentHelp), 2), 5) + ".HLP"
      CLOSE #2
      Filename2$ = VarZ$ + "\" + HelpStruc(CurrentHelp).Filename
      OPEN Filename2$ FOR OUTPUT AS #2
   END IF
   PRINT #2, RTRIM$(HelpRecord.Text)
NEXT
LastHelp = CurrentHelp

' write contents data file
CLOSE #2
IF EditFile THEN
   Filename2$ = VarZ$ + "\CONTENTD.HLP"
ELSE
   Filename2$ = VarZ$ + "\CONTENTS.HLP"
END IF
OPEN Filename2$ FOR OUTPUT AS #2
IF EditFile THEN
   PRINT #2, "Contents of DMHelp Data File:
ELSE
   PRINT #2, "Contents of Help Data File:"
END IF
PRINT #2, ""
Command.Count1 = 0
Var$ = ""
FOR Command.Count2 = 1 TO CurrentHelp
   Command1$ = HelpStruc(Command.Count2).CName
   Var$ = Var$ + Command1$
   Command.Count1 = Command.Count1 + 1
   IF Command.Count1 = 5 THEN
      PRINT #2, Var$
      Var$ = ""
      Command.Count1 = 0
   END IF
NEXT
IF LEN(Var$) THEN
   PRINT #2, Var$
END IF

' start helpedit loop
Call Read.Rows(Var)
Max.Row=Var
CLOSE
CLS
CALL Edit.Status.Line
LOCATE Max.Row-1, 1, 1
If Debug.Mode Then
   Print "Nodex="+Chr$(34)+NodeX+Chr$(34)
Endif
DO
   COLOR 15, 0
   PRINT "Help Editor v1.4a:"
   COLOR 14, 0
   PRINT "Options:"
   COLOR 15, 0
   PRINT "(1)List commands"
   PRINT "(2)Add menu"
   PRINT "(3)Edit menu"
   PRINT "(4)Remove command"
   PRINT "(5)Search filespec"
   PRINT "(6)Sort commands"
   PRINT "(7)Write help file"
   PRINT "(8)Quit editor"
   COLOR 14, 0
   PRINT "Enter option:";
   Char$ = ""
   WHILE Char$ = ""
      Char$ = INKEY$
      CALL Release.Time(1)
   WEND
   IF Char$=CHR$(13) THEN
      PRINT "8"
      Char$ = "8"
   ELSE
      PRINT Char$
   END IF
   Var1 = INT(VAL(Char$))
   SELECT CASE Var1
   CASE 1 ' list
      Command.Count1 = 0
      Line.Count = 0
      FOR Command.Count2 = 1 TO CurrentHelp
         Command1$ = HelpStruc(Command.Count2).CName
	 COLOR 15, 0
         PRINT Command1$;
         Command.Count1 = Command.Count1 + 1
         IF Command.Count1 = 5 THEN
	    PRINT
            Command.Count1 = 0
            Line.Count = Line.Count + 1
            IF Line.Count = Max.Row-2 THEN
               Line.Count = 0
	       COLOR 14, 0
	       PRINT "more:";
               DO
                  Char$ = INKEY$
                  IF UCASE$(Char$) = "N" THEN
                     PRINT
                     EXIT FOR
                  END IF
                  IF LEN(Char$) THEN
                     PRINT
                     EXIT DO
                  ENDIF
                  CALL Release.Time(1)
               LOOP
	    END IF
	 ELSE
	    PRINT " ";
	 END IF
         CALL Release.Time(1)
      NEXT
      IF Command.Count1 > 0 THEN
         Line.Count = Line.COunt + 1
         PRINT
      END IF
      IF Line.Count > 0 THEN
	 COLOR 14, 0
	 PRINT "more:";
         WHILE INKEY$ = ""
            CALL Release.Time(1)
         WEND
	 PRINT
      END IF
   CASE 2 ' add
      DO
	 COLOR 15, 0
	 PRINT "(1)Import file"
	 PRINT "(2)Create new command"
         PRINT "(3)Quit add menu"
	 COLOR 14, 0
	 PRINT "Enter option:";
         Char$ = ""
         WHILE Char$ = ""
            Char$ = INKEY$
            CALL Release.Time(1)
	 WEND
         IF Char$=CHR$(13) THEN
            PRINT "3"
            Char$ = "3"
         ELSE
            PRINT Char$
         END IF
         Var1 = INT(VAL(Char$))
         SELECT CASE Var1
	 CASE 1 ' import
	    COLOR 15, 0
	    PRINT "Enter filename:";
            Filespec1$ = KeyboardLine$
            PRINT
            IF Filespec1$ = "" THEN
               PRINT "File not found."
            ELSE
               IF DIR$(Filespec1$) = "" THEN
                  PRINT "File not found."
               ELSE
                  PRINT "Enter command name:";
                  Command1$ = KeyboardLine$
                  PRINT
                  IF Command1$ = "" THEN
                     PRINT "Command name not specified."
                  ELSE
                     IF LEN(Command1$) > 15 THEN
                        PRINT "Command name too long."
                     ELSE
                        CurrentHelp = CurrentHelp + 1
                        IF CurrentHelp > MaxHelp THEN
                           MaxHelp = MaxHelp + 16
                           REDIM PRESERVE HelpStruc(1 TO MaxHelp) AS HelpType2
                        END IF
                        LastHelp = LastHelp + 1
                        HelpStruc(CurrentHelp).CName = UCASE$(Command1$)
                        File2$ = "DND" + RIGHT$("00000" + MID$(STR$(LastHelp), 2), 5) + ".HLP"
                        HelpStruc(CurrentHelp).Filename = File2$
                        CLOSE
                        File2$ = RTRIM$(VarZ$) + "\" + File2$
                        IF DIR$(File2$) <> "" THEN
                           KILL File2$
                        END IF
                        OPEN Filespec1$ FOR INPUT AS #3
                        OPEN File2$ FOR OUTPUT AS #4
                        DO
                           IF EOF(3) THEN EXIT DO
                           LINE INPUT #3, Text$
                           Text$ = RTRIM$(Text$)
                           PRINT #4, Text$
                        LOOP
                        PRINT "Command added."
                     END IF
                  END IF
	       END IF
	    END IF
	 CASE 2 ' create
	    PRINT "Enter command name:";
            Command1$ = KeyboardLine$
            PRINT
            IF Command1$ = "" THEN
               PRINT "Command name not specified."
            ELSE
               IF LEN(Command1$) > 15 THEN
                  PRINT "Command name too long."
               ELSE
                  CurrentHelp = CurrentHelp + 1
                  IF CurrentHelp > MaxHelp THEN
                     MaxHelp = MaxHelp + 16
                     REDIM PRESERVE HelpStruc(1 TO MaxHelp) AS HelpType2
                  END IF
                  LastHelp = LastHelp + 1
                  HelpStruc(CurrentHelp).CName = UCASE$(Command1$)
                  File2$ = "DND" + RIGHT$("00000" + MID$(STR$(LastHelp), 2), 5) + ".HLP"
                  HelpStruc(CurrentHelp).Filename = File2$
                  File2$ = RTRIM$(VarZ$) + "\" + File2$
                  CLOSE #5
                  IF DIR$(File2$) <> "" THEN
                     KILL File2$
                  END IF
                  CALL Scrnedit(File2$)
               END IF
	    END IF
         CASE 3 ' quit
	    EXIT DO
	 END SELECT
         CALL Release.Time(1)
      LOOP
   CASE 3 ' edit
      DO
	 COLOR 15, 0
         PRINT "(1)Edit command"
         PRINT "(2)Edit file"
         PRINT "(3)Quit edit menu"
	 COLOR 14, 0
	 PRINT "Enter option:";
         Char$ = ""
         WHILE Char$ = ""
            Char$ = INKEY$
            CALL Release.Time(1)
	 WEND
         IF Char$=CHR$(13) THEN
            PRINT "3"
            Char$ = "3"
         ELSE
            PRINT Char$
         END IF
         Var1 = INT(VAL(Char$))
         SELECT CASE Var1
         CASE 1 ' edit command
            PRINT "Enter command name:";
            Command1$ = KeyboardLine$
            PRINT
            IF LEN(Command1$) > 15 THEN
               PRINT "Command name too long."
            ELSE
               Command1$ = UCASE$(Command1$)
               Commands = 0
               IF CurrentHelp > 0 THEN
                  FOR SearchHelp = 1 TO CurrentHelp
                     Command2$ = RTRIM$(HelpStruc(SearchHelp).CName)
                     IF Command2$ = Command1$ THEN
                        Commands = Commands + 1
                     END IF
                  NEXT
                  IF Commands > 0 THEN
                     If Commands = 1 Then
                        Print "Edit ";Command1$;"(y/n)? ";
                        Var$ = KeyboardLine$
                        PRINT
                        If Lcase$(Var$) = "y" Then
                           FOR SearchHelp = 1 TO CurrentHelp
                              Command2$ = RTRIM$(HelpStruc(SearchHelp).CName)
                              IF Command2$ = Command1$ THEN
                                 File2$ = RTRIM$(HelpStruc(SearchHelp).Filename)
                                 File2$ = RTRIM$(VarZ$) + "\" + File2$
                                 CLOSE
                                 CALL Scrnedit(File2$)
                              Endif
                           Next
                        Endif
                     Else
                        Print "Edit ";Command1$;"(1-";Mid$(Str$(Commands),2)")";
                        CommandNumber = INT(VAL(KeyboardLine$))
                        PRINT
                        If CommandNumber > 0 And CommandNumber <= Commands Then
                           Commands = 0
                           FOR SearchHelp = 1 TO CurrentHelp
                              Command2$ = RTRIM$(HelpStruc(SearchHelp).CName)
                              IF Command2$ = Command1$ THEN
                                 Commands = Commands + 1
                                 If Commands = CommandNumber Then
                                    File2$ = RTRIM$(HelpStruc(SearchHelp).Filename)
                                    File2$ = RTRIM$(VarZ$) + "\" + File2$
                                    CLOSE
                                    CALL Scrnedit(File2$)
                                 Endif
                              END IF
                           NEXT
                        Endif
                     Endif
                  Endif
               END IF
            END IF
         CASE 2 ' edit file
	    COLOR 15, 0
	    PRINT "Enter filename:";
            Filespec1$ = KeyboardLine$
            PRINT
            If Left$(Filespec1$,1)=Chr$(34) Then
               Filespec1$=Mid$(Filespec1$,2)
               If Right$(Filespec1$,1)=Chr$(34) Then
                  Filespec1$=Left$(Filespec1$,Len(Filespec1$)-1)
               Endif
            Endif
            IF DIR$(Filespec1$) = "" THEN
	       PRINT "File not found."
	    ELSE
               CLOSE
               CALL Scrnedit(Filespec1$)
            END IF
         CASE 3 ' quit
	    EXIT DO
         END SELECT
         CALL Release.Time(1)
      LOOP
   CASE 4 ' remove
      PRINT "Enter command name:";
      Command1$ = KeyboardLine$
      PRINT
      IF LEN(Command1$) > 15 THEN
	 PRINT "Command name too long."
      ELSE
         Command1$ = UCASE$(Command1$)
         Var = 0
         Commands = 0
	 IF CurrentHelp > 0 THEN
	    FOR SearchHelp = 1 TO CurrentHelp
               Command2$ = RTRIM$(HelpStruc(SearchHelp).CName)
               IF Command2$ = Command1$ THEN
                  Commands = Commands + 1
               END IF
            NEXT
            If Commands > 0 Then
               If Commands = 1 Then
                  Print "Delete ";Command1$;"(y/n)? ";
                  Var$ = KeyboardLine$
                  PRINT
                  If Lcase$(Var$) = "y" Then
                     FOR SearchHelp = 1 TO CurrentHelp
                        Command2$ = RTRIM$(HelpStruc(SearchHelp).CName)
                        IF Command2$ = Command1$ THEN
                           EXIT FOR
                        END IF
                     NEXT
                     For Var = SearchHelp To CurrentHelp - 1
                        HelpStruc(Var).CName = HelpStruc(Var + 1).CName
                        HelpStruc(Var).Filename = HelpStruc(Var + 1).Filename
                     Next
                     CurrentHelp = CurrentHelp - 1
                     PRINT "Command deleted."
                     Color 15,0
                     PRINT "More:";
                     Char$ = ""
                     WHILE Char$ = ""
                        Char$ = INKEY$
                        CALL Release.Time(1)
                     WEND
                     PRINT
                  Endif
               Else
                  Print "Delete ";Command1$;"(1-";Mid$(Str$(Commands),2);")? ";
                  Var$ = KeyboardLine$
                  PRINT
                  Var = Val(Var$)
                  If Var > 0 And Var <= Commands Then
                     Commands = 0
                     FOR SearchHelp = 1 TO CurrentHelp
                        Command2$ = RTRIM$(HelpStruc(SearchHelp).CName)
                        IF Command2$ = Command1$ THEN
                           Commands = Commands + 1
                           If Commands = Var Then
                              For Var = SearchHelp To CurrentHelp - 1
                                 HelpStruc(Var).CName = HelpStruc(Var + 1).CName
                                 HelpStruc(Var).Filename = HelpStruc(Var + 1).Filename
                              Next
                              CurrentHelp = CurrentHelp - 1
                              PRINT "Command deleted."
                              Color 15,0
                              PRINT "More:";
                              Char$ = ""
                              WHILE Char$ = ""
                                 Char$ = INKEY$
                                 CALL Release.Time(1)
                              WEND
                              PRINT
                              exit for
                           Endif
                        END IF
                     NEXT
		  END IF
	       END IF
            END IF
	 END IF
      END IF
   CASE 5 ' search filespec
      COLOR 15, 0
      PRINT "Enter pathname\filespec:";
      Filespec1$ = KeyboardLine$
      PRINT
      Line.Count = 2
      Total.Bytes# = 0#
      Total.Dirs# = 0#
      Total.Files# = 0#
      GOSUB DisplayHeader
      VarQ3=0

      ' check dirs/files
      For VarQ=1 To 2

         ' restore directory search dta
         InregsX.AX = &H1A00
         InregsX.DS = VARSEG(DTAfile)
         InregsX.DX = VARPTR(DTAfile)
         Call InterruptX(&H21,InregsX,OutregsX)

         ' find first filename
         ASCIIZ = Filespec1$ + CHR$(0)
         InregsX.AX = &H4E00
         InregsX.CX = &H37 ' directory/filename bitmask
         InregsX.DS = VARSEG(ASCIIZ)
         InregsX.DX = VARPTR(ASCIIZ)
         Call InterruptX(&H21,InregsX,OutregsX)

         ' check carry flag
         IF (OutregsX.Flags AND &H1) = &H0 THEN
            VarQ3=-1
            Continuous = 0
            DO
               COLOR 14, 0
               GOSUB DisplayFile
               If Continuous = 0 Then
                  IF Line.Count = Max.Row-2 THEN
                     Line.Count = 2
                     COLOR 14, 0
                     PRINT "More(y/n/c):";
                     Quit=0
                     DO
                        Char$ = ""
                        WHILE Char$ = ""
                           Char$ = INKEY$
                           CALL Release.Time(1)
                        WEND
                        Select Case Ucase$(Char$)
                        Case "N"
                           Line.Count = 0
                           Quit=-1
                           EXIT DO
                        Case "C"
                           Continuous = -1
                           Exit Do
                        Case " ", "Y", Chr$(13)
                           Exit Do
                        END Select
                     LOOP
                     PRINT
                     If Quit Then
                        Exit Do
                     Endif
                     GOSUB DisplayHeader
                  END IF
               Endif

               ' find next filename
               InregsX.AX = &H4F00
               Call InterruptX(&H21,InregsX,OutregsX)

               ' check carry flag
               IF (OutregsX.Flags AND &H1) = &H1 THEN
                  EXIT DO
               END IF
               CALL Release.Time(1)
            LOOP
         END IF

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

         ' check break flags
         If Quit Then
            Exit For
         Endif
      Next

      Gosub PrintTotals
      COLOR 14, 0
      PRINT "More:";
      WHILE INKEY$ = ""
         CALL Release.Time(1)
      WEND
      PRINT
   CASE 6 ' sort
      FOR Command1 = 1 TO CurrentHelp - 1
         FOR Command2 = Command1 + 1 TO CurrentHelp
            Command1$ = RTRIM$(HelpStruc(Command1).CName)
            Command2$ = RTRIM$(HelpStruc(Command2).CName)
            IF Command1$ > Command2$ THEN
               SWAP HelpStruc(Command1), HelpStruc(Command2)
	    END IF
	 NEXT
      NEXT
      PRINT "Commands sorted."
   CASE 7 ' write
      DO
         PRINT "Write "; Filename$; " to disk(y/n)? ";
         Char$ = KeyboardLine$
         PRINT
         Char$ = UCASE$(Char$)
         IF Char$ = "Y" THEN
            GOSUB WriteFile
	    EXIT DO
	 END IF
         IF Char$ = "N" THEN
	    EXIT DO
	 END IF
         IF Char$ = Nul THEN
	    EXIT DO
	 END IF
         CALL Release.Time(1)
      LOOP
   CASE 8 ' quit
      DO
         PRINT "Write "; Filename$; " to disk(y/n)? ";
         Char$ = KeyboardLine$
         PRINT
         Char$ = UCASE$(Char$)
         IF Char$ = "Y" THEN
            GOSUB WriteFile
	    EXIT DO
	 END IF
         IF Char$ = "N" THEN
	    EXIT DO
	 END IF
         IF Char$ = Nul THEN
	    EXIT DO
	 END IF
         CALL Release.Time(1)
      LOOP
      EXIT DO
   END SELECT
LOOP

' close and kill all temp files
CLOSE
Filename2$ = VarZ$ + "\CONTENTD.HLP"
IF DIR$(Filename2$)<>"" THEN
   KILL Filename2$
END IF
Filename2$ = VarZ$ + "\CONTENTS.HLP"
IF DIR$(Filename2$)<>"" THEN
   KILL Filename2$
END IF
File2$ = RTRIM$(VarZ$) + "\DND*.HLP"
Filename2$ = DIR$(File2$)
DO WHILE LEN(Filename2$)
   Filename3$ = VarZ$ + "\" + Filename2$
   KILL Filename3$
   Filename2$ = DIR$
LOOP
ON ERROR RESUME NEXT
IF NodeX <> "" THEN
   RMDIR VarZ$
END IF

' terminate program
TempX$ = SPACE$(79)
CALL Display.Status.Line(0, TempX$)
COLOR 7
CLS
Call Save.Screen(-1)
'Locate Max.Row,1,1
If TempX2=0 Then TempX2=1
Locate TempX2,1,1
Print
Color 15
PRINT "Exiting Help Editor."
COLOR 7
END

MainError:
 COLOR 7
 CLS
 Locate Max.Row,1,1
 Print
 Color 15
 PRINT "Help Editor v1.4a:"
 COLOR 14, 0
 PRINT
 Var=Err
 Call Error.String(Var,Var$)
 Print Var$ + "."
 TempX$ = SPACE$(79)
 CALL Display.Status.Line(0, TempX$)
 Color 15
 PRINT "Exiting Help Editor."
 Color 7
 END

MainError2:
 COLOR 7
 CLS
 Locate Max.Row,1,1
 Print
 Color 15
 PRINT "Help Editor v1.4a:"
 COLOR 14, 0
 PRINT
 Print "\Temp"+Rtrim$(NodeX)+" files already exist. Use another command line node,"
 Print "or delete \Temp"+Rtrim$(NodeX)+"\*.hlp"
 TempX$ = SPACE$(79)
 CALL Display.Status.Line(0, TempX$)
 Color 15
 PRINT "Exiting Help Editor."
 Color 7
 END

' write out help.dat/dmhelp.dat
WriteFile:
 CLOSE
 IF DIR$(Filename$) <> "" THEN
    KILL Filename$
 END IF
 OPEN Filename$ FOR RANDOM SHARED AS #1 LEN = HelpRecLen
 HelpRecord.NextRecNum = 0
 HelpRecord.CommandName = ""
 Text$ = CHR$(13) + CHR$(10)
 If EditFile Then
    Text$ = Text$ + "This file contains DM help text for Dndbbs !Help command v5.0+"
 Else
    Text$ = Text$ + "This file contains help text for Dndbbs Help command v5.0+"
 Endif
 Text$ = Text$ + CHR$(13) + CHR$(10) + CHR$(26)
 HelpRecord.Text = Text$
 PUT 1, 1, HelpRecord
 Rec! = 1!
 Header = 0
 LineCount = 0
 FOR Command.Count = 1 TO CurrentHelp
    Command1$ = HelpStruc(Command.Count).CName
    HelpRecord.CommandName = Command1$
    File2$ = HelpStruc(Command.Count).Filename
    CLOSE #2
    Filename2$ = RTRIM$(VarZ$) + "\" + File2$
    OPEN Filename2$ FOR INPUT AS #2
    LineHeader = 0
    DO
       IF EOF(2) THEN EXIT DO
       LINE INPUT #2, Text$
       Text$=Rtrim$(Text$)
       If Len(Text$)>78 Then
          If LineHeader = 0 Then
             LineHeader = -1
             If Header = 0 Then
                PRINT "Lines greater than 78 characters truncated in the commands:"
                Header = -1
             Endif
          Endif
          Print Command1$;
          LineCount = LineCount + 1
          If LineCount = 5 Then
             Print
             LineCount = 0
          Else
             Print " ";
          Endif
       Endif
       HelpRecord.Text = Text$
       Rec! = Rec! + 1!
       PUT 1, Rec!, HelpRecord
    LOOP
 NEXT
 CLOSE
 If LineCount Then
    Print
 Endif
 PRINT Filename$; " written to disk."
RETURN

' display list header
DisplayHeader:
 COLOR 15, 0
 PRINT "Filename      Date        Time      Size         Attr"
 PRINT "------------  ----------  --------  -----------  ----"
 Color 14, 0
 RETURN

' display a directory/filename/datetime/filesize/fileattr
DisplayFile:

 ' check directory/filename
 VarQ2=0
 Attribute = ASC(DTAfile.FileAttr)
 IF (Attribute AND &H10) = &H10 THEN
    If VarQ=1 Then
       VarQ$ = "<DIR>"
       Total.Dirs# = Total.Dirs# + 1#
       VarQ2=-1
    Endif
 ELSE
    If VarQ=2 Then
       ' store file size
       File.Size# = ASC(MID$(DTAfile.FileSize, 4, 1))
       File.Size# = File.Size# * &H100 + ASC(MID$(DTAfile.FileSize, 3, 1))
       File.Size# = File.Size# * &H100 + ASC(MID$(DTAfile.FileSize, 2, 1))
       File.Size# = File.Size# * &H100 + ASC(MID$(DTAfile.FileSize, 1, 1))

       ' calculate filespec totals
       Total.Bytes# = Total.Bytes# + File.Size#
       Total.Files# = Total.Files# + 1#
       Call Make.Format(File.Size#, VarQ$)
       VarQ2=-1
    Endif
 END IF

 ' check display flag
 If VarQ2=0 Then
    Return
 Endif

 ' construct file date and time for display
 File.Work.Time = ASC(MID$(DTAfile.FileTime, 2, 1))
 File.Work.Time = File.Work.Time * &H100 + ASC(MID$(DTAfile.FileTime, 1, 1))
 File.Work.Date = ASC(MID$(DTAfile.FileDate, 2, 1))
 File.Work.Date = File.Work.Date * &H100 + ASC(MID$(DTAfile.FileDate, 1, 1))
 WorkHour = INT(File.Work.Time / 2048)
 WorkMinute = INT((File.Work.Time AND &H7E0) / 32)
 WorkSeconds = INT((File.Work.Time AND &H1F) / 2)
 WorkYear = INT(File.Work.Date / 512)
 WorkMonth = INT((File.Work.Date AND &H1E0) / 32)
 WorkDay = INT(File.Work.Date AND &H1F)
 WorkYear = WorkYear + 1980
 File.Date = RIGHT$(STR$(WorkMonth + 100), 2) + "-" + RIGHT$(STR$(WorkDay + 100), 2) + "-" + MID$(STR$(WorkYear), 2)
 File.Time = RIGHT$(STR$(WorkHour + 100), 2) + ":" + RIGHT$(STR$(WorkMinute + 100), 2) + ":" + RIGHT$(STR$(WorkSeconds + 100), 2)

 ' make display line
 File3$ = DTAfile.ASCIIZfilename
 File3$ = LEFT$(File3$, INSTR(File3$, CHR$(0)) - 1)
 File3$ = LCASE$(File3$)
 MID$(File3$, 1, 1) = UCASE$(MID$(File3$, 1, 1))
 Display.Line$ = File3$ + SPACE$(14 - LEN(File3$))
 VarQ$=Left$(VarQ$,12)
 VarQ$=Space$(12-Len(VarQ$))+VarQ$
 Display.Line$ = Display.Line$ + File.Date + "  " + File.Time + " " + VarQ$

 ' check attribute bits
 VarZ1$ = Space$(4)
 IF (Attribute AND 1) = 1 THEN ' read-only
    Mid$(VarZ1$,1,1)="O"
 END IF
 IF (Attribute AND 2) = 2 THEN ' hidden
    Mid$(VarZ1$,2,1)="H"
 END IF
 IF (Attribute AND 4) = 4 THEN ' system
    Mid$(VarZ1$,3,1)="S"
 END IF
 IF (Attribute AND &H20) = &H20 THEN ' archive
    Mid$(VarZ1$,4,1)="A"
 END IF
 VarZ1$ = "  " + VarZ1$
 VarZ1$ = Rtrim$(VarZ1$)

 ' make display line
 Display.Line$ = Display.Line$ + VarZ1$

 ' display filename info
 COLOR 14, 0
 PRINT Display.Line$
 Line.Count = Line.Count + 1
 RETURN

PrintTotals:
 Color 14,0
 If VarQ3=0 Then
    Print "No files found."
    Return
 Endif

 Color 15,0
 Print String$(12,"-") + Space$(24) + STRING$(11,"-")
 Call Amount(Total.Files#,Total.Line$)
 Total.Line$ = Ltrim$(Total.Line$)
 If Total.Files# = 1# Then
    Total.Line$ = Total.Line$ + " File  "
 Else
    Total.Line$ = Total.Line$ + " Files  "
 Endif
 Call Amount(Total.Dirs#,Var$)
 Var$ = Ltrim$(Var$)
 Total.Line$ = Total.Line$ + Var$
 If Total.Dirs# = 1# Then
    Total.Line$ = Total.Line$ + " Dir"
 Else
    Total.Line$ = Total.Line$ + " Dirs"
 Endif
 Total.Line$ = Left$(Total.Line$, 35)
 Total.Line$ = Total.Line$ + SPACE$(35 - LEN(Total.Line$))
 Call Make.Format(Total.Bytes#, Strng2$)
 Print Total.Line$ + Space$(12-Len(Strng2$)) + Strng2$
 Return

' display status line
SUB Display.Status.Line (Var, Var$)
 IF Var THEN
    COLOR 14, 1
 ELSE
    COLOR 15, 0
 END IF
 LOCATE Max.Row, 1, 0
 PRINT Var$;
 LOCATE Max.Row, 80
 IF Var THEN
    COLOR 0, 1
 ELSE
    COLOR 7, 0
 END IF
 PRINT " ";
 LOCATE Max.Row-1, 1, 1
 COLOR 15, 0
END SUB

' format error string
SUB Error.String(Var,Var$)
 On Local Error Goto ErrorS1
 SELECT CASE Var
 CASE 7
    Var$ = "Out of memory"
 CASE 9
    Var$ = "Subscript out of range"
 CASE 52
    Var$ = "Bad file name or number"
 CASE 53
    Var$ = "File not found"
 CASE 55
    Var$ = "File already open"
 CASE 57
    Var$ = "Device I/O error"
 CASE 61
    Var$ = "Disk full"
 CASE 62
    Var$ = "Input past eof"
 CASE 64
    Var$ = "Bad filename"
 CASE 67
    Var$ = "Not enough file handles"
 CASE 68
    Var$ = "Device unavailable"
 CASE 70
    Var$ = "Permission denied"
 CASE 71
    Var$ = "Disk not ready"
 CASE 76
    Var$ = "Pathname not found"
 CASE ELSE
    Var$ = "Untrapped error" + STR$(Var)
 END SELECT
ErrorR1:
 EXIT SUB
ErrorS1:
 Resume ErrorR1
END SUB

' display editor status line
SUB Edit.Status.Line
 TempX$ = "DND Editor <timeon: " + Fclock$ + ">"
 TempX$ = LEFT$(TempX$, 79)
 TempX$ = TempX$ + SPACE$(79 - LEN(TempX$))
 CALL Display.Status.Line(-1, TempX$)
END SUB

' read help data path\filename
SUB Get.Config (Var3$)
 ON LOCAL ERROR GOTO Config.Error
 NodeX=""
 HelpRecLen2 = LEN(HelpRecord2)
 DND.Path$ = ENVIRON$("DNDBBS")
 IF DND.Path$ <> "" THEN
    IF RIGHT$(DND.Path$, 1) <> "\" THEN
       DND.Path$ = DND.Path$ + "\"
    END IF
 END IF
 Filename2$ = DND.Path$ + "DND.CFG"
 CommandLine$ = Command$
 Select Case CommandLine$
 Case "?", "-?", "/?"
    Color 15,0
    Print "Helpedit v1.4a"
    Color 14,0
    Print " Edit help datafiles."
    Color 15,0
    Print "Command line:"
    Color 14,0
    Print " Helpedit [/linux] [<node>] [/DM]"
    Color 15,0
    Print "Where:"
    Color 14,0
    Print " /linux reads binary file."
    Print " node specifies optional config file 0-9,A-Z,10-99."
    Print " /DM overrides to dmhelp.dat file."
    Color 7,0
    End
 End Select
 Var = Instr(CommandLine$, "/DM")
 If Var THEN
    EditFile = -1
    CommandLine$ = Left$(CommandLine$, Var - 1) + Mid$(CommandLine$, Var + 3)
    CommandLine$ = Rtrim$(CommandLine$)
    CommandLine$ = Ltrim$(CommandLine$)
 Endif
 Var = Instr(CommandLine$, "/Z")
 If Var THEN
    Debug.Mode = -1
    CommandLine$ = Left$(CommandLine$, Var - 1) + Mid$(CommandLine$, Var + 2)
    CommandLine$ = Rtrim$(CommandLine$)
    CommandLine$ = Ltrim$(CommandLine$)
 Endif
 Var = Instr(CommandLine$, "/LINUX")
 If Var THEN
    Linux = -1
    CommandLine$ = Left$(CommandLine$, Var - 1) + Mid$(CommandLine$, Var + 7)
    CommandLine$ = Rtrim$(CommandLine$)
    CommandLine$ = Ltrim$(CommandLine$)
 Endif
 If Len(CommandLine$) Then
    Select Case Len(CommandLine$)
    Case 1 ' 0-9, A-Z
       Select Case CommandLine$
       Case "0" To "9"
          Eat$=""
       Case "A" To "Z"
          Eat$=""
       Case Else
          Goto Config.Error2
       End Select
    Case 2 ' 10-99
       VarQ = Int(Val(CommandLine$))
       If VarQ >= 10 And VarQ <= 99 Then
          Eat$ = ""
       Else
          Goto Config.Error2
       Endif
    Case Else
       Goto Config.Error2
    End Select
    NodeX = CommandLine$
    NodeX = Ltrim$(Rtrim$(NodeX)) : NodeX = Ucase$(NodeX)
    Filename2$ = DND.Path$ + "DND" + Ucase$(NodeX) + ".CFG"
 Endif
 CLOSE
 OPEN Filename2$ FOR INPUT SHARED AS #1
 LINE INPUT #1, Var$
 FOR Temp1 = 1 TO MaxConfigArray1
    INPUT #1, Var!
 NEXT
 FOR Temp1 = 1 TO MaxConfigArray2
    INPUT #1, Var%
 NEXT
 FOR Temp1 = 1 TO MaxConfigArray3
    LINE INPUT #1, Var$
    SELECT CASE Temp1
    CASE 11 ' \dnddat\
       Data.Path1$ = Var$
    CASE 15 ' .dat
       File.Extension1$ = Var$
    CASE 56
       IF EditFile = 0 THEN
          DataFile$ = Var$ ' help
       END IF
    CASE 63
       IF EditFile THEN
          DataFile$ = Var$ ' dmhelp
       END IF
    END SELECT
 NEXT
 Var3$ = Data.Path1$ + DataFile$ + File.Extension1$
Config.Resume:
 EXIT SUB
Config.Error:
 COLOR 7
' CLS
 Locate Max.Row,1,1
 Print
 Color 15
 PRINT "Help Editor v1.4a:"
 COLOR 14, 0
' PRINT
 Var=Err
 Call Error.String(Var,Var$)
 PRINT "Error '" + Lcase$(Var$) + "' loading " + Filename2$
 Color 15
 PRINT "Exiting Help Editor."
 Color 7
 END
Config.Error2:
 COLOR 7
' CLS
 Locate Max.Row,1,1
 Print
 Color 15
 PRINT "Help Editor v1.4a:"
 COLOR 14, 0
' PRINT
 PRINT "Error parsing command line."
 Color 15
 PRINT "Exiting Help Editor."
 Color 7
 END
END SUB

' main fullscreen editor
SUB Scrnedit (OutX$)
 ON LOCAL ERROR GOTO Error.Trap72
 CALL Edit.Status.Line
 Filename$ = ""
 DO
    Filename$ = OutX$
    If Left$(Filename$,1)=Chr$(34) Then
       Filename$=Mid$(Filename$,2)
       If Right$(Filename$,1)=Chr$(34) Then
          Filename$=Left$(Filename$,Len(Filename)-1)
       Endif
    Endif
    REDIM Temp.ArrayS(1024) AS STRING
    CLOSE #5
    IF DIR$(Filename$) <> "" THEN
       OPEN FileName$ FOR BINARY AS #5 ' read file in binary
       Max.Lines = 0
       Var! = 0!
       LineX = Nul
       DO
          Var! = Var! + 1!
          IF Var! > LOF(5) THEN
             If Len(LineX) Then
                Max.Lines = Max.Lines + 1
                IF Max.Lines > 1024 THEN
                   PRINT "File too large."
                   Filename$ = ""
                   EXIT DO
                END IF
                Temp.ArrayS(Max.Lines) = LineX
             Endif
             EXIT DO
          END IF
          GET #5, Var!, VarX
          LineFeed = 0
          If Linux Then
             IF VarX = CHR$(10) THEN
                LineFeed=-1
             END IF
          Endif
          IF VarX = CHR$(13) THEN
             IF Var! + 1! <= LOF(5) THEN
                GET #5, Var! + 1!, VarY
                IF VarY = CHR$(10) THEN
                   Var! = Var! + 1!
                   LineFeed=-1
                END IF
             END IF
          END IF
          IF LineFeed THEN
             Max.Lines = Max.Lines + 1
             IF Max.Lines > 1024 THEN
                PRINT "File too large."
                Filename$ = ""
                EXIT DO
             END IF
             Temp.ArrayS(Max.Lines) = LineX
             LineX = Nul
          ELSE
             Select Case Asc(VarX)
             Case 0, 7 To 13, 26 To 31 ' unprintable characters
                Eat$=""
             Case Else
                LineX = LineX + VarX
             End Select
          END IF
       LOOP
       ' file too large
       IF LEN(Filename$) = 0 THEN
          CLOSE
	  ERASE Temp.ArrayS
          Print "Use edit.com(y/n)? ";
          Out2$ = KeyboardLine$
          PRINT
          If Ucase$(Out2$)="Y" Then
             Filename$=OutX$
             Shell "Edit.com "+Filename$
          Endif
	  EXIT DO
       END IF
    END IF
    IF Max.Lines = 0 THEN
       Max.Lines = 1
       Line.Number = 1
    END IF
    Xcoor = 1
    Ycoor = 1
    Column = 1
    Row = 1
    Line.Number = 1
    Line.Length = 78
    GOSUB Display.Screen
    DO
       V = Column + Ycoor - 1
       Var# = Cdbl(Line.Number)
       If Var# = 0# Then
          Var$ = " 0"
       Else
          Call Amount(Var#,Var$)
       Endif
       If V = 0 Then
          Var2$ = " 0"
       Else
          Call Amount(Cdbl(V),Var2$)
       Endif
       Strng$ = "Row" + Var$ + " Column" + Var2$

       If V > 0 And V <= Len(Temp.ArrayS(Line.Number)) Then
          V2 = Asc(Mid$(Temp.ArrayS(Line.Number), V, 1))
          Strng$ = Strng$ + " Ascii" + Str$(V2)

          Select Case V2
          Case 0
             Strng$ = Strng$ + " (nul)"
          Case 1
             Strng$ = Strng$ + " (soh)"
          Case 2
             Strng$ = Strng$ + " (stx)"
          Case 3
             Strng$ = Strng$ + " (etx)"
          Case 4
             Strng$ = Strng$ + " (eot)"
          Case 5
             Strng$ = Strng$ + " (enq)"
          Case 6
             Strng$ = Strng$ + " (ack)"
          Case 7
             Strng$ = Strng$ + " (bel)"
          Case 8
             Strng$ = Strng$ + " (bs)"
          Case 9
             Strng$ = Strng$ + " (tab)"
          Case 10
             Strng$ = Strng$ + " (lf)"
          Case 11
             Strng$ = Strng$ + " (vt)"
          Case 12
             Strng$ = Strng$ + " (np)"
          Case 13
             Strng$ = Strng$ + " (cr)"
          Case 14
             Strng$ = Strng$ + " (so)"
          Case 15
             Strng$ = Strng$ + " (si)"
          Case 16
             Strng$ = Strng$ + " (dle)"
          Case 17
             Strng$ = Strng$ + " (dc1)"
          Case 18
             Strng$ = Strng$ + " (dc2)"
          Case 19
             Strng$ = Strng$ + " (dc3)"
          Case 20
             Strng$ = Strng$ + " (dc4)"
          Case 21
             Strng$ = Strng$ + " (nak)"
          Case 22
             Strng$ = Strng$ + " (syn)"
          Case 23
             Strng$ = Strng$ + " (etb)"
          Case 24
             Strng$ = Strng$ + " (can)"
          Case 25
             Strng$ = Strng$ + " (em)"
          Case 26
             Strng$ = Strng$ + " (eof)"
          Case 27
             Strng$ = Strng$ + " (esc)"
          Case 28
             Strng$ = Strng$ + " (fs)"
          Case 29
             Strng$ = Strng$ + " (gs)"
          Case 30
             Strng$ = Strng$ + " (rs)"
          Case 31
             Strng$ = Strng$ + " (us)"
          Case 32
             Strng$ = Strng$ + " (spc)"
          Case 255
             Strng$ = Strng$ + " (?)"
          Case Else
             Strng$ = Strng$ + " (" + Chr$(V2) + ")"
          End Select
       Endif
       Strng$ = Strng$ + SPACE$(41 - LEN(Strng$))
       COLOR 14, 1
       Locate Max.Row-1, 1
       PRINT Strng$;
       LOCATE Xcoor, Ycoor
       COLOR 15, 0
       TempX$ = ""
       DO WHILE TempX$ = ""
	  TempX$ = INKEY$
          CALL Release.Time(1)
       LOOP
       SELECT CASE LEN(TempX$)
       CASE 1
	  SELECT CASE TempX$
	  CASE CHR$(13) ' insert line
	     IF Max.Lines < 1024 THEN
                ' above
                IF Column + Ycoor - 1 = 1 THEN
                   FOR Temp1 = Max.Lines TO Line.Number STEP -1
                      Temp.ArrayS(Temp1 + 1) = Temp.ArrayS(Temp1)
                   NEXT
                   Temp.ArrayS(Line.Number) = Nul
                   Max.Lines = Max.Lines + 1
                   Line.Number = Line.Number + 1
                   IF Xcoor < Max.Row - 2 THEN
                      Xcoor = Xcoor + 1
                   END IF
                ELSE
                   ' below
                   IF Column + Ycoor - 1 > LEN(Temp.ArrayS(Line.Number)) THEN
                      Line.Number = Line.Number + 1 ' below
                      FOR Temp1 = Max.Lines TO Line.Number STEP -1
                         Temp.ArrayS(Temp1 + 1) = Temp.ArrayS(Temp1)
                      NEXT
                      Temp.ArrayS(Line.Number) = Nul
                      Max.Lines = Max.Lines + 1
                      IF Xcoor < Max.Row - 2 THEN
                         Xcoor = Xcoor + 1
                      END IF
                   ELSE
                      ' split line
                      FOR Temp1 = Max.Lines TO Line.Number + 1 STEP -1
                         Temp.ArrayS(Temp1 + 1) = Temp.ArrayS(Temp1)
                      NEXT
                      T$ = Temp.ArrayS(Line.Number)
                      U$ = MID$(T$, Column + Ycoor - 1)
                      T$ = LEFT$(T$, Column + Ycoor - 2)
                      Temp.ArrayS(Line.Number) = T$
                      Line.Number = Line.Number + 1 ' below
                      Temp.ArrayS(Line.Number) = U$
                      Max.Lines = Max.Lines + 1
                      IF Xcoor < Max.Row - 2 THEN
                         Xcoor = Xcoor + 1
                      END IF
                   END IF
                END IF
		Column = 1
		Ycoor = 1
		GOSUB Display.Screen
	     END IF
	  CASE CHR$(8) ' backspace
	     Q = Column + Ycoor - 1
             IF Line.Number <= 1 AND Q <= 1 THEN ' no backspace at 1,1
                Eat$ = Nul
	     ELSE
                ' remove current line
                IF Temp.ArrayS(Line.Number) = Nul THEN
                   ' pack array
                   FOR Temp1 = Line.Number TO Max.Lines - 1
                      Temp.ArrayS(Temp1) = Temp.ArrayS(Temp1 + 1)
                   NEXT
                   IF Xcoor > 1 THEN
                      Xcoor = Xcoor - 1
                   END IF
                   Line.Number = Line.Number - 1
                   Max.Lines = Max.Lines - 1
                   ' position at eol
                   End.Line = LEN(Temp.ArrayS(Line.Number))
                   IF End.Line >= 80 THEN
                      Column = End.Line - 78
                      Ycoor = End.Line - Column + 2
                   ELSE
                      Ycoor = End.Line - Column + 2
                   END IF
                   GOSUB Display.Screen
                ELSE
                   ' concatenate previous line
                   IF Column + Ycoor - 1 <= 1 THEN
                      IF Line.Number > 1 THEN
                         IF Line.Number <= Max.Lines THEN
                            Var=0
                            If Temp.ArrayS(Line.Number-1)=Nul Then
                               If Ycoor=1 Then
                                  Var=-1
                               Endif
                            Endif

                            ' position at eol
                            If Var=0 Then
                               End.Line = LEN(Temp.ArrayS(Line.Number-1))
                            Endif

                            Temp.ArrayS(Line.Number - 1) = Temp.ArrayS(Line.Number - 1) + Temp.ArrayS(Line.Number)
                            FOR Temp1 = Line.Number TO Max.Lines - 1
                               Temp.ArrayS(Temp1) = Temp.ArrayS(Temp1 + 1)
                            NEXT
                            If Xcoor > 1 Then
                               Xcoor = Xcoor - 1
                            Endif
                            Line.Number = Line.Number - 1
                            Max.Lines = Max.Lines - 1
                            Column = 1
                            Ycoor = 1

                            ' position at eol
                            If Var=0 Then
                               IF End.Line >= 80 THEN
                                  Column = End.Line - 78
                                  Ycoor = End.Line - Column + 2
                               ELSE
                                  Ycoor = End.Line - Column + 2
                               END IF
                            Endif

                            GOSUB Display.Screen
                         END IF
                     END IF
                  ELSE
                      ' backspace 1 character
                      IF Column + Ycoor - 2 > False THEN
                         T$ = Temp.ArrayS(Line.Number)
                         T$ = LEFT$(T$, Column + Ycoor - 3) + MID$(T$, Column + Ycoor - 1)
                         Temp.ArrayS(Line.Number) = T$
                         ' move cursor 1 left
                         IF Ycoor > 1 THEN
                            Ycoor = Ycoor - 1
                            GOSUB Display.Screen
                         ELSE
                            IF Column > 1 THEN
                               Column = Column - 1
                               GOSUB Display.Screen
                            END IF
                         END IF
                      END IF
                   END IF
                END IF
             END IF
	  CASE CHR$(9) ' tab
	     IF Column + Ycoor + 7 <= LEN(Temp.ArrayS(Line.Number)) THEN
                IF Ycoor + 8 < 80 THEN
		   Ycoor = Ycoor + 8
		ELSE
		   Column = Column + 8
		   GOSUB Display.Screen
		END IF
	     ELSE ' end
                End.Line = LEN(Temp.ArrayS(Line.Number))
                IF End.Line >= 80 THEN
                   Column = End.Line - 78
                   Ycoor = End.Line - Column + 2
                   GOSUB Display.Screen
                ELSE
                   Ycoor = End.Line - Column + 2
                END IF
	     END IF
	  CASE CHR$(27) ' escape, exit editor
	     EXIT DO
	  CASE ELSE ' insert character
             SELECT CASE ASC(TempX$)
             CASE 12, 32 TO 126
                If Line.Number > 0 Then
                   T$ = Temp.ArrayS(Line.Number)
                   T$ = LEFT$(T$, Column + Ycoor - 2) + TempX$ + MID$(T$, Column + Ycoor - 1)
                   Temp.ArrayS(Line.Number) = T$
                   IF Column + Ycoor - 1 <= LEN(Temp.ArrayS(Line.Number)) THEN
                      IF Ycoor < 80 THEN
                         Ycoor = Ycoor + 1
                         GOSUB Display.Screen
                      ELSE
                         Column = Column + 1
                         GOSUB Display.Screen
                      END IF
                   END IF
                Endif
             END SELECT
	  END SELECT
       CASE 2
	  Temp = ASC(MID$(TempX$, 2, 1))
	  SELECT CASE Temp
	  CASE 15 ' shift-tab
	     IF Column + Ycoor - 8 > 0 THEN
		IF Column + Ycoor - 7 > 1 THEN
		   Ycoor = Ycoor - 7
		ELSE
		   IF Column > 8 THEN
		      Column = Column - 7
		      GOSUB Display.Screen
		   END IF
		END IF
	     ELSE ' home
		IF Column > 1 THEN
		   Column = 1
		   Ycoor = 1
		   GOSUB Display.Screen
		ELSE
		   Column = 1
		   Ycoor = 1
		END IF
	     END IF
          CASE 83, 147 ' delete/control-delete
	     Q = Column + Ycoor - 1
             ' no delete at 1,1
             IF (Line.Number <= 1 AND Q < 1) OR Max.Lines < 1 THEN
                Eat$ = Nul
	     ELSE
                ' remove line
                IF Temp.ArrayS(Line.Number) = Nul THEN
                   IF Line.Number = 1 AND Max.Lines = 1 THEN ' 1,1
                      Eat$ = Nul
                   ELSE
                      ' pack array
                      FOR Temp1 = Line.Number TO Max.Lines - 1
                         Temp.ArrayS(Temp1) = Temp.ArrayS(Temp1 + 1)
                      NEXT
                      IF Line.Number = Max.Lines THEN
                         Line.Number = Line.Number - 1
                         IF Xcoor > 1 THEN
                            Xcoor = Xcoor - 1
                         END IF
                      END IF
                      Max.Lines = Max.Lines - 1
                      Column = 1
                      Ycoor = 1
                      GOSUB Display.Screen
                   END IF
                ELSE
                   ' delete line
                   IF LEN(Temp.ArrayS(Line.Number))<1 THEN
                      Temp.ArrayS(Line.Number) = Nul
                      GOSUB Display.Screen
                   ELSE
                      ' concatenate line
                      IF Column + Ycoor - 1 > LEN(Temp.ArrayS(Line.Number)) THEN
                         If Line.Number + 1 <= Max.Lines Then
                            T$ = Temp.ArrayS(Line.Number)
                            T$ = T$ + Temp.ArrayS(Line.Number + 1)
                            Temp.ArrayS(Line.Number) = T$

                            ' pack array
                            FOR Temp1 = Line.Number + 1 TO Max.Lines - 1
                               Temp.ArrayS(Temp1) = Temp.ArrayS(Temp1 + 1)
                            NEXT
                            Max.Lines = Max.Lines - 1

                            GOSUB Display.SCreen
                         Endif
                      ELSE
                         ' delete character
                         T$ = Temp.ArrayS(Line.Number)
                         T$ = LEFT$(T$, Column + Ycoor - 2) + MID$(T$, Column + Ycoor)
                         Temp.ArrayS(Line.Number) = T$
                         GOSUB Display.Screen
                      END IF
                   END IF
                END IF
             END IF
	  CASE 71 ' home
	     IF Column > 1 THEN
		Column = 1
		Ycoor = 1
		GOSUB Display.Screen
	     ELSE
		Column = 1
		Ycoor = 1
	     END IF
	  CASE 79 ' end
	     End.Line = LEN(Temp.ArrayS(Line.Number))
             IF End.Line >= 80 THEN
		Column = End.Line - 78
		Ycoor = End.Line - Column + 2
		GOSUB Display.Screen
	     ELSE
		Ycoor = End.Line - Column + 2
	     END IF
          CASE 75, 155 ' left/alt-left
	     IF Ycoor > 1 THEN
		Ycoor = Ycoor - 1
	     ELSE
		IF Column > 1 THEN
		   Column = Column - 1
		   GOSUB Display.Screen
		END IF
	     END IF
          CASE 77, 157 ' right/alt-right
	     IF Column + Ycoor - 1 <= LEN(Temp.ArrayS(Line.Number)) THEN
                IF Ycoor < 80 THEN
		   Ycoor = Ycoor + 1
		ELSE
		   Column = Column + 1
		   GOSUB Display.Screen
		END IF
	     END IF
          CASE 72, 141, 152 ' up/ctrl-up/alt-up
	     Var = 0
	     IF Line.Number > 1 THEN
		Line.Number = Line.Number - 1
		IF Xcoor = 1 THEN
		   Var = -1
		ELSE
		   Xcoor = Xcoor - 1
		END IF
		End.Line = LEN(Temp.ArrayS(Line.Number)) + 1
		IF Column + Ycoor - 1 > End.Line THEN
		   Ycoor = End.Line - Column + 1
		   IF Ycoor <= 0 THEN
		      Ycoor = End.Line
		      IF Column > 1 THEN
			 Var = -1
		      END IF
		      Column = 1
		   END IF
		END IF
		IF Var THEN
		   GOSUB Display.Screen
		END IF
	     END IF
          CASE 80, 145, 160 ' down/ctrl-dn/alt-dn
	     Var = 0
             IF Line.Number < Max.Lines THEN
		Line.Number = Line.Number + 1
                IF Xcoor >= Max.Row - 3 THEN
		   Var = -1
                ELSE
		   Xcoor = Xcoor + 1
		END IF
		End.Line = LEN(Temp.ArrayS(Line.Number)) + 1
		IF Column + Ycoor - 1 > End.Line THEN
		   Ycoor = End.Line - Column + 1
		   IF Ycoor <= 0 THEN
		      Ycoor = End.Line
		      IF Column > 1 THEN
			 Var = -1
		      END IF
		      Column = 1
		   END IF
		END IF
		IF Var THEN
		   GOSUB Display.Screen
		END IF
	     END IF
          CASE 73, 132 ' pageup/ctrl-pageup
	     IF Line.Number > 1 THEN
                IF Line.Number - 22 > 1 THEN
                   Line.Number = Line.Number - 22
		ELSE
		   Line.Number = 1
		END IF
		Xcoor = 1
		End.Line = LEN(Temp.ArrayS(Line.Number)) + 1
		IF Column + Ycoor - 1 > End.Line THEN
		   Ycoor = End.Line - Column + 1
		   IF Ycoor <= 0 THEN
		      Ycoor = End.Line
		      IF Column > 1 THEN
			 Var = -1
		      END IF
		      Column = 1
		   END IF
		END IF
		GOSUB Display.Screen
	     END IF
          CASE 81, 118 ' pagedown/ctrl-pagedn
	     IF Line.Number < Max.Lines THEN
		IF Line.Number + 22 < Max.Lines THEN
		   Line.Number = Line.Number + 22
                   Xcoor = 1
		ELSE
		   Line.Number = Max.Lines
                   IF Max.Lines < Max.Row - 3 THEN
                      Xcoor = Max.Lines
                   ELSE
                      Xcoor = Max.Row - 3
                   END IF
		END IF
		End.Line = LEN(Temp.ArrayS(Line.Number)) + 1
		IF Column + Ycoor - 1 > End.Line THEN
		   Ycoor = End.Line - Column + 1
		   IF Ycoor <= 0 THEN
		      Ycoor = End.Line
		      IF Column > 1 THEN
			 Var = -1
		      END IF
		      Column = 1
		   END IF
		END IF
		GOSUB Display.Screen
	     END IF
	  CASE 116 ' control-right
             IF Column + Ycoor - 1 > LEN(Temp.ArrayS(Line.Number)) THEN ' eol
                If Line.Number + 1 <= Max.Lines Then
                   Line.Number = Line.Number + 1
                   IF Xcoor = Max.Row - 3 THEN
                      Var = True
                   ELSE
                      Xcoor = Xcoor + 1
                   END IF
                   Ycoor = 1
                   Column = 1
                   GOSUB Display.Screen
                Endif
             Else
                P = 0
                FOR Temp2 = Column + Ycoor - 1 TO LEN(Temp.ArrayS(Line.Number))
                   P = P + 1
                   IF MID$(Temp.ArrayS(Line.Number), Temp2, 1) = " " THEN
                      IF MID$(Temp.ArrayS(Line.Number), Temp2 + 1, 1) <> " " THEN
                         EXIT FOR
                      END IF
                   END IF
                NEXT
                'shift right
                FOR Var3 = 1 TO P
                   IF Ycoor < 80 THEN
                      Ycoor = Ycoor + 1
                   ELSE
                      Column = Column + 1
                   END IF
                NEXT
                GOSUB Display.Screen
             Endif
	  CASE 115 ' control-left
             If Column + Ycoor - 1 <= 1 Then
                If Line.Number > 1 Then
                   Line.Number = Line.Number - 1
                   IF Xcoor = 1 THEN
                      Var = True
                   ELSE
                      Xcoor = Xcoor - 1
                   END IF
                   End.Line = LEN(Temp.ArrayS(Line.Number))
                   IF End.Line >= 80 THEN
                      Column = End.Line - 78
                      Ycoor = End.Line - Column + 2
                   ELSE
                      Ycoor = End.Line - Column + 2
                   END IF
                   GOSUB Display.Screen
                Endif
             Else
                P = 0
                V = 0
                FOR Temp2 = Column + Ycoor - 3 TO 1 STEP -1
                   P = P + 1
                   IF MID$(Temp.ArrayS(Line.Number), Temp2, 1) = " " THEN
                      IF MID$(Temp.ArrayS(Line.Number), Temp2 + 1, 1) <> " " THEN
                         V = -1
                         EXIT FOR
                      END IF
                   END IF
                NEXT
                IF V = 0 THEN
                   P = P + 1
                END IF
                ' shift left
                FOR Var3 = 1 TO P
                   IF Ycoor > 1 THEN
                      Ycoor = Ycoor - 1
                   ELSE
                      IF Column > 1 THEN
                         Column = Column - 1
                      END IF
                   END IF
                NEXT
                GOSUB Display.Screen
             Endif
	  CASE 119 ' control-home
             If Max.Lines > 0 Then
                Line.Number = 1
                Xcoor = 1
                Ycoor = 1
                Column = 1
                GOSUB Display.Screen
             Endif
	  CASE 117 ' control-end
             If Max.Lines > 0 Then
                Line.Number = Max.Lines
                IF Max.Lines < Max.Row - 3 THEN
                   Xcoor = Max.Lines
                ELSE
                   Xcoor = Max.Row - 3
                END IF
                Ycoor = 1
                Column = 1
                GOSUB Display.Screen
             Endif
          CASE 82 ' insert
             If Line.Number > 0 Then
                Var = False
                Ascii$ = Nul
                Gosub Display.Ascii.Line
                Do
                   Var$ = Nul
                   Do
                      Var$ = Inkey$
                      If Len(Var$) Then
                         Exit Do
                      Endif
                      CALL Release.Time(1)
                   LOOP
                   If Len(Var$) = 1 Then
                      If Var$=Chr$(8) Then
                         If Len(Ascii$)>0 Then
                            Ascii$=Left$(Ascii$,Len(Ascii$)-1)
                            Gosub Display.Ascii.Line
                            Var=Var-1
                            Locate Max.Row-1, 26
                            Print Ascii$ + " ";
                            Locate Max.Row-1, 26
                            Print Ascii$;
                         Endif
                      Endif
                      If Var$=Chr$(13) Then
                         Exit Do
                      Endif
                      If Lcase$(Var$) = "x" Or Lcase$(Var$)="o" Or Lcase$(Var$)="b" Then
                         If Var=0 Then
                            Ascii$ = Ascii$ + Lcase$(Var$)
                            Gosub Display.Ascii.Line
                            Var = Var + 1
                            Locate Max.Row-1, 26 + Var
                            Strng$ = Lcase$(Var$)
                            Print Strng$;
                         Endif
                      Endif
                      If Lcase$(Var$) >= "a" And Lcase$(Var$) <= "f" Then
                         If Var>=1 And Var<3 Then
                            If Left$(Ascii$,1)="x" Then
                               Var = Var + 1
                               Locate Max.Row-1, 26 + Var
                               Strng$ = Var$
                               Print Strng$;
                               Ascii$ = Ascii$ + Var$
                            Endif
                         Endif
                      Endif
                      If Left$(Ascii$,1)="o" Then
                         If Var$ >= "0" And Var$ <= "7" Then
                            If Var<4 Then
                               Var = Var + 1
                               Locate Max.Row-1, 26 + Var
                               Strng$ = Var$
                               Print Strng$;
                               Ascii$ = Ascii$ + Var$
                            Endif
                         Endif
                      Else
                         If Left$(Ascii$,1)="b" Then
                            If Var$ = "0" Or Var$ = "1" Then
                               If Var<9 Then
                                  Var = Var + 1
                                  Locate Max.Row-1, 26 + Var
                                  Strng$ = Var$
                                  Print Strng$;
                                  Ascii$ = Ascii$ + Var$
                               Endif
                            Endif
                         Else
                            If Var$ >= "0" And Var$ <= "9" Then
                               If Var<3 Then
                                  Var = Var + 1
                                  Locate Max.Row-1, 26 + Var
                                  PRINT Var$;
                                  Ascii$ = Ascii$ + Var$
                               Endif
                            Endif
                         Endif
                      Endif
                   Endif
                LOOP
                COLOR 15, 0

                ' insert ascii character
                If Left$(Ascii$,1)="x" Then
                   Ascii.Value=Int(Val("&H"+Mid$(Ascii$,2)))
                Else
                   If Left$(Ascii$,1)="o" Then
                      Ascii.Value=Int(Val("&O"+Mid$(Ascii$,2)))
                   Else
                      If Left$(Ascii$,1)="b" Then ' binary
                         Ascii$=Mid$(Ascii$,2)
                         Gosub Binary.String
                      Else
                         Ascii.Value = Int(Val(Ascii$))
                      Endif
                   Endif
                Endif
                If Ascii.Value >= 0 And Ascii.Value <= 255 Then
                   Select Case Ascii.Value
                   Case 0, 7 To 13, 26 To 31 ' unprintable characters
                      Eat$=""
                   Case Else
                      TempX$ = Chr$(Ascii.Value)
                      T$ = Temp.ArrayS(Line.Number)
                      T$ = LEFT$(T$, Column + Ycoor - 2) + TempX$ + MID$(T$, Column + Ycoor - 1)
                      Temp.ArrayS(Line.Number) = T$

                      IF Column + Ycoor - 1 <= LEN(Temp.ArrayS(Line.Number)) THEN
                         IF Ycoor < 80 THEN
                            Ycoor = Ycoor + 1
                            GOSUB Display.Screen
                         ELSE
                            Column = Column + 1
                            GOSUB Display.Screen
                         END IF
                      END IF
                   End Select
                Endif
             Endif
	  END SELECT
       END SELECT
       CALL Release.Time(1)
    LOOP
    COLOR 15, 0
    CLS
    CALL Edit.Status.Line
    Locate Max.Row-1, 1
    DO
       Q = 0
       PRINT "Write "; Filename$; " to disk(y/n)? ";
       Char$ = KeyboardLine$
       PRINT
       Char$ = UCASE$(Char$)
       IF Char$ = "Y" THEN
          Q = -1
          EXIT DO
       END IF
       IF Char$ = "N" THEN
          EXIT DO
       END IF
       CALL Release.Time(1)
    LOOP
    IF Q THEN
       CLOSE #5
       If Dir$(FileName$)<>"" Then
          Kill FileName$
       Endif
       OPEN Filename$ FOR OUTPUT AS #5
       FOR Count = 1 TO Max.Lines
          PRINT #5, Temp.ArrayS(Count)
       NEXT
       PRINT "File stored to disk."
    END IF
    ERASE Temp.ArrayS
    EXIT DO
    CALL Release.Time(1)
 LOOP
 EXIT SUB

Display.Ascii.Line:
  COLOR 15, 1
  Locate Max.Row-1,1,1
  COLOR 15,1
  Strng$ = SPACE$(41)
  PRINT Strng$;
  Locate Max.Row-1,1,1
  If Left$(Ascii$,1)="x" Then
     Var2$ = "Enter 2-digit ascii code: " 
  Else
     If Left$(Ascii$,1)="o" Then
        Var2$ = "Enter 3-digit ascii code: " 
     Else
        If Left$(Ascii$,1)="b" Then
           Var2$ = "Enter 8-digit ascii code: "
        Else
           Var2$ = "Enter 3-digit ascii code: "
        Endif
     Endif
  Endif
  Var2$ = Var2$ + SPACE$(41 - LEN(Var2$))
  PRINT Var2$;
RETURN
Binary.String:
  Ascii.Value = False
  Binary.Power = False
  FOR Binary.Digit = LEN(Ascii$) TO 1 STEP -1
      OutX2$ = MID$(Ascii$, Binary.Digit, 1)
      SELECT CASE OutX2$
          CASE "0"
              ' nul
          CASE "1"
              Ascii.Value = Ascii.Value + 2 ^ Binary.Power
      END SELECT
      Binary.Power = Binary.Power + 1
  NEXT
RETURN

' redisplay editor screen
Display.Screen:
 COLOR 15, 0
 CLS
 LOCATE 1, 1
 Count = 0
 DO
    Count = Count + 1
    IF Count = Max.Row - 1 THEN
       EXIT DO
    END IF
    IF Count + Line.Number - Xcoor > Max.Lines THEN
       EXIT DO
    END IF
    LOCATE Count, 1
    Strng$ = MID$(Temp.ArrayS(Count + Line.Number - Xcoor), Column)
    IF LEN(Strng$) > 80 THEN
       Strng$ = LEFT$(Strng$, 80)
    END IF
    PRINT Strng$;
 LOOP
 IF Count < Max.Row-1 THEN
    LOCATE Count, 1
    PRINT "<end of file>";
 END IF
 COLOR 14, 1
 Locate Max.Row-1, 1
 PRINT SPACE$(78);
 COLOR 0, 1
 Locate Max.Row-1, 79, 0
 PRINT " ";
 Locate Max.Row-1, 80, 0
 PRINT " ";
 COLOR 15, 0
 CALL Edit.Status.Line
 RETURN
Error.Resume72:
 EXIT SUB
Error.Trap72:
 RESUME Error.Resume72
END SUB

Sub Release.Time(Var)
 On Local Error Goto Error.Trap6a
 If Supported.Call=False Then
    For Var1=1 To Var
       InregsX.AX=&H1680
       InregsX.BX=&H0000
       Call InterruptX(&H2F,InregsX,OutregsX)
       If (OutregsX.AX And &HFF)=&H80 Then
          Supported.Call=True
          Exit For
       Endif
    Next
 Endif
Error.Resume6a:
 Exit Sub
Error.Trap6a:
 Resume Error.Resume6a
End Sub

Sub Make.Format(Var#, Var$)
 On Local Error Goto ErrTrap13
 Var2#=Var#
 If Var2#<=0 Then
    Var$="0.00 B"
    Exit Sub
 Endif
 TempA=False
 Do
    If Var2#<1024# Then
       Exit Do
    Endif
    Var2#=Var2#/1024#
    TempA=TempA+1
    If TempA=8 Then
       Exit Do
    Endif
 Loop
 Strng$=Nul
 If TempA>=1 And TempA<=8 Then
    Strng$=Mid$("KMGTPEZY",TempA,1)
 Endif
 Var$=Format$(Var2#,"#,##0.00;;")+" "+Strng$+"B"
ErrResume13:
 Exit Sub
ErrTrap13:
 Resume ErrResume13
End Sub

Sub Read.Rows(Var)
 On Local Error Goto Error.Trap62x
 Temp1=60
 Locate 60,1,0
 Var=60
 Exit Sub
Next.Trap0:
 Temp1=50
 Locate 50,1,0
 Var=50
 Exit Sub
Next.Trap1:
 Temp1=43
 Locate 43,1,0
 Var=43
 Exit Sub
Next.Trap2:
 Var=25
Error.Resume62x:
 Exit Sub
Error.Trap62x:
 If Temp1=60 Then
    Resume Next.Trap0
 Endif
 If Temp1=50 Then
    Resume Next.Trap1
 Endif
 If Temp1=43 Then
    Resume Next.Trap2
 Endif
 Resume Error.Resume62x
End Sub

Sub Amount(Var#,Var$)
 If Var# = 0# Then
    Var$ = " 0"
 Else
    If Instr(Str$(Var#),"D") Then
       Var$=Str$(Var#)
    Else
       Var$=" "+Form$(Var#)
    Endif
 Endif
End Sub

Sub Save.Screen(Var)
 On Local Error Goto Error.Trap62
 If Var=False Then
    VarX3=(Max.Row-1)*80+80
    Redim Temp.ArrayY(VarX3) As Long
    Redim Temp.ArrayZ(VarX3) As Double
    For Var1=1 To Max.Row
       For Var2=1 To 80
          TempZ1=Screen(Var1,Var2)
          TempZ2=Screen(Var1,Var2,1)
          VarX2=(Var1-1)*80+Var2
          Temp.ArrayY(VarX2)=TempZ1
          Temp.ArrayZ(VarX2)=TempZ2
       Next
    Next
 Else
    Cls
    For VarQ=Max.Row To 1 Step -1
       For VarQ2=1 To 80
          VarX2=(VarQ-1)*80+VarQ2
          If Temp.ArrayY(VarX2)<>32 Then
             Goto Next.Line
          Endif
       Next
    Next
Next.Line:
    TempX2=VarQ
    For Var1=1 To VarQ ' Max.Row
       For Var2=1 To 80
          VarX2=(Var1-1)*80+Var2
          VarB=Int(Temp.ArrayZ(VarX2)/16)
          VarF=Temp.ArrayZ(VarX2) Mod 16
          TempZ1=Temp.ArrayY(VarX2)
          Locate Var1,Var2,0
          Color VarF,VarB
          Print Chr$(TempZ1);
       Next
    Next
 Endif
Error.Resume62:
 Exit Sub
Error.Trap62:
 Resume Error.Resume62
End Sub
