1function dynare(fname, varargin) 2% This command runs dynare with specified model file in argument 3% Filename. 4% The name of model file begins with an alphabetic character, 5% and has a filename extension of .mod or .dyn. 6% When extension is omitted, a model file with .mod extension 7% is processed. 8% 9% INPUTS 10% fname: file name 11% varargin: list of arguments following fname 12% 13% OUTPUTS 14% none 15% 16% SPECIAL REQUIREMENTS 17% none 18 19% Copyright (C) 2001-2020 Dynare Team 20% 21% This file is part of Dynare. 22% 23% Dynare is free software: you can redistribute it and/or modify 24% it under the terms of the GNU General Public License as published by 25% the Free Software Foundation, either version 3 of the License, or 26% (at your option) any later version. 27% 28% Dynare is distributed in the hope that it will be useful, 29% but WITHOUT ANY WARRANTY; without even the implied warranty of 30% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31% GNU General Public License for more details. 32% 33% You should have received a copy of the GNU General Public License 34% along with Dynare. If not, see <http://www.gnu.org/licenses/>. 35 36if ~nargin || strcmpi(fname,'help') 37 skipline() 38 disp(['This is Dynare version ' dynare_version() '.']) 39 skipline() 40 disp('USAGE: dynare FILENAME[.mod,.dyn] [OPTIONS]') 41 skipline() 42 disp('The dynare command executes instruction included in FILENAME.mod.') 43 disp('See the reference manual for the available options.') 44 skipline() 45 return 46end 47 48% The following needs to come early, to avoid spurious warnings (especially under Octave) 49warning_config; 50 51% Handle nopathchange option 52% Note that it is only handled if it appears on the command-line, and not at 53% the top of the .mod file (since the treatment needs to take place very early, 54% even before we make the various checks on the filename) 55change_path_flag = true; 56if nargin>1 57 id = ismember(varargin, 'nopathchange'); 58 if any(id) 59 change_path_flag = false; 60 varargin(id) = []; 61 end 62end 63check_matlab_path(change_path_flag); 64 65% Detect if MEX files are present; if not, use alternative M-files 66dynareroot = dynare_config(); 67 68if isoctave 69 % The supported_octave_version.m file is not in git nor in the source 70 % package, it is manually added in binary packages distributed on dynare.org 71 if exist('supported_octave_version', 'file') && ~strcmp(supported_octave_version, version) 72 skipline() 73 warning(['This version of Octave is not supported. Consider installing ' ... 74 'version %s of Octave\n' ... 75 'from www.octave.org, otherwise m files will be used instead ' ... 76 'of precompiled mex files and some\nfeatures, like solution ' ... 77 'of models approximated at third order, will not be available.'], supported_octave_version()) 78 skipline() 79 elseif octave_ver_less_than('4.2') % Should match the test in mex/build/octave/configure.ac 80 % and in m4/ax_mexopts.m4 81 skipline() 82 warning(['This version of Dynare has only been tested on Octave 4.2 and above. Dynare may fail to run or give unexpected result. Consider upgrading your version of Octave.']) 83 skipline() 84 end 85else 86 if matlab_ver_less_than('7.9') % Should match the test in mex/build/matlab/configure.ac 87 skipline() 88 warning('This version of Dynare has only been tested on MATLAB 7.9 (R2009b) and above. Since your MATLAB version is older than that, Dynare may fail to run, or give unexpected results. Consider upgrading your MATLAB installation, or switch to Octave.'); 89 skipline() 90 end 91end 92 93% disable output paging (it is on by default on Octave) 94more off 95 96% sets default format for save() command 97if isoctave 98 save_default_options('-mat') 99end 100 101if nargin < 1 102 error('Dynare: you must provide the name of the .mod file in argument') 103end 104 105if ~ischar(fname) 106 error('Dynare: argument of dynare must be a text string') 107end 108 109% Testing if filename has more than one period (not allowed). 110dot_location=strfind(fname,'.'); 111if length(dot_location)>1 112 error('Dynare: Periods in filenames are only allowed for .mod or .dyn extensions') 113end 114 115if dot_location==length(fname) 116 error('Dynare: Periods in filenames are only allowed for .mod or .dyn extensions') 117end 118 119% Add dyn or mod extension to the file name if not already provided. 120if isempty(dot_location) 121 fnamelength = length(fname); 122 fname1 = [fname '.dyn']; 123 d = dir(fname1); 124 if length(d) == 0 125 fname1 = [fname '.mod']; 126 end 127 fname = fname1; 128else 129 % Check provided file extension. 130 if ~strcmpi(fname(dot_location+1:end), 'mod') && ~strcmpi(fname(dot_location+1:end), 'dyn') 131 error('Dynare: argument must be a filename with .mod or .dyn extensions') 132 end 133 fnamelength = length(fname) - 4; 134end 135 136if fnamelength + length('.set_auxiliary_variables') > namelengthmax() 137 error('Dynare: the name of your .mod file is too long, please shorten it') 138end 139 140% Workaround for a strange bug with Octave: if there is any call to exist(fname) 141% before the call to the preprocessor, then Octave will use the old copy of 142% the .m instead of the newly generated one. Deleting the .m beforehand 143% fixes the problem. 144if isoctave && length(dir([fname(1:(end-4)) '.m'])) > 0 145 delete([fname(1:(end-4)) '.m']) 146end 147 148if ~isempty(strfind(fname,filesep)) 149 fprintf('\nIt seems you are trying to call a .mod file not located in the "Current Folder". This is not possible (the %s symbol is not allowed in the name of the .mod file).\n', filesep) 150 [pathtomodfile,basename] = fileparts(fname); 151 if exist(pathtomodfile,'dir') 152 filesindirectory = dir(pathtomodfile); 153 filesindirectory = struct2cell(filesindirectory); 154 filesindirectory = filesindirectory(1,:); 155 if ~isempty(strmatch([basename '.mod'],filesindirectory)) || ~isempty(strmatch([basename '.dyn'],filesindirectory)) 156 fprintf('Please set your "Current Folder" to the folder where the .mod file is located using the following command:\n') 157 fprintf('\n >> cd %s\n\n',pathtomodfile) 158 else 159 fprintf('The file %s[.mod,.dyn] could not be located!\n\n',basename) 160 end 161 end 162 error(['Dynare: can''t open ' fname, '.']) 163end 164 165if ~exist(fname,'file') || isequal(fname,'dir') 166 fprintf('\nThe file %s could not be located in the "Current Folder". Check whether you typed in the correct filename\n',fname) 167 fprintf('and whether the file is really located in the "Current Folder".\n') 168 try 169 list_of_mod_files = ls('*.mod'); 170 fprintf('\nCurrent folder is %s, and contains the following .mod files:\n\n',pwd) 171 disp(list_of_mod_files) 172 catch 173 fprintf('\nCurrent folder is %s, and does not contain any .mod files.\n\n',pwd) 174 end 175 error(['Dynare: can''t open ' fname]) 176end 177 178if ~isvarname(fname(1:end-4)) 179 error('Dynare: argument of dynare must conform to MATLAB''s convention for naming functions, i.e. start with a letter and not contain special characters. Please rename your .mod file.') 180end 181 182% pre-dynare-preprocessor-hook 183if exist(fname(1:end-4),'dir') && exist([fname(1:end-4) filesep 'hooks'],'dir') && exist([fname(1:end-4) filesep 'hooks/priorprocessing.m'],'file') 184 run([fname(1:end-4) filesep 'hooks/priorprocessing']) 185end 186 187% Parse some options, either for the command-line or from the top of the .mod file 188file_opts = parse_options_line(fname); 189preprocessoroutput = ~ismember('nopreprocessoroutput', varargin) && ... 190 ~ismember('nopreprocessoroutput', file_opts); 191nolog = ismember('nolog', varargin) || ismember('nolog', file_opts); 192onlymacro = ismember('onlymacro', varargin) || ismember('onlymacro', file_opts); 193onlyjson = ismember('onlyjson', varargin) || ismember('onlyjson', file_opts); 194 195if ispc 196 arch = getenv('PROCESSOR_ARCHITECTURE'); 197else 198 [~, arch] = system('uname -m'); 199end 200 201if isempty(strfind(arch, '64')) 202 arch_ext = '32'; 203 if preprocessoroutput 204 disp('Using 32-bit preprocessor'); 205 end 206else 207 arch_ext = '64'; 208 if preprocessoroutput 209 disp('Using 64-bit preprocessor'); 210 end 211end 212 213if preprocessoroutput 214 fprintf(['Starting Dynare (version ' dynare_version() ').\n']); 215 fprintf('Calling Dynare with arguments: '); 216 if isempty(varargin) 217 disp('none') 218 else 219 disp(strjoin(varargin, ' ')); 220 end 221end 222 223command = ['"' dynareroot 'preprocessor' arch_ext filesep 'dynare_m" ' fname] ; 224command = [ command ' mexext=' mexext ' "matlabroot=' matlabroot '"']; 225% Properly quote arguments before passing them to the shell 226if ~isempty(varargin) 227 varargincopy = varargin; 228 % Escape backslashes and double-quotes 229 varargincopy = strrep(varargincopy, '\', '\\'); 230 varargincopy = strrep(varargincopy, '"', '\"'); 231 if ~ispc 232 % On GNU/Linux and macOS, also escape dollars and backquotes 233 varargincopy = strrep(varargincopy, '$', '\$'); 234 varargincopy = strrep(varargincopy, '`', '\`'); 235 end 236 % Finally, enclose arguments within double quotes 237 dynare_varargin = ['"' strjoin(varargincopy, '" "') '"']; 238 command = [command ' ' dynare_varargin]; 239end 240 241% Under Windows, make sure the MEX file is unloaded (in the use_dll case), 242% otherwise the preprocessor can't recompile it 243if isoctave 244 clear([fname(1:end-4) '.static'], [fname(1:end-4) '.dynamic']) 245else 246 clear(['+' fname(1:end-4) '/static'], ['+' fname(1:end-4) '/dynamic']) 247end 248 249[status, result] = system(command); 250if status ~= 0 || preprocessoroutput 251 disp(result) 252end 253if onlymacro 254 if preprocessoroutput 255 disp('Preprocessor stopped after macroprocessing step because of ''onlymacro'' option.'); 256 end 257 return 258end 259 260if onlyjson 261 if preprocessoroutput 262 disp('Preprocessor stopped after preprocessing step because of ''onlyjson'' option.'); 263 end 264 return; 265end 266 267% post-dynare-prerocessor-hook 268if exist(fname(1:end-4),'dir') && exist([fname(1:end-4) filesep 'hooks'],'dir') && exist([fname(1:end-4) filesep 'hooks/postprocessing.m'],'file') 269 run([fname(1:end-4) filesep 'hooks/postprocessing']) 270end 271 272% Save preprocessor result in logfile (if `no_log' option not present) 273if ~nolog 274 logname = [fname(1:end-4) '.log']; 275 fid = fopen(logname, 'w'); 276 fprintf(fid, '%s', result); 277 fclose(fid); 278end 279 280if status 281 % Should not use "error(result)" since message will be truncated if too long 282 error('Dynare: preprocessing failed') 283end 284 285if ~ isempty(find(abs(fname) == 46)) 286 fname = fname(:,1:find(abs(fname) == 46)-1) ; 287end 288 289% We need to clear the driver (and only the driver, because the "clear all" 290% within the driver will clean the rest) 291clear(['+' fname '/driver']) 292 293evalin('base',[fname '.driver']) ; 294 295end 296 297% Looks for an options list in the first non-empty line of the .mod file 298% Should be kept in sync with the function of the same name in preprocessor/src/DynareMain.cc 299% 300% Note that separating options with commas is accepted, but is deprecated (and undocumented) 301% 302% Also, the parser does not handle correctly some corner cases: for example, it 303% will fail on something like -Dfoo="a b,c" (will split at whitespace and comma) 304function opts = parse_options_line(fname) 305 opts = {}; 306 fid = fopen(fname, 'r'); 307 while true 308 firstline = fgetl(fid); 309 if firstline == -1 310 fclose(fid); 311 return 312 end 313 if ~isempty(firstline) 314 break 315 end 316 end 317 fclose(fid); 318 t = regexp(firstline, '^\s*//\s*--\+\s*options:([^\+]*)\+--', 'tokens'); 319 if isempty(t) 320 return 321 end 322 323 opts = regexp(t{1}{1}, '[^,\s]+', 'match'); 324 325 if ismember(opts, 'nopathchange') 326 warning('The ''nopathchange'' option is not taken into account when it appears at the top of ''.mod'' file. You should rather pass it on the command-line.') 327 end 328end 329