commit 232a5f133e156ed5a134438d71913d44d1a5d4ca
Author: Pavel Sanda <[email protected]>
Date:   Thu Sep 17 11:16:21 2026 +0200

    Move the cygdrive probe off runCommand
    
    Last runCommand() caller. We can't use argv form as init() runs
    before QCoreApplication exists and QProcess is available.
    
    So we move runCommand->runComspec, leave it for _WIN32 only, and drop
    parts for other archs. We keep the same windows COMSPEC spawning and
    pipeline handling, no change intended.
    Deletion of original runCommand comes in the next patch.
    
    The input redirection and the 2>&1 handling not necessary for the
    single consumer left, but are kept so that we ship the same code on
    Windows without changes.
    
    Don't be deceived, cygdrive query runs in native Windows, not Cygwin.
    
    https://www.mail-archive.com/[email protected]/msg226898.html
    
    Tier 01 DiD / argv 04d: cygdrive probe keeps its own spawn code
    
    Assisted-by: Claude Opus 5
---
 src/support/os_win32.cpp | 107 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 103 insertions(+), 4 deletions(-)

diff --git a/src/support/os_win32.cpp b/src/support/os_win32.cpp
index a10c17ede0..17c9662336 100644
--- a/src/support/os_win32.cpp
+++ b/src/support/os_win32.cpp
@@ -32,17 +32,21 @@
 
 #include "support/lassert.h"
 
+#include <cstdio>
 #include <cstdlib>
+#include <cstring> // memset
 #include <iostream>
 #include <vector>
 
 #include <QString>
 
 #include <io.h>
+#include <fcntl.h>  // _O_RDONLY
 #include <direct.h> // _getdrive
 #include <fileapi.h> // GetFinalPathNameByHandle
 #include <shlobj.h>  // SHGetFolderPath
 #include <windef.h>
+#include <windows.h>
 #include <shellapi.h>
 #include <shlwapi.h>
 
@@ -89,6 +93,100 @@ bool windows_style_tex_paths_ = true;
 
 string cygdrive = "/cygdrive";
 
+
+// Run cmd through COMSPEC and return its standard output in result,
+// the return value tells whether the command exited successfully.
+//
+// Relic of the former cross-platform support::runCommand() and it spawns
+// a shell, so you need be extra careful about safety of the arguments. 
+// Preferably do not add new callers of this function - we have generic 
+// Systemcall and this is used only in init() before QCoreApplication
+// kicks in.
+bool runComspec(string const & cmd, string & result)
+{
+       result.clear();
+
+       if (verbose)
+               lyxerr << "\nRunning: " << cmd << endl;
+       else
+               LYXERR(Debug::INFO,"Running: " << cmd);
+
+       STARTUPINFO startup;
+       PROCESS_INFORMATION process;
+       SECURITY_ATTRIBUTES security;
+       HANDLE in, out;
+       FILE * inf = 0;
+       bool err2out = false;
+       string command;
+       string const infile = trim(split(cmd, command, '<'), " \"");
+       command = rtrim(command);
+       if (suffixIs(command, "2>&1")) {
+               command = rtrim(command, "2>&1");
+               err2out = true;
+       }
+       string const cmdarg = "/d /c \"" + command + "\"";
+       string const comspec = getEnv("COMSPEC");
+
+       security.nLength = sizeof(SECURITY_ATTRIBUTES);
+       security.bInheritHandle = TRUE;
+       security.lpSecurityDescriptor = NULL;
+
+       if (CreatePipe(&in, &out, &security, 0)) {
+               memset(&startup, 0, sizeof(STARTUPINFO));
+               memset(&process, 0, sizeof(PROCESS_INFORMATION));
+
+               startup.cb = sizeof(STARTUPINFO);
+               startup.dwFlags = STARTF_USESTDHANDLES;
+
+               startup.hStdError = err2out ? out : 
GetStdHandle(STD_ERROR_HANDLE);
+               startup.hStdInput = infile.empty()
+                       ? GetStdHandle(STD_INPUT_HANDLE)
+                       : CreateFile(infile.c_str(), GENERIC_READ,
+                               FILE_SHARE_READ, &security, OPEN_EXISTING,
+                               FILE_ATTRIBUTE_NORMAL, NULL);
+               startup.hStdOutput = out;
+
+               if (startup.hStdInput != INVALID_HANDLE_VALUE &&
+                       CreateProcess(comspec.c_str(), (LPTSTR)cmdarg.c_str(),
+                               &security, &security, TRUE, CREATE_NO_WINDOW,
+                               0, 0, &startup, &process)) {
+
+                       CloseHandle(process.hThread);
+                       int fno = _open_osfhandle((intptr_t)in, _O_RDONLY);
+                       CloseHandle(out);
+                       inf = _fdopen(fno, "r");
+               }
+       }
+
+       if (!inf) {
+               lyxerr << "RunCommand: could not start child process" << endl;
+               return false;
+       }
+
+       int c = fgetc(inf);
+       while (c != EOF) {
+               result += static_cast<char>(c);
+               c = fgetc(inf);
+       }
+
+       WaitForSingleObject(process.hProcess, INFINITE);
+       DWORD pret;
+       BOOL success = GetExitCodeProcess(process.hProcess, &pret);
+       bool valid = (pret == 0) && success;
+       if (!success)
+               pret = -1;
+       if (!infile.empty())
+               CloseHandle(startup.hStdInput);
+       CloseHandle(process.hProcess);
+       if (fclose(inf) != 0)
+               pret = -1;
+
+       if (pret == -1)
+               perror("RunCommand: could not terminate child process");
+
+       return valid;
+}
+
 BOOL terminate_handler(DWORD event)
 {
        if (event == CTRL_CLOSE_EVENT
@@ -221,8 +319,9 @@ void init(int argc, char ** argv[])
                RegCloseKey(hkey);
                string const mount = string(buf) + "\\bin\\mount.exe";
                if (retval == ERROR_SUCCESS && FileName(mount).exists()) {
-                       cmd_ret const p =
-                               runCommand(mount + " --show-cygdrive-prefix");
+                       string result;
+                       bool const valid = runComspec(
+                               mount + " --show-cygdrive-prefix", result);
                        // The output of the mount command is as follows:
                        // Prefix              Type         Flags
                        // /cygdrive           system       binmode
@@ -230,8 +329,8 @@ void init(int argc, char ** argv[])
                        // to the outer split which sets cygdrive with its
                        // contents until the first blank, discarding the
                        // unneeded return value.
-                       if (p.valid && prefixIs(p.result, "Prefix"))
-                               split(split(p.result, '\n'), cygdrive, ' ');
+                       if (valid && prefixIs(result, "Prefix"))
+                               split(split(result, '\n'), cygdrive, ' ');
                }
        }
 
-- 
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs

Reply via email to