readarg/readopt.h
2022-09-24 21:12:22 +02:00

118 lines
3 KiB
C

#pragma once
#include <stdio.h>
#define READOPT_ALLOC_STRINGS(...) ((char *[]){__VA_ARGS__, NULL})
enum readopt_error {
READOPT_ERROR_SUCCESS,
READOPT_ERROR_NOVAL,
READOPT_ERROR_NOTREQ,
READOPT_ERROR_NOTOPT,
READOPT_ERROR_RANGEOPT,
READOPT_ERROR_RANGEOPER
};
enum readopt_form {
READOPT_FORM_SHORT,
READOPT_FORM_LONG
};
enum readopt_format {
READOPT_FORMAT_PLAIN,
READOPT_FORMAT_MDOC,
};
struct readopt_view_strings {
const char **strings;
size_t len;
};
struct readopt_bounds {
/* upper val will be ignored if inf is non-zero */
size_t val[2];
int inf;
};
struct readopt_oper {
char *name;
struct readopt_bounds bounds;
struct readopt_view_strings val;
};
struct readopt_opt {
/* two null-terminated arrays of either long or short option names */
char **names[2];
struct {
int req;
/* oper.name is the name of the value itself (not the option), such as "file" in "--config=file" */
struct readopt_oper oper;
} cont;
};
struct readopt_parser {
struct readopt_opt *opts;
struct readopt_oper *opers;
struct readopt_view_strings args;
struct {
int pending;
const char *grppos;
struct {
struct readopt_opt *opt;
/* reference to the current argument being parsed */
const char **arg;
/* reference to the last element of the option/operand value view */
const char **eoval;
/* intermediate operands which have not yet been assigned */
struct readopt_view_strings ioper;
} curr;
} state;
enum readopt_error error;
};
struct readopt_write_context {
size_t written;
void *additional;
struct {
FILE *stream;
size_t size;
} dest;
struct {
const char *payload;
size_t len;
} src;
/* returning 0 means that the current string will not be written */
int (*callback)(struct readopt_write_context *);
};
struct readopt_format_context {
enum readopt_format fmt;
struct {
const char *needles;
char pre;
} esc;
struct readopt_write_context *wr;
};
/* iteratively parse the arguments */
int readopt_parse(struct readopt_parser *rp);
/* args should always exclude the first element, like this: {.strings = argv + 1, .len = argc - 1} */
void readopt_parser_init(struct readopt_parser *rp, struct readopt_opt *opts, struct readopt_oper *opers, struct readopt_view_strings args);
/* check whether the argument is a valid option (can be used to check for the end of an array of options) */
int readopt_validate_opt(struct readopt_opt *opt);
/* check whether the argument is a valid operand (can be used to check for the end of an array of operands) */
int readopt_validate_oper(struct readopt_oper *oper);
/* check whether the operand's values are within the defined limits */
int readopt_validate_within(struct readopt_oper *oper);
/* get the upper limit */
size_t readopt_select_upper(struct readopt_bounds bounds);
/* get the lower limit (this does not always return the minimum, if e.g. .val is {0, 1} and inf != 0, then 1 will be considered the lower limit as well as the upper limit) */
size_t readopt_select_lower(struct readopt_bounds bounds);