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.
This commit is contained in:
Siarzhuk Zharski 2013-01-30 22:12:13 +01:00
parent 238b435a8e
commit 718a28cead
7 changed files with 158 additions and 2 deletions

View File

@ -7,6 +7,7 @@
#include <alloca.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <algorithm>
@ -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

View File

@ -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;

View File

@ -46,6 +46,15 @@
#include <SupportDefs.h>
// 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';

View File

@ -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);

View File

@ -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

View File

@ -90,6 +90,9 @@ public:
void SetMouseClipboard(BClipboard *);
void MakeDebugSnapshots();
void RestartDebugCapture();
// edit functions
void Copy(BClipboard* clipboard);
void Paste(BClipboard* clipboard);

View File

@ -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;