Parse command-line arguments

This commit is contained in:
josh committed 2026-10-30 13:50:11 -04:00
1 parent 05dfa4f977
commit cc041168a1
4 files changed
+196 -2

No files matched your search

+173 -1
View File
@@ -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
View File
@@ -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);
};
+10
View File
@@ -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
View File
@@ -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;