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