Merge pull request #34511 from YHNdnzj/strv-extend-strv-consume
basic/strv: introduce strv_extend_strv_consume()
This commit is contained in:
@@ -43,7 +43,7 @@ void* greedy_realloc(
|
||||
size_t need,
|
||||
size_t size) {
|
||||
|
||||
size_t a, newalloc;
|
||||
size_t newalloc;
|
||||
void *q;
|
||||
|
||||
assert(p);
|
||||
@@ -60,14 +60,13 @@ void* greedy_realloc(
|
||||
return NULL;
|
||||
newalloc = need * 2;
|
||||
|
||||
if (size_multiply_overflow(newalloc, size))
|
||||
if (!MUL_ASSIGN_SAFE(&newalloc, size))
|
||||
return NULL;
|
||||
a = newalloc * size;
|
||||
|
||||
if (a < 64) /* Allocate at least 64 bytes */
|
||||
a = 64;
|
||||
if (newalloc < 64) /* Allocate at least 64 bytes */
|
||||
newalloc = 64;
|
||||
|
||||
q = realloc(*p, a);
|
||||
q = realloc(*p, newalloc);
|
||||
if (!q)
|
||||
return NULL;
|
||||
|
||||
|
||||
@@ -26,23 +26,23 @@ typedef void* (*mfree_func_t)(void *p);
|
||||
|
||||
#define alloca_safe(n) \
|
||||
({ \
|
||||
size_t _nn_ = n; \
|
||||
size_t _nn_ = (n); \
|
||||
assert(_nn_ <= ALLOCA_MAX); \
|
||||
alloca(_nn_ == 0 ? 1 : _nn_); \
|
||||
}) \
|
||||
|
||||
#define newa(t, n) \
|
||||
({ \
|
||||
size_t _n_ = n; \
|
||||
assert(!size_multiply_overflow(sizeof(t), _n_)); \
|
||||
(t*) alloca_safe(sizeof(t)*_n_); \
|
||||
size_t _n_ = (n); \
|
||||
assert_se(MUL_ASSIGN_SAFE(&_n_, sizeof(t))); \
|
||||
(t*) alloca_safe(_n_); \
|
||||
})
|
||||
|
||||
#define newa0(t, n) \
|
||||
({ \
|
||||
size_t _n_ = n; \
|
||||
assert(!size_multiply_overflow(sizeof(t), _n_)); \
|
||||
(t*) alloca0((sizeof(t)*_n_)); \
|
||||
size_t _n_ = (n); \
|
||||
assert_se(MUL_ASSIGN_SAFE(&_n_, sizeof(t))); \
|
||||
(t*) alloca0(_n_); \
|
||||
})
|
||||
|
||||
#define newdup(t, p, n) ((t*) memdup_multiply(p, n, sizeof(t)))
|
||||
|
||||
@@ -796,10 +796,10 @@ int replace_env_full(
|
||||
t = v;
|
||||
}
|
||||
|
||||
r = strv_extend_strv(&unset_variables, u, /* filter_duplicates= */ true);
|
||||
r = strv_extend_strv_consume(&unset_variables, TAKE_PTR(u), /* filter_duplicates= */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = strv_extend_strv(&bad_variables, b, /* filter_duplicates= */ true);
|
||||
r = strv_extend_strv_consume(&bad_variables, TAKE_PTR(b), /* filter_duplicates= */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -931,11 +931,11 @@ int replace_env_argv(
|
||||
return r;
|
||||
n[++k] = NULL;
|
||||
|
||||
r = strv_extend_strv(&unset_variables, u, /* filter_duplicates= */ true);
|
||||
r = strv_extend_strv_consume(&unset_variables, TAKE_PTR(u), /* filter_duplicates= */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = strv_extend_strv(&bad_variables, b, /*filter_duplicates= */ true);
|
||||
r = strv_extend_strv_consume(&bad_variables, TAKE_PTR(b), /* filter_duplicates= */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -368,17 +368,4 @@ assert_cc(sizeof(dummy_t) == 0);
|
||||
((long)(_current_ - _entries_) < (long)(ELEMENTSOF(_entries_) - 1)) && ({ entry = *_current_; true; }); \
|
||||
_current_++)
|
||||
|
||||
#define DECIMAL_STR_FMT(x) _Generic((x), \
|
||||
char: "%c", \
|
||||
bool: "%d", \
|
||||
unsigned char: "%d", \
|
||||
short: "%hd", \
|
||||
unsigned short: "%hu", \
|
||||
int: "%d", \
|
||||
unsigned: "%u", \
|
||||
long: "%ld", \
|
||||
unsigned long: "%lu", \
|
||||
long long: "%lld", \
|
||||
unsigned long long: "%llu")
|
||||
|
||||
#include "log.h"
|
||||
|
||||
@@ -35,7 +35,12 @@ static inline void* mempcpy_safe(void *dst, const void *src, size_t n) {
|
||||
return mempcpy(dst, src, n);
|
||||
}
|
||||
|
||||
#define mempcpy_typesafe(dst, src, n) (typeof((dst)[0])*) mempcpy_safe(dst, src, n)
|
||||
#define mempcpy_typesafe(dst, src, n) \
|
||||
({ \
|
||||
size_t _sz_; \
|
||||
assert_se(MUL_SAFE(&_sz_, sizeof((dst)[0]), n)); \
|
||||
(typeof((dst)[0])*) mempcpy_safe(dst, src, _sz_); \
|
||||
})
|
||||
|
||||
/* Normal memcmp() requires s1 and s2 to be nonnull. We do nothing if n is 0. */
|
||||
static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {
|
||||
|
||||
+11
-12
@@ -201,18 +201,17 @@ int strextendf_with_separator(char **x, const char *separator, const char *forma
|
||||
|
||||
char* strrep(const char *s, unsigned n);
|
||||
|
||||
#define strrepa(s, n) \
|
||||
({ \
|
||||
const char *_sss_ = (s); \
|
||||
size_t _nnn_ = (n), _len_ = strlen(_sss_); \
|
||||
assert(!size_multiply_overflow(_len_, _nnn_)); \
|
||||
_len_ *= _nnn_; \
|
||||
char *_d_, *_p_; \
|
||||
_p_ = _d_ = newa(char, _len_ + 1); \
|
||||
for (size_t _i_ = 0; _i_ < _nnn_; _i_++) \
|
||||
_p_ = stpcpy(_p_, _sss_); \
|
||||
*_p_ = 0; \
|
||||
_d_; \
|
||||
#define strrepa(s, n) \
|
||||
({ \
|
||||
const char *_sss_ = (s); \
|
||||
size_t _nnn_ = (n), _len_ = strlen(_sss_); \
|
||||
assert_se(MUL_ASSIGN_SAFE(&_len_, _nnn_)); \
|
||||
char *_d_, *_p_; \
|
||||
_p_ = _d_ = newa(char, _len_ + 1); \
|
||||
for (size_t _i_ = 0; _i_ < _nnn_; _i_++) \
|
||||
_p_ = stpcpy(_p_, _sss_); \
|
||||
*_p_ = 0; \
|
||||
_d_; \
|
||||
})
|
||||
|
||||
int split_pair(const char *s, const char *sep, char **l, char **r);
|
||||
|
||||
+78
-9
@@ -264,20 +264,18 @@ char** strv_new_internal(const char *x, ...) {
|
||||
|
||||
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
|
||||
size_t p, q, i = 0;
|
||||
char **t;
|
||||
|
||||
assert(a);
|
||||
|
||||
if (strv_isempty(b))
|
||||
q = strv_length(b);
|
||||
if (q == 0)
|
||||
return 0;
|
||||
|
||||
p = strv_length(*a);
|
||||
q = strv_length(b);
|
||||
|
||||
if (p >= SIZE_MAX - q)
|
||||
return -ENOMEM;
|
||||
|
||||
t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
|
||||
char **t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -306,9 +304,67 @@ rollback:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int strv_extend_strv_consume(char ***a, char **b, bool filter_duplicates) {
|
||||
_cleanup_strv_free_ char **b_consume = b;
|
||||
size_t p, q, i;
|
||||
|
||||
assert(a);
|
||||
|
||||
q = strv_length(b);
|
||||
if (q == 0)
|
||||
return 0;
|
||||
|
||||
p = strv_length(*a);
|
||||
if (p == 0) {
|
||||
strv_free_and_replace(*a, b_consume);
|
||||
|
||||
if (filter_duplicates)
|
||||
strv_uniq(*a);
|
||||
|
||||
return strv_length(*a);
|
||||
}
|
||||
|
||||
if (p >= SIZE_MAX - q)
|
||||
return -ENOMEM;
|
||||
|
||||
char **t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
t[p] = NULL;
|
||||
*a = t;
|
||||
|
||||
if (!filter_duplicates) {
|
||||
*mempcpy_typesafe(t + p, b, q) = NULL;
|
||||
i = q;
|
||||
} else {
|
||||
i = 0;
|
||||
|
||||
STRV_FOREACH(s, b) {
|
||||
if (strv_contains(t, *s)) {
|
||||
free(*s);
|
||||
continue;
|
||||
}
|
||||
|
||||
t[p+i] = *s;
|
||||
|
||||
i++;
|
||||
t[p+i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
assert(i <= q);
|
||||
|
||||
b_consume = mfree(b_consume);
|
||||
|
||||
return (int) i;
|
||||
}
|
||||
|
||||
int strv_extend_strv_biconcat(char ***a, const char *prefix, const char* const *b, const char *suffix) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
|
||||
STRV_FOREACH(s, b) {
|
||||
char *v;
|
||||
|
||||
@@ -384,7 +440,7 @@ int strv_split_full(char ***t, const char *s, const char *separators, ExtractFla
|
||||
}
|
||||
|
||||
int strv_split_and_extend_full(char ***t, const char *s, const char *separators, bool filter_duplicates, ExtractFlags flags) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
char **l;
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
@@ -394,7 +450,7 @@ int strv_split_and_extend_full(char ***t, const char *s, const char *separators,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = strv_extend_strv(t, l, filter_duplicates);
|
||||
r = strv_extend_strv_consume(t, l, filter_duplicates);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -987,10 +1043,16 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);
|
||||
|
||||
static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) {
|
||||
char **l;
|
||||
int r;
|
||||
|
||||
assert(h);
|
||||
assert(key);
|
||||
assert(value);
|
||||
|
||||
l = hashmap_get(h, key);
|
||||
if (l) {
|
||||
/* A list for this key already exists, let's append to it if it is not listed yet */
|
||||
@@ -1018,6 +1080,7 @@ static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const c
|
||||
r = hashmap_put(h, t, l2);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(t);
|
||||
TAKE_PTR(l2);
|
||||
}
|
||||
@@ -1028,6 +1091,10 @@ static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const c
|
||||
int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
|
||||
int r;
|
||||
|
||||
assert(h);
|
||||
assert(key);
|
||||
assert(value);
|
||||
|
||||
r = _hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1038,6 +1105,10 @@ int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HA
|
||||
int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
|
||||
int r;
|
||||
|
||||
assert(h);
|
||||
assert(key);
|
||||
assert(value);
|
||||
|
||||
r = _ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1045,8 +1116,6 @@ int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const
|
||||
return string_strv_hashmap_put_internal(PLAIN_HASHMAP(*h), key, value);
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);
|
||||
|
||||
int strv_rebreak_lines(char **l, size_t width, char ***ret) {
|
||||
_cleanup_strv_free_ char **broken = NULL;
|
||||
int r;
|
||||
|
||||
+3
-1
@@ -44,10 +44,13 @@ int strv_copy_unless_empty(char * const *l, char ***ret);
|
||||
size_t strv_length(char * const *l) _pure_;
|
||||
|
||||
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
|
||||
int strv_extend_strv_consume(char ***a, char **b, bool filter_duplicates);
|
||||
|
||||
int strv_extend_strv_biconcat(char ***a, const char *prefix, const char* const *b, const char *suffix);
|
||||
static inline int strv_extend_strv_concat(char ***a, const char* const *b, const char *suffix) {
|
||||
return strv_extend_strv_biconcat(a, NULL, b, suffix);
|
||||
}
|
||||
|
||||
int strv_prepend(char ***l, const char *value);
|
||||
|
||||
/* _with_size() are lower-level functions where the size can be provided externally,
|
||||
@@ -253,7 +256,6 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space);
|
||||
#define strv_free_and_replace(a, b) \
|
||||
free_and_replace_full(a, b, strv_free)
|
||||
|
||||
extern const struct hash_ops string_strv_hash_ops;
|
||||
int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS);
|
||||
int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS);
|
||||
#define string_strv_hashmap_put(h, k, v) _string_strv_hashmap_put(h, k, v HASHMAP_DEBUG_SRC_ARGS)
|
||||
|
||||
Reference in New Issue
Block a user