Parse command-line arguments
This commit is contained in:
1 parent
05dfa4f977
commit
cc041168a1
4 files changed
+196
-2
No files matched your search
+173
-1
@@ -1,5 +1,177 @@
|
||||
#include <fart/Cli.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
Cli::Cli()
|
||||
#define FLAGS \
|
||||
FLAG(height, "h", true) \
|
||||
FLAG(height_l, "height", true) \
|
||||
FLAG(help, "help", false) \
|
||||
FLAG(output, "o", true) \
|
||||
FLAG(output_l, "output", true) \
|
||||
FLAG(version, "version", false) \
|
||||
FLAG(width, "w", true) \
|
||||
FLAG(width_l, "width", true) \
|
||||
|
||||
#define FLAG(name, flag, arg) flag_##name,
|
||||
typedef enum
|
||||
{
|
||||
FLAGS
|
||||
flag__count
|
||||
} flag_id_t;
|
||||
#undef FLAG
|
||||
|
||||
#define FLAG(name, flag, arg) static const char flag_##name##_str[] = flag;
|
||||
FLAGS
|
||||
#undef FLAG
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char * flag;
|
||||
size_t flag_length;
|
||||
bool arg;
|
||||
} flag_def_t;
|
||||
|
||||
#define FLAG(name, flag, arg) { \
|
||||
flag_##name##_str, \
|
||||
sizeof(flag_##name##_str) - 1u, \
|
||||
arg},
|
||||
static const flag_def_t flag_defs[] = {
|
||||
FLAGS
|
||||
};
|
||||
#undef FLAG
|
||||
|
||||
int Cli::run(int argc, char * argv[])
|
||||
{
|
||||
for (size_t i = 1; i < argc; i++)
|
||||
{
|
||||
size_t dashes = 0u;
|
||||
if (strncmp(argv[i], "--", 2) == 0)
|
||||
{
|
||||
dashes = 2u;
|
||||
}
|
||||
else if (strncmp(argv[i], "-", 1) == 0)
|
||||
{
|
||||
dashes = 1u;
|
||||
}
|
||||
if (dashes > 0u)
|
||||
{
|
||||
const char * flag = &argv[i][dashes];
|
||||
size_t flag_idx;
|
||||
for (flag_idx = 0u; flag_idx < flag__count; flag_idx++)
|
||||
{
|
||||
size_t flag_length = flag_defs[flag_idx].flag_length;
|
||||
size_t flag_dashes = flag_length == 1u ? 1u : 2u;
|
||||
if (flag_dashes != dashes)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (strncmp(flag, flag_defs[flag_idx].flag, flag_length) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (dashes == 2 && flag[flag_length] != '\0' && flag[flag_length] != '=')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
bool arg = flag_defs[flag_idx].arg;
|
||||
const char * arg_value = nullptr;
|
||||
if (arg)
|
||||
{
|
||||
if (flag[flag_length] == '\0')
|
||||
{
|
||||
if (i >= (argc - 1))
|
||||
{
|
||||
fprintf(stderr, "Error: option %s requires an argument\n", flag_defs[flag_idx].flag);
|
||||
return 2;
|
||||
}
|
||||
i++;
|
||||
arg_value = argv[i];
|
||||
}
|
||||
else if (dashes == 1u)
|
||||
{
|
||||
arg_value = &flag[flag_length];
|
||||
}
|
||||
else if (flag[flag_length + 1] != '\0')
|
||||
{
|
||||
arg_value = &flag[flag_length + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error: option %s requires an argument\n", flag_defs[flag_idx].flag);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else if (dashes == 2u && flag[flag_length] == '=')
|
||||
{
|
||||
fprintf(stderr, "Error: option %s does not take an argument\n", flag_defs[flag_idx].flag);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: support combining short flags, e.g. -cofoo */
|
||||
}
|
||||
int r = handle_option(flag_idx, arg_value);
|
||||
if (r != 0)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (flag_idx == flag__count)
|
||||
{
|
||||
fprintf(stderr, "Unknown flag: %s\n", flag);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->options.input_file != "")
|
||||
{
|
||||
fprintf(stderr, "Extraneous argument: %s\n", argv[i]);
|
||||
return 2;
|
||||
}
|
||||
this->options.input_file = argv[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Cli::handle_option(size_t flag_idx, const char * arg_value)
|
||||
{
|
||||
switch (flag_idx)
|
||||
{
|
||||
case flag_height:
|
||||
case flag_height_l:
|
||||
this->options.height = atoi(arg_value);
|
||||
return 0;
|
||||
|
||||
case flag_help:
|
||||
printf("Usage: fart [options] input-file\n");
|
||||
printf("\n");
|
||||
printf(" Options:\n");
|
||||
printf("\n");
|
||||
printf(" -h, --height H Set render height to H\n");
|
||||
printf(" --help Show this help and exit\n");
|
||||
printf(" -o, --output F Write rendered image to file F\n");
|
||||
printf(" -w, --width W Set render width to W\n");
|
||||
printf(" --version Show fart version and exit\n");
|
||||
return 1;
|
||||
|
||||
case flag_output:
|
||||
case flag_output_l:
|
||||
this->options.output_file = arg_value;
|
||||
return 0;
|
||||
|
||||
case flag_width:
|
||||
case flag_width_l:
|
||||
this->options.width = atoi(arg_value);
|
||||
return 0;
|
||||
|
||||
case flag_version:
|
||||
printf("fart, version 0.0.0.0.0.1\n");
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, "Internal error: unhandled flag_idx=%zu\n", flag_idx);
|
||||
return 2;
|
||||
}
|
||||
+8
-1
@@ -1,7 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <fart/Options.h>
|
||||
|
||||
class Cli
|
||||
{
|
||||
public:
|
||||
Cli();
|
||||
Options options;
|
||||
|
||||
int run(int argc, char * argv[]);
|
||||
|
||||
private:
|
||||
int handle_option(size_t option_idx, const char * arg_value);
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
|
||||
struct Options
|
||||
{
|
||||
std::string input_file;
|
||||
std::string output_file;
|
||||
size_t width = 0u;
|
||||
size_t height = 0u;
|
||||
};
|
||||
@@ -5,6 +5,11 @@
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
Cli cli;
|
||||
int rc = cli.run(argc, argv);
|
||||
if (rc > 0)
|
||||
{
|
||||
return rc - 1;
|
||||
}
|
||||
Engine engine;
|
||||
printf("Hello\n");
|
||||
return 0;
|
||||
|
||||
Reference in new issue
Block a user