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