From 5b2d5709f381c3207391dff14de33add3a25d8a6 Mon Sep 17 00:00:00 2001
From: Marian Klymov <nekto1989@gmail.com>
Date: Sat, 21 Dec 2019 12:06:38 +0200
Subject: [PATCH] String: Add wrapper around strdup.

strdup isn't part of the ISO C standard and may be not available without compiler extensions
---
 CMakeLists.txt      | 10 +++++++++-
 EncodingCXX.cxx     | 10 +++++++---
 ProcessUNIX.c       | 10 ++++++----
 ProcessWin32.c      |  6 ++++--
 String.c            | 20 +++++++++++++++++++-
 String.h.in         |  9 +++++++++
 SystemTools.cxx     |  7 ++++---
 testProcess.c       |  4 +++-
 testSystemTools.cxx |  4 +++-
 9 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 09bcdb9..61a7d9f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -158,6 +158,7 @@ IF(KWSYS_USE_SystemTools)
   SET(KWSYS_USE_Directory 1)
   SET(KWSYS_USE_FStream 1)
   SET(KWSYS_USE_Encoding 1)
+  SET(KWSYS_USE_String 1)
 ENDIF()
 IF(KWSYS_USE_Glob)
   SET(KWSYS_USE_Directory 1)
@@ -167,6 +168,7 @@ IF(KWSYS_USE_Glob)
   SET(KWSYS_USE_Encoding 1)
 ENDIF()
 IF(KWSYS_USE_Process)
+  SET(KWSYS_USE_String 1)
   SET(KWSYS_USE_System 1)
   SET(KWSYS_USE_Encoding 1)
 ENDIF()
@@ -188,6 +190,9 @@ ENDIF()
 IF(KWSYS_USE_ConsoleBuf)
   SET(KWSYS_USE_Encoding 1)
 ENDIF()
+IF(KWSYS_USE_Encoding)
+  SET(KWSYS_USE_String 1)
+ENDIF()
 
 # Specify default 8 bit encoding for Windows
 IF(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE)
@@ -210,6 +215,7 @@ ENDIF()
 
 # Include helper macros.
 INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformTests.cmake)
+INCLUDE(CheckSymbolExists)
 INCLUDE(CheckTypeSize)
 
 # Do full dependency headers.
@@ -1028,9 +1034,11 @@ IF(WIN32)
 ENDIF()
 
 IF(KWSYS_USE_String)
+  CHECK_SYMBOL_EXISTS(strdup "string.h" KWSYS_C_HAS_STRDUP)
+  CHECK_SYMBOL_EXISTS(_strdup "string.h" KWSYS_C_HAS__STRDUP)
   # Activate code in "String.c".  See the comment in the source.
   SET_SOURCE_FILES_PROPERTIES(String.c PROPERTIES
-    COMPILE_FLAGS "-DKWSYS_STRING_C")
+    COMPILE_FLAGS "-DKWSYS_STRING_C -DKWSYS_C_HAS_STRDUP=${KWSYS_C_HAS_STRDUP} -DKWSYS_C_HAS__STRDUP=${KWSYS_C_HAS__STRDUP}")
 ENDIF()
 
 IF(KWSYS_USE_Encoding)
diff --git a/EncodingCXX.cxx b/EncodingCXX.cxx
index 5cad934..0229a75 100644
--- a/EncodingCXX.cxx
+++ b/EncodingCXX.cxx
@@ -9,12 +9,14 @@
 #include "kwsysPrivate.h"
 #include KWSYS_HEADER(Encoding.hxx)
 #include KWSYS_HEADER(Encoding.h)
+#include KWSYS_HEADER(String.h)
 
 // Work-around CMake dependency scanning limitation.  This must
 // duplicate the above list of headers.
 #if 0
 #  include "Encoding.h.in"
 #  include "Encoding.hxx.in"
+#  include "String.h.in"
 #endif
 
 #include <stdlib.h>
