This is less error-prone.
Supply a mempcpy if the system lacks it.
* Makefile, NEWS: Mention this.
* localtime.c (tzloadbody, tzparse):
* zic.c (random_dirent, relname, doabbr):
* zdump.c (my_snprintf) [!HAVE_SNPRINTF]:
(istrftime):
Prefer mempcpy to doing it by hand.
* private.h (HAVE_MEMPCPY): New macro.
(mempcpy) [!HAVE_MEMPCPY]: New function.
---
 Makefile    |  1 +
 NEWS        |  3 +++
 localtime.c | 13 +++++++------
 private.h   | 17 +++++++++++++++++
 zdump.c     | 11 +++++++----
 zic.c       | 36 ++++++++++++++++++++----------------
 6 files changed, 55 insertions(+), 26 deletions(-)

diff --git a/Makefile b/Makefile
index 83122ecc..5b577781 100644
--- a/Makefile
+++ b/Makefile
@@ -262,6 +262,7 @@ LDLIBS=
 #  -DHAVE_LOCALTIME_RZ=0 if you do not want zdump to use localtime_rz
 #      localtime_rz can make zdump significantly faster, but is nonstandard.
 #  -DHAVE_MALLOC_ERRNO=0 if malloc etc. do not set errno on failure.
+#  -DHAVE_MEMPCPY=1 if your system has mempcpy, 0 if not (default is guessed)
 #  -DHAVE_POSIX_DECLS=0 if your system's include files do not declare
 #      functions like 'link' or variables like 'tzname' required by POSIX
 #  -DHAVE_SETENV=0 if your system lacks the setenv function
diff --git a/NEWS b/NEWS
index 5c4786cb..0436c615 100644
--- a/NEWS
+++ b/NEWS
@@ -51,6 +51,9 @@ Unreleased, experimental changes
     -DHAVE_GETRESUID=[01], and -DHAVE_GETEUID=[01] to enable or
     disable these system calls' use.
 
+    tzcode now uses mempcpy if available, guessing its availability.
+    Compile with -DHAVE_MEMPCPY=1 or 0 to override the guess.
+
     tzcode now uses strnlen to improve asymptotic performance a bit.
     Compile with -DHAVE_STRNLEN=0 if your platform lacks it.
 
diff --git a/localtime.c b/localtime.c
index 67500312..316c7504 100644
--- a/localtime.c
+++ b/localtime.c
@@ -624,6 +624,7 @@ tzloadbody(char const *name, struct state *sp, char 
tzloadflags,
        }
 
        if (!SUPPRESS_TZDIR && name[0] != '/') {
+               char *cp;
                if (sizeof lsp->fullname - sizeof tzdirslash
                    <= strnlen(name, sizeof lsp->fullname - sizeof tzdirslash))
                  return ENAMETOOLONG;
@@ -631,8 +632,9 @@ tzloadbody(char const *name, struct state *sp, char 
tzloadflags,
                /* Create a string "TZDIR/NAME".  Using sprintf here
                   would pull in stdio (and would fail if the
                   resulting string length exceeded INT_MAX!).  */
-               memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash);
-               strcpy(lsp->fullname + sizeof tzdirslash, name);
+               cp = lsp->fullname;
+               cp = mempcpy(cp, tzdirslash, sizeof tzdirslash);
+               strcpy(cp, name);
                name = lsp->fullname;
        }
 
@@ -1471,12 +1473,11 @@ tzparse(const char *name, struct state *sp, struct 
state const *basep)
        }
        sp->charcnt = charcnt;
        cp = sp->chars;
-       memcpy(cp, stdname, stdlen);
-       cp += stdlen;
+       cp = mempcpy(cp, stdname, stdlen);
        *cp++ = '\0';
        if (dstlen != 0) {
-               memcpy(cp, dstname, dstlen);
-               *(cp + dstlen) = '\0';
+         cp = mempcpy(cp, dstname, dstlen);
+         *cp = '\0';
        }
        return true;
 }
diff --git a/private.h b/private.h
index 6ae0c2fd..867340fa 100644
--- a/private.h
+++ b/private.h
@@ -837,6 +837,23 @@ extern char *asctime_r(struct tm const *restrict, char 
*restrict);
 extern char **environ;
 #endif
 
+#ifndef HAVE_MEMPCPY
+# if (defined mempcpy \
+      || defined __FreeBSD__ || defined __NetBSD__ || defined __linux__)
+#  define HAVE_MEMPCPY 1
+# else
+#  define HAVE_MEMPCPY 0
+# endif
+#endif
+#if !HAVE_MEMPCPY
+static void *
+mempcpy(char *restrict s1, char const *restrict s2, size_t n)
+{
+  char *p = memcpy(s1, s2, n);
+  return p + n;
+}
+#endif
+
 #if 2 <= HAVE_TZNAME + (TZ_TIME_T || !HAVE_POSIX_DECLS)
 extern char *tzname[];
 #endif
