Skip to content

Instantly share code, notes, and snippets.

@pommicket
Created September 22, 2023 20:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pommicket/78c4332deac145a2f92a695b009f7c64 to your computer and use it in GitHub Desktop.
Save pommicket/78c4332deac145a2f92a695b009f7c64 to your computer and use it in GitHub Desktop.
tiny C argument parser
/*
tiny argument parser
accepts both - and -- prefixes (they are treated the same)
usage:
ArgParser parser = {.argc = argc, .argv = argv, .options_with_value = "output,foo"};
while (arg_parser_next(&parser)) {
if (!parser.option) {
printf("standalone argument %s\n", parser.value);
} else if (strcmp(parser.option, "output") == 0) {
printf("outputting to %s...\n", parser.value);
} else if (strcmp(parser.option, "foo") == 0) {
printf("your foo is %s\n", parser.value);
} else if (strcmp(parser.option, "bar") == 0) {
// parser.value will be NULL
printf("you passed in the bar flag!\n");
} else if (parser.option) {
printf("unrecognized option: %s\n", parser.option);
exit(EXIT_FAILURE);
}
}
wow its so simple!
license: 0BSD
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int argc;
char **argv;
const char *options_with_value;
const char *option;
const char *value;
int i;
unsigned char no_option;
} ArgParser;
static int arg_parser_next(ArgParser *parser) {
top:
if (parser->i <= 0)
parser->i = 1;
if (parser->i >= parser->argc)
return 0;
const char *const arg = parser->argv[parser->i++];
if (parser->no_option)
goto no_option;
if (arg[0] == '-') {
const char *option = arg + 1;
if (option[0] == '-') {
option += 1;
}
if (option[0] == '\0') {
parser->no_option = 1;
goto top;
}
int requires_arg = 0;
const char *p = parser->options_with_value;
while (p && *p) {
size_t n = strcspn(p, ",");
if (strncmp(p, option, n) == 0) {
requires_arg = 1;
break;
}
p += n;
while (*p == ',')
p += 1;
}
if (requires_arg) {
parser->option = option;
if (parser->i >= parser->argc) {
fprintf(stderr, "Error: no value provided for option %s\n", option);
exit(EXIT_FAILURE);
}
parser->value = parser->argv[parser->i++];
} else {
parser->option = option;
parser->value = 0;
}
return 1;
}
no_option:
parser->option = 0;
parser->value = arg;
return 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment