Compare commits
3 Commits
cc2dfc0218
...
93cab1ee41
| Author | SHA1 | Date | |
|---|---|---|---|
| 93cab1ee41 | |||
| 831e03e868 | |||
| 884e597e35 |
+3
-1
@@ -28,7 +28,9 @@ BreakConstructorInitializers: AfterColon
|
|||||||
BreakConstructorInitializersBeforeComma: false
|
BreakConstructorInitializersBeforeComma: false
|
||||||
ColumnLimit: 120
|
ColumnLimit: 120
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
ContinuationIndentWidth: 4
|
IndentAccessModifiers: false
|
||||||
|
AccessModifierOffset: 0
|
||||||
|
ContinuationIndentWidth: 0
|
||||||
IncludeCategories:
|
IncludeCategories:
|
||||||
- Regex: '^<.*'
|
- Regex: '^<.*'
|
||||||
Priority: 1
|
Priority: 1
|
||||||
|
|||||||
+2
-1
@@ -1,2 +1,3 @@
|
|||||||
tests/
|
tests/
|
||||||
build/
|
build/
|
||||||
|
.vscode/
|
||||||
+4
-2
@@ -8,6 +8,7 @@ option(BUILD_SHARED_LIBS OFF)
|
|||||||
|
|
||||||
include_directories(external/ELFIO)
|
include_directories(external/ELFIO)
|
||||||
include_directories(external/capstone/include)
|
include_directories(external/capstone/include)
|
||||||
|
include_directories(external/cflags/include)
|
||||||
include_directories(external)
|
include_directories(external)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
@@ -18,5 +19,6 @@ set(CAPSTONE_ARCHITECTURE_DEFAULT OFF)
|
|||||||
set(CAPSTONE_PPC_SUPPORT ON)
|
set(CAPSTONE_PPC_SUPPORT ON)
|
||||||
add_subdirectory(external/capstone)
|
add_subdirectory(external/capstone)
|
||||||
|
|
||||||
add_executable(weee main.cpp)
|
add_executable(weee main.cpp core/mem.cpp)
|
||||||
target_link_libraries(weee PUBLIC capstone)
|
target_link_libraries(weee PUBLIC capstone)
|
||||||
|
target_include_directories(weee PUBLIC core)
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#include <cstring>
|
||||||
|
#include <mem.hpp>
|
||||||
|
#include <ircolib/log.hpp>
|
||||||
|
|
||||||
|
namespace weee::core {
|
||||||
|
mem::mem() {
|
||||||
|
mem1.resize(24_mib);
|
||||||
|
std::fill(mem1.begin(), mem1.end(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem::copy(const std::vector<ircolib::u8> &src, const ircolib::u32 offset) {
|
||||||
|
if (offset + src.size() >= mem1.size())
|
||||||
|
ircolib::panic("mem::copy outside mem1 range (src @ 0x{:08} for size 0x{:08X})", offset, src.size());
|
||||||
|
|
||||||
|
std::println("Copying {} bytes to mem1[{}]", src.size(), offset);
|
||||||
|
std::copy(src.begin(), src.end(), mem1.begin() + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem::copy(const ircolib::u8 *src, const ircolib::u32 size, const ircolib::u32 offset) {
|
||||||
|
if (offset + size >= mem1.size())
|
||||||
|
ircolib::panic("mem::copy outside mem1 range (src @ 0x{:08} for size 0x{:08X})", offset, size);
|
||||||
|
|
||||||
|
std::println("Copying {} bytes to mem1[{}]", size, offset);
|
||||||
|
memcpy(&mem1[offset], src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem::set(const ircolib::u8 val, const ircolib::u32 size, const ircolib::u32 offset) {
|
||||||
|
if (offset + size >= mem1.size())
|
||||||
|
ircolib::panic("mem::set outside mem1 range (@ 0x{:08} for size 0x{:08X})", offset, size);
|
||||||
|
|
||||||
|
std::println("Setting {} bytes to {} from mem1[{}]", size, val, offset);
|
||||||
|
memset(&mem1[offset], val, size);
|
||||||
|
}
|
||||||
|
} // namespace weee::core
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
#include <ircolib/types.hpp>
|
||||||
|
|
||||||
|
namespace weee::core {
|
||||||
|
struct mem {
|
||||||
|
mem();
|
||||||
|
|
||||||
|
void copy(const std::vector<ircolib::u8> &src, const ircolib::u32 offset);
|
||||||
|
void copy(const ircolib::u8 *src, const ircolib::u32 size, const ircolib::u32 offset);
|
||||||
|
void set(const ircolib::u8 val, const ircolib::u32 size, const ircolib::u32 offset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<ircolib::u8> mem1;
|
||||||
|
};
|
||||||
|
} // namespace weee::core
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
*.vs
|
||||||
|
*.vscode
|
||||||
|
/[Bb]uild
|
||||||
|
|
||||||
Vendored
+121
@@ -0,0 +1,121 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
|
||||||
|
|
||||||
|
project(
|
||||||
|
cflags
|
||||||
|
LANGUAGES C CXX
|
||||||
|
DESCRIPTION "Command line flag parsing library in C/C++"
|
||||||
|
VERSION 3.0.3
|
||||||
|
)
|
||||||
|
|
||||||
|
###
|
||||||
|
### cflags
|
||||||
|
###
|
||||||
|
|
||||||
|
add_library(cflags INTERFACE)
|
||||||
|
add_library(cflags::cflags ALIAS cflags)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
cflags INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
)
|
||||||
|
|
||||||
|
###
|
||||||
|
### cppflags
|
||||||
|
###
|
||||||
|
|
||||||
|
add_library(cppflags INTERFACE)
|
||||||
|
add_library(cflags::cppflags ALIAS cppflags)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
cppflags INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(
|
||||||
|
cppflags
|
||||||
|
PROPERTIES
|
||||||
|
CXX_STANDARD 17
|
||||||
|
CXX_STANDARD_REQUIRED ON
|
||||||
|
)
|
||||||
|
|
||||||
|
###
|
||||||
|
### Install
|
||||||
|
###
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS cflags cppflags
|
||||||
|
EXPORT cflagsTargets
|
||||||
|
INCLUDES DESTINATION include
|
||||||
|
)
|
||||||
|
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
write_basic_package_version_file(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/cflagsConfigVersion.cmake
|
||||||
|
VERSION ${PROJECT_VERSION}
|
||||||
|
COMPATIBILITY AnyNewerVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
EXPORT cflagsTargets
|
||||||
|
NAMESPACE cflags::
|
||||||
|
DESTINATION lib/cmake/cflags
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_package_config_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/cmake/cflagsConfig.cmake.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/cflagsConfig.cmake
|
||||||
|
INSTALL_DESTINATION lib/cmake/cflags
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/cflagsConfigVersion.cmake
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/cflagsConfig.cmake
|
||||||
|
DESTINATION lib/cmake/cflags
|
||||||
|
)
|
||||||
|
|
||||||
|
include(FindPkgConfig)
|
||||||
|
|
||||||
|
if(PKG_CONFIG_FOUND)
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/cmake/cflags.pc.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/cflags.pc
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES ${CMAKE_CURRENT_BINARY_DIR}/cflags.pc
|
||||||
|
DESTINATION share/pkgconfig
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(
|
||||||
|
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
|
||||||
|
DESTINATION include
|
||||||
|
)
|
||||||
|
|
||||||
|
###
|
||||||
|
### Test executables
|
||||||
|
###
|
||||||
|
|
||||||
|
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
add_executable(example examples/example.c)
|
||||||
|
|
||||||
|
target_link_libraries(example cflags)
|
||||||
|
|
||||||
|
add_executable(example-cpp examples/example.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(example-cpp cppflags)
|
||||||
|
|
||||||
|
set_target_properties(
|
||||||
|
example-cpp
|
||||||
|
PROPERTIES
|
||||||
|
CXX_STANDARD 17
|
||||||
|
CXX_STANDARD_REQUIRED ON
|
||||||
|
)
|
||||||
|
|
||||||
|
endif()
|
||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Stephen Lane-Walsh
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
Vendored
+310
@@ -0,0 +1,310 @@
|
|||||||
|
|
||||||
|
# cflags
|
||||||
|
|
||||||
|
Command line flag parsing library in C
|
||||||
|
|
||||||
|
Heavily inspired by Go's `flag` package
|
||||||
|
https://golang.org/pkg/flag/
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
cflags is a header only library. To use it, simply copy `cflags.h` or `cflags.hpp` to your project, or add it to your include path.
|
||||||
|
|
||||||
|
You may also install it using cmake, like so:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake path/to/source
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
This will install both CMake and pkg-config configuration files.
|
||||||
|
|
||||||
|
## Argument Parsing Logic
|
||||||
|
|
||||||
|
* The first argument is stored in `program`
|
||||||
|
* The following arguments are parsed left to right
|
||||||
|
* If an argument does not start with `-`, it is placed in the additional arguments list stored in `args/argv`
|
||||||
|
* If the special `--` argument appears, all following arguments are treated as positional
|
||||||
|
e.g. `-c 4 -- --name hello` would parse the `-c`, but place `--name` and `hello` into `args/argv`
|
||||||
|
* Arguments starting with `--` are long name flags, e.g. `--example`
|
||||||
|
* The list of flags is searched for one with `long_name` equal to the argument name (after the `--`), e.g. `long_name == example`
|
||||||
|
* If a flag is not found with that name, an error is printed and `parse()` returns false
|
||||||
|
* Arguments starting with just `-` are short name flags, e.g. `-xvf`
|
||||||
|
* These can be grouped together, so they are searched one at a time from left to right, e.g. `x`, `v`, then `f`
|
||||||
|
* If any of these fail to match a flag, an error is printed and `parse()` returns false
|
||||||
|
* Once a flag is found, it attempts to find a value
|
||||||
|
* Arguments with long names can also come in the forms `--name`, `--name=value`, or `--name value`
|
||||||
|
* Arguemnts with short names can come in the forms `-n`, or `-n value`
|
||||||
|
* Note: Only the last short flag of a group can have a value, e.g. `-xvf file` will work, but `-xfv file` will fail
|
||||||
|
* If the flag is of type `[c]string`, `int`, or `float` then a value is required, and if one is not found an error is printed and `parse()` returns false
|
||||||
|
* Arguments of type `bool` can have a value, e.g. `--debug=false`, but one is not required
|
||||||
|
* Each time a flag is encountered, the `count` member is incremented
|
||||||
|
* The value for a flag is overwritten each time the flag is processed, the last argument parsed wins, e.g. `-c 4 -c 10` will result in `-c` being 10
|
||||||
|
* If you want to capture each argument separately, use `add_*_callback` instead
|
||||||
|
|
||||||
|
## Usage (C)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <cflags.h>
|
||||||
|
|
||||||
|
void process_string(const char * str)
|
||||||
|
{
|
||||||
|
printf("processing %s\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_bool(bool b)
|
||||||
|
{
|
||||||
|
printf("processing %d\n", b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_int(int i)
|
||||||
|
{
|
||||||
|
printf("processing %d\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_float(float f)
|
||||||
|
{
|
||||||
|
printf("processing %f\n", f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
// Create a cflags object
|
||||||
|
cflags_t * flags = cflags_init();
|
||||||
|
|
||||||
|
// Add a bool flag, which will be callable with -d or --debug
|
||||||
|
// The value will be true if it exists, and can bet set to false
|
||||||
|
// by saying -d false or --debug=false
|
||||||
|
bool debug = false;
|
||||||
|
cflags_add_bool(flags, 'd', "debug", &debug, "enable debug mode");
|
||||||
|
|
||||||
|
// Add a similar help flag, which will be callable with just --help
|
||||||
|
bool help = false;
|
||||||
|
cflags_add_bool(flags, '\0', "help", &help, "print this text and exit");
|
||||||
|
|
||||||
|
// Add a string flag
|
||||||
|
const char * string = NULL;
|
||||||
|
cflags_add_string(flags, 's', "string", &string, "enter a string");
|
||||||
|
|
||||||
|
// Add an int flag
|
||||||
|
int count = 0;
|
||||||
|
cflags_add_int(flags, 'c', "count", &count, "enter a number");
|
||||||
|
|
||||||
|
// Add a float flag
|
||||||
|
float amount = 0.f;
|
||||||
|
cflags_add_float(flags, 'a', "amount", &amount, "enter a float");
|
||||||
|
|
||||||
|
// Add a string callback flag. This will call the supplied function with the value
|
||||||
|
// when it is parsed
|
||||||
|
cflags_add_string_callback(flags, 'f', "file", &process_string, "process a file");
|
||||||
|
|
||||||
|
cflags_add_bool_callback(flags, 'q', "bool-flag", &process_bool, "process a bool");
|
||||||
|
|
||||||
|
cflags_add_int_callback(flags, 'w', "int-flag", &process_int, "process a int");
|
||||||
|
|
||||||
|
cflags_add_float_callback(flags, 'e', "float-flag", &process_float, "process a float");
|
||||||
|
|
||||||
|
// Add a flag that can be called multiple times
|
||||||
|
cflags_flag_t * verbose = cflags_add_bool(flags, 'v', "verbose", NULL, "enables verbose output, repeat up to 4 times for more verbosity");
|
||||||
|
|
||||||
|
// Parse the command arguments
|
||||||
|
if (!cflags_parse(flags, argc, argv) || help || flags->argc == 0) {
|
||||||
|
cflags_print_usage(flags,
|
||||||
|
"[OPTION]... [ARG]...",
|
||||||
|
"Tests the cflags library.",
|
||||||
|
"Additional information about this library can be found by at:\n"
|
||||||
|
" https://github.com/WhoBrokeTheBuild/cflags");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("debug: %d\n", debug);
|
||||||
|
printf("string: %s\n", string);
|
||||||
|
printf("count: %d\n", count);
|
||||||
|
printf("amount: %f\n", amount);
|
||||||
|
|
||||||
|
// Print the number of times verbose was added
|
||||||
|
printf("verbosity: %d\n", verbose->count);
|
||||||
|
|
||||||
|
// Print any additional arguments, in the order they were parsed
|
||||||
|
for (int i = 1; i < flags->argc; ++i) {
|
||||||
|
printf("positional arg %d: %s\n", i, flags->argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
cflags_free(flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage (C++)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <cflags.hpp>
|
||||||
|
|
||||||
|
void process_string(std::string str)
|
||||||
|
{
|
||||||
|
printf("processing %s\n", str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_cstring(const char * str)
|
||||||
|
{
|
||||||
|
printf("processing %s\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_bool(bool b)
|
||||||
|
{
|
||||||
|
printf("processing %d\n", b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_int(int i)
|
||||||
|
{
|
||||||
|
printf("processing %d\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_float(float f)
|
||||||
|
{
|
||||||
|
printf("processing %f\n", f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * argv[])
|
||||||
|
{
|
||||||
|
// Create a cflags object
|
||||||
|
cflags::cflags flags;
|
||||||
|
|
||||||
|
// Add a bool flag, which will be callable with -d or --debug
|
||||||
|
// The value will be true if it exists, and can bet set to false
|
||||||
|
// by saying -d false or --debug=false
|
||||||
|
bool debug = false;
|
||||||
|
flags.add_bool('d', "debug", &debug, "enable debug mode");
|
||||||
|
|
||||||
|
// Add a similar help flag, which will be callable with just --help
|
||||||
|
bool help = false;
|
||||||
|
flags.add_bool('\0', "help", &help, "print this text and exit");
|
||||||
|
|
||||||
|
// Add a string flag
|
||||||
|
std::string string;
|
||||||
|
flags.add_string('s', "string", &string, "enter a string");
|
||||||
|
|
||||||
|
// Add a cstring flag
|
||||||
|
const char * cstring = NULL;
|
||||||
|
flags.add_cstring('\0', "cstring", &cstring, "enter a string (cstring)");
|
||||||
|
|
||||||
|
// Add an int flag
|
||||||
|
int count = 0;
|
||||||
|
flags.add_int('c', "count", &count, "enter a number");
|
||||||
|
|
||||||
|
// Add a float flag
|
||||||
|
float amount = 0.f;
|
||||||
|
flags.add_float('a', "amount", &amount, "enter a float");
|
||||||
|
|
||||||
|
// Add a string callback flag. This will call the supplied function with the value
|
||||||
|
// when it is parsed
|
||||||
|
flags.add_string_callback('f', "file", &process_string, "process a file");
|
||||||
|
|
||||||
|
flags.add_cstring_callback('\0', "cfile", &process_cstring, "process a file (cstring)");
|
||||||
|
|
||||||
|
flags.add_bool_callback('q', "bool-flag", &process_bool, "process a bool");
|
||||||
|
|
||||||
|
flags.add_int_callback('w', "int-flag", &process_int, "process a int");
|
||||||
|
|
||||||
|
flags.add_float_callback('e', "float-flag", &process_float, "process a float");
|
||||||
|
|
||||||
|
// You can also use lambdas
|
||||||
|
flags.add_string_callback('l', "lambda",
|
||||||
|
[](std::string value) {
|
||||||
|
printf("Hello %s\n", value.c_str());
|
||||||
|
},
|
||||||
|
"use a lambda function"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add a flag that can be called multiple times
|
||||||
|
auto verbose = flags.add_bool('v', "verbose", NULL, "enables verbose output, repeat up to 4 times for more verbosity");
|
||||||
|
|
||||||
|
// Parse the command arguments
|
||||||
|
if (!flags.parse(argc, argv) || help || flags.argc == 0) {
|
||||||
|
flags.print_usage(
|
||||||
|
"[OPTION]... [ARG]...",
|
||||||
|
"Tests the cflags library.",
|
||||||
|
"Additional information about this library can be found by at:\n"
|
||||||
|
" https://github.com/WhoBrokeTheBuild/cflags");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("debug: %d\n", debug);
|
||||||
|
printf("string: %s\n", string.c_str());
|
||||||
|
printf("cstring: %s\n", cstring);
|
||||||
|
printf("count: %d\n", count);
|
||||||
|
printf("amount: %f\n", amount);
|
||||||
|
|
||||||
|
// Print the number of times verbose was added
|
||||||
|
printf("verbosity: %d\n", verbose->count);
|
||||||
|
|
||||||
|
// Print any additional arguments, in the order they were parsed
|
||||||
|
for (auto& arg : flags.args) {
|
||||||
|
printf("positional arg %s\n", arg.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
// For backwards compatability, the additional arguments are also exposed in argc/argv
|
||||||
|
for (int i = 0; i < flags.argc; ++i) {
|
||||||
|
printf("positional arg %d: %s\n", i, flags.argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quirks
|
||||||
|
|
||||||
|
### 1. Only the last short-name argument in a group may have a value.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
```cpp
|
||||||
|
flags.add_string('f', "file", parse_filename, "parse a filename");
|
||||||
|
flags.add_bool('d', "debug", &debug, "enable debug mode");
|
||||||
|
|
||||||
|
// These will work
|
||||||
|
test -df test.txt
|
||||||
|
test -df test.txt -f test2.txt
|
||||||
|
|
||||||
|
// And these will fail
|
||||||
|
test -fd test.txt
|
||||||
|
test -ff test.txt test2.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Any `char *` strings point to the original memory from `argv`
|
||||||
|
|
||||||
|
Call the following code as `program -s hello`
|
||||||
|
```cpp
|
||||||
|
int main(int argc, char ** argv)
|
||||||
|
{
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
printf("argv[%d] @ %p: %s\n", i, argv[i], argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cflags_t * flags = cflags_init();
|
||||||
|
|
||||||
|
const char * string = NULL;
|
||||||
|
cflags_add_string(flags, 's', "string", &string, "enter a string");
|
||||||
|
|
||||||
|
cflags_parse(flags, argc, argv);
|
||||||
|
|
||||||
|
// The address pointed to by `string` is the same memory pointed to by argv
|
||||||
|
printf("string @ %p: %s\n", string, string);
|
||||||
|
|
||||||
|
cflags_free(flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example output
|
||||||
|
```
|
||||||
|
argv[1] @ 0000024F6BDD665F: -s
|
||||||
|
argv[2] @ 0000024F6BDD6662: hello
|
||||||
|
string @ 0000024F6BDD6662: hello
|
||||||
|
```
|
||||||
|
|
||||||
|
When parsing arguments in the form `--name=value`, the memory pointed to by `argv` is altered and the `=` is replaced by a `\0`.
|
||||||
|
|
||||||
|
When using the C++ version, arguments as `std::string` do not point at `argv` as their memory gets copied.
|
||||||
|
|
||||||
|
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
includedir=include
|
||||||
|
|
||||||
|
Name: cflags
|
||||||
|
Description: Command Line Argument Parser in C
|
||||||
|
Version: @VERSION@
|
||||||
|
|
||||||
|
Requires:
|
||||||
|
Cflags: -I${includedir}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/cflagsTargets.cmake")
|
||||||
|
check_required_components("@PROJECT_NAME@")
|
||||||
Vendored
+56
@@ -0,0 +1,56 @@
|
|||||||
|
#include "cflags.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void parse_file(const char * filename)
|
||||||
|
{
|
||||||
|
printf("parsing %s\n", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
cflags_t * flags = cflags_init();
|
||||||
|
|
||||||
|
bool help = false;
|
||||||
|
cflags_add_bool(flags, '\0', "help", &help, "display this help and exit");
|
||||||
|
|
||||||
|
bool debug = false;
|
||||||
|
cflags_add_bool(flags, 'd', "debug", &debug, "enable debug mode");
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
cflags_add_int(flags, 'c', "count", &count, "enter a number");
|
||||||
|
|
||||||
|
float amount = 0.f;
|
||||||
|
cflags_add_float(flags, 'a', "amount", &amount, "enter a float");
|
||||||
|
|
||||||
|
cflags_add_bool(flags, 'q', "really-long-argument-name", NULL, "testing really long argument names");
|
||||||
|
|
||||||
|
cflags_add_string_callback(flags, 'f', "file", &parse_file, "process a file");
|
||||||
|
|
||||||
|
cflags_flag_t * verbose = cflags_add_bool(flags, 'v', "verbose", NULL, "enables verbose output, repeat up to 4 times for more verbosity");
|
||||||
|
|
||||||
|
// Parse the command arguments
|
||||||
|
if (!cflags_parse(flags, argc, argv) || help || argc == 1) {
|
||||||
|
cflags_print_usage(flags,
|
||||||
|
"[OPTION]... [ARG]...",
|
||||||
|
"Tests the cflags library.",
|
||||||
|
"Additional information about this library can be found by at:\n"
|
||||||
|
" https://github.com/WhoBrokeTheBuild/cflags");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("help: %d\n", help);
|
||||||
|
printf("debug: %d\n", debug);
|
||||||
|
|
||||||
|
printf("count: %d\n", count);
|
||||||
|
printf("amount: %f\n", amount);
|
||||||
|
|
||||||
|
printf("verbosity: %d\n", verbose->count);
|
||||||
|
|
||||||
|
printf("argc/argv:\n");
|
||||||
|
for (int i = 0; i < flags->argc; ++i) {
|
||||||
|
printf("positional %d: %s\n", i, flags->argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cflags_free(flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Vendored
+64
@@ -0,0 +1,64 @@
|
|||||||
|
#include "cflags.hpp"
|
||||||
|
|
||||||
|
void parse_file(const char * filename)
|
||||||
|
{
|
||||||
|
printf("parsing %s\n", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * argv[])
|
||||||
|
{
|
||||||
|
cflags::cflags flags;
|
||||||
|
|
||||||
|
bool help = false;
|
||||||
|
flags.add_bool('\0', "help", &help, "display this help and exit");
|
||||||
|
|
||||||
|
bool debug = false;
|
||||||
|
flags.add_bool('d', "debug", &debug, "enable debug mode");
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
flags.add_int('c', "count", &count, "enter a number");
|
||||||
|
|
||||||
|
float amount = 0.f;
|
||||||
|
flags.add_float('a', "amount", &amount, "enter a float");
|
||||||
|
|
||||||
|
flags.add_bool('q', "really-long-argument-name", nullptr, "testing really long argument names");
|
||||||
|
|
||||||
|
flags.add_cstring_callback('f', "file", &parse_file, "process a file");
|
||||||
|
|
||||||
|
flags.add_string_callback('n', "name",
|
||||||
|
[](std::string name) {
|
||||||
|
printf("Hello %s\n", name.c_str());
|
||||||
|
},
|
||||||
|
"say hello to name");
|
||||||
|
|
||||||
|
auto verbose = flags.add_bool('v', "verbose", NULL, "enables verbose output, repeat up to 4 times for more verbosity");
|
||||||
|
|
||||||
|
if (!flags.parse(argc, argv) || help || argc == 1) {
|
||||||
|
flags.print_usage(
|
||||||
|
"[OPTION]... [ARG]...",
|
||||||
|
"Tests the cflags library.",
|
||||||
|
"Additional information about this library can be found by contacting:\n"
|
||||||
|
" sdl.slane@gmail.com");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("help: %d\n", help);
|
||||||
|
printf("debug: %d\n", debug);
|
||||||
|
|
||||||
|
printf("count: %d\n", count);
|
||||||
|
printf("amount: %f\n", amount);
|
||||||
|
|
||||||
|
printf("verbosity: %d\n", verbose->count);
|
||||||
|
|
||||||
|
printf("args:\n");
|
||||||
|
for (auto& arg : flags.args) {
|
||||||
|
printf("Positional %s\n", arg.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("argc/argv:\n");
|
||||||
|
for (int i = 0; i < flags.argc; ++i) {
|
||||||
|
printf("positional %d: %s\n", i, flags.argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Vendored
+505
@@ -0,0 +1,505 @@
|
|||||||
|
//
|
||||||
|
// cflags version 3.0.3
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2022 Stephen Lane-Walsh
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef CFLAGS_H
|
||||||
|
#define CFLAGS_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#define CFLAGS_ERROR_OOM "cflags: out of memory"
|
||||||
|
|
||||||
|
enum cflags_type
|
||||||
|
{
|
||||||
|
CFLAGS_TYPE_UNDEFINED = -1,
|
||||||
|
CFLAGS_TYPE_STRING,
|
||||||
|
CFLAGS_TYPE_BOOL,
|
||||||
|
CFLAGS_TYPE_INT,
|
||||||
|
CFLAGS_TYPE_FLOAT,
|
||||||
|
CFLAGS_TYPE_STRING_CALLBACK,
|
||||||
|
CFLAGS_TYPE_BOOL_CALLBACK,
|
||||||
|
CFLAGS_TYPE_INT_CALLBACK,
|
||||||
|
CFLAGS_TYPE_FLOAT_CALLBACK,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum cflags_type cflags_type_t;
|
||||||
|
|
||||||
|
struct cflags_flag
|
||||||
|
{
|
||||||
|
char short_name;
|
||||||
|
const char * long_name;
|
||||||
|
const char * description;
|
||||||
|
|
||||||
|
cflags_type_t type;
|
||||||
|
unsigned count;
|
||||||
|
|
||||||
|
struct cflags_flag * next;
|
||||||
|
|
||||||
|
union {
|
||||||
|
const char ** string_ptr;
|
||||||
|
bool * bool_ptr;
|
||||||
|
int * int_ptr;
|
||||||
|
float * float_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
void (*string_callback)(const char *);
|
||||||
|
void (*bool_callback)(bool);
|
||||||
|
void (*int_callback)(int);
|
||||||
|
void (*float_callback)(float);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct cflags_flag cflags_flag_t;
|
||||||
|
|
||||||
|
struct cflags
|
||||||
|
{
|
||||||
|
const char * program;
|
||||||
|
|
||||||
|
int argc;
|
||||||
|
char ** argv;
|
||||||
|
|
||||||
|
cflags_flag_t * first_flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct cflags cflags_t;
|
||||||
|
|
||||||
|
static cflags_t * cflags_init()
|
||||||
|
{
|
||||||
|
cflags_t * flags = (cflags_t *)malloc(sizeof(cflags_t));
|
||||||
|
if (!flags) {
|
||||||
|
fprintf(stderr, CFLAGS_ERROR_OOM);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags->program = NULL;
|
||||||
|
flags->argc = 0;
|
||||||
|
flags->argv = NULL;
|
||||||
|
flags->first_flag = NULL;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
cflags_flag_t * _cflags_add_flag(cflags_t * flags)
|
||||||
|
{
|
||||||
|
cflags_flag_t ** next_flag = &flags->first_flag;
|
||||||
|
|
||||||
|
while (*next_flag) {
|
||||||
|
next_flag = &(*next_flag)->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
*next_flag = (cflags_flag_t *)malloc(sizeof(cflags_flag_t));
|
||||||
|
if (!*next_flag) {
|
||||||
|
fprintf(stderr, CFLAGS_ERROR_OOM);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*next_flag)->short_name = '\0';
|
||||||
|
(*next_flag)->long_name = NULL;
|
||||||
|
(*next_flag)->type = CFLAGS_TYPE_UNDEFINED;
|
||||||
|
(*next_flag)->count = 0;
|
||||||
|
(*next_flag)->description = NULL;
|
||||||
|
(*next_flag)->next = NULL;
|
||||||
|
|
||||||
|
return *next_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cflags_flag_t * cflags_add_string(cflags_t * flags, char short_name, const char * long_name, const char ** value, const char * description)
|
||||||
|
{
|
||||||
|
cflags_flag_t * flag = _cflags_add_flag(flags);
|
||||||
|
if (!flag) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag->short_name = short_name;
|
||||||
|
flag->long_name = long_name;
|
||||||
|
flag->type = CFLAGS_TYPE_STRING;
|
||||||
|
flag->string_ptr = value;
|
||||||
|
flag->description = description;
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cflags_flag_t * cflags_add_bool(cflags_t * flags, char short_name, const char * long_name, bool * value, const char * description)
|
||||||
|
{
|
||||||
|
cflags_flag_t * flag = _cflags_add_flag(flags);
|
||||||
|
if (!flag) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag->short_name = short_name;
|
||||||
|
flag->long_name = long_name;
|
||||||
|
flag->type = CFLAGS_TYPE_BOOL;
|
||||||
|
flag->bool_ptr = value;
|
||||||
|
flag->description = description;
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cflags_flag_t * cflags_add_int(cflags_t * flags, char short_name, const char * long_name, int * value, const char * description)
|
||||||
|
{
|
||||||
|
cflags_flag_t * flag = _cflags_add_flag(flags);
|
||||||
|
if (!flag) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag->short_name = short_name;
|
||||||
|
flag->long_name = long_name;
|
||||||
|
flag->type = CFLAGS_TYPE_INT;
|
||||||
|
flag->int_ptr = value;
|
||||||
|
flag->description = description;
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cflags_flag_t * cflags_add_float(cflags_t * flags, char short_name, const char * long_name, float * value, const char * description)
|
||||||
|
{
|
||||||
|
cflags_flag_t * flag = _cflags_add_flag(flags);
|
||||||
|
if (!flag) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag->short_name = short_name;
|
||||||
|
flag->long_name = long_name;
|
||||||
|
flag->type = CFLAGS_TYPE_FLOAT;
|
||||||
|
flag->float_ptr = value;
|
||||||
|
flag->description = description;
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cflags_flag_t * cflags_add_string_callback(cflags_t * flags, char short_name, const char * long_name, void (*func)(const char *), const char * description)
|
||||||
|
{
|
||||||
|
cflags_flag_t * flag = _cflags_add_flag(flags);
|
||||||
|
if (!flag) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag->short_name = short_name;
|
||||||
|
flag->long_name = long_name;
|
||||||
|
flag->type = CFLAGS_TYPE_STRING_CALLBACK;
|
||||||
|
flag->string_callback = func;
|
||||||
|
flag->description = description;
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cflags_flag_t * cflags_add_bool_callback(cflags_t * flags, char short_name, const char * long_name, void (*func)(bool), const char * description)
|
||||||
|
{
|
||||||
|
cflags_flag_t * flag = _cflags_add_flag(flags);
|
||||||
|
if (!flag) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag->short_name = short_name;
|
||||||
|
flag->long_name = long_name;
|
||||||
|
flag->type = CFLAGS_TYPE_BOOL_CALLBACK;
|
||||||
|
flag->bool_callback = func;
|
||||||
|
flag->description = description;
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cflags_flag_t * cflags_add_int_callback(cflags_t * flags, char short_name, const char * long_name, void (*func)(int), const char * description)
|
||||||
|
{
|
||||||
|
cflags_flag_t * flag = _cflags_add_flag(flags);
|
||||||
|
if (!flag) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag->short_name = short_name;
|
||||||
|
flag->long_name = long_name;
|
||||||
|
flag->type = CFLAGS_TYPE_INT_CALLBACK;
|
||||||
|
flag->int_callback = func;
|
||||||
|
flag->description = description;
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cflags_flag_t * cflags_add_float_callback(cflags_t * flags, char short_name, const char * long_name, void (*func)(float), const char * description)
|
||||||
|
{
|
||||||
|
cflags_flag_t * flag = _cflags_add_flag(flags);
|
||||||
|
if (!flag) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag->short_name = short_name;
|
||||||
|
flag->long_name = long_name;
|
||||||
|
flag->type = CFLAGS_TYPE_FLOAT_CALLBACK;
|
||||||
|
flag->float_callback = func;
|
||||||
|
flag->description = description;
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _cflags_parse_bool(const char * str)
|
||||||
|
{
|
||||||
|
return !(strcmp(str, "false") == 0 ||
|
||||||
|
strcmp(str, "FALSE") == 0 ||
|
||||||
|
strcmp(str, "0") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _cflags_process_flag(cflags_flag_t * flag, const char * value)
|
||||||
|
{
|
||||||
|
++flag->count;
|
||||||
|
|
||||||
|
switch (flag->type) {
|
||||||
|
case CFLAGS_TYPE_STRING:
|
||||||
|
if (flag->string_ptr) {
|
||||||
|
*flag->string_ptr = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CFLAGS_TYPE_STRING_CALLBACK:
|
||||||
|
if (flag->string_callback) {
|
||||||
|
flag->string_callback(value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CFLAGS_TYPE_BOOL:
|
||||||
|
if (flag->bool_ptr) {
|
||||||
|
if (value) {
|
||||||
|
*flag->bool_ptr = _cflags_parse_bool(value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*flag->bool_ptr = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CFLAGS_TYPE_BOOL_CALLBACK:
|
||||||
|
if (flag->bool_callback) {
|
||||||
|
if (value) {
|
||||||
|
flag->bool_callback(_cflags_parse_bool(value));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
flag->bool_callback(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CFLAGS_TYPE_INT:
|
||||||
|
if (flag->int_ptr) {
|
||||||
|
if (value) {
|
||||||
|
*flag->int_ptr = strtol(value, NULL, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CFLAGS_TYPE_INT_CALLBACK:
|
||||||
|
if (flag->int_callback) {
|
||||||
|
if (value) {
|
||||||
|
flag->int_callback(strtol(value, NULL, 10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CFLAGS_TYPE_FLOAT:
|
||||||
|
if (flag->float_ptr) {
|
||||||
|
if (value) {
|
||||||
|
*flag->float_ptr = strtof(value, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CFLAGS_TYPE_FLOAT_CALLBACK:
|
||||||
|
if (flag->float_callback) {
|
||||||
|
if (value) {
|
||||||
|
flag->float_callback(strtof(value, NULL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cflags_parse(cflags_t * flags, int argc, char ** argv)
|
||||||
|
{
|
||||||
|
flags->argc = 1;
|
||||||
|
flags->argv = (char **)malloc(flags->argc * sizeof(char *));
|
||||||
|
if (!flags->argv) {
|
||||||
|
fprintf(stderr, CFLAGS_ERROR_OOM);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
flags->argv[0] = argv[0];
|
||||||
|
flags->program = flags->argv[0];
|
||||||
|
|
||||||
|
bool passthrough = false;
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
char * pch = argv[i];
|
||||||
|
if (!passthrough && *pch == '-') {
|
||||||
|
++pch;
|
||||||
|
if (*pch == '-') {
|
||||||
|
++pch;
|
||||||
|
|
||||||
|
if (*pch == '\0') {
|
||||||
|
// All following flags are not to be processed
|
||||||
|
passthrough = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Long
|
||||||
|
char * key = pch;
|
||||||
|
char * value = NULL;
|
||||||
|
|
||||||
|
char * divider = strchr(pch, '=');
|
||||||
|
if (divider) {
|
||||||
|
*divider = '\0';
|
||||||
|
value = divider + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next_arg_is_value = (i + 1 < argc && argv[i + 1][0] != '-');
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
cflags_flag_t * flag = flags->first_flag;
|
||||||
|
while (flag) {
|
||||||
|
if (strcmp(flag->long_name, key) == 0) {
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
_cflags_process_flag(flag, value);
|
||||||
|
}
|
||||||
|
else if (next_arg_is_value) {
|
||||||
|
_cflags_process_flag(flag, argv[i + 1]);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
else if (flag->type == CFLAGS_TYPE_BOOL || flag->type == CFLAGS_TYPE_BOOL_CALLBACK) {
|
||||||
|
_cflags_process_flag(flag, NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "%s: option '--%s' requires an value\n", flags->program, key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag = flag->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
fprintf(stderr, "%s: unrecognized option '--%s'\n", flags->program, key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Short
|
||||||
|
while (*pch) {
|
||||||
|
bool is_last_short_flag = (*(pch + 1) == '\0');
|
||||||
|
bool next_arg_is_value = (i + 1 < argc && argv[i + 1][0] != '-');
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
cflags_flag_t * flag = flags->first_flag;
|
||||||
|
while (flag) {
|
||||||
|
if (flag->short_name == *pch) {
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
if (is_last_short_flag && next_arg_is_value) {
|
||||||
|
_cflags_process_flag(flag, argv[i + 1]);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
else if (flag->type == CFLAGS_TYPE_BOOL || flag->type == CFLAGS_TYPE_BOOL_CALLBACK) {
|
||||||
|
_cflags_process_flag(flag, NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "%s: option '-%c' requires an value\n", flags->program, *pch);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag = flag->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
fprintf(stderr, "%s: unrecognized option '-%c'\n", flags->program, *pch);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
++pch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++flags->argc;
|
||||||
|
char ** tmp = (char **)realloc(flags->argv, flags->argc * sizeof(char *));
|
||||||
|
if (!tmp) {
|
||||||
|
fprintf(stderr, CFLAGS_ERROR_OOM);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
flags->argv = tmp;
|
||||||
|
flags->argv[flags->argc - 1] = pch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cflags_free(cflags_t * flags)
|
||||||
|
{
|
||||||
|
free(flags->argv);
|
||||||
|
flags->argv = NULL;
|
||||||
|
|
||||||
|
cflags_flag_t * tmp = NULL;
|
||||||
|
cflags_flag_t * flag = flags->first_flag;
|
||||||
|
while (flag) {
|
||||||
|
tmp = flag;
|
||||||
|
flag = flag->next;
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(flags);
|
||||||
|
flags = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cflags_print_usage(cflags_t * flags, const char * usage, const char * above, const char * below)
|
||||||
|
{
|
||||||
|
printf("%s %s\n", flags->program, usage);
|
||||||
|
printf("%s\n\n", above);
|
||||||
|
|
||||||
|
cflags_flag_t * flag = flags->first_flag;
|
||||||
|
while (flag) {
|
||||||
|
printf(" ");
|
||||||
|
if (flag->short_name != '\0') {
|
||||||
|
printf("-%c, ", flag->short_name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
size_t long_name_len = 0;
|
||||||
|
if (flag->long_name) {
|
||||||
|
printf("--%s", flag->long_name);
|
||||||
|
long_name_len = strlen(flag->long_name);
|
||||||
|
}
|
||||||
|
if (long_name_len > 20) {
|
||||||
|
printf("\n ");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (size_t i = 0; i < 20 - long_name_len; ++i) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("%s\n", flag->description);
|
||||||
|
flag = flag->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n%s\n", below);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // CFLAGS_H
|
||||||
Vendored
+484
@@ -0,0 +1,484 @@
|
|||||||
|
//
|
||||||
|
// cflags version 3.0.3
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2022 Stephen Lane-Walsh
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef CFLAGS_HPP
|
||||||
|
#define CFLAGS_HPP
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace cflags {
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using std::string_view;
|
||||||
|
using std::vector;
|
||||||
|
using std::function;
|
||||||
|
|
||||||
|
struct flag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum class type
|
||||||
|
{
|
||||||
|
Undefined = -1,
|
||||||
|
String,
|
||||||
|
CString,
|
||||||
|
Bool,
|
||||||
|
Int,
|
||||||
|
Float,
|
||||||
|
StringCallback,
|
||||||
|
CStringCallback,
|
||||||
|
BoolCallback,
|
||||||
|
IntCallback,
|
||||||
|
FloatCallback,
|
||||||
|
};
|
||||||
|
|
||||||
|
char short_name;
|
||||||
|
string long_name;
|
||||||
|
string description;
|
||||||
|
|
||||||
|
type type;
|
||||||
|
unsigned count;
|
||||||
|
|
||||||
|
union {
|
||||||
|
string * string_ptr;
|
||||||
|
const char ** cstring_ptr;
|
||||||
|
bool * bool_ptr;
|
||||||
|
int * int_ptr;
|
||||||
|
float * float_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
function<void(string)> string_callback;
|
||||||
|
function<void(const char *)> cstring_callback;
|
||||||
|
function<void(bool)> bool_callback;
|
||||||
|
function<void(int)> int_callback;
|
||||||
|
function<void(float)> float_callback;
|
||||||
|
|
||||||
|
flag()
|
||||||
|
: short_name('\0')
|
||||||
|
, type(type::Undefined)
|
||||||
|
, count(0)
|
||||||
|
, string_ptr(nullptr) // This will set all of the *_ptr members
|
||||||
|
{ }
|
||||||
|
|
||||||
|
inline void process(const char * value)
|
||||||
|
{
|
||||||
|
auto parse_bool = [](string_view str) {
|
||||||
|
return !(
|
||||||
|
str == "false" ||
|
||||||
|
str == "FALSE" ||
|
||||||
|
str == "0"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
++count;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case type::String:
|
||||||
|
if (string_ptr) {
|
||||||
|
*string_ptr = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case type::StringCallback:
|
||||||
|
if (string_callback) {
|
||||||
|
if (value) {
|
||||||
|
string_callback(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case type::CString:
|
||||||
|
if (cstring_ptr) {
|
||||||
|
*cstring_ptr = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case type::CStringCallback:
|
||||||
|
if (cstring_callback) {
|
||||||
|
cstring_callback(value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case type::Bool:
|
||||||
|
if (bool_ptr) {
|
||||||
|
if (value) {
|
||||||
|
*bool_ptr = parse_bool(value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*bool_ptr = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case type::BoolCallback:
|
||||||
|
if (bool_callback) {
|
||||||
|
if (value) {
|
||||||
|
bool_callback(parse_bool(value));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bool_callback(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case type::Int:
|
||||||
|
if (int_ptr) {
|
||||||
|
if (value) {
|
||||||
|
*int_ptr = strtol(value, nullptr, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case type::IntCallback:
|
||||||
|
if (int_callback) {
|
||||||
|
if (value) {
|
||||||
|
int_callback(strtol(value, nullptr, 10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case type::Float:
|
||||||
|
if (float_ptr) {
|
||||||
|
if (value) {
|
||||||
|
*float_ptr = strtof(value, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case type::FloatCallback:
|
||||||
|
if (float_callback) {
|
||||||
|
if (value) {
|
||||||
|
float_callback(strtof(value, nullptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class cflags
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
string program;
|
||||||
|
vector<string_view> args;
|
||||||
|
|
||||||
|
int argc;
|
||||||
|
char ** argv;
|
||||||
|
|
||||||
|
cflags()
|
||||||
|
: argc(0)
|
||||||
|
, argv(nullptr)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
flag * add_flag(flag && flag)
|
||||||
|
{
|
||||||
|
_flags.push_back(flag);
|
||||||
|
return &_flags.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
flag * add_string(char short_name, string long_name, string * value_ptr, string description)
|
||||||
|
{
|
||||||
|
flag flag;
|
||||||
|
flag.short_name = short_name;
|
||||||
|
flag.long_name = long_name;
|
||||||
|
flag.type = flag::type::String;
|
||||||
|
flag.string_ptr = value_ptr;
|
||||||
|
flag.description = description;
|
||||||
|
|
||||||
|
_flags.push_back(flag);
|
||||||
|
return &_flags.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
flag * add_cstring(char short_name, string long_name, const char ** value_ptr, string description)
|
||||||
|
{
|
||||||
|
flag flag;
|
||||||
|
flag.short_name = short_name;
|
||||||
|
flag.long_name = long_name;
|
||||||
|
flag.type = flag::type::CString;
|
||||||
|
flag.cstring_ptr = value_ptr;
|
||||||
|
flag.description = description;
|
||||||
|
|
||||||
|
_flags.push_back(flag);
|
||||||
|
return &_flags.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
flag * add_bool(char short_name, string long_name, bool * value_ptr, string description)
|
||||||
|
{
|
||||||
|
flag flag;
|
||||||
|
flag.short_name = short_name;
|
||||||
|
flag.long_name = long_name;
|
||||||
|
flag.type = flag::type::Bool;
|
||||||
|
flag.bool_ptr = value_ptr;
|
||||||
|
flag.description = description;
|
||||||
|
|
||||||
|
_flags.push_back(flag);
|
||||||
|
return &_flags.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
flag * add_int(char short_name, string long_name, int * value_ptr, string description)
|
||||||
|
{
|
||||||
|
flag flag;
|
||||||
|
flag.short_name = short_name;
|
||||||
|
flag.long_name = long_name;
|
||||||
|
flag.type = flag::type::Int;
|
||||||
|
flag.int_ptr = value_ptr;
|
||||||
|
flag.description = description;
|
||||||
|
|
||||||
|
_flags.push_back(flag);
|
||||||
|
return &_flags.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
flag * add_float(char short_name, string long_name, float * value_ptr, string description)
|
||||||
|
{
|
||||||
|
flag flag;
|
||||||
|
flag.short_name = short_name;
|
||||||
|
flag.long_name = long_name;
|
||||||
|
flag.type = flag::type::Float;
|
||||||
|
flag.float_ptr = value_ptr;
|
||||||
|
flag.description = description;
|
||||||
|
|
||||||
|
_flags.push_back(flag);
|
||||||
|
return &_flags.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
flag * add_string_callback(char short_name, string long_name, function<void(string)> callback, string description)
|
||||||
|
{
|
||||||
|
flag flag;
|
||||||
|
flag.short_name = short_name;
|
||||||
|
flag.long_name = long_name;
|
||||||
|
flag.type = flag::type::StringCallback;
|
||||||
|
flag.string_callback = callback;
|
||||||
|
flag.description = description;
|
||||||
|
|
||||||
|
_flags.push_back(flag);
|
||||||
|
return &_flags.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
flag * add_cstring_callback(char short_name, string long_name, function<void(const char *)> callback, string description)
|
||||||
|
{
|
||||||
|
flag flag;
|
||||||
|
flag.short_name = short_name;
|
||||||
|
flag.long_name = long_name;
|
||||||
|
flag.type = flag::type::CStringCallback;
|
||||||
|
flag.cstring_callback = callback;
|
||||||
|
flag.description = description;
|
||||||
|
|
||||||
|
_flags.push_back(flag);
|
||||||
|
return &_flags.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
flag * add_bool_callback(char short_name, string long_name, function<void(bool)> callback, string description)
|
||||||
|
{
|
||||||
|
flag flag;
|
||||||
|
flag.short_name = short_name;
|
||||||
|
flag.long_name = long_name;
|
||||||
|
flag.type = flag::type::BoolCallback;
|
||||||
|
flag.bool_callback = callback;
|
||||||
|
flag.description = description;
|
||||||
|
|
||||||
|
_flags.push_back(flag);
|
||||||
|
return &_flags.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
flag * add_int_callback(char short_name, string long_name, function<void(int)> callback, string description)
|
||||||
|
{
|
||||||
|
flag flag;
|
||||||
|
flag.short_name = short_name;
|
||||||
|
flag.long_name = long_name;
|
||||||
|
flag.type = flag::type::IntCallback;
|
||||||
|
flag.int_callback = callback;
|
||||||
|
flag.description = description;
|
||||||
|
|
||||||
|
_flags.push_back(flag);
|
||||||
|
return &_flags.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
flag * add_float_callback(char short_name, string long_name, function<void(float)> callback, string description)
|
||||||
|
{
|
||||||
|
flag flag;
|
||||||
|
flag.short_name = short_name;
|
||||||
|
flag.long_name = long_name;
|
||||||
|
flag.type = flag::type::FloatCallback;
|
||||||
|
flag.float_callback = callback;
|
||||||
|
flag.description = description;
|
||||||
|
|
||||||
|
_flags.push_back(flag);
|
||||||
|
return &_flags.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
inline bool parse(int main_argc, char * main_argv[])
|
||||||
|
{
|
||||||
|
argc = main_argc;
|
||||||
|
argv = main_argv;
|
||||||
|
|
||||||
|
program = argv[0];
|
||||||
|
|
||||||
|
bool passthrough = false;
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
char * pch = argv[i];
|
||||||
|
if (!passthrough && *pch == '-') {
|
||||||
|
++pch;
|
||||||
|
if (*pch == '-') {
|
||||||
|
++pch;
|
||||||
|
|
||||||
|
if (*pch == '\0') {
|
||||||
|
// All following flags are not to be processed
|
||||||
|
passthrough = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Long
|
||||||
|
char * key = pch;
|
||||||
|
char * value = NULL;
|
||||||
|
|
||||||
|
char * divider = strchr(pch, '=');
|
||||||
|
if (divider) {
|
||||||
|
*divider = '\0';
|
||||||
|
value = divider + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next_arg_is_value = (i + 1 < argc && argv[i + 1][0] != '-');
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (auto& flag : _flags) {
|
||||||
|
if (flag.long_name == key) {
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
flag.process(value);
|
||||||
|
}
|
||||||
|
else if (next_arg_is_value) {
|
||||||
|
flag.process(argv[i + 1]);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
else if (flag.type == flag::type::Bool || flag.type == flag::type::BoolCallback) {
|
||||||
|
flag.process(nullptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "%s: option '--%s' requires an value\n", program.c_str(), key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
fprintf(stderr, "%s: unrecognized option '--%s'\n", program.c_str(), key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Short
|
||||||
|
while (*pch) {
|
||||||
|
bool is_last_short_flag = (*(pch + 1) == '\0');
|
||||||
|
bool next_arg_is_value = (i + 1 < argc && argv[i + 1][0] != '-');
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (flag& flag : _flags) {
|
||||||
|
if (flag.short_name == *pch) {
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
if (is_last_short_flag && next_arg_is_value) {
|
||||||
|
flag.process(argv[i + 1]);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
else if (flag.type == flag::type::Bool || flag.type == flag::type::BoolCallback) {
|
||||||
|
flag.process(nullptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "%s: option '-%c' requires an value\n", program.c_str(), *pch);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
fprintf(stderr, "%s: unrecognized option '-%c'\n", program.c_str(), *pch);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
++pch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
args.push_back(pch);
|
||||||
|
_argv.push_back(pch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc = static_cast<int>(_argv.size());
|
||||||
|
argv = _argv.data();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_usage(const string& usage, const string& above, const string& below)
|
||||||
|
{
|
||||||
|
printf("Usage: %s %s\n", program.c_str(), usage.c_str());
|
||||||
|
printf("%s\n\n", above.c_str());
|
||||||
|
|
||||||
|
for (auto& flag : _flags) {
|
||||||
|
printf(" ");
|
||||||
|
if (flag.short_name != '\0') {
|
||||||
|
printf("-%c, ", flag.short_name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!flag.long_name.empty()) {
|
||||||
|
printf("--%s", flag.long_name.c_str());
|
||||||
|
}
|
||||||
|
if (flag.long_name.size() > 20) {
|
||||||
|
printf("\n ");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (size_t i = 0; i < 20 - flag.long_name.size(); ++i) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("%s\n", flag.description.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n%s\n", below.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
vector<char *> _argv;
|
||||||
|
|
||||||
|
vector<flag> _flags;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cflags
|
||||||
|
|
||||||
|
#endif // CFLAGS_HPP
|
||||||
Vendored
+5
-5
@@ -7,29 +7,29 @@
|
|||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
namespace ircolib {
|
namespace ircolib {
|
||||||
static inline std::vector<u8> ReadFileBinary(const std::string &path) {
|
static inline std::vector<u8> read_file_binary(const std::string &path) {
|
||||||
std::ifstream file(path, std::ios::binary);
|
std::ifstream file(path, std::ios::binary);
|
||||||
return {std::istreambuf_iterator{file}, {}};
|
return {std::istreambuf_iterator{file}, {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void WriteFileBinary(const std::vector<u8> &data, const std::string &path) {
|
static inline void write_file_binary(const std::vector<u8> &data, const std::string &path) {
|
||||||
std::ofstream file(path, std::ios::binary);
|
std::ofstream file(path, std::ios::binary);
|
||||||
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
|
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void WriteFileBinary(const u8 *data, const size_t size, const std::string &path) {
|
static inline void write_file_binary(const u8 *data, const size_t size, const std::string &path) {
|
||||||
FILE *out = fopen(path.c_str(), "wb");
|
FILE *out = fopen(path.c_str(), "wb");
|
||||||
fwrite(data, size, 1, out);
|
fwrite(data, size, 1, out);
|
||||||
fclose(out);
|
fclose(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t Size>
|
template <size_t Size>
|
||||||
static inline void WriteFileBinary(const std::array<u8, Size> &data, const std::string &path) {
|
static inline void write_file_binary(const std::array<u8, Size> &data, const std::string &path) {
|
||||||
std::ofstream file(path, std::ios::binary);
|
std::ofstream file(path, std::ios::binary);
|
||||||
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
|
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t NextPow2(size_t num) {
|
static inline size_t next_pow2(size_t num) {
|
||||||
// Taken from "Bit Twiddling Hacks" by Sean Anderson:
|
// Taken from "Bit Twiddling Hacks" by Sean Anderson:
|
||||||
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||||
--num;
|
--num;
|
||||||
|
|||||||
Vendored
+52
-52
@@ -1,106 +1,106 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <types.hpp>
|
#include <ircolib/types.hpp>
|
||||||
|
|
||||||
namespace ircolib {
|
namespace ircolib {
|
||||||
static inline auto roundCeil(float f) {
|
static inline auto round_ceil(float f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128 t = _mm_set_ss(f);
|
__m128 t = _mm_set_ss(f);
|
||||||
t = _mm_round_ss(t, t, _MM_FROUND_TO_POS_INF);
|
t = _mm_round_ss(t, t, _MM_FROUND_TO_POS_INF);
|
||||||
return _mm_cvtss_f32(t);
|
return _mm_cvtss_f32(t);
|
||||||
#else
|
#else
|
||||||
return ceilf(f);
|
return ceilf(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundCeil(double f) {
|
static inline auto round_ceil(double f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128d t = _mm_set_sd(f);
|
__m128d t = _mm_set_sd(f);
|
||||||
t = _mm_round_sd(t, t, _MM_FROUND_TO_POS_INF);
|
t = _mm_round_sd(t, t, _MM_FROUND_TO_POS_INF);
|
||||||
return _mm_cvtsd_f64(t);
|
return _mm_cvtsd_f64(t);
|
||||||
#else
|
#else
|
||||||
return ceil(f);
|
return ceil(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundNearest(float f) {
|
static inline auto round_nearest(float f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128 t = _mm_set_ss(f);
|
__m128 t = _mm_set_ss(f);
|
||||||
t = _mm_round_ss(t, t, _MM_FROUND_TO_NEAREST_INT);
|
t = _mm_round_ss(t, t, _MM_FROUND_TO_NEAREST_INT);
|
||||||
return _mm_cvtss_f32(t);
|
return _mm_cvtss_f32(t);
|
||||||
#else
|
#else
|
||||||
return roundf(f);
|
return roundf(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundNearest(double f) {
|
static inline auto round_nearest(double f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128d t = _mm_set_sd(f);
|
__m128d t = _mm_set_sd(f);
|
||||||
t = _mm_round_sd(t, t, _MM_FROUND_TO_NEAREST_INT);
|
t = _mm_round_sd(t, t, _MM_FROUND_TO_NEAREST_INT);
|
||||||
return _mm_cvtsd_f64(t);
|
return _mm_cvtsd_f64(t);
|
||||||
#else
|
#else
|
||||||
return round(f);
|
return round(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundCurrent(float f) {
|
static inline auto round_current(float f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
auto t = _mm_set_ss(f);
|
auto t = _mm_set_ss(f);
|
||||||
t = _mm_round_ss(t, t, _MM_FROUND_CUR_DIRECTION);
|
t = _mm_round_ss(t, t, _MM_FROUND_CUR_DIRECTION);
|
||||||
return _mm_cvtss_f32(t);
|
return _mm_cvtss_f32(t);
|
||||||
#else
|
#else
|
||||||
return rint(f);
|
return rint(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundCurrent(double f) {
|
static inline auto round_current(double f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
auto t = _mm_set_sd(f);
|
auto t = _mm_set_sd(f);
|
||||||
t = _mm_round_sd(t, t, _MM_FROUND_CUR_DIRECTION);
|
t = _mm_round_sd(t, t, _MM_FROUND_CUR_DIRECTION);
|
||||||
return _mm_cvtsd_f64(t);
|
return _mm_cvtsd_f64(t);
|
||||||
#else
|
#else
|
||||||
return rint(f);
|
return rint(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline auto roundFloor(float f) {
|
static inline auto round_floor(float f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128 t = _mm_set_ss(f);
|
__m128 t = _mm_set_ss(f);
|
||||||
t = _mm_round_ss(t, t, _MM_FROUND_TO_NEG_INF);
|
t = _mm_round_ss(t, t, _MM_FROUND_TO_NEG_INF);
|
||||||
return _mm_cvtss_f32(t);
|
return _mm_cvtss_f32(t);
|
||||||
#else
|
#else
|
||||||
return floor(f);
|
return floor(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundFloor(double f) {
|
static inline auto round_floor(double f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128d t = _mm_set_sd(f);
|
__m128d t = _mm_set_sd(f);
|
||||||
t = _mm_round_sd(t, t, _MM_FROUND_TO_NEG_INF);
|
t = _mm_round_sd(t, t, _MM_FROUND_TO_NEG_INF);
|
||||||
return _mm_cvtsd_f64(t);
|
return _mm_cvtsd_f64(t);
|
||||||
#else
|
#else
|
||||||
return floor(f);
|
return floor(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundTrunc(float f) {
|
static inline auto round_trunc(float f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128 t = _mm_set_ss(f);
|
__m128 t = _mm_set_ss(f);
|
||||||
t = _mm_round_ss(t, t, _MM_FROUND_TO_ZERO);
|
t = _mm_round_ss(t, t, _MM_FROUND_TO_ZERO);
|
||||||
return _mm_cvtss_f32(t);
|
return _mm_cvtss_f32(t);
|
||||||
#else
|
#else
|
||||||
return trunc(f);
|
return trunc(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto roundTrunc(double f) {
|
static inline auto round_trunc(double f) {
|
||||||
#ifdef SIMD_SUPPORT
|
#ifdef SIMD_SUPPORT
|
||||||
__m128d t = _mm_set_sd(f);
|
__m128d t = _mm_set_sd(f);
|
||||||
t = _mm_round_sd(t, t, _MM_FROUND_TO_ZERO);
|
t = _mm_round_sd(t, t, _MM_FROUND_TO_ZERO);
|
||||||
return _mm_cvtsd_f64(t);
|
return _mm_cvtsd_f64(t);
|
||||||
#else
|
#else
|
||||||
return trunc(f);
|
return trunc(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} // namespace Util
|
} // namespace ircolib
|
||||||
|
|||||||
Vendored
+10
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <print>
|
||||||
|
|
||||||
|
namespace ircolib {
|
||||||
|
template <typename... Args>
|
||||||
|
void panic(std::format_string<Args...> fmt, Args &&...args) {
|
||||||
|
std::println(fmt, std::forward<Args>(args)...);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} // namespace ircolib
|
||||||
Vendored
+31
-23
@@ -8,7 +8,7 @@
|
|||||||
#include <concepts>
|
#include <concepts>
|
||||||
|
|
||||||
namespace ircolib {
|
namespace ircolib {
|
||||||
static inline std::vector<u8> IntegralToBuffer(const std::integral auto &val) {
|
static inline std::vector<u8> integral_to_buffer(const std::integral auto &val) {
|
||||||
std::vector<u8> ret{};
|
std::vector<u8> ret{};
|
||||||
ret.resize(sizeof(val));
|
ret.resize(sizeof(val));
|
||||||
|
|
||||||
@@ -17,27 +17,35 @@ static inline std::vector<u8> IntegralToBuffer(const std::integral auto &val) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline constexpr bool IsInsideRange(const std::integral auto &addr, const std::integral auto &start,
|
static inline auto integral_to_slice(const std::integral auto &val) -> std::array<u8, sizeof(val)> {
|
||||||
const std::integral auto &end) {
|
std::array<u8, sizeof(val)> ret{};
|
||||||
|
|
||||||
|
memcpy(ret.data(), &val, sizeof(val));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline constexpr bool is_inside_range(const std::integral auto &addr, const std::integral auto &start,
|
||||||
|
const std::integral auto &end) {
|
||||||
return addr >= start && addr <= end;
|
return addr >= start && addr <= end;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline T ReadAccess(const u8 *data, const u32 index);
|
static constexpr inline T read_access(const u8 *data, const u32 index);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline T ReadAccess(const std::vector<u8> &data, const u32 index);
|
static constexpr inline T read_access(const std::vector<u8> &data, const u32 index);
|
||||||
template <typename T, size_t Size>
|
template <typename T, size_t Size>
|
||||||
static constexpr inline T ReadAccess(const std::array<u8, Size> &data, const u32 index);
|
static constexpr inline T read_access(const std::array<u8, Size> &data, const u32 index);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline void WriteAccess(u8 *data, const u32 index, const T val);
|
static constexpr inline void write_access(u8 *data, const u32 index, const T val);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline void WriteAccess(std::vector<u8> &data, const u32 index, const T val);
|
static constexpr inline void write_access(std::vector<u8> &data, const u32 index, const T val);
|
||||||
template <typename T, size_t Size>
|
template <typename T, size_t Size>
|
||||||
static constexpr inline void WriteAccess(std::array<u8, Size> &data, const u32 index, const T val);
|
static constexpr inline void write_access(std::array<u8, Size> &data, const u32 index, const T val);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
constexpr inline u64 ReadAccess(const u8 *data, const u32 index) {
|
constexpr inline u64 read_access(const u8 *data, const u32 index) {
|
||||||
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
|
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
|
||||||
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
|
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
|
||||||
const auto &result = static_cast<u64>(hi) << 32 | static_cast<u64>(lo);
|
const auto &result = static_cast<u64>(hi) << 32 | static_cast<u64>(lo);
|
||||||
@@ -45,36 +53,36 @@ constexpr inline u64 ReadAccess(const u8 *data, const u32 index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline T ReadAccess(const u8 *data, const u32 index) {
|
static constexpr inline T read_access(const u8 *data, const u32 index) {
|
||||||
return *reinterpret_cast<const T *>(&data[index]);
|
return *reinterpret_cast<const T *>(&data[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
constexpr inline u64 ReadAccess(const std::vector<u8> &data, const u32 index) {
|
constexpr inline u64 read_access(const std::vector<u8> &data, const u32 index) {
|
||||||
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
|
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
|
||||||
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
|
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
|
||||||
return (static_cast<u64>(hi) << 32) | static_cast<u64>(lo);
|
return (static_cast<u64>(hi) << 32) | static_cast<u64>(lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline T ReadAccess(const std::vector<u8> &data, const u32 index) {
|
static constexpr inline T read_access(const std::vector<u8> &data, const u32 index) {
|
||||||
return *reinterpret_cast<const T *>(&data[index]);
|
return *reinterpret_cast<const T *>(&data[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t Size>
|
template <size_t Size>
|
||||||
constexpr inline u64 ReadAccess(const std::array<u8, Size> &data, const u32 index) {
|
constexpr inline u64 read_access(const std::array<u8, Size> &data, const u32 index) {
|
||||||
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
|
u32 hi = *reinterpret_cast<const u32 *>(&data[index + 0]);
|
||||||
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
|
u32 lo = *reinterpret_cast<const u32 *>(&data[index + 4]);
|
||||||
return static_cast<u64>(hi) << 32 | static_cast<u64>(lo);
|
return static_cast<u64>(hi) << 32 | static_cast<u64>(lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, size_t Size>
|
template <typename T, size_t Size>
|
||||||
static constexpr inline T ReadAccess(const std::array<u8, Size> &data, const u32 index) {
|
static constexpr inline T read_access(const std::array<u8, Size> &data, const u32 index) {
|
||||||
return *reinterpret_cast<const T *>(&data[index]);
|
return *reinterpret_cast<const T *>(&data[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t Size>
|
template <size_t Size>
|
||||||
constexpr inline void WriteAccess(std::array<u8, Size> &data, const u32 index, const u64 val) {
|
constexpr inline void write_access(std::array<u8, Size> &data, const u32 index, const u64 val) {
|
||||||
const u32 hi = val >> 32;
|
const u32 hi = val >> 32;
|
||||||
const u32 lo = val;
|
const u32 lo = val;
|
||||||
|
|
||||||
@@ -83,12 +91,12 @@ constexpr inline void WriteAccess(std::array<u8, Size> &data, const u32 index, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, size_t Size>
|
template <typename T, size_t Size>
|
||||||
static constexpr inline void WriteAccess(std::array<u8, Size> &data, const u32 index, const T val) {
|
static constexpr inline void write_access(std::array<u8, Size> &data, const u32 index, const T val) {
|
||||||
*reinterpret_cast<T *>(&data[index]) = val;
|
*reinterpret_cast<T *>(&data[index]) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
constexpr inline void WriteAccess(std::vector<u8> &data, const u32 index, const u64 val) {
|
constexpr inline void write_access(std::vector<u8> &data, const u32 index, const u64 val) {
|
||||||
const u32 hi = val >> 32;
|
const u32 hi = val >> 32;
|
||||||
const u32 lo = val;
|
const u32 lo = val;
|
||||||
|
|
||||||
@@ -97,12 +105,12 @@ constexpr inline void WriteAccess(std::vector<u8> &data, const u32 index, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline void WriteAccess(std::vector<u8> &data, const u32 index, const T val) {
|
static constexpr inline void write_access(std::vector<u8> &data, const u32 index, const T val) {
|
||||||
*reinterpret_cast<T *>(&data[index]) = val;
|
*reinterpret_cast<T *>(&data[index]) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
constexpr inline void WriteAccess(u8 *data, const u32 index, const u64 val) {
|
constexpr inline void write_access(u8 *data, const u32 index, const u64 val) {
|
||||||
const u32 hi = val >> 32;
|
const u32 hi = val >> 32;
|
||||||
const u32 lo = val;
|
const u32 lo = val;
|
||||||
|
|
||||||
@@ -111,12 +119,12 @@ constexpr inline void WriteAccess(u8 *data, const u32 index, const u64 val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline void WriteAccess(u8 *data, const u32 index, const T val) {
|
static constexpr inline void write_access(u8 *data, const u32 index, const T val) {
|
||||||
*reinterpret_cast<T *>(&data[index]) = val;
|
*reinterpret_cast<T *>(&data[index]) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr inline void SwapBuffer(std::vector<u8> &data) {
|
static constexpr inline void swap_buffer(std::vector<u8> &data) {
|
||||||
for (size_t i = 0; i < data.size(); i += sizeof(T)) {
|
for (size_t i = 0; i < data.size(); i += sizeof(T)) {
|
||||||
const T original = *reinterpret_cast<T *>(&data[i]);
|
const T original = *reinterpret_cast<T *>(&data[i]);
|
||||||
*reinterpret_cast<T *>(&data[i]) = std::byteswap(original);
|
*reinterpret_cast<T *>(&data[i]) = std::byteswap(original);
|
||||||
@@ -124,7 +132,7 @@ static constexpr inline void SwapBuffer(std::vector<u8> &data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, size_t Size>
|
template <typename T, size_t Size>
|
||||||
static constexpr inline void SwapBuffer(std::array<u8, Size> &data) {
|
static constexpr inline void swap_buffer(std::array<u8, Size> &data) {
|
||||||
for (size_t i = 0; i < data.size(); i += sizeof(T)) {
|
for (size_t i = 0; i < data.size(); i += sizeof(T)) {
|
||||||
const T original = *reinterpret_cast<T *>(&data[i]);
|
const T original = *reinterpret_cast<T *>(&data[i]);
|
||||||
*reinterpret_cast<T *>(&data[i]) = std::byteswap(original);
|
*reinterpret_cast<T *>(&data[i]) = std::byteswap(original);
|
||||||
|
|||||||
Vendored
+6
-1
@@ -10,4 +10,9 @@ using s8 = int8_t;
|
|||||||
using s16 = int16_t;
|
using s16 = int16_t;
|
||||||
using s32 = int32_t;
|
using s32 = int32_t;
|
||||||
using s64 = int64_t;
|
using s64 = int64_t;
|
||||||
}
|
|
||||||
|
} // namespace ircolib
|
||||||
|
|
||||||
|
constexpr ircolib::u32 operator""_kib(const unsigned long long v) { return v * 1024; }
|
||||||
|
constexpr ircolib::u32 operator""_mib(const unsigned long long v) { return v * 1024 * 1024; }
|
||||||
|
constexpr ircolib::u32 operator""_gib(const unsigned long long v) { return v * 1024 * 1024 * 1024; }
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
#include <print>
|
#include <print>
|
||||||
#include <elfio/elfio.hpp>
|
#include <elfio/elfio.hpp>
|
||||||
|
#include <cflags.hpp>
|
||||||
#include <ircolib/mem_access.hpp>
|
#include <ircolib/mem_access.hpp>
|
||||||
|
#include "mem.hpp"
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
ELFIO::elfio reader;
|
ELFIO::elfio reader;
|
||||||
if (!reader.load("tests/application/application.elf"))
|
|
||||||
return 1;
|
weee::core::mem mem;
|
||||||
|
|
||||||
|
cflags::cflags flags;
|
||||||
|
flags.add_string_callback('\0', "elf", [&](const std::string &v) { reader.load(v); }, "ELF binary to load");
|
||||||
|
|
||||||
|
if (!flags.parse(argc, argv))
|
||||||
|
return -1;
|
||||||
|
|
||||||
size_t sanity_bss_check_count = 0;
|
size_t sanity_bss_check_count = 0;
|
||||||
|
|
||||||
@@ -17,12 +25,6 @@ int main(int argc, char **argv) {
|
|||||||
if (segment->get_memory_size() == 0)
|
if (segment->get_memory_size() == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (segment->get_file_size() == 0) {
|
|
||||||
sanity_bss_check_count++;
|
|
||||||
if (sanity_bss_check_count > 1)
|
|
||||||
std::println("weee does not support multiple .bss segments");
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool exc = segment->get_flags() & ELFIO::PF_X;
|
const bool exc = segment->get_flags() & ELFIO::PF_X;
|
||||||
const bool rd = segment->get_flags() & ELFIO::PF_R;
|
const bool rd = segment->get_flags() & ELFIO::PF_R;
|
||||||
const bool wr = segment->get_flags() & ELFIO::PF_W;
|
const bool wr = segment->get_flags() & ELFIO::PF_W;
|
||||||
@@ -30,6 +32,21 @@ int main(int argc, char **argv) {
|
|||||||
std::println("Segment {} {}{}{} @ 0x{:08X} -> 0x{:08X}", segment->get_index(), rd ? 'R' : '_', wr ? 'W' : '_',
|
std::println("Segment {} {}{}{} @ 0x{:08X} -> 0x{:08X}", segment->get_index(), rd ? 'R' : '_', wr ? 'W' : '_',
|
||||||
exc ? 'X' : '_', segment->get_virtual_address(),
|
exc ? 'X' : '_', segment->get_virtual_address(),
|
||||||
segment->get_virtual_address() + segment->get_memory_size() - 1);
|
segment->get_virtual_address() + segment->get_memory_size() - 1);
|
||||||
|
|
||||||
|
if (segment->get_file_size() == 0) {
|
||||||
|
sanity_bss_check_count++;
|
||||||
|
if (sanity_bss_check_count > 1) {
|
||||||
|
std::println("weee does not support multiple .bss segments");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// .bss we zero out
|
||||||
|
mem.set(0, segment->get_memory_size(), segment->get_virtual_address() & 0x0FFFFFFF);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.copy((const ircolib::u8 *)segment->get_data(), segment->get_file_size(),
|
||||||
|
segment->get_virtual_address() & 0x0FFFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user