Merge topic 'clangcl-fixes'

091afa7342 Tests: Teach tests when to treat clang-cl as MSVC
006768903c Work around clang-cl breakage on make_unique/std::forward
d625dfcdf9 Avoid compiling CMake itself as C++17 with Clang's MSVC ABI

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !2573
diff --git a/Help/command/if.rst b/Help/command/if.rst
index a682c83..a48a0fa 100644
--- a/Help/command/if.rst
+++ b/Help/command/if.rst
@@ -23,7 +23,7 @@
 Finally, if no ``condition`` is true, ``commands`` in the optional ``else``
 block are executed.
 
-Per legacy, the :command:`else` and :command:`elseif` commands admit
+Per legacy, the :command:`else` and :command:`endif` commands admit
 an optional ``<condition>`` argument.
 If used, it must be a verbatim
 repeat of the argument of the opening
diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake
index 8544653..3547642 100644
--- a/Modules/FindMatlab.cmake
+++ b/Modules/FindMatlab.cmake
@@ -725,7 +725,7 @@
   file(REMOVE "${_matlab_temporary_folder}/matlabVersionLog.cmaketmp")
 
   set(index -1)
-  string(FIND ${_matlab_version_from_cmd} "ans" index)
+  string(FIND "${_matlab_version_from_cmd}" "ans" index)
   if(index EQUAL -1)
 
     if(MATLAB_FIND_DEBUG)
@@ -735,7 +735,7 @@
   else()
     set(matlab_list_of_all_versions_tmp)
 
-    string(SUBSTRING ${_matlab_version_from_cmd} ${index} -1 substring_ans)
+    string(SUBSTRING "${_matlab_version_from_cmd}" ${index} -1 substring_ans)
     string(
       REGEX MATCHALL "ans[\r\n\t ]*=[\r\n\t ]*'?([0-9]+(\\.[0-9]+)?)"
       matlab_versions_regex
diff --git a/Modules/FindOctave.cmake b/Modules/FindOctave.cmake
index 8ae6a47..8110ff1 100644
--- a/Modules/FindOctave.cmake
+++ b/Modules/FindOctave.cmake
@@ -15,7 +15,10 @@
 ``Octave::Interpreter``
   Octave interpreter (the main program)
 ``Octave::Octave``
-  include directories and libraries
+  include directories and the octave library
+``Octave::Octinterp``
+  include directories and the octinterp library including the dependency on
+  Octave::Octave
 
 If no ``COMPONENTS`` are specified, ``Interpreter`` is assumed.
 
@@ -144,6 +147,15 @@
                          )
   endif()
 
+  if(NOT TARGET Octave::Octinterp)
+    add_library(Octave::Octinterp UNKNOWN IMPORTED)
+    set_target_properties(Octave::Octinterp PROPERTIES
+                          IMPORTED_LOCATION ${Octave_INTERP_LIBRARY}
+                          INTERFACE_INCLUDE_DIRECTORIES ${Octave_INCLUDE_DIR})
+    target_link_libraries(Octave::Octinterp INTERFACE
+                          Octave::Octave)
+  endif()
+
 endif()
 
 
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 6c6b3a0..a4eb53f 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 14)
-set(CMake_VERSION_PATCH 20190211)
+set(CMake_VERSION_PATCH 20190212)
 #set(CMake_VERSION_RC 1)
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index b4c05ab..2917763 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -43,7 +43,8 @@
   this->MakefileMap = nullptr;
 }
 
