1 #ifdef  HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 
5 #include <ctype.h>
6 
7 #include "binary.h"
8 #include "cdf.h"
9 #include "cdi.h"
10 #include "cdi_int.h"
11 #include "dmemory.h"
12 #include "file.h"
13 #include "gribapi.h"
14 
15 #ifdef  HAVE_LIBCGRIBEX
16 #include "cgribex.h"
17 #endif
18 
19 int CDI_Default_Calendar = CALENDAR_PROLEPTIC;
20 
21 int CDI_Default_InstID   = CDI_UNDEFID;
22 int CDI_Default_ModelID  = CDI_UNDEFID;
23 int CDI_Default_TableID  = CDI_UNDEFID;
24 //int cdiNcMissingValue  = CDI_UNDEFID;
25 int CDI_Netcdf_Chunksizehint = CDI_UNDEFID;
26 int CDI_Chunk_Type       = CDI_CHUNK_GRID;
27 int CDI_Split_Ltype105   = CDI_UNDEFID;
28 
29 bool CDI_Ignore_Att_Coordinates = false;
30 bool CDI_Coordinates_Lon_Lat    = false;
31 bool CDI_Ignore_Valid_Range     = false;
32 int CDI_Skip_Records           = 0;
33 const char *CDI_GRIB1_Template = NULL;
34 const char *CDI_GRIB2_Template = NULL;
35 int CDI_Convention           = CDI_CONVENTION_ECHAM;
36 int CDI_Inventory_Mode       = 1;
37 int CDI_Version_Info         = 1;
38 int CDI_Convert_Cubesphere   = 1;
39 int CDI_Read_Cell_Corners    = 1;
40 int CDI_CMOR_Mode            = 0;
41 int CDI_Reduce_Dim           = 0;
42 size_t CDI_Netcdf_Hdr_Pad    = 0UL;
43 bool CDI_Netcdf_Lazy_Grid_Load = false;
44 
45 char *cdiPartabPath   = NULL;
46 int   cdiPartabIntern = 1;
47 
48 double CDI_Default_Missval = -9.E33;
49 double CDI_Grid_Missval    = -9999.;
50 
51 static const char Filetypes[][9] = {
52   "UNKNOWN",
53   "GRIB",
54   "GRIB2",
55   "NetCDF",
56   "NetCDF2",
57   "NetCDF4",
58   "NetCDF4c",
59   "NetCDF5",
60   "SERVICE",
61   "EXTRA",
62   "IEG",
63   "HDF5",
64 };
65 
66 int CDI_Debug   = 0;    // If set to 1, debugging
67 int CDI_Recopt  = 0;
68 
69 bool CDI_gribapi_debug  = false;
70 bool CDI_gribapi_grib1  = false;
71 int cdiDefaultLeveltype = -1;
72 int cdiDataUnreduced = 0;
73 int cdiSortName = 0;
74 int cdiSortParam = 0;
75 int cdiHaveMissval = 0;
76 
77 
78 static
cdiGetenvInt(const char * envName)79 long cdiGetenvInt(const char *envName)
80 {
81   long envValue = -1;
82 
83   char *envString = getenv(envName);
84   if ( envString )
85     {
86       long fact = 1;
87       int len = (int) strlen(envString);
88       for ( int loop = 0; loop < len; loop++ )
89 	{
90 	  if ( ! isdigit((int) envString[loop]) )
91 	    {
92 	      switch ( tolower((int) envString[loop]) )
93 		{
94 		case 'k':  fact = 1024;        break;
95 		case 'm':  fact = 1048576;     break;
96 		case 'g':  fact = 1073741824;  break;
97 		default:
98 		  fact = 0;
99 		  Message("Invalid number string in %s: %s", envName, envString);
100 		  Warning("%s must comprise only digits [0-9].",envName);
101 		  break;
102 		}
103 	      break;
104 	    }
105 	}
106 
107       if ( fact ) envValue = fact*atol(envString);
108 
109       if ( CDI_Debug ) Message("set %s to %ld", envName, envValue);
110     }
111 
112   return envValue;
113 }
114 
115 static
cdiPrintDefaults(void)116 void cdiPrintDefaults(void)
117 {
118   fprintf(stderr, "default instID     :  %d\n"
119           "default modelID    :  %d\n"
120           "default tableID    :  %d\n"
121           "default missval    :  %g\n", CDI_Default_InstID,
122           CDI_Default_ModelID, CDI_Default_TableID, CDI_Default_Missval);
123 }
124 
125 #ifdef  HAVE_LIBFDB5
126 #include <fdb5/fdb5_config.h>
127 #endif
128 
cdiPrintVersion(void)129 void cdiPrintVersion(void)
130 {
131   fprintf(stdout, "     CDI library version : %s\n", cdiLibraryVersion());
132 #ifdef  HAVE_LIBCGRIBEX
133   fprintf(stdout, " cgribex library version : %s\n", cgribexLibraryVersion());
134 #endif
135 #ifdef  HAVE_LIBGRIB_API
136   fprintf(stdout, " ecCodes library version : %s\n", gribapiLibraryVersionString());
137 #endif
138 #ifdef  HAVE_LIBNETCDF
139   fprintf(stdout, "  NetCDF library version : %s\n", cdfLibraryVersion());
140 #endif
141 #ifdef  HAVE_NC4HDF5
142   fprintf(stdout, "    hdf5 library version : %s\n", hdfLibraryVersion());
143 #endif
144 #ifdef  HAVE_LIBSERVICE
145   fprintf(stdout, "    exse library version : %s\n", srvLibraryVersion());
146 #endif
147   fprintf(stdout, "    FILE library version : %s\n", fileLibraryVersion());
148 #ifdef  HAVE_LIBFDB5
149   fprintf(stdout, "    FDB5 library version : %s\n", fdb5_version());
150 #endif
151 }
152 
153 static
cdiPrintDatatypes(void)154 void cdiPrintDatatypes(void)
155 {
156 #define XSTRING(x)	#x
157 #define STRING(x)	XSTRING(x)
158 
159   fprintf(stderr, "+-------------+-------+\n"
160           "| types       | bytes |\n"
161           "+-------------+-------+\n"
162           "| void *      |   %3d |\n"
163           "+-------------+-------+\n"
164           "| char        |   %3d |\n"
165           "+-------------+-------+\n"
166           "| bool        |   %3d |\n"
167           "| short       |   %3d |\n"
168           "| int         |   %3d |\n"
169           "| long        |   %3d |\n"
170           "| long long   |   %3d |\n"
171           "| size_t      |   %3d |\n"
172           "| off_t       |   %3d |\n"
173           "+-------------+-------+\n"
174           "| float       |   %3d |\n"
175           "| double      |   %3d |\n"
176           "| long double |   %3d |\n"
177           "+-------------+-------+\n\n",
178           (int) sizeof(void *), (int) sizeof(char), (int) sizeof(bool),
179           (int) sizeof(short), (int) sizeof(int), (int) sizeof(long), (int) sizeof(long long),
180           (int) sizeof(size_t), (int) sizeof(off_t),
181           (int) sizeof(float), (int) sizeof(double), (int) sizeof(long double));
182 
183   fprintf(stderr,
184           "+-------------+-----------+\n"
185           "| INT32       | %-9s |\n"
186           "| INT64       | %-9s |\n"
187           "| FLT32       | %-9s |\n"
188           "| FLT64       | %-9s |\n"
189           "| SizeType    | %-9s |\n"
190           "| DateType    | %-9s |\n"
191           "+-------------+-----------+\n",
192           STRING(INT32), STRING(INT64), STRING(FLT32), STRING(FLT64), STRING(CDI_SIZE_TYPE), STRING(CDI_DATE_TYPE));
193 
194   fprintf(stderr, "\n  byte ordering is %s\n\n",
195           ((HOST_ENDIANNESS == CDI_BIGENDIAN) ? "BIGENDIAN"
196            : ((HOST_ENDIANNESS == CDI_LITTLEENDIAN) ? "LITTLEENDIAN"
197               : "Unhandled endianness!")));
198 
199 #undef STRING
200 #undef XSTRING
201 }
202 
203 
cdiDebug(int level)204 void cdiDebug(int level)
205 {
206   unsigned ulevel = (unsigned) level;
207 
208   if ( ulevel == 1 || (ulevel &  2) ) CDI_Debug = 1;
209 
210   if ( CDI_Debug ) Message("debug level %d", level);
211 
212   if ( ulevel == 1 || (ulevel &  4) ) memDebug(1);
213 
214   if ( ulevel == 1 || (ulevel &  8) ) fileDebug(1);
215 
216   if ( ulevel == 1 || (ulevel & 16) )
217     {
218 #ifdef HAVE_LIBCGRIBEX
219       gribSetDebug(1);
220 #endif
221 #ifdef HAVE_LIBNETCDF
222       cdfDebug(1);
223 #endif
224 #ifdef HAVE_LIBSERVICE
225       srvDebug(1);
226 #endif
227 #ifdef HAVE_LIBEXTRA
228       extDebug(1);
229 #endif
230 #ifdef HAVE_LIBIEG
231       iegDebug(1);
232 #endif
233     }
234 
235   if ( CDI_Debug )
236     {
237       cdiPrintDefaults();
238       cdiPrintDatatypes();
239     }
240 }
241 
242 
cdiHaveFiletype(int filetype)243 int cdiHaveFiletype(int filetype)
244 {
245   int status = 0;
246 
247   switch (filetype)
248     {
249 #ifdef  HAVE_LIBSERVICE
250     case CDI_FILETYPE_SRV:  status = 1; break;
251 #endif
252 #ifdef  HAVE_LIBEXTRA
253     case CDI_FILETYPE_EXT:  status = 1; break;
254 #endif
255 #ifdef  HAVE_LIBIEG
256     case CDI_FILETYPE_IEG:  status = 1; break;
257 #endif
258 #ifdef  HAVE_LIBGRIB
259 #if  defined  HAVE_LIBGRIB_API || defined  HAVE_LIBCGRIBEX
260     case CDI_FILETYPE_GRB:  status = 1; break;
261 #endif
262 #ifdef  HAVE_LIBGRIB_API
263     case CDI_FILETYPE_GRB2: status = 1; break;
264 #endif
265 #endif
266 #ifdef  HAVE_LIBNETCDF
267     case CDI_FILETYPE_NC:   status = 1; break;
268 #ifdef  HAVE_NETCDF2
269     case CDI_FILETYPE_NC2:  status = 1; break;
270 #endif
271 #ifdef  HAVE_NETCDF4
272     case CDI_FILETYPE_NC4:  status = 1; break;
273     case CDI_FILETYPE_NC4C: status = 1; break;
274 #endif
275 #ifdef  HAVE_NETCDF5
276     case CDI_FILETYPE_NC5:  status = 1; break;
277 #endif
278 #endif
279     default: status = 0; break;
280     }
281 
282   return status;
283 }
284 
285 
cdiDefTableID(int tableID)286 void cdiDefTableID(int tableID)
287 {
288   CDI_Default_TableID = tableID;
289   int modelID = CDI_Default_ModelID = tableInqModel(tableID);
290   CDI_Default_InstID = modelInqInstitut(modelID);
291 }
292 
293 static
cdiSetChunk(const char * chunkAlgo)294 void cdiSetChunk(const char *chunkAlgo)
295 {
296   int algo = -1;
297 
298   if      (strIsEqual("auto",  chunkAlgo)) algo = CDI_CHUNK_AUTO;
299   else if (strIsEqual("grid",  chunkAlgo)) algo = CDI_CHUNK_GRID;
300   else if (strIsEqual("lines", chunkAlgo)) algo = CDI_CHUNK_LINES;
301   else
302     Warning("Invalid environment variable CDI_CHUNK_ALGO: %s", chunkAlgo);
303 
304   if ( algo != -1 )
305     {
306       CDI_Chunk_Type = algo;
307       if ( CDI_Debug ) Message("set ChunkAlgo to %s", chunkAlgo);
308     }
309 }
310 
311 
cdiSetEccodesGrib1(bool value)312 void cdiSetEccodesGrib1(bool value)
313 {
314 #ifndef HAVE_LIBGRIB_API
315   if (value)
316     {
317       Warning("ecCodes support not compiled in, used CGRIBEX to decode/encode GRIB1 records!");
318       value = false;
319     }
320 #endif
321   CDI_gribapi_grib1 = value;
322 }
323 
324 
cdiInitialize(void)325 void cdiInitialize(void)
326 {
327   static bool Init_CDI = false;
328 
329   if ( ! Init_CDI )
330     {
331       Init_CDI = true;
332       char *envstr;
333       long value;
334 
335 #ifdef  HAVE_LIBCGRIBEX
336       gribFixZSE(1);   // 1: Fix ZeroShiftError of simple packed spherical harmonics
337       gribSetConst(1); // 1: Don't pack constant fields on regular grids
338 #endif
339 #ifdef  HAVE_LIBGRIB_API
340       grib_multi_support_off(NULL);
341 #endif
342 
343       value = cdiGetenvInt("CDI_DEBUG");
344       if ( value >= 0 ) CDI_Debug = (int) value;
345 
346       value = cdiGetenvInt("CDI_GRIBAPI_DEBUG");
347       if ( value >= 0 ) CDI_gribapi_debug = (bool) value;
348 
349       value = cdiGetenvInt("CDI_ECCODES_DEBUG");
350       if ( value >= 0 ) CDI_gribapi_debug = (bool) value;
351 
352       value = cdiGetenvInt("CDI_ECCODES_GRIB1");
353       if ( value >= 0 ) cdiSetEccodesGrib1((bool) value);
354 
355       value = cdiGetenvInt("CDI_READ_CELL_CORNERS");
356       if ( value >= 0 ) CDI_Read_Cell_Corners = (int) value;
357 
358       value = cdiGetenvInt("CDI_RECOPT");
359       if ( value >= 0 ) CDI_Recopt = (int) value;
360 
361       value = cdiGetenvInt("CDI_REGULARGRID");
362       if ( value >= 0 ) cdiDataUnreduced = (int) value;
363 
364       value = cdiGetenvInt("CDI_SORTNAME");
365       if ( value >= 0 ) cdiSortName = (int) value;
366 
367       value = cdiGetenvInt("CDI_SORTPARAM");
368       if ( value >= 0 ) cdiSortParam = (int) value;
369 
370       value = cdiGetenvInt("CDI_HAVE_MISSVAL");
371       if ( value >= 0 ) cdiHaveMissval = (int) value;
372 
373       value = cdiGetenvInt("CDI_LEVELTYPE");
374       if ( value >= 0 ) cdiDefaultLeveltype = (int) value;
375 
376       value = cdiGetenvInt("CDI_NETCDF_HDR_PAD");
377       if ( value >= 0 ) CDI_Netcdf_Hdr_Pad = (size_t) value;
378 
379       envstr = getenv("CDI_GRIB1_TEMPLATE");
380       if ( envstr ) CDI_GRIB1_Template = envstr;
381 
382       envstr = getenv("CDI_GRIB2_TEMPLATE");
383       if ( envstr ) CDI_GRIB2_Template = envstr;
384 
385       envstr = getenv("CDI_MISSVAL");
386       if ( envstr ) CDI_Default_Missval = atof(envstr);
387       /*
388       envstr = getenv("NC_MISSING_VALUE");
389       if ( envstr ) cdiNcMissingValue = atoi(envstr);
390       */
391       envstr = getenv("NC_CHUNKSIZEHINT");
392       if ( envstr ) CDI_Netcdf_Chunksizehint = atoi(envstr);
393 
394       envstr = getenv("CDI_CHUNK_ALGO");
395       if ( envstr ) cdiSetChunk(envstr);
396 
397       envstr = getenv("SPLIT_LTYPE_105");
398       if ( envstr ) CDI_Split_Ltype105 = atoi(envstr);
399 
400       envstr = getenv("IGNORE_ATT_COORDINATES");
401       if ( envstr ) CDI_Ignore_Att_Coordinates = atoi(envstr) > 0;
402 
403       envstr = getenv("CDI_COORDINATES_LONLAT");
404       if ( envstr ) CDI_Coordinates_Lon_Lat = atoi(envstr) > 0;
405 
406       envstr = getenv("IGNORE_VALID_RANGE");
407       if ( envstr ) CDI_Ignore_Valid_Range = atoi(envstr) > 0;
408 
409       envstr = getenv("CDI_SKIP_RECORDS");
410       if ( envstr )
411 	{
412 	  CDI_Skip_Records = atoi(envstr);
413 	  CDI_Skip_Records = CDI_Skip_Records > 0 ? CDI_Skip_Records : 0;
414 	}
415 
416       envstr = getenv("CDI_CONVENTION");
417       if ( envstr )
418 	{
419 	  if ( strcmp(envstr, "CF") == 0 || strcmp(envstr, "cf") == 0 )
420 	    {
421 	      CDI_Convention = CDI_CONVENTION_CF;
422 	      if (CDI_Debug) Message("CDI convention was set to CF!");
423 	    }
424 	}
425 
426       envstr = getenv("CDI_INVENTORY_MODE");
427       if (envstr)
428 	{
429 	  if (strncmp(envstr, "time", 4) == 0)
430 	    {
431 	      CDI_Inventory_Mode = 2;
432 	      if (CDI_Debug) Message("Inventory mode was set to timestep!");
433 	    }
434 	}
435 
436       envstr = getenv("CDI_VERSION_INFO");
437       if (envstr)
438         {
439           const int ival = atoi(envstr);
440           if (ival == 0 || ival == 1)
441             {
442               CDI_Version_Info = ival;
443               if (CDI_Debug) Message("CDI_Version_Info = %s", envstr);
444             }
445         }
446 
447       envstr = getenv("CDI_CONVERT_CUBESPHERE");
448       if (envstr)
449         {
450           const int ival = atoi(envstr);
451           if (ival == 0 || ival == 1)
452             {
453               CDI_Convert_Cubesphere = ival;
454               if (CDI_Debug) Message("CDI_Convert_Cubesphere = %s", envstr);
455             }
456         }
457 
458       envstr = getenv("CDI_CALENDAR");
459       if ( envstr )
460 	{
461           // clang-format off
462 	  if      (strncmp(envstr, "standard", 8)  == 0) CDI_Default_Calendar = CALENDAR_STANDARD;
463 	  else if (strncmp(envstr, "gregorian", 9) == 0) CDI_Default_Calendar = CALENDAR_GREGORIAN;
464 	  else if (strncmp(envstr, "proleptic", 9) == 0) CDI_Default_Calendar = CALENDAR_PROLEPTIC;
465 	  else if (strncmp(envstr, "360days", 7)   == 0) CDI_Default_Calendar = CALENDAR_360DAYS;
466 	  else if (strncmp(envstr, "365days", 7)   == 0) CDI_Default_Calendar = CALENDAR_365DAYS;
467 	  else if (strncmp(envstr, "366days", 7)   == 0) CDI_Default_Calendar = CALENDAR_366DAYS;
468 	  else if (strncmp(envstr, "none", 4)      == 0) CDI_Default_Calendar = CALENDAR_NONE;
469           // clang-format on
470 	  if ( CDI_Debug ) Message("Default calendar set to %s!", envstr);
471 	}
472 #ifdef  HAVE_LIBCGRIBEX
473       gribSetCalendar(CDI_Default_Calendar);
474 #endif
475 
476       envstr = getenv("PARTAB_INTERN");
477       if ( envstr ) cdiPartabIntern = atoi(envstr);
478 
479       envstr = getenv("PARTAB_PATH");
480       if ( envstr ) cdiPartabPath = strdup(envstr);
481     }
482 }
483 
484 
strfiletype(int filetype)485 const char *strfiletype(int filetype)
486 {
487   int size = (int) (sizeof(Filetypes)/sizeof(char *));
488   return (filetype > 0 && filetype < size) ? Filetypes[filetype] : Filetypes[0];
489 }
490 
491 
cdiDefGlobal(const char * string,int value)492 void cdiDefGlobal(const char *string, int value)
493 {
494   // clang-format off
495   if      (strIsEqual(string, "REGULARGRID")          ) cdiDataUnreduced = value;
496   else if (strIsEqual(string, "ECCODES_DEBUG")        ) CDI_gribapi_debug = (bool) value;
497   else if (strIsEqual(string, "ECCODES_GRIB1")        ) cdiSetEccodesGrib1((bool) value);
498   else if (strIsEqual(string, "SORTNAME")             ) cdiSortName = value;
499   else if (strIsEqual(string, "SORTPARAM")            ) cdiSortParam = value;
500   else if (strIsEqual(string, "HAVE_MISSVAL")         ) cdiHaveMissval = value;
501   else if (strIsEqual(string, "NC_CHUNKSIZEHINT")     ) CDI_Netcdf_Chunksizehint = value;
502   else if (strIsEqual(string, "READ_CELL_CORNERS")    ) CDI_Read_Cell_Corners = value;
503   else if (strIsEqual(string, "CMOR_MODE")            ) CDI_CMOR_Mode = value;
504   else if (strIsEqual(string, "REDUCE_DIM")           ) CDI_Reduce_Dim = value;
505   else if (strIsEqual(string, "NETCDF_HDR_PAD")       ) CDI_Netcdf_Hdr_Pad = (size_t) value;
506   else if (strIsEqual(string, "NETCDF_LAZY_GRID_LOAD")) CDI_Netcdf_Lazy_Grid_Load = (bool) value;
507   else Warning("Unsupported global key: %s", string);
508   // clang-format on
509 }
510 
511 
cdiDefMissval(double missval)512 void cdiDefMissval(double missval)
513 {
514   cdiInitialize();
515 
516   CDI_Default_Missval = missval;
517 }
518 
519 
cdiInqMissval(void)520 double cdiInqMissval(void)
521 {
522   cdiInitialize();
523 
524   return CDI_Default_Missval;
525 }
526 
527 
cdiBaseFiletype(int filetype)528 int cdiBaseFiletype(int filetype)
529 {
530   switch (filetype)
531     {
532     case CDI_FILETYPE_NC:
533     case CDI_FILETYPE_NC2:
534     case CDI_FILETYPE_NC4:
535     case CDI_FILETYPE_NC4C:
536     case CDI_FILETYPE_NC5:   return CDI_FILETYPE_NETCDF;
537     default:                 return filetype;
538     }
539 
540   return filetype;
541 }
542 
543 /*
544  * Local Variables:
545  * c-file-style: "Java"
546  * c-basic-offset: 2
547  * indent-tabs-mode: nil
548  * show-trailing-whitespace: t
549  * require-trailing-newline: t
550  * End:
551  */
552 
553