Redefine the default boolean type to gmx_bool.
[alexxy/gromacs.git] / src / gmxlib / gmxfio.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 <ctype.h>
41 #include <stdio.h>
42 #include <errno.h>
43 #ifdef HAVE_IO_H
44 #include <io.h>
45 #endif
46
47 #include "gmx_fatal.h"
48 #include "macros.h"
49 #include "smalloc.h"
50 #include "futil.h"
51 #include "filenm.h"
52 #include "string2.h"
53 #include "gmxfio.h"
54 #include "md5.h"
55
56 #ifdef GMX_THREADS
57 #include "thread_mpi.h"
58 #endif
59
60 #include "gmxfio_int.h"
61
62 /* This is the new improved and thread safe version of gmxfio. */
63
64
65
66 /* the list of open files is a linked list, with a dummy element at its head; 
67        it is initialized when the first file is opened. */
68 static t_fileio *open_files = NULL;
69
70
71 #ifdef GMX_THREADS
72 /* this mutex locks the open_files structure so that no two threads can 
73    modify it.        
74
75    For now, we use this as a coarse grained lock on all file 
76    insertion/deletion operations because it makes avoiding deadlocks 
77    easier, and adds almost no overhead: the only overhead is during
78    opening and closing of files, or during global operations like
79    iterating along all open files. All these cases should be rare
80    during the simulation. */
81 static tMPI_Thread_mutex_t open_file_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
82 #endif
83
84
85 /* These simple lists define the I/O type for these files */
86 static const int ftpXDR[] =
87     { efTPR, efTRR, efEDR, efXTC, efMTX, efCPT };
88 static const int ftpASC[] =
89     { efTPA, efGRO, efPDB };
90 static const int ftpBIN[] =
91     { efTPB, efTRJ };
92 #ifdef HAVE_XML
93 static const int ftpXML[] =
94     {   efXML};
95 #endif
96
97 const char *itemstr[eitemNR] =
98     { "[header]", "[inputrec]", "[box]", "[topology]", "[coordinates]",
99                 "[velocities]", "[forces]" };
100
101 const char *eioNames[eioNR] =
102     { "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
103                 "IVEC", "STRING" };
104
105
106
107 /* Comment strings for TPA only */
108 const char *comment_str[eitemNR] = {
109 "; The header holds information on the number of atoms etc. and on whether\n"
110 "; certain items are present in the file or not.\n"
111 "; \n"
112 ";                             WARNING\n"
113 ";                   DO NOT EDIT THIS FILE BY HAND\n"
114 "; The GROMACS preprocessor performs a lot of checks on your input that\n"
115 "; you ignore when editing this. Your simulation may crash because of this\n",
116 "; The inputrec holds the parameters for MD such as the number of steps,\n"
117 "; the timestep and the cut-offs.\n",
118 "; The simulation box in nm.\n",
119 "; The topology section describes the topology of the molecules\n"
120 "; i.e. bonds, angles and dihedrals etc. and also holds the force field\n"
121 "; parameters.\n", 
122 "; The atomic coordinates in nm\n",
123 "; The atomic velocities in nm/ps\n",
124 "; The forces on the atoms in nm/ps^2\n" };
125
126
127
128
129 /******************************************************************
130  *
131  * Internal functions: 
132  *
133  ******************************************************************/
134
135 static int gmx_fio_int_flush(t_fileio* fio)
136 {
137     int rc = 0;
138
139     if (fio->fp)
140     {
141         rc = fflush(fio->fp);
142     }
143     else if (fio->xdr)
144     {
145         rc = fflush((FILE *) fio->xdr->x_private);
146     }
147
148     return rc;
149 }
150
151 /* returns TRUE if the file type ftp is in the set set */
152 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
153 {
154     int i;
155     gmx_bool bResult;
156
157     bResult = FALSE;
158     for (i = 0; (i < nset); i++)
159         if (ftp == set[i])
160             bResult = TRUE;
161
162     return bResult;
163 }
164
165
166
167 extern void gmx_fio_set_comment(t_fileio *fio, const char *comment)
168 {
169     fio->comment=comment;
170 }
171
172 extern void gmx_fio_unset_comment(t_fileio *fio)
173 {
174     fio->comment=NULL;
175 }
176
177
178 const char *gmx_fio_dbgstr(t_fileio *fio, const char *desc, char *buf)
179 {
180     if (!fio->bDebug)
181     {
182         /* set to empty string */
183         buf[0]=0;
184     }
185     else
186     {
187 #if (defined( _WIN32 ) || defined( _WIN64 ) )
188         /* windows doesn't do standard C */
189 #define snprintf sprintf_s
190 #endif
191         snprintf(buf, GMX_FIO_BUFLEN, "  ; %s %s", 
192                  fio->comment ? fio->comment : "", desc);
193     }
194     return buf;
195 }
196
197
198 /* check the number of items given against the type */
199 void gmx_fio_check_nitem(t_fileio *fio, int eio, int nitem, const char *file, 
200                          int line)
201 {
202     if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
203         gmx_fatal(FARGS, 
204                   "nitem (%d) may differ from 1 only for %s or %s, not   for %s"
205                   "(%s, %d)",nitem,eioNames[eioNUCHAR],eioNames[eioNRVEC],
206                   eioNames[eio],file,line);
207 }
208
209
210 /* output a data type error. */
211 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc, 
212                 const char *srcfile, int line)
213 {
214
215     gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
216               fio->bRead ? "read" : "write",desc,eio,
217               ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
218               srcfile,line);
219 }
220
221
222 /* set the reader/writer functions based on the file type */
223 static void gmx_fio_set_iotype(t_fileio *fio)
224 {
225     if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
226     {
227 #ifdef USE_XDR    
228         fio->iotp=&xdr_iotype;
229 #else
230         gmx_fatal(FARGS,"Sorry, no XDR");
231 #endif
232     }
233     else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
234     {
235         fio->iotp=&asc_iotype;
236     }
237     else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
238     {
239         fio->iotp=&bin_iotype;
240     }
241 #ifdef HAVE_XMl
242     else if (in_ftpset(fio->iFTP,asize(ftpXML),ftpXML))
243     {
244         fio->iotp=&dummy_iotype;
245     }
246 #endif
247     else
248         fio->iotp=&dummy_iotype;
249 }
250
251
252 /* lock the mutex associated with this fio. This needs to be done for every
253    type of access to the fio's elements. */
254 void gmx_fio_lock(t_fileio *fio)
255 {
256 #ifdef GMX_THREADS
257     tMPI_Spinlock_lock(&(fio->mtx));
258 #endif
259 }
260 /* unlock the mutex associated with this fio.  */
261 void gmx_fio_unlock(t_fileio *fio)
262 {
263 #ifdef GMX_THREADS
264     tMPI_Spinlock_unlock(&(fio->mtx));
265 #endif
266 }
267
268 /* make a dummy head element, assuming we locked everything. */
269 static void gmx_fio_make_dummy(void)
270 {
271     if (!open_files)
272     {
273         snew(open_files,1);
274         open_files->fp=NULL;
275         open_files->fn=NULL;
276         open_files->next=open_files;
277         open_files->prev=open_files;
278 #ifdef GMX_THREADS
279         tMPI_Spinlock_init(&(open_files->mtx));
280 #endif
281     }
282 }
283
284
285
286
287
288
289
290 /***********************************************************************
291  *
292  * FILE LIST OPERATIONS
293  *
294 ***********************************************************************/
295
296
297 /* insert a new t_fileio into the list */
298 static void gmx_fio_insert(t_fileio *fio)
299 {
300     t_fileio *prev;
301 #ifdef GMX_THREADS
302     /* first lock the big open_files mutex. */
303     tMPI_Thread_mutex_lock(&open_file_mutex);
304 #endif
305     /* now check whether the dummy element has been allocated, 
306        and allocate it if it hasn't */
307     gmx_fio_make_dummy();
308
309     /* and lock the fio we got and the list's head **/
310     gmx_fio_lock(fio);
311     gmx_fio_lock(open_files);
312     prev=open_files->prev;
313     /* lock the element after the current one */
314     if (prev != open_files)
315     {
316         gmx_fio_lock(prev);
317     }
318
319     /* now do the actual insertion: */
320     fio->next=open_files;
321     open_files->prev=fio;
322     prev->next=fio;
323     fio->prev=prev;
324
325     /* now unlock all our locks */
326     if (prev != open_files)
327     {
328         gmx_fio_unlock(prev);
329     }
330     gmx_fio_unlock(open_files);
331     gmx_fio_unlock(fio);
332
333 #ifdef GMX_THREADS
334     /* now unlock the big open_files mutex.  */
335     tMPI_Thread_mutex_unlock(&open_file_mutex);
336 #endif
337 }
338
339 /* remove a t_fileio into the list. We assume the fio is locked, and we leave 
340    it locked. */
341 static void gmx_fio_remove(t_fileio *fio, gmx_bool global_lock)
342 {    
343     t_fileio *prev;
344
345 #ifdef GMX_THREADS
346     /* first lock the big open_files mutex. */
347     /* We don't want two processes operating on this list at the same time */
348     if (global_lock)
349         tMPI_Thread_mutex_lock(&open_file_mutex);
350 #endif
351    
352     /* lock prev, because we're changing it */ 
353     gmx_fio_lock(fio->prev);
354
355     /* now set the prev's pointer */
356     fio->prev->next=fio->next;
357     gmx_fio_unlock(fio->prev);
358
359     /* with the next ptr, we can simply lock while the original was locked */
360     gmx_fio_lock(fio->next);
361     fio->next->prev=fio->prev;
362     gmx_fio_unlock(fio->next);
363
364     /* and make sure we point nowhere in particular */
365     fio->next=fio->prev=fio;
366
367 #ifdef GMX_THREADS
368     /* now unlock the big open_files mutex.  */
369     if (global_lock)
370         tMPI_Thread_mutex_unlock(&open_file_mutex);
371 #endif
372
373 }
374
375
376 /* get the first open file, or NULL if there is none. 
377    Returns a locked fio. */
378 static t_fileio *gmx_fio_get_first(void)
379 {
380     t_fileio *ret;
381     /* first lock the big open_files mutex and the dummy's mutex */
382
383 #ifdef GMX_THREADS
384     /* first lock the big open_files mutex. */
385     tMPI_Thread_mutex_lock(&open_file_mutex);
386 #endif
387     gmx_fio_make_dummy();
388
389     gmx_fio_lock(open_files);
390     ret=open_files->next;
391
392
393     /* check whether there were any to begin with */
394     if (ret==open_files)
395     {
396         /* after this, the open_file pointer should never change */
397         ret=NULL;
398     }
399     else
400     {
401         gmx_fio_lock(open_files->next);
402     }
403     gmx_fio_unlock(open_files);
404
405
406     return ret;
407 }
408
409 /* get the next open file, or NULL if there is none. 
410    Unlocks the previous fio and locks the next one. */
411 static t_fileio *gmx_fio_get_next(t_fileio *fio)
412 {
413     t_fileio *ret;
414
415     ret=fio->next;
416     /* check if that was the last one */
417     if (fio->next==open_files)
418     {
419         ret=NULL;
420 #ifdef GMX_THREADS
421         tMPI_Thread_mutex_unlock(&open_file_mutex);
422 #endif
423     }
424     else
425     {
426         gmx_fio_lock(ret);
427     }
428     gmx_fio_unlock(fio);
429
430     return ret;
431 }
432
433 /* Stop looping through the open_files.  Unlocks the global lock. */
434 static void gmx_fio_stop_getting_next(t_fileio *fio)
435 {
436     gmx_fio_unlock(fio);
437 #ifdef GMX_THREADS
438     tMPI_Thread_mutex_unlock(&open_file_mutex);
439 #endif
440 }
441
442
443
444
445 /*****************************************************************
446  *
447  *                     EXPORTED SECTION
448  *
449  *****************************************************************/
450 t_fileio *gmx_fio_open(const char *fn, const char *mode)
451 {
452     t_fileio *fio = NULL;
453     int i;
454     char newmode[5];
455     gmx_bool bRead, bReadWrite;
456     int xdrid;
457
458     if (fn2ftp(fn) == efTPA)
459     {
460         strcpy(newmode, mode);
461     }
462     else
463     {
464         /* sanitize the mode string */
465         if (strncmp(mode, "r+", 2) == 0)
466         {
467             strcpy(newmode, "r+");
468         }
469         else if (mode[0] == 'r')
470         {
471             strcpy(newmode, "r");
472         }
473         else if (strncmp(mode, "w+", 2) == 0)
474         {
475             strcpy(newmode, "w+");
476         }
477         else if (mode[0] == 'w')
478         {
479             strcpy(newmode, "w");
480         }
481         else if (strncmp(mode, "a+", 2) == 0)
482         {
483             strcpy(newmode, "a+");
484         }
485         else if (mode[0] == 'a')
486         {
487             strcpy(newmode, "a");
488         }
489         else
490         {
491             gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'",mode);
492         }
493     }
494
495     /* Check if it should be opened as a binary file */
496     if (strncmp(ftp2ftype(fn2ftp(fn)),"ASCII",5))
497     {
498         /* Not ascii, add b to file mode */
499         if ((strchr(newmode,'b')==NULL) && (strchr(newmode,'B')==NULL))
500         {
501             strcat(newmode,"b");
502         }
503     }
504
505     snew(fio, 1);
506 #ifdef GMX_THREADS
507     tMPI_Spinlock_init(&(fio->mtx));
508 #endif
509     bRead = (newmode[0]=='r' && newmode[1]!='+');
510     bReadWrite = (newmode[1]=='+');
511     fio->fp = NULL;
512     fio->xdr = NULL;
513     if (fn)
514     {
515         fio->iFTP = fn2ftp(fn);
516         fio->fn = strdup(fn);
517         fio->bStdio = FALSE;
518
519         /* If this file type is in the list of XDR files, open it like that */
520         if (in_ftpset(fio->iFTP,asize(ftpXDR),ftpXDR))
521         {
522             /* First check whether we have to make a backup,
523              * only for writing, not for read or append.
524              */
525             if (newmode[0]=='w')
526             {
527 #ifndef GMX_FAHCORE
528                 /* only make backups for normal gromacs */
529                 make_backup(fn);
530 #endif
531             }
532             else 
533             {
534                 /* Check whether file exists */
535                 if (!gmx_fexist(fn))
536                 {
537                     gmx_open(fn);
538                 }
539             }
540             /* Open the file */
541             fio->fp = ffopen(fn,newmode);
542
543             /* determine the XDR direction */
544             if (newmode[0] == 'w' || newmode[0]=='a')
545             {
546                 fio->xdrmode=XDR_ENCODE;
547             }
548             else
549             {
550                 fio->xdrmode=XDR_DECODE;
551             }
552
553             snew(fio->xdr,1);
554             xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
555         }
556         else
557         {
558             /* If it is not, open it as a regular file */
559             fio->fp = ffopen(fn,newmode);
560         }
561     }
562     else
563     {
564         /* Use stdin/stdout for I/O */
565         fio->iFTP   = efTPA;
566         fio->fp     = bRead ? stdin : stdout;
567         fio->fn     = strdup("STDIO");
568         fio->bStdio = TRUE;
569     }
570     fio->bRead  = bRead;
571     fio->bReadWrite = bReadWrite;
572     fio->bDouble= (sizeof(real) == sizeof(double));
573     fio->bDebug = FALSE;
574     fio->bOpen  = TRUE;
575     fio->bLargerThan_off_t = FALSE;
576
577     /* set the reader/writer functions */
578     gmx_fio_set_iotype(fio);
579
580     /* and now insert this file into the list of open files. */
581     gmx_fio_insert(fio);
582     return fio;
583 }
584
585 static int gmx_fio_close_locked(t_fileio *fio)
586 {
587     int rc = 0;
588
589     if (!fio->bOpen)
590     {
591         gmx_fatal(FARGS,"File %s closed twice!\n", fio->fn);
592     }
593
594     if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
595     {
596         xdr_destroy(fio->xdr);
597         sfree(fio->xdr);
598     }
599
600     /* Don't close stdin and stdout! */
601     if (!fio->bStdio && fio->fp!=NULL)
602         rc = ffclose(fio->fp); /* fclose returns 0 if happy */
603
604     fio->bOpen = FALSE;
605
606     return rc;
607 }
608
609 int gmx_fio_close(t_fileio *fio)
610 {
611     int rc = 0;
612
613     gmx_fio_lock(fio);
614     /* first remove it from the list */
615     gmx_fio_remove(fio, TRUE);
616     rc=gmx_fio_close_locked(fio);
617     gmx_fio_unlock(fio);
618
619     sfree(fio);
620
621     return rc;
622 }
623
624 /* close only fp but keep FIO entry. */
625 int gmx_fio_fp_close(t_fileio *fio)
626 {
627     int rc=0;
628     gmx_fio_lock(fio);
629     if (!in_ftpset(fio->iFTP,asize(ftpXDR),ftpXDR) && !fio->bStdio)
630     {
631         rc = ffclose(fio->fp); /* fclose returns 0 if happy */
632         fio->fp = NULL; 
633     }
634     gmx_fio_unlock(fio);
635
636     return rc;
637 }
638
639 FILE * gmx_fio_fopen(const char *fn, const char *mode)
640 {
641     FILE *fp, *ret;
642     t_fileio *fio;
643
644     fio = gmx_fio_open(fn, mode);
645     gmx_fio_lock(fio);
646     ret = fio->fp;
647     gmx_fio_unlock(fio);
648
649     return ret;
650 }
651
652 int gmx_fio_fclose(FILE *fp)
653 {
654     t_fileio *cur;
655     t_fileio *found=NULL;
656     int rc=-1;
657
658     cur=gmx_fio_get_first();
659     while(cur)
660     {
661         if (cur->fp == fp)
662         {
663             rc=gmx_fio_close_locked(cur);
664             gmx_fio_remove(cur,FALSE);
665             gmx_fio_stop_getting_next(cur);
666             break;
667         }
668         cur=gmx_fio_get_next(cur);
669     }
670
671     return rc;
672 }
673
674 /* internal variant of get_file_md5 that operates on a locked file */
675 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset, 
676                                     unsigned char digest[])
677 {
678     /*1MB: large size important to catch almost identical files */
679 #define CPT_CHK_LEN  1048576 
680     md5_state_t state;
681     unsigned char buf[CPT_CHK_LEN];
682     gmx_off_t read_len;
683     gmx_off_t seek_offset;
684     int ret = -1;
685
686     seek_offset = offset - CPT_CHK_LEN;
687     if (seek_offset < 0)
688     {
689         seek_offset = 0;
690     }
691     read_len = offset - seek_offset;
692
693
694     if (fio->fp && fio->bReadWrite)
695     {
696         ret=gmx_fseek(fio->fp, seek_offset, SEEK_SET);
697         if (ret)
698         {
699             gmx_fseek(fio->fp, 0, SEEK_END);
700         }
701     }
702     if (ret) /*either no fp, not readwrite, or fseek not successful */
703     {
704         return -1;
705     }
706
707     /* the read puts the file position back to offset */
708     if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
709     {
710         /* not fatal: md5sum check to prevent overwriting files
711          * works (less safe) without
712          * */
713         if (ferror(fio->fp))
714         {
715             fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
716                     strerror(errno));
717         }
718         else if (feof(fio->fp))
719         {
720             fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
721         }
722         else
723         {
724             fprintf(
725                 stderr,
726                 "\nTrying to get md5sum: Unknown reason for short read: %s\n",
727                 fio->fn);
728         }
729
730         gmx_fseek(fio->fp, 0, SEEK_END);
731
732         ret = -1;
733     }
734     gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows 
735                                        it gives problems otherwise*/
736
737     if (debug)
738     {
739         fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
740     }
741
742     if (!ret)
743     {
744         md5_init(&state);
745         md5_append(&state, buf, read_len);
746         md5_finish(&state, digest);
747         return read_len;
748     }
749     else
750     {
751         return ret;
752     }
753 }
754
755
756 /*
757  * fio: file to compute md5 for
758  * offset: starting pointer of region to use for md5
759  * digest: return array of md5 sum 
760  */
761 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset, 
762                          unsigned char digest[])
763 {
764     int ret;
765
766     gmx_fio_lock(fio);
767     ret=gmx_fio_int_get_file_md5(fio, offset, digest);
768     gmx_fio_unlock(fio);
769
770     return ret;
771 }
772
773 /* The fio_mutex should ALWAYS be locked when this function is called */
774 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
775 {
776     char buf[STRLEN];
777
778     /* Flush the file, so we are sure it is written */
779     if (gmx_fio_int_flush(fio))
780     {
781         char buf[STRLEN];
782         sprintf(
783             buf,
784             "Cannot write file '%s'; maybe you are out of disk space or quota?",
785             fio->fn);
786         gmx_file(buf);
787     }
788
789     /* We cannot count on XDR being able to write 64-bit integers, 
790      so separate into high/low 32-bit values.
791      In case the filesystem has 128-bit offsets we only care 
792      about the first 64 bits - we'll have to fix
793      this when exabyte-size output files are common...
794      */
795     *offset=gmx_ftell(fio->fp);
796
797     return 0;
798 }
799
800 int gmx_fio_check_file_position(t_fileio *fio)
801 {
802     /* If gmx_off_t is 4 bytes we can not store file offset > 2 GB.
803      * If we do not have ftello, we will play it safe.
804      */
805 #if (SIZEOF_GMX_OFF_T == 4 || !defined HAVE_FSEEKO)
806     gmx_off_t offset;
807
808     gmx_fio_lock(fio);
809     gmx_fio_int_get_file_position(fio,&offset);
810     /* We have a 4 byte offset,
811      * make sure that we will detect out of range for all possible cases.
812      */
813     if (offset < 0 || offset > 2147483647)
814     {
815         fio->bLargerThan_off_t = TRUE;
816     }
817     gmx_fio_unlock(fio);
818 #endif
819
820     return 0;
821 }
822
823 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
824                                       int *p_nfiles)
825 {
826     int i, nfiles, rc, nalloc;
827     int pos_hi, pos_lo;
828     long pos;
829     gmx_file_position_t * outputfiles;
830     char buf[STRLEN];
831     t_fileio *cur;
832
833     nfiles = 0;
834
835     /* pre-allocate 100 files */
836     nalloc = 100;
837     snew(outputfiles,nalloc);
838
839     cur=gmx_fio_get_first();
840     while(cur)
841     {
842         /* Skip the checkpoint files themselves, since they could be open when 
843            we call this routine... */
844         /* also skip debug files (shoud be the only iFTP==efNR) */
845         if (cur->bOpen && 
846             !cur->bRead && 
847             !cur->bStdio && 
848             cur->iFTP != efCPT && 
849             cur->iFTP != efNR)
850         {
851             int ret;
852             /* This is an output file currently open for writing, add it */
853             if (nfiles == nalloc)
854             {
855                 nalloc += 100;
856                 srenew(outputfiles,nalloc);
857             }
858
859             strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
860
861             /* Get the file position */
862             if (cur->bLargerThan_off_t)
863             {
864                 /* -1 signals out of range */
865                 outputfiles[nfiles].offset = -1;
866                 outputfiles[nfiles].chksum_size = -1;
867             }
868             else
869             {
870                 gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
871 #ifndef GMX_FAHCORE
872                 outputfiles[nfiles].chksum_size
873                     = gmx_fio_int_get_file_md5(cur, 
874                                                outputfiles[nfiles].offset,
875                                                outputfiles[nfiles].chksum);
876 #endif
877             }
878
879             nfiles++;
880         }
881
882         cur=gmx_fio_get_next(cur);
883     }
884     *p_nfiles = nfiles;
885     *p_outputfiles = outputfiles;
886
887     return 0;
888 }
889
890
891 void gmx_fio_checktype(t_fileio *fio)
892 {
893     if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
894     {
895         return;
896     }
897     else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
898     {
899         return;
900     }
901     else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
902     {
903         return;
904     }
905 #ifdef HAVE_XMl
906     else if (in_ftpset(fio->iFTP,asize(ftpXML),ftpXML))
907     {
908         return;
909     }
910 #endif
911     else
912         gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
913                   ftp2ext(fio->iFTP));
914
915 }
916
917
918 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
919 {
920     gmx_fio_lock(fio);
921     fio->bDouble = bDouble;
922     gmx_fio_unlock(fio);
923 }
924
925 gmx_bool gmx_fio_getdebug(t_fileio *fio)
926 {
927     gmx_bool ret;
928
929     gmx_fio_lock(fio);
930     ret = fio->bDebug;
931     gmx_fio_unlock(fio);
932
933     return ret;
934 }
935
936 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
937 {
938     gmx_fio_lock(fio);
939     fio->bDebug = bDebug;
940     gmx_fio_unlock(fio);
941 }
942
943 char *gmx_fio_getname(t_fileio *fio)
944 {
945     char *ret;
946     gmx_fio_lock(fio);
947     ret = fio->fn;
948     gmx_fio_unlock(fio);
949
950     return ret;
951 }
952
953 int gmx_fio_getftp(t_fileio* fio)
954 {
955     int ret;
956
957     gmx_fio_lock(fio);
958     ret = fio->iFTP;
959     gmx_fio_unlock(fio);
960
961     return ret;
962 }
963
964 void gmx_fio_rewind(t_fileio* fio)
965 {
966     gmx_fio_lock(fio);
967
968     if (fio->xdr)
969     {
970         xdr_destroy(fio->xdr);
971         frewind(fio->fp);
972         xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
973     }
974     else
975     {
976         frewind(fio->fp);
977     }
978     gmx_fio_unlock(fio);
979 }
980
981
982 int gmx_fio_flush(t_fileio* fio)
983 {
984     int ret;
985
986     gmx_fio_lock(fio);
987     ret=gmx_fio_int_flush(fio);
988     gmx_fio_unlock(fio);
989
990     return ret;
991 }
992
993
994
995 static int gmx_fio_int_fsync(t_fileio *fio)
996 {
997     int rc = 0;
998     int filen=-1;
999
1000
1001     if (fio->fp)
1002     {
1003         rc=gmx_fsync(fio->fp);
1004     }
1005     else if (fio->xdr) /* this should normally not happen */
1006     {
1007         rc=gmx_fsync((FILE*) fio->xdr->x_private);
1008                                     /* ^ is this actually OK? */
1009     }
1010
1011     return rc;
1012 }
1013
1014
1015 int gmx_fio_fsync(t_fileio *fio)
1016 {
1017     int rc;
1018
1019     gmx_fio_lock(fio);
1020     rc=gmx_fio_int_fsync(fio);
1021     gmx_fio_unlock(fio);
1022
1023     return rc;
1024 }
1025
1026
1027
1028 t_fileio *gmx_fio_all_output_fsync(void)
1029 {
1030     t_fileio *ret=NULL;
1031     t_fileio *cur;
1032
1033     cur=gmx_fio_get_first();
1034     while(cur)
1035     {
1036         /* skip debug files (shoud be the only iFTP==efNR) */
1037         if (cur->bOpen && 
1038             !cur->bRead && 
1039             !cur->bStdio && 
1040             cur->iFTP != efNR)
1041         {
1042             /* if any of them fails, return failure code */
1043             int rc=gmx_fio_int_fsync(cur);
1044             if (rc != 0 && !ret) 
1045             {
1046                 ret=cur;
1047             }
1048         }
1049         cur=gmx_fio_get_next(cur);
1050     }
1051
1052     /* in addition, we force these to be written out too, if they're being
1053        redirected. We don't check for errors because errors most likely mean
1054        that they're not redirected. */
1055     fflush(stdout);
1056     fflush(stderr);
1057 #if (defined(HAVE_FSYNC))
1058     /* again, fahcore defines HAVE_FSYNC and fsync() */
1059     fsync(STDOUT_FILENO);
1060     fsync(STDERR_FILENO);
1061 #endif
1062
1063     return ret;
1064 }
1065
1066
1067 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1068 {
1069     gmx_off_t ret = 0;
1070
1071     gmx_fio_lock(fio);
1072     if (fio->fp)
1073         ret = gmx_ftell(fio->fp);
1074     gmx_fio_unlock(fio);
1075     return ret;
1076 }
1077
1078 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1079 {
1080     int rc;
1081
1082     gmx_fio_lock(fio);
1083     if (fio->fp)
1084     {
1085         gmx_fseek(fio->fp, fpos, SEEK_SET);
1086     }
1087     else
1088     {
1089         gmx_file(fio->fn);
1090         rc = -1;
1091     }
1092     gmx_fio_unlock(fio);
1093     return rc;
1094 }
1095
1096 FILE *gmx_fio_getfp(t_fileio *fio)
1097 {
1098     FILE *ret = NULL;
1099
1100     gmx_fio_lock(fio);
1101     if (fio->fp)
1102         ret = fio->fp;
1103     gmx_fio_unlock(fio);
1104     return ret;
1105 }
1106
1107 XDR *gmx_fio_getxdr(t_fileio* fio)
1108 {
1109     XDR *ret = NULL;
1110
1111     gmx_fio_lock(fio);
1112     if (fio->xdr)
1113         ret = fio->xdr;
1114     gmx_fio_unlock(fio);
1115
1116     return ret;
1117 }
1118
1119 gmx_bool gmx_fio_getread(t_fileio* fio)
1120 {
1121     gmx_bool ret;
1122
1123     gmx_fio_lock(fio);
1124     ret = fio->bRead;
1125     gmx_fio_unlock(fio);
1126
1127     return ret;
1128 }
1129
1130 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1131 {
1132     int ret;
1133
1134     gmx_fio_lock(fio);
1135     ret=xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1136     gmx_fio_unlock(fio);
1137
1138     return ret;
1139 }
1140
1141 int xtc_seek_time(t_fileio *fio, real time, int natoms)
1142 {
1143     int ret;
1144
1145     gmx_fio_lock(fio);
1146     ret=xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms);
1147     gmx_fio_unlock(fio);
1148
1149     return ret;
1150 }
1151
1152