-void cmCPackGenerator::DisplayVerboseOutput(const char* msg, float progress)
+void cmCPackGenerator::DisplayVerboseOutput(const std::string& msg,
+                                            float progress)
 {
   (void)progress;
   cmCPackLogger(cmCPackLog::LOG_VERBOSE, "" << msg << std::endl);
@@ -689,7 +690,7 @@
   cm.SetHomeOutputDirectory("");
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
   cm.AddCMakePaths();
-  cm.SetProgressCallback([this](const char* msg, float prog) {
+  cm.SetProgressCallback([this](const std::string& msg, float prog) {
     this->DisplayVerboseOutput(msg, prog);
   });
   cm.SetTrace(this->Trace);
diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h
index 4755f94..9e4bf43 100644
--- a/Source/CPack/cmCPackGenerator.h
+++ b/Source/CPack/cmCPackGenerator.h
@@ -96,7 +96,7 @@
   void SetLogger(cmCPackLog* log) { this->Logger = log; }
 
   //! Display verbose information via logger
-  void DisplayVerboseOutput(const char* msg, float progress);
+  void DisplayVerboseOutput(const std::string& msg, float progress);
 
   bool ReadListFile(const char* moduleName);
 
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index 0413422..da9575b 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -90,7 +90,7 @@
   return 1;
 }
 
-static void cpackProgressCallback(const char* message, float /*unused*/)
+static void cpackProgressCallback(const std::string& message, float /*unused*/)
 {
   std::cout << "-- " << message << std::endl;
 }
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index 3856569..696b52f 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -126,10 +126,11 @@
     cmSystemTools::SetStdoutCallback([&s](std::string const& m) { s += m; });
     cmSystemTools::SetStderrCallback([&s](std::string const& m) { s += m; });
 
-    this->CM.SetProgressCallback([&s](const char* msg, float /*unused*/) {
-      s += msg;
-      s += "\n";
-    });
+    this->CM.SetProgressCallback(
+      [&s](const std::string& msg, float /*unused*/) {
+        s += msg;
+        s += "\n";
+      });
   }
 
   ~cmCTestBuildAndTestCaptureRAII()
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 5183c6f..41d02c5 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -9,8 +9,6 @@
 #include "cmSystemTools.h"
 #include "cmWorkingDirectory.h"
 
-#include "cm_zlib.h"
-#include "cmsys/Base64.h"
 #include "cmsys/RegularExpression.hxx"
 #include <chrono>
 #include <cmAlgorithms.h>
@@ -32,9 +30,6 @@
   this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
   this->TestResult.TestCount = 0;
   this->TestResult.Properties = nullptr;
-  this->ProcessOutput.clear();
-  this->CompressedOutput.clear();
-  this->CompressionRatio = 2;
   this->NumberOfRunsLeft = 1; // default to 1 run of the test
   this->RunUntilFail = false; // default to run the test once
   this->RunAgain = false;     // default to not having to run again
@@ -69,73 +64,8 @@
   }
 }
 