@@ -63,7 +65,7 @@ Encoding::CommandLineArguments::CommandLineArguments(int ac,
 {
   this->argv_.resize(ac + 1);
   for (int i = 0; i < ac; i++) {
-    this->argv_[i] = strdup(av[i]);
+    this->argv_[i] = kwsysString_strdup(av[i]);
   }
   this->argv_[ac] = nullptr;
 }
@@ -90,7 +92,8 @@ Encoding::CommandLineArguments::CommandLineArguments(
 {
   this->argv_.resize(other.argv_.size());
   for (size_t i = 0; i < this->argv_.size(); i++) {
-    this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : nullptr;
+    this->argv_[i] =
+      other.argv_[i] ? kwsysString_strdup(other.argv_[i]) : KWSYS_NULLPTR;
   }
 }
 
@@ -105,7 +108,8 @@ Encoding::CommandLineArguments& Encoding::CommandLineArguments::operator=(
 
     this->argv_.resize(other.argv_.size());
     for (i = 0; i < this->argv_.size(); i++) {
-      this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : nullptr;
+      this->argv_[i] =
+        other.argv_[i] ? kwsysString_strdup(other.argv_[i]) : KWSYS_NULLPTR;
     }
   }
 
diff --git a/ProcessUNIX.c b/ProcessUNIX.c
index f65690b..ebe5561 100644
--- a/ProcessUNIX.c
+++ b/ProcessUNIX.c
@@ -2,12 +2,14 @@
    file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
 #include "kwsysPrivate.h"
 #include KWSYS_HEADER(Process.h)
+#include KWSYS_HEADER(String.h)
 #include KWSYS_HEADER(System.h)
 
 /* Work-around CMake dependency scanning limitation.  This must
    duplicate the above list of headers.  */
 #if 0
 #  include "Process.h.in"
+#  include "String.h.in"
 #  include "System.h.in"
 #endif
 
@@ -52,7 +54,7 @@ do.
 #include <stddef.h>    /* ptrdiff_t */
 #include <stdio.h>     /* snprintf */
 #include <stdlib.h>    /* malloc, free */
-#include <string.h>    /* strdup, strerror, memset */
+#include <string.h>    /* strerror, memset */
 #include <sys/stat.h>  /* open mode */
 #include <sys/time.h>  /* struct timeval */
 #include <sys/types.h> /* pid_t, fd_set */
@@ -443,7 +445,7 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
     }
     for (i = 0; i < n; ++i) {
       assert(command[i]); /* Quiet Clang scan-build. */
-      newCommands[cp->NumberOfCommands][i] = strdup(command[i]);
+      newCommands[cp->NumberOfCommands][i] = kwsysString_strdup(command[i]);
       if (!newCommands[cp->NumberOfCommands][i]) {
         break;
       }
@@ -496,7 +498,7 @@ int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
     cp->WorkingDirectory = 0;
   }
   if (dir) {
-    cp->WorkingDirectory = strdup(dir);
+    cp->WorkingDirectory = kwsysString_strdup(dir);
     if (!cp->WorkingDirectory) {
       return 0;
     }
@@ -528,7 +530,7 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int prPipe, const char* file)
     *pfile = 0;
   }
   if (file) {
-    *pfile = strdup(file);
+    *pfile = kwsysString_strdup(file);
     if (!*pfile) {
       return 0;
     }
diff --git a/ProcessWin32.c b/ProcessWin32.c
index 68c5218..20cc3e2 100644
--- a/ProcessWin32.c
+++ b/ProcessWin32.c
@@ -3,12 +3,14 @@
 #include "kwsysPrivate.h"
 #include KWSYS_HEADER(Process.h)
 #include KWSYS_HEADER(Encoding.h)
+#include KWSYS_HEADER(String.h)
 
 /* Work-around CMake dependency scanning limitation.  This must
    duplicate the above list of headers.  */
 #if 0
 #  include "Encoding.h.in"
 #  include "Process.h.in"
+#  include "String.h.in"
 #endif
 
 /*
@@ -30,7 +32,7 @@ a UNIX-style select system call.
 #endif
 #include <io.h>     /* _unlink */
 #include <stdio.h>  /* sprintf */
-#include <string.h> /* strlen, strdup */
+#include <string.h> /* strlen */
 #ifdef __WATCOMC__
 #  define _unlink unlink
 #endif
@@ -717,7 +719,7 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
     *pfile = 0;
   }
   if (file) {
-    *pfile = strdup(file);
+    *pfile = kwsysString_strdup(file);
     if (!*pfile) {
       return 0;
     }
diff --git a/String.c b/String.c
index daf7ad1..9165390 100644
--- a/String.c
+++ b/String.c
@@ -17,10 +17,11 @@ condition blocks the compiler from seeing the symbols defined here.
 #    include "String.h.in"
 #  endif
 
+#  include <string.h> /* memcpy, _strdup, strdup, strlen */
+
 /* Select an implementation for strcasecmp.  */
 #  if defined(_MSC_VER)
 #    define KWSYS_STRING_USE_STRICMP
-#    include <string.h>
 #  elif defined(__GNUC__)
 #    define KWSYS_STRING_USE_STRCASECMP
 #    include <strings.h>
@@ -97,4 +98,21 @@ int kwsysString_strncasecmp(const char* lhs, const char* rhs, size_t n)
 #  endif
 }
 
+/*--------------------------------------------------------------------------*/
+char* kwsysString_strdup(const char* str1)
+{
+#  if defined(KWSYS_C_HAS__STRDUP)
+  return _strdup(str1);
+#  elif defined(KWSYS_C_HAS_STRDUP)
+  return strdup(str1);
+#  else
+  size_t size = strlen(s) + 1;
+  char* p = malloc(size);
+  if (p) {
+    memcpy(p, s, size);
+  }
+  return p;
+#  endif
+}
+
 #endif /* KWSYS_STRING_C */
diff --git a/String.h.in b/String.h.in
index 7c9348a..dd6ab30 100644
--- a/String.h.in
+++ b/String.h.in
@@ -18,6 +18,7 @@
 #if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
 #  define kwsysString_strcasecmp kwsys_ns(String_strcasecmp)
 #  define kwsysString_strncasecmp kwsys_ns(String_strncasecmp)
