1 /*
2      cmap_labels.c: read and write map header labels
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 <string.h>
20 #include "cmaplib.h"
21 #include "cmap_labels.h"
22 #include "cmap_errno.h"
23 
24 /*! Internal: read the labels from file header and copy into char * array
25   Called when the file is opened in read mode.
26   \param mfile (CMMFile *)
27   \return 1 on succes */
parse_maplabels(CMMFile * mfile)28 int parse_maplabels(CMMFile *mfile)
29 {
30   char buffer[81], *cptr;
31   const unsigned int n_byt_label = 80U, max_label = 10U;
32 /*  const unsigned int labels_offset = 224U; */
33   int i;
34 
35 /*  ccp4_file_seek(mfile->stream,labels_offset,SEEK_SET); */
36   for (i=0 ; i!=mfile->labels.number ; i++) {
37     ccp4_file_readchar(mfile->stream,(uint8 *) buffer,n_byt_label);
38     cptr = buffer+n_byt_label;
39     while (cptr> buffer && *--cptr == ' ');
40     *(++cptr) = '\0';
41     mfile->labels.labels[i] = strdup(buffer);
42   }
43   ccp4_file_raw_seek(mfile->stream,(max_label-mfile->labels.number)
44 		     *n_byt_label,
45 		     SEEK_CUR);
46   return 1;
47 }
48 
49 /*! Internal: dump the labels char * array to file, offset at 224 bytes.
50   Called when the file is opened or closed in write mode, immediately after the
51   header is written.
52  \param mfile (const CMMFile *)
53  \return 1 on success, 0 on failure */
write_maplabels(const CMMFile * mfile)54 int write_maplabels(const CMMFile *mfile)
55 {
56   char buffer[80];
57 /*  const unsigned int labels_offset = 224U; */
58   int i, result = 0;
59   size_t slen;
60 
61 /*  ccp4_file_seek(mfile->stream,labels_offset,SEEK_SET);  */
62   for (i=0 ; i != mfile->labels.number ; i++) {
63     memset(buffer,' ',80U);
64     slen = strlen(mfile->labels.labels[i]);
65     if (slen > 80U) slen = 80U;
66     strncpy(buffer,mfile->labels.labels[i],slen);
67     result += ccp4_file_writechar(mfile->stream,(uint8 *) buffer,80U);
68   }
69   memset(buffer,' ',80U);
70   while(i != 10) {
71     result += ccp4_file_writechar(mfile->stream,(uint8 *) buffer,80U);
72     i++;
73   }
74   return (result == 800) ? 1 : 0 ;
75 }
76 
77 /*! Set the label in the map header.  Headers are 80 characters long.
78   The labels are written to the file when it is closed. Therefore,
79   the file must be in write mode.
80   If label == NULL the element corresponding to posn is removed.
81   The number of labels is recalculated on each call.
82  \param mfile (CMMFile *)
83  \param label (const char *) the C-style character array
84  \param posn (int) the label number (C-style, 0 -> 9)
85  \return number of label effected, or EOF */
ccp4_cmap_set_label(CMMFile * mfile,const char * label,int posn)86 int ccp4_cmap_set_label(CMMFile *mfile, const char *label, int posn)
87 {
88   int i,j;
89 
90   if (mfile == NULL) {
91     ccp4_signal( CCP4_ERRLEVEL(3) | CMAP_ERRNO(CMERR_NoChannel),
92                 "ccp4_cmap_set_label",NULL);
93     return (EOF);}
94 
95   if (ccp4_file_is_write(mfile->stream) == 0) {
96     ccp4_signal( CCP4_ERRLEVEL(3) | CMAP_ERRNO(CMERR_WriteFail),
97                 "ccp4_cmap_label_set",NULL);
98     return (EOF);}
99 
100 /*posn must be between 0 and 9 */
101   if (posn < 0) {
102     posn = 0;
103   } else if (posn > mfile->labels.number) {
104     posn = mfile->labels.number;
105   }
106 
107   if (mfile->labels.labels[posn] != NULL)
108     free(mfile->labels.labels[posn]);
109 
110 /* if label == NULL reset the value and compress set */
111   if (label == NULL) {
112     mfile->labels.labels[posn] = NULL;
113     for ( i=posn ; i!=10 ; i++)
114       if (mfile->labels.labels[i] == NULL)
115         for ( j=i+1 ; j!=10; j++)
116           if (mfile->labels.labels[j] != NULL) {
117             mfile->labels.labels[i] = mfile->labels.labels[j];
118             mfile->labels.labels[j] = NULL;
119             break;
120           }
121     }
122   else
123     mfile->labels.labels[posn] = strdup(label);
124 
125 /* recalculate number */
126   for ( i=0 ; i!=10 ; i++)
127     if (mfile->labels.labels[i] == NULL)
128       break;
129   mfile->labels.number = i;
130 
131   return posn;
132 }
133 
134 /*! Get the label corresponding to position posn
135   \param mfile (const CMMFile *)
136   \param posn (int) desired label number
137   \return pointer to label posn */
ccp4_cmap_get_label(const CMMFile * mfile,int posn)138 char *ccp4_cmap_get_label(const CMMFile *mfile, int posn)
139 {
140   char *label;
141   if (mfile == NULL) {
142     ccp4_signal( CCP4_ERRLEVEL(3) | CMAP_ERRNO(CMERR_NoChannel),
143                 "ccp4_cmap_get_label",NULL);
144     return (NULL);}
145 
146   if (posn < 0 || posn >= mfile->labels.number)
147     label = NULL;
148   else
149     label = mfile->labels.labels[posn];
150 
151   return label;
152 }
153 
154 /*! Return the number of labels.
155  \param mfile (CMMFile *)
156  \return the number of labels */
ccp4_cmap_number_label(const CMMFile * mfile)157 int ccp4_cmap_number_label(const CMMFile *mfile)
158 {
159   return mfile->labels.number;
160 }
161 
162 /*! Get the label corresponding to the title
163     wrapping ccp4_cmap_get_label.
164  \param mfile (const CMMFile *)
165  \return pointer to label 0, or NULL */
ccp4_cmap_get_title(const CMMFile * mfile)166 char *ccp4_cmap_get_title(const CMMFile *mfile)
167 {
168   return ccp4_cmap_get_label(mfile, 0);
169 }
170 
171 /*! Set the label corresponding to the title,
172     wrapping ccp4_cmap_set_label
173  \param mfile (CMMFile *)
174  \param label
175  \return 0 or EOF on failure */
ccp4_cmap_set_title(CMMFile * mfile,const char * title)176 int ccp4_cmap_set_title(CMMFile *mfile, const char *title)
177 {
178   return ccp4_cmap_set_label(mfile, title, 0);
179 }
180