Merge release-4-6 into master
[alexxy/gromacs.git] / src / gromacs / gmxpreprocess / fflibutil.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2010,2012,2013, 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 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include "sysstuff.h"
46 #include "string2.h"
47 #include "gromacs/fileio/futil.h"
48 #include "network.h"
49 #include "gmx_fatal.h"
50 #include "smalloc.h"
51
52 #ifdef HAVE_UNISTD_H
53 #include <unistd.h>
54 #endif
55
56 #include "fflibutil.h"
57
58 const char *fflib_forcefield_dir_ext()
59 {
60     return ".ff";
61 }
62
63 const char *fflib_forcefield_itp()
64 {
65     return "forcefield.itp";
66 }
67
68 const char *fflib_forcefield_doc()
69 {
70     return "forcefield.doc";
71 }
72
73 void fflib_filename_base(const char *filename, char *filebase, int maxlen)
74 {
75     const char *cptr;
76     char       *ptr;
77
78     cptr = strrchr(filename, DIR_SEPARATOR);
79     if (cptr != NULL)
80     {
81         /* Skip the separator */
82         cptr += 1;
83     }
84     else
85     {
86         cptr = filename;
87     }
88     if (strlen(filename) >= (size_t)maxlen)
89     {
90         gmx_fatal(FARGS, "filename is longer (%d) than maxlen (%d)",
91                   strlen(filename), maxlen);
92     }
93     strcpy(filebase, cptr);
94     /* Remove the extension */
95     ptr = strrchr(filebase, '.');
96     if (ptr != NULL)
97     {
98         ptr[0] = '\0';
99     }
100 }
101
102 static void sort_filenames(int n, char **name, char **name2)
103 {
104     /* Slow sort, but we usually have tens of names */
105     int   i, j, f;
106     char *tmp;
107
108     for (i = 0; i < n-1; i++)
109     {
110         f = i;
111         for (j = i+1; j < n; j++)
112         {
113             if (strcmp(name[j], name[f]) < 0)
114             {
115                 f = j;
116             }
117         }
118         if (f > i)
119         {
120             tmp     = name[i];
121             name[i] = name[f];
122             name[f] = tmp;
123             if (name2 != NULL)
124             {
125                 tmp      = name2[i];
126                 name2[i] = name2[f];
127                 name2[f] = tmp;
128             }
129         }
130     }
131 }
132
133 static int low_fflib_search_file_end(const char *ffdir,
134                                      gmx_bool    bAddCWD,
135                                      const char *file_end,
136                                      gmx_bool    bFatalError,
137                                      char     ***filenames,
138                                      char     ***filenames_short)
139 {
140     char           *lib, *dir;
141     char           *libpath;
142     gmx_bool        env_is_set;
143     int             len_fe, len_name;
144     char          **fns, **fns_short;
145     char            dir_print[GMX_PATH_MAX];
146     char           *s, fn_dir[GMX_PATH_MAX];
147     gmx_directory_t dirhandle;
148     char            nextname[STRLEN];
149     int             n, n_thisdir, rc;
150
151     len_fe = strlen(file_end);
152
153     env_is_set = FALSE;
154     if (ffdir != NULL)
155     {
156         /* Search in current dir and ffdir */
157         libpath = gmxlibfn(ffdir);
158     }
159     else
160     {
161         /* GMXLIB can be a path now */
162         lib = getenv("GMXLIB");
163         snew(libpath, GMX_PATH_MAX);
164         if (bAddCWD)
165         {
166             sprintf(libpath, "%s%s", ".", PATH_SEPARATOR);
167         }
168         if (lib != NULL)
169         {
170             env_is_set = TRUE;
171             strncat(libpath, lib, GMX_PATH_MAX);
172         }
173         else
174         {
175             get_libdir(libpath + strlen(libpath));
176         }
177     }
178     s         = libpath;
179     n         = 0;
180     fns       = NULL;
181     fns_short = NULL;
182     /* Loop over all the entries in libpath */
183     while ((dir = gmx_strsep(&s, PATH_SEPARATOR)) != NULL)
184     {
185         rc = gmx_directory_open(&dirhandle, dir);
186         if (rc == 0)
187         {
188             strcpy(dir_print, dir);
189
190             n_thisdir = 0;
191             while (gmx_directory_nextfile(dirhandle, nextname, STRLEN-1) == 0)
192             {
193                 nextname[STRLEN-1] = 0;
194                 if (debug)
195                 {
196                     fprintf(debug, "dir '%s' %d file '%s'\n",
197                             dir, n_thisdir, nextname);
198                 }
199                 len_name = strlen(nextname);
200                 /* What about case sensitivity? */
201                 if (len_name >= len_fe &&
202                     strcmp(nextname+len_name-len_fe, file_end) == 0)
203                 {
204                     /* We have a match */
205                     srenew(fns, n+1);
206                     sprintf(fn_dir, "%s%c%s",
207                             dir_print, DIR_SEPARATOR, nextname);
208
209                     /* Copy the file name, possibly including the path. */
210                     fns[n] = strdup(fn_dir);
211
212                     if (ffdir == NULL)
213                     {
214                         /* We are searching in a path.
215                          * Use the relative path when we use share/top
216                          * from the installation.
217                          * Add the full path when we use the current
218                          * working directory of GMXLIB.
219                          */
220                         srenew(fns_short, n+1);
221                         if (strcmp(dir, ".") == 0 || env_is_set)
222                         {
223                             fns_short[n] = strdup(fn_dir);
224                         }
225                         else
226                         {
227                             fns_short[n] = strdup(nextname);
228                         }
229                     }
230                     n++;
231                     n_thisdir++;
232                 }
233             }
234             gmx_directory_close(dirhandle);
235
236             sort_filenames(n_thisdir,
237                            fns+n-n_thisdir,
238                            fns_short == NULL ? NULL : fns_short+n-n_thisdir);
239         }
240     }
241
242     sfree(libpath);
243
244     if (n == 0 && bFatalError)
245     {
246         if (ffdir != NULL)
247         {
248             gmx_fatal(FARGS, "Could not find any files ending on '%s' in the force field directory '%s'", file_end, ffdir);
249         }
250         else
251         {
252             gmx_fatal(FARGS, "Could not find any files ending on '%s' in the current directory or the GROMACS library search path", file_end);
253         }
254     }
255
256     *filenames = fns;
257     if (ffdir == NULL)
258     {
259         *filenames_short = fns_short;
260     }
261
262     return n;
263 }
264
265 int fflib_search_file_end(const char *ffdir,
266                           const char *file_end,
267                           gmx_bool    bFatalError,
268                           char     ***filenames)
269 {
270     return low_fflib_search_file_end(ffdir, FALSE, file_end, bFatalError,
271                                      filenames, NULL);
272 }
273
274 int fflib_search_file_in_dirend(const char *filename, const char *dirend,
275                                 char ***dirnames)
276 {
277     int             nf, i;
278     char          **f, **f_short;
279     int             n;
280     char          **dns;
281     gmx_directory_t dirhandle;
282     char            nextname[STRLEN];
283     int             rc;
284
285     /* Find all files (not only dir's) ending on dirend */
286     nf = low_fflib_search_file_end(NULL, TRUE, dirend, FALSE, &f, &f_short);
287
288     n   = 0;
289     dns = NULL;
290     for (i = 0; i < nf; i++)
291     {
292         rc = gmx_directory_open(&dirhandle, f[i]);
293
294         if (rc == 0)
295         {
296             while (gmx_directory_nextfile(dirhandle, nextname, STRLEN-1) == 0)
297             {
298                 nextname[STRLEN-1] = 0;
299                 if (strcmp(nextname, filename) == 0)
300                 {
301                     /* We have a match */
302                     srenew(dns, n+1);
303                     dns[n] = strdup(f_short[i]);
304                     n++;
305                 }
306             }
307             gmx_directory_close(dirhandle);
308         }
309         sfree(f[i]);
310         sfree(f_short[i]);
311     }
312     sfree(f);
313     sfree(f_short);
314
315     *dirnames = dns;
316
317     return n;
318 }
319
320 gmx_bool fflib_fexist(const char *file)
321 {
322     char *file_fullpath;
323
324     file_fullpath = low_gmxlibfn(file, TRUE, FALSE);
325
326     if (file_fullpath == NULL)
327     {
328         return FALSE;
329     }
330     else
331     {
332         sfree(file_fullpath);
333
334         return TRUE;
335     }
336 }
337
338
339 FILE *fflib_open(const char *file)
340 {
341     char *file_fullpath;
342     FILE *fp;
343
344     file_fullpath = gmxlibfn(file);
345     fprintf(stderr, "Opening force field file %s\n", file_fullpath);
346     fp = ffopen(file_fullpath, "r");
347     sfree(file_fullpath);
348
349     return fp;
350 }