3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
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.
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.
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.
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.
29 * For more info, check our website at http://www.gromacs.org
33 * Implements classes in filenameoption.h and filenameoptionstorage.h.
35 * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36 * \ingroup module_options
38 #include "filenameoption.h"
39 #include "filenameoptionstorage.h"
44 #include "gromacs/utility/file.h"
45 #include "gromacs/utility/stringutil.h"
53 class FileTypeRegistry;
55 /********************************************************************
60 * Handles a single file type known to FileNameOptionStorage.
62 * \ingroup module_options
67 //! Returns whether \p filename has a valid extension for this type.
68 bool hasKnownExtension(const std::string &filename) const;
69 //! Adds a default extension for this type to \p filename.
70 std::string addExtension(const std::string &filename) const;
72 * Adds an extension to \p filename if it results in an existing file.
74 * Tries to add each extension for this file type to \p filename and
75 * checks whether this results in an existing file.
76 * The first match is returned.
77 * Returns an empty string if no existing file is found.
79 std::string findFileWithExtension(const std::string &filename) const;
82 //! Possible extensions for this file type.
83 std::vector<const char *> extensions_;
86 * Needed for initialization; all initialization is handled by
89 friend class FileTypeRegistry;
93 FileTypeHandler::hasKnownExtension(const std::string &filename) const
95 for (size_t i = 0; i < extensions_.size(); ++i)
97 if (endsWith(filename, extensions_[i]))
106 FileTypeHandler::addExtension(const std::string &filename) const
108 if (extensions_.empty())
112 return filename + extensions_[0];
116 FileTypeHandler::findFileWithExtension(const std::string &filename) const
118 for (size_t i = 0; i < extensions_.size(); ++i)
120 std::string testFilename(filename + extensions_[i]);
121 if (File::exists(testFilename))
126 return std::string();
129 /********************************************************************
134 * Singleton for managing static file type info for FileNameOptionStorage.
136 * \ingroup module_options
138 class FileTypeRegistry
141 //! Returns a singleton instance of this class.
142 static const FileTypeRegistry &instance();
143 //! Returns a handler for a single file type.
144 const FileTypeHandler &handlerForType(OptionFileType type) const;
147 //! Initializes the file type registry.
150 //! Registers a file type with a single extension.
151 void registerType(OptionFileType type, const char *extension);
152 //! Registers a file type with multiple extensions.
153 template <size_t count>
154 void registerType(OptionFileType type,
155 const char *const (&extensions)[count]);
157 std::vector<FileTypeHandler> filetypes_;
161 const FileTypeRegistry &
162 FileTypeRegistry::instance()
164 static FileTypeRegistry singleton;
168 const FileTypeHandler &
169 FileTypeRegistry::handlerForType(OptionFileType type) const
171 GMX_RELEASE_ASSERT(type >= 0 && static_cast<size_t>(type) < filetypes_.size(),
172 "Invalid file type");
173 return filetypes_[type];
176 FileTypeRegistry::FileTypeRegistry()
178 filetypes_.resize(eftOptionFileType_NR);
179 const char *const topExtensions[] = {
180 ".tpr", ".tpb", ".tpa", ".gro", ".g96", ".pdb", ".brk", ".ent"
182 const char *const trajExtensions[] = {
183 ".xtc", ".trr", ".trj", ".cpt", ".gro", ".g96", ".g87", ".pdb"
185 registerType(eftTopology, topExtensions);
186 registerType(eftTrajectory, trajExtensions);
187 registerType(eftPDB, ".pdb");
188 registerType(eftIndex, ".ndx");
189 registerType(eftPlot, ".xvg");
190 registerType(eftGenericData, ".dat");
193 void FileTypeRegistry::registerType(OptionFileType type,
194 const char *extension)
196 GMX_RELEASE_ASSERT(type >= 0 && static_cast<size_t>(type) < filetypes_.size(),
197 "Invalid file type");
198 filetypes_[type].extensions_.assign(1, extension);
201 template <size_t count>
202 void FileTypeRegistry::registerType(OptionFileType type,
203 const char *const (&extensions)[count])
205 GMX_RELEASE_ASSERT(type >= 0 && static_cast<size_t>(type) < filetypes_.size(),
206 "Invalid file type");
207 filetypes_[type].extensions_.assign(extensions, extensions + count);
211 * Helper method to complete a file name provided to a file name option.
213 * \param[in] value Value provided to the file name option.
214 * \param[in] filetype File type for the option.
215 * \param[in] bCompleteToExisting
216 * Whether to check existing files when completing the extension.
217 * \returns \p value with possible extension added.
219 std::string completeFileName(const std::string &value, OptionFileType filetype,
220 bool bCompleteToExisting)
222 if (bCompleteToExisting && File::exists(value))
224 // TODO: This may not work as expected if the value is passed to a
225 // function that uses fn2ftp() to determine the file type and the input
226 // file has an unrecognized extension.
229 const FileTypeRegistry ®istry = FileTypeRegistry::instance();
230 const FileTypeHandler &typeHandler = registry.handlerForType(filetype);
231 if (typeHandler.hasKnownExtension(value))
235 if (bCompleteToExisting)
237 std::string newValue = typeHandler.findFileWithExtension(value);
238 if (!newValue.empty())
243 return typeHandler.addExtension(value);
248 /********************************************************************
249 * FileNameOptionStorage
252 FileNameOptionStorage::FileNameOptionStorage(const FileNameOption &settings)
253 : MyBase(settings), info_(this), filetype_(settings.filetype_),
254 bRead_(settings.bRead_), bWrite_(settings.bWrite_),
255 bLibrary_(settings.bLibrary_)
257 if (settings.defaultBasename_ != NULL)
261 setDefaultValue(completeFileName(settings.defaultBasename_,
266 setDefaultValueIfSet(completeFileName(settings.defaultBasename_,
272 std::string FileNameOptionStorage::formatSingleValue(const std::string &value) const
277 void FileNameOptionStorage::convertValue(const std::string &value)
279 bool bInput = isInputFile() || isInputOutputFile();
280 addValue(completeFileName(value, filetype_, bInput));
283 /********************************************************************
287 FileNameOptionInfo::FileNameOptionInfo(FileNameOptionStorage *option)
292 const FileNameOptionStorage &FileNameOptionInfo::option() const
294 return static_cast<const FileNameOptionStorage &>(OptionInfo::option());
297 bool FileNameOptionInfo::isInputFile() const
299 return option().isInputFile();
302 bool FileNameOptionInfo::isOutputFile() const
304 return option().isOutputFile();
307 bool FileNameOptionInfo::isInputOutputFile() const
309 return option().isInputOutputFile();
312 bool FileNameOptionInfo::isLibraryFile() const
314 return option().isLibraryFile();
317 /********************************************************************
321 AbstractOptionStoragePointer FileNameOption::createStorage() const
323 return AbstractOptionStoragePointer(new FileNameOptionStorage(*this));