Merge branch release-2016 into release-2018
[gromacs.git] / src / gromacs / utility / filestream.cpp
blobb24f687b27a50b7546a37973ca6806ef1e7d72c3
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2015,2017, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
35 /*! \internal \file
36 * \brief
37 * Implements classes from filestream.h.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_utility
42 #include "gmxpre.h"
44 #include "filestream.h"
46 #include "config.h"
48 #include <cerrno>
49 #include <cstdio>
51 #ifdef HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
55 #include "gromacs/utility/exceptions.h"
56 #include "gromacs/utility/gmxassert.h"
57 #include "gromacs/utility/stringutil.h"
59 namespace gmx
62 namespace
65 //! Helper function for implementing readLine() for input streams.
66 bool readLineImpl(FILE *fp, std::string *line)
68 line->clear();
69 const size_t bufsize = 256;
70 std::string result;
71 char buf[bufsize];
72 buf[0] = '\0';
73 while (std::fgets(buf, bufsize, fp) != nullptr)
75 const size_t length = std::strlen(buf);
76 result.append(buf, length);
77 if (length < bufsize - 1 || buf[length - 1] == '\n')
79 break;
82 if (std::ferror(fp))
84 GMX_THROW_WITH_ERRNO(FileIOError("Error while reading file"),
85 "fgets", errno);
87 *line = result;
88 return !result.empty() || !std::feof(fp);
91 } // namespace
93 namespace internal
96 /********************************************************************
97 * FileStreamImpl
100 class FileStreamImpl
102 public:
103 explicit FileStreamImpl(FILE *fp)
104 : fp_(fp), bClose_(false)
107 FileStreamImpl(const char *filename, const char *mode)
108 : fp_(nullptr), bClose_(true)
110 fp_ = std::fopen(filename, mode);
111 if (fp_ == nullptr)
113 GMX_THROW_WITH_ERRNO(
114 FileIOError(formatString("Could not open file '%s'", filename)),
115 "fopen", errno);
118 ~FileStreamImpl()
120 if (fp_ != nullptr && bClose_)
122 if (std::fclose(fp_) != 0)
124 // TODO: Log the error somewhere
129 FILE *handle()
131 GMX_RELEASE_ASSERT(fp_ != nullptr,
132 "Attempted to access a file object that is not open");
133 return fp_;
136 void close()
138 GMX_RELEASE_ASSERT(fp_ != nullptr,
139 "Attempted to close a file object that is not open");
140 GMX_RELEASE_ASSERT(bClose_,
141 "Attempted to close a file object that should not be");
142 const bool bOk = (std::fclose(fp_) == 0);
143 fp_ = nullptr;
144 if (!bOk)
146 GMX_THROW_WITH_ERRNO(
147 FileIOError("Error while closing file"), "fclose", errno);
151 private:
152 //! File handle for this object (NULL if the stream has been closed).
153 FILE *fp_;
154 //! Whether \p fp_ should be closed by this object.
155 bool bClose_;
158 } // namespace internal
160 using internal::FileStreamImpl;
162 /********************************************************************
163 * StandardInputStream
166 bool StandardInputStream::isInteractive() const
168 #ifdef HAVE_UNISTD_H
169 return isatty(fileno(stdin));
170 #else
171 return true;
172 #endif
175 bool StandardInputStream::readLine(std::string *line)
177 return readLineImpl(stdin, line);
180 // static
181 StandardInputStream &StandardInputStream::instance()
183 static StandardInputStream stdinObject;
184 return stdinObject;
187 /********************************************************************
188 * TextInputFile
191 // static
192 FILE *TextInputFile::openRawHandle(const char *filename)
194 FILE *fp = fopen(filename, "r");
195 if (fp == nullptr)
197 GMX_THROW_WITH_ERRNO(
198 FileIOError(formatString("Could not open file '%s'", filename)),
199 "fopen", errno);
201 return fp;
204 // static
205 FILE *TextInputFile::openRawHandle(const std::string &filename)
207 return openRawHandle(filename.c_str());
210 TextInputFile::TextInputFile(const std::string &filename)
211 : impl_(new FileStreamImpl(filename.c_str(), "r"))
215 TextInputFile::TextInputFile(FILE *fp)
216 : impl_(new FileStreamImpl(fp))
220 TextInputFile::~TextInputFile()
224 FILE *TextInputFile::handle()
226 return impl_->handle();
229 bool TextInputFile::readLine(std::string *line)
231 return readLineImpl(impl_->handle(), line);
234 void TextInputFile::close()
236 impl_->close();
239 /********************************************************************
240 * TextOutputFile
243 TextOutputFile::TextOutputFile(const std::string &filename)
244 : impl_(new FileStreamImpl(filename.c_str(), "w"))
248 TextOutputFile::TextOutputFile(FILE *fp)
249 : impl_(new FileStreamImpl(fp))
253 TextOutputFile::~TextOutputFile()
257 void TextOutputFile::write(const char *str)
259 if (std::fprintf(impl_->handle(), "%s", str) < 0)
261 GMX_THROW_WITH_ERRNO(FileIOError("Writing to file failed"),
262 "fprintf", errno);
266 void TextOutputFile::close()
268 impl_->close();
271 // static
272 TextOutputFile &TextOutputFile::standardOutput()
274 static TextOutputFile stdoutObject(stdout);
275 return stdoutObject;
278 // static
279 TextOutputFile &TextOutputFile::standardError()
281 static TextOutputFile stderrObject(stderr);
282 return stderrObject;
285 } // namespace gmx