]> git.tdb.fi Git - libs/core.git/blob - source/core/application.cpp
Merge branch 'fs-master'
[libs/core.git] / source / core / application.cpp
1 #ifdef WIN32
2 #include <windows.h>
3 #endif
4 #include <signal.h>
5 #include <typeinfo>
6 #include <msp/debug/demangle.h>
7 #include <msp/io/print.h>
8 #include "application.h"
9 #include "getopt.h"
10
11 using namespace std;
12
13 namespace Msp {
14
15 Application *Application::app_ = 0;
16 Application::Starter *Application::starter_ = 0;
17 void *Application::data_ = 0;
18
19 Application::Application():
20         exit_code(0)
21 { }
22
23 /**
24 Constructs an instance of the registered application class and runs it.  If the
25 application throws a usage_error, a help message is printed.  The GetOpt class
26 will throw such exceptions automatically in error conditions.
27
28 This function can only be called once.  The global main() function provided by
29 the library normally does it automatically at program startup.
30 */
31 int Application::run(int argc, char **argv, void *data)
32 {
33         static bool called = false;
34         if(called)
35         {
36                 IO::cerr.write("Trying to call Application::run_app twice!\n");
37                 return 125;
38         }
39         called = true;
40
41         if(!starter_)
42         {
43                 IO::cerr.write("Trying to run with no RegisteredApplication class!\n");
44                 return 126;
45         }
46
47         data_ = data;
48
49         try
50         {
51                 try
52                 {
53                         app_ = starter_->create_app(argc, argv);
54                 }
55                 catch(const usage_error &e)
56                 {
57                         IO::print(IO::cerr, "%s\n%s\n", e.what(), e.help());
58                         return 1;
59                 }
60
61                 int result = app_->main();
62                 Application *a = app_;
63                 app_ = 0;
64                 delete a;
65                 return result;
66         }
67         catch(const exception &e)
68         {
69                 delete app_;
70
71 #ifdef WIN32
72                 string msg = Debug::demangle(typeid(e).name())+":\n"+e.what();
73                 MessageBoxA(0, msg.c_str(), "Uncaught exception", MB_OK|MB_ICONERROR);
74 #else
75                 IO::print(IO::cerr, "An uncaught exception occurred.\n");
76                 IO::print(IO::cerr, "  type:   %s\n", Debug::demangle(typeid(e).name()));
77                 IO::print(IO::cerr, "  what(): %s\n", e.what());
78 #endif
79
80                 return 124;
81         }
82 }
83
84 /**
85 Default main loop.  Calls tick() repeatedly until exit() is called.  A custom
86 main loop should monitor the done member variable and return exit_code.
87 */
88 int Application::main()
89 {
90         done = false;
91         while(!done)
92                 tick();
93
94         return exit_code;
95 }
96
97 /**
98 Sets the specified signal to be delivered to the sighandler member function.
99 */
100 void Application::catch_signal(int s)
101 {
102         signal(s, &sighandler_);
103 }
104
105 /**
106 Causes the application to exit gracefully with the given exit code.
107 */
108 void Application::exit(int c)
109 {
110         done = true;
111         exit_code = c;
112 }
113
114 /**
115 Static wrapper function to call a member function of the Application instance.
116 */
117 void Application::sighandler_(int s)
118 {
119         app_->sighandler(s);
120 }
121
122
123 Application::Starter::Starter()
124 {
125         if(starter_)
126                 throw logic_error("Can't create more than one Starter instance");
127
128         starter_ = this;
129 }
130
131 } // namespace Msp