From ebbf3983de76a4506ba913817cb744b24e77d440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abd=C3=BCssamet=20ERSOYLU?= Date: Fri, 3 Oct 2025 23:56:54 +0400 Subject: [PATCH] feat(parser): add platform-specific parsers and argument conventions Implement platform-specific parsers for Windows, Linux, and macOS Add GNU argument convention implementations Create fake parser for testing purposes Update CMakeLists to include new headers --- CMakeLists.txt | 8 ++ include/argparse | 27 +++++ include/{ => conventions}/base_convention.hpp | 0 .../gnu_argument_convention.hpp | 0 include/{ => parser}/argument_parser.hpp | 5 +- include/parser/fake_parser.hpp | 29 +++++ .../platform_headers}/linux_parser.hpp | 6 +- .../parser/platform_headers/macos_parser.hpp | 27 +++++ .../platform_headers}/windows_parser.hpp | 6 +- src/main.cpp | 105 +++++++++++++++--- 10 files changed, 190 insertions(+), 23 deletions(-) create mode 100644 include/argparse rename include/{ => conventions}/base_convention.hpp (100%) rename include/{ => conventions/implementations}/gnu_argument_convention.hpp (100%) rename include/{ => parser}/argument_parser.hpp (99%) create mode 100644 include/parser/fake_parser.hpp rename include/{ => parser/platform_headers}/linux_parser.hpp (94%) create mode 100644 include/parser/platform_headers/macos_parser.hpp rename include/{ => parser/platform_headers}/windows_parser.hpp (76%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cc53b5..68fa7cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,4 +7,12 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_Release ${CMAKE_CURRENT_SOURCE_DIR}/bin/release) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_Debug ${CMAKE_CURRENT_SOURCE_DIR}/bin/debug) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +include_directories(include) +include_directories(include/parser) +include_directories(include/conventions) +include_directories(include/conventions/implementations) +include_directories(include/parser/platform_headers) + add_executable(test src/main.cpp) \ No newline at end of file diff --git a/include/argparse b/include/argparse new file mode 100644 index 0000000..f0b67dd --- /dev/null +++ b/include/argparse @@ -0,0 +1,27 @@ +#pragma once +#ifndef ARGPARSE_HPP +#define ARGPARSE_HPP +#include +# +#ifdef __linux__ +#include +namespace argument_parser { + using parser = linux_parser; +} +#elif __APPLE__ +#include +namespace argument_parser { + using parser = macos_parser; +} +#elif _WIN32 +#include +namespace argument_parser { + using parser = windows_parser; +} +#else +#error "Unsupported platform" +#endif +#endif + +#include +#include \ No newline at end of file diff --git a/include/base_convention.hpp b/include/conventions/base_convention.hpp similarity index 100% rename from include/base_convention.hpp rename to include/conventions/base_convention.hpp diff --git a/include/gnu_argument_convention.hpp b/include/conventions/implementations/gnu_argument_convention.hpp similarity index 100% rename from include/gnu_argument_convention.hpp rename to include/conventions/implementations/gnu_argument_convention.hpp diff --git a/include/argument_parser.hpp b/include/parser/argument_parser.hpp similarity index 99% rename from include/argument_parser.hpp rename to include/parser/argument_parser.hpp index ecd509b..a0fb194 100644 --- a/include/argument_parser.hpp +++ b/include/parser/argument_parser.hpp @@ -1,5 +1,5 @@ #pragma once -#include "base_convention.hpp" +#include #include #include #include @@ -17,6 +17,7 @@ #include #include + namespace argument_parser { namespace function { template @@ -501,6 +502,8 @@ namespace argument_parser { friend class linux_parser; friend class windows_parser; + friend class macos_parser; + friend class fake_parser; }; } diff --git a/include/parser/fake_parser.hpp b/include/parser/fake_parser.hpp new file mode 100644 index 0000000..645d3e5 --- /dev/null +++ b/include/parser/fake_parser.hpp @@ -0,0 +1,29 @@ +#pragma once + +#ifndef FAKE_PARSER_HPP +#define FAKE_PARSER_HPP + +#include +#include +#include +#include + +namespace argument_parser { + class fake_parser : public base_parser { + public: + fake_parser(std::string const& program_name, std::vector const& arguments) { + this->program_name = program_name; + parsed_arguments = arguments; + } + + fake_parser(std::string const& program_name, std::vector&& arguments) { + this->program_name = program_name; + parsed_arguments = std::move(arguments); + } + + fake_parser(std::string const& program_name, std::initializer_list const& arguments) : + fake_parser(program_name, std::vector(arguments)) {} + }; +} + +#endif \ No newline at end of file diff --git a/include/linux_parser.hpp b/include/parser/platform_headers/linux_parser.hpp similarity index 94% rename from include/linux_parser.hpp rename to include/parser/platform_headers/linux_parser.hpp index 5b9c0fb..61d3d0f 100644 --- a/include/linux_parser.hpp +++ b/include/parser/platform_headers/linux_parser.hpp @@ -1,11 +1,11 @@ #pragma once -#include -#include #ifdef __linux__ #ifndef LINUX_PARSER_HPP +#include +#include -#include "argument_parser.hpp" +#include namespace argument_parser { class linux_parser : public base_parser { diff --git a/include/parser/platform_headers/macos_parser.hpp b/include/parser/platform_headers/macos_parser.hpp new file mode 100644 index 0000000..dac3d3b --- /dev/null +++ b/include/parser/platform_headers/macos_parser.hpp @@ -0,0 +1,27 @@ +#pragma once +#ifdef __APPLE__ +#ifndef MACOS_PARSER_HPP +#define MACOS_PARSER_HPP + +#include +#include +#include + +namespace argument_parser { + class macos_parser : public base_parser { + public: + macos_parser() { + int argc = *_NSGetArgc(); + char **argv = *_NSGetArgv(); + if (argc > 0 && argv != nullptr && argv[0] != nullptr) { + program_name = argv[0]; + for (int i = 1; i < argc; ++i) { + if (argv[i] != nullptr) parsed_arguments.emplace_back(argv[i]); + } + } + } + }; +} + +#endif +#endif \ No newline at end of file diff --git a/include/windows_parser.hpp b/include/parser/platform_headers/windows_parser.hpp similarity index 76% rename from include/windows_parser.hpp rename to include/parser/platform_headers/windows_parser.hpp index ef94f93..578df8a 100644 --- a/include/windows_parser.hpp +++ b/include/parser/platform_headers/windows_parser.hpp @@ -2,7 +2,7 @@ #ifdef _WIN32 #ifndef WINDOWS_PARSER_HPP -#include "argument_parser.hpp" +#include #include #include @@ -11,7 +11,9 @@ namespace argument_parser { public: windows_parser() { } - }; + }; + + using parser = windows_parser; } #endif diff --git a/src/main.cpp b/src/main.cpp index ad3c39e..72f70ce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,32 +1,103 @@ -#include "../include/argument_parser.hpp" -#include "../include/linux_parser.hpp" -#include "../include/gnu_argument_convention.hpp" -#include +#include "argument_parser.hpp" +#include "fake_parser.hpp" +#include +#include #include +#include +#include +#include +#include using namespace argument_parser::conventions; -int main() { - auto parametered_action = argument_parser::helpers::make_parametered_action_ptr([](std::string const& test) { - std::cout << test << std::endl; - }); +const std::initializer_list conventions = { + &gnu_argument_convention, + &gnu_equal_argument_convention +}; - auto parser = argument_parser::linux_parser{}; - parser.add_argument("e", "echo", "echoes given variable", *parametered_action, false); - parser.add_argument("re", "required_echo", "required echo", *parametered_action, true); +const auto echo = argument_parser::helpers::make_parametered_action([](std::string const& text) { + std::cout << text << std::endl; +}); - std::initializer_list conventions = { - &gnu_argument_convention, - &gnu_equal_argument_convention +const auto cat = argument_parser::helpers::make_parametered_action([](std::string const& file_name) { + std::ifstream file(file_name); + if (!file.is_open()) { + throw std::runtime_error("Could not open file"); + } + std::string line; + while (std::getline(file, line)) { + std::cout << line << std::endl; + } + + file.close(); +}); + +auto make_grep_action(argument_parser::base_parser& parser) { + std::shared_ptr filename = std::make_shared(""); + std::shared_ptr grep_requested = std::make_shared(false); + std::shared_ptr grep_called = std::make_shared(false); + std::shared_ptr pattern = std::make_shared(); + + auto grep_impl = [&parser] (std::string const& filename, std::string const& pattern) { + if (filename.empty()) { + std::cerr << "Missing filename" << std::endl; + parser.display_help(conventions); + exit(-1); + } + std::ifstream file(filename); + if (!file.is_open()) { + std::cerr << "Could not open file: \"" << filename << '"' << std::endl; + exit(-1); + } + std::string line; + while (std::getline(file, line)) { + if (line.find(pattern) != std::string::npos) { + std::cout << line << std::endl; + } + } + file.close(); }; - parser.add_argument("h", "help", "Displays this help text.", argument_parser::helpers::make_non_parametered_action([&parser, conventions]{ + const auto filename_action = argument_parser::helpers::make_parametered_action([filename, grep_called, grep_requested, &grep_impl, pattern](std::string const& file_name) { + std::ifstream file(file_name); + if (!file.is_open()) { + throw std::runtime_error("Could not open file"); + } + *filename = file_name; + file.close(); + if (*grep_requested && !(*grep_called)) { + grep_impl(file_name, *pattern); + *grep_called = true; + } + }); + + const auto grep = argument_parser::helpers::make_parametered_action([filename, &parser, &grep_impl, grep_requested, grep_called, pattern](std::string const& p) { + *grep_requested = true; + if (!filename || filename -> empty()) { + *grep_called = false; + *pattern = p; + return; + } + grep_impl(*filename, p); + *grep_called = true; + }); + + return std::pair { filename_action, grep }; +} + +int main() { + std::vector fake_args = { "-g", "add", "-f", "src/main.cpp" }; + auto parser = argument_parser::fake_parser{"test", std::move(fake_args)}; + auto [file, grep] = make_grep_action(parser); + parser.add_argument("e", "echo", "echoes given variable", echo, false); + parser.add_argument("f", "file", "File to grep, required only if using grep", file, false); + parser.add_argument("g", "grep", "Grep pattern, required only if using grep", grep, false); + parser.add_argument("c", "cat", "Prints the content of the file", cat, false); + parser.add_argument("h", "help", "Displays this help text.", argument_parser::helpers::make_non_parametered_action([&parser]{ parser.display_help(conventions); }), false); parser.handle_arguments(conventions); - - return 0; } \ No newline at end of file