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