'*
'*  ANSIED v2.42
'*---------------------------------------------------------------------------
'*  Full Screen Text Editor for RBBS-PC
'*  QuickBASIC v3.0 Version
'*  02-14-90
'*
'* Changes from the QB 4.5 Version are marked with the
'* comment "QB 3.0 Mod"
'*
'*  v2.1xx ... made it work with RBBS v17
'*  v2.2 ... fixed some inconsistincies in the code as to # of lines in msg.
'*           Some of the code thought 99 was length, some thought 100.
'*  v2.3 .. let it work with quoted reply.  No more REDIM of ZOutTxt$
'*  v2.4 .. removed tabs, margins code to be smaller
'*  v2.41.. fixed bug with loss of bold attribute occasionally
'*  v2.42.. made it work as a v17.3 subroutine.  Added block delete.
'*
'*  Returns:
'*  ZSubParm  =  1 - Save Message
'*            =  2 - Abort Message
'*            = -1 - Dropped Carrier
'*            = -2 - Sleep Disconnect
'*

'  $INCLUDE: 'RBBS-VAR.MOD'


10 DEFINT A-Z

13    COMMON SHARED /Ansied/ CurrentRow, CurrentCol, TopLine
      COMMON SHARED /Ansied/ OldColour, IsBold, InsertMode
      COMMON SHARED /Ansied/ BlankLine$, SoftSpace$, ESCKey$, CarrRet$
      COMMON SHARED /Ansied/ ColLeftKey$, ColRightKey$, HomeKey$, EndKey$
      COMMON SHARED /Ansied/ PageUpKey$, PageDownKey$, LineUpKey$
      COMMON SHARED /Ansied/ LineDownKey$, HelpKey$, ReformTextKey$
      COMMON SHARED /Ansied/ ReflowTextKey, EndSessionKey$, ToggleINSKey$
      COMMON SHARED /Ansied/ RepaintKey$, BlockDelActive
      COMMON SHARED /Ansied/ BlockLine1, BlockLine2
      COMMON SHARED /Ansied/ YellowFore, CyanFore, WhiteFore

SUB Ansied STATIC

      REDIM ZWorkAra$(24)             ' Top 24 lines of screen (bottom line
				      ' used by comm program, top line =
				      ' (1) used for menu)
14    ESCKey$ = CHR$(27)
      BackspKey$ = CHR$(8)
      OtherBackspKey$ = CHR$(127)
      TabKey$ = CHR$(9)
      DelKey$ = CHR$(127)
      CarrRet$ = CHR$(13)
      ZLineFeed$ = CHR$(10)
      LineUpKey$ = CHR$(5)        ' Ctrl-E
      LineDownKey$ = CHR$(24)     ' Ctrl-X
      ColLeftKey$ = CHR$(19)      ' Ctrl-S
      ColRightKey$ = CHR$(4)      ' Ctrl-D
      WordLeftKey$ = CHR$(1)      ' Ctrl-A
      WordRightKey$ = CHR$(6)     ' Ctrl-F
      PageUpKey$ = CHR$(18)       ' Ctrl-R
      PageDownKey$ = CHR$(3)      ' Ctrl-C
      HomeKey$ = CHR$(23)         ' Ctrl-W
      EndKey$ = CHR$(26)          ' Ctrl-Z
      RepaintKey$ = CHR$(16)      ' Ctrl-P
      LineDeleteKey$ = CHR$(25)   ' Ctrl-Y
      CharDeleteKey$ = CHR$(7)    ' Ctrl-G
      ReformTextKey$ = CHR$(2)    ' Ctrl-B
      ReflowTextKey$ = CHR$(15)   ' Ctrl-O
      ToggleINSKey$ = CHR$(22)    ' Ctrl-V
      EndSessionKey$ = CHR$(11)   ' Ctrl-K
      HelpKey$ = CHR$(14)         ' Ctrl-N

      SoftSpace$ = CHR$(250)
      
15    BlankLine$ = ""
      
      InsertMode = ZTrue
      ZRightMargin = 75
      OldColour = 0
      Bold = ZFalse
      IsBold = 99                 ' v2.41
      BlockDelActive = ZFalse
      CurrentCol = 0
      CurrentRow = 0
      TopLine = 1           ' Line of ZOutTxt$ that corresponds to the top of
			    ' the displayed image (1..12..23..34..45..56..78)

      BlockDelKeys$ = ESCKey$ + LineUpKey$ + LineDownKey$ + PageUpKey$ + PageDownKey$ + CarrRet$

16    FOR I = 1 TO 24
	  ZWorkAra$(I) = BlankLine$
      NEXT I

      '*
      '* Initialize the screen    'Pe 03/22/90
      '*

17  IF ZFG4$ <> "" THEN  
     YellowFore = 33 
     CyanFore = 36 
     WhiteFore = 37
Else
     YellowFore = 37 
     CyanFore = 37 
     WhiteFore = 37
END IF

      CALL ClearScreen
      CALL ClearMainMenu
      CALL UpdateStatusLine
      CALL UpdateScreen   ' v2.3
      CALL MoveCursor(2, 1)

      '*
      '* Run the Editor
      '*

18    WHILE 1

	 CALL Carrier
	 IF ZSubParm = -1 THEN GOTO 1001
	 CALL Getch(B$)
	 IF ZSubParm <> 0 THEN GOTO 1001

