| poaflocParser Of Arguments For Lines Of Commands | 
| git clone git://git.dimitrijedobrota.com/poafloc.git | 
| Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING | 
| commit | 8950af9d55d13335e71fe92c0cfc6ee132919584 | 
| parent | 130362e87a569b184f3dfef590569354de92397a | 
| author | Dimitrije Dobrota < mail@dimitrijedobrota.com > | 
| date | Mon, 10 Jun 2024 21:23:26 +0200 | 
Proof of concept C bindings
| M | CMakeLists.txt | | | ++++++ -- | 
| M | demo/CMakeLists.txt | | | +++++++++++ ----- | 
| A | demo/main.c | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | include/args.h | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| M | include/args.hpp | | | +++++++++++++ -------------------------- | 
| M | src/CMakeLists.txt | | | +++++++++++++++++ - | 
| A | src/c_bindings.cpp | | | ++++++++ | 
7 files changed, 191 insertions(+), 34 deletions(-)
diff --git a/ CMakeLists.txt b/ CMakeLists.txt
          @@ -3,14 +3,18 @@ 
          set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
        
        
          project(
              args
              VERSION 0.0.1
              VERSION 0.0.2
              DESCRIPTION "Command Line Argument Parser"
              LANGUAGES CXX
              LANGUAGES CXX C
          )
          set(CMAKE_CXX_STANDARD 20)
          set(CMAKE_CXX_STANDARD_REQUIRED ON)
          set(CMAKE_CXX_EXTENSIONS OFF)
          set(CMAKE_C_STANDARD 17)
          set(CMAKE_C_STANDARD_REQUIRED ON)
          set(CMAKE_C_EXTENSIONS OFF)
          add_subdirectory(src)
          add_subdirectory(demo)
        
        diff --git a/ demo/CMakeLists.txt b/ demo/CMakeLists.txt
@@ -1,13 +1,19 @@
set(GENERATE_OUT "${CMAKE_BINARY_DIR}/bin")
          add_executable(demo
              main.cpp
          )
          add_executable(demo main.cpp)
          target_link_libraries(demo PRIVATE args)
          set_target_properties(demo PROPERTIES LINKER_LANGUAGE CXX)
          set_target_properties(demo PROPERTIES
              VERSION ${PROJECT_VERSION}
              SOVERSION ${PROJECT_VERSION_MAJOR}
              RUNTIME_OUTPUT_DIRECTORY "${GENERATE_OUT}"
          )
          add_executable(cdemo main.c)
          target_link_libraries(cdemo PRIVATE cargs)
          set_target_properties(cdemo PROPERTIES LINKER_LANGUAGE C)
          set_target_properties(cdemo PROPERTIES
              VERSION ${PROJECT_VERSION}
              SOVERSION ${PROJECT_VERSION_MAJOR}
              RUNTIME_OUTPUT_DIRECTORY "${GENERATE_OUT}"
          )
        
        diff --git a/ demo/main.c b/ demo/main.c
@@ -0,0 +1,82 @@
#include "args.h"
          #include <stdio.h>
          void error(const char *message) { fprintf(stderr, "%s\n", message); }
          typedef struct {
              const char *output_file;
              const char *input_file;
              int debug;
              int hex;
              int relocatable;
          } arguments_t;
          int parse_opt(int key, const char *arg, args_parser *parser) {
              arguments_t *arguments = (arguments_t *)args_parser_input(parser);
              switch (key) {
              case 777: arguments->debug = 1; break;
              case 'h':
                  if (arguments->relocatable) error("cannot mix -hex and -relocatable");
                  arguments->hex = 1;
                  break;
              case 'r':
                  if (arguments->hex) error("cannot mix -hex and -relocatable");
                  arguments->relocatable = 1;
                  break;
              case 'o': arguments->output_file = arg ? arg : "stdout"; break;
              case 'i': arguments->input_file = arg; break;
              // case Parser::Key::ARG: arguments->args.push_back(arg); break;
              case ARGS_KEY_ERROR: fprintf(stderr, "handled error\n");
              case ARGS_KEY_INIT:
                  arguments->input_file = "stdin";
                  arguments->output_file = "stdout";
              }
              return 0;
          }
          // clang-format off
          static const args_option_t options[] = {
              {           0,  'R',      0,                        0,        "random 0-group option"},
              {           0,    0,      0,                        0,                 "Program mode", 1},
              {"relocatable", 'r',      0,                        0, "Output in relocatable format"},
              {        "hex", 'h',      0,                        0,         "Output in hex format"},
              {"hexadecimal",   0,      0,  ARGS_OPTION_ALIAS | ARGS_OPTION_HIDDEN},
              {            0,   0,      0,                        0,               "For developers", 4},
              {      "debug", 777,      0,                        0,        "Enable debugging mode"},
              {            0,   0,      0,                        0,                 "Input/output", 3},
              {     "output", 'o', "file", ARGS_OPTION_ARG_OPTIONAL,  "Output file, default stdout"},
              {            0, 'i', "file",                        0,                  "Input  file"},
              {            0,   0,      0,                        0,        "Informational Options", -1},
              {0},
          };
          // clang-format on
          int main(int argc, char *argv[]) {
              arguments_t arguments = {0};
              args_argp_t argp = {
                  options, parse_opt, "doc string\nother usage",
                  "First half of the message\vsecond half of the message"};
              if (args_parse(&argp, argc, argv, &arguments)) {
                  error("There was an error while parsing arguments");
                  return 1;
              }
              printf("Command line options:\n");
              printf("\t       input: %s\n", arguments.input_file);
              printf("\t      output: %s\n", arguments.output_file);
              printf("\t         hex: %d\n", arguments.hex);
              printf("\t       debug: %d\n", arguments.debug);
              printf("\t relocatable: %d\n", arguments.relocatable);
              // std::cout << "\t args: ";
              // for (const auto &arg : arguments.args)
              //     std::cout << arg << " ";
              // std::cout << std::endl;
              return 0;
          }
        
        diff --git a/ include/args.h b/ include/args.h