+#  define kwsysString_strdup kwsys_ns(String_strdup)
 #endif
 
 #if defined(__cplusplus)
@@ -39,6 +40,13 @@ kwsysEXPORT int kwsysString_strcasecmp(const char* lhs, const char* rhs);
 kwsysEXPORT int kwsysString_strncasecmp(const char* lhs, const char* rhs,
                                         size_t n);
 
+/**
+ * Returns a pointer to a null-terminated byte string, which is a duplicate
+ * of the string pointed to by str1. The returned pointer must be passed to
+ * free to avoid a memory leak.
+ */
+kwsysEXPORT char* kwsysString_strdup(const char* str1);
+
 #if defined(__cplusplus)
 } /* extern "C" */
 #endif
@@ -51,6 +59,7 @@ kwsysEXPORT int kwsysString_strncasecmp(const char* lhs, const char* rhs,
 #  if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
 #    undef kwsysString_strcasecmp
 #    undef kwsysString_strncasecmp
+#    undef kwsysString_strdup
 #  endif
 #endif
 
diff --git a/SystemTools.cxx b/SystemTools.cxx
index 39873e6..1bdc055 100644
--- a/SystemTools.cxx
+++ b/SystemTools.cxx
@@ -23,6 +23,7 @@
 #include KWSYS_HEADER(FStream.hxx)
 #include KWSYS_HEADER(Encoding.h)
 #include KWSYS_HEADER(Encoding.hxx)
+#include KWSYS_HEADER(String.h)
 
 #include <fstream>
 #include <iostream>
@@ -38,6 +39,7 @@
 #  include "Encoding.hxx.in"
 #  include "FStream.hxx.in"
 #  include "RegularExpression.hxx.in"
+#  include "String.h.in"
 #  include "SystemTools.hxx.in"
 #endif
 
@@ -343,7 +345,6 @@ extern FILE* popen(__const char* __command, __const char* __modes) __THROW;
 extern int pclose(FILE* __stream) __THROW;
 extern char* realpath(__const char* __restrict __name,
                       char* __restrict __resolved) __THROW;
-extern char* strdup(__const char* __s) __THROW;
 extern int putenv(char* __string) __THROW;
 }
 #endif
@@ -836,7 +837,7 @@ public:
     const std::wstring wEnv = Encoding::ToWide(env);
     wchar_t* newEnv = _wcsdup(wEnv.c_str());
 #  else
-    char* newEnv = strdup(env);
+    char* newEnv = kwsysString_strdup(env);
 #  endif
     Free oldEnv(this->Release(newEnv));
     this->insert(newEnv);
@@ -981,7 +982,7 @@ void SystemToolsStatic::ReplaceString(std::string& source, const char* replace,
   }
 
   // perform replacements until done
-  char* orig = strdup(src);
+  char* orig = kwsysString_strdup(src);
   char* currentPos = orig;
   searchPos = searchPos - src + orig;
 
diff --git a/testProcess.c b/testProcess.c
index 39aaa23..ce1c744 100644
--- a/testProcess.c
+++ b/testProcess.c
@@ -3,12 +3,14 @@
 #include "kwsysPrivate.h"
 #include KWSYS_HEADER(Process.h)
 #include KWSYS_HEADER(Encoding.h)
+#include KWSYS_HEADER(String.h)
 
 /* Work-around CMake dependency scanning limitation.  This must
    duplicate the above list of headers.  */
 #if 0
 #  include "Encoding.h.in"
 #  include "Process.h.in"
+#  include "String.h.in"
 #endif
 
 #include <assert.h>
@@ -675,7 +677,7 @@ int main(int argc, const char* argv[])
       }
     }
 #ifdef _WIN32
-    if (n == 0 && (argv0 = strdup(argv[0]))) {
+    if (n == 0 && (argv0 = kwsysString_strdup(argv[0]))) {
       /* Try converting to forward slashes to see if it works.  */
       char* c;
       for (c = argv0; *c; ++c) {
diff --git a/testSystemTools.cxx b/testSystemTools.cxx
index 1f3a15b..b8b3665 100644
--- a/testSystemTools.cxx
+++ b/testSystemTools.cxx
@@ -7,12 +7,14 @@
 #endif
 
 #include KWSYS_HEADER(FStream.hxx)
+#include KWSYS_HEADER(String.h)
 #include KWSYS_HEADER(SystemTools.hxx)
 
 // Work-around CMake dependency scanning limitation.  This must
 // duplicate the above list of headers.
 #if 0
 #  include "FStream.hxx.in"
+#  include "String.h.in"
 #  include "SystemTools.hxx.in"
 #endif
 
@@ -537,7 +539,7 @@ static bool CheckStringOperations()
   }
   delete[] cres;
 
-  char* cres2 = strdup("Mary Had A Little Lamb.");
+  char* cres2 = kwsysString_strdup("Mary Had A Little Lamb.");
   kwsys::SystemTools::ReplaceChars(cres2, "aeiou", 'X');
   if (strcmp(cres2, "MXry HXd A LXttlX LXmb.")) {
     std::cerr << "Problem with ReplaceChars "
-- 
GitLab