diff --git a/zdump.c b/zdump.c
index 8e836e60..93fe05cb 100644
--- a/zdump.c
+++ b/zdump.c
@@ -927,6 +927,7 @@ my_snprintf(char *s, size_t size, char const *format, ...)
   int n;
   va_list args;
   char const *arg;
+  char *cp;
   size_t arglen, slen;
   char buf[1024];
   va_start(args, format);
@@ -943,8 +944,9 @@ my_snprintf(char *s, size_t size, char const *format, ...)
     arglen = n;
   }
   slen = arglen < size ? arglen : size - 1;
-  memcpy(s, arg, slen);
-  s[slen] = '\0';
+  cp = s;
+  cp = mempcpy(cp, arg, slen);
+  *cp = '\0';
   n = arglen <= INT_MAX ? arglen : -1;
   va_end(args);
   return n;
@@ -1073,8 +1075,9 @@ istrftime(char *buf, ptrdiff_t size, char const *time_fmt,
       char fbuf[100];
       bool oversized = sizeof fbuf <= f_prefix_copy_size;
       char *f_prefix_copy = oversized ? xmalloc(f_prefix_copy_size) : fbuf;
-      memcpy(f_prefix_copy, f, f_prefix_len);
-      strcpy(f_prefix_copy + f_prefix_len, "X");
+      char *cp = f_prefix_copy;
+      cp = mempcpy(cp, f, f_prefix_len);
+      strcpy(cp, "X");
       formatted_len = strftime(b, s, f_prefix_copy, tm);
       if (oversized)
        free(f_prefix_copy);
diff --git a/zic.c b/zic.c
index 6bdb039d..e78dfd47 100644
--- a/zic.c
+++ b/zic.c
@@ -1327,10 +1327,10 @@ random_dirent(char const **name, char **namealloc)
   uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6);
 
   if (!dst) {
-    dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1));
-    memcpy(dst, src, dirlen);
-    memcpy(dst + dirlen, prefix, prefixlen);
-    dst[dirlen + prefixlen + suffixlen] = '\0';
+    char *cp = dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1));
+    cp = mempcpy(cp, src, dirlen);
+    cp = mempcpy(cp, prefix, prefixlen);
+    cp[suffixlen] = '\0';
     *name = *namealloc = dst;
   }
 
@@ -1430,15 +1430,17 @@ relname(char const *target, char const *linkname)
   if (*linkname == '/') {
     /* Make F absolute too.  */
     size_t len = strlen(directory);
-    size_t lenslash = len + (len && directory[len - 1] != '/');
+    bool needs_slash = len && directory[len - 1] != '/';
+    size_t lenslash = len + needs_slash;
     size_t targetsize = strlen(target) + 1;
+    char *cp;
     if (*directory != '/')
       return NULL;
     linksize = size_sum(lenslash, targetsize);
-    f = result = xmalloc(linksize);
-    memcpy(result, directory, len);
-    result[len] = '/';
-    memcpy(result + lenslash, target, targetsize);
+    f = cp = result = xmalloc(linksize);
+    cp = mempcpy(cp, directory, len);
+    *cp = '/';
+    memcpy(cp + needs_slash, target, targetsize);
   }
   for (i = 0; f[i] && f[i] == linkname[i]; i++)
     if (f[i] == '/')
@@ -1448,11 +1450,13 @@ relname(char const *target, char const *linkname)
   taillen = strlen(f + dir_len);
   dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1);
   if (dotdotetcsize <= linksize) {
+    char *cp;
     if (!result)
       result = xmalloc(dotdotetcsize);
+    cp = result;
     for (i = 0; i < dotdots; i++)
-      memcpy(result + 3 * i, "../", 3);
-    memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
+      cp = mempcpy(cp, "../", 3);
+    memmove(cp, f + dir_len, taillen + 1);
   }
   return result;
 }
@@ -2875,11 +2879,11 @@ doabbr(char *abbr, struct zone const *zp, char const 
*letters,
          else if (letters == disable_percent_s)
            return 0;
          sprintf(abbr, format, letters);
-       } else if (isdst) {
-               strcpy(abbr, slashp + 1);
-       } else {
-               memcpy(abbr, format, slashp - format);
-               abbr[slashp - format] = '\0';
+       } else if (isdst)
+         strcpy(abbr, slashp + 1);
+       else {
+         char *abbrend = mempcpy(abbr, format, slashp - format);
+         *abbrend = '\0';
        }
        len = strlen(abbr);
        if (!doquotes)
-- 
2.48.1

Reply via email to