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