19       IF B$ = ESCKey$ THEN
	    IF BlockDelActive THEN
	       BlockDelActive = ZFalse
	       CALL SaveCursor(RowSave, ColSave)
	       CALL UpdateStatusLine
	       CALL MoveCursor(RowSave, ColSave)
               B$ = CHR$(255)
	    ELSE
	       CALL Getch(B$)
	       IF ZSubParm <> 0 THEN GOTO 1001
	       IF B$ = "[" THEN           ' ANSI sequence
		  CALL Getch(B$)
		  IF ZSubParm <> 0 THEN GOTO 1001
		  IF B$ = "C" THEN
		     B$ = ColRightKey$
		  ELSEIF B$ = "D" THEN
		     B$ = ColLeftKey$
		  ELSEIF B$ = "A" THEN
		     B$ = LineUpKey$
		  ELSEIF B$ = "B" THEN
		     B$ = LineDownKey$
		  END IF
	       END IF
	    END IF
	 END IF

	 IF BlockDelActive AND INSTR(BlockDelKeys$, B$) = 0 THEN

	 ELSEIF BlockDelActive AND B$ = CarrRet$ THEN

	    CALL CarrRetKey
	    CALL MoveCursor(RowSave, ColSave)

	 ELSEIF B$ = ESCKey$ THEN

            '*
            '* User wants to see main menu
            '*

            CALL SaveCursor(RowSave,ColSave)
            CALL ClearMainMenu
            CALL DisplayMainMenu
            CALL MoveCursor(RowSave, ColSave)

20          B$ = ""
            WHILE B$ <> ESCKey$ AND B$ <> "B"

               CALL Getch(B$)
               IF ZSubParm <> 0 THEN GOTO 1001
               CALL AllCaps(B$)                                    ' QB 3.0 Mod

               IF B$ = CarrRet$ THEN
                  CALL ExecuteMainMenuCommand("H")
                  IF ZSubParm = -1 THEN GOTO 1001
                  B$ = ESCKey$
               ELSEIF INSTR("HJREIPB", B$) <> 0 THEN
                  IF B$ = "B" THEN
                     BlockDelActive = ZTrue
                     BlockLine1 = RowSave + TopLine - 2
                     CALL ClearMainMenu
                     CALL Puts("Block Delete: Move cursor to last line to delete and press [ENTER], ESC Quits", YellowFore, ZFalse)
                     CALL MoveCursor(RowSave, ColSave)
                     BlockLine2 = 0
                  ELSE
                     CALL ExecuteMainMenuCommand(B$)
                     IF ZSubParm <> 0 THEN GOTO 1001
                     B$ = ESCKey$
                  END IF
               END IF

            WEND

            IF B$ <> "B" THEN
               CALL ClearMainMenu
               CALL UpdateStatusLine
            END IF

            CALL MoveCursor(RowSave, ColSave)

	 ELSEIF B$ = LineUpKey$ THEN

            '*
            '* Move the current cursor position up one line
            '*

	    IF CurrentRow > 2 THEN
	       CALL MoveCursor(CurrentRow - 1, CurrentCol)
	    ELSE
	       IF TopLine <> 1 THEN
		  TopLine = TopLine - 11
		  CALL MoveCursor(CurrentRow + 10, CurrentCol)
	       END IF
	       CALL UpdateScreen
	    END IF

	 ELSEIF B$ = LineDownKey$ THEN

            '*
            '* Move the current cursor position down one line
            '*

	    IF CurrentRow < 23 THEN
	       CALL MoveCursor(CurrentRow + 1, CurrentCol)
	    ELSE
	       IF NOT TopLine = 78 THEN
		  TopLine = TopLine + 11
		  CALL MoveCursor(CurrentRow - 10, CurrentCol)
		  CALL UpdateScreen
	       END IF
	    END IF

	 ELSEIF B$ = ColLeftKey$ THEN

            '*
            '* Move the current cursor left one column
            '*

	    IF CurrentCol > 1 THEN CALL MoveCursor(CurrentRow, CurrentCol - 1)

	 ELSEIF B$ = ColRightKey$ THEN

            '*
            '* Move the current cursor right one column
            '*

	    IF CurrentCol < 79 THEN CALL MoveCursor(CurrentRow, CurrentCol + 1)

	 ELSEIF B$ = WordRightKey$ THEN

            '*
            '* Move the current cursor right one word
            '*

	    Index = CurrentRow + TopLine - 2

	    FOR I = CurrentCol TO LEN(ZOutTxt$(Index)) - 1

	       YY$ = MID$(ZOutTxt$(Index), I, 1)
	       ZZ$ = MID$(ZOutTxt$(Index), I + 1, 1)
	       IF (YY$ = " " OR YY$ = SoftSpace$) AND ZZ$ <> " " AND ZZ$ <> SoftSpace$ THEN
		  Newcol = I + 1
		  IF Newcol > 79 THEN Newcol = 79
		  CALL MoveCursor(CurrentRow, Newcol)
		  EXIT FOR
	       END IF

	    NEXT I

	 ELSEIF B$ = WordLeftKey$ THEN

            '*
            '* Move the current cursor left one word
            '*

	    Index = CurrentRow + TopLine - 2

	    Found = ZFalse
	    FOR I = CurrentCol - 1 TO 2 STEP -1

	       ZZ$ = MID$(ZOutTxt$(Index), I, 1)
	       YY$ = MID$(ZOutTxt$(Index), I - 1, 1)
	       IF (YY$ = " " OR YY$ = SoftSpace$) AND ZZ$ <> " " AND ZZ$ <> SoftSpace$ THEN
		  Newcol = I
		  CALL MoveCursor(CurrentRow, Newcol)
		  Found = ZTrue
		  EXIT FOR
	       END IF

	    NEXT I
	    IF NOT Found THEN
	       CALL MoveCursor(CurrentRow, 1)
	    END IF

	 ELSEIF B$ = HomeKey$ THEN

            '*
            '* Move cursor to the start of the line
            '*

	    CALL MoveCursor(CurrentRow, 1)

	 ELSEIF B$ = EndKey$ THEN

            '*
            '* Move cursor to the end of the line
            '*

	    Index = CurrentRow + TopLine - 2
	    IF ZOutTxt$(Index) = STRING$(79, 250) THEN
	       Newcol = 1
	    ELSE
	       Newcol = 0
	       FOR I = LEN(ZOutTxt$(Index)) TO 1 STEP -1
		  IF MID$(ZOutTxt$(Index), I, 1) <> SoftSpace$ THEN
		     Newcol = I + 1
		     EXIT FOR
		  END IF
	       NEXT I
	       IF Newcol > 79 THEN
		  Newcol = 79
	       ELSEIF Newcol < 1 THEN
		  Newcol = 1
	       END IF
	    END IF
	    CALL MoveCursor(CurrentRow, Newcol)

	 ELSEIF B$ = PageDownKey$ THEN

            '*
            '* Move the display one page down
            '*

	    TopLine = TopLine + 22
	    IF TopLine > 78 THEN TopLine = 78
	    CALL UpdateScreen

	 ELSEIF B$ = PageUpKey$ THEN

            '*
            '* Move the display one page up
            '*

	    TopLine = TopLine - 22
	    IF TopLine < 1 THEN TopLine = 1
	    CALL UpdateScreen

	 ELSEIF B$ = LineDeleteKey$ THEN

            '*
            '* Delete the current line in the file
            '*

            CALL SaveCursor(RowSave,ColSave)
	    CALL DeleteCurrentLine
	    CALL MoveCursor(RowSave, ColSave)

	 ELSEIF B$ = CharDeleteKey$ THEN

            '*
            '* Delete the current character
            '*

	    Index = CurrentRow + TopLine - 2
	    IF CurrentCol <= LEN(ZOutTxt$(Index)) THEN
	       CALL MoveCursor(CurrentRow, CurrentCol + 1)
	       CALL BackspChar
	    END IF

	 ELSEIF B$ = BackspKey$ OR B$ = OtherBackspKey$ THEN

            '*
            '* Back up one character and destroy it
            '*

	    CALL BackspChar

	 ELSEIF B$ = CarrRet$ THEN

            '*
            '* Move to the next line, col LM
            '*

            CALL CarrRetKey

	 ELSEIF B$ = HelpKey$ OR B$ = ReformTextKey$ OR B$ = ReflowTextKey$ OR B$ = EndSessionKey$ OR B$ = ToggleINSKey$ OR B$ = RepaintKey$ THEN

            '*
            '* Execute a main menu command
            '*

            YY$ = HelpKey$ + ReformTextKey$ + ReflowTextKey$ + EndSessionKey$ + ToggleINSKey$ + RepaintKey$

            I = INSTR(YY$, B$)
            CALL SaveCursor(RowSave,ColSave)
            CALL ExecuteMainMenuCommand(MID$("HJREIP", I, 1))
            IF ZSubParm <> 0 THEN GOTO 1001
            CALL UpdateStatusLine
            CALL MoveCursor(RowSave, ColSave)

	 ELSEIF ASC(B$) > 127 OR ASC(B$) < 32 THEN

            '*
            '* Ignore characters above 127 or below 32
            '*

	 ELSE

            '*
            '* Input was a normal character
            '*

	    CALL NormalChar(B$)

	 END IF

      WEND

