Usermode - Starting on a text editor
authorJohn Hodge <[email protected]>
Sat, 29 Jan 2011 04:32:28 +0000 (12:32 +0800)
committerJohn Hodge <[email protected]>
Sat, 29 Jan 2011 04:32:28 +0000 (12:32 +0800)
Usermode/Applications/edit_src/Makefile [new file with mode: 0644]
Usermode/Applications/edit_src/main.c [new file with mode: 0644]

diff --git a/Usermode/Applications/edit_src/Makefile b/Usermode/Applications/edit_src/Makefile
new file mode 100644 (file)
index 0000000..05748b1
--- /dev/null
@@ -0,0 +1,12 @@
+# Project: text editor
+
+-include ../Makefile.cfg
+
+OBJ = main.o
+BIN = edit
+
+-include ../Makefile.tpl
+
+edit.lin:
+       gcc main.c -o edit.lin -DUSE_LOCAL=1 -Wall
+
diff --git a/Usermode/Applications/edit_src/main.c b/Usermode/Applications/edit_src/main.c
new file mode 100644 (file)
index 0000000..eba9be6
--- /dev/null
@@ -0,0 +1,374 @@
+/*\r
+ * Acess2 Text Editor\r
+ */\r
+#if !USE_LOCAL\r
+# include <acess/sys.h>        // Needed for IOCtl\r
+#endif\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <stdint.h>\r
+#include <string.h>\r
+#include <signal.h>\r
+#include <unistd.h>\r
+#if USE_LOCAL\r
+# include <sys/ioctl.h>\r
+# include <termios.h>\r
+#else\r
+# include <acess/devices/terminal.h>\r
+#endif\r
+\r
+#define MAX_FILES_OPEN 1\r
+\r
+// === TYPES ===\r
+typedef struct\r
+{\r
+       const char      *Filename;\r
+       char    **LineBuffer;\r
+        int    FileSize;\r
+        int    LineCount;\r
+        \r
+        int    FirstLine;\r
+        int    CurrentLine;    //!< Currently selected line\r
+        int    CurrentPos;     //!< Position in that line\r
+}      tFile;\r
+\r
+// === PROTOTYPES ===\r
+void   SigINT_Handler(int Signum);\r
+void   ExitHandler(void);\r
+ int   main(int argc, char *argv[]);\r
+ int   OpenFile(tFile *Dest, const char *Path);\r
+void   UpdateDisplayFull(void);\r
+void   UpdateDisplayLine(int LineNum);\r
+void   UpdateDisplayStatus(void);\r
+\r
+void   CursorUp(tFile *File);\r
+void   CursorDown(tFile *File);\r
+void   CursorRight(tFile *File);\r
+void   CursorLeft(tFile *File);\r
+\r
+void   Term_SetPos(int Row, int Col);\r
+\r
+// === GLOBALS ===\r
+ int   giProgramState = 0;\r
+tFile  gaFiles[MAX_FILES_OPEN];\r
+tFile  *gpCurrentFile;\r
+#if USE_LOCAL\r
+struct termios gOldTermios;\r
+#endif\r
+ int   giTerminal_Width = 80;\r
+ int   giTerminal_Height = 25;\r
+\r
+// === CODE ===\r
+void SigINT_Handler(int Signum)\r
+{\r
+       exit(55);\r
+}\r
+\r
+void ExitHandler(void)\r
+{\r
+       #if USE_LOCAL\r
+       tcsetattr(0, TCSANOW, &gOldTermios);\r
+       #endif\r
+       printf("\x1B[?1047l");\r
+}\r
+\r
+/**\r
+ * \fn int main(int argc, char *argv[])\r
+ * \brief Entrypoint\r
+ */\r
+int main(int argc, char *argv[])\r
+{\r
+       \r
+       if(argc < 2) {\r
+               printf("Usage: edit <file>\n");\r
+               return -1;\r
+       }\r
+\r
+       if( OpenFile(&gaFiles[0], argv[1]) ) {\r
+               return -1;\r
+       }\r
+       \r
+       signal(SIGINT, SigINT_Handler);\r
+       atexit(ExitHandler);\r
+\r
+       // Disable input buffering\r
+       #if USE_LOCAL\r
+       {\r
+               struct termios  term;\r
+               tcgetattr(0, &gOldTermios);\r
+               term = gOldTermios;\r
+               term.c_lflag &= ~(ICANON|ECHO);\r
+               tcsetattr(0, TCSANOW, &term);\r
+               //setbuf(stdin, NULL);\r
+       }\r
+       #endif\r
+       \r
+       // Go to alternte screen buffer\r
+       printf("\x1B[?1047h");\r
+       \r
+       gpCurrentFile = &gaFiles[0];\r
+       \r
+       UpdateDisplayFull();\r
+       \r
+       giProgramState = 1;\r
+       \r
+       while(giProgramState)\r
+       {\r
+               char    ch = 0;\r
+               \r
+               read(0, &ch, 1);\r
+               \r
+               if(ch == '\x1B')\r
+               {\r
+                       read(0, &ch, 1);\r
+                       switch(ch)\r
+                       {\r
+                       case 'A':       CursorUp(gpCurrentFile);        break;\r
+                       case 'B':       CursorDown(gpCurrentFile);      break;\r
+                       case 'C':       CursorRight(gpCurrentFile);     break;\r
+                       case 'D':       CursorLeft(gpCurrentFile);      break;\r
+                       \r
+                       case '[':\r
+                               read(0, &ch, 1);\r
+                               switch(ch)\r
+                               {\r
+                               case 'A':       CursorUp(gpCurrentFile);        break;\r
+                               case 'B':       CursorDown(gpCurrentFile);      break;\r
+                               case 'C':       CursorRight(gpCurrentFile);     break;\r
+                               case 'D':       CursorLeft(gpCurrentFile);      break;\r
+                               default:\r
+                                       printf("ch (\\x1B[) = %x\r", ch);\r
+                                       fflush(stdout);\r
+                                       break;\r
+                               }\r
+                               break;\r
+                       \r
+                       default:\r
+                               printf("ch (\\x1B) = %x\r", ch);\r
+                               fflush(stdout);\r
+                               break;\r
+                       }\r
+                       // TODO: Move\r
+               }\r
+               \r
+               switch(ch)\r
+               {\r
+               case 'q':\r
+                       giProgramState = 0;\r
+                       break;\r
+               }\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+int OpenFile(tFile *Dest, const char *Path)\r
+{\r
+       FILE    *fp;\r
+       char    *buffer;\r
+        int    i, j;\r
+        int    start;\r
+       \r
+       fp = fopen(Path, "r");\r
+       if(!fp) {\r
+               fprintf(stderr, "Unable to open %s\n", Path);\r
+               return -1;\r
+       }\r
+       \r
+       Dest->Filename = Path;\r
+       \r
+       fseek(fp, 0, SEEK_END);\r
+       Dest->FileSize = ftell(fp);\r
+       fseek(fp, 0, SEEK_SET);\r
+       \r
+       buffer = malloc(Dest->FileSize+1);\r
+       fread(buffer, Dest->FileSize, 1, fp);\r
+       fclose(fp);\r
+       buffer[Dest->FileSize] = '\0';\r
+       \r
+       Dest->LineCount = 1;\r
+       for( i = 0; i < Dest->FileSize; i ++ )\r
+       {\r
+               if( buffer[i] == '\n' )\r
+                       Dest->LineCount ++;\r
+       }\r
+       \r
+       Dest->LineBuffer = malloc( Dest->LineCount * sizeof(char*) );\r
+       start = 0;\r
+       j = 0;\r
+       for( i = 0; i < Dest->FileSize; i ++ )\r
+       {\r
+               if( buffer[i] == '\n' )\r
+               {\r
+                       buffer[i] = '\0';\r
+                       Dest->LineBuffer[j] = strdup( &buffer[start] );\r
+                       start = i+1;\r
+                       j ++;\r
+               }\r
+       }\r
+       Dest->LineBuffer[j] = strdup( &buffer[start] );\r
+       \r
+       free(buffer);\r
+       \r
+       Dest->FirstLine = 0;\r
+       Dest->CurrentLine = 0;\r
+       Dest->CurrentPos = 0;\r
+       \r
+       return 0;\r
+}\r
+\r
+void ShowLine(tFile *File, int LineNum, int X, int Y, int W)\r
+{\r
+        int    j, k;\r
+       char    *line;\r
+       \r
+       line = File->LineBuffer[LineNum];\r
+       printf("%6i  ", LineNum+1);\r
+       j = 8;\r
+       for( k = 0; j < W-1 && line[k]; j++, k++ )\r
+       {\r
+               switch( line[k] )\r
+               {\r
+               case '\t':\r
+                       printf("\t");\r
+                       j += 8;\r
+                       j &= ~7;\r
+                       break;\r
+               default:\r
+                       if( line[k] < ' ' || line[k] >= 0x7F )  continue;\r
+                       printf("%c", line[k]);\r
+                       break;\r
+               }\r
+       }\r
+       \r
+       for( ; j < W-1; j++ )\r
+               printf(" ");\r
+       printf("\n");\r
+}\r
+\r
+void ShowFile(tFile *File, int X, int Y, int W, int H)\r
+{\r
+        int    i;\r
+       Term_SetPos(Y, X);\r
+       \r
+       for( i = 0; i < H; i ++ )\r
+       {\r
+               if( File->FirstLine + i >= File->LineCount )    break;\r
+               ShowLine( File, File->FirstLine + i, X, Y + i, W );\r
+       }\r
+       for( ; i < H; i++ )\r
+               printf("\n");\r
+}\r
+\r
+void UpdateDisplayFull(void)\r
+{\r
+       #if USE_LOCAL\r
+       {\r
+               struct winsize ws;\r
+               ioctl(0, TIOCGWINSZ, &ws);\r
+               giTerminal_Width = ws.ws_col;\r
+               giTerminal_Height = ws.ws_row;\r
+       }\r
+       #else\r
+       giTerminal_Width = ioctl(1, TERM_IOCTL_WIDTH, NULL);\r
+       giTerminal_Height = ioctl(1, TERM_IOCTL_HEIGHT, NULL);\r
+       #endif\r
+       \r
+       printf("\x1B[2J");\r
+       \r
+       ShowFile(gpCurrentFile, 0, 0, giTerminal_Width, giTerminal_Height - 1);\r
+       \r
+       \r
+       // Status Line\r
+       UpdateDisplayStatus();\r
+       \r
+       Term_SetPos(\r
+               gpCurrentFile->CurrentLine-gpCurrentFile->FirstLine,\r
+               8 + gpCurrentFile->CurrentPos\r
+               );\r
+       fflush(stdout);\r
+}\r
+\r
+void UpdateDisplayLine(int Line)\r
+{\r
+       ShowLine(\r
+               gpCurrentFile, Line,\r
+               0, Line - gpCurrentFile->FirstLine,\r
+               giTerminal_Width );\r
+}\r
+\r
+void UpdateDisplayStatus(void)\r
+{\r
+       int lastLine = gpCurrentFile->FirstLine + giTerminal_Height - 1;\r
+       \r
+       if( lastLine > gpCurrentFile->LineCount )\r
+               lastLine = gpCurrentFile->LineCount;\r
+       \r
+       printf("--- Line %i/%i (showing %i to %i)",\r
+               gpCurrentFile->CurrentLine + 1, gpCurrentFile->LineCount,\r
+               gpCurrentFile->FirstLine, lastLine);\r
+}\r
+\r
+void CursorUp(tFile *File)\r
+{\r
+       if( File->CurrentLine > 0 )\r
+       {\r
+               File->CurrentLine --;\r
+               if( File->FirstLine > File->CurrentLine )\r
+               {\r
+                       File->FirstLine = File->CurrentLine;\r
+                       UpdateDisplayFull();\r
+               }\r
+               else\r
+               {\r
+                       UpdateDisplayLine(File->CurrentLine + 1);\r
+                       UpdateDisplayLine(File->CurrentLine);\r
+                       UpdateDisplayStatus();\r
+               }\r
+       }\r
+}\r
+\r
+void CursorDown(tFile *File)\r
+{\r
+       if( File->CurrentLine+1 < File->LineCount )\r
+       {\r
+               File->CurrentLine ++;\r
+               if( File->FirstLine < File->CurrentLine - (giTerminal_Height-2) )\r
+               {\r
+                       File->FirstLine = File->CurrentLine - (giTerminal_Height-2);\r
+                       UpdateDisplayFull();\r
+               }\r
+               else\r
+               {\r
+                       UpdateDisplayLine(File->CurrentLine - 1);\r
+                       UpdateDisplayLine(File->CurrentLine);\r
+                       UpdateDisplayStatus();\r
+               }\r
+       }\r
+}\r
+\r
+void CursorRight(tFile *File)\r
+{\r
+       if( File->CurrentPos > 0 )\r
+       {\r
+               File->CurrentPos --;\r
+               UpdateDisplayLine(File->CurrentLine);\r
+               UpdateDisplayStatus();\r
+       }\r
+}\r
+\r
+void CursorLeft(tFile *File)\r
+{\r
+       if( File->LineBuffer[File->CurrentLine][File->CurrentPos+1] )\r
+       {\r
+               File->CurrentPos --;\r
+               UpdateDisplayLine(File->CurrentLine);\r
+               UpdateDisplayStatus();\r
+       }\r
+}\r
+\r
+void Term_SetPos(int Row, int Col)\r
+{\r
+       printf("\x1B[%i;%iH", Row+1, Col+1);    // Set cursor\r
+       fflush(stdout);\r
+}\r

UCC git Repository :: git.ucc.asn.au