]> git.tdb.fi Git - libs/core.git/blob - source/core/application.cpp
Allow startup info to be set externally
[libs/core.git] / source / core / application.cpp
1 #include <typeinfo>
2 #include <signal.h>
3 #include <msp/debug/demangle.h>
4 #include <msp/debug/errorreporter.h>
5 #include <msp/fs/utils.h>
6 #include <msp/io/print.h>
7 #include "application.h"
8 #include "getopt.h"
9
10 using namespace std;
11
12 namespace Msp {
13
14 Application *Application::app_ = 0;
15 Application::Starter *Application::starter_ = 0;
16 const char *Application::argv0_ = 0;
17 string Application::name_;
18 void *Application::data_ = 0;
19
20 Application::Application(const string &n):
21         exit_code(0)
22 {
23         if(app_)
24                 throw logic_error("instance already exists");
25
26         if(!n.empty())
27                 name_ = n;
28         else
29                 name_ = FS::basename(argv0_);
30 }
31
32 int Application::run(int argc, char **argv, void *data, void (*created_callback)(void *))
33 {
34         if(!starter_)
35         {
36                 IO::cerr.write("Application::run called with no RegisteredApplication class!\n");
37                 return 126;
38         }
39
40         set_startup_info(argv[0], data);
41
42         try
43         {
44                 try
45                 {
46                         app_ = starter_->create_app(argc, argv);
47                 }
48                 catch(const usage_error &e)
49                 {
50                         IO::print(IO::cerr, "%s\n%s\n", e.what(), e.help());
51                         return 1;
52                 }
53
54                 if(created_callback)
55                         created_callback(data);
56
57                 int result = app_->main();
58                 Application *a = app_;
59                 app_ = 0;
60                 delete a;
61                 return result;
62         }
63         catch(const exception &e)
64         {
65                 bool handled = false;
66                 if(const Debug::ErrorReporter *er = Debug::ErrorReporter::get_current())
67                         handled = er->report_uncaught_exception(e);
68
69                 if(!handled)
70                 {
71                         IO::print(IO::cerr, "An uncaught exception occurred.\n");
72                         IO::print(IO::cerr, "  type:   %s\n", Debug::demangle(typeid(e).name()));
73                         IO::print(IO::cerr, "  what(): %s\n", e.what());
74                 }
75
76                 delete app_;
77                 app_ = 0;
78
79                 return 124;
80         }
81 }
82
83 void Application::set_startup_info(const char *argv0, void *data)
84 {
85         if(argv0_)
86                 throw logic_error("startup info already set");
87
88         argv0_ = argv0;
89         data_ = data;
90 }
91
92 int Application::main()
93 {
94         done = false;
95         while(!done)
96                 tick();
97
98         return exit_code;
99 }
100
101 void Application::catch_signal(int s)
102 {
103         signal(s, &sighandler_);
104 }
105
106 void Application::exit(int c)
107 {
108         done = true;
109         exit_code = c;
110 }
111
112 void Application::sighandler_(int s)
113 {
114         app_->sighandler(s);
115 }
116
117
118 Application::Starter::Starter()
119 {
120         if(starter_)
121                 throw logic_error("Can't create more than one Starter instance");
122
123         starter_ = this;
124 }
125
126 } // namespace Msp