Create fileio module
[alexxy/gromacs.git] / src / gromacs / utility / programinfo.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012,2013, by the GROMACS development team, led by
5  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
6  * others, as listed in the AUTHORS file in the top-level source
7  * 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 /*! \internal \file
36  * \brief
37  * Implements gmx::ProgramInfo.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_utility
41  */
42 #include "programinfo.h"
43
44 // For GMX_BINARY_SUFFIX
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
48
49 #include <cstdlib>
50 #include <cstring>
51
52 #include <algorithm>
53 #include <string>
54
55 #include <boost/scoped_ptr.hpp>
56
57 #include "gromacs/fileio/futil.h"
58 #include "gromacs/legacyheaders/thread_mpi/mutex.h"
59
60 #include "gromacs/utility/exceptions.h"
61 #include "gromacs/utility/gmxassert.h"
62 #include "gromacs/utility/path.h"
63 #include "gromacs/utility/stringutil.h"
64
65 namespace gmx
66 {
67
68 namespace
69 {
70
71 //! Mutex for updates to the global program info objects.
72 tMPI::mutex                    g_programInfoMutex;
73 //! Global program info; stores the object initialized with ProgramInfo::init().
74 boost::scoped_ptr<ProgramInfo> g_programInfo;
75
76 /*! \brief
77  * Quotes a string if it contains spaces.
78  */
79 std::string quoteIfNecessary(const char *str)
80 {
81     const bool bSpaces = (std::strchr(str, ' ') != NULL);
82     if (bSpaces)
83     {
84         return formatString("'%s'", str);
85     }
86     return str;
87 }
88
89 }   // namespace
90
91 /********************************************************************
92  * ProgramInfo::Impl
93  */
94
95 class ProgramInfo::Impl
96 {
97     public:
98         Impl();
99         Impl(const char *realBinaryName, int argc, const char *const argv[]);
100
101         std::string             realBinaryName_;
102         std::string             fullInvokedProgram_;
103         std::string             programName_;
104         std::string             invariantProgramName_;
105         std::string             commandLine_;
106         std::string             displayName_;
107         mutable tMPI::mutex     displayNameMutex_;
108 };
109
110 ProgramInfo::Impl::Impl()
111     : realBinaryName_("GROMACS"), fullInvokedProgram_("GROMACS"),
112       programName_("GROMACS"), invariantProgramName_("GROMACS")
113 {
114 }
115
116 ProgramInfo::Impl::Impl(const char *realBinaryName,
117                         int argc, const char *const argv[])
118     : realBinaryName_(realBinaryName != NULL ? realBinaryName : ""),
119       fullInvokedProgram_(argc != 0 ? argv[0] : ""),
120       programName_(Path::splitToPathAndFilename(fullInvokedProgram_).second)
121 {
122     // Temporary hack to make things work on Windows while waiting for #950.
123     // Some places in the existing code expect to have DIR_SEPARATOR in all
124     // input paths, but Windows may also give '/' (and does that, e.g., for
125     // tests invoked through CTest).
126     // When removing this, remove also the #include "gromacs/fileio/futil.h".
127     if (DIR_SEPARATOR == '\\')
128     {
129         std::replace(fullInvokedProgram_.begin(), fullInvokedProgram_.end(),
130                      '/', '\\');
131     }
132     programName_          = stripSuffixIfPresent(programName_, ".exe");
133     invariantProgramName_ = programName_;
134 #ifdef GMX_BINARY_SUFFIX
135     invariantProgramName_ =
136         stripSuffixIfPresent(invariantProgramName_, GMX_BINARY_SUFFIX);
137 #endif
138     if (realBinaryName == NULL)
139     {
140         realBinaryName_ = invariantProgramName_;
141     }
142
143     commandLine_ = quoteIfNecessary(programName_.c_str());
144     for (int i = 1; i < argc; ++i)
145     {
146         commandLine_.append(" ");
147         commandLine_.append(quoteIfNecessary(argv[i]));
148     }
149 }
150
151 /********************************************************************
152  * ProgramInfo
153  */
154
155 // static
156 const ProgramInfo &ProgramInfo::getInstance()
157 {
158     tMPI::lock_guard<tMPI::mutex> lock(g_programInfoMutex);
159     if (g_programInfo.get() == NULL)
160     {
161         static ProgramInfo fallbackInfo;
162         return fallbackInfo;
163     }
164     return *g_programInfo;
165 }
166
167 // static
168 ProgramInfo &ProgramInfo::init(int argc, const char *const argv[])
169 {
170     return init(NULL, argc, argv);
171 }
172
173 // static
174 ProgramInfo &ProgramInfo::init(const char *realBinaryName,
175                                int argc, const char *const argv[])
176 {
177     try
178     {
179         tMPI::lock_guard<tMPI::mutex> lock(g_programInfoMutex);
180         if (g_programInfo.get() == NULL)
181         {
182             g_programInfo.reset(new ProgramInfo(realBinaryName, argc, argv));
183         }
184         return *g_programInfo;
185     }
186     catch (const std::exception &ex)
187     {
188         printFatalErrorMessage(stderr, ex);
189         std::exit(processExceptionAtExit(ex));
190     }
191 }
192
193 ProgramInfo::ProgramInfo()
194     : impl_(new Impl)
195 {
196 }
197
198 ProgramInfo::ProgramInfo(const char *realBinaryName)
199     : impl_(new Impl(realBinaryName, 1, &realBinaryName))
200 {
201 }
202
203 ProgramInfo::ProgramInfo(int argc, const char *const argv[])
204     : impl_(new Impl(NULL, argc, argv))
205 {
206 }
207
208 ProgramInfo::ProgramInfo(const char *realBinaryName,
209                          int argc, const char *const argv[])
210     : impl_(new Impl(realBinaryName, argc, argv))
211 {
212 }
213
214 ProgramInfo::~ProgramInfo()
215 {
216 }
217
218 void ProgramInfo::setDisplayName(const std::string &name)
219 {
220     tMPI::lock_guard<tMPI::mutex> lock(impl_->displayNameMutex_);
221     GMX_RELEASE_ASSERT(impl_->displayName_.empty(),
222                        "Can only set display name once");
223     impl_->displayName_ = name;
224 }
225
226 const std::string &ProgramInfo::realBinaryName() const
227 {
228     return impl_->realBinaryName_;
229 }
230
231 const std::string &ProgramInfo::programNameWithPath() const
232 {
233     return impl_->fullInvokedProgram_;
234 }
235
236 const std::string &ProgramInfo::programName() const
237 {
238     return impl_->programName_;
239 }
240
241 const std::string &ProgramInfo::invariantProgramName() const
242 {
243     return impl_->invariantProgramName_;
244 }
245
246 const std::string &ProgramInfo::displayName() const
247 {
248     tMPI::lock_guard<tMPI::mutex> lock(impl_->displayNameMutex_);
249     return impl_->displayName_.empty()
250         ? impl_->programName_
251         : impl_->displayName_;
252 }
253
254 const std::string &ProgramInfo::commandLine() const
255 {
256     return impl_->commandLine_;
257 }
258
259 } // namespace gmx