1001  REDIM ZWorkAra$(13)

END SUB         ' Sub AnsiEd

'*----------------------------------------------------------------------------*
'*  This routine handles the user entering the backspace key                  *
'*----------------------------------------------------------------------------*
SUB BackspChar STATIC

      CALL SaveCursor(RowSave,ColSave)

      Index = TopLine + CurrentRow - 2
      IF Index = 1 AND CurrentCol = 1 AND CurrentRow = 2 THEN EXIT SUB

2101  AtEndOfLine = CurrentCol > LEN(ZOutTxt$(Index))

      IF CurrentCol > 1 THEN

2102     ZOutTxt$(Index) = LEFT$(ZOutTxt$(Index), CurrentCol - 2) + MID$(ZOutTxt$(Index), CurrentCol)
	 CALL EraseToEOL(CurrentRow, CurrentCol - 1)
	 IF NOT AtEndOfLine THEN
	    YY$ = MID$(ZOutTxt$(Index), ColSave - 1)
	    CALL MoveCursor(RowSave, ColSave - 1)
	    CALL Puts(YY$, YellowFore, ZTrue)
	 END IF
	 CALL MoveCursor(RowSave, ColSave - 1)
	 ZWorkAra$(CurrentRow) = ZOutTxt$(Index)

      ELSEIF LEN(ZOutTxt$(Index - 1)) >= ZRightMargin THEN

      ELSE

	 Newcol = LEN(ZOutTxt$(Index - 1)) + 1
	 YY$ = ZOutTxt$(Index)
	 CALL NoSoft(YY$)
	 ZOutTxt$(Index - 1) = ZOutTxt$(Index - 1) + YY$
	 IF LEN(ZOutTxt$(Index - 1)) < ZRightMargin THEN
	    FOR I = Index TO 98        ' v2.2
	       ZOutTxt$(I) = ZOutTxt$(I + 1)
	    NEXT I
	    ZOutTxt$(99) = BlankLine$       ' v2.2
	 ELSE
	    CALL FindWrap(LEFT$(ZOutTxt$(Index - 1), ZRightMargin + 1), I)
	    IF I = 0 OR I = 1 THEN I = ZRightMargin
	    ZOutTxt$(Index) = MID$(ZOutTxt$(Index - 1), I + 1)
	    ZOutTxt$(Index - 1) = LEFT$(ZOutTxt$(Index - 1), I)
	 END IF
	 IF RowSave > 2 THEN
	    CALL MoveCursor(RowSave - 1, Newcol)
	    CALL UpdateScreen
	 ELSE
	    CALL MoveCursor(RowSave, Newcol)
	    CALL Ungetch(LineUpKey$)
	 END IF

      END IF

END SUB

