]> git.saurik.com Git - wxWidgets.git/blame - src/common/log.cpp
Cured problem introduced by LEAVE/ENTER OnIdle code; bugs in gauge sizing
[wxWidgets.git] / src / common / log.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: log.cpp
3// Purpose: Assorted wxLogXXX functions, and wxLog (sink for logs)
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 29/01/98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19#ifdef __GNUG__
20 #pragma implementation "log.h"
21#endif
22
23// For compilers that support precompilation, includes "wx.h".
24#include "wx/wxprec.h"
25
26#ifdef __BORLANDC__
27 #pragma hdrstop
28#endif
29
30// wxWindows
31#ifndef WX_PRECOMP
c801d85f 32 #include <wx/app.h>
9ef3052c
VZ
33 #include <wx/string.h>
34 #include <wx/intl.h>
35
c801d85f 36 #include <wx/generic/msgdlgg.h>
9ef3052c
VZ
37 #include <wx/filedlg.h>
38 #include <wx/textctrl.h>
39#endif //WX_PRECOMP
c801d85f 40
9ef3052c
VZ
41#include <wx/file.h>
42#include <wx/textfile.h>
c801d85f
KB
43#include <wx/log.h>
44
45// other standard headers
46#include <errno.h>
47#include <stdlib.h>
48#include <time.h>
49
3078c3a6 50#ifdef __WINDOWS__
9ef3052c 51 #include <windows.h>
3078c3a6
VZ
52#else //Unix
53 #include <signal.h>
54#endif //Win/Unix
c801d85f
KB
55
56// ----------------------------------------------------------------------------
57// non member functions
58// ----------------------------------------------------------------------------
59
60// define this to enable wrapping of log messages
61//#define LOG_PRETTY_WRAP
62
9ef3052c 63#ifdef LOG_PRETTY_WRAP
c801d85f
KB
64 static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz);
65#endif
66
67// ============================================================================
68// implementation
69// ============================================================================
70
71// ----------------------------------------------------------------------------
72// implementation of Log functions
73//
74// NB: unfortunately we need all these distinct functions, we can't make them
75// macros and not all compilers inline vararg functions.
76// ----------------------------------------------------------------------------
77
78// log functions can't allocate memory (LogError("out of memory...") should
79// work!), so we use a static buffer for all log messages
80#define LOG_BUFFER_SIZE (4096)
81
82// static buffer for error messages (@@@ MT-unsafe)
83static char s_szBuf[LOG_BUFFER_SIZE];
84
85// generic log function
9ef3052c 86void wxLogGeneric(wxLogLevel level, wxTString strFormat, ...)
c801d85f 87{
9ef3052c
VZ
88 if ( wxLog::GetActiveTarget() != NULL ) {
89 va_list argptr;
90 va_start(argptr, strFormat);
91 vsprintf(s_szBuf, strFormat, argptr);
92 va_end(argptr);
93
94 wxLog::OnLog(level, s_szBuf);
95 }
c801d85f
KB
96}
97
98#define IMPLEMENT_LOG_FUNCTION(level) \
99 void wxLog##level(wxTString strFormat, ...) \
100 { \
101 if ( wxLog::GetActiveTarget() != NULL ) { \
102 va_list argptr; \
103 va_start(argptr, strFormat); \
104 vsprintf(s_szBuf, strFormat, argptr); \
105 va_end(argptr); \
106 \
9ef3052c 107 wxLog::OnLog(wxLOG_##level, s_szBuf); \
c801d85f
KB
108 } \
109 }
110
111IMPLEMENT_LOG_FUNCTION(FatalError)
112IMPLEMENT_LOG_FUNCTION(Error)
113IMPLEMENT_LOG_FUNCTION(Warning)
114IMPLEMENT_LOG_FUNCTION(Message)
115IMPLEMENT_LOG_FUNCTION(Info)
116IMPLEMENT_LOG_FUNCTION(Status)
117
9ef3052c
VZ
118// same as info, but only if 'verbose' mode is on
119void wxLogVerbose(wxTString strFormat, ...)
120{
121 wxLog *pLog = wxLog::GetActiveTarget();
122 if ( pLog != NULL && pLog->GetVerbose() ) {
123 va_list argptr;
124 va_start(argptr, strFormat);
125 vsprintf(s_szBuf, strFormat, argptr);
126 va_end(argptr);
127
128 wxLog::OnLog(wxLOG_Info, s_szBuf);
129 }
130}
131
132// debug functions
133#ifdef __DEBUG__
134#define IMPLEMENT_LOG_DEBUG_FUNCTION(level) \
c801d85f
KB
135 void wxLog##level(const char *szFormat, ...) \
136 { \
137 if ( wxLog::GetActiveTarget() != NULL ) { \
138 va_list argptr; \
139 va_start(argptr, szFormat); \
140 vsprintf(s_szBuf, szFormat, argptr); \
141 va_end(argptr); \
142 \
9ef3052c 143 wxLog::OnLog(wxLOG_##level, s_szBuf); \
c801d85f
KB
144 } \
145 }
146
9ef3052c
VZ
147 void wxLogTrace(wxTraceMask mask, const char *szFormat, ...)
148 {
149 wxLog *pLog = wxLog::GetActiveTarget();
c801d85f 150
9ef3052c
VZ
151 // we check that all of mask bits are set in the current mask, so
152 // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
153 // if both bits are set.
154 if ( pLog != NULL && (pLog->GetTraceMask() & mask == mask) ) {
155 va_list argptr;
156 va_start(argptr, szFormat);
157 vsprintf(s_szBuf, szFormat, argptr);
158 va_end(argptr);
159
160 wxLog::OnLog(wxLOG_Trace, s_szBuf);
161 }
162 }
163
164#else // release
165 #define IMPLEMENT_LOG_DEBUG_FUNCTION(level)
166#endif
167
168IMPLEMENT_LOG_DEBUG_FUNCTION(Debug)
169IMPLEMENT_LOG_DEBUG_FUNCTION(Trace)
170
171// wxLogSysError: one uses the last error code, for other you must give it
172// explicitly
173
174// common part of both wxLogSysError
175void wxLogSysErrorHelper(long lErrCode)
c801d85f 176{
9ef3052c
VZ
177 char szErrMsg[LOG_BUFFER_SIZE / 2];
178 sprintf(szErrMsg, _(" (error %ld: %s)"), lErrCode, wxSysErrorMsg(lErrCode));
179 strncat(s_szBuf, szErrMsg, WXSIZEOF(s_szBuf) - strlen(s_szBuf));
c801d85f 180
9ef3052c
VZ
181 wxLog::OnLog(wxLOG_Error, s_szBuf);
182}
c801d85f 183
9ef3052c
VZ
184void WXDLLEXPORT wxLogSysError(wxTString strFormat, ...)
185{
186 va_list argptr;
187 va_start(argptr, strFormat);
188 vsprintf(s_szBuf, strFormat, argptr);
189 va_end(argptr);
190
191 wxLogSysErrorHelper(wxSysErrorCode());
c801d85f
KB
192}
193
194void WXDLLEXPORT wxLogSysError(long lErrCode, wxTString strFormat, ...)
195{
9ef3052c
VZ
196 va_list argptr;
197 va_start(argptr, strFormat);
198 vsprintf(s_szBuf, strFormat, argptr);
199 va_end(argptr);
c801d85f 200
9ef3052c 201 wxLogSysErrorHelper(lErrCode);
c801d85f
KB
202}
203
204// ----------------------------------------------------------------------------
205// wxLog class implementation
206// ----------------------------------------------------------------------------
207
208wxLog::wxLog()
209{
210 m_bHasMessages = FALSE;
9ef3052c
VZ
211 m_bVerbose = FALSE;
212 m_szTimeFormat = "[%d/%b/%y %H:%M:%S] ";
213 m_ulTraceMask = (wxTraceMask)-1; // set all bits
c801d85f
KB
214}
215
216wxLog *wxLog::GetActiveTarget()
217{
218 if ( !ms_bInitialized ) {
9ef3052c
VZ
219 // prevent infinite recursion if someone calls wxLogXXX() from
220 // wxApp::CreateLogTarget()
c801d85f
KB
221 ms_bInitialized = TRUE;
222
9ef3052c
VZ
223 #ifdef WX_TEST_MINIMAL
224 ms_pLogger = new wxLogStderr;
225 #else
226 // ask the application to create a log target for us
c801d85f 227 ms_pLogger = wxTheApp->CreateLogTarget();
9ef3052c 228 #endif
c801d85f
KB
229
230 // do nothing if it fails - what can we do?
231 }
232
233 return ms_pLogger;
234}
235
236wxLog *wxLog::SetActiveTarget(wxLog *pLogger)
237{
238 // flush the old messages before changing
239 if ( ms_pLogger != NULL )
240 ms_pLogger->Flush();
241
242 ms_bInitialized = TRUE;
243
244 wxLog *pOldLogger = ms_pLogger;
245 ms_pLogger = pLogger;
246 return pOldLogger;
247}
248
9ef3052c 249void wxLog::DoLog(wxLogLevel level, const char *szString)
c801d85f 250{
9ef3052c 251 wxString str;
c801d85f 252
9ef3052c
VZ
253 // prepend a timestamp if not disabled
254 if ( !IsEmpty(m_szTimeFormat) ) {
255 char szBuf[128];
256 time_t timeNow;
257 struct tm *ptmNow;
c801d85f 258
9ef3052c
VZ
259 time(&timeNow);
260 ptmNow = localtime(&timeNow);
261
262 strftime(szBuf, WXSIZEOF(szBuf), m_szTimeFormat, ptmNow);
263 str = szBuf;
264 }
c801d85f
KB
265
266 switch ( level ) {
9ef3052c 267 case wxLOG_FatalError:
c801d85f
KB
268 DoLogString(str << _("Fatal error: ") << szString);
269 DoLogString(_("Program aborted."));
270 Flush();
271 abort();
272 break;
273
9ef3052c 274 case wxLOG_Error:
c801d85f
KB
275 DoLogString(str << _("Error: ") << szString);
276 break;
277
9ef3052c 278 case wxLOG_Warning:
c801d85f
KB
279 DoLogString(str << _("Warning: ") << szString);
280 break;
281
9ef3052c 282 case wxLOG_Info:
c801d85f 283 if ( GetVerbose() )
9ef3052c 284 case wxLOG_Message:
c801d85f
KB
285 DoLogString(str + szString);
286 // fall through
287
9ef3052c 288 case wxLOG_Status:
c801d85f
KB
289 // nothing to do
290 break;
291
9ef3052c
VZ
292 case wxLOG_Trace:
293 case wxLOG_Debug:
c801d85f
KB
294 #ifdef __DEBUG__
295 #ifdef __WIN32__
296 // in addition to normal logging, also send the string to debugger
297 // (don't prepend "Debug" here: it will go to debug window anyhow)
298 ::OutputDebugString(str + szString + "\n\r");
299 #endif //Win32
9ef3052c 300 DoLogString(str << (level == wxLOG_Trace ? "Trace" : "Debug")
c801d85f
KB
301 << ": " << szString);
302 #endif
303
304 break;
305
306 default:
307 wxFAIL_MSG("unknown log level in wxLog::DoLog");
308 }
309}
310
9ef3052c 311void wxLog::DoLogString(const char *szString)
c801d85f
KB
312{
313 wxFAIL_MSG("DoLogString must be overrided if it's called.");
314}
315
316void wxLog::Flush()
317{
318 // do nothing
319}
320
321// ----------------------------------------------------------------------------
322// wxLogStderr class implementation
323// ----------------------------------------------------------------------------
324
325wxLogStderr::wxLogStderr(FILE *fp)
326{
327 if ( fp == NULL )
328 m_fp = stderr;
329 else
330 m_fp = fp;
331}
332
333void wxLogStderr::DoLogString(const char *szString)
334{
335 fputs(szString, m_fp);
336 fputc('\n', m_fp);
337 fflush(m_fp);
338}
339
340// ----------------------------------------------------------------------------
341// wxLogStream implementation
342// ----------------------------------------------------------------------------
343
344wxLogStream::wxLogStream(ostream *ostr)
345{
346 if ( ostr == NULL )
347 m_ostr = &cerr;
348 else
349 m_ostr = ostr;
350}
351
352void wxLogStream::DoLogString(const char *szString)
353{
354 (*m_ostr) << szString << endl << flush;
355}
356
357// ----------------------------------------------------------------------------
358// wxLogTextCtrl implementation
359// ----------------------------------------------------------------------------
c801d85f 360wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl *pTextCtrl)
9ef3052c
VZ
361// @@@ TODO: in wxGTK wxTextCtrl doesn't derive from streambuf
362#ifndef __GTK__
c801d85f 363 : wxLogStream(new ostream(pTextCtrl))
9ef3052c 364#endif //GTK
c801d85f
KB
365{
366}
367
368wxLogTextCtrl::~wxLogTextCtrl()
369{
9ef3052c
VZ
370 #ifndef __GTK__
371 delete m_ostr;
372 #endif //GTK
c801d85f 373}
c801d85f
KB
374
375// ----------------------------------------------------------------------------
376// wxLogGui implementation
377// ----------------------------------------------------------------------------
378
379#ifndef WX_TEST_MINIMAL
380
381wxLogGui::wxLogGui()
382{
383 m_bErrors = FALSE;
384}
385
386void wxLogGui::Flush()
387{
388 if ( !m_bHasMessages )
389 return;
390
391 // @@@ ugly...
392
393 // concatenate all strings (but not too many to not overfill the msg box)
394 wxString str;
395 uint nLines = 0,
396 nMsgCount = m_aMessages.Count();
397
398 // start from the most recent message
399 for ( uint n = nMsgCount; n > 0; n-- ) {
400 // for Windows strings longer than this value are wrapped (NT 4.0)
401 const uint nMsgLineWidth = 156;
402
403 nLines += (m_aMessages[n - 1].Len() + nMsgLineWidth - 1) / nMsgLineWidth;
404
405 if ( nLines > 25 ) // don't put too many lines in message box
406 break;
407
408 str << m_aMessages[n - 1] << "\n";
409 }
410
411 if ( m_bErrors ) {
412 wxMessageBox(str, _("Error"), wxOK | wxICON_EXCLAMATION);
413 }
414 else {
415 wxMessageBox(str, _("Information"), wxOK | wxICON_INFORMATION);
416 }
417
418 // no undisplayed messages whatsoever
419 m_bHasMessages =
420 m_bErrors = FALSE;
421 m_aMessages.Empty();
422}
423
424// the default behaviour is to discard all informational messages if there
425// are any errors/warnings.
9ef3052c 426void wxLogGui::DoLog(wxLogLevel level, const char *szString)
c801d85f
KB
427{
428 switch ( level ) {
9ef3052c 429 case wxLOG_Info:
c801d85f 430 if ( GetVerbose() )
9ef3052c 431 case wxLOG_Message:
c801d85f
KB
432 if ( !m_bErrors ) {
433 m_aMessages.Add(szString);
434 m_bHasMessages = TRUE;
435 }
436 break;
437
9ef3052c 438 case wxLOG_Status:
c801d85f
KB
439 {
440 // find the top window and set it's status text if it has any
441 wxWindow *pWin = wxTheApp->GetTopWindow();
442 if ( pWin != NULL && pWin->IsKindOf(CLASSINFO(wxFrame)) ) {
443 wxFrame *pFrame = (wxFrame *)pWin;
444 pFrame->SetStatusText(szString);
445 }
446 }
447 break;
448
9ef3052c
VZ
449 case wxLOG_Trace:
450 case wxLOG_Debug:
c801d85f
KB
451 #ifdef __DEBUG__
452 #ifdef __WIN32__
453 OutputDebugString(szString);
454 OutputDebugString("\n\r");
455 #else //!WIN32
456 // send them to stderr
884d770a
VZ
457 fprintf(stderr, level == wxLOG_Trace ? "Trace: %s\n"
458 : "Debug: %s\n", szString);
c801d85f
KB
459 fflush(stderr);
460 #endif // WIN32
461 #endif
462 break;
463
9ef3052c 464 case wxLOG_FatalError:
c801d85f
KB
465 // show this one immediately
466 wxMessageBox(szString, "Fatal error", wxICON_HAND);
467 break;
468
9ef3052c
VZ
469 case wxLOG_Error:
470 case wxLOG_Warning:
c801d85f
KB
471 // discard earlier informational messages if this is the 1st error
472 if ( !m_bErrors ) {
473 m_aMessages.Empty();
474 m_bHasMessages = TRUE;
475 m_bErrors = TRUE;
476 }
477
478 m_aMessages.Add(szString);
479 break;
480
481 default:
482 wxFAIL_MSG("unknown log level in wxLogGui::DoLog");
483 }
484}
485
9ef3052c
VZ
486// ----------------------------------------------------------------------------
487// wxLogWindow implementation
488// ----------------------------------------------------------------------------
489
490// log frame class
491class wxLogFrame : public wxFrame
492{
493public:
494 // ctor
495 wxLogFrame(const char *szTitle);
496
497 // menu callbacks
498 void OnClose(wxCommandEvent& event);
499 void OnSave (wxCommandEvent& event);
500 void OnClear(wxCommandEvent& event);
501
502 // accessors
503 wxTextCtrl *TextCtrl() const { return m_pTextCtrl; }
504
505private:
506 enum
507 {
508 Menu_Close = 100,
509 Menu_Save,
510 Menu_Clear
511 };
512
513 wxTextCtrl *m_pTextCtrl;
514
515 DECLARE_EVENT_TABLE()
516};
517
518BEGIN_EVENT_TABLE(wxLogFrame, wxFrame)
519 // wxLogWindow menu events
520 EVT_MENU(Menu_Close, wxLogFrame::OnClose)
521 EVT_MENU(Menu_Save, wxLogFrame::OnSave)
522 EVT_MENU(Menu_Clear, wxLogFrame::OnClear)
523
524 EVT_CLOSE(wxLogFrame::OnClose)
525END_EVENT_TABLE()
526
527wxLogFrame::wxLogFrame(const char *szTitle)
528 : wxFrame(NULL, -1, szTitle)
529{
f42d2625
VZ
530 // we don't want to be a top-level frame because it would prevent the
531 // application termination when all other frames are closed
532 wxTopLevelWindows.DeleteObject(this);
533
9ef3052c
VZ
534 // @@ kludge: wxSIMPLE_BORDER is simply to prevent wxWindows from creating
535 // a rich edit control instead of a normal one we want
536 m_pTextCtrl = new wxTextCtrl(this, -1, wxEmptyString, wxDefaultPosition,
537 wxDefaultSize,
538 wxSIMPLE_BORDER |
539 wxTE_MULTILINE |
540 wxHSCROLL |
541 wxTE_READONLY);
542 /*
543 m_pTextCtrl->SetEditable(FALSE);
544 m_pTextCtrl->SetRichEdit(FALSE);
545 */
546
547 // create menu
548 wxMenuBar *pMenuBar = new wxMenuBar;
549 wxMenu *pMenu = new wxMenu;
550 pMenu->Append(Menu_Save, "&Save...");
551 pMenu->Append(Menu_Clear, "C&lear");
552 pMenu->AppendSeparator();
553 pMenu->Append(Menu_Close, "&Close");
554 pMenuBar->Append(pMenu, "&Log");
555 SetMenuBar(pMenuBar);
556
557 // @@ what about status bar? needed (for menu prompts)?
558}
559
560void wxLogFrame::OnClose(wxCommandEvent& event)
561{
562 // just hide the window
563 Show(FALSE);
564}
565
566void wxLogFrame::OnSave(wxCommandEvent& event)
567{
568 // get the file name
569 // -----------------
570 const char *szFileName = wxSaveFileSelector("log", "txt", "log.txt");
571 if ( szFileName == NULL ) {
572 // cancelled
573 return;
574 }
575
576 // open file
577 // ---------
578 wxFile file;
e51c4943 579 bool bOk;
9ef3052c 580 if ( wxFile::Exists(szFileName) ) {
e51c4943 581 bool bAppend;
9ef3052c
VZ
582 wxString strMsg;
583 strMsg.Printf(_("Append log to file '%s' "
584 "(choosing [No] will overwrite it)?"), szFileName);
585 switch ( wxMessageBox(strMsg, "Question", wxYES_NO | wxCANCEL) ) {
586 case wxYES:
587 bAppend = TRUE;
588 break;
589
590 case wxNO:
591 bAppend = FALSE;
592 break;
593
594 case wxCANCEL:
595 return;
596
597 default:
598 wxFAIL_MSG("invalid message box return value");
599 }
600
601 if ( bAppend ) {
602 bOk = file.Open(szFileName, wxFile::write_append);
603 }
604 else {
605 bOk = file.Create(szFileName, TRUE /* overwrite */);
606 }
607 }
608 else {
609 bOk = file.Create(szFileName);
610 }
611
612 // retrieve text and save it
613 // -------------------------
614
f42d2625 615#ifdef __GTK__
9ef3052c 616 // @@@@ TODO: no GetNumberOfLines and GetLineText in wxGTK yet
f42d2625
VZ
617 wxLogError("Sorry, this function is not implemented under GTK");
618#else
9ef3052c
VZ
619 int nLines = m_pTextCtrl->GetNumberOfLines();
620 for ( int nLine = 0; bOk && nLine < nLines; nLine++ ) {
621 bOk = file.Write(m_pTextCtrl->GetLineText(nLine) + wxTextFile::GetEOL());
622 }
623#endif //GTK
624
625 if ( bOk )
626 bOk = file.Close();
627
628 if ( !bOk ) {
629 wxLogError("Can't save log contents to file.");
630 return;
631 }
632}
633
634void wxLogFrame::OnClear(wxCommandEvent& event)
635{
636 m_pTextCtrl->Clear();
637}
638
f42d2625 639wxLogWindow::wxLogWindow(const wxTString& strTitle, bool bShow)
9ef3052c
VZ
640{
641 m_pOldLog = wxLog::GetActiveTarget();
642 m_pLogFrame = new wxLogFrame(strTitle);
f42d2625
VZ
643
644 if ( bShow )
645 m_pLogFrame->Show(TRUE);
9ef3052c
VZ
646}
647
e51c4943 648void wxLogWindow::Show(bool bShow)
9ef3052c
VZ
649{
650 m_pLogFrame->Show(bShow);
651}
652
653void wxLogWindow::DoLog(wxLogLevel level, const char *szString)
654{
655 // first let the previous logger show it
656 if ( m_pOldLog != NULL ) {
657 // @@@ why can't we access protected wxLog method from here (we derive
658 // from wxLog)? gcc gives "DoLog is protected in this context", what
659 // does this mean? Anyhow, the cast is harmless and let's us do what
660 // we want.
661 ((wxLogWindow *)m_pOldLog)->DoLog(level, szString);
662 }
663
664 // and this will format it nicely and call our DoLogString()
665 wxLog::DoLog(level, szString);
666}
667
668void wxLogWindow::DoLogString(const char *szString)
669{
670 // put the text into our window
671 wxTextCtrl *pText = m_pLogFrame->TextCtrl();
672
673 // remove selection (WriteText is in fact ReplaceSelection)
f42d2625
VZ
674 #ifdef __WINDOWS__
675 long nLen = pText->GetLastPosition();
676 pText->SetSelection(nLen, nLen);
677 #endif // Windows
9ef3052c
VZ
678
679 pText->WriteText(szString);
680 pText->WriteText("\n"); // "\n" ok here (_not_ "\r\n")
681
682 // ensure that the line can be seen
683 // @@@ TODO
684}
685
686wxLogWindow::~wxLogWindow()
687{
688 m_pLogFrame->Close(TRUE);
689}
690
c801d85f
KB
691#endif //WX_TEST_MINIMAL
692
693// ============================================================================
694// Global functions/variables
695// ============================================================================
696
697// ----------------------------------------------------------------------------
698// static variables
699// ----------------------------------------------------------------------------
700wxLog *wxLog::ms_pLogger = NULL;
701bool wxLog::ms_bInitialized = FALSE;
c801d85f
KB
702
703// ----------------------------------------------------------------------------
704// stdout error logging helper
705// ----------------------------------------------------------------------------
706
707// helper function: wraps the message and justifies it under given position
708// (looks more pretty on the terminal). Also adds newline at the end.
709//
710// @@ this is now disabled until I find a portable way of determining the
9ef3052c 711// terminal window size (ok, I found it but does anybody really cares?)
c801d85f
KB
712#ifdef LOG_PRETTY_WRAP
713static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz)
714{
715 size_t nMax = 80; // @@@@
716 size_t nStart = strlen(pszPrefix);
717 fputs(pszPrefix, f);
718
719 size_t n;
720 while ( *psz != '\0' ) {
721 for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ )
722 putc(*psz++, f);
723
724 // wrapped?
725 if ( *psz != '\0' ) {
726 /*putc('\n', f);*/
727 for ( n = 0; n < nStart; n++ )
728 putc(' ', f);
729
730 // as we wrapped, squeeze all white space
731 while ( isspace(*psz) )
732 psz++;
733 }
734 }
735
736 putc('\n', f);
737}
738#endif //LOG_PRETTY_WRAP
739
740// ----------------------------------------------------------------------------
741// error code/error message retrieval functions
742// ----------------------------------------------------------------------------
743
744// get error code from syste
745unsigned long wxSysErrorCode()
746{
747 #ifdef __WINDOWS__
748 #ifdef __WIN32__
749 return ::GetLastError();
750 #else //WIN16
751 // @@@@ what to do on Windows 3.1?
752 return 0;
753 #endif //WIN16/32
754 #else //Unix
755 return errno;
756 #endif //Win/Unix
757}
758
759// get error message from system
760const char *wxSysErrorMsg(unsigned long nErrCode)
761{
762 if ( nErrCode == 0 )
763 nErrCode = wxSysErrorCode();
764
9ef3052c
VZ
765 #ifdef __WINDOWS__
766 #ifdef __WIN32__
767 static char s_szBuf[LOG_BUFFER_SIZE / 2];
768
769 // get error message from system
770 LPVOID lpMsgBuf;
771 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
772 NULL, nErrCode,
773 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
774 (LPTSTR)&lpMsgBuf,
775 0, NULL);
776
777 // copy it to our buffer and free memory
778 strncpy(s_szBuf, (const char *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1);
779 s_szBuf[WXSIZEOF(s_szBuf) - 1] = '\0';
780 LocalFree(lpMsgBuf);
781
782 // returned string is capitalized and ended with '\r\n' - bad
783 s_szBuf[0] = (char)tolower(s_szBuf[0]);
784 size_t len = strlen(s_szBuf);
785 if ( len > 0 ) {
786 // truncate string
787 if ( s_szBuf[len - 2] == '\r' )
788 s_szBuf[len - 2] = '\0';
789 }
c801d85f 790
9ef3052c
VZ
791 return s_szBuf;
792 #else //Win16
793 // TODO @@@@
794 return NULL;
795 #endif // Win16/32
796 #else // Unix
797 return strerror(nErrCode);
798 #endif // Win/Unix
c801d85f
KB
799}
800
801// ----------------------------------------------------------------------------
802// debug helper
803// ----------------------------------------------------------------------------
804
805#ifdef __DEBUG__
806
807// this function is called when an assert fails
808void wxOnAssert(const char *szFile, int nLine, const char *szMsg)
809{
810 // this variable can be set to true to suppress "assert failure" messages
811 static s_bNoAsserts = FALSE;
812
813 char szBuf[LOG_BUFFER_SIZE];
814 sprintf(szBuf, _("Assert failed in file %s at line %d"), szFile, nLine);
815 if ( szMsg != NULL ) {
816 strcat(szBuf, ": ");
817 strcat(szBuf, szMsg);
818 }
819 else {
820 strcat(szBuf, ".");
821 }
822
823 // send it to the normal log destination
824 wxLogDebug(szBuf);
825
3078c3a6
VZ
826 if ( !s_bNoAsserts ) {
827 strcat(szBuf, _("\nDo you want to stop the program?"
828 "\nYou can also choose [Cancel] to suppress "
829 "further warnings."));
830
9fd239ad 831 switch ( wxMessageBox(szBuf, _("Debug"),
3078c3a6
VZ
832 wxYES_NO | wxCANCEL | wxICON_STOP ) ) {
833 case wxYES:
834 #ifdef __WINDOWS__
c801d85f 835 DebugBreak();
3078c3a6
VZ
836 #else // Unix
837 raise(SIGTRAP);
838 #endif // Win/Unix
839 break;
c801d85f 840
3078c3a6
VZ
841 case wxCANCEL:
842 s_bNoAsserts = TRUE;
843 break;
844
845 //case wxNO: nothing to do
c801d85f 846 }
3078c3a6 847 }
c801d85f
KB
848}
849
850#endif //DEBUG
851