diff --git a/src/include/globals.h b/src/include/globals.h
index 8eab1bc2..25344464 100644
--- a/src/include/globals.h
+++ b/src/include/globals.h
@@ -228,12 +228,21 @@ extern DLLIMPORT wxString MakeUniqueString(const wxString& text, const wxString
extern DLLIMPORT void AppendArray(const wxArrayString& from, wxArrayString& to);
extern DLLIMPORT wxString UnixFilename(const wxString& filename, wxPathFormat format = wxPATH_NATIVE);
extern DLLIMPORT void QuoteStringIfNeeded(wxString& str);
extern DLLIMPORT bool NeedQuotes(const wxString &str);
+/** \brief Remove all empty quote pairs (@c "" ) from a string.
+ *
+ * An empty quote pair is harmless inside a command line, the shell or the process
+ * launcher simply swallows it. It is fatal inside a path though, e.g. a global
+ * compiler variable defined as @c "" expands to @c ".../lib/gcc_dll""" which is not
+ * an existing directory when put into @c PATH .
+ */
+extern DLLIMPORT wxString cbStripEmptyQuotes(const wxString& str);
+
/// Escapes spaces and tabs (NOT quoting the string)
extern DLLIMPORT wxString EscapeSpaces(const wxString& str);
extern DLLIMPORT FileType FileTypeOf(const wxString& filename);
extern DLLIMPORT wxString cbFindFileInPATH(const wxString &filename);
diff --git a/src/plugins/debuggergdb/debuggergdb.cpp b/src/plugins/debuggergdb/debuggergdb.cpp
index 24facd91..e9cdc3da 100644
--- a/src/plugins/debuggergdb/debuggergdb.cpp
+++ b/src/plugins/debuggergdb/debuggergdb.cpp
@@ -897,13 +897,15 @@ int DebuggerGDB::DoDebug(bool breakOnEntry)
{
wxString newLibPath;
const wxString libPathSep = platform::windows ? ";" : ":";
newLibPath << "." << libPathSep;
CompilerCommandGenerator *generator = actualCompiler->GetCommandGenerator(m_pProject);
- newLibPath << GetStringFromArray(generator->GetLinkerSearchDirs(target), libPathSep);
+ // Strip empty quote pairs (e.g. from a global variable defined as ""), otherwise
+ // entries like "E:\wx\lib\gcc_dll""" end up in PATH and are not valid directories.
+ newLibPath << cbStripEmptyQuotes(GetStringFromArray(generator->GetLinkerSearchDirs(target), libPathSep));
delete generator;
if (newLibPath.Mid(newLibPath.Length() - 1, 1) != libPathSep)
newLibPath << libPathSep;
newLibPath << oldLibPath;
wxSetEnv(CB_LIBRARY_ENVVAR, newLibPath);
diff --git a/src/sdk/cbproject.cpp b/src/sdk/cbproject.cpp
index 9f6d363b..4bf60a0f 100644
--- a/src/sdk/cbproject.cpp
+++ b/src/sdk/cbproject.cpp
@@ -2033,13 +2033,15 @@ wxString cbGetDynamicLinkerPathForTarget(cbProject* project, ProjectBuildTarget*
if (!generator)
return wxEmptyString;
wxString libPath;
const wxString libPathSep = platform::windows ? ";" : ":";
libPath << "." << libPathSep;
- libPath << GetStringFromArray(generator->GetLinkerSearchDirs(target), libPathSep);
+ // Strip empty quote pairs (e.g. a global variable defined as ""), they would
+ // make the path entry invalid when used as PATH/LD_LIBRARY_PATH.
+ libPath << cbStripEmptyQuotes(GetStringFromArray(generator->GetLinkerSearchDirs(target), libPathSep));
if (!libPath.IsEmpty() && libPath.Mid(libPath.Length() - 1, 1) == libPathSep)
libPath.Truncate(libPath.Length() - 1);
delete generator;
return libPath;
}
diff --git a/src/sdk/globals.cpp b/src/sdk/globals.cpp
index 0cde5347..87a7b653 100644
--- a/src/sdk/globals.cpp
+++ b/src/sdk/globals.cpp
@@ -270,12 +270,28 @@ bool NeedQuotes(const wxString &str)
{
bool hasSpace = str.Find(_T(' ')) != -1;
bool hasParen = !platform::windows && (str.Find(_T('(')) != -1 || str.Find(_T(')')) != -1);
return !str.IsEmpty() && str.GetChar(0) != _T('"') && (hasSpace || hasParen);
}
+wxString cbStripEmptyQuotes(const wxString& str)
+{
+ if (str.Find(_T('"')) == wxNOT_FOUND)
+ return str;
+
+ // An empty quote pair ("") is swallowed by the shell/process launcher, so it does
+ // not hurt in a command line. In a path used as an environment variable (PATH,
+ // LD_LIBRARY_PATH) it makes the whole entry invalid, so remove all of them.
+ wxString result(str);
+ // Repeat, because there can be more than one pair (or nested ones).
+ while (result.Replace("\"\"", wxEmptyString, true) != 0)
+ ;
+
+ return result;
+}
+
wxString EscapeSpaces(const wxString& str)
{
wxString ret = str;
if (!ret.IsEmpty() && ret[0] != _T('"') && ret[0] != _T('\''))
{
// TODO: make it faster
diff --git a/src/sdk/uservarmanager.cpp b/src/sdk/uservarmanager.cpp
index f7c38584..5661c5e4 100644
--- a/src/sdk/uservarmanager.cpp
+++ b/src/sdk/uservarmanager.cpp
@@ -190,13 +190,18 @@ wxString UserVariableManager::Replace(const wxString& variable, std::vector<wxSt
std::set<wxString> ar = {varName};
m_ui->OpenEditWindow(ar);
Reload();
}
}
- return value;
+
+ // A variable is sometimes defined as "" (an empty quote pair) just to make
+ // $(#var) expand to nothing. Drop those empty quote pairs here, so that they
+ // can't leak into paths, e.g. "$(#wx.lib)/gcc_dll$(#wx.cfg)" turning into
+ // ".../gcc_dll""" which is an invalid directory when put into PATH.
+ return cbStripEmptyQuotes(value);
}
std::vector<wxString> UserVariableManager::GetVariableSetNames() const
{
std::vector<wxString> names;
names.reserve(m_VariableSetMap.size());
I'm testing above patch, it try to remove all the "" in the macro replacement in string generation, also in the compiler and debugger plugin.
The patch works fine.