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