'*----------------------------------------------------------------------------*
'*  This routine handles carriage returns entered in the file                 *
'*----------------------------------------------------------------------------*
SUB CarrRetKey STATIC

      IF BlockDelActive THEN
	 BlockDelActive = ZFalse
	 Index = CurrentRow + TopLine - 2
	 BlockLine2 = Index
	 IF Index < BlockLine1 THEN
	    BlockLine2 = BlockLine1
	    BlockLine1 = Index
	 END IF
	 K = 0
	 FOR I = BlockLine2 + 1 TO 99
	    ZOutTxt$(BlockLine1 + K) = ZOutTxt$(I)
	    K = K + 1
	 NEXT I
         WHILE BlockLine1 + K <= 99
            ZOutTxt$(BlockLine1 + K) = BlankLine$
            K = K + 1
         WEND
	 CALL UpdateScreen
	 CALL UpdateStatusLine
	 EXIT SUB
      END IF

2000  Index = CurrentRow + TopLine - 2
      IF Index >= 99 THEN EXIT SUB  ' v2.2
      IF InsertMode THEN         ' Insert a new line
	 FOR I = 98 TO Index + 1 STEP -1  ' v2.2
	    ZOutTxt$(I + 1) = ZOutTxt$(I)
	 NEXT I
	 IF LEN(ZOutTxt$(Index)) >= CurrentCol THEN
	    ZOutTxt$(Index + 1) = MID$(ZOutTxt$(Index), CurrentCol)
	    ZOutTxt$(Index) = LEFT$(ZOutTxt$(Index), CurrentCol - 1)
	 ELSE
	    ZOutTxt$(Index + 1) = ""
	 END IF
	 CALL UpdateScreen
      END IF
      IF CurrentRow < 23 THEN
	 CALL MoveCursor(CurrentRow + 1, 1)
      ELSE
	 CALL MoveCursor(CurrentRow, 1)
	 CALL Ungetch(LineDownKey$)
      END IF

END SUB

'*----------------------------------------------------------------------------*
'*           This routine clears a line from the screen                       *
'*----------------------------------------------------------------------------*
SUB ClearLine (LineNumber) STATIC

      CALL EraseToEOL(LineNumber, 1)

END SUB

'*----------------------------------------------------------------------------*
'*           This routine clears the main menu from the top line              *
'*----------------------------------------------------------------------------*
SUB ClearMainMenu STATIC

      CurrentRow = 0
      CurrentCol = 0
      CALL EraseToEOL(1, 1)

END SUB

'*----------------------------------------------------------------------------*
'*  This routine clears the screen and moves the cursor to row 2, col 1       *
'*----------------------------------------------------------------------------*
SUB ClearScreen STATIC

      CurrentRow = 0
      CurrentCol = 0
300   ZZ$ = "[2J[0m[2;1H"      ' clear screen, column 1, row 2
      FOR I = 1 TO 23
	 ZWorkAra$(I) = BlankLine$
      NEXT I
      CALL Puts(ZZ$, 99, ZFalse)
      ZSubParm = 2
      CALL Line25
      ZSubParm = 0
      CurrentCol = 1
      CurrentRow = 2
      IsBold = 99          ' v2.41

      CALL MoveCursor(2, 1)

END SUB

'*----------------------------------------------------------------------------*
'*  This routine deletes the current line on the screen and in the array      *
'*  ZOutTxt$, and moves the next lower line up one  It then repaints the      *
'*  affected portion of the screen (from the deleted line down)               *
'*----------------------------------------------------------------------------*
SUB DeleteCurrentLine STATIC

1900  Index = TopLine + CurrentRow - 2
      FOR I = Index TO 98
	 ZOutTxt$(I) = ZOutTxt$(I + 1)
      NEXT I
      ZOutTxt$(99) = BlankLine$
      CALL UpdateScreen

END SUB

'*----------------------------------------------------------------------------*
'*        This routine displays the main menu on the top line                 *
'*----------------------------------------------------------------------------*
SUB DisplayMainMenu STATIC

      CurrentRow = 0
      CurrentCol = 0
700   CALL MoveCursor(1, 1)
      CALL QuickTput(ZEmphasizeOff$, 0)
      YY$ = "Main Menu: [H]elp E)nd R)eflow J)ustify I)ns/Ovw P)aint B)lock Del   ESC Quits"
      YY$ = YY$ + SPACE$(79 - LEN(YY$))
      ZHiLiteOff = ZFalse
      CALL ColorPrompt(YY$)
      CALL Puts(YY$, 99, ZTrue)
      IsBold = 99                  ' v2.41
      CurrentRow = 0
      CurrentCol = 0

END SUB

'*----------------------------------------------------------------------------*
'*  This routine is called to save or abort the msg                           *
'*----------------------------------------------------------------------------*
SUB DoneWithMsg STATIC

2300  CALL SaveCursor(RowSave,ColSave)
      CALL ClearMainMenu
      CALL QuickTput(ZEmphasizeOff$, 0)
      CurrentRow = 0
      CurrentCol = 0
      CALL MoveCursor(1, 1)
      YY$ = "End Message: S)ave, A)bort, or [C]ontinue? "
      ZHiLiteOff = ZFalse
      CALL ColorPrompt(YY$)
      CALL Puts(YY$, 99, ZTrue)
      CurrentRow = 0
      CurrentCol = 0
      CALL Getch(B$)
      IF ZSubParm <> 0 THEN EXIT SUB
      WHILE INSTR("SAC", B$) = 0 AND INSTR("sac", B$) = 0 AND B$ <> CHR$(27) AND B$ <> CHR$(13)
	 CALL Getch(B$)
	 IF ZSubParm <> 0 THEN EXIT SUB
      WEND
      IF B$ = CHR$(13) OR B$ = CHR$(27) THEN B$ = "C"
      I = INSTR("SAC", B$)
      IF I = 0 THEN I = INSTR("sac", B$)
      ON I GOTO SaveMsg, AbortMsg, ContinueMsg
      EXIT SUB

ContinueMsg:

      EXIT SUB

