00001
00002
00003 #include "Iguana/Framework/interface/IgApplication.h"
00004 #include "Iguana/Framework/interface/IgLibraryPreloader.h"
00005 #include "Iguana/Framework/interface/IgOnCrashService.h"
00006 #include "Iguana/Framework/interface/IgOnLowMemoryService.h"
00007 #include "Iguana/Framework/interface/IgDriverDB.h"
00008 #include "Iguana/Framework/interface/IgPluginLoader.h"
00009 #include "Iguana/Framework/interface/IgArgsElement.h"
00010 #include "Iguana/Framework/interface/IgEnvsElement.h"
00011 #include "Iguana/Framework/interface/IgDriver.h"
00012 #include "Iguana/Framework/interface/IgState.h"
00013 #include "Iguana/Framework/interface/IgModule.h"
00014 #include "Iguana/Framework/interface/IgModuleCache.h"
00015 #include "Iguana/Framework/interface/IgModuleDescriptor.h"
00016 #include "classlib/utils/SearchPath.h"
00017 #include "classlib/utils/StringOps.h"
00018 #include "classlib/utils/DebugAids.h"
00019 #include "classlib/utils/TimeInfo.h"
00020 #include "classlib/utils/Signal.h"
00021 #include "classlib/utils/Error.h"
00022 #include <typeinfo>
00023 #include <exception>
00024 #include <algorithm>
00025 #include <iostream>
00026 #include <utility>
00027 #include <cstdlib>
00028 #include <cstring>
00029 #include <set>
00030
00031
00032
00033 #define IGUANA_APP "iguana"
00034 #define IGUANA_VERSION "undefined"
00035 #define IGUANA_UNAME "undefined"
00036 #define IGUANA_HOST "undefined"
00037 #define IGUANA_CXX "undefined"
00038 #define IGUANA_COMPILER "undefined"
00039 #define IGUANA_WHO "undefined"
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 IgApplication::IgApplication (void)
00051 : m_verbose (false),
00052 m_state (0),
00053 m_driver (0),
00054 m_argc (-1),
00055 m_argv (0),
00056 m_appname (0),
00057 m_all (false)
00058 {}
00059
00060 IgApplication::~IgApplication (void)
00061 {}
00062
00063 IgState *
00064 IgApplication::state (void) const
00065 { return m_state; }
00066
00067 const char *
00068 IgApplication::driver (void) const
00069 { return m_driver; }
00070
00071 const char *
00072 IgApplication::appname (void) const
00073 {
00074 const char *name = m_appname;
00075 if (const char *ptr = strrchr (name, '/'))
00076 name = ptr + 1;
00077 return name;
00078 }
00079
00080 bool
00081 IgApplication::verbose (void) const
00082 { return m_verbose; }
00083
00084 int
00085 IgApplication::argc (void) const
00086 { return m_argc; }
00087
00088 char **
00089 IgApplication::argv (void) const
00090 { return m_argv; }
00091
00093 int
00094 IgApplication::run (int argc, char *argv[])
00095 {
00096 lat::TimeInfo::init ();
00097 initDebugging (argv [0]);
00098
00099 bool list = false;
00100 bool help = false;
00101 char defDriver [] = { "IGUANA" };
00102 m_driver = defDriver;
00103 m_appname = argv [0];
00104
00105 if (char *preloads = ::getenv ("IGUANA_PRELOADS"))
00106 {
00107 char *start = preloads;
00108 char *end = strchr (start, ':');
00109 for ( ; end; start = end + 1, end = strchr (start, ':'))
00110 if (end - start)
00111 m_preload.push_back (std::string (start, end - start));
00112
00113 if (*start)
00114 m_preload.push_back (start);
00115 }
00116
00117 int i = 1;
00118
00119 while (*++argv && argv [0][0] == '-')
00120 {
00121 i++;
00122 if (!strcmp (*argv, "--list"))
00123 {
00124 list = true;
00125 if ((i < argc) && (!strcmp (*++argv, "all")))
00126 m_all = true;
00127 }
00128 else if (!strcmp (*argv, "--version"))
00129 {
00130 std::cout << "IGUANA " IGUANA_VERSION " (" IGUANA_HOST ")\n\n"
00131 << "Built by " IGUANA_WHO " on " __DATE__ " " __TIME__ " as:\n"
00132 << " " IGUANA_UNAME "\n"
00133 << " " IGUANA_CXX " (" IGUANA_COMPILER ")\n";
00134 return EXIT_SUCCESS;
00135 }
00136 else if (!strcmp (*argv, "--help"))
00137 help = true;
00138 else if (!strcmp (*argv, "--profile"))
00139 startProfiler ();
00140 else if (!strcmp (*argv, "--memstats"))
00141 startMemStats ();
00142 else if (!strcmp (*argv, "--driver") || !strcmp (*argv, "-D"))
00143 {
00144 if (! *++argv)
00145 {
00146 help = true;
00147 std::cerr << "--driver requires an argument\n";
00148 }
00149 else
00150 m_driver = *argv;
00151 }
00152 else if (!strcmp (*argv, "--verbose"))
00153 m_verbose = true;
00154 else if (!strcmp (*argv, "--preload"))
00155 {
00156 if (! *++argv)
00157 {
00158 help = true;
00159 std::cerr << "--preload requires an argument\n";
00160 }
00161 else
00162 m_preload.push_back (*argv);
00163 }
00164 else
00165
00166 break;
00167 }
00168
00169
00170
00171
00172 lat::Filename fakeApp (m_appname, m_driver);
00173 m_argc = argc;
00174 m_argv = new char *[m_argc+1];
00175 m_argv [0] = const_cast<char *> (static_cast<const char *> (fakeApp));
00176 for (m_argc = 1; *argv; ++argv, ++m_argc)
00177 m_argv [m_argc] = *argv;
00178 m_argv [m_argc] = 0;
00179
00180
00181 if (help || (! list && ! m_driver))
00182 return usage ();
00183
00184
00185 int status;
00186 IgLibraryPreloader loader (m_argv [0], m_verbose);
00187 std::for_each (m_preload.begin (), m_preload.end (), loader);
00188 if ((status = loader.status ()) != EXIT_SUCCESS)
00189 return status;
00190
00191
00192 if ((status = initDatabase ()) != EXIT_SUCCESS)
00193 return status;
00194
00195
00196 if ((status = initState ()) != EXIT_SUCCESS)
00197 return status;
00198
00199
00200
00201 status = (!list ? loadDriver () : dumpDatabase ());
00202
00203 if (m_verbose)
00204
00205
00206
00207
00208
00209 std::cout << "\nThanks for using " IGUANA_APP " " IGUANA_VERSION "!"
00210 << (lat::Signal::crashed () ? " (We apologize for the inconvenience.)"
00211 : "") << std::endl
00212 << IGUANA_APP " took "
00213 << lat::TimeInfo::processUserTime () * 1e-9 << "s user, "
00214 << lat::TimeInfo::processSystemTime () * 1e-9 << "s system, "
00215 << lat::TimeInfo::processRealTime () * 1e-9 << "s real ("
00216 << lat::TimeInfo::processIdleTime () * 1e-9 << "s idle)\n";
00217
00218 return status;
00219 }
00220
00221 void
00222 IgApplication::startProfiler (void)
00223 {
00224 #ifdef __linux
00225 try
00226 {
00227 if (! getenv ("JPROF_FLAGS"))
00228 {
00229 static char value [] = "JPROF_FLAGS=JP_START JP_PERIOD=.0015";
00230 putenv (value);
00231 }
00232
00233 lat::SharedLibrary *lib = lat::SharedLibrary::load (std::string ("libJProfLib.so"));
00234 void (*func) (void) = lib->function ("setupProfilingStuff");
00235 (*func) ();
00236 }
00237 catch (lat::Error &error)
00238 {
00239 std::cerr << "Cannot load or initialise jprof runtime\n";
00240 std::cerr << "Error was: " << error.explain () << "\n";
00241 }
00242 #else
00243 std::cerr << "Profiling not available on this platform. Continuing without.\n";
00244 #endif
00245 }
00246
00247 void
00248 IgApplication::startMemStats (void)
00249 {
00250 #ifdef __linux
00251 try
00252 {
00253 lat::SharedLibrary::load (std::string ("libMemProfLib.so"));
00254 }
00255 catch (lat::Error &error)
00256 {
00257 std::cerr << "Cannot load or initialise memprof runtime\n";
00258 std::cerr << "Error was: " << error.explain () << "\n";
00259 }
00260 #else
00261 std::cerr << "Memory profiling not available on this platform. Continuing without.\n";
00262 #endif
00263 }
00264
00265 int
00266 IgApplication::initDebugging (const char *appname)
00267 {
00268
00269 if (! IgOnCrashService::init (appname))
00270 return EXIT_FAILURE;
00271
00272 if (! IgOnLowMemoryService::init (appname))
00273 return EXIT_FAILURE;
00274
00275 return EXIT_SUCCESS;
00276 }
00277
00278 int
00279 IgApplication::initState (void)
00280 {
00281
00282 m_state = new IgState;
00283 new IgArgsElement (m_state, m_argc, m_argv);
00284 new IgEnvsElement (m_state);
00285 new IgPluginLoader (m_state);
00286 return EXIT_SUCCESS;
00287 }
00288
00289 int
00290 IgApplication::usage (void)
00291 {
00292 const char *app = appname ();
00293
00294 std::cerr << "Usage: " << app << " --help\n"
00295 << " or: " << app << " --version\n"
00296 << " or: " << app << " --list [all]\n"
00297 << " or: " << app
00298 << " [--verbose] [--preload LIBRARY]... [--profile] [--memstats]\n"
00299 << " [--driver|-D DRIVER] [DRIVER-OPTIONS...]\n\n"
00300 << "The $IGUANA_PLUGINS environment variable should be set to point to\n"
00301 << "the module registration directories, with directories separated\n"
00302 << "'" << lat::SearchPath::separator () << "' as with normal paths.\n\n"
00303 << "If no DRIVER is given, It will attempt to load `IGUANA'.\n"
00304 << "'IGUANA' DRIVER-OPTIONS are .....\n"
00305 << " [--iguana-session|-is <iguana-session>]\n\n"
00306 << "where '<iguana-session>' could be the name of any studio session type e.g.\n"
00307 << "'Vis Example--Qt Demo' or 'Vis Example--Open Inventor File Reader' etc.\n\n"
00308 << "One can also use the '; ' separated short names e.g. 'IvReader'\n\n"
00309 << "'IvReader' also support an optional command-line argument\n"
00310 << " [--ivfile|-iv <ivfile>]\n"
00311 << "for loading an open inventor IV file in the IV Reader.\n";
00312
00313 return EXIT_FAILURE;
00314 }
00315
00316 int
00317 IgApplication::initDatabase (void)
00318 {
00319 IgPluginManager::get ()->addFeedback
00320 (lat::CreateCallback (this, &IgApplication::pluginFeedback));
00321 IgPluginManager::get ()->initialise ();
00322 return EXIT_SUCCESS;
00323 }
00324
00325 void
00326 IgApplication::pluginFeedback (IgPluginManager::FeedbackData data)
00327 {
00328 std::string explanation;
00329 if (data.error)
00330 explanation = lat::StringOps::replace (data.error->explain (), '\n', "\n\t");
00331
00332 if (data.code == IgPluginManager::StatusLoading)
00333 std::cerr << "Info: Loading module " << data.scope << "\n";
00334
00335 else if (data.code == IgPluginManager::ErrorLoadFailure)
00336 std::cerr << " *** WARNING: module `" << data.scope
00337 << "' failed to load for the following reason\n\t"
00338 << explanation << "\n";
00339
00340 else if (data.code == IgPluginManager::ErrorBadModule)
00341 std::cerr << " *** WARNING: module `" << data.scope
00342 << "' ignored until problems with it are fixed.\n\n";
00343
00344 else if (data.code == IgPluginManager::ErrorBadCacheFile)
00345 std::cerr << " *** WARNING: cache file " << data.scope
00346 << " is corrupted.\n";
00347
00348 else if (data.code == IgPluginManager::ErrorEntryFailure)
00349 std::cerr << " *** WARNING: module `" << data.scope
00350 << "' does not have the required entry point, reason was\n\t"
00351 << explanation << "\n";
00352 }
00353
00354 int
00355 IgApplication::dumpDatabase (void)
00356 {
00357
00358 typedef std::pair<std::string,std::string> Seen;
00359 typedef std::set<Seen> SeenSet;
00360 typedef SeenSet::iterator SeenSetIterator;
00361
00362 IgPluginManager *db = IgPluginManager::get ();
00363 IgPluginManager::DirectoryIterator dir;
00364 IgModuleCache::Iterator plugin;
00365 IgModuleDescriptor *cache;
00366 SeenSet seen;
00367 unsigned i;
00368
00369 for (dir = db->beginDirectories (); dir != db->endDirectories (); ++dir)
00370 for (plugin = (*dir)->begin (); plugin != (*dir)->end (); ++plugin)
00371 for (cache=(*plugin)->cacheRoot(), i=0; i < cache->children(); ++i)
00372 seen.insert (Seen (cache->child (i)->token (0),
00373 cache->child (i)->token (1)));
00374
00375 SeenSetIterator cat = seen.begin ();
00376 SeenSetIterator current;
00377 while (cat != seen.end ())
00378 {
00379 if (m_all || !lat::StringOps::find (cat->first, "IGUANA"))
00380 std::cout << "Category " << cat->first << ":\n";
00381
00382 current = cat;
00383
00384 while (current != seen.end () && current->first == cat->first)
00385 {
00386 if (m_all || !lat::StringOps::find (cat->first, "IGUANA"))
00387 std::cout << " " << current->second << std::endl;
00388 ++current;
00389 }
00390 cat = current;
00391 }
00392
00393 if (seen.empty ())
00394 std::cout << "No plug-ins\n";
00395
00396 return EXIT_SUCCESS;
00397 }
00398
00399 int
00400 IgApplication::loadDriver (void)
00401 {
00402 try
00403 {
00404 ASSERT (m_driver);
00405
00406 if (m_verbose)
00407 std::cout << "Loading application driver `" << m_driver << "'.\n";
00408
00409 IgDriver *app = IgDriverDB::get ()->create (m_driver, m_state);
00410 if (! app)
00411 {
00412 std::cout << "No such application driver `" << m_driver << "'.\n\n";
00413 return usage ();
00414 }
00415
00416 if (m_verbose)
00417 std::cout << "Executing the driver.\n";
00418
00419 return app->run ();
00420 }
00421 catch (lat::Error &error)
00422 {
00423 IgOnCrashService::fatalException
00424 (typeid(error).name (), error.explain ().c_str ());
00425 std::cerr << m_argv [0] << ": cannot run the driver: "
00426 << error.explain () << "\n";
00427 return EXIT_FAILURE;
00428 }
00429 catch (std::exception &error)
00430 {
00431 IgOnCrashService::fatalException
00432 (typeid(error).name (), error.what ());
00433 std::cerr << m_argv [0] << ": cannot run the driver\n";
00434 return EXIT_FAILURE;
00435 }
00436 catch (...)
00437 {
00438 IgOnCrashService::fatalException (0, 0);
00439 std::cerr << m_argv [0] << ": cannot run the driver\n";
00440 return EXIT_FAILURE;
00441 }
00442 }