REM File: Dndsic4 for Dndbbs Version v5.0a Release r2.0 Tweak t6.0a

' get include files
REM $INCLUDE: 'DNDSIC.INC'

Function Form$(Var#)
 Form$=Format$(Var#,"#,##0")
End Function

' Timing functions
Function Timeit!
 t1$ = Format$(Now, "hh:mm:ss") ' seconds past midnight
 t1! = CSNG(INT(VAL(MID$(t1$, 1, 2))+.5)) * 3600! + CSNG(INT(VAL(MID$(t1$, 4, 2))+.5)) * 60! + CSNG(INT(VAL(MID$(t1$, 7, 2))+.5))
 Timeit!=t1!
End Function

Function Time.Elapsed(Start.Time!,Wait.Time!)
 On Local Error Goto Error.Trap8
 Elapsed.Time!=Timeit!-Start.Time!
 If Elapsed.Time!<SFalse Then
    Elapsed.Time!=Elapsed.Time!+86400!
 Endif
 If Elapsed.Time!>=Wait.Time! Then
    Time.Elapsed=True
 Else
    Time.Elapsed=False
 Endif
Error.Resume8:
 Exit Function
Error.Trap8:
 Resume Error.Resume8
End Function

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

Function FClock2$
 FClock2$=Format$(Now,"ddd dd mmm yyyy\, hh:mm:ss")
End Function

' tests if bytes to store in account exceed account byte limit
FUNCTION AccountLimit (Size#)
 On Local Error Goto Error.Trap11

 ' get total bytes in catalog account
 Program.Data$ = Current.Directory + Account + ".SIC\*.*"
 Bytes# = AsciizCount# (Program.Data$)

 ' compare total bytes in account to bytes to add to account
 IF Bytes# + Size# > CDBL(Max.Limit) * 1024# THEN
    AccountLimit = True
 ELSE
    AccountLimit = False
 END IF
Error.Resume11:
 Exit Function
Error.Trap11:
 Resume Error.Resume11
END FUNCTION

'Metric Suffixes:
'================
'Byte  (B)  - 1024^0  '  00x - FFx
'Kilo  (K)  - 1024^1
'Mega  (M)  - 1024^2
'Giga  (G)  - 1024^3
'Tera  (T)  - 1024^4
'Peta  (P)  - 1024^5
'Exa   (E)  - 1024^6
'Zetta (Z)  - 1024^7
'Yotta (Y)  - 1024^8

'experimental suffixes:
' SB     Superbyte 1024 YB
' DB     Duperbyte 1024 SB  1 MB YB
' XB     Xeabyte   1024 DB
' QB     Zeabyte   1024 XB  1 MB DB
' AB     Ackbyte   1024 QB
' UB     Ughbyte   1024 AB  1 MB QB
' LB     LowByte   1024 UB
' HB     HighByte  1024 LB  1 MB UB

' formats bytes to a string
FUNCTION ParseSize$ (Temp#)
 ' store bytes
 Temp2# = Temp#
 ' 1.#INF and -1.#INF and -1.#IND and 1#QNAN
 IF INSTR(Str$(Temp2#),"#") Then
    ParseSize$ = Ltrim$(Str$(Temp2#))
    Exit Function
 Endif
 IF Temp2# = 0# THEN
    ParseSize$ = "0 B."
    EXIT FUNCTION
 END IF
 ' store sign
 If Temp2# < 0# Then
    Sign = -1
    Temp2# = Abs(Temp2#)
 Endif
 ' reset type counter
 TempA = False
 ' divide by 1024 until less
 DO
    IF Temp2# >= 1024 THEN
       Temp2# = Temp2# / 1024#
       ' count type
       TempA = TempA + 1
       IF TempA = 17 THEN
          EXIT DO
       END IF
    ELSE
       EXIT DO
    END IF
 LOOP
 ' check overflow
 IF TempA>16 THEN
    VarX$=Ltrim$(Str$(Temp#))
    Var1$=Left$(VarX$,Instr(VarX$,"D")-1)
    Var2$=Mid$(VarX$,Instr(VarX$,"D"))
    If Instr(Var1$,".") Then Var1$=Left$(Var1$,Instr(Var1$,".")+2)
    ParseSize$=Var1$+Var2$ ' 1.23D100
    Exit Function
 Endif
 ' store type
 Strng2$ = Nul
 If TempA>=1 And TempA<=16 Then ' powers of 1024
    Strng2$=Mid$("KMGTPEZYSDXQAULH",TempA,1)
 Endif
 ' return formatted string
 VarX$ = FORMAT$(Temp2#, "#,##0.00") + " " + Strng2$ + "B."
 If Sign Then
    VarX$ = "-" + VarX$
 Endif
 ParseSize$ = VarX$
END FUNCTION

' replaces white spaces with blanks,
'   var=true skip blanks in quotes.
FUNCTION TTRIM$(Var$, Var)
 On Local Error Goto Error.Trap13
 VarX$ = Var$
 Temp = False
 DO
    Temp = Temp + 1
    IF Temp > LEN(VarX$) THEN
       EXIT DO
    END IF
    IF Var THEN
       IF MID$(VarX$, Temp, 1) = Quote$ THEN
          DO
             Temp = Temp + 1
             IF Temp > LEN(VarX$) THEN
                EXIT DO
             END IF
             IF MID$(VarX$, Temp, 1) = Quote$ THEN
                EXIT DO
             END IF
          LOOP
       END IF
    END IF
    FOR Blanks = 1 TO LEN(White.Space)
       IF MID$(VarX$, Temp, 1) = MID$(White.Space, Blanks, 1) THEN
          MID$(VarX$, Temp, 1) = " "
       END IF
    NEXT
 LOOP
 Temp = False
 DO
    Temp = Temp + 1
    IF Temp > LEN(VarX$) THEN
       EXIT DO
    END IF
    IF Var THEN
       IF MID$(VarX$, Temp, 1) = Quote$ THEN
          DO
             Temp = Temp + 1
             IF Temp > LEN(VarX$) THEN
                EXIT DO
             END IF
             IF MID$(VarX$, Temp, 1) = Quote$ THEN
                EXIT DO
             END IF
          LOOP
       END IF
    END IF
    IF MID$(VarX$, Temp, 2) = "  " THEN
       VarX$ = LEFT$(VarX$, Temp) + MID$(VarX$, Temp + 2)
       Temp = Temp - 1
    END IF
 LOOP
 TTRIM$ = VarX$
Error.Resume13:
 Exit Function
Error.Trap13:
 Resume Error.Resume13
END FUNCTION

' trim whitespaces from string
FUNCTION STRIM$ (Var$)
 On Local Error Goto Error.Trap14
 XVar$ = Var$
 DO
    Blanks = False
    FOR Count = 1 TO LEN(White.Space)
       IF LEFT$(XVar$, 1) = MID$(White.Space, Count, 1) THEN
          XVar$ = MID$(XVar$, 2)
          Blanks = True
       END IF
    NEXT
    IF Blanks = False THEN
       EXIT DO
    END IF
 LOOP
 DO
    Blanks = False
    FOR Count = 1 TO LEN(White.Space)
       IF RIGHT$(XVar$, 1) = MID$(White.Space, Count, 1) THEN
	  XVar$ = LEFT$(XVar$, LEN(XVar$) - 1)
          Blanks = True
       END IF
    NEXT
    IF Blanks = False THEN
       EXIT DO
    END IF
 LOOP
 STRIM$ = XVar$
Error.Resume14:
 Exit Function
Error.Trap14:
 Resume Error.Resume14
END FUNCTION

' replaces white spaces with nul,
' var = true; skip blanks in quotes
FUNCTION XTRIM$(Var$, Var)
 VarX$ = Var$
 Temp = False
 DO
    Temp = Temp + 1
    IF Temp > LEN(VarX$) THEN
       EXIT DO
    END IF
    IF Var THEN
       IF MID$(VarX$, Temp, 1) = Quote$ THEN
          DO
             Temp = Temp + 1
             IF Temp > LEN(VarX$) THEN
                EXIT DO
             END IF
             IF MID$(VarX$, Temp, 1) = Quote$ THEN
                EXIT DO
             END IF
          LOOP
       END IF
    END IF
    FOR Blanks = 1 TO LEN(White.Space)
       IF MID$(VarX$, Temp, 1) = MID$(White.Space, Blanks, 1) THEN
          VarX$ = LEFT$(VarX$, Temp - 1) + MID$(VarX$, Temp + 1)
          Temp = Temp - 1
          EXIT FOR
       END IF
    NEXT
 LOOP
 XTRIM$ = VarX$
END FUNCTION

' returns a randomized temporary filename.
' could be constructed from Date/Time.
FUNCTION TempName$
 On Local Error Goto Error.Trap15
 Var$ = Nul
 FOR Temp = 1 TO 8
    Var$ = Var$ + LTRIM$(STR$(INT(RND*9+1)))
 NEXT
 TempName$ = Var$
Error.Resume15:
 Exit Function
Error.Trap15:
 Resume Error.Resume15
END FUNCTION

' prepares program for analyze/run command
SUB Prepare.Program(Var%)
 ' check for storage
 IF Var% Then
    ' find temporary filename
    DO
       Temp.Filename$ = TempName$
       Filename = Temp.Filename$ + ".sc2"
       IF DIR$(Filename) = Nul THEN
          EXIT DO
       END IF
    LOOP
    ' write out current program
    Prepare.Filename = Filename
    CALL Store.Program
 Endif

 ' remove remark at end of line,
 '   search for end of matching double quotes
 '   which might contain a left apostrophe.
 CALL Count.Lines(Last.Line)
 FOR Program.Line = 1 TO Last.Line
    Out2 = STRIM$(Program(Program.Line))
    IF LEN(Out2) THEN
       Start.Char = 1
       DO
          Quote.Start = False
          FOR Temp = Start.Char TO LEN(Out2)
             IF MID$(Out2, Temp, 1) = Quote$ THEN
                Quote.Start = Temp
                EXIT FOR
             END IF
          NEXT
          IF Quote.Start = False THEN
             EXIT DO
          END IF
          Quote.Stop = False
          FOR Temp2 = Quote.Start + 1 TO LEN(Out2)
             IF MID$(Out2, Temp2, 1) = Quote$ THEN
                Quote.Stop = Temp2
                EXIT FOR
             END IF
          NEXT
          IF Quote.Stop = False THEN
             EXIT DO
          END IF
          Start.Char = Quote.Stop + 1
       LOOP
       FOR Temp = Start.Char TO LEN(Out2)
          IF MID$(Out2, Temp, 1) = "'" THEN
             Out2 = LEFT$(Out2, Temp - 1)
             EXIT FOR
          END IF
       NEXT
       Out2 = STRIM$(Out2)
       IF LEN(Out2) THEN
          Program(Program.Line) = Out2
       ELSE
          Program(Program.Line) = "REM"
       END IF
    END IF
 NEXT

 ' concatenate line continuation statements,
 '   replace continued lines with REM.
 Program.Line = False
 CALL Count.Lines(Last.Line)
 DO
    Program.Line = Program.Line + 1
    IF Program.Line > Last.Line THEN
       EXIT DO
    END IF
    IF Program.Line > Max.Lines THEN
       EXIT DO
    END IF
    First.Line = Program.Line
    Out2 = STRIM$(Program(Program.Line))
    IF LEN(Out2) THEN
       DO
          IF RIGHT$(Out2, 1) = "_" THEN
             WHILE RIGHT$(Out2, 1) = "_"
                Out2 = LEFT$(Out2, LEN(Out2) - 1)
                Out2 = RTRIM$(Out2)
             WEND
             FOR Next.Line = Program.Line + 1 TO Last.Line
                Out3 = STRIM$(Program(Next.Line))
                IF LEN(Out3) THEN
                   Out2 = Out2 + Out3
                   Program.Line = Next.Line
                   Program(Next.Line) = "REM"
                   EXIT FOR
                END IF
             NEXT
          ELSE
             EXIT DO
          END IF
          Out2 = STRIM$(Out2)
       LOOP
       Program(First.Line) = Out2
    END IF
 LOOP

 ' compress program array,
 '   replaces all white spaces with single space,
 '   replaces all double spaces with single space.
 Program.Line = False
 CALL Count.Lines(Last.Line)
 FOR Program.Line = 1 TO Last.Line
    Out2 = STRIM$(Program(Program.Line))
    IF LEN(Out2) THEN
       Program(Program.Line) = TTRIM$(Out2, True)
    ELSE
       Program(Program.Line) = Nul
    END IF
 NEXT
END SUB

' indents current .sic program
SUB Indent.Program
 On Local Error Goto Error.Trap15a
 DO While Lost.Carrier=False
    CALL More.Prompt("Indent with tabs or spaces(t/s/q)", "tsq", Output.Char$, "q")
    SELECT CASE Output.Char$
    CASE "t"
       Tabs = True
    CASE "s"
       Tabs = False
    CASE "q"
       EXIT SUB
    END SELECT
    Call Modem.ANSI(4,37,15)
    Call ScreenANSI(4,37,15)
    IF Tabs THEN
       Strng3 = "Enter number of tabs to indent?"
    ELSE
       Strng3 = "Enter number of spaces to indent?"
    END IF
    Call IO.I
    Increment = CINT(VAL(Out9))
    IF Increment > False Then
       EXIT DO
    END IF
 LOOP
 IF Lost.Carrier THEN
    EXIT SUB
 END IF
 IF Tabs THEN
    Strng3 = "Indenting with" + Str$(Increment) + " tabs."
 Else
    Strng3 = "Indenting with" + Str$(Increment) + " spaces."
 Endif
 Call IO.O
 Indent = False
 CALL Count.Lines(Last.Line)
 FOR Program.Line = 1 TO Last.Line
    IF Tabs THEN
       Number$ = CHR$(9)
    ELSE
       Number$ = SPACE$(6 - LEN(STR$(Program.Line)))
    END IF
    Out2 = Program(Program.Line)
    Out2 = STRIM$(Out2)
    IF LEN(Out2) THEN
       Temp1$ = STRIM$(Out2)
       Temp1$ = UCASE$(Temp1$)
       Temp1$ = TTRIM$(Temp1$, False)
       Next.Indent = False
       RESTORE Indent.Data
       DO
	  READ Keyword$, KeyIndent
	  IF Keyword$ = "EOF" THEN
	     EXIT DO
	  END IF
	  IF LEFT$(Temp1$, LEN(Keyword$)) = Keyword$ THEN
	     Next.Indent = KeyIndent
	     EXIT DO
	  END IF
       LOOP
       SELECT CASE Next.Indent
       CASE 1
	  Out2 = SPACE$(Indent * Increment) + STRIM$(Out2)
	  Indent = Indent + 1
       CASE -1
	  Indent = Indent - 1
	  IF Indent < False THEN
             Strng3 = "Indent error: Line:" + STR$(Program.Line)
             Call IO.O
	     EXIT FOR
	  END IF
	  Out2 = SPACE$(Indent * Increment) + STRIM$(Out2)
       CASE -2
	  Indent = Indent - 1
	  IF Indent < False THEN
             Strng3 = "Indent error: Line:" + STR$(Program.Line)
             Call IO.O
	     EXIT FOR
	  END IF
	  Out2 = SPACE$(Indent * Increment) + STRIM$(Out2)
	  Indent = Indent + 1
       CASE ELSE
	  Out2 = SPACE$(Indent * Increment) + STRIM$(Out2)
       END SELECT
       Out2 = Number$ + Out2
       Program(Program.Line) = Out2
    END IF
 NEXT
 IF Indent <> False THEN
    Strng3 = "Indent error: Line:"+Str$(Program.Line)+"."
 ELSE
    Strng3 = "Program indented."
 END IF
 Call IO.O
Error.Resume15a:
 Exit Sub
Error.Trap15a:
 Resume Error.Resume15a
END SUB

' renumbers current .sic program
SUB Renumber.Program
 On Local Error Goto Error.Trap15b
 DO While Lost.Carrier=False
    Call Modem.ANSI(4,37,15)
    Call ScreenANSI(4,37,15)
    Strng3 = "Starting line number(1-"+Mid$(Str$(Max.Lines),2)+")? "
    Call IO.I
    IF Out9=Nul THEN
       EXIT SUB
    END IF
    Start.Line = CINT(VAL(Out9))
    IF Start.Line <= False OR Start.Line > Max.Lines THEN
       Call Modem.ANSI(4,33,14)
       Call ScreenANSI(4,33,14)
       Strng3 = "Bad start line value."
       Call IO.O
    ELSE
       EXIT DO
    END IF
 LOOP
 DO While Lost.Carrier=False
    Call Modem.ANSI(4,37,15)
    Call ScreenANSI(4,37,15)
    Strng3 = "Increment value(1-"+Mid$(Str$(Int(Max.Lines/2)),2)+")? "
    Call IO.I
    IF Out9=Nul THEN
       EXIT SUB
    END IF
    Increment = CINT(VAL(Out9))
    IF Increment <= False OR Increment > INT(Max.Lines / 2) THEN
       Call Modem.ANSI(4,33,14)
       Call ScreenANSI(4,33,14)
       Strng3 = "Bad increment value."
       Call IO.O
    ELSE
       EXIT DO
    END IF
 LOOP
 IF Lost.Carrier THEN
    EXIT SUB
 END IF
 CALL Count.Lines(Last.Line)
 Running.Program = Program.Name
 REDIM Renumber.List(1 TO Max.Lines) AS INTEGER

 ' find temporary filename
 DO
    Temp.Filename$ = TempName$
    Renumber.Filename$ = Temp.Filename$ + ".sc1"
    IF DIR$(Renumber.Filename$) = Nul THEN
       EXIT DO
    END IF
 LOOP

 ' start renumber
 Filename = Renumber.Filename$
 CALL Store.Program
 New.Line.Number = Start.Line
 FOR Line.Number = 1 TO Last.Line
    ProgramLine$ = Program(Line.Number)
    IF STRIM$(ProgramLine$) <> Nul THEN
       IF New.Line.Number > Max.Lines THEN
          Call Modem.ANSI(4,37,15)
          Call ScreenANSI(4,37,15)
          Strng3 = "Renumber list exceeds " + Form$(Cdbl(Max.Lines)) + " lines."
          Call IO.O
	  ERASE Renumber.List
          CLOSE #TempFile2
          Filename=Renumber.Filename$
          If Dir$(Filename)<>"" Then
             Kill Filename
          Endif
	  EXIT SUB
       END IF
       Renumber.List(New.Line.Number) = Line.Number
       New.Line.Number = New.Line.Number + Increment
    END IF
 NEXT
 Strng3 = "Renumbering program."
 Call IO.O
 FOR Line.Number = 1 TO Last.Line
    New.Program.Line$ = Program(Line.Number)
    Old.Program.Line$ = Program(Line.Number)
    Old.Program.Line$ = STRIM$(Old.Program.Line$)
    Old.Program.Line$ = TTRIM$(Old.Program.Line$, True)
    IF Old.Program.Line$ <> Nul THEN
       Line.Renumbered = True
       IF UCASE$(LEFT$(Old.Program.Line$, 7)) = "RESTORE" THEN
          V$ = RTRIM$(MID$(Old.Program.Line$, 8))
          IF LEN(V$) THEN
             IF INT(VAL(V$)+.5) > 0 THEN
                Line.Renumbered = False
                Imbedded = INSTR(UCASE$(New.Program.Line$), "RESTORE") + 7
                GOSUB Next.Space
                Number$ = MID$(Old.Program.Line$, 8)
                Number$ = STRIM$(Number$)
                Old.Line.Number = CINT(VAL(Number$))
                IF Old.Line.Number > False AND Old.Line.Number <= Max.Lines THEN
                   FOR New.Line.Number = 1 TO Max.Lines
                      IF Renumber.List(New.Line.Number) = Old.Line.Number THEN
                         Program(Line.Number) = Next.Program.Line$ + LTRIM$(STR$(New.Line.Number))
                         Line.Renumbered = True
                         EXIT FOR
                      END IF
                   NEXT
                END IF
             END IF
          END IF
       END IF
       IF UCASE$(LEFT$(Old.Program.Line$, 4)) = "GOTO" THEN
	  Line.Renumbered = False
          Imbedded = INSTR(UCASE$(New.Program.Line$), "GOTO") + 4
          GOSUB Next.Space
	  Number$ = MID$(Old.Program.Line$, 5)
	  Number$ = STRIM$(Number$)
          Old.Line.Number = CINT(VAL(Number$))
          IF Old.Line.Number > False AND Old.Line.Number <= Max.Lines THEN
             FOR New.Line.Number = 1 TO Max.Lines
                IF Renumber.List(New.Line.Number) = Old.Line.Number THEN
                   Program(Line.Number) = Next.Program.Line$ + LTRIM$(STR$(New.Line.Number))
                   Line.Renumbered = True
                   EXIT FOR
                END IF
             NEXT
          END IF
       END IF
       IF UCASE$(LEFT$(Old.Program.Line$, 13)) = "ON ERROR GOTO" THEN
	  Line.Renumbered = False
          Imbedded = INSTR(UCASE$(New.Program.Line$), "GOTO") + 4
          GOSUB Next.Space
	  Number$ = MID$(Old.Program.Line$, 14)
	  Number$ = STRIM$(Number$)
          Old.Line.Number = CINT(VAL(Number$))
          IF Old.Line.Number > False AND Old.Line.Number <= Max.Lines THEN
             FOR New.Line.Number = 1 TO Max.Lines
                IF Renumber.List(New.Line.Number) = Old.Line.Number THEN
                   Program(Line.Number) = Next.Program.Line$ + LTRIM$(STR$(New.Line.Number))
                   Line.Renumbered = True
                   EXIT FOR
                END IF
             NEXT
          END IF
       END IF
       IF UCASE$(LEFT$(Old.Program.Line$, 6)) = "RESUME" THEN
	  IF UCASE$(LEFT$(Old.Program.Line$, 15)) <> "RESUME PREVIOUS" THEN
	     IF UCASE$(LEFT$(Old.Program.Line$, 11)) <> "RESUME SAME" THEN
		IF UCASE$(LEFT$(Old.Program.Line$, 11)) <> "RESUME NEXT" THEN
		   Line.Renumbered = False
                   Imbedded = INSTR(UCASE$(New.Program.Line$), "RESUME") + 6
                   GOSUB Next.Space
		   Number$ = MID$(Old.Program.Line$, 7)
		   Number$ = STRIM$(Number$)
                   Old.Line.Number = CINT(VAL(Number$))
                   IF Old.Line.Number > False AND Old.Line.Number <= Max.Lines THEN
                      FOR New.Line.Number = 1 TO Max.Lines
                         IF Renumber.List(New.Line.Number) = Old.Line.Number THEN
                            Program(Line.Number) = Next.Program.Line$ + LTRIM$(STR$(New.Line.Number))
                            Line.Renumbered = True
                            EXIT FOR
                         END IF
                      NEXT
                   END IF
		END IF
	     END IF
	  END IF
       END IF
       IF UCASE$(LEFT$(Old.Program.Line$, 5)) = "GOSUB" THEN
	  Line.Renumbered = False
          Imbedded = INSTR(UCASE$(New.Program.Line$), "GOSUB") + 5
          GOSUB Next.Space
	  Number$ = MID$(Old.Program.Line$, 6)
	  Number$ = STRIM$(Number$)
          Old.Line.Number = CINT(VAL(Number$))
          IF Old.Line.Number > False AND Old.Line.Number <= Max.Lines THEN
             FOR New.Line.Number = 1 TO Max.Lines
                IF Renumber.List(New.Line.Number) = Old.Line.Number THEN
                   Program(Line.Number) = Next.Program.Line$ + LTRIM$(STR$(New.Line.Number))
                   Line.Renumbered = True
                   EXIT FOR
                END IF
             NEXT
          END IF
       END IF
       IF UCASE$(LEFT$(Old.Program.Line$, 2)) = "ON" THEN
	  IF UCASE$(LEFT$(Old.Program.Line$, 8)) <> "ON ERROR" THEN
	     Line.Renumbered = False
             IF INSTR(UCASE$(Old.Program.Line$), "GOTO") THEN
                Imbedded = INSTR(UCASE$(New.Program.Line$), "GOTO") + 4
                Old.Number1$ = LTRIM$(MID$(New.Program.Line$, Imbedded))
                GOSUB Next.Space
                New.Program.Line1$ = Next.Program.Line$
                Imbedded2 = INSTR(UCASE$(Old.Program.Line$), "GOTO")
                Old.Number2$ = MID$(Old.Program.Line$, Imbedded2 + 4)
		DO
                   Imbedded1 = INSTR(Old.Number1$, ",")
                   IF Imbedded1 THEN
                      New.Number1$ = LEFT$(Old.Number1$, Imbedded1 - 1)
                      Old.Number1$ = MID$(Old.Number1$, Imbedded1 + 1)
		   ELSE
                      New.Number1$ = Old.Number1$
                      Old.Number1$ = Nul
		   END IF
                   IF INSTR(White.Space, MID$(New.Number1$, 1, 1)) THEN
                      Imbedded = 1
                      New.Program.Line$ = New.Number1$
                      GOSUB Next.Space
                      New.Number1$ = Next.Program.Line$
                   ELSE
                      New.Number1$ = Nul
                   END IF
                   Imbedded2 = INSTR(Old.Number2$, ",")
                   IF Imbedded2 THEN
                      New.Number2$ = LEFT$(Old.Number2$, Imbedded2 - 1)
                      Old.Number2$ = MID$(Old.Number2$, Imbedded2 + 1)
		   ELSE
                      New.Number2$ = Old.Number2$
                      Old.Number2$ = Nul
		   END IF
		   Line.Renumbered = False
                   Old.Line.Number = CINT(VAL(New.Number2$))
                   IF Old.Line.Number > False AND Old.Line.Number <= Max.Lines THEN
                      FOR New.Line.Number = 1 TO Max.Lines
                         IF Renumber.List(New.Line.Number) = Old.Line.Number THEN
                            New.Program.Line1$ = New.Program.Line1$ + New.Number1$ + LTRIM$(STR$(New.Line.Number)) + ","
                            Line.Renumbered = True
                            EXIT FOR
                         END IF
                      NEXT
                   END IF
                   IF Old.Number2$ = Nul THEN
		      EXIT DO
		   END IF
		   IF Line.Renumbered = False THEN
		      EXIT DO
		   END IF
		LOOP
                IF RIGHT$(New.Program.Line1$, 1) = "," THEN
                   New.Program.Line1$ = LEFT$(New.Program.Line1$, LEN(New.Program.Line1$) - 1)
                END IF
                Program(Line.Number) = New.Program.Line1$
	     ELSE
                IF INSTR(UCASE$(Old.Program.Line$), "GOSUB") THEN
                   Imbedded = INSTR(UCASE$(New.Program.Line$), "GOSUB") + 5
                   Old.Number1$ = LTRIM$(MID$(New.Program.Line$, Imbedded))
                   GOSUB Next.Space
                   New.Program.Line1$ = Next.Program.Line$
                   Imbedded2 = INSTR(UCASE$(Old.Program.Line$), "GOSUB")
                   Old.Number2$ = MID$(Old.Program.Line$, Imbedded2 + 5)
                   DO
                      Imbedded1 = INSTR(Old.Number1$, ",")
                      IF Imbedded1 THEN
                         New.Number1$ = LEFT$(Old.Number1$, Imbedded1 - 1)
                         Old.Number1$ = MID$(Old.Number1$, Imbedded1 + 1)
                      ELSE
                         New.Number1$ = Old.Number1$
                         Old.Number1$ = Nul
                      END IF
                      IF INSTR(White.Space, MID$(New.Number1$, 1, 1)) THEN
                         Imbedded = 1
                         New.Program.Line$ = New.Number1$
                         GOSUB Next.Space
                         New.Number1$ = Next.Program.Line$
                      ELSE
                         New.Number1$ = Nul
                      END IF
                      Imbedded2 = INSTR(Old.Number2$, ",")
                      IF Imbedded2 THEN
                         New.Number2$ = LEFT$(Old.Number2$, Imbedded2 - 1)
                         Old.Number2$ = MID$(Old.Number2$, Imbedded2 + 1)
                      ELSE
                         New.Number2$ = Old.Number2$
                         Old.Number2$ = Nul
                      END IF
                      Line.Renumbered = False
                      Old.Line.Number = CINT(VAL(New.Number2$))
                      IF Old.Line.Number > False AND Old.Line.Number <= Max.Lines THEN
                         FOR New.Line.Number = 1 TO Max.Lines
                            IF Renumber.List(New.Line.Number) = Old.Line.Number THEN
                               New.Program.Line1$ = New.Program.Line1$ + New.Number1$ + LTRIM$(STR$(New.Line.Number)) + ","
                               Line.Renumbered = True
                               EXIT FOR
                            END IF
                         NEXT
                      END IF
                      IF Old.Number2$ = Nul THEN
                         EXIT DO
                      END IF
                      IF Line.Renumbered = False THEN
                         EXIT DO
                      END IF
                   LOOP
                   IF RIGHT$(New.Program.Line1$, 1) = "," THEN
                      New.Program.Line1$ = LEFT$(New.Program.Line1$, LEN(New.Program.Line1$) - 1)
                   END IF
                   Program(Line.Number) = New.Program.Line1$
                END IF
	     END IF
	  END IF
       END IF
       IF Line.Renumbered = False THEN
          Call Modem.ANSI(4,37,15)
          Call ScreenANSI(4,37,15)
          Strng3 = "Error renumbering program."
          Call IO.O
          Filename = Renumber.Filename$
          CALL Read.Program(Var,Var#)
          Program.Name = Running.Program
          Call Modem.ANSI(4,37,15)
          Call ScreenANSI(4,37,15)
          Strng3 = "Program reloaded."
          Call IO.O
	  ERASE Renumber.List
          Close
          Filename=Renumber.Filename$
          If Dir$(Filename)<>"" Then
             Kill Filename
          Endif
	  EXIT SUB
       END IF
    END IF
 NEXT
 Strng3 = "Resequencing line numbers."
 Call IO.O
 Filename = Renumber.Filename$
 CALL Store.Program
 CLOSE #TempFile2
 OPEN Renumber.Filename$ FOR INPUT AS #TempFile2
 CALL New.Program
 WHILE NOT EOF(TempFile2)
    LINE INPUT #TempFile2, New.Program.Line$
    FOR Blanks = 1 TO LEN(White.Space)
       Imbedded = INSTR(New.Program.Line$, MID$(White.Space, Blanks, 1))
       IF Imbedded THEN
          EXIT FOR
       END IF
    NEXT
    Old.Line.Number = CINT(VAL(LEFT$(New.Program.Line$, Imbedded - 1)))
    FOR New.Program.Line = 1 TO Max.Lines
       IF Renumber.List(New.Program.Line) = Old.Line.Number THEN
          Program(New.Program.Line) = MID$(New.Program.Line$, Imbedded)
	  EXIT FOR
       END IF
    NEXT
 WEND
 CLOSE
 Filename=Renumber.Filename$
 If Dir$(Filename)<>"" Then
    Kill Filename
 Endif
 Program.Name = Running.Program
 Call Modem.ANSI(4,37,15)
 Call ScreenANSI(4,37,15)
 Strng3 = "Program renumbered."
 Call IO.O
 ERASE Renumber.List
 EXIT SUB

' locates string with following white spaces
Next.Space:
 Next.Program.Line$ = New.Program.Line$
 DO
    IF Imbedded >= LEN(Next.Program.Line$) THEN
       EXIT DO
    END IF
    IF INSTR(White.Space, MID$(Next.Program.Line$, Imbedded + 1, 1)) THEN
       Imbedded = Imbedded + 1
    ELSE
       EXIT DO
    END IF
 LOOP
 Next.Program.Line$ = LEFT$(Next.Program.Line$, Imbedded)
 RETURN
Error.Resume15b:
 Exit Sub
Error.Trap15b:
 Strng3="Err:"+Str$(Err)
 Call IO.O
 Resume Error.Resume15b
END SUB

' declares indent structure types
Indent.Data:
 ' 1=indent right
 DATA "SELECTIF CASE", 1
 DATA "DO WHILE", 1
 DATA "DO", 1
 DATA "IF", 1
 DATA "SELECT CASE", 1
 DATA "DO UNTIL", 1
 DATA "FORIF", 1
 DATA "FOR", 1
 DATA "WHILE", 1
 DATA "LOOPIF", 1
 ' -1=indent left
 DATA "ENDIF", -1
 DATA "END IF", -1
 DATA "NEXTIF", -1
 DATA "NEXT", -1
 DATA "LOOP UNTIL", -1
 DATA "LOOP WHILE", -1
 DATA "END SELECT", -1
 DATA "WEND", -1
 DATA "END LOOPIF", -1
 DATA "LOOP", -1
 DATA "END SELECTIF", -1
 ' -2=indent left, then right
 DATA "ELSE", -2
 DATA "CASE", -2
 DATA "EOF", 0

' check validity of program
SUB Analyze.Program
 On Local Error Goto Error.Trap15c
 Call Modem.ANSI(4,37,15)
 Call ScreenANSI(4,37,15)
 CALL Count.Lines(Last.Line)
 Strng3 = "Pass 1: counting matching structures."
 Call IO.O
 RESTORE Analyze.Data1
 FOR Data.Count = 1 TO 8
    READ Start.Structure$, Stop.Structure$
    Nested.Count = False
    FOR Program.Line = 1 TO Last.Line
       Out2 = Program(Program.Line)
       Out2 = STRIM$(Out2)
       IF LEN(Out2) THEN
	  Temp1$ = STRIM$(Out2)
	  Temp1$ = UCASE$(Temp1$)
          Count.Data1 = False
	  IF LEFT$(Temp1$, LEN(Start.Structure$)) = Start.Structure$ THEN
             Count.Data1 = True
	  END IF
          IF Start.Structure$ = "FOR" THEN
             IF LEFT$(Temp1$, 5) = "FORIF" THEN
                Count.Data1 = False
             END IF
          END IF
          IF Count.Data1 THEN
	     Nested.Count = Nested.Count + 1
          END IF
	  IF Start.Structure$ = "IF" THEN
	     IF LEFT$(Temp1$, 6) = "END IF" THEN
		Nested.Count = Nested.Count - 1
		IF Nested.Count < False THEN
                   Strng3 = "Analyze error, pass 1: Incomplete " + Start.Structure$ + ": Line:" + Str$(Program.Line)
                   Call IO.O
		   EXIT SUB
		END IF
	     END IF
	  END IF
          IF Stop.Structure$ = "LOOP" THEN
             IF LEFT$(Temp1$, 6) <> "LOOPIF" THEN
                Temp1$ = LEFT$(Temp1$, 4)
             END IF
          END IF
          IF Stop.Structure$ = "NEXT" THEN
             IF LEFT$(Temp1$, 6) <> "NEXTIF" THEN
                Temp1$ = LEFT$(Temp1$, 4)
             END IF
          END IF
          IF Stop.Structure$ = "END SELECT" THEN
             IF LEFT$(Temp1$, 12) <> "END SELECTIF" THEN
                Temp1$ = LEFT$(Temp1$, 10)
             END IF
          END IF
          IF Temp1$ = Stop.Structure$ THEN
	     Nested.Count = Nested.Count - 1
	     IF Nested.Count < False THEN
                Strng3 = "Analyze error, pass 1: Incomplete " + Start.Structure$ + ": Line:" + Str$(Program.Line)
                Call IO.O
		EXIT SUB
	     END IF
	  END IF
       END IF
    NEXT
 NEXT
 Strng3 = "Pass 2: counting matching imbedded structures."
 Call IO.O
 RESTORE Analyze.Data2
 FOR Data.Count = 1 TO 3
    READ Start.Structure$, Stop.Structure$, Imbedded1$, Imbedded2$
    Nested.Count = False
    FOR Program.Line = 1 TO Last.Line
       Out2 = Program(Program.Line)
       Out2 = STRIM$(Out2)
       IF LEN(Out2) THEN
	  Temp1$ = STRIM$(Out2)
	  Temp1$ = UCASE$(Temp1$)
	  IF LEFT$(Temp1$, LEN(Start.Structure$)) = Start.Structure$ THEN
	     Nested.Count = Nested.Count + 1
	  END IF
	  IF LEFT$(Temp1$, LEN(Imbedded1$)) = Imbedded1$ THEN
	     Nested.Count = Nested.Count - 1
	     IF Nested.Count < False THEN
                Strng3 =  "Analyze error, pass 2: Incomplete " + Start.Structure$ + ": Line:" + Str$(Program.Line)
                Call IO.O
		EXIT SUB
	     END IF
	     Nested.Count = Nested.Count + 1
	  ELSE
             Temp2$ = Temp1$
             IF Imbedded2$ <> "ELSEIF" THEN
                IF LEFT$(Temp1$, LEN(Imbedded2$)) = Imbedded2$ THEN
                   Imbedded3 = INSTR(Temp1$, " ")
                   IF Imbedded3 = False THEN
                      Strng3 = "Analyze error, pass 2: Bad " + Imbedded2$ + ": Line:" + Str$(Program.Line)
                      Call IO.O
                      EXIT SUB
                   END IF
                   Temp2$ = LEFT$(Temp1$, Imbedded3 - 1)
                END IF
             END IF
             IF Temp2$ = Imbedded2$ THEN
		Nested.Count = Nested.Count - 1
		IF Nested.Count < False THEN
                   Strng3 = "Analyze error, pass 2: Incomplete " + Start.Structure$ + ": Line:" + Str$(Program.Line)
                   Call IO.O
		   EXIT SUB
		END IF
		Nested.Count = Nested.Count + 1
	     END IF
	  END IF
	  IF Start.Structure$ = "IF" THEN
	     IF LEFT$(Temp1$, 6) = "END IF" THEN
		Nested.Count = Nested.Count - 1
		IF Nested.Count < False THEN
                   Strng3 = "Analyze error, pass 2: Incomplete " + Start.Structure$ + ": Line:" + Str$(Program.Line)
                   Call IO.O
		   EXIT SUB
		END IF
	     END IF
	  END IF
          IF Temp1$ = Stop.Structure$ THEN
	     Nested.Count = Nested.Count - 1
	     IF Nested.Count < False THEN
                Strng3 = "Analyze error, pass 2: Incomplete " + Start.Structure$ + ": Line:" + Str$(Program.Line)
                Call IO.O
		EXIT SUB
	     END IF
	  END IF
       END IF
    NEXT
 NEXT
 Strng3 = "Pass 3: multipass structure match."
 Call IO.O
 RESTORE Analyze.Data1
 FOR Data.Count = 1 TO 8
    READ Start.Structure$, Stop.Structure$
    FOR Program.Line = 1 TO Last.Line
       Out2 = Program(Program.Line)
       Out2 = STRIM$(Out2)
       IF LEN(Out2) THEN
	  Temp1$ = STRIM$(Out2)
	  Temp1$ = UCASE$(Temp1$)
          Count.Data1 = False
	  IF LEFT$(Temp1$, LEN(Start.Structure$)) = Start.Structure$ THEN
             Count.Data1 = True
          END IF
          IF Start.Structure$ = "FOR" THEN
             IF LEFT$(Temp1$, 5) = "FORIF" THEN
                Count.Data1 = False
             END IF
          END IF
          IF Count.Data1 THEN
	     Nested.Count = 1
	     FOR Nested.Lines = Program.Line + 1 TO Last.Line
		Temp2$ = Program(Nested.Lines)
		Temp2$ = STRIM$(Temp2$)
		IF LEN(Temp2$) THEN
		   Temp2$ = STRIM$(Temp2$)
		   Temp2$ = UCASE$(Temp2$)
                   Count.Data2 = False
		   IF LEFT$(Temp2$, LEN(Start.Structure$)) = Start.Structure$ THEN
                      Count.Data2 = True
                   END IF
                   IF Start.Structure$ = "FOR" THEN
                      IF LEFT$(Temp2$, 5) = "FORIF" THEN
                         Count.Data2 = False
                      END IF
                   END IF
                   IF Count.Data2 THEN
		      Nested.Count = Nested.Count + 1
		   END IF
                   IF Stop.Structure$ = "LOOP" THEN
                      IF LEFT$(Temp2$, 6) <> "LOOPIF" THEN
                         Temp2$ = LEFT$(Temp2$, 4)
                      END IF
                   END IF
                   IF Stop.Structure$ = "NEXT" THEN
                      IF LEFT$(Temp2$, 6) <> "NEXTIF" THEN
                         Temp2$ = LEFT$(Temp2$, 4)
                      END IF
                   END IF
                   IF Stop.Structure$ = "END SELECT" THEN
                      IF LEFT$(Temp1$, 12) <> "END SELECTIF" THEN
                         Temp1$ = LEFT$(Temp1$, 10)
                      END IF
                   END IF
                   IF Temp2$ = Stop.Structure$ THEN
		      Nested.Count = Nested.Count - 1
		      IF Nested.Count = False THEN
			 EXIT FOR
		      END IF
		   END IF
		   IF Start.Structure$ = "IF" THEN
		      IF LEFT$(Temp2$, 6) = "END IF" THEN
			 Nested.Count = Nested.Count - 1
			 IF Nested.Count = False THEN
			    EXIT FOR
			 END IF
		      END IF
		   END IF
		END IF
	     NEXT
	     IF Nested.Count <> False THEN
                Strng3 = "Analyze error, pass 3: Mismatched " + Start.Structure$ + ": Line:" + Str$(Program.Line)
                Call IO.O
		EXIT SUB
	     END IF
	  END IF
       END IF
    NEXT
 NEXT
 Strng3 = "Pass 4: multipass imbedded struture match."
 Call IO.O
 RESTORE Analyze.Data2
 FOR Data.Count = 1 TO 3
    READ Start.Structure$, Stop.Structure$, Imbedded1$, Imbedded2$
    FOR Program.Line = 1 TO Last.Line
       Out2 = Program(Program.Line)
       Out2 = STRIM$(Out2)
       IF LEN(Out2) THEN
	  Temp1$ = STRIM$(Out2)
	  Temp1$ = UCASE$(Temp1$)
	  IF LEFT$(Temp1$, LEN(Start.Structure$)) = Start.Structure$ THEN
	     Total.Nested1 = 1
             Total.Nested2 = False
	     Nested.Count1 = 1
             Nested.Count2 = False
	     FOR Nested.Lines = Program.Line + 1 TO Last.Line
		Temp2$ = Program(Nested.Lines)
		Temp2$ = STRIM$(Temp2$)
		IF LEN(Temp2$) THEN
		   Temp2$ = STRIM$(Temp2$)
		   Temp2$ = UCASE$(Temp2$)
		   IF LEFT$(Temp2$, LEN(Start.Structure$)) = Start.Structure$ THEN
		      Total.Nested1 = Total.Nested1 + 1
		      Nested.Count1 = Nested.Count1 + 1
		   END IF
                   IF Temp2$ = Stop.Structure$ THEN
		      Total.Nested2 = Total.Nested2 - 1
		      Nested.Count1 = Nested.Count1 - 1
                      IF Nested.Count1 = False THEN
			 EXIT FOR
		      END IF
		   END IF
		   IF Start.Structure$ = "IF" THEN
		      IF LEFT$(Temp2$, 6) = "END IF" THEN
			 Nested.Count1 = Nested.Count1 - 1
                         IF Nested.Count1 = False THEN
			    EXIT FOR
			 END IF
		      END IF
		   END IF
		   IF LEFT$(Temp2$, LEN(Imbedded1$)) = Imbedded1$ THEN
		      Nested.Count2 = Nested.Count2 + 1
		      IF Nested.Count2 > Nested.Count1 THEN
                         Strng3 = "Analyze error, pass 4: Mismatched " + Start.Structure$ + ": Line:" + Str$(Program.Line)
                         Call IO.O
			 EXIT SUB
		      END IF
		      Nested.Count2 = Nested.Count2 - 1
		   ELSE
                      Temp3$ = Temp2$
                      IF Imbedded2$ <> "ELSEIF" THEN
                         IF LEFT$(Temp2$, LEN(Imbedded2$)) = Imbedded2$ THEN
                            Imbedded3 = INSTR(Temp2$, " ")
                            IF Imbedded3 = False THEN
                               Strng3 = "Analyze error, pass 4: Bad "+ Imbedded2$ + ": Line:" + Str$(Program.Line)
                               Call IO.O
                               EXIT SUB
                            END IF
                            Temp3$ = LEFT$(Temp2$, Imbedded3 - 1)
                         END IF
                      END IF
                      IF Temp3$ = Imbedded2$ THEN
			 Nested.Count2 = Nested.Count2 + 1
			 IF Nested.Count2 > Nested.Count1 THEN
                            Strng3 = "Analyze error, pass 4: Mismatched "+ Start.Structure$ + ": Line:" + Str$(Program.Line)
                            Call IO.O
			    EXIT SUB
			 END IF
			 Nested.Count2 = Nested.Count2 - 1
		      END IF
		   END IF
		END IF
	     NEXT
	     IF Total.Nested2 > Total.Nested1 THEN
                Strng3 = "Analyze error, pass 4: Mismatched " + Start.Structure$ + ": Line:" + Str$(Program.Line)
                Call IO.O
		EXIT SUB
	     END IF
	  END IF
       END IF
    NEXT
 NEXT
 Strng3 = "Pass 5: single pass imbedded control structure match."
 Call IO.O
 RESTORE Analyze.Data3
 FOR Data.Count = 1 TO 5
    READ Start.Structure$, Stop.Structure$, Imbedded1$, Imbedded2$
    Nested.Count = False
    FOR Program.Line = 1 TO Last.Line
       Out2 = Program(Program.Line)
       Out2 = STRIM$(Out2)
       IF LEN(Out2) THEN
	  Temp1$ = STRIM$(Out2)
	  Temp1$ = UCASE$(Temp1$)
          Count.Data1 = False
	  IF LEFT$(Temp1$, LEN(Start.Structure$)) = Start.Structure$ THEN
             Count.Data1 = True
          END IF
          IF Start.Structure$ = "FOR" THEN
             IF LEFT$(Temp1$, 5) = "FORIF" THEN
                Count.Data1 = False
             END IF
          END IF
          IF Count.Data1 THEN
	     Nested.Count = Nested.Count + 1
	  END IF
          Count.Data2 = False
	  IF LEFT$(Temp1$, LEN(Stop.Structure$)) = Stop.Structure$ THEN
             Count.Data2 = True
          END IF
          IF Stop.Structure$ = "LOOP" THEN
             IF LEFT$(Temp1$, 6) = "LOOPIF" THEN
                Count.Data2 = False
             END IF
          END IF
          IF Stop.Structure$ = "NEXT" THEN
             IF LEFT$(Temp1$, 6) = "NEXTIF" THEN
                Count.Data2 = False
             END IF
          END IF
          IF Count.Data2 THEN
             Nested.Count = Nested.Count - 1
	  END IF
	  IF LEFT$(Temp1$, LEN(Imbedded1$)) = Imbedded1$ THEN
	     IF Nested.Count <= False THEN
                Strng3 = "Analyze error, pass 5: Badly nested " + Start.Structure$ + ": Line:" + Str$(Program.Line)
                Call IO.O
		EXIT SUB
	     END IF
	  END IF
	  IF LEFT$(Temp1$, LEN(Imbedded2$)) = Imbedded2$ THEN
	     IF Nested.Count <= False THEN
                Strng3 = "Analyze error, pass 5: Badly nested " + Start.Structure$ + ": Line:" + Str$(Program.Line)
                Call IO.O
		EXIT SUB
	     END IF
	  END IF
       END IF
    NEXT
 NEXT
 Strng3 = "Analysis completed. Program syntax correct."
 Call IO.O
Error.Resume15c:
 Exit Sub
Error.Trap15c:
 Resume Error.Resume15c
END SUB

Analyze.Data1:
 DATA "IF", "ENDIF"
 DATA "DO", "LOOP"
 DATA "FOR", "NEXT"
 DATA "WHILE", "WEND"
 DATA "FORIF", "NEXTIF"
 DATA "LOOPIF", "END LOOPIF"
 DATA "SELECT CASE", "END SELECT"
 DATA "SELECTIF CASE", "END SELECTIF"

Analyze.Data2:
 DATA "IF", "ENDIF", "ELSE", "ELSEIF"
 DATA "SELECT CASE", "END SELECT", "CASE ELSE", "CASE"
 DATA "SELECTIF CASE", "END SELECTIF", "CASEIF ELSE", "CASEIF"

Analyze.Data3:
 DATA "DO", "LOOP", "EXIT DO", "CONTINUE DO"
 DATA "FOR", "NEXT", "EXIT FOR", "CONTINUE FOR"
 DATA "WHILE", "WEND", "EXIT WHILE", "CONTINUE WHILE"
 DATA "FORIF","NEXTIF", "EXIT FORIF", "CONTINUE FORIF"
 DATA "LOOPIF", "END LOOPIF", "EXIT LOOPIF", "CONTINUE LOOPIF"

Sub Insert.Char(V$)
 On Local Error Goto Error.Trap58x3
 Call Get.Cursor.Row(X)
 Call Get.Cursor(Y)
 V$ = Nul
 Ascii$ = Nul
 Gosub Display.Ascii.Line
 DO
    Var3$ = INKEY$
    IF Var3$ = CHR$(13) THEN ' return
       Var3$ = Nul
       EXIT DO
    END IF
    IF Var3$ = CHR$(27) THEN ' escape
       Var3$ = Nul
       IF LEN(Ascii$) THEN
          Ascii$ = Nul
          Gosub Display.Ascii.Line
       END IF
    END IF
    IF Var3$ = CHR$(8) THEN ' backspace
       Var3$ = Nul
       IF LEN(Ascii$) THEN
          Ascii$ = LEFT$(Ascii$, LEN(Ascii$) - 1)
          Gosub Display.Ascii.Line
       END IF
    END IF
    If Lcase$(Var3$) = "x" Or Lcase$(Var3$)="o" Or Lcase$(Var3$)="b" Then
       If Len(Ascii$)=0 Then
          Ascii$ = Ascii$ + Lcase$(Var3$)
          Gosub Display.Ascii.Line
       Endif
    Endif
    If Lcase$(Var3$) >= "a" And Lcase$(Var3$) <= "f" Then
       If Len(Ascii$)>=1 And Len(Ascii$)<3 Then
          If Left$(Ascii$,1)="x" Then
             Ascii$ = Ascii$ + Var3$
             Gosub Display.Ascii.Line
          Endif
       Endif
    Endif
    If Left$(Ascii$,1)="o" Then
       If Var3$ >= "0" And Var3$ <= "7" Then
          If Len(Ascii$)<4 Then
             Ascii$ = Ascii$ + Var3$
             Gosub Display.Ascii.Line
          Endif
       Endif
    Else
       If Left$(Ascii$,1)="b" Then
          If Var3$ = "0" Or Var3$ = "1" Then
             If Len(Ascii$)<9 Then
                Ascii$ = Ascii$ + Var3$
                Gosub Display.Ascii.Line
             Endif
          Endif
       Else
          IF Var3$ >= "0" AND Var3$ <= "9" THEN
             IF LEN(Ascii$) < 3 THEN
                Ascii$ = Ascii$ + Var3$
                Gosub Display.Ascii.Line
             END IF
          END IF
       Endif
    Endif
 LOOP
 ' insert ascii character
 If Left$(Ascii$,1)="x" Then ' hexidecimal
    Ascii.Value=Int(Val("&H"+Mid$(Ascii$,2))+.5)
 Else
    If Left$(Ascii$,1)="o" Then ' octal
       Ascii.Value=Int(Val("&O"+Mid$(Ascii$,2))+.5)
    Else
       If Left$(Ascii$,1)="b" Then ' binary
          Ascii$=Mid$(Ascii$,2)
          Gosub Binary.String
       Else
          Ascii.Value = Int(Val(Ascii$)+.5)
       Endif
    Endif
 Endif
 IF Ascii.Value >= 0 AND Ascii.Value <= 255 THEN
    V$ = CHR$(Ascii.Value)
 END IF
 Color 15
 Locate X, Y, 1
 If Debug Then
    Call Sic.Status.Line2
 Else
    Call Sic.Status.Line
 Endif
 Exit Sub
Binary.String:
  Ascii.Value = False
  Binary.Power = False
  FOR Binary.Digit = LEN(Ascii$) TO 1 STEP -1
      OutX$ = MID$(Ascii$, Binary.Digit, 1)
      SELECT CASE OutX$
          CASE "0"
              ' nul
          CASE "1"
              Ascii.Value = Ascii.Value + 2 ^ Binary.Power
      END SELECT
      Binary.Power = Binary.Power + 1
  NEXT
  RETURN
Display.Ascii.Line:
  COLOR 15, 1
  LOCATE Max.Row, 1, 1
  If Left$(Ascii$,1)="x" Then
     Var2$ = "Enter 2-digit ascii code: " + Ascii$
  Else
     If Left$(Ascii$,1)="o" Then
        Var2$ = "Enter 3-digit ascii code: " + Ascii$
     Else
        If Left$(Ascii$,1)="b" Then
           Var2$ = "Enter 8-digit ascii code: " + Ascii$
        Else
           Var2$ = "Enter 3-digit ascii code: " + Ascii$
        Endif
     Endif
  Endif
  Var2$ = Var2$ + SPACE$(80 - LEN(Var2$))
  Var2$ = Left$(Var2$, 79)
  PRINT Var2$;
  VarC = LEN(Var2$) + 1
  Locate Max.Row,VarC,1
  RETURN
Error.Resume58x3:
 Exit Sub
Error.Trap58x3:
 Resume Error.Resume58x3
End sub

Sub Toggle.Display.Line
 On Local Error Goto Error.Trap58x2
 Debug = Not Debug
 If Debug Then
    Call Sic.Status.Line2
 Else
    Call Sic.Status.Line
 Endif
 Color 15
Error.Resume58x2:
 Exit Sub
Error.Trap58x2:
 Resume Error.Resume58x2
End Sub

Sub Sic.Status.Line
 On Local Error Goto Error.Trap58
 If StdinEnabled Then
    Exit Sub
 Endif
 Temp$="DNDSIC Interpreter > timeon: "+Fclock2$
 Temp$=Left$(Temp$,79)
 Temp$=Temp$+Space$(79-Len(Temp$))
 Call Display.Status.Line(True)
Error.Resume58:
 Exit Sub
Error.Trap58:
 Resume Error.Resume58
End Sub

Sub Sic.Status.Line2
 On Local Error Goto Error.Trap58x
 If StdinEnabled Then
    Exit Sub
 Endif
 Var2# = FRE(-1) + FRE("A")' far+near
 Var2$ = Format$(Var2#, "#,##0.00;;")
 S$ = "DNDSIC Interpreter - Free RAM: " + Var2$ + " bytes."
 S$ = S$ + SPACE$(80 - LEN(S$))
 Temp$=Left$(S$,79)
 Temp$=Temp$+Space$(79-Len(Temp$))
 Call Display.Status.Line(True)
Error.Resume58x:
 Exit Sub
Error.Trap58x:
 Resume Error.Resume58x
End Sub

Sub Clear.Status.Line
 On Local Error Goto Error.Trap58
 Temp$=Space$(79)
 Call Display.Status.Line(False)
Error.Resume58a:
 Exit Sub
Error.Trap58a:
 Resume Error.Resume58a
End Sub

Sub Display.Status.Line(Var)
 On Local Error Goto Error.Trap29
 Call Cursor(False)
 If Var Then
    Color 14,1
 Else
    Color 15,0
 Endif
 Locate Max.Row,1,0
 Print Temp$;
 Locate Max.Row,80
 If Var Then
    Color 0, 1
 Else
    Color 7, 0
 Endif
 Print " ";
 Locate Max.Row-1,1,1
 Call Cursor(True)
 Call Restore.Color
 Color 7, 0
Error.Resume29:
 Exit Sub
Error.Trap29:
 Resume Error.Resume29
End Sub

Sub Cursor(Var)
 On Local Error Goto Error.Trap42
 If Local.ANSI.Color Or Local.Avatar.Color Then
    Select Case Var
    Case False
       Call VideoInt(3,0)
       Cursor.Position=OutregsX.DX
    Case True
       Call VideoInt(2,Cursor.Position)
    End Select
 Else
    Select Case Var
    Case False
       CursorX=Csrlin
       CursorY=Pos(0)
    Case True
       Locate CursorX,CursorY,1
    End Select
 Endif
Error.Resume42:
 Exit Sub
Error.Trap42:
 Resume Error.Resume42
End Sub

Sub Restore.Color
 On Local Error Goto Error.Trap43
 Call ScreenANSI(1,37,15)
 If Graphics.Off Then
    Call ScreenANSI(4,37,15)
 Else
    Call ScreenANSI(4,Color.Code,Avatar.Code)
 Endif
Error.Resume43:
 Exit Sub
Error.Trap43:
 Resume Error.Resume43
End Sub

Sub Cryptograph(Var$)
 On Local Error Goto Error.Trap54
 Var1=Len(Var$)
 If Var1=False Then
    Exit Sub
 Endif
 For Var2=False To Var1-1
    VarZ=Asc(Mid$(Var$,Var2+1,1))
    VarZ=VarZ Xor Var1
    If Var2=False Then
       VarZ=VarZ Xor PrimeKey
    Else
       VarZ=VarZ Xor Var2
       VarZ=VarZ Xor Asc(Mid$(Var$,Var2,1))
    Endif
    Mid$(Var$,Var2+1,1)=Chr$(VarZ)
 Next
 If Var1=1 Then
    Exit Sub
 Endif
 For Var2=Var1-1 To 0 Step -1
    VarZ=Asc(Mid$(Var$,Var2+1,1))
    VarZ=VarZ Xor Var1
    If Var2=Var1-1 Then
       VarZ=VarZ Xor PrimeKey
    Else
       VarZ=VarZ Xor Var2
       VarZ=VarZ Xor Asc(Mid$(Var$,Var2+2,1))
    Endif
    Mid$(Var$,Var2+1,1)=Chr$(VarZ)
 Next
Error.Resume54:
 Exit Sub
Error.Trap54:
 Resume Error.Resume54
End Sub

' parse metacommand
Sub DebugCommand2 (VarX)
   If VarX Then Exit Sub
   Out2 = Mid$(Out2, 9) ' $Llines:
   Out2 = LTrim$(RTrim$(UCase$(Out2)))
   Select Case Out2
      Case "ON"
         ListLines = True
         Exit Sub
      Case "OFF"
         ListLines = False
         Exit Sub
   End Select
   Error 174
End Sub

' immediate debugging prompt.
SUB Debug.Command(VarX, VarX20)
 Static RecurseX As Integer
 If VarX20=0 Then
    Out2=Mid$(Out2,8) ' $Debug:
    Out2=Ltrim$(Rtrim$(Ucase$(Out2)))
    Select Case Out2
    Case "ON"
       Debug.Active=True
       Exit Sub
    Case "OFF"
       Debug.Active=False
       Exit Sub
    End Select
    TempIn$ = Out2
    Gosub Start.Debug1
    Exit Sub
 Endif
 ControlBreak = False
 Call ScreenANSI(4,37,15)
 If VarX = 0 Then RecurseX = 0
 If VarX = -1 Then
    RecurseX = RecurseX + 1
    Strng3="Debug recurse"+Str$(RecurseX)+" level."
    Call IO.O
 Endif
 Strng3 = "Type 'Quit' to exit Debug mode."
 Call IO.O
 Strng3 = "Or type ? for brief command list."
 Call IO.O
Start.Debug:
 DO
    Call Check.Carrier
    If Lost.Carrier Then
       Exit Sub
    Endif
    Allow.Break=True
    Break = False
    Call Modem.ANSI(4,33,14)
    Call ScreenANSI(4,33,14)
    Out9 = Nul
    X=CSRLIN
    Y=POS(0)
    If Debug Then
       Call Sic.Status.Line2
    Else
       Call Sic.Status.Line
    Endif
    Locate X,Y,1
    Call Modem.ANSI(4,37,15)
    Call ScreenANSI(4,37,15)
    If Brief.Prompt=0 Then
       If Len(NodeX) Then
          Strng3 = NodeX + "?"
       Else
          Strng3 = "#?"
       Endif
    Else
       If Len(NodeX) Then
          Strng3 = "Debug "+NodeX + "?"
       Else
          Strng3 = "Debug #?"
       Endif
    Endif
    Prompt = Strng3
    Temp0=3
    Line.Length=255
    CALL IO.I
    Temp0=0
    Allow.Break=False
    VarX = Break
    Break = False
    IF VarX THEN
       Call Modem.ANSI(4,31,12)
       Call ScreenANSI(4,31,12)
       Strng3 = NUL
       Call IO.O
       Strng3 = BreakMessage
       If Local.Mode Then
          If MakeBeep Then
             SOUND Freq, Duration
             SLEEP 1
          Endif
       Endif
       CALL IO.O
       Call Modem.ANSI(4,33,14)
       Call ScreenANSI(4,33,14)
       EXIT DO
    END IF
    Out9 = UCASE$(Out9)
    IF Out9 = "QUIT" THEN
       EXIT DO
    END IF

    VarX = Instr(Out9, " ")
    If VarX Then
       Var1$ = Left$(Out9, VarX - 1)
       Var2$ = Mid$(Out9, VarX + 1)
       Var1$ = Ucase$(Rtrim$(Ltrim$(Var1$)))
       Var2$ = Ucase$(Rtrim$(Ltrim$(Var2$)))
       If Var1$ = "ALARMS" Then
          Call AlarmMenu(Var2$)
          Goto Start.Debug
       Endif
    Endif
    If Ucase$(Out9) = "ALARMS" Then
       Call AlarmMenu("HELP")
       Goto Start.Debug
    End If
    Out2 = Out9

    ' list commands
    IF Out2 = "?" THEN
       Call Modem.ANSI(4,33,14)
       Call ScreenANSI(4,33,14)
       Strng3 = "Brief list of Debug commands:"
       Call IO.O
       Strng3 = "<command>           <shortcut>"
       Call IO.O
       Call ScreenANSI(4,37,15)
       Strng3 = "LISTLINES           --  LL"
       Call IO.O
       Strng3 = "SETBREAK <l>        --  SB <l>"
       Call IO.O
       Strng3 = "CLEARBREAK <l>      --  CB <l>"
       Call IO.O
       Strng3 = "LISTBREAKS          --  LB"
       Call IO.O
       Strng3 = "CLEARALLBREAKS      --  CA"
       Call IO.O
       Strng3 = "SETVARIABLE <x>,n,n --  SV <x>, n [,<sign>]"
       Call IO.O
       Strng3 = "CLEARVARIABLE <x>   --  CV <x>"
       Call IO.O
       Strng3 = "TOGGLEVARIABLE <x>  --  TV <x>"
       Call IO.O
       Strng3 = "LISTVARIABLES       --  LV"
       Call IO.O
       Strng3 = "CLEARALLVARIABLES   --  AV"
       Call IO.O
       Strng3 = "SETBREAKTIME <x>    --  ST <x>"
       Call IO.O
       Strng3 = "CLEARBREAKTIME      --  CT"
       Call IO.O
       Strng3 = "LISTBREAKTIME       --  LT"
       Call IO.O
       Strng3 = "SETFILE             --  SF <x>"
       Call IO.O
       Strng3 = "CLEARFILE           --  CF <x>"
       Call IO.O
       Strng3 = "LISTFILE            --  LF"
       Call IO.O
       Strng3 = "CLEARALLFILE        --  AF"
       Call IO.O
       ' new 03/05/2023
       Strng3 = "SETRECORD           --  SR <x>" : Call IO.O
       Strng3 = "CLEARRECORD         --  CR <x>" : Call IO.O
       Strng3 = "LISTRECORD          --  LR" : Call IO.O
       Strng3 = "CLEARALLRECORD      --  AR" : Call IO.O
       'Strng3 = "WHATIS              --  WA"
       'Call IO.O
    END IF
    If Len(Out2) Then
       TempIn$ = Out2
       Gosub Start.Debug1
    Endif
    If VarX20=0 Then Exit Sub
 LOOP
 Call Modem.ANSI(4,33,14)
 Call ScreenANSI(4,33,14)
 Strng3 = "Debug mode ended."
 Call IO.O
 EXIT SUB
' loop command line separated by colons.
Start.Debug1:
  Do
     Temp=Instr(TempIn$,":")
     If Temp Then
        Out2=Left$(TempIn$,Temp-1)
        Out2=Ltrim$(Rtrim$(Out2))
        TempIn$=Mid$(TempIn$,Temp+1)
        If Len(Out2) Then
           Gosub Start.Debug2
        Endif
     Else
        Out2=TempIn$
        Out2=Ltrim$(Rtrim$(Out2))
        If Len(Out2) Then
           Gosub Start.Debug2
        Endif
        Exit Do
     Endif
  Loop
  Return
' parse the command.
Start.Debug2:
  ' parse debug commands
  IF Out2 = "DEBUG" THEN ' DE
     Out2 = "DE"
  END IF
  IF Out2 = "WHATIS" THEN ' WA
     Out2 = "WA"
  END IF
  IF Out2 = "LISTBREAKTIME" THEN ' LT
     Out2 = "LT"
  END IF
  IF Out2 = "LISTFILE" THEN ' LF
     Out2 = "LF"
  END IF
  IF Out2 = "CLEARBREAKTIME" THEN ' CT
     Out2 = "CT"
  END IF
  IF Out2 = "LISTLINES" THEN ' LL
     Out2 = "LL"
  END IF
  IF Out2 = "CLEARALLFILE" THEN ' AF
     Out2 = "AF"
  END IF
  IF LEFT$(Out2,13) = "SETBREAKTIME " THEN ' ST
     Out2 = "ST" + Mid$(Out2, 14)
  END IF
  IF LEFT$(Out2,9) = "SETBREAK " THEN ' SB
     Out2 = "SB" + Mid$(Out2, 10)
  END IF
  IF LEFT$(Out2,11) = "CLEARBREAK " THEN ' CB
     Out2 = "CB" + Mid$(Out2, 12)
  END IF
  IF LEFT$(Out2,10) = "CLEARFILE " THEN ' CF
     Out2 = "CF" + Mid$(Out2, 11)
  END IF
  IF LEFT$(Out2,8) = "SETFILE " THEN ' SF
     Out2 = "SF" + Mid$(Out2, 9)
  END IF
  IF Out2 = "LISTBREAKS" THEN ' LB
     Out2 = "LB"
  END IF
  IF Out2 = "CLEARALLVARIABLES" THEN ' CA
     Out2 = "CA"
  END IF
  IF LEFT$(Out2,12) = "SETVARIABLE " THEN ' SV
     Out2 = "SV" + Mid$(Out2, 13)
  END IF
  IF LEFT$(Out2,14) = "CLEARVARIABLE " THEN ' CV
     Out2 = "CV" + Mid$(Out2, 15)
  END IF
  IF LEFT$(Out2,15) = "TOGGLEVARIABLE " THEN ' TV
     Out2 = "TV" + Mid$(Out2, 16)
  END IF
  IF Out2 = "LISTVARIABLES" THEN ' LV
     Out2 = "LV"
  END IF
  IF Out2 = "CLEARALLBREAKS" THEN ' AV
     Out2 = "AV"
  END IF
  ' new 02/10/2023
  If Out2 = "LISTRECORD" Then ' LR
     Out2 = "LR"
  End If
  If Out2 = "CLEARALLRECORD" Then ' AR
     Out2 = "AR"
  End If
  If Left$(Out2, 12) = "CLEARRECORD " Then ' CR
     Out2 = "CR" + Mid$(Out2, 13)
  End If
  If Left$(Out2, 10) = "SETRECORD " Then ' SR
     Out2 = "SR" + Mid$(Out2, 11)
  End If
  ' test shortcuts
  SELECT CASE LEFT$(Out2, 2)
  CASE "?"
     ' nul
  CASE "DE"
     If VarX20 Then
        Call Debug.Command(-1, -1)
     Endif
  CASE "WA"
     If VarX20 Then
        Call Whatis.Command(0)
     Endif
  CASE "LL"
     ListLines = NOT ListLines
     If VarX20 Then
        If ListLines Then
           Strng3 = "Debug: List lines on."
        Else
           Strng3 = "Debug: List lines off."
        Endif
       Call IO.O
     Endif
  CASE "LT"
     Gosub List.Break.Time
  CASE "LF"
     Gosub List.Break.File
  CASE "ST"
     Gosub Set.Break.Time
  CASE "CT"
     Gosub Clear.Break.Time
  CASE "SB"
     GOSUB Set.Break
  CASE "CB"
     GOSUB Clear.Break
  CASE "CF"
     GOSUB Clear.File
  CASE "AF"
     GOSUB Clear.All.File
  CASE "SF"
     GOSUB Set.File
  CASE "LB"
     GOSUB Display.Breaks
  CASE "CA"
     GOSUB Clear.All.Variables
  CASE "SV"
     GOSUB Set.Variable
  CASE "CV"
     GOSUB Clear.Variable
  CASE "TV"
     GOSUB Toggle.Variable
  CASE "LV"
     GOSUB Display.Variables
  CASE "AV"
     GOSUB Clear.All.Breaks
  Case "LR"
     GoSub ListRecordFile
  Case "CR"
     GoSub ClearRecord
  Case "AR"
     GoSub ClearAllRecord
  Case "SR"
     GoSub SetRecord
  CASE ELSE
     If VarX20=0 Then Error 173
     Strng3 = "Function not found."
     Call IO.O
  END SELECT
  Return
ListRecordFile:
 If VarX20 = 0 Then Return
 Var4$ = Nul
 VarX = 0
 For Z = 1 To RecordCount
    If File.Records(Z) Then
       Var4$ = Var4$ + Str$(File.Records(Z)) + ","
       VarX = -1
    End If
 Next
 If VarX Then
    Var4$ = Left$(Var4$, Len(Var4$) - 1) + "."
    Strng3 = "File number records:" + Var4$ : Call IO.O
 Else
    Strng3 = "No file records found." : Call IO.O
 End If
 Return

ClearRecord:
 Out2 = LTrim$(Mid$(Out2, 3))
 If Left$(Out2, 1) = "," Then Out2 = Mid$(Out2, 2)
 Z& = Int(Val(Out2)+.5)
 If Z& > 0& And Z& <= MaxLong Then
    For X = 1 To RecordCount
       If File.Records(X) = Z& Then
          File.Records(X) = False
          If VarX20 Then
             Strng3 = "File record" + Str$(X) + " cleared." : Call IO.O
          End If
          Return
       End If
    Next
 End If
 If VarX20 = 0 Then Error 173
 If VarX20 Then
    Strng3 = "Unknown record." : Call IO.O
 End If
 Return

ClearAllRecord:
 For VarZ = 1 To RecordCount
    File.Records(VarZ) = 0&
 Next
 If VarX20 Then
    Strng3 = "All file records cleared." : Call IO.O
 End If
 Return

SetRecord:
 Out2 = LTrim$(Mid$(Out2, 3))
 If Left$(Out2, 1) = "," Then Out2 = Mid$(Out2, 2)
 Z& = Int(Val(Out2)+.5)
 If Z& > 0& And Z& <= MaxLong Then
    If RecordCount < MaxRecords Then
       RecordCount = RecordCount + 1
       File.Records(RecordCount) = Z&
       If VarX20 Then
          Strng3 = "File record" + Str$(Z&) + " set." : Call IO.O
       End If
       Return
    Endif
 End If
 If VarX20 = 0 Then Error 173
 If VarX20 Then
    Strng3 = "Unknown record." : Call IO.O
 End If
 Return

Set.Break:
 Out2 = Ltrim$(Mid$(Out2, 3))
 If Left$(Out2, 1) = "," Then Out2 = Mid$(Out2, 2)
 BreakLine = CInt(Val(Out2))
 IF BreakLine > False AND BreakLine <= Max.Lines THEN
    LineBreak(BreakLine) = True
    If VarX20 Then
       Call ScreenANSI(4,37,15)
       Strng3 = "Break line" + STR$(BreakLine) + " set."
       Call IO.O
    Endif
    RETURN
 END IF
 If VarX20 = 0 Then Return
 If VarX20 Then
    Call ScreenANSI(4,37,15)
    Strng3 = "Unknown line."
    Call IO.O
 Endif
 RETURN

List.Break.Time:
 If VarX20=0 Then Return
 IF LineBreakTime > False THEN
    Call ScreenANSI(4,37,15)
    Strng3 = "Break time set to"+Str$(LineBreakTime)+" seconds."
    Call IO.O
    RETURN
 END IF
 Call ScreenANSI(4,37,15)
 Strng3 = "Break time not set."
 Call IO.O
 RETURN

List.Break.File:
 If VarX20=0 Then Return
 Var4$ = Nul
 VarX = 0
 If FileTrap0 Then
    Var4$ = " 0,"
    VarX = -1
 End If
 For Z = 1 To MaxFiles
    If File.Trap(Z) Then
       Var4$ = Var4$ + Str$(Z) + ","
       VarX = -1
    Endif
 Next
 If VarX Then
    Var4$ = Left$(Var4$, Len(Var4$) - 1) + "."
    Strng3 = "File number breaks:" + Var4$
    Call IO.O
 Else
    Strng3 = "No file breaks found."
    Call IO.O
 Endif
 Return

Set.Break.Time:
 Out2 = Ltrim$(Mid$(Out2, 3))
 If Left$(Out2, 1) = "," Then Out2 = Mid$(Out2, 2)
 BreakLine = Int(Val(Out2)+.5)
 IF BreakLine > False THEN
    LineBreakTime = BreakLine
    If VarX20 Then
       Call ScreenANSI(4,37,15)
       Strng3 = "Break time set."
       Call IO.O
    Endif
    RETURN
 END IF
 If VarX20 = 0 Then Error 173
 If VarX20 Then
    Call ScreenANSI(4,37,15)
    Strng3 = "Unknown time."
    Call IO.O
 Endif
 RETURN

Clear.Break:
 Out2 = Ltrim$(Mid$(Out2, 3))
 If Left$(Out2, 1) = "," Then Out2 = Mid$(Out2, 2)
 BreakLine = CInt(Val(Out2))
 IF BreakLine > False AND BreakLine <= Max.Lines THEN
    LineBreak(BreakLine) = False
    If VarX20 Then
       Call ScreenANSI(4,37,15)
       Strng3 = "Break line" + STR$(BreakLine) + " cleared."
       Call IO.O
    Endif
    RETURN
 END IF
 If VarX20 = 0 Then Error 173
 If VarX20 Then
    Call ScreenANSI(4,37,15)
    Strng3 = "Unknown line."
    Call IO.O
 Endif
 RETURN

Clear.File:
 Out2 = Ltrim$(Mid$(Out2, 3))
 If Left$(Out2, 1) = "," Then Out2 = Mid$(Out2, 2)
 BreakLine = CInt(Val(Out2))
 If BreakLine = 0 Then
    FileTrap0 = 0
    If VarX20 Then
       Strng3 = "File trap" + Str$(0) + " cleared."
       Call IO.O
    End If
    Return
 End If
 IF BreakLine > False AND BreakLine <= MaxFiles THEN
    File.Trap(BreakLine) = False
    If VarX20 Then
       Call ScreenANSI(4,37,15)
       Strng3 = "File trap" + STR$(BreakLine) + " cleared."
       Call IO.O
    Endif
    RETURN
 END IF
 If VarX20 = 0 Then Error 173
 If VarX20 Then
    Call ScreenANSI(4,37,15)
    Strng3 = "Unknown file."
    Call IO.O
 Endif
 RETURN

Clear.All.File:
 For VarZ = 1 To MaxFiles
    File.Trap(VarZ) = False
 Next
 FileTrap0 = 0
 If VarX20=0 Then Return
 Call ScreenANSI(4,37,15)
 Strng3 = "All file traps cleared."
 Call IO.O
 RETURN

Set.File:
 Out2 = Mid$(Out2, 3) : If Left$(Out2, 1) = "," Then Out2 = Mid$(Out2, 2)
 BreakLine = CInt(Val(Out2))
 If BreakLine = 0 Then
    FileTrap0 = -1
    If VarX20 Then
       Strng3 = "File trap" + Str$(0) + " set."
       Call IO.O
    End If
    Return
 End If
 IF BreakLine > False AND BreakLine <= MaxFiles THEN
    File.Trap(BreakLine) = True
    If VarX20 Then
       Call ScreenANSI(4,37,15)
       Strng3 = "File trap" + STR$(BreakLine) + " set."
       Call IO.O
    Endif
    RETURN
 END IF
 If VarX20 = 0 Then Error 173
 If VarX20 Then
    Call ScreenANSI(4,37,15)
    Strng3 = "Unknown file."
    Call IO.O
 Endif
 RETURN

Clear.Break.Time:
 LineBreakTime = False
 If VarX20=0 Then Return
 Call ScreenANSI(4,37,15)
 Strng3 = "Break time cleared."
 Call IO.O
 RETURN

Display.Breaks:
 If VarX20=0 Then Return
 Continuous.Display = False
 Line.Count = False
 Line.Flag = False
 FOR Var = 1 TO Max.Lines
    ' display line break variables 
    IF LineBreak(Var) THEN
       ' check page length
       Line.Count = Line.Count + 1
       IF Continuous.Display = False THEN
          IF Line.Count = 1 THEN
             Call ScreenANSI(4,37,15)
             Strng3 = "Line Number"
             Call IO.O
             Strng3 = "-----------"
             Call IO.O
          END IF
       END IF
       Call ScreenANSI(4,33,14)
       Strng3 = " " + Form$(Cdbl(Var))
       Call IO.O
       Line.Flag = True
    END IF

    ' check page length
    IF Line.Count = User.PageLength - 2 THEN
       GOSUB Check.Page
       SELECT CASE Output.Char$
       CASE "n"
          RETURN
       CASE "c"
          Continuous.Display = True
       END SELECT
    END IF
 NEXT
 IF Line.Flag = False THEN
    Call ScreenANSI(4,37,15)
    Strng3 = "No line breaks set."
    Call IO.O
 END IF
 RETURN

Set.Variable:
 BreakSign = -1
 Out2 = Ltrim$(Mid$(Out2, 3))
 If Left$(Out2, 1) = "," Then Out2 = Mid$(Out2, 2)
 Var$ = Out2
 Var$ = LTRIM$(Var$)
 VarX = Instr(Var$, ",")
 If VarX Then
    VarX = Instr(VarX+1,Var$, ",")
    If VarX Then
       VarX$ = Mid$(Var$, VarX + 1)
       VarX$ = Ltrim$(Rtrim$(VarX$))
       Var2$ = Left$(Var$, VarX - 1)
       Gosub Return.Sign
    Endif
 Endif
 Var2$ = LEFT$(Var$, 1)
 Var2$ = UCASE$(Var2$)
 IF Var2$>="A" AND Var2$<="Z" THEN
    BreakVar = ASC(Var2$)-64
    Var$ = MID$(Var$, 2)
    Var$ = LTRIM$(Var$)
    IF LEFT$(Var$, 1) = "(" THEN
       Imbedded = INSTR(Var$, ")")
       IF Imbedded THEN
          Var2$ = LEFT$(Var$, Imbedded - 1)
          Var2$ = MID$(Var2$, 2)
          BreakVar2 = INT(VAL(Var2$)+.5)
          IF BreakVar2 >= 1 AND BreakVar2 <= MaxArrays THEN
             Var$ = MID$(Var$, Imbedded + 1)
             Var$ = LTRIM$(Var$)
             IF LEFT$(Var$, 1) = "," THEN
                BreakVar3# = VAL(MID$(Var$, 2))
                VariableBreak3(BreakVar, BreakVar2) = BreakSign
                VariableValue3(BreakVar, BreakVar2) = BreakVar3#
                If VarX20 Then
                   Call ScreenANSI(4,37,15)
                   Strng3 = "Break variable " + CHR$(BreakVar+64) + "(" + MID$(STR$(BreakVar2),2)+") set to " + LTRIM$(STR$(BreakVar3#))+"."
                   Call IO.O
                Endif
                RETURN
             END IF
          END IF
       END IF
    ELSE
       IF LEFT$(Var$, 1) = "$" THEN
          Var$ = MID$(Var$, 2)
          Var$ = LTRIM$(Var$)
          IF LEFT$(Var$, 1) = "," THEN
             BreakVar2$ = MID$(Var$, 2)
             VariableBreak2(BreakVar) = BreakSign
             VariableValue2(BreakVar) = BreakVar2$
             If VarX20 Then
                Call ScreenANSI(4,37,15)
                Strng3 = "Break variable " + CHR$(BreakVar+64)+"$ set to " + Quote$ + BreakVar2$ + Quote$ + "."
                Call IO.O
             Endif
             RETURN
          END IF
       ELSE
          IF LEFT$(Var$, 1) = "," THEN
             BreakVar2# = VAL(MID$(Var$, 2))
             VariableBreak(BreakVar) = BreakSign
             VariableValue(BreakVar) = BreakVar2#
             If VarX20 Then
                Call ScreenANSI(4,37,15)
                Strng3 = "Break variable " + CHR$(BreakVar+64) + " set to " + LTRIM$(STR$(BreakVar2#))+"."
                Call IO.O
             Endif
             RETURN
          END IF
       END IF
    END IF
 END IF
 If VarX20 = 0 Then Error 173
 If VarX20 Then
    Call ScreenANSI(4,37,15)
    Strng3 = "Unknown variable."
    Call IO.O
 Endif
 RETURN

Clear.Variable:
 Out2 = Ltrim$(Mid$(Out2, 3))
 If Left$(Out2, 1) = "," Then Out2 = Mid$(Out2, 2)
 Var$ = Out2
 Var$ = UCASE$(Var$)
 Var$ = RTRIM$(Var$)
 Var$ = LTRIM$(Var$)
 Var2$ = LEFT$(Var$, 1)
 IF Var2$>="A" AND Var2$<="Z" THEN
    BreakVar=ASC(Var2$)-64
    IF LEN(Var$) = 1 THEN
       VariableBreak(BreakVar) = False
       VariableValue(BreakVar) = DFalse
       If VarX20 Then
          Call ScreenANSI(4,37,15)
          Strng3 = "Break variable "+CHR$(BreakVar+64)+" cleared."
          Call IO.O
       Endif
       RETURN
    ELSE
       IF LEN(Var$) = 2 THEN
          Var2$ = MID$(Var$, 2)
          IF Var2$ = "$" THEN
             VariableBreak2(BreakVar) = False
             VariableValue2(BreakVar) = Nul
             If VarX20 Then
                Call ScreenANSI(4,37,15)
                Strng3 = "Break variable "+CHR$(BreakVar+64)+"$ cleared."
                Call IO.O
             Endif
             RETURN
          END IF
       ELSE
          Var$ = MID$(Var$, 2)
          IF LEFT$(Var$, 1) = "(" THEN
             Imbedded = INSTR(Var$, ")")
             IF Imbedded THEN
                Var$ = LEFT$(Var$, Imbedded - 1)
                Var$ = MID$(Var$, 2)
                BreakVar2 = VAL(Var$)
                IF BreakVar2>=1 AND BreakVar2<=MaxArrays THEN
                   VariableBreak3(BreakVar, BreakVar2) = False
                   VariableValue3(BreakVar, BreakVar2) = DFalse
                   If VarX20 Then
                      Call ScreenANSI(4,37,15)
                      Strng3 = "Break variable "+CHR$(BreakVar+64)+"("+MID$(STR$(BreakVar2),2)+") cleared."
                      Call IO.O
                   Endif
                   RETURN
                END IF
             END IF
          END IF
       END IF
    END IF
 END IF
 If VarX20 = 0 Then Error 173
 If VarX20 Then
    Call ScreenANSI(4,37,15)
    Strng3 ="Unknown variable."
    Call IO.O
 Endif
 RETURN

Toggle.Variable:
 Out2 = Ltrim$(Mid$(Out2, 3))
 If Left$(Out2, 1) = "," Then Out2 = Mid$(Out2, 2)
 Var$ = Out2
 Var$ = UCASE$(Var$)
 Var$ = RTRIM$(Var$)
 Var$ = LTRIM$(Var$)
 Var2$ = LEFT$(Var$, 1)
 IF Var2$>="A" AND Var2$<="Z" THEN
    BreakVar=ASC(Var2$)-64
    IF LEN(Var$) = 1 THEN
       IF VariableBreak(BreakVar) THEN
          NewBreak = VariableBreak(BreakVar)
          GOSUB Next.Break
          VariableBreak(BreakVar) = NewBreak
          If VarX20 Then
             Call ScreenANSI(4,37,15)
             Strng3 = "Break variable "+CHR$(BreakVar+64)+" toggled to "+ Symbol$+ "."
             Call IO.O
          Endif
          RETURN
       END IF
    ELSE
       IF LEN(Var$) = 2 THEN
          Var2$ = MID$(Var$, 2)
          IF Var2$ = "$" THEN
             IF VariableBreak2(BreakVar) THEN
                NewBreak = VariableBreak2(BreakVar)
                GOSUB Next.Break
                VariableBreak2(BreakVar) = NewBreak
                If VarX20 Then
                   Call ScreenANSI(4,37,15)
                   Strng3 = "Break variable "+CHR$(BreakVar+64)+"$ toggled to "+ Symbol$+ "."
                   Call IO.O
                Endif
                RETURN
             END IF
          END IF
       ELSE
          Var$ = MID$(Var$, 2)
          IF LEFT$(Var$, 1) = "(" THEN
             Imbedded = INSTR(Var$, ")")
             IF Imbedded THEN
                Var$ = LEFT$(Var$, Imbedded - 1)
                Var$ = MID$(Var$, 2)
                BreakVar2 = VAL(Var$)
                IF BreakVar2>=1 AND BreakVar2<=MaxArrays THEN
                   IF VariableBreak3(BreakVar, BreakVar2) THEN
                      NewBreak = VariableBreak3(BreakVar, BreakVar2)
                      GOSUB Next.Break
                      VariableBreak3(BreakVar, BreakVar2) = NewBreak
                      If VarX20 Then
                         Call ScreenANSI(4,37,15)
                         Strng3 = "Break variable "+CHR$(BreakVar+64)+"("+MID$(STR$(BreakVar2),2)+") toggled to "+ Symbol$+ "."
                         Call IO.O
                      Endif
                      RETURN
                   END IF
                END IF
             END IF
          END IF
       END IF
    END IF
 END IF
 If VarX20 = 0 Then Error 173
 If VarX20 Then
    Call ScreenANSI(4,37,15)
    Strng3 = "Unknown variable."
    Call IO.O
 Endif
 RETURN

Display.Variables:
 If VarX20=0 Then Return
 Line.Count = False
 Line.Flag = False
 FOR Var = 1 TO 26
    ' display break variables 
    IF VariableBreak(Var) THEN
       ' check page length
       GOSUB Check.Title
       Call ScreenANSI(4,33,14)
       Strng3 = " " + CHR$(Var + 64) + "        "
       BreakSign = VariableBreak(Var)
       GOSUB Get.Sign
       Strng3 = Strng3 + Symbol$ + "   "
       Strng3 = Strng3 + STR$(VariableValue(Var))
       Call IO.O
       Line.Flag = True
    END IF

    ' check page length
    IF Line.Count = User.PageLength - 2 THEN
       GOSUB Check.Page
       SELECT CASE Output.Char$
       CASE "n"
          RETURN
       CASE "c"
          Continuous.Display = True
       END SELECT
    END IF
 NEXT
 FOR Var = 1 TO 26
    ' display break variables 
    IF VariableBreak2(Var) THEN
       ' check page length
       GOSUB Check.Title
       Call ScreenANSI(4,33,14)
       Strng3 = " " + CHR$(Var + 64) + "$       "
       BreakSign = VariableBreak2(Var)
       GOSUB Get.Sign
       Strng3 = Strng3 + Symbol$ + "   "
       IF LEN(VariableValue2(Var)) > 40 THEN
          Strng3 = Strng3 + Quote$ + LEFT$(VariableValue2(Var), 40) + "..."
       ELSE
          Strng3 = Strng3 + Quote$ + VariableValue2(Var) + Quote$
       END IF
       Call IO.O
       Line.FLag = True
    END IF

    ' check page length
    IF Line.Count = User.PageLength - 2 THEN
       GOSUB Check.Page
       SELECT CASE Output.Char$
       CASE "n"
          RETURN
       CASE "c"
          Continuous.Display = True
       END SELECT
    END IF
 NEXT

 FOR Var = 1 TO 26
    FOR Var2 = 1 TO MaxArrays
       ' display break variables 
       IF VariableBreak3(Var, Var2) THEN
          ' check page length
          GOSUB Check.Title
          Call ScreenANSI(4,33,14)
          VarL = Len(Mid$(Str$(Var2), 2))
          Strng3 = " " + CHR$(Var + 64) + "(" + MID$(STR$(Var2), 2)+ ")"
          If VarL = 3 Then Strng3 = Strng3 + "   "
          If VarL = 2 Then Strng3 = Strng3 + "    "
          If VarL = 1 Then Strng3 = Strng3 + "     "
          BreakSign = VariableBreak3(Var, Var2)
          GOSUB Get.Sign
          Strng3 = Strng3 + Symbol$ + "   " + STR$(VariableValue3(Var, Var2))
          Call IO.O
          Line.Flag = True
       END IF

       ' check page length
       IF Line.Count = User.PageLength - 2 THEN
          GOSUB Check.Page
          SELECT CASE Output.Char$
          CASE "n"
             RETURN
          CASE "c"
             Continuous.Display = True
          END SELECT
       END IF
    NEXT
 NEXT
 IF Line.Flag = False THEN
    Call ScreenANSI(4,37,15)
    Strng3 = "No variable breaks set."
    Call IO.O
 END IF
 RETURN

Check.Page:
 Line.Count = False
 IF Continuous.Display = False THEN
    CALL More.Prompt("More(y/n/c)", "ync", Output.Char$, "n")
 END IF
 RETURN

Check.Title:
 Line.Count = Line.Count + 1
 IF Continuous.Display = False THEN
    IF Line.Count = 1 THEN
       Call ScreenANSI(4,37,15)
       Strng3 = "Variable  Sign Value"
       Call IO.O
       Strng3 = "--------------------"
       Call IO.O
    END IF
 END IF
 RETURN

Return.Sign:
 SELECT CASE VarX$
 CASE "="
    BreakSign = -1
 CASE "<>"
    BreakSign = 1
 CASE ">"
    BreakSign = 2
 CASE ">="
    BreakSign = 3
 CASE "<"
    BreakSign = 4
 CASE "<="
    BreakSign = 5
 CASE ELSE
    BreakSign = -1
 END SELECT
 RETURN

Get.Sign:
 SELECT CASE BreakSign
 CASE -1
    Symbol$ = "= "
 CASE 1
    Symbol$ = "<>"
 CASE 2
    Symbol$ = "> "
 CASE 3
    Symbol$ = ">="
 CASE 4
    Symbol$ = "< "
 CASE 5
    Symbol$ = "<="
 END SELECT
 RETURN

Next.Break:
 SELECT CASE NewBreak
 CASE -1 ' =
    NewBreak = 1
    Symbol$ = "<>"
 CASE 1  ' <>
    NewBreak = 2
    Symbol$ = ">"
 CASE 2  ' >
    NewBreak = 3
    Symbol$ = ">="
 CASE 3  ' >=
    NewBreak = 4
    Symbol$ = "<"
 CASE 4  ' <
    NewBreak = 5
    Symbol$ = "<="
 CASE 5  ' <=
    NewBreak = -1
    Symbol$ = "="
 END SELECT
 RETURN

Clear.All.Breaks:
 REDIM LineBreak(1 TO Max.Lines) AS INTEGER
 If VarX20=0 Then Return
 Call ScreenANSI(4,37,15)
 Strng3 = "All line breaks cleared."
 Call IO.O
 RETURN

Clear.All.Variables:
 Call Clear.All.Arrays
 If VarX20=0 Then Return
 Call ScreenANSI(4,37,15)
 Strng3 = "All variable breaks cleared."
 Call IO.O
 RETURN
END SUB

Sub Clear.All.Arrays
 Redim VariableBreak(1 TO 26) AS INTEGER, _
 VariableBreak2(1 TO 26) AS INTEGER, _
 VariableBreak3(0 TO 26, 0 TO MaxArrays) AS INTEGER, _
 VariableValue(1 TO 26) AS DOUBLE, _
 VariableValue3(0 TO 26, 0 TO MaxArrays) AS DOUBLE
 FOR BreakVar = 1 TO 26
    VariableValue2(BreakVar) = Nul
 NEXT
End Sub

' lists all drives
SUB ListDrives
DIM BPBfile AS BPBtype
DIM DTAfile AS DTAtype
h = 3
l = 0
GOSUB DriveHeader
FOR c = 1 TO 26
    GOSUB DisplayDrive
    IF h = 20 THEN
        h = 0
        CALL More.Prompt("More(y/n/c)","y"+chr$(13),Output.Char$,"y")
        GOSUB DriveHeader
    END IF
NEXT
IF q = 0 THEN
    Strng3="<none>"
    Call io.o
ELSE
    Strng3="Total drives"+str$(l)
    Call io.o
END IF
EXIT SUB

DisplayDrive:
c$ = CHR$(c + 64)
Out3 = c$
CALL Check.Drive(c, Temp#)
IF Temp# THEN
    h = h + 1
    l = l + 1
    q = -1

    ' display drive letter
    z$ = c$ + ":    "

    ' display volume label
    Out3 = c$
    gosub Vlabel
    IF RTRIM$(Out3) = "" THEN
        q$ = ""
    ELSE
        q$ = LEFT$(Out3, 12)
    END IF
    z$ = z$ + q$ + SPACE$(13 - LEN(q$))

    ' display volume serial number
    Out3 = c$
    gosub Vserial
    q$ = LEFT$(Out3, 12)
    if q$ = "" then q$ = "<unknown>"
    z$ = z$ + q$ + SPACE$(13 - LEN(q$))

    ' display volume file system type
    Out3 = c$
    gosub Vtype
    q$ = LEFT$(Out3, 8)
    if q$ = "" then q$ = "<n/a>"
    z$ = z$ + q$ + SPACE$(9 - LEN(q$))

    ' display volume total disk space
    Out3 = c$
    CALL FreeSpace(2, Out3)
    x# = INT(VAL(Out3)+.5)
    x1# = x#
    IF x# > 0# THEN
        CALL Suffix(x#, S$) ' 1,024.0 KB
        z$ = z$ + SPACE$(11 - LEN(S$)) + S$
    ELSE
        z$ = z$ + "      <n/a>"
    END IF

    ' display volume free disk space
    Out3 = c$
    CALL FreeSpace(1, Out3)
    y# = INT(VAL(Out3)+.5)
    y1# = y#
    IF y# > 0# THEN
        CALL Suffix(y#, S$) ' 1,024.0 KB
        z$ = z$ + SPACE$(11 - LEN(S$)) + S$
    ELSE
        z$ = z$ + "      <n/a>"
    END IF

    ' display volume used disk space
    IF x1# > 0# OR y1# > 0# THEN
        z# = x1# - y1#
        CALL Suffix(z#, S$) ' 1,024.0 KB
        z$ = z$ + SPACE$(11 - LEN(S$)) + S$
    ELSE
        z$ = z$ + "      <n/a>"
    END IF
    Strng3 = z$
    CALL IO.O
END IF
RETURN

DriveHeader:
h = 2
Strng3 = "Drive Label        Serial       Type           Total       Free       Used"
Call io.o
Strng3 = "--------------------------------------------------------------------------"
Call io.o
RETURN

vlabel:
    ASCIIZ = CHR$(c + 64) + ":\*.*" + CHR$(0)
    Out3 = Nul
    ' restore directory search dta
    InregsX.AX = &H1A00
    InregsX.DS = VARSEG(DTAfile)
    InregsX.DX = VARPTR(DTAfile)
    CALL InterruptX(&H21, InregsX, OutregsX)
    ' find volume label
    InregsX.AX = &H4E00
    InregsX.CX = &H8
    InregsX.DS = VARSEG(ASCIIZ)
    InregsX.DX = VARPTR(ASCIIZ)
    CALL InterruptX(&H21, InregsX, OutregsX)
    ' check findfirst error
    IF (OutregsX.Flags AND &H1) = &H0 THEN
       Out3 = DTAfile.ASCIIZfilename
       Out3 = LEFT$(Out3, INSTR(Out3, CHR$(0)) - 1)
       Out3 = RTRIM$(Out3)
    END IF
    ' restore basic dta
    InregsX.AX = &H1A00
    InregsX.DS = BASIC.DTA.SEG
    InregsX.DX = BASIC.DTA.OFF
    CALL InterruptX(&H21, InregsX, OutregsX)
return

vserial:
    Out3 = Nul
    ' get volume info
    InregsX.AX = &H6900
    InregsX.BX = c
    InregsX.DS = VARSEG(BPBfile)
    InregsX.DX = VARPTR(BPBfile)
    CALL InterruptX(&H21, InregsX, OutregsX)
    ' check flag error
    IF (OutregsX.Flags AND &H1) = &H0 THEN
       ' store volume serial number
       FOR Serial.Digit = 4 TO 1 STEP -1
	  IF Serial.Digit = 2 THEN
	     Out3 = Out3 + "-"
	  END IF
          Digit = ASC(MID$(BPBfile.Serial, Serial.Digit, 1))
          Out3 = Out3 + RIGHT$(HEX$(Digit + &H100), 2)
       NEXT
    END IF
return

vtype:
    Out3 = Nul
    ' get volume info
    InregsX.AX = &H6900
    InregsX.BX = c
    InregsX.DS = VARSEG(BPBfile)
    InregsX.DX = VARPTR(BPBfile)
    CALL InterruptX(&H21, InregsX, OutregsX)
    ' check flag error
    IF (OutregsX.Flags AND &H1) = &H0 THEN
       ' store volume file system type
       Out3 = RTRIM$(BPBfile.System)
    END IF
return
END SUB

' edit multi-dimensional command history arrays w/ linewrapping
'   Temp0 = history array type
'   VarQ: -1=reset/0=enter/1-26=A-Z
Sub Command.History(VarQ)
 On Local Error Goto Error.Trap45z
 ' check flags
 Call Check.Carrier
 If Lost.Carrier Then
    Exit Sub
 Endif
 If Chat Then
    Exit Sub
 Endif
 ' select command history
 Select Case VarQ
 Case -1 ' reset
    History.Count2(Temp0)=0
    If History.Debug Then
       Print
       Print "History reset."
    Endif
 Case 0 ' enter
    If Len(Out9) Then
       Gosub Get.Count
       If History.Debug Then
          Print
          Print "History set:"; Var1
       Endif
       ' init
       EndOfHistoryFlag(Temp0) = -1
       If Var1=0 Then
          History.Count2(Temp0)=1
          History2(Temp0,1)=Out9
       Else
          ' add history
          If Var1<MaxHistory Then
             History.Count2(Temp0)=Var1+1
             History2(Temp0,Var1+1)=Out9
          Else
             ' pack history
             If Var1=MaxHistory Then
                For Var=History.Count2(Temp0) To MaxHistory-1
                   History2(Temp0,Var)=History2(Temp0,Var+1)
                Next
                History.Count2(Temp0)=MaxHistory
                History2(Temp0,MaxHistory)=Out9
             Else
                For Var=History.Count2(Temp0) To Var1-1
                   History2(Temp0,Var)=History2(Temp0,Var+1)
                Next
                History2(Temp0,Var1)=Out9
             Endif
          Endif
       Endif      
    Endif
 Case 3 ' right [C
    Gosub Get.Count
    ' return blank line at end of history
    IF Var1 > 0 THEN
       If Var1 = History.Count2(Temp0) Then
          EndOfHistoryFlag(Temp0) = -1
          GoSub EraseLine
          Var1 = 0
          Carriage.Input=True
          Graphics.Off=True
          Var$ = ""
          Strng3=Var$
          Call IO.O
          Out9=Var$
       End If
    End If
    ' move to next history
    If Var1>0 Then
       Select Case History.Count2(Temp0)
       Case 0
          Gosub EraseLine
          History.Count2(Temp0)=Var1
          Carriage.Input=True
          Graphics.Off=True
          Var$=Rtrim$(History2(Temp0,Var1))
          Strng3=Var$
          Call IO.O
          Out9=Var$
       Case 1 To MaxHistory-1
          If History.Count2(Temp0)+1<=Var1 Then
             Gosub EraseLine
             History.Count2(Temp0)=History.Count2(Temp0)+1
             Carriage.Input=True
             Graphics.Off=True
             Var$=Rtrim$(History2(Temp0,History.Count2(Temp0)))
             Strng3=Var$
             Call IO.O
             Out9=Var$
          Else
             If History.Count2(Temp0)=Var1 Then
                Gosub EraseLine
                Carriage.Input=True
                Graphics.Off=True
                Var$=Rtrim$(History2(Temp0,Var1))
                Strng3=Var$
                Call IO.O
                Out9=Var$
             Endif
          Endif
       Case MaxHistory
          Gosub EraseLine
          Carriage.Input=True
          Graphics.Off=True
          Var$=Rtrim$(History2(Temp0,MaxHistory))
          Strng3=Var$
          Call IO.O
          Out9=Var$
       End Select
    Endif
 Case 4 ' left [D
    Gosub Get.Count
    If Var1 > 0 Then
       If EndOfHistoryFlag(Temp0) Then
          EndOfHistoryFlag(Temp0) = 0
          GoSub EraseLine
          History.Count2(Temp0) = Var1
          Var$ = RTrim$(History2(Temp0, Var1))
          Carriage.Input=True
          Graphics.Off=True
          Var$=Rtrim$(History2(Temp0,Var1))
          Strng3=Var$
          Call IO.O
          Out9=Var$
          Var1=0
       Endif
    Endif
    If Var1>0 Then
       Select Case History.Count2(Temp0)
       Case 0
          Gosub EraseLine
          History.Count2(Temp0)=Var1
          Carriage.Input=True
          Graphics.Off=True
          Var$=Rtrim$(History2(Temp0,Var1))
          Strng3=Var$
          Call IO.O
          Out9=Var$
       Case 1
          Gosub EraseLine
          Carriage.Input=True
          Graphics.Off=True
          Var$=Rtrim$(History2(Temp0,1))
          Strng3=Var$
          Call IO.O
          Out9=Var$
       Case Else
          If History.Count2(Temp0)-1>0 Then
             Gosub EraseLine
             History.Count2(Temp0)=History.Count2(Temp0)-1
             Carriage.Input=True
             Graphics.Off=True
             Var$=Rtrim$(History2(Temp0,History.Count2(Temp0)))
             Strng3=Var$
             Call IO.O
             Out9=Var$
          Endif
       End Select
    Endif
 Case 8 ' home [H
    Gosub Get.Count
    If Var1>0 Then
       Gosub EraseLine
       History.Count2(Temp0)=1
       Carriage.Input=True
       Graphics.Off=True
       Var$=Rtrim$(History2(Temp0,1))
       Strng3=Var$
       Call IO.O
       Out9=Var$
    Endif
 Case 11 ' end [K
    Gosub Get.Count
    If Var1>0 Then
       Gosub EraseLine
       History.Count2(Temp0)=Var1
       Carriage.Input=True
       Graphics.Off=True
       Var$=Rtrim$(History2(Temp0,Var1))
       Strng3=Var$
       Call IO.O
       Out9=Var$
    Endif
 End Select
 Exit Sub
Get.Count:
 Var1=0
 For Var2=MaxHistory To 1 Step -1
    If Rtrim$(History2(Temp0,Var2))<>Nul Then
       Var1=Var2
       Exit For
    Endif
 Next
 Return
EraseLine:
 If Len(Out9) Then
    For VarZ=1 To Len(Out9)
       Call Back.Space
    Next
 Endif
 Out9=Nul
 Return
Error.Resume45z:
 Exit Sub
Error.Trap45z:
 Resume Error.Resume45z
End Sub

' stores last error string
SUB Display.Error
 VarX$ = Form$(Cdbl(ErrorLine))
 VarZ$ = Right$("000"+Mid$(Str$(ErrorValue),2),3)

 ' "Error #000: Line "
 VarQ2$ = "Error #"+VarZ$+": "
 VarQ$ = VarQ2$ + "Line "+VarX$+": "

 ' "Internal error #000: "
 VarR$ = "Internal error #"+VarZ$+": "

 ' "Reserved error #000: "
 VarS$ = "Reserved error #"+VarZ$+": "

 ' parameter string
 VarN$ = Strng
 If VarN$ = "" Or VarN$ = ")" Then
    VarN$ = "<unknown>"
 Endif

 SELECT CASE ErrorValue
 CASE 1
    Strng3 = VarR$ + "Next without For"
 CASE 2
    Strng3 = VarQ$ + "Syntax error"
 CASE 3
    Strng3 = VarR$ + "Return without Gosub"
 CASE 4
    Strng3 = VarR$ + "Out of Data"
 CASE 5
    Strng3 = VarQ$ + "Illegal function call"
 CASE 6
    Strng3 = VarQ$ + "Overflow"
 CASE 7
    Strng3 = VarQ$ + "Out of memory"
 CASE 8
    Strng3 = VarR$ + "Label not defined"
 CASE 9
    Strng3 = VarQ$ + "Subscript out of range"
 CASE 10
    Strng3 = VarR$ + "Duplicate definition"
 CASE 11
    Strng3 = VarQ$ + "Division by zero"
 CASE 12
    Strng3 = VarR$ + "Illegal in direct mode"
 CASE 13
    Strng3 = VarR$ + "Type mismatch"
 CASE 14
    Strng3 = VarQ$ + "Out of string space"
 CASE 15
    Strng3 = VarQ$ + "Invalid Pset statement"
 CASE 16
    Strng3 = VarQ$ + "String formula too complex"
 CASE 17
    Strng3 = VarS$ + "Cannot continue"
 CASE 18
    Strng3 = VarR$ + "Function not defined"
 CASE 19
    Strng3 = VarQ$ + "No Resume"
 CASE 20
    Strng3 = VarQ$ + "Resume without error"
 CASE 21
    Strng3 = VarQ$ + "Syntax error specifying filename to open"
 CASE 22
    Strng3 = VarQ$ + "Syntax error specifying filename to close"
 CASE 23
    Strng3 = VarQ$ + "Syntax error specifying filename field"
 CASE 24
    Strng3 = VarQ$ + "Device timeout"
 CASE 25
    Strng3 = VarQ$ + "Device fault"
 CASE 26
    Strng3 = VarR$ + "For without Next"
 CASE 27
    Strng3 = VarQ$ + "Out of paper"
 CASE 28
    Strng3 = VarQ$ + "Invalid Line statement"
 CASE 29
    Strng3 = VarR$ + "While without Wend"
 CASE 30
    Strng3 = VarR$ + "Wend without While"
 CASE 31
    Strng3 = VarQ$ + "Syntax error writing to file"
 CASE 32
    Strng3 = VarQ$ + "Syntax error printing to file"
 CASE 33
    Strng3 = VarR$ + "Duplicate label"
 CASE 34
    Strng3 = VarQ$ + "Syntax error inputing from file"
 CASE 35
    Strng3 = VarR$ + "Subprogram not defined"
 CASE 36
    Strng3 = VarQ$ + "Syntax error line inputing from file"
 CASE 37
    Strng3 = VarR$ + "Argument-count mismatch"
 CASE 38
    Strng3 = VarQ$ + "Array not defined"
 CASE 39
    Strng3 = VarQ$ + "Invalid Circle statement"
 CASE 40
    Strng3 = VarQ$ + "Variable required"
 CASE 41
    Strng3 = VarQ$ + "Invalid Lset statement"
 CASE 42
    Strng3 = VarQ$ + "Invalid Rset statement"
 CASE 43
    Strng3 = VarQ$ + "Invalid Put statement"
 CASE 44
    Strng3 = VarQ$ + "Invalid Get statement"
 CASE 45
    Strng3 = VarQ$ + "Invalid Read statement"
 CASE 46
    Strng3 = VarQ$ + "Invalid Draw statement"
 CASE 47
    Strng3 = VarQ$ + "Invalid Play statement"
 CASE 48
    Strng3 = VarQ$ + "Invalid Paint statement"
 CASE 49
    Strng3 = VarQ$ + "Invalid Get/Put statement"
 CASE 50
    Strng3 = VarQ$ + "Field overflow"
 CASE 51
    Strng3 = VarS$ + "Internal compiler error"
 CASE 52
    Strng3 = VarQ$ + "Bad file name or number"
 CASE 53
    Strng3 = VarQ$ + "File not found"
 CASE 54
    Strng3 = VarQ$ + "Bad file mode"
 CASE 55
    Strng3 = VarQ$ + "File already open"
 CASE 56
    Strng3 = VarQ$ + "Field statement active"
 CASE 57
    Strng3 = VarQ$ + "Device I/O error"
 CASE 58
    Strng3 = VarQ$ + "File already exists"
 CASE 59
    Strng3 = VarQ$ + "Bad record length"
 CASE 60
    Strng3 = VarQ$ + "Invalid Bsave/Bload statement. Filename: " + Filename$
 CASE 61
    Strng3 = VarQ$ + "Disk full"
 CASE 62
    Strng3 = VarQ$ + "Input past end of file"
 CASE 63
    Strng3 = VarQ$ + "Bad record number"
 CASE 64
    Strng3 = VarQ$ + "Bad file name: " + LCASE$(Filename)
 CASE 65
    Strng3 = VarQ$ + "Invalid Data statement"
 CASE 66
    Strng3 = VarQ$ + "Out of data"
 CASE 67
    Strng3 = VarQ$ + "Too many files"
 CASE 68
    Strng3 = VarQ$ + "Device unavailable"
 CASE 69
    Strng3 = VarQ$ + "Communication buffer overflow"
 CASE 70
    Strng3 = VarQ$ + "File permission denied"
 CASE 71
    Strng3 = VarQ$ + "Disk not ready"
 CASE 72
    Strng3 = VarQ$ + "Disk-media error"
 CASE 73
    Strng3 = VarR$ + "Feature unavailable"
 CASE 74
    Strng3 = VarQ$ + "Rename across disks"
 CASE 75
    Strng3 = VarQ$ + "Path/File access error"
 CASE 76
    Strng3 = VarQ$ + "Path not found"
 CASE 77
    Strng3 = VarQ$ + "Invalid View statement"
 CASE 78
    Strng3 = VarQ$ + "Invalid Window statement"
 CASE 80
    Strng3 = VarR$ + "Feature removed"
 CASE 81
    Strng3 = VarQ$ + "Invalid name"
 CASE 82
    Strng3 = VarS$ + "Table not found" ' isam
 CASE 83
    Strng3 = VarS$ + "Index not found" ' isam
 CASE 84
    Strng3 = VarS$ + "Invalid column" ' isam
 CASE 85
    Strng3 = VarS$ + "No current record" ' isam
 CASE 86
    Strng3 = VarS$ + "Duplicate value for unique index" ' isam
 CASE 87
    Strng3 = VarS$ + "Invalid operation on null index" ' isam
 CASE 88
    Strng3 = VarS$ + "Database needs repair" ' isam
 CASE 89
    Strng3 = VarS$ + "Insufficient ISAM buffers" ' isam
 CASE 91
    Strng3 = VarQ$ + "Unknown statement"
 CASE 92
    Strng3 = VarQ$ + "Whatis: " + VarN$
 CASE 97
    Strng3 = VarQ$ + "Mismatched for/next"
 CASE 98
    Strng3 = VarQ$ + "Mismatched do/loop"
 CASE 99
    Strng3 = VarQ$ + "Missing line number"
 CASE 100
    Strng3 = VarQ$ + "Unmatched gosub"
 CASE 101
    Strng3 = VarQ2$ + "Error accessing file " + LCASE$(Filename)
 CASE 102
    Strng3 = VarQ$ + "Mismatched select/end select"
 CASE 103
    Strng3 = VarQ$ + "Mismatched forif/nextif"
 CASE 104
    Strng3 = VarQ$ + "Mismatched loopif/endloopif"
 CASE 105
    Strng3 = VarQ$ + "Mismatched selectif/end selectif"
 CASE 110
    Strng3 = VarQ$ + "Unknown swap statement"
 CASE 111
    Strng3 = VarQ$ + "Record size overflow"
 CASE 112
    Strng3 = VarQ$ + "Error chaining to program"
 CASE 113
    Strng3 = VarQ$ + "Error naming file"
 CASE 114
    Strng3 = VarQ$ + "Error killing file"
 CASE 115
    Strng3 = VarQ$ + "Error changing directory"
 CASE 116
    Strng3 = VarQ$ + "Error making directory"
 CASE 117
    Strng3 = VarQ$ + "Error removing directory"
 CASE 118
    Strng3 = VarQ$ + "Error setting date"
 CASE 119
    Strng3 = VarQ$ + "Error setting time"
 CASE 120
    Strng3 = VarQ$ + "Error changing drive"
 CASE 121
    Strng3 = VarQ$ + "Error using OUT statement"
 CASE 122
    Strng3 = VarQ$ + "Error using WAIT statement"
 CASE 123
    Strng3 = VarQ$ + "Error using ABSOLUTE statement"
 CASE 124
    Strng3 = VarQ$ + "Error using POKE statement"
 CASE 125
    Strng3 = VarQ$ + "Error using DEFSEG statement"
 CASE 126
    Strng3 = VarQ$ + "Error specifying file handle number"
 CASE 127
    Strng3 = VarQ$ + "Error specifying hexidecimal number"
 CASE 128
    Strng3 = VarQ$ + "Error specifying octal number"
 CASE 129
    Strng3 = VarQ$ + "Error specifying binary number"
 CASE 130
    Strng3 = VarQ$ + "Error specifying decimal value"
 CASE 131
    Strng3 = VarQ$ + "Error specifying numeric value"
 CASE 132
    Strng3 = VarQ$ + "Error specifying factorial value"
 CASE 133
    Strng3 = VarQ$ + "Error specifying quoted value"
 CASE 134
    Strng3 = VarQ$ + "Bad input variable"
 CASE 135
    Strng3 = VarQ$ + "Mismatched data"
 CASE 136
    Strng3 = VarQ$ + "Too few input variables"
 CASE 137
    Strng3 = VarQ$ + "Too many input variables"
 CASE 138
    Strng3 = VarQ$ + "Missing left parenthesis"
 CASE 139
    Strng3 = VarQ$ + "Missing right parenthesis"
 CASE 140
    Strng3 = VarQ2$ + "Account maximum record size overflow"
 CASE 141
    Strng3 = VarQ$ + "Account record size overflow"
 CASE 142
    Strng3 = VarQ$ + "Illegal characters in filename"
 CASE 143
    Strng3 = VarQ$ + "Illegal command"
 CASE 144
    Strng3 = VarQ2$ + "Lost carrier"
 CASE 145
    Strng3 = VarQ2$ + "Program terminated"
 CASE 146
    Strng3 = VarQ2$ + "Unable to read user profile"
 CASE 147
    Strng3 = VarQ$ + "Line printer not selected"
 CASE 148
    Strng3 = VarQ$ + "Specified double exponent"
 CASE 149
    Strng3 = VarQ$ + "Missing exponent value"
 CASE 150
    Strng3 = VarQ$ + "Bad exponent unary sign"
 CASE 151
    Strng3 = VarQ$ + "Bad exponent decimal point"
 CASE 152
    Strng3 = VarQ$ + "Bad DEF FN declaration"
 CASE 153
    Strng3 = VarQ$ + "FN call error: " + VarN$
 CASE 154
    Strng3 = VarQ$ + "Bad SHELL call"
 CASE 155
    Strng3 = VarQ$ + "Restricted command"
 CASE 156
    Strng3 = VarQ$ + "Maximum nested gosub:"+Str$(MaxNestGosub)+" levels"
 CASE 157
    Strng3 = VarQ$ + "Square root of a negative value"
 CASE 158
    Strng3 = VarQ$ + "Unknown INT86 function"
 CASE 159
    Strng3 = VarQ$ + "Feature not available"
 CASE 160
    Strng3 = VarQ$ + "Unknown metacommand"
 CASE 161
    Strng3 = VarQ$ + "Illegal printer function call"
 CASE 162
    Strng3 = VarR$ + "Unsupported BPB call"
 Case 168
    Strng3 = VarQ$ + "Invalid TRIANGLE statement."
 Case 169
    Strng3 = VarQ$ + "Invalid POLYGON statement."
 Case 170
    Strng3 = VarQ$ + "Invalid CUBE statement."
 Case 171
    Strng3 = VarQ$ + "Invalid SQUARE statement."
 CASE 172
    Strng3 = VarQ$ + "Error recurse chaining to program"
 Case 173
    Strng3 = VarQ$ + "Invalid DEBUG statement."
 Case 174
    Strng3 = VarQ$ + "Invalid LLINES statement."
 Case 175
    Strng3 = VarQ$ + "Invalid SOUND statement."
 CASE 79, 90, 93 TO 96, 106 TO 109, 163 TO 167, 176 TO 255
    Strng3 = "User defined error #"+VarZ$+": Line "+VarX$
 CASE ELSE
    Strng3 = "Error #000: Error " + VarZ$
 END SELECT
 Strng3 = Strng3 + "."
 Last.Error = ErrorLine
END SUB

' function to match substring with ?, * characters in substring.
SUB InstrSUB (Var, Var1$, Var2$)
' store string match variables
S2$ = LCASE$(Var2$)
S3$ = LCASE$(Var1$)

' check default instr
IF INSTR(S2$, "*") = 0 THEN
   IF INSTR(S2$, "?") = 0 THEN
      Var = INSTR(S3$, S2$)
      EXIT SUB
   END IF
END IF

Var = -1 ' assume match

' see if S2$ matches in S3$ with substrings
FOR S3 = 1 TO LEN(S3$)
   S1$ = MID$(S3$, S3)
   P1 = 1 ' pointer to S1$
   P2 = 1 ' pointer to S2$
   P3 = S3 ' position match
   DO
      ' check token beyond string
      IF P2 > LEN(S2$) THEN
         Var = P3
         EXIT SUB
      END IF

      ' check character in S2$ at P2
      V$ = MID$(S2$, P2, 1)
      SELECT CASE V$
      CASE "*" ' global character
         ' scan to next char
         IF P2 > LEN(S2$) THEN
            EXIT DO
         END IF
         S4$ = MID$(S2$, P2 + 1, 1)
         SELECT CASE S4$
         CASE "*", "?"
            P2 = P2 + 1
         CASE ELSE
            DO
               IF MID$(S1$, P1, 1) = S4$ THEN
                  EXIT DO
               END IF
               IF P1 >= LEN(S1$) THEN
                  EXIT DO
               END IF
               P1 = P1 + 1
            LOOP
            P3 = P1
            P2 = P2 + 1
         END SELECT
      CASE "?" ' wildcard character
         P1 = P1 + 1
         P2 = P2 + 1
      CASE ELSE ' ascii character
         IF MID$(S1$, P1, 1) <> V$ THEN ' no match
            EXIT DO
         END IF
         P1 = P1 + 1
         P2 = P2 + 1
      END SELECT
   LOOP
NEXT
Var = 0 ' no match
END SUB
