[education/rkward] rkward: The old 8.3 hack for supporting paths with spaces on Windows no longer works.

Thomas Friedrichsmeier null at kde.org
Mon Oct 3 08:19:26 BST 2022


Git commit 25ad8f62eaa9af31761f75d29c054b99530b7260 by Thomas Friedrichsmeier.
Committed on 03/10/2022 at 07:18.
Pushed by tfry into branch 'master'.

The old 8.3 hack for supporting paths with spaces on Windows no longer works.

Try something new (needs more testing).

M  +4    -4    rkward/main.cpp
M  +0    -19   rkward/misc/rkcommonfunctions.cpp
M  +0    -2    rkward/misc/rkcommonfunctions.h
M  +11   -1    rkward/rbackend/rkfrontendtransmitter.cpp
M  +2    -2    rkward/rbackend/rkrinterface.cpp

https://invent.kde.org/education/rkward/commit/25ad8f62eaa9af31761f75d29c054b99530b7260

diff --git a/rkward/main.cpp b/rkward/main.cpp
index 92a0613f..e0e755d9 100644
--- a/rkward/main.cpp
+++ b/rkward/main.cpp
@@ -344,10 +344,10 @@ int main (int argc, char *argv[]) {
 	}
 #endif
 	// This is _not_ the same path adjustment as above: Make sure to add the current dir to the path, before launching R and backend.
