Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

colvarproxy_io.C

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 
00003 // This file is part of the Collective Variables module (Colvars).
00004 // The original version of Colvars and its updates are located at:
00005 // https://github.com/Colvars/colvars
00006 // Please update all Colvars source files before making any changes.
00007 // If you wish to distribute your changes, please submit them to the
00008 // Colvars repository at GitHub.
00009 
00010 // Using access() to check if a file exists (until we can assume C++14/17)
00011 #if !defined(_WIN32) || defined(__CYGWIN__)
00012 #include <unistd.h>
00013 #endif
00014 #if defined(_WIN32)
00015 #include <io.h>
00016 #endif
00017 
00018 #include <cerrno>
00019 #include <cstdio>
00020 
00021 #include <list>
00022 #include <map>
00023 #include <sstream>
00024 #include <fstream>
00025 
00026 #include "colvarmodule.h"
00027 #include "colvarproxy_io.h"
00028 
00029 
00030 colvarproxy_io::colvarproxy_io()
00031 {
00032   input_buffer_ = NULL;
00033   restart_frequency_engine = 0;
00034   input_stream_error_ = new std::istringstream();
00035   input_stream_error_->setstate(std::ios::badbit);
00036   output_stream_error_ = new std::ostringstream();
00037   output_stream_error_->setstate(std::ios::badbit);
00038 }
00039 
00040 
00041 colvarproxy_io::~colvarproxy_io()
00042 {
00043   delete input_stream_error_;
00044   close_input_streams();
00045   delete output_stream_error_;
00046   close_output_streams();
00047 }
00048 
00049 
00050 bool colvarproxy_io::io_available()
00051 {
00052   return false;
00053 }
00054 
00055 
00056 int colvarproxy_io::get_frame(long int&)
00057 {
00058   return COLVARS_NOT_IMPLEMENTED;
00059 }
00060 
00061 
00062 int colvarproxy_io::set_frame(long int)
00063 {
00064   return COLVARS_NOT_IMPLEMENTED;
00065 }
00066 
00067 
00068 int colvarproxy_io::backup_file(char const *filename)
00069 {
00070   // Simplified version of NAMD_file_exists()
00071   int exit_code;
00072   do {
00073 #if defined(_WIN32) && !defined(__CYGWIN__)
00074     // We could use _access_s here, but it is probably too new
00075     exit_code = _access(filename, 00);
00076 #else
00077     exit_code = access(filename, F_OK);
00078 #endif
00079   } while ((exit_code != 0) && (errno == EINTR));
00080   if (exit_code != 0) {
00081     if (errno == ENOENT) {
00082       // File does not exist
00083       return COLVARS_OK;
00084     } else {
00085       return cvm::error("Unknown error while checking if file \""+
00086                         std::string(filename)+"\" exists.\n", COLVARS_ERROR);
00087     }
00088   }
00089 
00090   // The file exists, then rename it
00091   if (std::string(filename).rfind(std::string(".colvars.state")) !=
00092       std::string::npos) {
00093     return rename_file(filename, (std::string(filename)+".old").c_str());
00094   } else {
00095     return rename_file(filename, (std::string(filename)+".BAK").c_str());
00096   }
00097 }
00098 
00099 
00100 int colvarproxy_io::remove_file(char const *filename)
00101 {
00102   int error_code = COLVARS_OK;
00103 #if defined(_WIN32) && !defined(__CYGWIN__)
00104   // Because the file may be open by other processes, rename it to filename.old
00105   std::string const renamed_file(std::string(filename)+".old");
00106   // It may still be there from an interrupted run, so remove it to be safe
00107   std::remove(renamed_file.c_str());
00108   int rename_exit_code = 0;
00109   while ((rename_exit_code = std::rename(filename,
00110                                          renamed_file.c_str())) != 0) {
00111     if (errno == EINTR) continue;
00112     error_code |= COLVARS_FILE_ERROR;
00113     break;
00114   }
00115   // Ask to remove filename.old, but ignore any errors raised
00116   std::remove(renamed_file.c_str());
00117 #else
00118   if (std::remove(filename)) {
00119     if (errno != ENOENT) {
00120       error_code |= COLVARS_FILE_ERROR;
00121     }
00122   }
00123 #endif
00124   if (error_code != COLVARS_OK) {
00125     return cvm::error("Error: in removing file \""+std::string(filename)+
00126                       "\".\n.",
00127                       error_code);
00128   }
00129   return COLVARS_OK;
00130 }
00131 
00132 
00133 int colvarproxy_io::rename_file(char const *filename, char const *newfilename)
00134 {
00135   int error_code = COLVARS_OK;
00136 #if defined(_WIN32) && !defined(__CYGWIN__)
00137   // On straight Windows, must remove the destination before renaming it
00138   error_code |= remove_file(newfilename);
00139 #endif
00140   int rename_exit_code = 0;
00141   while ((rename_exit_code = std::rename(filename, newfilename)) != 0) {
00142     if (errno == EINTR) continue;
00143     // Call log() instead of error to allow the next try
00144     cvm::log("Error: in renaming file \""+std::string(filename)+"\" to \""+
00145              std::string(newfilename)+"\".\n.");
00146     error_code |= COLVARS_FILE_ERROR;
00147     if (errno == EXDEV) continue;
00148     break;
00149   }
00150   return rename_exit_code ? error_code : COLVARS_OK;
00151 }
00152 
00153 
00154 std::istream &colvarproxy_io::input_stream(std::string const &input_name,
00155                                            std::string const description,
00156                                            bool error_on_fail)
00157 {
00158   if (!io_available()) {
00159     cvm::error("Error: trying to access an input file/channel "
00160                "from the wrong thread.\n", COLVARS_BUG_ERROR);
00161     return *input_stream_error_;
00162   }
00163 
00164   if (colvarproxy_io::input_stream_exists(input_name)) {
00165     return *(input_streams_[input_name]);
00166   }
00167 
00168   // Using binary to work around differences in line termination conventions
00169   // See https://github.com/Colvars/colvars/commit/8236879f7de4
00170   input_streams_[input_name] = new std::ifstream(input_name.c_str(),
00171                                                  std::ios::binary);
00172 
00173   if (input_streams_[input_name]->fail() && error_on_fail) {
00174     cvm::error("Error: cannot open "+description+" \""+input_name+"\".\n",
00175                COLVARS_FILE_ERROR);
00176   }
00177 
00178   return *(input_streams_[input_name]);
00179 }
00180 
00181 
00182 bool colvarproxy_io::input_stream_exists(std::string const &input_name)
00183 {
00184   return (input_streams_.count(input_name) > 0);
00185 }
00186 
00187 
00188 int colvarproxy_io::close_input_stream(std::string const &input_name)
00189 {
00190   if (colvarproxy_io::input_stream_exists(input_name)) {
00191     delete input_streams_[input_name];
00192     input_streams_.erase(input_name);
00193     return COLVARS_OK;
00194   }
00195   return cvm::error("Error: input file/channel \""+input_name+
00196                     "\" does not exist.\n", COLVARS_FILE_ERROR);
00197 }
00198 
00199 
00200 int colvarproxy_io::close_input_streams()
00201 {
00202   for (std::map<std::string, std::istream *>::iterator ii = input_streams_.begin();
00203        ii != input_streams_.end();
00204        ii++) {
00205     delete ii->second;
00206   }
00207   input_streams_.clear();
00208   return COLVARS_OK;
00209 }
00210 
00211 
00212 std::ostream & colvarproxy_io::output_stream(std::string const &output_name,
00213                                              std::string const description)
00214 {
00215   if (cvm::debug()) {
00216     cvm::log("Using colvarproxy_io::output_stream()\n");
00217   }
00218 
00219   if (!io_available()) {
00220     cvm::error("Error: trying to access an output file/channel "
00221                "from the wrong thread.\n", COLVARS_BUG_ERROR);
00222     return *output_stream_error_;
00223   }
00224 
00225   if (colvarproxy_io::output_stream_exists(output_name)) {
00226     return *(output_streams_[output_name]);
00227   }
00228 
00229   backup_file(output_name.c_str());
00230 
00231   output_streams_[output_name] = new std::ofstream(output_name.c_str());
00232   if (!*(output_streams_[output_name])) {
00233     cvm::error("Error: cannot write to "+description+" \""+output_name+"\".\n",
00234                COLVARS_FILE_ERROR);
00235   }
00236 
00237   return *(output_streams_[output_name]);
00238 }
00239 
00240 
00241 bool colvarproxy_io::output_stream_exists(std::string const &output_name)
00242 {
00243   return (output_streams_.count(output_name) > 0);
00244 }
00245 
00246 
00247 int colvarproxy_io::flush_output_stream(std::string const &output_name)
00248 {
00249   if (!io_available()) {
00250     // No-op
00251     return COLVARS_OK;
00252   }
00253 
00254   if (colvarproxy_io::output_stream_exists(output_name)) {
00255     (dynamic_cast<std::ofstream *>(output_streams_[output_name]))->flush();
00256     return COLVARS_OK;
00257   }
00258 
00259   return COLVARS_OK;
00260 }
00261 
00262 
00263 int colvarproxy_io::flush_output_streams()
00264 {
00265   if (!io_available()) {
00266     return COLVARS_OK;
00267   }
00268 
00269   for (std::map<std::string, std::ostream *>::iterator osi = output_streams_.begin();
00270        osi != output_streams_.end();
00271        osi++) {
00272     (dynamic_cast<std::ofstream *>(osi->second))->flush();
00273   }
00274 
00275   return COLVARS_OK;
00276 }
00277 
00278 
00279 int colvarproxy_io::close_output_stream(std::string const &output_name)
00280 {
00281   if (!io_available()) {
00282     return cvm::error("Error: trying to access an output file/channel "
00283                       "from the wrong thread.\n", COLVARS_BUG_ERROR);
00284   }
00285 
00286   if (colvarproxy_io::output_stream_exists(output_name)) {
00287     (dynamic_cast<std::ofstream *>(output_streams_[output_name]))->close();
00288     delete output_streams_[output_name];
00289     output_streams_.erase(output_name);
00290   }
00291 
00292   return COLVARS_OK;
00293 }
00294 
00295 
00296 int colvarproxy_io::close_output_streams()
00297 {
00298   if (! io_available()) {
00299     return COLVARS_OK;
00300   }
00301 
00302   for (std::map<std::string, std::ostream *>::iterator osi = output_streams_.begin();
00303        osi != output_streams_.end();
00304        osi++) {
00305     (dynamic_cast<std::ofstream *>(osi->second))->close();
00306   }
00307   output_streams_.clear();
00308 
00309   return COLVARS_OK;
00310 }

Generated on Wed Oct 9 02:42:18 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002