mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-14 09:06:58 +01:00
- `--test` is looked for before the rest of the command line is read. An unknown option before it (e.g. `-s x.scn --test-timout 90 --test`) used to end the run with exit code 0, which a caller reads as a pass. - `--test-timeout` without a value, or with one that isn't a number of seconds, fails the run instead of leaving the default or, through atof, turning the timeout off. - These, a missing -s, a failed start and an exception caught in main() end the test through test_manager::conclude(), which writes the usual `test: error (exit code 5) ... : <reason>` line to stdout and the log. Before, `eu07 --test` alone exited with 5 and nothing anywhere: the error went to the log queue and the process ended before the log thread wrote it. In test mode main() now stops the log thread and waits for it before _Exit(). Outside the test mode nothing changes: conclude() does nothing there.
194 lines
5.7 KiB
C++
194 lines
5.7 KiB
C++
/*
|
|
This Source Code Form is subject to the
|
|
terms of the Mozilla Public License, v.
|
|
2.0. If a copy of the MPL was not
|
|
distributed with this file, You can
|
|
obtain one at
|
|
http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
/*
|
|
MaSzyna EU07 locomotive simulator
|
|
Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others
|
|
*/
|
|
/*
|
|
Authors:
|
|
MarcinW, McZapkie, Shaxbee, ABu, nbmx, youBy, Ra, winger, mamut, Q424,
|
|
Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "application/application.h"
|
|
#include "simulation/simulationtest.h"
|
|
#include "utilities/Globals.h"
|
|
#include "utilities/Logs.h"
|
|
#include <cstdlib>
|
|
#include <format>
|
|
#ifdef WITHDUMPGEN
|
|
#ifdef _WIN32
|
|
#include <Windows.h>
|
|
#include <DbgHelp.h>
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
|
|
#endif
|
|
|
|
void export_e3d_standalone(std::string in, std::string out, int flags, bool dynamic);
|
|
int export_btf_standalone(std::string in, std::string out);
|
|
int generate_nodebank_previews(int Argc, char *Argv[]);
|
|
|
|
#include <ctime>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <utilities/Globals.h>
|
|
|
|
#ifdef _WIN32
|
|
#pragma comment(lib, "Dbghelp.lib")
|
|
|
|
LONG WINAPI CrashHandler(EXCEPTION_POINTERS *ExceptionInfo)
|
|
{
|
|
// Get current local time
|
|
SYSTEMTIME st;
|
|
GetLocalTime(&st);
|
|
|
|
// Format: crash_YYYY-MM-DD_HH-MM-SS.dmp
|
|
std::ostringstream oss;
|
|
oss << "crash_" << std::setw(4) << std::setfill('0') << st.wYear << "-" << std::setw(2) << std::setfill('0') << st.wMonth << "-" << std::setw(2) << std::setfill('0') << st.wDay << "_"
|
|
<< std::setw(2) << std::setfill('0') << st.wHour << "-" << std::setw(2) << std::setfill('0') << st.wMinute << "-" << std::setw(2) << std::setfill('0') << st.wSecond << ".dmp";
|
|
|
|
std::string filename = oss.str();
|
|
|
|
HANDLE hFile = CreateFileA(filename.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
|
|
dumpInfo.ThreadId = GetCurrentThreadId();
|
|
dumpInfo.ExceptionPointers = ExceptionInfo;
|
|
dumpInfo.ClientPointers = FALSE;
|
|
|
|
// Wybrana kombinacja flag
|
|
MINIDUMP_TYPE dumpType = MINIDUMP_TYPE(MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules | MiniDumpWithIndirectlyReferencedMemory |
|
|
MiniDumpWithFullMemoryInfo | MiniDumpWithTokenInformation);
|
|
|
|
MessageBoxA(nullptr, "Simulator crash occured :(\n", "Simulator crashed :(", MB_ICONERROR);
|
|
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, dumpType, &dumpInfo, nullptr, nullptr);
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
|
|
// the log is written by a thread of its own, which the closing of the application stops and waits for. on the ways
|
|
// out that skip the closing (a failed start, an exception) what was logged last would be lost with the process
|
|
void finish_log()
|
|
{
|
|
StopLogService();
|
|
if (auto const logservice{Global.threads.find("LogService")}; logservice != Global.threads.end() && logservice->second.joinable())
|
|
logservice->second.join();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
#ifdef WITHDUMPGEN
|
|
#ifdef _WIN32
|
|
SetUnhandledExceptionFilter(CrashHandler);
|
|
#endif
|
|
#endif
|
|
// init start timestamp
|
|
Global.startTimestamp = std::chrono::steady_clock::now();
|
|
|
|
// quick short-circuit for standalone e3d export
|
|
if (argc == 6 && std::string(argv[1]) == "-e3d")
|
|
{
|
|
std::string in(argv[2]);
|
|
std::string out(argv[3]);
|
|
int flags = std::stoi(std::string(argv[4]));
|
|
int dynamic = std::stoi(std::string(argv[5]));
|
|
export_e3d_standalone(in, out, flags, dynamic);
|
|
}
|
|
// standalone generation of preview images of the node bank models: -generate-nodebank-previews [options]
|
|
else if (argc >= 2 && std::string(argv[1]) == "-generate-nodebank-previews")
|
|
{
|
|
auto const result{generate_nodebank_previews(argc, argv)};
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
std::_Exit(result);
|
|
}
|
|
// standalone conversion of text terrain file to binary format: -btf -s <text file> [-o <binary file>]
|
|
else if (argc >= 4 && std::string(argv[1]) == "-btf")
|
|
{
|
|
std::string in;
|
|
std::string out;
|
|
for (int i = 2; i + 1 < argc; i += 2)
|
|
{
|
|
std::string const option(argv[i]);
|
|
if (option == "-s")
|
|
{
|
|
in = argv[i + 1];
|
|
}
|
|
else if (option == "-o")
|
|
{
|
|
out = argv[i + 1];
|
|
}
|
|
}
|
|
auto const result{export_btf_standalone(in, out)};
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
std::_Exit(result);
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
auto result{Application.init(argc, argv)};
|
|
if (result == 0)
|
|
{
|
|
result = Application.run();
|
|
Application.exit();
|
|
}
|
|
}
|
|
catch (std::bad_alloc const &Error)
|
|
{
|
|
ErrorLog("Critical error, memory allocation failure: " + std::string(Error.what()));
|
|
}
|
|
#ifdef _WIN32
|
|
catch (std::runtime_error const &Error)
|
|
{
|
|
ErrorLog(std::format("Critical error: {}", Error.what()));
|
|
// in test mode nobody is there to close the box, the exit code tells of the error
|
|
simulation::test().conclude(simulation::test_result::error, std::format("critical error: {}", Error.what()));
|
|
if (false == Global.test.enabled)
|
|
{
|
|
std::string msg = "Simulator crash occured :(\n";
|
|
msg += Error.what();
|
|
MessageBoxA(nullptr, msg.c_str(), "Simulator crashed :(", MB_ICONERROR);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#ifndef _WIN32
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
#endif
|
|
if (Global.test.enabled)
|
|
{
|
|
// a run that stopped before its test ended (a failed start, an exception) says so like any other end
|
|
simulation::test().conclude(simulation::test_result::error, "the simulator stopped before the test ended");
|
|
finish_log();
|
|
}
|
|
// skip destructors, there are ordering errors which causes segfaults
|
|
// a test run (--test) says its result in the exit code
|
|
std::_Exit(Global.test.enabled ? simulation::test().exit_code() : 0);
|
|
}
|