From 718a28ceadb872b766b13cb3743c575fe416e501 Mon Sep 17 00:00:00 2001 From: Siarzhuk Zharski Date: Wed, 30 Jan 2013 22:12:13 +0100 Subject: [PATCH] Add Debug snapshots and capture of Terminal data flow Two helper functions introduced: "make debug snapshots" triggered by Ctrl-Cmd-S shortcut and "capture data flow" triggered by Ctrl-Cmd-C shortcut. The first one makes debug dump of current data both in visual and in text buffer, including history lines if they available. The second one mirrors all characters and control sequences that are flowing through the Parser. Both dump and capture files are saved under /var/log folder. That functionality available only if the USE_DEBUG_SNAPSHOTS switch is defined. --- src/apps/terminal/BasicTerminalBuffer.cpp | 97 ++++++++++++++++++++++- src/apps/terminal/BasicTerminalBuffer.h | 7 ++ src/apps/terminal/TermConst.h | 9 +++ src/apps/terminal/TermParse.cpp | 5 ++ src/apps/terminal/TermView.cpp | 22 +++++ src/apps/terminal/TermView.h | 3 + src/apps/terminal/TermWindow.cpp | 17 ++++ 7 files changed, 158 insertions(+), 2 deletions(-) diff --git a/src/apps/terminal/BasicTerminalBuffer.cpp b/src/apps/terminal/BasicTerminalBuffer.cpp index 5658216bc6..19f4416e8e 100644 --- a/src/apps/terminal/BasicTerminalBuffer.cpp +++ b/src/apps/terminal/BasicTerminalBuffer.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -111,7 +112,8 @@ BasicTerminalBuffer::BasicTerminalBuffer() fOriginMode(false), fSavedOriginMode(false), fTabStops(NULL), - fEncoding(M_UTF8) + fEncoding(M_UTF8), + fCaptureFile(-1) { } @@ -121,6 +123,9 @@ BasicTerminalBuffer::~BasicTerminalBuffer() delete fHistory; _FreeLines(fScreen, fHeight); delete[] fTabStops; + + if (fCaptureFile >= 0) + close(fCaptureFile); } @@ -255,7 +260,8 @@ BasicTerminalBuffer::SynchronizeWith(const BasicTerminalBuffer* other, destLine->softBreak = sourceLine->softBreak; if (destLine->length > 0) { memcpy(destLine->cells, sourceLine->cells, - destLine->length * sizeof(TerminalCell)); +// destLine->length * sizeof(TerminalCell)); + fWidth * sizeof(TerminalCell)); } } else { // The source line was a history line and has been copied @@ -1631,3 +1637,90 @@ BasicTerminalBuffer::_NextChar(TermPos& pos, UTF8Char& c) const return true; } + + +#ifdef USE_DEBUG_SNAPSHOTS + +void +BasicTerminalBuffer::MakeLinesSnapshots(time_t timeStamp, const char* fileName) +{ + BString str("/var/log/"); + struct tm* ts = gmtime(&timeStamp); + str << ts->tm_hour << ts->tm_min << ts->tm_sec; + str << fileName; + FILE* fileOut = fopen(str.String(), "w"); + + bool dumpHistory = false; + do { + if (dumpHistory && fHistory == NULL) { + fprintf(fileOut, "> History is empty <\n"); + break; + } + + size_t countLines = dumpHistory ? fHistory->Size() : fHeight; + fprintf(fileOut, "> %s lines dump begin <\n", + dumpHistory ? "History" : "Terminal"); + + TerminalLine* lineBuffer = ALLOC_LINE_ON_STACK(fWidth); + for (int i = 0; i < countLines; i++) { + TerminalLine* line = dumpHistory + ? fHistory->GetTerminalLineAt(i, lineBuffer) + : fScreen[_LineIndex(i)]; + + if (line == NULL) { + fprintf(fileOut, "line: %ld is NULL!!!\n", i); + continue; + } + + fprintf(fileOut, "%02d:%02d:%08lx:\n", + i, line->length, line->attributes); + for (int j = 0; j < line->length; j++) + fprintf(fileOut, "%c", line->cells[j].character.bytes[0]); + + fprintf(fileOut, "\n"); + for (int s = 28; s >= 0; s -= 4) { + for (int j = 0; j < fWidth; j++) + fprintf(fileOut, "%01lx", + (line->cells[j].attributes >> s) & 0x0F); + + fprintf(fileOut, "\n"); + } + + fprintf(fileOut, "\n"); + } + + fprintf(fileOut, "> %s lines dump finished <\n", + dumpHistory ? "History" : "Terminal"); + + } while (dumpHistory = !dumpHistory); + + fclose(fileOut); +} + + +void +BasicTerminalBuffer::RestartDebugCapture() +{ + if (fCaptureFile >= 0) { + close(fCaptureFile); + fCaptureFile = -1; + return; + } + + time_t timeStamp = time(NULL); + BString str("/var/log/"); + struct tm* ts = gmtime(&timeStamp); + str << ts->tm_hour << ts->tm_min << ts->tm_sec; + str << ".Capture.log"; + fCaptureFile = open(str.String(), O_CREAT | O_WRONLY); +} + + +void +BasicTerminalBuffer::CaptureChar(char ch) +{ + if (fCaptureFile >= 0) + write(fCaptureFile, &ch, 1); +} + +#endif diff --git a/src/apps/terminal/BasicTerminalBuffer.h b/src/apps/terminal/BasicTerminalBuffer.h index 6caef3c3be..2be3efe833 100644 --- a/src/apps/terminal/BasicTerminalBuffer.h +++ b/src/apps/terminal/BasicTerminalBuffer.h @@ -104,6 +104,12 @@ public: bool matchWord, TermPos& matchStart, TermPos& matchEnd) const; + // snapshots and data capture for debugging + void MakeLinesSnapshots(time_t timeStamp, + const char* fileName); + void RestartDebugCapture(); + /*inline*/ void CaptureChar(char ch); + // insert chars/lines inline void InsertChar(UTF8Char c, uint32 attributes); void InsertChar(UTF8Char c, uint32 width, @@ -220,6 +226,7 @@ protected: bool* fTabStops; int fEncoding; + int fCaptureFile; // listener/dirty region management TerminalBufferDirtyInfo fDirtyInfo; diff --git a/src/apps/terminal/TermConst.h b/src/apps/terminal/TermConst.h index 50cf9cc1ff..89ec6dc0f8 100644 --- a/src/apps/terminal/TermConst.h +++ b/src/apps/terminal/TermConst.h @@ -46,6 +46,15 @@ #include +// define to get Ctrl-Cmd-S / Ctrl-Cmd-C shortcuts +// to get the debug buffers snapshots and control +// sequences capture logging +#define USE_DEBUG_SNAPSHOTS +#ifdef USE_DEBUG_SNAPSHOTS +const uint32 SHORTCUT_DEBUG_SNAPSHOTS = 'sdbs'; +const uint32 SHORTCUT_DEBUG_CAPTURE = 'srdc'; +#endif + // Menu Message static const uint32 MENU_SWITCH_TERM = 'MSWT'; static const uint32 MENU_NEW_TERM = 'MNTE'; diff --git a/src/apps/terminal/TermParse.cpp b/src/apps/terminal/TermParse.cpp index a038ea98a9..e892f47e1b 100644 --- a/src/apps/terminal/TermParse.cpp +++ b/src/apps/terminal/TermParse.cpp @@ -409,6 +409,11 @@ TermParse::EscParse() } //debug_printf("TermParse: char: '%c' (%d), parse state: %d\n", c, c, parsestate[c]); + +#ifdef USE_DEBUG_SNAPSHOTS + fBuffer->CaptureChar(c); +#endif + switch (parsestate[c]) { case CASE_PRINT: fBuffer->InsertChar((char)c, fAttr); diff --git a/src/apps/terminal/TermView.cpp b/src/apps/terminal/TermView.cpp index ff24da90f1..5cb6f8c7b0 100644 --- a/src/apps/terminal/TermView.cpp +++ b/src/apps/terminal/TermView.cpp @@ -3238,3 +3238,25 @@ void TermView::Listener::NextTermView(TermView* view) { } + + +#ifdef USE_DEBUG_SNAPSHOTS + +void +TermView::MakeDebugSnapshots() +{ + BAutolock _(fTextBuffer); + time_t timeStamp = time(NULL); + fTextBuffer->MakeLinesSnapshots(timeStamp, ".TextBuffer.log"); + fVisibleTextBuffer->MakeLinesSnapshots(timeStamp, ".VisualTextBuffer.log"); +} + + +void +TermView::RestartDebugCapture() +{ + BAutolock _(fTextBuffer); + fTextBuffer->RestartDebugCapture(); +} + +#endif diff --git a/src/apps/terminal/TermView.h b/src/apps/terminal/TermView.h index c7fe52ffb6..a22a74dabf 100644 --- a/src/apps/terminal/TermView.h +++ b/src/apps/terminal/TermView.h @@ -90,6 +90,9 @@ public: void SetMouseClipboard(BClipboard *); + void MakeDebugSnapshots(); + void RestartDebugCapture(); + // edit functions void Copy(BClipboard* clipboard); void Paste(BClipboard* clipboard); diff --git a/src/apps/terminal/TermWindow.cpp b/src/apps/terminal/TermWindow.cpp index 34d047fee4..1e33dfa4fb 100644 --- a/src/apps/terminal/TermWindow.cpp +++ b/src/apps/terminal/TermWindow.cpp @@ -517,6 +517,13 @@ TermWindow::_SetupMenu() AddChild(fMenuBar); _UpdateSwitchTerminalsMenuItem(); + +#ifdef USE_DEBUG_SNAPSHOTS + AddShortcut('S', B_COMMAND_KEY | B_CONTROL_KEY, + new BMessage(SHORTCUT_DEBUG_SNAPSHOTS)); + AddShortcut('C', B_COMMAND_KEY | B_CONTROL_KEY, + new BMessage(SHORTCUT_DEBUG_CAPTURE)); +#endif } @@ -658,6 +665,16 @@ TermWindow::MessageReceived(BMessage *message) _ActiveTermView()->Paste(be_clipboard); break; +#ifdef USE_DEBUG_SNAPSHOTS + case SHORTCUT_DEBUG_SNAPSHOTS: + _ActiveTermView()->MakeDebugSnapshots(); + break; + + case SHORTCUT_DEBUG_CAPTURE: + _ActiveTermView()->RestartDebugCapture(); + break; +#endif + case B_SELECT_ALL: _ActiveTermView()->SelectAll(); break;