AbortMsg:

      CALL ClearMainMenu
      CALL QuickTput(ZEmphasizeOff$, 0)
      CurrentRow = 0
      CurrentCol = 0
      CALL MoveCursor(1, 1)
      YY$ = "Abort: Are You Sure (Y)es,[N]o)? "
      ZHiLiteOff = ZFalse
      CALL ColorPrompt(YY$)
      CALL Puts(YY$, 99, ZTrue)
      CurrentRow = 0
      CurrentCol = 0
      CALL Getch(B$)
      IF ZSubParm <> 0 THEN B$ = "Y"
      IF B$ = "Y" OR B$ = "y" THEN
	 CALL ClearScreen
	 CALL QuickTput(ZEmphasizeOff$, 0)
	 ZSubParm = 2
      END IF
      EXIT SUB

SaveMsg:

      CALL ClearScreen
      FOR I = 99 TO 1 STEP -1
	 IF ZOutTxt$(I) <> BlankLine$ THEN
            EndOfMsg = I
	    EXIT FOR
	 END IF
      NEXT I
      FOR I = 1 TO EndOfMsg
	 j = INSTR(ZOutTxt$(I), SoftSpace$)
	 WHILE j <> 0
	    MID$(ZOutTxt$(I), j, 1) = " "
	    j = INSTR(ZOutTxt$(I), SoftSpace$)
	 WEND
      NEXT I
      FOR I = EndOfMsg TO 1 STEP -1
         CALL TrimTrail(ZOutTxt$," ")                              ' QB 3.0 Mod
	 IF ZOutTxt$(I) <> "" THEN
            EndOfMsg = I
	    EXIT FOR
	 END IF
      NEXT I
      ZLinesInMsg = EndOfMsg
      CALL QuickTput(ZEmphasizeOff$, 0)
      ZSubParm = 1
      EXIT SUB

END SUB

'*----------------------------------------------------------------------------*
'*    This routine clears from a position to to the end of that line          *
'*----------------------------------------------------------------------------*
SUB EraseToEOL (LineNumber, ColNumber) STATIC

      CALL SaveCursor(RowSave,ColSave)
      CALL MoveCursor(LineNumber, ColNumber)
      YY$ = "[K"
      CALL Puts(YY$, 99, ZFalse)
      CALL MoveCursor(RowSave, ColSave)

END SUB

'*----------------------------------------------------------------------------*
'* This routine executes the currently highlighted main menu command          *
'*----------------------------------------------------------------------------*
SUB ExecuteMainMenuCommand (CMD$) STATIC

1100  ZSubParm = 0
      SELECT CASE CMD$
	 CASE "H"
	    CALL HelpMe
	 CASE "E"
	    CALL DoneWithMsg
	 CASE "P"
	    CALL ClearScreen
	    CALL UpdateScreen
	 CASE "I"
	    InsertMode = NOT InsertMode
	 CASE "R"
	    CALL ReformText(ZFalse)
	 CASE "J"
	    CALL ReformText(ZTrue)
      END SELECT
      IsBold = 99        ' v2.41

END SUB

'*----------------------------------------------------------------------------*
'*  This routine finds a place in the string yy$ that could be used as a      *
'*  place to wrap the line WhereToWrap should be the last position that       *
'*  remains in the line, ie                                                   *
'*    set   currentline$ = left$(yy$,wheretowrap)                             *
'*          nextline$    = mid$ (yy$,wheretowrap+1)                           *
'*----------------------------------------------------------------------------*
SUB FindWrap (YY$, WhereToWrap) STATIC

      I = LEN(YY$)
      XX$ = " " + SoftSpace$
      
      ' back over "False hits"
      
      ZZ$ = MID$(YY$, I, 1)
      WHILE INSTR(XX$, ZZ$) <> 0 AND I <> 1
	 I = I - 1
	 ZZ$ = MID$(YY$, I, 1)
      WEND
      
      WHILE INSTR(XX$, ZZ$) = 0 AND I <> 1
	 I = I - 1
	 ZZ$ = MID$(YY$, I, 1)
      WEND
      WhereToWrap = I

END SUB

'*----------------------------------------------------------------------------*
'*         This routine reads a character from the user into yy$              *
'*----------------------------------------------------------------------------*
SUB Getch (YY$) STATIC

      ZAutoLogoff! = TIMER + ZWaitBeforeDisconnect
1500  CALL Carrier
      IF ZSubParm = -1 THEN EXIT SUB
      ZSubParm = 0
      IF LEN(ZCommPortStack$) > 0 THEN
	 YY$ = LEFT$(ZCommPortStack$, 1)
	 ZCommPortStack$ = MID$(ZCommPortStack$, 2)
	 EXIT SUB
      ELSEIF ZLocalUser THEN
	 CALL FindFKey
	 IF ZSubParm < 0 THEN EXIT SUB
	 YY$ = ZKeyPressed$
	 IF YY$ <> "" THEN EXIT SUB
	 GOTO 1500
      ELSE
	 CALL EofComm(Char%)       ' v2.2
	 IF Char% <> -1 THEN       ' v2.2
	    CALL Carrier
	    IF ZSubParm = -1 THEN EXIT SUB
	    ZSubParm = 0
	    CALL GetCom(YY$)
	    EXIT SUB
	 ELSE
	    CALL CheckTime(ZAutoLogoff!, Remain!, 1)
	    IF Remain! < 0 THEN
	       CALL UpdtCalr("Sleep disconnect", 1)
	       ZSubParm = -1
	       ZNo = ZTrue
	       ZSleepDisconnect = ZTrue
	       EXIT SUB
	    ELSE
	       GOTO 1500
	    END IF
	 END IF
      END IF

END SUB

'*----------------------------------------------------------------------------*
'*  This routine provides on-liine help for the user                          *
'*----------------------------------------------------------------------------*
SUB HelpMe STATIC

