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