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