From f9e67a323563010c85b5ca8e43f45cac04366965 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Mon, 10 Feb 2020 16:36:52 +0100
Subject: [PATCH] Further improvements to parsing of arguments on the MATLAB
 command-line

Under GNU/Linux and macOS, double-quote arguments before passing them to the
shell. In particular, this allows passing single-quotes within those arguments.

We therefore have to escape the four characters that are interpreted within
double-quoted strings in POSIX shells: \, ", $ and `

On Windows, also systematically escape the backslashes.

Also move display of arguments before escaping, so that it remains readable.

Ref. #1696

(cherry picked from commit ae59f4dcb22587c4041d503bdfe61f8ea1b17a05)
---
 doc/manual/source/running-dynare.rst |  7 ++---
 matlab/dynare.m                      | 38 ++++++++++++++--------------
 2 files changed, 23 insertions(+), 22 deletions(-)

diff --git a/doc/manual/source/running-dynare.rst b/doc/manual/source/running-dynare.rst
index bb69284af0..076d9ec780 100644
--- a/doc/manual/source/running-dynare.rst
+++ b/doc/manual/source/running-dynare.rst
@@ -334,9 +334,10 @@ by the ``dynare`` command.
         Defines a macro-variable from the command line (the same effect as
         using the Macro directive ``@#define`` in a model file, see
         :ref:`macro-proc-lang`). Note that when passing a MACRO_EXPRESSION that
-        contains a space, you must surround the entire ``-D`` flag with single
-        quotes, as in the following example. Also note that an expression
-        passed on the command line can reference variables defined before it.
+        contains a space (or, under Octave, a double quote), you must surround
+        the entire ``-D`` flag with single quotes, as in the following example.
+        Also note that an expression passed on the command line can reference
+        variables defined before it.
 
         *Example*
 
diff --git a/matlab/dynare.m b/matlab/dynare.m
index d429d54c22..9370ca06e0 100644
--- a/matlab/dynare.m
+++ b/matlab/dynare.m
@@ -210,32 +210,32 @@ else
     end
 end
 
-command = ['"' dynareroot 'preprocessor' arch_ext filesep 'dynare_m" ' fname] ;
-command = [ command ' mexext=' mexext ' "matlabroot=' matlabroot '"'];
-if ~isempty(varargin)
-    if ispc
-        varargincopy = varargin;
-        for i = 1:length(varargincopy)
-            if varargincopy{i}(end) == '\'
-                varargincopy{i} = [varargincopy{i} '\'];
-            end
-        end
-        varargincopy = strrep(varargincopy, '"', '\"');
-        dynare_varargin = ['"' strjoin(varargincopy, '" "') '"'];
-    else
-        dynare_varargin = ['''' strjoin(varargin, ''' ''') ''''];
-    end
-    command = [command ' ' dynare_varargin];
-end
-
 if preprocessoroutput
     fprintf(['Starting Dynare (version ' dynare_version() ').\n']);
     fprintf('Calling Dynare with arguments: ');
     if isempty(varargin)
         disp('none')
     else
-        disp(dynare_varargin);
+        disp(strjoin(varargin, ' '));
+    end
+end
+
+command = ['"' dynareroot 'preprocessor' arch_ext filesep 'dynare_m" ' fname] ;
+command = [ command ' mexext=' mexext ' "matlabroot=' matlabroot '"'];
+% Properly quote arguments before passing them to the shell
+if ~isempty(varargin)
+    varargincopy = varargin;
+    % Escape backslashes and double-quotes
+    varargincopy = strrep(varargincopy, '\', '\\');
+    varargincopy = strrep(varargincopy, '"', '\"');
+    if ~ispc
+        % On GNU/Linux and macOS, also escape dollars and backquotes
+        varargincopy = strrep(varargincopy, '$', '\$');
+        varargincopy = strrep(varargincopy, '`', '\`');
     end
+    % Finally, enclose arguments within double quotes
+    dynare_varargin = ['"' strjoin(varargincopy, '" "') '"'];
+    command = [command ' ' dynare_varargin];
 end
 
 % Under Windows, make sure the MEX file is unloaded (in the use_dll case),
-- 
GitLab