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