1 /*
2      cmap_symop.c: set and fetch symmetry operations in map header
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 #include <stdlib.h>
20 #include "cmaplib.h"
21 #include "cmap_errno.h"
22 
23 /*! Return the number of symops (estimated as the size/80)
24  \param mfile (const CMMFile *)
25  \return number of symops */
ccp4_cmap_num_symop(const CMMFile * mfile)26 int ccp4_cmap_num_symop(const CMMFile *mfile)
27 {
28   if (mfile == NULL)
29     return 0;
30   return (mfile->symop.number);
31 }
32 
33 /*! navigate around the symops, seeking in 80 byte units
34  The result must lie within the symop strings in the file.
35  \param mfile (CMMFile *)
36  \param isymop (int) the number of the symop "string" of interest
37  \param whence (unsigned int) mode of seek
38  \return symop string number or EOF */
ccp4_cmap_seek_symop(CMMFile * mfile,int isymop,unsigned int whence)39 int ccp4_cmap_seek_symop(CMMFile *mfile, int isymop, unsigned int whence)
40 {
41   const int n_byt_symop = 80;
42   div_t symops;
43   int result = EOF;
44 
45   if (ccp4_file_is_read(mfile->stream) == 0)
46     return EOF;
47 
48   switch (whence) {
49   case SEEK_SET:
50     if (isymop < 0 || isymop > mfile->symop.number)
51       ccp4_signal( CCP4_ERRLEVEL(2) | CMAP_ERRNO(CMERR_ParamError),
52 		   "ccp4_cmap_seek_symop",
53 		   NULL);
54     else
55       result = ccp4_file_raw_seek(mfile->stream, mfile->symop.offset +
56                               isymop*n_byt_symop, whence);
57     break;
58   case SEEK_END:
59     if (isymop > 0 || abs(isymop) > mfile->symop.number )
60       ccp4_signal( CCP4_ERRLEVEL(2) |  CMAP_ERRNO(CMERR_ParamError),
61 		   "ccp4_cmap_seek_symop",
62 		   NULL);
63     else
64       result = ccp4_file_raw_seek(mfile->stream, mfile->symop.offset +
65                               mfile->symop.size + isymop*n_byt_symop,
66                               SEEK_SET);
67     break;
68   case SEEK_CUR:
69     symops = div(ccp4_file_tell(mfile->stream) - mfile->symop.offset,n_byt_symop);
70     if (symops.quot < 0 || symops.quot >= mfile->symop.number ||
71         symops.quot + isymop < 0 || symops.quot + isymop >= mfile->symop.number)
72       ccp4_signal( CCP4_ERRLEVEL(2) | CMAP_ERRNO(CMERR_ParamError),
73 		   "ccp4_cmap_seek_symop",
74 		   NULL);
75     else
76       result = ccp4_file_raw_seek(mfile->stream,(isymop > 0) ?
77                               (n_byt_symop - symops.rem + n_byt_symop * (isymop-1)) :
78                               (n_byt_symop * isymop -symops.rem), SEEK_CUR);
79   }
80   return (result == EOF) ? EOF : (result - mfile->symop.offset)/n_byt_symop;
81 }
82 
83 /*! get a symop string of 80 characters
84  \param mfile (CMMFile *)
85  \param buffer (char *) array of bytes which will contain the symop string.
86  This must be at least 81 characters long (including space for null terminator).
87  \return 1 on success, 0 if no symops, EOF on failure */
ccp4_cmap_get_symop(CMMFile * mfile,char * buffer)88 int ccp4_cmap_get_symop(CMMFile *mfile, char *buffer)
89 {
90   const int n_byt_symop = 80;
91   off_t file_posn;
92 
93   if ( mfile->symop.size == 0)  {
94     ccp4_signal( CCP4_ERRLEVEL(2) | CMAP_ERRNO(CMERR_SymErr),
95 		 "cmap_get_symop",NULL);
96     return (0);}
97 
98   file_posn = ccp4_file_tell(mfile->stream);
99   if (file_posn < mfile->symop.offset ||
100       file_posn > mfile->symop.offset + mfile->symop.size) {
101     ccp4_signal( CCP4_ERRLEVEL(2) | CMAP_ERRNO(CMERR_SymErr),
102 		 "cmap_get_symop",NULL);
103     return (EOF);}
104 
105   if (ccp4_file_readchar(mfile->stream, (uint8 *) buffer, n_byt_symop) != n_byt_symop) {
106     ccp4_signal( CCP4_ERRLEVEL(3) | CMAP_ERRNO(CMERR_ReadFail),
107 		 "cmap_get_symop",NULL);
108     return (EOF);
109   }
110   buffer[n_byt_symop] = '\0';
111   return (1);
112 }
113 
114 /*! write symops to file.
115  This wraps a raw write.  It is up to the calling program to
116  ensure the positioning (effectively assume appends).  Writing
117  is blocked if data has alread been written to the file.  80
118  bytes of continuous memory is written to the file.
119  \param mfile (CMMFile *)
120  \param symop (const char *) character array containing the
121  symop string (at least 80 characters in length
122  \return 1 on success, EOF on failure */
ccp4_cmap_set_symop(CMMFile * mfile,const char * symop)123 int ccp4_cmap_set_symop(CMMFile *mfile, const char *symop)
124 {
125   const int n_byt_symop = 80;
126   char buffer[80];
127   memset(buffer,' ',80U);
128   memcpy(buffer, symop, (strlen(symop) > n_byt_symop) ?
129          n_byt_symop : strlen(symop) );
130   if (ccp4_file_is_write(mfile->stream) && mfile->data.number == 0) {
131     if (ccp4_file_writechar(mfile->stream, (uint8 *) buffer, n_byt_symop) != n_byt_symop) {
132       ccp4_signal( CCP4_ERRLEVEL(3) | CMAP_ERRNO(CMERR_WriteFail),
133 		   "cmap_set_symop",NULL);
134       return (EOF);
135     }
136   mfile->symop.number++;
137   mfile->symop.size += n_byt_symop;
138   mfile->data.offset = mfile->symop.offset + mfile->symop.size;
139 }
140   return (1);
141 }
142