Compiles in MSVC with cmake
[alexxy/gromacs.git] / src / gmxlib / futil.c
1 /*
2  * 
3  *                This source code is part of
4  * 
5  *                 G   R   O   M   A   C   S
6  * 
7  *          GROningen MAchine for Chemical Simulations
8  * 
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2004, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  * 
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  * 
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  * 
30  * For more info, check our website at http://www.gromacs.org
31  * 
32  * And Hey:
33  * GROningen Mixture of Alchemy and Childrens' Stories
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45
46 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
47 #include <direct.h>
48 #include <io.h>
49 #endif
50
51 #include "sysstuff.h"
52 #include "string2.h"
53 #include "futil.h"
54 #include "network.h"
55 #include "gmx_fatal.h"
56 #include "smalloc.h"
57 #include "statutil.h"
58
59 #ifdef GMX_THREADS
60 #include "thread_mpi.h"
61 #endif
62
63 /* Windows file stuff, only necessary for visual studio */
64 #ifdef _MSC_VER
65 #include "windows.h"
66 #endif
67
68 #define MAX_PATHBUF 4096
69
70 /* we keep a linked list of all files opened through pipes (i.e. 
71    compressed or .gzipped files. This way we can distinguish between them
72    without having to change the semantics of reading from/writing to files) 
73    */
74 typedef struct t_pstack {
75     FILE   *fp;
76     struct t_pstack *prev;
77 } t_pstack;
78
79 static t_pstack *pstack=NULL;
80 static bool     bUnbuffered=FALSE;
81
82 #ifdef GMX_THREADS
83 /* this linked list is an intrinsically globally shared object, so we have
84    to protect it with mutexes */
85 static tMPI_Thread_mutex_t pstack_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
86 #endif
87
88 void no_buffers(void)
89 {
90     bUnbuffered=TRUE;
91 }
92
93 void push_ps(FILE *fp)
94 {
95     t_pstack *ps;
96
97 #ifdef GMX_THREADS
98     tMPI_Thread_mutex_lock(&pstack_mutex);
99 #endif
100
101     snew(ps,1);
102     ps->fp   = fp;
103     ps->prev = pstack;
104     pstack   = ps;
105 #ifdef GMX_THREADS
106     tMPI_Thread_mutex_unlock(&pstack_mutex);
107 #endif
108 }
109
110 #ifdef GMX_FAHCORE
111 /* redefine fclose */
112 #define fclose fah_fclose
113 #else
114 #ifdef fclose
115 #undef fclose
116 #endif
117 #endif
118
119
120 #ifndef HAVE_PIPES
121 static FILE *popen(const char *nm,const char *mode)
122 {
123     gmx_impl("Sorry no pipes...");
124
125     return NULL;
126 }
127
128 static int pclose(FILE *fp)
129 {
130     gmx_impl("Sorry no pipes...");
131
132     return 0;
133 }
134 #endif
135
136
137
138 void ffclose(FILE *fp)
139 {
140     t_pstack *ps,*tmp;
141 #ifdef GMX_THREADS
142     tMPI_Thread_mutex_lock(&pstack_mutex);
143 #endif
144
145     ps=pstack;
146     if (ps == NULL) {
147         if (fp != NULL) 
148             fclose(fp);
149     }
150     else if (ps->fp == fp) {
151         if (fp != NULL)
152             pclose(fp);
153         pstack=pstack->prev;
154         sfree(ps);
155     }
156     else {
157         while ((ps->prev != NULL) && (ps->prev->fp != fp))
158             ps=ps->prev;
159         if (ps->prev->fp == fp) {
160             if (ps->prev->fp != NULL)
161                 pclose(ps->prev->fp);
162             tmp=ps->prev;
163             ps->prev=ps->prev->prev;
164             sfree(tmp);
165         }
166         else {
167             if (fp != NULL)
168                 fclose(fp);
169         }
170     }
171 #ifdef GMX_THREADS
172     tMPI_Thread_mutex_unlock(&pstack_mutex);
173 #endif
174 }
175
176 #ifdef rewind
177 #undef rewind
178 #endif
179
180 void frewind(FILE *fp)
181 {
182     t_pstack *ps;
183 #ifdef GMX_THREADS
184     tMPI_Thread_mutex_lock(&pstack_mutex);
185 #endif
186
187     ps=pstack;
188     while (ps != NULL) {
189         if (ps->fp == fp) {
190             fprintf(stderr,"Cannot rewind compressed file!\n");
191 #ifdef GMX_THREADS
192             tMPI_Thread_mutex_unlock(&pstack_mutex);
193 #endif
194             return;
195         }
196         ps=ps->prev;
197     }
198     rewind(fp);
199 #ifdef GMX_THREADS
200     tMPI_Thread_mutex_unlock(&pstack_mutex);
201 #endif
202 }
203
204 bool is_pipe(FILE *fp)
205 {
206     t_pstack *ps;
207 #ifdef GMX_THREADS
208     tMPI_Thread_mutex_lock(&pstack_mutex);
209 #endif
210
211     ps=pstack;
212     while (ps != NULL) {
213         if (ps->fp == fp) {
214 #ifdef GMX_THREADS
215             tMPI_Thread_mutex_unlock(&pstack_mutex);
216 #endif
217             return TRUE;
218         }
219         ps=ps->prev;
220     }
221 #ifdef GMX_THREADS
222     tMPI_Thread_mutex_unlock(&pstack_mutex);
223 #endif
224     return FALSE;
225 }
226
227
228 static FILE *uncompress(const char *fn,const char *mode)
229 {
230     FILE *fp;
231     char buf[256];
232
233     sprintf(buf,"uncompress -c < %s",fn);
234     fprintf(stderr,"Going to execute '%s'\n",buf);
235     if ((fp=popen(buf,mode)) == NULL)
236         gmx_open(fn);
237     push_ps(fp);
238
239     return fp;
240 }
241
242 static FILE *gunzip(const char *fn,const char *mode)
243 {
244     FILE *fp;
245     char buf[256];
246
247     sprintf(buf,"gunzip -c < %s",fn);
248     fprintf(stderr,"Going to execute '%s'\n",buf);
249     if ((fp=popen(buf,mode)) == NULL)
250         gmx_open(fn);
251     push_ps(fp);
252
253     return fp;
254 }
255
256 bool gmx_fexist(const char *fname)
257 {
258     FILE *test;
259
260     if (fname == NULL)
261         return FALSE;
262     test=fopen(fname,"r");
263     if (test == NULL) 
264         return FALSE;
265     else {
266         fclose(test);
267         return TRUE;
268     }
269 }
270
271 bool gmx_eof(FILE *fp)
272 {
273     char data[4];
274     bool beof;
275
276     if (is_pipe(fp))
277         return feof(fp);
278     else {
279         if ((beof=fread(data,1,1,fp))==1)
280             fseek(fp,-1,SEEK_CUR);
281         return !beof;
282     }
283 }
284
285 char *backup_fn(const char *file)
286 {
287     /* Use a reasonably low value for countmax; we might
288      * generate 4-5 files in each round, and we dont
289      * want to hit directory limits of 1024 or 2048 files.
290      */
291 #define COUNTMAX 128
292     int         i,count=1;
293     char        *directory,*fn;
294     char        *buf;
295
296     smalloc(buf, MAX_PATHBUF);
297
298     for(i=strlen(file)-1; ((i > 0) && (file[i] != '/')); i--)
299         ;
300     /* Must check whether i > 0, i.e. whether there is a directory
301      * in the file name. In that case we overwrite the / sign with
302      * a '\0' to end the directory string .
303      */
304     if (i > 0) {
305         directory    = strdup(file);
306         directory[i] = '\0';
307         fn           = strdup(file+i+1);
308     }
309     else {
310         directory    = strdup(".");
311         fn           = strdup(file);
312     }
313     do {
314         sprintf(buf,"%s/#%s.%d#",directory,fn,count);
315         count++;
316     } while ((count < COUNTMAX) && gmx_fexist(buf));
317
318     /* Arbitrarily bail out */
319     if (count == COUNTMAX) 
320         gmx_fatal(FARGS,"Won't make more than %d backups of %s for you",
321                 COUNTMAX,fn);
322
323     sfree(directory);
324     sfree(fn);
325
326     return buf;
327 }
328
329 bool make_backup(const char * name)
330 {
331     char * backup;
332
333 #ifdef GMX_FAHCORE
334     return FALSE; /* skip making backups */
335 #else
336
337     if(gmx_fexist(name)) {
338         backup = backup_fn(name);
339         if(rename(name, backup) == 0) {
340             fprintf(stderr, "\nBack Off! I just backed up %s to %s\n",
341                     name, backup);
342         } else {
343             fprintf(stderr, "Sorry couldn't backup %s to %s\n", name, backup);
344             return FALSE;
345         }
346         sfree(backup);
347     }
348     return TRUE;
349 #endif
350 }
351
352 FILE *ffopen(const char *file,const char *mode)
353 {
354     FILE *ff=NULL;
355     char buf[256],*bf,*bufsize=0,*ptr;
356     bool bRead;
357     int  bs;
358
359     if (mode[0]=='w') {
360         make_backup(file);
361     }
362     where();
363
364     bRead= mode[0]=='r';
365     strcpy(buf,file);
366     if (gmx_fexist(buf) || !bRead) {
367         if ((ff=fopen(buf,mode))==NULL)
368             gmx_file(buf);
369         where();
370         /* Check whether we should be using buffering (default) or not
371          * (for debugging)
372          */
373         if (bUnbuffered || ((bufsize=getenv("LOG_BUFS")) != NULL)) {
374             /* Check whether to use completely unbuffered */
375             if (bUnbuffered)
376                 bs = 0;
377             else
378                 bs=strtol(bufsize, NULL, 0); 
379             if (bs <= 0)
380                 setbuf(ff,NULL); 
381             else {
382                 snew(ptr,bs+8);
383                 if (setvbuf(ff,ptr,_IOFBF,bs) != 0)
384                     gmx_file("Buffering File");
385             }
386         }
387         where();
388     }
389     else {
390         sprintf(buf,"%s.Z",file);
391         if (gmx_fexist(buf)) {
392             ff=uncompress(buf,mode);
393         }
394         else {
395             sprintf(buf,"%s.gz",file);
396             if (gmx_fexist(buf)) {
397                 ff=gunzip(buf,mode);
398             }
399             else 
400                 gmx_file(file);
401         }
402     }
403     return ff;
404 }
405
406
407
408 bool search_subdirs(const char *parent, char *libdir)
409 {
410     char *ptr;
411     bool found;
412
413     /* Search a few common subdirectory names for the gromacs library dir */
414     sprintf(libdir,"%s%cshare%ctop%cgurgle.dat",parent,
415             DIR_SEPARATOR,DIR_SEPARATOR,DIR_SEPARATOR);
416     found=gmx_fexist(libdir);
417     if(!found) {
418         sprintf(libdir,"%s%cshare%cgromacs%ctop%cgurgle.dat",parent,
419                 DIR_SEPARATOR,DIR_SEPARATOR,
420                 DIR_SEPARATOR,DIR_SEPARATOR);
421         found=gmx_fexist(libdir);
422     }    
423     if(!found) {
424         sprintf(libdir,"%s%cshare%cgromacs-%s%ctop%cgurgle.dat",parent,
425                 DIR_SEPARATOR,DIR_SEPARATOR,VERSION,
426                 DIR_SEPARATOR,DIR_SEPARATOR);
427         found=gmx_fexist(libdir);
428     }    
429     if(!found) {
430         sprintf(libdir,"%s%cshare%cgromacs%cgromacs-%s%ctop%cgurgle.dat",parent,
431                 DIR_SEPARATOR,DIR_SEPARATOR,DIR_SEPARATOR,
432                 VERSION,DIR_SEPARATOR,DIR_SEPARATOR);
433         found=gmx_fexist(libdir);
434     }    
435
436     /* Remove the gurgle.dat part from libdir if we found something */
437     if(found) {
438         ptr=strrchr(libdir,DIR_SEPARATOR); /* slash or backslash always present, no check necessary */
439         *ptr='\0';
440     }
441     return found;
442 }
443
444
445 /* Check if the program name begins with "/" on unix/cygwin, or
446  * with "\" or "X:\" on windows. If not, the program name
447  * is relative to the current directory.
448  */
449 static bool filename_is_absolute(char *name)
450 {
451 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
452     return ((name[0] == DIR_SEPARATOR) || ((strlen(name)>3) && strncmp(name+1,":\\",2)));
453 #else
454     return (name[0] == DIR_SEPARATOR);
455 #endif
456 }
457
458 bool get_libdir(char *libdir)
459 {
460     char bin_name[512];
461     char buf[512];
462     char full_path[MAX_PATHBUF];
463     char test_file[MAX_PATHBUF];
464     char system_path[MAX_PATHBUF];
465     char *dir,*ptr,*s,*pdum;
466     bool found=FALSE;
467     int i;
468
469     /* First - detect binary name */
470     strncpy(bin_name,Program(),512);
471
472     /* On windows & cygwin we need to add the .exe extension
473      * too, or we wont be able to detect that the file exists
474      */
475 #if (defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64 || defined __CYGWIN__ || defined __CYGWIN32__)
476     if(strlen(bin_name)<3 || strncasecmp(bin_name+strlen(bin_name)-4,".exe",4))
477         strcat(bin_name,".exe");
478 #endif
479
480     /* Only do the smart search part if we got a real name */
481     if (NULL!=bin_name && strncmp(bin_name,"GROMACS",512)) {
482
483         if (!strchr(bin_name,DIR_SEPARATOR)) {
484             /* No slash or backslash in name means it must be in the path - search it! */
485             s=getenv("PATH");
486
487             /* Add the local dir since it is not in the path on windows */
488 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
489             pdum=_getcwd(system_path,sizeof(system_path)-1);
490 #else
491             pdum=getcwd(system_path,sizeof(system_path)-1);
492 #endif
493             strcat(system_path,PATH_SEPARATOR);
494             if (s != NULL)
495                 strcat(system_path,s);
496             s=system_path;
497             found=FALSE;
498             while(!found && (dir=gmx_strsep(&s, PATH_SEPARATOR)) != NULL)
499             {
500                 sprintf(full_path,"%s%c%s",dir,DIR_SEPARATOR,bin_name);
501                 found=gmx_fexist(full_path);
502             }
503             if (!found)
504                 return FALSE;
505         } else if (!filename_is_absolute(bin_name)) {
506             /* name contains directory separators, but 
507              * it does not start at the root, i.e.
508              * name is relative to the current dir 
509              */
510 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
511             pdum=_getcwd(buf,sizeof(buf)-1);
512 #else
513             pdum=getcwd(buf,sizeof(buf)-1);
514 #endif
515             strncpy(full_path,buf,MAX_PATHBUF);
516             strcat(full_path,"/");
517             strcat(full_path,bin_name);
518         } else {
519             strncpy(full_path,bin_name,MAX_PATHBUF);
520         }
521
522         /* Now we should have a full path and name in full_path,
523          * but on unix it might be a link, or a link to a link to a link..
524          */
525 #if (!defined WIN32 && !defined _WIN32 && !defined WIN64 && !defined _WIN64)
526         while( (i=readlink(full_path,buf,sizeof(buf)-1)) > 0 ) {
527             buf[i]='\0';
528             /* If it doesn't start with "/" it is relative */
529             if (buf[0]!=DIR_SEPARATOR) {
530                 strncpy(strrchr(full_path,DIR_SEPARATOR)+1,buf,MAX_PATHBUF);
531             } else
532                 strncpy(full_path,buf,MAX_PATHBUF);
533         }
534 #endif
535
536         /* Remove the executable name - it always contains at least one slash */
537         *(strrchr(full_path,DIR_SEPARATOR)+1)='\0';
538         /* Now we have the full path to the gromacs executable.
539          * Use it to find the library dir. 
540          */
541         found=FALSE;
542         while(!found && ( (ptr=strrchr(full_path,DIR_SEPARATOR)) != NULL ) ) {
543             *ptr='\0';
544             found=search_subdirs(full_path,libdir);
545         }
546     }
547     /* End of smart searching. If we didn't find it in our parent tree,
548      * or if the program name wasn't set, at least try some standard 
549      * locations before giving up, in case we are running from e.g. 
550      * a users home directory. This only works on unix or cygwin...
551      */
552 #if ((!defined WIN32 && !defined _WIN32 && !defined WIN64 && !defined _WIN64) || defined __CYGWIN__ || defined __CYGWIN32__)
553     if(!found) 
554         found=search_subdirs("/usr/local",libdir);
555     if(!found) 
556         found=search_subdirs("/usr",libdir);
557     if(!found) 
558         found=search_subdirs("/opt",libdir);
559 #endif
560     return found;
561 }
562
563
564 char *low_libfn(const char *file, bool bFatal)
565 {
566     char *ret=NULL;
567     char *lib,*dir;
568     char buf[1024];
569     char libpath[MAX_PATHBUF];
570     bool env_is_set=FALSE;
571     char   *s,tmppath[MAX_PATHBUF];
572     bool found;
573
574     /* GMXLIB can be a path now */
575     lib=getenv("GMXLIB");
576     if (lib != NULL) {
577         env_is_set=TRUE;
578         strncpy(libpath,lib,MAX_PATHBUF);
579     } 
580     else if (!get_libdir(libpath))
581         strncpy(libpath,GMXLIBDIR,MAX_PATHBUF);
582
583     if (gmx_fexist(file))
584     {
585         ret=strdup(file);
586     }
587     else 
588     {
589         found=FALSE;
590         strncpy(tmppath,libpath,MAX_PATHBUF);
591         s=tmppath;
592         while(!found && (dir=gmx_strsep(&s, PATH_SEPARATOR)) != NULL )
593         {
594             sprintf(buf,"%s%c%s",dir,DIR_SEPARATOR,file);
595             found=gmx_fexist(buf);
596         }
597         if (bFatal && !found) 
598         {
599             if (env_is_set) 
600                 gmx_fatal(FARGS,"Library file %s not found in current dir nor in your GMXLIB path.\n",file);
601             else
602                 gmx_fatal(FARGS,"Library file %s not found in current dir nor in default directories.\n"
603                         "(You can set the directories to search with the GMXLIB path variable)",file);
604         }
605         ret=strdup(buf);
606     }
607
608     return ret;
609 }
610
611
612
613
614 FILE *low_libopen(const char *file,bool bFatal)
615 {
616     FILE *ff;
617     char *fn;
618
619     fn=low_libfn(file,bFatal);
620
621     if (fn==NULL) {
622         ff=NULL;
623     } else {
624         if (bFatal)
625             fprintf(stderr,"Opening library file %s\n",fn);
626         ff=fopen(fn,"r");
627     }
628     sfree(fn);
629
630     return ff;
631 }
632
633 char *libfn(const char *file)
634 {
635     return low_libfn(file,TRUE);
636 }
637
638 FILE *libopen(const char *file)
639 {
640     return low_libopen(file,TRUE);
641 }
642
643 void gmx_tmpnam(char *buf)
644 {
645     int i,len,fd;
646
647     if ((len = strlen(buf)) < 7)
648         gmx_fatal(FARGS,"Buf passed to gmx_tmpnam must be at least 7 bytes long");
649     for(i=len-6; (i<len); i++) {
650         buf[i] = 'X';
651     }
652     /* mktemp is dangerous and we should use mkstemp instead, but 
653      * since windows doesnt support it we have to separate the cases.
654      * 20090307: mktemp deprecated, use iso c++ _mktemp instead.
655      */
656 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
657     _mktemp(buf);
658 #else
659     fd = mkstemp(buf);
660
661     switch (fd) {
662         case EINVAL:
663             gmx_fatal(FARGS,"Invalid template %s for mkstemp",buf);
664             break;
665         case EEXIST:
666             gmx_fatal(FARGS,"mkstemp created existing file",buf);
667             break;
668         case EACCES: 
669             gmx_fatal(FARGS,"Permission denied for opening %s",buf);
670             break;
671         default:
672             break;
673     }   
674     close(fd);
675 #endif
676     /* name in Buf should now be OK */
677 }
678
679     int
680 gmx_truncatefile(char *path, off_t length)
681 {
682 #ifdef _MSC_VER
683     /* Microsoft visual studio does not have "truncate" */
684     HANDLE fh;
685     LARGE_INTEGER win_length;
686
687     win_length.QuadPart = length;
688
689     fh = CreateFile(path,GENERIC_READ | GENERIC_WRITE,0,NULL,
690             OPEN_EXISTING,0,NULL);
691     SetFilePointerEx(fh,win_length,NULL,FILE_BEGIN);
692     SetEndOfFile(fh);
693     CloseHandle(fh);
694
695     return 0;
696 #else
697     return truncate(path,length);
698 #endif
699 }