mirror of
https://github.com/alterware/iw4-validator.git
synced 2025-04-19 08:32:53 +00:00
maint: better parsing of main arguments
Co-authored-by: William Roy <wroy@proton.me>
This commit is contained in:
parent
dc0759ee63
commit
0b374cd08f
102
src/main.cpp
102
src/main.cpp
@ -6,116 +6,86 @@
|
||||
#include "game/cg_client_side_effects_mp.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
bool load_client_effects(const std::string& filename)
|
||||
void load_client_effects(const std::string& filename)
|
||||
{
|
||||
assert(!filename.empty());
|
||||
if (filename.empty())
|
||||
{
|
||||
console::error("filename parameter is empty\n");
|
||||
return false;
|
||||
throw std::runtime_error("filename parameter is empty");
|
||||
}
|
||||
|
||||
const auto data = utils::io::read_file(filename);
|
||||
if (data.empty())
|
||||
std::string data;
|
||||
if (!utils::io::read_file(filename, &data) || data.empty())
|
||||
{
|
||||
console::error("'%s' is empty\n", filename.data());
|
||||
return false;
|
||||
throw std::runtime_error(utils::string::va("'%s' is empty", filename.data()));
|
||||
}
|
||||
|
||||
return game::parse_client_effects(data.data());
|
||||
game::parse_client_effects(data.data());
|
||||
}
|
||||
|
||||
bool load_map_rotation(const std::string& filename)
|
||||
void load_map_rotation(const std::string& filename)
|
||||
{
|
||||
assert(!filename.empty());
|
||||
if (filename.empty())
|
||||
{
|
||||
console::error("filename parameter is empty\n");
|
||||
return false;
|
||||
throw std::runtime_error("filename parameter is empty");
|
||||
}
|
||||
|
||||
const auto data = utils::io::read_file(filename);
|
||||
if (data.empty())
|
||||
std::string data;
|
||||
if (!utils::io::read_file(filename, &data) || data.empty())
|
||||
{
|
||||
console::error("'%s' is empty\n", filename.data());
|
||||
return false;
|
||||
throw std::runtime_error(utils::string::va("'%s' is empty", filename.data()));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
map_rotation::rotation_data rotation_data;
|
||||
rotation_data.parse(data);
|
||||
|
||||
console::info("Successfully parsed map rotation\n");
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
console::error("%s: '%s' contains invalid data!\n", ex.what(), filename.data());
|
||||
return false;
|
||||
console::error(utils::string::va("%s: '%s' contains invalid data!", ex.what(), filename.data()));
|
||||
}
|
||||
}
|
||||
|
||||
console::info("Successfully parsed map rotation\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int unsafe_main(std::string&& prog, std::vector<std::string>&& args)
|
||||
{
|
||||
// Parse command-line flags (only increment i for matching flags)
|
||||
for (auto i = args.begin(); i != args.end();)
|
||||
void unsafe_main(const std::span<char*> s)
|
||||
{
|
||||
if (*i == "-createfx")
|
||||
auto p = [&](const std::string& o, const std::function <void(const std::string&)>& c) -> void
|
||||
{
|
||||
++i;
|
||||
const auto filename = i != args.end() ? *i++ : std::string();
|
||||
console::info("Parsing createfx '%s'\n", filename.data());
|
||||
|
||||
if (!load_client_effects(filename))
|
||||
auto r(s | std::views::transform([](char* v) -> std::string
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
else if (*i == "-map-rotation")
|
||||
return { v };
|
||||
}));
|
||||
|
||||
const auto i(std::ranges::find(r, o));
|
||||
const auto e(r.end());
|
||||
|
||||
if (auto n(i != e ? std::ranges::next(i, 1, e) : e); i != e && n != e)
|
||||
{
|
||||
++i;
|
||||
const auto filename = i != args.end() ? *i++ : std::string();
|
||||
console::info("Parsing map rotation '%s'\n", filename.data());
|
||||
|
||||
if (!load_map_rotation(filename))
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
c({ *n });
|
||||
}
|
||||
};
|
||||
|
||||
p("-createfx", load_client_effects);
|
||||
p("-map-rotation", load_map_rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
console::info("X Labs IW4x validator tool\n"
|
||||
"Usage: %s OPTIONS\n"
|
||||
" -createfx <filename>\n"
|
||||
" -fx <filename>\n"
|
||||
" -map-rotation <filename>\n",
|
||||
prog.data()
|
||||
);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
console::set_title("X Labs IW4x-validator");
|
||||
console::log("Starting X Labs IW4x-validator");
|
||||
console::set_title("AlterWare IW4x-validator");
|
||||
console::log("Starting AlterWare iw4-validator");
|
||||
|
||||
try
|
||||
{
|
||||
std::string prog(argv[0]);
|
||||
std::vector<std::string> args;
|
||||
|
||||
args.reserve(argc - 1);
|
||||
args.assign(argv + 1, argv + argc);
|
||||
return unsafe_main(std::move(prog), std::move(args));
|
||||
unsafe_main(std::span(argv, argc));
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
|
@ -22,7 +22,7 @@
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <csignal>
|
||||
@ -30,12 +30,15 @@
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <ranges>
|
||||
#include <span>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
106
src/utils/memory.cpp
Normal file
106
src/utils/memory.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
#include <std_include.hpp>
|
||||
#include "memory.hpp"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
memory::allocator memory::mem_allocator_;
|
||||
|
||||
memory::allocator::~allocator()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
void memory::allocator::clear()
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
|
||||
for (const auto& data : this->pool_)
|
||||
{
|
||||
memory::free(data);
|
||||
}
|
||||
|
||||
this->pool_.clear();
|
||||
}
|
||||
|
||||
void memory::allocator::free(void* data)
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
|
||||
const auto j = std::find(this->pool_.begin(), this->pool_.end(), data);
|
||||
if (j != this->pool_.end())
|
||||
{
|
||||
memory::free(data);
|
||||
this->pool_.erase(j);
|
||||
}
|
||||
}
|
||||
|
||||
void memory::allocator::free(const void* data)
|
||||
{
|
||||
this->free(const_cast<void*>(data));
|
||||
}
|
||||
|
||||
void* memory::allocator::allocate(const std::size_t length)
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
|
||||
const auto data = memory::allocate(length);
|
||||
this->pool_.push_back(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
bool memory::allocator::empty() const
|
||||
{
|
||||
return this->pool_.empty();
|
||||
}
|
||||
|
||||
char* memory::allocator::duplicate_string(const std::string& string)
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
|
||||
const auto data = memory::duplicate_string(string);
|
||||
this->pool_.push_back(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void* memory::allocate(const std::size_t length)
|
||||
{
|
||||
return ::calloc(1, length);
|
||||
}
|
||||
|
||||
char* memory::duplicate_string(const std::string& string)
|
||||
{
|
||||
const auto new_string = allocate_array<char>(string.size() + 1);
|
||||
std::memcpy(new_string, string.data(), string.size());
|
||||
return new_string;
|
||||
}
|
||||
|
||||
void memory::free(void* data)
|
||||
{
|
||||
::free(data);
|
||||
}
|
||||
|
||||
void memory::free(const void* data)
|
||||
{
|
||||
free(const_cast<void*>(data));
|
||||
}
|
||||
|
||||
bool memory::is_set(const void* mem, const char chr, const std::size_t length)
|
||||
{
|
||||
auto* const mem_arr = static_cast<const char*>(mem);
|
||||
|
||||
for (std::size_t i = 0; i < length; ++i)
|
||||
{
|
||||
if (mem_arr[i] != chr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
memory::allocator* memory::get_allocator()
|
||||
{
|
||||
return &memory::mem_allocator_;
|
||||
}
|
||||
}
|
68
src/utils/memory.hpp
Normal file
68
src/utils/memory.hpp
Normal file
@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils
|
||||
{
|
||||
class memory final
|
||||
{
|
||||
public:
|
||||
class allocator final
|
||||
{
|
||||
public:
|
||||
~allocator();
|
||||
|
||||
void clear();
|
||||
|
||||
void free(void* data);
|
||||
|
||||
void free(const void* data);
|
||||
|
||||
void* allocate(std::size_t length);
|
||||
|
||||
template <typename T>
|
||||
T* allocate()
|
||||
{
|
||||
return this->allocate_array<T>(1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* allocate_array(const std::size_t count = 1)
|
||||
{
|
||||
return static_cast<T*>(this->allocate(count * sizeof(T)));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool empty() const;
|
||||
|
||||
char* duplicate_string(const std::string& string);
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::vector<void*> pool_;
|
||||
};
|
||||
|
||||
static void* allocate(std::size_t length);
|
||||
|
||||
template <typename T>
|
||||
static T* allocate()
|
||||
{
|
||||
return allocate_array<T>(1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T* allocate_array(const std::size_t count = 1)
|
||||
{
|
||||
return static_cast<T*>(allocate(count * sizeof(T)));
|
||||
}
|
||||
|
||||
static char* duplicate_string(const std::string& string);
|
||||
|
||||
static void free(void* data);
|
||||
static void free(const void* data);
|
||||
|
||||
static bool is_set(const void* mem, char chr, std::size_t length);
|
||||
|
||||
static allocator* get_allocator();
|
||||
|
||||
private:
|
||||
static allocator mem_allocator_;
|
||||
};
|
||||
}
|
@ -3,6 +3,19 @@
|
||||
|
||||
namespace utils::string
|
||||
{
|
||||
const char* va(const char* fmt, ...)
|
||||
{
|
||||
static thread_local va_provider<8, 256> provider;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
const auto* result = provider.get(fmt, ap);
|
||||
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(const std::string& s, const char delim)
|
||||
{
|
||||
std::stringstream ss(s);
|
||||
|
@ -1,7 +1,87 @@
|
||||
#pragma once
|
||||
#include "memory.hpp"
|
||||
|
||||
namespace utils::string
|
||||
{
|
||||
template <class Type, std::size_t n>
|
||||
constexpr auto ARRAY_COUNT(Type(&)[n]) { return n; }
|
||||
|
||||
template <std::size_t buffers, std::size_t min_buffer_size>
|
||||
class va_provider final
|
||||
{
|
||||
public:
|
||||
static_assert(buffers != 0 && min_buffer_size != 0, "buffers and min_buffer_size mustn't be 0");
|
||||
|
||||
va_provider() : current_buffer_(0)
|
||||
{
|
||||
}
|
||||
|
||||
char* get(const char* format, va_list ap)
|
||||
{
|
||||
++this->current_buffer_ %= ARRAY_COUNT(this->string_pool_);
|
||||
auto entry = &this->string_pool_[this->current_buffer_];
|
||||
|
||||
if (!entry->size_ || !entry->buffer_)
|
||||
{
|
||||
throw std::runtime_error("The string pool is not initialized");
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const auto res = vsnprintf_s(entry->buffer_, entry->size_, _TRUNCATE, format, ap);
|
||||
#else
|
||||
const auto res = vsnprintf(entry->buffer_, entry->size_, format, ap);
|
||||
#endif
|
||||
|
||||
if (res > 0) break; // Success
|
||||
if (res == 0) return nullptr; // Error
|
||||
|
||||
entry->double_size();
|
||||
}
|
||||
|
||||
return entry->buffer_;
|
||||
}
|
||||
|
||||
private:
|
||||
class entry final
|
||||
{
|
||||
public:
|
||||
explicit entry(const std::size_t size = min_buffer_size) : size_(size), buffer_(nullptr)
|
||||
{
|
||||
if (this->size_ < min_buffer_size) this->size_ = min_buffer_size;
|
||||
this->allocate();
|
||||
}
|
||||
|
||||
~entry()
|
||||
{
|
||||
if (this->buffer_) memory::get_allocator()->free(this->buffer_);
|
||||
this->size_ = 0;
|
||||
this->buffer_ = nullptr;
|
||||
}
|
||||
|
||||
void allocate()
|
||||
{
|
||||
if (this->buffer_) memory::get_allocator()->free(this->buffer_);
|
||||
this->buffer_ = memory::get_allocator()->allocate_array<char>(this->size_ + 1);
|
||||
}
|
||||
|
||||
void double_size()
|
||||
{
|
||||
this->size_ *= 2;
|
||||
this->allocate();
|
||||
}
|
||||
|
||||
std::size_t size_;
|
||||
char* buffer_;
|
||||
};
|
||||
|
||||
std::size_t current_buffer_;
|
||||
entry string_pool_[buffers];
|
||||
};
|
||||
|
||||
const char* va(const char* fmt, ...);
|
||||
|
||||
std::vector<std::string> split(const std::string& s, char delim);
|
||||
|
||||
std::string to_lower(const std::string& text);
|
||||
|
Loading…
x
Reference in New Issue
Block a user