Merge "Fix 'make install'."
[alexxy/gromacs.git] / src / gromacs / utility / file.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief
33  * Implements gmx::File.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_utility
37  */
38 #include "file.h"
39
40 #include <cerrno>
41 #include <cstdio>
42
43 #include <string>
44 #include <vector>
45
46 #include "gromacs/utility/exceptions.h"
47 #include "gromacs/utility/gmxassert.h"
48 #include "gromacs/utility/format.h"
49
50 namespace gmx
51 {
52
53 File::File(const char *filename, const char *mode)
54     : fp_(NULL)
55 {
56     open(filename, mode);
57 }
58
59 File::File(const std::string &filename, const char *mode)
60     : fp_(NULL)
61 {
62     open(filename, mode);
63 }
64
65 File::~File()
66 {
67     if (fp_ != NULL)
68     {
69         if (fclose(fp_) != 0)
70         {
71             // TODO: Log the error somewhere
72         }
73     }
74 }
75
76 void File::open(const char *filename, const char *mode)
77 {
78     GMX_RELEASE_ASSERT(fp_ == NULL,
79                        "Attempted to open the same file object twice");
80     // TODO: Port all necessary functionality from ffopen() here.
81     fp_ = fopen(filename, mode);
82     if (fp_ == NULL)
83     {
84         GMX_THROW_WITH_ERRNO(
85                 FileIOError(formatString("Could not open file '%s'", filename)),
86                 "fopen", errno);
87     }
88 }
89
90 void File::open(const std::string &filename, const char *mode)
91 {
92     open(filename.c_str(), mode);
93 }
94
95 void File::close()
96 {
97     GMX_RELEASE_ASSERT(fp_ != NULL,
98                        "Attempted to close a file object that is not open");
99     bool bOk = (fclose(fp_) == 0);
100     fp_ = NULL;
101     if (!bOk)
102     {
103         GMX_THROW_WITH_ERRNO(
104                 FileIOError("Error while closing file"), "fclose", errno);
105     }
106 }
107
108 FILE *File::handle()
109 {
110     GMX_RELEASE_ASSERT(fp_ != NULL,
111                        "Attempted to access a file object that is not open");
112     return fp_;
113 }
114
115 void File::readBytes(void *buffer, size_t bytes)
116 {
117     GMX_RELEASE_ASSERT(fp_ != NULL,
118                        "Attempted to access a file object that is not open");
119     errno = 0;
120     // TODO: Retry based on errno or something else?
121     size_t bytesRead = std::fread(buffer, 1, bytes, fp_);
122     if (bytesRead != bytes)
123     {
124         if (feof(fp_))
125         {
126             GMX_THROW(FileIOError("Premature end of file"));
127         }
128         else
129         {
130             GMX_THROW_WITH_ERRNO(FileIOError("Error while reading file"),
131                                  "fread", errno);
132         }
133     }
134 }
135
136 // static
137 std::string File::readToString(const char *filename)
138 {
139     File file(filename, "r");
140     FILE *fp = file.handle();
141
142     // TODO: Full error checking.
143     std::fseek(fp, 0L, SEEK_END);
144     long len = std::ftell(fp);
145     std::fseek(fp, 0L, SEEK_SET);
146
147     std::vector<char> data(len);
148     file.readBytes(&data[0], len);
149     std::string result(&data[0], len);
150
151     file.close();
152     return result;
153 }
154
155 // static
156 std::string File::readToString(const std::string &filename)
157 {
158     return readToString(filename.c_str());
159 }
160
161 } // namespace gmx