Fix non-portable argc/argv

This commit is contained in:
Will Toohey
2026-01-31 15:44:31 +10:00
parent 06f4217166
commit 2416c68614
6 changed files with 98 additions and 15 deletions

View File

@@ -1,10 +1,11 @@
project('layeredfs', 'c', 'cpp', version: '3.9',
project('layeredfs', 'c', 'cpp', version: '3.10',
default_options: [
'cpp_std=c++20',
'buildtype=release',
'strip=true',
'werror=true',
]
],
meson_version: '>=1.2.0',
)
add_project_link_arguments('-static', language: 'cpp')
@@ -204,3 +205,21 @@ test('unit tests', executable('tests_bin',
),
workdir: meson.current_source_dir(),
)
test('commandline parsing test', executable('test_commandline',
sources: 'src/test_commandline.cpp',
link_with: [layeredfs_lib, texbin_lib, avs_standalone_lib],
dependencies: [layeredfs_cfg_dep, gtest_main_dep, gmock_dep],
build_by_default: false,
),
workdir: meson.current_source_dir(),
args: [
'--layered-disable',
'--layered-verbose',
'--layered-devmode',
'--layered-allowlist=allowed,these folders',
'--layered-blocklist=blocked,these folders',
'--layered-logfile=some logfile.log',
'--layered-data-mods-folder=./some modfolder',
]
)

View File

@@ -67,39 +67,55 @@ void load_config(void) {
config.logfile = NULL;
#endif
int i;
int argc;
auto argv = CommandLineToArgvW(GetCommandLineW(), &argc);
if (!argv) {
log_warning("Couldn't fetch commandline args!");
return;
}
char* arg;
// so close to just pulling in a third party argparsing lib...
for (i = 0; i < __argc; i++) {
if (strcmp(__argv[i], VERBOSE_FLAG) == 0) {
for (int i = 0; i < argc; i++) {
if (!wstr_narrow(argv[i], &arg))
continue;
if (strcmp(arg, VERBOSE_FLAG) == 0) {
config.verbose_logs = true;
free(arg);
}
else if (strcmp(__argv[i], DEVMODE_FLAG) == 0) {
else if (strcmp(arg, DEVMODE_FLAG) == 0) {
config.developer_mode = true;
free(arg);
}
else if (strcmp(__argv[i], DISABLE_FLAG) == 0) {
else if (strcmp(arg, DISABLE_FLAG) == 0) {
config.disable = true;
free(arg);
}
else if (strncmp(__argv[i], ALLOWLIST_FLAG, strlen(ALLOWLIST_FLAG)) == 0) {
allowlist = parse_list(ALLOWLIST_FLAG, __argv[i], config.allowlist);
else if (strncmp(arg, ALLOWLIST_FLAG, strlen(ALLOWLIST_FLAG)) == 0) {
allowlist = parse_list(ALLOWLIST_FLAG, arg, config.allowlist);
}
else if (strncmp(__argv[i], BLOCKLIST_FLAG, strlen(BLOCKLIST_FLAG)) == 0) {
blocklist = parse_list(BLOCKLIST_FLAG, __argv[i], config.blocklist);
else if (strncmp(arg, BLOCKLIST_FLAG, strlen(BLOCKLIST_FLAG)) == 0) {
blocklist = parse_list(BLOCKLIST_FLAG, arg, config.blocklist);
}
else if (strncmp(__argv[i], LOGFILE_FLAG, strlen(LOGFILE_FLAG)) == 0) {
const char *path = &__argv[i][strlen(LOGFILE_FLAG)];
else if (strncmp(arg, LOGFILE_FLAG, strlen(LOGFILE_FLAG)) == 0) {
const char *path = &arg[strlen(LOGFILE_FLAG)];
// correct format: --layered-logfile=whatever.log
if(path[0] == '=' && path[1]) {
config.logfile = &path[1];
}
}
else if (strncmp(__argv[i], MOD_FOLDER_FLAG, strlen(MOD_FOLDER_FLAG)) == 0) {
std::string_view path = &__argv[i][strlen(MOD_FOLDER_FLAG)];
else if (strncmp(arg, MOD_FOLDER_FLAG, strlen(MOD_FOLDER_FLAG)) == 0) {
std::string_view path = &arg[strlen(MOD_FOLDER_FLAG)];
// correct format: --layered-data-mods-folder=./my_mods
if(path.starts_with("=./")) {
config.mod_folder = path.substr(1);
}
}
else {
free(arg);
}
}
}

20
src/test_commandline.cpp Normal file
View File

@@ -0,0 +1,20 @@
#include <sstream>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "config.hpp"
#include "avs_standalone.hpp"
using ::testing::ElementsAre;
TEST(Cmdline, ConfigParsingWorks) {
load_config();
EXPECT_EQ(config.verbose_logs, 1);
EXPECT_EQ(config.developer_mode, 1);
EXPECT_EQ(config.disable, 1);
EXPECT_STREQ(config.logfile, "some logfile.log");
EXPECT_THAT(config.allowlist, ElementsAre("allowed", "these folders"));
EXPECT_THAT(config.blocklist, ElementsAre("blocked", "these folders"));
EXPECT_EQ(config.mod_folder, "./some modfolder");
}

View File

@@ -99,6 +99,33 @@ wchar_t *str_widen(const char *src)
return result;
}
bool wstr_narrow(const wchar_t *src, char **dest)
{
int nbytes;
nbytes = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
if (nbytes <= 0) {
goto size_fail;
}
*dest = (char*)malloc(nbytes);
if (WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, nbytes, NULL, NULL) !=
nbytes) {
goto conv_fail;
}
return true;
conv_fail:
free(*dest);
*dest = NULL;
size_fail:
return false;
}
bool file_exists(const char* name) {
// file_exists is only used by the modfile machinery, so use the easy
// method, not avs_fs_open or avs_fs_lstat

View File

@@ -21,6 +21,7 @@ bool string_replace_first(std::string &str, const char* from, const char* to);
// Like string.find(), but case insensitive
std::size_t string_find_icase(const std::string & strHaystack, const std::string & strNeedle, std::size_t off = 0);
wchar_t *str_widen(const char *src);
bool wstr_narrow(const wchar_t *src, char **dest);
void str_toupper_inline(std::string &str);
bool file_exists(const char* name);
bool folder_exists(const char* name);

BIN
xp_dlls/shell32.dll Normal file

Binary file not shown.