]> git.tdb.fi Git - libs/core.git/blob - source/core/application.cpp
Make sure all files have the correct header
[libs/core.git] / source / core / application.cpp
1 /* $Id$
2
3 This file is part of libmspcore
4 Copyright © 2006 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():
23         exit_code(0),
24         loop_mode_(TICK_SLEEP)
25 { }
26
27 /**
28 Constructs an instance of the registered application class and runs it.  If the
29 application throws a UsageError, the static usage() function is called.
30
31 This function can only be called once.  The global main() function provided by
32 the library normally does it automatically at program startup.
33 */
34 int Application::run(int argc, char **argv, void *data)
35 {
36         static bool called=false;
37         if(called)
38         {
39                 cerr<<"Trying to call Application::run_app twice!\n";
40                 return 125;
41         }
42         called=true;
43
44         if(!reg_app_)
45         {
46                 cerr<<"Trying to run with no application class registered!\n";
47                 return 126;
48         }
49
50         data_=data;
51
52         try
53         {
54                 try
55                 {
56                         app_=reg_app_->create_app(argc, argv);
57                 }
58                 catch(const UsageError &e)
59                 {
60                         reg_app_->usage(e.what(), argv[0], e.get_brief());
61                         return 1;
62                 }
63
64                 int result=app_->main();
65                 delete app_;
66                 return result;
67         }
68         catch(const exception &e)
69         {
70                 delete app_;
71
72 #ifdef WIN32
73                 string msg=Debug::demangle(typeid(e).name())+":\n"+e.what();
74                 MessageBoxA(0, msg.c_str(), "Uncaught exception", MB_OK|MB_ICONERROR);
75 #else
76                 cerr<<"An uncaught exception occurred.\n";
77                 cerr<<"  type:   "<<Debug::demangle(typeid(e).name())<<'\n';
78                 cerr<<"  what(): "<<e.what()<<'\n';
79
80                 const Exception *exc=dynamic_cast<const Exception *>(&e);
81                 if(exc && !exc->get_backtrace().get_frames().empty())
82                 {
83                         cerr<<"  backtrace:\n";
84                         const list<Debug::Backtrace::StackFrame> &frames=exc->get_backtrace().get_frames();
85                         for(list<Debug::Backtrace::StackFrame>::const_iterator i=frames.begin(); i!=frames.end(); ++i)
86                                 cerr<<"    "<<*i<<'\n';
87                 }
88 #endif
89
90                 return 124;
91         }
92 }
93
94 /**
95 Prints a message describing the usage of the application.  The default version
96 will blame the programmer for being lazy.
97
98 @param   reason  Why the function was called
99 @param   argv0   The value of argv[0], to be used in the message
100 @param   brief   Whether to print a brief or long usage message
101 */
102 void Application::usage(const char *reason, const char *, bool)
103 {
104         if(reason)
105                 cerr<<"UsageError: "<<reason<<'\n';
106         cerr<<"The programmer was lazy and didn't write a usage() function for this application.\n";
107 }
108
109 /**
110 Default main loop.  Behavior depends on loop_mode_.  A custom main loop should
111 monitor the done member variable and return exit_code.
112 */
113 int Application::main()
114 {
115         if(loop_mode_==NONE)
116                 return 0;
117
118         done=false;
119         while(!done)
120         {
121                 if(loop_mode_==SLEEP)
122                 {
123                         sleep_sem_.wait();
124                         if(!done)
125                                 tick();
126                 }
127                 else if(loop_mode_==TICK_SLEEP)
128                 {
129                         tick();
130                         Time::sleep(Time::msec);
131                 }
132                 else if(loop_mode_==TICK_YIELD)
133                 {
134                         tick();
135 #ifdef WIN32
136                         Sleep(0);
137 #else
138                         sched_yield();
139 #endif
140                 }
141                 else if(loop_mode_==TICK_BUSY)
142                         tick();
143         }
144
145         return exit_code;
146 }
147
148 /**
149 Sets the specified signal to be delivered to the sighandler member function.
150 */
151 void Application::catch_signal(int s)
152 {
153         signal(s, &sighandler_);
154 }
155
156 /**
157 Changes the main loop mode.
158 */
159 void Application::set_loop_mode(LoopMode l)
160 {
161         LoopMode old_mode=loop_mode_;
162         loop_mode_=l;
163         if(old_mode==SLEEP)
164                 sleep_sem_.signal();
165 }
166
167 /**
168 Causes the tick() function to be executed once if loop mode is SLEEP.  Has no
169 effect with other loop modes.
170 */
171 void Application::induce_tick()
172 {
173         if(loop_mode_==SLEEP)
174                 sleep_sem_.signal();
175 }
176
177 /**
178 Causes the application to exit gracefully with the given exit code.
179 */
180 void Application::exit(int c)
181 {
182         done=true;
183         exit_code=c;
184         if(loop_mode_==SLEEP)
185                 sleep_sem_.signal();
186 }
187
188 /**
189 Static wrapper function to call a member function of the Application instance.
190 */
191 void Application::sighandler_(int s)
192 {
193         app_->sighandler(s);
194 }
195
196
197 Application::RegBase::RegBase()
198 {
199         if(reg_app_)
200         {
201                 cerr<<"Warning: registering the application twice\n";
202                 delete reg_app_;
203         }
204
205         reg_app_=this;
206 }
207
208 Application *Application::app_=0;
209 Application::RegBase *Application::reg_app_=0;
210 void *Application::data_=0;
211
212 } // namespace Msp