diff --git a/arch/i386/tty.c b/arch/i386/tty.c index a1c9651..c37516d 100755 --- a/arch/i386/tty.c +++ b/arch/i386/tty.c @@ -43,6 +43,7 @@ void term_putentryat (char c, uint8_t color, size_t x, size_t y) { void term_putchar(char c) { unsigned char uc = c; + //Handle escaped characters, such as newline, and crtn. switch (uc) { case '\n': terminal_column = 0; @@ -57,15 +58,69 @@ void term_putchar(char c) { { terminal_column = 0; if(++terminal_row == TERM_HEIGHT){ - term_scroll(); + term_scroll(false); terminal_row = 0; } } } void term_write(const char* data, size_t size) { - for(size_t i = 0; i < size; i++) + for(size_t i = 0; i < size; i++) { + //Begin handling ANSI escape codes. + if(data[i] == 0x1B) { //The current character is ESC - the start of ANSI codes. + term_writes("ANSI Code encountered: "); + + bool string_terminated = false; //Flag used in some of the escape codes + switch(data[i+1]) { + case 0x9b/*[*/: //CSI - Control Sequence Introducer (The most common one, hence it comes first) + char* controlSequence; + if(data[i+2] == NULL) { + controlSequence = '\0'; + for(size_t j = 0; j < (strlen(data) - (i+2); j++) { + if(data[j] == ' ') + break; + controlSequence += data[j]; + } + handleControlSequence(controlSequence); //Send it off to our handler function to keep this part clean + break; + + //Single shifts are not handled, so just print them and exit + case 0x8e/*N*/: //SS2 - Single Shift Two + term_writes("Single Shift Two\n"); + break; + case 0x8f/*O*/: //SS3 - Single Shift Three + term_writes("Single Shift Three\n"); + break; + + //Control Strings + case 0x90/*P*/: //DCS - Device Control String + term_writes("Device Control String"); + string_terminated = false; + break; + case 0x9c/*\*/: //ST - String Terminator + term_writes("String Terminator\n"); + string_terminated = true; + break; + case 0x9d/*]*/: //OSC - Operating System Command + term_writes("Operating System Command\n"); + string_terminated = false; + break; + case 0x98/*X*/: //SOS - Start Of String + term_writes("Start of String"); + string_terminated = false; + break; + case 0x9e/*^*/: //PM - Privacy Message + term_writes("Privacy Message\n"); + break; + case 0x9f/*_*/: //APC - Application Program Command + term_writes("Application Program Command\n"); + break; + } + + } + term_putchar(data[i]); + } } void term_writes(const char* data) { @@ -77,25 +132,163 @@ void puts(const char* string) { term_putchar('\n'); } -void term_scroll() { - int current_pos = 160; //Start of the second line. +void handleControlSequence(const char* sequence) { + //Check for our failsafes + if(sequence) { + if(sequence != '\0') { + int n = 0; //Default of the flag used for a few items + + bool nPresent = false; + bool terminated = false; + for(size_t i = 0; i < strlen(sequence); i++) { + if(isDigit(sequence[i])) { + nPresent = true; + n = (n*10) + sequence[i]; + } else if(n > 80) { + n = 80; + break; + } + } + + if(n == 0) + n = 1; + + switch(sequence[i]) { + case ';': + terminated = true; + int m = 0; + for(size_t j = 0; j < strlen(sequence - i); j++) { + if(sequence[j] == 'H' ||sequence[j] == 'f') + break; + + if(isDigit(sequence[j])) { + m = (m*10) + sequence[j]; + } else if(j > 80) break; + } + + if(m == 0) + m = 1; + cursor_pos(n, m); + + break; + case 'A': //CUU - Cursor Up + //cursor_pos(x, y) + + cursor_pos(terminal_column, terminal_row + n); + break; + case 'B': //CUD - Cursor Down + cursor_pos(terminal_column, terminal_row - n); + break; + case 'C': //CUF - Cursor Forward + cursor_pos(terminal_column + n, terminal_row); + break; + case 'D': //CUB - Cursor Back + cursor_pos(terminal_column - n, terminal_row); + break; + case 'E': //CNL - Cursor Next Line + cursor_pos(0, terminal_row + n); + break; + case 'F': //CPL - Cursor Previous Line + cursor_pos(0, terminal_row - n); + break; + case 'G': //CHA - Cursor Horizontal Absolute + cursor_pos(n, terminal_row); + case 'J': //ED - Erase in Display + //current cursor pos = y * width + x + int pos = terminal_row * 80 + terminal_column; + if(!nPresent) { + for(pos < (25 * 80); pos++) { + vga_buffer[pos] = '\0'; + } + n = 0; + } else if(nPresent && n == 1) { + for(pos > 0; pos--) { + vga_buffer[pos] = '\0'; + } + } else if(n == 2 || n == 3) { + for(int i = 0; i < (25*80); i++) { + vga_buffer[0] = '\0'; + } + } + break; + case 'K': //EL - Erase in Line + + int pos = terminal_row * 80 + terminal_column; + if(!nPresent) { //From cursor to end of line + int endPos = (terminal_row + 1) * 80 - 1; //End of line = current row + 25 columns = current row + 1 + for(pos < endPos; pos++) { + vga_buffer[pos] = '\0'; + } + } else if(nPresent && n == 1) { //From cursor to start of line + int endPos = terminal_row * 80; //Start of line = end of previous line + 1 == current line + for(pos > endPos; pos--) { + vga_buffer[pos] = '\0'; + } + } else if(nPresent && n == 2) { //Entire current line + pos = terminal_row * 80; + int endPos = (terminal_row + 1) * 80 - 1; + for(pos < endPos; pos++) { + vga_buffer[pos] = '\0'; + } + } + break; + case 'S': //SU - Scroll Up + term_scroll(true); + break; + case 'T': //SD - Scroll Down + term_scroll(false); + break; + } + } + } + } + +} + +bool isDigit(const char c) { + return c == '0' || c == '1' || c == '2' || c == '3' || + c == '4' || c == '5' || c == '6' || c == '7' || + c == '8' || c == '9'; +} + +void term_scroll(bool down) { + + int current_pos; + if(down) { + current_pos = 25 * 80; //Start of the last line. + } else { + current_pos = 160; //Start of the second line. + } unsigned char* term_buffer = (unsigned char*) vga_buffer; - - while (current_pos <= 4000) { - term_buffer[current_pos - 160 /*The character immediately below it*/] = vga_buffer[current_pos]; //Move each character up a line - term_buffer[current_pos - 159 /*The color of the character below*/] = vga_buffer[current_pos + 1]; //As well as its color - current_pos += 2; //Move to next char + + if(down) { //To scroll down, move every character into the one below it, or "pull" every character down + while(current_pos > 80) { + term_buffer[current_pos + 160] = vga_buffer[current_pos]; + term_buffer[current_pos + 159] = vga_buffer[current_pos - 1]; + current_pos -= 2; + } else { + while (current_pos <= 4000) { + term_buffer[current_pos - 160 /*The character immediately below it*/] = vga_buffer[current_pos]; //Move each character up a line + term_buffer[current_pos - 159 /*The color of the character below*/] = vga_buffer[current_pos + 1]; //As well as its color + current_pos += 2; //Move to next char + } } - current_pos = 3840; //Start of the last line - int i; //Offset for framebuffer - //Wipe out the bottom line - for(i = 1920; i <= 2000; i++) { - term_buffer[current_pos] = 0; - current_pos += 2; + if(down) { + current_pos = 0; //Start of first line + for(current_pos < 80; current_pos++) { + term_buffer[current_pos] = '\0'; + current_pos += 2; + } else { + ; //Start of the last line + //Wipe out the bottom line + for(current_pos = 3840; current_pos <= 3920; i++) { + term_buffer[current_pos] = 0; + current_pos += 2; + } } - i = 3840; - terminal_row = 24; //Prepare the screen to scroll + terminal_row = 24; //Start writing on the last line + terminal_column = 0; } \ No newline at end of file