summaryrefslogtreecommitdiffstats
path: root/simulator/app/LogWindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'simulator/app/LogWindow.cpp')
-rw-r--r--simulator/app/LogWindow.cpp1156
1 files changed, 0 insertions, 1156 deletions
diff --git a/simulator/app/LogWindow.cpp b/simulator/app/LogWindow.cpp
deleted file mode 100644
index b19debbea..000000000
--- a/simulator/app/LogWindow.cpp
+++ /dev/null
@@ -1,1156 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Display runtime log output.
-//
-
-// For compilers that support precompilation, include "wx/wx.h".
-#include "wx/wxprec.h"
-
-// Otherwise, include all standard headers
-#ifndef WX_PRECOMP
-# include "wx/wx.h"
-#endif
-#include "wx/image.h" // needed for Windows build
-#include "wx/dcbuffer.h"
-
-#include "LogWindow.h"
-#include "LogMessage.h"
-#include "LogPrefsDialog.h"
-#include "MyApp.h"
-#include "Preferences.h"
-#include "Resource.h"
-#include "UserEventMessage.h"
-
-#include <errno.h>
-
-static int android_snprintfBuffer(char** pBuf, int bufLen, const char* format, ...);
-static int android_vsnprintfBuffer(char** pBuf, int bufLen, const char* format, va_list args);
-
-
-using namespace android;
-
-#if 0 // experiment -- works on Win32, but not with GTK
-class MyTextCtrl : public wxTextCtrl {
-public:
- MyTextCtrl(wxWindow* parent, wxWindowID id, const wxString& value,
- const wxPoint& pos, const wxSize& size, int style = 0)
- : wxTextCtrl(parent, id, value, pos, size, style)
- {
- printf("***************** MyTextCtrl!\n");
- }
-
- void OnScroll(wxScrollWinEvent& event);
- void OnScrollBottom(wxScrollWinEvent& event);
-
-private:
- DECLARE_EVENT_TABLE()
-};
-
-BEGIN_EVENT_TABLE(MyTextCtrl, wxTextCtrl)
- EVT_SCROLLWIN(MyTextCtrl::OnScroll)
- EVT_SCROLLWIN_BOTTOM(MyTextCtrl::OnScrollBottom)
-END_EVENT_TABLE()
-
-void MyTextCtrl::OnScroll(wxScrollWinEvent& event)
-{
- printf("OnScroll!\n");
-}
-
-void MyTextCtrl::OnScrollBottom(wxScrollWinEvent& event)
-{
- printf("OnScrollBottom!\n");
-}
-#endif
-
-
-BEGIN_EVENT_TABLE(LogWindow, wxDialog)
- EVT_CLOSE(LogWindow::OnClose)
- EVT_MOVE(LogWindow::OnMove)
- EVT_COMBOBOX(IDC_LOG_LEVEL, LogWindow::OnLogLevel)
- EVT_BUTTON(IDC_LOG_CLEAR, LogWindow::OnLogClear)
- EVT_BUTTON(IDC_LOG_PAUSE, LogWindow::OnLogPause)
- EVT_BUTTON(IDC_LOG_PREFS, LogWindow::OnLogPrefs)
-END_EVENT_TABLE()
-
-/*
- * Information about log levels.
- *
- * Each entry here corresponds to an entry in the combo box. The first
- * letter of each name should be unique.
- */
-static const struct {
- wxString name;
- android_LogPriority priority;
-} gLogLevels[] = {
- { wxT("Verbose"), ANDROID_LOG_VERBOSE },
- { wxT("Debug"), ANDROID_LOG_DEBUG },
- { wxT("Info"), ANDROID_LOG_INFO },
- { wxT("Warn"), ANDROID_LOG_WARN },
- { wxT("Error"), ANDROID_LOG_ERROR }
-};
-
-
-/*
- * Create a new LogWindow. This should be a child of the main frame.
- */
-LogWindow::LogWindow(wxWindow* parent)
- : wxDialog(parent, wxID_ANY, wxT("Log Output"), wxDefaultPosition,
- wxDefaultSize,
- wxCAPTION | wxSYSTEM_MENU | wxCLOSE_BOX | wxRESIZE_BORDER),
- mDisplayArray(NULL), mMaxDisplayMsgs(0), mPaused(false),
- mMinPriority(ANDROID_LOG_VERBOSE),
- mHeaderFormat(LogPrefsDialog::kHFFull),
- mSingleLine(false), mExtraSpacing(0), mPointSize(10), mUseColor(true),
- mFontMonospace(true), mWriteFile(false), mTruncateOld(true), mLogFp(NULL),
- mNewlyShown(false), mLastPosition(wxDefaultPosition), mVisible(false)
-{
- ConstructControls();
-
- Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-
- int poolSize = 10240; // 10MB
- pPrefs->GetInt("log-pool-size-kbytes", &poolSize);
- assert(poolSize > 0);
- mPool.Resize(poolSize * 1024);
-
- mMaxDisplayMsgs = 1000;
- pPrefs->GetInt("log-display-msg-count", &mMaxDisplayMsgs);
- assert(mMaxDisplayMsgs > 0);
- mDisplayArray = new LogMessage*[mMaxDisplayMsgs];
- memset(mDisplayArray, 0, sizeof(LogMessage*) * mMaxDisplayMsgs);
- mTopPtr = -1;
- mNextPtr = 0;
-
- int tmpInt = (int) mHeaderFormat;
- pPrefs->GetInt("log-header-format", &tmpInt);
- mHeaderFormat = (LogPrefsDialog::HeaderFormat) tmpInt;
- pPrefs->GetBool("log-single-line", &mSingleLine);
- pPrefs->GetInt("log-extra-spacing", &mExtraSpacing);
- pPrefs->GetInt("log-point-size", &mPointSize);
- pPrefs->GetBool("log-use-color", &mUseColor);
- pPrefs->SetBool("log-font-monospace", &mFontMonospace);
- SetTextStyle();
-
- mFileName = wxT("/tmp/android-log.txt");
- pPrefs->GetBool("log-write-file", &mWriteFile);
- pPrefs->GetString("log-filename", /*ref*/mFileName);
- pPrefs->GetBool("log-truncate-old", &mTruncateOld);
-
- PrepareLogFile();
-}
-
-/*
- * Destroy everything we own.
- */
-LogWindow::~LogWindow(void)
-{
- ClearDisplay();
- delete[] mDisplayArray;
-
- if (mLogFp != NULL)
- fclose(mLogFp);
-}
-
-/*
- * Set the text style, based on our preferences.
- */
-void LogWindow::SetTextStyle(void)
-{
- wxTextCtrl* pTextCtrl;
- pTextCtrl = (wxTextCtrl*) FindWindow(IDC_LOG_TEXT);
- wxTextAttr style;
- style = pTextCtrl->GetDefaultStyle();
-
- if (mFontMonospace) {
- wxFont font(mPointSize, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL,
- wxFONTWEIGHT_NORMAL);
- style.SetFont(font);
- } else {
- wxFont font(mPointSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
- wxFONTWEIGHT_NORMAL);
- style.SetFont(font);
- }
-
- pTextCtrl->SetDefaultStyle(style);
-}
-
-/*
- * Set up the goodies in the window.
- *
- * Also initializes mMinPriority.
- */
-void LogWindow::ConstructControls(void)
-{
- Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
- wxPanel* base = new wxPanel(this, wxID_ANY);
- wxBoxSizer* masterSizer = new wxBoxSizer(wxVERTICAL);
- wxBoxSizer* indentSizer = new wxBoxSizer(wxHORIZONTAL);
- wxBoxSizer* configPrioritySizer = new wxBoxSizer(wxHORIZONTAL);
- wxGridSizer* configSizer = new wxGridSizer(4, 1);
-
- /*
- * Configure log level combo box.
- */
- wxComboBox* logLevel;
- int defaultLogLevel = 1;
- pPrefs->GetInt("log-display-level", &defaultLogLevel);
- logLevel = new wxComboBox(base, IDC_LOG_LEVEL, wxT(""),
- wxDefaultPosition, wxDefaultSize, 0, NULL,
- wxCB_READONLY /*| wxSUNKEN_BORDER*/);
- for (int i = 0; i < NELEM(gLogLevels); i++) {
- logLevel->Append(gLogLevels[i].name);
- logLevel->SetClientData(i, (void*) gLogLevels[i].priority);
- }
- logLevel->SetSelection(defaultLogLevel);
- mMinPriority = gLogLevels[defaultLogLevel].priority;
-
- /*
- * Set up stuff at the bottom, starting with the options
- * at the bottom left.
- */
- configPrioritySizer->Add(new wxStaticText(base, wxID_ANY, wxT("Log level:"),
- wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT),
- 0, wxALIGN_CENTER_VERTICAL);
- configPrioritySizer->AddSpacer(kInterSpacing);
- configPrioritySizer->Add(logLevel);
-
- wxButton* clear = new wxButton(base, IDC_LOG_CLEAR, wxT("&Clear"),
- wxDefaultPosition, wxDefaultSize, 0);
- wxButton* pause = new wxButton(base, IDC_LOG_PAUSE, wxT("&Pause"),
- wxDefaultPosition, wxDefaultSize, 0);
- wxButton* prefs = new wxButton(base, IDC_LOG_PREFS, wxT("C&onfigure"),
- wxDefaultPosition, wxDefaultSize, 0);
-
- configSizer->Add(configPrioritySizer, 0, wxALIGN_LEFT);
- configSizer->Add(clear, 0, wxALIGN_CENTER);
- configSizer->Add(pause, 0, wxALIGN_CENTER);
- configSizer->Add(prefs, 0, wxALIGN_RIGHT);
-
- /*
- * Create text ctrl.
- */
- wxTextCtrl* pTextCtrl;
- pTextCtrl = new wxTextCtrl(base, IDC_LOG_TEXT, wxT(""),
- wxDefaultPosition, wxDefaultSize,
- wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2 | wxTE_NOHIDESEL |
- wxHSCROLL);
-
- /*
- * Add components to master sizer.
- */
- masterSizer->AddSpacer(kEdgeSpacing);
- masterSizer->Add(pTextCtrl, 1, wxEXPAND);
- masterSizer->AddSpacer(kInterSpacing);
- masterSizer->Add(configSizer, 0, wxEXPAND);
- masterSizer->AddSpacer(kEdgeSpacing);
-
- /*
- * Indent from sides.
- */
- indentSizer->AddSpacer(kEdgeSpacing);
- indentSizer->Add(masterSizer, 1, wxEXPAND);
- indentSizer->AddSpacer(kEdgeSpacing);
-
- base->SetSizer(indentSizer);
-
- indentSizer->Fit(this); // shrink-to-fit
- indentSizer->SetSizeHints(this); // define minimum size
-}
-
-/*
- * In some cases, this means the user has clicked on our "close" button.
- * We don't really even want one, but both WinXP and KDE put one on our
- * window whether we want it or not. So, we make it work as a "hide"
- * button instead.
- *
- * This also gets called when the app is shutting down, and we do want
- * to destroy ourselves then, saving various information about our state.
- */
-void LogWindow::OnClose(wxCloseEvent& event)
-{
- /* just hide the window, unless we're shutting down */
- if (event.CanVeto()) {
- event.Veto();
- Show(false);
- return;
- }
-
- /*
- * Save some preferences.
- */
- SaveWindowPrefs();
-
- /* if we can't veto the Close(), destroy ourselves */
- Destroy();
-}
-
-/*
- * Save all of our preferences to the config file.
- */
-void LogWindow::SaveWindowPrefs(void)
-{
- Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-
- /*
- * Save shown/hidden state.
- */
- pPrefs->SetBool("window-log-show", IsShown());
-
- /*
- * Limits and formatting prefs.
- */
- pPrefs->SetInt("log-display-msg-count", mMaxDisplayMsgs);
- pPrefs->SetInt("log-pool-size-kbytes", mPool.GetMaxSize() / 1024);
-
- pPrefs->SetInt("log-header-format", mHeaderFormat);
- pPrefs->SetBool("log-single-line", mSingleLine);
- pPrefs->SetInt("log-extra-spacing", mExtraSpacing);
- pPrefs->SetInt("log-point-size", mPointSize);
- pPrefs->SetBool("log-use-color", mUseColor);
- pPrefs->SetBool("log-font-monospace", mFontMonospace);
-
- pPrefs->SetBool("log-write-file", mWriteFile);
- pPrefs->SetString("log-filename", mFileName.ToAscii());
- pPrefs->SetBool("log-truncate-old", mTruncateOld);
-
- /*
- * Save window size and position.
- */
- wxPoint posn;
- wxSize size;
-
- assert(pPrefs != NULL);
-
- posn = GetPosition();
- size = GetSize();
-
- pPrefs->SetInt("window-log-x", posn.x);
- pPrefs->SetInt("window-log-y", posn.y);
- pPrefs->SetInt("window-log-width", size.GetWidth());
- pPrefs->SetInt("window-log-height", size.GetHeight());
-
- /*
- * Save current setting of debug level combo box.
- */
- wxComboBox* pCombo;
- int selection;
- pCombo = (wxComboBox*) FindWindow(IDC_LOG_LEVEL);
- selection = pCombo->GetSelection();
- pPrefs->SetInt("log-display-level", selection);
-}
-
-/*
- * Return the desired position and size.
- */
-/*static*/ wxRect LogWindow::GetPrefWindowRect(void)
-{
- Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
- int x, y, width, height;
-
- assert(pPrefs != NULL);
-
- x = y = 10;
- width = 500;
- height = 200;
-
- /* these don't modify the arg if the pref doesn't exist */
- pPrefs->GetInt("window-log-x", &x);
- pPrefs->GetInt("window-log-y", &y);
- pPrefs->GetInt("window-log-width", &width);
- pPrefs->GetInt("window-log-height", &height);
-
- return wxRect(x, y, width, height);
-}
-
-/*
- * Under Linux+GTK, the first time you show the window, it appears where
- * it's supposed to. If you then hide it and show it again, it gets
- * moved on top of the parent window. After that, you can reposition it
- * and it remembers its position across hide/show.
- *
- * To counter this annoyance, we save the position when we hide, and
- * reset the position after a show. The "newly shown" flag ensures that
- * we only reposition the window as the result of a Show(true) call.
- *
- * Sometimes, something helpful will shift the window over if it's
- * partially straddling a seam between two monitors. I don't see an easy
- * way to block this, and I'm not sure I want to anyway.
- */
-void LogWindow::OnMove(wxMoveEvent& event)
-{
- wxPoint point;
- point = event.GetPosition();
- //printf("Sim: log window is at (%d,%d) (new=%d)\n", point.x, point.y,
- // mNewlyShown);
-
- if (mNewlyShown) {
- if (mLastPosition == wxDefaultPosition) {
- //printf("Sim: no last position established\n");
- } else {
- Move(mLastPosition);
- }
-
- mNewlyShown = false;
- }
-}
-
-/*
- * Set the "newly shown" flag.
- */
-bool LogWindow::Show(bool show)
-{
- if (show) {
- mNewlyShown = true;
- Redisplay();
- } else {
- mLastPosition = GetPosition();
- }
-
- mVisible = show;
- return wxDialog::Show(show);
-}
-
-/*
- * User has adjusted the log level. Update the display appropriately.
- *
- * This is a wxEVT_COMMAND_COMBOBOX_SELECTED event.
- */
-void LogWindow::OnLogLevel(wxCommandEvent& event)
-{
- int selection;
- android_LogPriority priority;
-
- selection = event.GetInt();
- wxComboBox* pCombo = (wxComboBox*) FindWindow(IDC_LOG_LEVEL);
- priority = (android_LogPriority) (long)pCombo->GetClientData(event.GetInt());
-
- printf("Sim: log level selected: %d (%s)\n", (int) priority,
- (const char*) gLogLevels[selection].name.ToAscii());
- mMinPriority = priority;
- Redisplay();
-}
-
-/*
- * Clear out the log.
- */
-void LogWindow::OnLogClear(wxCommandEvent& event)
-{
- ClearDisplay();
- mPool.Clear();
-}
-
-/*
- * Handle the pause/resume button.
- *
- * If we're un-pausing, we need to get caught up.
- */
-void LogWindow::OnLogPause(wxCommandEvent& event)
-{
- mPaused = !mPaused;
-
- wxButton* pButton = (wxButton*) FindWindow(IDC_LOG_PAUSE);
- if (mPaused) {
- pButton->SetLabel(wxT("&Resume"));
-
- mPool.SetBookmark();
- } else {
- pButton->SetLabel(wxT("&Pause"));
-
- LogMessage* pMsg = mPool.GetBookmark();
- if (pMsg == NULL) {
- /* bookmarked item fell out of pool */
- printf("--- bookmark was lost, redisplaying\n");
- Redisplay();
- } else {
- /*
- * The bookmark points to the last item added to the display.
- * We want to chase its "prev" pointer to walk toward the head
- * of the list, adding items from oldest to newest.
- */
- pMsg = pMsg->GetPrev();
- while (pMsg != NULL) {
- if (FilterMatches(pMsg))
- AddToDisplay(pMsg);
- pMsg = pMsg->GetPrev();
- }
- }
- }
-}
-
-/*
- * Open log preferences dialog.
- */
-void LogWindow::OnLogPrefs(wxCommandEvent& event)
-{
- LogPrefsDialog dialog(this);
-
- /*
- * Set up the dialog.
- */
- dialog.mHeaderFormat = mHeaderFormat;
- dialog.mSingleLine = mSingleLine;
- dialog.mExtraSpacing = mExtraSpacing;
- dialog.mPointSize = mPointSize;
- dialog.mUseColor = mUseColor;
- dialog.mFontMonospace = mFontMonospace;
-
- dialog.mDisplayMax = mMaxDisplayMsgs;
- dialog.mPoolSizeKB = mPool.GetMaxSize() / 1024;
-
- dialog.mWriteFile = mWriteFile;
- dialog.mFileName = mFileName;
- dialog.mTruncateOld = mTruncateOld;
-
- /*
- * Show it. If they hit "OK", copy the updated values out, and
- * re-display the log output.
- */
- if (dialog.ShowModal() == wxID_OK) {
- /* discard old display arra */
- ClearDisplay();
- delete[] mDisplayArray;
-
- mHeaderFormat = dialog.mHeaderFormat;
- mSingleLine = dialog.mSingleLine;
- mExtraSpacing = dialog.mExtraSpacing;
- mPointSize = dialog.mPointSize;
- mUseColor = dialog.mUseColor;
- mFontMonospace = dialog.mFontMonospace;
-
- assert(dialog.mDisplayMax > 0);
- assert(dialog.mPoolSizeKB > 0);
- mMaxDisplayMsgs = dialog.mDisplayMax;
- mPool.Resize(dialog.mPoolSizeKB * 1024);
-
- mWriteFile = dialog.mWriteFile;
- if (mLogFp != NULL && mFileName != dialog.mFileName) {
- printf("--- log file name changed, closing\n");
- fclose(mLogFp);
- mLogFp = NULL;
- }
- mFileName = dialog.mFileName;
- mTruncateOld = dialog.mTruncateOld;
-
- mDisplayArray = new LogMessage*[mMaxDisplayMsgs];
- memset(mDisplayArray, 0, sizeof(LogMessage*) * mMaxDisplayMsgs);
- Redisplay();
-
- PrepareLogFile();
- }
-}
-
-/*
- * Handle a log message "user event". This should only be called in
- * the main UI thread.
- *
- * We take ownership of "*pLogMessage".
- */
-void LogWindow::AddLogMessage(LogMessage* pLogMessage)
-{
- mPool.Add(pLogMessage);
-
- if (!mPaused && mVisible && FilterMatches(pLogMessage)) {
- /*
- * Thought: keep a reference to the previous message. If it
- * matches in most fields (all except timestamp?), hold it and
- * increment a counter. If we get a message that doesn't match,
- * or a timer elapses, synthesize a "previous message repeated N
- * times" string.
- */
- AddToDisplay(pLogMessage);
- }
-
- // release the initial ref caused by allocation
- pLogMessage->Release();
-
- if (mLogFp != NULL)
- LogToFile(pLogMessage);
-}
-
-/*
- * Clear out the display, releasing any log messages held in the display
- * array.
- */
-void LogWindow::ClearDisplay(void)
-{
- wxTextCtrl* pTextCtrl;
- pTextCtrl = (wxTextCtrl*) FindWindow(IDC_LOG_TEXT);
- pTextCtrl->Clear();
-
- /*
- * Just run through the entire array.
- */
- for (int i = 0; i < mMaxDisplayMsgs; i++) {
- if (mDisplayArray[i] != NULL) {
- mDisplayArray[i]->Release();
- mDisplayArray[i] = NULL;
- }
- }
- mTopPtr = -1;
- mNextPtr = 0;
-}
-
-/*
- * Clear the current display and regenerate it from the log pool. We need
- * to do this whenever we change filters or log message formatting.
- */
-void LogWindow::Redisplay(void)
-{
- /*
- * Freeze output rendering so it doesn't flash during update. Doesn't
- * seem to help for GTK, and it leaves garbage on the screen in WinXP,
- * so I'm leaving it commented out.
- */
- //wxTextCtrl* pText = (wxTextCtrl*) FindWindow(IDC_LOG_TEXT);
- //pText->Freeze();
-
- //printf("--- redisplay\n");
- ClearDisplay();
-
- /*
- * Set up the default wxWidgets text style stuff.
- */
- SetTextStyle();
-
- /*
- * Here's the plan:
- * - Start at the head of the pool (where the most recently added
- * items are).
- * - Check to see if the current item passes our filter. If it does,
- * increment the "found count".
- * - Continue in this manner until we run out of pool or have
- * sufficient items to fill the screen.
- * - Starting from the current position, walk back toward the head,
- * adding the items that meet the current filter criteria.
- *
- * Don't forget that the log pool could be empty.
- */
- LogMessage* pMsg = mPool.GetHead();
-
- if (pMsg != NULL) {
- int foundCount = 0;
-
- // note this stops before it runs off the end
- while (pMsg->GetNext() != NULL && foundCount < mMaxDisplayMsgs) {
- if (FilterMatches(pMsg))
- foundCount++;
- pMsg = pMsg->GetNext();
- }
-
- while (pMsg != NULL) {
- if (FilterMatches(pMsg))
- AddToDisplay(pMsg);
- pMsg = pMsg->GetPrev();
- }
- }
-
- //pText->Thaw();
-}
-
-
-/*
- * Returns "true" if the currently specified filters would allow this
- * message to be shown.
- */
-bool LogWindow::FilterMatches(const LogMessage* pLogMessage)
-{
- if (pLogMessage->GetPriority() >= mMinPriority)
- return true;
- else
- return false;
-}
-
-/*
- * Realloc the array of pointers, and remove anything from the display
- * that should no longer be there.
- */
-void LogWindow::SetMaxDisplayMsgs(int max)
-{
- Preferences* pPrefs = ((MyApp*)wxTheApp)->GetPrefs();
-
- pPrefs->SetInt("log-display-msg-count", max);
-}
-
-/*
- * Add the message to the display array and to the screen.
- */
-void LogWindow::AddToDisplay(LogMessage* pLogMessage)
-{
- wxTextCtrl* pTextCtrl;
- pTextCtrl = (wxTextCtrl*) FindWindow(IDC_LOG_TEXT);
-
- if (mNextPtr == mTopPtr) {
- /*
- * The display array is full.
- *
- * We need to eliminate the topmost entry. This requires removing
- * it from the array and removing the text from the wxTextCtrl.
- */
- pTextCtrl->Remove(0, mDisplayArray[mTopPtr]->GetTextCtrlLen());
- mDisplayArray[mTopPtr]->Release();
- mTopPtr = (mTopPtr + 1) % mMaxDisplayMsgs;
- }
-
- /*
- * Add formatted text to the text ctrl. Track how much actual space
- * is required. The space may be different on Win32 (CRLF-based) vs.
- * GTK (LF-based), so we need to measure it, not compute it from the
- * text string.
- */
- long lastBefore, lastAfter;
- //long insertBefore;
- //insertBefore = pTextCtrl->GetInsertionPoint();
- lastBefore = pTextCtrl->GetLastPosition();
- FormatMessage(pLogMessage, pTextCtrl);
- lastAfter = pTextCtrl->GetLastPosition();
- pLogMessage->SetTextCtrlLen(lastAfter - lastBefore);
-
- /*
- * If we restore the old insertion point, we will be glued to where
- * we were. This is okay until we start deleting text from the top,
- * at which point we need to adjust it to retain our position.
- *
- * If we set the insertion point to the bottom, we effectively
- * implement "scroll to bottom on output".
- *
- * If we don't set it at all, we get slightly strange behavior out
- * of GTK, which seems to be par for the course here.
- */
- //pTextCtrl->SetInsertionPoint(insertBefore); // restore insertion pt
- pTextCtrl->SetInsertionPoint(lastAfter);
-
- /* add it to array, claim ownership */
- mDisplayArray[mNextPtr] = pLogMessage;
- pLogMessage->Acquire();
-
- /* adjust pointers */
- if (mTopPtr < 0) // first time only
- mTopPtr = 0;
- mNextPtr = (mNextPtr + 1) % mMaxDisplayMsgs;
-}
-
-
-/*
- * Return a human-readable string for the priority level. Always returns
- * a valid string.
- */
-static const wxCharBuffer GetPriorityString(android_LogPriority priority)
-{
- int idx;
-
- idx = (int) priority - (int) ANDROID_LOG_VERBOSE;
- if (idx < 0 || idx >= NELEM(gLogLevels))
- return "?unknown?";
- return gLogLevels[idx].name.ToAscii();
-}
-
-/*
- * Format a message and write it to the text control.
- */
-void LogWindow::FormatMessage(const LogMessage* pLogMessage,
- wxTextCtrl* pTextCtrl)
-{
-#if defined(HAVE_LOCALTIME_R)
- struct tm tmBuf;
-#endif
- struct tm* ptm;
- char timeBuf[32];
- char msgBuf[256];
- int msgLen = 0;
- char* outBuf;
- char priChar;
- LogPrefsDialog::HeaderFormat headerFmt;
-
- headerFmt = mHeaderFormat;
- if (pLogMessage->GetInternal())
- headerFmt = LogPrefsDialog::kHFInternal;
-
- priChar = ((const char*)GetPriorityString(pLogMessage->GetPriority()))[0];
-
- /*
- * Get the current date/time in pretty form
- *
- * It's often useful when examining a log with "less" to jump to
- * a specific point in the file by searching for the date/time stamp.
- * For this reason it's very annoying to have regexp meta characters
- * in the time stamp. Don't use forward slashes, parenthesis,
- * brackets, asterisks, or other special chars here.
- */
- time_t when = pLogMessage->GetWhen();
- const char* fmt = NULL;
-#if defined(HAVE_LOCALTIME_R)
- ptm = localtime_r(&when, &tmBuf);
-#else
- ptm = localtime(&when);
-#endif
- switch (headerFmt) {
- case LogPrefsDialog::kHFFull:
- case LogPrefsDialog::kHFInternal:
- fmt = "%m-%d %H:%M:%S";
- break;
- case LogPrefsDialog::kHFBrief:
- case LogPrefsDialog::kHFMinimal:
- fmt = "%H:%M:%S";
- break;
- default:
- break;
- }
- if (fmt != NULL)
- strftime(timeBuf, sizeof(timeBuf), fmt, ptm);
- else
- strcpy(timeBuf, "-");
-
- const int kMaxExtraNewlines = 2;
- char hdrNewline[2];
- char finalNewlines[kMaxExtraNewlines+1 +1];
-
- if (mSingleLine)
- hdrNewline[0] = ' ';
- else
- hdrNewline[0] = '\n';
- hdrNewline[1] = '\0';
-
- assert(mExtraSpacing <= kMaxExtraNewlines);
- int i;
- for (i = 0; i < mExtraSpacing+1; i++)
- finalNewlines[i] = '\n';
- finalNewlines[i] = '\0';
-
- wxTextAttr msgColor;
- switch (pLogMessage->GetPriority()) {
- case ANDROID_LOG_WARN:
- msgColor.SetTextColour(*wxBLUE);
- break;
- case ANDROID_LOG_ERROR:
- msgColor.SetTextColour(*wxRED);
- break;
- case ANDROID_LOG_VERBOSE:
- case ANDROID_LOG_DEBUG:
- case ANDROID_LOG_INFO:
- default:
- msgColor.SetTextColour(*wxBLACK);
- break;
- }
- if (pLogMessage->GetInternal())
- msgColor.SetTextColour(*wxGREEN);
-
- /*
- * Construct a buffer containing the log header.
- */
- bool splitHeader = true;
- outBuf = msgBuf;
- switch (headerFmt) {
- case LogPrefsDialog::kHFFull:
- splitHeader = true;
- msgLen = android_snprintfBuffer(&outBuf, sizeof(msgBuf),
- "[ %s %5d %c/%-6.6s]%s",
- timeBuf, pLogMessage->GetPid(), priChar,
- pLogMessage->GetTag(), hdrNewline);
- break;
- case LogPrefsDialog::kHFBrief:
- splitHeader = true;
- msgLen = android_snprintfBuffer(&outBuf, sizeof(msgBuf),
- "[%s %5d]%s",
- timeBuf, pLogMessage->GetPid(), hdrNewline);
- break;
- case LogPrefsDialog::kHFMinimal:
- splitHeader = false;
- msgLen = android_snprintfBuffer(&outBuf, sizeof(msgBuf),
- "%s %5d- %s",
- timeBuf, pLogMessage->GetPid(), pLogMessage->GetMsg());
- break;
- case LogPrefsDialog::kHFInternal:
- splitHeader = false;
- msgLen = android_snprintfBuffer(&outBuf, sizeof(msgBuf),
- "[%s] %s", timeBuf, pLogMessage->GetMsg());
- break;
- default:
- fprintf(stderr, "Sim: unexpected header format %d\n", headerFmt);
- assert(false);
- break;
- }
-
- if (msgLen < 0) {
- fprintf(stderr, "WHOOPS\n");
- assert(outBuf == msgBuf);
- return;
- }
-
- if (splitHeader) {
- if (mUseColor)
- pTextCtrl->SetDefaultStyle(wxTextAttr(*wxLIGHT_GREY));
- pTextCtrl->AppendText(wxString::FromAscii(outBuf));
- if (mUseColor)
- pTextCtrl->SetDefaultStyle(msgColor);
- pTextCtrl->AppendText(wxString::FromAscii(pLogMessage->GetMsg()));
- if (mUseColor)
- pTextCtrl->SetDefaultStyle(*wxBLACK);
- pTextCtrl->AppendText(wxString::FromAscii(finalNewlines));
- } else {
- if (mUseColor)
- pTextCtrl->SetDefaultStyle(msgColor);
- pTextCtrl->AppendText(wxString::FromAscii(outBuf));
- if (mUseColor)
- pTextCtrl->SetDefaultStyle(*wxBLACK);
- pTextCtrl->AppendText(wxString::FromAscii(finalNewlines));
- }
-
- /* if we allocated storage for this message, free it */
- if (outBuf != msgBuf)
- free(outBuf);
-}
-
-/*
- * Write the message to the log file.
- *
- * We can't just do this in FormatMessage(), because that re-writes all
- * messages on the display whenever the output format or filter changes.
- *
- * Use a one-log-per-line format here to make "grep" useful.
- */
-void LogWindow::LogToFile(const LogMessage* pLogMessage)
-{
-#if defined(HAVE_LOCALTIME_R)
- struct tm tmBuf;
-#endif
- struct tm* ptm;
- char timeBuf[32];
- char msgBuf[256];
- int msgLen;
- char* outBuf;
- char priChar;
-
- assert(mLogFp != NULL);
-
- time_t when = pLogMessage->GetWhen();
-#if defined(HAVE_LOCALTIME_R)
- ptm = localtime_r(&when, &tmBuf);
-#else
- ptm = localtime(&when);
-#endif
-
- strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
- priChar = ((const char*)GetPriorityString(pLogMessage->GetPriority()))[0];
-
- outBuf = msgBuf;
- if (pLogMessage->GetInternal()) {
- msgLen = android_snprintfBuffer(&outBuf, sizeof(msgBuf),
- "[%s %5d *] %s\n",
- timeBuf, pLogMessage->GetPid(), pLogMessage->GetMsg());
- } else {
- msgLen = android_snprintfBuffer(&outBuf, sizeof(msgBuf),
- "[%s %5d %c] %s)\n",
- timeBuf, pLogMessage->GetPid(), priChar,
- pLogMessage->GetMsg());
- }
- if (fwrite(outBuf, msgLen, 1, mLogFp) != 1)
- fprintf(stderr, "Sim: WARNING: partial log write\n");
- fflush(mLogFp);
-
- /* if we allocated storage for this message, free it */
- if (outBuf != msgBuf)
- free(outBuf);
-}
-
-/*
- * Get the modification date of a file.
- */
-static bool GetFileModDate(const char* fileName, time_t* pModWhen)
-{
- struct stat sb;
-
- if (stat(fileName, &sb) < 0)
- return false;
-
- *pModWhen = sb.st_mtime;
- return true;
-}
-
-/*
- * Open or close the log file as appropriate.
- */
-void LogWindow::PrepareLogFile(void)
-{
- const int kLogFileMaxAge = 8 * 60 * 60; // 8 hours
-
- if (!mWriteFile && mLogFp != NULL) {
- printf("Sim: closing log file\n");
- fclose(mLogFp);
- mLogFp = NULL;
- } else if (mWriteFile && mLogFp == NULL) {
- printf("Sim: opening log file '%s'\n", (const char*)mFileName.ToAscii());
- time_t now, modWhen = 0;
- const char* openFlags;
-
- now = time(NULL);
- if (!mTruncateOld ||
- (GetFileModDate(mFileName.ToAscii(), &modWhen) &&
- modWhen + kLogFileMaxAge > now))
- {
- if (modWhen != 0) {
- printf("--- log file is %.3f hours old, appending\n",
- (now - modWhen) / 3600.0);
- }
- openFlags = "a"; // open for append (text mode)
- } else {
- if (modWhen != 0) {
- printf("--- log file is %.3f hours old, truncating\n",
- (now - modWhen) / 3600.0);
- }
- openFlags = "w"; // open for writing, truncate (text mode)
- }
-
- mLogFp = fopen(mFileName.ToAscii(), openFlags);
- if (mLogFp == NULL) {
- fprintf(stderr, "Sim: failed opening log file '%s': %s\n",
- (const char*) mFileName.ToAscii(), strerror(errno));
- } else {
- fprintf(mLogFp, "\n\n");
- fflush(mLogFp);
- }
- }
-}
-
-/*
- * Add a new log message.
- *
- * This function can be called from any thread. It makes a copy of the
- * stuff in "*pBundle" and sends it to the main UI thread.
- */
-/*static*/ void LogWindow::PostLogMsg(const android_LogBundle* pBundle)
-{
- LogMessage* pNewMessage = LogMessage::Create(pBundle);
-
- SendToWindow(pNewMessage);
-}
-
-/*
- * Post a simple string to the log.
- */
-/*static*/ void LogWindow::PostLogMsg(const char* msg)
-{
- LogMessage* pNewMessage = LogMessage::Create(msg);
-
- SendToWindow(pNewMessage);
-}
-
-/*
- * Post a simple wxString to the log.
- */
-/*static*/ void LogWindow::PostLogMsg(const wxString& msg)
-{
- LogMessage* pNewMessage = LogMessage::Create(msg.ToAscii());
-
- SendToWindow(pNewMessage);
-}
-
-/*
- * Send a log message to the log window.
- */
-/*static*/ void LogWindow::SendToWindow(LogMessage* pMessage)
-{
- if (pMessage != NULL) {
- wxWindow* pMainFrame = ((MyApp*)wxTheApp)->GetMainFrame();
- UserEventMessage* pUem = new UserEventMessage;
- pUem->CreateLogMessage(pMessage);
-
- UserEvent uev(0, (void*) pUem);
-
- pMainFrame->AddPendingEvent(uev);
- } else {
- fprintf(stderr, "Sim: failed to add new log message\n");
- }
-}
-
-
-/*
- * This is a sanity check. We need to stop somewhere to avoid trashing
- * the system on bad input.
- */
-#define kMaxLen 65536
-
-#define VSNPRINTF vsnprintf // used to worry about _vsnprintf
-
-
-/*
- * Print a formatted message into a buffer. Pass in a buffer to try to use.
- *
- * If the buffer isn't big enough to hold the message, allocate storage
- * with malloc() and return that instead. The caller is responsible for
- * freeing the storage.
- *
- * Returns the length of the string, or -1 if the printf call failed.
- */
-static int android_vsnprintfBuffer(char** pBuf, int bufLen, const char* format, va_list args)
-{
- int charsOut;
- char* localBuf = NULL;
-
- assert(pBuf != NULL && *pBuf != NULL);
- assert(bufLen > 0);
- assert(format != NULL);
-
- while (1) {
- /*
- * In some versions of libc, vsnprintf only returns 0 or -1, where
- * -1 indicates the the buffer wasn't big enough. In glibc 2.1
- * and later, it returns the actual size needed.
- *
- * MinGW is just returning -1, so we have to retry there.
- */
- char* newBuf;
-
- charsOut = VSNPRINTF(*pBuf, bufLen, format, args);
-
- if (charsOut >= 0 && charsOut < bufLen)
- break;
-
- //fprintf(stderr, "EXCEED: %d vs %d\n", charsOut, bufLen);
- if (charsOut < 0) {
- /* exact size not known, double previous size */
- bufLen *= 2;
- if (bufLen > kMaxLen)
- goto fail;
- } else {
- /* exact size known, just use that */
-
- bufLen = charsOut + 1;
- }
- //fprintf(stderr, "RETRY at %d\n", bufLen);
-
- newBuf = (char*) realloc(localBuf, bufLen);
- if (newBuf == NULL)
- goto fail;
- *pBuf = localBuf = newBuf;
- }
-
- // On platforms where snprintf() doesn't return the number of
- // characters output, we would need to call strlen() here.
-
- return charsOut;
-
-fail:
- if (localBuf != NULL) {
- free(localBuf);
- *pBuf = NULL;
- }
- return -1;
-}
-
-/*
- * Variable-arg form of the above.
- */
-static int android_snprintfBuffer(char** pBuf, int bufLen, const char* format, ...)
-{
- va_list args;
- int result;
-
- va_start(args, format);
- result = android_vsnprintfBuffer(pBuf, bufLen, format, args);
- va_end(args);
-
- return result;
-}
-
-