00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <ncbi_pch.hpp>
00035 #include <corelib/ncbiapp.hpp>
00036 #include <corelib/ncbifile.hpp>
00037 #include <corelib/ncbi_system.hpp>
00038 #include <corelib/ncbi_param.hpp>
00039 #include <corelib/syslog.hpp>
00040 #include <corelib/error_codes.hpp>
00041 #include <corelib/ncbi_safe_static.hpp>
00042
00043 #if defined(NCBI_OS_MSWIN)
00044 # include <corelib/ncbi_os_mswin.hpp>
00045 # include <corelib/ncbidll.hpp>
00046 # include <io.h>
00047 # include <fcntl.h>
00048 #endif
00049
00050 #if defined(NCBI_OS_UNIX)
00051 # include <unistd.h>
00052 #endif
00053
00054
00055 #define NCBI_USE_ERRCODE_X Corelib_App
00056
00057
00058 BEGIN_NCBI_SCOPE
00059
00060
00061
00062
00063
00064
00065 static const char* s_ArgLogFile = "-logfile";
00066 static const char* s_ArgCfgFile = "-conffile";
00067 static const char* s_ArgVersion = "-version";
00068 static const char* s_ArgFullVersion = "-version-full";
00069 static const char* s_ArgDryRun = "-dryrun";
00070
00071
00072
00073
00074
00075
00076 static bool s_IsApplicationStarted = false;
00077
00078
00079
00080
00081
00082
00083 CNcbiApplication* CNcbiApplication::m_Instance;
00084
00085
00086 CNcbiApplication* CNcbiApplication::Instance(void)
00087 {
00088 return m_Instance;
00089 }
00090
00091
00092 CNcbiApplication::CNcbiApplication(void)
00093 {
00094
00095 GetDiagContext().GetUID();
00096 GetDiagContext().InitMessages(size_t(-1));
00097 GetDiagContext().SetGlobalAppState(eDiagAppState_AppBegin);
00098
00099 m_DisableArgDesc = 0;
00100 m_HideArgs = 0;
00101 m_StdioFlags = 0;
00102 m_CinBuffer = 0;
00103 m_ExitCodeCond = eNoExits;
00104
00105
00106 if ( m_Instance ) {
00107 NCBI_THROW(CAppException, eSecond,
00108 "Second instance of CNcbiApplication is prohibited");
00109 }
00110 m_Instance = this;
00111
00112
00113 m_Version.Reset(new CVersion());
00114
00115
00116 m_Arguments.reset(new CNcbiArguments(0,0));
00117
00118
00119 m_Environ.reset(new CNcbiEnvironment);
00120
00121
00122 m_Config.Reset(new CNcbiRegistry);
00123
00124 m_DryRun = false;
00125 }
00126
00127
00128 CNcbiApplication::~CNcbiApplication(void)
00129 {
00130 m_Instance = 0;
00131 FlushDiag(0, true);
00132 if (m_CinBuffer) {
00133 delete [] m_CinBuffer;
00134 }
00135
00136 #if defined(NCBI_COMPILER_WORKSHOP)
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 NcbiCout.flush();
00147 #endif
00148 }
00149
00150
00151 void CNcbiApplication::Init(void)
00152 {
00153 return;
00154 }
00155
00156
00157 int CNcbiApplication::DryRun(void)
00158 {
00159 ERR_POST_X(1, Info << "DryRun: default implementation does nothing");
00160 return 0;
00161 }
00162
00163
00164 void CNcbiApplication::Exit(void)
00165 {
00166 return;
00167 }
00168
00169
00170 const CArgs& CNcbiApplication::GetArgs(void) const
00171 {
00172 if ( !m_Args.get() ) {
00173 NCBI_THROW(CAppException, eUnsetArgs,
00174 "Command-line argument description is not found");
00175 }
00176 return *m_Args;
00177 }
00178
00179
00180 SIZE_TYPE CNcbiApplication::FlushDiag(CNcbiOstream* os, bool )
00181 {
00182 if ( os ) {
00183 SetDiagStream(os, true, 0, 0, "STREAM");
00184 }
00185 GetDiagContext().FlushMessages(*GetDiagHandler());
00186 GetDiagContext().DiscardMessages();
00187 return 0;
00188 }
00189
00190
00191 #if defined(NCBI_OS_DARWIN)
00192 static void s_MacArgMunging(CNcbiApplication& app,
00193 int* argcPtr,
00194 const char* const** argvPtr,
00195 const string& exepath)
00196 {
00197
00198
00199
00200
00201
00202
00203 static const char* s_ArgMacPsn = "-psn_";
00204
00205 if (*argcPtr == 2 &&
00206 NStr::strncmp((*argvPtr)[1], s_ArgMacPsn, strlen(s_ArgMacPsn)) == 0) {
00207 --*argcPtr;
00208 }
00209
00210 if (*argcPtr > 1)
00211 return;
00212
00213
00214
00215
00216 string exedir;
00217 CDir::SplitPath(exepath, &exedir);
00218 string args_fname = exedir + app.GetProgramDisplayName() + ".args";
00219 CNcbiIfstream in(args_fname.c_str());
00220
00221 if ( !in.good() ) {
00222 ERR_POST_X(2, Info << "Mac arguments file not found: " << args_fname);
00223 return;
00224 }
00225
00226 vector<string> v;
00227
00228
00229 if (*argcPtr > 0) {
00230 v.push_back((*argvPtr)[0]);
00231 } else {
00232 v.push_back(exepath);
00233 }
00234
00235
00236
00237
00238 string arg;
00239 while (in >> arg) {
00240 v.push_back(arg);
00241 }
00242
00243
00244 *argcPtr = v.size();
00245
00246 char** argv = new char*[v.size()];
00247 int c = 0;
00248 ITERATE(vector<string>, vp, v) {
00249 argv[c++] = strdup(vp->c_str());
00250 }
00251 *argvPtr = argv;
00252 }
00253 #endif
00254
00255
00256 NCBI_PARAM_DECL(bool, Debug, Catch_Unhandled_Exceptions);
00257 NCBI_PARAM_DEF_EX(bool, Debug, Catch_Unhandled_Exceptions, true,
00258 eParam_NoThread,
00259 DEBUG_CATCH_UNHANDLED_EXCEPTIONS);
00260 typedef NCBI_PARAM_TYPE(Debug, Catch_Unhandled_Exceptions) TParamCatchExceptions;
00261
00262 bool s_HandleExceptions(void)
00263 {
00264 return TParamCatchExceptions::GetDefault();
00265 }
00266
00267
00268 void CNcbiApplication::x_TryInit(EAppDiagStream diag,
00269 const char* conf)
00270 {
00271
00272 if ( conf ) {
00273 string x_conf(conf);
00274 LoadConfig(*m_Config, &x_conf);
00275 } else {
00276 LoadConfig(*m_Config, NULL);
00277 }
00278
00279 CDiagContext::SetupDiag(diag, m_Config, eDCM_Flush);
00280 CDiagContext::x_FinalizeSetupDiag();
00281
00282
00283
00284
00285
00286 x_HonorStandardSettings();
00287
00288
00289 AppStart();
00290
00291
00292 #if (defined(NCBI_COMPILER_ICC) && NCBI_COMPILER_VERSION < 900)
00293
00294
00295 try {
00296 Init();
00297 }
00298 catch (CArgHelpException& ) {
00299 throw;
00300 }
00301 #else
00302 Init();
00303 #endif
00304
00305
00306 if (!m_DisableArgDesc && !m_ArgDesc.get()) {
00307 auto_ptr<CArgDescriptions> arg_desc(new CArgDescriptions);
00308 arg_desc->SetUsageContext
00309 (GetArguments().GetProgramBasename(),
00310 "This program has no mandatory arguments");
00311 SetupArgDescriptions(arg_desc.release());
00312 }
00313 }
00314
00315
00316 void CNcbiApplication::x_TryMain(EAppDiagStream diag,
00317 const char* conf,
00318 int* exit_code,
00319 bool* got_exception)
00320 {
00321
00322 if ( s_HandleExceptions() ) {
00323 try {
00324 x_TryInit(diag, conf);
00325 }
00326 catch (CArgHelpException& e) {
00327 x_AddDefaultArgs();
00328
00329 if (e.GetErrCode() == CArgHelpException::eHelpXml) {
00330 m_ArgDesc->PrintUsageXml(cout);
00331 } else {
00332 string str;
00333 m_ArgDesc->PrintUsage
00334 (str, e.GetErrCode() == CArgHelpException::eHelpFull);
00335 cout << str;
00336 }
00337 *exit_code = 0;
00338 }
00339 catch (CArgException& e) {
00340 NCBI_RETHROW_SAME(e, "Application's initialization failed");
00341 }
00342 catch (CException& e) {
00343 NCBI_REPORT_EXCEPTION_X(15,
00344 "Application's initialization failed", e);
00345 *got_exception = true;
00346 *exit_code = 2;
00347 }
00348 catch (exception& e) {
00349 ERR_POST_X(6, "Application's initialization failed: " << e.what());
00350 *got_exception = true;
00351 *exit_code = 2;
00352 }
00353 }
00354 else {
00355 x_TryInit(diag, conf);
00356 }
00357
00358
00359 if (*exit_code == 1) {
00360 GetDiagContext().SetGlobalAppState(eDiagAppState_AppRun);
00361 if ( s_HandleExceptions() ) {
00362 try {
00363 *exit_code = m_DryRun ? DryRun() : Run();
00364 }
00365 catch (CArgException& e) {
00366 NCBI_RETHROW_SAME(e, "Application's execution failed");
00367 }
00368 catch (CException& e) {
00369 NCBI_REPORT_EXCEPTION_X(16,
00370 "Application's execution failed", e);
00371 *got_exception = true;
00372 *exit_code = 3;
00373 }
00374 catch (exception& e) {
00375 ERR_POST_X(7, "Application's execution failed: " << e.what());
00376 *got_exception = true;
00377 *exit_code = 3;
00378 }
00379 }
00380 else {
00381 *exit_code = m_DryRun ? DryRun() : Run();
00382 }
00383 }
00384 GetDiagContext().SetGlobalAppState(eDiagAppState_AppEnd);
00385
00386
00387 if ( s_HandleExceptions() ) {
00388 try {
00389 Exit();
00390 }
00391 catch (CArgException& e) {
00392 NCBI_RETHROW_SAME(e, "Application's cleanup failed");
00393 }
00394 catch (CException& e) {
00395 NCBI_REPORT_EXCEPTION_X(17, "Application's cleanup failed", e);
00396 *got_exception = true;
00397 }
00398 catch (exception& e) {
00399 ERR_POST_X(8, "Application's cleanup failed: "<< e.what());
00400 *got_exception = true;
00401 }
00402 }
00403 else {
00404 Exit();
00405 }
00406 }
00407
00408
00409 int CNcbiApplication::AppMain
00410 (int argc,
00411 const char* const* argv,
00412 const char* const* envp,
00413 EAppDiagStream diag,
00414 const char* conf,
00415 const string& name)
00416 {
00417 if (conf) {
00418 m_DefaultConfig = conf;
00419 }
00420 x_SetupStdio();
00421
00422
00423 string exepath = FindProgramExecutablePath(argc, argv, &m_RealExePath);
00424 m_ExePath = exepath;
00425
00426
00427 string appname = name;
00428 if (appname.empty()) {
00429 if (!exepath.empty()) {
00430 CDirEntry::SplitPath(exepath, NULL, &appname);
00431 } else if (argc > 0 && argv[0] != NULL && *argv[0] != '\0') {
00432 CDirEntry::SplitPath(argv[0], NULL, &appname);
00433 } else {
00434 appname = "ncbi";
00435 }
00436 }
00437 if ( m_ProgramDisplayName.empty() ) {
00438 SetProgramDisplayName(appname);
00439 }
00440
00441
00442
00443 if ( exepath.empty() ) {
00444 ERR_POST_X(3, Warning
00445 << "Warning: Could not determine this application's "
00446 "file name and location. Using \""
00447 << appname << "\" instead.\n"
00448 "Please fix FindProgramExecutablePath() on this platform.");
00449 exepath = appname;
00450 }
00451
00452 #if defined(NCBI_OS_DARWIN)
00453
00454
00455
00456 s_MacArgMunging(*this, &argc, &argv, exepath);
00457 #endif
00458
00459
00460 if (PreparseArgs(argc, argv) == ePreparse_Exit) {
00461 GetDiagContext().DiscardMessages();
00462 return 0;
00463 }
00464
00465
00466
00467 bool is_diag_setup = false;
00468 if (!m_DisableArgDesc && argc > 1 && argv) {
00469 const char** v = new const char*[argc];
00470 v[0] = argv[0];
00471 int real_arg_index = 1;
00472 for (int i = 1; i < argc; i++) {
00473 if ( !argv[i] ) {
00474 continue;
00475 }
00476
00477
00478 if ( diag != eDS_User &&
00479 NStr::strcmp(argv[i], s_ArgLogFile) == 0 ) {
00480 if ( !argv[i++] ) {
00481 continue;
00482 }
00483 v[real_arg_index++] = argv[i - 1];
00484 v[real_arg_index++] = argv[i];
00485 if (SetLogFile(argv[i], eDiagFile_All, true)) {
00486 diag = eDS_User;
00487 is_diag_setup = true;
00488 }
00489
00490 } else if ( NStr::strcmp(argv[i], s_ArgCfgFile) == 0 ) {
00491 if ( !argv[i++] ) {
00492 continue;
00493 }
00494 v[real_arg_index++] = argv[i - 1];
00495 v[real_arg_index++] = argv[i];
00496 conf = argv[i];
00497
00498
00499 } else if ( NStr::strcmp(argv[i], s_ArgVersion) == 0 ) {
00500 if ( !argv[i++] ) {
00501 continue;
00502 }
00503
00504 cout << GetFullVersion().Print( appname,
00505 CVersion::fVersionInfo | CVersion::fPackageShort );
00506 GetDiagContext().DiscardMessages();
00507 return 0;
00508
00509
00510 } else if ( NStr::strcmp(argv[i], s_ArgFullVersion) == 0 ) {
00511 if ( !argv[i++] ) {
00512 continue;
00513 }
00514
00515 cout << GetFullVersion().Print( appname );
00516 GetDiagContext().DiscardMessages();
00517 return 0;
00518
00519
00520 } else if ( NStr::strcmp(argv[i], s_ArgDryRun) == 0 ) {
00521 m_DryRun = true;
00522
00523
00524 } else {
00525 v[real_arg_index++] = argv[i];
00526 }
00527 }
00528 if (real_arg_index == argc ) {
00529 delete[] v;
00530 } else {
00531 argc = real_arg_index;
00532 argv = v;
00533 }
00534 }
00535
00536
00537 m_Arguments->Reset(argc, argv, exepath, m_RealExePath);
00538
00539
00540 m_Environ->Reset(envp);
00541
00542
00543 if ( !m_Environ->Get(DIAG_TRACE).empty() ) {
00544 SetDiagTrace(eDT_Enable, eDT_Enable);
00545 }
00546 string post_level = m_Environ->Get(DIAG_POST_LEVEL);
00547 if ( !post_level.empty() ) {
00548 EDiagSev sev;
00549 if (CNcbiDiag::StrToSeverityLevel(post_level.c_str(), sev)) {
00550 SetDiagFixedPostLevel(sev);
00551 }
00552 }
00553 if ( !m_Environ->Get(ABORT_ON_THROW).empty() ) {
00554 SetThrowTraceAbort(true);
00555 }
00556
00557
00558 m_Config->Clear();
00559
00560
00561 try {
00562 if ( !is_diag_setup ) {
00563 CDiagContext::SetupDiag(diag);
00564 }
00565 } catch (CException& e) {
00566 NCBI_RETHROW(e, CAppException, eSetupDiag,
00567 "Application diagnostic stream's setup failed");
00568 } catch (exception& e) {
00569 NCBI_THROW(CAppException, eSetupDiag,
00570 "Application diagnostic stream's setup failed: " +
00571 string(e.what()));
00572 }
00573
00574
00575 int exit_code = 1;
00576 bool got_exception = false;
00577 s_IsApplicationStarted = true;
00578
00579 if ( s_HandleExceptions() ) {
00580 try {
00581 x_TryMain(diag, conf, &exit_code, &got_exception);
00582 }
00583 catch (CArgException& e) {
00584
00585 if ( m_ArgDesc.get() ) {
00586 x_AddDefaultArgs();
00587 string str;
00588 LOG_POST_X(9, m_ArgDesc->PrintUsage(str) << string(72, '='));
00589 }
00590 NCBI_REPORT_EXCEPTION_X(18, "", e);
00591 got_exception = true;
00592 exit_code = 1;
00593 }
00594 #if defined(NCBI_COMPILER_MSVC) && defined(_DEBUG)
00595
00596
00597
00598
00599
00600 catch (...) {
00601 ERR_POST_X(10, Warning <<
00602 "Application has thrown an exception of unknown type");
00603 throw;
00604 }
00605 #endif
00606 }
00607 else {
00608 x_TryMain(diag, conf, &exit_code, &got_exception);
00609 }
00610
00611 if (m_ExitCodeCond == eAllExits
00612 || (got_exception && m_ExitCodeCond == eExceptionalExits)) {
00613 _TRACE("Overriding exit code from " << exit_code
00614 << " to " << m_ExitCodeCond);
00615 exit_code = m_ExitCode;
00616 }
00617
00618
00619 AppStop(exit_code);
00620
00621
00622 return exit_code;
00623 }
00624
00625
00626 void CNcbiApplication::SetEnvironment(const string& name, const string& value)
00627 {
00628 SetEnvironment().Set(name, value);
00629 }
00630
00631
00632 void CNcbiApplication::SetVersion(const CVersionInfo& version)
00633 {
00634 if ( s_IsApplicationStarted ) {
00635 ERR_POST_X(19, "SetVersion() should be used from constructor of " \
00636 "CNcbiApplication derived class, see description");
00637 }
00638 m_Version->SetVersionInfo( new CVersionInfo(version) );
00639 }
00640
00641 void CNcbiApplication::SetFullVersion( CRef<CVersion> version)
00642 {
00643 if ( s_IsApplicationStarted ) {
00644 ERR_POST_X(19, "SetFullVersion() should be used from constructor of "\
00645 "CNcbiApplication derived class, see description");
00646 }
00647 m_Version.Reset( version );
00648 }
00649
00650
00651 CVersionInfo CNcbiApplication::GetVersion(void) const
00652 {
00653 return m_Version->GetVersionInfo();
00654 }
00655
00656 const CVersion& CNcbiApplication::GetFullVersion(void) const
00657 {
00658 return *m_Version;
00659 }
00660
00661
00662 void CNcbiApplication::SetupArgDescriptions(CArgDescriptions* arg_desc)
00663 {
00664 m_ArgDesc.reset(arg_desc);
00665
00666 if ( arg_desc ) {
00667 if ( !m_DisableArgDesc ) {
00668
00669 if ((m_HideArgs & fHideLogfile) == 0 &&
00670 !m_ArgDesc->Exist(s_ArgLogFile + 1) ) {
00671 m_ArgDesc->AddOptionalKey
00672 (s_ArgLogFile+1, "File_Name",
00673 "File to which the program log should be redirected",
00674 CArgDescriptions::eOutputFile);
00675 }
00676 if ((m_HideArgs & fHideConffile) == 0 &&
00677 !m_ArgDesc->Exist(s_ArgCfgFile + 1) ) {
00678 if (m_DefaultConfig.empty()) {
00679 m_ArgDesc->AddOptionalKey
00680 (s_ArgCfgFile + 1, "File_Name",
00681 "Program's configuration (registry) data file",
00682 CArgDescriptions::eInputFile);
00683 } else {
00684 m_ArgDesc->AddDefaultKey
00685 (s_ArgCfgFile + 1, "File_Name",
00686 "Program's configuration (registry) data file",
00687 CArgDescriptions::eInputFile,
00688 m_DefaultConfig);
00689 }
00690 }
00691 }
00692 m_Args.reset(arg_desc->CreateArgs(GetArguments()));
00693 } else {
00694 m_Args.reset();
00695 }
00696 }
00697
00698
00699 bool CNcbiApplication::SetupDiag(EAppDiagStream diag)
00700 {
00701 CDiagContext::SetupDiag(diag, 0, eDCM_Flush);
00702 return true;
00703 }
00704
00705
00706 bool CNcbiApplication::SetupDiag_AppSpecific(void)
00707 {
00708 CDiagContext::SetupDiag(eDS_ToStderr, 0, eDCM_Flush);
00709 return true;
00710 }
00711
00712
00713 bool CNcbiApplication::LoadConfig(CNcbiRegistry& reg,
00714 const string* conf,
00715 CNcbiRegistry::TFlags reg_flags)
00716 {
00717 string basename (m_Arguments->GetProgramBasename(eIgnoreLinks));
00718 string basename2(m_Arguments->GetProgramBasename(eFollowLinks));
00719 CMetaRegistry::SEntry entry;
00720
00721 if ( !conf ) {
00722 return false;
00723 } else if (conf->empty()) {
00724 entry = CMetaRegistry::Load(basename, CMetaRegistry::eName_Ini, 0,
00725 reg_flags, ®);
00726 if ( !entry.registry && basename2 != basename ) {
00727 entry = CMetaRegistry::Load(basename2, CMetaRegistry::eName_Ini, 0,
00728 reg_flags, ®);
00729 }
00730 m_DefaultConfig = CDirEntry(entry.actual_name).GetName();
00731 } else {
00732 entry = CMetaRegistry::Load(*conf, CMetaRegistry::eName_AsIs, 0,
00733 reg_flags, ®);
00734 }
00735 if ( !entry.registry ) {
00736
00737 string dir;
00738 CDirEntry::SplitPath(*conf, &dir, 0, 0);
00739 if (dir.empty()) {
00740 ERR_POST_X(11, Warning <<
00741 "Registry file of application \"" << basename
00742 << "\" is not found");
00743 } else {
00744 NCBI_THROW(CAppException, eNoRegistry,
00745 "Registry file \"" + *conf + "\" cannot be opened");
00746 }
00747
00748 reg.IncludeNcbircIfAllowed(reg_flags);
00749 return false;
00750 } else if (entry.registry != static_cast<IRWRegistry*>(®)) {
00751
00752 if (® == m_Config && reg.Empty()) {
00753 m_Config.Reset(dynamic_cast<CNcbiRegistry*>
00754 (entry.registry.GetPointer()));
00755 } else {
00756
00757 CNcbiStrstream str;
00758 entry.registry->Write(str);
00759 str.seekg(0);
00760 reg.Read(str);
00761 }
00762 }
00763 m_ConfigPath = entry.actual_name;
00764 return true;
00765 }
00766
00767
00768 bool CNcbiApplication::LoadConfig(CNcbiRegistry& reg,
00769 const string* conf)
00770 {
00771 return LoadConfig(reg, conf, IRegistry::fWithNcbirc);
00772 }
00773
00774
00775 CNcbiApplication::EPreparseArgs
00776 CNcbiApplication::PreparseArgs(int ,
00777 const char* const* )
00778 {
00779 return ePreparse_Continue;
00780 }
00781
00782
00783 void CNcbiApplication::DisableArgDescriptions(TDisableArgDesc disable)
00784 {
00785 m_DisableArgDesc = disable;
00786 }
00787
00788
00789 void CNcbiApplication::HideStdArgs(THideStdArgs hide_mask)
00790 {
00791 m_HideArgs = hide_mask;
00792 }
00793
00794
00795 void CNcbiApplication::SetStdioFlags(TStdioSetupFlags stdio_flags)
00796 {
00797
00798
00799 _ASSERT(m_StdioFlags == 0);
00800 m_StdioFlags = stdio_flags;
00801 }
00802
00803
00804 void CNcbiApplication::x_SetupStdio(void)
00805 {
00806 #if 1
00807 // CAUTION: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26777
00808
00809 if ((m_StdioFlags & fDefault_SyncWithStdio) == 0) {
00810
00811
00812
00813
00814 IOS_BASE::sync_with_stdio(false);
00815 }
00816 #endif
00817
00818 if ((m_StdioFlags & fDefault_CinBufferSize) == 0
00819 #ifdef NCBI_OS_UNIX
00820 && !isatty(0)
00821 #endif
00822 ) {
00823 #if defined(NCBI_COMPILER_GCC) && defined(NCBI_OS_SOLARIS)
00824 # if NCBI_COMPILER_VERSION >= 300
00825 _ASSERT(!m_CinBuffer);
00826
00827 const size_t kCinBufSize = 5120;
00828 m_CinBuffer = new char[kCinBufSize];
00829 cin.rdbuf()->pubsetbuf(m_CinBuffer, kCinBufSize);
00830 # endif
00831 #endif
00832 }
00833 #ifdef NCBI_OS_MSWIN
00834 if ((m_StdioFlags & fBinaryCin) != 0) {
00835 setmode(fileno(stdin), O_BINARY);
00836 }
00837 if ((m_StdioFlags & fBinaryCout) != 0) {
00838 setmode(fileno(stdout), O_BINARY);
00839 }
00840 #endif
00841 }
00842
00843 void CNcbiApplication::x_AddDefaultArgs(void)
00844 {
00845 if ( !m_DisableArgDesc ) {
00846 if (m_ArgDesc->IsAutoHelpEnabled()) {
00847 if ((m_HideArgs & fHideHelp) != 0) {
00848 if (m_ArgDesc->Exist("h")) {
00849 m_ArgDesc->Delete("h");
00850 }
00851 }
00852 }
00853 if ((m_HideArgs & fHideFullHelp) != 0) {
00854 if (m_ArgDesc->Exist("help")) {
00855 m_ArgDesc->Delete("help");
00856 }
00857 }
00858 if ((m_HideArgs & fHideXmlHelp) != 0) {
00859 if (m_ArgDesc->Exist("xmlhelp")) {
00860 m_ArgDesc->Delete("xmlhelp");
00861 }
00862 }
00863 if ((m_HideArgs & fHideLogfile) == 0 &&
00864 !m_ArgDesc->Exist(s_ArgLogFile + 1)) {
00865 m_ArgDesc->AddOptionalKey
00866 (s_ArgLogFile+1, "File_Name",
00867 "File to which the program log should be redirected",
00868 CArgDescriptions::eOutputFile);
00869 }
00870 if ((m_HideArgs & fHideConffile) == 0 &&
00871 !m_ArgDesc->Exist(s_ArgCfgFile + 1)) {
00872 m_ArgDesc->AddOptionalKey
00873 (s_ArgCfgFile + 1, "File_Name",
00874 "Program's configuration (registry) data file",
00875 CArgDescriptions::eInputFile);
00876 }
00877 if ((m_HideArgs & fHideVersion) == 0 &&
00878 !m_ArgDesc->Exist(s_ArgVersion + 1)) {
00879 m_ArgDesc->AddFlag
00880 (s_ArgVersion + 1,
00881 "Print version number; ignore other arguments");
00882 }
00883 if ((m_HideArgs & fHideFullVersion) == 0 &&
00884 !m_ArgDesc->Exist(s_ArgFullVersion + 1)) {
00885 m_ArgDesc->AddFlag
00886 (s_ArgFullVersion + 1,
00887 "Print extended version data; ignore other arguments");
00888 }
00889 if ((m_HideArgs & fHideDryRun) == 0 &&
00890 !m_ArgDesc->Exist(s_ArgDryRun + 1)) {
00891 m_ArgDesc->AddFlag
00892 (s_ArgDryRun + 1,
00893 "Dry run the application: do nothing, only test all preconditions");
00894 }
00895 }
00896 }
00897
00898 void CNcbiApplication::SetProgramDisplayName(const string& app_name)
00899 {
00900 m_ProgramDisplayName = app_name;
00901
00902 if ( GetDiagContext().GetAppName().empty() ) {
00903 GetDiagContext().SetAppName(app_name);
00904 }
00905 }
00906
00907
00908 string CNcbiApplication::FindProgramExecutablePath
00909 (int _DEBUG_ARG(argc),
00910 const char* const* argv,
00911 string* real_path)
00912 {
00913 string ret_val;
00914 #if defined(NCBI_OS_MSWIN) || defined(NCBI_OS_UNIX)
00915
00916 # ifdef NCBI_OS_MSWIN
00917
00918
00919 try {
00920
00921 CDll dll_psapi("psapi.dll", CDll::eLoadNow, CDll::eAutoUnload);
00922
00923
00924 BOOL (STDMETHODCALLTYPE FAR * dllEnumProcessModules)
00925 (HANDLE hProcess,
00926 HMODULE *lphModule,
00927 DWORD cb,
00928 LPDWORD lpcbNeeded
00929 ) = NULL;
00930
00931 dllEnumProcessModules =
00932 dll_psapi.GetEntryPoint_Func("EnumProcessModules",
00933 &dllEnumProcessModules);
00934 if ( !dllEnumProcessModules ) {
00935 NCBI_THROW(CException, eUnknown, kEmptyStr);
00936 }
00937
00938
00939 HANDLE process = GetCurrentProcess();
00940 HMODULE module = 0;
00941 DWORD needed = 0;
00942
00943
00944 if ( dllEnumProcessModules(process,
00945 &module, sizeof(HMODULE), &needed) ) {
00946 if ( needed && module ) {
00947 char buf[MAX_PATH + 1];
00948 DWORD ncount = GetModuleFileName(module, buf, MAX_PATH);
00949 if (ncount > 0) {
00950 ret_val.assign(buf, ncount);
00951 if (real_path) {
00952 *real_path = CDirEntry::NormalizePath(ret_val,
00953 eFollowLinks);
00954 }
00955 return ret_val;
00956 }
00957 }
00958 }
00959 }
00960 catch (CException) {
00961 ;
00962 }
00963
00964 # endif
00965
00966 # ifdef NCBI_OS_LINUX
00967
00968 if (real_path) {
00969 char buf[PATH_MAX + 1];
00970 string procfile = "/proc/" + NStr::IntToString(getpid()) + "/exe";
00971 int ncount = readlink((procfile).c_str(), buf, PATH_MAX);
00972 if (ncount > 0) {
00973 real_path->assign(buf, ncount);
00974 real_path = 0;
00975 }
00976 }
00977 # endif
00978
00979 _ASSERT(argc && argv);
00980 string app_path = argv[0];
00981
00982 if ( !CDirEntry::IsAbsolutePath(app_path) ) {
00983 # ifdef NCBI_OS_MSWIN
00984
00985
00986 string dir, title, ext;
00987 CDirEntry::SplitPath(app_path, &dir, &title, &ext);
00988 if ( ext.empty() ) {
00989 app_path = CDirEntry::MakePath(dir, title, "exe");
00990 }
00991 # endif
00992 if ( CFile(app_path).Exists() ) {
00993
00994 app_path = CDir::GetCwd() + CDirEntry::GetPathSeparator()+app_path;
00995 if ( !CFile(app_path).Exists() ) {
00996 app_path = kEmptyStr;
00997 }
00998 } else {
00999
01000
01001 string env_path = GetEnvironment().Get("PATH");
01002 list<string> split_path;
01003 # ifdef NCBI_OS_MSWIN
01004 NStr::Split(env_path, ";", split_path);
01005 # else
01006 NStr::Split(env_path, ":", split_path);
01007 # endif
01008 string base_name = CDirEntry(app_path).GetBase();
01009 ITERATE(list<string>, it, split_path) {
01010 app_path = CDirEntry::MakePath(*it, base_name);
01011 if ( CFile(app_path).Exists() ) {
01012 break;
01013 }
01014 app_path = kEmptyStr;
01015 }
01016 }
01017 }
01018 ret_val = CDirEntry::NormalizePath(app_path.empty() ? argv[0] : app_path);
01019
01020 #else // defined (NCBI_OS_MSWIN) || defined(NCBI_OS_UNIX)
01021
01022 # error "Unsupported platform, sorry -- please contact NCBI"
01023 #endif
01024 if (real_path) {
01025 *real_path = CDirEntry::NormalizePath(ret_val, eFollowLinks);
01026 }
01027 return ret_val;
01028 }
01029
01030
01031 void CNcbiApplication::x_HonorStandardSettings( IRegistry* reg)
01032 {
01033 if (reg == 0) {
01034 reg = m_Config.GetPointer();
01035 if (reg == 0)
01036 return;
01037 }
01038
01039
01040 CObject::SetAllocFillMode(reg->Get("NCBI", "MEMORY_FILL"));
01041
01042 {{
01043 CSysLog* syslog = dynamic_cast<CSysLog*>(GetDiagHandler());
01044 if (syslog) {
01045 syslog->HonorRegistrySettings(reg);
01046 }
01047 }}
01048
01049
01050
01051
01052 if ( !reg->Get("DEBUG", DIAG_TRACE).empty() ) {
01053 SetDiagTrace(eDT_Enable, eDT_Enable);
01054 }
01055
01056
01057 if ( !reg->Get("DEBUG", ABORT_ON_THROW).empty() ) {
01058 SetThrowTraceAbort(true);
01059 }
01060
01061
01062 string post_level = reg->Get("DEBUG", DIAG_POST_LEVEL);
01063 if ( !post_level.empty() ) {
01064 EDiagSev sev;
01065 if (CNcbiDiag::StrToSeverityLevel(post_level.c_str(), sev)) {
01066 SetDiagFixedPostLevel(sev);
01067 }
01068 }
01069
01070
01071 string msg_file = reg->Get("DEBUG", DIAG_MESSAGE_FILE);
01072 if ( !msg_file.empty() ) {
01073 CDiagErrCodeInfo* info = new CDiagErrCodeInfo();
01074 if ( !info || !info->Read(msg_file) ) {
01075 if ( info ) {
01076 delete info;
01077 }
01078 ERR_POST_X(12, Warning << "Applications message file \""
01079 << msg_file
01080 << "\" is not found");
01081 } else {
01082 SetDiagErrCodeInfo(info);
01083 }
01084 }
01085
01086
01087
01088
01089 if ( !reg->Get("NCBI", "HeapSizeLimit").empty() ) {
01090 int heap_size_limit = reg->GetInt("NCBI", "HeapSizeLimit", 0);
01091 if (heap_size_limit < 0) {
01092 NCBI_THROW(CAppException, eLoadConfig,
01093 "Configuration file error: [NCBI.HeapSizeLimit] < 0");
01094 }
01095 heap_size_limit *= 1024 * 1024;
01096 if ( !SetHeapLimit(heap_size_limit) ) {
01097 ERR_POST_X(13, Warning
01098 << "Failed to set the heap size limit to "
01099 << heap_size_limit
01100 << "Mb (as per the config param [NCBI.HeapSizeLimit])");
01101 }
01102 }
01103
01104
01105 if ( !reg->Get("NCBI", "CpuTimeLimit").empty() ) {
01106 int cpu_time_limit = reg->GetInt("NCBI", "CpuTimeLimit", 0);
01107 if (cpu_time_limit < 0) {
01108 NCBI_THROW(CAppException, eLoadConfig,
01109 "Configuration file error: [NCBI.CpuTimeLimit] < 0");
01110 }
01111 if ( !SetCpuTimeLimit(cpu_time_limit) ) {
01112 ERR_POST_X(14, Warning
01113 << "Failed to set the CPU time limit to "
01114 << cpu_time_limit
01115 << " sec (as per the config param [NCBI.CpuTimeLimit])");
01116 }
01117 }
01118
01119
01120
01121
01122 string trace_filter = reg->Get("DIAG", "TRACE_FILTER");
01123 if ( !trace_filter.empty() )
01124 SetDiagFilter(eDiagFilter_Trace, trace_filter.c_str());
01125
01126
01127 string post_filter = reg->Get("DIAG", "POST_FILTER");
01128 if ( !post_filter.empty() )
01129 SetDiagFilter(eDiagFilter_Post, post_filter.c_str());
01130 }
01131
01132
01133 void CNcbiApplication::AppStart(void)
01134 {
01135 string cmd_line = GetProgramExecutablePath();
01136 if ( m_Arguments.get() ) {
01137 if ( cmd_line.empty() ) {
01138 cmd_line = (*m_Arguments)[0];
01139 }
01140 for (SIZE_TYPE arg = 1; arg < m_Arguments->Size(); ++arg) {
01141 cmd_line += " ";
01142 cmd_line += (*m_Arguments)[arg];
01143 }
01144 }
01145
01146
01147 if ( !CDiagContext::IsSetOldPostFormat() ) {
01148 GetDiagContext().PrintStart(NStr::PrintableString(cmd_line));
01149 }
01150 }
01151
01152
01153 void CNcbiApplication::AppStop(int exit_code)
01154 {
01155 GetDiagContext().SetExitCode(exit_code);
01156 }
01157
01158
01159 void CNcbiApplication::SetExitCode(int exit_code, EExitMode when)
01160 {
01161 m_ExitCode = exit_code;
01162 m_ExitCodeCond = when;
01163 }
01164
01165 const char* CAppException::GetErrCodeString(void) const
01166 {
01167 switch (GetErrCode()) {
01168 case eUnsetArgs: return "eUnsetArgs";
01169 case eSetupDiag: return "eSetupDiag";
01170 case eLoadConfig: return "eLoadConfig";
01171 case eSecond: return "eSecond";
01172 case eNoRegistry: return "eNoRegistry";
01173 default: return CException::GetErrCodeString();
01174 }
01175 }
01176
01177
01178 void CDefaultIdler::Idle(void)
01179 {
01180 DiagHandler_Reopen();
01181 }
01182
01183
01184 class CIdlerWrapper
01185 {
01186 public:
01187 CIdlerWrapper(void) : m_Idler(new CDefaultIdler()) {}
01188 ~CIdlerWrapper(void) {}
01189
01190 INcbiIdler* GetIdler(EOwnership own);
01191 void SetIdler(INcbiIdler* idler, EOwnership own);
01192 void RunIdler(void);
01193
01194 private:
01195 CMutex m_Mutex;
01196 AutoPtr<INcbiIdler> m_Idler;
01197 };
01198
01199
01200 inline
01201 INcbiIdler* CIdlerWrapper::GetIdler(EOwnership own)
01202 {
01203 CMutexGuard guard(m_Mutex);
01204 m_Idler.reset(m_Idler.release(), own);
01205 return m_Idler.get();
01206 }
01207
01208
01209 inline
01210 void CIdlerWrapper::SetIdler(INcbiIdler* idler, EOwnership own)
01211 {
01212 CMutexGuard guard(m_Mutex);
01213 m_Idler.reset(idler, own);
01214 }
01215
01216
01217 inline
01218 void CIdlerWrapper::RunIdler(void)
01219 {
01220 if ( m_Idler.get() ) {
01221 CMutexGuard guard(m_Mutex);
01222 if ( m_Idler.get() ) {
01223 m_Idler->Idle();
01224 }
01225 }
01226 }
01227
01228
01229 CSafeStaticPtr<CIdlerWrapper> s_IdlerWrapper;
01230
01231 INcbiIdler* GetIdler(EOwnership ownership)
01232 {
01233 return s_IdlerWrapper.Get().GetIdler(ownership);
01234 }
01235
01236
01237 void SetIdler(INcbiIdler* idler, EOwnership ownership)
01238 {
01239 s_IdlerWrapper.Get().SetIdler(idler, ownership);
01240 }
01241
01242
01243 void RunIdler(void)
01244 {
01245 s_IdlerWrapper.Get().RunIdler();
01246 }
01247
01248
01249 END_NCBI_SCOPE
01250
01251