@@ -0,0 +1,54 @@
#ifndef ARGS_H
          #define ARGS_H
          #ifdef __cplusplus
          extern "C" {
          struct Parser;
          typedef Parser args_parser;
          #else
          struct __Parser;
          typedef struct __Parser args_parser;
          #endif
          typedef struct {
              const char *name;
              int key;
              const char *arg;
              int flags;
              const char *message;
              int group;
          } args_option_t;
          enum args_option_e {
              ARGS_OPTION_ARG_OPTIONAL = 0x1,
              ARGS_OPTION_HIDDEN = 0x2,
              ARGS_OPTION_ALIAS = 0x4,
          };
          enum args_key_e {
              ARGS_KEY_ARG = 0,
              ARGS_KEY_END = 0x1000001,
              ARGS_KEY_NO_ARGS = 0x1000002,
              ARGS_KEY_INIT = 0x1000003,
              ARGS_KEY_SUCCESS = 0x1000004,
              ARGS_KEY_ERROR = 0x1000005,
          };
          struct args_Parser;
          typedef int (*args_parse_f)(int key, const char *arg, args_parser *parser);
          typedef struct {
              const args_option_t *options;
              const args_parse_f parse;
              const char *doc;
              const char *message;
          } args_argp_t;
          int args_parse(args_argp_t *argp, int argc, char *argv[], void *input);
          void *args_parser_input(args_parser *parser);
          #ifdef __cplusplus
          } // extern "C"
          #endif
          #endif
        
        diff --git a/ include/args.hpp b/ include/args.hpp
@@ -1,43 +1,30 @@
#ifndef ARGS_HPP
          #define ARGS_HPP
          #include "args.h"
          #include <string>
          #include <unordered_map>
          #include <vector>
          class Parser {
            public:
              struct option_t {
                  const char *name;
                  const int key;
                  const char *arg;
                  const int flags;
                  const char *message;
                  const int group;
              };
              using option_t = args_option_t;
              using argp_t = args_argp_t;
              enum Option {
                  ARG_OPTIONAL = 0x1,
                  HIDDEN = 0x2,
                  ALIAS = 0x4,
                  ARG_OPTIONAL = ARGS_OPTION_ARG_OPTIONAL,
                  HIDDEN = ARGS_OPTION_HIDDEN,
                  ALIAS = ARGS_OPTION_ALIAS,
              };
              enum Key {
                  ARG = 0,
                  END = 0x1000001,
                  NO_ARGS = 0x1000002,
                  INIT = 0x1000003,
                  SUCCESS = 0x1000004,
                  ERROR = 0x1000005,
              };
              struct argp_t {
                  using parse_f = int (*)(int key, const char *arg, Parser *parser);
                  const option_t *options;
                  const parse_f parse;
                  const char *doc;
                  const char *message;
                  ARG = ARGS_KEY_ARG,
                  END = ARGS_KEY_END,
                  NO_ARGS = ARGS_KEY_NO_ARGS,
                  INIT = ARGS_KEY_INIT,
                  SUCCESS = ARGS_KEY_SUCCESS,
                  ERROR = ARGS_KEY_ERROR,
              };
              static int parse(argp_t *argp, int argc, char *argv[], void *input) {
        
        diff --git a/ src/CMakeLists.txt b/ src/CMakeLists.txt
@@ -1,5 +1,6 @@
add_library(args args.cpp help.cpp trie.cpp)
          add_library(args STATIC args.cpp help.cpp trie.cpp)
          target_include_directories(args PUBLIC ../include)
          set_target_properties(args PROPERTIES LINKER_LANGUAGE CXX)
          set_target_properties(args PROPERTIES
              VERSION ${PROJECT_VERSION}
        
        
          @@ -11,3 +12,18 @@ 
          install(TARGETS args
        
        
              LIBRARY DESTINATION lib
              PUBLIC_HEADER DESTINATION include
          )
           add_library(cargs STATIC c_bindings.cpp args.cpp help.cpp trie.cpp)
          target_include_directories(cargs PUBLIC ../include)
          set_target_properties(cargs PROPERTIES LINKER_LANGUAGE CXX)
          set_target_properties(cargs PROPERTIES
              VERSION ${PROJECT_VERSION}
              SOVERSION ${PROJECT_VERSION_MAJOR}
              PUBLIC_HEADER ../include/args.h
          )
          install(TARGETS cargs
              LIBRARY DESTINATION lib
              PUBLIC_HEADER DESTINATION include
          )
        
        diff --git a/ src/c_bindings.cpp b/ src/c_bindings.cpp
@@ -0,0 +1,8 @@
#include "args.h"
          #include "args.hpp"
          int args_parse(args_argp_t *argp, int argc, char *argv[], void *input) {
              return Parser::parse(argp, argc, argv, input);
          }
          void *args_parser_input(args_parser *parser) { return parser->input; }