From 5784dce1ca9cbb118772ba3e5e49e1981ec67517 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Thu, 20 Dec 2018 16:18:10 +0100
Subject: [PATCH] Remove the possibility of passing the mod-file as a string in
 the first shell argument

This feature is ill-designed and no longer needed by the GUI. And is not very
useful: it is not possible to interact with the preprocessor without using the
filesystem, since the preprocessor creates many files anyways.

If we really need to reimplement such a feature, it should rather be redesigned
by reading the modfile from standard input (cin). That could be triggered by
using "-" as the filename argument (as is already done by several standard Unix
utilities).
---
 src/DynareMain.cc        | 65 ++++++++++++++++------------------------
 src/DynareMain1.cc       |  6 ++--
 src/DynareMain2.cc       |  4 +--
 src/macro/MacroDriver.cc |  8 ++---
 src/macro/MacroDriver.hh |  2 +-
 5 files changed, 35 insertions(+), 50 deletions(-)

diff --git a/src/DynareMain.cc b/src/DynareMain.cc
index 5f8f7130..f74ad6ae 100644
--- a/src/DynareMain.cc
+++ b/src/DynareMain.cc
@@ -42,9 +42,9 @@
    Splitting main() in two parts was necessary because ParsingDriver.h and MacroDriver.h can't be
    included simultaneously (because of Bison limitations).
 */
-void main2(stringstream &in, string &basename, bool debug, bool clear_all, bool clear_global,
+void main2(stringstream &in, const string &basename, bool debug, bool clear_all, bool clear_global,
            bool no_tmp_terms, bool no_log, bool no_warn, bool warn_uninit, bool console,
-           bool nograph, bool nointeractive, bool parallel, ConfigFile &config_file,
+           bool nograph, bool nointeractive, bool parallel, const ConfigFile &config_file,
            WarningConsolidation &warnings_arg, bool nostrict, bool stochastic, bool check_model_changes,
            bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode,
            LanguageOutputType lang, int params_derivs_order, bool transform_unary_ops,
@@ -52,8 +52,8 @@ void main2(stringstream &in, string &basename, bool debug, bool clear_all, bool
            bool nopreprocessoroutput, const string &mexext, const boost::filesystem::path &matlabroot,
            const boost::filesystem::path &dynareroot, bool onlymodel);
 
-void main1(string &modfile, string &basename, string &modfiletxt, bool debug, bool save_macro, string &save_macro_file,
-           bool no_line_macro, bool no_empty_line_macro, map<string, string> &defines, vector<string> &path, stringstream &macro_output);
+void main1(const string &filename, const string &basename, istream &modfile, bool debug, bool save_macro, string &save_macro_file,
+           bool no_line_macro, bool no_empty_line_macro, const map<string, string> &defines, const vector<string> &path, stringstream &macro_output);
 
 void
 usage()
@@ -68,14 +68,14 @@ usage()
   exit(EXIT_FAILURE);
 }
 
+/* Looks for an options list in the first line of the mod file (but rewind
+   the input stream afterwards */
 vector<string>
-parse_options_line(const string &modfiletxt)
+parse_options_line(istream &modfile)
 {
-  // Looks for an options list in the first line of the mod file
-
   vector<string> options;
-  auto pos = modfiletxt.find('\n');
-  string first_line{modfiletxt.substr(0, pos)};
+  string first_line;
+  getline(modfile, first_line);
 
   regex pat{"^\\s*//\\s*--\\+\\s*options:([^\\+]*)\\+--"};
   smatch matches;
@@ -88,6 +88,9 @@ parse_options_line(const string &modfiletxt)
              p != sregex_iterator{}; ++p)
           options.push_back((*p)[1]);
       }
+
+  modfile.seekg(0);
+
   return options;
 }
 
@@ -107,40 +110,16 @@ main(int argc, char **argv)
       usage();
     }
 
-  /* Construct basename (i.e. remove file extension if there is one) and put
-     contents of mod-file into a buffer */
-  string basename = argv[1];
-  string modfile, modfiletxt;
-  size_t fsc = basename.find_first_of(';');
-  if (fsc != string::npos)
+  string filename = argv[1];
+  ifstream modfile(filename, ios::binary);
+  if (modfile.fail())
     {
-      // If a semicolon is found in argv[1], treat it as the text of the modfile
-      modfile = "mod_file_passed_as_string.mod";
-      basename = "mod_file_passed_as_string";
-      modfiletxt = argv[1];
-    }
-  else
-    {
-      // If a semicolon is NOT found in argv[1], treat it as the name of the modfile
-      modfile = argv[1];
-      size_t pos = basename.find_last_of('.');
-      if (pos != string::npos)
-        basename.erase(pos);
-
-      ifstream modfile(argv[1], ios::binary);
-      if (modfile.fail())
-        {
-          cerr << "ERROR: Could not open file: " << argv[1] << endl;
-          exit(EXIT_FAILURE);
-        }
-
-      stringstream buffer;
-      buffer << modfile.rdbuf();
-      modfiletxt = buffer.str();
+      cerr << "ERROR: Could not open file: " << argv[1] << endl;
+      exit(EXIT_FAILURE);
     }
 
   // Create options list, using first line of mod-file and command line
