Started adding func-ptr based argument definition & parsing structure and functions based around it.

view: Added more slicing / splitting related functions for arg parsing.

Fortune for sink's current commit: Future blessing − 末吉
args
Avril 2 years ago
parent 2d040d5584
commit 05a7b0f460

173
args.c

@ -6,6 +6,8 @@
#include "args.h"
#include "comp_features.h"
#define _PASTE_(x, y) x ## y
#define _PASTE(x, y) _PASTE_(x, y)
@ -19,6 +21,115 @@
_box_name(pT); })
typedef __typeof( *((pargs_t*)0)->fd_pass ) fd_pass_t;
typedef __typeof( ((pargs_t*)0)->replace ) replace_t;
struct input_arguments
{
int *restrict p_argc;
char** *restrict p_argv;
char** *restrict p_envp;
};
typedef bool (single_arg_parse_func)(int, const char*, struct input_arguments* restrict, pargs_t*);
typedef void (single_arg_error_func)(struct arg_parse_error* restrict);
enum argument_type {
AT_SHORT = 0,
AT_LONG,
AT_LONG_EQ,
AT_LONG_OR_EQ = AT_LONG | AT_LONG_EQ,
};
struct argument_parser {
union {
const char* l;
char s;
} name;
enum argument_type kind;
bool is_default;
const char* destription;
const char* example;
single_arg_parse_func* parse;
single_arg_error_func* error;
};
typedef __typeof( ((struct argument_parser*)0)->name ) av_name_t;
static bool _si_handle_replace(int idx, const char* arg, struct input_arguments* restrict in, pargs_t* out)
{
char c;
bool* restrict repl;
switch(c = *arg) {
case 'i':
case 'I':
repl = &out->replace.in;
break;
case 'o':
case 'O':
repl = &out->replace.out;
break;
case 'e':
case 'E':
repl = &out->replace.err;
break;
default: return false;
}
*repl = !(c & 0x20);
return true;
}
static const struct argument_parser AV_ARGS[] = {
{ { .s= 'i' }, AT_SHORT, true, "Sink stdin", NULL, _si_handle_replace, NULL },
{ { .s='o' }, AT_SHORT, true, "Sink stdout", NULL, _si_handle_replace, NULL },
{ { .s='e' }, AT_SHORT, false, "Sink stderr", NULL, _si_handle_replace, NULL },
{ { .s='I' }, AT_SHORT, false, "Keep stdin", NULL, _si_handle_replace, NULL },
{ { .s='O' }, AT_SHORT, false, "Keep stdout", NULL, _si_handle_replace, NULL },
{ { .s='E' }, AT_SHORT, true, "Keep stderr", NULL, _si_handle_replace, NULL },
};
#define AV_ARGS_SZ (sizeof(AV_ARGS) / sizeof(struct argument_parser))
static inline bool _av_long_extract_name(const char* name, enum argument_type ty, view_t* restrict out)
{
register bool ok = true;
switch(ty) {
case AT_LONG_EQ:
ok = !!sv_split_cstr(name, '=', out, NULL);
break;
case AT_LONG_OR_EQ:
if(!sv_split_cstr(name, '=', out, NULL)) {
if(0)
case AT_SHORT: name = (const char[2]){*name, 0};
*out = sv_from_cstr(name);
}
break;
default: return false;
}
return ok;
}
static inline const struct argument_parser* _av_lookup(av_name_t name, enum argument_type ty)
{
for(size_t i=0;i<AV_ARGS_SZ;i++) {
const struct argument_parser* current = AV_ARGS+i;
if(__builtin_constant_p(ty) && ty == AT_SHORT) {
if(current->name.s == name.s) return current;
} else switch(ty) {
case AT_SHORT: if(current->name.s == name.s) return current;
default: {
view_t real_name;
if(!_av_long_extract_name(name.l, ty, &real_name)) continue; // Argument requires `=` but one wasn't fount, continue.
if(sv_eq_cstr(real_name, current->name.l)) return current;
} break;
}
}
return NULL;
}
const pargs_t* parsed_args = NULL;
static const pargs_t default_args[1] = { A_DEFAULT_ARGS }; //A_DEFAULT_ARGS_P;
@ -143,11 +254,65 @@ const pargs_t* a_get_program_args() {
bool a_is_parsed() { return parsed_args != NULL; }
bool a_parse_into(union arg_parse_result *restrict parsed, int *restrict argc, char** *restrict p_argv, char** *restrict p_envp)
static bool a_parse__short(int i, const char* arg, struct input_arguments in, pargs_t* restrict out)
{
const struct argument_parser* p = _av_lookup( (av_name_t){ .s = *arg, }, AT_SHORT );
if(!p) return false;
else {
if(!p->parse(i, arg, &in, out)) {
if(p->error) {
//TODO: How to handle returning `struct arg_parse_error`? Make `out` union arg_parse_result* restrict` instead?
}
return false;
}
}
return true;
}
static bool a_parse__long(int i, const char* arg, struct input_arguments in, pargs_t* restrict out)
{
//TODO
parsed->err = (struct arg_parse_error) { .kind = A_PF_UNKNOWN, ._data = { .none = {} } };
return false;
//TODO: determine if `arg` is `k=v` or not
bool is_eq = /* TODO */ false;
const struct argument_parser* p = _av_lookup( (av_name_t){ .l = arg, }, is_eq ? AT_LONG_EQ : AT_LONG );
if(!p) return false;
else {
//TODO :if(!p->parse(
}
return true;
}
inline static bool _a_parse_into(union arg_parse_result *restrict parsed, struct input_arguments input)
{
bool ok = true;;
pargs_t args = A_DEFAULT_ARGS;
//TODO: Parse arguments
_end:
if(ok)
_set_ok: parsed->ok = args;
else
_set_err: parsed->err = (struct arg_parse_error) { .kind = A_PF_UNKNOWN, ._data = { .none = {} } };
return ok;
}
inline bool a_parse_into(union arg_parse_result *restrict parsed, int *restrict p_argc, char** *restrict p_argv, char** *restrict p_envp)
{
#if FEATURE_HAS_FLAG(NO_ARGS)
parsed->ok = A_DEFAULT_ARGS;
return true;
#else
struct input_arguments input = {
p_argc,
p_argv,
p_envp,
};
return _a_parse_into(parsed, input);
#endif
}
const struct arg_parse_error* a_parse(int *restrict argc, char** *restrict p_argv, char** *restrict p_envp)

105
view.c

@ -12,6 +12,20 @@
#define $nullchk(ptr, or) ({ __auto_type _$p = (ptr); \
__builtin_expect(_$p == NULL, false) ? ({ or; }),NULL : _$p; })
#define min(x, y) ({ __auto_type _$min_x = (x); \
__auto_type _$min_y = (y); \
_$min_x < _$min_y ? _$min_x : _$min_y; })
#define ptrdiff(x, y) ({ \
__auto_type _$ptrdiff_x = (x); \
__auto_type _$ptrdiff_y = (y); \
(ptrdiff_t)((_$ptrdiff_x < _$ptrdiff_y) \
? ((uintptr_t)_$ptrdiff_y) - ((uintptr_t)_$ptrdiff_x) \
: ((uintptr_t)_$ptrdiff_x) - ((uintptr_t)_$ptrdiff_y)); \
})
typedef uint8_t byte_t;
__attribute__((packed))
@ -111,3 +125,94 @@ size_t sv_copy_to(size_t sz, char buffer[restrict static sz], view_t view)
return _sv_copy_manual(sz, buffer, view);
}
}
// String views //
inline view_t sv_from_cstr(const char* p)
{
return (view_t) {
.len = strlen(p),
.ptr = (char*)p,
};
}
inline view_t sv_slice_cstr(const char* p, size_t n)
{
if(__builtin_constant_p(n) && !n ) return (view_t) { .len = 0, .ptr = (char*)p };
else return (view_t) { .len = min(strlen(p), n), .ptr = (char*)p };
}
inline view_t sv_slice(view_t v, size_t s, size_t n)
{
if(__builtin_expect((s = min(v.len, s)) == v.len,false)) return (view_t) { .len = 0, .ptr = v.ptr+v.len };
else {
return (view_t) {
.len = n
? min(v.len - s, n)//min(v.len,n) - s
: v.len - s, //XXX: Test this, I think it's correct, but dunno...
.ptr = v.ptr + s,
};
}
}
inline size_t sv_split(view_t p, char on, view_t* restrict first, view_t* restrict second)
{
if(__builtin_constant_p(first) && __builtin_constant_p(second) && !first && !second)
return (size_t)(((uintptr_t) $nullchk(memchr(p.ptr, (int)on, p.len), return 0)) - (uintptr_t)p.ptr);
else {
char* start = memchr(p.ptr, (int)on, p.len); // `on` chr here
if(__builtin_expect(start==NULL, false)) return 0;
size_t diff = (size_t)ptrdiff(p.ptr, start);
if(first) *first = (view_t) {
.len = diff,
.ptr = p.ptr,
};
if(second) *second = (view_t) {
.len = (p.len - diff) + 1, //XXX: WARNING: this might be an off-by-1 error...
.ptr = start + 1,
};
return diff;
}
}
size_t sv_split_cstr(const char* p, char on, view_t* restrict first, view_t* restrict second)
{
return sv_split(sv_from_cstr(p), on, first, second);
}
inline char* sv_to_cstr(view_t view, char* restrict buffer, size_t n)
{
if(__builtin_constant_p(buffer) && !buffer) {
if(__builtin_constant_p(n) && !n) return strndup(view.ptr, view.len);
else return strndup(view.ptr, n ? min(n, view.len) : view.len);
} else {
if(__builtin_constant_p(n) && !n) {
return buffer;
} else {
sv_copy_to(n, buffer, view);
return buffer;
}
}
}
__attribute__((malloc))
char* sv_dupto_cstr(view_t view)
{
return sv_to_cstr(view, NULL, 0);
}
bool sv_eq_cstr(view_t a, const char* b)
{
return strncmp(a.ptr, b, a.len) == 0 && strlen(b) == a.len;
}
bool sv_eq(view_t a, view_t b)
{
return a.len == b.len && (__builtin_expect(a.ptr == b.ptr, false) || memcmp(a.ptr, b.ptr, a.len));
}

