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 static 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
55 static void EnableConsoleOutput()
56 {
57  if (AttachConsole(ATTACH_PARENT_PROCESS)) {
58  freopen("CONOUT$", "w", stdout);
59  freopen("CONOUT$", "w", stderr);
60  }
61 }
62 #endif
63 
64 static 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 
85 static 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(argc, argv);
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.
170 int 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
std::string toString(time_t time)
Definition: Date.cc:150
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:59
#define ad_printf(...)
Definition: openmsx.hh:11
void randomize()
Seed the (shared) random number generator.
Definition: random.hh:16