-// Streamed compression of test output.  The compressed data
-// is appended to this->CompressedOutput
-void cmCTestRunTest::CompressOutput()
-{
-  int ret;
-  z_stream strm;
-
-  unsigned char* in = reinterpret_cast<unsigned char*>(
-    const_cast<char*>(this->ProcessOutput.c_str()));
-  // zlib makes the guarantee that this is the maximum output size
-  int outSize = static_cast<int>(
-    static_cast<double>(this->ProcessOutput.size()) * 1.001 + 13.0);
-  unsigned char* out = new unsigned char[outSize];
-
-  strm.zalloc = Z_NULL;
-  strm.zfree = Z_NULL;
-  strm.opaque = Z_NULL;
-  ret = deflateInit(&strm, -1); // default compression level
-  if (ret != Z_OK) {
-    delete[] out;
-    return;
-  }
-
-  strm.avail_in = static_cast<uInt>(this->ProcessOutput.size());
-  strm.next_in = in;
-  strm.avail_out = outSize;
-  strm.next_out = out;
-  ret = deflate(&strm, Z_FINISH);
-
-  if (ret != Z_STREAM_END) {
-    cmCTestLog(this->CTest, ERROR_MESSAGE,
-               "Error during output compression. Sending uncompressed output."
-                 << std::endl);
-    delete[] out;
-    return;
-  }
-
-  (void)deflateEnd(&strm);
-
-  unsigned char* encoded_buffer =
-    new unsigned char[static_cast<int>(outSize * 1.5)];
-
-  size_t rlen = cmsysBase64_Encode(out, strm.total_out, encoded_buffer, 1);
-
-  this->CompressedOutput.clear();
-  for (size_t i = 0; i < rlen; i++) {
-    this->CompressedOutput += encoded_buffer[i];
-  }
-
-  if (strm.total_in) {
-    this->CompressionRatio =
-      static_cast<double>(strm.total_out) / static_cast<double>(strm.total_in);
-  }
-
-  delete[] encoded_buffer;
-  delete[] out;
-}
-
 bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
 {
-  if ((!this->TestHandler->MemCheck &&
-       this->CTest->ShouldCompressTestOutput()) ||
-      (this->TestHandler->MemCheck &&
-       this->CTest->ShouldCompressTestOutput())) {
-    this->CompressOutput();
-  }
-
   this->WriteLogOutputTop(completed, total);
   std::string reason;
   bool passed = true;
@@ -336,10 +266,18 @@
   // if the test actually started and ran
   // record the results in TestResult
   if (started) {
-    bool compress = !this->TestHandler->MemCheck &&
-      this->CompressionRatio < 1 && this->CTest->ShouldCompressTestOutput();
+    std::string compressedOutput;
+    if (!this->TestHandler->MemCheck &&
+        this->CTest->ShouldCompressTestOutput()) {
+      std::string str = this->ProcessOutput;
+      if (this->CTest->CompressString(str)) {
+        compressedOutput = std::move(str);
+      }
+    }
+    bool compress = !compressedOutput.empty() &&
+      compressedOutput.length() < this->ProcessOutput.length();
     this->TestResult.Output =
-      compress ? this->CompressedOutput : this->ProcessOutput;
+      compress ? compressedOutput : this->ProcessOutput;
     this->TestResult.CompressOutput = compress;
     this->TestResult.ReturnValue = this->TestProcess->GetExitValue();
     if (!skipped) {
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 918d5fa..38cc417 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -58,9 +58,6 @@
   // Read and store output.  Returns true if it must be called again.
   void CheckOutput(std::string const& line);
 
-  // Compresses the output, writing to CompressedOutput
-  void CompressOutput();
-
   // launch the test process, return whether it started correctly
   bool StartTest(size_t completed, size_t total);
   // capture and report the test results
@@ -105,8 +102,6 @@
   cmCTest* CTest;
   std::unique_ptr<cmProcess> TestProcess;
   std::string ProcessOutput;
-  std::string CompressedOutput;
-  double CompressionRatio;
   // The test results
   cmCTestTestHandler::cmCTestTestResult TestResult;
   cmCTestMultiProcessHandler& MultiTestHandler;
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 2cbdc4e..a714abe 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -288,11 +288,12 @@
       this->ParentMakefile->GetRecursionDepth());
   }
 
-  this->CMake->SetProgressCallback([this](const char* m, float /*unused*/) {
-    if (m && *m) {
-      cmCTestLog(this->CTest, HANDLER_OUTPUT, "-- " << m << std::endl);
-    }
-  });
+  this->CMake->SetProgressCallback(
+    [this](const std::string& m, float /*unused*/) {
+      if (!m.empty()) {
+        cmCTestLog(this->CTest, HANDLER_OUTPUT, "-- " << m << std::endl);
+      }
+    });
 
   this->AddCTestCommand("ctest_build", new cmCTestBuildCommand);
   this->AddCTestCommand("ctest_configure", new cmCTestConfigureCommand);
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx
index 076ee3d..3fe1834 100644
--- a/Source/CursesDialog/cmCursesMainForm.cxx
+++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -79,18 +79,11 @@
 // See if a cache entry is in the list of entries in the ui.
 bool cmCursesMainForm::LookForCacheEntry(const std::string& key)
 {
-  if (!this->Entries) {
-    return false;
-  }
-
-  std::vector<cmCursesCacheEntryComposite*>::iterator it;
-  for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
-    if (key == (*it)->Key) {
-      return true;
-    }
-  }
-
-  return false;
+  return this->Entries &&
+    std::any_of(this->Entries->begin(), this->Entries->end(),
+                [&key](cmCursesCacheEntryComposite* entry) {
+                  return key == entry->Key;
+                });
 }
 
 // Create new cmCursesCacheEntryComposite entries from the cache
@@ -185,13 +178,12 @@
   } else {
     // If normal mode, count only non-advanced entries
     this->NumberOfVisibleEntries = 0;
-    std::vector<cmCursesCacheEntryComposite*>::iterator it;
-    for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+    for (cmCursesCacheEntryComposite* entry : *this->Entries) {
       const char* existingValue =
-        this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+        this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
       bool advanced =
         this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
-          (*it)->GetValue(), "ADVANCED");
+          entry->GetValue(), "ADVANCED");
       if (!existingValue || (!this->AdvancedMode && advanced)) {
         continue;
       }