2400  CALL SaveCursor(RowSave,ColSave)
      CALL ClearScreen
      CALL MoveCursor(1, 2)
      CALL QuickTput(ZEmphasizeOff$, 0)
      CALL BufFile(ZHelpPath$ + "ANSIED.HLP", X)   ' v2.2
      CurrentRow = 0
      CurrentCol = 0
      OldColour = 0                               ' v2.2
      IsBold = 99                                 ' v2.41
      CALL ClearScreen
      FOR I = 1 TO 24
	 ZWorkAra$(I) = BlankLine$
      NEXT I
      CALL UpdateScreen
      CALL MoveCursor(ColSave, RowSave)

END SUB

'*----------------------------------------------------------------------------*
'*  This routine returns ZTrue if ZOutTxt$(I) is the last line in a paragraph *
'*----------------------------------------------------------------------------*
SUB LastParaLine (I, LastLine, Result) STATIC                      ' QB 3.0 Mod

   Result = ZFalse
   IF I = LastLine OR I = 99 THEN
      Result = ZTrue
   ELSE
      YY$ = ZOutTxt$(I)
      j = INSTR(YY$, ">")
      IF j = 0 THEN j = 6
      IF j < 5 THEN
	 Result = ZTrue
      ELSEIF YY$ = BlankLine$ THEN
	 Result = ZTrue
      ELSE
	 IF ZOutTxt$(I + 1) = BlankLine$ THEN
	    Result = ZTrue
	 ELSEIF LEFT$(ZOutTxt$(I + 1), 1) = " " THEN
	    Result = ZTrue
	 ELSE
	    K = INSTR(ZOutTxt$(I + 1), ">")
	    IF K <> 0 AND K < 5 THEN Result = ZTrue
	 END IF
      END IF
   END IF

END SUB                                                            ' QB 3.0 Mod

'*----------------------------------------------------------------------------*
'*  This routine moves the cursor to the position spec'd by newcol and        *
'*  newrow and tries to do it with the minimum number of Ansi characters      *
'*----------------------------------------------------------------------------*
SUB MoveCursor (NewRow, Newcol) STATIC

600   IF CurrentRow = NewRow AND CurrentCol = Newcol THEN
	 EXIT SUB
      ELSEIF Newcol = 1 AND NewRow = 1 THEN
	 YY$ = "[f"
      ELSEIF CurrentCol = Newcol THEN
	 ' Just the row has changed
	 IF NewRow > CurrentRow THEN
	    ' Can use the "move down" command
	    I = NewRow - CurrentRow
	    IF I = 1 THEN
	       YY$ = "[B"
	    ELSE
	       YY$ = "[" + MID$(STR$(I), 2) + "B"
	    END IF
	 ELSE
	    ' Use the "move up" command
	    I = CurrentRow - NewRow
	    IF I = 1 THEN
	       YY$ = "[A"
	    ELSE
	       YY$ = "[" + MID$(STR$(I), 2) + "A"
	    END IF
	 END IF
      ELSEIF CurrentRow = NewRow THEN
	 ' Just the column has changed
	 IF Newcol > CurrentCol THEN
	    ' Can use the "move forward" command
	    I = Newcol - CurrentCol
	    IF I = 1 THEN
	       YY$ = "[C"
	    ELSE
	       YY$ = "[" + MID$(STR$(I), 2) + "C"
	    END IF
	 ELSE
	    ' Use the "move backward" command
	    I = CurrentCol - Newcol
	    IF I = 1 THEN
	       YY$ = "[D"
	    ELSE
	       YY$ = "[" + MID$(STR$(I), 2) + "D"
	    END IF
	 END IF
      ELSE
	 ' They both changed
	 YY$ = "[" + MID$(STR$(NewRow), 2) + ";" + MID$(STR$(Newcol), 2) + "f"
      END IF
      CALL Puts(YY$, 99, ZTrue)
      CurrentRow = NewRow
      CurrentCol = Newcol

END SUB

'*----------------------------------------------------------------------------*
'*  This routine handles 'normal' characters entered into the message         *
'*----------------------------------------------------------------------------*
SUB NormalChar (YY$) STATIC

      CALL SaveCursor(RowSave,ColSave)
      Index = CurrentRow + TopLine - 2
      currentlineblank = (ZOutTxt$(Index) = BlankLine$)
      lbi = LEN(ZOutTxt$(Index))
      
      IF CurrentCol = 80 THEN EXIT SUB
	 
      AtEndOfLine = ZFalse
      
      IF CurrentCol > lbi THEN
      
	 ZOutTxt$(Index) = ZOutTxt$(Index) + SPACE$(CurrentCol - lbi)
	 ZWorkAra$(CurrentRow) = ZWorkAra$(CurrentRow) + SPACE$(CurrentCol - lbi)
	 lbi = LEN(ZOutTxt$(Index))
	 AtEndOfLine = ZTrue
	 
      END IF

      IF (CurrentCol <= ZRightMargin AND AtEndOfLine) OR (CurrentCol <= ZRightMargin AND NOT InsertMode) THEN

	 ' single character changed
	    
	 MID$(ZOutTxt$(Index), CurrentCol, 1) = YY$
	 MID$(ZWorkAra$(CurrentRow), CurrentCol, 1) = YY$
	 CALL Puts(YY$, YellowFore, ZTrue)

      ELSEIF (NOT AtEndOfLine AND InsertMode AND CurrentCol <= ZRightMargin AND lbi <= ZRightMargin) THEN

	 ' have to rewrite the screen from the current pos forward

	 ZOutTxt$(Index) = LEFT$(ZOutTxt$(Index), CurrentCol - 1) + YY$ + MID$(ZOutTxt$(Index), CurrentCol)
			
	 ZWorkAra$(CurrentRow) = ZOutTxt$(Index)
				    
	 CALL EraseToEOL(CurrentRow, CurrentCol)
	 ZZ$ = MID$(ZWorkAra$(CurrentRow), CurrentCol)
	 CALL Puts(ZZ$, YellowFore, ZTrue)
	 CALL MoveCursor(RowSave, ColSave + 1)

      ELSE      '  word wrap time

	 IF NOT AtEndOfLine THEN
	 
	    ZOutTxt$(Index) = LEFT$(ZOutTxt$(Index), CurrentCol - 1) + YY$ + MID$(ZOutTxt$(Index), CurrentCol)
	    lbi = lbi + 1
	    
	 ELSE
	 
	    MID$(ZOutTxt$(Index), CurrentCol, 1) = YY$
					
	 END IF
	 
	 CALL FindWrap(ZOutTxt$(Index), I)
	 IF I = 0 OR I = 1 THEN I = ZRightMargin

	 ZZ$ = MID$(ZOutTxt$(Index), (I + 1))
	 CALL RightTrim(ZZ$)
	 ZOutTxt$(Index) = LEFT$(ZOutTxt$(Index), I)
	 ' add to the beginning of a new line
	 IF Index < 98 THEN Index = Index + 1
	 FOR j = 98 TO Index STEP -1
	    ZOutTxt$(j + 1) = ZOutTxt$(j)
	 NEXT j
	 ZOutTxt$(Index) = ZZ$

	 CALL EraseToEOL(CurrentRow, I + 1) ' do the "easy" line
	 ZWorkAra$(CurrentRow) = ZOutTxt$(Index)

	 CALL UpdateScreen
	 IF (ColSave > I) THEN
	    Newcol = ColSave - I + 1
	    IF RowSave <> 23 THEN
	       CALL MoveCursor(RowSave + 1, Newcol)
	    ELSE
	       CALL MoveCursor(RowSave, Newcol)
	       CALL Ungetch(LineDownKey$)
	    END IF
	 ELSE
	    CALL MoveCursor(RowSave, ColSave + 1)
	 END IF
      END IF

