Project

General

Profile

futil.c

modefied futil.c - Berk Hess, 08/17/2010 04:22 PM

 
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

    
47
#ifdef HAVE_DIRENT_H
48
/* POSIX */
49
#include <dirent.h>
50
#endif
51

    
52

    
53
#if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
54
#include <direct.h>
55
#include <io.h>
56
#endif
57

    
58
#include "sysstuff.h"
59
#include "string2.h"
60
#include "futil.h"
61
#include "network.h"
62
#include "gmx_fatal.h"
63
#include "smalloc.h"
64
#include "statutil.h"
65

    
66

    
67
#ifdef GMX_THREADS
68
#include "thread_mpi.h"
69
#endif
70

    
71
/* Windows file stuff, only necessary for visual studio */
72
#ifdef _MSC_VER
73
#include "windows.h"
74
#endif
75

    
76
/* we keep a linked list of all files opened through pipes (i.e. 
77
   compressed or .gzipped files. This way we can distinguish between them
78
   without having to change the semantics of reading from/writing to files) 
79
   */
80
typedef struct t_pstack {
81
    FILE   *fp;
82
    struct t_pstack *prev;
83
} t_pstack;
84

    
85
static t_pstack *pstack=NULL;
86
static bool     bUnbuffered=FALSE;
87

    
88
#ifdef GMX_THREADS
89
/* this linked list is an intrinsically globally shared object, so we have
90
   to protect it with mutexes */