@ -3,6 +3,7 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
typedef struct string_view {
size_t len;
@ -19,7 +20,31 @@ struct string;
view_t s_get_str(str_info_t data) __attribute__((pure));
str_info_t s_get_info(view_t str) __attribute__((pure));
view_t sv_slice(view_t v, size_t s, size_t n);
size_t sv_split(view_t p, char on, view_t* restrict first, view_t* restrict second);
view_t sv_from_cstr(const char* p);
view_t sv_slice_cstr(const char* p, size_t n);
__attribute__((__gnu_inline__))
extern inline size_t sv_split_cstr(const char* p, char on, view_t* restrict first, view_t* restrict second)
{
return sv_split(sv_from_cstr(p), on, first, second);
}
/// Copy `view` into nul-terminated `buffer`, up to `size` bytes. Return the number of bytes that would've been copied regardless of `sz` (incl. nul-terminator)
size_t sv_copy_to(size_t sz, char buffer[restrict static sz], view_t view);
char* sv_to_cstr(view_t view, char* restrict buffer, size_t n);
__attribute__((__gnu_inline__, malloc))
extern inline char* sv_dupto_cstr(view_t view)
{ return sv_to_cstr(view, (char*)0, 0); }
bool sv_eq_cstr(view_t a, const char* b);
__attribute__((__gnu_inline__))
extern inline bool sv_eq(view_t a, view_t b)
{
return a.len == b.len && (__builtin_expect(a.ptr == b.ptr, false) || (&sv_eq)(a, b));
}
#endif /* _VIEW_H */

Loading…
Cancel
Save