From a0ede2e51983f3fadd3162d96b397756b892854c Mon Sep 17 00:00:00 2001 From: Francois Bleibel <fbleibel@gmail.com> Date: Mon, 4 Oct 2010 16:04:36 +0900 Subject: [PATCH] Added import functions for scripts to dynamic-graph (from Thomas Moulard) --- include/CMakeLists.txt | 7 + .../import-default-paths.h.cmake | 28 ++ include/dynamic-graph/import.h | 66 +++++ src/CMakeLists.txt | 1 + src/dgraph/import.cpp | 265 ++++++++++++++++++ src/dgraph/interpreter.cpp | 4 + 6 files changed, 371 insertions(+) create mode 100644 include/dynamic-graph/import-default-paths.h.cmake create mode 100644 include/dynamic-graph/import.h create mode 100644 src/dgraph/import.cpp diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 80c21da..6a8d219 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -1,3 +1,8 @@ +# Generate header with default script directory. +SET(DG_IMPORT_DEFAULT_PATHS \"${CMAKE_INSTALL_PREFIX}/script\") +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}/import-default-paths.h.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}/import-default-paths.h) + SET(${PROJECT_NAME}_HEADERS contiifstream.h debug.h @@ -10,6 +15,8 @@ interpreter.h interpreter-helper.h plugin-loader.h pool.h +import.h +import-default-paths.h exception-abstract.h exception-factory.h diff --git a/include/dynamic-graph/import-default-paths.h.cmake b/include/dynamic-graph/import-default-paths.h.cmake new file mode 100644 index 0000000..5b26156 --- /dev/null +++ b/include/dynamic-graph/import-default-paths.h.cmake @@ -0,0 +1,28 @@ +/* -*- c++ -*- + * + * Copyright 2010, + * François Bleibel, + * Olivier Stasse, + * + * CNRS/AIST + * + * This file is part of dynamic-graph. + * dynamic-graph is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * dynamic-graph 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 Lesser General Public License for more details. You should + * have received a copy of the GNU Lesser General Public License along + * with dynamic-graph. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef DG_FACTORY_COMMAND_IMPORT_DEFAULT_PATHS_H +# define DG_FACTORY_COMMAND_IMPORT_DEFAULT_PATHS_H + +/// Default script path as known by CMake at configure time. +# define DG_IMPORT_DEFAULT_PATHS @DG_IMPORT_DEFAULT_PATHS@ + +#endif //! SOT_FACTORY_COMMAND_IMPORT_DEFAULT_PATHS_H diff --git a/include/dynamic-graph/import.h b/include/dynamic-graph/import.h new file mode 100644 index 0000000..3491d00 --- /dev/null +++ b/include/dynamic-graph/import.h @@ -0,0 +1,66 @@ +/* + * Copyright 2010, + * François Bleibel, + * Olivier Stasse, + * + * CNRS/AIST + * + * This file is part of sot-core. + * sot-core is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * sot-core 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 Lesser General Public License for more details. You should + * have received a copy of the GNU Lesser General Public License along + * with sot-core. If not, see <http://www.gnu.org/licenses/>. + */ + +// -*- c++ -*- +#ifndef SOT_FACTORY_COMMAND_IMPORT_H +# define SOT_FACTORY_COMMAND_IMPORT_H +# include <iosfwd> +# include <string> +# include <vector> + +namespace dynamicgraph +{ + class Interpreter; + namespace command + { + namespace + { + extern std::vector<std::string> importPaths; + } // end of anonymous namespace. + + /// \brief Implement sot interpretor import command. + /// + /// The import command sources a file and searches automatically + /// for it in the importPaths. + void import (Interpreter& interpretor, + const std::string& cmdLine, + std::istringstream& cmdArg, + std::ostream& os); + + /// \brief Implement sot interpretor pushImportPaths command. + /// + /// Append a path to importPaths. + void pushImportPaths (Interpreter& interpretor, + const std::string& cmdLine, + std::istringstream& cmdArg, + std::ostream& os); + + /// \brief Implement sot interpretor popImportPaths command. + /// + /// Drop the last path of importPaths. + void popImportPaths (Interpreter& interpretor, + const std::string& cmdLine, + std::istringstream& cmdArg, + std::ostream& os); + + } // end of namespace command. +} // end of namespace sot. + +#endif //! SOT_FACTORY_COMMAND_IMPORT_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 77f7d96..26c3c3f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,7 @@ ADD_LIBRARY(${LIBRARY_NAME} dgraph/interpreter-helper.cpp dgraph/plugin-loader.cpp dgraph/pool.cpp + dgraph/import.cpp exception/exception-abstract.cpp exception/exception-factory.cpp diff --git a/src/dgraph/import.cpp b/src/dgraph/import.cpp new file mode 100644 index 0000000..111d7b5 --- /dev/null +++ b/src/dgraph/import.cpp @@ -0,0 +1,265 @@ +/* + * Copyright 2010, + * François Bleibel, + * Olivier Stasse, + * + * CNRS/AIST + * + * This file is part of sot-core. + * sot-core is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * sot-core 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 Lesser General Public License for more details. You should + * have received a copy of the GNU Lesser General Public License along + * with sot-core. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <cassert> + +#include <iostream> +#include <fstream> +#include <sstream> +#include <string> +#include <vector> + +#include <boost/algorithm/string.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> + +#include <dynamic-graph/import-default-paths.h> +#include <dynamic-graph/import.h> +#include <dynamic-graph/debug.h> +#include <dynamic-graph/exception-abstract.h> +#include <dynamic-graph/exception-factory.h> +#include <dynamic-graph/interpreter.h> + +static const char* ENV_DG_PATH = "DG_PATH"; + +namespace dynamicgraph +{ + namespace command + { + namespace + { + /// Initialize import paths list (called during static initialization). + std::vector<std::string> initializePaths (); + + /// \brief Import paths list. + /// + /// This vector of string is similar to Unix variables such as + /// PATH. It contains all paths that are used to search when + /// importing a script. + /// + /// The look-up is made from right to left: + /// + /// importPaths = A:B:C + /// + /// When typing ``import foo'', C will be searched first then B + /// and A. The search stops when the file is found. + std::vector<std::string> importPaths = initializePaths (); + + /// Search for a module. + /// + /// Returns the module full absolute path or an empty string if + /// it cannot be found. + std::string searchModule (const std::string& module); + + /// \brief Remove quotes form a string. + /// + /// Transform strings such as "foo" or 'foo' into foo. + void removeQuotes (std::string& msg); + + std::vector<std::string> initializePaths () + { + std::vector<std::string> importPaths; + importPaths.push_back (DG_IMPORT_DEFAULT_PATHS); + + // Search for the environment variable value. + char* ScriptPath = getenv (ENV_DG_PATH); + if (!ScriptPath) + return importPaths; + + // Split the environment variable. + std::string environmentSeparator; + + // On Microsoft Windows, environment variables are splitted along + // the ``;'' character. It is ``:'' on *NIX systems. +#if defined _WIN32 || defined __CYGWIN__ + environmentSeparator = ";"; +#else + environmentSeparator = ":"; +#endif // defined _WIN32 || defined __CYGWIN__ + + std::vector<std::string> splittedEnvironmentVariable; + boost::split (splittedEnvironmentVariable, ScriptPath, + boost::is_any_of (environmentSeparator)); + + // Insert it back. + std::back_insert_iterator<std::vector<std::string> > bi (importPaths); + std::copy (splittedEnvironmentVariable.begin (), + splittedEnvironmentVariable.end (), bi); + return importPaths; + } + + std::string searchModule (const std::string& module) + { + // Make sure the traversal is right to left to enforce + // correct priorities. + typedef std::vector<std::string>::const_reverse_iterator citer_t; + for (citer_t it = importPaths.rbegin (); + it != importPaths.rend (); ++it) + { + const std::string& path = *it; + + assert (!path.empty ()); + + std::string filename (path); + if (filename[filename.length () - 1] != '/') + filename += "/"; + filename += module; + std::ifstream file (filename.c_str ()); + if (file.is_open () && file.good ()) + return filename; + } + return std::string (); + } + + void removeQuotes (std::string& msg) + { + if ((msg[0] == '"' && msg[msg.length () - 1] == '"') + || (msg[0] == '\'' && msg[msg.length () - 1] == '\'')) + msg = msg.substr (1, msg.length () - 2); + } + } // end of anonymous namespace. + + void import (dynamicgraph::Interpreter& interpreter, + const std::string& cmdLine, + std::istringstream& cmdArg, + std::ostream& os) + { + if (cmdLine == "help") + { + os << " - import <script.txt>\t\t\t\tImport the script." + << std::endl + << "\t\t\t\tBehaves like run but searches for files" + << " in default script directories." + << std::endl; + return; + } + + dgDEBUGIN(15); + + std::string module; + cmdArg >> module; + + // Get rid of quotes. + removeQuotes (module); + + std::string filename = searchModule (module); + std::ifstream file (filename.c_str ()); + if (filename.empty () || !file.is_open () || !file.good ()) + { + std::string scriptDirectories; + + if (importPaths.empty ()) + scriptDirectories = "empty"; + else + { + BOOST_FOREACH (const std::string& path, importPaths) + { + scriptDirectories += path; + scriptDirectories += ", "; + } + scriptDirectories = scriptDirectories.substr + (0, scriptDirectories.length () - 2); + } + + boost::format fmt + ("failed to import module ``%1%'' (import paths: %2%)."); + fmt % module; + fmt % scriptDirectories; + DG_THROW ExceptionFactory + (ExceptionFactory::READ_FILE, fmt.str ()); + return; + } + + int lineIdx = 0; + try + { + while (file.good ()) + { + ++lineIdx; + dgDEBUGIN (15); + + std::string line; + std::getline (file, line); + if (line.empty ()) + continue; + + std::istringstream iss (line); + std::string currentCmdName; + std::string currentCmdArgs; + if (iss >> currentCmdName) + { + std::getline (iss, currentCmdArgs); + boost::format fmt ("Run ``%1%'' with args ``%2%''"); + fmt % currentCmdName % currentCmdArgs; + dgDEBUG(25) << fmt.str () << std::endl; + std::istringstream issArgs (currentCmdArgs); + interpreter.cmd (currentCmdName, issArgs, os); + } + dgDEBUGOUT (15); + } + } + catch (ExceptionAbstract& exc) + { + // FIXME: come on... + std::string& msg = const_cast<std::string&> (exc.getStringMessage ()); + boost::format fmt (" (in line %1% of file ``%2%'')"); + fmt % lineIdx % filename; + msg = msg + fmt.str(); + throw; + } + + dgDEBUGOUT(15); + } + + void pushImportPaths (dynamicgraph::Interpreter& interpreter, + const std::string& cmdLine, + std::istringstream& cmdArg, + std::ostream& os) + { + if (cmdLine == "help") + { + os << " - pushImportPaths <path>\t\t\t\tAdd path to default directories." + << std::endl; + return; + } + std::string path; + cmdArg >> path; + removeQuotes (path); + + importPaths.push_back (path); + } + + void popImportPaths (dynamicgraph::Interpreter& interpreter, + const std::string& cmdLine, + std::istringstream& cmdArg, + std::ostream& os) + { + if (cmdLine == "help") + { + os << " - popImportPaths <path>\t\t\t\tDrop path from default directories." + << std::endl; + return; + } + if (!importPaths.empty ()) + importPaths.pop_back (); + } + + } // end of namespace command. +} // end of namespace sot. diff --git a/src/dgraph/interpreter.cpp b/src/dgraph/interpreter.cpp index 781c144..d4aa0ae 100644 --- a/src/dgraph/interpreter.cpp +++ b/src/dgraph/interpreter.cpp @@ -26,6 +26,7 @@ #include <dynamic-graph/interpreter.h> #include <dynamic-graph/plugin-loader.h> #include <dynamic-graph/debug.h> +#include <dynamic-graph/import.h> /* --- STD --- */ using namespace std; @@ -51,6 +52,9 @@ Interpreter( PluginLoader* dl__ ) registerFunction("set",boost::bind(&Interpreter::cmdSetSignal,this,_1,_2,_3)); registerFunction("get",boost::bind(&Interpreter::cmdGetSignal,this,_1,_2,_3)); registerFunction("compute",boost::bind(&Interpreter::cmdComputeSignal,this,_1,_2,_3)); + registerFunction("import",boost::bind(&dynamicgraph::command::import,boost::ref(*this),_1,_2,_3)); + registerFunction("pushImportPaths",boost::bind(&dynamicgraph::command::pushImportPaths,boost::ref(*this),_1,_2,_3)); + registerFunction("popImportPaths",boost::bind(&dynamicgraph::command::popImportPaths,boost::ref(*this),_1,_2,_3)); prompt = PROMPT_DEFAULT; initDone = true; } -- GitLab