]> git.tdb.fi Git - libs/core.git/blob - source/core/application.cpp
Assimilate exceptions and RefPtr from mspmisc
[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 #include <signal.h>
8 #include <iostream>
9 #include "../time/units.h"
10 #include "../time/utils.h"
11 #include "application.h"
12 #include "error.h"
13
14 using namespace std;
15
16 namespace Msp {
17
18 /**
19 Constructs an instance of the registered application class and runs it.  If the
20 application throws a UsageError, the static usage() function is called.
21
22 This function can only be called once.  The global main() function provided by
23 the library normally does it automatically at program startup.
24 */
25 int Application::run(int argc, char **argv)
26 {
27         static bool called=false;
28         if(called)
29         {
30                 cerr<<"Trying to call Application::run_app twice!\n";
31                 return 125;
32         }
33         called=true;
34
35         if(!reg_app_)
36         {
37                 cerr<<"Trying to run with no application class registered!\n";
38                 return 126;
39         }
40
41         try
42         {
43                 app_=reg_app_->create_app(argc, argv);
44         }
45         catch(const UsageError &e)
46         {
47                 reg_app_->usage(e.what(), argv[0], e.get_brief());
48                 return 1;
49         }
50
51         int result=app_->main();
52         delete app_;
53         return result;
54 }
55
56 /**
57 Prints a message describing the usage of the application.  The default version
58 will blame the programmer for being lazy.
59
60 @param   reason  Why the function was called
61 @param   argv0   The value of argv[0], to be used in the message
62 @param   brief   Whether to print a brief or long usage message
63 */
64 void Application::usage(const char *reason, const char *, bool)
65 {
66         if(reason)
67                 cerr<<"UsageError: "<<reason<<'\n';
68         cerr<<"The programmer was lazy and didn't write a usage() function for this application.\n";
69 }
70
71 Application::Application():
72         exit_code(0),
73         loop_mode_(TICK_SLEEP)
74 { }
75
76 /**
77 Default main loop.  Behavior depends on loop_mode_.  A custom main loop should
78 monitor the done member variable and return exit_code.
79 */
80 int Application::main()
81 {
82         if(loop_mode_==NONE)
83                 return 0;
84
85         done=false;
86         while(!done)
87         {
88                 if(loop_mode_==SLEEP)
89                 {
90                         sleep_sem_.wait();
91                         if(!done)
92                                 tick();
93                 }
94                 else if(loop_mode_==TICK_SLEEP)
95                 {
96                         tick();
97                         Time::sleep(Time::msec);
98                 }
99                 else if(loop_mode_==TICK_YIELD)
100                 {
101                         tick();
102 #ifdef WIN32
103                         Sleep(0);
104 #else
105                         sched_yield();
106 #endif
107                 }
108         }
109
110         return exit_code;
111 }
112
113 /**
114 Sets the specified signal to be delivered to the sighandler member function.
115 */
116 void Application::catch_signal(int s)
117 {
118         signal(s, &sighandler_);
119 }
120
121 /**
122 Changes the main loop mode.
123 */
124 void Application::set_loop_mode(LoopMode l)
125 {
126         LoopMode old_mode=loop_mode_;
127         loop_mode_=l;
128         if(old_mode==SLEEP)
129                 sleep_sem_.signal();
130 }
131
132 /**
133 Causes the tick() function to be executed once if loop mode is SLEEP.  Has no
134 effect with other loop modes.
135 */
136 void Application::induce_tick()
137 {
138         if(loop_mode_==SLEEP)
139                 sleep_sem_.signal();
140 }
141
142 /**
143 Causes the application to exit gracefully with the given exit code.
144 */
145 void Application::exit(int c)
146 {
147         done=true;
148         exit_code=c;
149         if(loop_mode_==SLEEP)
150                 sleep_sem_.signal();
151 }
152
153 /**
154 Static wrapper function to call a member function of the Application instance.
155 */
156 void Application::sighandler_(int s)
157 {
158         app_->sighandler(s);
159 }
160
161 Application::RegBase::RegBase()
162 {
163         if(reg_app_)
164         {
165                 cerr<<"Warning: registering the application twice\n";
166                 delete reg_app_;
167         }
168
169         reg_app_=this;
170 }
171
172 Application *Application::app_=0;
173 Application::RegBase *Application::reg_app_=0;
174
175 } // namespace Msp