-
-
Save emadflash/a19f40c6a17aeb9858ea995dbedc018d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef FTODO_HPP | |
#define FTODO_HPP | |
#include <string_view> | |
#include <vector> | |
#include <filesystem> | |
#include <cstring> | |
#include <cassert> | |
#include <memory> | |
#include <optional> | |
#define basic_println(X, ...) fprintf(X, __VA_ARGS__); printf("\n") | |
#define println(...) basic_println(stdout, __VA_ARGS__) | |
#define eprintln(...) basic_println(stderr, __VA_ARGS__) | |
#define STRCMP(X, Y) (strcmp((X), (Y)) == 0) | |
using String_Vec = std::vector<std::string>; | |
namespace fs = std::filesystem; | |
#ifndef _ITERABLE | |
#define _ITERABLE | |
template <typename It> | |
concept iterable = std::random_access_iterator<It>; | |
#endif | |
template <typename T, typename It> | |
bool _in_container(It begin , It end, T element); | |
template <typename T> | |
bool in_container(T Container, auto x); | |
void prefix_file_extension_with_dot(String_Vec& sv); | |
// | |
// Return status code from command | |
bool check_status_code(std::string_view command); | |
// | |
// Returns if directory is a git repo, by returning a status code of `git status` command | |
bool _is_git_repository(const fs::path& current_path, const fs::path& target_path); | |
// | |
// Check if its a file | |
bool is_file(const fs::path& _path); | |
// | |
// Path stuff | |
bool file_exists(const fs::path& _path); | |
// | |
// Prefixs paths | |
template<iterable It> | |
void prefix_paths(It begin , It end, const fs::path& path); | |
// ------------------------------------ | |
// CONFIG | |
// ------------------------------------ | |
struct Config { | |
String_Vec exclude_directories, file_extensions; | |
Config(String_Vec exclude_directories, String_Vec file_extensions); | |
}; | |
// ------------------------------------ | |
// DIRECTORY ITERATOR CONFIG | |
// ------------------------------------ | |
struct DirectoryIteratorConfig { | |
bool follow_symlinks, | |
follow_exclude_directories; | |
}; | |
using iterator_callback = void(*)(fs::path& path); | |
// ------------------------------------ | |
// TARGET | |
// ------------------------------------ | |
struct Target { | |
private: | |
std::vector<std::string> exclude_directories; | |
std::vector<std::string> file_extensions; | |
// | |
// Prefix string with target path | |
std::string prefix_file_w_target_path(std::string& _path); | |
// | |
// Get gitmodules path | |
std::string get_gitmodules_path(); | |
public: | |
Config config; | |
bool is_git_repository {}; | |
const ::fs::path path; | |
const ::fs::path current_path; | |
Target(const ::fs::path& current_path, const ::fs::path& target_path, Config config); | |
Target() = default; | |
inline bool in_file_extensions(const fs::path& path); | |
inline bool in_exclude_directories(const fs::path& path); | |
// | |
// Updates exclude_directories | |
void add_to_exclude_directories(std::string_view sv); | |
// Getters | |
auto get_exclude_directories() -> std::vector<std::string>; | |
}; | |
// --------------------------------- | |
// DIRECTORY ITERATOR | |
// --------------------------------- | |
struct Director_Iterator { | |
Target target; | |
DirectoryIteratorConfig Directory_Iterator_Config; | |
Director_Iterator(Target& target, const DirectoryIteratorConfig& Directory_Iterator_Config); | |
void iterate(iterator_callback callback); | |
// | |
// Iterates over a directory and lists files with given extensions | |
void _iterate(const fs::path& path, iterator_callback callback); | |
// | |
// Is follow symlinks | |
bool is_follow_symlinks(const fs::path& path); | |
// | |
// Is follow excluded directories | |
bool is_follow_exclude_directories(const fs::path& path); | |
}; | |
// -------------------------------------------------------------------------------------------- | |
// Argv_Iterator: does bound checks, throws Argv_Iterator_Out_Of_Bounds if bound exceeed | |
// -------------------------------------------------------------------------------------------- | |
struct Argv_Iterator_Out_Of_Bounds : public std::exception { | |
const char* what () const throw () { | |
return "Argv_Iterator: Out of bounds memory access"; | |
} | |
}; | |
struct Argv_Iterator { | |
char** begin; | |
char** end; | |
char** curr; | |
Argv_Iterator(int argc, char** argv); | |
char* get(); | |
// compare current value with dest | |
bool compare(const char* dest) { | |
return STRCMP(this->get(), dest); | |
} | |
friend void operator++(Argv_Iterator& iterator); | |
friend void operator--(Argv_Iterator& iterator); | |
}; | |
// -------------------------------------------------------------------------------------------- | |
// Flag: a flag | |
// -------------------------------------------------------------------------------------------- | |
// flag types | |
enum class flag_type { | |
flag_string, | |
flag_boolean, | |
flag_int, | |
}; | |
const char* flag_type_to_string(const flag_type& type) { | |
#define TO_STRING(X, Y)\ | |
case X:\ | |
return Y | |
switch (type) { | |
TO_STRING(flag_type::flag_string, "STRING"); | |
TO_STRING(flag_type::flag_boolean, "BOOL"); | |
TO_STRING(flag_type::flag_int, "INT"); | |
} | |
return "???"; | |
} | |
struct Flag_Arg_Value_Null_Error: public std::exception { | |
const char* what () const throw () { | |
return "Flag: Value is null, which might mean its not parsed yet!"; | |
} | |
}; | |
// Flag_Values: Contains all values a Flag might have | |
//struct Flag_Values { | |
//bool value_bool {}; | |
//std::string value_string {}; | |
//std::uint8_t value_int {}; | |
//Flag_Values() = default; | |
//template <typename T> | |
//constexpr T get(flag_type& type) { | |
//#define FLAG_VALUE_GET(X, Y)\ | |
//case X:\ | |
//return Y | |
//switch (type) { | |
//FLAG_VALUE_GET(flag_type::flag_boolean, this->value_bool); | |
//FLAG_VALUE_GET(flag_type::flag_string, this->value_string); | |
//FLAG_VALUE_GET(flag_type::flag_int, this->value_int); | |
//} | |
//assert(1 == 1 && "Invaild flag_type"); | |
//} | |
//template <typename T> | |
//constexpr void set(flag_type& type, T& value) { | |
//#define FLAG_VALUE_SET(X, Y)\ | |
//case X:\ | |
//Y = value;\ | |
//return | |
//switch (type) { | |
//FLAG_VALUE_SET(flag_type::flag_boolean, this->value_bool); | |
//FLAG_VALUE_SET(flag_type::flag_string, this->value_string); | |
//FLAG_VALUE_SET(flag_type::flag_int, this->value_int); | |
//} | |
//assert(1 == 1 && "Invaild flag_type"); | |
//} | |
//}; | |
struct Flag { | |
flag_type type; | |
const char* short_switch; | |
const char* long_switch; | |
const char* description; | |
bool is_on {}, is_positional {}; | |
std::string value_str {}; | |
std::uint8_t value_int {}; | |
bool value_bool {}; | |
Flag(const flag_type& type, const char* short_switch, const char* long_switch, const char* description): | |
type { type }, | |
short_switch { short_switch }, | |
long_switch { long_switch }, | |
description { description } | |
{} | |
Flag(const flag_type& type, const bool&& is_positional, const char* short_switch, const char* long_switch, const char* description): | |
type { type }, | |
is_positional { is_positional }, | |
short_switch { short_switch }, | |
long_switch { long_switch }, | |
description { description } | |
{} | |
operator bool() const { | |
return this->is_on; | |
} | |
void set_int(const std::uint8_t& val) { | |
assert(this->type == flag_type::flag_int && "Flag type must be flag_int"); | |
this->value_int = val; | |
} | |
void set_str(const std::string& val) { | |
assert(this->type == flag_type::flag_string && "Flag type must be flag_string"); | |
this->value_str = val; | |
} | |
void set_bool(const bool& val) { | |
assert(this->type == flag_type::flag_boolean && "Flag type must be flag_boolean"); | |
this->value_bool = val; | |
} | |
std::uint8_t get_int() { | |
assert(this->type == flag_type::flag_int && "Flag type must be flag_int"); | |
return this->value_int; | |
} | |
std::string get_string() { | |
assert(this->type == flag_type::flag_string && "Flag type must be flag_string"); | |
if (this->value_str.empty()) { | |
throw Flag_Arg_Value_Null_Error(); | |
} | |
return this->value_str; | |
} | |
bool get_bool() { | |
assert(this->type == flag_type::flag_boolean && "Flag type must be flag_boolean"); | |
return this->value_bool; | |
} | |
const std::string usage() const { | |
std::stringstream ss {}; | |
ss << "\t" | |
<< this->short_switch << ", " << this->long_switch << " [" << flag_type_to_string(this->type) << "]" | |
<< "\n\t\t" | |
<< this->description | |
<< "\n\n"; | |
return ss.str(); | |
} | |
}; | |
// -------------------------------------------------------------------------------------------- | |
// What_Usage: It contains usage things | |
// -------------------------------------------------------------------------------------------- | |
struct What_Usage { | |
const char* name; | |
const char* description; | |
const std::vector<Flag*> flags; | |
std::string optionals_usage {}, positionals_usage {}; | |
What_Usage(const char* name, const char* description, const std::vector<Flag*>& flags); | |
friend std::ostream& operator<<(std::ostream& os, const What_Usage& usage); | |
}; | |
// -------------------------------------------------------------------------------------------- | |
// Flag_Parser: a flag parser | |
// -------------------------------------------------------------------------------------------- | |
struct Flag_Parser { | |
const std::uint8_t max_buffer_size { 255 }; // Max buffer size | |
using argv_iterator_callback = void(*)(const What_Usage& what_usage, Argv_Iterator& argv_iterator); | |
Argv_Iterator& iterator; | |
const What_Usage& what_usage; | |
const std::vector<Flag*> flags; | |
Flag_Parser(const What_Usage& what_usage, Argv_Iterator& iterator, const std::vector<Flag*>& flags): | |
what_usage { what_usage }, | |
iterator { iterator }, | |
flags { flags } | |
{} | |
std::optional<Flag*> check(); | |
void parse(argv_iterator_callback callback); // if used, have to do the invaild flag error checking yourself | |
void parse(); // Without the callback will use default callback which checks for invaild flag | |
}; | |
#endif // FTODO_HPP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment