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