1 #ifdef  HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 
5 #include <ctype.h>
6 
7 #include "cdf.h"
8 #include "cdi.h"
9 #include "cdi_int.h"
10 #include "cdf_int.h"
11 
12 
cdfLibraryVersion(void)13 const char *cdfLibraryVersion(void)
14 {
15 #ifdef  HAVE_LIBNETCDF
16   return nc_inq_libvers();
17 #else
18   return "library undefined";
19 #endif
20 }
21 
22 #ifdef  HAVE_H5GET_LIBVERSION
23 #ifdef  __cplusplus
24 extern "C" {
25 #endif
26   int H5get_libversion(unsigned *, unsigned *, unsigned *);
27 #ifdef  __cplusplus
28 }
29 #endif
30 #endif
31 
hdfLibraryVersion(void)32 const char *hdfLibraryVersion(void)
33 {
34 #ifdef  HAVE_H5GET_LIBVERSION
35   static char hdf_libvers[256];
36   static int linit = 0;
37   if (!linit)
38     {
39       linit = 1;
40       unsigned majnum, minnum, relnum;
41       H5get_libversion(&majnum, &minnum, &relnum);
42 #ifdef  HAVE_NC4HDF5_THREADSAFE
43       sprintf(hdf_libvers, "%u.%u.%u threadsafe", majnum, minnum, relnum);
44 #else
45       sprintf(hdf_libvers, "%u.%u.%u", majnum, minnum, relnum);
46 #endif
47     }
48 
49   return hdf_libvers;
50 #else
51   return "library undefined";
52 #endif
53 }
54 
55 
56 int CDF_Debug   = 0;    /* If set to 1, debugging           */
57 
58 
cdfDebug(int debug)59 void cdfDebug(int debug)
60 {
61   CDF_Debug = debug;
62 
63   if ( CDF_Debug )
64     Message("debug level %d", debug);
65 }
66 
67 #ifdef  HAVE_LIBNETCDF
68 static
cdfComment(int ncid)69 void cdfComment(int ncid)
70 {
71   static char comment[256] = "Climate Data Interface version ";
72   static bool init = false;
73 
74   if ( ! init )
75     {
76       init = true;
77       const char *libvers = cdiLibraryVersion();
78 
79       if ( ! isdigit((int) *libvers) )
80 	strcat(comment, "??");
81       else
82 	strcat(comment, libvers);
83       strcat(comment, " (https://mpimet.mpg.de/cdi)");
84     }
85 
86   cdf_put_att_text(ncid, NC_GLOBAL, "CDI", strlen(comment), comment);
87 }
88 #endif
89 
cdfOpenFile(const char * filename,const char * mode,int * filetype)90 static int cdfOpenFile(const char *filename, const char *mode, int *filetype)
91 {
92   int ncid = -1;
93 #ifdef  HAVE_LIBNETCDF
94   int fmode = tolower(*mode);
95   int writemode = NC_CLOBBER;
96   int readmode = NC_NOWRITE;
97 
98   if ( filename == NULL )
99     ncid = CDI_EINVAL;
100   else
101     {
102       switch (fmode)
103 	{
104 	case 'r':
105           {
106             const int status = cdf_open(filename, readmode, &ncid);
107             if ( status > 0 && ncid < 0 ) ncid = CDI_ESYSTEM;
108 #ifdef  HAVE_NETCDF4
109             else
110               {
111                 int format;
112                 (void) nc_inq_format(ncid, &format);
113                 if ( format == NC_FORMAT_NETCDF4_CLASSIC )
114                   *filetype = CDI_FILETYPE_NC4C;
115               }
116 #endif
117           }
118 	  break;
119 	case 'w':
120 #ifdef  NC_64BIT_OFFSET
121 	  if      ( *filetype == CDI_FILETYPE_NC2  ) writemode |= NC_64BIT_OFFSET;
122 #endif
123 #ifdef  NC_64BIT_DATA
124 	  if      ( *filetype == CDI_FILETYPE_NC5  ) writemode |= NC_64BIT_DATA;
125 #endif
126 #ifdef  HAVE_NETCDF4
127 	  if      ( *filetype == CDI_FILETYPE_NC4  ) writemode |= NC_NETCDF4;
128 	  else if ( *filetype == CDI_FILETYPE_NC4C ) writemode |= NC_NETCDF4 | NC_CLASSIC_MODEL;
129 #endif
130 	  cdf_create(filename, writemode, &ncid);
131 	  if (CDI_Version_Info) cdfComment(ncid);
132           cdf_put_att_text(ncid, NC_GLOBAL, "Conventions", 6, "CF-1.6");
133 	  break;
134 	case 'a':
135 	  cdf_open(filename, NC_WRITE, &ncid);
136 	  break;
137 	default:
138 	  ncid = CDI_EINVAL;
139 	}
140     }
141 #endif
142 
143   return ncid;
144 }
145 
146 
cdfOpen(const char * filename,const char * mode,int filetype)147 int cdfOpen(const char *filename, const char *mode, int filetype)
148 {
149   int fileID = -1;
150   bool open_file = true;
151 
152   if ( CDF_Debug )
153     Message("Open %s with mode %c", filename, *mode);
154 
155 #ifdef  HAVE_LIBNETCDF
156 #ifndef  NC_64BIT_OFFSET
157   if ( filetype == CDI_FILETYPE_NC2 ) open_file = false;
158 #endif
159 #ifndef  NC_64BIT_DATA
160   if ( filetype == CDI_FILETYPE_NC5 ) open_file = false;
161 #endif
162 #endif
163 
164   if ( open_file )
165     {
166       fileID = cdfOpenFile(filename, mode, &filetype);
167 
168       if ( CDF_Debug )
169         Message("File %s opened with id %d", filename, fileID);
170     }
171   else
172     {
173       fileID = CDI_ELIBNAVAIL;
174     }
175 
176   return fileID;
177 }
178 
179 static
cdf4CheckLibVersions(void)180 int cdf4CheckLibVersions(void)
181 {
182   int status = 0;
183 #ifdef HAVE_NETCDF4
184 #ifdef HAVE_H5GET_LIBVERSION
185   static int checked = 0;
186   if (!checked)
187     {
188       checked = 1;
189       unsigned majnum, minnum, relnum;
190 
191       sscanf(nc_inq_libvers(), "%u.%u.%u", &majnum, &minnum, &relnum);
192       //printf("netCDF %u.%u.%u\n", majnum, minnum, relnum);
193       const unsigned ncmaxver = 4 * 1000000 + 4 * 1000;
194       const unsigned nclibver = majnum * 1000000 + minnum * 1000 + relnum;
195 
196       if (nclibver <= ncmaxver)
197         {
198           H5get_libversion(&majnum, &minnum, &relnum);
199           const unsigned hdf5maxver = 1 * 1000000 + 10 * 1000;
200           const unsigned hdf5libver = majnum * 1000000 + minnum * 1000 + relnum;
201 
202           if (hdf5libver >= hdf5maxver)
203             {
204               fprintf(stderr, "NetCDF library 4.4.0 or earlier, combined with libhdf5 1.10.0 or greater not supported!\n");
205               status = 1;
206             }
207         }
208     }
209 #endif
210 #endif
211   return status;
212 }
213 
cdf4Open(const char * filename,const char * mode,int * filetype)214 int cdf4Open(const char *filename, const char *mode, int *filetype)
215 {
216   int fileID = -1;
217   bool open_file = false;
218 
219   if ( CDF_Debug ) Message("Open %s with mode %c", filename, *mode);
220 
221 #ifdef  HAVE_NETCDF4
222   open_file = true;
223 #endif
224 
225   if ( open_file )
226     {
227       if (cdf4CheckLibVersions() == 0)
228         {
229           fileID = cdfOpenFile(filename, mode, filetype);
230           if ( CDF_Debug ) Message("File %s opened with id %d", filename, fileID);
231         }
232       else
233         {
234           fileID = CDI_EUFTYPE;
235         }
236     }
237   else
238     {
239       fileID = CDI_ELIBNAVAIL;
240     }
241 
242   return fileID;
243 }
244 
245 
cdfCloseFile(int fileID)246 static void cdfCloseFile(int fileID)
247 {
248 #ifdef  HAVE_LIBNETCDF
249   cdf_close(fileID);
250 #endif
251 }
252 
cdfClose(int fileID)253 void cdfClose(int fileID)
254 {
255   cdfCloseFile(fileID);
256 }
257 /*
258  * Local Variables:
259  * c-file-style: "Java"
260  * c-basic-offset: 2
261  * indent-tabs-mode: nil
262  * show-trailing-whitespace: t
263  * require-trailing-newline: t
264  * End:
265  */
266