From 4ea517a6e07f47117348c68c6fe087bf6d401558 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 16 Feb 2023 15:41:55 +0100
Subject: [PATCH] strv: add strv_copy_n() helper for copying part of a n strv

Conflict:Context Adaptation. Test case adaptation.
Reference:https://github.com/systemd/systemd/commit/4ea517a6e07f47117348c68c6fe087bf6d401558

---
 src/basic/strv.c     | 10 ++++++++--
 src/basic/strv.h     |  5 ++++-
 src/test/test-strv.c | 41 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+), 3 deletions(-)

diff --git a/src/basic/strv.c b/src/basic/strv.c
index 6a2e44c..d6c50f5 100644
--- a/src/basic/strv.c
+++ b/src/basic/strv.c
@@ -88,20 +88,26 @@ char** strv_free_erase(char **l) {
         return mfree(l);
 }
 
-char** strv_copy(char * const *l) {
+char** strv_copy_n(char * const *l, size_t m) {
         _cleanup_strv_free_ char **result = NULL;
         char **k, * const *i;
 
-        result = new(char*, strv_length(l) + 1);
+        result = new(char*, MIN(strv_length(l), m) + 1);
         if (!result)
                 return NULL;
 
         k = result;
         STRV_FOREACH(i, l) {
+                if (m == 0)
+                        break;
+
                 *k = strdup(*i);
                 if (!*k)
                         return NULL;
                 k++;
+
+                if (m != SIZE_MAX)
+                        m--;
         }
 
         *k = NULL;
diff --git a/src/basic/strv.h b/src/basic/strv.h
index 8674bfd..108ec25 100644
--- a/src/basic/strv.h
+++ b/src/basic/strv.h
@@ -29,7 +29,10 @@ char** strv_free_erase(char **l);
 DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase);
 #define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep)
 
-char** strv_copy(char * const *l);
+char** strv_copy_n(char * const *l, size_t n);
+static inline char** strv_copy(char * const *l) {
+        return strv_copy_n(l, SIZE_MAX);
+}
 size_t strv_length(char * const *l) _pure_;
 
 int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index 1345252..dd119a8 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -988,6 +988,46 @@ static void test_strv_fnmatch(void) {
         assert(pos == 1);
 }
 
+static void test_strv_copy_n(void) {
+        char **x = STRV_MAKE("a", "b", "c", "d", "e");
+        _cleanup_strv_free_ char **l = NULL;
+
+        l = strv_copy_n(x, 0);
+        assert_se(strv_equal(l, NULL));
+        strv_free(l);
+
+        l = strv_copy_n(x, 0);
+        assert_se(strv_equal(l, (char**) { NULL }));
+        strv_free(l);
+
+        l = strv_copy_n(x, 1);
+        assert_se(strv_equal(l, STRV_MAKE("a")));
+        strv_free(l);
+
+        l = strv_copy_n(x, 2);
+        assert_se(strv_equal(l, STRV_MAKE("a", "b")));
+        strv_free(l);
+
+        l = strv_copy_n(x, 3);
+        assert_se(strv_equal(l, STRV_MAKE("a", "b", "c")));
+        strv_free(l);
+
+        l = strv_copy_n(x, 4);
+        assert_se(strv_equal(l, STRV_MAKE("a", "b", "c", "d")));
+        strv_free(l);
+
+        l = strv_copy_n(x, 5);
+        assert_se(strv_equal(l, STRV_MAKE("a", "b", "c", "d", "e")));
+        strv_free(l);
+
+        l = strv_copy_n(x, 6);
+        assert_se(strv_equal(l, STRV_MAKE("a", "b", "c", "d", "e")));
+        strv_free(l);
+
+        l = strv_copy_n(x, SIZE_MAX);
+        assert_se(strv_equal(l, STRV_MAKE("a", "b", "c", "d", "e")));
+}
+
 int main(int argc, char *argv[]) {
         test_str_in_set();
         test_strptr_in_set();
@@ -1054,6 +1094,7 @@ int main(int argc, char *argv[]) {
 
         test_foreach_string();
         test_strv_fnmatch();
+        test_strv_copy_n();
 
         return 0;
 }
-- 
2.33.0

