X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Fdrv%2Fvterm_termbuf.c;h=fed577a9d768762b9a3c7ca8afcb90c4dfd90420;hb=2a17e7ae7dab0ac8ba8c434bc3b409f20d378e46;hp=b6aff95cf03eddafe4646740198d1d47c1caa04b;hpb=168af87d8fcc01a6a521f3929835f15b201b5251;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/drv/vterm_termbuf.c b/KernelLand/Kernel/drv/vterm_termbuf.c index b6aff95c..fed577a9 100644 --- a/KernelLand/Kernel/drv/vterm_termbuf.c +++ b/KernelLand/Kernel/drv/vterm_termbuf.c @@ -5,8 +5,18 @@ * drv/vterm_termbuf.c * - Virtual Terminal - Terminal buffer manipulation */ +#define DEBUG 0 +#define DEBUG_CHECKHEAP 0 #include "vterm.h" +#if DEBUG_CHECKHEAP +# define HEAP_VALIDATE() Heap_Validate() +#else +# define HEAP_VALIDATE() do{}while(0) +#endif + +extern int Term_HandleVT100(tVTerm *Term, int Len, const char *Buf); + // === CODE === /** @@ -15,30 +25,34 @@ */ void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count) { - Uint32 val; - int i; - // Iterate - for( i = 0; i < Count; i++ ) + for( int ofs = 0; ofs < Count; ) { - // Handle escape sequences - if( Buffer[i] == 0x1B ) - { - i ++; - i += VT_int_ParseEscape(Term, (const char*)&Buffer[i]) - 1; - continue; + int esc_len = Term_HandleVT100(Term, Count - ofs, (const void*)(Buffer + ofs)); + if( esc_len < 0 ) { + esc_len = -esc_len; + //LOG("%i '%*C'", esc_len, esc_len, Buffer+ofs); + LOG("%i '%.*s'", esc_len, esc_len, Buffer+ofs); + VT_int_PutRawString(Term, Buffer + ofs, esc_len); + //Debug("Raw string '%.*s'", esc_len, Buffer+ofs); } - - // Fast check for non UTF-8 - if( Buffer[i] < 128 ) // Plain ASCII - VT_int_PutChar(Term, Buffer[i]); - else { // UTF-8 - i += ReadUTF8(&Buffer[i], &val) - 1; - VT_int_PutChar(Term, val); + else { + //Debug("Escape code '%.*s'", esc_len, Buffer+ofs); } + ASSERTCR(esc_len, >, 0, ); + ofs += esc_len; } // Update Screen - VT_int_UpdateScreen( Term, 0 ); + VT_int_UpdateScreen( Term, 1 ); +} + +void VT_int_PutRawString(tVTerm *Term, const Uint8 *String, size_t Bytes) +{ + for( int i = 0; i < Bytes; ) { + Uint32 val; + i += ReadUTF8(String+i, &val); + VT_int_PutChar(Term, val); + } } /** @@ -48,37 +62,80 @@ void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count) void VT_int_PutChar(tVTerm *Term, Uint32 Ch) { int i; - tVT_Char *buffer; - int write_pos; - if(Term->Flags & VT_FLAG_ALTBUF) { - buffer = Term->AltBuf; - write_pos = Term->AltWritePos; + HEAP_VALIDATE(); + + const size_t maxrows = VT_int_GetBufferRows(Term); + const size_t limit = maxrows * Term->TextWidth; + tVT_Pos *wrpos = VT_int_GetWritePosPtr(Term); + tVT_Char *buffer = (Term->Flags & VT_FLAG_ALTBUF ? Term->AltBuf : Term->Text); + + // If writing with the cursor on righthand edge, wrap down to next line + // TODO: Wrap to same line? + if( wrpos->Col >= Term->TextWidth ) + { + ASSERTC(wrpos->Col, <=, Term->TextWidth); + VT_int_UpdateScreen( Term, 0 ); + //wrpos->Row ++; + wrpos->Col = 0; } - else { - buffer = Term->Text; - write_pos = Term->WritePos; + + // Scroll entire buffer (about to write outside limit) + if( wrpos->Row >= maxrows ) + { + ASSERTC(wrpos->Row, <, maxrows + 1); + VT_int_ScrollText(Term, 1); + wrpos->Row --; } - + + // Bring written cell into view + if( !(Term->Flags & VT_FLAG_ALTBUF) ) + { + if( wrpos->Row >= Term->ViewTopRow + Term->TextHeight ) + { + size_t new_pos = wrpos->Row - (Term->TextHeight - 1); + size_t count = new_pos - Term->ViewTopRow; + VT_int_ScrollFramebuffer(Term, count); + //Debug("VT_int_PutChar: VScroll down to %i", new_pos); + Term->ViewTopRow = new_pos; + } + else if( wrpos->Row < Term->ViewTopRow ) + { + size_t new_pos = wrpos->Row; + size_t count = Term->ViewTopRow - new_pos; + VT_int_ScrollFramebuffer(Term, -count); + //Debug("VT_int_PutChar: VScroll up to %i", new_pos); + Term->ViewTopRow = new_pos; + } + else + { + // no action, cell is visible + } + } + + size_t write_pos = wrpos->Row * Term->TextWidth + wrpos->Col; + ASSERTC(write_pos, <, limit); + switch(Ch) { - case '\0': return; // Ignore NULL byte + case '\0': // Ignore NULL byte + return; case '\n': VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining - write_pos += Term->TextWidth; + wrpos->Row ++; + // TODO: Force scroll? case '\r': - write_pos -= write_pos % Term->TextWidth; + wrpos->Col = 0; break; case '\t': { - int line = write_pos / Term->TextWidth; - write_pos %= Term->TextWidth; + size_t col = wrpos->Col; do { buffer[ write_pos ].Ch = '\0'; buffer[ write_pos ].Colour = Term->CurColour; write_pos ++; - } while(write_pos & 7); - write_pos += line * Term->TextWidth; + col ++; + } while( (col & 7) && col < Term->TextWidth ); break; } case '\b': @@ -101,6 +158,7 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0'); if(buffer[ write_pos ].Ch != '\0') write_pos ++; + wrpos->Col = write_pos % Term->TextWidth; break; default: @@ -110,47 +168,15 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) if( (write_pos + 1) % Term->TextWidth == 0 ) VT_int_UpdateScreen( Term, 0 ); write_pos ++; + wrpos->Col ++; break; } - if(Term->Flags & VT_FLAG_ALTBUF) - { - Term->AltWritePos = write_pos; - - if(Term->AltWritePos >= Term->TextWidth*Term->TextHeight) - { - Term->AltWritePos -= Term->TextWidth; - VT_int_ScrollText(Term, 1); - } - - } - else - { - Term->WritePos = write_pos; - // Move Screen - // - Check if we need to scroll the entire scrollback buffer - if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1)) - { - int base; - - // Update view position - base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback); - if(Term->ViewPos < base) - Term->ViewPos += Term->Width; - if(Term->ViewPos > base) - Term->ViewPos = base; - - VT_int_ScrollText(Term, 1); - Term->WritePos -= Term->TextWidth; - } - // Ok, so we only need to scroll the screen - else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight) - { - VT_int_ScrollFramebuffer( Term, 1 ); - - Term->ViewPos += Term->TextWidth; - } - } + ASSERTC(write_pos, <=, limit); + + HEAP_VALIDATE(); + + // TODO: Schedule a delayed screen update //LEAVE('-'); } @@ -158,64 +184,60 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) void VT_int_ScrollText(tVTerm *Term, int Count) { tVT_Char *buf; - int height, init_write_pos; - int len, i; int scroll_top, scroll_height; + + HEAP_VALIDATE(); // Get buffer pointer and attributes + size_t height = VT_int_GetBufferRows(Term); + tVT_Pos *wrpos = VT_int_GetWritePosPtr(Term); + if( Term->Flags & VT_FLAG_ALTBUF ) { buf = Term->AltBuf; - height = Term->TextHeight; - init_write_pos = Term->AltWritePos; scroll_top = Term->ScrollTop; scroll_height = Term->ScrollHeight; } else { buf = Term->Text; - height = Term->TextHeight*(giVT_Scrollback+1); - init_write_pos = Term->WritePos; scroll_top = 0; scroll_height = height; } + + const tVT_Pos init_wrpos = *wrpos; // Scroll text upwards (more space at bottom) if( Count > 0 ) { - int base; - // Set up if(Count > scroll_height) Count = scroll_height; - base = Term->TextWidth*(scroll_top + scroll_height - Count); - len = Term->TextWidth*(scroll_height - Count); + size_t chars = Term->TextWidth*Count; + size_t base = Term->TextWidth*scroll_top; + size_t len = Term->TextWidth*(scroll_height - Count); // Scroll terminal cache - memmove( - &buf[Term->TextWidth*scroll_top], - &buf[Term->TextWidth*(scroll_top+Count)], - len*sizeof(tVT_Char) - ); + ASSERTC( base + chars + len, <=, Term->TextWidth*height ); + memmove( &buf[base], &buf[base+chars], len*sizeof(tVT_Char) ); + // Clear last rows - for( i = 0; i < Term->TextWidth*Count; i ++ ) + for( int i = 0; i < chars; i ++ ) { - buf[ base + i ].Ch = 0; - buf[ base + i ].Colour = Term->CurColour; + ASSERTC(base + len + i, <, Term->TextWidth*height); + buf[ base + len + i ].Ch = 0; + buf[ base + len + i ].Colour = Term->CurColour; } // Update Screen VT_int_ScrollFramebuffer( Term, Count ); if( Term->Flags & VT_FLAG_ALTBUF ) - Term->AltWritePos = base; + wrpos->Row = scroll_top; else - Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count); - for( i = 0; i < Count; i ++ ) + wrpos->Row = Term->ViewTopRow + (Term->TextHeight - Count); + for( int i = 0; i < Count; i ++ ) { VT_int_UpdateScreen( Term, 0 ); - if( Term->Flags & VT_FLAG_ALTBUF ) - Term->AltWritePos += Term->TextWidth; - else - Term->WritePos += Term->TextWidth; + wrpos->Row ++; } } else @@ -223,40 +245,37 @@ void VT_int_ScrollText(tVTerm *Term, int Count) Count = -Count; if(Count > scroll_height) Count = scroll_height; - len = Term->TextWidth*(scroll_height - Count); + size_t chars = Term->TextWidth*Count; + size_t base = Term->TextWidth*scroll_top; + size_t len = Term->TextWidth*scroll_height - chars; // Scroll terminal cache - memmove( - &buf[Term->TextWidth*(scroll_top+Count)], - &buf[Term->TextWidth*scroll_top], - len*sizeof(tVT_Char) - ); + ASSERTC( base + chars + len, <=, Term->TextWidth*height ); + memmove( &buf[base+chars], &buf[base], len*sizeof(tVT_Char) ); + // Clear preceding rows - for( i = 0; i < Term->TextWidth*Count; i ++ ) + for( int i = 0; i < chars; i ++ ) { buf[ i ].Ch = 0; buf[ i ].Colour = Term->CurColour; } + // Update screen (shift framebuffer, re-render revealed lines) VT_int_ScrollFramebuffer( Term, -Count ); if( Term->Flags & VT_FLAG_ALTBUF ) - Term->AltWritePos = Term->TextWidth*scroll_top; + wrpos->Row = scroll_top; else - Term->WritePos = Term->ViewPos; - for( i = 0; i < Count; i ++ ) + wrpos->Row = Term->ViewTopRow; + for( int i = 0; i < Count; i ++ ) { VT_int_UpdateScreen( Term, 0 ); - if( Term->Flags & VT_FLAG_ALTBUF ) - Term->AltWritePos += Term->TextWidth; - else - Term->WritePos += Term->TextWidth; + // Increment? } } - if( Term->Flags & VT_FLAG_ALTBUF ) - Term->AltWritePos = init_write_pos; - else - Term->WritePos = init_write_pos; + *wrpos = init_wrpos; + + HEAP_VALIDATE(); } /** @@ -264,21 +283,48 @@ void VT_int_ScrollText(tVTerm *Term, int Count) * \param Term Terminal to modify * \param Num Line number to clear */ -void VT_int_ClearLine(tVTerm *Term, int Num) +void VT_int_ClearLine(tVTerm *Term, int Row) { - int i; - tVT_Char *cell; + HEAP_VALIDATE(); + + size_t height = VT_int_GetBufferRows(Term); + tVT_Char *buffer = (Term->Flags & VT_FLAG_ALTBUF ? Term->AltBuf : Term->Text); + ASSERTCR(Row, >=, 0, ); + ASSERTCR(Row, <, height, ); - if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) ) return ; + size_t base = Row * Term->TextWidth; - cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text; - cell = &cell[ Num*Term->TextWidth ]; + for( int i = 0; i < Term->TextWidth; i ++ ) + { + buffer[ base + i ].Ch = 0; + buffer[ base + i ].Colour = Term->CurColour; + } - for( i = Term->TextWidth; i--; ) + HEAP_VALIDATE(); +} + +void VT_int_ClearInLine(tVTerm *Term, int Row, int FirstCol, int LastCol) +{ + HEAP_VALIDATE(); + + size_t height = VT_int_GetBufferRows(Term); + tVT_Char *buffer = (Term->Flags & VT_FLAG_ALTBUF ? Term->AltBuf : Term->Text); + ASSERTCR(Row, >=, 0, ); + ASSERTCR(Row, <, height, ); + + ASSERTCR(FirstCol, <=, LastCol, ); + ASSERTCR(FirstCol, <, Term->TextWidth, ); + ASSERTCR(LastCol, <=, Term->TextWidth, ); + + size_t base = Row * Term->TextWidth; + for( int i = FirstCol; i < LastCol; i ++ ) { - cell[ i ].Ch = 0; - cell[ i ].Colour = Term->CurColour; + ASSERTC(base + i, <, height * Term->TextWidth); + buffer[ base + i ].Ch = 0; + buffer[ base + i ].Colour = Term->CurColour; } + + HEAP_VALIDATE(); } /** @@ -288,7 +334,7 @@ void VT_int_ClearLine(tVTerm *Term, int Num) * \param NewWidth New framebuffer width * \param NewHeight New framebuffer height */ -void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight) +void VT_int_Resize(tVTerm *Term, int NewWidth, int NewHeight) { int oldW = Term->Width; int oldTW = Term->TextWidth; @@ -296,14 +342,14 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight) int oldTH = Term->TextHeight; tVT_Char *oldTBuf = Term->Text; Uint32 *oldFB = Term->Buffer; - int w, h, i; + int w, h; + + HEAP_VALIDATE(); // TODO: Increase RealWidth/RealHeight when this happens if(NewWidth > giVT_RealWidth) NewWidth = giVT_RealWidth; if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight; - Term->Mode = NewMode; - // Fast exit if no resolution change if(NewWidth == Term->Width && NewHeight == Term->Height) return ; @@ -326,7 +372,7 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight) w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW; h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH; h *= giVT_Scrollback + 1; - for( i = 0; i < h; i ++ ) + for( int i = 0; i < h; i ++ ) { memcpy( &Term->Text[i*Term->TextWidth], @@ -349,7 +395,7 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight) // Copy old buffer w = (oldW > Term->Width) ? Term->Width : oldW; h = (oldH > Term->Height) ? Term->Height : oldH; - for( i = 0; i < h; i ++ ) + for( int i = 0; i < h; i ++ ) { memcpy( &Term->Buffer[i*Term->Width], @@ -361,7 +407,8 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight) } // Debug - switch(NewMode) + #if 0 + switch(Term->Mode) { case TERM_MODE_TEXT: Log_Log("VTerm", "Set VT %p to text mode (%ix%i)", @@ -375,6 +422,9 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight) //case TERM_MODE_3DACCEL: // return; } + #endif + + HEAP_VALIDATE(); } @@ -387,3 +437,13 @@ void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled) VT_int_UpdateScreen(Term, 1); } +tVT_Pos *VT_int_GetWritePosPtr(tVTerm *Term) +{ + return ((Term->Flags & VT_FLAG_ALTBUF) ? &Term->AltWritePos : &Term->WritePos); +} + +size_t VT_int_GetBufferRows(tVTerm *Term) +{ + return ((Term->Flags & VT_FLAG_ALTBUF) ? 1 : (giVT_Scrollback+1))*Term->TextHeight; +} +