mirror of
https://github.com/systemd/systemd.git
synced 2024-11-02 02:21:44 +03:00
path-util: add new path_join_many() API
This commit is contained in:
parent
de06c0cf77
commit
cd8194a389
@ -495,6 +495,70 @@ char* path_join(const char *root, const char *path, const char *rest) {
|
||||
rest && rest[0] == '/' ? rest+1 : rest);
|
||||
}
|
||||
|
||||
char* path_join_many_internal(const char *first, ...) {
|
||||
char *joined, *q;
|
||||
const char *p;
|
||||
va_list ap;
|
||||
bool slash;
|
||||
size_t sz;
|
||||
|
||||
assert(first);
|
||||
|
||||
/* Joins all listed strings until NULL and places an "/" between them unless the strings end/begin already with
|
||||
* one so that it is unnecessary. Note that "/" which are already duplicate won't be removed. The string
|
||||
* returned is hence always equal or longer than the sum of the lengths of each individual string.
|
||||
*
|
||||
* Note: any listed empty string is simply skipped. This can be useful for concatenating strings of which some
|
||||
* are optional.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* path_join_many("foo", "bar") → "foo/bar"
|
||||
* path_join_many("foo/", "bar") → "foo/bar"
|
||||
* path_join_many("", "foo", "", "bar", "") → "foo/bar" */
|
||||
|
||||
sz = strlen(first);
|
||||
va_start(ap, first);
|
||||
while ((p = va_arg(ap, char*))) {
|
||||
|
||||
if (*p == 0) /* Skip empty items */
|
||||
continue;
|
||||
|
||||
sz += 1 + strlen(p);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
joined = new(char, sz + 1);
|
||||
if (!joined)
|
||||
return NULL;
|
||||
|
||||
if (first[0] != 0) {
|
||||
q = stpcpy(joined, first);
|
||||
slash = endswith(first, "/");
|
||||
} else {
|
||||
/* Skip empty items */
|
||||
joined[0] = 0;
|
||||
q = joined;
|
||||
slash = true; /* no need to generate a slash anymore */
|
||||
}
|
||||
|
||||
va_start(ap, first);
|
||||
while ((p = va_arg(ap, char*))) {
|
||||
|
||||
if (*p == 0) /* Skip empty items */
|
||||
continue;
|
||||
|
||||
if (!slash && p[0] != '/')
|
||||
*(q++) = '/';
|
||||
|
||||
q = stpcpy(q, p);
|
||||
slash = endswith(p, "/");
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return joined;
|
||||
}
|
||||
|
||||
int find_binary(const char *name, char **ret) {
|
||||
int last_error, r;
|
||||
const char *p;
|
||||
|
@ -50,6 +50,9 @@ int path_compare(const char *a, const char *b) _pure_;
|
||||
bool path_equal(const char *a, const char *b) _pure_;
|
||||
bool path_equal_or_files_same(const char *a, const char *b, int flags);
|
||||
char* path_join(const char *root, const char *path, const char *rest);
|
||||
char* path_join_many_internal(const char *first, ...) _sentinel_;
|
||||
#define path_join_many(x, ...) path_join_many_internal(x, __VA_ARGS__, NULL)
|
||||
|
||||
char* path_simplify(char *path, bool kill_dots);
|
||||
|
||||
static inline bool path_equal_ptr(const char *a, const char *b) {
|
||||
|
@ -567,6 +567,43 @@ static void test_path_startswith_set(void) {
|
||||
assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo2/bar", "/foo/quux", "", "/zzz"), NULL));
|
||||
}
|
||||
|
||||
static void test_path_join_many(void) {
|
||||
char *j;
|
||||
|
||||
assert_se(streq_ptr(j = path_join_many("", NULL), ""));
|
||||
free(j);
|
||||
|
||||
assert_se(streq_ptr(j = path_join_many("foo", NULL), "foo"));
|
||||
free(j);
|
||||
|
||||
assert_se(streq_ptr(j = path_join_many("foo", "bar"), "foo/bar"));
|
||||
free(j);
|
||||
|
||||
assert_se(streq_ptr(j = path_join_many("", "foo", "", "bar", ""), "foo/bar"));
|
||||
free(j);
|
||||
|
||||
assert_se(streq_ptr(j = path_join_many("", "", "", "", "foo", "", "", "", "bar", "", "", ""), "foo/bar"));
|
||||
free(j);
|
||||
|
||||
assert_se(streq_ptr(j = path_join_many("", "/", "", "/foo/", "", "/", "", "/bar/", "", "/", ""), "//foo///bar//"));
|
||||
free(j);
|
||||
|
||||
assert_se(streq_ptr(j = path_join_many("/", "foo", "/", "bar", "/"), "/foo/bar/"));
|
||||
free(j);
|
||||
|
||||
assert_se(streq_ptr(j = path_join_many("foo", "bar", "baz"), "foo/bar/baz"));
|
||||
free(j);
|
||||
|
||||
assert_se(streq_ptr(j = path_join_many("foo/", "bar", "/baz"), "foo/bar/baz"));
|
||||
free(j);
|
||||
|
||||
assert_se(streq_ptr(j = path_join_many("foo/", "/bar/", "/baz"), "foo//bar//baz"));
|
||||
free(j);
|
||||
|
||||
assert_se(streq_ptr(j = path_join_many("//foo/", "///bar/", "///baz//"), "//foo////bar////baz//"));
|
||||
free(j);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
@ -588,6 +625,7 @@ int main(int argc, char **argv) {
|
||||
test_skip_dev_prefix();
|
||||
test_empty_or_root();
|
||||
test_path_startswith_set();
|
||||
test_path_join_many();
|
||||
|
||||
test_systemd_installation_has_version(argv[1]); /* NULL is OK */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user