@@ -212,27 +204,26 @@
 
   // Assign fields
   int j = 0;
-  std::vector<cmCursesCacheEntryComposite*>::iterator it;
-  for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+  for (cmCursesCacheEntryComposite* entry : *this->Entries) {
     const char* existingValue =
-      this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+      this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
     bool advanced =
       this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
-        (*it)->GetValue(), "ADVANCED");
+        entry->GetValue(), "ADVANCED");
     if (!existingValue || (!this->AdvancedMode && advanced)) {
       continue;
     }
-    this->Fields[3 * j] = (*it)->Label->Field;
-    this->Fields[3 * j + 1] = (*it)->IsNewLabel->Field;
-    this->Fields[3 * j + 2] = (*it)->Entry->Field;
+    this->Fields[3 * j] = entry->Label->Field;
+    this->Fields[3 * j + 1] = entry->IsNewLabel->Field;
+    this->Fields[3 * j + 2] = entry->Entry->Field;
     j++;
   }
   // if no cache entries there should still be one dummy field
   if (j == 0) {
-    it = this->Entries->begin();
-    this->Fields[0] = (*it)->Label->Field;
-    this->Fields[1] = (*it)->IsNewLabel->Field;
-    this->Fields[2] = (*it)->Entry->Field;
+    const auto& front = *this->Entries->front();
+    this->Fields[0] = front.Label->Field;
+    this->Fields[1] = front.IsNewLabel->Field;
+    this->Fields[2] = front.Entry->Field;
     this->NumberOfVisibleEntries = 1;
   }
   // Has to be null terminated.
@@ -273,13 +264,12 @@
   } else {
     // If normal, display only non-advanced entries
     this->NumberOfVisibleEntries = 0;
-    std::vector<cmCursesCacheEntryComposite*>::iterator it;
-    for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+    for (cmCursesCacheEntryComposite* entry : *this->Entries) {
       const char* existingValue =
-        this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+        this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
       bool advanced =
         this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
-          (*it)->GetValue(), "ADVANCED");
+          entry->GetValue(), "ADVANCED");
       if (!existingValue || (!this->AdvancedMode && advanced)) {
         continue;
       }
@@ -292,13 +282,12 @@
   if (height > 0) {
     bool isNewPage;
     int i = 0;
-    std::vector<cmCursesCacheEntryComposite*>::iterator it;
-    for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+    for (cmCursesCacheEntryComposite* entry : *this->Entries) {
       const char* existingValue =
-        this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+        this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
       bool advanced =
         this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
-          (*it)->GetValue(), "ADVANCED");
+          entry->GetValue(), "ADVANCED");
       if (!existingValue || (!this->AdvancedMode && advanced)) {
         continue;
       }
@@ -309,10 +298,10 @@
       if (isNewPage) {
         this->NumberOfPages++;
       }
-      (*it)->Label->Move(left, top + row - 1, isNewPage);
-      (*it)->IsNewLabel->Move(left + 32, top + row - 1, false);
-      (*it)->Entry->Move(left + 33, top + row - 1, false);
-      (*it)->Entry->SetPage(this->NumberOfPages);
+      entry->Label->Move(left, top + row - 1, isNewPage);
+      entry->IsNewLabel->Move(left + 32, top + row - 1, false);
+      entry->Entry->Move(left + 33, top + row - 1, false);
+      entry->Entry->SetPage(this->NumberOfPages);
       i++;
     }
   }
@@ -501,14 +490,14 @@
   pos_form_cursor(this->Form);
 }
 
-void cmCursesMainForm::UpdateProgress(const char* msg, float prog)
+void cmCursesMainForm::UpdateProgress(const std::string& msg, float prog)
 {
   char tmp[1024];
   const char* cmsg = tmp;
   if (prog >= 0) {
-    sprintf(tmp, "%s %i%%", msg, static_cast<int>(100 * prog));
+    sprintf(tmp, "%s %i%%", msg.c_str(), static_cast<int>(100 * prog));
   } else {
-    cmsg = msg;
+    cmsg = msg.c_str();
   }
   this->UpdateStatusBar(cmsg);
   this->PrintKeys(1);
@@ -528,7 +517,9 @@
   touchwin(stdscr);
   refresh();
   this->CMakeInstance->SetProgressCallback(
-    [this](const char* msg, float prog) { this->UpdateProgress(msg, prog); });
+    [this](const std::string& msg, float prog) {
+      this->UpdateProgress(msg, prog);
+    });
 
   // always save the current gui values to disk
   this->FillCacheManagerFromUI();
