]> git.tdb.fi Git - libs/core.git/blob - source/core/application.cpp
Merge branch 'strings-master'
[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/backtrace.h"
12 #include "../debug/demangle.h"
13 #include "../time/units.h"
14 #include "../time/utils.h"
15 #include "application.h"
16 #include "except.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 UsageError, the static usage() function is called.
33
34 This function can only be called once.  The global main() function provided by
35 the library normally does it automatically at program startup.
36 */
37 int Application::run(int argc, char **argv, void *data)
38 {
39         static bool called = false;
40         if(called)
41         {
42                 cerr<<"Trying to call Application::run_app twice!\n";
43                 return 125;
44         }
45         called = true;
46
47         if(!starter_)
48         {
49                 cerr<<"Trying to run with no RegisteredApplication class!\n";
50                 return 126;
51         }
52
53         data_ = data;
54
55         try
56         {
57                 try
58                 {
59                         app_ = starter_->create_app(argc, argv);
60                 }
61                 catch(const UsageError &e)
62                 {
63                         starter_->usage(e.what(), argv[0], e.get_brief());
64                         return 1;
65                 }
66
67                 int result = app_->main();
68                 Application *a = app_;
69                 app_ = 0;
70                 delete a;
71                 return result;
72         }
73         catch(const exception &e)
74         {
75                 delete app_;
76
77 #ifdef WIN32
78                 string msg = Debug::demangle(typeid(e).name())+":\n"+e.what();
79                 MessageBoxA(0, msg.c_str(), "Uncaught exception", MB_OK|MB_ICONERROR);
80 #else
81                 cerr<<"An uncaught exception occurred.\n";
82                 cerr<<"  type:   "<<Debug::demangle(typeid(e).name())<<'\n';
83                 cerr<<"  what(): "<<e.what()<<'\n';
84
85                 const Exception *exc = dynamic_cast<const Exception *>(&e);
86                 if(exc && !exc->get_backtrace().get_frames().empty())
87                 {
88                         cerr<<"  backtrace:\n";
89                         const list<Debug::Backtrace::StackFrame> &frames = exc->get_backtrace().get_frames();
90                         for(list<Debug::Backtrace::StackFrame>::const_iterator i=frames.begin(); i!=frames.end(); ++i)
91                                 cerr<<"    "<<*i<<'\n';
92                 }
93 #endif
94
95                 return 124;
96         }
97 }
98
99 /**
100 Prints a message describing the usage of the application.  The default version
101 will blame the programmer for being lazy.
102
103 @param   reason  Why the function was called
104 @param   argv0   The value of argv[0], to be used in the message
105 @param   brief   Whether to print a brief or long usage message
106 */
107 void Application::usage(const char *reason, const char *, bool)
108 {
109         if(reason)
110                 cerr<<"UsageError: "<<reason<<'\n';
111         cerr<<"The programmer was lazy and didn't write a usage() function for this application.\n";
112 }
113
114 /**
115 Default main loop.  Calls tick() repeatedly until exit() is called.  A custom
116 main loop should monitor the done member variable and return exit_code.
117 */
118 int Application::main()
119 {
120         done = false;
121         while(!done)
122                 tick();
123
124         return exit_code;
125 }
126
127 /**
128 Sets the specified signal to be delivered to the sighandler member function.
129 */
130 void Application::catch_signal(int s)
131 {
132         signal(s, &sighandler_);
133 }
134
135 /**
136 Causes the application to exit gracefully with the given exit code.
137 */
138 void Application::exit(int c)
139 {
140         done = true;
141         exit_code = c;
142 }
143
144 /**
145 Static wrapper function to call a member function of the Application instance.
146 */
147 void Application::sighandler_(int s)
148 {
149         app_->sighandler(s);
150 }
151
152
153 Application::Starter::Starter()
154 {
155         if(starter_)
156                 throw InvalidState("Can't create more than one Starter instance");
157
158         starter_ = this;
159 }
160
161 } // namespace Msp