From 0e6b5f44c4802aeb2f22b8a6041d849728352e95 Mon Sep 17 00:00:00 2001 From: hwangcc23 Date: Thu, 7 Apr 2016 19:11:26 +0800 Subject: [PATCH] Numbering Post-Push Numbering Post-Push is a good function for discussion in one post. See the issue #42(https://github.com/pcman-bbs/pcmanx/issues/42). 1). Add a field PostPushNum in the line structure. The line structure: struct{ char[ColsPerPage], char='\0', CTermCharAttr[ColsPerPage, char=0]} [ ColsPerPage*char + '\0' + ColsPerPage*CTermCharAttr + PostPushNum ] 2). Detect Post-Push lines and numbering them whenever a character is added in the screen buffer of CTermData. 3). Save the number in PostPushNum of Post-Push lines. 4). Draw PostPushNum in CTermView:DrawChar(). 5). Fix a bug of buffer overflow in CTermData::InsertChar(). p.s. Though the function is not used now. --- src/core/termdata.cpp | 153 ++++++++++++++++++++++++++++++++++++------ src/core/termdata.h | 17 +++-- src/core/termview.cpp | 65 +++++++++++++++--- src/core/termview.h | 2 + 4 files changed, 201 insertions(+), 36 deletions(-) diff --git a/src/core/termdata.cpp b/src/core/termdata.cpp index b694646f..54339adf 100644 --- a/src/core/termdata.cpp +++ b/src/core/termdata.cpp @@ -167,23 +167,24 @@ CTermData::~CTermData() void CTermData::SetScreenSize( int RowCount, unsigned short RowsPerPage, unsigned short ColsPerPage) { - m_RowsPerPage = RowsPerPage; - // if cols per page change, reallocate all existing rows. - if( m_ColsPerPage != ColsPerPage ) - { - for(int i=0; i < m_RowCount; i++) - { - char* NewLine = AllocNewLine(ColsPerPage); - unsigned short Cols = (ColsPerPage < m_ColsPerPage)?ColsPerPage:m_ColsPerPage; - //Copy context of old into new one. - memcpy(NewLine, m_Screen[i], Cols); - memcpy(GetLineAttr(NewLine, ColsPerPage), GetLineAttr(m_Screen[i]), sizeof(CTermCharAttr::AttrType)*Cols); - delete []m_Screen[i]; - m_Screen[i] = NewLine; - } - m_ColsPerPage = ColsPerPage; - } - SetRowCount(RowCount); + m_RowsPerPage = RowsPerPage; + // if cols per page change, reallocate all existing rows. + if( m_ColsPerPage != ColsPerPage ) + { + for(int i=0; i < m_RowCount; i++) + { + char* NewLine = AllocNewLine(ColsPerPage); + unsigned short Cols = (ColsPerPage < m_ColsPerPage)?ColsPerPage:m_ColsPerPage; + //Copy context of old into new one. + memcpy(NewLine, m_Screen[i], Cols); + memcpy(GetLineAttr(NewLine, ColsPerPage), GetLineAttr(m_Screen[i]), sizeof(CTermCharAttr::AttrType)*Cols); + *GetPostPushNum(NewLine) = *GetPostPushNum(m_Screen[i]); + delete []m_Screen[i]; + m_Screen[i] = NewLine; + } + m_ColsPerPage = ColsPerPage; + } + SetRowCount(RowCount); } // Change row count of screen buffer @@ -226,11 +227,19 @@ void CTermData::AllocScreenBuf(int RowCount, unsigned short RowsPerPage,unsigned } // Initialize new lines -void CTermData::InitNewLine(char* NewLine, const int ColsPerPage){ +void CTermData::InitNewLine(char* NewLine, const int ColsPerPage) +{ memset( NewLine, ' ', ColsPerPage); + NewLine[ColsPerPage] = '\0'; - CTermCharAttr DefAttr; DefAttr.SetToDefault(); DefAttr.SetNeedUpdate(true); + + CTermCharAttr DefAttr; + DefAttr.SetToDefault(); + DefAttr.SetNeedUpdate(true); memset16( GetLineAttr(NewLine, ColsPerPage), DefAttr.AsType(), ColsPerPage); + + unsigned char *num = GetPostPushNum(NewLine); + *num = 0; } // LF handler @@ -342,6 +351,8 @@ void CTermData::PutChar(unsigned char ch) m_Screen[m_CaretPos.y][m_CaretPos.x] = ch; + NumberingPostPush( m_CaretPos.y ); + CTermCharAttr* pAttr = GetLineAttr( m_Screen[m_CaretPos.y] ); // Check if we've changed a character which is part of a URL. @@ -424,6 +435,7 @@ void CTermData::ScrollUp(int n /*=1*/) { memset( m_Screen[end+i], ' ', m_ColsPerPage-1 ); memset16( GetLineAttr(m_Screen[end+i]), m_CurAttr.AsType(), m_ColsPerPage-1 ); + *GetPostPushNum(m_Screen[end+i]) = 0; SetWholeLineUpdate(m_Screen[end+i]); } } @@ -447,6 +459,7 @@ void CTermData::ScrollDown(int n /*=1*/) { memset( m_Screen[end-i], ' ', m_ColsPerPage-1 ); memset16( GetLineAttr(m_Screen[end-i]), m_CurAttr.AsType(), m_ColsPerPage-1 ); + *GetPostPushNum(m_Screen[end-i]) = 0; SetWholeLineUpdate(m_Screen[end-i]); } } @@ -630,7 +643,9 @@ void CTermData::ClearScreen(int p) if( i < m_RowsPerPage) break; memcpy( tmp, m_Screen[i-m_RowsPerPage],m_ColsPerPage); - memcpy( GetLineAttr(tmp),GetLineAttr(m_Screen[i-m_RowsPerPage]),m_ColsPerPage); } + memcpy( GetLineAttr(tmp),GetLineAttr(m_Screen[i-m_RowsPerPage]),m_ColsPerPage); + *GetPostPushNum(tmp) = *GetPostPushNum(m_Screen[i-m_RowsPerPage]); + } break; case 0: // Erase from current position to end (inclusive) default: @@ -647,7 +662,9 @@ void CTermData::ClearScreen(int p) if( i < m_RowsPerPage) break; memcpy( tmp, m_Screen[i-m_RowsPerPage],m_ColsPerPage); - memcpy( GetLineAttr(tmp),GetLineAttr(m_Screen[i-m_RowsPerPage]),m_ColsPerPage); } + memcpy( GetLineAttr(tmp),GetLineAttr(m_Screen[i-m_RowsPerPage]),m_ColsPerPage); + *GetPostPushNum(tmp) = *GetPostPushNum(m_Screen[i-m_RowsPerPage]); + } break; } } @@ -1288,7 +1305,7 @@ void CTermData::InsertChar( int line, int col, int n ) CTermCharAttr* pattr = GetLineAttr( pline ); int coln = col + n; - for( int end = m_ColsPerPage; end >= coln; end-- ) + for( int end = m_ColsPerPage - 1; end >= coln; end-- ) { pline[ end ] = pline[ end - n ]; pattr[ end ] = pattr[ end - n ]; @@ -1425,3 +1442,95 @@ void CTermData::OnLineModified(int row UNUSED) // This function can be overriden in derived class. } +bool CTermData::PostPushHeaderTest(int iLine) +{ + char *line = m_Screen[iLine]; + int col; + + // FIXME: Hack to detect PostPushHeader on PTT. Have a general method? + if( line[0] == '-' && line[1] == '-' ) + { + for( col = 2; col < m_ColsPerPage; col++ ) + { + if( line[col] != ' ' ) + return false; + } + return true; + } + + return false; +} + +bool CTermData::PostPushTest(int iLine) +{ + char *line = m_Screen[iLine]; + + // FIXME: Hack to detect PostPush on PTT. Have a general method? + if( line[0] == '\xb1' && line[1] == '\xc0' && line[2] == ' ' ) // like + return true; + if( line[0] == '\xbc' && line[1] == '\x4e' && line[2] == ' ' ) // dislike + return true; + if( line[0] == '\xa1' && line[1] == '\xf7' && line[2] == ' ' ) // line continuation + return true; + + return false; +} + +void CTermData::NumberingPostPush(int iLine) +{ + unsigned char num = 0; + int row; + + *GetPostPushNum(m_Screen[iLine]) = 0; + + if( !PostPushTest(iLine) ) + { + return ; + } + + for( row = iLine - 1; row >= m_FirstLine; row-- ) + { + if( PostPushHeaderTest(row) ) + { + num = 1; + goto Numbering; + } + + if( PostPushTest(row) ) + { + num = *GetPostPushNum( m_Screen[row] ); + if( num ) + { + //num += iLine - row; + num++; + goto Numbering; + } + } + } + + for( row = iLine + 1; row < m_RowsPerPage; row++ ) + { + if( PostPushHeaderTest(row) ) + { + goto Numbering; + } + + if( PostPushTest(row) ) + { + num = *GetPostPushNum( m_Screen[row] ); + if( num ) + { + //num -= iLine + row; + num--; + goto Numbering; + } + } + } + +Numbering: + if( num > 0 ) + { + *GetPostPushNum( m_Screen[iLine] ) = num; + + } +} diff --git a/src/core/termdata.h b/src/core/termdata.h index 828cd819..30abaf44 100644 --- a/src/core/termdata.h +++ b/src/core/termdata.h @@ -202,6 +202,11 @@ class X_EXPORT CTermData return ( CTermCharAttr* ) ( pLine + m_ColsPerPage + 1 ); } + unsigned char* GetPostPushNum( const char* pLine ) + { + return ( unsigned char* ) ( pLine + m_ColsPerPage + 1 + m_ColsPerPage * sizeof( CTermCharAttr::AttrType ) ); + } + //Get all text from (0,0) to (maxX, maxY), if trim is true, it return text //without tail black spaces. string GetAllText( bool trim = true ) @@ -227,6 +232,7 @@ class X_EXPORT CTermData #endif void UpdateDisplay(); void DoUpdateDisplay(); + void NumberingPostPush(); static void memset16( void* dest, short val, size_t n ); void ParseAnsiColor( const char* pParam ); void EraseLine( int p ); @@ -277,11 +283,11 @@ class X_EXPORT CTermData // Allocate new lines char* AllocNewLine( const int ColsPerPage ) { - // struct{ char[ColsPerPage], char='\0', CTermCharAttr[ColsPerPage]} + // struct{ char[ColsPerPage], char='\0', CTermCharAttr[ColsPerPage, char=0]} // Neversay:The structure is show below: - // [ ColsPerPage*char + '\0' + ColsPerPage*CTermCharAttr ] - // so size is: ColsPerPage*1 + 1 + ColsPerPage*sizeof(CTermCharAttr) - char * NewLine = new char[ 1 + ColsPerPage * ( 1 + sizeof( CTermCharAttr::AttrType ) ) ]; + // [ ColsPerPage*char + '\0' + ColsPerPage*CTermCharAttr + PostPushNum ] + // so size is: ColsPerPage*1 + 1 + ColsPerPage*sizeof(CTermCharAttr) + 1 + char * NewLine = new char[ 1 + ColsPerPage * ( 1 + sizeof( CTermCharAttr::AttrType ) ) + 1 ]; InitNewLine( NewLine, ColsPerPage ); return NewLine; @@ -292,6 +298,9 @@ class X_EXPORT CTermData void AllocScreenBuf( int RowCount, unsigned short RowsPerPage, unsigned short ColsPerPage ); virtual void OnLineModified( int row ); + bool PostPushHeaderTest(int iLine); + bool PostPushTest(int iLine); + void NumberingPostPush(int iLine); /////////////////////////////////////////////////////////////////// //Data Field Section diff --git a/src/core/termview.cpp b/src/core/termview.cpp index c880155c..794306a8 100644 --- a/src/core/termview.cpp +++ b/src/core/termview.cpp @@ -369,7 +369,7 @@ bool CTermView::DrawSpaceFillingChar(const char* ch, int len UNUSED, int x, int return false; } -int CTermView::DrawChar(int row, int col) +int CTermView::DoDrawChar(int row, int col, const char *str, CTermCharAttr *pAttr) { GdkDrawable* dc = m_Widget->window; if(!GDK_IS_DRAWABLE(dc) && m_XftDraw == NULL) @@ -378,11 +378,9 @@ int CTermView::DrawChar(int row, int col) return 1; } - const char* pLine = m_pTermData->m_Screen[m_pTermData->m_FirstLine + row]; - CTermCharAttr* pAttr = m_pTermData->GetLineAttr(pLine); int w = 2; bool is_mbcs2 = false; - switch( pAttr[col].GetCharSet() ) + switch( pAttr->GetCharSet() ) { case CTermCharAttr::CS_MBCS1: break; @@ -397,8 +395,6 @@ int CTermView::DrawChar(int row, int col) // case CTermCharAttr::CS_ASCII: w = 1; } - pLine += col; - pAttr += col; int loop_times = w; bool bSel[2]; @@ -465,7 +461,7 @@ int CTermView::DrawChar(int row, int col) if( !pAttr[i].IsBlink() || m_ShowBlink ) // If text should be drawn. { - if( ' ' != *pLine && '\0' != *pLine ) + if( ' ' != *str && '\0' != *str ) { gsize wl = 0; gchar* utf8 = NULL; @@ -473,13 +469,13 @@ int CTermView::DrawChar(int row, int col) /* UAO display support */ switch (m_UAO) { case 2: - utf8 = uao250_b2u(pLine, w, &wl); + utf8 = uao250_b2u(str, w, &wl); break; case 1: - utf8 = uao241_b2u(pLine, w, &wl); + utf8 = uao241_b2u(str, w, &wl); break; default: - utf8 = g_convert(pLine, w, "UTF-8", m_pTermData->m_Encoding.c_str(), NULL, &wl, NULL); + utf8 = g_convert(str, w, "UTF-8", m_pTermData->m_Encoding.c_str(), NULL, &wl, NULL); break; } @@ -536,6 +532,55 @@ int CTermView::DrawChar(int row, int col) return is_mbcs2 ? 1 : w; } +int CTermView::DrawChar(int row, int col) +{ + const char* pLine = m_pTermData->m_Screen[m_pTermData->m_FirstLine + row]; + CTermCharAttr* pAttr = m_pTermData->GetLineAttr(pLine); + int number, n; + char num_buff[16]; + + n = 0; + pLine += col; + pAttr += col; + + if( m_pTermData->PostPushTest(m_pTermData->m_FirstLine + row) ) + { + number = *(m_pTermData->GetPostPushNum(m_pTermData->m_Screen[m_pTermData->m_FirstLine + row])); + if( number == 0 ) + n = 0; + else + n = snprintf( num_buff, 16, "%dF ", number ); + } + + if( n != 0 && col >= 3 ) + { + if( col == 3 ) + { + // Draw PostPushNum + CTermCharAttr DefAttr; + DefAttr.SetToDefault(); + DefAttr.SetNeedUpdate(true); + for( int i = 0; i < n; i++ ) + { + DoDrawChar(row, col + i, num_buff + i, &DefAttr); + } + } + col += n; + } + + if( col < m_pTermData->m_ColsPerPage) + { + return DoDrawChar(row, col, pLine, pAttr); + } + else + { + if( pAttr->GetCharSet() == CTermCharAttr::CS_MBCS1) + return 2; + else + return 1; + } +} + void CTermView::PointToLineCol(int *x, int *y, bool *left) { *x -= m_LeftMargin; diff --git a/src/core/termview.h b/src/core/termview.h index 0aae34ab..b235ee77 100644 --- a/src/core/termview.h +++ b/src/core/termview.h @@ -27,6 +27,7 @@ #include "view.h" #include "caret.h" +#include "termdata.h" #include @@ -52,6 +53,7 @@ friend class CTermData; virtual bool PreKeyDown(GdkEventKey *evt); virtual bool OnKeyDown(GdkEventKey* evt); virtual void OnTextInput(const gchar* string); + int DoDrawChar(int row, int col, const char *str, CTermCharAttr *pAttr); int DrawChar(int row, int col); void PointToLineCol(int *x, int *y, bool *left = NULL);