@@ -598,7 +589,9 @@
   touchwin(stdscr);
   refresh();
   this->CMakeInstance->SetProgressCallback(
-    [this](const char* msg, float prog) { this->UpdateProgress(msg, prog); });
+    [this](const std::string& msg, float prog) {
+      this->UpdateProgress(msg, prog);
+    });
 
   // Get rid of previous errors
   this->Errors = std::vector<std::string>();
@@ -654,28 +647,28 @@
     return;
   }
 
-  std::vector<cmCursesCacheEntryComposite*>::iterator it;
-  for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
-    const char* val = (*it)->GetValue();
-    if (val && !strcmp(value, val)) {
-      this->CMakeInstance->UnwatchUnusedCli(value);
-      this->Entries->erase(it);
-      break;
-    }
+  auto removeIt = std::find_if(this->Entries->begin(), this->Entries->end(),
+                               [value](cmCursesCacheEntryComposite* entry) {
+                                 const char* val = entry->GetValue();
+                                 return val && !strcmp(value, val);
+                               });
+
+  if (removeIt != this->Entries->end()) {
+    this->CMakeInstance->UnwatchUnusedCli(value);
+    this->Entries->erase(removeIt);
   }
 }
 
 // copy from the list box to the cache manager
 void cmCursesMainForm::FillCacheManagerFromUI()
 {
-  size_t size = this->Entries->size();
-  for (size_t i = 0; i < size; i++) {
-    std::string cacheKey = (*this->Entries)[i]->Key;
+  for (cmCursesCacheEntryComposite* entry : *this->Entries) {
+    const std::string& cacheKey = entry->Key;
     const char* existingValue =
       this->CMakeInstance->GetState()->GetCacheEntryValue(cacheKey);
     if (existingValue) {
       std::string oldValue = existingValue;
-      std::string newValue = (*this->Entries)[i]->Entry->GetValue();
+      std::string newValue = entry->GetValue();
       std::string fixedOldValue;
       std::string fixedNewValue;
       cmStateEnums::CacheEntryType t =
@@ -971,17 +964,14 @@
 
           if (nextCur) {
             // make the next or prev. current field after deletion
-            nextCur = nullptr;
-            std::vector<cmCursesCacheEntryComposite*>::iterator it;
-            for (it = this->Entries->begin(); it != this->Entries->end();
-                 ++it) {
-              if (nextVal == (*it)->Key) {
-                nextCur = (*it)->Entry->Field;
-              }
-            }
+            auto nextEntryIt =
+              std::find_if(this->Entries->begin(), this->Entries->end(),
+                           [&nextVal](cmCursesCacheEntryComposite* entry) {
+                             return nextVal == entry->Key;
+                           });
 
-            if (nextCur) {
-              set_current_field(this->Form, nextCur);
+            if (nextEntryIt != this->Entries->end()) {
+              set_current_field(this->Form, (*nextEntryIt)->Entry->Field);
             }
           }
         }
diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h
index c09ce2a..d379975 100644
--- a/Source/CursesDialog/cmCursesMainForm.h
+++ b/Source/CursesDialog/cmCursesMainForm.h
@@ -102,7 +102,7 @@
   /**
    * Progress callback
    */
-  void UpdateProgress(const char* msg, float prog);
+  void UpdateProgress(const std::string& msg, float prog);
 
 protected:
   // Copy the cache values from the user interface to the actual
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index c90c142..f357f90 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -37,7 +37,7 @@
   this->CMakeInstance->SetCMakeEditCommand(
     cmSystemTools::GetCMakeGUICommand());
   this->CMakeInstance->SetProgressCallback(
-    [this](const char* msg, float percent) {
+    [this](const std::string& msg, float percent) {
       this->progressCallback(msg, percent);
     });
 
@@ -346,12 +346,12 @@
 #endif
 }
 
-void QCMake::progressCallback(const char* msg, float percent)
+void QCMake::progressCallback(const std::string& msg, float percent)
 {
   if (percent >= 0) {
-    emit this->progressChanged(QString::fromLocal8Bit(msg), percent);
+    emit this->progressChanged(QString::fromStdString(msg), percent);
   } else {
-    emit this->outputMessage(QString::fromLocal8Bit(msg));
+    emit this->outputMessage(QString::fromStdString(msg));
   }
   QCoreApplication::processEvents();
 }
diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h
index 8492606..f2fd6d9 100644
--- a/Source/QtDialog/QCMake.h
+++ b/Source/QtDialog/QCMake.h
@@ -168,7 +168,7 @@
   cmake* CMakeInstance;
 
   bool interruptCallback();
-  void progressCallback(const char* msg, float percent);
+  void progressCallback(std::string const& msg, float percent);
   void messageCallback(std::string const& msg, const char* title);
   void stdoutCallback(std::string const& msg);
   void stderrCallback(std::string const& msg);
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index fb3a1bc..4d9f657 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -1834,7 +1834,7 @@
     if (!this->MessageNever && (copy || !this->MessageLazy)) {
       std::string message = (copy ? "Installing: " : "Up-to-date: ");
       message += toFile;
-      this->Makefile->DisplayStatus(message.c_str(), -1);
+      this->Makefile->DisplayStatus(message, -1);
     }
     if (type != TypeDir) {
       // Add the file to the manifest.
@@ -2214,7 +2214,7 @@
       message += "\" to \"";
       message += newRPath;
       message += "\"";
-      this->Makefile->DisplayStatus(message.c_str(), -1);
+      this->Makefile->DisplayStatus(message, -1);
     }
     if (have_ft) {
       cmSystemTools::FileTimeSet(file, ft);
@@ -2278,7 +2278,7 @@
       std::string message = "Removed runtime path from \"";
       message += file;
       message += "\"";
-      this->Makefile->DisplayStatus(message.c_str(), -1);
+      this->Makefile->DisplayStatus(message, -1);
     }
     if (have_ft) {
       cmSystemTools::FileTimeSet(file, ft);
@@ -2647,7 +2647,7 @@
   if (helper->UpdatePercentage(dlnow, dltotal, status)) {
     cmFileCommand* fc = helper->GetFileCommand();
     cmMakefile* mf = fc->GetMakefile();
-    mf->DisplayStatus(status.c_str(), -1);
+    mf->DisplayStatus(status, -1);
   }
 
   return 0;
@@ -2665,7 +2665,7 @@
   if (helper->UpdatePercentage(ulnow, ultotal, status)) {
     cmFileCommand* fc = helper->GetFileCommand();
     cmMakefile* mf = fc->GetMakefile();
-    mf->DisplayStatus(status.c_str(), -1);
+    mf->DisplayStatus(status, -1);
   }
 
   return 0;
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 52ff5ea..45b096f 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -911,7 +911,7 @@
       std::ostringstream aw;
       aw << "Could NOT find " << this->Name << " (missing: " << this->Name
          << "_DIR)";
-      this->Makefile->DisplayStatus(aw.str().c_str(), -1);
+      this->Makefile->DisplayStatus(aw.str(), -1);
     }
   }
 
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 8e7ca12..11c382f 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -1225,7 +1225,7 @@
     } else {
       msg << "Configuring done";
     }
-    this->CMakeInstance->UpdateProgress(msg.str().c_str(), -1);
+    this->CMakeInstance->UpdateProgress(msg.str(), -1);
   }
 }
 
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index 7284f0b..f872de5 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -1006,7 +1006,7 @@
         winSDK_7_1)) {
     std::ostringstream m;
     m << "Found Windows SDK v7.1: " << winSDK_7_1;
-    mf->DisplayStatus(m.str().c_str(), -1);
+    mf->DisplayStatus(m.str(), -1);
     this->DefaultPlatformToolset = "Windows7.1SDK";
     return true;
   } else {
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index a0a9558..2d54c33 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -171,7 +171,7 @@
     std::ostringstream e;
     e << "Selecting Windows SDK version " << this->WindowsTargetPlatformVersion
       << " to target Windows " << this->SystemVersion << ".";
-    mf->DisplayStatus(e.str().c_str(), -1);
+    mf->DisplayStatus(e.str(), -1);
   }
   mf->AddDefinition("CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION",
                     this->WindowsTargetPlatformVersion.c_str());
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index f246da2..b0dacf1 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -3547,7 +3547,7 @@
   return this->GetCMakeInstance()->GetState();
 }
 
