Actual source code: sysio.c
2: /*
3: This file contains simple binary read/write routines.
4: */
6: #include petsc.h
7: #include petscsys.h
9: #include <errno.h>
10: #include <fcntl.h>
11: #if defined(PETSC_HAVE_UNISTD_H)
12: #include <unistd.h>
13: #endif
14: #if defined (PETSC_HAVE_IO_H)
15: #include <io.h>
16: #endif
17: #include petscbt.h
20: #if !defined(PETSC_WORDS_BIGENDIAN)
23: /*
24: PetscByteSwapInt - Swap bytes in an integer. NOT a PetscInt!
26: */
27: PetscErrorCode PetscByteSwapInt(int *buff,PetscInt n)
28: {
29: PetscInt i,j,tmp =0;
30: PetscInt *tptr = &tmp; /* Need to access tmp indirectly to get */
31: char *ptr1,*ptr2 = (char*)&tmp; /* arround the bug in DEC-ALPHA g++ */
32:
34: for (j=0; j<n; j++) {
35: ptr1 = (char*)(buff + j);
36: for (i=0; i<(int) sizeof(int); i++) {
37: ptr2[i] = ptr1[sizeof(int)-1-i];
38: }
39: buff[j] = *tptr;
40: }
41: return(0);
42: }
43: /* --------------------------------------------------------- */
46: /*
47: PetscByteSwapShort - Swap bytes in a short
48: */
49: PetscErrorCode PetscByteSwapShort(short *buff,PetscInt n)
50: {
51: PetscInt i,j;
52: short tmp;
53: short *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
54: char *ptr1,*ptr2 = (char*)&tmp;
57: for (j=0; j<n; j++) {
58: ptr1 = (char*)(buff + j);
59: for (i=0; i<(int) sizeof(short); i++) {
60: ptr2[i] = ptr1[sizeof(int)-1-i];
61: }
62: buff[j] = *tptr;
63: }
64: return(0);
65: }
66: /* --------------------------------------------------------- */
69: /*
70: PetscByteSwapScalar - Swap bytes in a double
71: Complex is dealt with as if array of double twice as long.
72: */
73: PetscErrorCode PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
74: {
75: PetscInt i,j;
76: PetscReal tmp,*buff1 = (PetscReal*)buff;
77: PetscReal *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
78: char *ptr1,*ptr2 = (char*)&tmp;
81: #if defined(PETSC_USE_COMPLEX)
82: n *= 2;
83: #endif
84: for (j=0; j<n; j++) {
85: ptr1 = (char*)(buff1 + j);
86: for (i=0; i<(int) sizeof(PetscReal); i++) {
87: ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
88: }
89: buff1[j] = *tptr;
90: }
91: return(0);
92: }
93: /* --------------------------------------------------------- */
96: /*
97: PetscByteSwapDouble - Swap bytes in a double
98: */
99: PetscErrorCode PetscByteSwapDouble(double *buff,PetscInt n)
100: {
101: PetscInt i,j;
102: double tmp,*buff1 = (double*)buff;
103: double *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
104: char *ptr1,*ptr2 = (char*)&tmp;
107: for (j=0; j<n; j++) {
108: ptr1 = (char*)(buff1 + j);
109: for (i=0; i<(int) sizeof(double); i++) {
110: ptr2[i] = ptr1[sizeof(double)-1-i];
111: }
112: buff1[j] = *tptr;
113: }
114: return(0);
115: }
116: #endif
117: /* --------------------------------------------------------- */
120: /*@C
121: PetscBinaryRead - Reads from a binary file.
123: Not Collective
125: Input Parameters:
126: + fd - the file
127: . n - the number of items to read
128: - type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
130: Output Parameters:
131: . p - the buffer
135: Level: developer
137: Notes:
138: PetscBinaryRead() uses byte swapping to work on all machines.
139: Integers are stored on the file as 32 long, regardless of whether
140: they are stored in the machine as 32 or 64, this means the same
141: binary file may be read on any machine.
143: Concepts: files^reading binary
144: Concepts: binary files^reading
146: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose()
147: @*/
148: PetscErrorCode PetscBinaryRead(int fd,void *p,PetscInt n,PetscDataType type)
149: {
150: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INT) || !defined(PETSC_WORDS_BIGENDIAN)
151: PetscErrorCode ierr;
152: #endif
153: int maxblock = 65536,wsize,err,m = (int) n;
154: char *pp = (char*)p;
155: #if (PETSC_SIZEOF_INT == 8) || !defined(PETSC_WORDS_BIGENDIAN) || defined(PETSC_USE_64BIT_INT)
156: void *ptmp = p;
157: #endif
160: if (!n) return(0);
163: if (type == PETSC_INT){
164: #if (PETSC_SIZEOF_INT == 8)
165: /* read them in as shorts, later stretch into ints */
166: m *= sizeof(short);
167: PetscMalloc(m,&pp);
168: ptmp = (void*)pp;
169: #elif defined(PETSC_USE_64BIT_INT)
170: /* read them in as int, later stretch into PetscInts */
171: m *= sizeof(int);
172: PetscMalloc(m,&pp);
173: ptmp = (void*)pp;
174: #else
175: m *= sizeof(int);
176: #endif
177: }
178: else if (type == PETSC_SCALAR) m *= sizeof(PetscScalar);
179: else if (type == PETSC_DOUBLE) m *= sizeof(double);
180: else if (type == PETSC_SHORT) m *= sizeof(short);
181: else if (type == PETSC_CHAR) m *= sizeof(char);
182: else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
183: else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
184:
185: while (m) {
186: wsize = (m < maxblock) ? m : maxblock;
187: err = read(fd,pp,wsize);
188: if (err < 0 && errno == EINTR) continue;
189: if (!err && wsize > 0) SETERRQ(PETSC_ERR_FILE_READ,"Read past end of file");
190: if (err < 0) SETERRQ(PETSC_ERR_FILE_READ,"Error reading from file");
191: m -= err;
192: pp += err;
193: }
194: #if !defined(PETSC_WORDS_BIGENDIAN)
195: if (type == PETSC_INT) {PetscByteSwapInt((int*)ptmp,n);}
196: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
197: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
198: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
199: #endif
201: #if (PETSC_SIZEOF_INT == 8)
202: if (type == PETSC_INT){
203: int *p_int = (int*)p,i;
204: short *p_short = (short *)ptmp;
205: for (i=0; i<n; i++) {
206: p_int[i] = (int)p_short[i];
207: }
208: PetscFree(ptmp);
209: }
210: #elif defined(PETSC_USE_64BIT_INT)
211: if (type == PETSC_INT){
212: PetscInt *p_int = (PetscInt*)p,i;
213: int *p_short = (int *)ptmp;
214: for (i=0; i<n; i++) {
215: p_int[i] = (PetscInt)p_short[i];
216: }
217: PetscFree(ptmp);
218: }
219: #endif
221: return(0);
222: }
223: /* --------------------------------------------------------- */
226: /*@C
227: PetscBinaryWrite - Writes to a binary file.
229: Not Collective
231: Input Parameters:
232: + fd - the file
233: . p - the buffer
234: . n - the number of items to write
235: . type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
236: - istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise.
238: Level: advanced
240: Notes:
241: PetscBinaryWrite() uses byte swapping to work on all machines.
242: Integers are stored on the file as 32 long, regardless of whether
243: they are stored in the machine as 32 or 64, this means the same
244: binary file may be read on any machine.
246: The Buffer p should be read-write buffer, and not static data.
247: This way, byte-swapping is done in-place, and then the buffer is
248: written to the file.
249:
250: This routine restores the original contents of the buffer, after
251: it is written to the file. This is done by byte-swapping in-place
252: the second time. If the flag istemp is set to 1, the second
253: byte-swapping operation is not done, thus saving some computation,
254: but the buffer corrupted is corrupted.
256: Concepts: files^writing binary
257: Concepts: binary files^writing
259: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose()
260: @*/
261: PetscErrorCode PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
262: {
263: char *pp = (char*)p;
264: int err,maxblock,wsize,m = (int)n;
265: #if !defined(PETSC_WORDS_BIGENDIAN) || (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INT)
267: void *ptmp = p;
268: #endif
271: if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
272: if (!n) return(0);
274: maxblock = 65536;
277: if (type == PETSC_INT){
278: #if (PETSC_SIZEOF_INT == 8)
279: int *p_int = (int*)p,i;
280: short *p_short;
281: m *= sizeof(short);
282: PetscMalloc(m,&pp);
283: ptmp = (void*)pp;
284: p_short = (short*)pp;
286: for (i=0; i<n; i++) {
287: p_short[i] = (short) p_int[i];
288: }
289: #elif defined(PETSC_USE_64BIT_INT)
290: PetscInt *p_int = (PetscInt*)p,i;
291: int *p_short;
292: m *= sizeof(int);
293: PetscMalloc(m,&pp);
294: ptmp = (void*)pp;
295: p_short = (int*)pp;
297: for (i=0; i<n; i++) {
298: p_short[i] = (int) p_int[i];
299: }
300: #else
301: m *= sizeof(int);
302: #endif
303: }
304: else if (type == PETSC_SCALAR) m *= sizeof(PetscScalar);
305: else if (type == PETSC_DOUBLE) m *= sizeof(double);
306: else if (type == PETSC_SHORT) m *= sizeof(short);
307: else if (type == PETSC_CHAR) m *= sizeof(char);
308: else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
309: else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
311: #if !defined(PETSC_WORDS_BIGENDIAN)
312: if (type == PETSC_INT) {PetscByteSwapInt((int*)ptmp,n);}
313: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
314: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
315: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
316: #endif
318: while (m) {
319: wsize = (m < maxblock) ? m : maxblock;
320: err = write(fd,pp,wsize);
321: if (err < 0 && errno == EINTR) continue;
322: if (err != wsize) SETERRQ(PETSC_ERR_FILE_WRITE,"Error writing to file.");
323: m -= wsize;
324: pp += wsize;
325: }
327: #if !defined(PETSC_WORDS_BIGENDIAN) && !(PETSC_SIZEOF_INT == 8) && !defined(PETSC_USE_64BIT_INT)
328: if (!istemp) {
329: if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
330: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
331: else if (type == PETSC_INT) {PetscByteSwapInt((int*)ptmp,n);}
332: }
333: #endif
335: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INT)
336: if (type == PETSC_INT){
337: PetscFree(ptmp);
338: }
339: #endif
340: return(0);
341: }
345: /*@C
346: PetscBinaryOpen - Opens a PETSc binary file.
348: Not Collective
350: Input Parameters:
351: + name - filename
352: - type - type of binary file, on of PETSC_FILE_RDONLY, PETSC_FILE_WRONLY, PETSC_FILE_CREATE
354: Output Parameter:
355: . fd - the file
357: Level: advanced
359: Concepts: files^opening binary
360: Concepts: binary files^opening
362: .seealso: PetscBinaryRead(), PetscBinaryWrite()
363: @*/
364: PetscErrorCode PetscBinaryOpen(const char name[],int type,int *fd)
365: {
367: #if defined(PETSC_HAVE_O_BINARY)
368: if (type == PETSC_FILE_CREATE) {
369: if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
370: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
371: }
372: } else if (type == PETSC_FILE_RDONLY) {
373: if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
374: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
375: }
376: } else if (type == PETSC_FILE_WRONLY) {
377: if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
378: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
379: }
380: #else
381: if (type == PETSC_FILE_CREATE) {
382: if ((*fd = creat(name,0666)) == -1) {
383: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
384: }
385: } else if (type == PETSC_FILE_RDONLY) {
386: if ((*fd = open(name,O_RDONLY,0)) == -1) {
387: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
388: }
389: }
390: else if (type == PETSC_FILE_WRONLY) {
391: if ((*fd = open(name,O_WRONLY,0)) == -1) {
392: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
393: }
394: #endif
395: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown file type");
396: return(0);
397: }
401: /*@C
402: PetscBinaryClose - Closes a PETSc binary file.
404: Not Collective
406: Output Parameter:
407: . fd - the file
409: Level: advanced
411: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
412: @*/
413: PetscErrorCode PetscBinaryClose(int fd)
414: {
416: close(fd);
417: return(0);
418: }
423: /*@C
424: PetscBinarySeek - Moves the file pointer on a PETSc binary file.
426: Not Collective
428: Input Parameters:
429: + fd - the file
430: . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
431: if PETSC_BINARY_SEEK_CUR then size is offset from current location
432: if PETSC_BINARY_SEEK_END then size is offset from end of file
433: - size - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
434: etc. in your calculation rather than sizeof() to compute byte lengths.
436: Output Parameter:
437: . offset - new offset in file
439: Level: developer
441: Notes:
442: Integers are stored on the file as 32 long, regardless of whether
443: they are stored in the machine as 32 or 64, this means the same
444: binary file may be read on any machine. Hence you CANNOT use sizeof()
445: to determine the offset or location.
447: Concepts: files^binary seeking
448: Concepts: binary files^seeking
450: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
451: @*/
452: PetscErrorCode PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
453: {
454: int iwhence=0;
457: if (whence == PETSC_BINARY_SEEK_SET) {
458: iwhence = SEEK_SET;
459: } else if (whence == PETSC_BINARY_SEEK_CUR) {
460: iwhence = SEEK_CUR;
461: } else if (whence == PETSC_BINARY_SEEK_END) {
462: iwhence = SEEK_END;
463: } else {
464: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
465: }
466: #if defined(PETSC_HAVE_LSEEK)
467: *offset = lseek(fd,off,iwhence);
468: #elif defined(PETSC_HAVE__LSEEK)
469: *offset = _lseek(fd,(long)off,iwhence);
470: #else
471: SETERRQ(PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
472: #endif
474: return(0);
475: }
479: /*@C
480: PetscSynchronizedBinaryRead - Reads from a binary file.
482: Collective on MPI_Comm
484: Input Parameters:
485: + comm - the MPI communicator
486: . fd - the file
487: . n - the number of items to read
488: - type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
490: Output Parameters:
491: . p - the buffer
493: Options Database Key:
494: . -binary_longints - indicates the file was generated on a Cray vector
495: machine (not the T3E/D) and the ints are stored as 64 bit
496: quantities, otherwise they are stored as 32 bit
498: Level: developer
500: Notes:
501: Does a PetscBinaryRead() followed by an MPI_Bcast()
503: PetscSynchronizedBinaryRead() uses byte swapping to work on all machines.
504: Integers are stored on the file as 32 long, regardless of whether
505: they are stored in the machine as 32 or 64, this means the same
506: binary file may be read on any machine.
508: Concepts: files^synchronized reading of binary files
509: Concepts: binary files^reading, synchronized
511: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
512: @*/
513: PetscErrorCode PetscSynchronizedBinaryRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
514: {
516: PetscMPIInt rank;
517: MPI_Datatype mtype;
520: MPI_Comm_rank(comm,&rank);
521: if (!rank) {
522: PetscBinaryRead(fd,p,n,type);
523: }
524: PetscDataTypeToMPIDataType(type,&mtype);
525: MPI_Bcast(p,n,mtype,0,comm);
526: return(0);
527: }
531: /*@C
532: PetscSynchronizedBinarySeek - Moves the file pointer on a PETSc binary file.
535: Input Parameters:
536: + fd - the file
537: . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
538: if PETSC_BINARY_SEEK_CUR then size is offset from current location
539: if PETSC_BINARY_SEEK_END then size is offset from end of file
540: - off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
541: etc. in your calculation rather than sizeof() to compute byte lengths.
543: Output Parameter:
544: . offset - new offset in file
546: Level: developer
548: Notes:
549: Integers are stored on the file as 32 long, regardless of whether
550: they are stored in the machine as 32 or 64, this means the same
551: binary file may be read on any machine. Hence you CANNOT use sizeof()
552: to determine the offset or location.
554: Concepts: binary files^seeking
555: Concepts: files^seeking in binary
557: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
558: @*/
559: PetscErrorCode PetscSynchronizedBinarySeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
560: {
562: PetscMPIInt rank;
565: MPI_Comm_rank(comm,&rank);
566: if (!rank) {
567: PetscBinarySeek(fd,off,whence,offset);
568: }
569: return(0);
570: }