Compare commits

...

5 Commits

Author SHA1 Message Date
Hleb Valoshka cd32920fbd fix 2021-07-05 13:18:41 +04:00
Hleb Valoshka 5c55b17caa wip 2021-07-05 12:25:42 +04:00
Hleb Valoshka c4e426d70b wip 2021-07-05 11:37:17 +04:00
Hleb Valoshka 803afffce6 wip 2021-07-04 23:56:09 +04:00
Hleb Valoshka bfacc111a4 wip 2021-07-04 21:09:18 +04:00
16 changed files with 421 additions and 381 deletions

View File

@ -5,6 +5,7 @@
#include <celutil/winutil.h>
#else
#include <sys/stat.h>
#include <unistd.h>
#endif
#if defined(_MSC_VER) && !defined(__clang__)
// M$VC++ build without C++ exceptions are not supported yet
@ -594,5 +595,66 @@ bool create_directory(const path& p)
return r;
}
path current_path()
{
std::error_code ec;
path p = current_path(ec);
if (ec)
#if __cpp_exceptions
throw filesystem_error(ec, "celfs::current_path error");
#else
std::abort();
#endif
return p;
}
path current_path(std::error_code& ec)
{
#ifdef _WIN32
std::wstring buffer(MAX_PATH + 1, 0);
DWORD r = GetModuleFileNameW(nullptr, &buffer[0], MAX_PATH);
if (r == 0)
{
ec = std::error_code(errno, std::system_category());
return path();
}
auto pos = buffer.find_last_of(L"\\/");
return buffer.substr(0, pos);
#else
std::string buffer(256, 0);
char *r = getcwd(&buffer[0], buffer.size());
if (r == nullptr)
{
ec = std::error_code(errno, std::system_category());
return path();
}
return buffer;
#endif
}
void current_path(const path& p)
{
std::error_code ec;
current_path(p, ec);
if (ec)
#if __cpp_exceptions
throw filesystem_error(ec, "celfs::current_path error");
#else
std::abort();
#endif
}
void current_path(const path& p, std::error_code& ec) noexcept
{
#ifdef _WIN32
BOOL ret = SetCurrentDirectoryW(p.c_str());
if (!ret)
ec = std::error_code(errno, std::system_category());
#else
int ret = chdir(p.c_str());
if (ret != 0)
ec = std::error_code(errno, std::system_category());
#endif
}
}
}

View File

@ -470,5 +470,10 @@ bool is_directory(const path& p, std::error_code& ec) noexcept;
bool create_directory(const path& p);
bool create_directory(const path& p, std::error_code& ec) noexcept;
path current_path();
path current_path(std::error_code& ec);
void current_path(const path& p);
void current_path(const path& p, std::error_code& ec) noexcept;
}
}

View File

@ -86,8 +86,10 @@ std::ofstream hdrlog;
#endif
#ifdef _MSC_VER
#include <malloc.h>
#ifndef alloca
#define alloca(s) _alloca(s)
#endif
#endif
using namespace cmod;
using namespace Eigen;

View File

@ -131,7 +131,7 @@ void VertexObject::enableAttribArrays() noexcept
auto n = t.first;
auto& p = t.second;
glEnableVertexAttribArray(n);
glVertexAttribPointer(n, p.count, p.type, p.normalized, p.stride, (GLvoid*) p.offset);
glVertexAttribPointer(n, p.count, p.type, p.normalized, p.stride, (GLvoid*) (size_t) p.offset);
}
}

View File

