]> git.tdb.fi Git - libs/core.git/blob - source/core/application.cpp
Add move semantics to Variant
[libs/core.git] / source / core / application.cpp
1 #include <cstring>
2 #include <typeinfo>
3 #include <signal.h>
4 #include <msp/debug/demangle.h>
5 #include <msp/debug/errorreporter.h>
6 #include <msp/fs/dir.h>
7 #include <msp/fs/path.h>
8 #include <msp/fs/utils.h>
9 #include <msp/io/print.h>
10 #include <msp/strings/utils.h>
11 #include "application.h"
12 #include "except.h"
13 #include "getopt.h"
14
15 using namespace std;
16
17 namespace Msp {
18
19 Application *Application::_app = nullptr;
20 Application::Starter *Application::_starter = nullptr;
21 const char *Application::_argv0 = nullptr;
22 string Application::_name;
23 void *Application::_data = nullptr;
24
25 Application::Application(const string &n)
26 {
27         if(_app)
28                 throw already_called("Application::Application");
29
30         if(!n.empty())
31                 _name = n;
32         else
33                 _name = FS::basename(_argv0);
34 }
35
36 int Application::run(int argc, char **argv, void *data, void (*created_callback)(void *))
37 {
38         if(!_starter)
39         {
40                 IO::cerr.write("Application::run called with no RegisteredApplication class!\n");
41                 return 126;
42         }
43
44         set_startup_info(argv[0], data);
45
46         try
47         {
48                 try
49                 {
50                         _app = _starter->create_app(argc, argv);
51                 }
52                 catch(const usage_error &e)
53                 {
54                         IO::print(IO::cerr, "%s\n%s\n", e.what(), e.help());
55                         return 1;
56                 }
57
58                 if(created_callback)
59                         created_callback(data);
60
61                 int result = _app->main();
62                 Application *a = _app;
63                 _app = nullptr;
64                 delete a;
65                 return result;
66         }
67         catch(const exception &e)
68         {
69                 bool handled = false;
70                 if(const Debug::ErrorReporter *er = Debug::ErrorReporter::get_current())
71                         handled = er->report_uncaught_exception(e);
72
73                 if(!handled)
74                 {
75                         IO::print(IO::cerr, "An uncaught exception occurred.\n");
76                         IO::print(IO::cerr, "  type:   %s\n", Debug::demangle(typeid(e).name()));
77                         vector<string> lines = split(e.what(), '\n');
78                         if(lines.size()<2)
79                                 IO::print(IO::cerr, "  what(): %s\n", e.what());
80                         else
81                         {
82                                 IO::print(IO::cerr, "  what(): %s\n", lines.front());
83                                 for(auto i=lines.begin(); ++i!=lines.end(); )
84                                         IO::print(IO::cerr, "          %s\n", *i);
85                         }
86                 }
87
88                 delete _app;
89                 _app = nullptr;
90
91                 return 124;
92         }
93 }
94
95 void Application::set_startup_info(const char *argv0, void *data)
96 {
97         if(_argv0)
98                 throw already_called("Application::set_startup_info");
99
100         static FS::Path exe;
101
102         if(!argv0 || !*argv0)
103         {
104 #ifdef _WIN32
105                 argv0 = "application.exe";
106 #else
107                 argv0 = "./application";
108 #endif
109         }
110
111         bool has_slash = strchr(argv0, FS::DIRSEP);
112         if(!has_slash)
113                 exe = FS::path_lookup(argv0);
114         if(exe.empty())
115                 exe = FS::realpath(argv0);
116
117         _argv0 = exe.c_str();
118         _data = data;
119 }
120
121 void *Application::get_data()
122 {
123         return _data;
124 }
125
126 const char *Application::get_argv0()
127 {
128         return _argv0;
129 }
130
131 const std::string &Application::get_name()
132 {
133         return _name;
134 }
135
136 int Application::main()
137 {
138         done = false;
139         while(!done)
140                 tick();
141
142         return exit_code;
143 }
144
145 void Application::catch_signal(int s)
146 {
147         signal(s, &_sighandler);
148 }
149
150 void Application::exit(int c)
151 {
152         done = true;
153         exit_code = c;
154 }
155
156 void Application::_sighandler(int s)
157 {
158         _app->sighandler(s);
159 }
160
161
162 Application::Starter::Starter()
163 {
164         if(_starter)
165                 throw already_called("Application::Starter::Starter");
166
167         _starter = this;
168 }
169
170 } // namespace Msp