readarg/readopt.h

141 lines
4.4 KiB
C
Raw Normal View History

2021-02-08 16:07:25 +00:00
#pragma once
#include <stdio.h>
#define READOPT_ALLOC_STRINGS(...) ((char *[]){__VA_ARGS__, NULL})
enum readopt_status {
READOPT_STATUS_SUCCESS,
READOPT_STATUS_NOVAL,
READOPT_STATUS_NOTREQ,
READOPT_STATUS_NOTOPT,
READOPT_STATUS_RANGEOPT,
READOPT_STATUS_RANGEOPER
};
enum readopt_form {
READOPT_FORM_SHORT,
READOPT_FORM_LONG
};
enum readopt_format {
READOPT_FORMAT_PLAIN,
READOPT_FORMAT_MDOC,
};
struct readopt_view_strings {
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;
char *grppos;
struct {
struct readopt_opt *opt;
/* reference to the current argument being parsed */
char **arg;
/* reference to the last element of the option/operand value view */
char **eoval;
/* intermediate operands which have not yet been assigned */
struct readopt_view_strings ioper;
} curr;
} state;
};
struct readopt_answer {
int end;
enum readopt_status status;
};
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;
};
/* parse everything at once until either an error occurs or the parsing process was successful */
struct readopt_answer readopt_parse_all(struct readopt_parser *rp);
/* iteratively parse the arguments */
struct readopt_answer 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);
/* args should always exclude the first element, like this: {.strings = argv + 1, .len = argc - 1} */
struct readopt_parser readopt_parser_create(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);
/* pass a string like "thing=value" and get "value" back */
char *readopt_keyval(char *s);
/* write the passed status as a string via ctx */
int readopt_put_status(enum readopt_status status, struct readopt_write_context *ctx);
/* write the usage string, either as plaintext or mdoc format */
void readopt_put_usage(struct readopt_parser *rp, struct readopt_format_context *ctx);
void readopt_write_stream(struct readopt_write_context *ctx);
void readopt_write_string(struct readopt_write_context *ctx, const char *string);
void readopt_write_char(struct readopt_write_context *ctx, char ch);
void readopt_cond_write_string(enum readopt_format desired, struct readopt_format_context *ctx, const char *string);
void readopt_cond_write_char(enum readopt_format desired, struct readopt_format_context *ctx, char ch);
void readopt_write_esc_string(struct readopt_format_context *ctx, const char *string);
void readopt_cond_write_esc_string(enum readopt_format desired, struct readopt_format_context *ctx, const char *string);