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