PoC: better argument building.

Add a few more ideas to todo.
This commit is contained in:
2025-10-26 08:21:34 +04:00
parent 44bc63d17d
commit 516c6fa732
7 changed files with 392 additions and 92 deletions

View File

@@ -5,6 +5,7 @@
#include <argument_parser.hpp>
#include <crt_externs.h>
#include <parser_v2.hpp>
#include <string>
namespace argument_parser {
@@ -13,13 +14,28 @@ namespace argument_parser {
macos_parser() {
const int argc = *_NSGetArgc();
if (char **argv = *_NSGetArgv(); argc > 0 && argv != nullptr && argv[0] != nullptr) {
program_name = argv[0];
program_name = (argv[0]);
for (int i = 1; i < argc; ++i) {
if (argv[i] != nullptr) parsed_arguments.emplace_back(argv[i]);
}
}
}
};
namespace v2 {
class macos_parser : public v2::base_parser {
public:
macos_parser() {
const int argc = *_NSGetArgc();
if (char **argv = *_NSGetArgv(); argc > 0 && argv != nullptr && argv[0] != nullptr) {
set_program_name(argv[0]);
for (int i = 1; i < argc; ++i) {
if (argv[i] != nullptr) ref_parsed_args().emplace_back(argv[i]);
}
}
}
};
}
}
#endif

View File

@@ -1,98 +1,61 @@
#pragma once
#ifdef _WIN32
#ifndef WINDOWS_PARSER_HPP
// compiler bitches if you don't use lean and mean and remove shit ton of other macros that comes preloaded with the windows api.
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
// I'm speaking to you Microsoft, STOP MAKING EVERYTHING A FUCKING MACRO. IT BREAKES CPP!
#define NOGDI
#define NOHELP
#define NOMCX
#define NOIME
#define NOCOMM
#define NOKANJI
#define NOSERVICE
#define NOMDI
#define NOSOUND
// also this fixes error about no architecture being targeted (somehow)
#if defined(_M_AMD64) && !defined(_AMD64_)
# define _AMD64_
#endif
#if defined(_M_IX86) && !defined(_X86_)
# define _X86_
#endif
#if defined(_M_ARM64) && !defined(_ARM64_)
# define _ARM64_
#endif
#include <argument_parser.hpp>
#include <fstream>
#include <memory>
#include <string>
// THIS HAS TO BE THE FIRST. DON'T CHANGE THEIR ORDER.
#include <windows.h>
#include <processenv.h>
#include <shellapi.h>
namespace argument_parser {
class windows_parser : public base_parser {
public:
windows_parser() {
int nArgs;
LPWSTR commandLineA = GetCommandLineW();
auto argvW = std::unique_ptr<LPWSTR, local_free_deleter> { CommandLineToArgvW(commandLineA, &nArgs) };
if (argvW == nullptr) {
throw std::runtime_error("Failed to get command line arguments.");
}
class windows_parser : public base_parser {
public:
windows_parser() {
int nArgs = 0;
LPWSTR* raw = ::CommandLineToArgvW(::GetCommandLineW(), &nArgs);
if (!raw) {
throw std::runtime_error("CommandLineToArgvW failed (" +
std::to_string(::GetLastError()) + ")");
}
std::unique_ptr<LPWSTR, void(*)(LPWSTR*)> argvW{ raw, [](LPWSTR* p){ if (p) ::LocalFree(p); } };
if (nArgs <= 0) {
throw std::runtime_error("No command line arguments found, including program name.");
}
program_name = utf8_from_wstring(argvW.get()[0]);
parsed_arguments.reserve(static_cast<size_t>(nArgs - 1));
for (int i = 1; i < nArgs; ++i) {
parsed_arguments.emplace_back(utf8_from_wstring(argvW.get()[i]));
}
if (nArgs <= 0) {
throw std::runtime_error("No command line arguments found.");
}
private:
struct local_free_deleter {
void operator()(HLOCAL ptr) const noexcept {
if (ptr != nullptr) ::LocalFree(ptr);
}
};
static std::string utf8_from_wstring(const std::wstring& w) {
if (w.empty()) return {};
int needed = ::WideCharToMultiByte(CP_UTF8, 0, w.c_str(), -1, nullptr, 0, nullptr, nullptr);
if (needed == 0) {
throw std::runtime_error("WideCharToMultiByte sizing failed ("
+ std::to_string(GetLastError()) + ")");
}
std::string out;
out.resize(static_cast<size_t>(needed - 1));
int written = ::WideCharToMultiByte(CP_UTF8, 0, w.c_str(), -1,
out.data(), needed, nullptr, nullptr);
if (written == 0) {
throw std::runtime_error("WideCharToMultiByte convert failed ("
+ std::to_string(GetLastError()) + ")");
}
return out;
{
std::wstring w0 = argvW.get()[0];
auto pos = w0.find_last_of(L"\\/");
std::wstring base = (pos == std::wstring::npos) ? w0 : w0.substr(pos + 1);
program_name = utf8_from_wstring(base);
}
};
using parser = windows_parser;
parsed_arguments.reserve(static_cast<size_t>(nArgs > 0 ? nArgs - 1 : 0));
for (int i = 1; i < nArgs; ++i) {
parsed_arguments.emplace_back(utf8_from_wstring(argvW.get()[i]));
}
}
private:
static std::string utf8_from_wstring(const std::wstring& w) {
if (w.empty()) return {};
int needed = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
w.c_str(), -1, nullptr, 0, nullptr, nullptr);
if (needed <= 0) {
throw std::runtime_error("WideCharToMultiByte sizing failed (" +
std::to_string(::GetLastError()) + ")");
}
std::string out;
out.resize(static_cast<size_t>(needed - 1));
int written = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
w.c_str(), -1, out.data(), needed - 1, nullptr, nullptr);
if (written <= 0) {
throw std::runtime_error("WideCharToMultiByte convert failed (" +
std::to_string(::GetLastError()) + ")");
}
return out;
}
};
}
#endif
#endif