Framework for printing help for selections.
[gromacs/adressmacs.git] / src / gmxlib / futil.c
blob9fda243721184ff74ac0fd592027acae5cf5e201
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.
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.
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.
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.
30 * For more info, check our website at http://www.gromacs.org
32 * And Hey:
33 * GROningen Mixture of Alchemy and Childrens' Stories
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
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>
46 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
47 #include <direct.h>
48 #include <io.h>
49 #endif
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"
59 #ifdef GMX_THREADS
60 #include "thread_mpi.h"
61 #endif
63 /* Windows file stuff, only necessary for visual studio */
64 #ifdef _MSC_VER
65 #include "windows.h"
66 #endif
68 #define MAX_PATHBUF 4096
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)
74 typedef struct t_pstack {
75 FILE *fp;
76 struct t_pstack *prev;
77 } t_pstack;
79 static t_pstack *pstack=NULL;
80 static bool bUnbuffered=FALSE;
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
88 void no_buffers(void)
90 bUnbuffered=TRUE;
93 void push_ps(FILE *fp)
95 t_pstack *ps;
97 #ifdef GMX_THREADS
98 tMPI_Thread_mutex_lock(&pstack_mutex);
99 #endif
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
110 #ifdef GMX_FAHCORE
111 /* redefine fclose */
112 #define fclose fah_fclose
113 #else
114 #ifdef fclose
115 #undef fclose
116 #endif
117 #endif
120 #ifndef HAVE_PIPES
121 static FILE *popen(const char *nm,const char *mode)
123 gmx_impl("Sorry no pipes...");
125 return NULL;
128 static int pclose(FILE *fp)
130 gmx_impl("Sorry no pipes...");
132 return 0;
134 #endif
138 void ffclose(FILE *fp)
140 t_pstack *ps,*tmp;
141 #ifdef GMX_THREADS
142 tMPI_Thread_mutex_lock(&pstack_mutex);
143 #endif
145 ps=pstack;
146 if (ps == NULL) {
147 if (fp != NULL)
148 fclose(fp);
150 else if (ps->fp == fp) {
151 if (fp != NULL)
152 pclose(fp);
153 pstack=pstack->prev;
154 sfree(ps);
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);
166 else {
167 if (fp != NULL)
168 fclose(fp);
171 #ifdef GMX_THREADS
172 tMPI_Thread_mutex_unlock(&pstack_mutex);
173 #endif
176 #ifdef rewind
177 #undef rewind
178 #endif
180 void frewind(FILE *fp)
182 t_pstack *ps;
183 #ifdef GMX_THREADS
184 tMPI_Thread_mutex_lock(&pstack_mutex);
185 #endif
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;
196 ps=ps->prev;
198 rewind(fp);
199 #ifdef GMX_THREADS
200 tMPI_Thread_mutex_unlock(&pstack_mutex);
201 #endif
204 bool is_pipe(FILE *fp)
206 t_pstack *ps;
207 #ifdef GMX_THREADS
208 tMPI_Thread_mutex_lock(&pstack_mutex);
209 #endif
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;
219 ps=ps->prev;
221 #ifdef GMX_THREADS
222 tMPI_Thread_mutex_unlock(&pstack_mutex);
223 #endif
224 return FALSE;
228 static FILE *uncompress(const char *fn,const char *mode)
230 FILE *fp;
231 char buf[256];
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);
239 return fp;
242 static FILE *gunzip(const char *fn,const char *mode)
244 FILE *fp;
245 char buf[256];
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);
253 return fp;
256 bool gmx_fexist(const char *fname)
258 FILE *test;
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;
272 bool gmx_fexist_master(const char *fname, t_commrec *cr)
274 bool bExist;
276 if (SIMMASTER(cr))
278 bExist = gmx_fexist(fname);
280 if (PAR(cr))
282 gmx_bcast(sizeof(bExist),&bExist,cr);
284 return bExist;
287 bool gmx_eof(FILE *fp)
289 char data[4];
290 bool beof;
292 if (is_pipe(fp))
293 return feof(fp);
294 else {
295 if ((beof=fread(data,1,1,fp))==1)
296 fseek(fp,-1,SEEK_CUR);
297 return !beof;
301 char *backup_fn(const char *file)
303 /* Use a reasonably low value for countmax; we might
304 * generate 4-5 files in each round, and we dont
305 * want to hit directory limits of 1024 or 2048 files.
307 #define COUNTMAX 128
308 int i,count=1;
309 char *directory,*fn;
310 char *buf;
312 smalloc(buf, MAX_PATHBUF);
314 for(i=strlen(file)-1; ((i > 0) && (file[i] != '/')); i--)
316 /* Must check whether i > 0, i.e. whether there is a directory
317 * in the file name. In that case we overwrite the / sign with
318 * a '\0' to end the directory string .
320 if (i > 0) {
321 directory = strdup(file);
322 directory[i] = '\0';
323 fn = strdup(file+i+1);
325 else {
326 directory = strdup(".");
327 fn = strdup(file);
329 do {
330 sprintf(buf,"%s/#%s.%d#",directory,fn,count);
331 count++;
332 } while ((count < COUNTMAX) && gmx_fexist(buf));
334 /* Arbitrarily bail out */
335 if (count == COUNTMAX)
336 gmx_fatal(FARGS,"Won't make more than %d backups of %s for you",
337 COUNTMAX,fn);
339 sfree(directory);
340 sfree(fn);
342 return buf;
345 bool make_backup(const char * name)
347 char * backup;
349 #ifdef GMX_FAHCORE
350 return FALSE; /* skip making backups */
351 #else
353 if(gmx_fexist(name)) {
354 backup = backup_fn(name);
355 if(rename(name, backup) == 0) {
356 fprintf(stderr, "\nBack Off! I just backed up %s to %s\n",
357 name, backup);
358 } else {
359 fprintf(stderr, "Sorry couldn't backup %s to %s\n", name, backup);
360 return FALSE;
362 sfree(backup);
364 return TRUE;
365 #endif
368 FILE *ffopen(const char *file,const char *mode)
370 FILE *ff=NULL;
371 char buf[256],*bf,*bufsize=0,*ptr;
372 bool bRead;
373 int bs;
375 if (mode[0]=='w') {
376 make_backup(file);
378 where();
380 bRead= mode[0]=='r';
381 strcpy(buf,file);
382 if (gmx_fexist(buf) || !bRead) {
383 if ((ff=fopen(buf,mode))==NULL)
384 gmx_file(buf);
385 where();
386 /* Check whether we should be using buffering (default) or not
387 * (for debugging)
389 if (bUnbuffered || ((bufsize=getenv("LOG_BUFS")) != NULL)) {
390 /* Check whether to use completely unbuffered */
391 if (bUnbuffered)
392 bs = 0;
393 else
394 bs=strtol(bufsize, NULL, 10);
395 if (bs <= 0)
396 setbuf(ff,NULL);
397 else {
398 snew(ptr,bs+8);
399 if (setvbuf(ff,ptr,_IOFBF,bs) != 0)
400 gmx_file("Buffering File");
403 where();
405 else {
406 sprintf(buf,"%s.Z",file);
407 if (gmx_fexist(buf)) {
408 ff=uncompress(buf,mode);
410 else {
411 sprintf(buf,"%s.gz",file);
412 if (gmx_fexist(buf)) {
413 ff=gunzip(buf,mode);
415 else
416 gmx_file(file);
419 return ff;
424 bool search_subdirs(const char *parent, char *libdir)
426 char *ptr;
427 bool found;
429 /* Search a few common subdirectory names for the gromacs library dir */
430 sprintf(libdir,"%s%cshare%ctop%cgurgle.dat",parent,
431 DIR_SEPARATOR,DIR_SEPARATOR,DIR_SEPARATOR);
432 found=gmx_fexist(libdir);
433 if(!found) {
434 sprintf(libdir,"%s%cshare%cgromacs%ctop%cgurgle.dat",parent,
435 DIR_SEPARATOR,DIR_SEPARATOR,
436 DIR_SEPARATOR,DIR_SEPARATOR);
437 found=gmx_fexist(libdir);
439 if(!found) {
440 sprintf(libdir,"%s%cshare%cgromacs-%s%ctop%cgurgle.dat",parent,
441 DIR_SEPARATOR,DIR_SEPARATOR,VERSION,
442 DIR_SEPARATOR,DIR_SEPARATOR);
443 found=gmx_fexist(libdir);
445 if(!found) {
446 sprintf(libdir,"%s%cshare%cgromacs%cgromacs-%s%ctop%cgurgle.dat",parent,
447 DIR_SEPARATOR,DIR_SEPARATOR,DIR_SEPARATOR,
448 VERSION,DIR_SEPARATOR,DIR_SEPARATOR);
449 found=gmx_fexist(libdir);
452 /* Remove the gurgle.dat part from libdir if we found something */
453 if(found) {
454 ptr=strrchr(libdir,DIR_SEPARATOR); /* slash or backslash always present, no check necessary */
455 *ptr='\0';
457 return found;
461 /* Check if the program name begins with "/" on unix/cygwin, or
462 * with "\" or "X:\" on windows. If not, the program name
463 * is relative to the current directory.
465 static bool filename_is_absolute(char *name)
467 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
468 return ((name[0] == DIR_SEPARATOR) || ((strlen(name)>3) && strncmp(name+1,":\\",2)));
469 #else
470 return (name[0] == DIR_SEPARATOR);
471 #endif
474 bool get_libdir(char *libdir)
476 char bin_name[512];
477 char buf[512];
478 char full_path[MAX_PATHBUF];
479 char test_file[MAX_PATHBUF];
480 char system_path[MAX_PATHBUF];
481 char *dir,*ptr,*s,*pdum;
482 bool found=FALSE;
483 int i;
485 /* First - detect binary name */
486 strncpy(bin_name,Program(),512);
488 /* On windows & cygwin we need to add the .exe extension
489 * too, or we wont be able to detect that the file exists
491 #if (defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64 || defined __CYGWIN__ || defined __CYGWIN32__)
492 if(strlen(bin_name)<3 || strncasecmp(bin_name+strlen(bin_name)-4,".exe",4))
493 strcat(bin_name,".exe");
494 #endif
496 /* Only do the smart search part if we got a real name */
497 if (NULL!=bin_name && strncmp(bin_name,"GROMACS",512)) {
499 if (!strchr(bin_name,DIR_SEPARATOR)) {
500 /* No slash or backslash in name means it must be in the path - search it! */
501 s=getenv("PATH");
503 /* Add the local dir since it is not in the path on windows */
504 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
505 pdum=_getcwd(system_path,sizeof(system_path)-1);
506 #else
507 pdum=getcwd(system_path,sizeof(system_path)-1);
508 #endif
509 strcat(system_path,PATH_SEPARATOR);
510 if (s != NULL)
511 strcat(system_path,s);
512 s=system_path;
513 found=FALSE;
514 while(!found && (dir=gmx_strsep(&s, PATH_SEPARATOR)) != NULL)
516 sprintf(full_path,"%s%c%s",dir,DIR_SEPARATOR,bin_name);
517 found=gmx_fexist(full_path);
519 if (!found)
520 return FALSE;
521 } else if (!filename_is_absolute(bin_name)) {
522 /* name contains directory separators, but
523 * it does not start at the root, i.e.
524 * name is relative to the current dir
526 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
527 pdum=_getcwd(buf,sizeof(buf)-1);
528 #else
529 pdum=getcwd(buf,sizeof(buf)-1);
530 #endif
531 strncpy(full_path,buf,MAX_PATHBUF);
532 strcat(full_path,"/");
533 strcat(full_path,bin_name);
534 } else {
535 strncpy(full_path,bin_name,MAX_PATHBUF);
538 /* Now we should have a full path and name in full_path,
539 * but on unix it might be a link, or a link to a link to a link..
541 #if (!defined WIN32 && !defined _WIN32 && !defined WIN64 && !defined _WIN64)
542 while( (i=readlink(full_path,buf,sizeof(buf)-1)) > 0 ) {
543 buf[i]='\0';
544 /* If it doesn't start with "/" it is relative */
545 if (buf[0]!=DIR_SEPARATOR) {
546 strncpy(strrchr(full_path,DIR_SEPARATOR)+1,buf,MAX_PATHBUF);
547 } else
548 strncpy(full_path,buf,MAX_PATHBUF);
550 #endif
552 /* Remove the executable name - it always contains at least one slash */
553 *(strrchr(full_path,DIR_SEPARATOR)+1)='\0';
554 /* Now we have the full path to the gromacs executable.
555 * Use it to find the library dir.
557 found=FALSE;
558 while(!found && ( (ptr=strrchr(full_path,DIR_SEPARATOR)) != NULL ) ) {
559 *ptr='\0';
560 found=search_subdirs(full_path,libdir);
563 /* End of smart searching. If we didn't find it in our parent tree,
564 * or if the program name wasn't set, at least try some standard
565 * locations before giving up, in case we are running from e.g.
566 * a users home directory. This only works on unix or cygwin...
568 #if ((!defined WIN32 && !defined _WIN32 && !defined WIN64 && !defined _WIN64) || defined __CYGWIN__ || defined __CYGWIN32__)
569 if(!found)
570 found=search_subdirs("/usr/local",libdir);
571 if(!found)
572 found=search_subdirs("/usr",libdir);
573 if(!found)
574 found=search_subdirs("/opt",libdir);
575 #endif
576 return found;
580 char *low_libfn(const char *file, bool bFatal)
582 char *ret=NULL;
583 char *lib,*dir;
584 char buf[1024];
585 char libpath[MAX_PATHBUF];
586 bool env_is_set=FALSE;
587 char *s,tmppath[MAX_PATHBUF];
588 bool found;
590 /* GMXLIB can be a path now */
591 lib=getenv("GMXLIB");
592 if (lib != NULL) {
593 env_is_set=TRUE;
594 strncpy(libpath,lib,MAX_PATHBUF);
596 else if (!get_libdir(libpath))
597 strncpy(libpath,GMXLIBDIR,MAX_PATHBUF);
599 if (gmx_fexist(file))
601 ret=strdup(file);
603 else
605 found=FALSE;
606 strncpy(tmppath,libpath,MAX_PATHBUF);
607 s=tmppath;
608 while(!found && (dir=gmx_strsep(&s, PATH_SEPARATOR)) != NULL )
610 sprintf(buf,"%s%c%s",dir,DIR_SEPARATOR,file);
611 found=gmx_fexist(buf);
613 if (bFatal && !found)
615 if (env_is_set)
616 gmx_fatal(FARGS,"Library file %s not found in current dir nor in your GMXLIB path.\n",file);
617 else
618 gmx_fatal(FARGS,"Library file %s not found in current dir nor in default directories.\n"
619 "(You can set the directories to search with the GMXLIB path variable)",file);
621 ret=strdup(buf);
624 return ret;
630 FILE *low_libopen(const char *file,bool bFatal)
632 FILE *ff;
633 char *fn;
635 fn=low_libfn(file,bFatal);
637 if (fn==NULL) {
638 ff=NULL;
639 } else {
640 if (bFatal)
641 fprintf(stderr,"Opening library file %s\n",fn);
642 ff=fopen(fn,"r");
644 sfree(fn);
646 return ff;
649 char *libfn(const char *file)
651 return low_libfn(file,TRUE);
654 FILE *libopen(const char *file)
656 return low_libopen(file,TRUE);
659 void gmx_tmpnam(char *buf)
661 int i,len,fd;
663 if ((len = strlen(buf)) < 7)
664 gmx_fatal(FARGS,"Buf passed to gmx_tmpnam must be at least 7 bytes long");
665 for(i=len-6; (i<len); i++) {
666 buf[i] = 'X';
668 /* mktemp is dangerous and we should use mkstemp instead, but
669 * since windows doesnt support it we have to separate the cases.
670 * 20090307: mktemp deprecated, use iso c++ _mktemp instead.
672 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
673 _mktemp(buf);
674 #else
675 fd = mkstemp(buf);
677 switch (fd) {
678 case EINVAL:
679 gmx_fatal(FARGS,"Invalid template %s for mkstemp",buf);
680 break;
681 case EEXIST:
682 gmx_fatal(FARGS,"mkstemp created existing file",buf);
683 break;
684 case EACCES:
685 gmx_fatal(FARGS,"Permission denied for opening %s",buf);
686 break;
687 default:
688 break;
690 close(fd);
691 #endif
692 /* name in Buf should now be OK */
696 gmx_truncatefile(char *path, off_t length)
698 #ifdef _MSC_VER
699 /* Microsoft visual studio does not have "truncate" */
700 HANDLE fh;
701 LARGE_INTEGER win_length;
703 win_length.QuadPart = length;
705 fh = CreateFile(path,GENERIC_READ | GENERIC_WRITE,0,NULL,
706 OPEN_EXISTING,0,NULL);
707 SetFilePointerEx(fh,win_length,NULL,FILE_BEGIN);
708 SetEndOfFile(fh);
709 CloseHandle(fh);
711 return 0;
712 #else
713 return truncate(path,length);
714 #endif