91
static tMPI_Thread_mutex_t pstack_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
92
#endif
93

    
94
void no_buffers(void)
95
{
96
    bUnbuffered=TRUE;
97
}
98

    
99
void push_ps(FILE *fp)
100
{
101
    t_pstack *ps;
102

    
103
#ifdef GMX_THREADS
104
    tMPI_Thread_mutex_lock(&pstack_mutex);
105
#endif
106

    
107
    snew(ps,1);
108
    ps->fp   = fp;
109
    ps->prev = pstack;
110
    pstack   = ps;
111
#ifdef GMX_THREADS
112
    tMPI_Thread_mutex_unlock(&pstack_mutex);
113
#endif
114
}
115

    
116
#ifdef GMX_FAHCORE
117
/* don't use pipes!*/
118
#define popen fah_fopen
119
#define pclose fah_fclose
120
#define SKIP_FFOPS 1
121
#else
122
#ifdef ffclose
123
#undef ffclose
124
#endif
125
#endif
126

    
127
#ifndef GMX_FAHCORE
128
#ifndef HAVE_PIPES
129
static FILE *popen(const char *nm,const char *mode)
130
{
131
    gmx_impl("Sorry no pipes...");
132

    
133
    return NULL;
134
}
135

    
136
static int pclose(FILE *fp)
137
{
138
    gmx_impl("Sorry no pipes...");
139

    
140
    return 0;
141
}
142
#endif
143
#endif
144

    
145
int ffclose(FILE *fp)
146
{
147
#ifdef SKIP_FFOPS
148
    return fclose(fp);
149
#else
150
    t_pstack *ps,*tmp;
151
    int ret=0;
152
#ifdef GMX_THREADS
153
    tMPI_Thread_mutex_lock(&pstack_mutex);
154
#endif
155

    
156
    ps=pstack;
157
    if (ps == NULL) {
158
        if (fp != NULL) 
159
            ret = fclose(fp);
160
    }
161
    else if (ps->fp == fp) {
162
        if (fp != NULL)
163
            ret = pclose(fp);
164
        pstack=pstack->prev;
165
        sfree(ps);
166
    }
167
    else {
168
        while ((ps->prev != NULL) && (ps->prev->fp != fp))
169
            ps=ps->prev;
170
        if (ps->prev->fp == fp) {
171
            if (ps->prev->fp != NULL)
172
                ret = pclose(ps->prev->fp);
173
            tmp=ps->prev;
174
            ps->prev=ps->prev->prev;
175
            sfree(tmp);
176
        }
177
        else {
178
            if (fp != NULL)
179
                ret = fclose(fp);
180
        }
181
    }
182
#ifdef GMX_THREADS
183
    tMPI_Thread_mutex_unlock(&pstack_mutex);
184
#endif
185
    return ret;
186
#endif
187
}
188

    
189

    
190
#ifdef rewind
191
#undef rewind
192
#endif
193

    
194
void frewind(FILE *fp)
195
{
196
    t_pstack *ps;
197
#ifdef GMX_THREADS
198
    tMPI_Thread_mutex_lock(&pstack_mutex);
199
#endif
200

    
201
    ps=pstack;
202
    while (ps != NULL) {
203
        if (ps->fp == fp) {
204
            fprintf(stderr,"Cannot rewind compressed file!\n");
205
#ifdef GMX_THREADS
206
            tMPI_Thread_mutex_unlock(&pstack_mutex);
207
#endif
208
            return;
209
        }
210
        ps=ps->prev;
211
    }
212
    rewind(fp);
213
#ifdef GMX_THREADS
214
    tMPI_Thread_mutex_unlock(&pstack_mutex);
215
#endif
216
}
217

    
218
int gmx_fseek(FILE *stream, gmx_off_t offset, int whence)
219
{
220
#ifdef HAVE_FSEEKO
221
    return fseeko(stream, offset, whence);
222
#else
223
#ifdef HAVE__FSEEKI64
224
    return _fseeki64(stream, offset, whence);
225
#else
226
    return fseek(stream, offset, whence);
227
#endif
228
#endif
229
}
230

    
231
gmx_off_t gmx_ftell(FILE *stream)
232
{
233
#ifdef HAVE_FSEEKO
234
    return ftello(stream);
235
#else
236
#ifdef HAVE__FSEEKI64 
237
    return _ftelli64(stream);
238
#else
239
    return ftell(stream);
240
#endif
241
#endif
242
}
243

    
244

    
245
bool is_pipe(FILE *fp)
246
{
247
    t_pstack *ps;
248
#ifdef GMX_THREADS
249
    tMPI_Thread_mutex_lock(&pstack_mutex);
250
#endif
251

    
252
    ps=pstack;
253
    while (ps != NULL) {
254
        if (ps->fp == fp) {
255
#ifdef GMX_THREADS
256
            tMPI_Thread_mutex_unlock(&pstack_mutex);
257
#endif
258
            return TRUE;
259
        }
260
        ps=ps->prev;
261
    }
262
#ifdef GMX_THREADS
263
    tMPI_Thread_mutex_unlock(&pstack_mutex);
264
#endif
265
    return FALSE;
266
}
267

    
268

    
269
static FILE *uncompress(const char *fn,const char *mode)
270
{
271
    FILE *fp;
272
    char buf[256];
273

    
274
    sprintf(buf,"uncompress -c < %s",fn);
275
    fprintf(stderr,"Going to execute '%s'\n",buf);
276
    if ((fp=popen(buf,mode)) == NULL)
277
        gmx_open(fn);
278
    push_ps(fp);
279

    
280
    return fp;
281
}
282

    
283
static FILE *gunzip(const char *fn,const char *mode)
284
{
285
    FILE *fp;
286
    char buf[256];
287

    
288
    sprintf(buf,"gunzip -c < %s",fn);
289
    fprintf(stderr,"Going to execute '%s'\n",buf);
290
    if ((fp=popen(buf,mode)) == NULL)
291
        gmx_open(fn);
292
    push_ps(fp);
293

    
294
    return fp;
295
}
296

    
297
bool gmx_fexist(const char *fname)
298
{
299
    FILE *test;
300

    
301
    if (fname == NULL)
302
        return FALSE;
303
    test=fopen(fname,"r");
304
    if (test == NULL) {
305
        /*Windows doesn't allow fopen of directory - so we need to check this seperately */
306
        #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__) 
307
            DWORD attr = GetFileAttributes(fname);
308
            return (attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY);
309
        #else 
310
            return FALSE;
311
        #endif
312
    } else {
313
        fclose(test);
314
        return TRUE;
315
    }
316
}
317

    
318

    
319
bool gmx_fexist_master(const char *fname, t_commrec *cr)
320
{
321
  bool bExist;
322
  
323
  if (SIMMASTER(cr)) 
324
  {
325
      bExist = gmx_fexist(fname);
326
  }
327
  if (PAR(cr)) 
328
  {
329
      gmx_bcast(sizeof(bExist),&bExist,cr);
330
  }
331
  return bExist;
332
}
333

    
334
bool gmx_eof(FILE *fp)
335
{
336
    char data[4];
337
    bool beof;
338

    
339
    if (is_pipe(fp))
340
        return feof(fp);
341
    else {
342
        if ((beof=fread(data,1,1,fp))==1)
343
            gmx_fseek(fp,-1,SEEK_CUR);
344
        return !beof;
345
    }
346
}
347

    
348
static char *backup_fn(const char *file,int count_max)
349
{
350
    /* Use a reasonably low value for countmax; we might
351
     * generate 4-5 files in each round, and we dont
352
     * want to hit directory limits of 1024 or 2048 files.
353
     */
354
#define COUNTMAX 99
355
    int         i,count=1;
356
    char        *directory,*fn;
357
    char        *buf;
358

    
359
    if (count_max == -1)
360
    {
361
        count_max = COUNTMAX;
362
    }
363

    
364
    smalloc(buf, GMX_PATH_MAX);
365

    
366
    for(i=strlen(file)-1; ((i > 0) && (file[i] != DIR_SEPARATOR)); i--)
367
        ;
368
    /* Must check whether i > 0, i.e. whether there is a directory
369
     * in the file name. In that case we overwrite the / sign with
370
     * a '\0' to end the directory string .
371
     */
372
    if (i > 0) {
373
        directory    = strdup(file);
374
        directory[i] = '\0';
375
        fn           = strdup(file+i+1);
376
    }
377
    else {
378
        directory    = strdup(".");
379
        fn           = strdup(file);
380
    }
381
    do {
382
        sprintf(buf,"%s/#%s.%d#",directory,fn,count);
383
        count++;
384
    } while ((count <= count_max) && gmx_fexist(buf));
385

    
386
    /* Arbitrarily bail out */
387
    if (count > count_max) 
388
        gmx_fatal(FARGS,"Won't make more than %d backups of %s for you.\n"
389
                  "The env.var. GMX_MAXBACKUP controls this maximum, -1 disables backups.",
390
                  count_max,fn);
391

    
392
    sfree(directory);
393
    sfree(fn);
394

    
395
    return buf;
396
}
397

    
398
bool make_backup(const char * name)
399
{
400
    char * env;
401
    int  count_max;
402
    char * backup;
403

    
404
#ifdef GMX_FAHCORE
405
    return FALSE; /* skip making backups */
406
#else
407

    
408
    if (gmx_fexist(name))
409
    {
410
        env = getenv("GMX_MAXBACKUP");
411
        if (env != NULL)
412
        {
413
            count_max = 0;
414
            sscanf(env,"%d",&count_max);
415
            if (count_max == -1)
416
            {
417
                /* Do not make backups and possibly overwrite old files */
418
                return TRUE;
419
            }
420
        }
421
        else
422
        {
423
            /* Use the default maximum */
424
            count_max = -1;
425
        }
426
        backup = backup_fn(name,count_max);
427
        if(rename(name, backup) == 0) {
428
            fprintf(stderr, "\nBack Off! I just backed up %s to %s\n",
429
                    name, backup);
430
        } else {
431
            fprintf(stderr, "Sorry couldn't backup %s to %s\n", name, backup);
432
            return FALSE;
433
        }
434
        sfree(backup);
435
    }
436
    return TRUE;
437
#endif
438
}
439

    
440
FILE *ffopen(const char *file,const char *mode)
441
{
442
#ifdef SKIP_FFOPS
443
    return fopen(file,mode);
444
#else
445
    FILE *ff=NULL;
446
    char buf[256],*bf,*bufsize=0,*ptr;
447
    bool bRead;
448
    int  bs;
449

    
450
    if (mode[0]=='w') {
451
        make_backup(file);
452
    }
453
    where();
454

    
455
    bRead= (mode[0]=='r'&&mode[1]!='+');
456
    strcpy(buf,file);
457
    if (gmx_fexist(buf) || !bRead) {
458
        if ((ff=fopen(buf,mode))==NULL)
459
            gmx_file(buf);
460
        where();
461
        /* Check whether we should be using buffering (default) or not
462
         * (for debugging)
463
         */
464
        if (bUnbuffered || ((bufsize=getenv("LOG_BUFS")) != NULL)) {
465
            /* Check whether to use completely unbuffered */
466
            if (bUnbuffered)
467
                bs = 0;
468
            else
469
                bs=strtol(bufsize, NULL, 10); 
470
            if (bs <= 0)
471
                setbuf(ff,NULL); 
472
            else {
473
                snew(ptr,bs+8);
474
                if (setvbuf(ff,ptr,_IOFBF,bs) != 0)
475
                    gmx_file("Buffering File");
476
            }
477
        }
478
        where();
479
    }
480
    else {
481
        sprintf(buf,"%s.Z",file);
482
        if (gmx_fexist(buf)) {
483
            ff=uncompress(buf,mode);
484
        }
485
        else {
486
            sprintf(buf,"%s.gz",file);
487
            if (gmx_fexist(buf)) {
488
                ff=gunzip(buf,mode);
489
            }
490
            else 
491
                gmx_file(file);
492
        }
493
    }
494
    return ff;
495
#endif
496
}
497

    
498
/* Our own implementation of dirent-like functionality to scan directories. */
499
struct gmx_directory
500
{
501
#ifdef HAVE_DIRENT_H
502
    DIR  *               dirent_handle;
503
#elif (defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64)
504
    intptr_t             windows_handle;
505
    struct _finddata_t   finddata;
506
    int                  first;
507
#else
508
    int      dummy;
509
#endif
510
};
511

    
512

    
513
int
514
gmx_directory_open(gmx_directory_t *p_gmxdir,const char *dirname)
515
{
516
    struct gmx_directory *  gmxdir;
517
    int                     rc;
518
    
519
    snew(gmxdir,1);
520
    
521
    *p_gmxdir = gmxdir;
522
    
523
#ifdef HAVE_DIRENT_H
524
    if( (gmxdir->dirent_handle = opendir(dirname)) != NULL)
525
    {
526
        rc = 0;
527
    }
528
    else 
529
    {
530
        sfree(gmxdir);
531
        *p_gmxdir = NULL;
532
        rc        = EINVAL;
533
    }
534
#elif (defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64)
535
    
536
    if(dirname!=NULL && strlen(dirname)>0)
537
    {
538
        char *     tmpname;
539
        size_t     namelength;
540
        int        len;
541
        
542
        len = strlen(dirname);
543
        snew(tmpname,len+3);
544
        
545
        strncpy(tmpname,dirname,len+1);
546
        
547
        /* Remove possible trailing directory separator */
548
        if(tmpname[len]=='/' || tmpname[len]=='\\')
549
        {
550
            tmpname[len]='\0';
551
        }
552
        
553
        /* Add wildcard */
554
        strcat(tmpname,"/*");
555
        
556
        gmxdir->first = 1;
557
        if( (gmxdir->windows_handle=_findfirst(tmpname,&gmxdir->finddata))>0L)
558
        {
559
            rc = 0;
560
        }
561
        else
562
        {
563
            if(errno=EINVAL)
564
            {
565
                sfree(gmxdir);
566
                *p_gmxdir = NULL;
567
                rc        = EINVAL;                
568
            }
569
            else
570
            {
571
                rc        = 0;
572
            }
573
        }
574
    }
575
    else
576
    {
577
        rc = EINVAL;
578
    }
579
#else
580
    gmx_fatal(FARGS,
581
              "Source compiled without POSIX dirent or windows support - cannot scan directories.\n"
582
              "In the very unlikely event this is not a compile-time mistake you could consider\n"
583
              "implementing support for your platform in futil.c, but contact the developers\n"
584
              "to make sure it's really necessary!\n");
585
    rc = -1;
586
#endif
587
    return rc;
588
}
589

    
590

    
591
int
592
gmx_directory_nextfile(gmx_directory_t gmxdir,char *name,int maxlength_name)
593
{
594
    int                     rc;
595
    
596
#ifdef HAVE_DIRENT_H
597
    
598
    struct dirent           tmp_dirent;
599
    struct dirent *         p;
600
    
601
    
602
    if(gmxdir!=NULL && gmxdir->dirent_handle!=NULL)
603
    {
604
        rc = readdir_r(gmxdir->dirent_handle,&tmp_dirent,&p);
605
        if(p!=NULL && rc==0)
606
        {
607
            strncpy(name,tmp_dirent.d_name,maxlength_name);
608
        }
609
        else
610
        {
611
            name[0] = '\0';
612
            rc      = ENOENT;
613
        }
614
    }
615
    else 
616
    {
617
        name[0] = '\0';
618
        rc      = EINVAL;
619
    }
620
    
621
#elif (defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64)
622
    
623
    if(gmxdir!=NULL)
624
    {
625
        if(gmxdir->windows_handle<=0)
626
        {
627
            
628
            name[0] = '\0';
629
            rc      = ENOENT;
630
        }
631
        else if(gmxdir->first==1)
632
        {
633
            strncpy(name,gmxdir->finddata.name,maxlength_name);
634
            rc            = 0;
635
            gmxdir->first = 0;
636
        }
637
        else
638
        {
639
            if(_findnext(gmxdir->windows_handle,&gmxdir->finddata)==0)
640
            {
641
                strncpy(name,gmxdir->finddata.name,maxlength_name);
642
                rc      = 0;
643
            }
644
            else
645
            {
646
                name[0] = '\0';
647
                rc      = ENOENT;
648
            }
649
        }
650
    }
651
    
652
#else
653
    gmx_fatal(FARGS,
654
              "Source compiled without POSIX dirent or windows support - cannot scan directories.\n");
655
    rc = -1;
656
#endif
657
    return rc;
658
}
659

    
660

    
661
int 
662
gmx_directory_close(gmx_directory_t gmxdir)
663
{
664
    int                     rc;
665
#ifdef HAVE_DIRENT_H
666
    rc = (gmxdir != NULL) ? closedir(gmxdir->dirent_handle) : EINVAL;
667
#elif (defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64)
668
    rc = (gmxdir != NULL) ? _findclose(gmxdir->windows_handle) : EINVAL;
669
#else
670
    gmx_fatal(FARGS,
671
              "Source compiled without POSIX dirent or windows support - cannot scan directories.\n");
672
    rc = -1;
673
#endif
674
    
675
    sfree(gmxdir);
676
    return rc;
677
}
678

    
679

    
680

    
681

    
682
bool search_subdirs(const char *parent, char *libdir)
683
{
684
    char *ptr;
685
    bool found;
686

    
687
    /* Search a few common subdirectory names for the gromacs library dir */
688
    sprintf(libdir,"%s%cshare%ctop%cgurgle.dat",parent,
689
            DIR_SEPARATOR,DIR_SEPARATOR,DIR_SEPARATOR);
690
    found=gmx_fexist(libdir);
691
    if(!found) {
692
        sprintf(libdir,"%s%cshare%cgromacs%ctop%cgurgle.dat",parent,
693
                DIR_SEPARATOR,DIR_SEPARATOR,
694
                DIR_SEPARATOR,DIR_SEPARATOR);
695
        found=gmx_fexist(libdir);
696
    }    
697
    if(!found) {
698
        sprintf(libdir,"%s%cshare%cgromacs-%s%ctop%cgurgle.dat",parent,
699
                DIR_SEPARATOR,DIR_SEPARATOR,VERSION,
700
                DIR_SEPARATOR,DIR_SEPARATOR);
701
        found=gmx_fexist(libdir);
702
    }    
703
    if(!found) {
704
        sprintf(libdir,"%s%cshare%cgromacs%cgromacs-%s%ctop%cgurgle.dat",parent,
705
                DIR_SEPARATOR,DIR_SEPARATOR,DIR_SEPARATOR,
706
                VERSION,DIR_SEPARATOR,DIR_SEPARATOR);
707
        found=gmx_fexist(libdir);
708
    }    
709

    
710
    /* Remove the gurgle.dat part from libdir if we found something */
711
    if(found) {
712
        ptr=strrchr(libdir,DIR_SEPARATOR); /* slash or backslash always present, no check necessary */
713
        *ptr='\0';
714
    }
715
    return found;
716
}
717

    
718

    
719
/* Check if the program name begins with "/" on unix/cygwin, or
720
 * with "\" or "X:\" on windows. If not, the program name
721
 * is relative to the current directory.
722
 */
