* To help us fund GROMACS development, we humbly ask that you cite
* the research papers on the package. Check out http://www.gromacs.org.
*/
-#ifdef HAVE_CONFIG_H
+#include "gmxpre.h"
+
+#include "futil.h"
+
#include "config.h"
-#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
-
-#ifdef HAVE_DIRENT_H
-/* POSIX */
-#include <dirent.h>
-#endif
+#include <sys/stat.h>
+#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-
#ifdef GMX_NATIVE_WINDOWS
-#include <windows.h>
-#include <direct.h>
+#include <direct.h> // For _chdir() and _getcwd()
#include <io.h>
-#endif
-
-/* Windows file stuff, only necessary for visual studio */
-#ifdef _MSC_VER
#include <windows.h>
#endif
#include "thread_mpi/threads.h"
-#include "gromacs/legacyheaders/gmx_fatal.h"
-#include "gromacs/legacyheaders/types/commrec.h"
-#include "gromacs/legacyheaders/network.h"
-
-#include "gromacs/fileio/futil.h"
-#include "gromacs/fileio/path.h"
#include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/datafilefinder.h"
+#include "gromacs/utility/dir_separator.h"
#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/path.h"
#include "gromacs/utility/programcontext.h"
#include "gromacs/utility/smalloc.h"
#include "gromacs/utility/stringutil.h"
struct t_pstack *prev;
} t_pstack;
-static t_pstack *pstack = NULL;
-static gmx_bool bUnbuffered = FALSE;
+static t_pstack *pstack = NULL;
+static bool bUnbuffered = false;
+static int s_maxBackupCount = 0;
/* this linked list is an intrinsically globally shared object, so we have
to protect it with mutexes */
static tMPI_Thread_mutex_t pstack_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
-void no_buffers(void)
+namespace gmx
{
- bUnbuffered = TRUE;
+namespace
+{
+//! Global library file finder; stores the object set with setLibraryFileFinder().
+const DataFileFinder *g_libFileFinder;
+//! Default library file finder if nothing is set.
+const DataFileFinder g_defaultLibFileFinder;
+} // namespace
+
+const DataFileFinder &getLibraryFileFinder()
+{
+ if (g_libFileFinder != NULL)
+ {
+ return *g_libFileFinder;
+ }
+ return g_defaultLibFileFinder;
+}
+
+void setLibraryFileFinder(const DataFileFinder *finder)
+{
+ g_libFileFinder = finder;
+}
+
+} // namespace gmx
+
+void gmx_disable_file_buffering(void)
+{
+ bUnbuffered = true;
+}
+
+void gmx_set_max_backup_count(int count)
+{
+ if (count < 0)
+ {
+ const char *env = getenv("GMX_MAXBACKUP");
+ if (env != NULL)
+ {
+ // TODO: Check that the value is converted properly.
+ count = strtol(env, NULL, 10);
+ if (count < 0)
+ {
+ count = 0;
+ }
+ }
+ else
+ {
+ // Use a reasonably low value for countmax; we might
+ // generate 4-5 files in each round, and we don't
+ // want to hit directory limits of 1024 or 2048 files.
+ count = 99;
+ }
+ }
+ s_maxBackupCount = count;
}
void push_ps(FILE *fp)
}
-#ifdef rewind
-#undef rewind
-#endif
-
void frewind(FILE *fp)
{
tMPI_Thread_mutex_lock(&pstack_mutex);
#endif
}
-
-gmx_bool is_pipe(FILE *fp)
+int gmx_truncate(const char *filename, gmx_off_t length)
{
- tMPI_Thread_mutex_lock(&pstack_mutex);
-
- t_pstack *ps = pstack;
- while (ps != NULL)
+#ifdef GMX_NATIVE_WINDOWS
+ FILE *fp = fopen(filename, "rb+");
+ if (fp == NULL)
{
- if (ps->fp == fp)
- {
- tMPI_Thread_mutex_unlock(&pstack_mutex);
- return TRUE;
- }
- ps = ps->prev;
+ return -1;
}
- tMPI_Thread_mutex_unlock(&pstack_mutex);
- return FALSE;
+#ifdef _MSC_VER
+ int rc = _chsize_s(fileno(fp), length);
+#else
+ int rc = _chsize(fileno(fp), length);
+#endif
+ fclose(fp);
+ return rc;
+#else
+ return truncate(filename, length);
+#endif
}
-
static FILE *uncompress(const char *fn, const char *mode)
{
FILE *fp;
}
}
-
-gmx_bool gmx_fexist_master(const char *fname, t_commrec *cr)
-{
- gmx_bool bExist;
-
- if (SIMMASTER(cr))
- {
- bExist = gmx_fexist(fname);
- }
- if (PAR(cr))
- {
- gmx_bcast(sizeof(bExist), &bExist, cr);
- }
- return bExist;
-}
-
-gmx_bool gmx_eof(FILE *fp)
-{
- char data[4];
- gmx_bool beof;
-
- if (is_pipe(fp))
- {
- return feof(fp);
- }
- else
- {
- if ((beof = fread(data, 1, 1, fp)) == 1)
- {
- gmx_fseek(fp, -1, SEEK_CUR);
- }
- return !beof;
- }
-}
-
-static char *backup_fn(const char *file, int count_max)
+static char *backup_fn(const char *file)
{
- /* Use a reasonably low value for countmax; we might
- * generate 4-5 files in each round, and we dont
- * want to hit directory limits of 1024 or 2048 files.
- */
-#define COUNTMAX 99
int i, count = 1;
char *directory, *fn;
char *buf;
- if (count_max == -1)
- {
- count_max = COUNTMAX;
- }
-
smalloc(buf, GMX_PATH_MAX);
for (i = strlen(file)-1; ((i > 0) && (file[i] != DIR_SEPARATOR)); i--)
sprintf(buf, "%s/#%s.%d#", directory, fn, count);
count++;
}
- while ((count <= count_max) && gmx_fexist(buf));
+ while ((count <= s_maxBackupCount) && gmx_fexist(buf));
/* Arbitrarily bail out */
- if (count > count_max)
+ if (count > s_maxBackupCount)
{
+ /* TODO: The error message is only accurate for code that starts with
+ * Gromacs command-line interface. */
gmx_fatal(FARGS, "Won't make more than %d backups of %s for you.\n"
"The env.var. GMX_MAXBACKUP controls this maximum, -1 disables backups.",
- count_max, fn);
+ s_maxBackupCount, fn);
}
sfree(directory);
return buf;
}
-gmx_bool make_backup(const char * name)
+void make_backup(const char *name)
{
- char * env;
- int count_max;
- char * backup;
-
-#ifdef GMX_FAHCORE
- return FALSE; /* skip making backups */
-#else
-
+ if (s_maxBackupCount <= 0)
+ {
+ return;
+ }
if (gmx_fexist(name))
{
- env = getenv("GMX_MAXBACKUP");
- if (env != NULL)
- {
- count_max = strtol(env, NULL, 10);
- if (count_max == -1)
- {
- /* Do not make backups and possibly overwrite old files */
- return TRUE;
- }
- }
- else
- {
- /* Use the default maximum */
- count_max = -1;
- }
- backup = backup_fn(name, count_max);
+ char *backup = backup_fn(name);
if (rename(name, backup) == 0)
{
fprintf(stderr, "\nBack Off! I just backed up %s to %s\n",
}
else
{
- fprintf(stderr, "Sorry couldn't backup %s to %s\n", name, backup);
- return FALSE;
+ fprintf(stderr, "\nSorry couldn't backup %s to %s\n", name, backup);
}
sfree(backup);
}
- return TRUE;
-#endif
}
FILE *gmx_ffopen(const char *file, const char *mode)
#endif
}
-/* Our own implementation of dirent-like functionality to scan directories. */
-struct gmx_directory
-{
-#if defined(GMX_NATIVE_WINDOWS)
- intptr_t windows_handle;
- struct _finddata_t finddata;
- int first;
-#elif defined(HAVE_DIRENT_H)
- DIR * dirent_handle;
-#else
- int dummy;
-#endif
-};
-
-
-int
-gmx_directory_open(gmx_directory_t *p_gmxdir, const char *dirname)
-{
- struct gmx_directory * gmxdir;
- int rc;
-
- snew(gmxdir, 1);
-
- *p_gmxdir = gmxdir;
-
-#if defined(GMX_NATIVE_WINDOWS)
- if (dirname != NULL && strlen(dirname) > 0)
- {
- char * tmpname;
- int len;
-
- len = strlen(dirname);
- snew(tmpname, len+3);
-
- strncpy(tmpname, dirname, len+1);
-
- /* Remove possible trailing directory separator */
- if (tmpname[len] == '/' || tmpname[len] == '\\')
- {
- tmpname[len] = '\0';
- }
-
- /* Add wildcard */
- strcat(tmpname, "/*");
-
- gmxdir->first = 1;
- if ( (gmxdir->windows_handle = _findfirst(tmpname, &gmxdir->finddata)) > 0L)
- {
- rc = 0;
- }
- else
- {
- if (errno == EINVAL)
- {
- sfree(gmxdir);
- *p_gmxdir = NULL;
- rc = EINVAL;
- }
- else
- {
- rc = 0;
- }
- }
- }
- else
- {
- rc = EINVAL;
- }
-#elif defined(HAVE_DIRENT_H)
- if ( (gmxdir->dirent_handle = opendir(dirname)) != NULL)
- {
- rc = 0;
- }
- else
- {
- sfree(gmxdir);
- *p_gmxdir = NULL;
- rc = EINVAL;
- }
-#else
- gmx_fatal(FARGS,
- "Source compiled without POSIX dirent or windows support - cannot scan directories.\n"
- "In the very unlikely event this is not a compile-time mistake you could consider\n"
- "implementing support for your platform in futil.c, but contact the developers\n"
- "to make sure it's really necessary!\n");
- rc = -1;
-#endif
- return rc;
-}
-
-
-int
-gmx_directory_nextfile(gmx_directory_t gmxdir, char *name, int maxlength_name)
-{
- int rc;
-
-#if defined(GMX_NATIVE_WINDOWS)
- if (gmxdir != NULL)
- {
- if (gmxdir->windows_handle <= 0)
- {
-
- name[0] = '\0';
- rc = ENOENT;
- }
- else if (gmxdir->first == 1)
- {
- strncpy(name, gmxdir->finddata.name, maxlength_name);
- rc = 0;
- gmxdir->first = 0;
- }
- else
- {
- if (_findnext(gmxdir->windows_handle, &gmxdir->finddata) == 0)
- {
- strncpy(name, gmxdir->finddata.name, maxlength_name);
- rc = 0;
- }
- else
- {
- name[0] = '\0';
- rc = ENOENT;
- }
- }
- }
- else
- {
- name[0] = '\0';
- rc = EINVAL;
- }
-#elif defined(HAVE_DIRENT_H)
- struct dirent * direntp_large;
- struct dirent * p;
-
-
- if (gmxdir != NULL && gmxdir->dirent_handle != NULL)
- {
- /* On some platforms no space is present for d_name in dirent.
- * Since d_name is guaranteed to be the last entry, allocating
- * extra space for dirent will allow more size for d_name.
- * GMX_MAX_PATH should always be >= the max possible d_name.
- */
- smalloc(direntp_large, sizeof(*direntp_large) + GMX_PATH_MAX);
- rc = readdir_r(gmxdir->dirent_handle, direntp_large, &p);
-
- if (p != NULL && rc == 0)
- {
- strncpy(name, direntp_large->d_name, maxlength_name);
- }
- else
- {
- name[0] = '\0';
- rc = ENOENT;
- }
- sfree(direntp_large);
- }
- else
- {
- name[0] = '\0';
- rc = EINVAL;
- }
-#else
- gmx_fatal(FARGS,
- "Source compiled without POSIX dirent or windows support - cannot scan directories.\n");
- rc = -1;
-#endif
- return rc;
-}
-
-
-int
-gmx_directory_close(gmx_directory_t gmxdir)
-{
- int rc;
-#if defined(GMX_NATIVE_WINDOWS)
- rc = (gmxdir != NULL) ? _findclose(gmxdir->windows_handle) : EINVAL;
-#elif defined(HAVE_DIRENT_H)
- rc = (gmxdir != NULL) ? closedir(gmxdir->dirent_handle) : EINVAL;
-#else
- gmx_fatal(FARGS,
- "Source compiled without POSIX dirent or windows support - cannot scan directories.\n");
- rc = -1;
-#endif
-
- sfree(gmxdir);
- return rc;
-}
-
char *low_gmxlibfn(const char *file, gmx_bool bAddCWD, gmx_bool bFatal)
{
- bool bEnvIsSet = false;
try
{
- if (bAddCWD && gmx_fexist(file))
+ const gmx::DataFileFinder &finder = gmx::getLibraryFileFinder();
+ std::string result =
+ finder.findFile(gmx::DataFileOptions(file)
+ .includeCurrentDir(bAddCWD)
+ .throwIfNotFound(bFatal));
+ if (!result.empty())
{
- return gmx_strdup(file);
- }
- else
- {
- std::string libpath;
- // GMXLIB can be a path.
- const char *lib = getenv("GMXLIB");
- if (lib != NULL)
- {
- bEnvIsSet = true;
- libpath = lib;
- }
- else
- {
- libpath = gmx::getProgramContext().defaultLibraryDataPath();
- }
-
- std::vector<std::string> pathEntries;
- gmx::Path::splitPathEnvironment(libpath, &pathEntries);
- std::vector<std::string>::const_iterator i;
- for (i = pathEntries.begin(); i != pathEntries.end(); ++i)
- {
- std::string testPath = gmx::Path::join(*i, file);
- if (gmx::Path::exists(testPath))
- {
- return gmx_strdup(testPath.c_str());
- }
- }
+ return gmx_strdup(result.c_str());
}
}
GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
- if (bFatal)
- {
- if (bEnvIsSet)
- {
- gmx_fatal(FARGS,
- "Library file %s not found %sin your GMXLIB path.",
- file, bAddCWD ? "in current dir nor " : "");
- }
- else
- {
- gmx_fatal(FARGS,
- "Library file %s not found %sin default directories.\n"
- "(You can set the directories to search with the GMXLIB path variable)",
- file, bAddCWD ? "in current dir nor " : "");
- }
- }
return NULL;
}
FILE *low_libopen(const char *file, gmx_bool bFatal)
{
- FILE *ff;
- char *fn;
-
- fn = low_gmxlibfn(file, TRUE, bFatal);
-
- if (fn == NULL)
- {
- ff = NULL;
- }
- else
+ try
{
- if (debug)
- {
- fprintf(debug, "Opening library file %s\n", fn);
- }
- ff = fopen(fn, "r");
+ const gmx::DataFileFinder &finder = gmx::getLibraryFileFinder();
+ FILE *fp =
+ finder.openFile(gmx::DataFileOptions(file)
+ .includeCurrentDir(true)
+ .throwIfNotFound(bFatal));
+ return fp;
}
- sfree(fn);
-
- return ff;
+ GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+ return NULL;
}
char *gmxlibfn(const char *file)
/* name in Buf should now be OK */
}
-int gmx_truncatefile(char *path, gmx_off_t length)
-{
-#ifdef GMX_NATIVE_WINDOWS
- /* Microsoft visual studio does not have "truncate" */
- HANDLE fh;
- LARGE_INTEGER win_length;
-
- win_length.QuadPart = length;
-
- fh = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
- OPEN_EXISTING, 0, NULL);
- SetFilePointerEx(fh, win_length, NULL, FILE_BEGIN);
- SetEndOfFile(fh);
- CloseHandle(fh);
-
- return 0;
-#else
- return truncate(path, length);
-#endif
-}
-
-
int gmx_file_rename(const char *oldname, const char *newname)
{
#ifndef GMX_NATIVE_WINDOWS
rc = fah_fsync(fp);
#else /* GMX_FAHCORE */
{
- int fn = -1;
+ int fn;
/* get the file number */
#if defined(HAVE_FILENO)
fn = fileno(fp);
#elif defined(HAVE__FILENO)
fn = _fileno(fp);
+#else
+ fn = -1;
#endif
/* do the actual fsync */