diff --git a/inst/private/cygpath.m b/inst/private/cygpath.m new file mode 100644 index 000000000..bea5221b3 --- /dev/null +++ b/inst/private/cygpath.m @@ -0,0 +1,39 @@ +%% Copyright (C) 2022 Alex Vong +%% +%% This file is part of OctSymPy. +%% +%% OctSymPy is free software; you can redistribute it and/or modify +%% it under the terms of the GNU General Public License as published +%% by the Free Software Foundation; either version 3 of the License, +%% or (at your option) any later version. +%% +%% This software is distributed in the hope that it will be useful, +%% but WITHOUT ANY WARRANTY; without even the implied warranty +%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +%% the GNU General Public License for more details. +%% +%% You should have received a copy of the GNU General Public +%% License along with this software; see the file COPYING. +%% If not, see . + +%% -*- texinfo -*- +%% @defun cygpath () +%% Convert Windows native path to Cygwin POSIX-style path. +%% +%% @seealso{python_env_is_cygwin_like} +%% @end defun + +function posix_path = cygpath (native_path) + %% FIXME: only allow safe characters inside "..." + if ~isempty (strfind (native_path, '"')) + error ('cygpath: native path %s must not contain "', native_path); + end + + [status, out] = system (['cygpath -u "' native_path '"']); + if status ~= 0 + error ('cygpath: cygpath exited with status %d', status); + end + + posix_path = regexprep (out, '[\r]?[\n]$', ''); % strip trailing newline + assert (logical (regexp (posix_path, '^[^\r\n]+$'))); % validate path +end diff --git a/inst/private/python_env_is_cygwin_like.m b/inst/private/python_env_is_cygwin_like.m new file mode 100644 index 000000000..9d0a177e9 --- /dev/null +++ b/inst/private/python_env_is_cygwin_like.m @@ -0,0 +1,54 @@ +%% Copyright (C) 2022 Alex Vong +%% +%% This file is part of OctSymPy. +%% +%% OctSymPy is free software; you can redistribute it and/or modify +%% it under the terms of the GNU General Public License as published +%% by the Free Software Foundation; either version 3 of the License, +%% or (at your option) any later version. +%% +%% This software is distributed in the hope that it will be useful, +%% but WITHOUT ANY WARRANTY; without even the implied warranty +%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +%% the GNU General Public License for more details. +%% +%% You should have received a copy of the GNU General Public +%% License along with this software; see the file COPYING. +%% If not, see . + +%% -*- texinfo -*- +%% @defun python_env_is_cygwin_like (pyexec) +%% Check if Python @var{pyexec} is running in a Cygwin-like POSIX environment, +%% such as Cygwin or MSYS2. The result is memoized to speed up subsequent +%% calls. +%% +%% @seealso{cygpath} +%% @end defun + +function r = python_env_is_cygwin_like (pyexec) + persistent python_env_is_cygwin_like_memo + + if ~isempty (python_env_is_cygwin_like_memo) + r = python_env_is_cygwin_like_memo; + return + end + + if ispc () + if system ('where /q cygpath') ~= 0 + r = false; + python_env_is_cygwin_like_memo = r; + return + end + + [status, out] = system ([pyexec ' -c "import os; print(os.name)"']); + if status ~= 0 + error ('python_env_is_cygwin_like: %s exited with status %d', ... + pyexec, status); + end + r = ~isempty (regexp (out, 'posix', 'match')); + python_env_is_cygwin_like_memo = r; + else + r = false; + python_env_is_cygwin_like_memo = r; + end +end diff --git a/inst/private/python_ipc_system.m b/inst/private/python_ipc_system.m index c264f153b..66104d69b 100644 --- a/inst/private/python_ipc_system.m +++ b/inst/private/python_ipc_system.m @@ -1,4 +1,5 @@ %% Copyright (C) 2014-2016, 2022 Colin B. Macdonald +%% Copyright (C) 2022 Alex Vong %% %% This file is part of OctSymPy. %% @@ -131,6 +132,10 @@ error ('system ipc: failed to close %s (fd %d) after writing', ... tmpfilename, fd); end + + if python_env_is_cygwin_like (pyexec) + tmpfilename = cygpath (tmpfilename); + end [status, out] = system ([pyexec ' ' tmpfilename]); end