MODULE editor1; (* based on the kilo editor building course*) (* Step 28 *) (******************** INCLUDES ******************) IMPORT IO, Strings, ASCII, NumberIO, termios, FIO, Delay, SplitV1, STextIO; IMPORT libc, SYSTEM, Storage, MemUtils; (******************** DATA ******************) TYPE abufType = RECORD b : SYSTEM.ADDRESS; len : CARDINAL; END; abufTypePtr = POINTER TO abufType; VAR editorConfig : RECORD screenrows : CARDINAL; screencols : CARDINAL; theTermios : termios.TERMIOS; END; TCSAFLUSH : INTEGER; theStructure : SplitV1.Structure; cursorposStr : ARRAY [0..15] OF CHAR; clearScreenStr : ARRAY[0..6] OF CHAR; cursorHomeStr : ARRAY[0..2] OF CHAR; requestCursorPosStr : ARRAY[0..15] OF CHAR; resultStr : ARRAY [0..15] OF CHAR; tmpString : ARRAY[0..15] OF CHAR; tmpString1 : ARRAY[0..15] OF CHAR; tmpString2 : Strings.String1; cc : Strings.String1; i : CARDINAL; str : ARRAY [0..15] OF CHAR; abuf : abufType; (******************** Utilities *****************) PROCEDURE Card2Str ( x : CARDINAL; VAR str : ARRAY OF CHAR); BEGIN IF x < 10 THEN NumberIO.CardToStr(x,1,str); ELSIF x < 100 THEN NumberIO.CardToStr(x,2,str); ELSE NumberIO.CardToStr(x,3,str); END; END Card2Str; (******************** TERMINAL ******************) PROCEDURE CtrlKey(c: CHAR) : CARDINAL; (* return a value < ORD(" ") for the control keys *) VAR n : BITSET; BEGIN n := BITSET(ORD(c)); n := n * BITSET(1FH); RETURN CARDINAL(n) END CtrlKey; PROCEDURE die (s : ARRAY OF CHAR); BEGIN libc.perror(s); FOR i := 0 TO Strings.Length(s) DO IO.Write(s[i]) END; HALT END die; PROCEDURE disablerawMode() : INTEGER; VAR result : INTEGER; BEGIN IO.BufferedMode(0,TRUE); IO.BufferedMode(1,TRUE); result := termios.tcsetattr(FIO.StdIn, TCSAFLUSH, editorConfig.theTermios); IF result = -1 THEN die("tcsetattr") ELSE RETURN result END; END disablerawMode; PROCEDURE enablerawMode; BEGIN libc.atexit(disablerawMode); editorConfig.theTermios := termios.InitTermios(); (* raw := termios.InitTermios(); *) IF termios.tcgetattr(FIO.StdIn, editorConfig.theTermios) = -1 THEN die("tcgetattr") END; IO.UnBufferedMode(0,TRUE); IO.UnBufferedMode(1,TRUE); END enablerawMode; PROCEDURE editorReadKey() : CHAR; VAR c : CHAR; BEGIN IO.Read(c); RETURN c END editorReadKey; (******************** Buffer ******************) PROCEDURE abufInit( VAR ptr : abufTypePtr); BEGIN Storage.ALLOCATE(ptr,SYSTEM.TSIZE(abufType) ); ptr^.b := NIL; ptr^.len := 0; END abufInit; PROCEDURE abAppend (VAR ptr : abufTypePtr; str: ARRAY OF CHAR ); VAR llen : CARDINAL; BEGIN (* REALLOCATE - attempts to reallocate storage. The address, a, should either be NIL in which case ALLOCATE is called, or alternatively it should have already been initialized by ALLOCATE. The allocated storage is resized accordingly. *) (* PROCEDURE REALLOCATE (VAR a: ADDRESS; Size: CARDINAL) ; *) (* PROCEDURE MemCopy (from: ADDRESS; length: CARDINAL; to: ADDRESS) ; *) llen := Strings.Length(str); IF ptr <> NIL THEN IF ptr^.b = NIL THEN Storage.ALLOCATE(ptr^.b,llen) ELSE Storage.REALLOCATE( ptr^.b,ptr^.len + llen); END; MemUtils.MemCopy(SYSTEM.ADR(str),llen, SYSTEM.ADDADR(ptr^.b,ptr^.len)); ptr^.len := ptr^.len + llen; END; END abAppend; PROCEDURE abFree (VAR ptr : abufTypePtr); BEGIN (* PROCEDURE DEALLOCATE (VAR a: ADDRESS ; Size: CARDINAL) ; *) (* PROCEDURE DISPOSE (VAR p:) ; *) Storage.DEALLOCATE(ptr^.b, ptr^.len); Storage.DEALLOCATE(ptr,SYSTEM.TSIZE(abufType)); END abFree; (******************** output ******************) PROCEDURE editorDrawRows(VAR ptr : abufTypePtr); VAR y : CARDINAL; str : ARRAY [0..15] OF CHAR; BEGIN abufInit(ptr); IF ptr = NIL THEN die("not enough memory") END; str[0] := "~"; str[1] := CHR(13); str[2] := CHR(10); str[3] := CHR(0); (* FOR y := 1 TO editorConfig.screenrows -1 DO libc.write(FIO.StdOut,SYSTEM.ADR(str),3); END;*) FOR y := 1 TO editorConfig.screenrows -1 DO abAppend(ptr,str) END; (* IO.Write("~"); *) abAppend(ptr,"~"); libc.write(FIO.StdOut,ptr^.b,ptr^.len); abFree(ptr); END editorDrawRows; PROCEDURE editorRefreshScreen; VAR ptr : abufTypePtr; BEGIN (* modif using libc write procedure *) libc.write(FIO.StdOut,SYSTEM.ADR(clearScreenStr),4); libc.write(FIO.StdOut,SYSTEM.ADR(cursorHomeStr),3); (* abAppend(ptr,clearScreenStr); abAppend(ptr,cursorHomeStr); *) editorDrawRows(ptr); libc.write(FIO.StdOut,SYSTEM.ADR(cursorHomeStr),3); (* abAppend(ptr,cursorHomeStr); libc.write(FIO.StdOut,ptr^.b,ptr^.len); abFree(ptr); *) END editorRefreshScreen; PROCEDURE requestCursorPosition(VAR x,y : CARDINAL); VAR c : CHAR; BEGIN str := ""; SplitV1.InitStructure(theStructure); Strings.Concat(str,ASCII.esc,str); Strings.Concat(str,"[6n", str); (* sending request *) (* FOR i := 0 TO 3 DO IO.Write(str[i]) END; *) libc.write(FIO.StdOut,SYSTEM.ADR(str),4); (* getting answer *) str := ""; REPEAT IO.Read(c); cc[0] := c; Strings.Concat(str,cc,str); UNTIL c = "R"; (* displaying the retour , changing the escape to ? *) (* str[0] := "?"; *) (* FOR i := 0 TO Strings.Length(str) DO IO.Write(str[i]) END; *) (* libc.write(FIO.StdOut,SYSTEM.ADR(str),Length(str)); *) (* extracting the coordinates *) Strings.Delete(str,0,2); Strings.Delete(str,Strings.Length(str) -1 ,1); SplitV1.SplitStr(str, ";", theStructure); NumberIO.StrToCard(theStructure[0].element,x); NumberIO.StrToCard(theStructure[1].element,y); (* NumberIO.WriteCard(x, 5); NumberIO.WriteCard(y, 5); *) END requestCursorPosition; PROCEDURE cursorpos(x,y : CARDINAL); BEGIN cursorposStr := ""; Strings.Concat(cursorposStr, ASCII.esc,cursorposStr); Strings.Concat(cursorposStr, "[",cursorposStr); tmpString := ""; Strings.Concat(tmpString,cursorposStr, tmpString); tmpString1 := ""; Card2Str(y,tmpString1); Strings.Concat(tmpString,tmpString1, tmpString); tmpString2[0] := ";"; Strings.Concat(tmpString, tmpString2,tmpString); tmpString1 := ""; Card2Str(x,tmpString1); Strings.Concat(tmpString,tmpString1, tmpString); tmpString2[0] := "H"; Strings.Concat(tmpString, tmpString2,tmpString); (* FOR i := 0 TO Strings.Length(tmpString) DO IO.Write(tmpString[i]) END; *) libc.write(FIO.StdOut,SYSTEM.ADR(tmpString),Strings.Length(tmpString)); END cursorpos; PROCEDURE getWindowSize(VAR y : CARDINAL; VAR x: CARDINAL); BEGIN cursorpos(999,999); requestCursorPosition(x,y); END getWindowSize; (******************** input ******************) PROCEDURE editorProcessKeypress; VAR c : CHAR; b : BOOLEAN; BEGIN c := editorReadKey(); CASE ORD(c) OF 17 : HALT; END END editorProcessKeypress; (******************** INIT ******************) PROCEDURE InitScreenEscapes; VAR temp : ARRAY[0..10] OF CHAR; BEGIN cursorHomeStr := ""; Strings.Concat(cursorHomeStr,ASCII.esc,cursorHomeStr); Strings.Concat(cursorHomeStr,"[H",cursorHomeStr); clearScreenStr := ""; Strings.Concat(clearScreenStr,ASCII.esc,clearScreenStr); Strings.Concat(clearScreenStr,"[2J",clearScreenStr); cursorposStr := ""; Strings.Concat(cursorposStr,ASCII.esc,cursorposStr); Strings.Concat(cursorposStr,"[",cursorposStr); requestCursorPosStr := ""; Strings.Concat(requestCursorPosStr,ASCII.esc,requestCursorPosStr); Strings.Concat(requestCursorPosStr,"[6n",requestCursorPosStr); END InitScreenEscapes; PROCEDURE InitEditor; BEGIN TCSAFLUSH := termios.tcsflush (); InitScreenEscapes; getWindowSize(editorConfig.screenrows, editorConfig.screencols); END InitEditor; BEGIN enablerawMode; InitEditor; LOOP editorRefreshScreen; editorProcessKeypress; editorRefreshScreen; END; (* Delay.Delay(2000); *) IF disablerawMode() = -1 THEN HALT END; NumberIO.WriteCard(editorConfig.screencols, 5); NumberIO.WriteCard(editorConfig.screenrows, 5); END editor1.