@ -1916,6 +1916,10 @@ void CelestiaCore::setStartURL(const string &url)
}
}
std::string_view CelestiaCore::getStartURL() const
{
return startURL;
}
void CelestiaCore::tick()
{
@ -3680,13 +3684,15 @@ using StarLoader = CatalogLoader<StarDatabase>;
using DeepSkyLoader = CatalogLoader<DSODatabase>;
bool CelestiaCore::initSimulation(const fs::path& configFileName,
const vector<fs::path>& extrasDirs,
ProgressNotifier* progressNotifier)
bool CelestiaCore::initSimulation(ProgressNotifier* progressNotifier)
{
if (!configFileName.empty())
initDataPath();
std::error_code ec;
fs::current_path(m_dataPath, ec);
if (!m_configFileName.empty())
{
config = ReadCelestiaConfig(configFileName);
config = ReadCelestiaConfig(m_configFileName);
}
else
{
@ -3723,12 +3729,12 @@ bool CelestiaCore::initSimulation(const fs::path& configFileName,
// after the ones from the config file and the order in which they were
// specified is preserved. This process in O(N*M), but the number of
// additional extras directories should be small.
for (const auto& dir : extrasDirs)
for (const auto& dir : m_extrasDirs)
{
if (find(config->extrasDirs.begin(), config->extrasDirs.end(), dir.string()) ==
if (find(config->extrasDirs.begin(), config->extrasDirs.end(), dir) ==
config->extrasDirs.end())
{
config->extrasDirs.push_back(dir.string());
config->extrasDirs.push_back(dir);
}
}
@ -4764,7 +4770,7 @@ bool CelestiaCore::saveScreenShot(const fs::path& filename, ContentType type) co
return false;
}
void CelestiaCore::setLogFile(fs::path &fn)
void CelestiaCore::setLogFile(const fs::path &fn)
{
m_logfile = std::ofstream(fn.string());
if (m_logfile.good())
@ -4779,6 +4785,39 @@ void CelestiaCore::setLogFile(fs::path &fn)
}
}
bool CelestiaCore::initDataPath()
{
// was set using command line
if (!m_dataPath.empty())
return true;
#ifdef _WIN32
const wchar_t *d = _wgetenv(L"CELESTIA_DATA_DIR");
#else
const char *d = getenv("CELESTIA_DATA_DIR");
#endif
if (d != nullptr)
{
m_dataPath = fs::path(d);
return true;
}
#ifdef NATIVE_OSX_APP
// On macOS data directory is in a fixed position relative to the
// application bundle
error_code ec;
auto curDir = fs::current_path(ec);
if (ec != error_code())
return false;
assert(curDir.is_absolute());
m_dataPath = curDir.parent_path() / "Resources";
#else
m_dataPath = fs::path(CONFIG_DATA_DIR);
#endif
return true;
}
#ifdef USE_FFMPEG
auto CelestiaCore::getSupportedMovieSizes() const
-> celestia::util::array_view<MovieSize>
@ -4800,9 +4839,9 @@ auto CelestiaCore::getSupportedMovieSizes() const
auto CelestiaCore::getSupportedMovieFramerates() const
-> celestia::util::array_view<float>
{
static std::array<float, 5> MovieFramerates =
static std::array<float, 6> MovieFramerates =
{
15.0f, 24.0f, 25.0f, 29.97f, 30.0f
15.0f, 24.0f, 25.0f, 29.97f, 30.0f, 60.0f
};
return MovieFramerates;
}
@ -4818,3 +4857,30 @@ auto CelestiaCore::getSupportedMovieCodecs() const
return MovieCodecs;
}
#endif
static void CommandLineError(const char *message)
{
cout << message << '\n';
}
util::CmdLineParser CelestiaCore::getCommandLineParser()
{
util::CmdLineParser parser;
parser.on("conf", 'c', true,
_("Configuration file name expected after --conf/-c"),
[this](const char *v) { m_configFileName = v; return true; });
parser.on("dir", 'd', true,
_("Directory expected after --dir/-d"),
[this](const char *v) { m_dataPath = v; return true; });
parser.on("extrasdir", 'e', true,
_("Directory expected after --extrasdir/-e"),
[this](const char *v) { m_extrasDirs.push_back(v); return true; });
parser.on("url", 'u', true,
_("URL expected after --url/-u"),
[this](const char *v) { setStartURL(v); return true; });
parser.on("log", 'l', true,
_("A filename expected after --log/-l"),
[this](const char *v) { setLogFile(v); return true; });
return parser;
}

View File

@ -13,10 +13,14 @@
#include <fstream>
#include <string>
#include <memory>
#include <celutil/array_view.h>
#include <celutil/cmdline.h>
#include <celutil/filetype.h>
#include <celutil/tee.h>
#include <celutil/timer.h>
#include <celutil/watcher.h>
// #include <celutil/watchable.h>
#include <celcompat/string_view.h>
#include <celengine/solarsys.h>
#include <celengine/overlay.h>
#include <celengine/texture.h>
@ -25,7 +29,6 @@
#include <celengine/simulation.h>
#include <celengine/overlayimage.h>
#include <celengine/viewporteffect.h>
#include <celutil/tee.h>
#include "configfile.h"
#include "favorites.h"
#include "destination.h"
@ -195,9 +198,7 @@ class CelestiaCore // : public Watchable<CelestiaCore>
CelestiaCore();
~CelestiaCore();
bool initSimulation(const fs::path& configFileName = fs::path(),
const std::vector<fs::path>& extrasDirs = {},
ProgressNotifier* progressNotifier = nullptr);
bool initSimulation(ProgressNotifier* progressNotifier = nullptr);
bool initRenderer();
void start(double t);
void start();
@ -206,6 +207,7 @@ class CelestiaCore // : public Watchable<CelestiaCore>
// URLs and history navigation
void setStartURL(const std::string& url);
std::string_view getStartURL() const;
bool goToUrl(const std::string& urlStr);
void addToHistory();
void back();
@ -322,12 +324,12 @@ class CelestiaCore // : public Watchable<CelestiaCore>
void notifyWatchers(int);
void setLogFile(fs::path&);
void setLogFile(const fs::path&);
class Alerter
{
public:
virtual ~Alerter() {};
virtual ~Alerter() = default;
virtual void fatalError(const std::string&) = 0;
};
@ -337,7 +339,7 @@ class CelestiaCore // : public Watchable<CelestiaCore>
class CursorHandler
{
public:
virtual ~CursorHandler() {};
virtual ~CursorHandler() = default;
virtual void setCursorShape(CursorShape) = 0;
virtual CursorShape getCursorShape() const = 0;
};
@ -389,6 +391,8 @@ class CelestiaCore // : public Watchable<CelestiaCore>
Image captureImage() const;
bool saveScreenShot(const fs::path&, ContentType = Content_Unknown) const;
celestia::util::CmdLineParser getCommandLineParser();
protected:
bool readStars(const CelestiaConfig&, ProgressNotifier*);
void renderOverlay();
@ -397,6 +401,8 @@ class CelestiaCore // : public Watchable<CelestiaCore>
#endif // CELX
private:
bool initDataPath();
CelestiaConfig* config{ nullptr };
Universe* universe{ nullptr };
@ -538,6 +544,12 @@ class CelestiaCore // : public Watchable<CelestiaCore>
std::ofstream m_logfile;
teestream m_tee;
// options passed through command line
fs::path m_dataPath;
fs::path m_configFileName;
fs::path m_logFilename;
std::vector<fs::path> m_extrasDirs;
#ifdef CELX
friend View* getViewByObserver(CelestiaCore*, Observer*);
friend void getObservers(CelestiaCore*, std::vector<Observer*>&);

View File

@ -75,24 +75,9 @@ static void initRealize(GtkWidget* widget, AppData* app);
/* Command-Line Options */
static gchar* configFile = NULL;
static gchar* installDir = NULL;
static gchar** extrasDir = NULL;
static gboolean fullScreen = FALSE;
static gboolean noSplash = FALSE;
/* Command-Line Options specification */
static GOptionEntry optionEntries[] =
{
{ "conf", 'c', 0, G_OPTION_ARG_FILENAME, &configFile, "Alternate configuration file", "file" },
{ "dir", 'd', 0, G_OPTION_ARG_FILENAME, &installDir, "Alternate installation directory", "directory" },
{ "extrasdir", 'e', 0, G_OPTION_ARG_FILENAME_ARRAY, &extrasDir, "Additional \"extras\" directory", "directory" },
{ "fullscreen", 'f', 0, G_OPTION_ARG_NONE, &fullScreen, "Start full-screen", NULL },
{ "nosplash", 's', 0, G_OPTION_ARG_NONE, &noSplash, "Disable splash screen", NULL },
{ NULL, '\0', 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
};
/* Initializes GtkActions and creates main menu */
static void createMainMenu(GtkWidget* window, AppData* app)
{
@ -339,34 +324,6 @@ int main(int argc, char* argv[])
/* Watcher enables sending signals from inside of core */
GtkWatcher* gtkWatcher;
/* Command line option parsing */
GError *error = NULL;
GOptionContext* context = g_option_context_new("");
g_option_context_add_main_entries(context, optionEntries, NULL);
g_option_context_add_group(context, gtk_get_option_group(TRUE));
g_option_context_parse(context, &argc, &argv, &error);
if (error != NULL)
{
g_print("Error in command line options. Use --help for full list.\n");
exit(1);
}
/* At this point, the argument count should be 1 or 2, with the lastX
* potentially being a cel:// URL. */
/* If there's an argument left, assume it's a URL. This happens here
* because it's after the saved prefs are applied. The appCore gets
* initialized elsewhere. */
if (argc > 1)
app->startURL = argv[argc - 1];
if (installDir == NULL)
installDir = (gchar*)CONFIG_DATA_DIR;
if (chdir(installDir) == -1)
cerr << "Cannot chdir to '" << installDir << "', probably due to improper installation.\n";
#ifdef GNOME
/* GNOME Initialization */
GnomeProgram *program;
@ -384,34 +341,20 @@ int main(int argc, char* argv[])
SetDebugVerbosity(0);
app->core = new CelestiaCore();
if (app->core == NULL)
{
cerr << "Failed to initialize Celestia core.\n";
return 1;
}
auto parser = app->core->getCommandLineParser();
parser.on("fullscreen", 'f', false,
_("Start full-screen"),
[](bool) { fullScreen = TRUE; });
parser.on("nosplash", 's', false,
_("Disable splash screen"),
[](bool) { noSplash = TRUE; });
parser.parse(argc, argv);
app->renderer = app->core->getRenderer();
g_assert(app->renderer);
/* Parse simulation arguments */
string altConfig;
if (configFile != NULL)
altConfig = string(configFile);
vector<fs::path> configDirs;
if (extrasDir != NULL)
{
/* Add each extrasDir to the vector */
int i = 0;
while (extrasDir[i] != NULL)
{
configDirs.push_back(extrasDir[i]);
i++;
}
}
/* Initialize the simulation */
if (!app->core->initSimulation(altConfig, configDirs, ss->notifier))
if (!app->core->initSimulation(ss->notifier))
return 1;
app->simulation = app->core->getSimulation();

View File

@ -187,43 +187,12 @@ CelestiaAppWindow::~CelestiaAppWindow()
}
void CelestiaAppWindow::init(const QString& qConfigFileName,
const QStringList& qExtrasDirectories,
const QString& logFilename)
void CelestiaAppWindow::init(int argc, char *argv[])
{
QString celestia_data_dir = QString::fromLocal8Bit(::getenv("CELESTIA_DATA_DIR"));
if (celestia_data_dir.isEmpty()) {
#ifdef NATIVE_OSX_APP
// On macOS data directory is in a fixed position relative to the application bundle
QString dataDir = QApplication::applicationDirPath() + "/../Resources";
#else
QString dataDir = CONFIG_DATA_DIR;
#endif
QString celestia_data_dir = dataDir;
QDir::setCurrent(celestia_data_dir);
} else if (QDir(celestia_data_dir).isReadable()) {
QDir::setCurrent(celestia_data_dir);
} else {
QMessageBox::critical(0, "Celestia",
_("Celestia is unable to run because the data directory was not "
"found, probably due to improper installation."));
exit(1);
}
// Get the config file name
string configFileName;
if (!qConfigFileName.isEmpty())
configFileName = qConfigFileName.toStdString();
// Translate extras directories from QString -> std::string
vector<fs::path> extrasDirectories;
for (const auto& dir : qExtrasDirectories)
extrasDirectories.push_back(dir.toUtf8().data());
initAppDataDirectory();
m_appCore = new CelestiaCore();
m_appCore->getCommandLineParser().parse(argc, argv);
auto* progress = new AppProgressNotifier(this);
alerter = new AppAlerter(this);
@ -231,15 +200,7 @@ void CelestiaAppWindow::init(const QString& qConfigFileName,
setWindowIcon(QIcon(":/icons/celestia.png"));
if (!logFilename.isEmpty())
{
fs::path fn(logFilename.toStdString());
m_appCore->setLogFile(fn);
}
if (!m_appCore->initSimulation(configFileName,
extrasDirectories,
progress))
if (!m_appCore->initSimulation(progress))
{
// Error message is shown by celestiacore so we silently exit here.
exit(1);

View File

@ -40,9 +40,7 @@ class CelestiaAppWindow : public QMainWindow, public CelestiaCore::ContextMenuHa
CelestiaAppWindow(QWidget* parent = nullptr);
~CelestiaAppWindow();
void init(const QString& configFileName,
const QStringList& extrasDirectories,
const QString& logFilename);
void init(int argc, char *argv[]);
void readSettings();
void writeSettings();

View File

@ -33,22 +33,6 @@
using namespace std;
//static const char *description = "Celestia";
// Command line options
static bool startFullscreen = false;
static bool runOnce = false;
static QString startURL;
static QString logFilename;
static QString startDirectory;
static QString startScript;
static QStringList extrasDirectories;
static QString configFileName;
static bool useAlternateConfigFile = false;
static bool skipSplashScreen = false;
static bool ParseCommandLine();
int main(int argc, char *argv[])
{
#ifndef GL_ES
@ -71,8 +55,6 @@ int main(int argc, char *argv[])
QCoreApplication::setOrganizationName("Celestia Development Team");
QCoreApplication::setApplicationName("Celestia QT");
ParseCommandLine();
#ifdef NATIVE_OSX_APP
// On macOS data directory is in a fixed position relative to the application bundle
QDir splashDir(QApplication::applicationDirPath() + "/../Resources/splash");
@ -112,7 +94,7 @@ int main(int argc, char *argv[])
QObject::connect(&window, SIGNAL(progressUpdate(const QString&, int, const QColor&)),
&splash, SLOT(showMessage(const QString&, int, const QColor&)));
window.init(configFileName, extrasDirectories, logFilename);
window.init(argc, argv);
window.show();
splash.finish(&window);
@ -122,103 +104,3 @@ int main(int argc, char *argv[])
return app.exec();
}
static void CommandLineError(const char* /*unused*/)
{
}
bool ParseCommandLine()
{
QStringList args = QCoreApplication::arguments();
int i = 1;
while (i < args.size())
{
bool isLastArg = (i == args.size() - 1);
#if 0
if (strcmp(argv[i], "--verbose") == 0)
{
SetDebugVerbosity(1);
}
else
#endif
if (args.at(i) == "--fullscreen")
{
startFullscreen = true;
}
else if (args.at(i) == "--once")
{
runOnce = true;
}
else if (args.at(i) == "--dir")
{
if (isLastArg)
{
CommandLineError(_("Directory expected after --dir"));
return false;
}
i++;
startDirectory = args.at(i);
}
else if (args.at(i) == "--conf")
{
if (isLastArg)
{
CommandLineError(_("Configuration file name expected after --conf"));
return false;
}
i++;
configFileName = args.at(i);
useAlternateConfigFile = true;
}
else if (args.at(i) == "--extrasdir")
{
if (isLastArg)
{
CommandLineError(_("Directory expected after --extrasdir"));
return false;
}
i++;
extrasDirectories.push_back(args.at(i));
}
else if (args.at(i) == "-u" || args.at(i) == "--url")
{
if (isLastArg)
{
CommandLineError(_("URL expected after --url"));
return false;
}
i++;
startURL = args.at(i);
}
else if (args.at(i) == "-s" || args.at(i) == "--nosplash")
{
skipSplashScreen = true;
}
else if (args.at(i) == "-l" || args.at(i) == "--log")
{
if (isLastArg)
{
CommandLineError(_("A filename expected after --log/-l"));
return false;
}
i++;
logFilename = args.at(i);
}
else
{
string buf = fmt::sprintf(_("Invalid command line option '%s'"), args.at(i).toUtf8().data());
CommandLineError(buf.c_str());
return false;
}
i++;
}
return true;
}

View File

@ -76,6 +76,11 @@ typedef vector<IntStrPair> IntStrPairVec;
char AppName[] = "Celestia";
// command line options
static bool startFullscreen = false;
static bool runOnce = false;
static bool skipSplashScreen = false;
static CelestiaCore* appCore = NULL;
// Display modes for full screen operation
@ -2997,110 +3002,6 @@ static char** splitCommandLine(LPSTR cmdLine,
}
static bool startFullscreen = false;
static bool runOnce = false;
static string startURL;
static string startDirectory;
static string startScript;
static vector<fs::path> extrasDirectories;
static string configFileName;
static bool useAlternateConfigFile = false;
static bool skipSplashScreen = false;
static bool parseCommandLine(int argc, char* argv[])
{
int i = 0;
while (i < argc)
{
bool isLastArg = (i == argc - 1);
if (strcmp(argv[i], "--verbose") == 0)
{
SetDebugVerbosity(1);
}
else if (strcmp(argv[i], "--fullscreen") == 0)
{
startFullscreen = true;
}
else if (strcmp(argv[i], "--once") == 0)
{
runOnce = true;
}
else if (strcmp(argv[i], "--dir") == 0)
{
if (isLastArg)
{
MessageBox(NULL,
_("Directory expected after --dir"),
_("Celestia Command Line Error"),
MB_OK | MB_ICONERROR);
return false;
}
i++;
startDirectory = string(argv[i]);
}
else if (strcmp(argv[i], "--conf") == 0)
{
if (isLastArg)
{
MessageBox(NULL,
_("Configuration file name expected after --conf"),
_("Celestia Command Line Error"),
MB_OK | MB_ICONERROR);
return false;
}
i++;
configFileName = string(argv[i]);
useAlternateConfigFile = true;
}
else if (strcmp(argv[i], "--extrasdir") == 0)
{
if (isLastArg)
{
MessageBox(NULL,
_("Directory expected after --extrasdir"),
_("Celestia Command Line Error"),
MB_OK | MB_ICONERROR);
return false;
}
i++;
extrasDirectories.push_back(string(argv[i]));
}
else if (strcmp(argv[i], "-u") == 0 || strcmp(argv[i], "--url") == 0)
{
if (isLastArg)
{
MessageBox(NULL,
_("URL expected after --url"),
_("Celestia Command Line Error"),
MB_OK | MB_ICONERROR);
return false;
}
i++;
startURL = string(argv[i]);
}
else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--nosplash") == 0)
{
skipSplashScreen = true;
}
else
{
char* buf = new char[strlen(argv[i]) + 256];
sprintf(buf, _("Invalid command line option '%s'"), argv[i]);
MessageBox(NULL,
buf, _("Celestia Command Line Error"),
MB_OK | MB_ICONERROR);
delete[] buf;
return false;
}
i++;
}
return true;
}
class WinSplashProgressNotifier : public ProgressNotifier
{
public:
@ -3130,9 +3031,19 @@ int APIENTRY WinMain(HINSTANCE hInstance,
int argc;
char** argv;
argv = splitCommandLine(lpCmdLine, argc);
bool cmdLineOK = parseCommandLine(argc, argv);
if (!cmdLineOK)
return 1;
appCore = new CelestiaCore();
auto parser = appCore->getCommandLineParser();
parser.on("fullscreen", 'f', false,
_("Start full-screen"),
[](bool) { startFullscreen = true; });
parser.on("nosplash", 's', false,
_("Disable splash screen"),
[](bool) { skipSplashScreen = true; });
parser.on("once", 'o', false,
_("Run only one Celestia instance"),
[](bool) { runOnce = true; });
parser.parse(argc, argv);
// If Celestia was invoked with the --once command line parameter,
// check to see if there's already an instance of Celestia running.
@ -3147,12 +3058,13 @@ int APIENTRY WinMain(HINSTANCE hInstance,
// If there's an existing instance and we've been given a
// URL on the command line, send the URL to the running instance
// of Celestia before terminating.
if (startURL != "")
auto startURL = appCore->getStartURL();
if (!startURL.empty())
{
COPYDATASTRUCT cd;
cd.dwData = 0;
cd.cbData = startURL.length();
cd.lpData = reinterpret_cast<void*>(const_cast<char*>(startURL.c_str()));
cd.lpData = reinterpret_cast<void*>(const_cast<char*>(startURL.data()));
SendMessage(existingWnd, WM_COPYDATA, 0, reinterpret_cast<LPARAM>(&cd));
}
SetForegroundWindow(existingWnd);
@ -3161,11 +3073,6 @@ int APIENTRY WinMain(HINSTANCE hInstance,
}
}
// If a start directory was given on the command line, switch to it
// now.
if (startDirectory != "")
SetCurrentDirectory(startDirectory.c_str());
s_splash = new SplashWindow(SPLASH_DIR "\\" "splash.png");
s_splash->setMessage(_("Loading data files..."));
if (!skipSplashScreen)
@ -3252,8 +3159,6 @@ int APIENTRY WinMain(HINSTANCE hInstance,
lastFullScreenMode = fallbackFullScreenMode;
}
appCore = new CelestiaCore();
// Gettext integration
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C");
@ -3282,8 +3187,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,
if (!skipSplashScreen)
progressNotifier = new WinSplashProgressNotifier(s_splash);
bool initSucceeded = appCore->initSimulation(configFileName, extrasDirectories, progressNotifier);
bool initSucceeded = appCore->initSimulation(progressNotifier);
delete progressNotifier;
// Close the splash screen after all data has been loaded
@ -3298,9 +3202,6 @@ int APIENTRY WinMain(HINSTANCE hInstance,
if (!initSucceeded)
return 1;
if (startURL != "")
appCore->setStartURL(startURL);
menuBar = CreateMenuBar();
acceleratorTable = LoadAccelerators(hRes,
MAKEINTRESOURCE(IDR_ACCELERATORS));
@ -3464,15 +3365,6 @@ int APIENTRY WinMain(HINSTANCE hInstance,
appCore->start();
if (startURL != "")
{
COPYDATASTRUCT cd;
cd.dwData = 0;
cd.cbData = startURL.length();
cd.lpData = reinterpret_cast<void*>(const_cast<char*>(startURL.c_str()));
SendMessage(mainWindow, WM_COPYDATA, 0, reinterpret_cast<LPARAM>(&cd));
}
// Initial tick required before first frame is rendered; this gives
// start up scripts a chance to run.
appCore->tick();

View File

@ -3,6 +3,8 @@ set(CELUTIL_SOURCES
bigfix.h
blockarray.h
bytes.h
cmdline.cpp
cmdline.h
color.cpp
color.h
debug.cpp

View File

@ -39,13 +39,22 @@ class array_view
~array_view() noexcept = default;
/**
* Wrap a C-style array.
* Wrap a compile-time C-style array.
*/
template<size_t N> constexpr array_view(const T (&ary)[N]) noexcept :
m_ptr(ary),
m_size(N)
{};
/**
* Wrap a run-time C-style array.
*/
constexpr array_view(const T ary[], size_t n) noexcept :
m_ptr(ary),
m_size(n)
{};
/**
* Wrap a std::array or std::vector or other classes which have the same
* memory layout and interface.

View File

@ -0,0 +1,140 @@
#include "cmdline.h"
namespace celestia
{
namespace util
{
CmdLineParser::Option::Option(const char *longOption,
char shortOption,
bool hasValue,
std::function<bool(const char*)> handler) :
hasValue(hasValue),
handler1(handler)
{
this->longOption = fmt::format("--{}", longOption);
this->shortOption = fmt::format("-{}", shortOption);
}
CmdLineParser::Option::Option(const char *longOption,
char shortOption,
bool hasValue,
std::function<void(bool)> handler) :
hasValue(hasValue),
handler0(handler)
{
this->longOption = fmt::format("--{}", longOption);
this->shortOption = fmt::format("-{}", shortOption);
}
CmdLineParser&
CmdLineParser::on(const char *longOption,
char shortOption,
bool hasValue,
const char *errorMessage,
std::function<bool(const char*)> handler)
{
(void) errorMessage;
m_options.emplace_back(longOption, shortOption, hasValue, handler);
return *this;
}
CmdLineParser&
CmdLineParser::on(const char *longOption,
char shortOption,
bool hasValue,
const char *errorMessage,
std::function<void(bool)> handler)
{
(void) errorMessage;
m_options.emplace_back(longOption, shortOption, hasValue, handler);
return *this;
}
CmdLineParser&
CmdLineParser::on(const CmdLineParser::Option &option)
{
m_options.push_back(option);
return *this;
}
const char*
CmdLineParser::getBadOption() const noexcept
{
return m_badOption;
}
CmdLineParser::ErrorClass
CmdLineParser::getError() const noexcept
{
return m_ec;
}
const char*
CmdLineParser::getErrorString() const noexcept
{
switch (m_ec)
{
case NoError:
return "no error";
case ArgumentMissing:
return "argument missing";
case UnknownOption:
return "unknown option";
default:
return "unknown error";
}
}
bool
CmdLineParser::parse(int argc, char *argv[])
{
for (int i = 1; i < argc; i++)
{
const char* arg = argv[i];
auto op = [arg](const Option &option) {
return option.longOption == arg || option.shortOption == arg;
};
auto it = std::find_if(m_options.begin(), m_options.end(), op);
if (it == m_options.end())
{
m_ec = UnknownOption;
m_badOption = argv[i];
return false;
}
if (it->hasValue)
{
if (i == argc - 1)
{
m_ec = ArgumentMissing;
m_badOption = argv[i];
return false;
}
it->handler1(argv[++i]);
}
else
{
it->handler0(true);
}
}
return true;
}
}
}
#if 0
using namespace celestia::util;
#include <iostream>
int main(int argc, char *argv[])
{
CmdLineParser cmdline;
cmdline.on("value", 'v', true, "", [](const char *value) { std::cout << value << '\n'; return true; })
.on("bool", 'b', false, "", [](bool on) { std::cout << "bool=" << on << '\n'; });
if (!cmdline.parse(argc, argv))
{
std::cerr << "Bad option: " << cmdline.getBadOption() << ", " << cmdline.getErrorString() << '\n';
}
std::cout << sizeof(std::function<void(const char*)>) << ' ' << sizeof(std::function<void()>) << '\n';
return 0;
}
#endif

View File

@ -0,0 +1,67 @@
#pragma once
#include <algorithm>
#include <functional>
#include <string>
#include <vector>
#include <fmt/format.h>
namespace celestia
{
namespace util
{
class CmdLineParser
{
public:
enum ErrorClass
{
NoError = 0,
ArgumentMissing = 1,
UnknownOption = 2,
};
struct Option
{
std::string longOption;
std::string shortOption;
bool hasValue;
std::function<bool(const char*)> handler1;
std::function<void(bool)> handler0;
Option(const char *longOption,
char shortOption,
bool hasValue,
std::function<bool(const char*)> handler);
Option(const char *longOption,
char shortOption,
bool hasValue,
std::function<void(bool)> handler);
};
bool parse(int argc, char *argv[]);
const char* getBadOption() const noexcept;
ErrorClass getError() const noexcept;
const char* getErrorString() const noexcept;
CmdLineParser& on(const char *longOption,
char shortOption,
bool hasValue,
const char *errorMessage,
std::function<bool(const char*)> handler);
CmdLineParser& on(const char *longOption,
char shortOption,
bool hasValue,
const char *errorMessage,
std::function<void(bool)> handler);
CmdLineParser& on(const Option &option);
private:
std::vector<Option> m_options;
const char* m_badOption { nullptr };
ErrorClass m_ec { NoError };
};
}
}

View File

@ -14,7 +14,6 @@ add_subdirectory(charm2)
add_subdirectory(cmod)
add_subdirectory(galaxies)
add_subdirectory(globulars)
add_subdirectory(qttxf)
add_subdirectory(spice2xyzv)
add_subdirectory(stardb)
add_subdirectory(vsop)