Code beautification with uncrustify
[alexxy/gromacs.git] / src / gromacs / utility / programinfo.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::ProgramInfo.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_utility
37  */
38 #include "programinfo.h"
39
40 // For GMX_BINARY_SUFFIX
41 #ifdef HAVE_CONFIG_H
42 #include "config.h"
43 #endif
44
45 #include <cstdlib>
46 #include <cstring>
47
48 #include <algorithm>
49 #include <string>
50
51 #include <boost/scoped_ptr.hpp>
52
53 #include "gromacs/legacyheaders/futil.h"
54 #include "gromacs/legacyheaders/thread_mpi/mutex.h"
55
56 #include "gromacs/utility/exceptions.h"
57 #include "gromacs/utility/path.h"
58 #include "gromacs/utility/stringutil.h"
59
60 namespace gmx
61 {
62
63 namespace
64 {
65 //! Mutex for updates to the global program info objects.
66 tMPI::mutex                    g_programInfoMutex;
67 //! Partially filled program info, needed to support set_program_name().
68 boost::scoped_ptr<ProgramInfo> g_partialProgramInfo;
69 //! Global program info; stores the object initialized with ProgramInfo::init().
70 boost::scoped_ptr<ProgramInfo> g_programInfo;
71 }   // namespace
72
73 /********************************************************************
74  * ProgramInfo::Impl
75  */
76
77 class ProgramInfo::Impl
78 {
79     public:
80         Impl();
81         Impl(const char *realBinaryName, int argc, const char *const argv[]);
82
83         std::string realBinaryName_;
84         std::string fullInvokedProgram_;
85         std::string programName_;
86         std::string invariantProgramName_;
87         std::string commandLine_;
88 };
89
90 ProgramInfo::Impl::Impl()
91     : realBinaryName_("GROMACS"), fullInvokedProgram_("GROMACS"),
92       programName_("GROMACS"), invariantProgramName_("GROMACS")
93 {
94 }
95
96 ProgramInfo::Impl::Impl(const char *realBinaryName,
97                         int argc, const char *const argv[])
98     : realBinaryName_(realBinaryName != NULL ? realBinaryName : ""),
99       fullInvokedProgram_(argc != 0 ? argv[0] : ""),
100       programName_(Path::splitToPathAndFilename(fullInvokedProgram_).second)
101 {
102     // Temporary hack to make things work on Windows while waiting for #950.
103     // Some places in the existing code expect to have DIR_SEPARATOR in all
104     // input paths, but Windows may also give '/' (and does that, e.g., for
105     // tests invoked through CTest).
106     // When removing this, remove also the #include "futil.h".
107     if (DIR_SEPARATOR == '\\')
108     {
109         std::replace(fullInvokedProgram_.begin(), fullInvokedProgram_.end(),
110                      '/', '\\');
111     }
112     programName_          = stripSuffixIfPresent(programName_, ".exe");
113     invariantProgramName_ = programName_;
114 #ifdef GMX_BINARY_SUFFIX
115     invariantProgramName_ =
116         stripSuffixIfPresent(invariantProgramName_, GMX_BINARY_SUFFIX);
117 #endif
118     if (realBinaryName == NULL)
119     {
120         realBinaryName_ = invariantProgramName_;
121     }
122
123     for (int i = 0; i < argc; ++i)
124     {
125         if (i > 0)
126         {
127             commandLine_.append(" ");
128         }
129         const char *arg     = argv[i];
130         bool        bSpaces = (std::strchr(arg, ' ') != NULL);
131         if (bSpaces)
132         {
133             commandLine_.append("'");
134         }
135         commandLine_.append(arg);
136         if (bSpaces)
137         {
138             commandLine_.append("'");
139         }
140     }
141 }
142
143 /********************************************************************
144  * ProgramInfo
145  */
146
147 // static
148 const ProgramInfo &ProgramInfo::getInstance()
149 {
150     tMPI::lock_guard<tMPI::mutex> lock(g_programInfoMutex);
151     if (g_programInfo.get() == NULL)
152     {
153         if (g_partialProgramInfo.get() != NULL)
154         {
155             return *g_partialProgramInfo;
156         }
157         static ProgramInfo fallbackInfo;
158         return fallbackInfo;
159     }
160     return *g_programInfo;
161 }
162
163 // static
164 const ProgramInfo &ProgramInfo::init(int argc, const char *const argv[])
165 {
166     return init(NULL, argc, argv);
167 }
168
169 // static
170 const ProgramInfo &ProgramInfo::init(const char *realBinaryName,
171                                      int argc, const char *const argv[])
172 {
173     try
174     {
175         tMPI::lock_guard<tMPI::mutex> lock(g_programInfoMutex);
176         if (g_programInfo.get() == NULL)
177         {
178             // TODO: Remove this hack with negative argc once there is no need for
179             // set_program_name().
180             if (argc < 0)
181             {
182                 if (g_partialProgramInfo.get() == NULL)
183                 {
184                     g_partialProgramInfo.reset(
185                             new ProgramInfo(realBinaryName, -argc, argv));
186                 }
187                 return *g_partialProgramInfo;
188             }
189             g_programInfo.reset(new ProgramInfo(realBinaryName, argc, argv));
190         }
191         return *g_programInfo;
192     }
193     catch (const std::exception &ex)
194     {
195         printFatalErrorMessage(stderr, ex);
196         std::exit(1);
197     }
198 }
199
200 ProgramInfo::ProgramInfo()
201     : impl_(new Impl)
202 {
203 }
204
205 ProgramInfo::ProgramInfo(const char *realBinaryName)
206     : impl_(new Impl(realBinaryName, 1, &realBinaryName))
207 {
208 }
209
210 ProgramInfo::ProgramInfo(int argc, const char *const argv[])
211     : impl_(new Impl(NULL, argc, argv))
212 {
213 }
214
215 ProgramInfo::ProgramInfo(const char *realBinaryName,
216                          int argc, const char *const argv[])
217     : impl_(new Impl(realBinaryName, argc, argv))
218 {
219 }
220
221 ProgramInfo::~ProgramInfo()
222 {
223 }
224
225 const std::string &ProgramInfo::realBinaryName() const
226 {
227     return impl_->realBinaryName_;
228 }
229
230 const std::string &ProgramInfo::programNameWithPath() const
231 {
232     return impl_->fullInvokedProgram_;
233 }
234
235 const std::string &ProgramInfo::programName() const
236 {
237     return impl_->programName_;
238 }
239
240 const std::string &ProgramInfo::invariantProgramName() const
241 {
242     return impl_->invariantProgramName_;
243 }
244
245 const std::string &ProgramInfo::commandLine() const
246 {
247     return impl_->commandLine_;
248 }
249
250 } // namespace gmx