2 // This file is part of the aMule Project.
4 // Copyright (c) 2004-2011 aMule Team ( admin@amule.org / http://www.amule.org )
6 // Any parts of this program derived from the xMule, lMule or eMule project,
7 // or contributed by third-party developers are copyrighted by their
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "ExternalConnector.h"
28 #include "config.h" // Needed for VERSION and readline detection
30 #include <common/ClientVersion.h>
33 #include <common/Format.h> // Needed for CFormat
34 #include <wx/tokenzr.h> // For wxStringTokenizer
37 #ifdef HAVE_LIBREADLINE
38 #if defined(HAVE_READLINE_READLINE_H)
39 #include <readline/readline.h> // Do_not_auto_remove
40 #elif defined(HAVE_READLINE_H)
41 #include <readline.h> // Do_not_auto_remove
42 #endif /* !defined(HAVE_READLINE_H) */
43 #else /* !defined(HAVE_READLINE_READLINE_H) */
45 #endif /* HAVE_LIBREADLINE */
48 #ifdef HAVE_READLINE_HISTORY
49 #if defined(HAVE_READLINE_HISTORY_H)
50 #include <readline/history.h> // Do_not_auto_remove
51 #elif defined(HAVE_HISTORY_H)
52 #include <history.h> // Do_not_auto_remove
53 #endif /* defined(HAVE_READLINE_HISTORY_H) */
56 #endif /* HAVE_READLINE_HISTORY */
59 #include <ec/cpp/ECFileConfig.h> // Needed for CECFileConfig
60 #include <common/MD5Sum.h>
61 #include "OtherFunctions.h" // Needed for GetPassword()
62 #include "MuleVersion.h" // Needed for GetMuleVersion()
64 #ifdef _MSC_VER // silly warnings about deprecated functions
65 #pragma warning(disable:4996)
68 //-------------------------------------------------------------------
70 CaMuleExternalConnector
* CCommandTree::m_app
;
72 CCommandTree::~CCommandTree()
74 DeleteContents(m_subcommands
);
78 CCommandTree
* CCommandTree::AddCommand(CCommandTree
* command
)
80 command
->m_parent
= this;
81 const wxString
& cmd
= command
->m_command
;
83 for (it
= m_subcommands
.begin(); it
!= m_subcommands
.end(); ++it
) {
84 if ((*it
)->m_command
> cmd
) {
88 m_subcommands
.insert(it
, command
);
93 int CCommandTree::FindCommandId(const wxString
& command
, wxString
& args
, wxString
& cmdstr
) const
95 wxString cmd
= command
.BeforeFirst(wxT(' ')).Lower();
96 for (CmdPosConst_t it
= m_subcommands
.begin(); it
!= m_subcommands
.end(); ++it
) {
97 if ((*it
)->m_command
.Lower() == cmd
) {
98 args
= command
.AfterFirst(wxT(' ')).Trim(false);
99 return (*it
)->FindCommandId(args
, args
, cmdstr
);
102 cmdstr
= GetFullCommand().Lower();
103 if (m_params
== CMD_PARAM_ALWAYS
&& args
.IsEmpty()) {
104 return CMD_ERR_MUST_HAVE_PARAM
;
105 } else if (m_params
== CMD_PARAM_NEVER
&& !args
.IsEmpty()) {
106 return CMD_ERR_NO_PARAM
;
108 if ((m_cmd_id
>= 0) && (m_cmd_id
& CMD_DEPRECATED
)) {
109 m_app
->Show(wxT('\n') + m_verbose
+ wxT('\n'));
110 return m_cmd_id
& ~CMD_DEPRECATED
;
118 wxString
CCommandTree::GetFullCommand() const
120 wxString cmd
= m_command
;
122 const CCommandTree
*parent
= m_parent
;
123 while (parent
&& parent
->m_parent
) {
124 cmd
= parent
->m_command
+ wxT(" ") + cmd
;
125 parent
= parent
->m_parent
;
132 void CCommandTree::PrintHelpFor(const wxString
& command
) const
134 wxString cmd
= command
.BeforeFirst(wxT(' ')).Lower();
135 if (!cmd
.IsEmpty()) {
136 for (CmdPosConst_t it
= m_subcommands
.begin(); it
!= m_subcommands
.end(); ++it
) {
137 if ((*it
)->m_command
.Lower() == cmd
) {
138 (*it
)->PrintHelpFor(command
.AfterFirst(wxT(' ')).Trim(false));
143 m_app
->Show(CFormat(_("Unknown extension '%s' for the '%s' command.\n")) % command
% GetFullCommand());
145 m_app
->Show(CFormat(_("Unknown command '%s'.\n")) % command
);
148 wxString fullcmd
= GetFullCommand();
149 if (!fullcmd
.IsEmpty()) {
150 m_app
->Show(fullcmd
.Upper() + wxT(": ") + wxGetTranslation(m_short
) + wxT("\n"));
151 if (!m_verbose
.IsEmpty()) {
152 m_app
->Show(wxT("\n"));
153 m_app
->Show(wxGetTranslation(m_verbose
));
156 if (m_params
== CMD_PARAM_NEVER
) {
157 m_app
->Show(_("\nThis command cannot have an argument.\n"));
158 } else if (m_params
== CMD_PARAM_ALWAYS
) {
159 m_app
->Show(_("\nThis command must have an argument.\n"));
161 if (m_cmd_id
== CMD_ERR_INCOMPLETE
) {
162 m_app
->Show(_("\nThis command is incomplete, you must use one of the extensions below.\n"));
164 if (!m_subcommands
.empty()) {
168 m_app
->Show(_("\nAvailable extensions:\n"));
170 m_app
->Show(_("Available commands:\n"));
172 for (it
= m_subcommands
.begin(); it
!= m_subcommands
.end(); ++it
) {
173 if (!((*it
)->m_cmd_id
>= 0 && (*it
)->m_cmd_id
& CMD_DEPRECATED
) || m_parent
) {
174 int len
= (*it
)->m_command
.Length();
181 for (it
= m_subcommands
.begin(); it
!= m_subcommands
.end(); ++it
) {
182 if (!((*it
)->m_cmd_id
>= 0 && (*it
)->m_cmd_id
& CMD_DEPRECATED
) || m_parent
) {
183 m_app
->Show((*it
)->m_command
+ wxString(wxT(' '), maxlen
- (*it
)->m_command
.Length()) + wxGetTranslation((*it
)->m_short
) + wxT("\n"));
187 m_app
->Show(CFormat(_("\nAll commands are case insensitive.\nType '%s <command>' to get detailed info on <command>.\n")) % wxT("help"));
191 m_app
->Show(wxT("\n"));
194 //-------------------------------------------------------------------
196 #ifdef HAVE_LIBREADLINE
198 const CmdList_t
* CCommandTree::GetSubCommandsFor(const wxString
& command
, bool mayRestart
) const
200 if (command
.IsEmpty()) {
201 return &m_subcommands
;
204 wxString cmd
= command
.BeforeFirst(wxT(' ')).Lower();
206 if (mayRestart
&& cmd
== wxT("help")) {
207 return GetSubCommandsFor(command
.AfterFirst(wxT(' ')), false);
210 for (CmdPosConst_t it
= m_subcommands
.begin(); it
!= m_subcommands
.end(); ++it
) {
211 if ((*it
)->m_command
.Lower() == cmd
) {
212 return (*it
)->GetSubCommandsFor(command
.AfterFirst(wxT(' ')).Trim(false), mayRestart
);
220 // Forward-declare the completion function to make sure it's declaration
221 // matches the library requirements.
222 rl_compentry_func_t command_completion
;
225 // File-scope pointer to the application's command set.
226 static CCommandTree
* theCommands
;
229 char *command_completion(const char *text
, int state
)
231 static const CmdList_t
* curCommands
;
232 static CmdPosConst_t nextCommand
;
235 wxString
lineBuffer(rl_line_buffer
, *wxConvCurrent
);
236 wxString
prefix(lineBuffer
.Left(rl_point
).BeforeLast(wxT(' ')));
238 curCommands
= theCommands
->GetSubCommandsFor(prefix
);
240 nextCommand
= curCommands
->begin();
246 wxString
test(wxString(text
, *wxConvCurrent
).Lower());
247 while (nextCommand
!= curCommands
->end()) {
248 wxString curTest
= (*nextCommand
)->GetCommand();
250 if (curTest
.Lower().StartsWith(test
)) {
251 return strdup(static_cast<const char *>(unicode2char(curTest
)));
259 #endif /* HAVE_LIBREADLINE */
261 //-------------------------------------------------------------------
263 CaMuleExternalConnector::CaMuleExternalConnector()
264 : m_configFile(NULL
),
269 m_interactive(false),
274 m_NeedsConfigSave(false),
276 m_strFullVersion(NULL
),
277 m_strOSDescription(NULL
)
279 SetAppName(wxT("aMule")); // Do not change!
282 CaMuleExternalConnector::~CaMuleExternalConnector()
286 free(m_strFullVersion
);
287 free(m_strOSDescription
);
290 void CaMuleExternalConnector::OnInitCommandSet()
292 m_commands
.AddCommand(wxT("Quit"), CMD_ID_QUIT
, wxTRANSLATE("Exits from the application."), wxEmptyString
);
293 m_commands
.AddCommand(wxT("Exit"), CMD_ID_QUIT
, wxTRANSLATE("Exits from the application."), wxEmptyString
);
294 m_commands
.AddCommand(wxT("Help"), CMD_ID_HELP
, wxTRANSLATE("Show help."),
296 Do not translate the word 'help', it is a command to the program! */
297 wxTRANSLATE("To get help on a command, type 'help <command>'.\nTo get the full command list type 'help'.\n"));
300 void CaMuleExternalConnector::Show(const wxString
&s
)
303 printf("%s", (const char *)unicode2char(s
));
310 void CaMuleExternalConnector::ShowGreet()
312 wxString text
= GetGreetingTitle();
313 int len
= text
.Length();
314 Show(wxT('\n') + wxString(wxT('-'), 22 + len
) + wxT('\n'));
315 Show(wxT('|') + wxString(wxT(' '), 10) + text
+ wxString(wxT(' '), 10) + wxT('|') + wxT('\n'));
316 Show(wxString(wxT('-'), 22 + len
) + wxT('\n'));
317 // Do not merge the line below, or translators could translate "Help"
318 Show(CFormat(_("\nUse '%s' for command list\n\n")) % wxT("Help"));
321 void CaMuleExternalConnector::Process_Answer(const wxString
& answer
)
323 wxStringTokenizer
tokens(answer
, wxT("\n"));
324 while ( tokens
.HasMoreTokens() ) {
325 Show(wxT(" > ") + tokens
.GetNextToken() + wxT("\n"));
329 bool CaMuleExternalConnector::Parse_Command(const wxString
& buffer
)
332 wxStringTokenizer
tokens(buffer
);
333 while (tokens
.HasMoreTokens()) {
334 cmd
+= tokens
.GetNextToken() + wxT(' ');
341 int cmd_ID
= GetIDFromString(cmd
);
343 cmd_ID
= ProcessCommand(cmd_ID
);
348 m_commands
.PrintHelpFor(GetCmdArgs());
351 error
= _("Syntax error!");
353 case CMD_ERR_PROCESS_CMD
:
354 Show(_("Error processing command - should never happen! Report bug, please\n"));
356 case CMD_ERR_NO_PARAM
:
357 error
= _("This command should not have any parameters.");
359 case CMD_ERR_MUST_HAVE_PARAM
:
360 error
= _("This command must have a parameter.");
362 case CMD_ERR_INVALID_ARG
:
363 error
= _("Invalid argument.");
365 case CMD_ERR_INCOMPLETE
:
366 error
= _("This is an incomplete command.");
369 if (!error
.IsEmpty()) {
370 Show(error
+ wxT('\n'));
371 wxString
helpStr(wxT("help"));
372 if (!GetLastCmdStr().IsEmpty()) {
373 helpStr
<< wxT(' ') << GetLastCmdStr();
375 Show(CFormat(_("Type '%s' to get more help.\n")) % helpStr
);
377 return cmd_ID
== CMD_ID_QUIT
;
380 void CaMuleExternalConnector::GetCommand(const wxString
&prompt
, char* buffer
, size_t buffer_size
)
382 #ifdef HAVE_LIBREADLINE
383 char *text
= readline(unicode2char(prompt
+ wxT("$ ")));
385 (m_InputLine
== 0 || strcmp(text
,m_InputLine
) != 0)) {
392 Show(prompt
+ wxT("$ "));
393 const char *text
= fgets(buffer
, buffer_size
, stdin
); // == buffer if ok, NULL if eof
394 #endif /* HAVE_LIBREADLINE */
396 size_t len
= strlen(text
);
397 if (len
> buffer_size
- 1) {
398 len
= buffer_size
- 1;
400 if (buffer
!= text
) {
401 strncpy(buffer
, text
, len
);
405 strncpy(buffer
, "quit", buffer_size
);
409 void CaMuleExternalConnector::TextShell(const wxString
&prompt
)
414 bool The_End
= false;
416 GetCommand(prompt
, buffer
, sizeof buffer
);
417 buf
= char2unicode(buffer
);
418 The_End
= Parse_Command(buf
);
419 } while ((!The_End
) && (m_ECClient
->IsSocketConnected()));
422 void CaMuleExternalConnector::ConnectAndRun(const wxString
&ProgName
, const wxString
& ProgVersion
)
424 if (m_NeedsConfigSave
) {
430 Show(CFormat(_("This is %s %s %s\n")) % wxString::FromAscii(m_appname
) % wxT(VERSION
) % wxT(SVNDATE
));
432 Show(CFormat(_("This is %s %s\n")) % wxString::FromAscii(m_appname
) % wxT(VERSION
));
435 // HostName, Port and Password
436 if ( m_password
.IsEmpty() ) {
437 m_password
= GetPassword(true);
438 // MD5 hash for an empty string, according to rfc1321.
439 if (m_password
.Encode() == wxT("D41D8CD98F00B204E9800998ECF8427E")) {
444 if (!m_password
.IsEmpty()) {
447 Show(_("\nCreating client...\n"));
448 m_ECClient
= new CRemoteConnect(NULL
);
449 m_ECClient
->SetCapabilities(m_ZLIB
, true, false); // ZLIB, UTF8 numbers, notification
451 // ConnectToCore is blocking since m_ECClient was initialized with NULL
452 if (!m_ECClient
->ConnectToCore(m_host
, m_port
, wxT("foobar"), m_password
.Encode(), ProgName
, ProgVersion
)) {
453 // no connection => close gracefully
454 if (!m_ECClient
->GetServerReply().IsEmpty()) {
455 Show(CFormat(wxT("%s\n")) % m_ECClient
->GetServerReply());
457 Show(CFormat(_("Connection Failed. Unable to connect to %s:%d\n")) % m_host
% m_port
);
459 // Authenticate ourselves
460 // ConnectToCore() already authenticated for us.
461 //m_ECClient->ConnectionEstablished();
462 Show(m_ECClient
->GetServerReply()+wxT("\n"));
463 if (m_ECClient
->IsSocketConnected()) {
471 Show(CFormat(_("\nOk, exiting %s...\n")) % ProgName
);
475 m_ECClient
->DestroySocket();
477 Show(_("Cannot connect with an empty password.\nYou must specify a password either in config file\nor on command-line, or enter one when asked.\n\nExiting...\n"));
481 void CaMuleExternalConnector::OnInitCmdLine(wxCmdLineParser
& parser
, const char* appname
)
485 parser
.AddSwitch(wxEmptyString
, wxT("help"),
486 _("Show this help text."),
487 wxCMD_LINE_PARAM_OPTIONAL
);
488 parser
.AddOption(wxT("h"), wxT("host"),
489 _("Host where aMule is running. (default: localhost)"),
490 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
);
491 parser
.AddOption(wxT("p"), wxT("port"),
492 _("aMule's port for External Connection. (default: 4712)"),
493 wxCMD_LINE_VAL_NUMBER
, wxCMD_LINE_PARAM_OPTIONAL
);
494 parser
.AddOption(wxT("P"), wxT("password"),
495 _("External Connection password."),
496 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
);
497 parser
.AddOption(wxT("f"), wxT("config-file"),
498 _("Read configuration from file."),
499 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
);
500 parser
.AddSwitch(wxT("q"), wxT("quiet"),
501 _("Do not print any output to stdout."),
502 wxCMD_LINE_PARAM_OPTIONAL
);
503 parser
.AddSwitch(wxT("v"), wxT("verbose"),
504 _("Be verbose - show also debug messages."),
505 wxCMD_LINE_PARAM_OPTIONAL
);
506 parser
.AddOption(wxT("l"), wxT("locale"),
507 _("Sets program locale (language)."),
508 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
);
509 parser
.AddSwitch(wxT("w"), wxT("write-config"),
510 _("Write command line options to config file."),
511 wxCMD_LINE_PARAM_OPTIONAL
);
512 parser
.AddOption(wxEmptyString
, wxT("create-config-from"),
513 _("Creates config file based on aMule's config file."),
514 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
);
515 parser
.AddSwitch(wxEmptyString
, wxT("version"),
516 _("Print program version."),
517 wxCMD_LINE_PARAM_OPTIONAL
);
520 bool CaMuleExternalConnector::OnCmdLineParsed(wxCmdLineParser
& parser
)
522 if (parser
.Found(wxT("version"))) {
523 printf("%s %s\n", m_appname
, (const char *)unicode2char(GetMuleVersion()));
527 if (!parser
.Found(wxT("config-file"), &m_configFileName
)) {
528 m_configFileName
= wxT("remote.conf");
530 m_configDir
= GetConfigDir(m_configFileName
);
531 m_configFileName
= m_configDir
+ m_configFileName
;
533 wxString aMuleConfigFile
;
534 if (parser
.Found(wxT("create-config-from"), &aMuleConfigFile
)) {
535 aMuleConfigFile
= FinalizeFilename(aMuleConfigFile
);
536 if (!::wxFileExists(aMuleConfigFile
)) {
537 fprintf(stderr
, "%s\n", (const char *)unicode2char(wxT("FATAL ERROR: File does not exist: ") + aMuleConfigFile
));
540 CECFileConfig
aMuleConfig(aMuleConfigFile
);
541 LoadAmuleConfig(aMuleConfig
);
543 m_configFile
->Flush();
549 if ( !parser
.Found(wxT("host"), &m_host
) ) {
550 if ( m_host
.IsEmpty() ) {
551 m_host
= wxT("localhost");
556 if (parser
.Found(wxT("port"), &port
)) {
561 if (parser
.Found(wxT("password"), &pass_plain
)) {
562 if (!pass_plain
.IsEmpty()) {
563 m_password
.Decode(MD5Sum(pass_plain
).GetHash());
569 if (parser
.Found(wxT("write-config"))) {
570 m_NeedsConfigSave
= true;
573 parser
.Found(wxT("locale"), &m_language
);
575 if (parser
.Found(wxT("help"))) {
580 m_KeepQuiet
= parser
.Found(wxT("quiet"));
581 m_Verbose
= parser
.Found(wxT("verbose"));
586 void CaMuleExternalConnector::LoadAmuleConfig(CECFileConfig
& cfg
)
588 m_host
= wxT("localhost");
589 m_port
= cfg
.Read(wxT("/ExternalConnect/ECPort"), 4712l);
590 cfg
.ReadHash(wxT("/ExternalConnect/ECPassword"), &m_password
);
591 m_language
= cfg
.Read(wxT("/eMule/Language"), wxEmptyString
);
595 void CaMuleExternalConnector::LoadConfigFile()
598 m_configFile
= new CECFileConfig(m_configFileName
);
601 m_language
= m_configFile
->Read(wxT("/Locale"), wxEmptyString
);
602 m_host
= m_configFile
->Read(wxT("/EC/Host"), wxEmptyString
);
603 m_port
= m_configFile
->Read(wxT("/EC/Port"), 4712l);
604 m_configFile
->ReadHash(wxT("/EC/Password"), &m_password
);
605 m_ZLIB
= m_configFile
->Read(wxT("/EC/ZLIB"), 1l) != 0;
609 void CaMuleExternalConnector::SaveConfigFile()
611 if (!wxFileName::DirExists(m_configDir
)) {
612 wxFileName::Mkdir(m_configDir
);
615 m_configFile
= new CECFileConfig(m_configFileName
);
618 m_configFile
->Write(wxT("/Locale"), m_language
);
619 m_configFile
->Write(wxT("/EC/Host"), m_host
);
620 m_configFile
->Write(wxT("/EC/Port"), m_port
);
621 m_configFile
->WriteHash(wxT("/EC/Password"), m_password
);
625 bool CaMuleExternalConnector::OnInit()
628 #if wxUSE_ON_FATAL_EXCEPTION
629 // catch fatal exceptions
630 wxHandleFatalExceptions(true);
634 // If we didn't know that OnInit is called only once when creating the
635 // object, it could cause a memory leak. The two pointers below should
636 // be free()'d before assigning the new value.
637 // cppcheck-suppress publicAllocationError
638 m_strFullVersion
= strdup((const char *)unicode2char(GetMuleVersion()));
639 m_strOSDescription
= strdup((const char *)unicode2char(wxGetOsDescription()));
641 // Handle uncaught exceptions
642 InstallMuleExceptionHandler();
644 bool retval
= wxApp::OnInit();
646 InitCustomLanguages();
647 SetLocale(m_language
);
649 #ifdef HAVE_LIBREADLINE
650 // Allow conditional parsing of the ~/.inputrc file.
652 // OnInitCmdLine() is called from wxApp::OnInit() above,
653 // thus m_appname is already set.
654 rl_readline_name
= m_appname
;
656 // Allow completion of our commands
657 theCommands
= &m_commands
;
658 rl_completion_entry_function
= &command_completion
;
664 wxString
CaMuleExternalConnector::SetLocale(const wxString
& language
)
666 if (!language
.IsEmpty()) {
667 m_language
= language
;
671 m_locale
= new wxLocale
;
672 InitLocale(*m_locale
, StrLang2wx(language
));
675 return m_locale
== NULL
? wxString() : m_locale
->GetCanonicalName();
678 #if !wxUSE_GUI && defined(__WXMAC__) && !wxCHECK_VERSION(2, 9, 0)
680 #include <wx/apptrait.h> // Do_not_auto_remove
681 #include <wx/stdpaths.h> // Do_not_auto_remove
683 class CaMuleExternalConnectorTraits
: public wxConsoleAppTraits
686 virtual wxStandardPathsBase
& GetStandardPaths()
692 static wxStandardPathsCF s_stdPaths
;
695 wxStandardPathsCF
CaMuleExternalConnectorTraits::s_stdPaths
;
697 wxAppTraits
* CaMuleExternalConnector::CreateTraits()
699 return new CaMuleExternalConnectorTraits
;
704 #if wxUSE_ON_FATAL_EXCEPTION
705 // Gracefully handle fatal exceptions and print backtrace if possible
706 void CaMuleExternalConnector::OnFatalException()
708 /* Print the backtrace */
709 fprintf(stderr
, "\n--------------------------------------------------------------------------------\n");
710 fprintf(stderr
, "A fatal error has occurred and %s has crashed.\n", m_appname
);
711 fprintf(stderr
, "Please assist us in fixing this problem by posting the backtrace below in our\n");
712 fprintf(stderr
, "'aMule Crashes' forum and include as much information as possible regarding the\n");
713 fprintf(stderr
, "circumstances of this crash. The forum is located here:\n");
714 fprintf(stderr
, " http://forum.amule.org/index.php?board=67.0\n");
715 fprintf(stderr
, "If possible, please try to generate a real backtrace of this crash:\n");
716 fprintf(stderr
, " http://wiki.amule.org/wiki/Backtraces\n\n");
717 fprintf(stderr
, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
718 fprintf(stderr
, "Current version is: %s %s\n", m_appname
, m_strFullVersion
);
719 fprintf(stderr
, "Running on: %s\n\n", m_strOSDescription
);
721 print_backtrace(1); // 1 == skip this function.
723 fprintf(stderr
, "\n--------------------------------------------------------------------------------\n");
728 void CaMuleExternalConnector::OnAssertFailure(const wxChar
*file
, int line
, const wxChar
*func
, const wxChar
*cond
, const wxChar
*msg
)
730 #if !defined wxUSE_STACKWALKER || !wxUSE_STACKWALKER
731 wxString errmsg
= CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") ) % file
% func
% line
% cond
% ( msg
? msg
: wxT("") );
733 fprintf(stderr
, "Assertion failed: %s\n", (const char*)unicode2char(errmsg
));
735 // Skip the function-calls directly related to the assert call.
736 fprintf(stderr
, "\nBacktrace follows:\n");
738 fprintf(stderr
, "\n");
740 wxApp::OnAssertFailure(file
, line
, func
, cond
, msg
);
744 // File_checked_for_headers