END SUB

'*----------------------------------------------------------------------------*
'*  This routine removes soft spaces from the string specified                *
'*----------------------------------------------------------------------------*
SUB NoSoft (YY$) STATIC

      I = INSTR(YY$, SoftSpace$)
      WHILE I <> 0
	 YY$ = LEFT$(YY$, I - 1) + MID$(YY$, I + 1)
	 I = INSTR(YY$, SoftSpace$)
      WEND

END SUB

'*----------------------------------------------------------------------------*
'* This routine writes yy$ to the user in the color and intensity specified   *
'*----------------------------------------------------------------------------*
SUB Puts (YY$, Colour, Bold) STATIC

      ZZ$ = ""
      IF Colour <> 99 THEN
	 IF (Colour <> OldColour) OR (Bold <> IsBold) THEN ' v2.41
		 
	    ZZ$ = "["
	    
	    IF Bold <> IsBold THEN       ' v2.41
	       IF Bold THEN              ' v2.41
		  ZZ$ = ZZ$ + "1;"       ' v2.41
		  IsBold = ZTrue         ' v2.41
	       ELSE                      ' v2.41
		  ZZ$ = ZZ$ + "0;"       ' v2.41
		  IsBold = ZFalse        ' v2.41
	       END IF                    ' v2.41
	    END IF                       ' v2.41
	       
	    ZZ$ = ZZ$ + MID$(STR$(Colour), 2)
	    ZZ$ = ZZ$ + "m"
	 END IF
      END IF
      ZZ$ = ZZ$ + YY$

      ZOutTxt$ = ZZ$
      ZSubParm = 4
      CALL Tput
      ZSubParm = 0

      IF INSTR(YY$, "[") = 0 THEN
	 CurrentCol = CurrentCol + LEN(YY$)
	 IF CurrentCol > 80 THEN Col = 80
      END IF
      OldColour = Colour
      Colour = 99

END SUB

'*----------------------------------------------------------------------------*
'*  This routine reformats the text file to the current margins               *
'*----------------------------------------------------------------------------*
SUB ReformText (Justify%) STATIC

