summaryrefslogtreecommitdiffstats
path: root/src/yuzu_cmd/citra.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu_cmd/citra.cpp')
-rw-r--r--src/yuzu_cmd/citra.cpp175
1 files changed, 175 insertions, 0 deletions
diff --git a/src/yuzu_cmd/citra.cpp b/src/yuzu_cmd/citra.cpp
new file mode 100644
index 000000000..e524c5535
--- /dev/null
+++ b/src/yuzu_cmd/citra.cpp
@@ -0,0 +1,175 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+
+// This needs to be included before getopt.h because the latter #defines symbols used by it
+#include "common/microprofile.h"
+
+#ifdef _MSC_VER
+#include <getopt.h>
+#else
+#include <getopt.h>
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+// windows.h needs to be included before shellapi.h
+#include <windows.h>
+
+#include <shellapi.h>
+#endif
+
+#include "citra/config.h"
+#include "citra/emu_window/emu_window_sdl2.h"
+#include "common/logging/backend.h"
+#include "common/logging/filter.h"
+#include "common/logging/log.h"
+#include "common/scm_rev.h"
+#include "common/scope_exit.h"
+#include "common/string_util.h"
+#include "core/core.h"
+#include "core/gdbstub/gdbstub.h"
+#include "core/loader/loader.h"
+#include "core/settings.h"
+
+static void PrintHelp(const char* argv0) {
+ std::cout << "Usage: " << argv0
+ << " [options] <filename>\n"
+ "-g, --gdbport=NUMBER Enable gdb stub on port NUMBER\n"
+ "-h, --help Display this help and exit\n"
+ "-v, --version Output version information and exit\n";
+}
+
+static void PrintVersion() {
+ std::cout << "Citra " << Common::g_scm_branch << " " << Common::g_scm_desc << std::endl;
+}
+
+/// Application entry point
+int main(int argc, char** argv) {
+ Config config;
+ int option_index = 0;
+ bool use_gdbstub = Settings::values.use_gdbstub;
+ u32 gdb_port = static_cast<u32>(Settings::values.gdbstub_port);
+ char* endarg;
+#ifdef _WIN32
+ int argc_w;
+ auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w);
+
+ if (argv_w == nullptr) {
+ LOG_CRITICAL(Frontend, "Failed to get command line arguments");
+ return -1;
+ }
+#endif
+ std::string filepath;
+
+ static struct option long_options[] = {
+ {"gdbport", required_argument, 0, 'g'},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'v'},
+ {0, 0, 0, 0},
+ };
+
+ while (optind < argc) {
+ char arg = getopt_long(argc, argv, "g:hv", long_options, &option_index);
+ if (arg != -1) {
+ switch (arg) {
+ case 'g':
+ errno = 0;
+ gdb_port = strtoul(optarg, &endarg, 0);
+ use_gdbstub = true;
+ if (endarg == optarg)
+ errno = EINVAL;
+ if (errno != 0) {
+ perror("--gdbport");
+ exit(1);
+ }
+ break;
+ case 'h':
+ PrintHelp(argv[0]);
+ return 0;
+ case 'v':
+ PrintVersion();
+ return 0;
+ }
+ } else {
+#ifdef _WIN32
+ filepath = Common::UTF16ToUTF8(argv_w[optind]);
+#else
+ filepath = argv[optind];
+#endif
+ optind++;
+ }
+ }
+
+#ifdef _WIN32
+ LocalFree(argv_w);
+#endif
+
+ Log::Filter log_filter(Log::Level::Debug);
+ Log::SetFilter(&log_filter);
+
+ MicroProfileOnThreadCreate("EmuThread");
+ SCOPE_EXIT({ MicroProfileShutdown(); });
+
+ if (filepath.empty()) {
+ LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
+ return -1;
+ }
+
+ log_filter.ParseFilterString(Settings::values.log_filter);
+
+ // Apply the command line arguments
+ Settings::values.gdbstub_port = gdb_port;
+ Settings::values.use_gdbstub = use_gdbstub;
+ Settings::Apply();
+
+ std::unique_ptr<EmuWindow_SDL2> emu_window{std::make_unique<EmuWindow_SDL2>()};
+
+ Core::System& system{Core::System::GetInstance()};
+
+ SCOPE_EXIT({ system.Shutdown(); });
+
+ const Core::System::ResultStatus load_result{system.Load(emu_window.get(), filepath)};
+
+ switch (load_result) {
+ case Core::System::ResultStatus::ErrorGetLoader:
+ LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filepath.c_str());
+ return -1;
+ case Core::System::ResultStatus::ErrorLoader:
+ LOG_CRITICAL(Frontend, "Failed to load ROM!");
+ return -1;
+ case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted:
+ LOG_CRITICAL(Frontend, "The game that you are trying to load must be decrypted before "
+ "being used with Citra. \n\n For more information on dumping and "
+ "decrypting games, please refer to: "
+ "https://citra-emu.org/wiki/dumping-game-cartridges/");
+ return -1;
+ case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
+ LOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported.");
+ return -1;
+ case Core::System::ResultStatus::ErrorNotInitialized:
+ LOG_CRITICAL(Frontend, "CPUCore not initialized");
+ return -1;
+ case Core::System::ResultStatus::ErrorSystemMode:
+ LOG_CRITICAL(Frontend, "Failed to determine system mode!");
+ return -1;
+ case Core::System::ResultStatus::ErrorVideoCore:
+ LOG_CRITICAL(Frontend, "VideoCore not initialized");
+ return -1;
+ case Core::System::ResultStatus::Success:
+ break; // Expected case
+ }
+
+ Core::Telemetry().AddField(Telemetry::FieldType::App, "Frontend", "SDL");
+
+ while (emu_window->IsOpen()) {
+ system.RunLoop();
+ }
+
+ return 0;
+}