-void cmMakefile::DisplayStatus(const char* message, float s) const
+void cmMakefile::DisplayStatus(const std::string& message, float s) const
 {
   cmake* cm = this->GetCMakeInstance();
   if (cm->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index fce90f2..9f01986 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -639,7 +639,7 @@
 #endif
 
   ///! Display progress or status message.
-  void DisplayStatus(const char*, float) const;
+  void DisplayStatus(const std::string&, float) const;
 
   /**
    * Expand the given list file arguments into the full set after
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index 95f5fcb..1a21ae4 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -68,7 +68,7 @@
     m->DisplayMessage(type, message, this->Makefile->GetBacktrace());
   } else {
     if (status) {
-      this->Makefile->DisplayStatus(message.c_str(), -1);
+      this->Makefile->DisplayStatus(message, -1);
     } else {
       cmSystemTools::Message(message);
     }
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
index 719e6b1..1903fd9 100644
--- a/Source/cmServer.cxx
+++ b/Source/cmServer.cxx
@@ -103,7 +103,7 @@
 
   if (this->Protocol) {
     this->Protocol->CMakeInstance()->SetProgressCallback(
-      [&request](const char* msg, float prog) {
+      [&request](const std::string& msg, float prog) {
         reportProgress(msg, prog, request);
       });
     this->WriteResponse(connection, this->Protocol->Process(request),
@@ -155,7 +155,7 @@
   this->WriteJsonObject(connection, hello, nullptr);
 }
 
-void cmServer::reportProgress(const char* msg, float progress,
+void cmServer::reportProgress(const std::string& msg, float progress,
                               const cmServerRequest& request)
 {
   if (progress < 0.0f || progress > 1.0f) {
diff --git a/Source/cmServer.h b/Source/cmServer.h
index 3edc887..aba4924 100644
--- a/Source/cmServer.h
+++ b/Source/cmServer.h
@@ -119,7 +119,7 @@
   void OnConnected(cmConnection* connection) override;
 
 private:
-  static void reportProgress(const char* msg, float progress,
+  static void reportProgress(const std::string& msg, float progress,
                              const cmServerRequest& request);
   static void reportMessage(const std::string& msg, const char* title,
                             const cmServerRequest& request);
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 8023298..d507484 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -1705,7 +1705,7 @@
   ret = this->Generate();
   std::string message = "Build files have been written to: ";
   message += this->GetHomeOutputDirectory();
-  this->UpdateProgress(message.c_str(), -1);
+  this->UpdateProgress(message, -1);
   return ret;
 }
 
@@ -1925,7 +1925,7 @@
   this->ProgressCallback = std::move(f);
 }
 
-void cmake::UpdateProgress(const char* msg, float prog)
+void cmake::UpdateProgress(const std::string& msg, float prog)
 {
   if (this->ProgressCallback && !this->State->GetIsInTryCompile()) {
     this->ProgressCallback(msg, prog);
@@ -2640,7 +2640,7 @@
       }
       std::string message = "Build files have been written to: ";
       message += this->GetHomeOutputDirectory();
-      this->UpdateProgress(message.c_str(), -1);
+      this->UpdateProgress(message, -1);
 
       // Restore the previously set directories to their original value.
       this->SetHomeDirectory(homeOrig);
diff --git a/Source/cmake.h b/Source/cmake.h
index 53d44f1..6fa2d3a 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -273,7 +273,7 @@
   ///! Parse command line arguments that might set cache values
   bool SetCacheArgs(const std::vector<std::string>&);
 
-  using ProgressCallbackType = std::function<void(const char*, float)>;
+  using ProgressCallbackType = std::function<void(const std::string&, float)>;
   /**
    *  Set the function used by GUIs to receive progress updates
    *  Function gets passed: message as a const char*, a progress
@@ -284,7 +284,7 @@
   void SetProgressCallback(ProgressCallbackType f);
 
   ///! this is called by generators to update the progress
-  void UpdateProgress(const char* msg, float prog);
+  void UpdateProgress(const std::string& msg, float prog);
 
 #if defined(CMAKE_BUILD_WITH_CMAKE)
   ///! Get the variable watch object
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index a49246b..09068f8 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -148,14 +148,15 @@
   std::cerr << m << cmakemainGetStack(cm) << std::endl << std::flush;
 }
 
-static void cmakemainProgressCallback(const char* m, float prog, cmake* cm)
+static void cmakemainProgressCallback(const std::string& m, float prog,
+                                      cmake* cm)
 {
   cmMakefile* mf = cmakemainGetMakefile(cm);
   std::string dir;
-  if ((mf) && (strstr(m, "Configuring") == m) && (prog < 0)) {
+  if (mf && cmHasLiteralPrefix(m, "Configuring") && (prog < 0)) {
     dir = " ";
     dir += mf->GetCurrentSourceDirectory();
-  } else if ((mf) && (strstr(m, "Generating") == m)) {
+  } else if (mf && cmHasLiteralPrefix(m, "Generating")) {
     dir = " ";
     dir += mf->GetCurrentBinaryDirectory();
   }
@@ -323,7 +324,7 @@
     [&cm](const std::string& msg, const char* title) {
       cmakemainMessageCallback(msg, title, &cm);
     });
-  cm.SetProgressCallback([&cm](const char* msg, float prog) {
+  cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
     cmakemainProgressCallback(msg, prog, &cm);
   });
   cm.SetWorkingMode(workingMode);
@@ -504,7 +505,7 @@
     [&cm](const std::string& msg, const char* title) {
       cmakemainMessageCallback(msg, title, &cm);
     });
-  cm.SetProgressCallback([&cm](const char* msg, float prog) {
+  cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
     cmakemainProgressCallback(msg, prog, &cm);
   });
   return cm.Build(jobs, dir, target, config, nativeOptions, clean, verbose);
@@ -547,7 +548,7 @@
     [&cm](const std::string& msg, const char* title) {
       cmakemainMessageCallback(msg, title, &cm);
     });
-  cm.SetProgressCallback([&cm](const char* msg, float prog) {
+  cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
     cmakemainProgressCallback(msg, prog, &cm);
   });
   return cm.Open(dir, false) ? 0 : 1;
diff --git a/Tests/FindOctave/Test/CMakeLists.txt b/Tests/FindOctave/Test/CMakeLists.txt
index ce33fcd..73aa831 100644
--- a/Tests/FindOctave/Test/CMakeLists.txt
+++ b/Tests/FindOctave/Test/CMakeLists.txt
@@ -10,6 +10,10 @@
 target_link_libraries(test_tgt Octave::Octave)
 add_test(NAME test_tgt COMMAND test_tgt)
 
+add_executable(test_octinterp_tgt interp_main.cpp)
+target_link_libraries(test_octinterp_tgt Octave::Octinterp)
+add_test(NAME test_octinterp_tgt COMMAND test_octinterp_tgt)
+
 add_test(NAME test_tgt_exe
          COMMAND Octave::Interpreter -q --eval "runtests('.')"
          WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/Tests/FindOctave/Test/interp_main.cpp b/Tests/FindOctave/Test/interp_main.cpp
new file mode 100644
index 0000000..1efa187
--- /dev/null
+++ b/Tests/FindOctave/Test/interp_main.cpp
@@ -0,0 +1,26 @@
+#include <iostream>
+#include <oct.h>
+#include <octave.h>
+#include <parse.h>
+#include <toplev.h>
+
+int main(void)
+{
+  string_vector argv(2);
+  argv(0) = "embedded";
+  argv(1) = "-q";
+
+  try {
+    octave_main(2, argv.c_str_vec(), 1);
+    octave_value_list in;
+    in(0) = 72.0;
+    const octave_value_list result = feval("sqrt", in);
+    std::cout << "result is " << result(0).scalar_value() << std::endl;
+    clean_up_and_exit(0);
+  } catch (const octave::exit_exception& ex) {
+    std::cerr << "Octave interpreter exited with status = " << ex.exit_status()
+              << std::endl;
+  } catch (const octave::execution_exception&) {
+    std::cerr << "error encountered in Octave evaluator!" << std::endl;
+  }
+}