-	QStringList syspaths = QString (qgetenv ("PATH")).split (PATH_VAR_SEP);
-	if (!syspaths.contains (app.applicationDirPath ())) {
-		syspaths.prepend (RKCommonFunctions::windowsShellScriptSafeCommand (app.applicationDirPath ()));
-		qputenv ("PATH", syspaths.join (PATH_VAR_SEP).toLocal8Bit ());
+	QStringList syspaths = QString(qgetenv("PATH")).split(PATH_VAR_SEP);
+	if (!syspaths.contains(app.applicationDirPath())) {
+		syspaths.prepend(app.applicationDirPath());
+		qputenv("PATH", syspaths.join(PATH_VAR_SEP).toLocal8Bit());
 	}
 
 	// Handle --reuse option, by placing a dbus-call to existing RKWard process (if any) and exiting
diff --git a/rkward/misc/rkcommonfunctions.cpp b/rkward/misc/rkcommonfunctions.cpp
index db3f0375..42142019 100644
--- a/rkward/misc/rkcommonfunctions.cpp
+++ b/rkward/misc/rkcommonfunctions.cpp
@@ -249,25 +249,6 @@ namespace RKCommonFunctions {
 		return (i18n ("<p><em>Note:</em> This setting does not take effect until you restart RKWard.</p>"));
 	}
 
-#ifdef Q_OS_WIN
-#	include <windows.h>
-#	include <QTemporaryFile>
-#endif
-	QString windowsShellScriptSafeCommand (const QString &orig) {
-#ifdef Q_OS_WIN
-		// credits to http://erasmusjam.wordpress.com/2012/10/01/get-8-3-windows-short-path-names-in-a-qt-application/
-		QByteArray input (sizeof (wchar_t) * (orig.size()+1), '\0');
-		// wchar_t input[orig.size()+1]; -- No: MSVC (2013) does not support variable length arrays. Oh dear...
-		orig.toWCharArray ((wchar_t*) input.data ());
-		long length = GetShortPathName ((wchar_t*) input.data (), NULL, 0);
-		QByteArray output (sizeof (wchar_t) * (length), '\0');
-		GetShortPathName ((wchar_t*) input.data (), (wchar_t*) output.data (), length);
-		return QString::fromWCharArray ((wchar_t*) output.data (), length-1);
-#else
-		return orig;
-#endif
-	}
-
 	QLabel* wordWrappedLabel (const QString& text) {
 		QLabel* ret = new QLabel (text);
 		ret->setWordWrap (true);
diff --git a/rkward/misc/rkcommonfunctions.h b/rkward/misc/rkcommonfunctions.h
index e9f1e939..e5dd1257 100644
--- a/rkward/misc/rkcommonfunctions.h
+++ b/rkward/misc/rkcommonfunctions.h
@@ -49,8 +49,6 @@ namespace RKCommonFunctions {
 /** simultaneously sets tool tips and what's this tips on up to three QWidgets */
 	void setTips (const QString &tip, QWidget *first, QWidget *second=0, QWidget *third=0);
 	QString noteSettingsTakesEffectAfterRestart ();
-/** Passing commands as part of arguments to windows shell scripts will fail miserably for paths with spaces or special characters. Transform to short path names for safety. No-op on sane platforms.*/
-	QString windowsShellScriptSafeCommand (const QString &orig);
 
 /** create a QLabel that has wordwarp enabled, in a single line of code. */
 	QLabel* wordWrappedLabel (const QString &text);
diff --git a/rkward/rbackend/rkfrontendtransmitter.cpp b/rkward/rbackend/rkfrontendtransmitter.cpp
index db49c694..c99822b8 100644
--- a/rkward/rbackend/rkfrontendtransmitter.cpp
+++ b/rkward/rbackend/rkfrontendtransmitter.cpp
@@ -110,7 +110,16 @@ void RKFrontendTransmitter::run () {
 		exec();   // To actually show the transmission error
 		return;
 	}
-	args.append(RKCommonFunctions::windowsShellScriptSafeCommand(backend_executable));
+
+#ifdef Q_OS_WIN
+	// Needed for paths with spaces. R CMD is too simple to deal with those, even if we provide proper quoting.
+	// So rather we need to work from a relative path with all spaces eliminated
+	QFileInfo bfi(backend_executable);
+	backend->setWorkingDirectory(bfi.absolutePath());
+	args.append(bfi.fileName());
+#else
+	args.append(backend_executable);
+#endif
 
 	args.append ("--debug-level=" + QString::number (RK_Debug::RK_Debug_Level));
 	// NOTE: QProcess quotes its arguments, *but* properly passing all spaces and quotes through the R CMD wrapper, seems near(?) impossible on Windows. Instead, we use percent encoding, internally.
@@ -138,6 +147,7 @@ void RKFrontendTransmitter::run () {
 	// What appears to function as a workaround is start a dummy process, before that.
 	QProcess dummy;
 	QStringList dummyargs = args;
+	dummy.setWorkingDirectory(backend->workingDirectory());
 	dummyargs.removeAt(dummyargs.size()-4); // the --server-name. With this empty, the backend will exit
 	dummy.start(RKSessionVars::RBinary(), dummyargs, QIODevice::ReadOnly);
 	dummy.waitForFinished();
diff --git a/rkward/rbackend/rkrinterface.cpp b/rkward/rbackend/rkrinterface.cpp
index f52282ad..a24194ab 100644
--- a/rkward/rbackend/rkrinterface.cpp
+++ b/rkward/rbackend/rkrinterface.cpp
@@ -417,8 +417,8 @@ void RInterface::handleRequest (RBackendRequest* request) {
 			// initialize output file
 			RKOutputDirectory::getCurrentOutput(chain);
 
-#ifdef Q_OS_MACOS
-			// On MacOS, the backend is started from inside R home to allow resolution of dynamic libs. Re-set to frontend wd, here.
+#if defined(Q_OS_MACOS) || defined(Q_OS_WIN)
+			// On MacOS and Windows, the backend is started with different working directories set, for hackish reasons (see rkfrontendtransmitter.cpp). Fix that, here.
 			runStartupCommand(new RCommand("setwd (" + RKRSharedFunctionality::quote(QDir::currentPath()) + ")\n", RCommand::App | RCommand::Sync), chain, runtimeopt_callback);
 #endif
 			// Workaround for https://bugs.kde.org/show_bug.cgi?id=421958


More information about the rkward-tracker mailing list