723
static bool filename_is_absolute(char *name)
724
{
725
#if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
726
    return ((name[0] == DIR_SEPARATOR) || ((strlen(name)>3) && strncmp(name+1,":\\",2)) == 0);
727
#else
728
    return (name[0] == DIR_SEPARATOR);
729
#endif
730
}
731

    
732
bool get_libdir(char *libdir)
733
{
734
    char bin_name[512];
735
    char buf[512];
736
    char full_path[GMX_PATH_MAX];
737
    char test_file[GMX_PATH_MAX];
738
    char system_path[GMX_PATH_MAX];
739
    char *dir,*ptr,*s,*pdum;
740
    bool found=FALSE;
741
    int i;
742

    
743
    if (Program() != NULL)
744
    {
745

    
746
    /* First - detect binary name */
747
    strncpy(bin_name,Program(),512);
748

    
749
    /* On windows & cygwin we need to add the .exe extension
750
     * too, or we wont be able to detect that the file exists
751
     */
752
#if (defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64 || defined __CYGWIN__ || defined __CYGWIN32__)
753
    if(strlen(bin_name)<3 || strncasecmp(bin_name+strlen(bin_name)-4,".exe",4))
754
        strcat(bin_name,".exe");
755
#endif
756

    
757
    /* Only do the smart search part if we got a real name */
758
    if (NULL!=bin_name && strncmp(bin_name,"GROMACS",512)) {
759

    
760
        if (!strchr(bin_name,DIR_SEPARATOR)) {
761
            /* No slash or backslash in name means it must be in the path - search it! */
762
            /* Add the local dir since it is not in the path on windows */
763
#if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
764
            pdum=_getcwd(system_path,sizeof(system_path)-1);
765
#else
766
            pdum=getcwd(system_path,sizeof(system_path)-1);
767
#endif
768
            s=system_path;
769
            found=FALSE;
770
            while(!found && (dir=gmx_strsep(&s, PATH_SEPARATOR)) != NULL)
771
            {
772
                sprintf(full_path,"%s%c%s",dir,DIR_SEPARATOR,bin_name);
773
                found=gmx_fexist(full_path);
774
            }
775
            if (!found && (s=getenv("PATH")) != NULL)
776
            {
777
                while(!found && (dir=gmx_strsep(&s, PATH_SEPARATOR)) != NULL)
778
                {
779
                    sprintf(full_path,"%s%c%s",dir,DIR_SEPARATOR,bin_name);
780
                    found=gmx_fexist(full_path);
781
                }
782
            }
783
            if (!found)
784
            {
785
                return FALSE;
786
            }
787
        } else if (!filename_is_absolute(bin_name)) {
788
            /* name contains directory separators, but 
789
             * it does not start at the root, i.e.
790
             * name is relative to the current dir 
791
             */
792
#if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
793
            pdum=_getcwd(buf,sizeof(buf)-1);
794
#else
795
            pdum=getcwd(buf,sizeof(buf)-1);
796
#endif
797
            sprintf(full_path,"%s%c%s",buf,DIR_SEPARATOR,bin_name);
798
        } else {
799
            strncpy(full_path,bin_name,GMX_PATH_MAX);
800
        }
801

    
802
        /* Now we should have a full path and name in full_path,
803
         * but on unix it might be a link, or a link to a link to a link..
804
         */
805
#if (!defined WIN32 && !defined _WIN32 && !defined WIN64 && !defined _WIN64)
806
        while( (i=readlink(full_path,buf,sizeof(buf)-1)) > 0 ) {
807
            buf[i]='\0';
808
            /* If it doesn't start with "/" it is relative */
809
            if (buf[0]!=DIR_SEPARATOR) {
810
                strncpy(strrchr(full_path,DIR_SEPARATOR)+1,buf,GMX_PATH_MAX);
811
            } else
812
                strncpy(full_path,buf,GMX_PATH_MAX);
813
        }
814
#endif
815

    
816
        /* Remove the executable name - it always contains at least one slash */
817
        *(strrchr(full_path,DIR_SEPARATOR)+1)='\0';
818
        /* Now we have the full path to the gromacs executable.
819
         * Use it to find the library dir. 
820
         */
821
        found=FALSE;
822
        while(!found && ( (ptr=strrchr(full_path,DIR_SEPARATOR)) != NULL ) ) {
823
            *ptr='\0';
824
            found=search_subdirs(full_path,libdir);
825
        }
826
    }
827
    }
828
    /* End of smart searching. If we didn't find it in our parent tree,
829
     * or if the program name wasn't set, at least try some standard 
830
     * locations before giving up, in case we are running from e.g. 
831
     * a users home directory. This only works on unix or cygwin...
832
     */
833
#if ((!defined WIN32 && !defined _WIN32 && !defined WIN64 && !defined _WIN64) || defined __CYGWIN__ || defined __CYGWIN32__)
834
    if(!found) 
835
        found=search_subdirs("/usr/local",libdir);
836
    if(!found) 
837
        found=search_subdirs("/usr",libdir);
838
    if(!found) 
839
        found=search_subdirs("/opt",libdir);
840
#endif
841
    return found;
842
}
843

    
844

    
845
char *low_gmxlibfn(const char *file, bool bFatal)
846
{
847
    char *ret;
848
    char *lib,*dir;
849
    char buf[1024];
850
    char libpath[GMX_PATH_MAX];
851
    bool env_is_set=FALSE;
852
    char   *s,tmppath[GMX_PATH_MAX];
853

    
854
    /* GMXLIB can be a path now */
855
    lib=getenv("GMXLIB");
856
    if (lib != NULL)
857
    {
858
        env_is_set=TRUE;
859
        strncpy(libpath,lib,GMX_PATH_MAX);
860
    } 
861
    else if (!get_libdir(libpath))
862
    {
863
        strncpy(libpath,GMXLIBDIR,GMX_PATH_MAX);
864
    }
865

    
866
    ret = NULL;
867
    if (gmx_fexist(file))
868
    {
869
        ret = strdup(file);
870
    }
871
    else 
872
    {
873
        strncpy(tmppath,libpath,GMX_PATH_MAX);
874
        s=tmppath;
875
        while(ret == NULL && (dir=gmx_strsep(&s, PATH_SEPARATOR)) != NULL )
876
        {
877
            sprintf(buf,"%s%c%s",dir,DIR_SEPARATOR,file);
878
            if (gmx_fexist(buf))
879
            {
880
                ret = strdup(buf);
881
            }
882
        }
883
        if (ret == NULL && bFatal) 
884
        {
885
            if (env_is_set) 
886
            {
887
                gmx_fatal(FARGS,"Library file %s not found in current dir nor in your GMXLIB path.\n",file);
888
            }
889
            else
890
            {
891
                gmx_fatal(FARGS,"Library file %s not found in current dir nor in default directories.\n"
892
                        "(You can set the directories to search with the GMXLIB path variable)",file);
893
            }
894
        }
895
    }
896

    
897
    return ret;
898
}
899

    
900

    
901

    
902

    
903

    
904
FILE *low_libopen(const char *file,bool bFatal)
905
{
906
    FILE *ff;
907
    char *fn;
908

    
909
    fn=low_gmxlibfn(file,bFatal);
910

    
911
    if (fn==NULL) {
912
        ff=NULL;
913
    } else {
914
      if (debug)
915
        fprintf(debug,"Opening library file %s\n",fn);
916
      ff=fopen(fn,"r");
917
    }
918
    sfree(fn);
919

    
920
    return ff;
921
}
922

    
923
char *gmxlibfn(const char *file)
924
{
925
    return low_gmxlibfn(file,TRUE);
926
}
927

    
928
FILE *libopen(const char *file)
929
{
930
    return low_libopen(file,TRUE);
931
}
932

    
933
void gmx_tmpnam(char *buf)
934
{
935
    int i,len,fd;
936

    
937
    if ((len = strlen(buf)) < 7)
938
        gmx_fatal(FARGS,"Buf passed to gmx_tmpnam must be at least 7 bytes long");
939
    for(i=len-6; (i<len); i++) {
940
        buf[i] = 'X';
941
    }
942
    /* mktemp is dangerous and we should use mkstemp instead, but 
943
     * since windows doesnt support it we have to separate the cases.
944
     * 20090307: mktemp deprecated, use iso c++ _mktemp instead.
945
     */
946
#if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
947
    _mktemp(buf);
948
#else
949
    fd = mkstemp(buf);
950

    
951
    switch (fd) {
952
        case EINVAL:
953
            gmx_fatal(FARGS,"Invalid template %s for mkstemp",buf);
954
            break;
955
        case EEXIST:
956
            gmx_fatal(FARGS,"mkstemp created existing file",buf);
957
            break;
958
        case EACCES: 
959
            gmx_fatal(FARGS,"Permission denied for opening %s",buf);
960
            break;
961
        default:
962
            break;
963
    }   
964
    close(fd);
965
#endif
966
    /* name in Buf should now be OK */
967
}
968

    
969
int gmx_truncatefile(char *path, gmx_off_t length)
970
{
971
#ifdef _MSC_VER
972
    /* Microsoft visual studio does not have "truncate" */
973
    HANDLE fh;
974
    LARGE_INTEGER win_length;
975

    
976
    win_length.QuadPart = length;
977

    
978
    fh = CreateFile(path,GENERIC_READ | GENERIC_WRITE,0,NULL,
979
            OPEN_EXISTING,0,NULL);
980
    SetFilePointerEx(fh,win_length,NULL,FILE_BEGIN);
981
    SetEndOfFile(fh);
982
    CloseHandle(fh);
983

    
984
    return 0;
985
#else
986
    return truncate(path,length);
987
#endif
988
}
989

    
990

    
991
int gmx_file_rename(const char *oldname, const char *newname)
992
{
993
#if (!(defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)))
994
    /* under unix, rename() is atomic (at least, it should be). */
995
    return rename(oldname, newname);
996
#else
997
    if (MoveFileEx(oldname, newname, 
998
                   MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH))
999
        return 0;
1000
    else
1001
        return 1;
1002
#endif
1003
}
1004

    
1005
int gmx_file_copy(const char *oldname, const char *newname, bool copy_if_empty)
1006
{
1007
/* the full copy buffer size: */
1008
#define FILECOPY_BUFSIZE (1<<16)
1009
    /* POSIX doesn't support any of the above. */
1010
    FILE *in=NULL; 
1011
    FILE *out=NULL;
1012
    char *buf;
1013

    
1014
    snew(buf, FILECOPY_BUFSIZE); 
1015

    
1016
    in=fopen(oldname, "rb");
1017
    if (!in)
1018
        goto error;
1019

    
1020
    /* If we don't copy when empty, we postpone opening the file
1021
       until we're actually ready to write. */
1022
    if (copy_if_empty)
1023
    {
1024
        out=fopen(newname, "wb");
1025
        if (!out)
1026
            goto error;
1027
    }
1028

    
1029
    while(!feof(in))
1030
    {
1031
        size_t nread;
1032
        
1033
        nread=fread(buf, sizeof(char), FILECOPY_BUFSIZE, in);
1034
        if (nread>0)
1035
        {
1036
            size_t ret;
1037
            if (!out)
1038
            {
1039
                out=fopen(newname, "wb");
1040
                if (!out)
1041
                    goto error;
1042
            }
1043
            ret=fwrite(buf, sizeof(char), nread, out);
1044
            if (ret!=nread)
1045
            {
1046
                goto error;
1047
            }
1048
        }
1049
        if (ferror(in))
1050
            goto error;
1051
    }
1052
    sfree(buf);
1053
    fclose(in);
1054
    fclose(out);
1055
    return 0;
1056
error:
1057
    sfree(buf);
1058
    if (in)
1059
        fclose(in);
1060
    if (out)
1061
        fclose(out);
1062
    return 1;
1063
#undef FILECOPY_BUFSIZE
1064
}
1065

    
1066

    
1067
int gmx_fsync(FILE *fp)
1068
{
1069
    int rc=0;
1070

    
1071
#ifdef GMX_FAHCORE
1072
    /* the fahcore defines its own os-independent fsync */
1073
    rc=gmx_fsync_lowlevel(fio->fp);
1074
#else /* GMX_FAHCORE */
1075
    {
1076
        int fn=-1;
1077

    
1078
        /* get the file number */
1079
#if defined(HAVE_FILENO)
1080
        fn= fileno(fp);
1081
#elif defined(HAVE__FILENO)
1082
        fn= _fileno(fp);
1083
#endif
1084

    
1085
        /* do the actual fsync */
1086
        if (fn >= 0)
1087
        {
1088
#if (defined(HAVE_FSYNC))
1089
            rc=fsync(fn);
1090
#elif (defined(HAVE__COMMIT)) 
1091
            rc=_commit(fn);
1092
#endif
1093
        }
1094
    }
1095
#endif /* GMX_FAHCORE */
1096

    
1097
    /* We check for these error codes this way because POSIX requires them
1098
       to be defined, and using anything other than macros is unlikely: */
1099
#ifdef EINTR
1100
    /* we don't want to report an error just because fsync() caught a signal.
1101
       For our purposes, we can just ignore this. */
1102
    if (rc && errno==EINTR)
1103
        rc=0;
1104
#endif
1105
#ifdef EINVAL
1106
    /* we don't want to report an error just because we tried to fsync() 
1107
       stdout, a socket or a pipe. */
1108
    if (rc && errno==EINVAL)
1109
        rc=0;
1110
#endif
1111
    return rc;
1112
}
1113

    
1114

    
1115