Apply clang-format to source tree
[alexxy/gromacs.git] / src / gromacs / utility / datafilefinder.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2014,2015,2018,2019, 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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 /*! \file
36  * \brief
37  * Declares gmx::DataFileFinder and related classes.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \inpublicapi
41  * \ingroup module_utility
42  */
43 #ifndef GMX_UTILITY_LIBFILEFINDER_H
44 #define GMX_UTILITY_LIBFILEFINDER_H
45
46 #include <cstdio>
47
48 #include <string>
49 #include <vector>
50
51 #include "gromacs/utility/classhelpers.h"
52 #include "gromacs/utility/fileptr.h"
53
54 namespace gmx
55 {
56
57 class DataFileFinder;
58
59 /*! \brief
60  * Search parameters for DataFileFinder.
61  *
62  * This class implements a named parameter idiom for DataFileFinder::findFile()
63  * and DataFileFinder::openFile() to support an easily readable and
64  * customizable way of searching data files.
65  *
66  * By default, the search first considers the current directory, followed by
67  * specified and default data directories, and an exception is thrown if the
68  * file could not be found.
69  * To skip searching in the current directory, use includeCurrentDir().
70  *
71  * Methods in this class do not throw.
72  *
73  * \inpublicapi
74  * \ingroup module_utility
75  */
76 class DataFileOptions
77 {
78 public:
79     /*! \brief
80      * Constructs default options for searching for a file with the
81      * specified name.
82      *
83      * \param[in] filename  File name to search for.
84      *
85      * This constructor is not explicit to allow passing a simple string to
86      * DataFileFinder methods to search for the string with the default
87      * parameters.
88      */
89     DataFileOptions(const char* filename) : filename_(filename), bCurrentDir_(true), bThrow_(true)
90     {
91     }
92     //! \copydoc DataFileOptions(const char *)
93     DataFileOptions(const std::string& filename) :
94         filename_(filename.c_str()),
95         bCurrentDir_(true),
96         bThrow_(true)
97     {
98     }
99
100     //! Sets whether to search first in the current (working) directory.
101     DataFileOptions& includeCurrentDir(bool bInclude)
102     {
103         bCurrentDir_ = bInclude;
104         return *this;
105     }
106     //! Sets whether an exception is thrown if the file could not be found.
107     DataFileOptions& throwIfNotFound(bool bThrow)
108     {
109         bThrow_ = bThrow;
110         return *this;
111     }
112
113 private:
114     const char* filename_;
115     bool        bCurrentDir_;
116     bool        bThrow_;
117
118     /*! \brief
119      * Needed to access the members without otherwise unnecessary accessors.
120      */
121     friend class DataFileFinder;
122 };
123
124 /*! \brief
125  * Information about a data file found by DataFileFinder::enumerateFiles().
126  *
127  * \inpublicapi
128  * \ingroup module_utility
129  */
130 struct DataFileInfo
131 {
132     //! Initializes the structure with given values.
133     DataFileInfo(const std::string& dir, const std::string& name, bool bDefault) :
134         dir(dir),
135         name(name),
136         bFromDefaultDir(bDefault)
137     {
138     }
139
140     /*! \brief
141      * Directory from which the file was found.
142      *
143      * If the file was found from the current directory, this will be `"."`.
144      * In other cases, this will be a full path (except if the user-provided
145      * search path contains relative paths).
146      */
147     std::string dir;
148     /*! \brief
149      * Name of the file without any directory name.
150      */
151     std::string name;
152     /*! \brief
153      * Whether the file was found from the default directory.
154      *
155      * If `true`, the file was found from the default installation data
156      * directory, not from the current directory or any user-provided (through
157      * DataFileFinder::setSearchPathFromEnv()) location.
158      * \todo
159      * Consider replacing with an enum that identifies the source (current dir,
160      * GMXLIB, default).
161      */
162     bool bFromDefaultDir;
163 };
164
165 /*! \brief
166  * Searches data files from a set of paths.
167  *
168  * \inpublicapi
169  * \ingroup module_utility
170  */
171 class DataFileFinder
172 {
173 public:
174     /*! \brief
175      * Constructs a default data file finder.
176      *
177      * The constructed finder searches only in the directory specified by
178      * the global program context (see IProgramContext), and
179      * optionally in the current directory.
180      *
181      * Does not throw.
182      */
183     DataFileFinder();
184     ~DataFileFinder();
185
186     /*! \brief
187      * Adds search path from an environment variable.
188      *
189      * \param[in] envVarName  Name of the environment variable to use.
190      * \throws std::bad_alloc if out of memory.
191      *
192      * If the specified environment variable is set, it is interpreted like
193      * a `PATH` environment variable on the platform (split at appropriate
194      * separators), and each path found is added to the search path this
195      * finder searches.  The added paths take precedence over the default
196      * directory specified by the global program context, but the current
197      * directory is searched first.
198      */
199     void setSearchPathFromEnv(const char* envVarName);
200
201     /*! \brief
202      * Opens a data file (if found) in an RAII-style `FILE` handle.
203      *
204      * \param[in] options  Identifies the file to be searched for.
205      * \returns The opened file handle, or `NULL` if the file could not be
206      *     found and exceptions were turned off.
207      * \throws  std::bad_alloc if out of memory.
208      * \throws  FileIOError if
209      *   - no such file can be found, and \p options specifies that an
210      *     exception should be thrown, or
211      *   - there is an error opening the file (note that a file is skipped
212      *     during the search if the user does not have rights to open the
213      *     file at all).
214      *
215      * See findFile() for more details.
216      */
217     FilePtr openFile(const DataFileOptions& options) const;
218     /*! \brief
219      * Finds a full path to a data file if found.
220      *
221      * \param[in] options  Identifies the file to be searched for.
222      * \returns Full path to the data file, or an empty string if the file
223      *     could not be found and exceptions were turned off.
224      * \throws  std::bad_alloc if out of memory.
225      * \throws  FileIOError if no such file can be found, and \p options
226      *     specifies that an exception should be thrown.
227      *
228      * Searches for a data file in the search paths configured for the
229      * finder, as well as in the current directory if so required.
230      * Returns the full path to the first file found.
231      */
232     std::string findFile(const DataFileOptions& options) const;
233     /*! \brief
234      * Enumerates files in the data directories.
235      *
236      * \param[in] options  Idenfies files to be searched for.
237      * \returns Information about each found file.
238      * \throws  std::bad_alloc if out of memory.
239      * \throws  FileIOError if no such file can be found, and \p options
240      *     specifies that an exception should be thrown.
241      *
242      * Enumerates all files in the data directories that have the
243      * extension/suffix specified by the file name in \p options.
244      * Unlike findFile() and openFile(), this only works on files that are
245      * in the actual data directories, not for any entry within
246      * subdirectories of those.
247      * See DataFileInfo for details on what is returned for each found
248      * file.
249      * Files from the same directory will be returned as a continuous block
250      * in the returned vector.
251      */
252     std::vector<DataFileInfo> enumerateFiles(const DataFileOptions& options) const;
253
254 private:
255     class Impl;
256
257     PrivateImplPointer<Impl> impl_;
258 };
259
260 } // namespace gmx
261
262 #endif