-  vector<string> options = parse_options_line(modfiletxt);
+  vector<string> options = parse_options_line(modfile);
   for (int arg = 2; arg < argc; arg++)
     options.push_back(argv[arg]);
 
@@ -418,6 +397,12 @@ main(int argc, char **argv)
   if (!nopreprocessoroutput)
     cout << "Starting preprocessing of the model file ..." << endl;
 
+  // Construct basename (i.e. remove file extension if there is one)
+  string basename = argv[1];
+  size_t pos = basename.find_last_of('.');
+  if (pos != string::npos)
+    basename.erase(pos);
+
   WarningConsolidation warnings(no_warn);
 
   // Process config file
@@ -434,7 +419,7 @@ main(int argc, char **argv)
 
   // Do macro processing
   stringstream macro_output;
-  main1(modfile, basename, modfiletxt, debug, save_macro, save_macro_file, no_line_macro, no_empty_line_macro,
+  main1(filename, basename, modfile, debug, save_macro, save_macro_file, no_line_macro, no_empty_line_macro,
         defines, path, macro_output);
 
   if (only_macro)
diff --git a/src/DynareMain1.cc b/src/DynareMain1.cc
index cc66a4c3..c2592fdd 100644
--- a/src/DynareMain1.cc
+++ b/src/DynareMain1.cc
@@ -27,13 +27,13 @@ bool compareNewline (int i, int j) {
 }
 
 void
-main1(string &modfile, string &basename, string &modfiletxt, bool debug, bool save_macro, string &save_macro_file,
-      bool no_line_macro, bool no_empty_line_macro, map<string, string> &defines, vector<string> &path, stringstream &macro_output)
+main1(const string &filename, const string &basename, istream &modfile, bool debug, bool save_macro, string &save_macro_file,
+      bool no_line_macro, bool no_empty_line_macro, const map<string, string> &defines, const vector<string> &path, stringstream &macro_output)
 {
   // Do macro processing
   MacroDriver m;
 
-  m.parse(modfile, basename, modfiletxt, macro_output, debug, no_line_macro, defines, path);
+  m.parse(filename, basename, modfile, macro_output, debug, no_line_macro, defines, path);
   if (save_macro)
     {
       if (save_macro_file.empty())
diff --git a/src/DynareMain2.cc b/src/DynareMain2.cc
index 3f8d1179..611a4bd4 100644
--- a/src/DynareMain2.cc
+++ b/src/DynareMain2.cc
@@ -27,9 +27,9 @@
 #include "ExtendedPreprocessorTypes.hh"
 
 void
-main2(stringstream &in, string &basename, bool debug, bool clear_all, bool clear_global,
+main2(stringstream &in, const string &basename, bool debug, bool clear_all, bool clear_global,
       bool no_tmp_terms, bool no_log, bool no_warn, bool warn_uninit, bool console,
-      bool nograph, bool nointeractive, bool parallel, ConfigFile &config_file,
+      bool nograph, bool nointeractive, bool parallel, const ConfigFile &config_file,
       WarningConsolidation &warnings, bool nostrict, bool stochastic, bool check_model_changes,
       bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode,
       LanguageOutputType language, int params_derivs_order, bool transform_unary_ops,
diff --git a/src/macro/MacroDriver.cc b/src/macro/MacroDriver.cc
index 4142030c..5b341fd2 100644
--- a/src/macro/MacroDriver.cc
+++ b/src/macro/MacroDriver.cc
@@ -27,12 +27,12 @@
 #include "MacroDriver.hh"
 
 void
-MacroDriver::parse(const string &f, const string &fb, const string &modfiletxt,
+MacroDriver::parse(const string &file_arg, const string &basename_arg, istream &modfile,
                    ostream &out, bool debug, bool no_line_macro_arg, map<string, string> defines,
                    vector<string> path)
 {
-  file = f;
-  basename = fb;
+  file = file_arg;
+  basename = basename_arg;
   no_line_macro = no_line_macro_arg;
 
   /*
@@ -55,7 +55,7 @@ MacroDriver::parse(const string &f, const string &fb, const string &modfiletxt,
         else
           file_with_endl << "@#define " << define.first << " = \"" << define.second << "\"" << endl;
       }
-  file_with_endl << modfiletxt << endl;
+  file_with_endl << modfile.rdbuf() << endl;
 
   lexer = make_unique<MacroFlex>(&file_with_endl, &out, no_line_macro, path);
   lexer->set_debug(debug);
diff --git a/src/macro/MacroDriver.hh b/src/macro/MacroDriver.hh
index 1d1e9d28..d1e3657b 100644
--- a/src/macro/MacroDriver.hh
+++ b/src/macro/MacroDriver.hh
@@ -226,7 +226,7 @@ public:
 
   //! Starts parsing a file, returns output in out
   /*! \param no_line_macro should we omit the @#line statements ? */
-  void parse(const string &f, const string &fb, const string &modfiletxt, ostream &out, bool debug, bool no_line_macro_arg,
+  void parse(const string &file_arg, const string &basename_arg, istream &modfile, ostream &out, bool debug, bool no_line_macro_arg,
              map<string, string> defines, vector<string> path);
 
   //! Name of main file being parsed
-- 
GitLab