Add missing linker flags
[alexxy/gromacs.git] / src / gromacs / 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 #ifdef HAVE_UNISTD_H
53 #include <unistd.h>
54 #endif
55
56 #ifdef GMX_NATIVE_WINDOWS
57 #include <direct.h>
58 #include <io.h>
59 #endif
60
61 #include "sysstuff.h"
62 #include "string2.h"
63 #include "futil.h"
64 #include "network.h"
65 #include "gmx_fatal.h"
66 #include "smalloc.h"
67 #include "statutil.h"
68
69
70 #ifdef GMX_THREAD_MPI
71 #include "thread_mpi.h"
72 #endif
73
74 /* Windows file stuff, only necessary for visual studio */
75 #ifdef _MSC_VER
76 #include "windows.h"
77 #endif
78
79 /* we keep a linked list of all files opened through pipes (i.e. 
80    compressed or .gzipped files. This way we can distinguish between them
81    without having to change the semantics of reading from/writing to files) 
82    */
83 typedef struct t_pstack {
84     FILE   *fp;
85     struct t_pstack *prev;
86 } t_pstack;
87
88 static t_pstack *pstack=NULL;
89 static gmx_bool     bUnbuffered=FALSE;
90
91 #ifdef GMX_THREAD_MPI
92 /* this linked list is an intrinsically globally shared object, so we have
93    to protect it with mutexes */
94 static tMPI_Thread_mutex_t pstack_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
95 #endif
96
97 void no_buffers(void)
98 {
99     bUnbuffered=TRUE;
100 }
101
102 void push_ps(FILE *fp)
103 {
104     t_pstack *ps;
105
106 #ifdef GMX_THREAD_MPI
107     tMPI_Thread_mutex_lock(&pstack_mutex);
108 #endif
109
110     snew(ps,1);
111     ps->fp   = fp;
112     ps->prev = pstack;
113     pstack   = ps;
114 #ifdef GMX_THREAD_MPI
115     tMPI_Thread_mutex_unlock(&pstack_mutex);
116 #endif
117 }
118
119 #ifdef GMX_FAHCORE
120 /* don't use pipes!*/
121 #define popen fah_fopen
122 #define pclose fah_fclose
123 #define SKIP_FFOPS 1
124 #else
125 #ifdef ffclose
126 #undef ffclose
127 #endif
128 #endif
129
130 #ifndef GMX_FAHCORE
131 #ifndef HAVE_PIPES
132 static FILE *popen(const char *nm,const char *mode)
133 {
134     gmx_impl("Sorry no pipes...");
135
136     return NULL;
137 }
138
139 static int pclose(FILE *fp)
140 {
141     gmx_impl("Sorry no pipes...");
142
143     return 0;
144 }
145 #endif
146 #endif
147
148 int ffclose(FILE *fp)
149 {
150 #ifdef SKIP_FFOPS
151     return fclose(fp);
152 #else
153     t_pstack *ps,*tmp;
154     int ret=0;
155 #ifdef GMX_THREAD_MPI
156     tMPI_Thread_mutex_lock(&pstack_mutex);
157 #endif
158
159     ps=pstack;
160     if (ps == NULL) {
161         if (fp != NULL) 
162             ret = fclose(fp);
163     }
164     else if (ps->fp == fp) {
165         if (fp != NULL)
166             ret = pclose(fp);
167         pstack=pstack->prev;
168         sfree(ps);
169     }
170     else {
171         while ((ps->prev != NULL) && (ps->prev->fp != fp))
172             ps=ps->prev;
173         if ((ps->prev != NULL) && ps->prev->fp == fp) {
174             if (ps->prev->fp != NULL)
175                 ret = pclose(ps->prev->fp);
176             tmp=ps->prev;
177             ps->prev=ps->prev->prev;
178             sfree(tmp);
179         }
180         else {
181             if (fp != NULL)
182                 ret = fclose(fp);
183         }
184     }
185 #ifdef GMX_THREAD_MPI
186     tMPI_Thread_mutex_unlock(&pstack_mutex);
187 #endif
188     return ret;
189 #endif
190 }
191
192
193 #ifdef rewind
194 #undef rewind
195 #endif
196
197 void frewind(FILE *fp)
198 {
199     t_pstack *ps;
200 #ifdef GMX_THREAD_MPI
201     tMPI_Thread_mutex_lock(&pstack_mutex);
202 #endif
203
204     ps=pstack;
205     while (ps != NULL) {
206         if (ps->fp == fp) {
207             fprintf(stderr,"Cannot rewind compressed file!\n");
208 #ifdef GMX_THREAD_MPI
209             tMPI_Thread_mutex_unlock(&pstack_mutex);
210 #endif
211             return;
212         }
213         ps=ps->prev;
214     }
215     rewind(fp);
216 #ifdef GMX_THREAD_MPI
217     tMPI_Thread_mutex_unlock(&pstack_mutex);
218 #endif
219 }
220
221 int gmx_fseek(FILE *stream, gmx_off_t offset, int whence)
222 {
223 #ifdef HAVE_FSEEKO
224     return fseeko(stream, offset, whence);
225 #else
226 #ifdef HAVE__FSEEKI64
227     return _fseeki64(stream, offset, whence);
228 #else
229     return fseek(stream, offset, whence);
230 #endif
231 #endif
232 }
233
234 gmx_off_t gmx_ftell(FILE *stream)
235 {
236 #ifdef HAVE_FSEEKO
237     return ftello(stream);
238 #else
239 #ifdef HAVE__FSEEKI64 
240     return _ftelli64(stream);
241 #else
242     return ftell(stream);
243 #endif
244 #endif
245 }
246
247
248 gmx_bool is_pipe(FILE *fp)
249 {
250     t_pstack *ps;
251 #ifdef GMX_THREAD_MPI
252     tMPI_Thread_mutex_lock(&pstack_mutex);
253 #endif
254
255     ps=pstack;
256     while (ps != NULL) {
257         if (ps->fp == fp) {
258 #ifdef GMX_THREAD_MPI
259             tMPI_Thread_mutex_unlock(&pstack_mutex);
260 #endif
261             return TRUE;
262         }
263         ps=ps->prev;
264     }
265 #ifdef GMX_THREAD_MPI
266     tMPI_Thread_mutex_unlock(&pstack_mutex);
267 #endif
268     return FALSE;
269 }
270
271
272 static FILE *uncompress(const char *fn,const char *mode)
273 {
274     FILE *fp;
275     char buf[256];
276
277     sprintf(buf,"uncompress -c < %s",fn);
278     fprintf(stderr,"Going to execute '%s'\n",buf);
279     if ((fp=popen(buf,mode)) == NULL)
280         gmx_open(fn);
281     push_ps(fp);
282
283     return fp;
284 }
285
286 static FILE *gunzip(const char *fn,const char *mode)
287 {
288     FILE *fp;
289     char buf[256];
290
291     sprintf(buf,"gunzip -c < %s",fn);
292     fprintf(stderr,"Going to execute '%s'\n",buf);
293     if ((fp=popen(buf,mode)) == NULL)
294         gmx_open(fn);
295     push_ps(fp);
296
297     return fp;
298 }
299
300 gmx_bool gmx_fexist(const char *fname)
301 {
302     FILE *test;
303
304     if (fname == NULL)
305         return FALSE;
306     test=fopen(fname,"r");
307     if (test == NULL) {
308         /*Windows doesn't allow fopen of directory - so we need to check this seperately */
309         #ifdef GMX_NATIVE_WINDOWS
310             DWORD attr = GetFileAttributes(fname);
311             return (attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY);
312         #else 
313             return FALSE;
314         #endif
315     } else {
316         fclose(test);
317         return TRUE;
318     }
319 }
320
321 static gmx_bool gmx_is_file(const char *fname)
322 {
323     FILE *test;
324
325     if (fname == NULL)
326         return FALSE;
327     test=fopen(fname,"r");
328     if (test == NULL)
329     {
330         return FALSE;
331     }
332     else
333     {
334         fclose(test);
335         /*Windows doesn't allow fopen of directory - so we don't need to check this seperately */
336         #if (!((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__))
337         {
338             int status;
339             struct stat st_buf;
340             #ifdef HAVE_LSTAT
341                 status = lstat (fname, &st_buf);
342             #else
343                 status = stat (fname, &st_buf);
344             #endif
345             if (status != 0 || !S_ISREG(st_buf.st_mode))
346             {
347                 return FALSE;
348             }
349         }
350         #endif
351         return TRUE;
352     }
353 }
354
355
356 gmx_bool gmx_fexist_master(const char *fname, t_commrec *cr)
357 {
358   gmx_bool bExist;
359   
360   if (SIMMASTER(cr)) 
361   {
362       bExist = gmx_fexist(fname);
363   }
364   if (PAR(cr)) 
365   {
366       gmx_bcast(sizeof(bExist),&bExist,cr);
367   }
368   return bExist;
369 }
370
371 gmx_bool gmx_eof(FILE *fp)
372 {
373     char data[4];
374     gmx_bool beof;
375
376     if (is_pipe(fp))
377         return feof(fp);
378     else {
379         if ((beof=fread(data,1,1,fp))==1)
380             gmx_fseek(fp,-1,SEEK_CUR);
381         return !beof;
382     }
383 }
384
385 static char *backup_fn(const char *file,int count_max)
386 {
387     /* Use a reasonably low value for countmax; we might
388      * generate 4-5 files in each round, and we dont
389      * want to hit directory limits of 1024 or 2048 files.
390      */
391 #define COUNTMAX 99
392     int         i,count=1;
393     char        *directory,*fn;
394     char        *buf;
395
396     if (count_max == -1)
397     {
398         count_max = COUNTMAX;
399     }
400
401     smalloc(buf, GMX_PATH_MAX);
402
403     for(i=strlen(file)-1; ((i > 0) && (file[i] != DIR_SEPARATOR)); i--)
404         ;
405     /* Must check whether i > 0, i.e. whether there is a directory
406      * in the file name. In that case we overwrite the / sign with
407      * a '\0' to end the directory string .
408      */
409     if (i > 0) {
410         directory    = gmx_strdup(file);
411         directory[i] = '\0';
412         fn           = gmx_strdup(file+i+1);
413     }
414     else {
415         directory    = gmx_strdup(".");
416         fn           = gmx_strdup(file);
417     }
418     do {
419         sprintf(buf,"%s/#%s.%d#",directory,fn,count);
420         count++;
421     } while ((count <= count_max) && gmx_fexist(buf));
422
423     /* Arbitrarily bail out */
424     if (count > count_max) 
425         gmx_fatal(FARGS,"Won't make more than %d backups of %s for you.\n"
426                   "The env.var. GMX_MAXBACKUP controls this maximum, -1 disables backups.",
427                   count_max,fn);
428
429     sfree(directory);
430     sfree(fn);
431
432     return buf;
433 }
434
435 gmx_bool make_backup(const char * name)
436 {
437     char * env;
438     int  count_max;
439     char * backup;
440
441 #ifdef GMX_FAHCORE
442     return FALSE; /* skip making backups */
443 #else
444
445     if (gmx_fexist(name))
446     {
447         env = getenv("GMX_MAXBACKUP");
448         if (env != NULL)
449         {
450             count_max = 0;
451             sscanf(env,"%d",&count_max);
452             if (count_max == -1)
453             {
454                 /* Do not make backups and possibly overwrite old files */
455                 return TRUE;
456             }
457         }
458         else
459         {
460             /* Use the default maximum */
461             count_max = -1;
462         }
463         backup = backup_fn(name,count_max);
464         if(rename(name, backup) == 0) {
465             fprintf(stderr, "\nBack Off! I just backed up %s to %s\n",
466                     name, backup);
467         } else {
468             fprintf(stderr, "Sorry couldn't backup %s to %s\n", name, backup);
469             return FALSE;
470         }
471         sfree(backup);
472     }
473     return TRUE;
474 #endif
475 }
476
477 FILE *ffopen(const char *file,const char *mode)
478 {
479 #ifdef SKIP_FFOPS
480     return fopen(file,mode);
481 #else
482     FILE *ff=NULL;
483     char buf[256],*bf,*bufsize=0,*ptr;
484     gmx_bool bRead;
485     int  bs;
486
487     if (file == NULL) 
488     {
489         return NULL;
490     }
491
492     if (mode[0]=='w') {
493         make_backup(file);
494     }
495     where();
496
497     bRead= (mode[0]=='r'&&mode[1]!='+');
498     strcpy(buf,file);
499     if (!bRead || gmx_fexist(buf)) {
500         if ((ff=fopen(buf,mode))==NULL)
501             gmx_file(buf);
502         where();
503         /* Check whether we should be using buffering (default) or not
504          * (for debugging)
505          */
506         if (bUnbuffered || ((bufsize=getenv("LOG_BUFS")) != NULL)) {
507             /* Check whether to use completely unbuffered */
508             if (bUnbuffered)
509                 bs = 0;
510             else
511                 bs=strtol(bufsize, NULL, 10); 
512             if (bs <= 0)
513                 setbuf(ff,NULL); 
514             else {
515                 snew(ptr,bs+8);
516                 if (setvbuf(ff,ptr,_IOFBF,bs) != 0)
517                     gmx_file("Buffering File");
518             }
519         }
520         where();
521     }
522     else {
523         sprintf(buf,"%s.Z",file);
524         if (gmx_fexist(buf)) {
525             ff=uncompress(buf,mode);
526         }
527         else {
528             sprintf(buf,"%s.gz",file);
529             if (gmx_fexist(buf)) {
530                 ff=gunzip(buf,mode);
531             }
532             else 
533                 gmx_file(file);
534         }
535     }
536     return ff;
537 #endif
538 }
539
540 /* Our own implementation of dirent-like functionality to scan directories. */
541 struct gmx_directory
542 {
543 #ifdef HAVE_DIRENT_H
544     DIR  *               dirent_handle;
545 #elif (defined GMX_NATIVE_WINDOWS)
546     intptr_t             windows_handle;
547     struct _finddata_t   finddata;
548     int                  first;
549 #else
550     int      dummy;
551 #endif
552 };
553
554
555 int
556 gmx_directory_open(gmx_directory_t *p_gmxdir,const char *dirname)
557 {
558     struct gmx_directory *  gmxdir;
559     int                     rc;
560     
561     snew(gmxdir,1);
562     
563     *p_gmxdir = gmxdir;
564     
565 #ifdef HAVE_DIRENT_H
566     if( (gmxdir->dirent_handle = opendir(dirname)) != NULL)
567     {
568         rc = 0;
569     }
570     else 
571     {
572         sfree(gmxdir);
573         *p_gmxdir = NULL;
574         rc        = EINVAL;
575     }
576 #elif (defined GMX_NATIVE_WINDOWS)
577     
578     if(dirname!=NULL && strlen(dirname)>0)
579     {
580         char *     tmpname;
581         size_t     namelength;
582         int        len;
583         
584         len = strlen(dirname);
585         snew(tmpname,len+3);
586         
587         strncpy(tmpname,dirname,len+1);
588         
589         /* Remove possible trailing directory separator */
590         if(tmpname[len]=='/' || tmpname[len]=='\\')
591         {
592             tmpname[len]='\0';
593         }
594         
595         /* Add wildcard */
596         strcat(tmpname,"/*");
597         
598         gmxdir->first = 1;
599         if( (gmxdir->windows_handle=_findfirst(tmpname,&gmxdir->finddata))>0L)
600         {
601             rc = 0;
602         }
603         else
604         {
605             if(errno==EINVAL)
606             {
607                 sfree(gmxdir);
608                 *p_gmxdir = NULL;
609                 rc        = EINVAL;                
610             }
611             else
612             {
613                 rc        = 0;
614             }
615         }
616     }
617     else
618     {
619         rc = EINVAL;
620     }
621 #else
622     gmx_fatal(FARGS,
623               "Source compiled without POSIX dirent or windows support - cannot scan directories.\n"
624               "In the very unlikely event this is not a compile-time mistake you could consider\n"
625               "implementing support for your platform in futil.c, but contact the developers\n"
626               "to make sure it's really necessary!\n");
627     rc = -1;
628 #endif
629     return rc;
630 }
631
632
633 int
634 gmx_directory_nextfile(gmx_directory_t gmxdir,char *name,int maxlength_name)
635 {
636     int                     rc;
637     
638 #ifdef HAVE_DIRENT_H
639     
640     struct dirent *         direntp_large;
641     struct dirent *         p;
642     
643     
644     if(gmxdir!=NULL && gmxdir->dirent_handle!=NULL)
645     {
646         /* On some platforms no space is present for d_name in dirent.
647          * Since d_name is guaranteed to be the last entry, allocating
648          * extra space for dirent will allow more size for d_name.
649          * GMX_MAX_PATH should always be >= the max possible d_name.
650          */
651         smalloc(direntp_large, sizeof(*direntp_large) + GMX_PATH_MAX);
652         rc = readdir_r(gmxdir->dirent_handle,direntp_large,&p);
653
654         if(p!=NULL && rc==0)
655         {
656             strncpy(name,direntp_large->d_name,maxlength_name);
657         }
658         else
659         {
660             name[0] = '\0';
661             rc      = ENOENT;
662         }
663         sfree(direntp_large);
664     }
665     else 
666     {
667         name[0] = '\0';
668         rc      = EINVAL;
669     }
670     
671 #elif (defined GMX_NATIVE_WINDOWS)
672     
673     if(gmxdir!=NULL)
674     {
675         if(gmxdir->windows_handle<=0)
676         {
677             
678             name[0] = '\0';
679             rc      = ENOENT;
680         }
681         else if(gmxdir->first==1)
682         {
683             strncpy(name,gmxdir->finddata.name,maxlength_name);
684             rc            = 0;
685             gmxdir->first = 0;
686         }
687         else
688         {
689             if(_findnext(gmxdir->windows_handle,&gmxdir->finddata)==0)
690             {
691                 strncpy(name,gmxdir->finddata.name,maxlength_name);
692                 rc      = 0;
693             }
694             else
695             {
696                 name[0] = '\0';
697                 rc      = ENOENT;
698             }
699         }
700     }
701     
702 #else
703     gmx_fatal(FARGS,
704               "Source compiled without POSIX dirent or windows support - cannot scan directories.\n");
705     rc = -1;
706 #endif
707     return rc;
708 }
709
710
711 int 
712 gmx_directory_close(gmx_directory_t gmxdir)
713 {
714     int                     rc;
715 #ifdef HAVE_DIRENT_H
716     rc = (gmxdir != NULL) ? closedir(gmxdir->dirent_handle) : EINVAL;
717 #elif (defined GMX_NATIVE_WINDOWS)
718     rc = (gmxdir != NULL) ? _findclose(gmxdir->windows_handle) : EINVAL;
719 #else
720     gmx_fatal(FARGS,
721               "Source compiled without POSIX dirent or windows support - cannot scan directories.\n");
722     rc = -1;
723 #endif
724     
725     sfree(gmxdir);
726     return rc;
727 }
728
729
730 static gmx_bool search_subdirs(const char *parent, char *libdir)
731 {
732     char *ptr;
733     gmx_bool found;
734
735     /* Search a few common subdirectory names for the gromacs library dir */
736     sprintf(libdir,"%s%cshare%ctop%cgurgle.dat",parent,
737             DIR_SEPARATOR,DIR_SEPARATOR,DIR_SEPARATOR);
738     found=gmx_fexist(libdir);
739     if(!found) {
740         sprintf(libdir,"%s%cshare%cgromacs%ctop%cgurgle.dat",parent,
741                 DIR_SEPARATOR,DIR_SEPARATOR,
742                 DIR_SEPARATOR,DIR_SEPARATOR);
743         found=gmx_fexist(libdir);
744     }    
745     if(!found) {
746         sprintf(libdir,"%s%cshare%cgromacs-%s%ctop%cgurgle.dat",parent,
747                 DIR_SEPARATOR,DIR_SEPARATOR,VERSION,
748                 DIR_SEPARATOR,DIR_SEPARATOR);
749         found=gmx_fexist(libdir);
750     }    
751     if(!found) {
752         sprintf(libdir,"%s%cshare%cgromacs%cgromacs-%s%ctop%cgurgle.dat",parent,
753                 DIR_SEPARATOR,DIR_SEPARATOR,DIR_SEPARATOR,
754                 VERSION,DIR_SEPARATOR,DIR_SEPARATOR);
755         found=gmx_fexist(libdir);
756     }    
757
758     /* Remove the gurgle.dat part from libdir if we found something */
759     if(found) {
760         ptr=strrchr(libdir,DIR_SEPARATOR); /* slash or backslash always present, no check necessary */
761         *ptr='\0';
762     }
763     return found;
764 }
765
766
767 /* Check if the program name begins with "/" on unix/cygwin, or
768  * with "\" or "X:\" on windows. If not, the program name
769  * is relative to the current directory.
770  */
771 static gmx_bool filename_is_absolute(char *name)
772 {
773 #ifdef GMX_NATIVE_WINDOWS
774     return ((name[0] == DIR_SEPARATOR) || ((strlen(name)>3) && strncmp(name+1,":\\",2)) == 0);
775 #else
776     return (name[0] == DIR_SEPARATOR);
777 #endif
778 }
779
780 gmx_bool get_libdir(char *libdir)
781 {
782 #define GMX_BINNAME_MAX 512
783     char bin_name[GMX_BINNAME_MAX];
784     char buf[GMX_BINNAME_MAX];
785     char full_path[GMX_PATH_MAX+GMX_BINNAME_MAX];
786     char system_path[GMX_PATH_MAX];
787     char *dir,*ptr,*s,*pdum;
788     gmx_bool found=FALSE;
789     int i;
790
791     if (Program() != NULL)
792     {
793
794     /* First - detect binary name */
795     if (strlen(Program()) >= GMX_BINNAME_MAX)
796     {
797         gmx_fatal(FARGS,"The name of the binary is longer than the allowed buffer size (%d):\n'%s'",GMX_BINNAME_MAX,Program());
798     }
799     strncpy(bin_name,Program(),GMX_BINNAME_MAX-1);
800
801     /* On windows & cygwin we need to add the .exe extension
802      * too, or we wont be able to detect that the file exists
803      */
804 #if (defined GMX_NATIVE_WINDOWS || defined GMX_CYGWIN)
805     if(strlen(bin_name)<3 || gmx_strncasecmp(bin_name+strlen(bin_name)-4,".exe",4))
806         strcat(bin_name,".exe");
807 #endif
808
809     /* Only do the smart search part if we got a real name */
810     if (NULL!=bin_name && strncmp(bin_name,"GROMACS",GMX_BINNAME_MAX)) {
811
812         if (!strchr(bin_name,DIR_SEPARATOR)) {
813             /* No slash or backslash in name means it must be in the path - search it! */
814             /* Add the local dir since it is not in the path on windows */
815             gmx_getcwd(system_path, sizeof(system_path));
816             sprintf(full_path,"%s%c%s",system_path,DIR_SEPARATOR,bin_name);
817             found = gmx_is_file(full_path);
818             if (!found && (s=getenv("PATH")) != NULL)
819             {
820                 char *dupped;
821                 
822                 dupped=gmx_strdup(s);
823                 s=dupped;
824                 while(!found && (dir=gmx_strsep(&s, PATH_SEPARATOR)) != NULL)
825                 {
826                     sprintf(full_path,"%s%c%s",dir,DIR_SEPARATOR,bin_name);
827                     found = gmx_is_file(full_path);
828                 }
829                 sfree(dupped);
830             }
831             if (!found)
832             {
833                 return FALSE;
834             }
835         } else if (!filename_is_absolute(bin_name)) {
836             /* name contains directory separators, but 
837              * it does not start at the root, i.e.
838              * name is relative to the current dir 
839              */
840             gmx_getcwd(buf, sizeof(buf));
841             sprintf(full_path,"%s%c%s",buf,DIR_SEPARATOR,bin_name);
842         } else {
843             strncpy(full_path,bin_name,GMX_PATH_MAX);
844         }
845
846         /* Now we should have a full path and name in full_path,
847          * but on unix it might be a link, or a link to a link to a link..
848          */
849 #ifndef GMX_NATIVE_WINDOWS
850         while( (i=readlink(full_path,buf,sizeof(buf)-1)) > 0 ) {
851             buf[i]='\0';
852             /* If it doesn't start with "/" it is relative */
853             if (buf[0]!=DIR_SEPARATOR) {
854                 strncpy(strrchr(full_path,DIR_SEPARATOR)+1,buf,GMX_PATH_MAX);
855             } else
856                 strncpy(full_path,buf,GMX_PATH_MAX);
857         }
858 #endif
859
860         /* If running directly from the build tree, try to use the source
861          * directory.
862          */
863 #if (defined CMAKE_SOURCE_DIR && defined CMAKE_BINARY_DIR)
864         if (strncmp(full_path, CMAKE_BINARY_DIR, strlen(CMAKE_BINARY_DIR)) == 0)
865         {
866             if (search_subdirs(CMAKE_SOURCE_DIR, libdir))
867             {
868                 return TRUE;
869             }
870         }
871 #endif
872
873         /* Remove the executable name - it always contains at least one slash */
874         *(strrchr(full_path,DIR_SEPARATOR)+1)='\0';
875         /* Now we have the full path to the gromacs executable.
876          * Use it to find the library dir. 
877          */
878         found=FALSE;
879         while(!found && ( (ptr=strrchr(full_path,DIR_SEPARATOR)) != NULL ) ) {
880             *ptr='\0';
881             found=search_subdirs(full_path,libdir);
882         }
883     }
884     }
885     /* End of smart searching. If we didn't find it in our parent tree,
886      * or if the program name wasn't set, at least try some standard 
887      * locations before giving up, in case we are running from e.g. 
888      * a users home directory. This only works on unix or cygwin...
889      */
890 #ifndef GMX_NATIVE_WINDOWS
891     if(!found) 
892         found=search_subdirs("/usr/local",libdir);
893     if(!found) 
894         found=search_subdirs("/usr",libdir);
895     if(!found) 
896         found=search_subdirs("/opt",libdir);
897 #endif
898     return found;
899 }
900
901
902 char *low_gmxlibfn(const char *file, gmx_bool bAddCWD, gmx_bool bFatal)
903 {
904     char *ret;
905     char *lib,*dir;
906     char buf[1024];
907     char libpath[GMX_PATH_MAX];
908     gmx_bool env_is_set=FALSE;
909     char   *s,tmppath[GMX_PATH_MAX];
910
911     /* GMXLIB can be a path now */
912     lib=getenv("GMXLIB");
913     if (lib != NULL)
914     {
915         env_is_set=TRUE;
916         strncpy(libpath,lib,GMX_PATH_MAX);
917     } 
918     else if (!get_libdir(libpath))
919     {
920         strncpy(libpath,GMXLIBDIR,GMX_PATH_MAX);
921     }
922
923     ret = NULL;
924     if (bAddCWD && gmx_fexist(file))
925     {
926         ret = gmx_strdup(file);
927     }
928     else 
929     {
930         strncpy(tmppath,libpath,GMX_PATH_MAX);
931         s=tmppath;
932         while(ret == NULL && (dir=gmx_strsep(&s, PATH_SEPARATOR)) != NULL )
933         {
934             sprintf(buf,"%s%c%s",dir,DIR_SEPARATOR,file);
935             if (gmx_fexist(buf))
936             {
937                 ret = gmx_strdup(buf);
938             }
939         }
940         if (ret == NULL && bFatal) 
941         {
942             if (env_is_set) 
943             {
944                 gmx_fatal(FARGS,
945                           "Library file %s not found %sin your GMXLIB path.",
946                           file, bAddCWD ? "in current dir nor " : "");
947             }
948             else
949             {
950                 gmx_fatal(FARGS,
951                           "Library file %s not found %sin default directories.\n"
952                         "(You can set the directories to search with the GMXLIB path variable)",
953                           file, bAddCWD ? "in current dir nor " : "");
954             }
955         }
956     }
957
958     return ret;
959 }
960
961
962
963
964
965 FILE *low_libopen(const char *file,gmx_bool bFatal)
966 {
967     FILE *ff;
968     char *fn;
969
970     fn=low_gmxlibfn(file,TRUE,bFatal);
971
972     if (fn==NULL) {
973         ff=NULL;
974     } else {
975       if (debug)
976         fprintf(debug,"Opening library file %s\n",fn);
977       ff=fopen(fn,"r");
978     }
979     sfree(fn);
980
981     return ff;
982 }
983
984 char *gmxlibfn(const char *file)
985 {
986     return low_gmxlibfn(file,TRUE,TRUE);
987 }
988
989 FILE *libopen(const char *file)
990 {
991     return low_libopen(file,TRUE);
992 }
993
994 void gmx_tmpnam(char *buf)
995 {
996     int i,len,fd;
997
998     if ((len = strlen(buf)) < 7)
999         gmx_fatal(FARGS,"Buf passed to gmx_tmpnam must be at least 7 bytes long");
1000     for(i=len-6; (i<len); i++) {
1001         buf[i] = 'X';
1002     }
1003     /* mktemp is dangerous and we should use mkstemp instead, but 
1004      * since windows doesnt support it we have to separate the cases.
1005      * 20090307: mktemp deprecated, use iso c++ _mktemp instead.
1006      */
1007 #ifdef GMX_NATIVE_WINDOWS
1008     _mktemp(buf);
1009 #else
1010     fd = mkstemp(buf);
1011
1012     switch (fd) {
1013         case EINVAL:
1014             gmx_fatal(FARGS,"Invalid template %s for mkstemp",buf);
1015             break;
1016         case EEXIST:
1017             gmx_fatal(FARGS,"mkstemp created existing file",buf);
1018             break;
1019         case EACCES: 
1020             gmx_fatal(FARGS,"Permission denied for opening %s",buf);
1021             break;
1022         default:
1023             break;
1024     }   
1025     close(fd);
1026 #endif
1027     /* name in Buf should now be OK */
1028 }
1029
1030 int gmx_truncatefile(char *path, gmx_off_t length)
1031 {
1032 #ifdef _MSC_VER
1033     /* Microsoft visual studio does not have "truncate" */
1034     HANDLE fh;
1035     LARGE_INTEGER win_length;
1036
1037     win_length.QuadPart = length;
1038
1039     fh = CreateFile(path,GENERIC_READ | GENERIC_WRITE,0,NULL,
1040             OPEN_EXISTING,0,NULL);
1041     SetFilePointerEx(fh,win_length,NULL,FILE_BEGIN);
1042     SetEndOfFile(fh);
1043     CloseHandle(fh);
1044
1045     return 0;
1046 #else
1047     return truncate(path,length);
1048 #endif
1049 }
1050
1051
1052 int gmx_file_rename(const char *oldname, const char *newname)
1053 {
1054 #ifndef GMX_NATIVE_WINDOWS
1055     /* under unix, rename() is atomic (at least, it should be). */
1056     return rename(oldname, newname);
1057 #else
1058     if (MoveFileEx(oldname, newname, 
1059                    MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH))
1060         return 0;
1061     else
1062         return 1;
1063 #endif
1064 }
1065
1066 int gmx_file_copy(const char *oldname, const char *newname, gmx_bool copy_if_empty)
1067 {
1068 /* the full copy buffer size: */
1069 #define FILECOPY_BUFSIZE (1<<16)
1070     FILE *in=NULL; 
1071     FILE *out=NULL;
1072     char *buf;
1073
1074     snew(buf, FILECOPY_BUFSIZE); 
1075
1076     in=fopen(oldname, "rb");
1077     if (!in)
1078         goto error;
1079
1080     /* If we don't copy when empty, we postpone opening the file
1081        until we're actually ready to write. */
1082     if (copy_if_empty)
1083     {
1084         out=fopen(newname, "wb");
1085         if (!out)
1086             goto error;
1087     }
1088
1089     while(!feof(in))
1090     {
1091         size_t nread;
1092         
1093         nread=fread(buf, sizeof(char), FILECOPY_BUFSIZE, in);
1094         if (nread>0)
1095         {
1096             size_t ret;
1097             if (!out)
1098             {
1099                 /* so this is where we open when copy_if_empty is false:
1100                    here we know we read something. */
1101                 out=fopen(newname, "wb");
1102                 if (!out)
1103                     goto error;
1104             }
1105             ret=fwrite(buf, sizeof(char), nread, out);
1106             if (ret!=nread)
1107             {
1108                 goto error;
1109             }
1110         }
1111         if (ferror(in))
1112             goto error;
1113     }
1114     sfree(buf);
1115     fclose(in);
1116     fclose(out);
1117     return 0;
1118 error:
1119     sfree(buf);
1120     if (in)
1121         fclose(in);
1122     if (out)
1123         fclose(out);
1124     return 1;
1125 #undef FILECOPY_BUFSIZE
1126 }
1127
1128
1129 int gmx_fsync(FILE *fp)
1130 {
1131     int rc=0;
1132
1133 #ifdef GMX_FAHCORE
1134     /* the fahcore defines its own os-independent fsync */
1135     rc=fah_fsync(fp);
1136 #else /* GMX_FAHCORE */
1137     {
1138         int fn=-1;
1139
1140         /* get the file number */
1141 #if defined(HAVE_FILENO)
1142         fn= fileno(fp);
1143 #elif defined(HAVE__FILENO)
1144         fn= _fileno(fp);
1145 #endif
1146
1147         /* do the actual fsync */
1148         if (fn >= 0)
1149         {
1150 #if (defined(HAVE_FSYNC))
1151             rc=fsync(fn);
1152 #elif (defined(HAVE__COMMIT)) 
1153             rc=_commit(fn);
1154 #endif
1155         }
1156     }
1157 #endif /* GMX_FAHCORE */
1158
1159     /* We check for these error codes this way because POSIX requires them
1160        to be defined, and using anything other than macros is unlikely: */
1161 #ifdef EINTR
1162     /* we don't want to report an error just because fsync() caught a signal.
1163        For our purposes, we can just ignore this. */
1164     if (rc && errno==EINTR)
1165         rc=0;
1166 #endif
1167 #ifdef EINVAL
1168     /* we don't want to report an error just because we tried to fsync() 
1169        stdout, a socket or a pipe. */
1170     if (rc && errno==EINVAL)
1171         rc=0;
1172 #endif
1173     return rc;
1174 }
1175
1176 void gmx_chdir(const char *directory)
1177 {
1178 #ifdef GMX_NATIVE_WINDOWS
1179     int rc = _chdir(directory);
1180 #else
1181     int rc = chdir(directory);
1182 #endif
1183     if (rc != 0)
1184     {
1185         gmx_fatal(FARGS, "Cannot change directory to '%s'. Reason: %s",
1186                   directory, strerror(errno));
1187     }
1188 }
1189
1190 void gmx_getcwd(char *buffer, size_t size)
1191 {
1192 #ifdef GMX_NATIVE_WINDOWS
1193     char *pdum = _getcwd(buffer, size);
1194 #else
1195     char *pdum = getcwd(buffer, size);
1196 #endif
1197     if (pdum == NULL)
1198     {
1199         gmx_fatal(FARGS, "Cannot get working directory. Reason: %s",
1200                   strerror(errno));
1201     }
1202 }