Author: David Rheinsberg <david.rheinsberg@gmail.com>
Origin: backport, https://github.com/c-util/c-stdaux/commit/7a8493bebc595f94ea57fa1cb6a765a66185aa95
Description: add c_memcpy()
 Alongside c_memset(), this adds c_memcpy() with the same trick of
 allowing empty copies.
--- a/subprojects/c-stdaux/src/c-stdaux.h
+++ b/subprojects/c-stdaux/src/c-stdaux.h
@@ -488,6 +488,24 @@
         return p;
 }
 
+/**
+ * c_memcpy() - copy memory area
+ * @dst:        pointer to target area
+ * @src:        pointer to source area
+ * @n:          length of area to copy
+ *
+ * Copy the memory of size @n from @src to @dst, just as `memcpy(3)` does,
+ * except this function allows either to be NULL if @n is zero. In the latter
+ * case, the operation is a no-op.
+ *
+ * Return: @p is returned.
+ */
+static inline void *c_memcpy(void *dst, const void *src, size_t n) {
+        if (n > 0)
+                memcpy(dst, src, n);
+        return dst;
+}
+
 /*
  * Common Destructors
  *
--- a/subprojects/c-stdaux/src/test-api.c
+++ b/subprojects/c-stdaux/src/test-api.c
@@ -188,6 +188,7 @@
         void *fns[] = {
                 (void *)c_errno,
                 (void *)c_memset,
+                (void *)c_memcpy,
                 (void *)c_free,
                 (void *)c_close,
                 (void *)c_fclose,
--- a/subprojects/c-stdaux/src/test-basic.c
+++ b/subprojects/c-stdaux/src/test-basic.c
@@ -332,6 +332,19 @@
                         abort();
                 c_assert(p == NULL);
         }
+
+        /*
+         * Test c_memcpy() with a simple 8-byte copy.
+         */
+        {
+                uint64_t v1 = (uint64_t)-1, v2 = (uint64_t)0;
+
+                c_assert(v1 == (uint64_t)-1);
+                c_memcpy(&v1, &v2, sizeof(v1));
+                c_assert(v1 == (uint64_t)0);
+
+                c_memcpy(NULL, NULL, 0);
+        }
 }
 
 /*
