Remove #ifdef GMX_THREAD_MPI for basic thread safety.
[alexxy/gromacs.git] / src / gromacs / gmxpreprocess / fflibutil.cpp
1 /*  -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
2  *
3  *
4  *                This source code is part of
5  *
6  *                 G   R   O   M   A   C   S
7  *
8  *          GROningen MAchine for Chemical Simulations
9  *
10  *                        VERSION 3.2.0
11  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13  * Copyright (c) 2001-2004, The GROMACS development team,
14  * check out http://www.gromacs.org for more information.
15
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * If you want to redistribute modifications, please consider that
22  * scientific software is very special. Version control is crucial -
23  * bugs must be traceable. We will be happy to consider code for
24  * inclusion in the official distribution, but derived work must not
25  * be called official GROMACS. Details are found in the README & COPYING
26  * files - if they are missing, get the official version at www.gromacs.org.
27  *
28  * To help us fund GROMACS development, we humbly ask that you cite
29  * the papers on the package - you can find them in the top README file.
30  *
31  * For more info, check our website at http://www.gromacs.org
32  *
33  * And Hey:
34  * GROningen Mixture of Alchemy and Childrens' Stories
35  */
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include "sysstuff.h"
47 #include "string2.h"
48 #include "gromacs/fileio/futil.h"
49 #include "network.h"
50 #include "gmx_fatal.h"
51 #include "smalloc.h"
52 #include "statutil.h"
53
54 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57
58 #include "fflibutil.h"
59
60 const char *fflib_forcefield_dir_ext()
61 {
62     return ".ff";
63 }
64
65 const char *fflib_forcefield_itp()
66 {
67     return "forcefield.itp";
68 }
69
70 const char *fflib_forcefield_doc()
71 {
72     return "forcefield.doc";
73 }
74
75 void fflib_filename_base(const char *filename, char *filebase, int maxlen)
76 {
77     const char *cptr;
78     char       *ptr;
79
80     cptr = strrchr(filename, DIR_SEPARATOR);
81     if (cptr != NULL)
82     {
83         /* Skip the separator */
84         cptr += 1;
85     }
86     else
87     {
88         cptr = filename;
89     }
90     if (strlen(filename) >= (size_t)maxlen)
91     {
92         gmx_fatal(FARGS, "filename is longer (%d) than maxlen (%d)",
93                   strlen(filename), maxlen);
94     }
95     strcpy(filebase, cptr);
96     /* Remove the extension */
97     ptr = strrchr(filebase, '.');
98     if (ptr != NULL)
99     {
100         ptr[0] = '\0';
101     }
102 }
103
104 static void sort_filenames(int n, char **name, char **name2)
105 {
106     /* Slow sort, but we usually have tens of names */
107     int   i, j, f;
108     char *tmp;
109
110     for (i = 0; i < n-1; i++)
111     {
112         f = i;
113         for (j = i+1; j < n; j++)
114         {
115             if (strcmp(name[j], name[f]) < 0)
116             {
117                 f = j;
118             }
119         }
120         if (f > i)
121         {
122             tmp     = name[i];
123             name[i] = name[f];
124             name[f] = tmp;
125             if (name2 != NULL)
126             {
127                 tmp      = name2[i];
128                 name2[i] = name2[f];
129                 name2[f] = tmp;
130             }
131         }
132     }
133 }
134
135 static int low_fflib_search_file_end(const char *ffdir,
136                                      gmx_bool    bAddCWD,
137                                      const char *file_end,
138                                      gmx_bool    bFatalError,
139                                      char     ***filenames,
140                                      char     ***filenames_short)
141 {
142     char           *lib, *dir;
143     char           *libpath;
144     gmx_bool        env_is_set;
145     int             len_fe, len_name;
146     char          **fns, **fns_short;
147     char            dir_print[GMX_PATH_MAX];
148     char           *s, fn_dir[GMX_PATH_MAX];
149     gmx_directory_t dirhandle;
150     char            nextname[STRLEN];
151     int             n, n_thisdir, rc;
152
153     len_fe = strlen(file_end);
154
155     env_is_set = FALSE;
156     if (ffdir != NULL)
157     {
158         /* Search in current dir and ffdir */
159         libpath = gmxlibfn(ffdir);
160     }
161     else
162     {
163         /* GMXLIB can be a path now */
164         lib = getenv("GMXLIB");
165         snew(libpath, GMX_PATH_MAX);
166         if (bAddCWD)
167         {
168             sprintf(libpath, "%s%s", ".", PATH_SEPARATOR);
169         }
170         if (lib != NULL)
171         {
172             env_is_set = TRUE;
173             strncat(libpath, lib, GMX_PATH_MAX);
174         }
175         else
176         {
177             get_libdir(libpath + strlen(libpath));
178         }
179     }
180     s         = libpath;
181     n         = 0;
182     fns       = NULL;
183     fns_short = NULL;
184     /* Loop over all the entries in libpath */
185     while ((dir = gmx_strsep(&s, PATH_SEPARATOR)) != NULL)
186     {
187         rc = gmx_directory_open(&dirhandle, dir);
188         if (rc == 0)
189         {
190             strcpy(dir_print, dir);
191
192             n_thisdir = 0;
193             while (gmx_directory_nextfile(dirhandle, nextname, STRLEN-1) == 0)
194             {
195                 nextname[STRLEN-1] = 0;
196                 if (debug)
197                 {
198                     fprintf(debug, "dir '%s' %d file '%s'\n",
199                             dir, n_thisdir, nextname);
200                 }
201                 len_name = strlen(nextname);
202                 /* What about case sensitivity? */
203                 if (len_name >= len_fe &&
204                     strcmp(nextname+len_name-len_fe, file_end) == 0)
205                 {
206                     /* We have a match */
207                     srenew(fns, n+1);
208                     sprintf(fn_dir, "%s%c%s",
209                             dir_print, DIR_SEPARATOR, nextname);
210
211                     /* Copy the file name, possibly including the path. */
212                     fns[n] = strdup(fn_dir);
213
214                     if (ffdir == NULL)
215                     {
216                         /* We are searching in a path.
217                          * Use the relative path when we use share/top
218                          * from the installation.
219                          * Add the full path when we use the current
220                          * working directory of GMXLIB.
221                          */
222                         srenew(fns_short, n+1);
223                         if (strcmp(dir, ".") == 0 || env_is_set)
224                         {
225                             fns_short[n] = strdup(fn_dir);
226                         }
227                         else
228                         {
229                             fns_short[n] = strdup(nextname);
230                         }
231                     }
232                     n++;
233                     n_thisdir++;
234                 }
235             }
236             gmx_directory_close(dirhandle);
237
238             sort_filenames(n_thisdir,
239                            fns+n-n_thisdir,
240                            fns_short == NULL ? NULL : fns_short+n-n_thisdir);
241         }
242     }
243
244     sfree(libpath);
245
246     if (n == 0 && bFatalError)
247     {
248         if (ffdir != NULL)
249         {
250             gmx_fatal(FARGS, "Could not find any files ending on '%s' in the force field directory '%s'", file_end, ffdir);
251         }
252         else
253         {
254             gmx_fatal(FARGS, "Could not find any files ending on '%s' in the current directory or the GROMACS library search path", file_end);
255         }
256     }
257
258     *filenames = fns;
259     if (ffdir == NULL)
260     {
261         *filenames_short = fns_short;
262     }
263
264     return n;
265 }
266
267 int fflib_search_file_end(const char *ffdir,
268                           const char *file_end,
269                           gmx_bool    bFatalError,
270                           char     ***filenames)
271 {
272     return low_fflib_search_file_end(ffdir, FALSE, file_end, bFatalError,
273                                      filenames, NULL);
274 }
275
276 int fflib_search_file_in_dirend(const char *filename, const char *dirend,
277                                 char ***dirnames)
278 {
279     int             nf, i;
280     char          **f, **f_short;
281     int             n;
282     char          **dns;
283     gmx_directory_t dirhandle;
284     char            nextname[STRLEN];
285     int             rc;
286
287     /* Find all files (not only dir's) ending on dirend */
288     nf = low_fflib_search_file_end(NULL, TRUE, dirend, FALSE, &f, &f_short);
289
290     n   = 0;
291     dns = NULL;
292     for (i = 0; i < nf; i++)
293     {
294         rc = gmx_directory_open(&dirhandle, f[i]);
295
296         if (rc == 0)
297         {
298             while (gmx_directory_nextfile(dirhandle, nextname, STRLEN-1) == 0)
299             {
300                 nextname[STRLEN-1] = 0;
301                 if (strcmp(nextname, filename) == 0)
302                 {
303                     /* We have a match */
304                     srenew(dns, n+1);
305                     dns[n] = strdup(f_short[i]);
306                     n++;
307                 }
308             }
309             gmx_directory_close(dirhandle);
310         }
311         sfree(f[i]);
312         sfree(f_short[i]);
313     }
314     sfree(f);
315     sfree(f_short);
316
317     *dirnames = dns;
318
319     return n;
320 }
321
322 gmx_bool fflib_fexist(const char *file)
323 {
324     char *file_fullpath;
325
326     file_fullpath = low_gmxlibfn(file, TRUE, FALSE);
327
328     if (file_fullpath == NULL)
329     {
330         return FALSE;
331     }
332     else
333     {
334         sfree(file_fullpath);
335
336         return TRUE;
337     }
338 }
339
340
341 FILE *fflib_open(const char *file)
342 {
343     char *file_fullpath;
344     FILE *fp;
345
346     file_fullpath = gmxlibfn(file);
347     fprintf(stderr, "Opening force field file %s\n", file_fullpath);
348     fp = ffopen(file_fullpath, "r");
349     sfree(file_fullpath);
350
351     return fp;
352 }