openMSX
main.cc
Go to the documentation of this file.
1/*
2 * openmsx - the MSX emulator that aims for perfection
3 *
4 */
5
6#include "openmsx.hh"
7#include "Date.hh"
8#include "Reactor.hh"
10#include "CliServer.hh"
11#include "Display.hh"
12#include "EventDistributor.hh"
13#include "RenderSettings.hh"
14#include "EnumSetting.hh"
15#include "MSXException.hh"
16#include "Thread.hh"
17#include "build-info.hh"
18#include "random.hh"
19#include <iostream>
20#include <exception>
21#include <ctime>
22#include <cstdio>
23#include <cstdlib>
24#include <SDL.h>
25#ifdef _WIN32
26#include "win32-arggen.hh"
27#endif
28
29// Set LOG_TO_FILE to 1 for any platform on which stdout and stderr must
30// be redirected to a file
31// Also, specify the appropriate file names, depending on the platform conventions
32#if PLATFORM_ANDROID
33#define LOG_TO_FILE 1
34#define STDOUT_LOG_FILE_NAME "openmsx_system/openmsx.stdout"
35#define STDERR_LOG_FILE_NAME "openmsx_system/openmsx.stderr"
36#else
37#define LOG_TO_FILE 0
38#endif
39
40namespace openmsx {
41
42#ifdef _WIN32
43// wrapper for Windows, as the MS runtime doesn't provide setenv!?
44static int setenv(const char* name, const char* value, int overwrite)
45{
46 if (!overwrite && getenv(name)) {
47 return 0;
48 }
49 return _putenv_s(name, value);
50}
51#endif
52
53#ifdef _WIN32
54// enable console output on Windows
55static void EnableConsoleOutput()
56{
57 if (AttachConsole(ATTACH_PARENT_PROCESS)) {
58 freopen("CONOUT$", "w", stdout);
59 freopen("CONOUT$", "w", stderr);
60 }
61}
62#endif
63
64static void initializeSDL()
65{
66 int flags = 0;
67#ifndef SDL_JOYSTICK_DISABLED
68 flags |= SDL_INIT_JOYSTICK;
69#endif
70#ifndef NDEBUG
71 flags |= SDL_INIT_NOPARACHUTE;
72#endif
73 if (SDL_Init(flags) < 0) {
74 throw FatalError("Couldn't init SDL: ", SDL_GetError());
75 }
76
77 // for now: instruct FreeType to use the v35 TTF engine
78 // this is the rendering we had before FreeType implemented and
79 // switched over to the v40 engine. To keep this the same for now, we
80 // select the old engine explicitly, until we decide how to continue
81 // (e.g. just use v40 or use a font that renders better on v40
82 setenv("FREETYPE_PROPERTIES", "truetype:interpreter-version=35", 0);
83}
84
85static int main(int argc, char **argv)
86{
87#if LOG_TO_FILE
88 ad_printf("Redirecting stdout to %s and stderr to %s\n",
89 STDOUT_LOG_FILE_NAME, STDERR_LOG_FILE_NAME);
90
91 if (!freopen(STDOUT_LOG_FILE_NAME, "a", stdout)) {
92 ad_printf("Couldn't redirect stdout to logfile, aborting\n");
93 std::cerr << "Couldn't redirect stdout to "
94 STDOUT_LOG_FILE_NAME "\n";
95 return 1;
96 }
97 if (!freopen(STDERR_LOG_FILE_NAME, "a", stderr)) {
98 ad_printf("Couldn't redirect stderr to logfile, aborting\n");
99 std::cout << "Couldn't redirect stderr to "
100 STDERR_LOG_FILE_NAME "\n";
101 return 1;
102 }
103
104 std::string msg = Date::toString(time(nullptr)) + ": starting openMSX";
105 std::cout << msg << '\n';
106 std::cerr << msg << '\n';
107#endif
108
109#ifdef _WIN32
110 EnableConsoleOutput();
111#endif
112
113 try {
114 randomize(); // seed global random generator
115 initializeSDL();
116
118 Reactor reactor;
119#ifdef _WIN32
120 ArgumentGenerator argGen;
121 argv = argGen.GetArguments(argc);
122#endif
123 CommandLineParser parser(reactor);
124 parser.parse({argv, size_t(argc)});
125 CommandLineParser::ParseStatus parseStatus = parser.getParseStatus();
126
127 if (parseStatus != CommandLineParser::EXIT) {
128 if (!parser.isHiddenStartup()) {
129 auto& render = reactor.getDisplay().getRenderSettings().getRendererSetting();
130 render.setValue(render.getRestoreValue());
131 // Switching renderer requires events, handle
132 // these events before continuing with the rest
133 // of initialization. This fixes a bug where
134 // you have a '-script bla.tcl' command line
135 // argument where bla.tcl contains a line like
136 // 'ext gfx9000'.
137 reactor.getEventDistributor().deliverEvents();
138 }
139 if (parseStatus != CommandLineParser::TEST) {
140 CliServer cliServer(reactor.getCommandController(),
141 reactor.getEventDistributor(),
142 reactor.getGlobalCliComm());
143 reactor.run(parser);
144 }
145 }
146 } catch (FatalError& e) {
147 std::cerr << "Fatal error: " << e.getMessage() << '\n';
148 exitCode = 1;
149 } catch (MSXException& e) {
150 std::cerr << "Uncaught exception: " << e.getMessage() << '\n';
151 exitCode = 1;
152 } catch (std::exception& e) {
153 std::cerr << "Uncaught std::exception: " << e.what() << '\n';
154 exitCode = 1;
155 } catch (...) {
156 std::cerr << "Uncaught exception of unexpected type." << '\n';
157 exitCode = 1;
158 }
159 // Clean up.
160 if (SDL_WasInit(SDL_INIT_EVERYTHING)) {
161 SDL_Quit();
162 }
163
164 return exitCode;
165}
166
167} // namespace openmsx
168
169// Enter the openMSX namespace.
170int main(int argc, char **argv)
171{
172 // TODO with SDL1 we had the comment:
173 // need exit() iso return on win32/SDL
174 // Is that still the case with SDL2? Because for Android we need to
175 // return from main instead of exit().
176 return openmsx::main(argc, argv);
177}
int main(int argc, char **argv)
Definition: main.cc:170
constexpr double e
Definition: Math.hh:21
std::string toString(time_t time)
Definition: Date.cc:152
void setMainThread()
Store ID of the main thread, should be called exactly once from the main thread.
Definition: Thread.cc:9
This file implemented 3 utility functions:
Definition: Autofire.cc:9
int exitCode
Definition: Reactor.cc:60
#define ad_printf(...)
Definition: openmsx.hh:11
void randomize()
Seed the (shared) random number generator.
Definition: random.hh:16