2201  CALL SaveCursor(RowSave,ColSave)

      DIM SpacePlace(80)

      CALL ClearMainMenu
      CALL MoveCursor(1, 1)
      CALL Puts("Reformatting...", YellowFore, ZTrue)

      LastLine = 1
      FOR I = 99 TO 1 STEP -1
	 IF ZOutTxt$(I) <> BlankLine$ THEN
	    LastLine = I
	    EXIT FOR
	 END IF
      NEXT

      I = 1   ' Read index
      j = 1   ' Write index

      ' Reflow the text to the maximum on a line

      DO WHILE I <= LastLine
	 ZOutTxt$ = ""
	 DO WHILE 1
	    YY$ = ZOutTxt$(I)
	    CALL NoSoft(YY$)
	    IF ZOutTxt$ <> "" AND RIGHT$(ZOutTxt$, 1) <> " " THEN ZOutTxt$ = ZOutTxt$ + " "
	    ZOutTxt$ = ZOutTxt$ + YY$
            CALL LastParaLine(I, LastLine, Z)                      ' QB 3.0 Mod
	    IF LEN(ZOutTxt$) > ZRightMargin OR Z THEN
	       IF LEN(ZOutTxt$) > ZRightMargin THEN
		  CALL FindWrap(LEFT$(ZOutTxt$, ZRightMargin + 1), K)
		  IF K = 0 OR K = 1 THEN K = ZRightMargin
		  ZOutTxt$(j) = LEFT$(ZOutTxt$, K)
		  IF Z THEN
		     ' Go to the next paragraph
		     ZOutTxt$(j + 1) = MID$(ZOutTxt$, K + 1)
		     j = j + 2
		     I = I + 1
		     EXIT DO
		  ELSE
		     ZOutTxt$(I) = MID$(ZOutTxt$, K + 1)
		     j = j + 1
		     EXIT DO
		  END IF
	       ELSE          ' Z is ZTrue
		  ZOutTxt$(j) = ZOutTxt$
		  j = j + 1
		  I = I + 1
		  EXIT DO
	       END IF
	    ELSE
	       I = I + 1
	    END IF
	 LOOP
      LOOP

      FOR I = j TO 99
	 ZOutTxt$(I) = BlankLine$
      NEXT

      LastLine = j - 1

      ' Now space out the text on each line
      IF Justify% THEN
	 FOR I = 1 TO LastLine
            CALL LastParaLine(I, LastLine, Z)                      ' QB 3.0 Mod
            IF Z THEN
	    ELSE
	       ZOutTxt$ = ZOutTxt$(I)
	       ' Find out all of the possible places to put spaces
               CALL TrimTrail(ZOutTxt$," ")                        ' QB 3.0 Mod
	       ' Skip leading spaces
	       FOR K = 1 TO LEN(ZOutTxt$)
		  IF MID$(ZOutTxt$, K, 1) <> " " THEN EXIT FOR
	       NEXT
	       L = 0
	       FOR K = K TO LEN(ZOutTxt$)
		  IF MID$(ZOutTxt$, K, 1) = " " THEN L = L + 1
	       NEXT
	       IF L <> 0 THEN
		  FOR K = 1 TO LEN(ZOutTxt$)
		     IF MID$(ZOutTxt$, K, 1) <> " " THEN EXIT FOR
		  NEXT
		  L = 1
		  FOR K = K TO LEN(ZOutTxt$)
		     IF MID$(ZOutTxt$, K, 1) = " " THEN
			SpacePlace(L) = K
			L = L + 1
		     END IF
		  NEXT
		  L = L - 1
		  ' Space it out
		  SpacesToAdd = ZRightMargin - LEN(ZOutTxt$)
		  M = 1
		  N = L
		  DoM = ZTrue
		  WHILE SpacesToAdd <> 0
		     IF DoM THEN
			Place = SpacePlace(M)
			M = M + 1
		     ELSE
			Place = SpacePlace(N)
			N = N - 1
		     END IF
		     DoM = NOT DoM
		     ZOutTxt$(I) = LEFT$(ZOutTxt$(I), Place) + SoftSpace$ + MID$(ZOutTxt$(I), Place + 1)
		     SpacesToAdd = SpacesToAdd - 1
		     FOR P = 1 TO L
			IF SpacePlace(P) > Place THEN
			   SpacePlace(P) = SpacePlace(P) + 1
			END IF
		     NEXT
		     IF M = N THEN
			M = 1
			N = L
		     END IF
		  WEND
	       END IF
	    END IF
	 NEXT
      END IF

      CALL UpdateScreen
      CALL MoveCursor(ColSave, RowSave)

END SUB

'*----------------------------------------------------------------------------*
'*   Removes soft spaces from a string                                        *
'*----------------------------------------------------------------------------*
SUB RightTrim (YY$) STATIC

      FOR I = LEN(YY$) TO 1 STEP -1
	 IF MID$(YY$, I, 1) <> SoftSpace$ THEN
	    YY$ = LEFT$(YY$, I)
	    EXIT SUB
	 END IF
      NEXT I
      YY$ = ""

END SUB

'*----------------------------------------------------------------------------*
'*   Puts a key in the beginning of the keyboard buffer                       *
'*----------------------------------------------------------------------------*
SUB Ungetch (YY$) STATIC

      ZCommPortStack$ = YY$ + ZCommPortStack$

END SUB

'*----------------------------------------------------------------------------*
'*  This is one of the most important routines  It compares the arrays        *
'*  ZOutTxt$ and ZWorkAra$ and only sends the user the DIFFERENCE between the *
'*  two within the viewing area  In this way all processing can be done on    *
'*  ZOutTxt$ and then the screen is updated to reflect the changes After the  *
'*  users screen is updated, ZWorkAra$ is changed to reflect what should be   *
'*  on the users' screen The cursor is restored to its original position      *
'*----------------------------------------------------------------------------*
SUB UpdateScreen STATIC

      CALL SaveCursor(RowSave,ColSave)

      CurrentRow = 0
      CurrentCol = 0

      FOR I = 2 TO 23

	 Index = I + TopLine - 2
	 scri$ = ZWorkAra$(I)
	 bufind$ = ZOutTxt$(Index)
	 lbi = LEN(bufind$)
	 lsi = LEN(scri$)

	 IF bufind$ = scri$ THEN
	    ' Do Nothing
	 ELSEIF bufind$ = BlankLine$ OR bufind$ = SPACE$(lbi) THEN
	    CALL ClearLine(I)
	    ZWorkAra$(I) = bufind$
	 ELSE
	    CALL MoveCursor(I, 1)
	    YY$ = bufind$
	    CALL Puts(YY$, YellowFore, ZTrue)
	    CALL EraseToEOL(CurrentRow, CurrentCol)
	    ZWorkAra$(I) = ZOutTxt$(Index)
	 END IF
      NEXT I
      CALL MoveCursor(RowSave, ColSave)

END SUB

'*----------------------------------------------------------------------------*
'*  This routine rewrites the status line on screen line 1                    *
'*----------------------------------------------------------------------------*
SUB UpdateStatusLine STATIC

      CurrentRow = 0
      CurrentCol = 0
1000  CALL MoveCursor(1, 1)
      YY$ = "ANSIED v2.42 by Tom Collins  "
      IF InsertMode THEN
	 YY$ = YY$ + "   Insert  "
      ELSE
	 YY$ = YY$ + "  Overwrite"
      END IF
      YY$ = YY$ + "  - Press ESC Twice For Menu -"
      YY$ = YY$ + SPACE$(80 - LEN(YY$))
      CALL Puts(YY$, CyanFore, ZFalse)

END SUB

'*----------------------------------------------------------------------------*
'*  This routine saves the current cursor position                            *
'*----------------------------------------------------------------------------*
SUB SaveCursor (Row%, Col%) STATIC

   Row% = CurrentRow
   Col% = CurrentCol

END SUB
