1 /*
2      library_file.c: functions for file i/o
3      Copyright (C) 2001  CCLRC, Charles Ballard
4 
5      This library is free software: you can redistribute it and/or
6      modify it under the terms of the GNU Lesser General Public License
7      version 3, modified in accordance with the provisions of the
8      license to address the requirements of UK law.
9 
10      You should have received a copy of the modified GNU Lesser General
11      Public License along with this library.  If not, copies may be
12      downloaded from http://www.ccp4.ac.uk/ccp4license.php
13 
14      This program is distributed in the hope that it will be useful,
15      but WITHOUT ANY WARRANTY; without even the implied warranty of
16      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17      GNU Lesser General Public License for more details.
18 */
19 
20 /** @file library_file.c
21  *  Functions for file i/o.
22  *  Charles Ballard
23  */
24 
25 #include<string.h>
26 #include <limits.h>
27 #include <fcntl.h>
28 #if defined _MSC_VER
29 #include <io.h>
30 #endif
31 #include "library_file.h"
32 #include "ccp4_errno.h"
33 #include "ccp4_file_err.h"
34 /* rcsid[] = "$Id: library_file.c,v 1.26 2012/08/20 12:21:16 gxg60988 Exp $" */
35 
36 static uint16 nativeIT = NATIVEIT; /* machine integer type */
37 static uint16 nativeFT = NATIVEFT; /* machine float type */
38 
39 static int _item_sizes[] = {
40   (int) sizeof (char),          /* 0: bytes */
41   (int) sizeof (short int),     /* 1: (integer) half words */
42   (int) sizeof (float),         /* 2: reals/words */
43   (int) sizeof (int),           /* 3: `short complex' (pairs of half words).
44                                    NB int rather than 2*short since must fit
45                                    into fortran integer */
46   (int) 2*sizeof (float),        /* 4: complex (pairs of words) */
47   (int) sizeof (int),           /* 5: not used */
48   (int) sizeof (int)            /* 6: integers */
49 };
50 
51 static int (*_read_mode[])(CCP4File *, uint8 *, size_t) = {
52   ccp4_file_readchar,
53   ccp4_file_readshort,
54   ccp4_file_readfloat,
55   ccp4_file_readshortcomp,
56   ccp4_file_readcomp,
57   NULL,
58   ccp4_file_readint
59 };
60 
61 static int (*_write_mode[])(CCP4File *, const uint8 *, size_t) = {
62   ccp4_file_writechar,
63   ccp4_file_writeshort,
64   ccp4_file_writefloat,
65   ccp4_file_writeshortcomp,
66   ccp4_file_writecomp,
67   NULL,
68   ccp4_file_writeint
69 };
70 
71 /**
72  * vaxF2ieeeF:
73  * @param buffer (float_uint_uchar *) vax order float array
74  * @param size (unsigned int) number of items
75  *
76  * Translation from Vax floating point format to ieee.
77  *
78  */
vaxF2ieeeF(union float_uint_uchar * buffer,const unsigned int size)79 static void vaxF2ieeeF(union float_uint_uchar *buffer, const unsigned int size)
80 {
81   union float_uint_uchar out;
82   unsigned char exp;
83   unsigned int i;
84 
85   if ( buffer == NULL || size == 0) return;
86 
87   for (i = 0; i < size; i++) {
88     exp = (buffer[i].c[1] << 1) | (buffer[i].c[0] >> 7); /* extract exponent */
89     if (!exp && !buffer[i].c[1])        /* zero value */
90       out.c[0] = out.c[1] = out.c[2] = out.c[3] = 0;
91     else if (exp > 2) {         /* normal value */
92       out.c[0] = buffer[i].c[1] - (uint8)1; /* subtracts 2 from exponent */
93       /* copy mantissa, LSB of exponent */
94       out.c[1] = buffer[i].c[0];
95       out.c[2] = buffer[i].c[3];
96       out.c[3] = buffer[i].c[2];
97     } else if (exp) {           /* denormalized number */
98       int shft;
99 
100       out.c[0] = buffer[i].c[1] & 0x80; /* keep sign, zero exponent */
101       shft = 3 - exp;
102       /* shift original mant by 1 or 2 to get denormalized mant */
103       /* prefix mantissa with '1'b or '01'b as appropriate */
104       out.c[1] = (uint8)((buffer[i].c[0] & 0x7f) >> shft) |
105         (uint8)(0x10 << exp);
106       out.c[2] = (uint8)(buffer[i].c[0] << (8-shft)) |
107         (uint8)(buffer[i].c[3] >> shft);
108       out.c[3] = (uint8)(buffer[i].c[3] << (8-shft)) |
109         (uint8)(buffer[i].c[2] >> shft);
110     } else {                    /* sign=1 -> infinity or NaN */
111       out.c[0] = 0xff;          /* set exp to 255 */
112       /* copy mantissa */
113       out.c[1] = buffer[i].c[0] | (uint8)0x80; /* LSB of exp = 1 */
114       out.c[2] = buffer[i].c[3];
115       out.c[3] = buffer[i].c[2];
116     }
117     buffer[i] = out;            /* copy back result */
118   }
119 }
120 
121 /**
122  * ieeeF2vaxF:
123  * @param buffer (float_uint_uchar *) big endian order float array
124  * @param size (unsigned int) number of items
125  *
126  * Translation from ieee floating point format to vax.
127  *
128  */
ieeeF2vaxF(union float_uint_uchar * buffer,const unsigned int size)129 static void ieeeF2vaxF(union float_uint_uchar *buffer, const unsigned int size)
130 {
131   union float_uint_uchar out;
132   unsigned char exp;
133   unsigned int i;
134 
135   if ( buffer == NULL || size == 0) return;
136 
137   for (i=0; i<size; i++) {
138     exp = (buffer[i].c[0]<<1) | (buffer[i].c[1]>>7); /* extract exponent */
139     if (exp) {                  /* non-zero exponent */
140       /* copy mantissa, last bit of exponent */
141       out.c[0] = buffer[i].c[1];
142       out.c[2] = buffer[i].c[3];
143       out.c[3] = buffer[i].c[2];
144       if (exp < 254)            /* normal value */
145         out.c[1] = buffer[i].c[0] + (uint8)1; /* actually adds two to exp */
146       else {                    /* infinity or NaN */
147         if (exp == 254)         /* unrepresentable - OFL */
148           /* set mant=0 for overflow */
149           out.c[0] = out.c[1] = out.c[2] = out.c[3] = 0;
150         out.c[0] &= 0x7f;       /* set last bit of exp to 0 */
151         out.c[1] = 0x80;        /* sign=1 exp=0 -> OFL or NaN.  this will raise
152                                    a reserved operand exception if used. */
153       }
154     } else if (buffer[i].c[1] & 0x60) { /* denormalized value */
155       int shft;
156 
157       shft = (buffer[i].c[1] & 0x40) ? 1 : 2; /* shift needed to normalize */
158       /* shift mantissa */
159       /* note last bit of exp set to 1 implicitly */
160       out.c[0] = (uint8)(buffer[i].c[1] << shft) |
161         (uint8)(buffer[i].c[2] >> (8-shft));
162       out.c[3] = (uint8)(buffer[i].c[2] << shft) |
163         (uint8)(buffer[i].c[3] >> (8-shft));
164       out.c[2] = (uint8)(buffer[i].c[3] << shft);
165       out.c[1] = (uint8)(buffer[i].c[0] & 0x80); /* sign */
166       if (shft==1) {            /* set exp to 2 */
167         out.c[1] |= 0x01;
168         out.c[0] &= 0x7f;       /* set LSB of exp to 0 */
169       }
170     } else                      /* zero */
171       out.c[0] = out.c[1] = out.c[2] = out.c[3] = 0;
172     buffer[i] = out;            /* copy back the result */
173   }
174 }
175 
176 /**
177  * convexF2ieeeF:
178  * @param buffer (float_uint_uchar *) float array with convex byte ordering
179  * @param size (unsigned int) number of items
180  *
181  * Translation from convex floating point format to ieee.
182  *
183  */
convexF2ieeeF(union float_uint_uchar * buffer,const unsigned int size)184 static void convexF2ieeeF(union float_uint_uchar *buffer, const unsigned int size)
185 {
186   union float_uint_uchar out;
187   unsigned char exp;
188   unsigned int i;
189 
190   if ( buffer == NULL || size == 0) return;
191 
192   for (i = 0; i < size; i++) {
193     exp = (buffer[i].c[0]<<1) | (buffer[i].c[1]>>7); /* extract exponent */
194     if (!exp && !buffer[i].c[0])        /* zero value */
195       out.c[0] = out.c[1] = out.c[2] = out.c[3] = 0;
196     else if (exp > 2) {         /* normal value */
197       out.c[0] = buffer[i].c[0] - (uint8)1; /* subtracts 2 from exponent */
198       /* copy mantissa, LSB of exponent */
199       out.c[1] = buffer[i].c[1];
200       out.c[2] = buffer[i].c[2];
201       out.c[3] = buffer[i].c[3];
202     } else if (exp) {           /* denormalized number */
203       int shft;
204 
205       out.c[0] = buffer[i].c[0] & 0x80; /* keep sign, zero exponent */
206       shft = 3 - exp;
207       /* shift original mant by 1 or 2 to get denormalized mant */
208       /* prefix mantissa with '1'b or '01'b as appropriate */
209       out.c[1] = (uint8)((buffer[i].c[1] & 0x7f) >> shft) |
210         (uint8)(0x10 << exp);
211       out.c[2] = (uint8)(buffer[i].c[1] << (8-shft)) |
212         (uint8)(buffer[i].c[2] >> shft);
213       out.c[3] = (uint8)(buffer[i].c[2] << (8-shft)) |
214         (uint8)(buffer[i].c[3] >> shft);
215     } else {                    /* sign=1 -> infinity or NaN */
216       out.c[0] = 0xff;          /* set exp to 255 */
217       /* copy mantissa */
218       out.c[1] = buffer[i].c[1] | (uint8)0x80; /* LSB of exp = 1 */
219       out.c[2] = buffer[i].c[2];
220       out.c[3] = buffer[i].c[3];
221     }
222     buffer[i] = out;            /* copy back result */
223   }
224 }
225 
226 /**
227  * ieeeF2convexF:
228  * @param buffer (float_uint_uchar *) float array with big endian byte ordering
229  * @param size (const unsigned int) numnber of items
230  *
231  * Translation from ieee floating point format to convex.
232  *
233  */
ieeeF2convexF(union float_uint_uchar * buffer,const unsigned int size)234 static void ieeeF2convexF(union float_uint_uchar *buffer, const unsigned int size)
235 {
236   union float_uint_uchar out;
237   unsigned char exp;
238   unsigned int i;
239 
240   if ( buffer == NULL || size == 0) return;
241 
242   for (i=0; i < size; i++) {
243     exp = (uint8)(buffer[i].c[0] << 1) |
244       (uint8)(buffer[i].c[1] >> 7); /* extract exponent */
245     if (exp) {                  /* non-zero exponent */
246       /* copy mantissa, last bit of exponent */
247       out.c[1] = buffer[i].c[1];
248       out.c[3] = buffer[i].c[3];
249       out.c[2] = buffer[i].c[2];
250       if (exp < 254)            /* normal value */
251         out.c[0] = buffer[i].c[0] + (uint8)1; /* actually adds two to exp */
252       else {                    /* infinity or NaN */
253         if (exp == 254)         /* unrepresentable - OFL */
254           /* set mant=0 for overflow */
255           out.c[0] = out.c[1] = out.c[2] = out.c[3] = 0;
256         out.c[1] &= 0x7f;       /* set last bit of exp to 0 */
257         out.c[0] = 0x80;        /* sign=1 exp=0 -> OFL or NaN.  this will raise
258                                    a reserved operand exception if used. */
259       }
260     } else if (buffer[i].c[1] & 0x60) { /* denormalized value */
261       int shft;
262 
263       shft = (buffer[i].c[1] & 0x40) ? 1 : 2; /* shift needed to normalize */
264       /* shift mantissa */
265       /* note last bit of exp set to 1 implicitly */
266       out.c[1] = (uint8)(buffer[i].c[1] << shft) |
267         (uint8)(buffer[i].c[2] >> (8-shft));
268       out.c[2] = (uint8)(buffer[i].c[2] << shft) |
269         (uint8)(buffer[i].c[3] >> (8-shft));
270       out.c[3] = (uint8)(buffer[i].c[3] << shft);
271       out.c[0] = (uint8)(buffer[i].c[0] & 0x80); /* sign */
272       if (shft==1) {            /* set exp to 2 */
273         out.c[0] |= 0x01;
274         out.c[1] &= 0x7f;       /* set LSB of exp to 0 */
275       }
276     } else                      /* zero */
277       out.c[0] = out.c[1] = out.c[2] = out.c[3] = 0;
278     buffer[i] = out;            /* copy back the result */
279   }
280 }
281 
282 /**
283  * ccp4_file_raw_read:
284  * @param cfile *  (CCP4File *)
285  * @param buffer * (char *) input array
286  * @param n_items (size_t) number of items
287  *
288  * reads block of n_items bytes from cfile to buffer via
289  * FILE struct cfile->stream(fread) or file desc cfile->fd
290  * read/_read).  Increments location value cfile->loc. The
291  * cfile->iostat flag is set on failure.
292  * @return number of bytes read.
293  */
ccp4_file_raw_read(CCP4File * cfile,char * buffer,size_t n_items)294 int ccp4_file_raw_read(CCP4File *cfile, char *buffer, size_t n_items)
295 {
296   int result;
297 
298   if (cfile->buffered && cfile->stream) {
299     result = fread (buffer, (size_t) sizeof(char), n_items,
300                     cfile->stream);
301     if (result != n_items && feof(cfile->stream)) {
302       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_EOF),
303 		  "ccp4_file_raw_read", NULL);
304       cfile->iostat = CIO_EOF;
305       result = EOF;
306     } else if (result != n_items && ferror(cfile->stream)) {
307       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_raw_read", NULL);
308       cfile->iostat = CIO_ReadFail;
309       result = 0; }
310   } else {
311 #if defined _MSC_VER
312     result = _read (cfile->fd, buffer, n_items);
313 #else
314     result = read (cfile->fd, buffer, n_items);
315 #endif
316     if (n_items && result <= 0) {
317       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_ReadFail),
318 		  "ccp4_file_raw_read", NULL);
319       cfile->iostat = CIO_ReadFail;
320       result = 0; }
321   }
322   cfile->last_op = READ_OP;
323 
324   cfile->loc += result;
325   cfile->getbuff = 0;
326 
327   return result;
328 }
329 
330 /**
331  * ccp4_file_raw_write:
332  * @param cfile  (CCP4File *)
333  * @param buffer (char *) output array
334  * @param n_items (size_t) number of items
335  *
336  * writes block of @n_items bytes from @buffer to @cfile via FILE struct
337  * @cfile->stream(fwrite) or file desc @cfile->fd(write/_write).  Increments
338  * @cfile->loc on success, or resets on failure, which is then used to
339  * determine the file length.  On failure @cfile->iostat is set.
340  * @return number of bytes written.
341  */
ccp4_file_raw_write(CCP4File * cfile,const char * buffer,size_t n_items)342 int ccp4_file_raw_write(CCP4File *cfile, const char *buffer, size_t n_items)
343 {
344   int result;
345 
346   if (cfile->buffered && cfile->stream)
347     result = fwrite (buffer, (size_t) sizeof(char), n_items,
348                     cfile->stream);
349   else
350 #if defined _MSC_VER
351     result = _write (cfile->fd, buffer, n_items);
352 #else
353     result = write (cfile->fd, buffer, n_items);
354 #endif
355 
356   cfile->last_op = WRITE_OP;
357 
358   if (result == n_items)
359     cfile->loc += n_items;
360   else {
361     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_WriteFail),
362 		"ccp4_file_raw_write", NULL);
363     cfile->iostat = CIO_WriteFail;
364     ccp4_file_tell(cfile); }
365   cfile->length = MAX(cfile->loc,cfile->length);
366   cfile->getbuff = 0;
367 
368   return result;
369 }
370 
371 /**
372  * ccp4_file_raw_seek:
373  * @param cfile  (CCP4File *)
374  * @param offset (long) offset in bytes
375  * @param whence (int) SEEK_SET, SEEK_CUR, or SEEK_END
376  *
377  * if the file is "seekable" (not stdin) the function
378  * seeks on @cfile by offset bytes using fseek/ftell (@cfile->stream)
379  * or lseek (@cfile->fd).  %SEEK_SET is relative
380  * to start of file, %SEEK_CUR to current, %SEEK_END to
381  * end.
382  * @return offset in bytes on success, -1 on failure.
383  */
ccp4_file_raw_seek(CCP4File * cfile,long offset,int whence)384 int ccp4_file_raw_seek(CCP4File *cfile, long offset, int whence)
385 {
386   int result = -1;
387 
388   if (!cfile->direct)  {
389     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
390 		"ccp4_file_raw_seek", NULL);
391     return result; }
392 
393   if (cfile->buffered) {
394 #if defined (__alpha) && defined (vms)
395     (void) fflush (cfile->stream);
396 #endif
397     if (!(result = (fseek (cfile->stream,offset,whence))))
398       result = ftell(cfile->stream);
399   } else {
400 #if defined _MSC_VER
401      result = _lseek(cfile->fd,offset,whence);
402 #else
403      result = lseek(cfile->fd, offset, whence);
404 #endif
405   }
406 
407   cfile->last_op = IRRELEVANT_OP;
408 
409   if (result ==  -1) {
410     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_SeekFail),
411 		"ccp4_file_raw_seek", NULL);
412     cfile->iostat = CIO_SeekFail;
413   } else
414     cfile->loc = result;
415   cfile->getbuff = 0;
416 
417   return (result);
418 }
419 
420 /**
421  * _file_free:
422  * @param cfile  (CCP4File *)
423  *
424  * free up @cfile
425  */
_file_free(CCP4File * cfile)426 static void _file_free(CCP4File *cfile)
427 {
428   if(cfile->name) free(cfile->name);
429   cfile->name = NULL;
430   free(cfile);
431 }
432 
433 /**
434  * _file_init:
435  * @param cfile ()
436  *
437  * initialise cfile struct
438  * @return cfile struct
439  */
_file_init()440 static CCP4File *_file_init()
441 {
442   CCP4File *cfile = (CCP4File *) malloc(sizeof(CCP4File));
443   char *foreign = getenv ("CONVERT_FROM");
444   char *native = getenv ("NATIVEMTZ");
445 
446   memset(cfile,'\0',sizeof(CCP4File));
447   cfile->fd = -1;
448   cfile->buffered = 1;
449   cfile->binary = 1;
450   cfile->last_op = IRRELEVANT_OP;
451   cfile->mode = DEFMODE;
452   cfile->itemsize = _item_sizes[DEFMODE];
453   if (native == NULL && foreign != NULL) {
454     if (strcmp (foreign, "BEIEEE") == 0) {
455       cfile->fconvert = DFNTF_BEIEEE ;
456       cfile->iconvert = DFNTI_MBO ; }
457     else if (strcmp (foreign, "LEIEEE") == 0) {
458       cfile->fconvert = DFNTF_LEIEEE;
459       cfile->iconvert = DFNTI_IBO ; }
460     else if (strcmp (foreign, "VAX") == 0) {
461       cfile->fconvert = DFNTF_VAX ;
462       cfile->iconvert = DFNTI_IBO ; }
463     else if (strcmp (foreign, "CONVEXNATIVE") == 0) {
464       cfile->fconvert = DFNTF_CONVEXNATIVE ;
465       cfile->iconvert = DFNTI_MBO ; }
466   } else {
467     cfile->fconvert = nativeFT;
468     cfile->iconvert = nativeIT;
469   }
470   cfile->_read=_read_mode[DEFMODE];
471   cfile->_write=_write_mode[DEFMODE];
472   return (cfile);
473 }
474 
475 /**
476  * _file_open_mode:
477  * @param cfile (CCP4File *)
478  * @param flag (const int) mode flag
479  *
480  * set file open mode elements of @cfile (see ccp4_sysdep.h)
481  *  O_TMP    = 0x0010
482  *  O_RDONLY = 0x0000
483  *  O_WRONLY = 0x0001
484  *  O_RDWR   = 0x0002
485  *  O_APPEND = 0x0008
486  */
_file_open_mode(CCP4File * cfile,const int flag)487 static void _file_open_mode(CCP4File * cfile, const int flag)
488 {
489   if (flag & O_TMP)
490     cfile->scratch = 1;
491   if (flag & (O_WRONLY | O_RDWR | O_APPEND) ) {
492     cfile->write = 1;
493     if (flag & O_RDWR)
494       cfile->read = 1;
495     if (flag & O_APPEND)
496       cfile->append = 1;
497   } else
498     cfile->read = 1;
499 }
500 
501 /**
502  * _file_close:
503  * @param cfile  (CCP4File *)
504  *
505  * close @cfile if it is "owned" (@cfile->own) using fclose or close.
506  * Reset @cfile to some safe value.  Note: flush anyway.
507  * @return 0 on success, -1 on failure.
508  */
_file_close(CCP4File * cfile)509 static int _file_close (CCP4File *cfile)
510 {
511   int result = 0;
512 
513   if(cfile->buffered && cfile->stream) {
514     if (cfile->own)
515       result = fclose (cfile->stream);
516     else
517       result = fflush(cfile->stream);
518   } else {
519     if (cfile->own)
520 #if defined _MSC_VER
521       result = _close(cfile->fd);
522 #else
523       result = close (cfile->fd);
524 #endif
525   }
526 
527   if (result == EOF)
528     cfile->iostat = CIO_CloseFail;
529   else
530     cfile->stream = NULL;
531 
532   return (result);
533 }
534 
535 /**
536  * ccp4_file_is_write:
537  * @param cfile  (CCP4File *)
538  *
539  * is the @cfile writeable
540  * @return 1 if true
541  */
ccp4_file_is_write(const CCP4File * cfile)542 int ccp4_file_is_write(const CCP4File *cfile)
543 {
544   return (cfile->write);
545 }
546 
547 /**
548  * ccp4_file_is_read:
549  * @param cfile  (CCP4File *)
550  *
551  * is the @cfile readable
552  * @return 1 if true.
553  */
ccp4_file_is_read(const CCP4File * cfile)554 int ccp4_file_is_read(const CCP4File *cfile)
555 {
556   return (cfile->read);
557 }
558 
559 /**
560  * ccp4_file_is_append:
561  * @param cfile  (CCP4File *)
562  *
563  * is the @cfile in append mode
564  * @return 1 if true.
565  */
ccp4_file_is_append(const CCP4File * cfile)566 int ccp4_file_is_append(const CCP4File *cfile)
567 {
568   return (cfile->append);
569 }
570 
571 /**
572  * ccp4_file_is_scratch:
573  * @param cfile  (CCP4File *)
574  *
575  * is scratch file
576  * @return 1 if true.
577  */
ccp4_file_is_scratch(const CCP4File * cfile)578 int ccp4_file_is_scratch(const CCP4File *cfile)
579 {
580   return (cfile->scratch);
581 }
582 
583 /**
584  * ccp4_file_is_buffered:
585  * @param cfile  (CCP4File *)
586  *
587  * is the file buffered
588  * @return 1 if true
589  */
ccp4_file_is_buffered(const CCP4File * cfile)590 int ccp4_file_is_buffered(const CCP4File *cfile)
591 {
592   return (cfile->buffered);
593 }
594 
595 /**
596  * ccp4_file_status:
597  * @param cfile  (CCP4File *)
598  *
599  * @return @cfile error status
600  */
ccp4_file_status(const CCP4File * cfile)601 int ccp4_file_status(const CCP4File *cfile)
602 {
603   return (cfile->iostat);
604 }
605 
ccp4_file_raw_setstamp(CCP4File * cfile,const size_t offset)606 int ccp4_file_raw_setstamp(CCP4File *cfile, const size_t offset)
607 {
608   cfile->stamp_loc = offset;
609   return 0;
610 }
611 
612 /**
613  * ccp4_file_setstamp:
614  * @param cfile  (CCP4File *)
615  * @param stamp_loc (size_t) offset in items
616  *
617  * set the machine stamp offset in CCP4 items determined
618  * by the mode of @cfile.  See ccp4_file_setmode().
619  * @return 0 on success, %EOF on failure
620  */
ccp4_file_setstamp(CCP4File * cfile,const size_t offset)621 int ccp4_file_setstamp(CCP4File *cfile, const size_t offset)
622 {
623   if (!cfile) {
624     ccp4_signal(CCP4_ERRLEVEL(3)| CCP4_ERRNO(CIO_NullPtr),
625 		"ccp4_file_setstamp", NULL);
626     return EOF; }
627 
628   return ccp4_file_raw_setstamp(cfile, offset*cfile->itemsize);
629 }
630 
631 /**
632  * ccp4_file_setmode:
633  * @param cfile  (CCP4File *)
634  * @param mode (int) io_mode
635  *
636  * set the data mode of cfile to mode
637  * (CCP4_BYTE (8 bit) = 0,
638  *  CCP4_INT16 (16 bit) = 1,
639  *  CCP4_INT32 (32 bit) = 6,
640  *  FLOAT32 (32 bit) = 2,
641  *  COMP32 (2*16 bit) = 3,
642  *  COMP64 (2*32 bit) = 4).
643  * @return 0 on success, EOF on failure.
644  */
ccp4_file_setmode(CCP4File * cfile,const int mode)645 int ccp4_file_setmode (CCP4File *cfile, const int mode)
646 {
647   if (!cfile) {
648     ccp4_signal(CCP4_ERRLEVEL(3)| CCP4_ERRNO(CIO_NullPtr),
649 		"ccp4_file_mode", NULL);
650     return EOF; }
651 
652   if (mode >= 0 && mode <= 6 && mode != 5) {
653     cfile->mode = mode;
654     cfile->itemsize = _item_sizes[mode];
655     cfile->_read=_read_mode[mode];
656     cfile->_write=_write_mode[mode];
657   } else {
658     ccp4_signal(CCP4_ERRLEVEL(3)| CCP4_ERRNO(CIO_BadMode),
659 		"ccp4_file_mode", NULL);
660     return EOF; }
661 
662   return  0;
663 }
664 
665 /**
666  * ccp4_file_mode:
667  * @param cfile  (CCP4File *)
668  *
669  * get data mode of @cfile (CCP4_BYTE =0, CCP4_INT16 =1, CCP4_INT32=6,
670  * FLOAT32 =2, COMP32 =3, COMP64 =4)
671  * @return %mode
672  */
ccp4_file_mode(const CCP4File * cfile)673 int ccp4_file_mode (const CCP4File *cfile)
674 {
675   if (!cfile) {
676     ccp4_signal(CCP4_ERRLEVEL(3)| CCP4_ERRNO(CIO_NullPtr),
677 		"ccp4_file_mode", NULL);
678     return EOF; }
679 
680   return (cfile->mode);
681 }
682 
683 /**
684  * ccp4_file_itemsize:
685  * @param cfile  (CCP4File *)
686  *
687  * @return %itemsize of @cfile.
688  */
ccp4_file_itemsize(const CCP4File * cfile)689 int ccp4_file_itemsize(const CCP4File *cfile)
690 {
691   if (!cfile) {
692     ccp4_signal(CCP4_ERRLEVEL(3)| CCP4_ERRNO(CIO_BadMode),
693 		"ccp4_file_itemsize", NULL);
694     return EOF; }
695 
696   return (cfile->itemsize);
697 }
698 
699 /**
700  * ccp4_file_name:
701  * @param cfile (CCP4File *)
702  *
703  * strdup @cfile->name
704  * @return name of file as char *
705  */
ccp4_file_name(CCP4File * cfile)706 char *ccp4_file_name( CCP4File *cfile)
707 {
708 #if defined _MSC_VER
709   return ( cfile == NULL ? NULL : _strdup(cfile->name));
710 #else
711   return ( cfile == NULL ? NULL : strdup(cfile->name));
712 #endif
713 }
714 
715 /**
716  * ccp4_file_setbyte:
717  * @param cfile (CCP4File *)
718  * @param byte_order (int)
719  *
720  * set byte ordering for file
721  * Return:
722   */
ccp4_file_setbyte(CCP4File * cfile,const int byte_order)723 int ccp4_file_setbyte(CCP4File *cfile, const int byte_order)
724 {
725   int result = (cfile->fconvert | (cfile->iconvert<<8));
726 
727   switch (byte_order) {
728   case DFNTF_BEIEEE:
729     cfile->fconvert = DFNTF_BEIEEE;
730     cfile->iconvert = DFNTI_MBO;
731     break;
732   case DFNTF_LEIEEE:
733     cfile->fconvert = DFNTF_LEIEEE;
734     cfile->iconvert = DFNTI_IBO ;
735     break;
736   case DFNTF_VAX:
737     cfile->fconvert = DFNTF_VAX ;
738     cfile->iconvert = DFNTI_IBO ;
739     break;
740   case DFNTF_CONVEXNATIVE:
741     cfile->fconvert = DFNTF_CONVEXNATIVE ;
742     cfile->iconvert = DFNTI_MBO ;
743     break;
744   default:
745     ccp4_signal(CCP4_ERRLEVEL(3)| CCP4_ERRNO(CIO_BadMode),
746 		"ccp4_file_setbyte", NULL);
747     result = 0;
748   }
749   return result;
750 }
751 
752 /**
753  * ccp4_file_byte:
754  * @param cfile (CCP4File *)
755  *
756  * get byte ordering for file
757  * @return byte ordering information
758   */
ccp4_file_byte(CCP4File * cfile)759 int ccp4_file_byte(CCP4File *cfile)
760 {
761   return (cfile->fconvert | (cfile->iconvert<<8));
762 }
763 
764 /**
765  * ccp4_file_open_file:
766  * @param file (const FILE *) FILE struct
767  * @param flag (const int) io mode (O_RDONLY =0, O_WRONLY =1, O_RDWR =2,
768  *        O_TMP =, O_APPEND =)
769  *
770  * open @cfile with existing handle FILE struct file and mode @flag.
771  * The struct stat is check to determine if file is a regular file,
772  * if it is, and is not stdin, it is assumed to be direct access.
773  * @return (CCP4File *) on success, NULL on failure
774  */
ccp4_file_open_file(const FILE * file,const int flag)775 CCP4File *ccp4_file_open_file (const FILE *file, const int flag)
776 {
777   CCP4File *cfile;
778 #if defined _MSC_VER
779   struct _stat st;
780 #else
781   struct stat st;
782 #endif
783 
784   if (!file) {
785     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
786                 "ccp4_file_open_file", NULL);
787     return NULL; }
788 
789   if (!(cfile = _file_init() ) ) {
790       ccp4_signal(CCP4_ERRLEVEL(3),
791                   "ccp4_file_open_file", NULL);
792       return NULL; }
793 
794   /* set values in structure */
795   _file_open_mode(cfile,flag);
796   cfile->stream = (FILE *) file;
797   cfile->buffered = 1;
798   cfile->open = 1;
799 
800 #if defined _MSC_VER
801   _fstat(_fileno(cfile->stream), &st);
802   if ( !(st.st_mode & S_IFREG) || file == stdin) {
803 #else
804   fstat(fileno(cfile->stream), &st);
805   if ( !S_ISREG(st.st_mode) || file == stdin ) {
806 #endif
807     cfile->length = INT_MAX;
808     cfile->direct = 0;
809   } else {
810     cfile->length = st.st_size;
811     cfile->direct = 1;
812   }
813   cfile->loc = ftell( (FILE *)file);
814 
815   return cfile;
816 }
817 
818 /**
819  * ccp4_file_open_fd:
820  * @param fd (const int) file descriptor
821  * @param flag (const int) io mode (O_RDONLY =0, O_WRONLY =1, O_RDWR =2,
822  *        O_TMP =, O_APPEND =)
823  *
824  * initialise CCP4File struct with file descriptor @fd and mode @flag
825  * The struct stat is check to determine if file is a regular file,
826  * if it is, and is not stdin, it is assumed to be direct access.
827  * @return (CCP4File *) on success, NULL on failure
828  */
829 CCP4File *ccp4_file_open_fd (const int fd, const int flag)
830 {
831   CCP4File * cfile;
832 #if defined _MSC_VER
833   struct _stat st;
834 #else
835   struct stat st;
836 #endif
837 
838   if (!(cfile = _file_init() ) ) {
839       ccp4_signal(CCP4_ERRLEVEL(3),
840                   "ccp4_file_open_fd", NULL);
841       return NULL; }
842 
843   _file_open_mode(cfile, flag);
844   cfile->fd = fd;
845   cfile->open = 1;
846   cfile->buffered = 0;
847 
848 #if defined _MSC_VER
849   _fstat(fd, &st);
850   if ( !(st.st_mode & S_IFREG) || fd == 0) {
851 #else
852   fstat(fd, &st);
853   if ( !S_ISREG(st.st_mode) || fd == 0 ) {
854 #endif
855     cfile->length = INT_MAX;
856     cfile->direct = 0;
857     cfile->loc = 0;
858   } else {
859     cfile->length = st.st_size;
860     cfile->direct = 1;
861 #if defined _MSC_VER
862     cfile->loc = _lseek(fd, 0L, SEEK_CUR);
863 #else
864     cfile->loc = lseek(fd, 0L, SEEK_CUR);
865 #endif
866   }
867 
868   return cfile;
869 }
870 
871 /**
872  * ccp4_file_open:
873  * @param filename (const char *) filename
874  * @param flag (const int) i/o mode, possible values are O_RDONLY, O_WRONLY,
875  *      O_RDWR, O_APPEND, O_TMP, O_CREAT, O_TRUNC - see ccp4_sysdep.h
876  *
877  * initialise CCP4File struct for file filename with mode @flag.
878  * If !buffered use open(), otherwise fopen()
879   * The struct stat is check to determine if file is a regular file,
880  * if it is, and is not stdin, it is assumed to be direct access.
881  *
882  * @return (CCP4File *) on success, NULL on failure
883  */
884 CCP4File *ccp4_file_open (const char *filename, const int flag)
885 {
886   CCP4File *cfile;
887   int openflags = O_RDONLY;
888   char fmode[5];
889 #if defined _MSC_VER
890   struct _stat st;
891 #else
892   struct stat st;
893 #endif
894 
895   if (!(cfile = _file_init())) {
896     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_open", NULL);
897     return NULL; }
898   _file_open_mode(cfile, flag);
899 
900   if (!cfile->buffered) {
901     if (cfile->read && cfile->write) openflags = (O_RDWR | O_CREAT);
902     else if (cfile->write)  openflags = (O_WRONLY | O_CREAT);
903     if (cfile->append) openflags |= O_APPEND;
904     if (flag & O_TRUNC) openflags |= O_TRUNC;
905 #if defined _MSC_VER
906     if (cfile->scratch) openflags |= O_TEMPORARY;
907 #endif
908 #if defined(__DECC) && defined(VMS) || defined (_MSC_VER)
909     openflags |= O_BINARY;
910 #endif
911 #if defined _MSC_VER
912     cfile->fd = _open(filename, openflags);
913 #else
914     cfile->fd = open(filename, openflags);
915 #endif
916     if (cfile->fd == -1) {
917       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_CantOpenFile),
918                   "ccp4_file_open1", NULL);
919       return NULL;
920     } else {
921 #if defined _MSC_VER
922       _fstat(cfile->fd, &st); }
923 #else
924       fstat(cfile->fd, &st); }
925 #endif
926   } else {
927     char *mptr = fmode;
928     if (cfile->append) {
929       *mptr++ = 'a';
930       if (cfile->read) *mptr++ = '+';
931     } else {
932       if (cfile->read && cfile->write) {
933         if (flag & O_TRUNC) {*mptr++ = 'w'; }
934         else *mptr++ = 'r';
935         *mptr++ = '+';
936       } else if (cfile->write)
937         *mptr++ = 'w';
938       else
939         *mptr++ = 'r';
940     }
941 #if defined(__DECC) && defined(VMS) || defined (_WIN32)
942     *mptr++ = 'b';
943 #endif
944     *mptr++ = '\0';
945 
946 #ifdef VMS
947     if (cfile->scratch)
948       cfile->stream = fopen (filename, fmode,
949                              "mbc=16",        /* bigger blocksize */
950                              "fop=tmd");      /* temporary, delete on close */
951     else
952       cfile->stream = fopen (filename, fmode,
953                              "mbc=16",        /* bigger blocksize */
954                              "ctx=stm", "mrs=0", "rat=cr", "rfm=stmlf");
955 #elif defined(_WIN32)
956     if (cfile->scratch) {
957       cfile->stream = tmpfile();
958       if (!cfile->stream) {
959         ccp4_signal(CCP4_ERRLEVEL(2) | CCP4_ERRNO(CIO_CantOpenFile),
960                     "tmpfile() failed, opening normal file instead.", NULL);
961         cfile->stream = fopen (filename, fmode);
962       }
963     }
964     else
965       cfile->stream = fopen (filename, fmode);
966 #else
967     cfile->stream = fopen (filename, fmode);
968     if (cfile->stream)
969       if (cfile->scratch && unlink (filename)!=0) {
970         ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_UnlinkFail),
971                     "ccp4_file_open(unlink)", NULL);
972         cfile->iostat = CIO_UnlinkFail; return NULL; }
973 #endif
974     if (!cfile->stream) {
975       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_CantOpenFile),
976                   "ccp4_file_open2", NULL);
977       cfile->iostat = CIO_CantOpenFile;
978       free(cfile);
979       return NULL; }
980 #if defined (__alpha) && defined (vms)
981 (void) fflush (cfile->stream);
982 #endif
983 #if defined _MSC_VER
984   _fstat(_fileno(cfile->stream), &st);
985 #else
986   fstat(fileno(cfile->stream), &st);
987 #endif
988   }
989 #if defined _MSC_VER
990   cfile->name = _strdup(filename);
991 #else
992   cfile->name = strdup(filename);
993 #endif
994   cfile->open = 1;
995   cfile->own = 1;
996 #if defined _MSC_VER
997   if ( !(st.st_mode & S_IFREG) ) {
998 #else
999   if ( !S_ISREG(st.st_mode) ) {
1000 #endif
1001     cfile->length = INT_MAX;
1002     cfile->direct = 0;
1003   } else {
1004     cfile->length = st.st_size;
1005     cfile->direct = 1;
1006   }
1007   cfile->loc = cfile->append ? cfile->length : 0;
1008 
1009   return cfile;
1010 }
1011 
1012 /**
1013  * ccp4_file_close:
1014  * @param cfile (CCP4File *)
1015  *
1016  * close @cfile if owned, close (non-buffered) or
1017  * fclose (buffered),  or fflush if stream not owned.
1018  * Free resources.
1019  * @return 0 on success, EOF on failure
1020  */
1021 int ccp4_file_close (CCP4File *cfile)
1022 {
1023 
1024   if (!cfile) {
1025     ccp4_signal(CCP4_ERRLEVEL(3)| CCP4_ERRNO(CIO_NullPtr),
1026 		"ccp4_file_close", NULL);
1027     return EOF; }
1028 
1029   if (_file_close (cfile) == EOF) {
1030     ccp4_signal(CCP4_ERRLEVEL(3),"ccp4_file_close", NULL);
1031     return EOF; }
1032 
1033   _file_free(cfile);
1034 
1035   return (0);
1036 }
1037 
1038 /**
1039  * ccp4_file_rarch:
1040  * @param cfile (CCP4File *)
1041  *
1042  * read machine stamp from file @cfile->stream.
1043  * The machine stamp is at @cfile->stamp_loc items, set
1044  * by ccp4_file_setstamp() (default 0).
1045  * NB. these values may be overrriden with the environmental
1046  * variable CONVERT_FROM.
1047  * @return fileFT | (fileIT<<8)
1048  */
1049 int ccp4_file_rarch (CCP4File *cfile)
1050 {
1051   unsigned char mtstring[4];    /* machine stamp */
1052   char *native = getenv ("NATIVEMTZ");
1053   char *foreign = getenv ("CONVERT_FROM");
1054 
1055   if (!cfile) {
1056     ccp4_signal(CCP4_ERRLEVEL(3)| CCP4_ERRNO(CIO_NullPtr),
1057 		"ccp4_file_rarch", NULL);
1058     return EOF; }
1059 
1060   if (native != NULL) return (nativeFT | (nativeIT<<8));
1061   if (foreign == NULL) {
1062     if (ccp4_file_raw_seek(cfile, cfile->stamp_loc, SEEK_SET) == -1) {
1063       ccp4_signal(CCP4_ERRLEVEL(3),"ccp4_file_rarch", NULL);
1064       return EOF; }
1065 
1066     if (ccp4_file_raw_read(cfile, (char *) mtstring, 4UL) != 4) {
1067         ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_rarch", NULL);
1068         return EOF; }
1069 
1070     cfile->iconvert = (mtstring[1]>>4) & 0x0f;
1071     cfile->fconvert = (mtstring[0]>>4) & 0x0f;
1072 
1073     /* iconvert and fconvert should be one of the DFNTI/DFNTF values listed
1074        in ccp4_sysdep.h and hence non-zero. Some machine stamps can be corrupted
1075        (e.g. mrc files from chimera). We try to trap for this, and revert to
1076        native. */
1077     if (cfile->iconvert == 0 || cfile->fconvert == 0) {
1078        if (ccp4_liberr_verbosity(-1))
1079           printf("Warning: Machine stamp corrupted? Assuming native format. \n");
1080        cfile->iconvert = nativeIT;
1081        cfile->fconvert = nativeFT;
1082     }
1083   }
1084 
1085   return (cfile->fconvert | (cfile->iconvert<<8));
1086 }
1087 
1088 /**
1089  * ccp4_file_warch:
1090  * @param cfile (CCP4File *)
1091  *
1092  * write machine stamp to file @cfile->stream.
1093  * The machine stamp is placed at @cfile->stamp_loc items,
1094  * set by ccp4_file_setstamp() (defaults to 0).
1095  *
1096  * @return 0 on success, EOF on failure
1097  */
1098 int ccp4_file_warch (CCP4File *cfile)
1099 {
1100   unsigned char mtstring[4];    /* machine stamp */
1101 
1102   if (!cfile) {
1103     ccp4_signal(CCP4_ERRLEVEL(3)| CCP4_ERRNO(CIO_NullPtr),
1104 		"ccp4_file_warch", NULL);
1105     return EOF; }
1106 
1107   if (ccp4_file_raw_seek(cfile, cfile->stamp_loc, SEEK_SET) == -1) {
1108       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_warch", NULL);
1109       return EOF; }
1110 
1111   mtstring[0] = cfile->fconvert | (cfile->fconvert << 4);
1112   mtstring[1] = 1 | (cfile->iconvert << 4);
1113   mtstring[2] = mtstring[3] = 0;
1114 
1115   if (ccp4_file_raw_write(cfile, (const char *) mtstring, 4) != 4) {
1116       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_warch", NULL);
1117     return EOF; }
1118 
1119   return 0;
1120 }
1121 
1122 /**
1123  * ccp4_file_read:
1124  * @param cfile (CCP4File *)
1125  * @param buffer (uint8 *) buffer
1126  * @param nitems (size_t) number of items
1127  *
1128  * mode dependent read function.  Reads @nitems items from stream
1129  * @cfile->stream to @buffer as determined by cfile->mode.
1130  *
1131  * @return number of items read on success, EOF on failure
1132  */
1133 int ccp4_file_read (CCP4File *cfile, uint8 *buffer, size_t nitems)
1134 {
1135   int result;
1136 
1137   result = cfile->_read(cfile,(uint8 *) buffer,nitems);
1138 
1139   if (result != nitems)
1140     ccp4_signal(CCP4_ERRLEVEL(3),
1141 	       "ccp4_file_read", NULL);
1142   return (result);
1143 }
1144 
1145 /**
1146  * ccp4_file_readcomp:
1147  * @param cfile (CCP4File *)
1148  * @param buffer (uint8 *) buffer
1149  * @param nitems (size_t) number of items
1150  *
1151  * float complex {float,float} read function.  Reads @nitems complex from stream
1152  * @cfile->stream to @buffer.  Allows short count when eof is detected (
1153  * buffered input only).
1154  *
1155  * @return number of complex read on success, EOF on failure
1156  */
1157 int ccp4_file_readcomp (CCP4File *cfile, uint8 *buffer, size_t nitems)
1158 {
1159   int i, n, result;
1160 
1161   if (!cfile)  {
1162       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
1163 		  "ccp4_file_readcomp", NULL);
1164     return EOF; }
1165 
1166   if ( !cfile->read || cfile->iostat) {
1167     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1168 		"ccp4_file_readcomp", NULL);
1169     return EOF; }
1170 
1171   if (cfile->last_op == WRITE_OP)
1172     if (ccp4_file_raw_seek(cfile,0L,SEEK_CUR) == -1) {
1173       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_readcomp", NULL);
1174       return EOF; }
1175 
1176   n = _item_sizes[COMP64] * nitems;
1177   if ( (result = ccp4_file_raw_read (cfile, (char *) buffer, n)) != n) {
1178     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_readcomp", NULL);
1179     if (cfile->stream && !feof(cfile->stream))
1180       return EOF;  }  /* short count on stream is OK if EOF */
1181 
1182   result /= _item_sizes[COMP64];
1183   n = result;
1184   if (cfile->fconvert != nativeFT) {
1185     n *= 2;                        /* pairs of reals */
1186     switch (cfile->fconvert) {     /* get to BE IEEE */
1187     case DFNTF_VAX :
1188         vaxF2ieeeF((union float_uint_uchar *) buffer, n);
1189         break;
1190     case DFNTF_CONVEXNATIVE :
1191         convexF2ieeeF((union float_uint_uchar *) buffer, n);
1192         break;
1193     case DFNTF_BEIEEE :
1194         break;
1195     case DFNTF_LEIEEE :
1196         {
1197             char j;
1198             for (i=0; i < n*4; i+=4) {
1199                 j = buffer[i];
1200                 buffer[i] = buffer[i+3];
1201                 buffer[i+3] = j;
1202                 j = buffer[i+1];
1203                 buffer[i+1] = buffer[i+2];
1204                 buffer[i+2] =j; }
1205         }
1206         break;
1207     default :
1208       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1209 		  "ccp4_file_readcomp", NULL);
1210       return EOF;
1211     }
1212     switch (nativeFT) {              /* get to Native if not BE IEEE */
1213     case DFNTF_BEIEEE :
1214         break;
1215     case DFNTF_LEIEEE :
1216         {
1217             char j;
1218             for (i=0; i < n*4; i+=4) {
1219                 j = buffer[i];
1220                 buffer[i] = buffer[i+3];
1221                 buffer[i+3] = j;
1222                 j = buffer[i+1];
1223                 buffer[i+1] = buffer[i+2];
1224                 buffer[i+2] =j; }
1225         }
1226         break;
1227     case DFNTF_CONVEXNATIVE :
1228         ieeeF2convexF((union float_uint_uchar *) buffer, n);
1229         break;
1230     case DFNTF_VAX :
1231         ieeeF2vaxF((union float_uint_uchar *) buffer, n);
1232         break;
1233     default :
1234       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1235 		  "ccp4_file_readcomp", NULL);
1236       return EOF;
1237     }
1238   }
1239   return (result);
1240 }
1241 
1242 /**
1243  * ccp4_file_readshortcomp:
1244  * @param cfile (CCP4File *)
1245  * @param buffer (uint8 *) buffer
1246  * @param nitems (size_t) number of items
1247  *
1248  * short complex {short,short} read function.  Reads @nitems complex from stream
1249  * @cfile->stream to @buffer. Allows short count when eof is detected (
1250  * buffered input only).
1251  *
1252  * @return number of complex read on success, EOF on failure
1253  */
1254 int ccp4_file_readshortcomp (CCP4File *cfile, uint8 *buffer, size_t nitems)
1255 {
1256   int i, n, result;
1257 
1258   if (!cfile)  {
1259       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
1260 		  "ccp4_file_readshortcomp", NULL);
1261     return EOF; }
1262 
1263   if ( !cfile->read || cfile->iostat) {
1264     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1265 		"ccp4_file_readshortcomp", NULL);
1266     return EOF; }
1267 
1268   if (cfile->last_op == WRITE_OP)
1269     if (ccp4_file_raw_seek(cfile,0L,SEEK_CUR) == -1) {
1270       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_readshortcomp", NULL);
1271       return EOF; }
1272 
1273   n = _item_sizes[COMP32] * nitems;
1274   if ( (result = ccp4_file_raw_read (cfile, (char *) buffer, n)) != n) {
1275       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_readshortcomp", NULL);
1276     if (cfile->stream && !feof(cfile->stream))
1277       return EOF; }
1278 
1279   result /= _item_sizes[COMP32];
1280 
1281   n = result;
1282   if (cfile->iconvert != nativeIT) {
1283     n *= 2;                  /* pairs of ints */
1284     {
1285       if ((cfile->iconvert==DFNTI_MBO && nativeIT==DFNTI_IBO) ||
1286           (cfile->iconvert==DFNTI_IBO && nativeIT==DFNTI_MBO)) {
1287         char j;
1288         for (i=0; i < n*2; i+=2) {
1289           j = buffer[i];
1290           buffer[i] = buffer[i+1];
1291           buffer[i+1] = j; } }
1292       else {
1293         ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1294                     "ccp4_file_readshortcomp", NULL);
1295         return EOF; }
1296     }
1297   }
1298   return (result);
1299 }
1300 
1301 /**
1302  * ccp4_file_readfloat:
1303  * @param cfile (CCP4File *)
1304  * @param buffer (uint8 *) buffer
1305  * @param nitems (size_t) number of items
1306  *
1307  * float read function.  Reads @nitems floats from stream
1308  * @cfile->stream to @buffer.
1309  *
1310  * @return number of floats read on success, EOF on failure
1311  */
1312 int ccp4_file_readfloat (CCP4File *cfile, uint8 *buffer, size_t nitems)
1313 {
1314   int i, n, result;
1315 
1316   if (!cfile)  {
1317       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
1318 		  "ccp4_file_readfloat", NULL);
1319     return EOF; }
1320 
1321   if (!cfile->read || cfile->iostat) {
1322       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1323 		  "ccp4_file_readfloat", NULL);
1324       return EOF; }
1325 
1326   if (cfile->last_op == WRITE_OP)
1327     if (ccp4_file_raw_seek(cfile,0L,SEEK_CUR) == -1) {
1328       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_readfloat", NULL);
1329       return EOF; }
1330 
1331   n = _item_sizes[FLOAT32] * nitems;
1332   if ( (result = ccp4_file_raw_read (cfile, (char *) buffer, n)) != n) {
1333     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_readfloat", NULL);
1334     if (cfile->stream && !feof(cfile->stream))
1335       return EOF; }
1336 
1337   result /= _item_sizes[FLOAT32];
1338 
1339   n = result;
1340   if (cfile->fconvert != nativeFT) {
1341     switch (cfile->fconvert) {     /* get to BE IEEE */
1342     case DFNTF_VAX :
1343       vaxF2ieeeF((union float_uint_uchar *) buffer, n);
1344       break;
1345     case DFNTF_CONVEXNATIVE :
1346       convexF2ieeeF((union float_uint_uchar *) buffer, n);
1347       break;
1348     case DFNTF_BEIEEE :
1349       break;
1350     case DFNTF_LEIEEE :
1351       {
1352 	char j;
1353 	for (i=0; i < n*4; i+=4) {
1354 	  j = buffer[i];
1355 	  buffer[i] = buffer[i+3];
1356 	  buffer[i+3] = j;
1357 	  j = buffer[i+1];
1358 	  buffer[i+1] = buffer[i+2];
1359 	  buffer[i+2] =j; }
1360       }
1361       break;
1362     default :
1363       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1364 		  "ccp4_file_readfloat", NULL);
1365       return EOF;
1366     }
1367     switch (nativeFT) {
1368     case DFNTF_BEIEEE :
1369       break;                      /* done enough */
1370     case DFNTF_LEIEEE :
1371       {
1372 	char j;
1373 	for (i=0; i < n*4; i+=4) {
1374 	  j = buffer[i];
1375 	  buffer[i] = buffer[i+3];
1376 	  buffer[i+3] = j;
1377 	  j = buffer[i+1];
1378 	  buffer[i+1] = buffer[i+2];
1379 	  buffer[i+2] =j; }
1380       }
1381       break;
1382     case DFNTF_CONVEXNATIVE :
1383       ieeeF2convexF((union float_uint_uchar *) buffer, n);
1384       break;
1385     case DFNTF_VAX :
1386       ieeeF2vaxF((union float_uint_uchar *) buffer, n);
1387       break;
1388     default :
1389       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1390 		  "ccp4_file_readfloat", NULL);
1391       return EOF;
1392     }
1393   }
1394   return (result);
1395 }
1396 
1397 /**
1398  * ccp4_file_readint:
1399  * @param cfile (CCP4File *)
1400  * @param buffer (uint8 *) buffer
1401  * @param nitems (size_t) number of items
1402  *
1403  * integer read function.  Reads @nitems int from stream
1404  * @cfile->stream to @buffer.
1405  *
1406  * @return number of int read on success, EOF on failure
1407  */
1408 int ccp4_file_readint (CCP4File *cfile, uint8 *buffer, size_t nitems)
1409 {
1410   int n, result;
1411 
1412   if (!cfile)  {
1413       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
1414 		  "ccp4_file_readint", NULL);
1415     return EOF; }
1416 
1417   if ( !cfile->read || cfile->iostat) {
1418     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1419 		"ccp4_file_readint", NULL);
1420     return EOF; }
1421 
1422   if (cfile->last_op == WRITE_OP)
1423     if (ccp4_file_raw_seek(cfile,0L,SEEK_CUR) == -1) {
1424       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_readint", NULL);
1425       return EOF; }
1426 
1427   n = _item_sizes[CCP4_INT32] * nitems;
1428   if ( (result = ccp4_file_raw_read (cfile, (char *) buffer, n)) != n) {
1429     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_readint", NULL);
1430     if (cfile->stream && !feof(cfile->stream))
1431       return EOF; }
1432 
1433   result /= _item_sizes[CCP4_INT32];
1434 
1435   n = result;
1436 
1437   if (cfile->iconvert != nativeIT) {
1438     if ((cfile->iconvert==DFNTI_MBO && nativeIT==DFNTI_IBO) ||
1439 	(cfile->iconvert==DFNTI_IBO && nativeIT==DFNTI_MBO)) {
1440       char j;
1441       int i;
1442       for (i=0; i < n*4; i+=4) {
1443 	j = buffer[i];
1444 	buffer[i] = buffer[i+3];
1445 	buffer[i+3] = j;
1446 	j = buffer[i+1];
1447 	buffer[i+1] = buffer[i+2];
1448 	buffer[i+2] =j; }
1449     } else {
1450       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1451 		"ccp4_file_readint", NULL);
1452       return EOF; }
1453   }
1454   return (result);
1455 }
1456 
1457 /**
1458  * ccp4_file_readshort:
1459  * @param cfile (CCP4File *)
1460  * @param buffer (uint8 *) buffer
1461  * @param nitems (size_t) number of items
1462  *
1463  * short read function.  Reads @nitems shorts from stream
1464  * @cfile->stream to @buffer.
1465  *
1466  * @return number of shorts read on success, EOF on failure
1467  */
1468 int ccp4_file_readshort (CCP4File *cfile, uint8 *buffer, size_t nitems)
1469 {
1470   int n, result;
1471 
1472   if (!cfile)  {
1473     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
1474 		"ccp4_file_readshort", NULL);
1475     return EOF; }
1476 
1477   if (!cfile->read || cfile->iostat) {
1478     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1479 		"ccp4_file_readshort", NULL);
1480     return EOF; }
1481 
1482   if (cfile->last_op == WRITE_OP)
1483     if (ccp4_file_raw_seek(cfile,0L,SEEK_CUR) == -1) {
1484       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_readshort", NULL);
1485       return EOF; }
1486 
1487   n = _item_sizes[CCP4_INT16] * nitems;
1488   if ( (result = ccp4_file_raw_read (cfile, (char *) buffer, n)) != n) {
1489     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_readshort", NULL);
1490     if (cfile->stream && !feof(cfile->stream))
1491       return EOF; }
1492 
1493   result /= _item_sizes[CCP4_INT16];
1494 
1495   n = result;
1496   if (cfile->iconvert != nativeIT) {
1497     if ((cfile->iconvert==DFNTI_MBO && nativeIT==DFNTI_IBO) ||
1498 	(cfile->iconvert==DFNTI_IBO && nativeIT==DFNTI_MBO)) {
1499       char j;
1500       int i;
1501       for (i=0; i < n*2; i+=2) {
1502 	j = buffer[i];
1503 	buffer[i] = buffer[i+1];
1504 	buffer[i+1] = j; }
1505     } else {
1506       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1507 		  "ccp4_file_readshort", NULL);
1508       return EOF; }
1509   }
1510   return (result);
1511 }
1512 
1513 /**
1514  * ccp4_file_readchar:
1515  * @param cfile (CCP4File *)
1516  * @param buffer (uint8 *) buffer
1517  * @param nitems (size_t) number of items
1518  *
1519  * character read function.  Reads @nitems characters from stream
1520  * @cfile->stream to @buffer.
1521  *
1522  * @return number of characters read on success, EOF on failure
1523  */
1524 int ccp4_file_readchar (CCP4File *cfile, uint8 *buffer, size_t nitems)
1525 {
1526   size_t result;
1527 
1528   if (! cfile) {
1529       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
1530 		  "ccp4_file_readchar", NULL);
1531       return EOF; }
1532 
1533   if (!cfile->read || cfile->iostat) {
1534     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1535 		"ccp4_file_readchar", NULL);
1536     return EOF; }
1537 
1538   if (cfile->last_op == WRITE_OP)
1539     if (ccp4_file_raw_seek(cfile,0L,SEEK_CUR) == -1) {
1540       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_readchar", NULL);
1541       return EOF; }
1542 
1543   if ( (result = ccp4_file_raw_read (cfile, (char *) buffer, nitems)) != nitems) {
1544     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_readchar", NULL);
1545     if (cfile->stream && !feof(cfile->stream))
1546       return EOF; }
1547 
1548   return (result);
1549 }
1550 
1551 /**
1552  * ccp4_file_write:
1553  * @param cfile (CCP4File *)
1554  * @param buffer (uint8 *) buffer
1555  * @param nitems (size_t) number of items
1556  *
1557  * mode dependent write function.  Write @nitems items from @buffer
1558  * to @cfile->stream as determined by cfile->mode.
1559  *
1560  * @return number of items written on success, EOF on failure
1561  */
1562 int ccp4_file_write (CCP4File *cfile, const uint8 *buffer, size_t nitems)
1563 {
1564   size_t result;
1565 
1566   result = cfile->_write(cfile, buffer, nitems);
1567 
1568   if ( result != nitems)
1569     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_write", NULL);
1570 
1571   return (result);
1572 }
1573 
1574 /**
1575  * ccp4_file_writecomp:
1576  * @param cfile (CCP4File *)
1577  * @param buffer (uint8 *) buffer
1578  * @param nitems (size_t) number of items
1579  *
1580  * complex {float,float} write function.  Write @nitems items from @buffer
1581  * to @cfile->stream.
1582  *
1583  * @return number of complex items written on success, EOF on failure
1584  */
1585 int ccp4_file_writecomp (CCP4File *cfile, const uint8 *buffer, size_t nitems)
1586 {
1587   size_t result = 0, n;
1588 
1589   if (!cfile) {
1590     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
1591 		"ccp4_file_writecomp", NULL);
1592     return EOF; }
1593 
1594   if (!cfile->write ||cfile->iostat) {
1595     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1596 		"ccp4_file_writecomp", NULL);
1597     return EOF;}
1598 
1599   if (cfile->last_op == READ_OP)
1600     if (ccp4_file_raw_seek(cfile,0L,SEEK_CUR) == -1) {
1601       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_writecomp", NULL);
1602       return EOF; }
1603 
1604   n = nitems * _item_sizes[COMP64];
1605 
1606   if (cfile->fconvert != nativeFT) {
1607     char out_buffer[8];
1608     const char *out_ptr = (char *) buffer;
1609     size_t i;
1610     for (i = 0; i != nitems; i++) {
1611       switch (nativeFT) {
1612       case DFNTF_BEIEEE :
1613         memcpy(out_buffer, out_ptr, _item_sizes[COMP64]);
1614         out_ptr += _item_sizes[COMP64];
1615         break;
1616       case DFNTF_LEIEEE :
1617         out_buffer[3] = *out_ptr++;
1618         out_buffer[2] = *out_ptr++;
1619         out_buffer[1] = *out_ptr++;
1620         out_buffer[0] = *out_ptr++;
1621         out_buffer[7] = *out_ptr++;
1622         out_buffer[6] = *out_ptr++;
1623         out_buffer[5] = *out_ptr++;
1624         out_buffer[4] = *out_ptr++;
1625         break;
1626     case DFNTF_CONVEXNATIVE :
1627         memcpy(out_buffer, out_ptr, _item_sizes[COMP64]);
1628         out_ptr += _item_sizes[COMP64];
1629         ieeeF2convexF((union float_uint_uchar *) out_buffer, 2);
1630         break;
1631     case DFNTF_VAX :
1632         memcpy(out_buffer, out_ptr, _item_sizes[COMP64]);
1633         out_ptr += _item_sizes[COMP64];
1634         ieeeF2vaxF((union float_uint_uchar *) out_buffer, 2);
1635         break;
1636     default :
1637       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1638 		  "CCP4_File::writecomp", NULL);
1639     }
1640     switch (cfile->fconvert) {
1641     case DFNTF_VAX :
1642         vaxF2ieeeF((union float_uint_uchar *) out_buffer, 2);
1643         break;
1644     case DFNTF_CONVEXNATIVE :
1645         convexF2ieeeF((union float_uint_uchar *) out_buffer, 2);
1646         break;
1647     case DFNTF_BEIEEE :
1648         break;
1649     case DFNTF_LEIEEE :
1650         {
1651           char j;
1652           j = out_buffer[0];
1653           out_buffer[0] = out_buffer[3];
1654           out_buffer[3] = j;
1655           j = out_buffer[1];
1656           out_buffer[1] = out_buffer[2];
1657           out_buffer[2] =j;
1658           j = out_buffer[4];
1659           out_buffer[4] = out_buffer[7];
1660           out_buffer[7] = j;
1661           j = out_buffer[5];
1662           out_buffer[5] = out_buffer[6];
1663           out_buffer[6] =j;
1664         }
1665         break;
1666     default :
1667       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1668 		  "ccp4_file_writecomp", NULL);
1669       return EOF;
1670     }
1671     result += ccp4_file_raw_write (cfile, out_buffer, _item_sizes[COMP64]);
1672     }
1673   } else {
1674     result = ccp4_file_raw_write (cfile, (char *) buffer, n);
1675   }
1676 
1677   if (result != n)
1678     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_writecomp", NULL);
1679 
1680   return (result / _item_sizes[COMP64]);
1681 }
1682 
1683 /**
1684  * ccp4_file_writeshortcomp:
1685  * @param cfile (CCP4File *)
1686  * @param buffer (uint8 *) buffer
1687  * @param nitems (size_t) number of items
1688  *
1689  * short complex {short,short} write function.  Write @nitems items from @buffer
1690  * to @cfile->stream.
1691  *
1692  * @return number of complex items written on success, EOF on failure
1693  */
1694 int ccp4_file_writeshortcomp (CCP4File *cfile, const uint8 *buffer, size_t nitems)
1695 {
1696   size_t result = 0, n;
1697 
1698   if (!cfile) {
1699     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
1700 		"ccp4_file_writeshortcomp", NULL);
1701     return EOF; }
1702 
1703   if (!cfile->write ||cfile->iostat) {
1704     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1705 		"ccp4_file_writeshortcomp", NULL);
1706     return EOF;}
1707 
1708   if (cfile->last_op == READ_OP)
1709     if (ccp4_file_raw_seek(cfile,0L,SEEK_CUR) == -1) {
1710       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_writeshortcomp", NULL);
1711       return EOF; }
1712 
1713   n = nitems * _item_sizes[COMP32];
1714 
1715   if (cfile->iconvert != nativeIT) {
1716     char out_buffer[4];
1717     const char *out_ptr = (char *) buffer;
1718     size_t i;
1719     for (i = 0; i != nitems; i++) {
1720       if ((cfile->iconvert==DFNTI_MBO && nativeIT==DFNTI_IBO) ||
1721 	  (cfile->iconvert==DFNTI_IBO && nativeIT==DFNTI_MBO)) {
1722         out_buffer[1] = *out_ptr++;
1723         out_buffer[0] = *out_ptr++;
1724         out_buffer[3] = *out_ptr++;
1725         out_buffer[2] = *out_ptr++;
1726       } else {
1727         ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1728 		"ccp4_file_writeshortcomp", NULL);
1729         return EOF; }
1730     result += ccp4_file_raw_write (cfile, out_buffer, _item_sizes[COMP32]);
1731     }
1732    } else {
1733     result = ccp4_file_raw_write (cfile, (char *) buffer, n);
1734   }
1735 
1736   if ( result != n)
1737     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_writeshortcomp", NULL);
1738 
1739   return (result / _item_sizes[COMP32]);
1740 }
1741 
1742 /**
1743  * ccp4_file_writefloat:
1744  * @param cfile (CCP4File *)
1745  * @param buffer (uint8 *) buffer
1746  * @param nitems (size_t) number of items
1747  *
1748  * float write function.  Write @nitems items from @buffer
1749  * to @cfile->stream.
1750  *
1751  * Returns number of floats written on success, EOF on failure
1752  */
1753 int ccp4_file_writefloat (CCP4File *cfile, const uint8 *buffer, size_t nitems)
1754 {
1755   size_t result = 0, n;
1756 
1757   if (!cfile) {
1758     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
1759 		"ccp4_file_writefloat", NULL);
1760     return EOF; }
1761 
1762   if (!cfile->write ||cfile->iostat) {
1763     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1764 		"ccp4_file_writefloat", NULL);
1765     return EOF;}
1766 
1767   if (cfile->last_op == READ_OP)
1768     if (ccp4_file_raw_seek(cfile,0L,SEEK_CUR) == -1) {
1769       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_writefloat", NULL);
1770       return EOF; }
1771 
1772   n = nitems * _item_sizes[FLOAT32];
1773 
1774   if (cfile->fconvert != nativeFT) {
1775     char out_buffer[4];
1776     const char *out_ptr = (char *) buffer;
1777     size_t i;
1778     for (i = 0; i != nitems; i++) {
1779       switch (nativeFT) {
1780       case DFNTF_BEIEEE :
1781         memcpy(out_buffer, out_ptr, _item_sizes[FLOAT32]);
1782         out_ptr += _item_sizes[FLOAT32];
1783         break;
1784       case DFNTF_LEIEEE :
1785         out_buffer[3] = *out_ptr++;
1786         out_buffer[2] = *out_ptr++;
1787         out_buffer[1] = *out_ptr++;
1788         out_buffer[0] = *out_ptr++;
1789         break;
1790     case DFNTF_CONVEXNATIVE :
1791         memcpy(out_buffer, out_ptr, _item_sizes[FLOAT32]);
1792         out_ptr += _item_sizes[FLOAT32];
1793         ieeeF2convexF((union float_uint_uchar *) out_buffer, 1);
1794         break;
1795     case DFNTF_VAX :
1796         memcpy(out_buffer, out_ptr, _item_sizes[FLOAT32]);
1797         out_ptr += _item_sizes[FLOAT32];
1798         ieeeF2vaxF((union float_uint_uchar *) out_buffer, 1);
1799         break;
1800     default :
1801       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1802 		  "CCP4_File::writefloat", NULL);
1803     }
1804     switch (cfile->fconvert) {
1805     case DFNTF_VAX :
1806         vaxF2ieeeF((union float_uint_uchar *) out_buffer, 1);
1807         break;
1808     case DFNTF_CONVEXNATIVE :
1809         convexF2ieeeF((union float_uint_uchar *) out_buffer, 1);
1810         break;
1811     case DFNTF_BEIEEE :
1812         break;
1813     case DFNTF_LEIEEE :
1814         {
1815           char j;
1816           j = out_buffer[0];
1817           out_buffer[0] = out_buffer[3];
1818           out_buffer[3] = j;
1819           j = out_buffer[1];
1820           out_buffer[1] = out_buffer[2];
1821           out_buffer[2] =j;
1822         }
1823         break;
1824     default :
1825       ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1826 		  "ccp4_file_writefloat", NULL);
1827       return EOF;
1828     }
1829     result += ccp4_file_raw_write (cfile, out_buffer, _item_sizes[FLOAT32]);
1830     }
1831   } else {
1832     result = ccp4_file_raw_write (cfile, (char *) buffer, n);
1833   }
1834 
1835   if (result != n)
1836     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_writefloat", NULL);
1837 
1838   return (result / _item_sizes[FLOAT32]);
1839 }
1840 
1841 /**
1842  * ccp4_file_writeint:
1843  * @param cfile (CCP4File *)
1844  * @param buffer (uint8 *) buffer
1845  * @param nitems (size_t) number of items
1846  *
1847  * int write function.  Write @nitems items from @buffer
1848  * to @cfile->stream.
1849  *
1850  * @return number of int written on success, EOF on failure
1851  */
1852 int ccp4_file_writeint (CCP4File *cfile, const uint8 *buffer, size_t nitems)
1853 {
1854   size_t result = 0, n;
1855 
1856   if (!cfile) {
1857     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
1858 		"ccp4_file_writeint", NULL);
1859     return EOF; }
1860 
1861   if (!cfile->write ||cfile->iostat) {
1862     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1863 		"ccp4_file_writeint", NULL);
1864     return EOF;}
1865 
1866   if (cfile->last_op == READ_OP)
1867     if (ccp4_file_raw_seek(cfile,0L,SEEK_CUR) == -1) {
1868       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_writeint", NULL);
1869       return EOF; }
1870 
1871   n = nitems * _item_sizes[CCP4_INT32];
1872 
1873   if (cfile->iconvert != nativeIT) {
1874     char out_buffer[4];
1875     const char *out_ptr = (char *) buffer;
1876     size_t i;
1877     for (i = 0; i != nitems; i++) {
1878       if ((cfile->iconvert==DFNTI_MBO && nativeIT==DFNTI_IBO) ||
1879 	  (cfile->iconvert==DFNTI_IBO && nativeIT==DFNTI_MBO)) {
1880         out_buffer[3] = *out_ptr++;
1881         out_buffer[2] = *out_ptr++;
1882         out_buffer[1] = *out_ptr++;
1883         out_buffer[0] = *out_ptr++;
1884       } else {
1885         ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1886 		"ccp4_file_writeint", NULL);
1887         return EOF; }
1888     result += ccp4_file_raw_write (cfile, out_buffer, _item_sizes[CCP4_INT32]);
1889     }
1890    } else {
1891     result = ccp4_file_raw_write (cfile, (char *) buffer, n);
1892   }
1893 
1894   if ( result != n)
1895     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_writeint", NULL);
1896 
1897   return (result / _item_sizes[CCP4_INT32]);
1898 }
1899 
1900 /**
1901  * ccp4_file_writeshort:
1902  * @param cfile (CCP4File *)
1903  * @param buffer (uint8 *) buffer
1904  * @param nitems (size_t) number of items
1905  *
1906  * short write function.  Write @nitems items from @buffer
1907  * to @cfile->stream.
1908  *
1909  * @return number of short written on success, EOF on failure
1910  */
1911 int ccp4_file_writeshort (CCP4File *cfile, const uint8 *buffer, size_t nitems)
1912 {
1913   size_t result = 0, n;
1914 
1915   if (!cfile) {
1916     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
1917 		"ccp4_file_writeshort", NULL);
1918     return EOF; }
1919 
1920   if (!cfile->write ||cfile->iostat) {
1921     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1922 		"ccp4_file_writeshort", NULL);
1923     return EOF;}
1924 
1925   if (cfile->last_op == READ_OP)
1926     if (ccp4_file_raw_seek(cfile,0L,SEEK_CUR) == -1) {
1927       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_writeshort", NULL);
1928       return EOF; }
1929 
1930   n = nitems * _item_sizes[CCP4_INT16];
1931 
1932   if (cfile->iconvert != nativeIT) {
1933     char out_buffer[2];
1934     const char *out_ptr = (char *) buffer;
1935     size_t i;
1936     for (i = 0; i != nitems; i++) {
1937       if ((cfile->iconvert==DFNTI_MBO && nativeIT==DFNTI_IBO) ||
1938 	  (cfile->iconvert==DFNTI_IBO && nativeIT==DFNTI_MBO)) {
1939         out_buffer[1] = *out_ptr++;
1940         out_buffer[0] = *out_ptr++;
1941       } else {
1942         ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1943 		"ccp4_file_readint", NULL);
1944         return EOF; }
1945     result += ccp4_file_raw_write (cfile, out_buffer, _item_sizes[CCP4_INT16]);
1946     }
1947    } else {
1948     result = ccp4_file_raw_write (cfile, (char *) buffer, n);
1949   }
1950 
1951   if ( result != n)
1952     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_writeshort", NULL);
1953 
1954   return (result / _item_sizes[CCP4_INT16]);
1955 }
1956 
1957 /**
1958  * ccp4_file_writechar:
1959  * @param cfile (CCP4File *)
1960  * @param buffer (uint8 *) buffer
1961  * @param nitems (size_t) number of items
1962  *
1963  * char write function.  Write @nitems items from @buffer
1964  * to @cfile->stream.
1965  *
1966  * @return number of bytes written on success, EOF on failure
1967  */
1968 int ccp4_file_writechar (CCP4File *cfile, const uint8 *buffer, size_t nitems)
1969 {
1970   size_t result;
1971 
1972   if (!cfile) {
1973     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
1974 		"ccp4_file_writechar", NULL);
1975     return EOF; }
1976 
1977   if (!cfile->write ||cfile->iostat) {
1978     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_BadMode),
1979 		"ccp4_file_writechar", NULL);
1980     return EOF;}
1981 
1982   if (cfile->last_op == READ_OP)
1983     if (ccp4_file_raw_seek(cfile,0L,SEEK_CUR) == -1) {
1984       ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_writechar", NULL);
1985       return EOF; }
1986 
1987   if ( (result = ccp4_file_raw_write (cfile, (char *) buffer, nitems)) != nitems)
1988     ccp4_signal(CCP4_ERRLEVEL(3), "ccp4_file_writechar", NULL);
1989 
1990   return (result);
1991 }
1992 
1993 /**
1994  * ccp4_file_seek:
1995  * @param cfile (CCP4File *)
1996  * @param offset (long) offset in items
1997  * @param whence (int) SEEK_SET, SEEK_CUR, or SEEK_END
1998  *
1999  * seeks on file by offset items.  SEEK_SET is relative
2000  * to start of file, SEEK_CUR to current, SEEK_END to
2001  * end.
2002  *
2003  * @return 0 on success, -1 on failure
2004  */
2005 int ccp4_file_seek (CCP4File *cfile, long offset, int whence)
2006 {
2007   int result;
2008 
2009   if (!cfile) {
2010     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
2011 		"ccp4_file_seek", NULL);
2012     return -1; }
2013 
2014   result = ccp4_file_raw_seek(cfile, offset*cfile->itemsize, whence);
2015 
2016   if (result != -1) ccp4_file_clearerr(cfile);
2017 
2018   return ((result == -1) ? -1 : 0);
2019 }
2020 
2021 /**
2022  * ccp4_file_rewind:
2023  * @param cfile (CCP4File *)
2024  *
2025  * Seek to start of file.  Clear error status.
2026  *
2027  * @return 0 on success, EOF on failure
2028  */
2029 void ccp4_file_rewind (CCP4File *cfile)
2030 {
2031   if (!cfile) {
2032     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
2033 		"ccp4_file_rewind", NULL);
2034     return ; }
2035 
2036   if (ccp4_file_raw_seek(cfile, 0, SEEK_SET)) {
2037       ccp4_signal(CCP4_ERRLEVEL(3),
2038 	  	  "ccp4_file_rewind", NULL);
2039   } else {
2040     ccp4_file_clearerr(cfile);
2041   }
2042 }
2043 
2044 /**
2045  * ccp4_file_length:
2046  * @param cfile (CCP4File *)
2047  *
2048  * Length of file on disk.
2049  * @return length of @cfile on success, EOF on failure
2050  */
2051 long ccp4_file_length (CCP4File *cfile)
2052 {
2053 #if defined _MSC_VER
2054   struct _stat st;
2055 #else
2056   struct stat st;
2057 #endif
2058 
2059   if (!cfile) {
2060     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
2061 		"ccp4_file_length", NULL);
2062     return EOF; }
2063 
2064   cfile->last_op = IRRELEVANT_OP;
2065 
2066   if (cfile->buffered && cfile->stream)
2067       fflush (cfile->stream);
2068 #if defined _MSC_VER
2069     _fstat(cfile->stream ? _fileno(cfile->stream) : cfile->fd, &st);
2070 #else
2071     fstat(cfile->stream ? fileno(cfile->stream) : cfile->fd, &st);
2072 #endif
2073     cfile->length = st.st_size;
2074 
2075   return (st.st_size);
2076 }
2077 
2078 /**
2079  * ccp4_file_tell:
2080  * @param cfile (CCP4File *)
2081  *
2082  * Current location in file, uses either ftell or lseek.
2083  * @return current offset of @cfile in bytes.
2084  */
2085 long ccp4_file_tell (CCP4File *cfile)
2086 {
2087   long result;
2088 
2089   if (! cfile) {
2090     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
2091 		"ccp4_file_tell", NULL);
2092     return EOF; }
2093 
2094   cfile->last_op = IRRELEVANT_OP;
2095 
2096   if (cfile->buffered && cfile->stream) {
2097 #if !defined (_MSC_VER)
2098     if ( cfile->last_op == WRITE_OP ) fflush (cfile->stream);
2099 #endif
2100     result = (long) ftell(cfile->stream);
2101   } else
2102 #if defined _MSC_VER
2103     result = _lseek(cfile->fd, 0L, SEEK_CUR);
2104 #else
2105     result = lseek(cfile->fd, 0L, SEEK_CUR);
2106 #endif
2107 
2108   cfile->loc = result;
2109 
2110   return (result);
2111 }
2112 
2113 /**
2114  * ccp4_file_feof:
2115  * @param cfile (CCP4File *)
2116  *
2117  * @return true if @cfile is at EoF.
2118  *
2119  */
2120 int ccp4_file_feof(CCP4File *cfile)
2121 {
2122   if (!cfile) {
2123     ccp4_signal(CCP4_ERRLEVEL(3) | CCP4_ERRNO(CIO_NullPtr),
2124 		"ccp4_file_feof", NULL);
2125     return EOF; }
2126 
2127   return (cfile->stream) ? feof(cfile->stream) : cfile->loc >= cfile->length;
2128 }
2129 
2130 /**
2131  * ccp4_file_clearerr:
2132  * @param cfile (CCP4File *)
2133  *
2134  * Clears error status of @cfile.
2135  *
2136  */
2137 void ccp4_file_clearerr(CCP4File *cfile)
2138 {
2139   if (!cfile || !cfile->stream)
2140     return;
2141   cfile->iostat = CIO_Ok;
2142   clearerr(cfile->stream);
2143 }
2144 
2145 /**
2146  * ccp4_file_fatal:
2147  * @param cfile (CCP4File *)
2148  *
2149  * Die with error message based on @cfile error status.
2150  */
2151 void ccp4_file_fatal (CCP4File *cfile, char *message)
2152 {
2153   char *buff;
2154   size_t l;
2155 
2156   if (!cfile)
2157     ccp4_signal(CCP4_ERRLEVEL(4) | CCP4_ERRNO(CIO_NullPtr), "ccp4_file_fatal",
2158                 NULL);
2159 
2160   l = strlen (message) + strlen (cfile->name) + 1;
2161   if ( !(buff = malloc(l)))
2162       ccp4_signal(CCP4_ERRLEVEL(4), "ccp4_file_fatal", NULL);
2163   buff[0] = '\0';
2164   strcat (buff, message);
2165   strcat (buff, cfile->name);
2166   ccp4_fatal(buff);
2167 }
2168 
2169 /**
2170  * ccp4_file_error:
2171  * @param cfile (CCP4File *)
2172  *
2173  * print error mesage.
2174  * @return associated error code
2175  */
2176 int ccp4_file_error(CCP4File *cfile)
2177 {
2178   if (!cfile->iostat)
2179     return 0;
2180   fprintf(stderr,"%s %s \n",
2181             cfile->name,ccp4_strerror(cfile->iostat));
2182   return CCP4_ERRGETCODE(cfile->iostat);
2183 }
2184 
2185 /**
2186  * ccp4_file_flush:
2187  * @param cfile (CCP4File *)
2188  *
2189  * flush buffer contents of @cfile
2190  */
2191 void ccp4_file_flush(CCP4File *cfile)
2192 {
2193    if (cfile && cfile->stream && cfile->buffered)
2194      fflush(cfile->stream);
2195 }
2196 
2197 /**
2198  * ccp4_file_print:
2199  * @param cfile (CCP4File *)
2200  *
2201  * @return @cfile information in char array for printing.
2202  */
2203 char *ccp4_file_print(CCP4File *cfile, char *msg_start, char *msg_end)
2204 {
2205   char *msg_curr = msg_start;
2206 
2207   if (!cfile)
2208     return msg_start;
2209 
2210   if (cfile->name)
2211     if ((msg_end - msg_curr) > strlen(cfile->name)) {
2212       strcpy(msg_curr,cfile->name);
2213       msg_curr = strrchr(msg_curr,'\0'); }
2214 
2215   if (cfile->open) {
2216     if ((msg_end - msg_curr) > 6 ) {
2217       strcat(msg_start, " opened");
2218       msg_curr = strrchr(msg_curr,'\0'); }
2219   } else {
2220     if ((msg_end - msg_curr) > 7 ) {
2221       strcat(msg_start, " closed");
2222       msg_curr = strrchr(msg_curr,'\0'); }
2223   }
2224 
2225   if (cfile->append) {
2226     if ((msg_end - msg_curr) > 13 ) {
2227       strcat(msg_start, ", append mode");
2228       msg_curr = strrchr(msg_curr,'\0'); }
2229   } else if (cfile->read && cfile->write) {
2230     if ((msg_end - msg_curr) > 17 ) {
2231       strcat(msg_start, ", read-write mode");
2232       msg_curr = strrchr(msg_curr,'\0'); }
2233   } else if (cfile->write) {
2234     if ((msg_end - msg_curr) > 12 ) {
2235       strcat(msg_start, ", write mode");
2236       msg_curr = strrchr(msg_curr,'\0'); }
2237   } else {
2238     if ((msg_end - msg_curr) > 11 ) {
2239       strcat(msg_start, ", read mode");
2240       msg_curr = strrchr(msg_curr,'\0'); }
2241   }
2242 
2243   return msg_curr;
2244 }
2245 
2246