7ce203e7a53e892946c45762ea0bcb4e6a674b4d
[alexxy/gromacs.git] / src / gmxlib / futil.c
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 #define GMX_BINNAME_MAX 512
735     char bin_name[GMX_BINNAME_MAX];
736     char buf[GMX_BINNAME_MAX];
737     char full_path[GMX_PATH_MAX+GMX_BINNAME_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     if (strlen(Program()) >= GMX_BINNAME_MAX)
748     {
749         gmx_fatal(FARGS,"The name of the binary is longer than the allowed buffer size (%d):\n'%s'",GMX_BINNAME_MAX,Program());
750     }
751     strncpy(bin_name,Program(),GMX_BINNAME_MAX-1);
752
753     /* On windows & cygwin we need to add the .exe extension
754      * too, or we wont be able to detect that the file exists
755      */
756 #if (defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64 || defined __CYGWIN__ || defined __CYGWIN32__)
757     if(strlen(bin_name)<3 || gmx_strncasecmp(bin_name+strlen(bin_name)-4,".exe",4))
758         strcat(bin_name,".exe");
759 #endif
760
761     /* Only do the smart search part if we got a real name */
762     if (NULL!=bin_name && strncmp(bin_name,"GROMACS",GMX_BINNAME_MAX)) {
763
764         if (!strchr(bin_name,DIR_SEPARATOR)) {
765             /* No slash or backslash in name means it must be in the path - search it! */
766             /* Add the local dir since it is not in the path on windows */
767 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
768             pdum=_getcwd(system_path,sizeof(system_path)-1);
769 #else
770             pdum=getcwd(system_path,sizeof(system_path)-1);
771 #endif
772             sprintf(full_path,"%s%c%s",system_path,DIR_SEPARATOR,bin_name);
773             found = gmx_fexist(full_path);
774             if (!found && (s=getenv("PATH")) != NULL)
775             {
776                 char *dupped;
777                 
778                 dupped=gmx_strdup(s);
779                 s=dupped;
780                 while(!found && (dir=gmx_strsep(&s, PATH_SEPARATOR)) != NULL)
781                 {
782                     sprintf(full_path,"%s%c%s",dir,DIR_SEPARATOR,bin_name);
783                     found = gmx_fexist(full_path);
784                 }
785                 sfree(dupped);
786             }
787             if (!found)
788             {
789                 return FALSE;
790             }
791         } else if (!filename_is_absolute(bin_name)) {
792             /* name contains directory separators, but 
793              * it does not start at the root, i.e.
794              * name is relative to the current dir 
795              */
796 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
797             pdum=_getcwd(buf,sizeof(buf)-1);
798 #else
799             pdum=getcwd(buf,sizeof(buf)-1);
800 #endif
801             sprintf(full_path,"%s%c%s",buf,DIR_SEPARATOR,bin_name);
802         } else {
803             strncpy(full_path,bin_name,GMX_PATH_MAX);
804         }
805
806         /* Now we should have a full path and name in full_path,
807          * but on unix it might be a link, or a link to a link to a link..
808          */
809 #if (!defined WIN32 && !defined _WIN32 && !defined WIN64 && !defined _WIN64)
810         while( (i=readlink(full_path,buf,sizeof(buf)-1)) > 0 ) {
811             buf[i]='\0';
812             /* If it doesn't start with "/" it is relative */
813             if (buf[0]!=DIR_SEPARATOR) {
814                 strncpy(strrchr(full_path,DIR_SEPARATOR)+1,buf,GMX_PATH_MAX);
815             } else
816                 strncpy(full_path,buf,GMX_PATH_MAX);
817         }
818 #endif
819
820         /* Remove the executable name - it always contains at least one slash */
821         *(strrchr(full_path,DIR_SEPARATOR)+1)='\0';
822         /* Now we have the full path to the gromacs executable.
823          * Use it to find the library dir. 
824          */
825         found=FALSE;
826         while(!found && ( (ptr=strrchr(full_path,DIR_SEPARATOR)) != NULL ) ) {
827             *ptr='\0';
828             found=search_subdirs(full_path,libdir);
829         }
830     }
831     }
832     /* End of smart searching. If we didn't find it in our parent tree,
833      * or if the program name wasn't set, at least try some standard 
834      * locations before giving up, in case we are running from e.g. 
835      * a users home directory. This only works on unix or cygwin...
836      */
837 #if ((!defined WIN32 && !defined _WIN32 && !defined WIN64 && !defined _WIN64) || defined __CYGWIN__ || defined __CYGWIN32__)
838     if(!found) 
839         found=search_subdirs("/usr/local",libdir);
840     if(!found) 
841         found=search_subdirs("/usr",libdir);
842     if(!found) 
843         found=search_subdirs("/opt",libdir);
844 #endif
845     return found;
846 }
847
848
849 char *low_gmxlibfn(const char *file, bool bAddCWD, bool bFatal)
850 {
851     char *ret;
852     char *lib,*dir;
853     char buf[1024];
854     char libpath[GMX_PATH_MAX];
855     bool env_is_set=FALSE;
856     char   *s,tmppath[GMX_PATH_MAX];
857
858     /* GMXLIB can be a path now */
859     lib=getenv("GMXLIB");
860     if (lib != NULL)
861     {
862         env_is_set=TRUE;
863         strncpy(libpath,lib,GMX_PATH_MAX);
864     } 
865     else if (!get_libdir(libpath))
866     {
867         strncpy(libpath,GMXLIBDIR,GMX_PATH_MAX);
868     }
869
870     ret = NULL;
871     if (bAddCWD && gmx_fexist(file))
872     {
873         ret = strdup(file);
874     }
875     else 
876     {
877         strncpy(tmppath,libpath,GMX_PATH_MAX);
878         s=tmppath;
879         while(ret == NULL && (dir=gmx_strsep(&s, PATH_SEPARATOR)) != NULL )
880         {
881             sprintf(buf,"%s%c%s",dir,DIR_SEPARATOR,file);
882             if (gmx_fexist(buf))
883             {
884                 ret = strdup(buf);
885             }
886         }
887         if (ret == NULL && bFatal) 
888         {
889             if (env_is_set) 
890             {
891                 gmx_fatal(FARGS,
892                           "Library file %s not found %sin your GMXLIB path.",
893                           bAddCWD ? "in current dir nor " : "",file);
894             }
895             else
896             {
897                 gmx_fatal(FARGS,
898                           "Library file %s not found %sin default directories.\n"
899                         "(You can set the directories to search with the GMXLIB path variable)",
900                           bAddCWD ? "in current dir nor " : "",file);
901             }
902         }
903     }
904
905     return ret;
906 }
907
908
909
910
911
912 FILE *low_libopen(const char *file,bool bFatal)
913 {
914     FILE *ff;
915     char *fn;
916
917     fn=low_gmxlibfn(file,TRUE,bFatal);
918
919     if (fn==NULL) {
920         ff=NULL;
921     } else {
922       if (debug)
923         fprintf(debug,"Opening library file %s\n",fn);
924       ff=fopen(fn,"r");
925     }
926     sfree(fn);
927
928     return ff;
929 }
930
931 char *gmxlibfn(const char *file)
932 {
933     return low_gmxlibfn(file,TRUE,TRUE);
934 }
935
936 FILE *libopen(const char *file)
937 {
938     return low_libopen(file,TRUE);
939 }
940
941 void gmx_tmpnam(char *buf)
942 {
943     int i,len,fd;
944
945     if ((len = strlen(buf)) < 7)
946         gmx_fatal(FARGS,"Buf passed to gmx_tmpnam must be at least 7 bytes long");
947     for(i=len-6; (i<len); i++) {
948         buf[i] = 'X';
949     }
950     /* mktemp is dangerous and we should use mkstemp instead, but 
951      * since windows doesnt support it we have to separate the cases.
952      * 20090307: mktemp deprecated, use iso c++ _mktemp instead.
953      */
954 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
955     _mktemp(buf);
956 #else
957     fd = mkstemp(buf);
958
959     switch (fd) {
960         case EINVAL:
961             gmx_fatal(FARGS,"Invalid template %s for mkstemp",buf);
962             break;
963         case EEXIST:
964             gmx_fatal(FARGS,"mkstemp created existing file",buf);
965             break;
966         case EACCES: 
967             gmx_fatal(FARGS,"Permission denied for opening %s",buf);
968             break;
969         default:
970             break;
971     }   
972     close(fd);
973 #endif
974     /* name in Buf should now be OK */
975 }
976
977 int gmx_truncatefile(char *path, gmx_off_t length)
978 {
979 #ifdef _MSC_VER
980     /* Microsoft visual studio does not have "truncate" */
981     HANDLE fh;
982     LARGE_INTEGER win_length;
983
984     win_length.QuadPart = length;
985
986     fh = CreateFile(path,GENERIC_READ | GENERIC_WRITE,0,NULL,
987             OPEN_EXISTING,0,NULL);
988     SetFilePointerEx(fh,win_length,NULL,FILE_BEGIN);
989     SetEndOfFile(fh);
990     CloseHandle(fh);
991
992     return 0;
993 #else
994     return truncate(path,length);
995 #endif
996 }
997
998
999 int gmx_file_rename(const char *oldname, const char *newname)
1000 {
1001 #if (!(defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)))
1002     /* under unix, rename() is atomic (at least, it should be). */
1003     return rename(oldname, newname);
1004 #else
1005     if (MoveFileEx(oldname, newname, 
1006                    MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH))
1007         return 0;
1008     else
1009         return 1;
1010 #endif
1011 }
1012
1013 int gmx_file_copy(const char *oldname, const char *newname, bool copy_if_empty)
1014 {
1015 /* the full copy buffer size: */
1016 #define FILECOPY_BUFSIZE (1<<16)
1017     FILE *in=NULL; 
1018     FILE *out=NULL;
1019     char *buf;
1020
1021     snew(buf, FILECOPY_BUFSIZE); 
1022
1023     in=fopen(oldname, "rb");
1024     if (!in)
1025         goto error;
1026
1027     /* If we don't copy when empty, we postpone opening the file
1028        until we're actually ready to write. */
1029     if (copy_if_empty)
1030     {
1031         out=fopen(newname, "wb");
1032         if (!out)
1033             goto error;
1034     }
1035
1036     while(!feof(in))
1037     {
1038         size_t nread;
1039         
1040         nread=fread(buf, sizeof(char), FILECOPY_BUFSIZE, in);
1041         if (nread>0)
1042         {
1043             size_t ret;
1044             if (!out)
1045             {
1046                 /* so this is where we open when copy_if_empty is false:
1047                    here we know we read something. */
1048                 out=fopen(newname, "wb");
1049                 if (!out)
1050                     goto error;
1051             }
1052             ret=fwrite(buf, sizeof(char), nread, out);
1053             if (ret!=nread)
1054             {
1055                 goto error;
1056             }
1057         }
1058         if (ferror(in))
1059             goto error;
1060     }
1061     sfree(buf);
1062     fclose(in);
1063     fclose(out);
1064     return 0;
1065 error:
1066     sfree(buf);
1067     if (in)
1068         fclose(in);
1069     if (out)
1070         fclose(out);
1071     return 1;
1072 #undef FILECOPY_BUFSIZE
1073 }
1074
1075
1076 int gmx_fsync(FILE *fp)
1077 {
1078     int rc=0;
1079
1080 #ifdef GMX_FAHCORE
1081     /* the fahcore defines its own os-independent fsync */
1082     rc=fah_fsync(fp);
1083 #else /* GMX_FAHCORE */
1084     {
1085         int fn=-1;
1086
1087         /* get the file number */
1088 #if defined(HAVE_FILENO)
1089         fn= fileno(fp);
1090 #elif defined(HAVE__FILENO)
1091         fn= _fileno(fp);
1092 #endif
1093
1094         /* do the actual fsync */
1095         if (fn >= 0)
1096         {
1097 #if (defined(HAVE_FSYNC))
1098             rc=fsync(fn);
1099 #elif (defined(HAVE__COMMIT)) 
1100             rc=_commit(fn);
1101 #endif
1102         }
1103     }
1104 #endif /* GMX_FAHCORE */
1105
1106     /* We check for these error codes this way because POSIX requires them
1107        to be defined, and using anything other than macros is unlikely: */
1108 #ifdef EINTR
1109     /* we don't want to report an error just because fsync() caught a signal.
1110        For our purposes, we can just ignore this. */
1111     if (rc && errno==EINTR)
1112         rc=0;
1113 #endif
1114 #ifdef EINVAL
1115     /* we don't want to report an error just because we tried to fsync() 
1116        stdout, a socket or a pipe. */
1117     if (rc && errno==EINVAL)
1118         rc=0;
1119 #endif
1120     return rc;
1121 }
1122
1123
1124