From fc81dd4b749767818b6145d87474ed128c7ec306 Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 14 Mar 2022 14:46:39 +0000 Subject: [PATCH] Added `pargs_t.env_pass`: Pass all, none, or specific (allocated) environment vars. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fortune for sink's current commit: Curse − 凶 --- args.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- args.h | 9 +++-- 2 files changed, 112 insertions(+), 6 deletions(-) diff --git a/args.c b/args.c index bf0bc4a..de88ffc 100644 --- a/args.c +++ b/args.c @@ -21,6 +21,79 @@ typedef __typeof( *((pargs_t*)0)->fd_pass ) fd_pass_t; const pargs_t* parsed_args = NULL; static const pargs_t default_args[1] = { A_DEFAULT_ARGS }; //A_DEFAULT_ARGS_P; +__attribute__((__gnu_inline__, __always_inline__)) +static inline size_t _a_ptr_list_len(void* const* restrict arr) +{ + register size_t n=0; + while(*arr++) n+=1; + return n; +} + +inline static void* _a_clone__string(const void* i) { return __builtin_expect(i!=NULL, true) ? strdup(i) : NULL; } +inline static void** _a_clone_ptr_list(void* const arr[static 1], void* (*clone_elem)(const void*), size_t* restrict _n) +{ + size_t len; + if(__builtin_constant_p(_n) && _n) *_n = len = _a_ptr_list_len(arr); + else { + len = _a_ptr_list_len(arr); + if(_n) *_n = len; + } + + void* *array = aligned_alloc(_Alignof(void*), sizeof(void*)*(len+1)); + if(__builtin_expect(array!=NULL, true)) { + if(__builtin_constant_p(clone_elem) && !clone_elem) + memcpy(array, arr, sizeof(void*) * len); + else if(clone_elem) { + //void* *restrict out = array; + while(len --> 0) { + // *out++ = clone_elem(*arr++); + array[len] = clone_elem(arr[len]); + } + } else memcpy(array, arr, sizeof(void*) * len); + array[len] = NULL; // NULL-terminate ptr list + } + return array; +} +static char** _a_clone_string_list(char* const arr[static 1], size_t* restrict n) +{ + return (char**)_a_clone_ptr_list((void* const*)arr, _a_clone__string, n); +} + +inline static void _a_free_ptr_list(void* arr[static restrict 1], void (*free_elem)(void*), size_t* restrict _n) +{ + if(__builtin_constant_p(_n) && __builtin_constant_p(free_elem) && !_n && !free_elem) { + free(arr); + return; + } else { + size_t n =0; + void* restrict _to_free = arr; + + void* cur; + if(__builtin_constant_p(free_elem) && free_elem) { + if( __builtin_constant_p(_n) && !_n) + while( (cur = *arr++) ) free_elem(cur); + else + while( (cur = *arr++) ) + { + free_elem(cur); n+=1; + } + } else if(!free_elem) + while( (cur = *arr++) ) n+=1; + else while( (cur = *arr++) ) + { + free_elem(cur); n+=1; + } + + free(_to_free); + + if(_n) *_n = n; + } +} +static void _a_free_string_list(char* *restrict arr/*[static restrict 1]*/, size_t* restrict n) +{ + _a_free_ptr_list((void**restrict)arr, free, n); +} + static fd_pass_t* _a_alloc_fd_pass(size_t n) { fd_pass_t* pass = aligned_alloc(_Alignof(fd_pass_t), sizeof(fd_pass_t) + (sizeof(int)*n)); @@ -105,7 +178,7 @@ pargs_t* a_clone_args(const pargs_t* args) case ((uintptr_t)A_FD_PASS_ALL): case ((uintptr_t)A_FD_PASS_NONE): clone.fd_pass = fd_pass_p; - break; + if(0) default: { // Clone fd_pass_p. clone.fd_pass = a_pass_fds_a(fd_pass_p->n, fd_pass_p->fds); @@ -113,6 +186,21 @@ pargs_t* a_clone_args(const pargs_t* args) } }; + /* env_pass */ { + char** env_pass_p = args->env_pass; + switch((uintptr_t)env_pass_p) { + case (uintptr_t)A_ENV_PASS_ALL: + case (uintptr_t)A_ENV_PASS_NONE: + clone.env_pass = env_pass_p; + if(0) + default: { + // Clone envp deeply. + clone.env_pass = _a_clone_string_list(env_pass_p, NULL); + + } break; + } + }; + return $box(clone); } else return NULL; } @@ -121,15 +209,28 @@ inline void a_free_args(const pargs_t* args) { if(__builtin_expect(args==NULL, false)) return; + /* target */ { + char* target_p = args->target; + if(target_p) free(target_p); + }; + /* fd_pass */ { __auto_type fd_pass_p = args->fd_pass; if(fd_pass_p != A_FD_PASS_NONE && fd_pass_p != A_FD_PASS_ALL) free(fd_pass_p); }; - /* target */ { - char* target_p = args->target; - if(target_p) free(target_p); + /* env_pass */ { + char** env_pass_p = args->env_pass; + switch((uintptr_t)env_pass_p) { + case (uintptr_t)A_ENV_PASS_ALL: + case (uintptr_t)A_ENV_PASS_NONE: + if(0) + default: { + // Free each string in `env_pass_p`, then free `env_pass_p` itself + _a_free_string_list(env_pass_p, NULL); + } break; + } }; } diff --git a/args.h b/args.h index 9ca8bb0..80d799f 100644 --- a/args.h +++ b/args.h @@ -30,6 +30,8 @@ typedef struct arg_parsed { int fds[]; }* restrict fd_pass; // A_FD_PASS_NONE + char** env_pass; // A_ENV_PASS_ALL + } pargs_t; struct arg_parse_error { @@ -38,17 +40,20 @@ struct arg_parse_error { struct{} none; } _data; }; -_Static_assert(sizeof( ((struct arg_parse_error*)(0))->_data ) == 0, "Bad union ZST"); +_Static_assert(sizeof( ((struct arg_parse_error*)(0))->_data.none ) == 0, "Bad union ZST"); union arg_parse_result { struct arg_parsed ok; struct arg_parse_error err; }; +#define A_ENV_PASS_ALL NULL +#define A_ENV_PASS_NONE ((void*)(~((uintptr_t)0ul))) + #define A_FD_PASS_ALL ((void*)(~((uintptr_t)0ul))) #define A_FD_PASS_NONE NULL -#define A_DEFAULT_ARGS ((pargs_t){ { true, true, false}, NULL, A_FD_PASS_NONE }) +#define A_DEFAULT_ARGS ((pargs_t){ { true, true, false}, NULL, A_FD_PASS_NONE, A_ENV_PASS_ALL }) #define A_DEFAULT_ARGS_P ((pargs_t[1]) { A_DEFAULT_ARGS } ) extern const pargs_t* parsed_args;