From 7941d6b368acb0abc17e6a77ffaf7b4c306b67ab Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 8 Jun 2011 01:24:19 +0800 Subject: [PATCH] Networking - Heaps of changes Working on IRC Client - Fixed various networking bugs (firewall failure, etc) - Updating VTerm implementation to support alternate buffers and scroll regions. > Scroll is currently broken, doesn't clear the last line. - Implemented atexit() in libc --- Kernel/debug.c | 2 +- Kernel/drv/vterm.c | 617 ++++++++++++++++-------- Kernel/include/tpl_drv_terminal.h | 9 +- Modules/IPStack/ipv4.c | 2 +- Modules/IPStack/tcp.c | 10 +- Modules/IPStack/udp.c | 10 +- Usermode/Applications/irc_src/main.c | 91 +++- Usermode/Libraries/libc.so_src/stdlib.c | 8 + Usermode/include/stdlib.h | 1 + 9 files changed, 531 insertions(+), 219 deletions(-) diff --git a/Kernel/debug.c b/Kernel/debug.c index 6e7a0003..76525bf3 100644 --- a/Kernel/debug.c +++ b/Kernel/debug.c @@ -390,7 +390,7 @@ void Debug_HexDump(const char *Header, const void *Data, Uint Length) Debug_Puts(1, Header); LogF(" (Hexdump of %p)\r\n", Data); - #define CH(n) ((' '<=cdat[(n)]&&cdat[(n)]<=0x7F) ? cdat[(n)] : '.') + #define CH(n) ((' '<=cdat[(n)]&&cdat[(n)]<0x7F) ? cdat[(n)] : '.') while(Length >= 16) { diff --git a/Kernel/drv/vterm.c b/Kernel/drv/vterm.c index 9e1055ef..bb658f2f 100644 --- a/Kernel/drv/vterm.c +++ b/Kernel/drv/vterm.c @@ -28,6 +28,7 @@ #define DEFAULT_COLOUR (VT_COL_BLACK|(0xAAA<<16)) #define VT_FLAG_HIDECSR 0x01 +#define VT_FLAG_ALTBUF 0x02 //!< Alternate screen buffer #define VT_FLAG_HASFB 0x10 //!< Set if the VTerm has requested the Framebuffer enum eVT_InModes { @@ -48,9 +49,16 @@ typedef struct { short TextWidth; //!< Text Virtual Width short TextHeight; //!< Text Virtual Height + Uint32 CurColour; //!< Current Text Colour + int ViewPos; //!< View Buffer Offset (Text Only) int WritePos; //!< Write Buffer Offset (Text Only) - Uint32 CurColour; //!< Current Text Colour + tVT_Char *Text; + + tVT_Char *AltBuf; //!< Alternate Screen Buffer + int AltWritePos; //!< Alternate write position + short ScrollTop; //!< Top of scrolling region (smallest) + short ScrollHeight; //!< Length of scrolling region tMutex ReadingLock; //!< Lock the VTerm when a process is reading from it tTID ReadingThread; //!< Owner of the lock @@ -59,7 +67,6 @@ typedef struct { char InputBuffer[MAX_INPUT_CHARS8]; // tSemaphore InputSemaphore; - tVT_Char *Text; Uint32 *Buffer; char Name[2]; //!< Name of the terminal @@ -87,9 +94,11 @@ void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count); void VT_int_ClearLine(tVTerm *Term, int Num); int VT_int_ParseEscape(tVTerm *Term, char *Buffer); void VT_int_PutChar(tVTerm *Term, Uint32 Ch); -void VT_int_ScrollFramebuffer( tVTerm *Term ); +void VT_int_ScrollText(tVTerm *Term, int Count); +void VT_int_ScrollFramebuffer( tVTerm *Term, int Count ); void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ); void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight); +void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled); // === CONSTANTS === const Uint16 caVT100Colours[] = { @@ -206,8 +215,10 @@ int VT_Install(char **Arguments) gVT_Terminals[i].Flags = 0; gVT_Terminals[i].CurColour = DEFAULT_COLOUR; gVT_Terminals[i].WritePos = 0; + gVT_Terminals[i].AltWritePos = 0; gVT_Terminals[i].ViewPos = 0; gVT_Terminals[i].ReadingThread = -1; + gVT_Terminals[i].ScrollHeight = 0; // Initialise VT_int_ChangeMode( &gVT_Terminals[i], @@ -678,6 +689,11 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) VT_SetTerminal( Node->Inode ); LEAVE('i', 1); return 1; + + case TERM_IOCTL_GETCURSOR: + ret = (term->Flags & VT_FLAG_ALTBUF) ? term->AltWritePos : term->WritePos-term->ViewPos; + LEAVE('i', ret); + return ret; } LEAVE('i', -1); return -1; @@ -698,9 +714,10 @@ void VT_SetTerminal(int ID) if( gpVT_CurTerm->Mode == TERM_MODE_TEXT && !(gpVT_CurTerm->Flags & VT_FLAG_HIDECSR) ) { tVideo_IOCtl_Pos pos; - pos.x = (gpVT_CurTerm->WritePos - gpVT_CurTerm->ViewPos) % gpVT_CurTerm->TextWidth; - pos.y = (gpVT_CurTerm->WritePos - gpVT_CurTerm->ViewPos) / gpVT_CurTerm->TextWidth; - if( pos.x < gpVT_CurTerm->TextHeight ) + int offset = (gpVT_CurTerm->Flags & VT_FLAG_ALTBUF) ? gpVT_CurTerm->AltWritePos : gpVT_CurTerm->WritePos - gpVT_CurTerm->ViewPos; + pos.x = offset % gpVT_CurTerm->TextWidth; + pos.y = offset / gpVT_CurTerm->TextWidth; + if( 0 <= pos.y && pos.y < gpVT_CurTerm->TextHeight ) VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); } @@ -779,12 +796,16 @@ void VT_KBCallBack(Uint32 Codepoint) case KEY_F12: VT_SetTerminal(11); return; // Scrolling case KEY_PGUP: + if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF ) + return ; if( gpVT_CurTerm->ViewPos > gpVT_CurTerm->Width ) gpVT_CurTerm->ViewPos -= gpVT_CurTerm->Width; else gpVT_CurTerm->ViewPos = 0; return; case KEY_PGDOWN: + if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF ) + return ; if( gpVT_CurTerm->ViewPos < gpVT_CurTerm->Width*gpVT_CurTerm->Height*(giVT_Scrollback-1) ) gpVT_CurTerm->ViewPos += gpVT_CurTerm->Width; else @@ -823,8 +844,9 @@ void VT_KBCallBack(Uint32 Codepoint) break; case KEY_PGUP: - buf[0] = '\x1B'; buf[1] = '['; buf[2] = '5'; // Some overline also + //buf[0] = '\x1B'; buf[1] = '['; buf[2] = '5'; // Some overline also //len = 4; // Commented out until I'm sure + len = 0; break; case KEY_PGDOWN: len = 0; @@ -887,15 +909,18 @@ void VT_KBCallBack(Uint32 Codepoint) void VT_int_ClearLine(tVTerm *Term, int Num) { int i; - tVT_Char *cell = &Term->Text[ Num*Term->TextWidth ]; + tVT_Char *cell; + if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) ) return ; - //ENTER("pTerm iNum", Term, Num); + + cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text; + cell = &cell[ Num*Term->TextWidth ]; + for( i = Term->TextWidth; i--; ) { cell[ i ].Ch = 0; cell[ i ].Colour = Term->CurColour; } - //LEAVE('-'); } /** @@ -908,6 +933,7 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) int argc = 0, j = 1; int tmp; int args[6] = {0,0,0,0}; + int bQuestionMark = 0; switch(Buffer[0]) { @@ -915,6 +941,10 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) case '[': // Get Arguments c = Buffer[j++]; + if(c == '?') { + bQuestionMark = 1; + c = Buffer[j++]; + } if( '0' <= c && c <= '9' ) { do { @@ -931,80 +961,145 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) // Get Command if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) { - switch(c) + if( bQuestionMark ) { - // Left - case 'D': - if(argc == 1) tmp = args[0]; - else tmp = 1; - - if( Term->WritePos-(tmp-1) % Term->TextWidth == 0 ) - Term->WritePos -= Term->WritePos % Term->TextWidth; - else - Term->WritePos -= tmp; - break; - - // Right - case 'C': - if(argc == 1) tmp = args[0]; - else tmp = 1; - if( (Term->WritePos + tmp) % Term->TextWidth == 0 ) { - Term->WritePos -= Term->WritePos % Term->TextWidth; - Term->WritePos += Term->TextWidth - 1; - } else - Term->WritePos += tmp; - break; - - // Clear By Line - case 'J': - // Clear Screen - switch(args[0]) + switch(c) { - case 2: + // DEC Private Mode Set + case 'h': + if(argc != 1) break; + switch(args[0]) + { + case 1047: + VT_int_ToggleAltBuffer(Term, 1); + break; + } + break; + case 'l': + if(argc != 1) break; + switch(args[0]) { - int i = Term->TextHeight * (giVT_Scrollback + 1); - while( i-- ) VT_int_ClearLine(Term, i); - Term->WritePos = 0; - Term->ViewPos = 0; - VT_int_UpdateScreen(Term, 1); + case 1047: + VT_int_ToggleAltBuffer(Term, 0); + break; } break; } - break; - // Set cursor position - case 'h': - Term->WritePos = args[0] + args[1]*Term->TextWidth; - Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]); - break; - // Set Font flags - case 'm': - for( ; argc--; ) + } + else + { + tmp = 1; + switch(c) { - // Flags - if( 0 <= args[argc] && args[argc] <= 8) + // Left + case 'D': + tmp = -1; + // Right + case 'C': + if(argc == 1) tmp *= args[0]; + if( Term->Flags & VT_FLAG_ALTBUF ) { - switch(args[argc]) - { - case 0: Term->CurColour = DEFAULT_COLOUR; break; // Reset - case 1: Term->CurColour |= 0x80000000; break; // Bright - case 2: Term->CurColour &= ~0x80000000; break; // Dim + if( (Term->AltWritePos + tmp) % Term->TextWidth == 0 ) { + Term->AltWritePos -= Term->AltWritePos % Term->TextWidth; + Term->AltWritePos += Term->TextWidth - 1; + } + else + Term->AltWritePos += tmp; + } + else + { + if( (Term->WritePos + tmp) % Term->TextWidth == 0 ) { + Term->WritePos -= Term->WritePos % Term->TextWidth; + Term->WritePos += Term->TextWidth - 1; } + else + Term->WritePos += tmp; } - // Foreground Colour - else if(30 <= args[argc] && args[argc] <= 37) { - Term->CurColour &= 0xF000FFFF; - Term->CurColour |= (Uint32)caVT100Colours[ args[argc]-30+(Term->CurColour>>28) ] << 16; + break; + + // Erase + case 'J': + switch(args[0]) + { + case 0: // Erase below + break; + case 1: // Erase above + break; + case 2: // Erase all + if( Term->Flags & VT_FLAG_ALTBUF ) + { + int i = Term->TextHeight; + while( i-- ) VT_int_ClearLine(Term, i); + Term->AltWritePos = 0; + VT_int_UpdateScreen(Term, 1); + } + else + { + int i = Term->TextHeight * (giVT_Scrollback + 1); + while( i-- ) VT_int_ClearLine(Term, i); + Term->WritePos = 0; + Term->ViewPos = 0; + VT_int_UpdateScreen(Term, 1); + } + break; } - // Background Colour - else if(40 <= args[argc] && args[argc] <= 47) { - Term->CurColour &= 0xFFFF8000; - Term->CurColour |= caVT100Colours[ args[argc]-40+((Term->CurColour>>12)&15) ]; + break; + // Set cursor position + case 'H': + if( Term->Flags & VT_FLAG_ALTBUF ) + Term->AltWritePos = args[0] + args[1]*Term->TextWidth; + else + Term->WritePos = args[0] + args[1]*Term->TextWidth; + Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]); + break; + + // Scroll up `n` lines + case 'S': + tmp = -1; + // Scroll down `n` lines + case 'P': + if(argc == 1) tmp *= args[0]; + + break; + + // Set Font flags + case 'm': + for( ; argc--; ) + { + // Flags + if( 0 <= args[argc] && args[argc] <= 8) + { + switch(args[argc]) + { + case 0: Term->CurColour = DEFAULT_COLOUR; break; // Reset + case 1: Term->CurColour |= 0x80000000; break; // Bright + case 2: Term->CurColour &= ~0x80000000; break; // Dim + } + } + // Foreground Colour + else if(30 <= args[argc] && args[argc] <= 37) { + Term->CurColour &= 0xF000FFFF; + Term->CurColour |= (Uint32)caVT100Colours[ args[argc]-30+(Term->CurColour>>28) ] << 16; + } + // Background Colour + else if(40 <= args[argc] && args[argc] <= 47) { + Term->CurColour &= 0xFFFF8000; + Term->CurColour |= caVT100Colours[ args[argc]-40+((Term->CurColour>>12)&15) ]; + } } + break; + + // Set scrolling region + case 'r': + if( argc != 2 ) break; + Term->ScrollTop = args[0]; + Term->ScrollHeight = args[1] - args[0]; + break; + + default: + Log_Warning("VTerm", "Unknown control sequence"); + break; } - break; - default: - Log_Warning("VTerm", "Unknown control sequence"); - break; } } break; @@ -1051,9 +1146,11 @@ void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count) if( Term == gpVT_CurTerm && !(Term->Flags & VT_FLAG_HIDECSR) ) { tVideo_IOCtl_Pos pos; - pos.x = (Term->WritePos - Term->ViewPos) % Term->TextWidth; - pos.y = (Term->WritePos - Term->ViewPos) / Term->TextWidth; - VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); + int offset = (gpVT_CurTerm->Flags & VT_FLAG_ALTBUF) ? gpVT_CurTerm->AltWritePos : gpVT_CurTerm->WritePos - gpVT_CurTerm->ViewPos; + pos.x = offset % gpVT_CurTerm->TextWidth; + pos.y = offset / gpVT_CurTerm->TextWidth; + if( 0 <= pos.y && pos.y < gpVT_CurTerm->TextHeight ) + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); } } @@ -1064,125 +1161,210 @@ void VT_int_PutString(tVTerm *Term, 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; + } + else { + buffer = Term->Text; + write_pos = Term->WritePos; + } switch(Ch) { case '\0': return; // Ignore NULL byte case '\n': VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining - Term->WritePos += Term->TextWidth; + write_pos += Term->TextWidth; case '\r': - Term->WritePos -= Term->WritePos % Term->TextWidth; + write_pos -= write_pos % Term->TextWidth; break; case '\t': do { - Term->Text[ Term->WritePos ].Ch = '\0'; - Term->Text[ Term->WritePos ].Colour = Term->CurColour; - Term->WritePos ++; - } while(Term->WritePos & 7); + buffer[ write_pos ].Ch = '\0'; + buffer[ write_pos ].Colour = Term->CurColour; + write_pos ++; + } while(write_pos & 7); break; case '\b': // Backspace is invalid at Offset 0 - if(Term->WritePos == 0) break; + if(write_pos == 0) break; - Term->WritePos --; + write_pos --; // Singe Character - if(Term->Text[ Term->WritePos ].Ch != '\0') { - Term->Text[ Term->WritePos ].Ch = 0; - Term->Text[ Term->WritePos ].Colour = Term->CurColour; + if(buffer[ write_pos ].Ch != '\0') { + buffer[ write_pos ].Ch = 0; + buffer[ write_pos ].Colour = Term->CurColour; break; } // Tab i = 7; // Limit it to 8 do { - Term->Text[ Term->WritePos ].Ch = 0; - Term->Text[ Term->WritePos ].Colour = Term->CurColour; - Term->WritePos --; - } while(Term->WritePos && i-- && Term->Text[ Term->WritePos ].Ch == '\0'); - if(Term->Text[ Term->WritePos ].Ch != '\0') - Term->WritePos ++; + buffer[ write_pos ].Ch = 0; + buffer[ write_pos ].Colour = Term->CurColour; + write_pos --; + } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0'); + if(buffer[ write_pos ].Ch != '\0') + write_pos ++; break; default: - Term->Text[ Term->WritePos ].Ch = Ch; - Term->Text[ Term->WritePos ].Colour = Term->CurColour; + buffer[ write_pos ].Ch = Ch; + buffer[ write_pos ].Colour = Term->CurColour; // Update the line before wrapping - if( (Term->WritePos + 1) % Term->TextWidth == 0 ) + if( (write_pos + 1) % Term->TextWidth == 0 ) VT_int_UpdateScreen( Term, 0 ); - Term->WritePos ++; + write_pos ++; break; } - // Move Screen - // - Check if we need to scroll the entire scrollback buffer - if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1)) + if(Term->Flags & VT_FLAG_ALTBUF) { - int base; + Term->AltBuf = buffer; + Term->AltWritePos = write_pos; - // Move back by one - Term->WritePos -= Term->TextWidth; - // Update the scren - VT_int_UpdateScreen( Term, 0 ); + if(Term->AltWritePos >= Term->TextWidth*Term->TextHeight) + { + Term->AltWritePos -= Term->TextWidth; + VT_int_ScrollText(Term, 1); + } - // 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; + } + else + { + Term->Text = buffer; + 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 previous line + Term->WritePos -= Term->TextWidth; + VT_int_UpdateScreen( Term, 0 ); + + // 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); + } + // Ok, so we only need to scroll the screen + else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight) + { + // Update the last line + Term->WritePos -= Term->TextWidth; + VT_int_UpdateScreen( Term, 0 ); + + VT_int_ScrollText(Term, 1); + } + } + + //LEAVE('-'); +} + +void VT_int_ScrollText(tVTerm *Term, int Count) +{ + tVT_Char *buf; + int height, init_write_pos; + int base, len, i; + + if( Term->Flags & VT_FLAG_ALTBUF ) + { + buf = Term->AltBuf; + height = Term->TextHeight; + init_write_pos = Term->AltWritePos; + } + else + { + buf = Term->Text; + height = Term->TextHeight*giVT_Scrollback; + init_write_pos = Term->WritePos; + } + + if( Count > 0 ) + { + if(Count > Term->ScrollHeight) Count = Term->ScrollHeight; + base = Term->TextWidth*(Term->ScrollTop + Term->ScrollHeight - Count); + len = Term->TextWidth*(height - Term->ScrollHeight - Count - Term->ScrollTop); // Scroll terminal cache - base = Term->TextWidth*(Term->TextHeight*(giVT_Scrollback+1)-1); memcpy( - Term->Text, - &Term->Text[Term->TextWidth], - base*sizeof(tVT_Char) + &buf[Term->TextWidth*Term->ScrollTop], + &buf[Term->TextWidth*(Term->ScrollTop+Count)], + len*sizeof(tVT_Char) ); - - // Clear last row - for( i = 0; i < Term->TextWidth; i ++ ) + // Clear last rows + for( i = 0; i < Term->TextWidth*Count; i ++ ) { - Term->Text[ base + i ].Ch = 0; - Term->Text[ base + i ].Colour = Term->CurColour; + Term->AltBuf[ base + i ].Ch = 0; + Term->AltBuf[ base + i ].Colour = Term->CurColour; } - VT_int_ScrollFramebuffer( Term ); - VT_int_UpdateScreen( Term, 0 ); + // Update Screen + VT_int_ScrollFramebuffer( Term, Count ); + Term->WritePos = Term->ViewPos + Term->ScrollTop + (Term->ScrollHeight - Count); + for( 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; + } } - // Ok, so we only need to scroll the screen - else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight) + else { - //Debug("Term->WritePos (%i) >= %i", - // Term->WritePos, - // Term->ViewPos + Term->TextWidth*Term->TextHeight - // ); - //Debug("Scrolling screen only"); + Count = -Count; + if(Count > Term->ScrollHeight) Count = Term->ScrollHeight; - // Update the last line - Term->WritePos -= Term->TextWidth; - VT_int_UpdateScreen( Term, 0 ); - Term->WritePos += Term->TextWidth; - VT_int_ClearLine(Term, Term->WritePos / Term->TextWidth); + len = Term->TextWidth*(height - Term->ScrollHeight - Count - Term->ScrollTop); - // Scroll - Term->ViewPos += Term->TextWidth; - //Debug("Term->ViewPos = %i", Term->ViewPos); - VT_int_ScrollFramebuffer( Term ); - VT_int_UpdateScreen( Term, 0 ); + // Scroll terminal cache + memcpy( + &buf[Term->TextWidth*(Term->ScrollTop+Count)], + &buf[Term->TextWidth*Term->ScrollTop], + len*sizeof(tVT_Char) + ); + // Clear preceding rows + for( i = 0; i < Term->TextWidth*Count; i ++ ) + { + Term->AltBuf[ i ].Ch = 0; + Term->AltBuf[ i ].Colour = Term->CurColour; + } - //VT_int_UpdateScreen( Term, 1 ); // HACK! + VT_int_ScrollFramebuffer( Term, -Count ); + Term->WritePos = Term->ViewPos + Term->ScrollTop; + for( 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; + } } - //LEAVE('-'); + if( Term->Flags & VT_FLAG_ALTBUF ) + Term->AltWritePos = init_write_pos; + else + Term->WritePos = init_write_pos; } /** - * \fn void VT_int_ScrollFramebuffer( tVTerm *Term ) - * \note Scrolls the framebuffer by 1 text line + * \fn void VT_int_ScrollFramebuffer( tVTerm *Term, int Count ) + * \note Scrolls the framebuffer down by \a Count text lines */ -void VT_int_ScrollFramebuffer( tVTerm *Term ) +void VT_int_ScrollFramebuffer( tVTerm *Term, int Count ) { int tmp; struct { @@ -1195,16 +1377,29 @@ void VT_int_ScrollFramebuffer( tVTerm *Term ) // Only update if this is the current terminal if( Term != gpVT_CurTerm ) return; + if( Count > Term->ScrollHeight ) Count = Term->ScrollHeight; + if( Count < -Term->ScrollHeight ) Count = -Term->ScrollHeight; + // Switch to 2D Command Stream tmp = VIDEO_BUFFMT_2DSTREAM; VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp); - // BLIT from 0,0 to 0,giVT_CharHeight + // BLIT to 0,0 from 0,giVT_CharHeight buf.Op = VIDEO_2DOP_BLIT; - buf.DstX = 0; buf.DstY = 0; - buf.SrcX = 0; buf.SrcY = giVT_CharHeight; + buf.SrcX = 0; buf.DstX = 0; buf.W = Term->TextWidth * giVT_CharWidth; - buf.H = (Term->TextHeight-1) * giVT_CharHeight; + if( Count > 0 ) + { + buf.SrcY = (Term->ScrollTop+Count) * giVT_CharHeight; + buf.DstY = Term->ScrollTop * giVT_CharHeight; + buf.H = (Term->ScrollHeight-Count) * giVT_CharHeight; + } + else // Scroll up, move text down + { + buf.SrcY = Term->ScrollTop * giVT_CharHeight; + buf.DstY = (Term->ScrollTop+Count) * giVT_CharHeight; + buf.H = (Term->ScrollHeight+Count) * giVT_CharHeight; + } VFS_WriteAt(giVT_OutputDevHandle, 0, sizeof(buf), &buf); // Restore old mode (this function is only called during text mode) @@ -1218,29 +1413,34 @@ void VT_int_ScrollFramebuffer( tVTerm *Term ) */ void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) { + tVT_Char *buffer; + int view_pos, write_pos; // Only update if this is the current terminal if( Term != gpVT_CurTerm ) return; switch( Term->Mode ) { case TERM_MODE_TEXT: + view_pos = (Term->Flags & VT_FLAG_ALTBUF) ? 0 : Term->ViewPos; + write_pos = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltWritePos : Term->WritePos; + buffer = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text; // Re copy the entire screen? if(UpdateAll) { VFS_WriteAt( giVT_OutputDevHandle, 0, Term->TextWidth*Term->TextHeight*sizeof(tVT_Char), - &Term->Text[Term->ViewPos] + &buffer[view_pos] ); } // Only copy the current line else { - int pos = Term->WritePos - Term->WritePos % Term->TextWidth; + int ofs = write_pos - write_pos % Term->TextWidth; VFS_WriteAt( giVT_OutputDevHandle, - (pos - Term->ViewPos)*sizeof(tVT_Char), + (ofs - view_pos)*sizeof(tVT_Char), Term->TextWidth*sizeof(tVT_Char), - &Term->Text[pos] + &buffer[ofs] ); } break; @@ -1264,64 +1464,72 @@ void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) */ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight) { - int oldW = Term->Width; - int oldTW = oldW / giVT_CharWidth; - int oldH = Term->Height; - int oldTH = oldH / giVT_CharWidth; - tVT_Char *oldTBuf = Term->Text; - Uint32 *oldFB = Term->Buffer; - int w, h, i; // TODO: Increase RealWidth/RealHeight when this happens if(NewWidth > giVT_RealWidth) NewWidth = giVT_RealWidth; if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight; - // Calculate new dimensions - Term->TextWidth = NewWidth / giVT_CharWidth; - Term->TextHeight = NewHeight / giVT_CharHeight; - Term->Width = NewWidth; - Term->Height = NewHeight; Term->Mode = NewMode; - // Allocate new buffers - // - Text - Term->Text = calloc( - Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1), - sizeof(tVT_Char) - ); - if(oldTBuf) { - // Copy old buffer - w = oldTW; - if( w > Term->TextWidth ) w = Term->TextWidth; - h = oldTH; - if( h > Term->TextHeight ) h = Term->TextHeight; - h *= giVT_Scrollback + 1; - for( i = 0; i < h; i ++ ) - { - memcpy( - &Term->Text[i*Term->TextWidth], - &oldTBuf[i*oldTW], - w*sizeof(tVT_Char) - ); - + if(NewWidth != Term->Width || NewHeight != Term->Height) + { + int oldW = Term->Width; + int oldTW = Term->TextWidth; + int oldH = Term->Height; + int oldTH = Term->TextHeight; + tVT_Char *oldTBuf = Term->Text; + Uint32 *oldFB = Term->Buffer; + int w, h, i; + // Calculate new dimensions + Term->Width = NewWidth; + Term->Height = NewHeight; + Term->TextWidth = NewWidth / giVT_CharWidth; + Term->TextHeight = NewHeight / giVT_CharHeight; + Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop; + + // Allocate new buffers + // - Text + Term->Text = calloc( + Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1), + sizeof(tVT_Char) + ); + if(oldTBuf) { + // Copy old buffer + w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW; + h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH; + h *= giVT_Scrollback + 1; + for( i = 0; i < h; i ++ ) + { + memcpy( + &Term->Text[i*Term->TextWidth], + &oldTBuf[i*oldTW], + w*sizeof(tVT_Char) + ); + } + free(oldTBuf); } - } - - // - Framebuffer - Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) ); - if(oldFB) { - // Copy old buffer - w = oldW; - if( w > Term->Width ) w = Term->Width; - h = oldH; - if( h > Term->Height ) h = Term->Height; - for( i = 0; i < h; i ++ ) - { - memcpy( - &Term->Buffer[i*Term->Width], - &oldFB[i*oldW], - w*sizeof(Uint32) - ); + + // - Alternate Text + Term->AltBuf = realloc( + Term->AltBuf, + Term->TextWidth * Term->TextHeight * sizeof(tVT_Char) + ); + + // - Framebuffer + Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) ); + if(oldFB) { + // Copy old buffer + w = (oldW > Term->Width) ? Term->Width : oldW; + h = (oldH > Term->Height) ? Term->Height : oldH; + for( i = 0; i < h; i ++ ) + { + memcpy( + &Term->Buffer[i*Term->Width], + &oldFB[i*oldW], + w*sizeof(Uint32) + ); + } + free(oldFB); } } @@ -1343,6 +1551,15 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight) } } + +void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled) +{ + if(Enabled) + Term->Flags |= VT_FLAG_ALTBUF; + else + Term->Flags &= ~VT_FLAG_ALTBUF; +} + // --- // Font Render // --- diff --git a/Kernel/include/tpl_drv_terminal.h b/Kernel/include/tpl_drv_terminal.h index ee50392b..b32b83d5 100644 --- a/Kernel/include/tpl_drv_terminal.h +++ b/Kernel/include/tpl_drv_terminal.h @@ -65,7 +65,14 @@ enum eTplTerminal_IOCtl { * ioctl(...) * \brief Forces the current terminal to be shown */ - TERM_IOCTL_FORCESHOW + TERM_IOCTL_FORCESHOW, + + /** + * ioctl(...) + * \brief Returns the current text cursor position + * \return Cursor position (as X+Y*Width) + */ + TERM_IOCTL_GETCURSOR }; /** diff --git a/Modules/IPStack/ipv4.c b/Modules/IPStack/ipv4.c index a2e63efa..b77581eb 100644 --- a/Modules/IPStack/ipv4.c +++ b/Modules/IPStack/ipv4.c @@ -208,7 +208,7 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff break ; // Unknown, silent drop default: - Log_Warning("IPv4", "Unknown firewall response %i", ret); + Log_Warning("IPv4", "Unknown firewall rule"); return ; } diff --git a/Modules/IPStack/tcp.c b/Modules/IPStack/tcp.c index 83a71b64..80a5eee8 100644 --- a/Modules/IPStack/tcp.c +++ b/Modules/IPStack/tcp.c @@ -354,9 +354,10 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // - Handle State changes // if( Header->Flags & TCP_FLAG_FIN ) { - Log_Log("TCP", "Conn %p closed, recieved FIN, acknowledging", Connection); + Log_Log("TCP", "Conn %p closed, recieved FIN", Connection); VFS_MarkError(&Connection->Node, 1); Connection->State = TCP_ST_CLOSE_WAIT; +// Header->Flags &= ~TCP_FLAG_FIN; // CLOSE WAIT requires the client to close (or does it?) #if 0 @@ -1091,6 +1092,11 @@ Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buf ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); +// #if DEBUG +// Debug_HexDump("TCP_Client_Write: Buffer = ", +// Buffer, Length); +// #endif + // Check if connection is open while( conn->State == TCP_ST_SYN_RCVD || conn->State == TCP_ST_SYN_SENT ) Threads_Yield(); @@ -1117,7 +1123,7 @@ Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buf TCP_INT_SendDataPacket(conn, len, Buffer); Buffer += len; - rem += len; + rem -= len; } while( rem > 0 ); LEAVE('i', Length); diff --git a/Modules/IPStack/udp.c b/Modules/IPStack/udp.c index 1fce3ac2..6f3abc60 100644 --- a/Modules/IPStack/udp.c +++ b/Modules/IPStack/udp.c @@ -70,7 +70,8 @@ int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, in // Check for remote address restriction if(chan->RemoteMask) { - if(chan->Remote.AddrType != Interface->Type) continue; + if(chan->Remote.AddrType != Interface->Type) + continue; if(!IPStack_CompareAddress(Interface->Type, Address, &chan->Remote.Addr, chan->RemoteMask) ) @@ -94,6 +95,7 @@ int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, in else chan->QueueEnd = chan->Queue = pack; SHORTREL(&chan->lQueue); + VFS_MarkAvaliable(&chan->Node, 1); Mutex_Release(&glUDP_Channels); return 1; } @@ -190,7 +192,10 @@ Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buf tUDPEndpoint *ep; int ofs; - if(chan->LocalPort == 0) return 0; + if(chan->LocalPort == 0) { + Log_Notice("UDP", "Channel %p sent with no local port", chan); + return 0; + } while(chan->Queue == NULL) Threads_Yield(); @@ -217,6 +222,7 @@ Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buf ofs = 4 + IPStack_GetAddressSize(pack->Remote.AddrType); if(Length < ofs) { free(pack); + Log_Notice("UDP", "Insuficient space for header in buffer (%i < %i)", (int)Length, ofs); return 0; } diff --git a/Usermode/Applications/irc_src/main.c b/Usermode/Applications/irc_src/main.c index 0c90c501..9c7eccc6 100644 --- a/Usermode/Applications/irc_src/main.c +++ b/Usermode/Applications/irc_src/main.c @@ -64,13 +64,14 @@ tWindow *Window_Create(tServer *Server, const char *Name); int ProcessIncoming(tServer *Server); // --- Helpers + int SetCursorPos(int Row, int Col); int writef(int FD, const char *Format, ...); int OpenTCP(const char *AddressString, short PortNumber); char *GetValue(char *Str, int *Ofs); static inline int isdigit(int ch); // === GLOBALS === -char *gsUsername = "root"; +char *gsUsername = "user"; char *gsHostname = "acess"; char *gsRealName = "Acess2 IRC Client"; char *gsNickname = "acess"; @@ -81,8 +82,15 @@ tWindow gWindow_Status = { }; tWindow *gpWindows = &gWindow_Status; tWindow *gpCurrentWindow = &gWindow_Status; + int giTerminal_Width = 80; + int giTerminal_Height = 25; // ==== CODE ==== +void ExitHandler(void) +{ + printf("\x1B[?1047l"); +} + int main(int argc, const char *argv[], const char *envp[]) { int tmp; @@ -91,6 +99,14 @@ int main(int argc, const char *argv[], const char *envp[]) // Parse Command line if( (tmp = ParseArguments(argc, argv)) ) return tmp; + atexit(ExitHandler); + + giTerminal_Width = ioctl(1, 5, NULL); // getset_width + giTerminal_Height = ioctl(1, 6, NULL); // getset_height + + printf("\x1B[?1047h"); + printf("\x1B[%i;%ir", 0, giTerminal_Height-1); + // HACK: Static server entry // UCC (University [of Western Australia] Computer Club) IRC Server gWindow_Status.Server = Server_Connect( "UCC", "130.95.13.18", 6667 ); @@ -100,6 +116,9 @@ int main(int argc, const char *argv[], const char *envp[]) readline_info = Readline_Init(1); + SetCursorPos(giTerminal_Height-1, 0); + printf("[(status)] "); + for( ;; ) { fd_set readfds, errorfds; @@ -133,6 +152,12 @@ int main(int argc, const char *argv[], const char *envp[]) ParseUserCommand(cmd); } free(cmd); + // Prompt + SetCursorPos(giTerminal_Height-1, 0); + if( gpCurrentWindow->Name[0] ) + printf("[%s:%s] ", gpCurrentWindow->Server->Name, gpCurrentWindow->Name); + else + printf("[(status)] "); } } @@ -188,7 +213,7 @@ int ParseUserCommand(char *String) if( gpCurrentWindow->Server ) { - writef(gpCurrentWindow->Server->FD, "JOIN %s\n", channel_name); + writef(gpCurrentWindow->Server->FD, "JOIN :%s\n", channel_name); } } else if( strcmp(command, "/quit") == 0 ) @@ -196,13 +221,15 @@ int ParseUserCommand(char *String) char *quit_message = GetValue(String, &pos); tServer *srv; - if( !quit_message ) + if( quit_message == NULL || quit_message[0] == '\0' ) quit_message = "/quit - Acess2 IRC Client"; for( srv = gpServers; srv; srv = srv->Next ) { - writef(srv->FD, "QUIT %s\n", quit_message); + writef(srv->FD, "QUIT :%s\n", quit_message); } + + exit(0); } else if( strcmp(command, "/window") == 0 || strcmp(command, "/win") == 0 || strcmp(command, "/w") == 0 ) { @@ -217,13 +244,20 @@ int ParseUserCommand(char *String) for( win = gpWindows; win && window_num--; win = win->Next ); if( win ) { gpCurrentWindow = win; - if( win->Name[0] ) - printf("[%s:%s] ", win->Server->Name, win->Name); - else - printf("[(status)] ", win->Server->Name, win->Name); } // Otherwise, silently ignore } + else + { + tWindow *win; + window_num = 1; + for( win = gpWindows; win; win = win->Next, window_num ++ ) + { + char tmp[snprintf(NULL, 1000, "%i: %s/%s", window_num, win->Server->Name, win->Name)+1]; + snprintf(tmp, 1000, "%i: %s/%s", window_num, win->Server->Name, win->Name); + Message_Append(NULL, MSG_TYPE_SERVER, "client", "", tmp); + } + } } else { @@ -359,6 +393,22 @@ tMessage *Message_Append(tServer *Server, int Type, const char *Source, const ch ret->Next = win->Messages; win->Messages = ret; + //TODO: Set location + + #if 1 + if( win == gpCurrentWindow ) { + int pos = SetCursorPos(giTerminal_Height-2, 0); + printf("\x1B[S"); // Scroll up 1 + printf("[%s] %s\n", Source, Message); + SetCursorPos(-1, pos); + } + #else + if(win->Name[0]) + printf("%s/%s [%s] %s\n", win->Server->Name, win->Name, Source, Message); + else + printf("(status) [%s] %s\n", Source, Message); + #endif + return ret; } @@ -387,14 +437,15 @@ tWindow *Window_Create(tServer *Server, const char *Name) gpWindows = ret; } - printf("Win %i %s:%s created\n", num, Server->Name, Name); +// printf("Win %i %s:%s created\n", num, Server->Name, Name); return ret; } void Cmd_PRIVMSG(tServer *Server, const char *Dest, const char *Src, const char *Message) { - printf("<%s:%s:%s> %s\n", Server->Name, Dest, Src, Message); + Message_Append(Server, MSG_TYPE_STANDARD, Dest, Src, Message); + //printf("<%s:%s:%s> %s\n", Server->Name, Dest, Src, Message); } /** @@ -431,7 +482,7 @@ void ParseServerLine(tServer *Server, char *Line) switch(num) { default: - printf("[%s] %i %s\n", Server->Name, num, message); + //printf("[%s] %i %s\n", Server->Name, num, message); Message_Append(Server, MSG_TYPE_SERVER, ident, user, message); break; } @@ -449,7 +500,7 @@ void ParseServerLine(tServer *Server, char *Line) message = GetValue(Line, &pos); } - printf("[%s] NOTICE %s: %s\n", Server->Name, ident, message); + //printf("[%s] NOTICE %s: %s\n", Server->Name, ident, message); Message_Append(Server, MSG_TYPE_NOTICE, ident, "", message); } else if( strcmp(cmd, "PRIVMSG") == 0 ) @@ -466,6 +517,12 @@ void ParseServerLine(tServer *Server, char *Line) Cmd_PRIVMSG(Server, dest, ident, message); Message_Append(Server, MSG_TYPE_STANDARD, ident, dest, message); } + else if( strcmp(cmd, "JOIN" ) == 0 ) + { + char *channel; + channel = GetValue(Line, &pos) + 1; + Window_Create(Server, channel); + } else { printf("Unknown message %s (%s)\n", cmd, Line+pos); @@ -639,6 +696,16 @@ char *GetValue(char *Src, int *Ofs) return ret; } +int SetCursorPos(int Row, int Col) +{ + if( Row == -1 ) { + Row = Col / giTerminal_Width; + Col = Col % giTerminal_Width; + } + printf("\x1B[%i;%iH", Col, Row); + return ioctl(1, 9, NULL); // Ugh, constants +} + static inline int isdigit(int ch) { return '0' <= ch && ch < '9'; diff --git a/Usermode/Libraries/libc.so_src/stdlib.c b/Usermode/Libraries/libc.so_src/stdlib.c index ce5a8d0c..733cb919 100644 --- a/Usermode/Libraries/libc.so_src/stdlib.c +++ b/Usermode/Libraries/libc.so_src/stdlib.c @@ -17,7 +17,15 @@ EXPORT int atoi(const char *str); EXPORT void exit(int status); +// === GLOBALS === +void (*g_stdlib_exithandler)(void); + // === CODE === +void atexit(void (*__func)(void)) +{ + g_stdlib_exithandler = __func; +} + /** * \fn EXPORT void exit(int status) * \brief Exit diff --git a/Usermode/include/stdlib.h b/Usermode/include/stdlib.h index baf12c31..6ea8db50 100644 --- a/Usermode/include/stdlib.h +++ b/Usermode/include/stdlib.h @@ -22,6 +22,7 @@ extern void _exit(int code) __attribute__((noreturn)); //NOTE: Also defined in acess/sys.h extern int atoi(const char *ptr); extern void exit(int status) __attribute__((noreturn)); +extern void atexit(void (*__func)(void)); extern void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)); // --- Environment --- -- 2.20.1