1 
2 /* Automatically generated by m214003 at 2020-11-18, do not edit */
3 
4 /* CDILIB_VERSION="1.9.9" */
5 
6 #if defined(_WIN32) || defined(_WIN64)
7 #define restrict
8 #define ssize_t long
9 #else
10 #define HAVE_UNISTD_H
11 #endif
12 
13 #ifdef _ARCH_PWR6
14 #pragma options nostrict
15 #endif
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #ifndef _XOPEN_SOURCE
22 #define _XOPEN_SOURCE 600
23 #endif
24 
25 #ifdef  HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <limits.h>
35 #include <float.h>
36 #include <math.h>
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <stdbool.h>
42 #include <assert.h>
43 
44 #ifdef HAVE_LIBGRIB_API
45 #include <grib_api.h>
46 #endif
47 
48 #ifdef HAVE_MMAP
49 #include <sys/mman.h> /* mmap() is defined in this header */
50 #endif
51 
52 #ifdef HAVE_LIBPTHREAD
53 #include <pthread.h>
54 #endif
55 
56 #ifdef HAVE_LIBSZ
57 #include <szlib.h>
58 #endif
59 
60 #ifndef HAVE_CONFIG_H
61 #define  HAVE_LIBGRIB      1
62 #define  HAVE_LIBCGRIBEX   1
63 #define  HAVE_LIBSERVICE   1
64 #define  HAVE_LIBEXTRA     1
65 #define  HAVE_LIBIEG       1
66 #define  CDI              -1
67 #endif
68 
69 #ifndef ASYNC_WORKER_H
70 #define ASYNC_WORKER_H
71 
72 typedef struct AsyncJob AsyncJob;
73 typedef struct AsyncManager AsyncManager;
74 
75 // a negative threadCount gives the number of cores that should remain unused by the worker threads, returns an error code
76 int AsyncWorker_init(AsyncManager **jobManager, int threadCount);
77 
78 // executes work(data) in a worker thread, must be followed by a call to AsyncWorker_wait()
79 AsyncJob *AsyncWorker_requestWork(AsyncManager *jobManager, int (*work)(void *data), void *data);
80 
81 // waits for the async job to finish and returns its result (or some other error code)
82 int AsyncWorker_wait(AsyncManager *jobManager, AsyncJob *job);
83 
84 // return the number of workers that are currently idle
85 int AsyncWorker_availableWorkers(AsyncManager *jobManager);
86 
87 // waits for all pending jobs to finish, stops all workers, returns a non-zero error code from a pending job if there were any
88 int AsyncWorker_finalize(AsyncManager *jobManager);
89 
90 #endif
91 /*
92   CDI C header file
93 
94   This is the only file that must be included to use the CDI library from C.
95 */
96 
97 #ifndef  CDI_H_
98 #define  CDI_H_
99 
100 #include <stdio.h>
101 #include <stdint.h>    // int64_t
102 #include <sys/types.h>
103 
104 #ifdef __cplusplus
105 extern "C" {
106 #endif
107 
108 #define  CDI_MAX_NAME             256   // Max length of a name
109 
110 #define  CDI_UNDEFID               -1
111 #define  CDI_GLOBAL                -1   // Global var ID for vlist and Z-axis
112 #define  CDI_XAXIS                  1   // X-axis ID for grid
113 #define  CDI_YAXIS                  2   // Y-axis ID for grid
114 
115 // Byte order
116 
117 #define  CDI_BIGENDIAN              0   // Byte order BIGENDIAN
118 #define  CDI_LITTLEENDIAN           1   // Byte order LITTLEENDIAN
119 #define  CDI_PDPENDIAN              2
120 
121 #define  CDI_REAL                   1   // Real numbers
122 #define  CDI_COMP                   2   // Complex numbers
123 #define  CDI_BOTH                   3   // Both numbers
124 
125 // Error identifier
126 
127 #define	 CDI_NOERR        	    0   // No Error
128 #define  CDI_EEOF                  -1   // The end of file was encountered
129 #define  CDI_ETMOF                 -9   // Too many open files
130 #define  CDI_ESYSTEM              -10   // Operating system error
131 #define  CDI_EINVAL               -20   // Invalid argument
132 #define  CDI_EISDIR               -21   // Is a directory
133 #define  CDI_EISEMPTY             -22   // Is empty
134 #define  CDI_EUFTYPE              -23   // Unsupported file type
135 #define  CDI_ELIBNAVAIL           -24   // xxx library not available
136 #define  CDI_EUFSTRUCT            -25   // Unsupported file structure
137 #define  CDI_EUNC4                -26   // Unsupported NetCDF4 structure
138 #define  CDI_EDIMSIZE             -27   // Invalid dimension size
139 #define  CDI_ELIMIT               -99   // Internal limits exceeded
140 
141 // File types
142 
143 #define  CDI_FILETYPE_GRB           1   // File type GRIB
144 #define  CDI_FILETYPE_GRB2          2   // File type GRIB version 2
145 #define  CDI_FILETYPE_NC            3   // File type NetCDF
146 #define  CDI_FILETYPE_NC2           4   // File type NetCDF version 2 (64-bit offset)
147 #define  CDI_FILETYPE_NC4           5   // File type NetCDF version 4
148 #define  CDI_FILETYPE_NC4C          6   // File type NetCDF version 4 (classic)
149 #define  CDI_FILETYPE_NC5           7   // File type NetCDF version 5 (64-bit data)
150 #define  CDI_FILETYPE_SRV           8   // File type SERVICE
151 #define  CDI_FILETYPE_EXT           9   // File type EXTRA
152 #define  CDI_FILETYPE_IEG          10   // File type IEG
153 
154 // Compress types
155 
156 #define  CDI_COMPRESS_NONE          0
157 #define  CDI_COMPRESS_SZIP          1
158 #define  CDI_COMPRESS_AEC           2
159 #define  CDI_COMPRESS_ZIP           3
160 #define  CDI_COMPRESS_JPEG          4
161 
162 // external data types
163 
164 #define  CDI_DATATYPE_PACK          0
165 #define  CDI_DATATYPE_PACK1         1
166 #define  CDI_DATATYPE_PACK2         2
167 #define  CDI_DATATYPE_PACK3         3
168 #define  CDI_DATATYPE_PACK4         4
169 #define  CDI_DATATYPE_PACK5         5
170 #define  CDI_DATATYPE_PACK6         6
171 #define  CDI_DATATYPE_PACK7         7
172 #define  CDI_DATATYPE_PACK8         8
173 #define  CDI_DATATYPE_PACK9         9
174 #define  CDI_DATATYPE_PACK10       10
175 #define  CDI_DATATYPE_PACK11       11
176 #define  CDI_DATATYPE_PACK12       12
177 #define  CDI_DATATYPE_PACK13       13
178 #define  CDI_DATATYPE_PACK14       14
179 #define  CDI_DATATYPE_PACK15       15
180 #define  CDI_DATATYPE_PACK16       16
181 #define  CDI_DATATYPE_PACK17       17
182 #define  CDI_DATATYPE_PACK18       18
183 #define  CDI_DATATYPE_PACK19       19
184 #define  CDI_DATATYPE_PACK20       20
185 #define  CDI_DATATYPE_PACK21       21
186 #define  CDI_DATATYPE_PACK22       22
187 #define  CDI_DATATYPE_PACK23       23
188 #define  CDI_DATATYPE_PACK24       24
189 #define  CDI_DATATYPE_PACK25       25
190 #define  CDI_DATATYPE_PACK26       26
191 #define  CDI_DATATYPE_PACK27       27
192 #define  CDI_DATATYPE_PACK28       28
193 #define  CDI_DATATYPE_PACK29       29
194 #define  CDI_DATATYPE_PACK30       30
195 #define  CDI_DATATYPE_PACK31       31
196 #define  CDI_DATATYPE_PACK32       32
197 #define  CDI_DATATYPE_CPX32        64
198 #define  CDI_DATATYPE_CPX64       128
199 #define  CDI_DATATYPE_FLT32       132
200 #define  CDI_DATATYPE_FLT64       164
201 #define  CDI_DATATYPE_INT8        208
202 #define  CDI_DATATYPE_INT16       216
203 #define  CDI_DATATYPE_INT32       232
204 #define  CDI_DATATYPE_UINT8       308
205 #define  CDI_DATATYPE_UINT16      316
206 #define  CDI_DATATYPE_UINT32      332
207 
208 // internal data types
209 #define  CDI_DATATYPE_INT         251
210 #define  CDI_DATATYPE_FLT         252
211 #define  CDI_DATATYPE_TXT         253
212 #define  CDI_DATATYPE_CPX         254
213 #define  CDI_DATATYPE_UCHAR       255
214 #define  CDI_DATATYPE_LONG        256
215 #define  CDI_DATATYPE_UINT        257
216 
217 // Chunks
218 
219 #define  CDI_CHUNK_AUTO             1  // use default chunk size
220 #define  CDI_CHUNK_GRID             2
221 #define  CDI_CHUNK_LINES            3
222 
223 // GRID types
224 
225 #define  GRID_GENERIC               1  // Generic grid
226 #define  GRID_GAUSSIAN              2  // Regular Gaussian lon/lat grid
227 #define  GRID_GAUSSIAN_REDUCED      3  // Reduced Gaussian lon/lat grid
228 #define  GRID_LONLAT                4  // Regular longitude/latitude grid
229 #define  GRID_SPECTRAL              5  // Spherical harmonic coefficients
230 #define  GRID_FOURIER               6  // Fourier coefficients
231 #define  GRID_GME                   7  // Icosahedral-hexagonal GME grid
232 #define  GRID_TRAJECTORY            8  // Trajectory
233 #define  GRID_UNSTRUCTURED          9  // General unstructured grid
234 #define  GRID_CURVILINEAR          10  // Curvilinear grid
235 #define  GRID_PROJECTION           12  // Projected coordinates
236 #define  GRID_CHARXY               13  // One horizontal character dimension
237 
238 #define  CDI_PROJ_RLL              21  // Rotated Latitude Longitude
239 #define  CDI_PROJ_LCC              22  // Lambert Conformal Conic
240 #define  CDI_PROJ_LAEA             23  // Lambert Azimuthal Equal Area
241 #define  CDI_PROJ_SINU             24  // Sinusoidal
242 #define  CDI_PROJ_STERE            25  // Polar stereographic
243 
244 // ZAXIS types
245 
246 #define  ZAXIS_SURFACE              0  // Surface level
247 #define  ZAXIS_GENERIC              1  // Generic level
248 #define  ZAXIS_HYBRID               2  // Hybrid level
249 #define  ZAXIS_HYBRID_HALF          3  // Hybrid half level
250 #define  ZAXIS_PRESSURE             4  // Isobaric pressure level in Pascal
251 #define  ZAXIS_HEIGHT               5  // Height above ground
252 #define  ZAXIS_DEPTH_BELOW_SEA      6  // Depth below sea level in meters
253 #define  ZAXIS_DEPTH_BELOW_LAND     7  // Depth below land surface in centimeters
254 #define  ZAXIS_ISENTROPIC           8  // Isentropic
255 #define  ZAXIS_TRAJECTORY           9  // Trajectory
256 #define  ZAXIS_ALTITUDE            10  // Altitude above mean sea level in meters
257 #define  ZAXIS_SIGMA               11  // Sigma level
258 #define  ZAXIS_MEANSEA             12  // Mean sea level
259 #define  ZAXIS_TOA                 13  // Norminal top of atmosphere
260 #define  ZAXIS_SEA_BOTTOM          14  // Sea bottom
261 #define  ZAXIS_ATMOSPHERE          15  // Entire atmosphere
262 #define  ZAXIS_CLOUD_BASE          16  // Cloud base level
263 #define  ZAXIS_CLOUD_TOP           17  // Level of cloud tops
264 #define  ZAXIS_ISOTHERM_ZERO       18  // Level of 0o C isotherm
265 #define  ZAXIS_SNOW                19  // Snow level
266 #define  ZAXIS_LAKE_BOTTOM         20  // Lake or River Bottom
267 #define  ZAXIS_SEDIMENT_BOTTOM     21  // Bottom Of Sediment Layer
268 #define  ZAXIS_SEDIMENT_BOTTOM_TA  22  // Bottom Of Thermally Active Sediment Layer
269 #define  ZAXIS_SEDIMENT_BOTTOM_TW  23  // Bottom Of Sediment Layer Penetrated By Thermal Wave
270 #define  ZAXIS_MIX_LAYER           24  // Mixing Layer
271 #define  ZAXIS_REFERENCE           25  // zaxis reference number
272 #define  ZAXIS_CHAR                26  // Area types
273 #define  ZAXIS_TROPOPAUSE          27  // Tropopause
274 
275 // SUBTYPE types
276 
277 enum {
278   SUBTYPE_TILES                   = 0  // Tiles variable
279 };
280 
281 #define MAX_KV_PAIRS_MATCH 10
282 
283 /* Data structure defining a key-value search, possibly with multiple
284    key-value pairs in combination.
285 
286    Currently, only multiple pairs combined by AND are supported.
287 */
288 typedef struct  {
289   int nAND;                                   // no. of key-value pairs that have to match
290   int key_value_pairs[2][MAX_KV_PAIRS_MATCH]; // key-value pairs
291 } subtype_query_t;
292 
293 
294 
295 // TIME types
296 
297 #define  TIME_CONSTANT            0  // Time constant
298 #define  TIME_VARYING             1  // Time varying
299 #define  TIME_VARIABLE            1  // obsolete, use TIME_VARYING
300 
301 // TSTEP types
302 
303 #define  TSTEP_INSTANT            1  // Instant
304 #define  TSTEP_AVG                2  // Average
305 #define  TSTEP_ACCUM              3  // Accumulation
306 #define  TSTEP_MAX                4  // Maximum
307 #define  TSTEP_MIN                5  // Minimum
308 #define  TSTEP_DIFF               6  // Difference
309 #define  TSTEP_RMS                7  // Root mean square
310 #define  TSTEP_SD                 8  // Standard deviation
311 #define  TSTEP_COV                9  // Covariance
312 #define  TSTEP_RATIO             10  // Ratio
313 #define  TSTEP_SUM               11  // Summation
314 #define  TSTEP_RANGE             12
315 #define  TSTEP_INSTANT2          13
316 #define  TSTEP_INSTANT3          14
317 
318 // TAXIS types
319 
320 #define  TAXIS_ABSOLUTE           1
321 #define  TAXIS_RELATIVE           2
322 #define  TAXIS_FORECAST           3
323 
324 // TUNIT types
325 
326 #define  TUNIT_SECOND             1
327 #define  TUNIT_MINUTE             2
328 #define  TUNIT_QUARTER            3
329 #define  TUNIT_30MINUTES          4
330 #define  TUNIT_HOUR               5
331 #define  TUNIT_3HOURS             6
332 #define  TUNIT_6HOURS             7
333 #define  TUNIT_12HOURS            8
334 #define  TUNIT_DAY                9
335 #define  TUNIT_MONTH             10
336 #define  TUNIT_YEAR              11
337 
338 // CALENDAR types
339 
340 #define  CALENDAR_STANDARD        0  // don't change this value (used also in cgribexlib)!
341 #define  CALENDAR_GREGORIAN       1
342 #define  CALENDAR_PROLEPTIC       2
343 #define  CALENDAR_360DAYS         3
344 #define  CALENDAR_365DAYS         4
345 #define  CALENDAR_366DAYS         5
346 #define  CALENDAR_NONE            6
347 
348 // number of unsigned char needed to store UUID
349 #define  CDI_UUID_SIZE           16
350 
351 // Structs that are used to return data to the user
352 
353 typedef struct CdiParam { int discipline; int category; int number; } CdiParam;
354 
355 
356 // Opaque types
357 typedef struct CdiIterator CdiIterator;
358 typedef struct CdiGribIterator CdiGribIterator;
359 
360 // CDI control routines
361 
362 void    cdiReset(void);
363 
364 const char *cdiStringError(int cdiErrno);
365 
366 void    cdiDebug(int debug);
367 
368 const char *cdiLibraryVersion(void);
369 void    cdiPrintVersion(void);
370 
371 int     cdiHaveFiletype(int filetype);
372 
373 void    cdiDefMissval(double missval);
374 double  cdiInqMissval(void);
375 double  cdiInqGridMissval(void);
376 void    cdiDefGlobal(const char *string, int val);
377 
378 int     namespaceNew(void);
379 void    namespaceSetActive(int namespaceID);
380 int     namespaceGetActive(void);
381 void    namespaceDelete(int namespaceID);
382 
383 
384 // CDI converter routines
385 
386 // parameter
387 
388 void    cdiParamToString(int param, char *paramstr, int maxlen);
389 
390 void    cdiDecodeParam(int param, int *pnum, int *pcat, int *pdis);
391 int     cdiEncodeParam(int pnum, int pcat, int pdis);
392 
393 // date format:  YYYYMMDD
394 // time format:    hhmmss
395 
396 void    cdiDecodeDate(int64_t date, int *year, int *month, int *day);
397 int64_t cdiEncodeDate(int year, int month, int day);
398 
399 void    cdiDecodeTime(int time, int *hour, int *minute, int *second);
400 int     cdiEncodeTime(int hour, int minute, int second);
401 
402 
403 // STREAM control routines
404 
405 int     cdiGetFiletype(const char *path, int *byteorder);
406 
407 //      streamOpenRead: Open a dataset for reading
408 int     streamOpenRead(const char *path);
409 
410 //      streamOpenWrite: Create a new dataset
411 int     streamOpenWrite(const char *path, int filetype);
412 
413 int     streamOpenAppend(const char *path);
414 
415 //      streamClose: Close an open dataset
416 void    streamClose(int streamID);
417 
418 //      streamSync: Synchronize an Open Dataset to Disk
419 void    streamSync(int streamID);
420 
421 void    streamDefNumWorker(int streamID, int numWorker);
422 
423 //      streamDefVlist: Define the Vlist for a stream
424 void    streamDefVlist(int streamID, int vlistID);
425 
426 //      streamInqVlist: Get the Vlist of a stream
427 int     streamInqVlist(int streamID);
428 
429 //      streamInqFiletype: Get the filetype
430 int     streamInqFiletype(int streamID);
431 
432 //      streamDefByteorder: Define the byteorder
433 void    streamDefByteorder(int streamID, int byteorder);
434 
435 //      streamInqByteorder: Get the byteorder
436 int     streamInqByteorder(int streamID);
437 
438 //      streamDefCompType: Define compression type
439 void    streamDefCompType(int streamID, int comptype);
440 
441 //      streamInqCompType: Get compression type
442 int     streamInqCompType(int streamID);
443 
444 //      streamDefCompLevel: Define compression level
445 void    streamDefCompLevel(int streamID, int complevel);
446 
447 //      streamInqCompLevel: Get compression level
448 int     streamInqCompLevel(int streamID);
449 
450 //      streamDefTimestep: Define time step
451 int     streamDefTimestep(int streamID, int tsID);
452 
453 //      streamInqTimestep: Get time step
454 int     streamInqTimestep(int streamID, int tsID);
455 
456 //      PIO: query currently set timestep id
457 int     streamInqCurTimestepID(int streamID);
458 
459 const char *streamFilename(int streamID);
460 const char *streamFilesuffix(int filetype);
461 
462 size_t  streamNvals(int streamID);
463 
464 int     streamInqNvars(int streamID);
465 
466 // STREAM var I/O routines (random access)
467 
468 //      streamWriteVar: Write a variable
469 void    streamWriteVar(int streamID, int varID, const double data[], size_t nmiss);
470 void    streamWriteVarF(int streamID, int varID, const float data[], size_t nmiss);
471 
472 //      streamReadVar: Read a variable
473 void    streamReadVar(int streamID, int varID, double data[], size_t *nmiss);
474 void    streamReadVarF(int streamID, int varID, float data[], size_t *nmiss);
475 void    streamReadVarPart(int streamID, int varID, int varType, int start, size_t size, void *data, size_t *nmiss, int memtype);
476 
477 //      streamWriteVarSlice: Write a horizontal slice of a variable
478 void    streamWriteVarSlice(int streamID, int varID, int levelID, const double data[], size_t nmiss);
479 void    streamWriteVarSliceF(int streamID, int varID, int levelID, const float data[], size_t nmiss);
480 void    streamReadVarSlicePart(int streamID, int varID, int levelID, int varType, int start, size_t size, void *data, size_t *nmiss, int memtype);
481 
482 //      streamReadVarSlice: Read a horizontal slice of a variable
483 void    streamReadVarSlice(int streamID, int varID, int levelID, double data[], size_t *nmiss);
484 void    streamReadVarSliceF(int streamID, int varID, int levelID, float data[], size_t *nmiss);
485 
486 void    streamWriteVarChunk(int streamID, int varID, const int rect[3][2], const double data[], size_t nmiss);
487 
488 
489 // STREAM record I/O routines (sequential access)
490 
491 void    streamDefRecord(int streamID, int  varID, int  levelID);
492 void    streamInqRecord(int streamID, int *varID, int *levelID);
493 void    streamWriteRecord(int streamID, const double data[], size_t nmiss);
494 void    streamWriteRecordF(int streamID, const float data[], size_t nmiss);
495 void    streamReadRecord(int streamID, double data[], size_t *nmiss);
496 void    streamReadRecordF(int streamID, float data[], size_t *nmiss);
497 void    streamCopyRecord(int streamIDdest, int streamIDsrc);
498 
499 void    streamInqGRIBinfo(int streamID, int *intnum, float *fltnum, off_t *bignum);
500 
501 
502 // File driven I/O (may yield better performance than using the streamXXX functions)
503 
504 // Creation & Destruction
505 CdiIterator *cdiIterator_new(const char *path);  // Requires a subsequent call to cdiIteratorNextField() to point the iterator at the first field.
506 CdiIterator *cdiIterator_clone(CdiIterator *me);
507 char *cdiIterator_serialize(CdiIterator *me);  // Returns a malloc'ed string.
508 CdiIterator *cdiIterator_deserialize(const char *description);  // description is a string that was returned by cdiIteratorSerialize(). Returns a copy of the original iterator.
509 void cdiIterator_print(CdiIterator *me, FILE *stream);
510 void cdiIterator_delete(CdiIterator *me);
511 
512 // Advancing an iterator
513 int cdiIterator_nextField(CdiIterator *me);      // Points the iterator at the next field, returns CDI_EEOF if there are no more fields in the file.
514 
515 // Introspecting metadata
516 // All outXXX arguments to these functions may be NULL.
517 char *cdiIterator_inqStartTime(CdiIterator *me);    // Returns the (start) time as an ISO-8601 coded string. The caller is responsible to Free() the returned string.
518 char *cdiIterator_inqEndTime(CdiIterator *me);      // Returns the end time of an integration period as an ISO-8601 coded string, or NULL if there is no end time. The caller is responsible to Free() the returned string.
519 char *cdiIterator_inqRTime(CdiIterator *me);        // Returns the reference date as an ISO-8601 coded string. The caller is responsible to Free() the returned string.
520 char *cdiIterator_inqVTime(CdiIterator *me);        // Returns the validity date as an ISO-8601 coded string. The caller is responsible to Free() the returned string.
521 int cdiIterator_inqLevelType(CdiIterator *me, int levelSelector, char **outName_optional, char **outLongName_optional, char **outStdName_optional, char **outUnit_optional);      // callers are responsible to Free() strings that they request
522 int cdiIterator_inqLevel(CdiIterator *me, int levelSelector, double *outValue1_optional, double *outValue2_optional);       // outValue2 is only written to if the level is a hybrid level
523 int cdiIterator_inqLevelUuid(CdiIterator *me, int *outVgridNumber_optional, int *outLevelCount_optional, unsigned char outUuid_optional[CDI_UUID_SIZE]);   // outUuid must point to a buffer of 16 bytes, returns an error code if no generalized zaxis is used.
524 int cdiIterator_inqTile(CdiIterator *me, int *outTileIndex, int *outTileAttribute); // Returns CDI_EINVAL if there is no tile information connected to the current field, *outTileIndex and *outTileAttribute will be set to -1 in this case.
525 int cdiIterator_inqTileCount(CdiIterator *me, int *outTileCount, int *outTileAttributeCount); // outTileAttributeCount is the count for the tile associated with the current field, a total attribute count cannot be inquired. Returns CDI_EINVAL if there is no tile information connected to the current field, *outTileCount and *outTileAttributeCount will be set to 0 in this case.
526 CdiParam cdiIterator_inqParam(CdiIterator *me);
527 void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber);	// Some FORTRAN compilers produce wrong code for the cdiIterator_inqParam()-wrapper, rendering it unusable from FORTRAN. This function is the workaround.
528 int cdiIterator_inqDatatype(CdiIterator *me);
529 int cdiIterator_inqFiletype(CdiIterator *me);
530 int cdiIterator_inqTsteptype(CdiIterator *me);
531 char *cdiIterator_inqVariableName(CdiIterator *me);     // The caller is responsible to Free() the returned buffer.
532 int cdiIterator_inqGridId(CdiIterator *me);             // The returned id is only valid until the next call to cdiIteratorNextField().
533 
534 // Reading data
535 void cdiIterator_readField(CdiIterator *me, double data[], size_t *nmiss_optional);
536 void cdiIterator_readFieldF(CdiIterator *me, float data[], size_t *nmiss_optional);
537 // TODO[NH]: Add functions to read partial fields.
538 
539 
540 // Direct access to grib fields
541 CdiGribIterator *cdiGribIterator_clone(CdiIterator *me);  // Returns NULL if the associated file is not a GRIB file.
542 void cdiGribIterator_delete(CdiGribIterator *me);
543 
544 // Callthroughs to GRIB-API
545 int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *value);         // Same semantics as grib_get_long().
546 int cdiGribIterator_getDouble(CdiGribIterator *me, const char *key, double *value);     // Same semantics as grib_get_double().
547 int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *value);     // Same semantics as grib_get_length().
548 int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *value, size_t *length);       // Same semantics as grib_get_string().
549 int cdiGribIterator_getSize(CdiGribIterator *me, const char *key, size_t *value);       // Same semantics as grib_get_size().
550 int cdiGribIterator_getLongArray(CdiGribIterator *me, const char *key, long *value, size_t *array_size);       // Same semantics as grib_get_long_array().
551 int cdiGribIterator_getDoubleArray(CdiGribIterator *me, const char *key, double *value, size_t *array_size);   // Same semantics as grib_get_double_array().
552 
553 // Convenience functions for accessing GRIB-API keys
554 int cdiGribIterator_inqEdition(CdiGribIterator *me);
555 long cdiGribIterator_inqLongValue(CdiGribIterator *me, const char *key);       // Aborts on failure to fetch the given key.
556 long cdiGribIterator_inqLongDefaultValue(CdiGribIterator *me, const char *key, long defaultValue); // Returns the default value if the given key is not present.
557 double cdiGribIterator_inqDoubleValue(CdiGribIterator *me, const char *key);   // Aborts on failure to fetch the given key.
558 double cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator *me, const char *key, double defaultValue); // Returns the default value if the given key is not present.
559 char *cdiGribIterator_inqStringValue(CdiGribIterator *me, const char *key);    // Returns a malloc'ed string.
560 
561 // VLIST routines
562 
563 //      vlistCreate: Create a variable list
564 int     vlistCreate(void);
565 
566 //      vlistDestroy: Destroy a variable list
567 void    vlistDestroy(int vlistID);
568 
569 //      vlistDuplicate: Duplicate a variable list
570 int     vlistDuplicate(int vlistID);
571 
572 //      vlistCopy: Copy a variable list
573 void    vlistCopy(int vlistID2, int vlistID1);
574 
575 //      vlistCopyFlag: Copy some entries of a variable list
576 void    vlistCopyFlag(int vlistID2, int vlistID1);
577 
578 void    vlistClearFlag(int vlistID);
579 
580 //      vlistCat: Concatenate two variable lists
581 void    vlistCat(int vlistID2, int vlistID1);
582 
583 //      vlistMerge: Merge two variable lists
584 void    vlistMerge(int vlistID2, int vlistID1);
585 
586 void    vlistPrint(int vlistID);
587 
588 //      vlistNumber: Number type in a variable list
589 int     vlistNumber(int vlistID);
590 
591 //      vlistNvars: Number of variables in a variable list
592 int     vlistNvars(int vlistID);
593 
594 //      vlistNgrids: Number of grids in a variable list
595 int     vlistNgrids(int vlistID);
596 
597 //      vlistNzaxis: Number of zaxis in a variable list
598 int     vlistNzaxis(int vlistID);
599 
600 //      vlistNsubtypes: Number of subtypes in a variable list
601 int     vlistNsubtypes(int vlistID);
602 
603 void    vlistDefNtsteps(int vlistID, int nts);
604 int     vlistNtsteps(int vlistID);
605 size_t  vlistGridsizeMax(int vlistID);
606 int     vlistGrid(int vlistID, int index);
607 int     vlistGridIndex(int vlistID, int gridID);
608 void    vlistChangeGridIndex(int vlistID, int index, int gridID);
609 void    vlistChangeGrid(int vlistID, int gridID1, int gridID2);
610 int     vlistZaxis(int vlistID, int index);
611 int     vlistZaxisIndex(int vlistID, int zaxisID);
612 void    vlistChangeZaxisIndex(int vlistID, int index, int zaxisID);
613 void    vlistChangeZaxis(int vlistID, int zaxisID1, int zaxisID2);
614 int     vlistNrecs(int vlistID);
615 int     vlistSubtype(int vlistID, int index);
616 int     vlistSubtypeIndex(int vlistID, int subtypeID);
617 
618 //      vlistDefTaxis: Define the time axis of a variable list
619 void    vlistDefTaxis(int vlistID, int taxisID);
620 
621 //      vlistInqTaxis: Get the time axis of a variable list
622 int     vlistInqTaxis(int vlistID);
623 
624 void    vlistDefTable(int vlistID, int tableID);
625 int     vlistInqTable(int vlistID);
626 void    vlistDefInstitut(int vlistID, int instID);
627 int     vlistInqInstitut(int vlistID);
628 void    vlistDefModel(int vlistID, int modelID);
629 int     vlistInqModel(int vlistID);
630 
631 
632 // VLIST VAR routines
633 
634 //      vlistDefVarTiles: Create a new tile-based variable
635 int     vlistDefVarTiles(int vlistID, int gridID, int zaxisID, int timetype, int tilesetID);
636 
637 //      vlistDefVar: Create a new variable
638 int     vlistDefVar(int vlistID, int gridID, int zaxisID, int timetype);
639 
640 void    vlistChangeVarGrid(int vlistID, int varID, int gridID);
641 void    vlistChangeVarZaxis(int vlistID, int varID, int zaxisID);
642 
643 void    vlistInqVar(int vlistID, int varID, int *gridID, int *zaxisID, int *timetype);
644 int     vlistInqVarGrid(int vlistID, int varID);
645 int     vlistInqVarZaxis(int vlistID, int varID);
646 
647 //      used in MPIOM
648 int     vlistInqVarID(int vlistID, int code);
649 
650 void    vlistDefVarTimetype(int vlistID, int varID, int timetype);
651 int     vlistInqVarTimetype(int vlistID, int varID);
652 
653 void    vlistDefVarTsteptype(int vlistID, int varID, int tsteptype);
654 
655 //      vlistInqVarTsteptype: Get the timestep type of a Variable
656 int     vlistInqVarTsteptype(int vlistID, int varID);
657 
658 void    vlistDefVarCompType(int vlistID, int varID, int comptype);
659 int     vlistInqVarCompType(int vlistID, int varID);
660 void    vlistDefVarCompLevel(int vlistID, int varID, int complevel);
661 int     vlistInqVarCompLevel(int vlistID, int varID);
662 
663 //      vlistDefVarParam: Define the parameter number of a Variable
664 void    vlistDefVarParam(int vlistID, int varID, int param);
665 
666 //      vlistInqVarParam: Get the parameter number of a Variable
667 int     vlistInqVarParam(int vlistID, int varID);
668 
669 //      vlistDefVarCode: Define the code number of a Variable
670 void    vlistDefVarCode(int vlistID, int varID, int code);
671 
672 //      vlistInqVarCode: Get the code number of a Variable
673 int     vlistInqVarCode(int vlistID, int varID);
674 
675 //      vlistDefVarDatatype: Define the data type of a Variable
676 void    vlistDefVarDatatype(int vlistID, int varID, int datatype);
677 
678 //      vlistInqVarDatatype: Get the data type of a Variable
679 int     vlistInqVarDatatype(int vlistID, int varID);
680 
681 void    vlistDefVarChunkType(int vlistID, int varID, int chunktype);
682 int     vlistInqVarChunkType(int vlistID, int varID);
683 
684 void    vlistDefVarXYZ(int vlistID, int varID, int xyz);
685 int     vlistInqVarXYZ(int vlistID, int varID);
686 
687 int     vlistInqVarNumber(int vlistID, int varID);
688 
689 void    vlistDefVarInstitut(int vlistID, int varID, int instID);
690 int     vlistInqVarInstitut(int vlistID, int varID);
691 void    vlistDefVarModel(int vlistID, int varID, int modelID);
692 int     vlistInqVarModel(int vlistID, int varID);
693 void    vlistDefVarTable(int vlistID, int varID, int tableID);
694 int     vlistInqVarTable(int vlistID, int varID);
695 
696 //      vlistDefVarName: Define the name of a Variable
697 void    vlistDefVarName(int vlistID, int varID, const char *name);
698 
699 //      vlistInqVarName: Get the name of a Variable
700 void    vlistInqVarName(int vlistID, int varID, char *name);
701 
702 //      vlistCopyVarName: Safe and convenient version of vlistInqVarName
703 char   *vlistCopyVarName(int vlistId, int varId);
704 
705 //      vlistDefVarStdname: Define the standard name of a Variable
706 void    vlistDefVarStdname(int vlistID, int varID, const char *stdname);
707 
708 //      vlistInqVarStdname: Get the standard name of a Variable
709 void    vlistInqVarStdname(int vlistID, int varID, char *stdname);
710 
711 //      vlistDefVarLongname: Define the long name of a Variable
712 void    vlistDefVarLongname(int vlistID, int varID, const char *longname);
713 
714 //      vlistInqVarLongname: Get the long name of a Variable
715 void    vlistInqVarLongname(int vlistID, int varID, char *longname);
716 
717 //      vlistDefVarUnits: Define the units of a Variable
718 void    vlistDefVarUnits(int vlistID, int varID, const char *units);
719 
720 //      vlistInqVarUnits: Get the units of a Variable
721 void    vlistInqVarUnits(int vlistID, int varID, char *units);
722 
723 //      vlistDefVarMissval: Define the missing value of a Variable
724 void    vlistDefVarMissval(int vlistID, int varID, double missval);
725 
726 //      vlistInqVarMissval: Get the missing value of a Variable
727 double  vlistInqVarMissval(int vlistID, int varID);
728 
729 //      vlistDefVarExtra: Define extra information of a Variable
730 void    vlistDefVarExtra(int vlistID, int varID, const char *extra);
731 
732 //      vlistInqVarExtra: Get extra information of a Variable
733 void    vlistInqVarExtra(int vlistID, int varID, char *extra);
734 
735 void    vlistDefVarScalefactor(int vlistID, int varID, double scalefactor);
736 double  vlistInqVarScalefactor(int vlistID, int varID);
737 void    vlistDefVarAddoffset(int vlistID, int varID, double addoffset);
738 double  vlistInqVarAddoffset(int vlistID, int varID);
739 
740 size_t  vlistInqVarSize(int vlistID, int varID);
741 
742 void    vlistDefIndex(int vlistID, int varID, int levID, int index);
743 int     vlistInqIndex(int vlistID, int varID, int levID);
744 void    vlistDefFlag(int vlistID, int varID, int levID, int flag);
745 int     vlistInqFlag(int vlistID, int varID, int levID);
746 int     vlistFindVar(int vlistID, int fvarID);
747 int     vlistFindLevel(int vlistID, int fvarID, int flevelID);
748 int     vlistMergedVar(int vlistID, int varID);
749 int     vlistMergedLevel(int vlistID, int varID, int levelID);
750 
751 //      cdiClearAdditionalKeys: Clear the list of additional GRIB keys
752 void    cdiClearAdditionalKeys(void);
753 //      cdiDefAdditionalKey: Register an additional GRIB key which is read when file is opened
754 void    cdiDefAdditionalKey(const char *string);
755 
756 //      vlistDefVarIntKey: Set an arbitrary keyword/integer value pair for GRIB API
757 void    vlistDefVarIntKey(int vlistID, int varID, const char *name, int value);
758 //      vlistDefVarDblKey: Set an arbitrary keyword/double value pair for GRIB API
759 void    vlistDefVarDblKey(int vlistID, int varID, const char *name, double value);
760 
761 //      vlistHasVarKey: returns 1 if meta-data key was read, 0 otherwise
762 int     vlistHasVarKey(int vlistID, int varID, const char *name);
763 //      vlistInqVarDblKey: raw access to GRIB meta-data
764 double  vlistInqVarDblKey(int vlistID, int varID, const char *name);
765 //      vlistInqVarIntKey: raw access to GRIB meta-data
766 int     vlistInqVarIntKey(int vlistID, int varID, const char *name);
767 
768 // CDI attributes
769 
770 //      cdiInqNatts: Get number of attributes assigned to this variable
771 int     cdiInqNatts(int cdiID, int varID, int *nattsp);
772 //      cdiInqAtt: Get information about an attribute
773 int     cdiInqAtt(int cdiID, int varID, int attrnum, char *name, int *typep, int *lenp);
774 int     cdiInqAttLen(int cdiID, int varID, const char *name);
775 int     cdiInqAttType(int cdiID, int varID, const char *name);
776 int     cdiDelAtt(int cdiID, int varID, const char *name);
777 
778 int     cdiCopyAtts(int cdiID1, int varID1, int cdiID2, int varID2);
779 
780 //      cdiDefAttInt: Define an integer attribute
781 int     cdiDefAttInt(int cdiID, int varID, const char *name, int type, int len, const int ip[]);
782 //      cdiDefAttFlt: Define a floating point attribute
783 int     cdiDefAttFlt(int cdiID, int varID, const char *name, int type, int len, const double dp[]);
784 //      cdiDefAttTxt: Define a text attribute
785 int     cdiDefAttTxt(int cdiID, int varID, const char *name, int len, const char *tp_cbuf);
786 
787 //      cdiInqAttInt: Get the value(s) of an integer attribute
788 int     cdiInqAttInt(int cdiID, int varID, const char *name, int mlen, int ip[]);
789 //      cdiInqAttFlt: Get the value(s) of a floating point attribute
790 int     cdiInqAttFlt(int cdiID, int varID, const char *name, int mlen, double dp[]);
791 //      cdiInqAttTxt: Get the value(s) of a text attribute
792 int     cdiInqAttTxt(int cdiID, int varID, const char *name, int mlen, char *tp_cbuf);
793 
794 
795 // GRID routines
796 
797 void    gridName(int gridtype, char *gridname);
798 const char *gridNamePtr(int gridtype);
799 
800 void    gridCompress(int gridID);
801 
802 void    gridDefMaskGME(int gridID, const int mask[]);
803 int     gridInqMaskGME(int gridID, int mask[]);
804 
805 void    gridDefMask(int gridID, const int mask[]);
806 int     gridInqMask(int gridID, int mask[]);
807 
808 //      gridCreate: Create a horizontal Grid
809 int     gridCreate(int gridtype, size_t size);
810 
811 //      gridDestroy: Destroy a horizontal Grid
812 void    gridDestroy(int gridID);
813 
814 //      gridDuplicate: Duplicate a Grid
815 int     gridDuplicate(int gridID);
816 
817 //      gridDefProj: Define the projection ID of a Grid
818 void    gridDefProj(int gridID, int projID);
819 
820 //      gridInqProj: Get the projection ID of a Grid
821 int     gridInqProj(int gridID);
822 
823 //      gridInqProjType: Get the projection type
824 int     gridInqProjType(int gridID);
825 
826 //      gridInqType: Get the type of a Grid
827 int     gridInqType(int gridID);
828 
829 //      gridInqSize: Get the size of a Grid
830 size_t  gridInqSize(int gridID);
831 
832 //      gridDefXsize: Define the size of a X-axis
833 void    gridDefXsize(int gridID, size_t xsize);
834 
835 //      gridInqXsize: Get the size of a X-axis
836 size_t  gridInqXsize(int gridID);
837 
838 //      gridDefYsize: Define the size of a Y-axis
839 void    gridDefYsize(int gridID, size_t ysize);
840 
841 //      gridInqYsize: Get the size of a Y-axis
842 size_t  gridInqYsize(int gridID);
843 
844 //      gridDefNP: Define the number of parallels between a pole and the equator
845 void    gridDefNP(int gridID, int np);
846 
847 //      gridInqNP: Get the number of parallels between a pole and the equator
848 int     gridInqNP(int gridID);
849 
850 //      gridDefXvals: Define the values of a X-axis
851 void    gridDefXvals(int gridID, const double xvals[]);
852 
853 //      gridInqXvals: Get all values of a X-axis
854 size_t  gridInqXvals(int gridID, double xvals[]);
855 size_t  gridInqXvalsPart(int gridID, int start, size_t size, double xvals[]);
856 
857 //      gridInqXIsc: Find out whether X-coordinate is of type CHAR
858 int     gridInqXIsc(int gridID);
859 
860 //      gridInqXCvals: Get strings from X-axis in case grid is of type GRID_CHARXY
861 size_t  gridInqXCvals(int gridID, char *xcvals[]);
862 
863 //      gridDefYvals: Define the values of a Y-axis
864 void    gridDefYvals(int gridID, const double yvals[]);
865 
866 //      gridInqYvals: Get all values of a Y-axis
867 size_t  gridInqYvals(int gridID, double yvals[]);
868 size_t  gridInqYvalsPart(int gridID, int start, size_t size, double yvals[]);
869 
870 //      gridInqYIsc: Find out whether Y-coordinate is of type CHAR
871 int     gridInqYIsc(int gridID);
872 
873 //      gridInqYCvals: Get strings from Y-axis in case grid is of type GRID_CHARXY
874 size_t  gridInqYCvals(int gridID, char *ycvals[]);
875 
876 // CDI var keys
877 
878 // String keys
879 #define  CDI_KEY_NAME                          942  // Variable name
880 #define  CDI_KEY_LONGNAME                      943  // Long name of the variable
881 #define  CDI_KEY_STDNAME                       944  // CF Standard name of the variable
882 #define  CDI_KEY_UNITS                         945  // Units of the variable
883 #define  CDI_KEY_REFERENCEURI                  965  // Reference URI to grid file
884 
885 // Integer keys
886 #define  CDI_KEY_NUMBEROFGRIDUSED              963  // GRIB2 numberOfGridUsed
887 #define  CDI_KEY_NUMBEROFGRIDINREFERENCE       964  // GRIB2 numberOfGridInReference
888 #define  CDI_KEY_NUMBEROFVGRIDUSED             961  // GRIB2 numberOfVGridUsed
889 #define  CDI_KEY_NLEV                          962  // GRIB2 nlev
890 
891 // Floating point keys
892 #define  CDI_KEY_MISSVAL                       701  // Missing value
893 
894 // Byte array keys
895 #define  CDI_KEY_UUID                          960  // UUID for grid/Z-axis reference [size: CDI_UUID_SIZE]
896 
897 
898 #define  CDI_KEY_DIMNAME                       941  // Dimension name
899 
900 #define  CDI_KEY_PSNAME                        950  // Z-axis surface pressure name
901 #define  CDI_KEY_P0NAME                        951  // Z-axis reference pressure name
902 #define  CDI_KEY_P0VALUE                       952  // Z-axis reference pressure in Pa
903 
904 #define  CDI_KEY_TABLESVERSION                 801  // GRIB2 tablesVersion
905 #define  CDI_KEY_LOCALTABLESVERSION            802  // GRIB2 localTablesVersion
906 #define  CDI_KEY_TYPEOFGENERATINGPROCESS       803  // GRIB2 typeOfGeneratingProcess
907 #define  CDI_KEY_PRODUCTDEFINITIONTEMPLATE     804  // GRIB2 productDefinitionTemplate
908 #define  CDI_KEY_TYPEOFPROCESSEDDATA           805  // GRIB2 typeOfProcessedData
909 #define  CDI_KEY_SHAPEOFTHEEARTH               806  // GRIB2 shapeOfTheEarth
910 #define  CDI_KEY_BACKGROUNDPROCESS             807  // GRIB2 backgroundProcess
911 #define  CDI_KEY_TYPEOFENSEMBLEFORECAST        808  // GRIB2 typeOfEnsembleForecast
912 #define  CDI_KEY_NUMBEROFFORECASTSINENSEMBLE   809  // GRIB2 numberOfForecastsInEnsemble
913 #define  CDI_KEY_PERTURBATIONNUMBER            810  // GRIB2 perturbationNumber
914 #define  CDI_KEY_CENTRE                        811  // GRIB2 centre
915 #define  CDI_KEY_SUBCENTRE                     812  // GRIB2 subCentre
916 #define  CDI_KEY_MPIMTYPE                      813  // GRIB2 mpimType
917 #define  CDI_KEY_MPIMCLASS                     814  // GRIB2 mpimClass
918 #define  CDI_KEY_MPIMUSER                      815  // GRIB2 mpimUser
919 #define  CDI_KEY_REVSTATUS                     816  // GRIB2 revStatus
920 #define  CDI_KEY_REVNUMBER                     817  // GRIB2 revNumber
921 #define  CDI_KEY_GRIB2LOCALSECTIONNUMBER       818  // GRIB2 grib2LocalSectionNumber
922 #define  CDI_KEY_SECTION2PADDINGLENGTH         819  // GRIB2 length of section2Padding
923 #define  CDI_KEY_SECTION2PADDING               820  // GRIB2 section2Padding
924 #define  CDI_KEY_CONSTITUENTTYPE               821  // GRIB2 constituentType
925 #define  CDI_KEY_TYPEOFTIMEINCREMENT           822  // GRIB2 typeOfTimeIncrement
926 #define  CDI_KEY_TYPEOFFIRSTFIXEDSURFACE       823  // GRIB2 typeOfFirstFixedSurface
927 #define  CDI_KEY_TYPEOFSECONDFIXEDSURFACE      824  // GRIB2 typeOfSecondFixedSurface
928 #define  CDI_KEY_UVRELATIVETOGRID              825  // GRIB  uvRelativeToGrid
929 #define  CDI_KEY_SCANNINGMODE                  826  // GRIB  scanningMode
930 
931 #define  CDI_KEY_VDIMNAME                      920  // Vertex dimension name
932 #define  CDI_KEY_GRIDMAP_VARTYPE               921  // Grid mapping var datatype
933 #define  CDI_KEY_GRIDMAP_VARNAME               922  // Grid mapping var name
934 #define  CDI_KEY_GRIDMAP_NAME                  923  // Grid mapping name
935 
936 //      cdiDefKeyInt: Define an integer value from a key
937 int     cdiDefKeyInt(int cdiID, int varID, int key, int value);
938 
939 //      cdiInqKeyInt: Get an integer value from a key
940 int     cdiInqKeyInt(int cdiID, int varID, int key, int *value);
941 
942 //      cdiDefKeyFloat: Define a float value from a key
943 int     cdiDefKeyFloat(int cdiID, int varID, int key, double value);
944 
945 //      cdiInqKeyFloat Get a float value from a key
946 int     cdiInqKeyFloat(int cdiID, int varID, int key, double *value);
947 
948 //      cdiDefKeyBytes: Define a byte array from a key
949 int     cdiDefKeyBytes(int cdiID, int varID, int key, const unsigned char bytes[], int length);
950 
951 //      cdiInqKeyBytes: Get a byte array from a key
952 int     cdiInqKeyBytes(int cdiID, int varID, int key, unsigned char bytes[], int *length);
953 
954 //      cdiDefKeyString: Define a string from a key
955 int     cdiDefKeyString(int cdiID, int varID, int key, const char *string);
956 
957 //      cdiInqKeyString: Get a string from a key
958 int     cdiInqKeyString(int cdiID, int varID, int key, char *string, int *length);
959 
960 //      cdiInqKeyLen: Get the length of the string representation of the key
961 int     cdiInqKeyLen(int cdiID, int varID, int key, int *length);
962 
963 int     cdiCopyKeys(int cdiID1, int varID1, int cdiID2, int varID2);
964 
965 int     cdiCopyKey(int cdiID1, int varID1, int key, int cdiID2);
966 
967 int     cdiDeleteKey(int cdiID, int varID, int key);
968 
969 // GRID routines
970 
971 //      gridDefXname: Define the name of a X-axis
972 void    gridDefXname(int gridID, const char *xname);
973 
974 //      gridInqXname: Get the name of a X-axis
975 void    gridInqXname(int gridID, char *xname);
976 
977 //      gridDefXlongname: Define the longname of a X-axis
978 void    gridDefXlongname(int gridID, const char *xlongname);
979 
980 //      gridInqXlongname: Get the longname of a X-axis
981 void    gridInqXlongname(int gridID, char *xlongname);
982 
983 //      gridDefXunits: Define the units of a X-axis
984 void    gridDefXunits(int gridID, const char *xunits);
985 
986 //      gridInqXunits: Get the units of a X-axis
987 void    gridInqXunits(int gridID, char *xunits);
988 
989 //      gridDefYname: Define the name of a Y-axis
990 void    gridDefYname(int gridID, const char *yname);
991 
992 //      gridInqYname: Get the name of a Y-axis
993 void    gridInqYname(int gridID, char *yname);
994 
995 //      gridDefYlongname: Define the longname of a Y-axis
996 void    gridDefYlongname(int gridID, const char *ylongname);
997 
998 //      gridInqYlongname: Get the longname of a Y-axis
999 void    gridInqYlongname(int gridID, char *ylongname);
1000 
1001 //      gridDefYunits: Define the units of a Y-axis
1002 void    gridDefYunits(int gridID, const char *yunits);
1003 
1004 //      gridInqYunits: Get the units of a Y-axis
1005 void    gridInqYunits(int gridID, char *yunits);
1006 
1007 //      gridDefDatatype: Define the data type of a Grid
1008 void    gridDefDatatype(int gridID, int prec);
1009 
1010 //      gridInqDatatype: Get the data type of a Grid
1011 int     gridInqDatatype(int gridID);
1012 
1013 //      gridInqXval: Get one value of a X-axis
1014 double  gridInqXval(int gridID, size_t index);
1015 
1016 //      gridInqYval: Get one value of a Y-axis
1017 double  gridInqYval(int gridID, size_t index);
1018 
1019 double  gridInqXinc(int gridID);
1020 double  gridInqYinc(int gridID);
1021 
1022 int     gridIsCircular(int gridID);
1023 
1024 int     gridInqTrunc(int gridID);
1025 void    gridDefTrunc(int gridID, int trunc);
1026 
1027 // Reference of an unstructured grid
1028 
1029 //      gridDefNumber: Define the reference number for an unstructured grid
1030 void    gridDefNumber(int gridID, int number);
1031 
1032 //      gridInqNumber: Get the reference number to an unstructured grid
1033 int     gridInqNumber(int gridID);
1034 
1035 //      gridDefPosition: Define the position of grid in the reference file
1036 void    gridDefPosition(int gridID, int position);
1037 
1038 //      gridInqPosition: Get the position of grid in the reference file
1039 int     gridInqPosition(int gridID);
1040 
1041 //      gridDefReference: Define the reference URI for an unstructured grid
1042 void    gridDefReference(int gridID, const char *reference);
1043 
1044 //      gridInqReference: Get the reference URI to an unstructured grid
1045 int     gridInqReference(int gridID, char *reference);
1046 
1047 //      gridDefUUID: Define the UUID of an unstructured grid
1048 void    gridDefUUID(int gridID, const unsigned char uuid[CDI_UUID_SIZE]);
1049 
1050 //      gridInqUUID: Get the UUID of an unstructured grid
1051 void    gridInqUUID(int gridID, unsigned char uuid[CDI_UUID_SIZE]);
1052 
1053 // Rotated Lon/Lat grid
1054 void    gridDefParamRLL(int gridID, double xpole, double ypole, double angle);
1055 void    gridInqParamRLL(int gridID, double *xpole, double *ypole, double *angle);
1056 
1057 // Hexagonal GME grid
1058 void    gridDefParamGME(int gridID, int nd, int ni, int ni2, int ni3);
1059 void    gridInqParamGME(int gridID, int *nd, int *ni, int *ni2, int *ni3);
1060 
1061 // Lambert Conformal Conic grid
1062 void    gridDefParamLCC(int gridID, double missval, double lon_0, double lat_0, double lat_1, double lat_2, double a, double rf, double xval_0, double yval_0, double x_0, double y_0);
1063 int     gridInqParamLCC(int gridID, double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2, double *a, double *rf, double *xval_0, double *yval_0, double *x_0, double *y_0);
1064 
1065 // Polar stereographic grid
1066 void    gridDefParamSTERE(int gridID, double missval, double lon_0, double lat_ts, double lat_0, double a, double xval_0, double yval_0, double x_0, double y_0);
1067 int     gridInqParamSTERE(int gridID, double missval, double *lon_0, double *lat_ts, double *lat_0, double *a, double *xval_0, double *yval_0, double *x_0, double *y_0);
1068 
1069 void    gridDefArea(int gridID, const double area[]);
1070 void    gridInqArea(int gridID, double area[]);
1071 int     gridHasArea(int gridID);
1072 
1073 //      gridDefNvertex: Define the number of vertex of a Gridbox
1074 void    gridDefNvertex(int gridID, int nvertex);
1075 
1076 //      gridInqNvertex: Get the number of vertex of a Gridbox
1077 int     gridInqNvertex(int gridID);
1078 
1079 //      gridDefXbounds: Define the bounds of a X-axis
1080 void    gridDefXbounds(int gridID, const double xbounds[]);
1081 
1082 //      gridInqXbounds: Get the bounds of a X-axis
1083 size_t  gridInqXbounds(int gridID, double xbounds[]);
1084 size_t  gridInqXboundsPart(int gridID, int start, size_t size, double xbounds[]);
1085 
1086 //      gridDefYbounds: Define the bounds of a Y-axis
1087 void    gridDefYbounds(int gridID, const double ybounds[]);
1088 
1089 //      gridInqYbounds: Get the bounds of a Y-axis
1090 size_t  gridInqYbounds(int gridID, double ybounds[]);
1091 size_t  gridInqYboundsPart(int gridID, int start, size_t size, double ybounds[]);
1092 
1093 void    gridDefReducedPoints(int gridID, int reducedPointsSize, const int reducedPoints[]);
1094 void    gridInqReducedPoints(int gridID, int reducedPoints[]);
1095 void    gridChangeType(int gridID, int gridtype);
1096 
1097 void    gridDefComplexPacking(int gridID, int lpack);
1098 int     gridInqComplexPacking(int gridID);
1099 
1100 // ZAXIS routines
1101 
1102 void    zaxisName(int zaxistype, char *zaxisname);
1103 const char *zaxisNamePtr(int leveltype);
1104 
1105 //      zaxisCreate: Create a vertical Z-axis
1106 int     zaxisCreate(int zaxistype, int size);
1107 
1108 //      zaxisDestroy: Destroy a vertical Z-axis
1109 void    zaxisDestroy(int zaxisID);
1110 
1111 //      zaxisInqType: Get the type of a Z-axis
1112 int     zaxisInqType(int zaxisID);
1113 
1114 //      zaxisInqSize: Get the size of a Z-axis
1115 int     zaxisInqSize(int zaxisID);
1116 
1117 //      zaxisDuplicate: Duplicate a Z-axis
1118 int     zaxisDuplicate(int zaxisID);
1119 
1120 //      zaxisDefLevels: Define the levels of a Z-axis
1121 void    zaxisDefLevels(int zaxisID, const double levels[]);
1122 
1123 //      zaxisDefCvals: Define area types of a Z-axis
1124 void    zaxisDefCvals(int zaxisID, const char *cvals[], int clength);
1125 
1126 //      zaxisInqLevels: Get all levels of a Z-axis
1127 int     zaxisInqLevels(int zaxisID, double levels[]);
1128 
1129 //      zaxisInqCLen: Get maximal string length of character Z-axis
1130 int     zaxisInqCLen(int zaxisID);
1131 
1132 //      zaxisInqCVals: Get all string values of a character Z-axis
1133 int     zaxisInqCVals(int zaxisID, char ***clevels);
1134 
1135 //      zaxisDefLevel: Define one level of a Z-axis
1136 void    zaxisDefLevel(int zaxisID, int levelID, double levels);
1137 
1138 //      zaxisInqLevel: Get one level of a Z-axis
1139 double  zaxisInqLevel(int zaxisID, int levelID);
1140 
1141 //      zaxisDefNlevRef: Define the number of half levels of a generalized Z-axis
1142 void    zaxisDefNlevRef(int gridID, int nhlev);
1143 
1144 //      zaxisInqNlevRef: Get the number of half levels of a generalized Z-axis
1145 int     zaxisInqNlevRef(int gridID);
1146 
1147 //      zaxisDefNumber: Define the reference number for a generalized Z-axis
1148 void    zaxisDefNumber(int gridID, int number);
1149 
1150 //      zaxisInqNumber: Get the reference number to a generalized Z-axis
1151 int     zaxisInqNumber(int gridID);
1152 
1153 //      zaxisDefUUID: Define the UUID of a generalized Z-axis
1154 void    zaxisDefUUID(int zaxisID, const unsigned char uuid[CDI_UUID_SIZE]);
1155 
1156 //      zaxisInqUUID: Get the UUID of a generalized Z-axis
1157 void    zaxisInqUUID(int zaxisID, unsigned char uuid[CDI_UUID_SIZE]);
1158 
1159 //      zaxisDefName: Define the name of a Z-axis
1160 void    zaxisDefName(int zaxisID, const char *name_optional);
1161 
1162 //      zaxisInqName: Get the name of a Z-axis
1163 void    zaxisInqName(int zaxisID, char *name);
1164 
1165 //      zaxisDefLongname: Define the longname of a Z-axis
1166 void    zaxisDefLongname(int zaxisID, const char *longname_optional);
1167 
1168 //      zaxisInqLongname: Get the longname of a Z-axis
1169 void    zaxisInqLongname(int zaxisID, char *longname);
1170 
1171 //      zaxisDefUnits: Define the units of a Z-axis
1172 void    zaxisDefUnits(int zaxisID, const char *units_optional);
1173 
1174 //      zaxisInqUnits: Get the units of a Z-axis
1175 void    zaxisInqUnits(int zaxisID, char *units);
1176 
1177 //      zaxisInqStdname: Get the standard name of a Z-axis
1178 void    zaxisInqStdname(int zaxisID, char *stdname);
1179 
1180 void    zaxisDefDatatype(int zaxisID, int prec);
1181 int     zaxisInqDatatype(int zaxisID);
1182 
1183 void    zaxisDefPositive(int zaxisID, int positive);
1184 int     zaxisInqPositive(int zaxisID);
1185 
1186 void    zaxisDefScalar(int zaxisID);
1187 int     zaxisInqScalar(int zaxisID);
1188 
1189 void    zaxisDefVct(int zaxisID, int size, const double vct[]);
1190 void    zaxisInqVct(int zaxisID, double vct[]);
1191 int     zaxisInqVctSize(int zaxisID);
1192 const double *zaxisInqVctPtr(int zaxisID);
1193 void    zaxisDefLbounds(int zaxisID, const double lbounds[]);
1194 int     zaxisInqLbounds(int zaxisID, double lbounds_optional[]);
1195 double  zaxisInqLbound(int zaxisID, int index);
1196 void    zaxisDefUbounds(int zaxisID, const double ubounds[]);
1197 int     zaxisInqUbounds(int zaxisID, double ubounds_optional[]);
1198 double  zaxisInqUbound(int zaxisID, int index);
1199 void    zaxisDefWeights(int zaxisID, const double weights[]);
1200 int     zaxisInqWeights(int zaxisID, double weights_optional[]);
1201 void    zaxisChangeType(int zaxisID, int zaxistype);
1202 
1203 // TAXIS routines
1204 
1205 //      taxisCreate: Create a Time axis
1206 int     taxisCreate(int taxistype);
1207 
1208 //      taxisDestroy: Destroy a Time axis
1209 void    taxisDestroy(int taxisID);
1210 
1211 int     taxisDuplicate(int taxisID);
1212 
1213 void    taxisCopyTimestep(int taxisIDdes, int taxisIDsrc);
1214 
1215 void    taxisDefType(int taxisID, int taxistype);
1216 int     taxisInqType(int taxisID);
1217 
1218 //      taxisDefVdate: Define the verification date
1219 void    taxisDefVdate(int taxisID, int64_t date);
1220 
1221 //      taxisDefVtime: Define the verification time
1222 void    taxisDefVtime(int taxisID, int time);
1223 
1224 //      taxisInqVdate: Get the verification date
1225 int64_t taxisInqVdate(int taxisID);
1226 
1227 //      taxisInqVtime: Get the verification time
1228 int     taxisInqVtime(int taxisID);
1229 
1230 //      taxisDefRdate: Define the reference date
1231 void    taxisDefRdate(int taxisID, int64_t date);
1232 
1233 //      taxisDefRtime: Define the reference time
1234 void    taxisDefRtime(int taxisID, int time);
1235 
1236 //      taxisInqRdate: Get the reference date
1237 int64_t taxisInqRdate(int taxisID);
1238 
1239 //      taxisInqRtime: Get the reference time
1240 int     taxisInqRtime(int taxisID);
1241 
1242 //      taxisDefFdate: Define the forecast reference date
1243 void    taxisDefFdate(int taxisID, int64_t date);
1244 
1245 //      taxisDefFtime: Define the forecast reference time
1246 void    taxisDefFtime(int taxisID, int time);
1247 
1248 //      taxisInqFdate: Get the forecast reference date
1249 int64_t taxisInqFdate(int taxisID);
1250 
1251 //      taxisInqFtime: Get the forecast reference time
1252 int     taxisInqFtime(int taxisID);
1253 
1254 int     taxisHasBounds(int taxisID);
1255 void    taxisWithBounds(int taxisID);
1256 
1257 void    taxisDeleteBounds(int taxisID);
1258 
1259 void    taxisDefVdateBounds(int taxisID, int64_t vdate_lb, int64_t vdate_ub);
1260 
1261 void    taxisDefVtimeBounds(int taxisID, int vtime_lb, int vtime_ub);
1262 
1263 void    taxisInqVdateBounds(int taxisID, int64_t *vdate_lb, int64_t *vdate_ub);
1264 
1265 void    taxisInqVtimeBounds(int taxisID, int *vtime_lb, int *vtime_ub);
1266 
1267 //      taxisDefCalendar: Define the calendar
1268 void    taxisDefCalendar(int taxisID, int calendar);
1269 
1270 //      taxisInqCalendar: Get the calendar
1271 int     taxisInqCalendar(int taxisID);
1272 
1273 void    taxisDefTunit(int taxisID, int tunit);
1274 int     taxisInqTunit(int taxisID);
1275 
1276 void    taxisDefForecastTunit(int taxisID, int tunit);
1277 int     taxisInqForecastTunit(int taxisID);
1278 
1279 void    taxisDefForecastPeriod(int taxisID, double fc_period);
1280 double  taxisInqForecastPeriod(int taxisID);
1281 
1282 void    taxisDefNumavg(int taxisID, int numavg);
1283 int     taxisInqNumavg(int taxisID);
1284 
1285 const char *tunitNamePtr(int tunitID);
1286 
1287 
1288 // Institut routines
1289 
1290 int     institutDef(int center, int subcenter, const char *name, const char *longname);
1291 int     institutInq(int center, int subcenter, const char *name, const char *longname);
1292 int     institutInqNumber(void);
1293 int     institutInqCenter(int instID);
1294 int     institutInqSubcenter(int instID);
1295 const char *institutInqNamePtr(int instID);
1296 const char *institutInqLongnamePtr(int instID);
1297 
1298 // Model routines
1299 
1300 int     modelDef(int instID, int modelgribID, const char *name);
1301 int     modelInq(int instID, int modelgribID, const char *name);
1302 int     modelInqInstitut(int modelID) ;
1303 int     modelInqGribID(int modelID);
1304 const char *modelInqNamePtr(int modelID);
1305 
1306 // Table routines
1307 
1308 //      tableFWriteC: write table of parameters to FILE* in C language format
1309 void    tableFWriteC(FILE *ptfp, int tableID);
1310 //      tableWrite: write table of parameters to file in tabular format
1311 void    tableWrite(const char *filename, int tableID);
1312 //      tableRead: read table of parameters from file in tabular format
1313 int     tableRead(const char *tablefile);
1314 int     tableDef(int modelID, int tablenum, const char *tablename);
1315 
1316 const char *tableInqNamePtr(int tableID);
1317 
1318 int     tableInq(int modelID, int tablenum, const char *tablename);
1319 int     tableInqNumber(void);
1320 
1321 int     tableInqNum(int tableID);
1322 int     tableInqModel(int tableID);
1323 
1324 void    tableInqEntry(int tableID, int id, int ltype, char *name, char *longname, char *units);
1325 
1326 // Subtype routines
1327 
1328 //      subtypeCreate: Create a variable subtype
1329 int     subtypeCreate(int subtype);
1330 
1331 //      Gives a textual summary of the variable subtype
1332 void    subtypePrint(int subtypeID);
1333 
1334 // Compares two subtype data structures
1335 int     subtypeCompare(int subtypeID1, int subtypeID2);
1336 
1337 //      subtypeInqSize: Get the size of a subtype (e.g. no. of tiles)
1338 int     subtypeInqSize(int subtypeID);
1339 
1340 //      subtypeInqActiveIndex: Get the currently active index of a subtype (e.g. current tile index)
1341 int     subtypeInqActiveIndex(int subtypeID);
1342 
1343 //      subtypeDefActiveIndex: Set the currently active index of a subtype (e.g. current tile index)
1344 void    subtypeDefActiveIndex(int subtypeID, int index);
1345 
1346 //      Generate a "query object" out of a key-value pair
1347 subtype_query_t keyValuePair(const char *key, int value);
1348 
1349 //       Generate an AND-combined "query object" out of two previous query objects
1350 subtype_query_t matchAND(subtype_query_t q1, subtype_query_t q2);
1351 
1352 //      subtypeInqSubEntry: Returns subtype entry ID for a given criterion
1353 int     subtypeInqSubEntry(int subtypeID, subtype_query_t criterion);
1354 
1355 //      subtypeInqTile: Specialized version of subtypeInqSubEntry looking for tile/attribute pair
1356 int     subtypeInqTile(int subtypeID, int tileindex, int attribute);
1357 
1358 //      subtypeInqAttribute: Inquire the value of a subtype attribute. Returns CDI_EINVAL if the attribute does not exist.
1359 int     subtypeInqAttribute(int subtypeID, int index, const char *key, int *outValue);
1360 
1361 //      vlistInqVarSubtype: Return subtype ID for a given variable
1362 int     vlistInqVarSubtype(int vlistID, int varID);
1363 
1364 void gribapiLibraryVersion(int *major_version, int *minor_version, int *revision_version);
1365 
1366 #ifdef __cplusplus
1367 }
1368 #endif
1369 
1370 //FINT_OFF  <--- don't change or remove this line!!!
1371 
1372 #ifdef __cplusplus
1373 extern "C" {
1374 #endif
1375 
1376 void gaussianLatitudes(double *latitudes, double *weights, size_t nlat);
1377 
1378 #define HAVE_CDI_PROJ_FUNCS 1
1379 extern int (*proj_lonlat_to_lcc_func)(double, double, double, double, double, double, double, size_t, double*, double*);
1380 extern int (*proj_lcc_to_lonlat_func)(double, double, double, double, double, double, double, double, double, size_t, double*, double*);
1381 extern int (*proj_lonlat_to_stere_func)(double, double, double, double, double, size_t, double*, double*);
1382 extern int (*proj_stere_to_lonlat_func)(double, double, double, double, double, double, double, size_t, double*, double*);
1383 
1384 #ifdef __cplusplus
1385 }
1386 #endif
1387 
1388 #endif  /* CDI_H_ */
1389 /*
1390  * Local Variables:
1391  * c-file-style: "Java"
1392  * c-basic-offset: 2
1393  * indent-tabs-mode: nil
1394  * show-trailing-whitespace: t
1395  * require-trailing-newline: t
1396  * End:
1397  */
1398 #ifndef ERROR_H
1399 #define ERROR_H
1400 
1401 #include <stdarg.h>
1402 #include <stdlib.h>
1403 
1404 #ifndef  WITH_CALLER_NAME
1405 #define  WITH_CALLER_NAME
1406 #endif
1407 
1408 #ifdef __cplusplus
1409 extern "C" {
1410 #endif
1411 
1412 extern int _ExitOnError;  /* If set to 1, exit on error (default 1)       */
1413 extern int _Verbose;      /* If set to 1, errors are reported (default 1) */
1414 extern int _Debug;        /* If set to 1, debuggig (default 0)            */
1415 
1416 void SysError_(const char *caller, const char *fmt, ...);
1417 void    Error_(const char *caller, const char *fmt, ...);
1418 void  Warning_(const char *caller, const char *fmt, ...);
1419 /* delegate used by Warning_ unless mode is PIO */
1420 void cdiWarning(const char *caller, const char *fmt, va_list ap);
1421 void  Message_(const char *caller, const char *fmt, ...);
1422 
1423 #if  defined  WITH_CALLER_NAME
1424 #  define  SysError(...)  SysError_(__func__, __VA_ARGS__)
1425 #  define    Errorc(...)     Error_(  caller, __VA_ARGS__)
1426 #  define     Error(...)     Error_(__func__, __VA_ARGS__)
1427 #  define   Warning(...)   Warning_(__func__, __VA_ARGS__)
1428 #  define  Messagec(...)   Message_(  caller, __VA_ARGS__)
1429 #  define   Message(...)   Message_(__func__, __VA_ARGS__)
1430 #else
1431 #  define  SysError(...)  SysError_((void *), __VA_ARGS__)
1432 #  define    Errorc(...)     Error_((void *), __VA_ARGS__)
1433 #  define     Error(...)     Error_((void *), __VA_ARGS__)
1434 #  define   Warning(...)   Warning_((void *), __VA_ARGS__)
1435 #  define  Messagec(...)   Message_((void *), __VA_ARGS__)
1436 #  define   Message(...)   Message_((void *), __VA_ARGS__)
1437 #endif
1438 
1439 /* If we're not using GNU C, elide __attribute__ */
1440 #ifndef __GNUC__
1441 #  define  __attribute__(x)  /*NOTHING*/
1442 #endif
1443 
1444 void cdiAbortC(const char *caller, const char *filename,
1445                const char *functionname, int line,
1446                const char *errorString, ... )
1447   __attribute__((noreturn));
1448 #define xabortC(caller, ...)                                    \
1449   cdiAbortC(caller, __FILE__, __func__, __LINE__, __VA_ARGS__ )
1450 #define xabort(...)                                             \
1451   cdiAbortC(NULL, __FILE__, __func__, __LINE__, __VA_ARGS__ )
1452 #define cdiAbort(file, func, line, ...)                 \
1453   cdiAbortC(NULL, (file), (func), (line), __VA_ARGS__)
1454 
1455 #define xassert(arg) do {                       \
1456     if ((arg)) { } else {                       \
1457       xabort("assertion `" #arg "` failed");}   \
1458   } while(0)
1459 
1460 void
1461 cdiAbortC_serial(const char *caller, const char *filename,
1462                  const char *functionname, int line,
1463                  const char *errorString, va_list ap)
1464   __attribute__((noreturn));
1465 
1466 #if defined (__cplusplus)
1467 }
1468 #endif
1469 
1470 #endif  /* ERROR_H */
1471 /*
1472  * Local Variables:
1473  * c-file-style: "Java"
1474  * c-basic-offset: 2
1475  * indent-tabs-mode: nil
1476  * show-trailing-whitespace: t
1477  * require-trailing-newline: t
1478  * End:
1479  */
1480 #ifdef HAVE_CONFIG_H
1481 #endif
1482 
1483 #ifdef HAVE_LIBPTHREAD
1484 #include <pthread.h>
1485 #endif
1486 
1487 
1488 
1489 #include <stdbool.h>
1490 
1491 #ifdef HAVE_LIBPTHREAD
1492 #ifdef __APPLE__
1493 #include <dispatch/dispatch.h>
1494 #else
1495 #include <errno.h>
1496 #include <semaphore.h>
1497 #endif
1498 
1499 typedef struct sema {
1500 #ifdef __APPLE__
1501   dispatch_semaphore_t    sem;
1502 #else
1503   sem_t                   sem;
1504 #endif
1505 } sema_t;
1506 #endif
1507 
1508 struct AsyncJob {
1509   bool inUse;
1510 #ifdef HAVE_LIBPTHREAD
1511   sema_t request, completion;
1512 #endif
1513   int (*work)(void *data);
1514   void *data;
1515   int result;
1516 };
1517 
1518 struct AsyncManager {
1519   int workerCount, idleWorkerCount;
1520   AsyncJob *communicators;
1521 };
1522 
1523 #ifdef HAVE_LIBPTHREAD
1524 static inline int
sema_init(sema_t * s,int pshared,uint32_t value)1525 sema_init(sema_t *s, int pshared, uint32_t value)
1526 {
1527   int status = 0;
1528 #ifdef __APPLE__
1529   dispatch_semaphore_t *sem = &s->sem;
1530 
1531   (void)pshared;
1532   *sem = dispatch_semaphore_create(value);
1533 #else
1534   status = sem_init(&s->sem, pshared, value);
1535 #endif
1536   return status;
1537 }
1538 
1539 static inline int
sema_wait(sema_t * s)1540 sema_wait(sema_t *s)
1541 {
1542 #ifdef __APPLE__
1543   dispatch_semaphore_wait(s->sem, DISPATCH_TIME_FOREVER);
1544 #else
1545   int r;
1546 
1547   do {
1548     r = sem_wait(&s->sem);
1549   } while (r == -1 && errno == EINTR);
1550 #endif
1551   return 0;
1552 }
1553 
1554 static inline int
sema_post(sema_t * s)1555 sema_post(sema_t *s)
1556 {
1557 #ifdef __APPLE__
1558   dispatch_semaphore_signal(s->sem);
1559 #else
1560   sem_post(&s->sem);
1561 #endif
1562   return 0;
1563 }
1564 
1565 static
workerMain(void * arg)1566 void *workerMain(void *arg)
1567 {
1568   AsyncJob *communicator = arg;
1569 
1570   while (true)
1571     {
1572       while (sema_wait(&communicator->request)) ;
1573       if (communicator->work)
1574         {
1575           communicator->result = communicator->work(communicator->data);
1576           if (sema_post(&communicator->completion)) xabort("sema_post() failed");
1577         }
1578       else
1579         {
1580           if (sema_post(&communicator->completion)) xabort("sema_post() failed");
1581           break;
1582         }
1583     }
1584 
1585   return NULL;
1586 }
1587 
1588 static
startWorker(AsyncJob * communicator)1589 void startWorker(AsyncJob *communicator)
1590 {
1591   communicator->inUse = false;
1592   communicator->work = NULL;
1593   communicator->data = NULL;
1594   communicator->result = 0;
1595   if (sema_init(&communicator->request, 0, 0)) xabort("sema_init() failed");
1596   if (sema_init(&communicator->completion, 0, 0)) xabort("sema_init() failed");
1597 
1598   pthread_t worker;
1599   if (pthread_create(&worker, NULL, workerMain, communicator)) xabort("pthread_create() failed");
1600   if (pthread_detach(worker)) xabort("pthread_detach() failed");
1601 }
1602 #endif
1603 
AsyncWorker_init(AsyncManager ** jobManager,int threadCount)1604 int AsyncWorker_init(AsyncManager **jobManager, int threadCount)
1605 {
1606   if (threadCount <= 0)
1607     {
1608       xabort("CPU core count discovery not implemented yet");
1609       return CDI_EINVAL;  // TODO: discover CPU core count, and set threadCount to a sensible positive value
1610     }
1611 
1612   if (*jobManager) return CDI_NOERR;
1613 
1614 #ifdef HAVE_LIBPTHREAD
1615   *jobManager = malloc(sizeof(AsyncManager));
1616   if(!*jobManager) return CDI_ESYSTEM;
1617   (*jobManager)->workerCount = threadCount;
1618   (*jobManager)->communicators = malloc(threadCount*sizeof(AsyncJob));
1619   if (!(*jobManager)->communicators) xabort("memory allocation failure");
1620 
1621   for (int i = 0; i < threadCount; i++) startWorker(&((*jobManager)->communicators[i]));
1622   (*jobManager)->idleWorkerCount = threadCount;
1623 #else
1624 
1625   Error("pthread support not compiled in!");
1626 #endif
1627 
1628   return CDI_NOERR;
1629 }
1630 
AsyncWorker_requestWork(AsyncManager * jobManager,int (* work)(void * data),void * data)1631 AsyncJob *AsyncWorker_requestWork(AsyncManager *jobManager, int (*work)(void *data), void *data)
1632 {
1633   if (!jobManager) xabort("AsyncWorker_requestWork() called without calling AsyncWorker_init() first");
1634   if (!work) xabort("AsyncWorker_requestWork() called without a valid function pointer");	//need to catch this condition to stop users from terminating our worker threads
1635 
1636   // find an unused worker
1637   if(!jobManager->idleWorkerCount) return NULL;
1638 
1639   AsyncJob *worker = NULL;
1640   for (int i = 0; i < jobManager->workerCount; i++)
1641     {
1642       if (!jobManager->communicators[i].inUse)
1643         {
1644           worker = &jobManager->communicators[i];
1645           break;
1646         }
1647     }
1648   if (!worker) xabort("internal error: idleWorkerCount is not in sync with the worker states, please report this bug");
1649 
1650   // pass the request to that worker
1651   jobManager->idleWorkerCount--;
1652   worker->inUse = true;
1653   worker->work = work;
1654   worker->data = data;
1655   worker->result = 0;
1656 #ifdef HAVE_LIBPTHREAD
1657   if (sema_post(&worker->request)) xabort("sema_post() failed");
1658 #endif
1659   return worker;
1660 }
1661 
AsyncWorker_wait(AsyncManager * jobManager,AsyncJob * job)1662 int AsyncWorker_wait(AsyncManager *jobManager, AsyncJob *job)
1663 {
1664   if (!jobManager) xabort("AsyncWorker_wait() called without calling AsyncWorker_init() first");
1665   if (job < jobManager->communicators) return CDI_EINVAL;
1666   if (job >= jobManager->communicators + jobManager->workerCount) return CDI_EINVAL;
1667   if (!job->inUse) return CDI_EINVAL;
1668 
1669 #ifdef HAVE_LIBPTHREAD
1670   while (sema_wait(&job->completion)) ;
1671 #endif
1672   int result = job->result;
1673 
1674   // reset the communicator
1675   job->work = NULL;
1676   job->data = NULL;
1677   job->result = 0;
1678   job->inUse = false;
1679   jobManager->idleWorkerCount++;
1680 
1681   return result;
1682 }
1683 
AsyncWorker_availableWorkers(AsyncManager * jobManager)1684 int AsyncWorker_availableWorkers(AsyncManager *jobManager)
1685 {
1686   if (!jobManager) return 0;
1687   return jobManager->idleWorkerCount;
1688 }
1689 
AsyncWorker_finalize(AsyncManager * jobManager)1690 int AsyncWorker_finalize(AsyncManager *jobManager)
1691 {
1692   int result = CDI_NOERR;
1693   if (!jobManager) return CDI_NOERR;
1694 
1695   for (int i = 0; i < jobManager->workerCount; i++)
1696     {
1697       AsyncJob *curWorker = &jobManager->communicators[i];
1698 
1699       // finish any pending job
1700       if (curWorker->inUse)
1701         {
1702           AsyncWorker_wait(jobManager, curWorker);
1703           if (curWorker->result) result = curWorker->result;
1704         }
1705 
1706       // send the teardown signal
1707       curWorker->inUse = true;
1708       curWorker->work = NULL;
1709       curWorker->data = NULL;
1710       curWorker->result = 0;
1711 #ifdef HAVE_LIBPTHREAD
1712       if (sema_post(&curWorker->request)) xabort("sema_post() failed");
1713 #endif
1714       // wait for the worker to exit
1715       AsyncWorker_wait(jobManager, curWorker);
1716     }
1717 
1718   free(jobManager->communicators);
1719   free(jobManager);
1720 
1721   return result;
1722 }
1723 #ifndef _BASETIME_H
1724 #define _BASETIME_H
1725 
1726 #include <stdbool.h>
1727 
1728 //#define USE_TIMECACHE 1
1729 #define MAX_TIMECACHE_SIZE 1024*1024
1730 
1731 typedef struct {
1732   size_t size;
1733   size_t startid;
1734   size_t maxvals;
1735   double cache[MAX_TIMECACHE_SIZE];
1736 }
1737 timecache_t;
1738 
1739 typedef struct {
1740   int   ncvarid;
1741   int   ncdimid;
1742   int   ncvarboundsid;
1743   int   leadtimeid;
1744   bool  lunits;
1745   bool  lwrf;     // true for time axis in WRF format
1746   timecache_t *timevar_cache;
1747 }
1748 basetime_t;
1749 
1750 void basetimeInit(basetime_t *basetime);
1751 
1752 #endif  /* _BASETIME_H */
1753 /*
1754  * Local Variables:
1755  * c-file-style: "Java"
1756  * c-basic-offset: 2
1757  * indent-tabs-mode: nil
1758  * show-trailing-whitespace: t
1759  * require-trailing-newline: t
1760  * End:
1761  */
1762 #include <stddef.h>  // for NULL
1763 
1764 
basetimeInit(basetime_t * basetime)1765 void basetimeInit(basetime_t *basetime)
1766 {
1767   if (basetime == NULL) Error("Internal problem! Basetime not allocated.");
1768 
1769   if (basetime)
1770     {
1771       basetime->ncvarid       = CDI_UNDEFID;
1772       basetime->ncdimid       = CDI_UNDEFID;
1773       basetime->ncvarboundsid = CDI_UNDEFID;
1774       basetime->leadtimeid    = CDI_UNDEFID;
1775       basetime->lunits        = false;
1776       basetime->lwrf          = false;
1777       basetime->timevar_cache = NULL;
1778     }
1779 }
1780 
1781 /*
1782  * Local Variables:
1783  * c-file-style: "Java"
1784  * c-basic-offset: 2
1785  * indent-tabs-mode: nil
1786  * show-trailing-whitespace: t
1787  * require-trailing-newline: t
1788  * End:
1789  */
1790 #ifndef _FILE_H
1791 #define _FILE_H
1792 
1793 #include <stdio.h>
1794 #include <sys/types.h>
1795 
1796 #define  FILE_UNDEFID      -1
1797 
1798 #define  FILE_TYPE_OPEN     1
1799 #define  FILE_TYPE_FOPEN    2
1800 
1801 // buffer types for FILE_TYPE_OPEN
1802 #define  FILE_BUFTYPE_STD   1
1803 #define  FILE_BUFTYPE_MMAP  2
1804 
1805 const
1806 char  *fileLibraryVersion(void);
1807 
1808 void   fileDebug(int debug);
1809 
1810 void  *filePtr(int fileID);
1811 
1812 int    fileSetBufferType(int fileID, int type);
1813 void   fileSetBufferSize(int fileID, long buffersize);
1814 
1815 int    fileOpen(const char *filename, const char *mode);
1816 int    fileOpen_serial(const char *filename, const char *mode);
1817 int    fileClose(int fileID);
1818 int    fileClose_serial(int fileID);
1819 
1820 char  *fileInqName(int fileID);
1821 int    fileInqMode(int fileID);
1822 
1823 int    fileFlush(int fileID);
1824 void   fileClearerr(int fileID);
1825 int    fileEOF(int fileID);
1826 int    filePtrEOF(void *fileptr);
1827 void   fileRewind(int fileID);
1828 
1829 off_t  fileGetPos(int fileID);
1830 int    fileSetPos(int fileID, off_t offset, int whence);
1831 
1832 int    fileGetc(int fileID);
1833 int    filePtrGetc(void *fileptr);
1834 
1835 size_t filePtrRead(void *fileptr, void *restrict ptr, size_t size);
1836 size_t fileRead(int fileID, void *restrict ptr, size_t size);
1837 size_t fileWrite(int fileID, const void *restrict ptr, size_t size);
1838 
1839 #endif  /* _FILE_H */
1840 /*
1841  * Local Variables:
1842  * c-file-style: "Java"
1843  * c-basic-offset: 2
1844  * indent-tabs-mode: nil
1845  * show-trailing-whitespace: t
1846  * require-trailing-newline: t
1847  * End:
1848  */
1849 #ifndef  SWAP_H_
1850 #define  SWAP_H_
1851 
1852 void swap4byte(void *ptr, size_t size);
1853 void swap8byte(void *ptr, size_t size);
1854 
1855 #endif
1856 
1857 /*
1858  * Local Variables:
1859  * c-file-style: "Java"
1860  * c-basic-offset: 2
1861  * indent-tabs-mode: nil
1862  * show-trailing-whitespace: t
1863  * require-trailing-newline: t
1864  * End:
1865  */
1866 #ifndef  DTYPES_H
1867 #define  DTYPES_H
1868 
1869 #include <stdio.h>
1870 #include <limits.h>
1871 
1872 /* INT32 */
1873 
1874 #ifndef  INT_MAX
1875 #error INT_MAX undefined
1876 #endif
1877 
1878 #undef  INT32
1879 #if  INT_MAX == 2147483647L
1880 #  define  INT32  int
1881 #elif LONG_MAX == 2147483647L
1882 #  define  INT32  long
1883 #endif
1884 
1885 /* INT64 */
1886 
1887 #ifndef  LONG_MAX
1888 #  error LONG_MAX undefined
1889 #endif
1890 
1891 #undef  INT64
1892 #if  LONG_MAX > 2147483647L
1893 #  define  INT64  long
1894 #else
1895 #  define  INT64  long long
1896 #endif
1897 
1898 /* FLT32 */
1899 
1900 #undef   FLT32
1901 #define  FLT32  float
1902 
1903 /* FLT64 */
1904 
1905 #undef   FLT64
1906 #define  FLT64  double
1907 
1908 /* UINT32 and UINT64 */
1909 
1910 #define  UINT32   unsigned INT32
1911 #define  UINT64   unsigned INT64
1912 
1913 #endif  /* DTYPES_H */
1914 /*
1915  * Local Variables:
1916  * c-file-style: "Java"
1917  * c-basic-offset: 2
1918  * indent-tabs-mode: nil
1919  * show-trailing-whitespace: t
1920  * require-trailing-newline: t
1921  * End:
1922  */
1923 #ifndef BINARY_H
1924 #define BINARY_H
1925 
1926 #ifdef HAVE_CONFIG_H
1927 #endif
1928 
1929 #include <inttypes.h>
1930 
1931 
1932 #ifndef HOST_ENDIANNESS
1933 #ifdef __cplusplus
1934 static const uint32_t HOST_ENDIANNESS_temp[1] = { UINT32_C(0x00030201) };
1935 #define HOST_ENDIANNESS (((const unsigned char *)HOST_ENDIANNESS_temp)[0])
1936 #else
1937 #define HOST_ENDIANNESS (((const unsigned char *)&(const uint32_t[1]){UINT32_C(0x00030201)})[0])
1938 #endif
1939 #endif
1940 
1941 
1942 UINT32 get_UINT32(unsigned char *x);
1943 UINT32 get_SUINT32(unsigned char *x);
1944 UINT64 get_UINT64(unsigned char *x);
1945 UINT64 get_SUINT64(unsigned char *x);
1946 
1947 
1948 size_t binReadF77Block(int fileID, int byteswap);
1949 void   binWriteF77Block(int fileID, int byteswap, size_t blocksize);
1950 
1951 int binReadInt32(int fileID, int byteswap, size_t size, INT32 *ptr);
1952 int binReadInt64(int fileID, int byteswap, size_t size, INT64 *ptr);
1953 
1954 int binWriteInt32(int fileID, int byteswap, size_t size, INT32 *ptr);
1955 int binWriteInt64(int fileID, int byteswap, size_t size, INT64 *ptr);
1956 
1957 int binWriteFlt32(int fileID, int byteswap, size_t size, FLT32 *ptr);
1958 int binWriteFlt64(int fileID, int byteswap, size_t size, FLT64 *ptr);
1959 
1960 #endif  /* BINARY_H */
1961 /*
1962  * Local Variables:
1963  * c-file-style: "Java"
1964  * c-basic-offset: 2
1965  * indent-tabs-mode: nil
1966  * show-trailing-whitespace: t
1967  * require-trailing-newline: t
1968  * End:
1969  */
1970 
1971 
get_UINT32(unsigned char * x)1972 UINT32 get_UINT32(unsigned char *x)
1973 {
1974   switch (HOST_ENDIANNESS)
1975     {
1976     case CDI_BIGENDIAN:
1977       return (((UINT32)x[0])<<24) + (((UINT32)x[1])<<16) + (((UINT32)x[2])<< 8) + (UINT32)x[3];
1978     case CDI_LITTLEENDIAN:
1979       return (((UINT32)x[3])<<24) + (((UINT32)x[2])<<16) + (((UINT32)x[1])<< 8) + (UINT32)x[0];
1980     default:
1981       Error("Unhandled endianness %d", HOST_ENDIANNESS);
1982       return UINT32_C(0xFFFFFFFF);
1983     }
1984 }
1985 
1986 
get_SUINT32(unsigned char * x)1987 UINT32 get_SUINT32(unsigned char *x)
1988 {
1989   switch (HOST_ENDIANNESS)
1990     {
1991     case CDI_BIGENDIAN:
1992       return (((UINT32)x[3])<<24) + (((UINT32)x[2])<<16) + (((UINT32)x[1])<< 8) + (UINT32)x[0];
1993     case CDI_LITTLEENDIAN:
1994       return (((UINT32)x[0])<<24) + (((UINT32)x[1])<<16) + (((UINT32)x[2])<< 8) + (UINT32)x[3];
1995     default:
1996       Error("Unhandled endianness %d", HOST_ENDIANNESS);
1997       return UINT32_C(0xFFFFFFFF);
1998     }
1999 }
2000 
2001 
get_UINT64(unsigned char * x)2002 UINT64 get_UINT64(unsigned char *x)
2003 {
2004   switch (HOST_ENDIANNESS)
2005     {
2006     case CDI_BIGENDIAN:
2007       return (((UINT64)x[0])<<56) + (((UINT64)x[1])<<48) + (((UINT64)x[2])<<40) + (((UINT64)x[3])<<32) +
2008              (((UINT64)x[4])<<24) + (((UINT64)x[5])<<16) + (((UINT64)x[6])<< 8) + (UINT64)x[7];
2009     case CDI_LITTLEENDIAN:
2010       return (((UINT64)x[7])<<56) + (((UINT64)x[6])<<48) + (((UINT64)x[5])<<40) + (((UINT64)x[4])<<32) +
2011              (((UINT64)x[3])<<24) + (((UINT64)x[2])<<16) + (((UINT64)x[1])<< 8) + (UINT64)x[0];
2012     default:
2013       Error("Unhandled endianness %d", HOST_ENDIANNESS);
2014       return UINT64_C(0xFFFFFFFFFFFFFFFF);
2015     }
2016 }
2017 
2018 
get_SUINT64(unsigned char * x)2019 UINT64 get_SUINT64(unsigned char *x)
2020 {
2021   switch (HOST_ENDIANNESS)
2022     {
2023     case CDI_BIGENDIAN:
2024       return (((UINT64)x[7])<<56) + (((UINT64)x[6])<<48) + (((UINT64)x[5])<<40) + (((UINT64)x[4])<<32) +
2025              (((UINT64)x[3])<<24) + (((UINT64)x[2])<<16) + (((UINT64)x[1])<< 8) + (UINT64)x[0];
2026     case CDI_LITTLEENDIAN:
2027       return (((UINT64)x[0])<<56) + (((UINT64)x[1])<<48) + (((UINT64)x[2])<<40) + (((UINT64)x[3])<<32) +
2028              (((UINT64)x[4])<<24) + (((UINT64)x[5])<<16) + (((UINT64)x[6])<< 8) + (UINT64)x[7];
2029     default:
2030       Error("Unhandled endianness %d", HOST_ENDIANNESS);
2031       return UINT64_C(0xFFFFFFFFFFFFFFFF);
2032     }
2033 }
2034 
2035 
binReadF77Block(int fileID,int byteswap)2036 size_t binReadF77Block(int fileID, int byteswap)
2037 {
2038   unsigned char f77block[4];
2039   size_t blocklen = 0;
2040 
2041   if ( fileRead(fileID, f77block, 4) == 4 )
2042     {
2043       blocklen = byteswap ? get_SUINT32(f77block) : get_UINT32(f77block);
2044     }
2045 
2046   return blocklen;
2047 }
2048 
2049 
binWriteF77Block(int fileID,int byteswap,size_t blocksize)2050 void binWriteF77Block(int fileID, int byteswap, size_t blocksize)
2051 {
2052   static unsigned int s[4] = {0, 8, 16, 24};
2053   unsigned long ublocksize = (unsigned long) blocksize;
2054   unsigned char f77block[4];
2055 
2056   switch (HOST_ENDIANNESS)
2057     {
2058     case CDI_BIGENDIAN:
2059       if ( byteswap )
2060 	{
2061           for (int i = 0; i <= 3; ++i) f77block[i] = (unsigned char) (ublocksize >> s[i]);
2062 	}
2063       else
2064 	{
2065           for (int i = 0; i <= 3; ++i) f77block[3-i] = (unsigned char) (ublocksize >> s[i]);
2066 	}
2067       break;
2068     case CDI_LITTLEENDIAN:
2069       if ( byteswap )
2070 	{
2071           for (int i = 0; i <= 3; ++i) f77block[3-i] = (unsigned char) (ublocksize >> s[i]);
2072 	}
2073       else
2074 	{
2075           for (int i = 0; i <= 3; ++i) f77block[i] = (unsigned char) (ublocksize >> s[i]);
2076 	}
2077       break;
2078     default:
2079       Error("Unhandled endianness %d", HOST_ENDIANNESS);
2080     }
2081 
2082   if ( fileWrite(fileID, f77block, 4) != 4 )
2083     Error("Write failed on %s", fileInqName(fileID));
2084 }
2085 
2086 
binReadInt32(int fileID,int byteswap,size_t size,INT32 * ptr)2087 int binReadInt32(int fileID, int byteswap, size_t size, INT32 *ptr)
2088 {
2089   if ( sizeof(INT32) != 4 ) Error("Not implemented for %d byte integer!", sizeof(INT32));
2090 
2091   fileRead(fileID, (void *) ptr, 4*size);
2092   if ( byteswap ) swap4byte(ptr, size);
2093 
2094   return 0;
2095 }
2096 
2097 
binReadInt64(int fileID,int byteswap,size_t size,INT64 * ptr)2098 int binReadInt64(int fileID, int byteswap, size_t size, INT64 *ptr)
2099 {
2100   if ( sizeof(INT64) != 8 ) Error("Not implemented for %d byte integer!", sizeof(INT64));
2101 
2102   fileRead(fileID, (void *) ptr, 8*size);
2103   if ( byteswap ) swap8byte(ptr, size);
2104 
2105   return 0;
2106 }
2107 
2108 
binWriteInt32(int fileID,int byteswap,size_t size,INT32 * ptr)2109 int binWriteInt32(int fileID, int byteswap, size_t size, INT32 *ptr)
2110 {
2111   if ( sizeof(INT32) != 4 ) Error("Not implemented for %d byte integer!", sizeof(INT32));
2112 
2113   if ( byteswap ) swap4byte(ptr, size);
2114   fileWrite(fileID, (void *) ptr, 4*size);
2115 
2116   return 0;
2117 }
2118 
2119 
binWriteInt64(int fileID,int byteswap,size_t size,INT64 * ptr)2120 int binWriteInt64(int fileID, int byteswap, size_t size, INT64 *ptr)
2121 {
2122   if ( sizeof(INT64) != 8 ) Error("Not implemented for %d byte integer!", sizeof(INT64));
2123 
2124   if ( byteswap ) swap8byte(ptr, size);
2125   fileWrite(fileID, (void *) ptr, 8*size);
2126 
2127   return 0;
2128 }
2129 
2130 
binWriteFlt32(int fileID,int byteswap,size_t size,FLT32 * ptr)2131 int binWriteFlt32(int fileID, int byteswap, size_t size, FLT32 *ptr)
2132 {
2133   if ( sizeof(FLT32) != 4 ) Error("Not implemented for %d byte float!", sizeof(FLT32));
2134 
2135   if ( byteswap ) swap4byte(ptr, size);
2136   fileWrite(fileID, (void *) ptr, 4*size);
2137 
2138   return 0;
2139 }
2140 
2141 
binWriteFlt64(int fileID,int byteswap,size_t size,FLT64 * ptr)2142 int binWriteFlt64(int fileID, int byteswap, size_t size, FLT64 *ptr)
2143 {
2144   if ( sizeof(FLT64) != 8 ) Error("Not implemented for %d byte float!", sizeof(FLT64));
2145 
2146   if ( byteswap ) swap8byte(ptr, size);
2147   fileWrite(fileID, (void *) ptr, 8*size);
2148 
2149   return 0;
2150 }
2151 /*
2152  * Local Variables:
2153  * c-file-style: "Java"
2154  * c-basic-offset: 2
2155  * indent-tabs-mode: nil
2156  * show-trailing-whitespace: t
2157  * require-trailing-newline: t
2158  * End:
2159  */
2160 #ifndef CALENDAR_H
2161 #define CALENDAR_H
2162 
2163 #include <inttypes.h>
2164 
2165 #ifdef __cplusplus
2166 extern "C" {
2167 #endif
2168 
2169 void encode_caldaysec(int calendar, int year, int month, int day, int hour, int minute, int second,
2170 		      int64_t *julday, int *secofday);
2171 void decode_caldaysec(int calendar, int64_t julday, int secofday,
2172 		      int *year, int *month, int *day, int *hour, int *minute, int *second);
2173 
2174 int calendar_dpy(int calendar);
2175 int days_per_year(int calendar, int year);
2176 int days_per_month(int calendar, int year, int month);
2177 
2178 #ifdef __cplusplus
2179 }
2180 #endif
2181 
2182 #endif  /* CALENDAR_H */
2183 /*
2184  * Local Variables:
2185  * c-file-style: "Java"
2186  * c-basic-offset: 2
2187  * indent-tabs-mode: nil
2188  * show-trailing-whitespace: t
2189  * require-trailing-newline: t
2190  * End:
2191  */
2192 #ifndef TIMEBASE_H
2193 #define TIMEBASE_H
2194 
2195 #include <inttypes.h>
2196 
2197 #ifdef __cplusplus
2198 extern "C" {
2199 #endif
2200 
2201 /* date format:  YYYYMMDD */
2202 /* time format:  hhmmss   */
2203 
2204 void decode_julday(int calendar, int64_t julday, int *year, int *mon, int *day);
2205 int64_t encode_julday(int calendar, int year, int month, int day);
2206 
2207 int64_t date_to_julday(int calendar, int64_t date);
2208 int64_t julday_to_date(int calendar, int64_t julday);
2209 
2210 int time_to_sec(int time);
2211 int sec_to_time(int secofday);
2212 
2213 void   julday_add_seconds(int64_t seconds, int64_t *julday, int *secofday);
2214 void   julday_add(int days, int secs, int64_t *julday, int *secofday);
2215 double julday_sub(int64_t julday1, int secofday1, int64_t julday2, int secofday2, int64_t *days, int *secs);
2216 
2217 void encode_juldaysec(int calendar, int year, int month, int day, int hour, int minute, int second, int64_t *julday, int *secofday);
2218 void decode_juldaysec(int calendar, int64_t julday, int secofday, int *year, int *month, int *day, int *hour, int *minute, int *second);
2219 
2220 #ifdef __cplusplus
2221 }
2222 #endif
2223 
2224 #endif /* TIMEBASE_H */
2225 
2226 /*
2227  * Local Variables:
2228  * c-file-style: "Java"
2229  * c-basic-offset: 2
2230  * indent-tabs-mode: nil
2231  * show-trailing-whitespace: t
2232  * require-trailing-newline: t
2233  * End:
2234  */
2235 #include <limits.h>
2236 
2237 
2238 
2239 static const int month_360[12] = {30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30};
2240 static const int month_365[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
2241 static const int month_366[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
2242 
2243 
calendar_dpy(int calendar)2244 int calendar_dpy(int calendar)
2245 {
2246   int daysperyear = 0;
2247 
2248   if      ( calendar == CALENDAR_360DAYS ) daysperyear = 360;
2249   else if ( calendar == CALENDAR_365DAYS ) daysperyear = 365;
2250   else if ( calendar == CALENDAR_366DAYS ) daysperyear = 366;
2251 
2252   return daysperyear;
2253 }
2254 
2255 
days_per_month(int calendar,int year,int month)2256 int days_per_month(int calendar, int year, int month)
2257 {
2258   int daysperyear = calendar_dpy(calendar);
2259 
2260   const int *dpm;
2261   if      ( daysperyear == 360 ) dpm = month_360;
2262   else if ( daysperyear == 365 ) dpm = month_365;
2263   else                           dpm = month_366;
2264 
2265   int dayspermonth = 0;
2266   if ( month >= 1 && month <= 12 )
2267     dayspermonth = dpm[month-1];
2268   /*
2269   else
2270     fprintf(stderr, "days_per_month: month %d out of range\n", month);
2271   */
2272   if ( daysperyear == 0 && month == 2 )
2273     {
2274       if ( (year%4 == 0 && year%100 != 0) || year%400 == 0 )
2275 	dayspermonth = 29;
2276       else
2277 	dayspermonth = 28;
2278     }
2279 
2280   return dayspermonth;
2281 }
2282 
2283 
days_per_year(int calendar,int year)2284 int days_per_year(int calendar, int year)
2285 {
2286   int daysperyear = calendar_dpy(calendar);
2287 
2288   if ( daysperyear == 0 )
2289     {
2290       if ( year == 1582 && (calendar == CALENDAR_STANDARD || calendar == CALENDAR_GREGORIAN) )
2291         daysperyear = 355;
2292       else if ( (year%4 == 0 && year%100 != 0) || year%400 == 0 )
2293         daysperyear = 366;
2294       else
2295         daysperyear = 365;
2296     }
2297 
2298   return daysperyear;
2299 }
2300 
2301 
decode_day(int dpy,int days,int * year,int * month,int * day)2302 static void decode_day(int dpy, int days, int *year, int *month, int *day)
2303 {
2304   int i = 0;
2305 
2306   *year = (days-1) / dpy;
2307   days -= (*year*dpy);
2308 
2309   const int *dpm = NULL;
2310   if      ( dpy == 360 ) dpm = month_360;
2311   else if ( dpy == 365 ) dpm = month_365;
2312   else if ( dpy == 366 ) dpm = month_366;
2313 
2314   if ( dpm )
2315     for ( i = 0; i < 12; i++ )
2316       {
2317 	if ( days > dpm[i] ) days -= dpm[i];
2318 	else break;
2319       }
2320 
2321   *month = i + 1;
2322   *day   = days;
2323 }
2324 
2325 
encode_day(int dpy,int year,int month,int day)2326 static int64_t encode_day(int dpy, int year, int month, int day)
2327 {
2328   int64_t rval = (int64_t)dpy * year + day;
2329 
2330   const int *dpm = NULL;
2331   if      ( dpy == 360 ) dpm = month_360;
2332   else if ( dpy == 365 ) dpm = month_365;
2333   else if ( dpy == 366 ) dpm = month_366;
2334 
2335   if ( dpm ) for ( int i = 0; i < month-1; i++ ) rval += dpm[i];
2336   if ( rval > LONG_MAX || rval < LONG_MIN ) Error("Unhandled date: %lld", rval);
2337 
2338   return rval;
2339 }
2340 
2341 
encode_caldaysec(int calendar,int year,int month,int day,int hour,int minute,int second,int64_t * julday,int * secofday)2342 void encode_caldaysec(int calendar, int year, int month, int day, int hour, int minute, int second,
2343 		      int64_t *julday, int *secofday)
2344 {
2345   int dpy = calendar_dpy(calendar);
2346 
2347   if ( dpy == 360 || dpy == 365 || dpy == 366 )
2348     *julday = encode_day(dpy, year, month, day);
2349   else
2350     *julday = encode_julday(calendar, year, month, day);
2351 
2352   *secofday = hour*3600 + minute*60 + second;
2353 }
2354 
2355 
decode_caldaysec(int calendar,int64_t julday,int secofday,int * year,int * month,int * day,int * hour,int * minute,int * second)2356 void decode_caldaysec(int calendar, int64_t julday, int secofday,
2357 		      int *year, int *month, int *day, int *hour, int *minute, int *second)
2358 {
2359   int dpy = calendar_dpy(calendar);
2360 
2361   if ( dpy == 360 || dpy == 365 || dpy == 366 )
2362     decode_day(dpy, julday, year, month, day);
2363   else
2364     decode_julday(calendar, julday, year, month, day);
2365 
2366   *hour   = secofday/3600;
2367   *minute = secofday/60 - *hour*60;
2368   *second = secofday - *hour*3600 - *minute*60;
2369 }
2370 
2371 
2372 #ifdef TEST
date_to_calday(int calendar,int date)2373 static int date_to_calday(int calendar, int date)
2374 {
2375   int dpy = calendar_dpy(calendar);
2376 
2377   int year, month, day;
2378   cdiDecodeDate(date, &year, &month, &day);
2379 
2380   int calday;
2381   if ( dpy == 360 || dpy == 365 || dpy == 366 )
2382     calday = encode_day(dpy, year, month, day);
2383   else
2384     calday = encode_julday(calendar, year, month, day);
2385 
2386   return calday;
2387 }
2388 
2389 
calday_to_date(int calendar,int calday)2390 static int calday_to_date(int calendar, int calday)
2391 {
2392   int year, month, day;
2393   int dpy = calendar_dpy(calendar);
2394 
2395   if ( dpy == 360 || dpy == 365 || dpy == 366 )
2396     decode_day(dpy, calday, &year, &month, &day);
2397   else
2398     decode_julday(calendar, calday, &year, &month, &day);
2399 
2400   int date = cdiEncodeDate(year, month, day);
2401 
2402   return date;
2403 }
2404 
2405 
main(void)2406 int main(void)
2407 {
2408   int calendar = CALENDAR_STANDARD;
2409   int nmin;
2410   int64_t vdate0, vdate;
2411   int vtime0, vtime;
2412   int ijulinc;
2413   int i, j = 0;
2414   int year, mon, day, hour, minute, second;
2415   int calday, secofday;
2416 
2417   /* 1 - Check valid range of years */
2418 
2419   nmin = 11000;
2420   vdate0 = -80001201;
2421   vtime0 = 120500;
2422 
2423   printf("start time: %8ld %4d\n", vdate0, vtime0);
2424 
2425   for ( i = 0; i < nmin; i++ )
2426     {
2427       cdiDecodeDate(vdate0, &year, &mon, &day);
2428       cdiDecodeTime(vtime0, &hour, &minute, &second);
2429 
2430       calday  = date_to_calday(calendar, vdate0);
2431       secofday = time_to_sec(vtime0);
2432 
2433       vdate = calday_to_date(calendar, calday);
2434       vtime = sec_to_time(secofday);
2435 
2436       if ( vdate0 != vdate || vtime0 != vtime )
2437 	printf("%4d %8ld %4d %8ld %4d %9d %9d\n",
2438 	       ++j, vdate0, vtime0, vdate, vtime, calday, secofday);
2439 
2440       year++;
2441       vdate0 = cdiEncodeDate(year, mon, day);
2442       vtime0 = cdiEncodeTime(hour, minute, second);
2443     }
2444 
2445   printf("stop time: %8ld %4d\n", vdate0, vtime0);
2446 
2447   /* 2 - Check time increment of one minute */
2448 
2449   nmin = 120000;
2450   ijulinc = 60;
2451   vdate0 = 20001201;
2452   vtime0 = 0;
2453 
2454   printf("start time: %8ld %4d\n", vdate0, vtime0);
2455 
2456   calday = date_to_calday(calendar, vdate0);
2457   secofday = time_to_sec(vtime0);
2458   for ( i = 0; i < nmin; i++ )
2459     {
2460       cdiDecodeDate(vdate0, &year, &mon, &day);
2461       cdiDecodeTime(vtime0, &hour, &minute, &second);
2462 
2463       if ( ++minute >= 60 )
2464 	{
2465 	  minute = 0;
2466 	  if ( ++hour >= 24 )
2467 	    {
2468 	      hour = 0;
2469 	      if ( ++day >= 32 )
2470 		{
2471 		  day = 1;
2472 		  if ( ++mon >= 13 )
2473 		    {
2474 		      mon = 1;
2475 		      year++;
2476 		    }
2477 		}
2478 	    }
2479 	}
2480 
2481       vdate0 = cdiEncodeDate(year, mon, day);
2482       vtime0 = cdiEncodeTime(hour, minute, second);
2483 
2484       julday_add_seconds(ijulinc, &calday, &secofday);
2485 
2486       vdate = calday_to_date(calendar, calday);
2487       vtime = sec_to_time(secofday);
2488       if ( vdate0 != vdate || vtime0 != vtime )
2489 	printf("%4d %8ld %4d %8ld %4d %9d %9d\n",
2490 	       ++j, vdate0, vtime0, vdate, vtime, calday, secofday);
2491     }
2492 
2493   printf("stop time: %8ld %4d\n", vdate0, vtime0);
2494 
2495   return 0;
2496 }
2497 #endif
2498 
2499 
2500 #ifdef TEST2
main(void)2501 int main(void)
2502 {
2503   int calendar = CALENDAR_STANDARD;
2504   int i;
2505   int calday, secofday;
2506   int year, month, day, hour, minute, second;
2507   int value = 30;
2508   int factor = 86400;
2509 
2510   calendar = CALENDAR_360DAYS;
2511 
2512   year=1979; month=1; day=15; hour=12; minute=30; second = 0;
2513 
2514   printf("calendar = %d\n", calendar);
2515   printf("%d/%02d/%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second);
2516 
2517   encode_caldaysec(calendar, year, month, day, hour, minute, second, &calday, &secofday);
2518 
2519   decode_caldaysec(calendar, calday, secofday, &year, &month, &day, &hour, &minute, &second);
2520   printf("%d/%02d/%02d %02d:%02d:%02d   %d %d\n", year, month, day, hour, minute, second, calday, secofday);
2521 
2522   for ( i = 0; i < 420; i++ )
2523     {
2524 
2525       decode_caldaysec(calendar, calday, secofday, &year, &month, &day, &hour, &minute, &second);
2526       printf("%2d %d/%02d/%02d %02d:%02d:%02d\n", i, year, month, day, hour, minute, second);
2527       julday_add_seconds(value*factor, &calday, &secofday);
2528     }
2529 
2530   return 0;
2531 }
2532 #endif
2533 /*
2534  * Local Variables:
2535  * c-file-style: "Java"
2536  * c-basic-offset: 2
2537  * indent-tabs-mode: nil
2538  * show-trailing-whitespace: t
2539  * require-trailing-newline: t
2540  * End:
2541  */
2542 #ifndef  CDF_H
2543 #define  CDF_H
2544 
2545 void cdfDebug(int debug);
2546 
2547 extern int CDF_Debug;
2548 
2549 const char *cdfLibraryVersion(void);
2550 const char *hdfLibraryVersion(void);
2551 
2552 int  cdfOpen(const char *filename, const char *mode, int filetype);
2553 int  cdf4Open(const char *filename, const char *mode, int *filetype);
2554 void cdfClose(int fileID);
2555 
2556 #endif  /* CDF_H */
2557 /*
2558  * Local Variables:
2559  * c-file-style: "Java"
2560  * c-basic-offset: 2
2561  * indent-tabs-mode: nil
2562  * show-trailing-whitespace: t
2563  * require-trailing-newline: t
2564  * End:
2565  */
2566 #ifndef  CDF_CONFIG_H_
2567 #define  CDF_CONFIG_H_
2568 
2569 #ifdef  HAVE_CONFIG_H
2570 #endif
2571 
2572 #ifdef  HAVE_LIBNETCDF
2573 
2574 #include  <netcdf.h>
2575 
2576 #ifdef  NC_FORMAT_64BIT_DATA
2577 #define  HAVE_NETCDF5  1
2578 #endif
2579 
2580 #endif
2581 
2582 #endif
2583 #ifndef RESOURCE_HANDLE_H
2584 #define RESOURCE_HANDLE_H
2585 
2586 #ifdef HAVE_CONFIG_H
2587 #endif
2588 
2589 #include <stdio.h>
2590 
2591 /*
2592  * CDI internal handling of resource handles given to user code
2593  */
2594 
2595 /*
2596  * for reasons of compatibility with cfortran.h, the handle type is: int
2597  */
2598 typedef int cdiResH;
2599 
2600 /* return 0 on equality, not 0 otherwise */
2601 typedef int    ( * valCompareFunc     )( void *, void * );
2602 typedef void   ( * valDestroyFunc     )( void * );
2603 typedef void   ( * valPrintFunc       )( void *, FILE * );
2604 typedef int    ( * valGetPackSizeFunc )( void *, void *context );
2605 typedef void   ( * valPackFunc        )( void *, void *buf, int size, int *pos, void *context );
2606 typedef int    ( * valTxCodeFunc      )( void );
2607 
2608 typedef struct {
2609   valCompareFunc     valCompare;
2610   valDestroyFunc     valDestroy;
2611   valPrintFunc       valPrint;
2612   valGetPackSizeFunc valGetPackSize;
2613   valPackFunc        valPack;
2614   valTxCodeFunc      valTxCode;
2615 }resOps;
2616 
2617 enum {
2618   RESH_IN_USE_BIT = 1 << 0,
2619   RESH_SYNC_BIT = 1 << 1,
2620   /* resource holds no value */
2621   RESH_UNUSED = 0,
2622   /* resource was deleted and needs to be synced */
2623   RESH_DESYNC_DELETED
2624     = RESH_SYNC_BIT,
2625   /* resource is synchronized */
2626   RESH_IN_USE
2627     = RESH_IN_USE_BIT,
2628   /* resource is in use, desynchronized and needs to be synced */
2629   RESH_DESYNC_IN_USE
2630     = RESH_IN_USE_BIT | RESH_SYNC_BIT,
2631 };
2632 
2633 void   reshListCreate(int namespaceID);
2634 void   reshListDestruct(int namespaceID);
2635 int    reshPut ( void *, const resOps * );
2636 void reshReplace(cdiResH resH, void *p, const resOps *ops);
2637 void   reshRemove ( cdiResH, const resOps * );
2638 /*> doesn't check resource type */
2639 void reshDestroy(cdiResH);
2640 
2641 unsigned reshCountType(const resOps *resTypeOps);
2642 
2643 void * reshGetValue(const char* caller, const char* expressionString, cdiResH id, const resOps* ops);
2644 #define reshGetVal(resH, ops)  reshGetValue(__func__, #resH, resH, ops)
2645 
2646 void reshGetResHListOfType(unsigned numIDs, int IDs[], const resOps *ops);
2647 
2648 enum cdiApplyRet {
2649   CDI_APPLY_ERROR = -1,
2650   CDI_APPLY_STOP,
2651   CDI_APPLY_GO_ON,
2652 };
2653 enum cdiApplyRet
2654 cdiResHApply(enum cdiApplyRet (*func)(int id, void *res, const resOps *p,
2655                                       void *data), void *data);
2656 enum cdiApplyRet
2657 cdiResHFilterApply(const resOps *p,
2658                    enum cdiApplyRet (*func)(int id, void *res,
2659                                             void *data),
2660                    void *data);
2661 
2662 int reshPackBufferCreate(char **packBuf, int *packBufSize, void *context);
2663 void   reshPackBufferDestroy ( char ** );
2664 int    reshResourceGetPackSize_intern(int resh, const resOps *ops, void *context, const char* caller, const char* expressionString);
2665 #define reshResourceGetPackSize(resh, ops, context) reshResourceGetPackSize_intern(resh, ops, context, __func__, #resh)
2666 void   reshPackResource_intern(int resh, const resOps *ops, void *buf, int buf_size, int *position, void *context, const char* caller, const char* expressionString);
2667 #define reshPackResource(resh, ops, buf, buf_size, position, context) reshPackResource_intern(resh, ops, buf, buf_size, position, context, __func__, #resh)
2668 
2669 void   reshSetStatus ( cdiResH, const resOps *, int );
2670 int    reshGetStatus ( cdiResH, const resOps * );
2671 
2672 void   reshLock   ( void );
2673 void   reshUnlock ( void );
2674 
2675 enum reshListMismatch {
2676   cdiResHListOccupationMismatch,
2677   cdiResHListResourceTypeMismatch,
2678   cdiResHListResourceContentMismatch,
2679 };
2680 
2681 int reshListCompare(int nsp0, int nsp1);
2682 void reshListPrint(FILE *fp);
2683 int reshGetTxCode(cdiResH resH);
2684 
2685 #endif
2686 /*
2687  * Local Variables:
2688  * c-file-style: "Java"
2689  * c-basic-offset: 2
2690  * indent-tabs-mode: nil
2691  * show-trailing-whitespace: t
2692  * require-trailing-newline: t
2693  * End:
2694  */
2695 #ifndef TAXIS_H
2696 #define TAXIS_H
2697 
2698 #include <stdbool.h>
2699 
2700 #ifndef RESOURCE_HANDLE_H
2701 #endif
2702 
2703 typedef struct {
2704   /* Date format  YYYYMMDD */
2705   /* Time format    hhmmss */
2706   int     self;
2707   bool    used;
2708   short   has_bounds;
2709   int     datatype;       // datatype
2710   int     type;           // time type
2711   int64_t sdate;          // start date
2712   int     stime;          // start time
2713   int64_t vdate;          // verification date
2714   int     vtime;          // verification time
2715   int64_t rdate;          // reference date
2716   int     rtime;          // reference time
2717   int64_t fdate;          // forecast reference date
2718   int     ftime;          // forecast reference time
2719   int     calendar;
2720   int     unit;           // time unit
2721   int     numavg;
2722   bool    climatology;
2723   int64_t vdate_lb;       // lower bounds of vdate
2724   int     vtime_lb;       // lower bounds of vtime
2725   int64_t vdate_ub;       // upper bounds of vdate
2726   int     vtime_ub;       // upper bounds of vtime
2727   int     fc_unit;        // forecast time unit
2728   double  fc_period;      // forecast time period
2729   char   *name;
2730   char   *longname;
2731   char   *units;
2732 }
2733 taxis_t;
2734 
2735 //      taxisInqSdate: Get the start date
2736 int64_t taxisInqSdate(int taxisID);
2737 
2738 //      taxisInqStime: Get the start time
2739 int     taxisInqStime(int taxisID);
2740 
2741 void     ptaxisInit(taxis_t* taxis);
2742 void     ptaxisCopy(taxis_t* dest, taxis_t* source);
2743 taxis_t* taxisPtr(int taxisID);
2744 void     cdiSetForecastPeriod(double timevalue, taxis_t *taxis);
2745 void     cdiDecodeTimeval(double timevalue, taxis_t* taxis, int64_t* date, int* time);
2746 double   cdiEncodeTimeval(int64_t date, int time, taxis_t* taxis);
2747 void     timeval2vtime(double timevalue, taxis_t* taxis, int64_t* vdate, int* vtime);
2748 double   vtime2timeval(int64_t vdate, int vtime, taxis_t *taxis);
2749 
2750 void    ptaxisDefDatatype(taxis_t *taxisptr, int datatype);
2751 void    ptaxisDefName(taxis_t *taxisptr, const char *name);
2752 void    ptaxisDefLongname(taxis_t *taxisptr, const char *longname);
2753 void    ptaxisDefUnits(taxis_t *taxisptr, const char *units);
2754 void    taxisDestroyKernel(taxis_t *taxisptr);
2755 #if !defined (SX)
2756 extern const resOps taxisOps;
2757 #endif
2758 
2759 int
2760 taxisUnpack(char *unpackBuffer, int unpackBufferSize, int *unpackBufferPos,
2761             int originNamespace, void *context, int checkForSameID);
2762 
2763 #endif  /* TAXIS_H */
2764 /*
2765  * Local Variables:
2766  * c-file-style: "Java"
2767  * c-basic-offset: 2
2768  * indent-tabs-mode: nil
2769  * show-trailing-whitespace: t
2770  * require-trailing-newline: t
2771  * End:
2772  */
2773 #ifndef  CDI_LIMITS_H
2774 #define  CDI_LIMITS_H
2775 
2776 #define  MAX_GRIDS_PS    128  // maximum number of different grids per stream
2777 #define  MAX_ZAXES_PS    128  // maximum number of different zaxes per stream
2778 #define  MAX_ATTRIBUTES  256  // maximum number of attributes per variable
2779 #define  MAX_KEYS         64  // maximum number of keys per variable
2780 #define  MAX_SUBTYPES_PS 128  // maximum number of different subtypes per stream
2781 
2782 #endif  /* CDI_LIMITS_H */
2783 /*
2784  * Local Variables:
2785  * c-file-style: "Java"
2786  * c-basic-offset: 2
2787  * indent-tabs-mode: nil
2788  * show-trailing-whitespace: t
2789  * require-trailing-newline: t
2790  * End:
2791  */
2792 #ifndef _SERVICE_H
2793 #define _SERVICE_H
2794 
2795 
2796 typedef struct {
2797   int    checked;
2798   int    byteswap;
2799   int    header[8];
2800   int    hprec;      /* header precision */
2801   int    dprec;      /* data   precision */
2802   size_t datasize;
2803   size_t buffersize;
2804   void  *buffer;
2805 }
2806 srvrec_t;
2807 
2808 
2809 const char *srvLibraryVersion(void);
2810 
2811 void srvDebug(int debug);
2812 
2813 int  srvCheckFiletype(int fileID, int *swap);
2814 
2815 void *srvNew(void);
2816 void srvDelete(void *srv);
2817 
2818 int  srvRead(int fileID, void *srv);
2819 void srvWrite(int fileID, void *srv);
2820 
2821 int  srvInqHeader(void *srv, int *header);
2822 int  srvInqDataSP(void *srv, float *data);
2823 int  srvInqDataDP(void *srv, double *data);
2824 
2825 int  srvDefHeader(void *srv, const int *header);
2826 int  srvDefDataSP(void *srv, const float *data);
2827 int  srvDefDataDP(void *srv, const double *data);
2828 
2829 
2830 #endif  /* _SERVICE_H */
2831 /*
2832  * Local Variables:
2833  * c-file-style: "Java"
2834  * c-basic-offset: 2
2835  * indent-tabs-mode: nil
2836  * show-trailing-whitespace: t
2837  * require-trailing-newline: t
2838  * End:
2839  */
2840 #ifndef _EXTRA_H
2841 #define _EXTRA_H
2842 
2843 #define  EXT_REAL   1
2844 #define  EXT_COMP   2
2845 
2846 
2847 typedef struct {
2848   int    checked;
2849   int    byteswap;
2850   int    header[4];
2851   int    prec;      /* single or double precison */
2852   int    number;    /* real or complex */
2853   size_t datasize;
2854   size_t buffersize;
2855   void  *buffer;
2856 }
2857 extrec_t;
2858 
2859 
2860 const char *extLibraryVersion(void);
2861 
2862 void extDebug(int debug);
2863 
2864 int  extCheckFiletype(int fileID, int *swap);
2865 
2866 void *extNew(void);
2867 void extDelete(void *ext);
2868 
2869 int  extRead(int fileID, void *ext);
2870 int  extWrite(int fileID, void *ext);
2871 
2872 int  extInqHeader(void *ext, int *header);
2873 int  extInqDataSP(void *ext, float *data);
2874 int  extInqDataDP(void *ext, double *data);
2875 
2876 int  extDefHeader(void *ext, const int *header);
2877 int  extDefDataSP(void *ext, const float *data);
2878 int  extDefDataDP(void *ext, const double *data);
2879 
2880 #endif  /* _EXTRA_H */
2881 /*
2882  * Local Variables:
2883  * c-file-style: "Java"
2884  * c-basic-offset: 2
2885  * indent-tabs-mode: nil
2886  * show-trailing-whitespace: t
2887  * require-trailing-newline: t
2888  * End:
2889  */
2890 #ifndef _IEG_H
2891 #define _IEG_H
2892 
2893 /* Level Types */
2894 #define  IEG_LTYPE_SURFACE               1
2895 #define  IEG_LTYPE_99                   99
2896 #define  IEG_LTYPE_ISOBARIC            100
2897 #define  IEG_LTYPE_MEANSEA             102
2898 #define  IEG_LTYPE_ALTITUDE            103
2899 #define  IEG_LTYPE_HEIGHT              105
2900 #define  IEG_LTYPE_SIGMA               107
2901 #define  IEG_LTYPE_HYBRID              109
2902 #define  IEG_LTYPE_HYBRID_LAYER        110
2903 #define  IEG_LTYPE_LANDDEPTH           111
2904 #define  IEG_LTYPE_LANDDEPTH_LAYER     112
2905 #define  IEG_LTYPE_SEADEPTH            160
2906 
2907 /*
2908  *  Data representation type (Grid Type) [Table 6]
2909  */
2910 #define  IEG_GTYPE_LATLON             0  /*  latitude/longitude                       */
2911 #define  IEG_GTYPE_LATLON_ROT        10  /*  rotated latitude/longitude               */
2912 
2913 #define  IEG_P_CodeTable(x)   (x[ 5])  /*  Version number of code table                 */
2914 #define  IEG_P_Parameter(x)   (x[ 6])  /*  Parameter indicator                          */
2915 #define  IEG_P_LevelType(x)   (x[ 7])  /*  Type of level indicator                      */
2916 #define  IEG_P_Level1(x)      (x[ 8])  /*  Level 1                                      */
2917 #define  IEG_P_Level2(x)      (x[ 9])  /*  Level 2                                      */
2918 #define  IEG_P_Year(x)        (x[10])  /*  Year of century (YY)                         */
2919 #define  IEG_P_Month(x)       (x[11])  /*  Month (MM)                                   */
2920 #define  IEG_P_Day(x)         (x[12])  /*  Day (DD)                                     */
2921 #define  IEG_P_Hour(x)        (x[13])  /*  Hour (HH)                                    */
2922 #define  IEG_P_Minute(x)      (x[14])  /*  Minute (MM)                                  */
2923 
2924 /*
2925  *  Macros for the grid definition section ( Section 2 )
2926  */
2927 #define  IEG_G_Size(x)        (x[ 0])
2928 #define  IEG_G_NumVCP(x)      (x[3] == 10 ? (x[0]-42)/4 : (x[0]-32)/4)
2929 #define  IEG_G_GridType(x)    (x[ 3])  /*  Data representation type */
2930 #define  IEG_G_NumLon(x)      (x[ 4])  /*  Number of points along a parallel (Ni)       */
2931 #define  IEG_G_NumLat(x)      (x[ 5])  /*  Number of points along a meridian (Nj)       */
2932 #define  IEG_G_FirstLat(x)    (x[ 6])  /*  Latitude of the first grid point             */
2933 #define  IEG_G_FirstLon(x)    (x[ 7])  /*  Longitude of the first grid point            */
2934 #define  IEG_G_ResFlag(x)     (x[ 8])  /*  Resolution flag: 128 regular grid            */
2935 #define  IEG_G_LastLat(x)     (x[ 9])  /*  Latitude of the last grid point              */
2936 #define  IEG_G_LastLon(x)     (x[10])  /*  Longitude of the last grid point             */
2937 #define  IEG_G_LonIncr(x)     (x[11])  /*  i direction increment                        */
2938 #define  IEG_G_LatIncr(x)     (x[12])  /*  j direction increment                        */
2939 #define  IEG_G_ScanFlag(x)    (x[13])
2940 #define  IEG_G_LatSP(x)       (x[16])  /*  Latitude of the southern pole of rotation    */
2941 #define  IEG_G_LonSP(x)       (x[17])  /*  Longitude of the southern pole of rotation   */
2942 #define  IEG_G_ResFac(x)      (x[18])  /*  Resolution factor                            */
2943 
2944 
2945 typedef struct {
2946   int    checked;
2947   int    byteswap;
2948   int    dprec;      /* data   precision */
2949   int    ipdb[37];
2950   double refval;
2951   int    igdb[22];
2952   double vct[100];
2953   size_t datasize;
2954   size_t buffersize;
2955   void  *buffer;
2956 }
2957 iegrec_t;
2958 
2959 
2960 const char *iegLibraryVersion(void);
2961 
2962 void iegDebug(int debug);
2963 int  iegCheckFiletype(int fileID, int *swap);
2964 
2965 void *iegNew(void);
2966 void iegDelete(void *ieg);
2967 void iegInitMem(void *ieg);
2968 
2969 int  iegRead(int fileID, void *ieg);
2970 int  iegWrite(int fileID, void *ieg);
2971 
2972 void iegCopyMeta(void *dieg, void *sieg);
2973 int  iegInqHeader(void *ieg, int *header);
2974 int  iegInqDataSP(void *ieg, float *data);
2975 int  iegInqDataDP(void *ieg, double *data);
2976 
2977 int  iegDefHeader(void *ieg, const int *header);
2978 int  iegDefDataSP(void *ieg, const float *data);
2979 int  iegDefDataDP(void *ieg, const double *data);
2980 
2981 #endif  /* _IEG_H */
2982 /*
2983  * Local Variables:
2984  * c-file-style: "Java"
2985  * c-basic-offset: 2
2986  * indent-tabs-mode: nil
2987  * show-trailing-whitespace: t
2988  * require-trailing-newline: t
2989  * End:
2990  */
2991 #ifndef  CDI_INT_H
2992 #define  CDI_INT_H
2993 
2994 #ifdef HAVE_CONFIG_H
2995 #endif
2996 
2997 #include <assert.h>
2998 #include <stdio.h>
2999 #include <stdbool.h>
3000 #include <string.h>
3001 #include <errno.h>
3002 #include <limits.h>
3003 #include <math.h>
3004 #include <sys/types.h>
3005 
3006 
3007 // Base file types
3008 
3009 #define  CDI_FILETYPE_GRIB        100   // File type GRIB
3010 #define  CDI_FILETYPE_NETCDF      101   // File type NetCDF
3011 
3012 // dummy use of unused parameters to silence compiler warnings
3013 #ifndef  UNUSED
3014 #define  UNUSED(x) (void)x
3015 #endif
3016 
3017 #ifndef strdupx
3018 #ifndef strdup
3019 char *strdup(const char *s);
3020 #endif
3021 #define strdupx  strdup
3022 /*
3023 #define strdupx(s)			          \
3024 ({					      	  \
3025    const char *__old = (s);			  \
3026    size_t __len = strlen(__old) + 1;		  \
3027    char *__new = (char *) Malloc(__len);	  \
3028    (char *) memcpy(__new, __old, __len);	  \
3029 })
3030 */
3031 #endif
3032 
3033 char *strToLower(char *str);
3034 bool strStartsWith(const char *vstr, const char *cstr);
3035 
3036 static inline bool
strIsEqual(const char * x,const char * y)3037 strIsEqual(const char *x, const char *y)
3038 {
3039   return (*x == *y) && strcmp(x, y) == 0;
3040 }
3041 
3042 
3043 #ifndef  M_PI
3044 #define  M_PI        3.14159265358979323846  /* pi */
3045 #endif
3046 
3047 
3048 #ifndef  ERROR_H
3049 #endif
3050 #ifndef _BASETIME_H
3051 #endif
3052 #ifndef TIMEBASE_H
3053 #endif
3054 #ifndef TAXIS_H
3055 #endif
3056 #ifndef CDI_LIMITS_H
3057 #endif
3058 #ifndef  _SERVICE_H
3059 #endif
3060 #ifndef  _EXTRA_H
3061 #endif
3062 #ifndef  _IEG_H
3063 #endif
3064 #ifndef RESOURCE_HANDLE_H
3065 #endif
3066 
3067 
3068 #define check_parg(arg)  if ( arg == 0 ) Warning("Argument '" #arg "' not allocated!")
3069 
3070 #if defined (__xlC__) /* performance problems on IBM */
3071 #ifndef DBL_IS_NAN
3072 #  define DBL_IS_NAN(x)     ((x) != (x))
3073 #endif
3074 #else
3075 #ifndef DBL_IS_NAN
3076 #if  defined  (HAVE_DECL_ISNAN)
3077 #  define DBL_IS_NAN(x)     (isnan(x))
3078 #elif  defined  (FP_NAN)
3079 #  define DBL_IS_NAN(x)     (fpclassify(x) == FP_NAN)
3080 #else
3081 #  define DBL_IS_NAN(x)     ((x) != (x))
3082 #endif
3083 #endif
3084 #endif
3085 
3086 #ifndef DBL_IS_EQUAL
3087 /*#define DBL_IS_EQUAL(x,y) (!(x < y || y < x)) */
3088 #  define DBL_IS_EQUAL(x,y) (DBL_IS_NAN(x)||DBL_IS_NAN(y)?(DBL_IS_NAN(x)&&DBL_IS_NAN(y)):!(x < y || y < x))
3089 #endif
3090 
3091 #ifndef IS_EQUAL
3092 #  define IS_NOT_EQUAL(x,y) (x < y || y < x)
3093 #  define IS_EQUAL(x,y)     (!IS_NOT_EQUAL(x,y))
3094 #endif
3095 
3096 #define  FALSE  0
3097 #define  TRUE   1
3098 
3099 #define  TYPE_REC  0
3100 #define  TYPE_VAR  1
3101 
3102 #define  MEMTYPE_DOUBLE  1
3103 #define  MEMTYPE_FLOAT   2
3104 
3105 typedef struct
3106 {
3107   void     *buffer;             // gribapi, cgribex
3108   size_t    buffersize;         // gribapi, cgribex
3109   off_t     position;           // file position
3110   int       param;
3111   int       level;
3112   int       date;
3113   int       time;
3114   int       gridID;
3115   int       varID;
3116   int       levelID;
3117   int       prec;               // ext, srv
3118   void     *exsep;              // ieg, ext, srv container
3119   void     *cgribexp;           // cgribex container
3120 }
3121 Record;
3122 
3123 // data structure specifying tile-related meta-data. structure contains "-1" if this is no tile-variable.
3124 typedef struct {
3125   int
3126     tileindex,
3127     totalno_of_tileattr_pairs,
3128     tileClassification,
3129     numberOfTiles,
3130     numberOfAttributes,
3131     attribute;
3132 } var_tile_t;
3133 
3134 
3135 typedef struct {
3136   short perturbationNumber;
3137   short typeOfGeneratingProcess;
3138 } VarScanKeys;
3139 
3140 static inline void
varScanKeysInit(VarScanKeys * s)3141 varScanKeysInit(VarScanKeys *s)
3142 {
3143   memset(s, 0, sizeof(VarScanKeys));
3144 }
3145 
3146 static inline bool
varScanKeysIsEqual(const VarScanKeys * s1,const VarScanKeys * s2)3147 varScanKeysIsEqual(const VarScanKeys *s1, const VarScanKeys *s2)
3148 {
3149   return memcmp(s1, s2, sizeof(VarScanKeys)) == 0;
3150 }
3151 
3152 typedef struct
3153 {
3154   off_t     position;
3155   size_t    size;
3156   size_t    gridsize;
3157   int       zip;
3158   int       param;
3159   int       ilevel;
3160   int       ilevel2;
3161   int       ltype;
3162   short     tsteptype;
3163   short     varID;
3164   short     levelID;
3165   short     used;
3166   char      varname[32]; // needed for grib decoding with GRIB_API
3167   VarScanKeys scanKeys;
3168   var_tile_t tiles;      // tile-related meta-data, currently for GRIB-API only.
3169 }
3170 record_t;
3171 
3172 
3173 typedef struct {
3174   record_t *records;
3175   int      *recIDs;      // IDs of non constant records
3176   int       recordSize;  // number of allocated records
3177   int       nrecs;       // number of used records
3178                          // tsID=0 nallrecs
3179                          // tsID>0 number of non constant records
3180   int       nallrecs;    // number of all records
3181   int       curRecID;    // current record ID
3182   bool      next;
3183   off_t     position;    // timestep file position
3184   taxis_t   taxis;
3185 }
3186 tsteps_t;
3187 
3188 
3189 typedef struct {
3190   int       nlevs;
3191   int       subtypeIndex; // corresponding tile in subtype_t structure (subtype->self)
3192   int      *recordID;     // record IDs: [nlevs]
3193   int      *lindex;       // level index
3194 } sleveltable_t;
3195 
3196 
3197 typedef struct {
3198   int            ncvarid;
3199   int            subtypeSize;
3200   sleveltable_t *recordTable; // record IDs for each subtype
3201   bool           defmiss;     // true: if missval is defined in file
3202   bool           isUsed;
3203 
3204   int            gridID;
3205   int            zaxisID;
3206   int            tsteptype;   // TSTEP_*
3207   int            subtypeID;   // subtype ID, e.g. for tile-related meta-data (currently for GRIB-API only).
3208 }
3209 svarinfo_t;
3210 
3211 
3212 typedef struct {
3213   int       ilev;
3214   int       mlev;
3215   int       ilevID;
3216   int       mlevID;
3217 }
3218 VCT;
3219 
3220 #ifdef HAVE_LIBNETCDF
3221 enum {
3222   CDF_DIMID_X,
3223   CDF_DIMID_Y,
3224   CDF_DIMID_RP, // reducedPoints
3225   CDF_VARID_X,
3226   CDF_VARID_Y,
3227   CDF_VARID_RP, // reducedPoints
3228   CDF_VARID_A,
3229   CDF_SIZE_ncIDs,
3230 };
3231 typedef struct {
3232   int gridID;
3233   int ncIDs[CDF_SIZE_ncIDs];
3234 }
3235 ncgrid_t;
3236 #endif
3237 
3238 typedef struct {
3239   int         self;
3240   int         accesstype;   // TYPE_REC or TYPE_VAR
3241   int         accessmode;
3242   int         filetype;
3243   int         byteorder;
3244   int         fileID;
3245   int         filemode;
3246   int         nrecs;        // number of records
3247   size_t      numvals;
3248   char       *filename;
3249   Record     *record;
3250   svarinfo_t *vars;
3251   int         nvars;        // number of variables
3252   int         varsAllocated;
3253   int         curTsID;      // current timestep ID
3254   int         rtsteps;      // number of tsteps accessed
3255   long        ntsteps;      // number of tsteps : only set if all records accessed
3256   tsteps_t   *tsteps;
3257   int         tstepsTableSize;
3258   int         tstepsNextID;
3259   basetime_t  basetime;
3260   int         ncmode;
3261   int         vlistID;
3262 #ifdef HAVE_LIBNETCDF
3263   int         nc_complex_float_id;
3264   int         nc_complex_double_id;
3265   ncgrid_t    ncgrid[MAX_GRIDS_PS];
3266   int         zaxisID[MAX_ZAXES_PS];	// Warning: synchronous array to vlist_to_pointer(vlistID)->zaxisIDs
3267   int         nczvarID[MAX_ZAXES_PS];
3268   VCT         vct;
3269 #endif
3270   int         globalatts;
3271   int         localatts;
3272   int         unreduced;
3273   int         have_missval;
3274   int         comptype;      // compression type
3275   int         complevel;     // compression level
3276   bool        sortname;
3277   bool        sortparam;
3278 #if defined (GRIBCONTAINER2D)
3279   void      **gribContainers;
3280 #else
3281   void       *gribContainers;
3282 #endif
3283 
3284   int         numWorker;
3285   int         nextRecID;
3286   int         cachedTsID;
3287   void       *jobs;
3288   void       *jobManager;
3289 
3290   void *gh; // grib handle
3291 }
3292 stream_t;
3293 
3294 
3295 /* Length of optional keyword/value pair list */
3296 #define MAX_OPT_GRIB_ENTRIES 500
3297 
3298 enum cdi_convention {CDI_CONVENTION_ECHAM, CDI_CONVENTION_CF};
3299 
3300 // Data type specification for optional key/value pairs (GRIB)
3301 typedef enum {
3302   t_double = 0,
3303   t_int    = 1
3304 } key_val_pair_datatype;
3305 
3306 // Data structure holding optional key/value pairs for GRIB
3307 typedef struct
3308 {
3309   char*                  keyword;        // keyword string
3310   bool                   update;
3311   key_val_pair_datatype  data_type;      // data type of this key/value pair
3312   double                 dbl_val;        // double value (data_type == t_double)
3313   int                    int_val;        // integer value (data_type == t_int)
3314   int                    subtype_index;  // tile index for this key-value pair
3315 } opt_key_val_pair_t;
3316 
3317 // enum for differenciating between the different times that we handle
3318 typedef enum {
3319   kCdiTimeType_referenceTime,
3320   kCdiTimeType_startTime,
3321   kCdiTimeType_endTime
3322 } CdiTimeType;
3323 
3324 
3325 #define  CDI_FILETYPE_UNDEF          -1   // Unknown/not yet defined file type
3326 
3327 
3328 extern int cdiDebugExt;
3329 extern int CDI_Debug;      // If set to 1, debuggig (default 0)
3330 extern int CDI_Recopt;
3331 extern bool CDI_gribapi_debug;
3332 extern bool CDI_gribapi_grib1;
3333 extern double CDI_Default_Missval;
3334 extern double CDI_Grid_Missval;
3335 extern int CDI_Default_InstID;
3336 extern int CDI_Default_ModelID;
3337 extern int CDI_Default_TableID;
3338 extern int cdiDefaultLeveltype;
3339 extern int CDI_Default_Calendar;
3340 //extern int cdiNcMissingValue;
3341 extern int CDI_Netcdf_Chunksizehint;
3342 extern int CDI_Chunk_Type;
3343 extern int CDI_Split_Ltype105;
3344 extern int cdiDataUnreduced;
3345 extern int cdiSortName;
3346 extern int cdiSortParam;
3347 extern int cdiHaveMissval;
3348 extern bool CDI_Ignore_Att_Coordinates;
3349 extern bool CDI_Coordinates_Lon_Lat;
3350 extern bool CDI_Ignore_Valid_Range;
3351 extern int CDI_Skip_Records;
3352 extern int CDI_Convention;
3353 extern int CDI_Inventory_Mode;
3354 extern int CDO_version_info;
3355 extern int CDI_Read_Cell_Corners;
3356 extern int CDI_CMOR_Mode;
3357 extern int CDI_Reduce_Dim;
3358 extern size_t CDI_Netcdf_Hdr_Pad;
3359 extern bool CDI_Netcdf_Lazy_Grid_Load;
3360 extern int STREAM_Debug;
3361 
3362 
3363 extern char *cdiPartabPath;
3364 extern int   cdiPartabIntern;
3365 extern const resOps streamOps;
3366 
3367 static inline stream_t *
stream_to_pointer(int idx)3368 stream_to_pointer(int idx)
3369 {
3370   return (stream_t *)reshGetVal(idx, &streamOps);
3371 }
3372 
3373 static inline void
stream_check_ptr(const char * caller,stream_t * streamptr)3374 stream_check_ptr(const char *caller, stream_t *streamptr)
3375 {
3376   if ( streamptr == NULL )
3377     Errorc("stream undefined!");
3378 }
3379 
3380 int     streamInqFileID(int streamID);
3381 
3382 void    gridDefHasDims(int gridID, int hasdims);
3383 int     gridInqHasDims(int gridID);
3384 int     zaxisInqLevelID(int zaxisID, double level);
3385 
3386 void    streamCheckID(const char *caller, int streamID);
3387 
3388 void    streamDefineTaxis(int streamID);
3389 
3390 int     streamsNewEntry(int filetype);
3391 void    streamsInitEntry(int streamID);
3392 void    cdiStreamSetupVlist(stream_t *streamptr, int vlistID);
3393 // default implementation of the overridable function
3394 void    cdiStreamSetupVlist_(stream_t *streamptr, int vlistID);
3395 int     stream_new_var(stream_t *streamptr, int gridID, int zaxisID, int tilesetID);
3396 
3397 int     tstepsNewEntry(stream_t *streamptr);
3398 
3399 const char *strfiletype(int filetype);
3400 
3401 void    cdi_generate_vars(stream_t *streamptr);
3402 
3403 void    vlist_check_contents(int vlistID);
3404 
3405 void    cdi_create_records(stream_t *streamptr, int tsID);
3406 
3407 void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1, const char *container_name);
3408 
3409 int     recordNewEntry(stream_t *streamptr, int tsID);
3410 
3411 void    cdiCreateTimesteps(stream_t *streamptr);
3412 
3413 void    recordInitEntry(record_t *record);
3414 
3415 void    cdiCheckZaxis(int zaxisID);
3416 
3417 void    cdiDefAccesstype(int streamID, int type);
3418 int     cdiInqAccesstype(int streamID);
3419 
3420 int     getByteswap(int byteorder);
3421 
3422 void cdiStreamGetIndexList(unsigned numIDs, int IDs[]);
3423 
3424 void  cdiInitialize(void);
3425 
3426 char *cdiEscapeSpaces(const char *string);
3427 char *cdiUnescapeSpaces(const char *string, const char **outStringEnd);
3428 
3429 #define CDI_UNIT_PA   1
3430 #define CDI_UNIT_HPA  2
3431 #define CDI_UNIT_MM   3
3432 #define CDI_UNIT_CM   4
3433 #define CDI_UNIT_DM   5
3434 #define CDI_UNIT_M    6
3435 
3436 struct streamAssoc
3437 {
3438   int streamID, vlistID;
3439 };
3440 
3441 struct streamAssoc
3442 streamUnpack(char *unpackBuffer, int unpackBufferSize,
3443              int *unpackBufferPos, int originNamespace, void *context);
3444 
3445 int
3446 cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
3447                              int filetype, stream_t *streamptr,
3448                              int recordBufIsToBeCreated);
3449 
3450 int
3451 streamOpenID(const char *filename, char filemode, int filetype,
3452              int resH);
3453 
3454 void
3455 cdiStreamDefVlist_(int streamID, int vlistID);
3456 
3457 int
3458 cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, size_t nmiss);
3459 
3460 void
3461 cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
3462                         const int rect[][2], const void *data, size_t nmiss);
3463 void
3464 cdiStreamCloseDefaultDelegate(stream_t *streamptr,
3465                               int recordBufIsToBeDeleted);
3466 
3467 int cdiStreamDefTimestep_(stream_t *streamptr, int tsID);
3468 
3469 void cdiStreamSync_(stream_t *streamptr);
3470 
3471 const char *cdiUnitNamePtr(int cdi_unit);
3472 
3473 enum {
3474   // 8192 is known to work on most systems (4096 isn't on Alpha)
3475   commonPageSize = 8192,
3476 };
3477 
3478 size_t cdiGetPageSize(bool largePageAlign);
3479 
3480 void zaxisGetIndexList(int nzaxis, int *zaxisIndexList);
3481 
3482 #ifdef __cplusplus
3483 extern "C" {
3484 #endif
3485 
3486 // functions used in CDO !!!
3487 
3488 void cdiDefTableID(int tableID);
3489 
3490 void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *xvals);
3491 void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *yvals);
3492 
3493 static inline
cdi_check_gridsize_int_limit(const char * format,size_t gridsize)3494 void cdi_check_gridsize_int_limit(const char *format, size_t gridsize)
3495 {
3496   if ( gridsize > INT_MAX ) Error("%s format grid size (%zu) limit exceeded (%zu)!", format, gridsize, INT_MAX);
3497 }
3498 
3499 int cdiBaseFiletype(int filetype);
3500 
3501 #if defined (__cplusplus)
3502 }
3503 #endif
3504 
3505 #endif  /* CDI_INT_H */
3506 /*
3507  * Local Variables:
3508  * c-file-style: "Java"
3509  * c-basic-offset: 2
3510  * indent-tabs-mode: nil
3511  * show-trailing-whitespace: t
3512  * require-trailing-newline: t
3513  * End:
3514  */
3515 #ifndef  CDF_INT_H
3516 #define  CDF_INT_H
3517 
3518 #ifdef HAVE_LIBNETCDF
3519 
3520 #include <netcdf.h>
3521 
3522 void cdf_create(const char *path, int cmode, int *idp);
3523 int  cdf_open(const char *path, int omode, int *idp);
3524 void cdf_close(int ncid);
3525 
3526 void cdf_redef(int ncid);
3527 void cdf_enddef(int ncid);
3528 void cdf__enddef(const int ncid, const size_t hdr_pad);
3529 void cdf_sync(int ncid);
3530 
3531 void cdf_inq(int ncid, int *ndimsp, int *nvarsp, int *ngattsp, int *unlimdimidp);
3532 
3533 void cdf_def_dim(int ncid, const char *name, size_t len, int *idp);
3534 void cdf_inq_dimid(int ncid, const char *name, int *dimidp);
3535 void cdf_inq_dim(int ncid, int dimid, char *name, size_t * lengthp);
3536 void cdf_inq_dimname(int ncid, int dimid, char *name);
3537 void cdf_inq_dimlen(int ncid, int dimid, size_t * lengthp);
3538 void cdf_def_var(int ncid, const char *name, nc_type xtype, int ndims, const int dimids[], int *varidp);
3539 void cdf_def_var_serial(int ncid, const char *name, nc_type xtype, int ndims, const int dimids[], int *varidp);
3540 void cdf_inq_varid(int ncid, const char *name, int *varidp);
3541 void cdf_inq_nvars(int ncid, int *nvarsp);
3542 void cdf_inq_var(int ncid, int varid, char *name, nc_type *xtypep, int *ndimsp, int dimids[], int *nattsp);
3543 void cdf_inq_varname(int ncid, int varid, char *name);
3544 void cdf_inq_vartype(int ncid, int varid, nc_type *xtypep);
3545 void cdf_inq_varndims(int ncid, int varid, int *ndimsp);
3546 void cdf_inq_vardimid(int ncid, int varid, int dimids[]);
3547 void cdf_inq_varnatts(int ncid, int varid, int *nattsp);
3548 
3549 void cdf_copy_att (int ncid_in, int varid_in, const char *name, int ncid_out, int varid_out);
3550 void cdf_put_var_text   (int ncid, int varid, const char *tp);
3551 void cdf_put_var_uchar  (int ncid, int varid, const unsigned char *up);
3552 void cdf_put_var_schar  (int ncid, int varid, const signed char *cp);
3553 void cdf_put_var_short  (int ncid, int varid, const short *sp);
3554 void cdf_put_var_int    (int ncid, int varid, const int *ip);
3555 void cdf_put_var_long   (int ncid, int varid, const long *lp);
3556 void cdf_put_var_float  (int ncid, int varid, const float *fp);
3557 void cdf_put_var_double (int ncid, int varid, const double *dp);
3558 
3559 void cdf_get_var_text   (int ncid, int varid, char *tp);
3560 void cdf_get_var_uchar  (int ncid, int varid, unsigned char *up);
3561 void cdf_get_var_schar  (int ncid, int varid, signed char *cp);
3562 void cdf_get_var_short  (int ncid, int varid, short *sp);
3563 void cdf_get_var_int    (int ncid, int varid, int *ip);
3564 void cdf_get_var_long   (int ncid, int varid, long *lp);
3565 void cdf_get_var_float  (int ncid, int varid, float *fp);
3566 void cdf_get_var_double (int ncid, int varid, double *dp);
3567 
3568 void cdf_get_var1_text(int ncid, int varid, const size_t index[], char *tp);
3569 
3570 void cdf_get_var1_double(int ncid, int varid, const size_t index[], double *dp);
3571 void cdf_put_var1_double(int ncid, int varid, const size_t index[], const double *dp);
3572 
3573 void cdf_get_vara_uchar(int ncid, int varid, const size_t start[], const size_t count[], unsigned char *tp);
3574 void cdf_get_vara_text(int ncid, int varid, const size_t start[], const size_t count[], char *tp);
3575 
3576 void cdf_get_vara_double(int ncid, int varid, const size_t start[], const size_t count[], double *dp);
3577 void cdf_put_vara_double(int ncid, int varid, const size_t start[], const size_t count[], const double *dp);
3578 
3579 void cdf_get_vara_float(int ncid, int varid, const size_t start[], const size_t count[], float *fp);
3580 void cdf_put_vara_float(int ncid, int varid, const size_t start[], const size_t count[], const float *fp);
3581 
3582 void cdf_get_vara_int(int ncid, int varid, const size_t start[], const size_t count[], int *dp);
3583 
3584 void cdf_get_vara(int ncid, int varid, const size_t start[], const size_t count[], void *cp);
3585 void cdf_put_vara(int ncid, int varid, const size_t start[], const size_t count[], const void *cp);
3586 
3587 void cdf_put_att_text(int ncid, int varid, const char *name, size_t len, const char *tp);
3588 void cdf_put_att_int(int ncid, int varid, const char *name, nc_type xtype, size_t len, const int *ip);
3589 void cdf_put_att_float(int ncid, int varid, const char *name, nc_type xtype, size_t len, const float *dp);
3590 void cdf_put_att_double(int ncid, int varid, const char *name, nc_type xtype, size_t len, const double *dp);
3591 
3592 void cdf_get_att_string(int ncid, int varid, const char *name, char **tp);
3593 void cdf_get_att_text  (int ncid, int varid, const char *name, char *tp);
3594 void cdf_get_att_int   (int ncid, int varid, const char *name, int *ip);
3595 void cdf_get_att_long  (int ncid, int varid, const char *name, long *ip);
3596 void cdf_get_att_double(int ncid, int varid, const char *name, double *dp);
3597 
3598 void cdf_inq_att    (int ncid, int varid, const char *name, nc_type * xtypep, size_t * lenp);
3599 void cdf_inq_atttype(int ncid, int varid, const char *name, nc_type *xtypep);
3600 void cdf_inq_attlen (int ncid, int varid, const char *name, size_t *lenp);
3601 void cdf_inq_attname(int ncid, int varid, int attnum, char *name);
3602 void cdf_inq_attid  (int ncid, int varid, const char *name, int *attnump);
3603 
3604 void cdf_def_var_chunking(int ncid, int varid, int storage, const size_t *chunksizesp);
3605 
3606 typedef int (*cdi_nc__create_funcp)(const char *path, int cmode,
3607                                     size_t initialsz, size_t *chunksizehintp,
3608                                     int *ncidp);
3609 
3610 typedef void (*cdi_cdf_def_var_funcp)(int ncid, const char *name,
3611                                       nc_type xtype, int ndims,
3612                                       const int dimids[], int *varidp);
3613 
3614 #endif
3615 
3616 #endif  /* CDF_INT_H */
3617 /*
3618  * Local Variables:
3619  * c-file-style: "Java"
3620  * c-basic-offset: 2
3621  * indent-tabs-mode: nil
3622  * show-trailing-whitespace: t
3623  * require-trailing-newline: t
3624  * End:
3625  */
3626 #ifdef  HAVE_CONFIG_H
3627 #endif
3628 
3629 #include <ctype.h>
3630 
3631 
3632 
cdfLibraryVersion(void)3633 const char *cdfLibraryVersion(void)
3634 {
3635 #ifdef  HAVE_LIBNETCDF
3636   return nc_inq_libvers();
3637 #else
3638   return "library undefined";
3639 #endif
3640 }
3641 
3642 #ifdef  HAVE_H5GET_LIBVERSION
3643 #ifdef  __cplusplus
3644 extern "C" {
3645 #endif
3646   int H5get_libversion(unsigned *, unsigned *, unsigned *);
3647 #ifdef  __cplusplus
3648 }
3649 #endif
3650 #endif
3651 
hdfLibraryVersion(void)3652 const char *hdfLibraryVersion(void)
3653 {
3654 #ifdef  HAVE_H5GET_LIBVERSION
3655   static char hdf_libvers[256];
3656   static int linit = 0;
3657   if (!linit)
3658     {
3659       linit = 1;
3660       unsigned majnum, minnum, relnum;
3661       H5get_libversion(&majnum, &minnum, &relnum);
3662 #ifdef  HAVE_NC4HDF5_THREADSAFE
3663       sprintf(hdf_libvers, "%u.%u.%u threadsafe", majnum, minnum, relnum);
3664 #else
3665       sprintf(hdf_libvers, "%u.%u.%u", majnum, minnum, relnum);
3666 #endif
3667     }
3668 
3669   return hdf_libvers;
3670 #else
3671   return "library undefined";
3672 #endif
3673 }
3674 
3675 
3676 int CDF_Debug   = 0;    /* If set to 1, debugging           */
3677 
3678 
cdfDebug(int debug)3679 void cdfDebug(int debug)
3680 {
3681   CDF_Debug = debug;
3682 
3683   if ( CDF_Debug )
3684     Message("debug level %d", debug);
3685 }
3686 
3687 #ifdef  HAVE_LIBNETCDF
3688 static
cdfComment(int ncid)3689 void cdfComment(int ncid)
3690 {
3691   static char comment[256] = "Climate Data Interface version ";
3692   static bool init = false;
3693 
3694   if ( ! init )
3695     {
3696       init = true;
3697       const char *libvers = cdiLibraryVersion();
3698 
3699       if ( ! isdigit((int) *libvers) )
3700 	strcat(comment, "??");
3701       else
3702 	strcat(comment, libvers);
3703       strcat(comment, " (https://mpimet.mpg.de/cdi)");
3704     }
3705 
3706   cdf_put_att_text(ncid, NC_GLOBAL, "CDI", strlen(comment), comment);
3707 }
3708 #endif
3709 
cdfOpenFile(const char * filename,const char * mode,int * filetype)3710 static int cdfOpenFile(const char *filename, const char *mode, int *filetype)
3711 {
3712   int ncid = -1;
3713 #ifdef  HAVE_LIBNETCDF
3714   int fmode = tolower(*mode);
3715   int writemode = NC_CLOBBER;
3716   int readmode = NC_NOWRITE;
3717 
3718   if ( filename == NULL )
3719     ncid = CDI_EINVAL;
3720   else
3721     {
3722       switch (fmode)
3723 	{
3724 	case 'r':
3725           {
3726             int status = cdf_open(filename, readmode, &ncid);
3727             if ( status > 0 && ncid < 0 ) ncid = CDI_ESYSTEM;
3728 #ifdef  HAVE_NETCDF4
3729             else
3730               {
3731                 int format;
3732                 (void) nc_inq_format(ncid, &format);
3733                 if ( format == NC_FORMAT_NETCDF4_CLASSIC )
3734                   *filetype = CDI_FILETYPE_NC4C;
3735               }
3736 #endif
3737           }
3738 	  break;
3739 	case 'w':
3740 #ifdef  NC_64BIT_OFFSET
3741 	  if      ( *filetype == CDI_FILETYPE_NC2  ) writemode |= NC_64BIT_OFFSET;
3742 #endif
3743 #ifdef  NC_64BIT_DATA
3744 	  if      ( *filetype == CDI_FILETYPE_NC5  ) writemode |= NC_64BIT_DATA;
3745 #endif
3746 #ifdef  HAVE_NETCDF4
3747 	  if      ( *filetype == CDI_FILETYPE_NC4  ) writemode |= NC_NETCDF4;
3748 	  else if ( *filetype == CDI_FILETYPE_NC4C ) writemode |= NC_NETCDF4 | NC_CLASSIC_MODEL;
3749 #endif
3750 	  cdf_create(filename, writemode, &ncid);
3751 	  if ( CDO_version_info ) cdfComment(ncid);
3752           cdf_put_att_text(ncid, NC_GLOBAL, "Conventions", 6, "CF-1.6");
3753 	  break;
3754 	case 'a':
3755 	  cdf_open(filename, NC_WRITE, &ncid);
3756 	  break;
3757 	default:
3758 	  ncid = CDI_EINVAL;
3759 	}
3760     }
3761 #endif
3762 
3763   return ncid;
3764 }
3765 
3766 
cdfOpen(const char * filename,const char * mode,int filetype)3767 int cdfOpen(const char *filename, const char *mode, int filetype)
3768 {
3769   int fileID = -1;
3770   bool open_file = true;
3771 
3772   if ( CDF_Debug )
3773     Message("Open %s with mode %c", filename, *mode);
3774 
3775 #ifdef  HAVE_LIBNETCDF
3776 #ifndef  NC_64BIT_OFFSET
3777   if ( filetype == CDI_FILETYPE_NC2 ) open_file = false;
3778 #endif
3779 #ifndef  NC_64BIT_DATA
3780   if ( filetype == CDI_FILETYPE_NC5 ) open_file = false;
3781 #endif
3782 #endif
3783 
3784   if ( open_file )
3785     {
3786       fileID = cdfOpenFile(filename, mode, &filetype);
3787 
3788       if ( CDF_Debug )
3789         Message("File %s opened with id %d", filename, fileID);
3790     }
3791   else
3792     {
3793       fileID = CDI_ELIBNAVAIL;
3794     }
3795 
3796   return fileID;
3797 }
3798 
3799 static
cdf4CheckLibVersions(void)3800 int cdf4CheckLibVersions(void)
3801 {
3802   int status = 0;
3803 #ifdef HAVE_NETCDF4
3804 #ifdef HAVE_H5GET_LIBVERSION
3805   static int checked = 0;
3806   if (!checked)
3807     {
3808       checked = 1;
3809       unsigned majnum, minnum, relnum;
3810 
3811       sscanf(nc_inq_libvers(), "%u.%u.%u", &majnum, &minnum, &relnum);
3812       //printf("netCDF %u.%u.%u\n", majnum, minnum, relnum);
3813       const unsigned ncmaxver = 4 * 1000000 + 4 * 1000;
3814       const unsigned nclibver = majnum * 1000000 + minnum * 1000 + relnum;
3815 
3816       if (nclibver <= ncmaxver)
3817         {
3818           H5get_libversion(&majnum, &minnum, &relnum);
3819           const unsigned hdf5maxver = 1 * 1000000 + 10 * 1000;
3820           const unsigned hdf5libver = majnum * 1000000 + minnum * 1000 + relnum;
3821 
3822           if (hdf5libver >= hdf5maxver)
3823             {
3824               fprintf(stderr, "NetCDF library 4.4.0 or earlier, combined with libhdf5 1.10.0 or greater not supported!\n");
3825               status = 1;
3826             }
3827         }
3828     }
3829 #endif
3830 #endif
3831   return status;
3832 }
3833 
cdf4Open(const char * filename,const char * mode,int * filetype)3834 int cdf4Open(const char *filename, const char *mode, int *filetype)
3835 {
3836   int fileID = -1;
3837   bool open_file = false;
3838 
3839   if ( CDF_Debug ) Message("Open %s with mode %c", filename, *mode);
3840 
3841 #ifdef  HAVE_NETCDF4
3842   open_file = true;
3843 #endif
3844 
3845   if ( open_file )
3846     {
3847       if (cdf4CheckLibVersions() == 0)
3848         {
3849           fileID = cdfOpenFile(filename, mode, filetype);
3850           if ( CDF_Debug ) Message("File %s opened with id %d", filename, fileID);
3851         }
3852       else
3853         {
3854           fileID = CDI_EUFTYPE;
3855         }
3856     }
3857   else
3858     {
3859       fileID = CDI_ELIBNAVAIL;
3860     }
3861 
3862   return fileID;
3863 }
3864 
3865 
cdfCloseFile(int fileID)3866 static void cdfCloseFile(int fileID)
3867 {
3868 #ifdef  HAVE_LIBNETCDF
3869   cdf_close(fileID);
3870 #endif
3871 }
3872 
cdfClose(int fileID)3873 void cdfClose(int fileID)
3874 {
3875   cdfCloseFile(fileID);
3876 }
3877 /*
3878  * Local Variables:
3879  * c-file-style: "Java"
3880  * c-basic-offset: 2
3881  * indent-tabs-mode: nil
3882  * show-trailing-whitespace: t
3883  * require-trailing-newline: t
3884  * End:
3885  */
3886 #ifndef NAMESPACE_H
3887 #define NAMESPACE_H
3888 
3889 #ifdef HAVE_CONFIG_H
3890 #endif
3891 
3892 
3893 typedef struct {
3894   int idx;
3895   int nsp;
3896 } namespaceTuple_t;
3897 
3898 enum namespaceSwitch
3899 {
3900   NSSWITCH_NO_SUCH_SWITCH = -1,
3901   NSSWITCH_ABORT,
3902   NSSWITCH_WARNING,
3903   NSSWITCH_SERIALIZE_GET_SIZE,
3904   NSSWITCH_SERIALIZE_PACK,
3905   NSSWITCH_SERIALIZE_UNPACK,
3906   NSSWITCH_FILE_OPEN,
3907   NSSWITCH_FILE_WRITE,
3908   NSSWITCH_FILE_CLOSE,
3909   NSSWITCH_STREAM_OPEN_BACKEND,
3910   NSSWITCH_STREAM_DEF_VLIST_,
3911   NSSWITCH_STREAM_SETUP_VLIST,
3912   NSSWITCH_STREAM_WRITE_VAR_,
3913   NSSWITCH_STREAM_WRITE_VAR_CHUNK_,
3914   NSSWITCH_STREAM_WRITE_VAR_PART_,
3915   NSSWITCH_STREAM_WRITE_SCATTERED_VAR_PART_,
3916   NSSWITCH_STREAM_CLOSE_BACKEND,
3917   NSSWITCH_STREAM_DEF_TIMESTEP_,
3918   NSSWITCH_STREAM_SYNC,
3919 #ifdef HAVE_LIBNETCDF
3920   NSSWITCH_NC__CREATE,
3921   NSSWITCH_CDF_DEF_VAR,
3922   NSSWITCH_CDF_DEF_TIMESTEP,
3923   NSSWITCH_CDF_STREAM_SETUP,
3924 #endif
3925   NUM_NAMESPACE_SWITCH,
3926 };
3927 
3928 union namespaceSwitchValue
3929 {
3930   void *data;
3931   void (*func)();
3932 };
3933 
3934 #define NSSW_FUNC(p) ((union namespaceSwitchValue){ .func = (void (*)())(p) })
3935 #define NSSW_DATA(p) ((union namespaceSwitchValue){ .data = (void *)(p) })
3936 
3937 //int              namespaceNew();
3938 //void             namespaceDelete(int namespaceID);
3939 void             namespaceCleanup      ( void );
3940 int              namespaceGetNumber    ( void );
3941 //void             namespaceSetActive(int namespaceID);
3942 //int              namespaceGetActive    ( void );
3943 int              namespaceIdxEncode    ( namespaceTuple_t );
3944 int              namespaceIdxEncode2   ( int, int );
3945 namespaceTuple_t namespaceResHDecode   ( int );
3946 int              namespaceAdaptKey     ( int originResH, int originNamespace);
3947 int              namespaceAdaptKey2    ( int );
3948 void namespaceSwitchSet(enum namespaceSwitch sw,
3949                         union namespaceSwitchValue value);
3950 union namespaceSwitchValue namespaceSwitchGet(enum namespaceSwitch sw);
3951 
3952 
3953 #endif
3954 /*
3955  * Local Variables:
3956  * c-file-style: "Java"
3957  * c-basic-offset: 2
3958  * indent-tabs-mode: nil
3959  * show-trailing-whitespace: t
3960  * require-trailing-newline: t
3961  * End:
3962  */
3963 #ifdef HAVE_CONFIG_H
3964 #endif
3965 
3966 #include <sys/stat.h>
3967 
3968 
3969 #ifdef HAVE_LIBNETCDF
3970 
cdf_create(const char * path,int cmode,int * ncidp)3971 void cdf_create(const char *path, int cmode, int *ncidp)
3972 {
3973   size_t initialsz = 0, chunksizehint = 0;
3974 
3975 #if defined(__SX__) || defined(ES)
3976   chunksizehint = 16777216; /* 16 MB */
3977 #endif
3978 
3979   if ( CDI_Netcdf_Chunksizehint != CDI_UNDEFID )
3980     chunksizehint = (size_t)CDI_Netcdf_Chunksizehint;
3981 
3982   cdi_nc__create_funcp my_nc__create =
3983     (cdi_nc__create_funcp)namespaceSwitchGet(NSSWITCH_NC__CREATE).func;
3984   int status = my_nc__create(path, cmode, initialsz, &chunksizehint, ncidp);
3985 
3986   if ( CDF_Debug || status != NC_NOERR )
3987     Message("ncid = %d  mode = %d  chunksizehint = %zu file = %s", *ncidp, cmode, chunksizehint, path);
3988 
3989   if ( status != NC_NOERR ) Error("%s: %s", path, nc_strerror(status));
3990 
3991   int oldfill;
3992   status = nc_set_fill(*ncidp, NC_NOFILL, &oldfill);
3993 
3994   if ( status != NC_NOERR ) Error("%s: %s", path, nc_strerror(status));
3995 }
3996 
3997 
cdf_open(const char * path,int omode,int * ncidp)3998 int cdf_open(const char *path, int omode, int *ncidp)
3999 {
4000   int status = 0;
4001   bool dapfile = false;
4002 
4003 #ifdef HAVE_LIBNC_DAP
4004   if ( strncmp(path, "http:", 5) == 0 || strncmp(path, "https:", 6) == 0 ) dapfile = true;
4005 #endif
4006 
4007   if ( dapfile )
4008     {
4009       status = nc_open(path, omode, ncidp);
4010     }
4011   else
4012     {
4013       struct stat filestat;
4014       if ( stat(path, &filestat) != 0 ) SysError(path);
4015 
4016       size_t chunksizehint = 0;
4017 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
4018       chunksizehint = (size_t) filestat.st_blksize * 4;
4019       if ( chunksizehint > (size_t) filestat.st_size ) chunksizehint = (size_t) filestat.st_size;
4020 #endif
4021       /*
4022       if ( chunksizehint < ChunkSizeMin ) chunksizehint = ChunkSizeMin;
4023       */
4024       if ( CDI_Netcdf_Chunksizehint != CDI_UNDEFID )
4025         chunksizehint = (size_t)CDI_Netcdf_Chunksizehint;
4026 
4027       /* FIXME: parallel part missing */
4028       status = nc__open(path, omode, &chunksizehint, ncidp);
4029 
4030       if ( CDF_Debug ) Message("chunksizehint %zu", chunksizehint);
4031     }
4032 
4033   if ( CDF_Debug )
4034     Message("ncid = %d  mode = %d  file = %s", *ncidp, omode, path);
4035 
4036   if ( CDF_Debug && status != NC_NOERR ) Message("%s", nc_strerror(status));
4037 
4038   return status;
4039 }
4040 
4041 
cdf_close(int ncid)4042 void cdf_close(int ncid)
4043 {
4044   int status = nc_close(ncid);
4045   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4046 }
4047 
4048 
cdf_redef(int ncid)4049 void cdf_redef(int ncid)
4050 {
4051   int status = nc_redef(ncid);
4052   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4053 }
4054 
4055 
cdf_enddef(int ncid)4056 void cdf_enddef(int ncid)
4057 {
4058   int status = nc_enddef(ncid);
4059   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4060 }
4061 
4062 
cdf__enddef(const int ncid,const size_t hdr_pad)4063 void cdf__enddef(const int ncid, const size_t hdr_pad)
4064 {
4065   const size_t v_align   = 4UL; // [B] Alignment of beginning of data section for fixed variables
4066   const size_t v_minfree = 0UL; // [B] Pad at end of data section for fixed size variables
4067   const size_t r_align   = 4UL; // [B] Alignment of beginning of data section for record variables
4068 
4069   // nc_enddef(ncid) is equivalent to nc__enddef(ncid, 0, 4, 0, 4)
4070   int status = nc__enddef(ncid, hdr_pad, v_align, v_minfree, r_align);
4071   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4072 }
4073 
4074 
cdf_sync(int ncid)4075 void cdf_sync(int ncid)
4076 {
4077   int status = nc_sync(ncid);
4078   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4079 }
4080 
4081 
cdf_inq(int ncid,int * ndimsp,int * nvarsp,int * ngattsp,int * unlimdimidp)4082 void cdf_inq(int ncid, int *ndimsp, int *nvarsp, int *ngattsp, int *unlimdimidp)
4083 {
4084   int status = nc_inq(ncid, ndimsp, nvarsp, ngattsp, unlimdimidp);
4085 
4086   if ( CDF_Debug || status != NC_NOERR )
4087     Message("ncid = %d ndims = %d nvars = %d ngatts = %d unlimid = %d",
4088 	    ncid, *ndimsp, *nvarsp, *ngattsp, *unlimdimidp);
4089 
4090   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4091 }
4092 
4093 
cdf_def_dim(int ncid,const char * name,size_t len,int * dimidp)4094 void cdf_def_dim(int ncid, const char *name, size_t len, int *dimidp)
4095 {
4096   int status = nc_def_dim(ncid, name, len, dimidp);
4097 
4098   if ( CDF_Debug || status != NC_NOERR )
4099     Message("ncid = %d  name = %s  len = %d", ncid, name, len);
4100 
4101   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4102 }
4103 
4104 
cdf_inq_dimid(int ncid,const char * name,int * dimidp)4105 void cdf_inq_dimid(int ncid, const char *name, int *dimidp)
4106 {
4107   int status = nc_inq_dimid(ncid, name, dimidp);
4108 
4109   if ( CDF_Debug || status != NC_NOERR )
4110     Message("ncid = %d  name = %s  dimid= %d", ncid, name, *dimidp);
4111 
4112   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4113 }
4114 
4115 
cdf_inq_dim(int ncid,int dimid,char * name,size_t * lengthp)4116 void cdf_inq_dim(int ncid, int dimid, char *name, size_t * lengthp)
4117 {
4118   int status = nc_inq_dim(ncid, dimid, name, lengthp);
4119 
4120   if ( CDF_Debug || status != NC_NOERR )
4121     Message("ncid = %d  dimid = %d  length = %d name = %s", ncid, dimid, *lengthp, name);
4122 
4123   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4124 }
4125 
4126 
cdf_inq_dimname(int ncid,int dimid,char * name)4127 void cdf_inq_dimname(int ncid, int dimid, char *name)
4128 {
4129   int status = nc_inq_dimname(ncid, dimid, name);
4130 
4131   if ( CDF_Debug || status != NC_NOERR )
4132     Message("ncid = %d  dimid = %d  name = %s", ncid, dimid, name);
4133 
4134   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4135 }
4136 
4137 
cdf_inq_dimlen(int ncid,int dimid,size_t * lengthp)4138 void cdf_inq_dimlen(int ncid, int dimid, size_t * lengthp)
4139 {
4140   int status = nc_inq_dimlen(ncid, dimid, lengthp);
4141 
4142   if ( CDF_Debug || status != NC_NOERR )
4143     Message("ncid = %d dimid = %d length = %d", ncid, dimid, *lengthp);
4144 
4145   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4146 }
4147 
4148 
cdf_def_var(int ncid,const char * name,nc_type xtype,int ndims,const int dimids[],int * varidp)4149 void cdf_def_var(int ncid, const char *name, nc_type xtype, int ndims,
4150                  const int dimids[], int *varidp)
4151 {
4152   cdi_cdf_def_var_funcp my_cdf_def_var
4153     = (cdi_cdf_def_var_funcp)namespaceSwitchGet(NSSWITCH_CDF_DEF_VAR).func;
4154   my_cdf_def_var(ncid, name, xtype, ndims, dimids, varidp);
4155 }
4156 
4157 void
cdf_def_var_serial(int ncid,const char * name,nc_type xtype,int ndims,const int dimids[],int * varidp)4158 cdf_def_var_serial(int ncid, const char *name, nc_type xtype, int ndims,
4159                    const int dimids[], int *varidp)
4160 {
4161   int status = nc_def_var(ncid, name, xtype, ndims, dimids, varidp);
4162 
4163   if ( CDF_Debug || status != NC_NOERR )
4164     Message("ncid = %d  name = %s  xtype = %d  ndims = %d  varid = %d",
4165 	    ncid, name, xtype, ndims, *varidp);
4166 
4167   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4168 }
4169 
4170 
4171 
cdf_inq_varid(int ncid,const char * name,int * varidp)4172 void cdf_inq_varid(int ncid, const char *name, int *varidp)
4173 {
4174   int status = nc_inq_varid(ncid, name, varidp);
4175 
4176   if ( CDF_Debug || status != NC_NOERR )
4177     Message("ncid = %d  name = %s  varid = %d ", ncid, name, *varidp);
4178 
4179   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4180 }
4181 
4182 
cdf_inq_nvars(int ncid,int * nvarsp)4183 void cdf_inq_nvars(int ncid, int *nvarsp)
4184 {
4185   int status = nc_inq_nvars(ncid, nvarsp);
4186 
4187   if ( CDF_Debug || status != NC_NOERR )
4188     Message("ncid = %d  nvars = %d", ncid, *nvarsp);
4189 
4190   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4191 }
4192 
4193 
cdf_inq_var(int ncid,int varid,char * name,nc_type * xtypep,int * ndimsp,int dimids[],int * nattsp)4194 void cdf_inq_var(int ncid, int varid, char *name, nc_type *xtypep, int *ndimsp,
4195 		 int dimids[], int *nattsp)
4196 {
4197   int status = nc_inq_var(ncid, varid, name, xtypep, ndimsp, dimids, nattsp);
4198 
4199   if ( CDF_Debug || status != NC_NOERR )
4200     Message("ncid = %d varid = %d ndims = %d xtype = %d natts = %d name = %s",
4201 	    ncid, varid, *ndimsp, *xtypep, *nattsp, name);
4202 
4203   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4204 }
4205 
4206 
cdf_inq_varname(int ncid,int varid,char * name)4207 void cdf_inq_varname(int ncid, int varid, char *name)
4208 {
4209   int status = nc_inq_varname(ncid, varid, name);
4210 
4211   if ( CDF_Debug || status != NC_NOERR )
4212     Message("ncid = %d varid = %d name = %s", ncid, varid, name);
4213 
4214   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4215 }
4216 
4217 
cdf_inq_vartype(int ncid,int varid,nc_type * xtypep)4218 void cdf_inq_vartype(int ncid, int varid, nc_type *xtypep)
4219 {
4220   int status = nc_inq_vartype(ncid, varid, xtypep);
4221 
4222   if ( CDF_Debug || status != NC_NOERR )
4223     Message("ncid = %d varid = %d xtype = %s", ncid, varid, *xtypep);
4224 
4225   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4226 }
4227 
4228 
cdf_inq_varndims(int ncid,int varid,int * ndimsp)4229 void cdf_inq_varndims(int ncid, int varid, int *ndimsp)
4230 {
4231   int status = nc_inq_varndims(ncid, varid, ndimsp);
4232 
4233   if ( CDF_Debug || status != NC_NOERR )
4234     Message("ncid = %d varid = %d", ncid, varid);
4235 
4236   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4237 }
4238 
4239 
cdf_inq_vardimid(int ncid,int varid,int dimids[])4240 void cdf_inq_vardimid(int ncid, int varid, int dimids[])
4241 {
4242   int status = nc_inq_vardimid(ncid, varid, dimids);
4243 
4244   if ( CDF_Debug || status != NC_NOERR )
4245     Message("ncid = %d varid = %d", ncid, varid);
4246 
4247   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4248 }
4249 
4250 
cdf_inq_varnatts(int ncid,int varid,int * nattsp)4251 void cdf_inq_varnatts(int ncid, int varid, int *nattsp)
4252 {
4253   int status = nc_inq_varnatts(ncid, varid, nattsp);
4254 
4255   if ( CDF_Debug || status != NC_NOERR )
4256     Message("ncid = %d varid = %d nattsp = %d", ncid, varid, *nattsp);
4257 
4258   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4259 }
4260 
4261 
cdf_put_var_text(int ncid,int varid,const char * tp)4262 void cdf_put_var_text(int ncid, int varid, const char *tp)
4263 {
4264   int status = nc_put_var_text(ncid, varid, tp);
4265 
4266   if ( CDF_Debug || status != NC_NOERR )
4267     Message("%d %d %s", ncid, varid, tp);
4268 
4269   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4270 }
4271 
4272 
cdf_put_var_short(int ncid,int varid,const short * sp)4273 void cdf_put_var_short(int ncid, int varid, const short *sp)
4274 {
4275   int status = nc_put_var_short(ncid, varid, sp);
4276 
4277   if ( CDF_Debug || status != NC_NOERR )
4278     Message("%d %d %hd", ncid, varid, *sp);
4279 
4280   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4281 }
4282 
4283 
cdf_put_var_int(int ncid,int varid,const int * ip)4284 void cdf_put_var_int(int ncid, int varid, const int *ip)
4285 {
4286   int status = nc_put_var_int(ncid, varid, ip);
4287 
4288   if ( CDF_Debug || status != NC_NOERR )
4289     Message("%d %d %d", ncid, varid, *ip);
4290 
4291   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4292 }
4293 
4294 
cdf_put_var_long(int ncid,int varid,const long * lp)4295 void cdf_put_var_long(int ncid, int varid, const long *lp)
4296 {
4297   int status = nc_put_var_long(ncid, varid, lp);
4298 
4299   if ( CDF_Debug || status != NC_NOERR )
4300     Message("%d %d %ld", ncid, varid, *lp);
4301 
4302   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4303 }
4304 
4305 
cdf_put_var_float(int ncid,int varid,const float * fp)4306 void cdf_put_var_float(int ncid, int varid, const float *fp)
4307 {
4308   int status = nc_put_var_float(ncid, varid, fp);
4309 
4310   if ( CDF_Debug || status != NC_NOERR )
4311     Message("%d %d %f", ncid, varid, *fp);
4312 
4313   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4314 }
4315 
4316 static
cdf_var_type(nc_type xtype)4317 const char *cdf_var_type(nc_type xtype)
4318 {
4319   const char *ctype = "unknown";
4320 
4321   if      ( xtype == NC_BYTE   )  ctype = "NC_BYTE";
4322   else if ( xtype == NC_CHAR   )  ctype = "NC_CHAR";
4323   else if ( xtype == NC_SHORT  )  ctype = "NC_SHORT";
4324   else if ( xtype == NC_INT    )  ctype = "NC_INT";
4325   else if ( xtype == NC_FLOAT  )  ctype = "NC_FLOAT";
4326   else if ( xtype == NC_DOUBLE )  ctype = "NC_DOUBLE";
4327 #ifdef  HAVE_NETCDF4
4328   else if ( xtype == NC_UBYTE  )  ctype = "NC_UBYTE";
4329   else if ( xtype == NC_LONG   )  ctype = "NC_LONG";
4330   else if ( xtype == NC_USHORT )  ctype = "NC_USHORT";
4331   else if ( xtype == NC_UINT   )  ctype = "NC_UINT";
4332   else if ( xtype == NC_INT64  )  ctype = "NC_INT64";
4333   else if ( xtype == NC_UINT64 )  ctype = "NC_UINT64";
4334 #endif
4335 
4336   return ctype;
4337 }
4338 
4339 static
minmaxval(size_t nvals,const double * array,double * minval,double * maxval)4340 void minmaxval(size_t nvals, const double *array, double *minval, double *maxval)
4341 {
4342   *minval = array[0];
4343   *maxval = array[0];
4344   for ( size_t i = 1; i < nvals; ++i )
4345     {
4346       if      ( array[i] > *maxval ) *maxval = array[i];
4347       else if ( array[i] < *minval ) *minval = array[i];
4348     }
4349 }
4350 
4351 static
minmaxvalf(size_t nvals,const float * array,double * minval,double * maxval)4352 void minmaxvalf(size_t nvals, const float *array, double *minval, double *maxval)
4353 {
4354   *minval = array[0];
4355   *maxval = array[0];
4356   for ( size_t i = 1; i < nvals; ++i )
4357     {
4358       if      ( array[i] > *maxval ) *maxval = array[i];
4359       else if ( array[i] < *minval ) *minval = array[i];
4360     }
4361 }
4362 
cdf_put_vara_double(int ncid,int varid,const size_t start[],const size_t count[],const double * dp)4363 void cdf_put_vara_double(int ncid, int varid, const size_t start[],
4364                          const size_t count[], const double *dp)
4365 {
4366   int status = nc_put_vara_double(ncid, varid, start, count, dp);
4367 
4368   if ( CDF_Debug || status != NC_NOERR )
4369     {
4370       char name[256];
4371       nc_inq_varname(ncid, varid, name);
4372       nc_type xtype;
4373       nc_inq_vartype(ncid, varid, &xtype);
4374       int ndims;
4375       nc_inq_varndims(ncid, varid, &ndims);
4376       double minval = 0, maxval = 0;
4377       size_t nvals = 1;
4378       for ( int i = 0; i < ndims; ++i ) nvals *= count[i];
4379       minmaxval(nvals, dp, &minval, &maxval);
4380       // Message("ncid = %d varid = %d val0 = %f", ncid, varid, *dp);
4381       Message("name=%s  type=%s  minval=%f  maxval=%f", name, cdf_var_type(xtype), minval, maxval);
4382     }
4383 
4384   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4385 }
4386 
4387 
cdf_put_vara_float(int ncid,int varid,const size_t start[],const size_t count[],const float * fp)4388 void cdf_put_vara_float(int ncid, int varid, const size_t start[],
4389                         const size_t count[], const float *fp)
4390 {
4391   int status = nc_put_vara_float(ncid, varid, start, count, fp);
4392 
4393   if ( CDF_Debug || status != NC_NOERR )
4394     {
4395       char name[256];
4396       nc_inq_varname(ncid, varid, name);
4397       nc_type xtype;
4398       nc_inq_vartype(ncid, varid, &xtype);
4399       int ndims;
4400       nc_inq_varndims(ncid, varid, &ndims);
4401       double minval = 0, maxval = 0;
4402       size_t nvals = 1;
4403       for ( int i = 0; i < ndims; ++i ) nvals *= count[i];
4404       minmaxvalf(nvals, fp, &minval, &maxval);
4405       // Message("ncid = %d varid = %d val0 = %f", ncid, varid, *dp);
4406       Message("name=%s  type=%s  minval=%f  maxval=%f", name, cdf_var_type(xtype), minval, maxval);
4407     }
4408 
4409   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4410 }
4411 
4412 
cdf_put_vara(int ncid,int varid,const size_t start[],const size_t count[],const void * cp)4413 void cdf_put_vara(int ncid, int varid, const size_t start[], const size_t count[], const void *cp)
4414 {
4415   int status = nc_put_vara(ncid, varid, start, count, cp);
4416 
4417   if ( CDF_Debug || status != NC_NOERR )
4418     Message("ncid = %d varid = %d", ncid, varid);
4419 
4420   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4421 }
4422 
4423 
cdf_get_vara(int ncid,int varid,const size_t start[],const size_t count[],void * cp)4424 void cdf_get_vara(int ncid, int varid, const size_t start[], const size_t count[], void *cp)
4425 {
4426   int status = nc_get_vara(ncid, varid, start, count, cp);
4427 
4428   if ( CDF_Debug || status != NC_NOERR )
4429     Message("ncid = %d varid = %d", ncid, varid);
4430 
4431   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4432 }
4433 
4434 
cdf_get_vara_int(int ncid,int varid,const size_t start[],const size_t count[],int * dp)4435 void cdf_get_vara_int(int ncid, int varid, const size_t start[], const size_t count[], int *dp)
4436 {
4437   int status = nc_get_vara_int(ncid, varid, start, count, dp);
4438 
4439   if ( CDF_Debug || status != NC_NOERR )
4440     Message("ncid = %d varid = %d", ncid, varid);
4441 
4442   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4443 }
4444 
4445 
cdf_get_vara_double(int ncid,int varid,const size_t start[],const size_t count[],double * dp)4446 void cdf_get_vara_double(int ncid, int varid, const size_t start[], const size_t count[], double *dp)
4447 {
4448   int status = nc_get_vara_double(ncid, varid, start, count, dp);
4449 
4450   if ( CDF_Debug || status != NC_NOERR )
4451     Message("ncid = %d varid = %d", ncid, varid);
4452 
4453   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4454 }
4455 
4456 
cdf_get_vara_float(int ncid,int varid,const size_t start[],const size_t count[],float * fp)4457 void cdf_get_vara_float(int ncid, int varid, const size_t start[], const size_t count[], float *fp)
4458 {
4459   int status = nc_get_vara_float(ncid, varid, start, count, fp);
4460 
4461   if ( CDF_Debug || status != NC_NOERR )
4462     Message("ncid = %d varid = %d", ncid, varid);
4463 
4464   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4465 }
4466 
4467 
cdf_get_vara_text(int ncid,int varid,const size_t start[],const size_t count[],char * tp)4468 void cdf_get_vara_text(int ncid, int varid, const size_t start[], const size_t count[], char *tp)
4469 {
4470   int status = nc_get_vara_text(ncid, varid, start, count, tp);
4471 
4472   if ( CDF_Debug || status != NC_NOERR )
4473     Message("ncid = %d varid = %d", ncid, varid);
4474 
4475   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4476 }
4477 
4478 
cdf_get_vara_uchar(int ncid,int varid,const size_t start[],const size_t count[],unsigned char * tp)4479 void cdf_get_vara_uchar(int ncid, int varid, const size_t start[], const size_t count[], unsigned char *tp)
4480 {
4481   int status = nc_get_vara_uchar(ncid, varid, start, count, tp);
4482 
4483   if ( CDF_Debug || status != NC_NOERR )
4484     Message("ncid = %d varid = %d", ncid, varid);
4485 
4486   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4487 }
4488 
4489 
cdf_put_var_double(int ncid,int varid,const double * dp)4490 void cdf_put_var_double(int ncid, int varid, const double *dp)
4491 {
4492   int status = nc_put_var_double(ncid, varid, dp);
4493 
4494   if ( CDF_Debug || status != NC_NOERR )
4495     Message("ncid = %d varid = %d val0 = %f", ncid, varid, *dp);
4496 
4497   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4498 }
4499 
4500 
cdf_get_var1_text(int ncid,int varid,const size_t index[],char * tp)4501 void cdf_get_var1_text(int ncid, int varid, const size_t index[], char *tp)
4502 {
4503   int status = nc_get_var1_text(ncid, varid, index, tp);
4504 
4505   if ( CDF_Debug || status != NC_NOERR )
4506     Message("ncid = %d varid = %d", ncid, varid);
4507 
4508   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4509 }
4510 
4511 
cdf_get_var1_double(int ncid,int varid,const size_t index[],double * dp)4512 void cdf_get_var1_double(int ncid, int varid, const size_t index[], double *dp)
4513 {
4514   int status = nc_get_var1_double(ncid, varid, index, dp);
4515 
4516   if ( CDF_Debug || status != NC_NOERR )
4517     Message("ncid = %d varid = %d", ncid, varid);
4518 
4519   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4520 }
4521 
4522 
cdf_put_var1_double(int ncid,int varid,const size_t index[],const double * dp)4523 void cdf_put_var1_double(int ncid, int varid, const size_t index[], const double *dp)
4524 {
4525   int status = nc_put_var1_double(ncid, varid, index, dp);
4526 
4527   if ( CDF_Debug || status != NC_NOERR )
4528     Message("ncid = %d varid = %d val = %f", ncid, varid, *dp);
4529 
4530   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4531 }
4532 
4533 
cdf_get_var_text(int ncid,int varid,char * tp)4534 void cdf_get_var_text(int ncid, int varid, char *tp)
4535 {
4536   int status = nc_get_var_text(ncid, varid, tp);
4537 
4538   if ( CDF_Debug || status != NC_NOERR )
4539     Message("ncid = %d varid = %d", ncid, varid);
4540 
4541   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4542 }
4543 
4544 
cdf_get_var_short(int ncid,int varid,short * sp)4545 void cdf_get_var_short(int ncid, int varid, short *sp)
4546 {
4547   int status = nc_get_var_short(ncid, varid, sp);
4548 
4549   if ( CDF_Debug || status != NC_NOERR )
4550     Message("ncid = %d varid = %d", ncid, varid);
4551 
4552   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4553 }
4554 
4555 
cdf_get_var_int(int ncid,int varid,int * ip)4556 void cdf_get_var_int(int ncid, int varid, int *ip)
4557 {
4558   int status = nc_get_var_int(ncid, varid, ip);
4559 
4560   if ( CDF_Debug || status != NC_NOERR )
4561     Message("ncid = %d varid = %d", ncid, varid);
4562 
4563   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4564 }
4565 
4566 
cdf_get_var_long(int ncid,int varid,long * lp)4567 void cdf_get_var_long(int ncid, int varid, long *lp)
4568 {
4569   int status = nc_get_var_long(ncid, varid, lp);
4570 
4571   if ( CDF_Debug || status != NC_NOERR )
4572     Message("ncid = %d varid = %d", ncid, varid);
4573 
4574   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4575 }
4576 
4577 
cdf_get_var_float(int ncid,int varid,float * fp)4578 void cdf_get_var_float(int ncid, int varid, float *fp)
4579 {
4580   int status = nc_get_var_float(ncid, varid, fp);
4581 
4582   if ( CDF_Debug || status != NC_NOERR )
4583     Message("ncid = %d varid = %d", ncid, varid);
4584 
4585   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4586 }
4587 
4588 
cdf_get_var_double(int ncid,int varid,double * dp)4589 void cdf_get_var_double(int ncid, int varid, double *dp)
4590 {
4591   int status = nc_get_var_double(ncid, varid, dp);
4592 
4593   if ( CDF_Debug || status != NC_NOERR )
4594     Message("ncid = %d varid = %d val[0] = %f", ncid, varid, *dp);
4595 
4596   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4597 }
4598 
4599 
cdf_copy_att(int ncid_in,int varid_in,const char * name,int ncid_out,int varid_out)4600 void cdf_copy_att(int ncid_in, int varid_in, const char *name, int ncid_out, int varid_out)
4601 {
4602   int status = nc_copy_att(ncid_in, varid_in, name, ncid_out, varid_out);
4603 
4604   if ( CDF_Debug || status != NC_NOERR )
4605     Message("%d %d %s %d %d", ncid_in, varid_out, name, ncid_out, varid_out);
4606 
4607   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4608 }
4609 
4610 
cdf_put_att_text(int ncid,int varid,const char * name,size_t len,const char * tp)4611 void cdf_put_att_text(int ncid, int varid, const char *name, size_t len, const char *tp)
4612 {
4613   int status = nc_put_att_text(ncid, varid, name, len, tp);
4614 
4615   if ( CDF_Debug || status != NC_NOERR )
4616     Message("ncid = %d varid = %d att = %s text = %.*s", ncid, varid, name, (int)len, tp);
4617 
4618   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4619 }
4620 
4621 
cdf_put_att_int(int ncid,int varid,const char * name,nc_type xtype,size_t len,const int * ip)4622 void cdf_put_att_int(int ncid, int varid, const char *name, nc_type xtype, size_t len, const int *ip)
4623 {
4624   int status = nc_put_att_int(ncid, varid, name, xtype, len, ip);
4625 
4626   if ( CDF_Debug || status != NC_NOERR )
4627     Message("ncid = %d varid = %d att = %s val = %d", ncid, varid, name, *ip);
4628 
4629   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4630 }
4631 
4632 
cdf_put_att_float(int ncid,int varid,const char * name,nc_type xtype,size_t len,const float * dp)4633 void cdf_put_att_float(int ncid, int varid, const char *name, nc_type xtype, size_t len, const float *dp)
4634 {
4635   int status = nc_put_att_float(ncid, varid, name, xtype, len, dp);
4636 
4637   if ( CDF_Debug || status != NC_NOERR )
4638     Message("ncid = %d varid = %d att = %s val = %g", ncid, varid, name, *dp);
4639 
4640   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4641 }
4642 
4643 
cdf_put_att_double(int ncid,int varid,const char * name,nc_type xtype,size_t len,const double * dp)4644 void cdf_put_att_double(int ncid, int varid, const char *name, nc_type xtype, size_t len, const double *dp)
4645 {
4646   int status = nc_put_att_double(ncid, varid, name, xtype, len, dp);
4647 
4648   if ( CDF_Debug || status != NC_NOERR )
4649     Message("ncid = %d varid = %d att = %s val = %g", ncid, varid, name, *dp);
4650 
4651   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4652 }
4653 
4654 
cdf_get_att_text(int ncid,int varid,const char * name,char * tp)4655 void cdf_get_att_text(int ncid, int varid, const char *name, char *tp)
4656 {
4657   int status = nc_get_att_text(ncid, varid, name, tp);
4658 
4659   if ( CDF_Debug || status != NC_NOERR )
4660     Message("ncid = %d varid = %d name = %s", ncid, varid, name);
4661 
4662   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4663 }
4664 
4665 
cdf_get_att_string(int ncid,int varid,const char * name,char ** tp)4666 void cdf_get_att_string(int ncid, int varid, const char *name, char **tp)
4667 {
4668 #ifdef  HAVE_NETCDF4
4669   int status = nc_get_att_string(ncid, varid, name, tp);
4670 
4671   if ( CDF_Debug || status != NC_NOERR )
4672     Message("ncid = %d varid = %d name = %s", ncid, varid, name);
4673 
4674   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4675 #endif
4676 }
4677 
4678 
cdf_get_att_int(int ncid,int varid,const char * name,int * ip)4679 void cdf_get_att_int(int ncid, int varid, const char *name, int *ip)
4680 {
4681   int status = nc_get_att_int(ncid, varid, name, ip);
4682 
4683   if ( CDF_Debug || status != NC_NOERR )
4684     Message("ncid = %d varid = %d att = %s val = %d", ncid, varid, name, *ip);
4685 
4686   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4687 }
4688 
4689 
cdf_get_att_long(int ncid,int varid,const char * name,long * ip)4690 void cdf_get_att_long(int ncid, int varid, const char *name, long *ip)
4691 {
4692 #ifdef  HAVE_NETCDF4
4693   int status = nc_get_att_long(ncid, varid, name, ip);
4694 
4695   if ( CDF_Debug || status != NC_NOERR )
4696     Message("ncid = %d varid = %d att = %s val = %ld", ncid, varid, name, *ip);
4697 
4698   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4699 #endif
4700 }
4701 
4702 
cdf_get_att_double(int ncid,int varid,const char * name,double * dp)4703 void cdf_get_att_double(int ncid, int varid, const char *name, double *dp)
4704 {
4705   int status;
4706 
4707   status = nc_get_att_double(ncid, varid, name, dp);
4708 
4709   if ( CDF_Debug || status != NC_NOERR )
4710     Message("ncid = %d varid = %d att = %s val = %.9g", ncid, varid, name, *dp);
4711 
4712   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4713 }
4714 
4715 
cdf_inq_att(int ncid,int varid,const char * name,nc_type * xtypep,size_t * lenp)4716 void cdf_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, size_t *lenp)
4717 {
4718   int status = nc_inq_att(ncid, varid, name, xtypep, lenp);
4719 
4720   if ( CDF_Debug || status != NC_NOERR )
4721     Message("ncid = %d varid = %d att = %s", ncid, varid, name);
4722 
4723   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4724 }
4725 
4726 
cdf_inq_atttype(int ncid,int varid,const char * name,nc_type * xtypep)4727 void cdf_inq_atttype(int ncid, int varid, const char *name, nc_type * xtypep)
4728 {
4729   int status = nc_inq_atttype(ncid, varid, name, xtypep);
4730 
4731   if ( CDF_Debug || status != NC_NOERR )
4732     Message("ncid = %d varid = %d att = %s", ncid, varid, name);
4733 
4734   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4735 }
4736 
4737 
cdf_inq_attlen(int ncid,int varid,const char * name,size_t * lenp)4738 void cdf_inq_attlen(int ncid, int varid, const char *name, size_t * lenp)
4739 {
4740   int status = nc_inq_attlen(ncid, varid, name, lenp);
4741 
4742   if ( CDF_Debug || status != NC_NOERR )
4743     Message("ncid = %d varid = %d att = %s len = %d", ncid, varid, name, *lenp);
4744 
4745   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4746 }
4747 
4748 
cdf_inq_attname(int ncid,int varid,int attnum,char * name)4749 void cdf_inq_attname(int ncid, int varid, int attnum, char *name)
4750 {
4751   int status = nc_inq_attname(ncid, varid, attnum, name);
4752 
4753   if ( CDF_Debug || status != NC_NOERR )
4754     Message("ncid = %d varid = %d attnum = %d att = %s", ncid, varid, attnum, name);
4755 
4756   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4757 }
4758 
4759 
cdf_inq_attid(int ncid,int varid,const char * name,int * attnump)4760 void cdf_inq_attid(int ncid, int varid, const char *name, int *attnump)
4761 {
4762   int status = nc_inq_attid(ncid, varid, name, attnump);
4763 
4764   if ( CDF_Debug || status != NC_NOERR )
4765     Message("ncid = %d varid = %d att = %s", ncid, varid, name);
4766 
4767   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4768 }
4769 
4770 
4771 #ifdef  HAVE_NETCDF4
cdf_def_var_chunking(int ncid,int varid,int storage,const size_t * chunksizesp)4772 void cdf_def_var_chunking(int ncid, int varid, int storage, const size_t *chunksizesp)
4773 {
4774   int status = nc_def_var_chunking(ncid, varid, storage, chunksizesp);
4775   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
4776 }
4777 #endif
4778 
4779 #endif
4780 /*
4781  * Local Variables:
4782  * c-file-style: "Java"
4783  * c-basic-offset: 2
4784  * indent-tabs-mode: nil
4785  * show-trailing-whitespace: t
4786  * require-trailing-newline: t
4787  * End:
4788  */
4789 #ifndef  _DMEMORY_H
4790 #define  _DMEMORY_H
4791 
4792 #include <stdio.h>
4793 
4794 // if DEBUG_MEMORY is defined setenv MEMORY_DEBUG to debug memory
4795 #define  DEBUG_MEMORY
4796 
4797 #ifndef  WITH_FUNCTION_NAME
4798 #define  WITH_FUNCTION_NAME
4799 #endif
4800 
4801 #ifdef __cplusplus
4802 extern "C" {
4803 #endif
4804 
4805 extern size_t  memTotal(void);
4806 extern void    memDebug(int debug);
4807 extern void    memExitOnError(void);
4808 
4809 #if  defined  DEBUG_MEMORY
4810 
4811 extern void   *memRealloc(void *ptr, size_t size, const char *file, const char *functionname, int line);
4812 extern void   *memCalloc (size_t nmemb, size_t size, const char *file, const char *functionname, int line);
4813 extern void   *memMalloc (size_t size, const char *file, const char *functionname, int line);
4814 extern void    memFree   (void *ptr, const char *file, const char *functionname, int line);
4815 
4816 #ifdef  __cplusplus
4817 }
4818 #endif
4819 
4820 #ifdef  WITH_FUNCTION_NAME
4821 #  define  Realloc(p, s)  memRealloc((p), (s), __FILE__, __func__, __LINE__)
4822 #  define   Calloc(n, s)   memCalloc((n), (s), __FILE__, __func__, __LINE__)
4823 #  define   Malloc(s)      memMalloc((s), __FILE__, __func__, __LINE__)
4824 #  define     Free(p)        memFree((p), __FILE__, __func__, __LINE__)
4825 #else
4826 #  define  Realloc(p, s)  memRealloc((p), (s), __FILE__, (void *) NULL, __LINE__)
4827 #  define   Calloc(n, s)   memCalloc((n), (s), __FILE__, (void *) NULL, __LINE__)
4828 #  define   Malloc(s)      memMalloc((s), __FILE__, (void *) NULL, __LINE__)
4829 #  define     Free(p)        memFree((p), __FILE__, (void *) NULL, __LINE__)
4830 #endif
4831 
4832 #endif /* DEBUG_MEMORY */
4833 
4834 #endif /* _DMEMORY_H */
4835 /*
4836  * Local Variables:
4837  * c-file-style: "Java"
4838  * c-basic-offset: 2
4839  * indent-tabs-mode: nil
4840  * show-trailing-whitespace: t
4841  * require-trailing-newline: t
4842  * End:
4843  */
4844 #ifndef  CDF_UTIL_H_
4845 #define  CDF_UTIL_H_
4846 
4847 #include <stdbool.h>
4848 
4849 int get_timeunit(size_t len, const char *ptu);
4850 
4851 bool is_time_units(const char *timeunits);
4852 bool is_timeaxis_units(const char *timeunits);
4853 
4854 bool is_height_units(const char *units);
4855 bool is_pressure_units(const char *units);
4856 bool is_DBL_axis(/*const char *units,*/ const char *longname);
4857 bool is_depth_axis(const char *stdname, const char *longname);
4858 bool is_height_axis(const char *stdname, const char *longname);
4859 bool is_altitude_axis(const char *stdname, const char *longname);
4860 
4861 bool is_lon_axis(const char *units, const char *stdname);
4862 bool is_lat_axis(const char *units, const char *stdname);
4863 
4864 bool is_x_axis(const char *units, const char *stdname);
4865 bool is_y_axis(const char *units, const char *stdname);
4866 
4867 void cdf_set_gridtype(const char *attstring, int *gridtype);
4868 void cdf_set_zaxistype(const char *attstring, int *zaxistype);
4869 void cdf_set_calendar(const char *attstring, int *calendar);
4870 
4871 #endif
4872 #include <string.h>
4873 #include <ctype.h>
4874 
4875 
4876 
strToLower(char * str)4877 char *strToLower(char *str)
4878 {
4879   if (str)
4880     for (size_t i = 0; str[i]; ++i)
4881       str[i] = (char)tolower((int)str[i]);
4882 
4883   return str;
4884 }
4885 
4886 
strStartsWith(const char * vstr,const char * cstr)4887 bool strStartsWith(const char *vstr, const char *cstr)
4888 {
4889   bool is_equal = false;
4890   if (vstr && cstr)
4891     {
4892       size_t clen = strlen(cstr);
4893       size_t vlen = strlen(vstr);
4894       if (clen <= vlen) is_equal = (memcmp(vstr, cstr, clen) == 0);
4895     }
4896   return is_equal;
4897 }
4898 
get_timeunit(size_t len,const char * ptu)4899 int get_timeunit(size_t len, const char *ptu)
4900 {
4901   int timeunit = -1;
4902 
4903   while (isspace(*ptu) && len) { ptu++; len--; }
4904 
4905   // clang-format off
4906   if (len > 2)
4907     {
4908       if      (strStartsWith(ptu, "sec"))            timeunit = TUNIT_SECOND;
4909       else if (strStartsWith(ptu, "minute"))         timeunit = TUNIT_MINUTE;
4910       else if (strStartsWith(ptu, "hour"))           timeunit = TUNIT_HOUR;
4911       else if (strStartsWith(ptu, "day"))            timeunit = TUNIT_DAY;
4912       else if (strStartsWith(ptu, "month"))          timeunit = TUNIT_MONTH;
4913       else if (strStartsWith(ptu, "calendar_month")) timeunit = TUNIT_MONTH;
4914       else if (strStartsWith(ptu, "year"))           timeunit = TUNIT_YEAR;
4915     }
4916   else if (len == 1 && ptu[0] == 's')  timeunit = TUNIT_SECOND;
4917   // clang-format on
4918 
4919   return timeunit;
4920 }
4921 
4922 
is_time_units(const char * timeunits)4923 bool is_time_units(const char *timeunits)
4924 {
4925   while ( isspace(*timeunits) ) timeunits++;
4926 
4927   bool status = strStartsWith(timeunits, "sec")
4928              || strStartsWith(timeunits, "minute")
4929              || strStartsWith(timeunits, "hour")
4930              || strStartsWith(timeunits, "day")
4931              || strStartsWith(timeunits, "month")
4932              || strStartsWith(timeunits, "calendar_month")
4933              || strStartsWith(timeunits, "year");
4934 
4935   return status;
4936 }
4937 
4938 
is_timeaxis_units(const char * timeunits)4939 bool is_timeaxis_units(const char *timeunits)
4940 {
4941   bool status = false;
4942 
4943   size_t len = strlen(timeunits);
4944   char *tu = (char *) Malloc((len+1)*sizeof(char));
4945   memcpy(tu, timeunits, (len+1) * sizeof(char));
4946   char *ptu = tu;
4947 
4948   for (size_t i = 0; i < len; i++) ptu[i] = (char)tolower((int)ptu[i]);
4949 
4950   int timeunit = get_timeunit(len, ptu);
4951   if (timeunit != -1)
4952     {
4953       while (! isspace(*ptu) && *ptu != 0) ptu++;
4954       if (*ptu)
4955         {
4956           while (isspace(*ptu)) ptu++;
4957 
4958           int timetype = strStartsWith(ptu, "as") ? TAXIS_ABSOLUTE :
4959                          strStartsWith(ptu, "since") ? TAXIS_RELATIVE : -1;
4960 
4961           status = timetype != -1;
4962         }
4963     }
4964 
4965   Free(tu);
4966 
4967   return status;
4968 }
4969 
4970 
is_height_units(const char * units)4971 bool is_height_units(const char *units)
4972 {
4973   const int u0 = units[0];
4974 
4975   bool status
4976     = (u0=='m' && (!units[1] || strStartsWith(units, "meter")))
4977     || (!units[2] && units[1]=='m' && (u0=='c' || u0=='d' || u0=='k'))
4978     || (strStartsWith(units, "decimeter"))
4979     || (strStartsWith(units, "centimeter"))
4980     || (strStartsWith(units, "millimeter"))
4981     || (strStartsWith(units, "kilometer"));
4982 
4983   return status;
4984 }
4985 
4986 
is_pressure_units(const char * units)4987 bool is_pressure_units(const char *units)
4988 {
4989   bool status = strStartsWith(units, "millibar")
4990              || strStartsWith(units, "mb")
4991              || strStartsWith(units, "hectopas")
4992              || strStartsWith(units, "hPa")
4993              || strStartsWith(units, "Pa");
4994 
4995   return status;
4996 }
4997 
4998 
is_DBL_axis(const char * longname)4999 bool is_DBL_axis(const char *longname)
5000 {
5001   bool status = strIsEqual(longname, "depth below land")
5002              || strIsEqual(longname, "depth_below_land")
5003              || strIsEqual(longname, "levels below the surface");
5004 
5005   return status;
5006 }
5007 
5008 
is_depth_axis(const char * stdname,const char * longname)5009 bool is_depth_axis(const char *stdname, const char *longname)
5010 {
5011   bool status = strIsEqual(stdname, "depth")
5012              || strIsEqual(longname, "depth_below_sea")
5013              || strIsEqual(longname, "depth below sea");
5014 
5015   return status;
5016 }
5017 
5018 
is_height_axis(const char * stdname,const char * longname)5019 bool is_height_axis(const char *stdname, const char *longname)
5020 {
5021   bool status = strIsEqual(stdname, "height")
5022              || strIsEqual(longname, "height")
5023              || strIsEqual(longname, "height above the surface");
5024 
5025   return status;
5026 }
5027 
is_altitude_axis(const char * stdname,const char * longname)5028 bool is_altitude_axis(const char *stdname, const char *longname)
5029 {
5030   bool status = strIsEqual(stdname, "altitude")
5031              || strIsEqual(longname, "altitude");
5032 
5033   return status;
5034 }
5035 
5036 
is_lon_axis(const char * units,const char * stdname)5037 bool is_lon_axis(const char *units, const char *stdname)
5038 {
5039   bool status = false;
5040   char lc_units[16];
5041 
5042   memcpy(lc_units, units, 15);
5043   lc_units[15] = 0;
5044   strToLower(lc_units);
5045 
5046   if ((strStartsWith(lc_units, "degree") || strStartsWith(lc_units, "radian")) &&
5047       (strStartsWith(stdname, "grid_longitude") || strStartsWith(stdname, "longitude")))
5048     {
5049       status = true;
5050     }
5051   else if (strStartsWith(lc_units, "degree")
5052            && !strStartsWith(stdname, "grid_latitude")
5053            && !strStartsWith(stdname, "latitude"))
5054     {
5055       int ioff = 6;
5056       if (lc_units[ioff] == 's') ioff++;
5057       if (lc_units[ioff] == ' ') ioff++;
5058       if (lc_units[ioff] == '_') ioff++;
5059       if (lc_units[ioff] == 'e') status = true;
5060     }
5061 
5062   return status;
5063 }
5064 
5065 
is_lat_axis(const char * units,const char * stdname)5066 bool is_lat_axis(const char *units, const char *stdname)
5067 {
5068   bool status = false;
5069   char lc_units[16];
5070 
5071   memcpy(lc_units, units, 15);
5072   lc_units[15] = 0;
5073   strToLower(lc_units);
5074 
5075   if ((strStartsWith(lc_units, "degree") || strStartsWith(lc_units, "radian")) &&
5076       (strStartsWith(stdname, "grid_latitude") || strStartsWith(stdname, "latitude")))
5077     {
5078       status = true;
5079     }
5080   else if (strStartsWith(lc_units, "degree")
5081            && !strStartsWith(stdname, "grid_longitude")
5082            && !strStartsWith(stdname, "longitude"))
5083     {
5084       int ioff = 6;
5085       if (lc_units[ioff] == 's') ioff++;
5086       if (lc_units[ioff] == ' ') ioff++;
5087       if (lc_units[ioff] == '_') ioff++;
5088       if (lc_units[ioff] == 'n' || lc_units[ioff] == 's') status = true;
5089     }
5090 
5091   return status;
5092 }
5093 
5094 
is_x_axis(const char * units,const char * stdname)5095 bool is_x_axis(const char *units, const char *stdname)
5096 {
5097   (void)units;
5098   return (strIsEqual(stdname, "projection_x_coordinate"));
5099 }
5100 
5101 
is_y_axis(const char * units,const char * stdname)5102 bool is_y_axis(const char *units, const char *stdname)
5103 {
5104   (void)units;
5105   return (strIsEqual(stdname, "projection_y_coordinate"));
5106 }
5107 
5108 
cdf_set_gridtype(const char * attstring,int * gridtype)5109 void cdf_set_gridtype(const char *attstring, int *gridtype)
5110 {
5111   // clang-format off
5112   if      (strIsEqual(attstring, "gaussian_reduced")) *gridtype = GRID_GAUSSIAN_REDUCED;
5113   else if (strIsEqual(attstring, "gaussian"))         *gridtype = GRID_GAUSSIAN;
5114   else if (strStartsWith(attstring, "spectral"))      *gridtype = GRID_SPECTRAL;
5115   else if (strStartsWith(attstring, "fourier"))       *gridtype = GRID_FOURIER;
5116   else if (strIsEqual(attstring, "trajectory"))       *gridtype = GRID_TRAJECTORY;
5117   else if (strIsEqual(attstring, "generic"))          *gridtype = GRID_GENERIC;
5118   else if (strIsEqual(attstring, "cell"))             *gridtype = GRID_UNSTRUCTURED;
5119   else if (strIsEqual(attstring, "unstructured"))     *gridtype = GRID_UNSTRUCTURED;
5120   else if (strIsEqual(attstring, "curvilinear")) ;
5121   else if (strIsEqual(attstring, "characterxy"))      *gridtype = GRID_CHARXY;
5122   else if (strIsEqual(attstring, "sinusoidal")) ;
5123   else if (strIsEqual(attstring, "laea")) ;
5124   else if (strIsEqual(attstring, "lcc2")) ;
5125   else if (strIsEqual(attstring, "linear")) ; // ignore grid type linear
5126   else
5127     {
5128       static bool warn = true;
5129       if (warn)
5130         {
5131           warn = false;
5132           Warning("NetCDF attribute grid_type='%s' unsupported!", attstring);
5133         }
5134     }
5135   // clang-format on
5136 }
5137 
5138 
cdf_set_zaxistype(const char * attstring,int * zaxistype)5139 void cdf_set_zaxistype(const char *attstring, int *zaxistype)
5140 {
5141   // clang-format off
5142   if      (strIsEqual(attstring, "toa"))              *zaxistype = ZAXIS_TOA;
5143   else if (strIsEqual(attstring, "tropopause"))       *zaxistype = ZAXIS_TROPOPAUSE;
5144   else if (strIsEqual(attstring, "cloudbase"))        *zaxistype = ZAXIS_CLOUD_BASE;
5145   else if (strIsEqual(attstring, "cloudtop"))         *zaxistype = ZAXIS_CLOUD_TOP;
5146   else if (strIsEqual(attstring, "isotherm0"))        *zaxistype = ZAXIS_ISOTHERM_ZERO;
5147   else if (strIsEqual(attstring, "seabottom"))        *zaxistype = ZAXIS_SEA_BOTTOM;
5148   else if (strIsEqual(attstring, "lakebottom"))       *zaxistype = ZAXIS_LAKE_BOTTOM;
5149   else if (strIsEqual(attstring, "sedimentbottom"))   *zaxistype = ZAXIS_SEDIMENT_BOTTOM;
5150   else if (strIsEqual(attstring, "sedimentbottomta")) *zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;
5151   else if (strIsEqual(attstring, "sedimentbottomtw")) *zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;
5152   else if (strIsEqual(attstring, "mixlayer"))         *zaxistype = ZAXIS_MIX_LAYER;
5153   else if (strIsEqual(attstring, "atmosphere"))       *zaxistype = ZAXIS_ATMOSPHERE;
5154   else
5155     {
5156       static bool warn = true;
5157       if (warn)
5158         {
5159           warn = false;
5160           Warning("NetCDF attribute level_type='%s' unsupported!", attstring);
5161         }
5162     }
5163   // clang-format on
5164 }
5165 
5166 
cdf_set_calendar(const char * attstring,int * calendar)5167 void cdf_set_calendar(const char *attstring, int *calendar)
5168 {
5169   // clang-format off
5170   if      (strStartsWith(attstring, "standard"))  *calendar = CALENDAR_STANDARD;
5171   else if (strStartsWith(attstring, "gregorian")) *calendar = CALENDAR_GREGORIAN;
5172   else if (strStartsWith(attstring, "none"))      *calendar = CALENDAR_NONE;
5173   else if (strStartsWith(attstring, "proleptic")) *calendar = CALENDAR_PROLEPTIC;
5174   else if (strStartsWith(attstring, "360"))       *calendar = CALENDAR_360DAYS;
5175   else if (strStartsWith(attstring, "365") ||
5176            strStartsWith(attstring, "noleap"))    *calendar = CALENDAR_365DAYS;
5177   else if (strStartsWith(attstring, "366") ||
5178            strStartsWith(attstring, "all_leap"))  *calendar = CALENDAR_366DAYS;
5179   else Warning("calendar >%s< unsupported!", attstring);
5180   // clang-format on
5181 }
5182 #ifndef _STREAM_CDF_H
5183 #define _STREAM_CDF_H
5184 
5185 
5186 void   cdfDefCoordinateVars(stream_t *streamptr);
5187 void   cdfDefTimestep(stream_t *streamptr, int tsID);
5188 int    cdfInqTimestep(stream_t *streamptr, int tsID);
5189 int    cdfInqContents(stream_t *streamptr);
5190 
5191 void   cdfEndDef(stream_t * streamptr);
5192 void   cdfDefRecord(stream_t * streamptr);
5193 
5194 void   cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
5195 
5196 void   cdfDefineAttributes(int vlistID, int varID, int fileID, int ncvarID);
5197 
5198 void   cdf_read_record(stream_t *streamptr, int memtype, void *data, size_t *nmiss);
5199 void   cdf_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss);
5200 
5201 void   cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, size_t *nmiss);
5202 void   cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss);
5203 
5204 void   cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, size_t *nmiss);
5205 void   cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss);
5206 
5207 void   cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
5208                            const int rect[][2], const void *data, size_t nmiss);
5209 
5210 void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level);
5211 void cdfDefTime(stream_t* streamptr);
5212 
5213 void cdf_scale_add(size_t size, double *data, double addoffset, double scalefactor);
5214 
5215 int cdfDefDatatype(int datatype, stream_t* streamptr);
5216 
5217 #endif
5218 /*
5219  * Local Variables:
5220  * c-file-style: "Java"
5221  * c-basic-offset: 2
5222  * indent-tabs-mode: nil
5223  * show-trailing-whitespace: t
5224  * require-trailing-newline: t
5225  * End:
5226  */
5227 #ifndef  CDI_KEY_H
5228 #define  CDI_KEY_H
5229 
5230 
5231 // CDI key
5232 typedef struct {
5233   int       key;          // CDI key
5234   int       type;         // KEY_INT, KEY_FLOAT, KEY_BYTES
5235   int       length;       // number of bytes in v.s
5236   union {
5237     int i;
5238     double d;
5239     unsigned char *s;
5240   } v;
5241 } cdi_key_t;
5242 
5243 
5244 typedef struct {
5245   size_t     nalloc;		// number allocated >= nelems
5246   size_t     nelems;		// length of the array
5247   cdi_key_t  value[MAX_KEYS];
5248 } cdi_keys_t;
5249 
5250 enum  {KEY_INT = 1, KEY_FLOAT, KEY_BYTES};
5251 
5252 void cdiDefVarKeyInt(cdi_keys_t *keysp, int key, int value);
5253 void cdiDefVarKeyFloat(cdi_keys_t *keysp, int key, double value);
5254 void cdiDefVarKeyBytes(cdi_keys_t *keysp, int key, const unsigned char *bytes, int length);
5255 int  cdiInqVarKeyInt(const cdi_keys_t *keysp, int key);
5256 int  cdiInqVarKeyBytes(const cdi_keys_t *keysp, int key, unsigned char *bytes, int *length);
5257 
5258 cdi_key_t *find_key(cdi_keys_t *keysp, int key);
5259 const char *cdiInqVarKeyStringPtr(cdi_keys_t *keysp, int key);
5260 
5261 static inline
cdiInqVarKeyString(cdi_keys_t * keysp,int key)5262 const char *cdiInqVarKeyString(cdi_keys_t *keysp, int key)
5263 {
5264   const char *string = cdiInqVarKeyStringPtr(keysp, key);
5265   if (string == NULL) string = "";
5266   return string;
5267 }
5268 
5269 int  cdiCopyVarKey(const cdi_keys_t *keysp1, int key, cdi_keys_t *keysp2);
5270 void cdiCopyVarKeys(const cdi_keys_t *keysp1, cdi_keys_t *keysp2);
5271 void cdiDeleteVarKeys(cdi_keys_t *keysp);
5272 void cdiDeleteKeys(int cdiID, int varID);
5273 void cdiPrintKeys(int cdiID, int varID);
5274 
5275 void cdiInitKeys(cdi_keys_t *keysp);
5276 
5277 int cdi_key_compare(cdi_keys_t *keyspa, cdi_keys_t *keyspb, int keynum);
5278 
5279 #endif
5280 
5281 /*
5282  * Local Variables:
5283  * c-file-style: "Java"
5284  * c-basic-offset: 2
5285  * indent-tabs-mode: nil
5286  * show-trailing-whitespace: t
5287  * require-trailing-newline: t
5288  * End:
5289  */
5290 #ifndef  CDI_ATT_H
5291 #define  CDI_ATT_H
5292 
5293 #ifdef  HAVE_CONFIG_H
5294 #endif
5295 
5296 #ifndef  CDI_LIMITS_H
5297 #endif
5298 
5299 // CDI attribute
5300 typedef struct {
5301   size_t    xsz;	  // amount of space at xvalue
5302   size_t    namesz;       // size of name
5303   char     *name;         // attribute name
5304   int       indtype;	  // internal data type of xvalue (INT, FLT or TXT)
5305   int       exdtype;      // external data type
5306                           // indtype    exdtype
5307                           // TXT        TXT
5308                           // INT        INT16, INT32
5309                           // FLT        FLT32, FLT64
5310   size_t    nelems;    	  // number of elements
5311   void     *xvalue;       // the actual data
5312 } cdi_att_t;
5313 
5314 
5315 typedef struct {
5316   size_t     nalloc;		// number allocated >= nelems
5317   size_t     nelems;		// length of the array
5318   cdi_att_t  value[MAX_ATTRIBUTES];
5319 } cdi_atts_t;
5320 
5321 
5322 int cdiDeleteAtts(int vlistID, int varID);
5323 int cdiAttsGetSize(void *p, int varID, void *context);
5324 void cdiAttsPack(void *p, int varID, void *buf, int size, int *position, void *context);
5325 void cdiAttsUnpack(int cdiID, int varID, void *buf, int size, int *position, void *context);
5326 
5327 int cdi_att_compare(cdi_atts_t *attspa, cdi_atts_t *attspb, int attnum);
5328 
5329 #endif
5330 
5331 /*
5332  * Local Variables:
5333  * c-file-style: "Java"
5334  * c-basic-offset: 2
5335  * indent-tabs-mode: nil
5336  * show-trailing-whitespace: t
5337  * require-trailing-newline: t
5338  * End:
5339  */
5340 #ifndef  GRID_H
5341 #define  GRID_H
5342 
5343 #include <stdbool.h>
5344 
5345 
5346 extern int (*proj_lonlat_to_lcc_func)();
5347 extern int (*proj_lcc_to_lonlat_func)();
5348 extern int (*proj_lonlat_to_stere_func)();
5349 extern int (*proj_stere_to_lonlat_func)();
5350 
5351 typedef unsigned char mask_t;
5352 
5353 typedef struct grid_t grid_t;
5354 
5355 struct gridVirtTable
5356 {
5357   void (*destroy)(grid_t *gridptr);
5358   grid_t *(*copy)(grid_t *gridptr);
5359   void (*copyScalarFields)(grid_t *gridptrOrig, grid_t *gridptrDup);
5360   void (*copyArrayFields)(grid_t *gridptrOrig, grid_t *gridptrDup);
5361   void (*defXVals)(grid_t *gridptr, const double *xvals);
5362   void (*defYVals)(grid_t *gridptr, const double *yvals);
5363   void (*defMask)(grid_t *gridptr, const int *mask);
5364   void (*defMaskGME)(grid_t *gridptr, const int *mask);
5365   void (*defXBounds)(grid_t *gridptr, const double *xbounds);
5366   void (*defYBounds)(grid_t *gridptr, const double *ybounds);
5367   void (*defArea)(grid_t *gridptr, const double *area);
5368   double (*inqXVal)(grid_t *gridptr, size_t index);
5369   double (*inqYVal)(grid_t *gridptr, size_t index);
5370   size_t (*inqXVals)(grid_t *gridptr, double *xvals);
5371   size_t (*inqXValsPart)(grid_t *gridptr, int start, size_t length, double *xvals);
5372   size_t (*inqYVals)(grid_t *gridptr, double *yvals);
5373   size_t (*inqYValsPart)(grid_t *gridptr, int start, size_t length, double *yvals);
5374   const double *(*inqXValsPtr)(grid_t *gridptr);
5375   const double *(*inqYValsPtr)(grid_t *gridptr);
5376 #ifndef USE_MPI
5377   int (*inqXIsc)(grid_t *gridptr);
5378   int (*inqYIsc)(grid_t *gridptr);
5379   size_t (*inqXCvals)(grid_t *gridptr, char **xcvals);
5380   size_t (*inqYCvals)(grid_t *gridptr, char **ycvals);
5381   const char **(*inqXCvalsPtr)(grid_t *gridptr);
5382   const char **(*inqYCvalsPtr)(grid_t *gridptr);
5383 #endif
5384   /* return if for both grids, all xval and all yval are equal */
5385   bool (*compareXYFull)(grid_t *gridRef, grid_t *gridTest);
5386   /* return if for both grids, x[0], y[0], x[size-1] and y[size-1] are
5387    * respectively equal */
5388   bool (*compareXYAO)(grid_t *gridRef, grid_t *gridTest);
5389   void (*inqArea)(grid_t *gridptr, double *area);
5390   const double *(*inqAreaPtr)(grid_t *gridptr);
5391   int (*hasArea)(grid_t *gridptr);
5392   size_t (*inqMask)(grid_t *gridptr, int *mask);
5393   int (*inqMaskGME)(grid_t *gridptr, int *mask_gme);
5394   size_t (*inqXBounds)(grid_t *gridptr, double *xbounds);
5395   size_t (*inqYBounds)(grid_t *gridptr, double *ybounds);
5396   const double *(*inqXBoundsPtr)(grid_t *gridptr);
5397   const double *(*inqYBoundsPtr)(grid_t *gridptr);
5398 };
5399 
5400 struct gridaxis_t {
5401   size_t      size;                   // number of values
5402   short       flag;                   // 0: undefined 1:vals 2:first+inc
5403   double      first, last, inc;
5404   double     *vals;
5405   double     *bounds;
5406   cdi_keys_t  keys;
5407 #ifndef USE_MPI
5408   int         clength;
5409   char      **cvals;
5410 #endif
5411 };
5412 
5413 // GME Grid
5414 struct grid_gme_t {
5415   int     nd, ni, ni2, ni3;           // parameter for GRID_GME
5416 };
5417 
5418 struct grid_t {
5419   char       *name;
5420   int         self;
5421   size_t      size;
5422   int         type;                   // grid type
5423   int         datatype;               // grid data type
5424   int         proj;                   // grid projection
5425   int         projtype;               // grid projection type
5426   mask_t     *mask;
5427   mask_t     *mask_gme;
5428   double     *area;
5429   struct grid_gme_t  gme;
5430   int         trunc;                  // parameter for GRID_SPECTRAL
5431   int         nvertex;
5432   int        *reducedPoints;
5433   int         reducedPointsSize;
5434   int         np;                     // number of parallels between a pole and the equator
5435   signed char isCyclic;               // three possible states:
5436                                       // -1 if unknown,
5437                                       //  0 if found not cyclic, or
5438                                       //  1 for global cyclic grids
5439   bool        lcomplex;
5440   bool        hasdims;
5441   struct gridaxis_t x;
5442   struct gridaxis_t y;
5443   const struct gridVirtTable *vtable;
5444   cdi_keys_t  keys;
5445   cdi_atts_t  atts;
5446 };
5447 
5448 
5449 void grid_init(grid_t *gridptr);
5450 void cdiGridTypeInit(grid_t *gridptr, int gridtype, size_t size);
5451 void grid_free(grid_t *gridptr);
5452 grid_t *grid_to_pointer(int gridID);
5453 extern const struct gridVirtTable cdiGridVtable;
5454 
5455 unsigned cdiGridCount(void);
5456 
5457 void gridVerifyProj(int gridID);
5458 
5459 const double *gridInqXvalsPtr(int gridID);
5460 const double *gridInqYvalsPtr(int gridID);
5461 
5462 const char **gridInqXCvalsPtr(int gridID);
5463 const char **gridInqYCvalsPtr(int gridID);
5464 
5465 const double *gridInqXboundsPtr(int gridID);
5466 const double *gridInqYboundsPtr(int gridID);
5467 const double *gridInqAreaPtr(int gridID);
5468 
5469 int gridGenerate(const grid_t *grid);
5470 
5471 //int gridIsEqual(int gridID1, int gridID2);
5472 
5473 void cdiGridGetIndexList(unsigned, int * );
5474 
5475 void
5476 gridUnpack(char * unpackBuffer, int unpackBufferSize,
5477            int * unpackBufferPos, int originNamespace, void *context,
5478            int force_id);
5479 
5480 struct addIfNewRes
5481 {
5482   int Id;
5483   int isNew;
5484 };
5485 
5486 struct addIfNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode);
5487 
5488 int gridVerifyGribParamLCC(double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2,
5489                            double *a, double *rf, double *xval_0, double *yval_0, double *x_0, double *y_0);
5490 int gridVerifyGribParamSTERE(double missval, double *lon_0, double *lat_ts, double *lat_0,
5491                              double *a, double *xval_0, double *yval_0, double *x_0, double *y_0);
5492 
5493 bool isGaussGrid(size_t ysize, double yinc, const double *yvals);
5494 
5495 #endif
5496 /*
5497  * Local Variables:
5498  * c-file-style: "Java"
5499  * c-basic-offset: 2
5500  * indent-tabs-mode: nil
5501  * show-trailing-whitespace: t
5502  * require-trailing-newline: t
5503  * End:
5504  */
5505 #ifndef  CDF_LAZY_GRID_H_
5506 #define  CDF_LAZY_GRID_H_
5507 
5508 #ifdef HAVE_CONFIG_H
5509 #endif
5510 
5511 #ifdef HAVE_MMAP
5512 #include <unistd.h>
5513 #include <sys/mman.h>
5514 #include <sys/types.h>
5515 #include <sys/stat.h>
5516 #include <fcntl.h>
5517 #endif
5518 
5519 #ifdef HAVE_LIBPTHREAD
5520 #include <pthread.h>
5521 #endif
5522 
5523 #include <string.h>
5524 
5525 
5526 struct xyValGet {
5527   double scalefactor, addoffset;
5528   size_t start[3], count[3], size, dimsize;
5529   int datasetNCId, varNCId;
5530   short ndims;
5531 };
5532 
5533 struct cdfLazyGridIds {
5534   int datasetNCId, varNCId;
5535 };
5536 
5537 struct cdfLazyGrid
5538 {
5539   grid_t base;
5540   const struct gridVirtTable *baseVtable;
5541   struct cdfLazyGridIds cellAreaGet, xBoundsGet, yBoundsGet;
5542   struct xyValGet xValsGet, yValsGet;
5543 #ifdef HAVE_LIBPTHREAD
5544   pthread_mutex_t loadSerialize;
5545 #endif
5546 };
5547 
5548 
5549 extern double *cdfPendingLoad;
5550 
5551 void cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype);
5552 void cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype);
5553 
5554 void cdfLazyGridDestroy(struct cdfLazyGrid *lazyGrid);
5555 
5556 #endif
5557 /*
5558  * Local Variables:
5559  * c-file-style: "Java"
5560  * c-basic-offset: 2
5561  * indent-tabs-mode: nil
5562  * show-trailing-whitespace: t
5563  * require-trailing-newline: t
5564  * End:
5565  */
5566 #ifdef HAVE_CONFIG_H
5567 #endif
5568 
5569 #ifdef HAVE_LIBNETCDF
5570 
5571 
5572 static struct gridVirtTable cdfLazyGridVtable;
5573 double *cdfPendingLoad;
5574 #ifdef HAVE_LIBPTHREAD
5575 static pthread_once_t cdfLazyInitialized = PTHREAD_ONCE_INIT;
5576 #else
5577 static bool cdfLazyInitialized;
5578 #endif
5579 
5580 
5581 #ifdef HAVE_LIBPTHREAD
5582 #define lock_lazy_load(plGrid) pthread_mutex_lock(&((plGrid)->loadSerialize))
5583 #define unlock_lazy_load(plGrid) pthread_mutex_unlock(&((plGrid)->loadSerialize))
5584 #define destroy_lazy_load_lock(plGrid) pthread_mutex_destroy(&((plGrid)->loadSerialize))
5585 #define init_lazy_load_lock(plGrid) pthread_mutex_init(&((plGrid)->loadSerialize), NULL)
5586 #else
5587 #define lock_lazy_load(plGrid)
5588 #define unlock_lazy_load(plGrid)
5589 #define destroy_lazy_load_lock(plGrid)
5590 #define init_lazy_load_lock(plGrid)
5591 #endif
5592 
5593 
5594 
cdfLazyGridDestroy(struct cdfLazyGrid * lazyGrid)5595 void cdfLazyGridDestroy(struct cdfLazyGrid *lazyGrid)
5596 {
5597   if (lazyGrid->base.area == cdfPendingLoad)  lazyGrid->base.area = NULL;
5598   if (lazyGrid->base.x.vals == cdfPendingLoad) lazyGrid->base.x.vals = NULL;
5599   if (lazyGrid->base.y.vals == cdfPendingLoad) lazyGrid->base.y.vals = NULL;
5600   if (lazyGrid->base.x.bounds == cdfPendingLoad) lazyGrid->base.x.bounds = NULL;
5601   if (lazyGrid->base.y.bounds == cdfPendingLoad) lazyGrid->base.y.bounds = NULL;
5602   destroy_lazy_load_lock(lazyGrid);
5603 }
5604 
cdfLazyGridDelete(grid_t * grid)5605 static void cdfLazyGridDelete(grid_t *grid)
5606 {
5607   struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
5608   void (*baseDestroy)(grid_t *grid) = cdfGrid->baseVtable->destroy;
5609   cdfLazyGridDestroy(cdfGrid);
5610   baseDestroy(grid);
5611 }
5612 
cdfLazyGridDestroyOnce(void)5613 static void cdfLazyGridDestroyOnce(void)
5614 {
5615   /*
5616 #ifdef HAVE_MMAP
5617   size_t pgSize = cdiGetPageSize(false);
5618   munmap(cdfPendingLoad, pgSize);
5619 #endif
5620   */
5621 }
5622 
5623 static void
cdfLazyGridDefArea(grid_t * grid,const double * area)5624 cdfLazyGridDefArea(grid_t *grid, const double *area)
5625 {
5626   struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
5627   lock_lazy_load(cdfGrid);
5628   if (grid->area == cdfPendingLoad) grid->area = NULL;
5629   cdfGrid->cellAreaGet.datasetNCId = -1;
5630   cdfGrid->cellAreaGet.varNCId = -1;
5631   cdfGrid->baseVtable->defArea(grid, area);
5632   unlock_lazy_load(cdfGrid);
5633 }
5634 
5635 
5636 static const double *
cdfLazyGridInqAreaPtr(grid_t * grid)5637 cdfLazyGridInqAreaPtr(grid_t *grid)
5638 {
5639   struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
5640   lock_lazy_load(lazyGrid);
5641   if (grid->area == cdfPendingLoad)
5642     {
5643       grid->area = (double *)Malloc(grid->size * sizeof(double));
5644       cdf_get_var_double(lazyGrid->cellAreaGet.datasetNCId,
5645                          lazyGrid->cellAreaGet.varNCId, grid->area);
5646     }
5647   unlock_lazy_load(lazyGrid);
5648   return lazyGrid->baseVtable->inqAreaPtr(grid);
5649 }
5650 
5651 static void
cdfLazyGridInqArea(grid_t * grid,double * area)5652 cdfLazyGridInqArea(grid_t *grid, double *area)
5653 {
5654   grid->vtable->inqAreaPtr(grid);
5655   struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
5656   lazyGrid->baseVtable->inqArea(grid, area);
5657 }
5658 
5659 
5660 static void
cdfLazyLoadXYVals(struct xyValGet * valsGet,double ** valsp)5661 cdfLazyLoadXYVals(struct xyValGet *valsGet, double **valsp)
5662 {
5663   double *grid_vals = (double *)Malloc(valsGet->size * sizeof (double));
5664   *valsp = grid_vals;
5665   if ( valsGet->ndims == 3 )
5666     cdf_get_vara_double(valsGet->datasetNCId, valsGet->varNCId,
5667                         valsGet->start, valsGet->count, grid_vals);
5668   else
5669     cdf_get_var_double(valsGet->datasetNCId, valsGet->varNCId, grid_vals);
5670   cdf_scale_add(valsGet->size, grid_vals, valsGet->addoffset, valsGet->scalefactor);
5671 }
5672 
5673 static const double *
cdfLazyGridInqXValsPtr(grid_t * grid)5674 cdfLazyGridInqXValsPtr(grid_t *grid)
5675 {
5676   struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
5677   lock_lazy_load(lazyGrid);
5678   if (grid->x.vals == cdfPendingLoad)
5679     cdfLazyLoadXYVals(&lazyGrid->xValsGet, &grid->x.vals);
5680   unlock_lazy_load(lazyGrid);
5681   return lazyGrid->baseVtable->inqXValsPtr(grid);
5682 }
5683 
5684 static const double *
cdfLazyGridInqYValsPtr(grid_t * grid)5685 cdfLazyGridInqYValsPtr(grid_t *grid)
5686 {
5687   struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
5688   lock_lazy_load(lazyGrid);
5689   if (grid->y.vals == cdfPendingLoad)
5690     cdfLazyLoadXYVals(&lazyGrid->yValsGet, &grid->y.vals);
5691   unlock_lazy_load(lazyGrid);
5692   return lazyGrid->baseVtable->inqYValsPtr(grid);
5693 }
5694 
5695 static double
cdfLazyGridInqXYVal(grid_t * grid,size_t index,const struct xyValGet * valsGet,double * vals,const double * (* inqValsPtr)(grid_t * gridptr))5696 cdfLazyGridInqXYVal(grid_t *grid, size_t index,
5697                     const struct xyValGet *valsGet, double *vals,
5698                     const double *(*inqValsPtr)(grid_t *gridptr))
5699 {
5700   size_t size = valsGet->size;
5701   double v;
5702   if ( vals == cdfPendingLoad )
5703     {
5704       /* prevent full load if only first/last values get inspected */
5705       if ( index == 0 || index == size - 1 )
5706         {
5707           size_t indexND[3];
5708           if ( valsGet->ndims == 3 )
5709             {
5710               indexND[0] = 0;
5711               indexND[1] = index / valsGet->count[2];
5712               indexND[2] = index % valsGet->count[2];
5713             }
5714           else if ( valsGet->ndims == 2)
5715             {
5716               indexND[0] = index / grid->x.size;
5717               indexND[1] = index % grid->x.size;
5718             }
5719           else
5720             indexND[0] = index;
5721           cdf_get_var1_double(valsGet->datasetNCId, valsGet->varNCId, indexND, &v);
5722         }
5723       else
5724         {
5725           const double *grid_vals = inqValsPtr(grid);
5726           v = grid_vals[index];
5727         }
5728     }
5729   else if ( vals )
5730     v = vals[index];
5731   else
5732     v = 0.0;
5733 
5734   return v;
5735 }
5736 
5737 static void
cdfLazyGridDefXVals(grid_t * grid,const double * vals)5738 cdfLazyGridDefXVals(grid_t *grid, const double *vals)
5739 {
5740   struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
5741   lock_lazy_load(cdfGrid);
5742   if (grid->x.vals == cdfPendingLoad)
5743     grid->x.vals = NULL;
5744   cdfGrid->xValsGet.datasetNCId = -1;
5745   cdfGrid->xValsGet.varNCId = -1;
5746   cdfGrid->baseVtable->defXVals(grid, vals);
5747   unlock_lazy_load(cdfGrid);
5748 }
5749 
5750 static void
cdfLazyGridDefYVals(grid_t * grid,const double * vals)5751 cdfLazyGridDefYVals(grid_t *grid, const double *vals)
5752 {
5753   struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
5754   lock_lazy_load(cdfGrid);
5755   if (grid->y.vals == cdfPendingLoad)
5756     grid->y.vals = NULL;
5757   cdfGrid->yValsGet.datasetNCId = -1;
5758   cdfGrid->yValsGet.varNCId = -1;
5759   cdfGrid->baseVtable->defYVals(grid, vals);
5760   unlock_lazy_load(cdfGrid);
5761 }
5762 
5763 static double
cdfLazyGridInqXVal(grid_t * grid,size_t index)5764 cdfLazyGridInqXVal(grid_t *grid, size_t index)
5765 {
5766   struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
5767   lock_lazy_load(lazyGrid);
5768   double rv = cdfLazyGridInqXYVal(grid, index, &lazyGrid->xValsGet,
5769                                   grid->x.vals, grid->vtable->inqXValsPtr);
5770   unlock_lazy_load(lazyGrid);
5771   return rv;
5772 }
5773 
5774 static double
cdfLazyGridInqYVal(grid_t * grid,size_t index)5775 cdfLazyGridInqYVal(grid_t *grid, size_t index)
5776 {
5777   struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
5778   lock_lazy_load(lazyGrid);
5779   double rv = cdfLazyGridInqXYVal(grid, index, &lazyGrid->yValsGet,
5780                                   grid->y.vals, grid->vtable->inqYValsPtr);
5781   unlock_lazy_load(lazyGrid);
5782   return rv;
5783 }
5784 
5785 static bool
cdfLazyXYValGetCompare(struct cdfLazyGrid * lazyGridRef,struct cdfLazyGrid * lazyGridTest)5786 cdfLazyXYValGetCompare(struct cdfLazyGrid *lazyGridRef,
5787                        struct cdfLazyGrid *lazyGridTest)
5788 {
5789   struct xyValGet *valsGetXRef = &lazyGridRef->xValsGet,
5790     *valsGetYRef = &lazyGridRef->yValsGet,
5791     *valsGetXTest = &lazyGridTest->xValsGet,
5792     *valsGetYTest = &lazyGridTest->yValsGet;
5793   if (valsGetXRef->datasetNCId == -1
5794       || valsGetXTest->datasetNCId == -1
5795       || valsGetYRef->datasetNCId == -1
5796       || valsGetYTest->datasetNCId == -1)
5797     return lazyGridRef->baseVtable->compareXYFull(&lazyGridRef->base,
5798                                                   &lazyGridTest->base);
5799   return valsGetXRef->datasetNCId != valsGetXTest->datasetNCId
5800     ||   valsGetXRef->varNCId     != valsGetXTest->varNCId
5801     ||   valsGetYRef->datasetNCId != valsGetYTest->datasetNCId
5802     ||   valsGetYRef->varNCId     != valsGetYTest->varNCId;
5803 }
5804 
5805 static bool
cdfLazyCompareXYFull(grid_t * gridRef,grid_t * gridTest)5806 cdfLazyCompareXYFull(grid_t *gridRef, grid_t *gridTest)
5807 {
5808   bool diff;
5809   struct cdfLazyGrid *lazyGridRef = (struct cdfLazyGrid *)gridRef;
5810   if (gridTest->vtable == &cdfLazyGridVtable)
5811     diff = cdfLazyXYValGetCompare(lazyGridRef, (struct cdfLazyGrid *)gridTest);
5812   else
5813     diff = lazyGridRef->baseVtable->compareXYFull(gridRef, gridTest);
5814   return diff;
5815 }
5816 
5817 static bool
cdfLazyCompareXYAO(grid_t * gridRef,grid_t * gridTest)5818 cdfLazyCompareXYAO(grid_t *gridRef, grid_t *gridTest)
5819 {
5820   bool diff;
5821   struct cdfLazyGrid *lazyGridRef = (struct cdfLazyGrid *)gridRef;
5822   if (gridTest->vtable == &cdfLazyGridVtable)
5823     diff = cdfLazyXYValGetCompare(lazyGridRef, (struct cdfLazyGrid *)gridTest);
5824   else
5825     diff = lazyGridRef->baseVtable->compareXYAO(gridRef, gridTest);
5826   return diff;
5827 }
5828 
5829 
5830 static const double *
cdfLazyGridInqXBoundsPtr(grid_t * grid)5831 cdfLazyGridInqXBoundsPtr(grid_t *grid)
5832 {
5833   struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
5834   lock_lazy_load(lazyGrid);
5835   if (grid->x.bounds == cdfPendingLoad)
5836     {
5837       grid->x.bounds = (double *)Malloc((size_t)grid->nvertex * grid->size * sizeof(double));
5838       cdf_get_var_double(lazyGrid->xBoundsGet.datasetNCId,
5839                          lazyGrid->xBoundsGet.varNCId, grid->x.bounds);
5840     }
5841   unlock_lazy_load(lazyGrid);
5842   return lazyGrid->baseVtable->inqXBoundsPtr(grid);
5843 }
5844 
5845 static void
cdfLazyGridDefXBounds(grid_t * grid,const double * xbounds)5846 cdfLazyGridDefXBounds(grid_t *grid, const double *xbounds)
5847 {
5848   struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
5849   lock_lazy_load(cdfGrid);
5850   if (grid->x.bounds == cdfPendingLoad)
5851     grid->x.bounds = NULL;
5852   cdfGrid->xBoundsGet.datasetNCId = -1;
5853   cdfGrid->xBoundsGet.varNCId = -1;
5854   cdfGrid->baseVtable->defXBounds(grid, xbounds);
5855   unlock_lazy_load(cdfGrid);
5856 }
5857 
5858 static void
cdfLazyGridDefYBounds(grid_t * grid,const double * ybounds)5859 cdfLazyGridDefYBounds(grid_t *grid, const double *ybounds)
5860 {
5861   struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
5862   lock_lazy_load(cdfGrid);
5863   if (grid->y.bounds == cdfPendingLoad)
5864     grid->y.bounds = NULL;
5865   cdfGrid->yBoundsGet.datasetNCId = -1;
5866   cdfGrid->yBoundsGet.varNCId = -1;
5867   cdfGrid->baseVtable->defYBounds(grid, ybounds);
5868   unlock_lazy_load(cdfGrid);
5869 }
5870 
5871 static const double *
cdfLazyGridInqYBoundsPtr(grid_t * grid)5872 cdfLazyGridInqYBoundsPtr(grid_t *grid)
5873 {
5874   struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
5875   lock_lazy_load(lazyGrid);
5876   if (grid->y.bounds == cdfPendingLoad)
5877     {
5878       grid->y.bounds = (double *)Malloc((size_t)grid->nvertex * grid->size * sizeof(double));
5879       cdf_get_var_double(lazyGrid->yBoundsGet.datasetNCId, lazyGrid->yBoundsGet.varNCId, grid->y.bounds);
5880     }
5881   unlock_lazy_load(lazyGrid);
5882   return lazyGrid->baseVtable->inqYBoundsPtr(grid);
5883 }
5884 
5885 static void
cdfLazyGridCopyScalarFields(grid_t * gridptrOrig,grid_t * gridptrDup)5886 cdfLazyGridCopyScalarFields(grid_t *gridptrOrig, grid_t *gridptrDup)
5887 {
5888   struct cdfLazyGrid *lazyGridDup = (struct cdfLazyGrid *)gridptrDup,
5889     *lazyGridOrig = (struct cdfLazyGrid *)gridptrOrig;
5890   lazyGridOrig->baseVtable->copyScalarFields(gridptrOrig, &lazyGridDup->base);
5891   lazyGridDup->baseVtable = lazyGridOrig->baseVtable;
5892   lazyGridDup->cellAreaGet = lazyGridOrig->cellAreaGet;
5893   lazyGridDup->xBoundsGet = lazyGridOrig->xBoundsGet;
5894   lazyGridDup->yBoundsGet = lazyGridOrig->yBoundsGet;
5895   lazyGridDup->xValsGet = lazyGridOrig->xValsGet;
5896   lazyGridDup->yValsGet = lazyGridOrig->yValsGet;
5897   init_lazy_load_lock(lazyGridDup);
5898 }
5899 
5900 static void
cdfLazyGridCopyArrayFields(grid_t * gridptrOrig,grid_t * gridptrDup)5901 cdfLazyGridCopyArrayFields(grid_t *gridptrOrig, grid_t *gridptrDup)
5902 {
5903   size_t reducedPointsSize = (size_t)gridptrOrig->reducedPointsSize;
5904   size_t gridsize = gridptrOrig->size;
5905   int gridtype = gridptrOrig->type;
5906   int irregular = gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED;
5907 
5908   if ( reducedPointsSize )
5909     {
5910       gridptrDup->reducedPoints = (int *)Malloc(reducedPointsSize * sizeof (int));
5911       memcpy(gridptrDup->reducedPoints, gridptrOrig->reducedPoints, reducedPointsSize * sizeof(int));
5912     }
5913 
5914   if ( gridptrOrig->x.vals != NULL && gridptrOrig->x.vals != cdfPendingLoad )
5915     {
5916       size_t size  = irregular ? gridsize : gridptrOrig->x.size;
5917       gridptrDup->x.vals = (double *)Malloc(size * sizeof (double));
5918       memcpy(gridptrDup->x.vals, gridptrOrig->x.vals, size * sizeof (double));
5919     }
5920 
5921   if ( gridptrOrig->y.vals != NULL && gridptrOrig->y.vals != cdfPendingLoad )
5922     {
5923       size_t size  = irregular ? gridsize : gridptrOrig->y.size;
5924       gridptrDup->y.vals = (double *)Malloc(size * sizeof (double));
5925       memcpy(gridptrDup->y.vals, gridptrOrig->y.vals, size * sizeof (double));
5926     }
5927 
5928   if ( gridptrOrig->x.bounds != NULL && gridptrOrig->x.bounds != cdfPendingLoad )
5929     {
5930       size_t size  = (irregular ? gridsize : gridptrOrig->x.size) * (size_t)gridptrOrig->nvertex;
5931       gridptrDup->x.bounds = (double *)Malloc(size * sizeof (double));
5932       memcpy(gridptrDup->x.bounds, gridptrOrig->x.bounds, size * sizeof (double));
5933     }
5934 
5935   if ( gridptrOrig->y.bounds != NULL && gridptrOrig->y.bounds != cdfPendingLoad )
5936     {
5937       size_t size = (irregular ? gridsize : gridptrOrig->y.size) * (size_t)gridptrOrig->nvertex;
5938       gridptrDup->y.bounds = (double *)Malloc(size * sizeof (double));
5939       memcpy(gridptrDup->y.bounds, gridptrOrig->y.bounds, size * sizeof (double));
5940     }
5941 
5942   {
5943     if ( gridptrOrig->area != NULL && gridptrOrig->area != cdfPendingLoad )
5944       {
5945         size_t size = gridsize;
5946         gridptrDup->area = (double *)Malloc(size * sizeof (double));
5947         memcpy(gridptrDup->area, gridptrOrig->area, size * sizeof (double));
5948       }
5949   }
5950 
5951   if ( gridptrOrig->mask != NULL )
5952     {
5953       size_t size = gridsize;
5954       gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
5955       memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
5956     }
5957 
5958   if ( gridptrOrig->mask_gme != NULL )
5959     {
5960       size_t size = gridsize;
5961       gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
5962       memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
5963     }
5964 }
5965 
5966 static grid_t *
cdfLazyGridCopy(grid_t * gridptrOrig)5967 cdfLazyGridCopy(grid_t *gridptrOrig)
5968 {
5969   struct cdfLazyGrid *lazyGridDup = (struct cdfLazyGrid *)Malloc(sizeof (*lazyGridDup));
5970   gridptrOrig->vtable->copyScalarFields(gridptrOrig, &lazyGridDup->base);
5971   gridptrOrig->vtable->copyArrayFields(gridptrOrig, &lazyGridDup->base);
5972   return &lazyGridDup->base;
5973 }
5974 
5975 static void
cdfLazyGridInitOnce(void)5976 cdfLazyGridInitOnce(void)
5977 {
5978   cdfLazyGridVtable = cdiGridVtable;
5979   cdfLazyGridVtable.destroy = cdfLazyGridDelete;
5980   cdfLazyGridVtable.copy = cdfLazyGridCopy;
5981   cdfLazyGridVtable.copyScalarFields = cdfLazyGridCopyScalarFields;
5982   cdfLazyGridVtable.copyArrayFields = cdfLazyGridCopyArrayFields;
5983   cdfLazyGridVtable.defArea = cdfLazyGridDefArea;
5984   cdfLazyGridVtable.inqAreaPtr = cdfLazyGridInqAreaPtr;
5985   cdfLazyGridVtable.inqArea = cdfLazyGridInqArea;
5986   cdfLazyGridVtable.inqXValsPtr = cdfLazyGridInqXValsPtr;
5987   cdfLazyGridVtable.inqYValsPtr = cdfLazyGridInqYValsPtr;
5988   cdfLazyGridVtable.inqXVal = cdfLazyGridInqXVal;
5989   cdfLazyGridVtable.inqYVal = cdfLazyGridInqYVal;
5990   cdfLazyGridVtable.defXVals = cdfLazyGridDefXVals;
5991   cdfLazyGridVtable.defYVals = cdfLazyGridDefYVals;
5992   cdfLazyGridVtable.compareXYFull = cdfLazyCompareXYFull;
5993   cdfLazyGridVtable.compareXYAO = cdfLazyCompareXYAO;
5994   cdfLazyGridVtable.defXBounds = cdfLazyGridDefXBounds;
5995   cdfLazyGridVtable.defYBounds = cdfLazyGridDefYBounds;
5996   cdfLazyGridVtable.inqXBoundsPtr = cdfLazyGridInqXBoundsPtr;
5997   cdfLazyGridVtable.inqYBoundsPtr = cdfLazyGridInqYBoundsPtr;
5998   /* create inaccessible memory area, if possible, this serves as
5999    * dummy value for pointers to data not yet loaded */
6000   /*
6001 #ifdef HAVE_MMAP
6002   {
6003     size_t pgSize = cdiGetPageSize(false);
6004     static const char devZero[] = "/dev/zero";
6005     int fd = open(devZero, O_RDWR);
6006     if (fd == -1)
6007       SysError("Could not open %s to map anonymous memory", devZero);
6008     void *cdfInvalid = mmap(NULL, pgSize, PROT_NONE, MAP_PRIVATE, fd, 0);
6009     if (cdfInvalid == MAP_FAILED)
6010       SysError("Could not mmap anonymous memory");
6011     cdfPendingLoad = cdfInvalid;
6012     int rc = close(fd);
6013     if (rc == -1)
6014       SysError("Could not close %s file handle %d after mapping anonymous"
6015                " memory", devZero, fd);
6016   }
6017 #else
6018   */
6019   cdfPendingLoad = (double *)&cdfPendingLoad;
6020   //#endif
6021   atexit(cdfLazyGridDestroyOnce);
6022 #ifndef HAVE_LIBPTHREAD
6023   cdfLazyInitialized = true;
6024 #endif
6025 }
6026 
6027 static void
cdfBaseGridInit(grid_t * grid,int gridtype)6028 cdfBaseGridInit(grid_t *grid, int gridtype)
6029 {
6030   grid_init(grid);
6031   cdiGridTypeInit(grid, gridtype, 0);
6032 }
6033 
6034 static void
cdfLazyGridInit(struct cdfLazyGrid * grid,int gridtype)6035 cdfLazyGridInit(struct cdfLazyGrid *grid, int gridtype)
6036 {
6037 #ifdef HAVE_LIBPTHREAD
6038   pthread_once(&cdfLazyInitialized, cdfLazyGridInitOnce);
6039 #else
6040   if (cdfLazyInitialized) ; else cdfLazyGridInitOnce();
6041 #endif
6042   cdfBaseGridInit(&grid->base, gridtype);
6043   grid->baseVtable = grid->base.vtable;
6044   grid->cellAreaGet.datasetNCId = -1;
6045   grid->cellAreaGet.varNCId = -1;
6046   grid->xValsGet.datasetNCId = -1;
6047   grid->xValsGet.varNCId = -1;
6048   grid->yValsGet.datasetNCId = -1;
6049   grid->yValsGet.varNCId = -1;
6050   grid->xBoundsGet.datasetNCId = -1;
6051   grid->xBoundsGet.varNCId = -1;
6052   grid->yBoundsGet.datasetNCId = -1;
6053   grid->yBoundsGet.varNCId = -1;
6054   grid->base.vtable = &cdfLazyGridVtable;
6055   init_lazy_load_lock(grid);
6056 }
6057 
6058 
cdfLazyGridRenew(struct cdfLazyGrid * restrict * restrict gridpptr,int gridtype)6059 void cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
6060 {
6061   struct cdfLazyGrid *restrict grid = *gridpptr;
6062   if (!grid)
6063     *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (*grid));
6064   cdfLazyGridInit(grid, gridtype);
6065 }
6066 
6067 
cdfBaseGridRenew(struct cdfLazyGrid * restrict * restrict gridpptr,int gridtype)6068 void cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
6069 {
6070   struct cdfLazyGrid *restrict grid = *gridpptr;
6071   if (!grid)
6072     *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (grid_t));
6073   cdfBaseGridInit((grid_t*)grid, gridtype);
6074 }
6075 
6076 #endif
6077 
6078 /*
6079  * Local Variables:
6080  * c-file-style: "Java"
6081  * c-basic-offset: 2
6082  * indent-tabs-mode: nil
6083  * show-trailing-whitespace: t
6084  * require-trailing-newline: t
6085  * End:
6086  */
6087 #ifndef CDI_CKSUM_H_
6088 #define CDI_CKSUM_H_
6089 
6090 #include <inttypes.h>
6091 
6092 uint32_t cdiCheckSum(int type, int count, const void *data);
6093 
6094 #endif
6095 
6096 /*
6097  * Local Variables:
6098  * c-file-style: "Java"
6099  * c-basic-offset: 2
6100  * indent-tabs-mode: nil
6101  * show-trailing-whitespace: t
6102  * require-trailing-newline: t
6103  * End:
6104  */
6105 #ifdef HAVE_CONFIG_H
6106 #endif
6107 
6108 #include <inttypes.h>
6109 #include <sys/types.h>
6110 
6111 void
6112 memcrc_r(uint32_t *state, const unsigned char *block, size_t block_len);
6113 
6114 void
6115 memcrc_r_eswap(uint32_t *state, const unsigned char *elems, size_t num_elems,
6116                size_t elem_size);
6117 
6118 uint32_t
6119 memcrc_finish(uint32_t *state, off_t total_size);
6120 
6121 uint32_t
6122 memcrc(const unsigned char *b, size_t n);
6123 
6124 /*
6125  * Local Variables:
6126  * c-file-style: "Java"
6127  * c-basic-offset: 2
6128  * indent-tabs-mode: nil
6129  * show-trailing-whitespace: t
6130  * require-trailing-newline: t
6131  * End:
6132  */
6133 #ifdef HAVE_CONFIG_H
6134 #endif
6135 
6136 #ifndef SERIALIZE_H
6137 #define SERIALIZE_H
6138 
6139 #include <string.h>
6140 
6141 #ifndef  CDI_CKSUM_H_
6142 #endif
6143 #ifndef  CDI_KEY_H_
6144 #endif
6145 #ifndef  ERROR_H
6146 #endif
6147 
6148 /*
6149  * Generic interfaces for (de-)marshalling
6150  */
6151 int serializeGetSize(int count, int datatype, void *context);
6152 void serializePack(const void *data, int count, int datatype,
6153                    void *buf, int buf_size, int *position, void *context);
6154 void serializeUnpack(const void *buf, int buf_size, int *position,
6155                      void *data, int count, int datatype, void *context);
6156 
6157 
6158 /*
6159  * (de-)marshalling function for key/value structures
6160  */
6161 static inline int
serializeKeysGetPackSize(const cdi_keys_t * keysp,void * context)6162 serializeKeysGetPackSize(const cdi_keys_t *keysp, void *context)
6163 {
6164   int packBuffSize = 0;
6165 
6166   int nelems = keysp->nelems;
6167   packBuffSize += serializeGetSize(1, CDI_DATATYPE_INT, context);
6168   for ( int keyid = 0; keyid < nelems; keyid++ )
6169     {
6170       const cdi_key_t *keyp = &(keysp->value[keyid]);
6171       int type = keyp->type;
6172       packBuffSize += serializeGetSize(1, CDI_DATATYPE_INT, context); // key
6173       packBuffSize += serializeGetSize(1, CDI_DATATYPE_INT, context); // type
6174       if (type == KEY_BYTES)
6175         {
6176           int length = keyp->length;
6177           packBuffSize +=
6178             serializeGetSize(1, CDI_DATATYPE_INT, context)
6179             + serializeGetSize(length, CDI_DATATYPE_TXT, context);
6180         }
6181       else
6182         {
6183           packBuffSize += serializeGetSize(1, CDI_DATATYPE_INT, context);
6184         }
6185     }
6186   packBuffSize += serializeGetSize(1, CDI_DATATYPE_UINT32, context);
6187   return packBuffSize;
6188 }
6189 
6190 static inline void
serializeKeysPack(const cdi_keys_t * keysp,void * buf,int buf_size,int * position,void * context)6191 serializeKeysPack(const cdi_keys_t *keysp, void *buf, int buf_size, int *position, void *context)
6192 {
6193   uint32_t d = 0;
6194 
6195   int nelems = keysp->nelems;
6196   serializePack(&nelems, 1, CDI_DATATYPE_INT, buf, buf_size, position, context);
6197   for ( int keyid = 0; keyid < nelems; keyid++ )
6198     {
6199       const cdi_key_t *keyp = &(keysp->value[keyid]);
6200       int key = keyp->key;
6201       int type = keyp->type;
6202       serializePack(&key, 1, CDI_DATATYPE_INT, buf, buf_size, position, context);
6203       serializePack(&type, 1, CDI_DATATYPE_INT, buf, buf_size, position, context);
6204       if (type == KEY_BYTES)
6205         {
6206           int length = keyp->length;
6207           serializePack(&length, 1, CDI_DATATYPE_INT, buf, buf_size, position, context);
6208           serializePack(keyp->v.s, length, CDI_DATATYPE_TXT, buf, buf_size, position, context);
6209           d ^= cdiCheckSum(CDI_DATATYPE_TXT, length, keyp->v.s);
6210         }
6211       else if (type == KEY_INT)
6212         {
6213           serializePack(&keyp->v.i, 1, CDI_DATATYPE_INT, buf, buf_size, position, context);
6214         }
6215       else if (type == KEY_FLOAT)
6216         {
6217           serializePack(&keyp->v.d, 1, CDI_DATATYPE_FLT64, buf, buf_size, position, context);
6218         }
6219     }
6220 
6221   serializePack(&d, 1, CDI_DATATYPE_UINT32, buf, buf_size, position, context);
6222 }
6223 
6224 static inline void
serializeKeysUnpack(const void * buf,int buf_size,int * position,cdi_keys_t * keysp,void * context)6225 serializeKeysUnpack(const void *buf, int buf_size, int *position, cdi_keys_t *keysp, void *context)
6226 {
6227   uint32_t d, d2 = 0;
6228   void *buffer = NULL;
6229   int buffersize = 0;
6230 
6231   int nelems;
6232   serializeUnpack(buf, buf_size, position, &nelems, 1, CDI_DATATYPE_INT, context);
6233   for (int i = 0; i < nelems; ++i)
6234     {
6235       int key, type;
6236       serializeUnpack(buf, buf_size, position, &key, 1, CDI_DATATYPE_INT, context);
6237       serializeUnpack(buf, buf_size, position, &type, 1, CDI_DATATYPE_INT, context);
6238       if (type == KEY_BYTES)
6239         {
6240           int length;
6241           serializeUnpack(buf, buf_size, position, &length, 1, CDI_DATATYPE_INT, context);
6242           if (length > buffersize)
6243             {
6244               buffersize = length;
6245               buffer = realloc(buffer, buffersize);
6246             }
6247           serializeUnpack(buf, buf_size, position, buffer, length, CDI_DATATYPE_TXT, context);
6248           cdiDefVarKeyBytes(keysp, key, buffer, length);
6249           d2 ^= cdiCheckSum(CDI_DATATYPE_TXT, length, buffer);
6250         }
6251       else if (type == KEY_INT)
6252         {
6253           int ival;
6254           serializeUnpack(buf, buf_size, position, &ival, 1, CDI_DATATYPE_INT, context);
6255           cdiDefVarKeyInt(keysp, key, ival);
6256         }
6257     }
6258   serializeUnpack(buf, buf_size, position, &d, 1, CDI_DATATYPE_UINT32, context);
6259   xassert(d == d2);
6260   if (buffer) free(buffer);
6261 }
6262 
6263 /*
6264  * (de-)marshalling function for common data structures
6265  */
6266 static inline int
serializeStrTabGetPackSize(const char ** strTab,int numStr,void * context)6267 serializeStrTabGetPackSize(const char **strTab, int numStr,
6268                            void *context)
6269 {
6270   xassert(numStr >= 0);
6271   int packBuffSize = 0;
6272   for (size_t i = 0; i < (size_t)numStr; ++i)
6273   {
6274     size_t len = strlen(strTab[i]);
6275     packBuffSize +=
6276       serializeGetSize(1, CDI_DATATYPE_INT, context)
6277       + serializeGetSize((int)len, CDI_DATATYPE_TXT, context);
6278   }
6279   packBuffSize +=
6280     serializeGetSize(1, CDI_DATATYPE_UINT32, context);
6281   return packBuffSize;
6282 }
6283 
6284 static inline void
serializeStrTabPack(const char ** strTab,int numStr,void * buf,int buf_size,int * position,void * context)6285 serializeStrTabPack(const char **strTab, int numStr,
6286                     void *buf, int buf_size, int *position, void *context)
6287 {
6288   uint32_t d = 0;
6289   xassert(numStr >= 0);
6290   for (size_t i = 0; i < (size_t)numStr; ++i)
6291   {
6292     int len = (int)strlen(strTab[i]);
6293     serializePack(&len, 1, CDI_DATATYPE_INT,
6294                   buf, buf_size, position, context);
6295     serializePack(strTab[i], len, CDI_DATATYPE_TXT,
6296                   buf, buf_size, position, context);
6297     d ^= cdiCheckSum(CDI_DATATYPE_TXT, len, strTab[i]);
6298   }
6299   serializePack(&d, 1, CDI_DATATYPE_UINT32,
6300                 buf, buf_size, position, context);
6301 }
6302 
6303 static inline void
serializeStrTabUnpack(const void * buf,int buf_size,int * position,char ** strTab,int numStr,void * context)6304 serializeStrTabUnpack(const void *buf, int buf_size, int *position,
6305                       char **strTab, int numStr, void *context)
6306 {
6307   uint32_t d, d2 = 0;
6308   xassert(numStr >= 0);
6309   for (size_t i = 0; i < (size_t)numStr; ++i)
6310     {
6311       int len;
6312       serializeUnpack(buf, buf_size, position,
6313                       &len, 1, CDI_DATATYPE_INT, context);
6314       serializeUnpack(buf, buf_size, position,
6315                       strTab[i], len, CDI_DATATYPE_TXT, context);
6316       strTab[i][len] = '\0';
6317       d2 ^= cdiCheckSum(CDI_DATATYPE_TXT, len, strTab[i]);
6318     }
6319   serializeUnpack(buf, buf_size, position,
6320                   &d, 1, CDI_DATATYPE_UINT32, context);
6321   xassert(d == d2);
6322 }
6323 
6324 /*
6325  * Interfaces for marshalling within a single memory domain
6326  */
6327 int serializeGetSizeInCore(int count, int datatype, void *context);
6328 void serializePackInCore(const void *data, int count, int datatype,
6329                           void *buf, int buf_size, int *position, void *context);
6330 void serializeUnpackInCore(const void *buf, int buf_size, int *position,
6331                            void *data, int count, int datatype, void *context);
6332 
6333 #endif
6334 /*
6335  * Local Variables:
6336  * c-file-style: "Java"
6337  * c-basic-offset: 2
6338  * indent-tabs-mode: nil
6339  * show-trailing-whitespace: t
6340  * require-trailing-newline: t
6341  * End:
6342  */
6343 #include <inttypes.h>
6344 #include <sys/types.h>
6345 #include <stdlib.h>
6346 
6347 
cdiCheckSum(int type,int count,const void * buffer)6348 uint32_t cdiCheckSum(int type, int count, const void *buffer)
6349 {
6350   uint32_t s = 0U;
6351   xassert(count >= 0);
6352   size_t elemSize = (size_t)serializeGetSizeInCore(1, type, NULL);
6353   memcrc_r_eswap(&s, (const unsigned char *)buffer, (size_t)count, elemSize);
6354   s = memcrc_finish(&s, (off_t)(elemSize * (size_t)count));
6355   return s;
6356 }
6357 
6358 /*
6359  * Local Variables:
6360  * c-file-style: "Java"
6361  * c-basic-offset: 2
6362  * indent-tabs-mode: nil
6363  * show-trailing-whitespace: t
6364  * require-trailing-newline: t
6365  * End:
6366  */
6367 #include <stdio.h>
6368 #include <string.h>
6369 #include <errno.h>
6370 
cdiStringError(int cdiErrno)6371 const char *cdiStringError(int cdiErrno)
6372 {
6373   static const char UnknownError[] = "Unknown Error";
6374   static const char _ETMOF[]       = "Too many open files";
6375   static const char _EISDIR[]      = "Is a directory";
6376   static const char _EISEMPTY[]    = "File is empty";
6377   static const char _EUFTYPE[]     = "Unsupported file type";
6378   static const char _ELIBNAVAIL[]  = "Unsupported file type (library support not compiled in)";
6379   static const char _EUFSTRUCT[]   = "Unsupported file structure";
6380   static const char _EUNC4[]       = "Unsupported NetCDF4 structure";
6381   static const char _EDIMSIZE[]    = "Invalid dimension size";
6382   static const char _ELIMIT[]      = "Internal limits exceeded";
6383 
6384   switch (cdiErrno) {
6385   case CDI_ESYSTEM:
6386     {
6387       const char *cp = strerror(errno);
6388       if ( cp == NULL ) break;
6389       return cp;
6390     }
6391   case CDI_ETMOF:      return _ETMOF;
6392   case CDI_EISDIR:     return _EISDIR;
6393   case CDI_EISEMPTY:   return _EISEMPTY;
6394   case CDI_EUFTYPE:    return _EUFTYPE;
6395   case CDI_ELIBNAVAIL: return _ELIBNAVAIL;
6396   case CDI_EUFSTRUCT:  return _EUFSTRUCT;
6397   case CDI_EUNC4:      return _EUNC4;
6398   case CDI_EDIMSIZE:   return _EDIMSIZE;
6399   case CDI_ELIMIT:     return _ELIMIT;
6400   }
6401 
6402   return UnknownError;
6403 }
6404 
6405 /*
6406  * Local Variables:
6407  * c-file-style: "Java"
6408  * c-basic-offset: 2
6409  * indent-tabs-mode: nil
6410  * show-trailing-whitespace: t
6411  * require-trailing-newline: t
6412  * End:
6413  */
6414 #ifndef  GRIBAPI_H
6415 #define  GRIBAPI_H
6416 
6417 #ifdef  HAVE_LIBGRIB_API
6418 #include <grib_api.h>
6419 #ifndef  ERROR_H
6420 #endif
6421 #endif
6422 
6423 #ifndef  CDI_INT_H
6424 #endif
6425 
6426 #define  GRIBAPI_MISSVAL  -9.E33
6427 
6428 // GRIB2 Level Types
6429 #define  GRIB2_LTYPE_SURFACE               1
6430 #define  GRIB2_LTYPE_CLOUD_BASE            2
6431 #define  GRIB2_LTYPE_CLOUD_TOP             3
6432 #define  GRIB2_LTYPE_ISOTHERM0             4
6433 #define  GRIB2_LTYPE_TROPOPAUSE            7
6434 #define  GRIB2_LTYPE_TOA                   8
6435 #define  GRIB2_LTYPE_SEA_BOTTOM            9
6436 #define  GRIB2_LTYPE_ATMOSPHERE           10
6437 #define  GRIB2_LTYPE_ISOBARIC            100
6438 #define  GRIB2_LTYPE_MEANSEA             101
6439 #define  GRIB2_LTYPE_ALTITUDE            102
6440 #define  GRIB2_LTYPE_HEIGHT              103
6441 #define  GRIB2_LTYPE_SIGMA               104
6442 #define  GRIB2_LTYPE_HYBRID              105
6443 #define  GRIB2_LTYPE_LANDDEPTH           106
6444 #define  GRIB2_LTYPE_ISENTROPIC          107
6445 #define  GRIB2_LTYPE_SNOW                114
6446 #define  GRIB2_LTYPE_REFERENCE           150
6447 #define  GRIB2_LTYPE_SEADEPTH            160  // Depth Below Sea Level
6448 #define  GRIB2_LTYPE_LAKE_BOTTOM         162  // Lake or River Bottom
6449 #define  GRIB2_LTYPE_SEDIMENT_BOTTOM     163  // Bottom Of Sediment Layer
6450 #define  GRIB2_LTYPE_SEDIMENT_BOTTOM_TA  164  // Bottom Of Thermally Active Sediment Layer
6451 #define  GRIB2_LTYPE_SEDIMENT_BOTTOM_TW  165  // Bottom Of Sediment Layer Penetrated By Thermal Wave
6452 #define  GRIB2_LTYPE_MIX_LAYER           166  // Mixing Layer
6453 
6454 /* GRIB2 Data representation type (Grid Type) */
6455 #define  GRIB2_GTYPE_LATLON                0  // Latitude/longitude (or equidistant cylindrical, or Plate Carree)
6456 #define  GRIB2_GTYPE_LATLON_ROT            1  // Rotated Latitude/longitude
6457 #define  GRIB2_GTYPE_LATLON_STR            2  // Stretched Latitude/longitude
6458 #define  GRIB2_GTYPE_LATLON_ROTSTR         3  // Stretched and Rotated Latitude/longitude
6459 #define  GRIB2_GTYPE_STERE                20  // Polar stereographic projection
6460 #define  GRIB2_GTYPE_LCC                  30  // Lambert conformal
6461 #define  GRIB2_GTYPE_GAUSSIAN             40  // Gaussian latitude/longitude
6462 #define  GRIB2_GTYPE_GAUSSIAN_ROT         41  // Rotated Gaussian latitude/longitude
6463 #define  GRIB2_GTYPE_GAUSSIAN_STR         42  // Stretched Gaussian latitude/longitude
6464 #define  GRIB2_GTYPE_GAUSSIAN_ROTSTR      43  // Stretched and rotated Gaussian latitude/longitude
6465 #define  GRIB2_GTYPE_SPECTRAL             50  // Spherical harmonic coefficients
6466 #define  GRIB2_GTYPE_GME                 100  // Triangular grid based on an icosahedron (GME)
6467 #define  GRIB2_GTYPE_UNSTRUCTURED        101  // General Unstructured Grid
6468 
6469 const char *gribapiLibraryVersionString(void);
6470 void gribContainersNew(stream_t * streamptr);
6471 void gribContainersDelete(stream_t * streamptr);
6472 
6473 #ifdef HAVE_LIBGRIB_API
my_grib_set_double(grib_handle * h,const char * key,double val)6474 static inline int my_grib_set_double(grib_handle* h, const char* key, double val)
6475 {
6476   if ( CDI_gribapi_debug )
6477     fprintf(stderr, "grib_set_double(\tgrib_handle* h, \"%s\", %f)\n", key, val);
6478 
6479   int ret_val = grib_set_double(h, key, val);
6480   if (ret_val != 0)
6481     fprintf(stderr, "!!! failed call to grib_set_double(\tgrib_handle* h, \"%s\", %f) !!!\n", key, val);
6482   return ret_val;
6483 }
6484 
my_grib_set_long(grib_handle * h,const char * key,long val)6485 static inline int my_grib_set_long(grib_handle* h, const char* key, long val)
6486 {
6487   if ( CDI_gribapi_debug )
6488     fprintf(stderr, "grib_set_long(  \tgrib_handle* h, \"%s\", %ld)\n", key, val);
6489 
6490   int ret_val = grib_set_long(h, key, val);
6491   if (ret_val != 0)
6492     fprintf(stderr, "!!! failed call to grib_set_long(  \tgrib_handle* h, \"%s\", %ld) !!!\n", key, val);
6493   return ret_val;
6494 }
6495 
my_grib_set_string(grib_handle * h,const char * key,const char * val,size_t * length)6496 static inline int my_grib_set_string(grib_handle* h, const char* key, const char* val, size_t* length)
6497 {
6498   if ( CDI_gribapi_debug )
6499     fprintf(stderr, "grib_set_string(\tgrib_handle* h, \"%s\", \"%s\")\n", key, val);
6500 
6501   int ret_val = grib_set_string(h, key, val, length);
6502   if (ret_val != 0)
6503     fprintf(stderr, "!!! grib_set_string(\tgrib_handle* h, \"%s\", \"%s\") !!!\n", key, val);
6504   return ret_val;
6505 }
6506 
gribHandleNew(int editionNumber)6507 static inline void *gribHandleNew(int editionNumber)
6508 {
6509   grib_handle *gh = grib_handle_new_from_samples(NULL, (editionNumber == 1) ? "GRIB1" : "GRIB2");
6510   if ( gh == NULL ) Error("grib_handle_new_from_samples failed!");
6511 
6512   if ( editionNumber == 1 ) GRIB_CHECK(my_grib_set_long(gh, "deleteLocalDefinition", 1L), 0);
6513   if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "grib2LocalSectionPresent", 0L), 0);
6514   if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", 0L), 0);
6515 
6516   return gh;
6517 }
6518 
gribHandleDelete(void * gh)6519 static inline void gribHandleDelete(void *gh)
6520 {
6521   grib_handle_delete((struct grib_handle *)gh);
6522 }
6523 #else
6524 #define gribHandleNew(editionNumber) (NULL)
6525 #define gribHandleDelete(gh)
6526 #endif
6527 
6528 typedef struct {
6529   bool init;
6530   void *gribHandle;
6531 }
6532 gribContainer_t;
6533 
6534 #endif  /* GRIBAPI_H */
6535 /*
6536  * Local Variables:
6537  * c-file-style: "Java"
6538  * c-basic-offset: 2
6539  * indent-tabs-mode: nil
6540  * show-trailing-whitespace: t
6541  * require-trailing-newline: t
6542  * End:
6543  */
6544 #ifndef  CGRIBEX_H
6545 #define  CGRIBEX_H
6546 
6547 #include <stdio.h>
6548 #include <stdbool.h>
6549 #include <sys/types.h>
6550 
6551 #define  GRIB_MISSVAL  -9.E33
6552 
6553 // GRIB1 Level Types
6554 #define  GRIB1_LTYPE_SURFACE               1
6555 #define  GRIB1_LTYPE_CLOUD_BASE            2
6556 #define  GRIB1_LTYPE_CLOUD_TOP             3
6557 #define  GRIB1_LTYPE_ISOTHERM0             4
6558 #define  GRIB1_LTYPE_TROPOPAUSE            7
6559 #define  GRIB1_LTYPE_TOA                   8
6560 #define  GRIB1_LTYPE_SEA_BOTTOM            9
6561 #define  GRIB1_LTYPE_ATMOSPHERE           10
6562 #define  GRIB1_LTYPE_99                   99
6563 #define  GRIB1_LTYPE_ISOBARIC            100
6564 #define  GRIB1_LTYPE_ISOBARIC_PA         210
6565 #define  GRIB1_LTYPE_MEANSEA             102
6566 #define  GRIB1_LTYPE_ALTITUDE            103
6567 #define  GRIB1_LTYPE_HEIGHT              105
6568 #define  GRIB1_LTYPE_SIGMA               107
6569 #define  GRIB1_LTYPE_SIGMA_LAYER         108
6570 #define  GRIB1_LTYPE_HYBRID              109
6571 #define  GRIB1_LTYPE_HYBRID_LAYER        110
6572 #define  GRIB1_LTYPE_LANDDEPTH           111
6573 #define  GRIB1_LTYPE_LANDDEPTH_LAYER     112
6574 #define  GRIB1_LTYPE_ISENTROPIC          113
6575 #define  GRIB1_LTYPE_SEADEPTH            160  // Depth Below Sea Level
6576 #define  GRIB1_LTYPE_LAKE_BOTTOM         162  // Lake or River Bottom
6577 #define  GRIB1_LTYPE_SEDIMENT_BOTTOM     163  // Bottom Of Sediment Layer
6578 #define  GRIB1_LTYPE_SEDIMENT_BOTTOM_TA  164  // Bottom Of Thermally Active Sediment Layer
6579 #define  GRIB1_LTYPE_SEDIMENT_BOTTOM_TW  165  // Bottom Of Sediment Layer Penetrated By Thermal Wave
6580 #define  GRIB1_LTYPE_MIX_LAYER           166  // Mixing Layer
6581 
6582 // GRIB1 Data representation type (Grid Type) [Table 6]
6583 #define  GRIB1_GTYPE_LATLON                0  //  latitude/longitude
6584 #define  GRIB1_GTYPE_LATLON_ROT           10  //  rotated latitude/longitude
6585 #define  GRIB1_GTYPE_LATLON_STR           20  //  stretched latitude/longitude
6586 #define  GRIB1_GTYPE_LATLON_ROTSTR        30  //  rotated and stretched latitude/longitude
6587 #define  GRIB1_GTYPE_GAUSSIAN              4  //  gaussian grid
6588 #define  GRIB1_GTYPE_GAUSSIAN_ROT         14  //  rotated gaussian grid
6589 #define  GRIB1_GTYPE_GAUSSIAN_STR         24  //  stretched gaussian grid
6590 #define  GRIB1_GTYPE_GAUSSIAN_ROTSTR      34  //  rotated and stretched gaussian grid
6591 #define  GRIB1_GTYPE_LCC                   3  //  Lambert conformal
6592 #define  GRIB1_GTYPE_SPECTRAL             50  //  spherical harmonics
6593 #define  GRIB1_GTYPE_GME                 192  //  hexagonal GME grid
6594 
6595 // Macros for the indicator section ( Section 0 )
6596 #define  ISEC0_GRIB_Len             (isec0[ 0])  //  Number of octets in the GRIB message
6597 #define  ISEC0_GRIB_Version         (isec0[ 1])  //  GRIB edition number
6598 
6599 
6600 // Macros for the product definition section ( Section 1 )
6601 #define  ISEC1_TABLE4_MINUTE      0
6602 #define  ISEC1_TABLE4_HOUR        1
6603 #define  ISEC1_TABLE4_DAY         2
6604 #define  ISEC1_TABLE4_3HOURS     10
6605 #define  ISEC1_TABLE4_6HOURS     11
6606 #define  ISEC1_TABLE4_12HOURS    12
6607 #define  ISEC1_TABLE4_QUARTER    13
6608 #define  ISEC1_TABLE4_30MINUTES  14
6609 
6610 
6611 #define  ISEC1_CodeTable            (isec1[ 0])  //  Version number of code table
6612 #define  ISEC1_CenterID             (isec1[ 1])  //  Identification of centre
6613 #define  ISEC1_ModelID              (isec1[ 2])  //  Identification of model
6614 #define  ISEC1_GridDefinition       (isec1[ 3])  //  Grid definition
6615 #define  ISEC1_Sec2Or3Flag          (isec1[ 4])  //  Section 2 or 3 included
6616 #define  ISEC1_Parameter            (isec1[ 5])  //  Parameter indicator
6617 #define  ISEC1_LevelType            (isec1[ 6])  //  Type of level indicator
6618 #define  ISEC1_Level1               (isec1[ 7])  //  Level 1
6619 #define  ISEC1_Level2               (isec1[ 8])  //  Level 2
6620 #define  ISEC1_Year                 (isec1[ 9])  //  Year of century (YY)
6621 #define  ISEC1_Month                (isec1[10])  //  Month (MM)
6622 #define  ISEC1_Day                  (isec1[11])  //  Day (DD)
6623 #define  ISEC1_Hour                 (isec1[12])  //  Hour (HH)
6624 #define  ISEC1_Minute               (isec1[13])  //  Minute (MM)
6625 #define  ISEC1_TimeUnit             (isec1[14])  //  Time unit indicator
6626 #define  ISEC1_TimePeriod1          (isec1[15])  //  P1 Time period
6627 #define  ISEC1_TimePeriod2          (isec1[16])  //  P2 Time period
6628 #define  ISEC1_TimeRange            (isec1[17])  //  Time range indicator
6629 #define  ISEC1_AvgNum               (isec1[18])  //  Number of products included in an average
6630 #define  ISEC1_AvgMiss              (isec1[19])  //  Number of products missing from an average
6631 #define  ISEC1_Century              (isec1[20])  //  Century
6632 #define  ISEC1_SubCenterID          (isec1[21])  //  Subcenter identifier
6633 #define  ISEC1_DecScaleFactor       (isec1[22])  //  Decimal scale factor
6634 #define  ISEC1_LocalFLag            (isec1[23])  //  Flag field to indicate local use in isec1
6635 
6636 #define  ISEC1_ECMWF_LocalExtension (isec1[36])
6637 #define  ISEC1_ECMWF_Class          (isec1[37])
6638 
6639 
6640 // Macros for the grid definition section ( Section 2 )
6641 #define  ISEC2_GridType             (isec2[ 0])  // Data representation type
6642 
6643 // Triangular grids
6644 
6645 #define  ISEC2_GME_NI2              (isec2[ 1])  //  Number of factor 2 in factorisation of Ni
6646 #define  ISEC2_GME_NI3              (isec2[ 2])  //  Number of factor 3 in factorisation of Ni
6647 #define  ISEC2_GME_ND               (isec2[ 3])  //  Nubmer of diamonds
6648 #define  ISEC2_GME_NI               (isec2[ 4])  //  Number of tri. subdiv. of the icosahedron
6649 #define  ISEC2_GME_AFlag            (isec2[ 5])  //  Flag for orientation of diamonds (Table A)
6650 #define  ISEC2_GME_LatPP            (isec2[ 6])  //  Latitude of pole point
6651 #define  ISEC2_GME_LonPP            (isec2[ 7])  //  Longitude of pole point
6652 #define  ISEC2_GME_LonMPL           (isec2[ 8])  //  Longitude of the first diamond
6653 #define  ISEC2_GME_BFlag            (isec2[ 9])  //  Flag for storage sequence (Table B)
6654 
6655 // Spherical harmonic coeficients
6656 
6657 #define  ISEC2_PentaJ               (isec2[ 1])  //  J pentagonal resolution parameter
6658 #define  ISEC2_PentaK               (isec2[ 2])  //  K pentagonal resolution parameter
6659 #define  ISEC2_PentaM               (isec2[ 3])  //  M pentagonal resolution parameter
6660 #define  ISEC2_RepType              (isec2[ 4])  //  Representation type
6661 #define  ISEC2_RepMode              (isec2[ 5])  //  Representation mode
6662 
6663 // Gaussian grids
6664 
6665 #define  ISEC2_NumLon               (isec2[ 1])  //  Number of points along a parallel (Ni)
6666 #define  ISEC2_NumLat               (isec2[ 2])  //  Number of points along a meridian (Nj)
6667 #define  ISEC2_FirstLat             (isec2[ 3])  //  Latitude of the first grid point
6668 #define  ISEC2_FirstLon             (isec2[ 4])  //  Longitude of the first grid point
6669 #define  ISEC2_ResFlag              (isec2[ 5])  //  Resolution flag: 128 regular grid
6670 #define  ISEC2_LastLat              (isec2[ 6])  //  Latitude of the last grid point
6671 #define  ISEC2_LastLon              (isec2[ 7])  //  Longitude of the last grid point
6672 #define  ISEC2_LonIncr              (isec2[ 8])  //  i direction increment
6673 #define  ISEC2_LatIncr              (isec2[ 9])  //  j direction increment
6674 #define  ISEC2_NumPar               (isec2[ 9])  //  Number of parallels between a pole and the E.
6675 #define  ISEC2_ScanFlag             (isec2[10])  //  Scanning mode flags
6676 #define  ISEC2_NumVCP               (isec2[11])  //  Number of vertical coordinate parameters
6677 
6678 // Lambert
6679 
6680 #define  ISEC2_Lambert_Lov          (isec2[ 6])  //  Orientation of the grid
6681 #define  ISEC2_Lambert_dx           (isec2[ 8])  //  X-direction grid length
6682 #define  ISEC2_Lambert_dy           (isec2[ 9])  //  Y-direction grid length
6683 #define  ISEC2_Lambert_ProjFlag     (isec2[12])  //  Projection centre flag
6684 #define  ISEC2_Lambert_LatS1        (isec2[13])  //  First lat at which the secant cone cuts the sphere
6685 #define  ISEC2_Lambert_LatS2        (isec2[14])  //  Second lat at which the secant cone cuts the sphere
6686 #define  ISEC2_Lambert_LatSP        (isec2[19])  //  Latitude of the southern pole
6687 #define  ISEC2_Lambert_LonSP        (isec2[20])  //  Longitude of the southern pole
6688 
6689 
6690 #define  ISEC2_Reduced              (isec2[16])  // 0: regular, 1: reduced grid
6691 
6692 #define  ISEC2_ReducedPointsPtr     (&isec2[22])
6693 #define  ISEC2_ReducedPoints(i)     (isec2[22+i]) // Number of points along each parallel
6694 
6695 
6696 #define  ISEC2_LatSP                (isec2[12])  // Latitude of the southern pole of rotation
6697 #define  ISEC2_LonSP                (isec2[13])  // Longitude of the southern pole of rotation
6698 
6699 #define  FSEC2_RotAngle             (fsec2[ 0])  // Angle of rotation
6700 #define  FSEC2_StrFact              (fsec2[ 1])  // Stretching factor
6701 
6702 // Macros for the bit map section ( Section 3 )
6703 
6704 #define  ISEC3_PredefBitmap         (isec3[ 0])  // Predefined bitmap
6705 #define  ISEC3_MissVal              (isec3[ 1])  // Missing data value for integers
6706 #define  FSEC3_MissVal              (fsec3[ 1])  // Missing data value for floats
6707 
6708 // Macros for the binary data section ( Section 4 )
6709 
6710 #define  ISEC4_NumValues            (isec4[ 0])  // Number of data values for encode/decode
6711 #define  ISEC4_NumBits              (isec4[ 1])  // Number of bits used for each encoded value
6712 #define  ISEC4_NumNonMissValues     (isec4[20])  // Number of non-missing values
6713 
6714 
6715 #ifdef __cplusplus
6716 extern "C" {
6717 #endif
6718 
6719 
6720 void  gribFixZSE(int flag);     // 1: Fix ZeroShiftError of simple packed spherical harmonics
6721 void  gribSetConst(int flag);   // 1: Don't pack constant fields on regular grids
6722 void  gribSetDebug(int debug);  // 1: Debugging
6723 void  gribSetRound(int round);
6724 void  gribSetRefDP(double refval);
6725 void  gribSetRefSP(float  refval);
6726 void  gribSetValueCheck(int vcheck);
6727 
6728 
6729 void  gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
6730                float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
6731                int kleng, int *kword, const char *hoper, int *kret);
6732 
6733 void  gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
6734                double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
6735                int kleng, int *kword, const char *hoper, int *kret);
6736 
6737 
6738 const char *cgribexLibraryVersion(void);
6739 
6740 void  gribDebug(int debug);
6741 void  gribSetCalendar(int calendar);
6742 
6743 void  gribDateTimeX(int *isec1, int *date, int *time, int *startDate, int *startTime);
6744 void  gribDateTime(int *isec1, int *date, int *time);
6745 int   gribRefDate(int *isec1);
6746 int   gribRefTime(int *isec1);
6747 bool  gribTimeIsFC(int *isec1);
6748 
6749 void  gribPrintSec0(int *isec0);
6750 void  gribPrintSec1(int *isec0, int *isec1);
6751 void  gribPrintSec2DP(int *isec0, int *isec2, double *fsec2);
6752 void  gribPrintSec2SP(int *isec0, int *isec2, float  *fsec2);
6753 void  gribPrintSec3DP(int *isec0, int *isec3, double *fsec3);
6754 void  gribPrintSec3SP(int *isec0, int *isec3, float  *fsec3);
6755 void  gribPrintSec4DP(int *isec0, int *isec4, double *fsec4);
6756 void  gribPrintSec4SP(int *isec0, int *isec4, float  *fsec4);
6757 void  gribPrintSec4Wave(int *isec4);
6758 
6759 void  gribPrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer);
6760 void  gribPrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
6761 void  gribPrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
6762 void  gribPrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
6763 void  gribPrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
6764 void  gribCheck1(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
6765 void  gribRepair1(int nrec, long recsize, unsigned char *gribbuffer);
6766 
6767 int   gribGetZip(size_t recsize, unsigned char *gribbuffer, size_t *urecsize);
6768 
6769 int   gribBzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
6770 int   gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
6771 int   gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
6772 
6773 int   gribOpen(const char *filename, const char *mode);
6774 void  gribClose(int fileID);
6775 
6776 int   gribRead(int fileID, unsigned char *buffer, size_t *buffersize);
6777 int   gribWrite(int fileID, unsigned char *buffer, size_t buffersize);
6778 off_t gribGetPos(int fileID);
6779 size_t gribGetSize(int fileID);
6780 int   gribCheckSeek(int fileID, long *offset, int *version);
6781 int   gribFileSeek(int fileID, long *offset);
6782 size_t gribReadSize(int fileID);
6783 int   gribVersion(unsigned char *buffer, size_t buffersize);
6784 
6785 int   grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer, int *intnum, float *fltnum, off_t *bignum);
6786 
6787 double calculate_pfactor_float(const float* spectralField, long fieldTruncation, long subsetTruncation);
6788 double calculate_pfactor_double(const double* spectralField, long fieldTruncation, long subsetTruncation);
6789 
6790 #ifdef  __cplusplus
6791 }
6792 #endif
6793 
6794 #endif  /* CGRIBEX_H */
6795 
6796 #ifdef  HAVE_CONFIG_H
6797 #endif
6798 
6799 #include <ctype.h>
6800 
6801 
6802 #ifdef  HAVE_LIBCGRIBEX
6803 #endif
6804 
6805 int CDI_Default_Calendar = CALENDAR_PROLEPTIC;
6806 
6807 int CDI_Default_InstID   = CDI_UNDEFID;
6808 int CDI_Default_ModelID  = CDI_UNDEFID;
6809 int CDI_Default_TableID  = CDI_UNDEFID;
6810 //int cdiNcMissingValue  = CDI_UNDEFID;
6811 int CDI_Netcdf_Chunksizehint = CDI_UNDEFID;
6812 int CDI_Chunk_Type       = CDI_CHUNK_GRID;
6813 int CDI_Split_Ltype105   = CDI_UNDEFID;
6814 
6815 bool CDI_Ignore_Att_Coordinates = false;
6816 bool CDI_Coordinates_Lon_Lat    = false;
6817 bool CDI_Ignore_Valid_Range     = false;
6818 int CDI_Skip_Records           = 0;
6819 int CDI_Convention           = CDI_CONVENTION_ECHAM;
6820 int CDI_Inventory_Mode       = 1;
6821 int CDO_version_info         = 1;
6822 int CDI_Read_Cell_Corners    = 1;
6823 int CDI_CMOR_Mode            = 0;
6824 int CDI_Reduce_Dim           = 0;
6825 size_t CDI_Netcdf_Hdr_Pad    = 0UL;
6826 bool CDI_Netcdf_Lazy_Grid_Load = false;
6827 
6828 char *cdiPartabPath   = NULL;
6829 int   cdiPartabIntern = 1;
6830 
6831 double CDI_Default_Missval = -9.E33;
6832 double CDI_Grid_Missval    = -9999.;
6833 
6834 static const char Filetypes[][9] = {
6835   "UNKNOWN",
6836   "GRIB",
6837   "GRIB2",
6838   "NetCDF",
6839   "NetCDF2",
6840   "NetCDF4",
6841   "NetCDF4c",
6842   "NetCDF5",
6843   "SERVICE",
6844   "EXTRA",
6845   "IEG",
6846   "HDF5",
6847 };
6848 
6849 int CDI_Debug   = 0;    // If set to 1, debugging
6850 int CDI_Recopt  = 0;
6851 
6852 bool CDI_gribapi_debug  = false;
6853 bool CDI_gribapi_grib1  = false;
6854 int cdiDefaultLeveltype = -1;
6855 int cdiDataUnreduced = 0;
6856 int cdiSortName = 0;
6857 int cdiSortParam = 0;
6858 int cdiHaveMissval = 0;
6859 
6860 
6861 static
cdiGetenvInt(const char * envName)6862 long cdiGetenvInt(const char *envName)
6863 {
6864   long envValue = -1;
6865 
6866   char *envString = getenv(envName);
6867   if ( envString )
6868     {
6869       long fact = 1;
6870       int len = (int) strlen(envString);
6871       for ( int loop = 0; loop < len; loop++ )
6872 	{
6873 	  if ( ! isdigit((int) envString[loop]) )
6874 	    {
6875 	      switch ( tolower((int) envString[loop]) )
6876 		{
6877 		case 'k':  fact = 1024;        break;
6878 		case 'm':  fact = 1048576;     break;
6879 		case 'g':  fact = 1073741824;  break;
6880 		default:
6881 		  fact = 0;
6882 		  Message("Invalid number string in %s: %s", envName, envString);
6883 		  Warning("%s must comprise only digits [0-9].",envName);
6884 		  break;
6885 		}
6886 	      break;
6887 	    }
6888 	}
6889 
6890       if ( fact ) envValue = fact*atol(envString);
6891 
6892       if ( CDI_Debug ) Message("set %s to %ld", envName, envValue);
6893     }
6894 
6895   return envValue;
6896 }
6897 
6898 static
cdiPrintDefaults(void)6899 void cdiPrintDefaults(void)
6900 {
6901   fprintf(stderr, "default instID     :  %d\n"
6902           "default modelID    :  %d\n"
6903           "default tableID    :  %d\n"
6904           "default missval    :  %g\n", CDI_Default_InstID,
6905           CDI_Default_ModelID, CDI_Default_TableID, CDI_Default_Missval);
6906 }
6907 
cdiPrintVersion(void)6908 void cdiPrintVersion(void)
6909 {
6910   fprintf(stderr, "     CDI library version : %s\n", cdiLibraryVersion());
6911 #ifdef  HAVE_LIBCGRIBEX
6912   fprintf(stderr, " cgribex library version : %s\n", cgribexLibraryVersion());
6913 #endif
6914 #ifdef  HAVE_LIBGRIB_API
6915   fprintf(stderr, " ecCodes library version : %s\n", gribapiLibraryVersionString());
6916 #endif
6917 #ifdef  HAVE_LIBNETCDF
6918   fprintf(stderr, "  NetCDF library version : %s\n", cdfLibraryVersion());
6919 #endif
6920 #ifdef  HAVE_NC4HDF5
6921   fprintf(stderr, "    hdf5 library version : %s\n", hdfLibraryVersion());
6922 #endif
6923 #ifdef  HAVE_LIBSERVICE
6924   fprintf(stderr, "    exse library version : %s\n", srvLibraryVersion());
6925 #endif
6926   fprintf(stderr, "    FILE library version : %s\n", fileLibraryVersion());
6927 }
6928 
6929 static
cdiPrintDatatypes(void)6930 void cdiPrintDatatypes(void)
6931 {
6932 #define XSTRING(x)	#x
6933 #define STRING(x)	XSTRING(x)
6934   fprintf (stderr, "+-------------+-------+\n"
6935            "| types       | bytes |\n"
6936            "+-------------+-------+\n"
6937            "| void *      |   %3d |\n"
6938            "+-------------+-------+\n"
6939            "| char        |   %3d |\n"
6940            "+-------------+-------+\n"
6941            "| bool        |   %3d |\n"
6942            "| short       |   %3d |\n"
6943            "| int         |   %3d |\n"
6944            "| long        |   %3d |\n"
6945            "| long long   |   %3d |\n"
6946            "| size_t      |   %3d |\n"
6947            "| off_t       |   %3d |\n"
6948            "+-------------+-------+\n"
6949            "| float       |   %3d |\n"
6950            "| double      |   %3d |\n"
6951            "| long double |   %3d |\n"
6952            "+-------------+-------+\n\n"
6953            "+-------------+-----------+\n"
6954            "| INT32       | %-9s |\n"
6955            "| INT64       | %-9s |\n"
6956            "| FLT32       | %-9s |\n"
6957            "| FLT64       | %-9s |\n"
6958            "+-------------+-----------+\n"
6959            "\n  byte ordering is %s\n\n",
6960            (int) sizeof(void *), (int) sizeof(char), (int) sizeof(bool),
6961            (int) sizeof(short), (int) sizeof(int), (int) sizeof(long), (int) sizeof(long long),
6962            (int) sizeof(size_t), (int) sizeof(off_t),
6963            (int) sizeof(float), (int) sizeof(double), (int) sizeof(long double),
6964            STRING(INT32), STRING(INT64), STRING(FLT32), STRING(FLT64),
6965            ((HOST_ENDIANNESS == CDI_BIGENDIAN) ? "BIGENDIAN"
6966             : ((HOST_ENDIANNESS == CDI_LITTLEENDIAN) ? "LITTLEENDIAN"
6967                : "Unhandled endianness!")));
6968 #undef STRING
6969 #undef XSTRING
6970 }
6971 
6972 
cdiDebug(int level)6973 void cdiDebug(int level)
6974 {
6975   unsigned ulevel = (unsigned) level;
6976 
6977   if ( ulevel == 1 || (ulevel &  2) ) CDI_Debug = 1;
6978 
6979   if ( CDI_Debug ) Message("debug level %d", level);
6980 
6981   if ( ulevel == 1 || (ulevel &  4) ) memDebug(1);
6982 
6983   if ( ulevel == 1 || (ulevel &  8) ) fileDebug(1);
6984 
6985   if ( ulevel == 1 || (ulevel & 16) )
6986     {
6987 #ifdef HAVE_LIBCGRIBEX
6988       gribSetDebug(1);
6989 #endif
6990 #ifdef HAVE_LIBNETCDF
6991       cdfDebug(1);
6992 #endif
6993 #ifdef HAVE_LIBSERVICE
6994       srvDebug(1);
6995 #endif
6996 #ifdef HAVE_LIBEXTRA
6997       extDebug(1);
6998 #endif
6999 #ifdef HAVE_LIBIEG
7000       iegDebug(1);
7001 #endif
7002     }
7003 
7004   if ( CDI_Debug )
7005     {
7006       cdiPrintDefaults();
7007       cdiPrintDatatypes();
7008     }
7009 }
7010 
7011 
cdiHaveFiletype(int filetype)7012 int cdiHaveFiletype(int filetype)
7013 {
7014   int status = 0;
7015 
7016   switch (filetype)
7017     {
7018 #ifdef  HAVE_LIBSERVICE
7019     case CDI_FILETYPE_SRV:  status = 1; break;
7020 #endif
7021 #ifdef  HAVE_LIBEXTRA
7022     case CDI_FILETYPE_EXT:  status = 1; break;
7023 #endif
7024 #ifdef  HAVE_LIBIEG
7025     case CDI_FILETYPE_IEG:  status = 1; break;
7026 #endif
7027 #ifdef  HAVE_LIBGRIB
7028 #if  defined  HAVE_LIBGRIB_API || defined  HAVE_LIBCGRIBEX
7029     case CDI_FILETYPE_GRB:  status = 1; break;
7030 #endif
7031 #ifdef  HAVE_LIBGRIB_API
7032     case CDI_FILETYPE_GRB2: status = 1; break;
7033 #endif
7034 #endif
7035 #ifdef  HAVE_LIBNETCDF
7036     case CDI_FILETYPE_NC:   status = 1; break;
7037 #ifdef  HAVE_NETCDF2
7038     case CDI_FILETYPE_NC2:  status = 1; break;
7039 #endif
7040 #ifdef  HAVE_NETCDF4
7041     case CDI_FILETYPE_NC4:  status = 1; break;
7042     case CDI_FILETYPE_NC4C: status = 1; break;
7043 #endif
7044 #ifdef  HAVE_NETCDF5
7045     case CDI_FILETYPE_NC5:  status = 1; break;
7046 #endif
7047 #endif
7048     default: status = 0; break;
7049     }
7050 
7051   return status;
7052 }
7053 
7054 
cdiDefTableID(int tableID)7055 void cdiDefTableID(int tableID)
7056 {
7057   CDI_Default_TableID = tableID;
7058   int modelID = CDI_Default_ModelID = tableInqModel(tableID);
7059   CDI_Default_InstID = modelInqInstitut(modelID);
7060 }
7061 
7062 static
cdiSetChunk(const char * chunkAlgo)7063 void cdiSetChunk(const char *chunkAlgo)
7064 {
7065   int algo = -1;
7066 
7067   if      ( strcmp("auto",  chunkAlgo) == 0 ) algo = CDI_CHUNK_AUTO;
7068   else if ( strcmp("grid",  chunkAlgo) == 0 ) algo = CDI_CHUNK_GRID;
7069   else if ( strcmp("lines", chunkAlgo) == 0 ) algo = CDI_CHUNK_LINES;
7070   else
7071     Warning("Invalid environment variable CDI_CHUNK_ALGO: %s", chunkAlgo);
7072 
7073   if ( algo != -1 )
7074     {
7075       CDI_Chunk_Type = algo;
7076       if ( CDI_Debug ) Message("set ChunkAlgo to %s", chunkAlgo);
7077     }
7078 }
7079 
7080 
cdiSetEccodesGrib1(bool value)7081 void cdiSetEccodesGrib1(bool value)
7082 {
7083 #ifndef HAVE_LIBGRIB_API
7084   if (value)
7085     {
7086       Warning("ecCodes support not compiled in, used CGRIBEX to decode/encode GRIB1 records!");
7087       value = false;
7088     }
7089 #endif
7090   CDI_gribapi_grib1 = value;
7091 }
7092 
7093 
cdiInitialize(void)7094 void cdiInitialize(void)
7095 {
7096   static bool Init_CDI = false;
7097 
7098   if ( ! Init_CDI )
7099     {
7100       Init_CDI = true;
7101       char *envstr;
7102       long value;
7103 
7104 #ifdef  HAVE_LIBCGRIBEX
7105       gribFixZSE(1);   // 1: Fix ZeroShiftError of simple packed spherical harmonics
7106       gribSetConst(1); // 1: Don't pack constant fields on regular grids
7107 #endif
7108 #ifdef  HAVE_LIBGRIB_API
7109       grib_multi_support_off(NULL);
7110 #endif
7111 
7112       value = cdiGetenvInt("CDI_DEBUG");
7113       if ( value >= 0 ) CDI_Debug = (int) value;
7114 
7115       value = cdiGetenvInt("CDI_GRIBAPI_DEBUG");
7116       if ( value >= 0 ) CDI_gribapi_debug = (bool) value;
7117 
7118       value = cdiGetenvInt("CDI_ECCODES_DEBUG");
7119       if ( value >= 0 ) CDI_gribapi_debug = (bool) value;
7120 
7121       value = cdiGetenvInt("CDI_ECCODES_GRIB1");
7122       if ( value >= 0 ) cdiSetEccodesGrib1((bool) value);
7123 
7124       value = cdiGetenvInt("CDI_READ_CELL_CORNERS");
7125       if ( value >= 0 ) CDI_Read_Cell_Corners = (int) value;
7126 
7127       value = cdiGetenvInt("CDI_RECOPT");
7128       if ( value >= 0 ) CDI_Recopt = (int) value;
7129 
7130       value = cdiGetenvInt("CDI_REGULARGRID");
7131       if ( value >= 0 ) cdiDataUnreduced = (int) value;
7132 
7133       value = cdiGetenvInt("CDI_SORTNAME");
7134       if ( value >= 0 ) cdiSortName = (int) value;
7135 
7136       value = cdiGetenvInt("CDI_SORTPARAM");
7137       if ( value >= 0 ) cdiSortParam = (int) value;
7138 
7139       value = cdiGetenvInt("CDI_HAVE_MISSVAL");
7140       if ( value >= 0 ) cdiHaveMissval = (int) value;
7141 
7142       value = cdiGetenvInt("CDI_LEVELTYPE");
7143       if ( value >= 0 ) cdiDefaultLeveltype = (int) value;
7144 
7145       value = cdiGetenvInt("CDI_NETCDF_HDR_PAD");
7146       if ( value >= 0 ) CDI_Netcdf_Hdr_Pad = (size_t) value;
7147 
7148       envstr = getenv("CDI_MISSVAL");
7149       if ( envstr ) CDI_Default_Missval = atof(envstr);
7150       /*
7151       envstr = getenv("NC_MISSING_VALUE");
7152       if ( envstr ) cdiNcMissingValue = atoi(envstr);
7153       */
7154       envstr = getenv("NC_CHUNKSIZEHINT");
7155       if ( envstr ) CDI_Netcdf_Chunksizehint = atoi(envstr);
7156 
7157       envstr = getenv("CDI_CHUNK_ALGO");
7158       if ( envstr ) cdiSetChunk(envstr);
7159 
7160       envstr = getenv("SPLIT_LTYPE_105");
7161       if ( envstr ) CDI_Split_Ltype105 = atoi(envstr);
7162 
7163       envstr = getenv("IGNORE_ATT_COORDINATES");
7164       if ( envstr ) CDI_Ignore_Att_Coordinates = atoi(envstr) > 0;
7165 
7166       envstr = getenv("CDI_COORDINATES_LONLAT");
7167       if ( envstr ) CDI_Coordinates_Lon_Lat = atoi(envstr) > 0;
7168 
7169       envstr = getenv("IGNORE_VALID_RANGE");
7170       if ( envstr ) CDI_Ignore_Valid_Range = atoi(envstr) > 0;
7171 
7172       envstr = getenv("CDI_SKIP_RECORDS");
7173       if ( envstr )
7174 	{
7175 	  CDI_Skip_Records = atoi(envstr);
7176 	  CDI_Skip_Records = CDI_Skip_Records > 0 ? CDI_Skip_Records : 0;
7177 	}
7178 
7179       envstr = getenv("CDI_CONVENTION");
7180       if ( envstr )
7181 	{
7182 	  if ( strcmp(envstr, "CF") == 0 || strcmp(envstr, "cf") == 0 )
7183 	    {
7184 	      CDI_Convention = CDI_CONVENTION_CF;
7185 	      if ( CDI_Debug )
7186 		Message("CDI convention was set to CF!");
7187 	    }
7188 	}
7189 
7190       envstr = getenv("CDI_INVENTORY_MODE");
7191       if ( envstr )
7192 	{
7193 	  if ( strncmp(envstr, "time", 4) == 0 )
7194 	    {
7195 	      CDI_Inventory_Mode = 2;
7196 	      if ( CDI_Debug )
7197 		Message("Inventory mode was set to timestep!");
7198 	    }
7199 	}
7200 
7201       envstr = getenv("CDI_VERSION_INFO");
7202       if ( envstr )
7203         {
7204           int ival = atoi(envstr);
7205           if ( ival == 0 || ival == 1 )
7206             {
7207               CDO_version_info = ival;
7208               if ( CDI_Debug )
7209                 Message("CDO_version_info = %s", envstr);
7210             }
7211         }
7212 
7213       envstr = getenv("CDI_CALENDAR");
7214       if ( envstr )
7215 	{
7216           // clang-format off
7217 	  if      (strncmp(envstr, "standard", 8)  == 0) CDI_Default_Calendar = CALENDAR_STANDARD;
7218 	  else if (strncmp(envstr, "gregorian", 9) == 0) CDI_Default_Calendar = CALENDAR_GREGORIAN;
7219 	  else if (strncmp(envstr, "proleptic", 9) == 0) CDI_Default_Calendar = CALENDAR_PROLEPTIC;
7220 	  else if (strncmp(envstr, "360days", 7)   == 0) CDI_Default_Calendar = CALENDAR_360DAYS;
7221 	  else if (strncmp(envstr, "365days", 7)   == 0) CDI_Default_Calendar = CALENDAR_365DAYS;
7222 	  else if (strncmp(envstr, "366days", 7)   == 0) CDI_Default_Calendar = CALENDAR_366DAYS;
7223 	  else if (strncmp(envstr, "none", 4)      == 0) CDI_Default_Calendar = CALENDAR_NONE;
7224           // clang-format on
7225 	  if ( CDI_Debug ) Message("Default calendar set to %s!", envstr);
7226 	}
7227 #ifdef  HAVE_LIBCGRIBEX
7228       gribSetCalendar(CDI_Default_Calendar);
7229 #endif
7230 
7231       envstr = getenv("PARTAB_INTERN");
7232       if ( envstr ) cdiPartabIntern = atoi(envstr);
7233 
7234       envstr = getenv("PARTAB_PATH");
7235       if ( envstr ) cdiPartabPath = strdup(envstr);
7236     }
7237 }
7238 
7239 
strfiletype(int filetype)7240 const char *strfiletype(int filetype)
7241 {
7242   int size = (int) (sizeof(Filetypes)/sizeof(char *));
7243   return (filetype > 0 && filetype < size) ? Filetypes[filetype] : Filetypes[0];
7244 }
7245 
7246 
cdiDefGlobal(const char * string,int value)7247 void cdiDefGlobal(const char *string, int value)
7248 {
7249   // clang-format off
7250   if      (strcmp(string, "REGULARGRID")           == 0) cdiDataUnreduced = value;
7251   else if (strcmp(string, "ECCODES_DEBUG")         == 0) CDI_gribapi_debug = (bool) value;
7252   else if (strcmp(string, "ECCODES_GRIB1")         == 0) cdiSetEccodesGrib1((bool) value);
7253   else if (strcmp(string, "SORTNAME")              == 0) cdiSortName = value;
7254   else if (strcmp(string, "SORTPARAM")             == 0) cdiSortParam = value;
7255   else if (strcmp(string, "HAVE_MISSVAL")          == 0) cdiHaveMissval = value;
7256   else if (strcmp(string, "NC_CHUNKSIZEHINT")      == 0) CDI_Netcdf_Chunksizehint = value;
7257   else if (strcmp(string, "READ_CELL_CORNERS")     == 0) CDI_Read_Cell_Corners = value;
7258   else if (strcmp(string, "CMOR_MODE")             == 0) CDI_CMOR_Mode = value;
7259   else if (strcmp(string, "REDUCE_DIM")            == 0) CDI_Reduce_Dim = value;
7260   else if (strcmp(string, "NETCDF_HDR_PAD")        == 0) CDI_Netcdf_Hdr_Pad = (size_t) value;
7261   else if (strcmp(string, "NETCDF_LAZY_GRID_LOAD") == 0) CDI_Netcdf_Lazy_Grid_Load = (bool) value;
7262   else Warning("Unsupported global key: %s", string);
7263   // clang-format on
7264 }
7265 
7266 
cdiDefMissval(double missval)7267 void cdiDefMissval(double missval)
7268 {
7269   cdiInitialize();
7270 
7271   CDI_Default_Missval = missval;
7272 }
7273 
7274 
cdiInqMissval(void)7275 double cdiInqMissval(void)
7276 {
7277   cdiInitialize();
7278 
7279   return CDI_Default_Missval;
7280 }
7281 
7282 
cdiInqGridMissval(void)7283 double cdiInqGridMissval(void)
7284 {
7285   cdiInitialize();
7286 
7287   return CDI_Default_Missval;
7288 }
7289 
cdiBaseFiletype(int filetype)7290 int cdiBaseFiletype(int filetype)
7291 {
7292   switch (filetype)
7293     {
7294     case CDI_FILETYPE_NC:
7295     case CDI_FILETYPE_NC2:
7296     case CDI_FILETYPE_NC4:
7297     case CDI_FILETYPE_NC4C:
7298     case CDI_FILETYPE_NC5:   return CDI_FILETYPE_NETCDF;
7299     default:                 return filetype;
7300     }
7301 
7302   return filetype;
7303 }
7304 
7305 /*
7306  * Local Variables:
7307  * c-file-style: "Java"
7308  * c-basic-offset: 2
7309  * indent-tabs-mode: nil
7310  * show-trailing-whitespace: t
7311  * require-trailing-newline: t
7312  * End:
7313  */
7314 
7315 #ifdef HAVE_CONFIG_H
7316 #endif
7317 
7318 #ifdef HAVE_UNISTD_H
7319 #include <unistd.h>
7320 #endif
7321 
7322 #include <limits.h>
7323 #include <stdio.h>
7324 #include <stdlib.h>
7325 
cdiDecodeParam(int param,int * pnum,int * pcat,int * pdis)7326 void cdiDecodeParam(int param, int *pnum, int *pcat, int *pdis)
7327 {
7328   unsigned uparam = (unsigned)param;
7329 
7330   *pdis = (int) (0xffU & uparam);
7331   *pcat = (int) (0xffU & (uparam >> 8));
7332   unsigned upnum = 0xffffU & (uparam >> 16);
7333   if ( upnum > 0x7fffU ) upnum = 0x8000U - upnum;
7334   *pnum = (int) upnum;
7335 }
7336 
7337 
cdiEncodeParam(int pnum,int pcat,int pdis)7338 int cdiEncodeParam(int pnum, int pcat, int pdis)
7339 {
7340   if ( pcat < 0 || pcat > 255 ) pcat = 255;
7341   if ( pdis < 0 || pdis > 255 ) pdis = 255;
7342 
7343   unsigned upnum = (unsigned)pnum;
7344   if ( pnum < 0 ) upnum = (unsigned)(0x8000 - pnum);
7345 
7346   unsigned uparam = (upnum << 16) | (((unsigned)pcat) << 8) | (unsigned)pdis;
7347 
7348   return (int)uparam;
7349 }
7350 
7351 
cdiDecodeDate(int64_t date,int * year,int * month,int * day)7352 void cdiDecodeDate(int64_t date, int *year, int *month, int *day)
7353 {
7354   int64_t iyear = (int)(date / 10000);
7355   *year = (int)iyear;
7356   int64_t idate = date - iyear * 10000;
7357   if ( idate < 0 ) idate = -idate;
7358   int64_t imonth = idate / 100;
7359   *month = (int)imonth;
7360   *day   = (int)(idate - imonth * 100);
7361 }
7362 
7363 
cdiEncodeDate(int year,int month,int day)7364 int64_t cdiEncodeDate(int year, int month, int day)
7365 {
7366   int64_t iyear = abs(year);
7367   int64_t date = iyear * 10000 + month * 100 + day;
7368   if ( year < 0 ) date = -date;
7369 
7370   return date;
7371 }
7372 
7373 
cdiDecodeTime(int time,int * hour,int * minute,int * second)7374 void cdiDecodeTime(int time, int *hour, int *minute, int *second)
7375 {
7376   int ihour = time / 10000,
7377     itime = time - ihour * 10000,
7378     iminute = itime / 100;
7379   *hour   = ihour;
7380   *minute = iminute;
7381   *second = itime - iminute * 100;
7382 }
7383 
7384 
cdiEncodeTime(int hour,int minute,int second)7385 int cdiEncodeTime(int hour, int minute, int second)
7386 {
7387   return hour*10000 + minute*100 + second;
7388 }
7389 
7390 
cdiParamToString(int param,char * paramstr,int maxlen)7391 void cdiParamToString(int param, char *paramstr, int maxlen)
7392 {
7393   int dis, cat, num;
7394   cdiDecodeParam(param, &num, &cat, &dis);
7395 
7396   size_t umaxlen = maxlen >= 0 ? (unsigned)maxlen : 0U;
7397   int len;
7398   if ( dis == 255 && (cat == 255 || cat == 0 ) )
7399     len = snprintf(paramstr, umaxlen, "%d", num);
7400   else  if ( dis == 255 )
7401     len = snprintf(paramstr, umaxlen, "%d.%d", num, cat);
7402   else
7403     len = snprintf(paramstr, umaxlen, "%d.%d.%d", num, cat, dis);
7404 
7405   if ( len >= maxlen || len < 0)
7406     fprintf(stderr, "Internal problem (%s): size of input string is too small!\n", __func__);
7407 }
7408 
7409 
cdiUnitNamePtr(int cdi_unit)7410 const char *cdiUnitNamePtr(int cdi_unit)
7411 {
7412   const char *cdiUnits[] = {
7413     /*  0 */  "undefined",
7414     /*  1 */  "Pa",
7415     /*  2 */  "hPa",
7416     /*  3 */  "mm",
7417     /*  4 */  "cm",
7418     /*  5 */  "dm",
7419     /*  6 */  "m",
7420   };
7421   enum { numUnits = (int) (sizeof(cdiUnits)/sizeof(char *)) };
7422   const char *name = ( cdi_unit > 0 && cdi_unit < numUnits ) ?
7423     cdiUnits[cdi_unit] : NULL;
7424 
7425   return name;
7426 }
7427 
7428 size_t
cdiGetPageSize(bool largePageAlign)7429 cdiGetPageSize(bool largePageAlign)
7430 {
7431   long pagesize = -1L;
7432 #if HAVE_DECL__SC_LARGE_PAGESIZE || HAVE_DECL__SC_PAGE_SIZE || HAVE_DECL__SC_PAGESIZE
7433   bool nameAssigned = false;
7434   int name;
7435 #  if HAVE_DECL__SC_LARGE_PAGESIZE
7436   if (largePageAlign)
7437     {
7438       name = _SC_LARGE_PAGESIZE;
7439       nameAssigned = true;
7440     }
7441   else
7442 #  else
7443     (void)largePageAlign;
7444 #  endif
7445     {
7446 #  if HAVE_DECL__SC_PAGESIZE || HAVE_DECL__SC_PAGE_SIZE
7447       name =
7448 #    if HAVE_DECL__SC_PAGESIZE
7449         _SC_PAGESIZE
7450 #    elif HAVE_DECL__SC_PAGE_SIZE
7451         _SC_PAGE_SIZE
7452 #    endif
7453         ;
7454       nameAssigned = true;
7455 #  endif
7456     }
7457   if (nameAssigned)
7458     pagesize = sysconf(name);
7459 #endif
7460   if (pagesize == -1L)
7461     pagesize =
7462 #if HAVE_DECL_PAGESIZE
7463       PAGESIZE
7464 #elif HAVE_DECL_PAGE_SIZE
7465       PAGE_SIZE
7466 #else
7467       commonPageSize
7468 #endif
7469       ;
7470   return (size_t)pagesize;
7471 }
7472 
7473 
7474 /*
7475  * Local Variables:
7476  * c-file-style: "Java"
7477  * c-basic-offset: 2
7478  * indent-tabs-mode: nil
7479  * show-trailing-whitespace: t
7480  * require-trailing-newline: t
7481  * End:
7482  */
7483 
7484 /* Automatically generated by m214003 at 2020-04-30, do not edit */
7485 
7486 /* CGRIBEXLIB_VERSION="1.9.5" */
7487 
7488 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5) || defined (__clang__)
7489 #pragma GCC diagnostic push
7490 #pragma GCC diagnostic ignored "-Wconversion"
7491 #pragma GCC diagnostic ignored "-Wsign-conversion"
7492 #pragma GCC diagnostic warning "-Wstrict-overflow"
7493 #endif
7494 
7495 #ifdef _ARCH_PWR6
7496 #pragma options nostrict
7497 #include <ppu_intrinsics.h>
7498 #endif
7499 
7500 #ifdef  HAVE_CONFIG_H
7501 #endif
7502 
7503 #include <string.h>
7504 #include <ctype.h>
7505 #include <stdarg.h>
7506 #include <stdbool.h>
7507 #include <sys/types.h>
7508 #include <inttypes.h>
7509 
7510 
7511 
7512 #ifndef CGRIBEX_TEMPLATES_H
7513 #define CGRIBEX_TEMPLATES_H
7514 
7515 #define CAT(X,Y)      X##_##Y
7516 #define TEMPLATE(X,Y) CAT(X,Y)
7517 
7518 #endif
7519 #ifndef GRIB_INT_H
7520 #define GRIB_INT_H
7521 
7522 #if defined (HAVE_CONFIG_H)
7523 #endif
7524 
7525 #include <inttypes.h>
7526 #include <stdio.h>
7527 #include <stdlib.h>
7528 #include <stdbool.h>
7529 #include <math.h>
7530 #include <float.h>
7531 
7532 
7533 #if ! defined   (CGRIBEX_H)
7534 #endif
7535 #if ! defined   (ERROR_H)
7536 #endif
7537 #if ! defined   (DTYPES_H)
7538 #endif
7539 
7540 
7541 #if ! defined   (UCHAR)
7542 #define  UCHAR  unsigned char
7543 #endif
7544 
7545 
7546 #if defined (CRAY) || defined (SX) || defined (__uxpch__)
7547 #define VECTORCODE
7548 #endif
7549 
7550 
7551 #ifdef VECTORCODE
7552 #ifdef  INT32
7553 #  define  GRIBPACK     unsigned INT32
7554 #  define  PACK_GRIB    packInt32
7555 #  define  UNPACK_GRIB  unpackInt32
7556 #else
7557 #  define  GRIBPACK     unsigned INT64
7558 #  define  PACK_GRIB    packInt64
7559 #  define  UNPACK_GRIB  unpackInt64
7560 #endif
7561 #else
7562 #  define  GRIBPACK     unsigned char
7563 #endif
7564 
7565 #ifndef HOST_ENDIANNESS
7566 #ifdef __cplusplus
7567 static const uint32_t HOST_ENDIANNESS_temp[1] = { UINT32_C(0x00030201) };
7568 #define HOST_ENDIANNESS (((const unsigned char *)HOST_ENDIANNESS_temp)[0])
7569 #else
7570 #define HOST_ENDIANNESS (((const unsigned char *)&(const uint32_t[1]){UINT32_C(0x00030201)})[0])
7571 #endif
7572 #endif
7573 
7574 #define  U_BYTEORDER
7575 #define  IS_BIGENDIAN()  (HOST_ENDIANNESS == 0)
7576 
7577 #if defined (__xlC__) /* performance problems on IBM */
7578 #ifndef DBL_IS_NAN
7579 #  define DBL_IS_NAN(x)     ((x) != (x))
7580 #endif
7581 #else
7582 #ifndef DBL_IS_NAN
7583 #if  defined  (HAVE_DECL_ISNAN)
7584 #  define DBL_IS_NAN(x)     (isnan(x))
7585 #elif  defined  (FP_NAN)
7586 #  define DBL_IS_NAN(x)     (fpclassify(x) == FP_NAN)
7587 #else
7588 #  define DBL_IS_NAN(x)     ((x) != (x))
7589 #endif
7590 #endif
7591 #endif
7592 
7593 #ifndef IS_EQUAL
7594 #  define IS_NOT_EQUAL(x,y) (x < y || y < x)
7595 #  define IS_EQUAL(x,y)     (!IS_NOT_EQUAL(x,y))
7596 #endif
7597 
7598 /* dummy use of unused parameters to silence compiler warnings */
7599 #ifndef UNUSED
7600 #define  UNUSED(x) (void)(x)
7601 #endif
7602 
7603 #define  JP24SET    0xFFFFFF  /* 2**24     (---> 16777215) */
7604 #define  JP23SET    0x7FFFFF  /* 2**23 - 1 (--->  8388607) */
7605 
7606 #define  POW_2_M24  0.000000059604644775390625  /* pow(2.0, -24.0) */
7607 
7608 #ifdef __cplusplus
7609 extern "C" {
7610 #endif
7611 
7612 #define intpow2(x) (ldexp(1.0, (x)))
7613 
7614 static inline int
gribrec_len(unsigned b1,unsigned b2,unsigned b3)7615 gribrec_len(unsigned b1, unsigned b2, unsigned b3)
7616 {
7617   /*
7618     If bit 7 of b1 is set, we have to rescale by factor of 120.
7619     This is a fixup to get round the restriction on product lengths
7620     due to the count being only 24 bits. It is only possible because
7621     the (default) rounding for GRIB products is 120 bytes.
7622   */
7623   int needRescaling = b1 & (1 << 7);
7624 
7625   int gribsize = (int)((((b1&127) << 16)+(b2<<8) + b3));
7626 
7627   if ( needRescaling ) gribsize *= 120;
7628 
7629   return gribsize;
7630 
7631 }
7632 
7633 unsigned correct_bdslen(unsigned bdslen, long recsize, long gribpos);
7634 
7635 /* CDI converter routines */
7636 
7637 /* param format:  DDDCCCNNN */
7638 
7639 void    cdiDecodeParam(int param, int *pnum, int *pcat, int *pdis);
7640 int     cdiEncodeParam(int pnum, int pcat, int pdis);
7641 
7642 /* date format:  YYYYMMDD */
7643 /* time format:  hhmmss   */
7644 
7645 void    cdiDecodeDate(int64_t date, int *year, int *month, int *day);
7646 int64_t cdiEncodeDate(int year, int month, int day);
7647 
7648 void    cdiDecodeTime(int time, int *hour, int *minute, int *second);
7649 int     cdiEncodeTime(int hour, int minute, int second);
7650 
7651 /* CALENDAR types */
7652 
7653 #define  CALENDAR_STANDARD        0  /* don't change this value (used also in cgribexlib)! */
7654 #define  CALENDAR_GREGORIAN       1
7655 #define  CALENDAR_PROLEPTIC       2
7656 #define  CALENDAR_360DAYS         3
7657 #define  CALENDAR_365DAYS         4
7658 #define  CALENDAR_366DAYS         5
7659 #define  CALENDAR_NONE            6
7660 
7661 extern FILE *grprsm;
7662 
7663 extern int  CGRIBEX_Debug, CGRIBEX_Fix_ZSE, CGRIBEX_Const;
7664 extern int  CGRIBEX_grib_calendar;
7665 
7666 void   gprintf(const char *caller, const char *fmt, ...);
7667 
7668 void   grsdef(void);
7669 
7670 void   prtbin(int kin, int knbit, int *kout, int *kerr);
7671 void   confp3(double pval, int *kexp, int *kmant, int kbits, int kround);
7672 double decfp2(int kexp, int kmant);
7673 void   ref2ibm(double *pref, int kbits);
7674 
7675 void   scale_complex_double(double *fpdata, int pcStart, int pcScale, int trunc, int inv);
7676 void   scale_complex_float(float *fpdata, int pcStart, int pcScale, int trunc, int inv);
7677 void   scatter_complex_double(double *fpdata, int pcStart, int trunc, int nsp);
7678 void   scatter_complex_float(float *fpdata, int pcStart, int trunc, int nsp);
7679 void   gather_complex_double(double *fpdata, size_t pcStart, size_t trunc, size_t nsp);
7680 void   gather_complex_float(float *fpdata, size_t pcStart, size_t trunc, size_t nsp);
7681 
7682 int    qu2reg2(double *pfield, int *kpoint, int klat, int klon,
7683 	       double *ztemp, double msval, int *kret);
7684 int    qu2reg3_double(double *pfield, int *kpoint, int klat, int klon,
7685 		      double msval, int *kret, int omisng, int operio, int oveggy);
7686 int    qu2reg3_float(float *pfield, int *kpoint, int klat, int klon,
7687 		     float msval, int *kret, int omisng, int operio, int oveggy);
7688 
7689 #ifdef  INT32
7690 long   packInt32(unsigned INT32 *up, unsigned char *cp, long bc, long tc);
7691 #endif
7692 long   packInt64(unsigned INT64 *up, unsigned char *cp, long bc, long tc);
7693 #ifdef  INT32
7694 long   unpackInt32(const unsigned char *cp, unsigned INT32 *up, long bc, long tc);
7695 #endif
7696 long   unpackInt64(const unsigned char *cp, unsigned INT64 *up, long bc, long tc);
7697 
7698 void  grib_encode_double(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
7699 			 double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
7700 			 int kleng, int *kword, int efunc, int *kret);
7701 void  grib_encode_float(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
7702 			float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
7703 			int kleng, int *kword, int efunc, int *kret);
7704 
7705 void  grib_decode_double(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
7706 			 double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
7707 			 int kleng, int *kword, int dfunc, int *kret);
7708 void  grib_decode_float(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
7709 			float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
7710 			int kleng, int *kword, int dfunc, int *kret);
7711 
7712 
7713 int grib1Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **pdsp,
7714 		  unsigned char **gdsp, unsigned char **bmsp, unsigned char **bdsp, long *gribrecsize);
7715 int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **idsp,
7716 		  unsigned char **lusp, unsigned char **gdsp, unsigned char **pdsp,
7717 		  unsigned char **drsp, unsigned char **bmsp, unsigned char **bdsp);
7718 
7719 #ifdef  __cplusplus
7720 }
7721 #endif
7722 
7723 #endif  /* GRIB_INT_H */
7724 #ifndef GRIBDECODE_H
7725 #define GRIBDECODE_H
7726 
7727 #define  UNDEFINED          9.999e20
7728 
7729 
7730 #define  GET_INT3(a,b,c)    ((1-(int) ((unsigned) (a & 128) >> 6)) * (int) (((a & 127) << 16)+(b<<8)+c))
7731 #define  GET_INT2(a,b)      ((1-(int) ((unsigned) (a & 128) >> 6)) * (int) (((a & 127) << 8) + b))
7732 #define  GET_INT1(a)        ((1-(int) ((unsigned) (a & 128) >> 6)) * (int) (a&127))
7733 
7734 /* this requires a 32-bit default integer machine */
7735 #define  GET_UINT4(a,b,c,d) ((unsigned) ((a << 24) + (b << 16) + (c << 8) + (d)))
7736 #define  GET_UINT3(a,b,c)   ((unsigned) ((a << 16) + (b << 8)  + (c)))
7737 #define  GET_UINT2(a,b)     ((unsigned) ((a << 8)  + (b)))
7738 #define  GET_UINT1(a)       ((unsigned)  (a))
7739 
7740 #define  BUDG_START(s)      (s[0]=='B' && s[1]=='U' && s[2]=='D' && s[3]=='G')
7741 #define  TIDE_START(s)      (s[0]=='T' && s[1]=='I' && s[2]=='D' && s[3]=='E')
7742 #define  GRIB_START(s)      (s[0]=='G' && s[1]=='R' && s[2]=='I' && s[3]=='B')
7743 #define  GRIB_FIN(s)        (s[0]=='7' && s[1]=='7' && s[2]=='7' && s[3]=='7')
7744 
7745 /* GRIB1 Section 0: Indicator Section (IS) */
7746 
7747 #define  GRIB1_SECLEN(s)     GET_UINT3(s[ 4], s[ 5], s[ 6])
7748 #define  GRIB_EDITION(s)     GET_UINT1(s[ 7])
7749 
7750 /* GRIB1 Section 1: Product Definition Section (PDS) */
7751 
7752 #define  PDS_Len             GET_UINT3(pds[ 0], pds[ 1], pds[ 2])
7753 #define  PDS_CodeTable       GET_UINT1(pds[ 3])
7754 #define  PDS_CenterID        GET_UINT1(pds[ 4])
7755 #define  PDS_ModelID         GET_UINT1(pds[ 5])
7756 #define  PDS_GridDefinition  GET_UINT1(pds[ 6])
7757 #define  PDS_Sec2Or3Flag     GET_UINT1(pds[ 7])
7758 #define  PDS_HAS_GDS         ((pds[7] & 128) != 0)
7759 #define  PDS_HAS_BMS         ((pds[7] &  64) != 0)
7760 #define  PDS_Parameter       GET_UINT1(pds[ 8])
7761 #define  PDS_LevelType       GET_UINT1(pds[ 9])
7762 #define  PDS_Level1          (pds[10])
7763 #define  PDS_Level2	     (pds[11])
7764 #define  PDS_Level	     GET_UINT2(pds[10], pds[11])
7765 #define  PDS_Year            GET_INT1(pds[12])
7766 #define  PDS_Month           GET_UINT1(pds[13])
7767 #define  PDS_Day             GET_UINT1(pds[14])
7768 #define  PDS_Hour            GET_UINT1(pds[15])
7769 #define  PDS_Minute          GET_UINT1(pds[16])
7770 #define  PDS_Date            (PDS_Year*10000+PDS_Month*100+PDS_Day)
7771 #define  PDS_Time            (PDS_Hour*100+PDS_Minute)
7772 #define  PDS_TimeUnit        GET_UINT1(pds[17])
7773 #define  PDS_TimePeriod1     GET_UINT1(pds[18])
7774 #define  PDS_TimePeriod2     GET_UINT1(pds[19])
7775 #define  PDS_TimeRange       GET_UINT1(pds[20])
7776 #define  PDS_AvgNum          GET_UINT2(pds[21], pds[22])
7777 #define  PDS_AvgMiss         GET_UINT1(pds[23])
7778 #define  PDS_Century         GET_UINT1(pds[24])
7779 #define  PDS_Subcenter       GET_UINT1(pds[25])
7780 #define  PDS_DecimalScale    GET_INT2(pds[26],pds[27])
7781 
7782 
7783 /* GRIB1 Section 2: Grid Description Section (GDS) */
7784 
7785 #define  GDS_Len             ((gds) == NULL ? 0 : GET_UINT3(gds[0], gds[1], gds[2]))
7786 #define  GDS_NV              GET_UINT1(gds[ 3])
7787 #define  GDS_PVPL            GET_UINT1(gds[ 4])
7788 #define  GDS_PV	             ((gds[3] ==    0) ? -1 : (int) gds[4] - 1)
7789 #define  GDS_PL	             ((gds[4] == 0xFF) ? -1 : (int) gds[3] * 4 + (int) gds[4] - 1)
7790 #define  GDS_GridType        GET_UINT1(gds[ 5])
7791 
7792 
7793 /* GRIB1 Triangular grid of DWD */
7794 #define  GDS_GME_NI2         GET_UINT2(gds[ 6], gds[ 7])
7795 #define  GDS_GME_NI3         GET_UINT2(gds[ 8], gds[ 9])
7796 #define  GDS_GME_ND          GET_UINT3(gds[10], gds[11], gds[12])
7797 #define  GDS_GME_NI          GET_UINT3(gds[13], gds[14], gds[15])
7798 #define  GDS_GME_AFlag       GET_UINT1(gds[16])
7799 #define  GDS_GME_LatPP       GET_INT3(gds[17], gds[18], gds[19])
7800 #define  GDS_GME_LonPP       GET_INT3(gds[20], gds[21], gds[22])
7801 #define  GDS_GME_LonMPL      GET_INT3(gds[23], gds[24], gds[25])
7802 #define  GDS_GME_BFlag       GET_UINT1(gds[27])
7803 
7804 /* GRIB1 Spectral */
7805 #define  GDS_PentaJ          GET_UINT2(gds[ 6], gds[ 7])
7806 #define  GDS_PentaK          GET_UINT2(gds[ 8], gds[ 9])
7807 #define  GDS_PentaM          GET_UINT2(gds[10], gds[11])
7808 #define  GDS_RepType         GET_UINT1(gds[12])
7809 #define  GDS_RepMode         GET_UINT1(gds[13])
7810 
7811 /* GRIB1 Regular grid */
7812 #define  GDS_NumLon          GET_UINT2(gds[ 6], gds[ 7])
7813 #define  GDS_NumLat          GET_UINT2(gds[ 8], gds[ 9])
7814 #define  GDS_FirstLat        GET_INT3(gds[10], gds[11], gds[12])
7815 #define  GDS_FirstLon        GET_INT3(gds[13], gds[14], gds[15])
7816 #define  GDS_ResFlag         GET_UINT1(gds[16])
7817 #define  GDS_LastLat         GET_INT3(gds[17], gds[18], gds[19])
7818 #define  GDS_LastLon         GET_INT3(gds[20], gds[21], gds[22])
7819 #define  GDS_LonIncr         GET_UINT2(gds[23], gds[24])
7820 #define  GDS_LatIncr         GET_UINT2(gds[25], gds[26])
7821 #define  GDS_NumPar          GET_UINT2(gds[25], gds[26])
7822 #define  GDS_ScanFlag        GET_UINT1(gds[27])
7823 #define  GDS_LatSP           GET_INT3(gds[32], gds[33], gds[34])
7824 #define  GDS_LonSP           GET_INT3(gds[35], gds[36], gds[37])
7825 #define  GDS_RotAngle        (GET_Real(&(gds[38])))
7826 
7827 /* GRIB1 Lambert */
7828 #define  GDS_Lambert_Lov     GET_INT3(gds[17], gds[18], gds[19])
7829 #define  GDS_Lambert_dx	     GET_INT3(gds[20], gds[21], gds[22])
7830 #define  GDS_Lambert_dy	     GET_INT3(gds[23], gds[24], gds[25])
7831 #define  GDS_Lambert_ProjFlag GET_UINT1(gds[26])
7832 #define  GDS_Lambert_LatS1   GET_INT3(gds[28], gds[29], gds[30])
7833 #define  GDS_Lambert_LatS2   GET_INT3(gds[31], gds[32], gds[33])
7834 #define  GDS_Lambert_LatSP   GET_INT3(gds[34], gds[35], gds[36])
7835 #define  GDS_Lambert_LonSP   GET_INT3(gds[37], gds[37], gds[37])
7836 
7837 /* GRIB1 Section 3: Bit Map Section (BMS) */
7838 
7839 #define  BMS_Len	     ((bms) == NULL ? 0 : GET_UINT3(bms[0], bms[1], bms[2]))
7840 #define  BMS_UnusedBits      (bms[3])
7841 #define  BMS_Bitmap	     ((bms) == NULL ? NULL : (bms)+6)
7842 #define  BMS_BitmapSize      (((((bms[0]<<16)+(bms[1]<<8)+bms[2]) - 6)<<3) - bms[3])
7843 
7844 /* GRIB1 Section 4: Binary Data Section (BDS) */
7845 
7846 #define  BDS_Len	    GET_UINT3(bds[0], bds[1], bds[2])
7847 #define  BDS_Flag	    (bds[3])
7848 #define  BDS_BinScale       GET_INT2(bds[ 4], bds[ 5])
7849 #define  BDS_RefValue       (decfp2((int)bds[ 6], GET_UINT3(bds[7], bds[8], bds[9])))
7850 #define  BDS_NumBits        ((int) bds[10])
7851 #define  BDS_RealCoef       (decfp2((int)bds[zoff+11], GET_UINT3(bds[zoff+12], bds[zoff+13], bds[zoff+14])))
7852 #define  BDS_PackData       ((int) ((bds[zoff+11]<<8) + bds[zoff+12]))
7853 #define  BDS_Power          GET_INT2(bds[zoff+13], bds[zoff+14])
7854 #define  BDS_Z              (bds[13])
7855 
7856 /* GRIB1 Section 5: End Section (ES) */
7857 
7858 /* GRIB2 */
7859 
7860 #define  GRIB2_SECLEN(section)   (GET_UINT4(section[0], section[1], section[2], section[3]))
7861 #define  GRIB2_SECNUM(section)   (GET_UINT1(section[4]))
7862 
7863 #endif  /* GRIBDECODE_H */
7864 #ifndef CGRIBEX_GRIB_ENCODE_H
7865 #define CGRIBEX_GRIB_ENCODE_H
7866 
7867 #include <limits.h>
7868 
7869 #define PutnZero(n) \
7870 { \
7871   for ( size_t i___ = z >= 0 ? (size_t)z : 0; i___ < (size_t)(z+n); i___++ ) lGrib[i___] = 0; \
7872   z += n; \
7873 }
7874 
7875 #define Put1Byte(Value)  (lGrib[z++] = (GRIBPACK)(Value))
7876 #define Put2Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
7877                          (lGrib[z++] = (GRIBPACK)(Value)))
7878 #define Put3Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >> 16)),      \
7879                          (lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
7880                          (lGrib[z++] = (GRIBPACK)(Value)))
7881 #define Put4Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >> 24)),      \
7882                          (lGrib[z++] = (GRIBPACK)((Value) >> 16)),      \
7883                          (lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
7884                          (lGrib[z++] = (GRIBPACK)(Value)))
7885 
7886 #define Put1Int(Value)  {ival = Value; if ( ival < 0 ) ival =     0x80 - ival; Put1Byte(ival);}
7887 #define Put2Int(Value)  {ival = Value; if ( ival < 0 ) ival =   0x8000 - ival; Put2Byte(ival);}
7888 #define Put3Int(Value)  {ival = Value; if ( ival < 0 ) ival = 0x800000 - ival; Put3Byte(ival);}
7889 
7890 enum {
7891   BitsPerInt = (int) (sizeof(int) * CHAR_BIT),
7892 };
7893 
7894 
7895 #define Put1Real(Value)          \
7896 {                                \
7897   confp3(Value, &exponent, &mantissa, BitsPerInt, 1); \
7898   Put1Byte(exponent);            \
7899   Put3Byte(mantissa);            \
7900 }
7901 
7902 #endif  /* CGRIBEX_GRIB_ENCODE_H */
7903 #ifndef CODEC_COMMON_H
7904 #define CODEC_COMMON_H
7905 #define gribSwapByteOrder_uint16(ui16)  ((uint16_t)((ui16<<8) | (ui16>>8)))
7906 #endif  /* CODEC_COMMON_H */
7907 /*
7908 icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_MINMAXVAL -qopenmp -DOMP_SIMD minmax_val.c
7909  result on hama2 (icc 16.0.0):
7910      float:
7911 minmax_val: fmin: -500000  fmax: 499999  time:   1.22s
7912 simd      : fmin: -500000  fmax: 499999  time:   1.20s
7913     double:
7914 minmax_val: fmin: -500000  fmax: 499999  time:   2.86s
7915 orig      : fmin: -500000  fmax: 499999  time:   2.74s
7916 simd      : fmin: -500000  fmax: 499999  time:   2.70s
7917 avx       : fmin: -500000  fmax: 499999  time:   2.99s
7918 
7919 gcc -g -Wall -O3 -march=native -std=c99 -DTEST_MINMAXVAL -fopenmp -DOMP_SIMD -Wa,-q minmax_val.c
7920  result on thunder5 (gcc 6.1.0):
7921 float:
7922 minmax_val: fmin: -500000  fmax: 499999  time:   8.25s
7923   simd    : fmin: -500000  fmax: 499999  time:   1.24s
7924 double:
7925 minmax_val: fmin: -500000  fmax: 499999  time:   2.73s
7926   orig    : fmin: -500000  fmax: 499999  time:   9.24s
7927   simd    : fmin: -500000  fmax: 499999  time:   2.78s
7928   avx     : fmin: -500000  fmax: 499999  time:   2.90s
7929 
7930 gcc -g -Wall -O3 -march=native -std=c99 -DTEST_MINMAXVAL minmax_val.c
7931  result on bailung (gcc 4.8.2):
7932   orig    : fmin: -500000  fmax: 499999  time:   4.82s
7933   sse2    : fmin: -500000  fmax: 499999  time:   4.83s
7934 
7935 gcc -g -Wall -O3 -march=native -std=c99 -DTEST_MINMAXVAL -fopenmp -DOMP_SIMD -Wa,-q minmax_val.c
7936  result on thunder5 (gcc 4.8.2):
7937   orig    : fmin: -500000  fmax: 499999  time:   3.10s
7938   simd    : fmin: -500000  fmax: 499999  time:   3.10s # omp simd in gcc 4.9
7939   avx     : fmin: -500000  fmax: 499999  time:   2.84s
7940 
7941 icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_MINMAXVAL -openmp -DOMP_SIMD minmax_val.c
7942  result on thunder5 (icc 14.0.2):
7943   orig    : fmin: -500000  fmax: 499999  time:   2.83s
7944   simd    : fmin: -500000  fmax: 499999  time:   2.83s
7945   avx     : fmin: -500000  fmax: 499999  time:   2.92s
7946 
7947 xlc_r -g -O3 -qhot -q64 -qarch=auto -qtune=auto -qreport -DTEST_MINMAXVAL minmax_val.c
7948  result on blizzard (xlc 12):
7949   orig    : fmin: -500000  fmax: 499999  time:   7.26s
7950   pwr6u6  : fmin: -500000  fmax: 499999  time:   5.92s
7951 */
7952 #if defined(_ARCH_PWR6)
7953 #pragma options nostrict
7954 #endif
7955 
7956 #if defined(OMP_SIMD)
7957 #include <omp.h>
7958 #endif
7959 
7960 #include <stdlib.h>
7961 
7962 //#undef _GET_X86_COUNTER
7963 //#undef _GET_IBM_COUNTER
7964 //#undef _GET_MACH_COUNTER
7965 //#undef _ARCH_PWR6
7966 
7967 #if defined(_GET_IBM_COUNTER)
7968 #include <libhpc.h>
7969 #elif defined(_GET_X86_COUNTER)
7970 #include <x86intrin.h>
7971 #elif defined(_GET_MACH_COUNTER)
7972 #include <mach/mach_time.h>
7973 #endif
7974 
7975 #if   defined(__GNUC__) && !defined(__ICC) && !defined(__clang__)
7976 #if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 4)
7977 #define GNUC_PUSH_POP
7978 #endif
7979 #endif
7980 
7981 #ifndef DISABLE_SIMD
7982 #if   defined(__GNUC__) && (__GNUC__ >= 4)
7983 #elif defined(__ICC)    && (__ICC >= 1100)
7984 #elif defined(__clang__)
7985 #else
7986 #define DISABLE_SIMD
7987 #endif
7988 #endif
7989 
7990 #ifdef DISABLE_SIMD
7991 #define DISABLE_SIMD_MINMAXVAL
7992 #endif
7993 
7994 #if !defined(TEST_MINMAXVAL)
7995 #define DISABLE_SIMD_MINMAXVAL
7996 #endif
7997 
7998 #ifdef DISABLE_SIMD_MINMAXVAL
7999 # if defined(ENABLE_AVX)
8000 #  define _ENABLE_AVX
8001 # endif
8002 # if defined(ENABLE_SSE2)
8003 #  define _ENABLE_SSE2
8004 # endif
8005 #endif
8006 
8007 #ifndef DISABLE_SIMD_MINMAXVAL
8008 # if defined(__AVX__)
8009 #  define _ENABLE_AVX
8010 # endif
8011 # if defined(__SSE2__)
8012 #  define _ENABLE_SSE2
8013 # endif
8014 #endif
8015 
8016 #include <float.h>
8017 #include <stdint.h>
8018 #include <inttypes.h>
8019 
8020 #if defined(_ENABLE_AVX)
8021 #include <immintrin.h>
8022 #elif defined(_ENABLE_SSE2)
8023 #include <emmintrin.h>
8024 #endif
8025 
8026 
8027 #if defined(_ENABLE_AVX)
8028 
8029 static
avx_minmax_val_double(const double * restrict buf,size_t nframes,double * min,double * max)8030 void avx_minmax_val_double(const double *restrict buf, size_t nframes, double *min, double *max)
8031 {
8032   double fmin[4], fmax[4];
8033   __m256d current_max, current_min, work;
8034 
8035   // load max and min values into all four slots of the YMM registers
8036   current_min = _mm256_set1_pd(*min);
8037   current_max = _mm256_set1_pd(*max);
8038 
8039   // Work input until "buf" reaches 32 byte alignment
8040   while ( ((unsigned long)buf) % 32 != 0 && nframes > 0) {
8041 
8042     // Load the next double into the work buffer
8043     work = _mm256_set1_pd(*buf);
8044     current_min = _mm256_min_pd(current_min, work);
8045     current_max = _mm256_max_pd(current_max, work);
8046     buf++;
8047     nframes--;
8048   }
8049 
8050   while (nframes >= 16) {
8051 
8052     (void) _mm_prefetch((const char *)(buf+8), _MM_HINT_NTA);
8053 
8054     work = _mm256_load_pd(buf);
8055     current_min = _mm256_min_pd(current_min, work);
8056     current_max = _mm256_max_pd(current_max, work);
8057     buf += 4;
8058 
8059     work = _mm256_load_pd(buf);
8060     current_min = _mm256_min_pd(current_min, work);
8061     current_max = _mm256_max_pd(current_max, work);
8062     buf += 4;
8063 
8064     (void) _mm_prefetch((const char *)(buf+8), _MM_HINT_NTA);
8065 
8066     work = _mm256_load_pd(buf);
8067     current_min = _mm256_min_pd(current_min, work);
8068     current_max = _mm256_max_pd(current_max, work);
8069     buf += 4;
8070 
8071     work = _mm256_load_pd(buf);
8072     current_min = _mm256_min_pd(current_min, work);
8073     current_max = _mm256_max_pd(current_max, work);
8074     buf += 4;
8075     nframes -= 16;
8076   }
8077 
8078   // work through aligned buffers
8079   while (nframes >= 4) {
8080     work = _mm256_load_pd(buf);
8081     current_min = _mm256_min_pd(current_min, work);
8082     current_max = _mm256_max_pd(current_max, work);
8083     buf += 4;
8084     nframes -= 4;
8085   }
8086 
8087   // work through the remainung values
8088   while ( nframes > 0) {
8089     work = _mm256_set1_pd(*buf);
8090     current_min = _mm256_min_pd(current_min, work);
8091     current_max = _mm256_max_pd(current_max, work);
8092     buf++;
8093     nframes--;
8094   }
8095 
8096   // find min & max value through shuffle tricks
8097 
8098   work = current_min;
8099   work = _mm256_shuffle_pd(work, work, 5);
8100   work = _mm256_min_pd (work, current_min);
8101   current_min = work;
8102   work = _mm256_permute2f128_pd(work, work, 1);
8103   work = _mm256_min_pd (work, current_min);
8104   _mm256_storeu_pd(fmin, work);
8105 
8106   work = current_max;
8107   work = current_max;
8108   work = _mm256_shuffle_pd(work, work, 5);
8109   work = _mm256_max_pd (work, current_max);
8110   current_max = work;
8111   work = _mm256_permute2f128_pd(work, work, 1);
8112   work = _mm256_max_pd (work, current_max);
8113   _mm256_storeu_pd(fmax, work);
8114 
8115   *min = fmin[0];
8116   *max = fmax[0];
8117 
8118   return;
8119 }
8120 
8121 #elif defined(_ENABLE_SSE2)
8122 
8123 static
sse2_minmax_val_double(const double * restrict buf,size_t nframes,double * min,double * max)8124 void sse2_minmax_val_double(const double *restrict buf, size_t nframes, double *min, double *max)
8125 {
8126   __m128d current_max, current_min, work;
8127 
8128   // load starting max and min values into all slots of the XMM registers
8129   current_min = _mm_set1_pd(*min);
8130   current_max = _mm_set1_pd(*max);
8131 
8132   // work on input until buf reaches 16 byte alignment
8133   while ( ((unsigned long)buf) % 16 != 0 && nframes > 0) {
8134 
8135     // load one double and replicate
8136     work = _mm_set1_pd(*buf);
8137     current_min = _mm_min_pd(current_min, work);
8138     current_max = _mm_max_pd(current_max, work);
8139     buf++;
8140     nframes--;
8141   }
8142 
8143   while (nframes >= 8) {
8144     // use 64 byte prefetch for double octetts
8145     // __builtin_prefetch(buf+64,0,0); // for GCC 4.3.2 +
8146 
8147     work = _mm_load_pd(buf);
8148     current_min = _mm_min_pd(current_min, work);
8149     current_max = _mm_max_pd(current_max, work);
8150     buf += 2;
8151     work = _mm_load_pd(buf);
8152     current_min = _mm_min_pd(current_min, work);
8153     current_max = _mm_max_pd(current_max, work);
8154     buf += 2;
8155     work = _mm_load_pd(buf);
8156     current_min = _mm_min_pd(current_min, work);
8157     current_max = _mm_max_pd(current_max, work);
8158     buf += 2;
8159     work = _mm_load_pd(buf);
8160     current_min = _mm_min_pd(current_min, work);
8161     current_max = _mm_max_pd(current_max, work);
8162     buf += 2;
8163     nframes -= 8;
8164   }
8165 
8166   // work through smaller chunks of aligned buffers without prefetching
8167   while (nframes >= 2) {
8168     work = _mm_load_pd(buf);
8169     current_min = _mm_min_pd(current_min, work);
8170     current_max = _mm_max_pd(current_max, work);
8171     buf += 2;
8172     nframes -= 2;
8173   }
8174 
8175   // work through the remaining value
8176   while ( nframes > 0) {
8177     // load the last double and replicate
8178     work = _mm_set1_pd(*buf);
8179     current_min = _mm_min_pd(current_min, work);
8180     current_max = _mm_max_pd(current_max, work);
8181     buf++;
8182     nframes--;
8183   }
8184 
8185   // find final min and max value through shuffle tricks
8186   work = current_min;
8187   work = _mm_shuffle_pd(work, work, _MM_SHUFFLE2(0, 1));
8188   work = _mm_min_pd (work, current_min);
8189   _mm_store_sd(min, work);
8190   work = current_max;
8191   work = _mm_shuffle_pd(work, work, _MM_SHUFFLE2(0, 1));
8192   work = _mm_max_pd (work, current_max);
8193   _mm_store_sd(max, work);
8194 
8195   return;
8196 }
8197 
8198 #endif // SIMD
8199 
8200 #if defined(_ARCH_PWR6)
8201 static
pwr6_minmax_val_double_unrolled6(const double * restrict data,size_t datasize,double * fmin,double * fmax)8202 void pwr6_minmax_val_double_unrolled6(const double *restrict data, size_t datasize, double *fmin, double *fmax)
8203 {
8204 #define __UNROLL_DEPTH_1 6
8205 
8206   // to allow pipelining we have to unroll
8207 
8208   {
8209     size_t i, j;
8210     size_t residual =  datasize % __UNROLL_DEPTH_1;
8211     size_t ofs = datasize - residual;
8212     double register dmin[__UNROLL_DEPTH_1];
8213     double register dmax[__UNROLL_DEPTH_1];
8214 
8215     for ( j = 0; j < __UNROLL_DEPTH_1; j++)
8216       {
8217 	dmin[j] = data[0];
8218 	dmax[j] = data[0];
8219       }
8220 
8221     for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_1 )
8222       {
8223 	for (j = 0; j < __UNROLL_DEPTH_1; j++)
8224 	  {
8225 	    dmin[j] = __fsel(dmin[j] - data[i+j], data[i+j], dmin[j]);
8226 	    dmax[j] = __fsel(data[i+j] - dmax[j], data[i+j], dmax[j]);
8227 	  }
8228       }
8229 
8230     for (j = 0; j < residual; j++)
8231       {
8232 	dmin[j] = __fsel(dmin[j] - data[ofs+j], data[ofs+j], dmin[j]);
8233 	dmax[j] = __fsel(data[ofs+j] - dmax[j], data[ofs+j], dmax[j]);
8234       }
8235 
8236     for ( j = 0; j < __UNROLL_DEPTH_1; j++)
8237       {
8238 	*fmin = __fsel(*fmin - dmin[j], dmin[j], *fmin);
8239 	*fmax = __fsel(dmax[j] - *fmax, dmax[j], *fmax);
8240       }
8241   }
8242 #undef __UNROLL_DEPTH_1
8243 }
8244 #endif
8245 
8246 #if defined(TEST_MINMAXVAL) && defined(__GNUC__)
8247 static
8248 void minmax_val_double_orig(const double *restrict data, size_t datasize, double *fmin, double *fmax) __attribute__ ((noinline));
8249 static
8250 void minmax_val_double_simd(const double *restrict data, size_t datasize, double *fmin, double *fmax) __attribute__ ((noinline));
8251 static
8252 void minmax_val_double_omp(const double *restrict data, size_t datasize, double *fmin, double *fmax) __attribute__ ((noinline));
8253 static
8254 void minmax_val_float(const float *restrict data, long datasize, float *fmin, float *fmax) __attribute__ ((noinline));
8255 static
8256 void minmax_val_float_simd(const float *restrict data, size_t datasize, float *fmin, float *fmax) __attribute__ ((noinline));
8257 #endif
8258 
8259 #if defined(GNUC_PUSH_POP)
8260 #pragma GCC push_options
8261 #pragma GCC optimize ("O3", "fast-math")
8262 #endif
8263 static
minmax_val_double_orig(const double * restrict data,size_t datasize,double * fmin,double * fmax)8264 void minmax_val_double_orig(const double *restrict data, size_t datasize, double *fmin, double *fmax)
8265 {
8266   double dmin = *fmin, dmax = *fmax;
8267 
8268 #if   defined(CRAY)
8269 #pragma _CRI ivdep
8270 #elif defined(SX)
8271 #pragma vdir nodep
8272 #elif defined(__uxp__)
8273 #pragma loop novrec
8274 #elif defined (__ICC)
8275 #pragma ivdep
8276 #endif
8277   for ( size_t i = 0; i < datasize; ++i )
8278     {
8279       dmin = dmin < data[i] ? dmin : data[i];
8280       dmax = dmax > data[i] ? dmax : data[i];
8281     }
8282 
8283   *fmin = dmin;
8284   *fmax = dmax;
8285 }
8286 
8287 static
minmax_val_float(const float * restrict data,long idatasize,float * fmin,float * fmax)8288 void minmax_val_float(const float *restrict data, long idatasize, float *fmin, float *fmax)
8289 {
8290   size_t datasize = (size_t)idatasize;
8291   float dmin = *fmin, dmax = *fmax;
8292 
8293 #if   defined(CRAY)
8294 #pragma _CRI ivdep
8295 #elif defined(SX)
8296 #pragma vdir nodep
8297 #elif defined(__uxp__)
8298 #pragma loop novrec
8299 #elif defined (__ICC)
8300 #pragma ivdep
8301 #endif
8302   for ( size_t i = 0; i < datasize; ++i )
8303     {
8304       dmin = dmin < data[i] ? dmin : data[i];
8305       dmax = dmax > data[i] ? dmax : data[i];
8306     }
8307 
8308   *fmin = dmin;
8309   *fmax = dmax;
8310 }
8311 #if defined(GNUC_PUSH_POP)
8312 #pragma GCC pop_options
8313 #endif
8314 
8315 // TEST
8316 #if defined(OMP_SIMD)
8317 
8318 #if defined(GNUC_PUSH_POP)
8319 #pragma GCC push_options
8320 #pragma GCC optimize ("O3", "fast-math")
8321 #endif
8322 static
minmax_val_double_omp(const double * restrict data,size_t datasize,double * fmin,double * fmax)8323 void minmax_val_double_omp(const double *restrict data, size_t datasize, double *fmin, double *fmax)
8324 {
8325   double dmin = *fmin, dmax = *fmax;
8326 
8327 #if defined(_OPENMP)
8328 #pragma omp parallel for simd reduction(min:dmin) reduction(max:dmax)
8329 #endif
8330   for ( size_t i = 0; i < datasize; ++i )
8331     {
8332       dmin = dmin < data[i] ? dmin : data[i];
8333       dmax = dmax > data[i] ? dmax : data[i];
8334     }
8335 
8336   *fmin = dmin;
8337   *fmax = dmax;
8338 }
8339 
8340 static
minmax_val_double_simd(const double * restrict data,size_t datasize,double * fmin,double * fmax)8341 void minmax_val_double_simd(const double *restrict data, size_t datasize, double *fmin, double *fmax)
8342 {
8343   double dmin = *fmin, dmax = *fmax;
8344 
8345 #if defined(_OPENMP)
8346 #pragma omp simd reduction(min:dmin) reduction(max:dmax)
8347 #endif
8348   for ( size_t i = 0; i < datasize; ++i )
8349     {
8350       dmin = dmin < data[i] ? dmin : data[i];
8351       dmax = dmax > data[i] ? dmax : data[i];
8352     }
8353 
8354   *fmin = dmin;
8355   *fmax = dmax;
8356 }
8357 
8358 static
minmax_val_float_simd(const float * restrict data,size_t datasize,float * fmin,float * fmax)8359 void minmax_val_float_simd(const float *restrict data, size_t datasize, float *fmin, float *fmax)
8360 {
8361   float dmin = *fmin, dmax = *fmax;
8362 
8363 #if defined(_OPENMP)
8364 #pragma omp simd reduction(min:dmin) reduction(max:dmax)
8365 #endif
8366   for ( size_t i = 0; i < datasize; ++i )
8367     {
8368       dmin = dmin < data[i] ? dmin : data[i];
8369       dmax = dmax > data[i] ? dmax : data[i];
8370     }
8371 
8372   *fmin = dmin;
8373   *fmax = dmax;
8374 }
8375 #if defined(GNUC_PUSH_POP)
8376 #pragma GCC pop_options
8377 #endif
8378 #endif
8379 
8380 static
minmax_val_double(const double * restrict data,long idatasize,double * fmin,double * fmax)8381 void minmax_val_double(const double *restrict data, long idatasize, double *fmin, double *fmax)
8382 {
8383 #if defined(_GET_X86_COUNTER) || defined(_GET_MACH_COUNTER)
8384   uint64_t start_minmax, end_minmax;
8385 #endif
8386   size_t datasize = (size_t)idatasize;
8387 
8388   if ( idatasize >= 1 ) ; else return;
8389 
8390 #if defined(_GET_X86_COUNTER)
8391   start_minmax = _rdtsc();
8392 #endif
8393 #if defined(_GET_MACH_COUNTER)
8394   start_minmax = mach_absolute_time();
8395 #endif
8396 
8397 #if defined(_ENABLE_AVX)
8398 
8399   avx_minmax_val_double(data, datasize, fmin, fmax);
8400 
8401 #elif defined(_ENABLE_SSE2)
8402 
8403   sse2_minmax_val_double(data, datasize, fmin, fmax);
8404 
8405 #else
8406 
8407 #if defined(_ARCH_PWR6)
8408 #define __UNROLL_DEPTH_1 6
8409 
8410   // to allow pipelining we have to unroll
8411 
8412 #if defined(_GET_IBM_COUNTER)
8413   hpmStart(1, "minmax fsel");
8414 #endif
8415 
8416   pwr6_minmax_val_double_unrolled6(data, datasize, fmin, fmax);
8417 
8418 #if defined(_GET_IBM_COUNTER)
8419   hpmStop(1);
8420 #endif
8421 
8422 #undef __UNROLL_DEPTH_1
8423 
8424 #else // original loop
8425 
8426 #if defined(_GET_IBM_COUNTER)
8427   hpmStart(1, "minmax base");
8428 #endif
8429 
8430   minmax_val_double_orig(data, datasize, fmin, fmax);
8431 
8432 #if defined(_GET_IBM_COUNTER)
8433   hpmStop(1);
8434 #endif
8435 
8436 #endif // _ARCH_PWR6 && original loop
8437 #endif // SIMD
8438 
8439 #if defined(_GET_X86_COUNTER) || defined(_GET_MACH_COUNTER)
8440 #if defined(_GET_X86_COUNTER)
8441   end_minmax = _rdtsc();
8442 #endif
8443 #if defined(_GET_MACH_COUNTER)
8444   end_minmax = mach_absolute_time();
8445 #endif
8446 #if defined(_ENABLE_AVX)
8447   printf("AVX minmax cycles:: %" PRIu64 "\n",  end_minmax-start_minmax);
8448   fprintf (stderr, "AVX min: %lf max: %lf\n", *fmin, *fmax);
8449 #elif defined(_ENABLE_SSE2)
8450   printf("SSE2 minmax cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
8451   fprintf (stderr, "SSE2 min: %lf max: %lf\n", *fmin, *fmax);
8452 #else
8453   printf("loop minmax cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
8454   fprintf (stderr, "loop min: %lf max: %lf\n", *fmin, *fmax);
8455 #endif
8456 #endif
8457 
8458   return;
8459 }
8460 
8461 #if defined(TEST_MINMAXVAL)
8462 
8463 #include <stdio.h>
8464 #include <sys/time.h>
8465 
8466 static
dtime()8467 double dtime()
8468 {
8469   double tseconds = 0.0;
8470   struct timeval mytime;
8471   gettimeofday(&mytime, NULL);
8472   tseconds = (double) (mytime.tv_sec + (double)mytime.tv_usec*1.0e-6);
8473   return (tseconds);
8474 }
8475 
8476 #define NRUN 10000
8477 
main(void)8478 int main(void)
8479 {
8480   long datasize = 1000000;
8481   double t_begin, t_end;
8482 
8483   printf("datasize %ld\n", datasize);
8484 #if   defined(_OPENMP)
8485   printf("_OPENMP=%d\n", _OPENMP);
8486 #endif
8487 
8488 #if   defined(__ICC)
8489   printf("icc\n");
8490 #elif defined(__clang__)
8491   printf("clang\n");
8492 #elif defined(__GNUC__)
8493   printf("gcc\n");
8494 #endif
8495 
8496   {
8497     float fmin, fmax;
8498     float *data_sp = (float*) malloc(datasize*sizeof(float));
8499 
8500     for ( long i = 0; i < datasize/2; i++ )        data_sp[i] = (float) (i);
8501     for ( long i = datasize/2; i < datasize; i++ ) data_sp[i] = (float) (-datasize + i);
8502 
8503     printf("float:\n");
8504 
8505     t_begin = dtime();
8506     for ( int i = 0; i < NRUN; ++i )
8507       {
8508 	fmin = fmax = data_sp[0];
8509 	minmax_val_float(data_sp, datasize, &fmin, &fmax);
8510       }
8511     t_end = dtime();
8512     printf("minmax_val: fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
8513 
8514 #if defined(OMP_SIMD)
8515     t_begin = dtime();
8516     for ( int i = 0; i < NRUN; ++i )
8517       {
8518 	fmin = fmax = data_sp[0];
8519 	minmax_val_float_simd(data_sp, datasize, &fmin, &fmax);
8520       }
8521     t_end = dtime();
8522     printf("simd      : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
8523 #endif
8524 
8525     free(data_sp);
8526   }
8527 
8528   {
8529     double fmin, fmax;
8530     double *data_dp = (double*) malloc(datasize*sizeof(double));
8531 
8532     // for ( long i = datasize-1; i >= 0; i-- ) data[i] = (double) (-datasize/2 + i);
8533     for ( long i = 0; i < datasize/2; i++ )        data_dp[i] = (double) (i);
8534     for ( long i = datasize/2; i < datasize; i++ ) data_dp[i] = (double) (-datasize + i);
8535 
8536     printf("double:\n");
8537 
8538     t_begin = dtime();
8539     for ( int i = 0; i < NRUN; ++i )
8540       {
8541 	fmin = fmax = data_dp[0];
8542 	minmax_val_double(data_dp, datasize, &fmin, &fmax);
8543       }
8544     t_end = dtime();
8545     printf("minmax_val: fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
8546 
8547     t_begin = dtime();
8548     for ( int i = 0; i < NRUN; ++i )
8549       {
8550 	fmin = fmax = data_dp[0];
8551 	minmax_val_double_orig(data_dp, datasize, &fmin, &fmax);
8552       }
8553     t_end = dtime();
8554     printf("orig      : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
8555 
8556 #if defined(OMP_SIMD)
8557     t_begin = dtime();
8558     for ( int i = 0; i < NRUN; ++i )
8559       {
8560 	fmin = fmax = data_dp[0];
8561 	minmax_val_double_simd(data_dp, datasize, &fmin, &fmax);
8562       }
8563     t_end = dtime();
8564     printf("simd      : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
8565 
8566     t_begin = dtime();
8567     for ( int i = 0; i < NRUN; ++i )
8568       {
8569 	fmin = fmax = data_dp[0];
8570 	minmax_val_double_omp(data_dp, datasize, &fmin, &fmax);
8571       }
8572     t_end = dtime();
8573     printf("openmp %d  : fmin: %ld  fmax: %ld  time: %6.2fs\n", omp_get_max_threads(), (long)fmin, (long) fmax, t_end-t_begin);
8574 #endif
8575 
8576 #if defined(_ENABLE_AVX)
8577     t_begin = dtime();
8578     for ( int i = 0; i < NRUN; ++i )
8579       {
8580 	fmin = fmax = data_dp[0];
8581 	avx_minmax_val_double(data_dp, datasize, &fmin, &fmax);
8582       }
8583     t_end = dtime();
8584     printf("avx       : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
8585 #elif defined(_ENABLE_SSE2)
8586     t_begin = dtime();
8587     for ( int i = 0; i < NRUN; ++i )
8588       {
8589 	fmin = fmax = data_dp[0];
8590 	sse2_minmax_val_double(data_dp, datasize, &fmin, &fmax);
8591       }
8592     t_end = dtime();
8593     printf("sse2      : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
8594 #endif
8595 #if defined(_ARCH_PWR6)
8596     t_begin = dtime();
8597     for ( int i = 0; i < NRUN; ++i )
8598       {
8599 	fmin = fmax = data_dp[0];
8600 	pwr6_minmax_val_double_unrolled6(data_dp, datasize, &fmin, &fmax);
8601       }
8602     t_end = dtime();
8603     printf("pwr6u6  : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
8604 #endif
8605     free(data_dp);
8606   }
8607 
8608   return (0);
8609 }
8610 #endif // TEST_MINMAXVAL
8611 
8612 #undef DISABLE_SIMD_MINMAXVAL
8613 #undef _ENABLE_AVX
8614 #undef _ENABLE_SSE2
8615 #undef GNUC_PUSH_POP
8616 /*
8617 ### new version with gribSwapByteOrder_uint16()
8618 icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_ENCODE encode_array.c
8619  result on hama2 (icc 16.0.2):
8620    float:
8621     orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 1.8731s
8622 unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 2.0898s
8623   double:
8624     orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.68089s
8625 unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.30798s
8626      avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.23864s
8627 
8628 gcc -g -Wall -O3 -march=native -Wa,-q -std=c99 -DTEST_ENCODE encode_array.c
8629  result on hama2 (gcc 6.1.0):
8630 float:
8631     orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 2.22871s
8632 unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 2.30281s
8633 double:
8634     orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.2669s
8635 unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.81643s
8636      avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.98415s
8637 
8638 ###
8639 icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_ENCODE encode_array.c
8640  result on hama2 (icc 16.0.0):
8641    float:
8642     orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 9.10691s
8643 unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 8.63584s
8644   double:
8645     orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 13.5768s
8646 unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 9.17742s
8647      avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.9488s
8648 
8649 gcc -g -Wall -O3 -std=c99 -DTEST_ENCODE encode_array.c
8650  result on hama2 (gcc 5.2.0):
8651    float:
8652     orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 5.32775s
8653 unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 7.87125s
8654   double:
8655     orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 7.85873s
8656 unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 12.9979s
8657 
8658 ###
8659 gcc -g -Wall -O3 -march=native -std=c99 -DTEST_ENCODE encode_array.c
8660  result on bailung (gcc 4.7):
8661   orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 8.4166s
8662   sse41   : val1: 1  val2: 1  val3: 2  valn: 66  time: 7.1522s
8663 
8664 gcc -g -Wall -O3 -march=native -std=c99 -DTEST_ENCODE encode_array.c
8665  result on thunder5 (gcc 4.7):
8666   orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 6.21976s
8667   avx     : val1: 1  val2: 1  val3: 2  valn: 66  time: 4.54485s
8668 
8669 icc -g -Wall -O3 -march=native -std=c99 -vec-report=1 -DTEST_ENCODE encode_array.c
8670  result on thunder5 (icc 13.2):
8671   orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 14.6279s
8672   avx     : val1: 1  val2: 1  val3: 2  valn: 66  time:  4.9776s
8673 
8674 xlc_r -g -O3 -qhot -q64 -qarch=auto -qtune=auto -qreport -DTEST_ENCODE encode_array.c
8675  result on blizzard (xlc 12):
8676   orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 132.25s
8677   unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time:  27.202s
8678   orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 106.627s  // without -qhot
8679   unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time:  39.929s  // without -qhot
8680 */
8681 #ifdef _ARCH_PWR6
8682 #pragma options nostrict
8683 #endif
8684 
8685 #ifdef TEST_ENCODE
8686 #include <stdio.h>
8687 #include <stdlib.h>
8688 #define  GRIBPACK     unsigned char
8689 
8690 #ifndef HOST_ENDIANNESS
8691 #ifdef __cplusplus
8692 static const uint32_t HOST_ENDIANNESS_temp[1] = { UINT32_C(0x00030201) };
8693 #define HOST_ENDIANNESS (((const unsigned char *)HOST_ENDIANNESS_temp)[0])
8694 #else
8695 #define HOST_ENDIANNESS (((const unsigned char *)&(const uint32_t[1]){UINT32_C(0x00030201)})[0])
8696 #endif
8697 #endif
8698 
8699 #define  U_BYTEORDER
8700 #define  IS_BIGENDIAN()  (HOST_ENDIANNESS == 0)
8701 #define  Error(x,y)
8702 #endif
8703 
8704 //#undef _GET_X86_COUNTER
8705 //#undef _GET_MACH_COUNTER
8706 //#undef _GET_IBM_COUNTER
8707 //#undef _ARCH_PWR6
8708 
8709 #if defined _GET_IBM_COUNTER
8710 #include <libhpc.h>
8711 #elif defined _GET_X86_COUNTER
8712 #include <x86intrin.h>
8713 #elif defined _GET_MACH_COUNTER
8714 #include <mach/mach_time.h>
8715 #endif
8716 
8717 #include <stdint.h>
8718 #include <math.h>
8719 
8720 #ifndef DISABLE_SIMD
8721 #if   defined(__GNUC__) && (__GNUC__ >= 4)
8722 #elif defined(__ICC)    && (__ICC >= 1100)
8723 #elif defined(__clang__)
8724 #else
8725 #define DISABLE_SIMD
8726 #endif
8727 #endif
8728 
8729 #ifdef DISABLE_SIMD
8730 #define DISABLE_SIMD_ENCODE
8731 #endif
8732 
8733 //#define DISABLE_SIMD_ENCODE
8734 
8735 #ifdef DISABLE_SIMD_ENCODE
8736 # ifdef ENABLE_AVX
8737 #  define _ENABLE_AVX
8738 # endif
8739 # ifdef ENABLE_SSE4_1
8740 #  define _ENABLE_SSE4_1
8741 # endif
8742 #endif
8743 
8744 #ifndef DISABLE_SIMD_ENCODE
8745 # ifdef __AVX__
8746 #  define _ENABLE_AVX
8747 # endif
8748 # ifdef __SSE4_1__
8749 #  define _ENABLE_SSE4_1
8750 # endif
8751 #endif
8752 
8753 #if defined _ENABLE_AVX
8754 #include <immintrin.h>
8755 #elif defined _ENABLE_SSE4_1
8756 #include <smmintrin.h>
8757 #endif
8758 
8759 #if defined _ENABLE_AVX
8760 
8761 static
avx_encode_array_2byte_double(size_t datasize,unsigned char * restrict lGrib,const double * restrict data,double zref,double factor,size_t * gz)8762 void avx_encode_array_2byte_double(size_t datasize,
8763 				   unsigned char * restrict lGrib,
8764 				   const double * restrict data,
8765 				   double zref, double factor, size_t *gz)
8766 {
8767   size_t i, j, residual;
8768   const double *dval = data;
8769   __m128i *sgrib = (__m128i *) (lGrib+(*gz));
8770 
8771   const __m128i swap = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
8772 
8773   const __m256d c0 = _mm256_set1_pd(zref);
8774   const __m256d c1 = _mm256_set1_pd(factor);
8775   const __m256d c2 = _mm256_set1_pd(0.5);
8776 
8777   __m256d d0, d3, d2, d1;
8778   __m128i i0, i1, i2, i3;
8779   __m128i s0, s1;
8780 
8781   residual = datasize % 16;
8782 
8783   for (i = 0; i < (datasize-residual); i += 16)
8784     {
8785       (void) _mm_prefetch((const char*)(dval+8), _MM_HINT_NTA);
8786       //_____________________________________________________________________________
8787 
8788       d0 = _mm256_loadu_pd (dval);
8789       d0 = _mm256_sub_pd (d0, c0);
8790       d0 = _mm256_mul_pd (d0, c1);
8791       d0 = _mm256_add_pd (d0, c2);
8792 
8793       i0 = _mm256_cvttpd_epi32 (d0);
8794 
8795       //_____________________________________________________________________________
8796 
8797       d1 = _mm256_loadu_pd (dval+4);
8798       d1 = _mm256_sub_pd (d1, c0);
8799       d1 = _mm256_mul_pd (d1, c1);
8800       d1 = _mm256_add_pd (d1, c2);
8801 
8802       i1 = _mm256_cvttpd_epi32 (d1);
8803 
8804       //_____________________________________________________________________________
8805 
8806       s0 = _mm_packus_epi32(i0, i1);
8807       s0 = _mm_shuffle_epi8 (s0, swap);
8808       (void) _mm_storeu_si128 (sgrib, s0);
8809 
8810       //_____________________________________________________________________________
8811 
8812       (void) _mm_prefetch((const char*)(dval+16), _MM_HINT_NTA);
8813 
8814       //_____________________________________________________________________________
8815 
8816       d2 = _mm256_loadu_pd (dval+8);
8817       d2 = _mm256_sub_pd (d2, c0);
8818       d2 = _mm256_mul_pd (d2, c1);
8819       d2 = _mm256_add_pd (d2, c2);
8820 
8821       i2 = _mm256_cvttpd_epi32 (d2);
8822 
8823       //_____________________________________________________________________________
8824 
8825       d3 = _mm256_loadu_pd (dval+12);
8826       d3 = _mm256_sub_pd (d3, c0);
8827       d3 = _mm256_mul_pd (d3, c1);
8828       d3 = _mm256_add_pd (d3, c2);
8829 
8830       i3 = _mm256_cvttpd_epi32 (d3);
8831 
8832       //_____________________________________________________________________________
8833 
8834       s1 = _mm_packus_epi32(i2, i3);
8835       s1 = _mm_shuffle_epi8 (s1, swap);
8836       (void) _mm_storeu_si128 (sgrib+1, s1);
8837 
8838       //_____________________________________________________________________________
8839 
8840       dval += 16;
8841       sgrib += 2;
8842     }
8843 
8844   if (i != datasize)
8845     {
8846       uint16_t ui16;
8847       for ( j = i; j < datasize; j++ )
8848 	{
8849 	  ui16 = (uint16_t) ((data[j] - zref) * factor + 0.5);
8850 	  lGrib[*gz+2*j  ] = ui16 >>  8;
8851 	  lGrib[*gz+2*j+1] = ui16;
8852 	}
8853     }
8854 
8855   *gz += 2*datasize;
8856 
8857   return;
8858 }
8859 
8860 #define grib_encode_array_2byte_double avx_encode_array_2byte_double
8861 
8862 #elif defined _ENABLE_SSE4_1
8863 
8864 static
sse41_encode_array_2byte_double(size_t datasize,unsigned char * restrict lGrib,const double * restrict data,double zref,double factor,size_t * gz)8865 void sse41_encode_array_2byte_double(size_t datasize,
8866 				     unsigned char * restrict lGrib,
8867 				     const double * restrict data,
8868 				     double zref, double factor, size_t *gz)
8869 {
8870   size_t i, j, residual;
8871   const double *dval = data;
8872   __m128i *sgrib = (__m128i *) (lGrib+(*gz));
8873 
8874   const __m128i swap = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
8875 
8876   const __m128d c0 = _mm_set1_pd(zref);
8877   const __m128d c1 = _mm_set1_pd(factor);
8878   const __m128d c2 = _mm_set1_pd(0.5);
8879 
8880   __m128d d0, d4, d3, d2, d1;
8881   __m128i i0, i1, i2, i3, i4;
8882   __m128i s0, s1;
8883 
8884   residual = datasize % 16;
8885 
8886   for (i = 0; i < (datasize-residual); i += 16)
8887     {
8888       (void) _mm_prefetch((const char*)(dval+8), _MM_HINT_NTA);
8889       //_____________________________________________________________________________
8890 
8891       d0 = _mm_loadu_pd (dval);
8892       d0 = _mm_sub_pd (d0, c0);
8893       d0 = _mm_mul_pd (d0, c1);
8894       d0 = _mm_add_pd (d0, c2);
8895 
8896       d4 = _mm_loadu_pd (dval+2);
8897       d4 = _mm_sub_pd (d4, c0);
8898       d4 = _mm_mul_pd (d4, c1);
8899       d4 = _mm_add_pd (d4, c2);
8900 
8901       i0 = _mm_cvttpd_epi32 (d0);
8902       i4 = _mm_cvttpd_epi32 (d4);
8903       i0 = _mm_unpacklo_epi64 (i0, i4);
8904 
8905       //_____________________________________________________________________________
8906 
8907       d1 = _mm_loadu_pd (dval+4);
8908       d1 = _mm_sub_pd (d1, c0);
8909       d1 = _mm_mul_pd (d1, c1);
8910       d1 = _mm_add_pd (d1, c2);
8911 
8912       d4 = _mm_loadu_pd (dval+6);
8913       d4 = _mm_sub_pd (d4, c0);
8914       d4 = _mm_mul_pd (d4, c1);
8915       d4 = _mm_add_pd (d4, c2);
8916 
8917       i1 = _mm_cvttpd_epi32 (d1);
8918       i4 = _mm_cvttpd_epi32 (d4);
8919       i1 = _mm_unpacklo_epi64 (i1, i4);
8920 
8921       //_____________________________________________________________________________
8922 
8923       s0 = _mm_packus_epi32(i0, i1);
8924       s0 = _mm_shuffle_epi8 (s0, swap);
8925       (void) _mm_storeu_si128 (sgrib, s0);
8926 
8927       //_____________________________________________________________________________
8928 
8929       (void) _mm_prefetch((const char*)(dval+16), _MM_HINT_NTA);
8930 
8931       //_____________________________________________________________________________
8932 
8933       d2 = _mm_loadu_pd (dval+8);
8934       d2 = _mm_sub_pd (d2, c0);
8935       d2 = _mm_mul_pd (d2, c1);
8936       d2 = _mm_add_pd (d2, c2);
8937 
8938       d4 = _mm_loadu_pd (dval+10);
8939       d4 = _mm_sub_pd (d4, c0);
8940       d4 = _mm_mul_pd (d4, c1);
8941       d4 = _mm_add_pd (d4, c2);
8942 
8943       i2 = _mm_cvttpd_epi32 (d2);
8944       i4  = _mm_cvttpd_epi32 (d4);
8945       i2 = _mm_unpacklo_epi64 (i2, i4);
8946 
8947       //_____________________________________________________________________________
8948 
8949       d3 = _mm_loadu_pd (dval+12);
8950       d3 = _mm_sub_pd (d3, c0);
8951       d3 = _mm_mul_pd (d3, c1);
8952       d3 = _mm_add_pd (d3, c2);
8953 
8954       d4 = _mm_loadu_pd (dval+14);
8955       d4 = _mm_sub_pd (d4, c0);
8956       d4 = _mm_mul_pd (d4, c1);
8957       d4 = _mm_add_pd (d4, c2);
8958 
8959       i3 = _mm_cvttpd_epi32 (d3);
8960       i4 = _mm_cvttpd_epi32 (d4);
8961       i3 = _mm_unpacklo_epi64 (i3, i4);
8962 
8963       //_____________________________________________________________________________
8964 
8965       s1 = _mm_packus_epi32(i2, i3);
8966       s1 = _mm_shuffle_epi8 (s1, swap);
8967       (void) _mm_storeu_si128 (sgrib+1, s1);
8968 
8969       //_____________________________________________________________________________
8970 
8971       dval += 16;
8972       sgrib += 2;
8973     }
8974 
8975   if (i != datasize)
8976     {
8977       uint16_t ui16;
8978       for ( j = i; j < datasize; j++ )
8979 	{
8980 	  ui16 = (uint16_t) ((data[j] - zref) * factor + 0.5);
8981 	  lGrib[*gz+2*j  ] = ui16 >>  8;
8982 	  lGrib[*gz+2*j+1] = ui16;
8983 	}
8984     }
8985 
8986   *gz += 2*datasize;
8987 
8988   return;
8989 }
8990 
8991 #define grib_encode_array_2byte_double sse41_encode_array_2byte_double
8992 
8993 #else
8994 
8995 #define grib_encode_array_2byte_double encode_array_2byte_double
8996 
8997 #endif // SIMD variants
8998 
8999 
9000 #ifdef TEST_ENCODE
9001 
9002 #define CAT(X,Y)      X##_##Y
9003 #define TEMPLATE(X,Y) CAT(X,Y)
9004 
9005 #ifdef T
9006 #undef T
9007 #endif
9008 #define T double
9009 
9010 #ifdef T
9011 #undef T
9012 #endif
9013 #define T float
9014 
9015 
9016 #include <sys/time.h>
9017 
9018 static
dtime()9019 double dtime()
9020 {
9021   double tseconds = 0.0;
9022   struct timeval mytime;
9023   gettimeofday(&mytime, NULL);
9024   tseconds = (double) (mytime.tv_sec + (double)mytime.tv_usec*1.0e-6);
9025   return (tseconds);
9026 }
9027 
9028 
9029 static
pout(char * name,int s,unsigned char * lgrib,long datasize,double tt)9030 void pout(char *name, int s, unsigned char *lgrib, long datasize, double tt)
9031 {
9032   printf("%8s: val1: %d  val2: %d  val3: %d  valn: %d  time: %gs\n",
9033          name, (int) lgrib[s*1+1], (int) lgrib[s*2+1], (int) lgrib[s*3+1], (int) lgrib[2*datasize-1], tt);
9034 }
9035 
main(void)9036 int main(void)
9037 {
9038   enum {
9039     datasize = 1000000,
9040     NRUN = 10000,
9041   };
9042 
9043   double t_begin, t_end;
9044 
9045   float *dataf = (float*) malloc(datasize*sizeof(float));
9046   double *data = (double*) malloc(datasize*sizeof(double));
9047   unsigned char *lgrib = (unsigned char*) malloc(2*datasize*sizeof(unsigned char));
9048 
9049   for ( long i = 0; i < datasize; ++i ) dataf[i] = (float) (-datasize/2 + i);
9050   for ( long i = 0; i < datasize; ++i ) data[i] = (double) (-datasize/2 + i);
9051 
9052   int PackStart = 0;
9053   int nbpv = 16;
9054   double zref = data[0];
9055   size_t z;
9056   double factor = 0.00390625;
9057   int s = 256;
9058 
9059   if ( 0 )
9060     {
9061       encode_array_float(0, 0, 0, NULL, NULL, 0, 0, NULL);
9062       encode_array_double(0, 0, 0, NULL, NULL, 0, 0, NULL);
9063     }
9064 
9065 #if   defined(__ICC)
9066   printf("icc\n");
9067 #elif defined(__clang__)
9068   printf("clang\n");
9069 #elif defined(__GNUC__)
9070   printf("gcc\n");
9071 #endif
9072 
9073   printf("float:\n");
9074 
9075   t_begin = dtime();
9076   for ( int i = 0; i < NRUN; ++i )
9077     {
9078       z = 0;
9079       encode_array_2byte_float(datasize, lgrib, dataf, (float)zref, (float)factor, &z);
9080     }
9081   t_end = dtime();
9082   pout("orig", s, lgrib, datasize, t_end-t_begin);
9083 
9084   t_begin = dtime();
9085   for ( int i = 0; i < NRUN; ++i )
9086     {
9087       z = 0;
9088       encode_array_unrolled_float(nbpv, PackStart, datasize, lgrib, dataf, (float)zref, (float)factor, &z);
9089     }
9090   t_end = dtime();
9091   pout("unrolled", s, lgrib, datasize, t_end-t_begin);
9092 
9093   printf("double:\n");
9094 
9095   t_begin = dtime();
9096   for ( int i = 0; i < NRUN; ++i )
9097     {
9098       z = 0;
9099       encode_array_2byte_double(datasize, lgrib, data, zref, factor, &z);
9100     }
9101   t_end = dtime();
9102   pout("orig", s, lgrib, datasize, t_end-t_begin);
9103 
9104   t_begin = dtime();
9105   for ( int i = 0; i < NRUN; ++i )
9106     {
9107       z = 0;
9108       encode_array_unrolled_double(nbpv, PackStart, datasize, lgrib, data, zref, factor, &z);
9109     }
9110   t_end = dtime();
9111   pout("unrolled", s, lgrib, datasize, t_end-t_begin);
9112 
9113 #if defined _ENABLE_AVX
9114   t_begin = dtime();
9115   for ( int i = 0; i < NRUN; ++i )
9116     {
9117       z = 0;
9118       avx_encode_array_2byte_double(datasize, lgrib, data, zref, factor, &z);
9119     }
9120   t_end = dtime();
9121   pout("avx", s, lgrib, datasize, t_end-t_begin);
9122 #elif defined _ENABLE_SSE4_1
9123   t_begin = dtime();
9124   for ( int i = 0; i < NRUN; ++i )
9125     {
9126       z = 0;
9127       sse41_encode_array_2byte_double(datasize, lgrib, data, zref, factor, &z);
9128     }
9129   t_end = dtime();
9130   pout("sse41", s, lgrib, datasize, t_end-t_begin);
9131 #endif
9132 
9133   return 0;
9134 }
9135 #endif // TEST_ENCODE
9136 
9137 #undef DISABLE_SIMD_ENCODE
9138 #undef _ENABLE_AVX
9139 #undef _ENABLE_SSE4_1
9140 
9141 
confp3(double pval,int * kexp,int * kmant,int kbits,int kround)9142 void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
9143 {
9144   /*
9145 
9146     Purpose:
9147     --------
9148 
9149     Convert floating point number from machine
9150     representation to GRIB representation.
9151 
9152     Input Parameters:
9153     -----------------
9154 
9155        pval    - Floating point number to be converted.
9156        kbits   - Number of bits in computer word.
9157        kround  - Conversion type.
9158                  0 , Closest number in GRIB format less than
9159                      original number.
9160                  1 , Closest number in GRIB format to the
9161                      original number (equal to, greater than or
9162                      less than original number).
9163 
9164     Output Parameters:
9165     ------------------
9166 
9167        kexp    - 8 Bit signed exponent.
9168        kmant   - 24 Bit mantissa.
9169 
9170     Method:
9171     -------
9172 
9173     Floating point number represented as 8 bit signed
9174     exponent and 24 bit mantissa in integer values.
9175 
9176     Externals.
9177     ----------
9178 
9179     decfp2    - Decode from IBM floating point format.
9180 
9181     Reference:
9182     ----------
9183 
9184     WMO Manual on Codes re GRIB representation.
9185 
9186     Comments:
9187     ---------
9188 
9189     Routine aborts if an invalid conversion type parameter
9190     is used or if a 24 bit mantissa is not produced.
9191 
9192     Author:
9193     -------
9194 
9195     John Hennessy   ECMWF   18.06.91
9196 
9197     Modifications:
9198     --------------
9199 
9200     Uwe Schulzweida   MPIfM   01/04/2001
9201 
9202     Convert to C from EMOS library version 130
9203 
9204     Uwe Schulzweida   MPIfM   02/08/2002
9205 
9206      - speed up by factor 1.6 on NEC SX6
9207         - replace 1.0 / pow(16.0, (double)(iexp - 70)) by rpow16m70tab[iexp]
9208   */
9209 
9210   // extern int CGRIBEX_Debug;
9211 
9212   /* ----------------------------------------------------------------- */
9213   /*   Section 1 . Initialise                                          */
9214   /* ----------------------------------------------------------------- */
9215 
9216   // Check conversion type parameter.
9217 
9218   int iround = kround;
9219   if ( iround != 0 && iround != 1 )
9220     {
9221       Error("Invalid conversion type = %d", iround);
9222 
9223       // If not aborting, arbitrarily set rounding to 'up'.
9224      iround = 1;
9225     }
9226 
9227   /* ----------------------------------------------------------------- */
9228   /*   Section 2 . Convert value of zero.                              */
9229   /* ----------------------------------------------------------------- */
9230 
9231   if (fabs(pval) <= 0)
9232     {
9233       *kexp  = 0;
9234       *kmant = 0;
9235       goto LABEL900;
9236     }
9237 
9238   /* ----------------------------------------------------------------- */
9239   /*   Section 3 . Convert other values.                               */
9240   /* ----------------------------------------------------------------- */
9241   {
9242     const double zeps = (kbits != 32) ? 1.0e-12 : 1.0e-8;
9243     double zref = pval;
9244 
9245     // Sign of value.
9246     const int isign = (zref >= 0.0) ? 0 : 128;
9247     zref = fabs(zref);
9248 
9249     // Exponent.
9250     int iexp = (int) (log(zref)/log(16.0) + 65.0 + zeps);
9251 
9252     // only ANSI C99 has log2
9253     // iexp = (int) (log2(zref) * 0.25 + 65.0 + zeps);
9254 
9255     if ( iexp < 0   ) iexp = 0;
9256     if ( iexp > 127 ) iexp = 127;
9257 
9258     // double rpowref = zref / pow(16.0, (double)(iexp - 70));
9259     double rpowref = ldexp(zref, 4 * -(iexp - 70));
9260 
9261     // Mantissa.
9262     if ( iround == 0 )
9263     {
9264       /*  Closest number in GRIB format less than original number. */
9265       /*  Truncate for positive numbers. */
9266       /*  Round up for negative numbers. */
9267       *kmant = (isign == 0) ? (int)rpowref : (int)lround(rpowref + 0.5);
9268     }
9269     else
9270     {
9271       /*  Closest number in GRIB format to the original number   */
9272       /*  (equal to, greater than or less than original number). */
9273       *kmant = (int)lround(rpowref);
9274     }
9275 
9276     /*  Check that mantissa value does not exceed 24 bits. */
9277     /*  If it does, adjust the exponent upwards and recalculate the mantissa. */
9278     /*  16777215 = 2**24 - 1 */
9279     if ( *kmant > 16777215 )
9280     {
9281 
9282     LABEL350:
9283 
9284       ++iexp;
9285 
9286       // Check for exponent overflow during adjustment
9287       if ( iexp > 127 )
9288       {
9289         Message("Exponent overflow");
9290         Message("Original number = %30.20f", pval);
9291         Message("Sign = %3d, Exponent = %3d, Mantissa = %12d", isign, iexp, *kmant);
9292 
9293         Error("Exponent overflow");
9294 
9295         // If not aborting, arbitrarily set value to zero
9296         Message("Value arbitrarily set to zero.");
9297         *kexp  = 0;
9298         *kmant = 0;
9299         goto LABEL900;
9300       }
9301 
9302       rpowref = ldexp(zref, 4 * -(iexp - 70));
9303 
9304       if ( iround == 0 )
9305       {
9306         /*  Closest number in GRIB format less than original number. */
9307         /*  Truncate for positive numbers. */
9308         /*  Round up for negative numbers. */
9309         *kmant = (isign == 0) ? (int)rpowref : (int)lround(rpowref + 0.5);
9310       }
9311       else
9312       {
9313         /*  Closest number in GRIB format to the original number */
9314         /*  (equal to, greater or less than original number). */
9315         *kmant = (int)lround(rpowref);
9316       }
9317 
9318       // Repeat calculation (with modified exponent) if still have mantissa overflow.
9319       if ( *kmant > 16777215 ) goto LABEL350;
9320     }
9321 
9322     // Add sign bit to exponent.
9323     *kexp = iexp + isign;
9324   }
9325 
9326   /* ----------------------------------------------------------------- */
9327   /*   Section 9. Return                                               */
9328   /* ----------------------------------------------------------------- */
9329 
9330 LABEL900:
9331   /*
9332   if ( CGRIBEX_Debug )
9333     {
9334       double zval;
9335 
9336       Message("Conversion type parameter = %4d", kround);
9337       Message("Original number = %30.20f", pval);
9338 
9339       zval = decfp2(*kexp, *kmant);
9340 
9341       Message("Converted to      %30.20f", zval);
9342       Message("Sign = %3d, Exponent = %3d, Mantissa = %12d", isign, iexp, *kmant);
9343     }
9344   */
9345   return;
9346 } /* confp3 */
9347 #include <math.h>
9348 
9349 
decfp2(int kexp,int kmant)9350 double decfp2(int kexp, int kmant)
9351 {
9352   /*
9353 
9354     Purpose:
9355     --------
9356 
9357     Convert GRIB representation of a floating point
9358     number to machine representation.
9359 
9360     Input Parameters:
9361     -----------------
9362 
9363     kexp    - 8 Bit signed exponent.
9364     kmant   - 24 Bit mantissa.
9365 
9366     Output Parameters:
9367     ------------------
9368 
9369     Return value   - Floating point number represented
9370                      by kexp and kmant.
9371 
9372     Method:
9373     -------
9374 
9375     Floating point number represented as 8 bit exponent
9376     and 24 bit mantissa in integer values converted to
9377     machine floating point format.
9378 
9379     Externals:
9380     ----------
9381 
9382     None.
9383 
9384     Reference:
9385     ----------
9386 
9387     WMO Manual on Codes re GRIB representation.
9388 
9389     Comments:
9390     ---------
9391 
9392     Rewritten from DECFP, to conform to programming standards.
9393     Sign bit on 0 value now ignored, if present.
9394     If using 32 bit reals, check power of 16 is not so small as to
9395     cause overflows (underflows!); this causes warning to be given
9396     on Fujitsus.
9397 
9398     Author:
9399     -------
9400 
9401     John Hennessy   ECMWF   18.06.91
9402 
9403     Modifications:
9404     --------------
9405 
9406     Uwe Schulzweida   MPIfM   01/04/2001
9407 
9408      - Convert to C from EMOS library version 130
9409 
9410     Uwe Schulzweida   MPIfM   02/08/2002
9411 
9412      - speed up by factor 2 on NEC SX6
9413         - replace pow(2.0, -24.0) by constant POW_2_M24
9414         - replace pow(16.0, (double)(iexp - 64)) by pow16m64tab[iexp]
9415   */
9416 
9417   /* ----------------------------------------------------------------- */
9418   /*   Section 1 . Convert value of 0.0. Ignore sign bit.              */
9419   /* ----------------------------------------------------------------- */
9420 
9421   if ( (kexp == 128) || (kexp == 0) || (kexp == 255) ) return 0.0;
9422 
9423   /* ----------------------------------------------------------------- */
9424   /*   Section 2 . Convert other values.                               */
9425   /* ----------------------------------------------------------------- */
9426 
9427   /*  Sign of value. */
9428 
9429   int iexp = kexp;
9430   const int isign = (iexp < 128) * 2 - 1;
9431 
9432   iexp -= iexp < 128 ? 0 : 128;
9433 
9434   /*  Decode value. */
9435 
9436   /* pval = isign * pow(2.0, -24.0) * kmant * pow(16.0, (double)(iexp - 64)); */
9437 
9438   iexp -= 64;
9439 
9440   const double pval = ldexp(1.0, 4 * iexp) * isign * POW_2_M24 * kmant;
9441 
9442   /* ----------------------------------------------------------------- */
9443   /*   Section 9. Return to calling routine.                           */
9444   /* ----------------------------------------------------------------- */
9445 
9446   return pval;
9447 } /* decfp2 */
9448 #include <stdint.h>
9449 #include <string.h>
9450 #include <stdarg.h>
9451 
9452 
9453 static
gribDecodeRefDate(int * isec1,int * year,int * month,int * day)9454 void gribDecodeRefDate(int *isec1, int *year, int *month, int *day)
9455 {
9456   int century = ISEC1_Century;
9457   int ryear   = ISEC1_Year;
9458 
9459   if ( century < 0 ) century = -century;
9460   century -= 1;
9461 
9462   if ( century == -255 && ryear == 127 )
9463     {
9464       century = 0;
9465       ryear = 0;
9466     }
9467   else
9468     {
9469       /* if ( century != 0 ) */
9470       {
9471         if ( ryear == 100 )
9472           {
9473             ryear = 0;
9474             century += 1;
9475           }
9476 
9477         if ( ryear != 255 )
9478           {
9479             ryear = century*100 + ryear;
9480             if ( ISEC1_Century < 0 ) ryear = -ryear;
9481           }
9482         else
9483           ryear = 1;
9484       }
9485     }
9486 
9487   *year  = ryear;
9488   *month = ISEC1_Month;
9489   *day   = ISEC1_Day;
9490 }
9491 
9492 
gribRefDate(int * isec1)9493 int gribRefDate(int *isec1)
9494 {
9495   int ryear, rmonth, rday;
9496   gribDecodeRefDate(isec1, &ryear, &rmonth, &rday);
9497   return cdiEncodeDate(ryear, rmonth, rday);
9498 }
9499 
9500 static
gribDecodeRefTime(int * isec1,int * hour,int * minute,int * second)9501 void gribDecodeRefTime(int *isec1, int *hour, int *minute, int *second)
9502 {
9503   *hour = ISEC1_Hour;
9504   *minute = ISEC1_Minute;
9505   *second = 0;
9506 }
9507 
9508 
gribRefTime(int * isec1)9509 int gribRefTime(int *isec1)
9510 {
9511   int rhour, rminute, rsecond;
9512   gribDecodeRefTime(isec1, &rhour, &rminute, &rsecond);
9513   return cdiEncodeTime(rhour, rminute, rsecond);
9514 }
9515 
9516 
gribTimeIsFC(int * isec1)9517 bool gribTimeIsFC(int *isec1)
9518 {
9519   bool isFC = false;
9520 
9521   int time_period = (ISEC1_TimeRange == 10) ? (ISEC1_TimePeriod1<<8) + ISEC1_TimePeriod2 : ISEC1_TimePeriod1;
9522 
9523   if ( time_period > 0 && ISEC1_Day > 0 )
9524     {
9525       if ( ISEC1_TimeRange == 0 || ISEC1_TimeRange == 10 ) isFC = true;
9526     }
9527 
9528   return isFC;
9529 }
9530 
9531 static
getTimeUnitFactor(int timeUnit)9532 int getTimeUnitFactor(int timeUnit)
9533 {
9534   static bool lprint = true;
9535   switch ( timeUnit )
9536     {
9537     case ISEC1_TABLE4_MINUTE:    return    60; break;
9538     case ISEC1_TABLE4_QUARTER:   return   900; break;
9539     case ISEC1_TABLE4_30MINUTES: return  1800; break;
9540     case ISEC1_TABLE4_HOUR:      return  3600; break;
9541     case ISEC1_TABLE4_3HOURS:    return 10800; break;
9542     case ISEC1_TABLE4_6HOURS:    return 21600; break;
9543     case ISEC1_TABLE4_12HOURS:   return 43200; break;
9544     case ISEC1_TABLE4_DAY:       return 86400; break;
9545     default:
9546       if ( lprint )
9547         {
9548           gprintf(__func__, "Time unit %d unsupported", timeUnit);
9549           lprint = false;
9550         }
9551       break;
9552     }
9553 
9554   return 0;
9555 }
9556 
9557 
gribDateTimeX(int * isec1,int * date,int * time,int * startDate,int * startTime)9558 void gribDateTimeX(int *isec1, int *date, int *time, int *startDate, int *startTime)
9559 {
9560   *startDate = 0;
9561   *startTime = 0;
9562 
9563   int ryear, rmonth, rday;
9564   gribDecodeRefDate(isec1, &ryear, &rmonth, &rday);
9565 
9566   int rhour, rminute, rsecond;
9567   gribDecodeRefTime(isec1, &rhour, &rminute, &rsecond);
9568 
9569   // printf("ref %d/%d/%d %d:%d\n", ryear, rmonth, rday, rhour, rminute);
9570 
9571   int64_t time_period = 0, time_period_x = 0;
9572   if ( ISEC1_TimeRange == 10 )
9573     time_period = (ISEC1_TimePeriod1<<8) + ISEC1_TimePeriod2;
9574   else if ( ISEC1_TimeRange >=2 && ISEC1_TimeRange <= 5 )
9575     {
9576       time_period_x = ISEC1_TimePeriod1;
9577       time_period = ISEC1_TimePeriod2;
9578     }
9579   else if ( ISEC1_TimeRange == 0 )
9580     time_period = ISEC1_TimePeriod1;
9581 
9582   if ( time_period > 0 && rday > 0 )
9583     {
9584       int64_t julday;
9585       int secofday;
9586       encode_caldaysec(CGRIBEX_grib_calendar, ryear, rmonth, rday, rhour, rminute, rsecond, &julday, &secofday);
9587 
9588       int time_unit_factor = getTimeUnitFactor(ISEC1_TimeUnit);
9589 
9590       if (time_period_x > 0)
9591         {
9592           int64_t julday_x = julday;
9593           int secofday_x = secofday;
9594           julday_add_seconds(time_unit_factor * time_period_x, &julday_x, &secofday_x);
9595           decode_caldaysec(CGRIBEX_grib_calendar, julday_x, secofday_x, &ryear, &rmonth, &rday, &rhour, &rminute, &rsecond);
9596           *startDate = cdiEncodeDate(ryear, rmonth, rday);
9597           *startTime = cdiEncodeTime(rhour, rminute, 0);
9598         }
9599 
9600       julday_add_seconds(time_unit_factor * time_period, &julday, &secofday);
9601       decode_caldaysec(CGRIBEX_grib_calendar, julday, secofday, &ryear, &rmonth, &rday, &rhour, &rminute, &rsecond);
9602     }
9603 
9604   // printf("new %d/%d/%d %d:%d\n", ryear, rmonth, rday, rhour, rminute);
9605   *date = cdiEncodeDate(ryear, rmonth, rday);
9606   *time = cdiEncodeTime(rhour, rminute, 0);
9607 
9608   return;
9609 }
9610 
9611 
gribDateTime(int * isec1,int * date,int * time)9612 void gribDateTime(int *isec1, int *date, int *time)
9613 {
9614   int sdate, stime;
9615   gribDateTimeX(isec1, date, time, &sdate, &stime);
9616 }
9617 
9618 
gprintf(const char * caller,const char * fmt,...)9619 void gprintf(const char *caller, const char *fmt, ...)
9620 {
9621   va_list args;
9622 
9623   if ( grprsm == NULL ) Error("GRIBEX initialization missing!");
9624 
9625   va_start(args, fmt);
9626 
9627    fprintf(grprsm, "%-18s : ", caller);
9628   vfprintf(grprsm, fmt, args);
9629    fputs("\n", grprsm);
9630 
9631   va_end(args);
9632 }
9633 
9634 
9635 void
gribExDP(int * isec0,int * isec1,int * isec2,double * fsec2,int * isec3,double * fsec3,int * isec4,double * fsec4,int klenp,int * kgrib,int kleng,int * kword,const char * hoper,int * kret)9636 gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
9637 	 double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
9638 	 int kleng, int *kword, const char *hoper, int *kret)
9639 {
9640   int yfunc = *hoper;
9641 
9642   if ( yfunc == 'C' )
9643     {
9644       grib_encode_double(isec0, isec1, isec2, fsec2, isec3,
9645 			 fsec3, isec4, fsec4, klenp, kgrib,
9646 			 kleng, kword, yfunc, kret);
9647     }
9648   else if ( yfunc == 'D' || yfunc == 'J' || yfunc == 'R' )
9649     {
9650       grib_decode_double(isec0, isec1, isec2, fsec2, isec3,
9651 			 fsec3, isec4, fsec4, klenp, kgrib,
9652 			 kleng, kword, yfunc, kret);
9653     }
9654   else if ( yfunc == 'V' )
9655     {
9656       fprintf(stderr, "  cgribex: Version is %s\n", cgribexLibraryVersion());
9657     }
9658   else
9659     {
9660       Error("oper %c unsupported!", yfunc);
9661       *kret=-9;
9662     }
9663 }
9664 
9665 
9666 void
gribExSP(int * isec0,int * isec1,int * isec2,float * fsec2,int * isec3,float * fsec3,int * isec4,float * fsec4,int klenp,int * kgrib,int kleng,int * kword,const char * hoper,int * kret)9667 gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
9668 	 float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
9669 	 int kleng, int *kword, const char *hoper, int *kret)
9670 {
9671   int yfunc = *hoper;
9672 
9673   if ( yfunc == 'C' )
9674     {
9675       grib_encode_float(isec0, isec1, isec2, fsec2, isec3,
9676 			fsec3, isec4, fsec4, klenp, kgrib,
9677 			kleng, kword, yfunc, kret);
9678     }
9679   else if ( yfunc == 'D' || yfunc == 'J' || yfunc == 'R' )
9680     {
9681       grib_decode_float(isec0, isec1, isec2, fsec2, isec3,
9682 			fsec3, isec4, fsec4, klenp, kgrib,
9683 			kleng, kword, yfunc, kret);
9684     }
9685   else if ( yfunc == 'V' )
9686     {
9687       fprintf(stderr, " cgribex: Version is %s\n", cgribexLibraryVersion());
9688     }
9689   else
9690     {
9691       Error("oper %c unsupported!", yfunc);
9692       *kret=-9;
9693     }
9694 }
9695 
9696 int CGRIBEX_Fix_ZSE  = 0;    /* 1: Fix ZeroShiftError of simple packed spherical harmonics */
9697 int CGRIBEX_Const    = 0;    /* 1: Don't pack constant fields on regular grids */
9698 int CGRIBEX_Debug    = 0;    /* 1: Debugging */
9699 
gribSetDebug(int debug)9700 void gribSetDebug(int debug)
9701 {
9702   CGRIBEX_Debug = debug;
9703 
9704   if ( CGRIBEX_Debug )
9705     Message("debug level %d", debug);
9706 }
9707 
9708 
gribFixZSE(int flag)9709 void gribFixZSE(int flag)
9710 {
9711   CGRIBEX_Fix_ZSE = flag;
9712 
9713   if ( CGRIBEX_Debug )
9714     Message("Fix ZeroShiftError set to %d", flag);
9715 }
9716 
9717 
gribSetConst(int flag)9718 void gribSetConst(int flag)
9719 {
9720   CGRIBEX_Const = flag;
9721 
9722   if ( CGRIBEX_Debug )
9723     Message("Const set to %d", flag);
9724 }
9725 
9726 
gribSetRound(int round)9727 void gribSetRound(int round)
9728 {
9729   UNUSED(round);
9730 }
9731 
9732 
gribSetRefDP(double refval)9733 void gribSetRefDP(double refval)
9734 {
9735   UNUSED(refval);
9736 }
9737 
9738 
gribSetRefSP(float refval)9739 void gribSetRefSP(float refval)
9740 {
9741   gribSetRefDP((double) refval);
9742 }
9743 
9744 
gribSetValueCheck(int vcheck)9745 void gribSetValueCheck(int vcheck)
9746 {
9747   UNUSED(vcheck);
9748 }
9749 #include <string.h>
9750 #include <math.h>
9751 
9752 
9753 
gribPrintSec0(int * isec0)9754 void gribPrintSec0(int *isec0)
9755 {
9756   /*
9757 
9758     Print the information in the Indicator
9759     Section (Section 0) of decoded GRIB data.
9760 
9761     Input Parameters:
9762 
9763        isec0 - Array of decoded integers from Section 0
9764 
9765 
9766     Converted from EMOS routine GRPRS0.
9767 
9768        Uwe Schulzweida   MPIfM   01/04/2001
9769 
9770   */
9771 
9772   grsdef();
9773 
9774   fprintf(grprsm, " \n");
9775   fprintf(grprsm, " Section 0 - Indicator Section.       \n");
9776   fprintf(grprsm, " -------------------------------------\n");
9777   fprintf(grprsm, " Length of GRIB message (octets).     %9d\n", ISEC0_GRIB_Len);
9778   fprintf(grprsm, " GRIB Edition Number.                 %9d\n", ISEC0_GRIB_Version);
9779 }
9780 
gribPrintSec1(int * isec0,int * isec1)9781 void gribPrintSec1(int *isec0, int *isec1)
9782 {
9783   /*
9784 
9785     Print the information in the Product Definition
9786     Section (Section 1) of decoded GRIB data.
9787 
9788     Input Parameters:
9789 
9790        isec0 - Array of decoded integers from Section 0
9791 
9792        isec1 - Array of decoded integers from Section 1
9793 
9794     Comments:
9795 
9796        When decoding data from Experimental Edition or Edition 0,
9797        routine GRIBEX adds the additional fields available in
9798        Edition 1.
9799 
9800 
9801     Converted from EMOS routine GRPRS1.
9802 
9803        Uwe Schulzweida   MPIfM   01/04/2001
9804 
9805   */
9806 
9807   int iprev, icurr, ioffset;
9808   int ibit, ierr, iout, iyear;
9809   int jloop, jiloop;
9810   float value;
9811 
9812   char hversion[9];
9813   /*
9814   char hfirst[121], hsecond[121], hthird[121], hfourth[121];
9815   */
9816 
9817   grsdef();
9818 
9819   /*
9820     -----------------------------------------------------------------
9821     Section 0 . Print required information.
9822     -----------------------------------------------------------------
9823   */
9824 
9825   fprintf(grprsm, " \n");
9826   fprintf(grprsm, " Section 1 - Product Definition Section.\n");
9827   fprintf(grprsm, " ---------------------------------------\n");
9828 
9829   fprintf(grprsm, " Code Table 2 Version Number.         %9d\n", isec1[0]);
9830   fprintf(grprsm, " Originating centre identifier.       %9d\n", isec1[1]);
9831   fprintf(grprsm, " Model identification.                %9d\n", isec1[2]);
9832   fprintf(grprsm, " Grid definition.                     %9d\n", isec1[3]);
9833 
9834   ibit = 8;
9835   prtbin(isec1[4], ibit, &iout, &ierr);
9836   fprintf(grprsm, " Flag (Code Table 1)                   %8.8d\n", iout);
9837   fprintf(grprsm, " Parameter identifier (Code Table 2). %9d\n", isec1[5]);
9838 
9839   /*
9840       IERR = CHKTAB2(ISEC1,HFIRST,HSECOND,HTHIRD,HFOURTH)
9841       IF( IERR .EQ. 0 ) THEN
9842        DO JLOOP = 121, 1, -1
9843           IF( HSECOND(JLOOP:JLOOP).NE.' ' ) THEN
9844             IOFFSET = JLOOP
9845             GOTO 110
9846           ENDIF
9847         ENDDO
9848         GOTO 120
9849  110    CONTINUE
9850         WRITE(*,'(2H ",A,1H")') HSECOND(1:IOFFSET)
9851  120    CONTINUE
9852       ENDIF
9853   */
9854 
9855   if ( isec1[5] != 127 )
9856     {
9857       fprintf(grprsm, " Type of level (Code Table 3).        %9d\n", isec1[6]);
9858       fprintf(grprsm, " Value 1 of level (Code Table 3).     %9d\n", isec1[7]);
9859       fprintf(grprsm, " Value 2 of level (Code Table 3).     %9d\n", isec1[8]);
9860     }
9861   else
9862     {
9863       fprintf(grprsm, " Satellite identifier.                %9d\n", isec1[6]);
9864       fprintf(grprsm, " Spectral band.                       %9d\n", isec1[7]);
9865     }
9866 
9867   iyear = isec1[9];
9868   if ( iyear != 255 )
9869     {
9870       int date, time;
9871       /* iyear  = ((isec1[20]-1)*100 + isec1[9]); */
9872       gribDateTime(isec1, &date, &time);
9873       iyear = date/10000;
9874       fprintf(grprsm, " Year of reference time of data.      %9d  (%4d)\n", isec1[9], iyear);
9875     }
9876   else
9877     {
9878       fprintf(grprsm, " Year of reference time of data MISSING  (=255)\n");
9879     }
9880 
9881   fprintf(grprsm, " Month of reference time of data.     %9d\n", isec1[10]);
9882   fprintf(grprsm, " Day of reference time of data.       %9d\n", isec1[11]);
9883   fprintf(grprsm, " Hour of reference time of data.      %9d\n", isec1[12]);
9884   fprintf(grprsm, " Minute of reference time of data.    %9d\n", isec1[13]);
9885   fprintf(grprsm, " Time unit (Code Table 4).            %9d\n", isec1[14]);
9886   fprintf(grprsm, " Time range one.                      %9d\n", isec1[15]);
9887   fprintf(grprsm, " Time range two.                      %9d\n", isec1[16]);
9888   fprintf(grprsm, " Time range indicator (Code Table 5)  %9d\n", isec1[17]);
9889   fprintf(grprsm, " Number averaged.                     %9d\n", isec1[18]);
9890   fprintf(grprsm, " Number missing from average.         %9d\n", isec1[19]);
9891   /*
9892      All ECMWF data in GRIB Editions before Edition 1 is decoded
9893      as 20th century data. Other centres are decoded as missing.
9894   */
9895   if ( isec0[1] < 1 && isec1[1] != 98 )
9896     fprintf(grprsm, " Century of reference time of data.   Not given\n");
9897   else
9898     fprintf(grprsm, " Century of reference time of data.   %9d\n", isec1[20]);
9899 
9900   /*   Print sub-centre  */
9901   fprintf(grprsm, " Sub-centre identifier.               %9d\n", ISEC1_SubCenterID);
9902 
9903   /*   Decimal scale factor  */
9904   fprintf(grprsm, " Units decimal scaling factor.        %9d\n", isec1[22]);
9905 
9906   /*
9907     -----------------------------------------------------------------
9908     Section 1 . Print local DWD information.
9909     -----------------------------------------------------------------
9910   */
9911   if ( (ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250) &&
9912        (isec1[36] == 253     || isec1[36] == 254) )
9913     {
9914       fprintf(grprsm, " DWD local usage identifier.          %9d\n", isec1[36]);
9915       if ( isec1[36] == 253 )
9916 	fprintf(grprsm, " (Database labelling and ensemble forecast)\n");
9917       if ( isec1[36] == 254 )
9918 	fprintf(grprsm, " (Database labelling)\n");
9919 
9920       fprintf(grprsm, " Year of database entry                     %3d  (%4d)\n", isec1[43], 1900+isec1[43]);
9921       fprintf(grprsm, " Month of database entry                    %3d\n", isec1[44]);
9922       fprintf(grprsm, " Day of database entry                      %3d\n", isec1[45]);
9923       fprintf(grprsm, " Hour of database entry                     %3d\n", isec1[46]);
9924       fprintf(grprsm, " Minute of database entry                   %3d\n", isec1[47]);
9925       fprintf(grprsm, " DWD experiment number                %9d\n",isec1[48]);
9926       fprintf(grprsm, " DWD run type                         %9d\n",isec1[49]);
9927       if ( isec1[36] == 253 )
9928 	{
9929 	  fprintf(grprsm, " User id                              %9d\n",isec1[50]);
9930 	  fprintf(grprsm, " Experiment identifier                %9d\n",isec1[51]);
9931 	  fprintf(grprsm, " Ensemble identification type         %9d\n",isec1[52]);
9932 	  fprintf(grprsm, " Number of ensemble members           %9d\n",isec1[53]);
9933 	  fprintf(grprsm, " Actual number of ensemble member     %9d\n",isec1[54]);
9934 	  fprintf(grprsm, " Model version                            %2d.%2.2d\n",isec1[55],isec1[56]);
9935 	}
9936     }
9937 
9938   /*
9939     -----------------------------------------------------------------
9940     Section 2 . Print local ECMWF information.
9941     -----------------------------------------------------------------
9942   */
9943   /*
9944     Regular MARS labelling, or reformatted Washington EPS products.
9945   */
9946   if ( (ISEC1_CenterID    == 98 && ISEC1_LocalFLag ==  1) ||
9947        (ISEC1_SubCenterID == 98 && ISEC1_LocalFLag ==  1) ||
9948        (ISEC1_CenterID    ==  7 && ISEC1_SubCenterID == 98) )
9949     {
9950       /*   Parameters common to all definitions.  */
9951 
9952       fprintf(grprsm, " ECMWF local usage identifier.        %9d\n", isec1[36]);
9953       if ( isec1[36] == 1 )
9954 	fprintf(grprsm, " (Mars labelling or ensemble forecast)\n");
9955       if ( isec1[36] == 2 )
9956         fprintf(grprsm, " (Cluster means and standard deviations)\n");
9957       if ( isec1[36] == 3 )
9958         fprintf(grprsm, " (Satellite image data)\n");
9959       if ( isec1[36] == 4 )
9960         fprintf(grprsm, " (Ocean model data)\n");
9961       if ( isec1[36] == 5 )
9962         fprintf(grprsm, " (Forecast probability data)\n");
9963       if ( isec1[36] == 6 )
9964         fprintf(grprsm, " (Surface temperature data)\n");
9965       if ( isec1[36] == 7 )
9966         fprintf(grprsm, " (Sensitivity data)\n");
9967       if ( isec1[36] == 8 )
9968         fprintf(grprsm, " (ECMWF re-analysis data)\n");
9969       if ( isec1[36] == 9 )
9970         fprintf(grprsm, " (Singular vectors and ensemble perturbations)\n");
9971       if ( isec1[36] == 10 )
9972         fprintf(grprsm, " (EPS tubes)\n");
9973       if ( isec1[36] == 11 )
9974         fprintf(grprsm, " (Supplementary data used by analysis)\n");
9975       if ( isec1[36] == 13 )
9976         fprintf(grprsm, " (Wave 2D spectra direction and frequency)\n");
9977 
9978       fprintf(grprsm, " Class.                               %9d\n", isec1[37]);
9979       fprintf(grprsm, " Type.                                %9d\n", isec1[38]);
9980       fprintf(grprsm, " Stream.                              %9d\n", isec1[39]);
9981       sprintf(hversion, "%4s", (char*)&isec1[40]); hversion[4] = 0;
9982       fprintf(grprsm, " Version number or Experiment identifier.  %4s\n", hversion);
9983       /*
9984 	ECMWF Local definition 1.
9985 	(MARS labelling or ensemble forecast data)
9986       */
9987       if ( isec1[36] == 1 )
9988 	{
9989 	  fprintf(grprsm, " Forecast number.                     %9d\n", isec1[41]);
9990 	  if ( isec1[39] != 1090 )
9991 	    fprintf(grprsm, " Total number of forecasts.           %9d\n", isec1[42]);
9992 
9993 	  return;
9994 	}
9995       /*
9996 	ECMWF Local definition 2.
9997 	(Cluster means and standard deviations)
9998       */
9999       if ( isec1[36] == 2 )
10000 	{
10001 	  fprintf(grprsm, " Cluster number.                      %9d\n", isec1[41]);
10002 	  fprintf(grprsm, " Total number of clusters.            %9d\n", isec1[42]);
10003 	  fprintf(grprsm, " Clustering method.                   %9d\n", isec1[43]);
10004 	  fprintf(grprsm, " Start time step when clustering.     %9d\n", isec1[44]);
10005 	  fprintf(grprsm, " End time step when clustering.       %9d\n", isec1[45]);
10006 	  fprintf(grprsm, " Northern latitude of domain.         %9d\n", isec1[46]);
10007 	  fprintf(grprsm, " Western longitude of domain.         %9d\n", isec1[47]);
10008 	  fprintf(grprsm, " Southern latitude of domain.         %9d\n", isec1[48]);
10009 	  fprintf(grprsm, " Eastern longitude of domain.         %9d\n", isec1[49]);
10010 	  fprintf(grprsm, " Operational forecast in cluster      %9d\n", isec1[50]);
10011 	  fprintf(grprsm, " Control forecast in cluster          %9d\n", isec1[51]);
10012 	  fprintf(grprsm, " Number of forecasts in cluster.      %9d\n", isec1[52]);
10013 
10014 	  for (jloop = 0; jloop < isec1[52]; jloop++)
10015 	    fprintf(grprsm, " Forecast number                      %9d\n", isec1[jloop+53]);
10016 
10017 	  return;
10018 	}
10019       /*
10020 	ECMWF Local definition 3.
10021 	(Satellite image data)
10022       */
10023       if ( isec1[36] == 3 )
10024 	{
10025 	  fprintf(grprsm, " Satellite spectral band.             %9d\n", isec1[41]);
10026 	  fprintf(grprsm, " Function code.                       %9d\n", isec1[42]);
10027 	  return;
10028 	}
10029       /*
10030 	ECMWF Local definition 4.
10031 	(Ocean model data)
10032       */
10033       if ( isec1[36] == 4 )
10034 	{
10035 	  fprintf(grprsm, " Satellite spectral band.             %9d\n", isec1[41]);
10036 	  if ( isec1[39] != 1090 )
10037 	    fprintf(grprsm, " Function code.                       %9d\n", isec1[42]);
10038 	  fprintf(grprsm, " Coordinate structure definition.\n");
10039 	  fprintf(grprsm, " Fundamental spatial reference system.%9d\n", isec1[43]);
10040 	  fprintf(grprsm, " Fundamental time reference.          %9d\n", isec1[44]);
10041 	  fprintf(grprsm, " Space unit flag.                     %9d\n", isec1[45]);
10042 	  fprintf(grprsm, " Vertical coordinate definition.      %9d\n", isec1[46]);
10043 	  fprintf(grprsm, " Horizontal coordinate definition.    %9d\n", isec1[47]);
10044 	  fprintf(grprsm, " Time unit flag.                      %9d\n", isec1[48]);
10045 	  fprintf(grprsm, " Time coordinate definition.          %9d\n", isec1[49]);
10046 	  fprintf(grprsm, " Position definition.     \n");
10047 	  fprintf(grprsm, " Mixed coordinate field flag.         %9d\n", isec1[50]);
10048 	  fprintf(grprsm, " Coordinate 1 flag.                   %9d\n", isec1[51]);
10049 	  fprintf(grprsm, " Averaging flag.                      %9d\n", isec1[52]);
10050 	  fprintf(grprsm, " Position of level 1.                 %9d\n", isec1[53]);
10051 	  fprintf(grprsm, " Position of level 2.                 %9d\n", isec1[54]);
10052 	  fprintf(grprsm, " Coordinate 2 flag.                   %9d\n", isec1[55]);
10053 	  fprintf(grprsm, " Averaging flag.                      %9d\n", isec1[56]);
10054 	  fprintf(grprsm, " Position of level 1.                 %9d\n", isec1[57]);
10055 	  fprintf(grprsm, " Position of level 2.                 %9d\n", isec1[58]);
10056 	  fprintf(grprsm, " Grid Definition.\n");
10057 	  fprintf(grprsm, " Coordinate 3 flag (x-axis)           %9d\n", isec1[59]);
10058 	  fprintf(grprsm, " Coordinate 4 flag (y-axis)           %9d\n", isec1[60]);
10059 	  fprintf(grprsm, " Coordinate 4 of first grid point.    %9d\n", isec1[61]);
10060 	  fprintf(grprsm, " Coordinate 3 of first grid point.    %9d\n", isec1[62]);
10061 	  fprintf(grprsm, " Coordinate 4 of last grid point.     %9d\n", isec1[63]);
10062 	  fprintf(grprsm, " Coordinate 3 of last grid point.     %9d\n", isec1[64]);
10063 	  fprintf(grprsm, " i - increment.                       %9d\n", isec1[65]);
10064 	  fprintf(grprsm, " j - increment.                       %9d\n", isec1[66]);
10065 	  fprintf(grprsm, " Flag for irregular grid coordinates. %9d\n", isec1[67]);
10066 	  fprintf(grprsm, " Flag for normal or staggered grids.  %9d\n", isec1[68]);
10067 	  fprintf(grprsm, " Further information.\n");
10068 	  fprintf(grprsm, " Further information flag.            %9d\n", isec1[69]);
10069 	  fprintf(grprsm, " Auxiliary information.\n");
10070 	  fprintf(grprsm, " No. entries in horizontal coordinate %9d\n", isec1[70]);
10071 	  fprintf(grprsm, " No. entries in mixed coordinate defn.%9d\n", isec1[71]);
10072 	  fprintf(grprsm, " No. entries in grid coordinate list. %9d\n", isec1[72]);
10073 	  fprintf(grprsm, " No. entries in auxiliary array.      %9d\n", isec1[73]);
10074 	  /*
10075 	    Horizontal coordinate supplement.
10076 	  */
10077 	  fprintf(grprsm, " Horizontal coordinate supplement.\n");
10078 	  if ( isec1[70] == 0 )
10079 	    {
10080 	      fprintf(grprsm, "(None).\n");
10081 	    }
10082 	  else
10083 	    {
10084 	      fprintf(grprsm, "Number of items = %d\n", isec1[70]);
10085 	      for (jloop = 0; jloop < isec1[70]; jloop++)
10086 		fprintf(grprsm, "         %12d\n", isec1[74+jloop]);
10087 	    }
10088 	  /*
10089 	    Mixed coordinate definition.
10090 	  */
10091 	  fprintf(grprsm, " Mixed coordinate definition.\n");
10092 	  if ( isec1[71] == 0 )
10093 	    {
10094 	      fprintf(grprsm, "(None).\n");
10095 	    }
10096 	  else
10097 	    {
10098 	      fprintf(grprsm, "Number of items = %d\n", isec1[71]);
10099 	      ioffset = 74 + isec1[70];
10100 	      for (jloop = 0; jloop < isec1[71]; jloop++)
10101 		fprintf(grprsm, "         %12d\n", isec1[ioffset+jloop]);
10102 	    }
10103 	  /*
10104 	    Grid coordinate list.
10105 	  */
10106 	  fprintf(grprsm, " Grid coordinate list. \n");
10107 	  if ( isec1[72] == 0 )
10108 	    {
10109 	      fprintf(grprsm, "(None).\n");
10110 	    }
10111 	  else
10112 	    {
10113 	      fprintf(grprsm, "Number of items = %d\n", isec1[72]);
10114 	      ioffset = 74 + isec1[70] + isec1[71];
10115 	      for (jloop = 0; jloop < isec1[72]; jloop++)
10116 		fprintf(grprsm, "         %12d\n", isec1[ioffset+jloop]);
10117 	    }
10118 	  /*
10119 	    Auxiliary array.
10120 	  */
10121 	  fprintf(grprsm, " Auxiliary array.      \n");
10122 	  if ( isec1[73] == 0 )
10123 	    {
10124 	      fprintf(grprsm, "(None).\n");
10125 	    }
10126 	  else
10127 	    {
10128 	      fprintf(grprsm, "Number of items = %d\n", isec1[73]);
10129 	      ioffset = 74 + isec1[70] + isec1[71] + isec1[72];
10130 	      for (jloop = 0; jloop < isec1[73]; jloop++)
10131 		fprintf(grprsm, "         %12d\n", isec1[ioffset+jloop]);
10132 	    }
10133 	  /*
10134 	    Post-auxiliary array.
10135 	  */
10136 	  fprintf(grprsm, " Post-auxiliary array. \n");
10137 	  ioffset = 74 + isec1[70] + isec1[71] + isec1[72] + isec1[73];
10138 	  if ( isec1[ioffset] == 0 )
10139 	    {
10140 	      fprintf(grprsm, "(None).\n");
10141 	    }
10142 	  else
10143 	    {
10144 	      fprintf(grprsm, "Number of items = %d\n", isec1[ioffset]);
10145 	      for (jloop = 1; jloop < isec1[ioffset]; jloop++)
10146 		fprintf(grprsm, "         %12d\n", isec1[ioffset+jloop]);
10147 	    }
10148 
10149 	  return;
10150 	}
10151       /*
10152 	ECMWF Local definition 5.
10153 	(Forecast probability data)
10154       */
10155       if ( isec1[36] == 5 )
10156 	{
10157 	  fprintf(grprsm, " Forecast probability number          %9d\n", isec1[41]);
10158 	  fprintf(grprsm, " Total number of forecast probabilities %7d\n", isec1[42]);
10159 	  fprintf(grprsm, " Threshold units decimal scale factor %9d\n", isec1[43]);
10160 	  fprintf(grprsm, " Threshold indicator(1=lower,2=upper,3=both) %2d\n", isec1[44]);
10161 	  if ( isec1[44]  !=  2 )
10162 	    fprintf(grprsm, " Lower threshold value                %9d\n", isec1[45]);
10163 	  if ( isec1[44]  !=  1 )
10164 	    fprintf(grprsm, " Upper threshold value                %9d\n", isec1[46]);
10165 	  return;
10166 	}
10167       /*
10168 	ECMWF Local definition 6.
10169 	(Surface temperature data)
10170       */
10171       if ( isec1[36] == 6 )
10172 	{
10173 	  iyear = isec1[43];
10174 	  if ( iyear > 100 )
10175 	    {
10176 	      if ( iyear < 19000000 ) iyear = iyear + 19000000;
10177 	      fprintf(grprsm, " Date of SST field used               %9d\n", iyear);
10178 	    }
10179 	  else
10180 	    fprintf(grprsm, "Date of SST field used               Not given\n");
10181 	}
10182       if ( isec1[44] == 0 )
10183 	fprintf(grprsm, " Type of SST field (= climatology)    %9d\n", isec1[44]);
10184       if ( isec1[44] == 1 )
10185 	fprintf(grprsm, " Type of SST field (= 1/1 degree)     %9d\n", isec1[44]);
10186       if ( isec1[44] == 2 )
10187 	fprintf(grprsm, " Type of SST field (= 2/2 degree)     %9d\n", isec1[44]);
10188 
10189       fprintf(grprsm, " Number of ICE fields used:           %9d\n", isec1[45]);
10190 
10191       for (jloop = 1; jloop <= isec1[45]; jloop++)
10192 	{
10193 	  iyear = isec1[44+(jloop*2)];
10194 	  if ( iyear > 100 )
10195 	    {
10196               if ( iyear < 19000000 ) iyear = iyear + 19000000;
10197 	      fprintf(grprsm, " Date of ICE field%3d                 %9d\n", jloop, iyear);
10198 	      fprintf(grprsm, " Satellite number (ICE field%3d)      %9d\n", jloop,
10199 		     isec1[45+(jloop*2)]);
10200 	    }
10201 	  else
10202 	    fprintf(grprsm, "Date of SST field used               Not given\n");
10203 	}
10204       /*
10205 	ECMWF Local definition 7.
10206 	(Sensitivity data)
10207       */
10208       if ( isec1[36] == 7 )
10209 	{
10210 	  if ( isec1[38]  ==  51 )
10211 	    fprintf(grprsm, " Forecast number                      %9d\n", isec1[41]);
10212 	  if ( isec1[38]  !=  51 )
10213 	    fprintf(grprsm, " Iteration number                     %9d\n", isec1[41]);
10214 	  if ( isec1[38]  !=  52 )
10215 	    fprintf(grprsm, " Total number of diagnostics          %9d\n", isec1[42]);
10216 	  if ( isec1[38]  ==  52 )
10217 	    fprintf(grprsm, " No.interations in diag. minimisation %9d\n", isec1[42]);
10218 	  fprintf(grprsm, " Domain(0=Global,1=Europe,2=N.Hem.,3=S.Hem.) %2d\n", isec1[43]);
10219 	  fprintf(grprsm, " Diagnostic number                    %9d\n", isec1[44]);
10220 	}
10221       /*
10222 	ECMWF Local definition 8.
10223 	(ECMWF re-analysis data)
10224       */
10225       if ( isec1[36] == 8 )
10226 	{
10227 	  if ( (isec1[39] == 1043) ||
10228 	       (isec1[39] == 1070) ||
10229 	       (isec1[39] == 1071) )
10230 	    {
10231 	      fprintf(grprsm, " Interval between reference times     %9d\n", isec1[41]);
10232 	      for (jloop = 43; jloop <= 54; jloop++)
10233 		{
10234 		  jiloop = jloop + 8;
10235 		  fprintf(grprsm, " ERA section 1 octet %2d.              %9d\n",
10236 			 jiloop, isec1[jloop-1]);
10237 		}
10238 	    }
10239 	  else
10240 	    {
10241 	      for (jloop = 42; jloop <= 54; jloop++)
10242 		{
10243 		  jiloop = jloop + 8;
10244 		  fprintf(grprsm, " ERA section 1 octet %2d.              %9d\n",
10245 			 jiloop, isec1[jloop-1]);
10246 		}
10247 	    }
10248 	  return;
10249 	}
10250 
10251       if ( isec1[38] > 4  && isec1[38] < 9 )
10252 	{
10253 	  fprintf(grprsm, " Simulation number.                   %9d\n", isec1[41]);
10254 	  fprintf(grprsm, " Total number of simulations.         %9d\n", isec1[42]);
10255 	}
10256       /*
10257 	ECMWF Local definition 9.
10258 	(Singular vectors and ensemble perturbations)
10259       */
10260       if ( isec1[36] == 9 )
10261 	{
10262 	  if ( isec1[38] == 60 )
10263 	    fprintf(grprsm, " Perturbed ensemble forecast number   %9d\n", isec1[41]);
10264 	  if ( isec1[38] == 61 )
10265 	    fprintf(grprsm, " Initial state perturbation number    %9d\n", isec1[41]);
10266 	  if ( isec1[38] == 62 )
10267 	    fprintf(grprsm, " Singular vector number               %9d\n", isec1[41]);
10268 	  if ( isec1[38] == 62 )
10269 	    {
10270 	      fprintf(grprsm, " Number of iterations                 %9d\n", isec1[42]);
10271 	      fprintf(grprsm, " Number of singular vectors computed  %9d\n", isec1[43]);
10272 	      fprintf(grprsm, " Norm used at initial time            %9d\n", isec1[44]);
10273 	      fprintf(grprsm, " Norm used at final time              %9d\n", isec1[45]);
10274 	      fprintf(grprsm, " Multiplication factor                %9d\n", isec1[46]);
10275     	      fprintf(grprsm, " Latitude of north-west corner        %9d\n", isec1[47]);
10276     	      fprintf(grprsm, " Longitude of north-west corner       %9d\n", isec1[48]);
10277 	      fprintf(grprsm, " Latitude of south-east corner        %9d\n", isec1[49]);
10278 	      fprintf(grprsm, " Longitude of south-east corner       %9d\n", isec1[50]);
10279 	      fprintf(grprsm, " Accuracy                             %9d\n", isec1[51]);
10280 	      fprintf(grprsm, " Number of singular vectors evolved   %9d\n", isec1[52]);
10281 	      fprintf(grprsm, " Ritz number one                      %9d\n", isec1[53]);
10282 	      fprintf(grprsm, " Ritz number two                      %9d\n", isec1[54]);
10283 	    }
10284 	}
10285       /*
10286 	ECMWF Local definition 10.
10287 	(EPS tubes)
10288       */
10289       if ( isec1[36] == 10 )
10290 	{
10291 	  fprintf(grprsm, " Tube number                          %9d\n", isec1[41]);
10292           fprintf(grprsm, " Total number of tubes                %9d\n", isec1[42]);
10293           fprintf(grprsm, " Central cluster definition           %9d\n", isec1[43]);
10294           fprintf(grprsm, " Parameter                            %9d\n", isec1[44]);
10295           fprintf(grprsm, " Type of level                        %9d\n", isec1[45]);
10296           fprintf(grprsm, " Northern latitude of domain of tubing%9d\n", isec1[46]);
10297           fprintf(grprsm, " Western longitude of domain of tubing%9d\n", isec1[47]);
10298           fprintf(grprsm, " Southern latitude of domain of tubing%9d\n", isec1[48]);
10299           fprintf(grprsm, " Eastern longitude of domain of tubing%9d\n", isec1[49]);
10300           fprintf(grprsm, " Tube number of operational forecast  %9d\n", isec1[50]);
10301           fprintf(grprsm, " Tube number of control forecast      %9d\n", isec1[51]);
10302           fprintf(grprsm, " Height/pressure of level             %9d\n", isec1[52]);
10303           fprintf(grprsm, " Reference step                       %9d\n", isec1[53]);
10304           fprintf(grprsm, " Radius of central cluster            %9d\n", isec1[54]);
10305           fprintf(grprsm, " Ensemble standard deviation          %9d\n", isec1[55]);
10306           fprintf(grprsm, " Dist.of tube extreme to ensemble mean%9d\n", isec1[56]);
10307           fprintf(grprsm, " Number of forecasts in the tube      %9d\n", isec1[57]);
10308 
10309           fprintf(grprsm, " List of ensemble forecast numbers:\n");
10310           for (jloop = 1; jloop <=  isec1[57]; jloop++)
10311 	    fprintf(grprsm, "    %9d\n", isec1[57+jloop]);
10312 	}
10313       /*
10314 	ECMWF Local definition 11.
10315 	(Supplementary data used by the analysis)
10316       */
10317       if ( isec1[36] == 11 )
10318 	{
10319 	  fprintf(grprsm, " Details of analysis which used the supplementary data:\n");
10320 	  fprintf(grprsm, "   Class                              %9d\n", isec1[41]);
10321 	  fprintf(grprsm, "   Type                               %9d\n", isec1[42]);
10322 	  fprintf(grprsm, "   Stream                             %9d\n", isec1[43]);
10323 	  /*
10324 	  sprintf(hversion, "%8d", isec1[44]);
10325 	  fprintf(grprsm, "   Version number/experiment identifier:   %4s\n", &hversion[4]);
10326 	  */
10327 	  iyear = isec1[45];
10328 	  if ( iyear > 50 )
10329 	    iyear = iyear + 1900;
10330 	  else
10331 	    iyear = iyear + 2000;
10332 
10333 	  fprintf(grprsm, "   Year                               %9d\n", iyear);
10334 	  fprintf(grprsm, "   Month                              %9d\n", isec1[46]);
10335 	  fprintf(grprsm, "   Day                                %9d\n", isec1[47]);
10336 	  fprintf(grprsm, "   Hour                               %9d\n", isec1[48]);
10337 	  fprintf(grprsm, "   Minute                             %9d\n", isec1[49]);
10338 	  fprintf(grprsm, "   Century                            %9d\n", isec1[50]);
10339 	  fprintf(grprsm, "   Originating centre                 %9d\n", isec1[51]);
10340 	  fprintf(grprsm, "   Sub-centre                         %9d\n", isec1[52]);
10341 	}
10342       /*
10343 	ECMWF Local definition 12.
10344       */
10345       if ( isec1[36] == 12 )
10346 	{
10347 	  fprintf(grprsm, " (Mean, average, etc)\n");
10348           fprintf(grprsm, " Start date of the period              %8d\n", isec1[41]);
10349           fprintf(grprsm, " Start time of the period                  %4.4d\n", isec1[42]);
10350           fprintf(grprsm, " Finish date of the period             %8d\n", isec1[43]);
10351           fprintf(grprsm, " Finish time of the period                 %4.4d\n", isec1[44]);
10352           fprintf(grprsm, " Verifying date of the period          %8d\n", isec1[45]);
10353           fprintf(grprsm, " Verifying time of the period              %4.4d\n", isec1[46]);
10354           fprintf(grprsm, " Code showing method                   %8d\n", isec1[47]);
10355           fprintf(grprsm, " Number of different time intervals used  %5d\n", isec1[48]);
10356           fprintf(grprsm, " List of different time intervals used:\n");
10357           iprev  = isec1[49];
10358           unsigned icount = 0;
10359           for (jloop = 1; jloop <= isec1[48]; jloop++)
10360 	    {
10361 	      icurr = isec1[48+jloop];
10362 	      if ( icurr != iprev )
10363 		{
10364 		  if ( icount == 1 )
10365 		    fprintf(grprsm, "  - interval %5.4d used       once\n", iprev);
10366 		  if ( icount == 2 )
10367 		    fprintf(grprsm, "  - interval %5.4d used       twice\n", iprev);
10368 		  if ( icount > 2 )
10369 		    fprintf(grprsm, "  - interval %5.4d used %5u times\n",  iprev, icount);
10370 		  iprev  = icurr;
10371 		  icount = 1;
10372 		}
10373 	      else
10374 		icount = icount + 1;
10375 	    }
10376 	  if ( icount == 1 )
10377 	    fprintf(grprsm, "  - interval %5.4d used       once\n", iprev);
10378 	  if ( icount == 2 )
10379 	    fprintf(grprsm, "  - interval %5.4d used       twice\n", iprev);
10380 	  if ( icount > 2 )
10381 	    fprintf(grprsm, "  - interval %5.4d used %5u times\n",  iprev, icount);
10382 	}
10383       /*
10384 	ECMWF Local definition 13.
10385 	(Wave 2D spectra direction and frequency)
10386       */
10387       if ( isec1[36] == 13 )
10388 	{
10389           fprintf(grprsm, " Direction number                     %9d\n", isec1[43]);
10390 	  fprintf(grprsm, " Frequency number                     %9d\n", isec1[44]);
10391 	  fprintf(grprsm, " Total number of directions           %9d\n", isec1[45]);
10392 	  fprintf(grprsm, " Total number of frequencies          %9d\n", isec1[46]);
10393 	  fprintf(grprsm, " Scale factor applied to directions   %9d\n", isec1[47]);
10394 	  fprintf(grprsm, " Scale factor applied to frequencies  %9d\n", isec1[48]);
10395 	  fprintf(grprsm, " List of directions:\n");
10396           for (jloop = 1; jloop <= isec1[45]; jloop++)
10397             {
10398 	      value = (float)(isec1[48+jloop])/(float)(isec1[47]);
10399 	      if ( isec1[43] == jloop )
10400 		fprintf(grprsm, " %2.2d:%15.7f   <-- this field value\n",  jloop, value);
10401 	      else
10402 		fprintf(grprsm, "%2.2d:%15.7f\n",  jloop, value);
10403             }
10404 	  fprintf(grprsm, " List of frequencies:\n");
10405           for (jloop = 1; jloop <= isec1[46]; jloop++)
10406 	    {
10407 	      value = (float)(isec1[48+isec1[45]+jloop])/(float)(isec1[48]);
10408 	      if ( isec1[44] == jloop )
10409 		fprintf(grprsm, " %2.2d:%15.7f   <-- this field value\n",  jloop, value);
10410 	      else
10411 		fprintf(grprsm, "%2.2d:%15.7f\n",  jloop, value);
10412 
10413 	      if ( isec1[49+isec1[45]+isec1[46]] != 0 )
10414 		{
10415 		  fprintf(grprsm, " System number (65535 = missing)      %9d\n",
10416 			 isec1[49+isec1[45]+isec1[46]]);
10417 		  fprintf(grprsm, " Method number (65535 = missing)      %9d\n",
10418 			 isec1[50+isec1[45]+isec1[46]]);
10419 		}
10420 	    }
10421 	  /*
10422 	    ECMWF Local definition 14.
10423 	    (Brightness temperature)
10424 	  */
10425 	  if ( isec1[36] == 14 )
10426 	    {
10427 	      fprintf(grprsm, " Channel number                       %9d\n", isec1[43]);
10428 	      fprintf(grprsm, " Scale factor applied to frequencies  %9d\n", isec1[44]);
10429 	      fprintf(grprsm, " Total number of frequencies          %9d\n", isec1[45]);
10430 	      fprintf(grprsm, " List of frequencies:\n");
10431               for (jloop = 1; jloop <= isec1[45]; jloop++)
10432 		{
10433 		  value = (float)(isec1[45+jloop])/(float)(isec1[44]);
10434 		  if ( isec1[43] == jloop )
10435 		    fprintf(grprsm, " %3d:%15.9f   <-- this channel\n", jloop, value);
10436 		  else
10437 		    fprintf(grprsm, " %3d:%15.9f\n", jloop, value);
10438 		}
10439 	    }
10440 	  /*
10441 	    ECMWF Local definition 15.
10442 	    (Ocean ensemble seasonal forecast)
10443 	  */
10444 	  if ( isec1[36] == 15 )
10445 	    {
10446 	      fprintf(grprsm, " Ensemble member number               %9d\n", isec1[41]);
10447 	      fprintf(grprsm, " System number                        %9d\n", isec1[42]);
10448 	      fprintf(grprsm, " Method number                        %9d\n", isec1[43]);
10449 	    }
10450 	  /*
10451 	    ECMWF Local definition 16.
10452 	    (Seasonal forecast monthly mean atmosphere data)
10453 	  */
10454         if ( isec1[36] == 16 )
10455 	  {
10456 	    fprintf(grprsm, " Ensemble member number               %9d\n", isec1[41]);
10457 	    fprintf(grprsm, " System number                        %9d\n", isec1[43]);
10458 	    fprintf(grprsm, " Method number                        %9d\n", isec1[44]);
10459 	    fprintf(grprsm, " Verifying month                      %9d\n", isec1[45]);
10460 	    fprintf(grprsm, " Averaging period                     %9d\n", isec1[46]);
10461 	  }
10462 	/*
10463 	  ECMWF Local definition 17.
10464 	  (Sst or sea-ice used by analysis)
10465 	*/
10466         if ( isec1[36] == 17 )
10467 	  {
10468 	    iyear = isec1[43];
10469 	    if ( iyear > 100 )
10470 	      {
10471 		if ( iyear < 19000000 ) iyear = iyear + 19000000;
10472 		fprintf(grprsm, " Date of sst/ice field used           %9d\n", iyear);
10473 	      }
10474 	    else
10475               fprintf(grprsm, " Date of sst/ice field used           Not given\n");
10476 
10477 	    if ( isec1[44] == 0 )
10478 	      fprintf(grprsm, " Type of sst/ice field (= climatology)%9d\n", isec1[44]);
10479 	    if ( isec1[44] == 1 )
10480 	      fprintf(grprsm, " Type of sst/ice field (= 1/1 degree) %9d\n", isec1[44]);
10481 	    if ( isec1[44] == 2 )
10482 	      fprintf(grprsm, " Type of sst/ice field (= 2/2 degree) %9d\n", isec1[44]);
10483 
10484 	    fprintf(grprsm, " Number of ICE fields used:           %9d\n", isec1[45]);
10485 
10486 	    for (jloop = 1; jloop < isec1[45]; jloop++)
10487 	      {
10488 		iyear = isec1[44+(jloop*2)];
10489 		if ( iyear > 100 )
10490 		  {
10491 		    if ( iyear < 19000000 ) iyear = iyear + 19000000;
10492 		    fprintf(grprsm, " Date of ICE field%3d                 %9d\n", jloop,
10493 			   iyear);
10494 		    fprintf(grprsm, " Satellite number (ICE field%3d)      %9d\n", jloop,
10495 			   isec1[45+(jloop*2)]);
10496 		  }
10497 		else
10498 		  fprintf(grprsm, "Date of sst/ice field used           Not given\n");
10499 	      }
10500 	  }
10501 	}
10502     }
10503   /*
10504     -----------------------------------------------------------------
10505     Section 3 . Print Washington ensemble product information.
10506     -----------------------------------------------------------------
10507   */
10508   /*
10509     Washington EPS products (but not reformatted Washington EPS
10510     products.
10511   */
10512   if ( (isec1[1] == 7 && isec1[23] == 1) && (! (ISEC1_SubCenterID == 98)) )
10513     {
10514       /*   CALL KWPRS1 (iSEC0,iSEC1)*/
10515     }
10516   /*
10517     -----------------------------------------------------------------
10518     Section 4 . Print local MPIM information.
10519     -----------------------------------------------------------------
10520   */
10521   if (isec1[ 1] == 252 && isec1[36] == 1)
10522     {
10523       fprintf(grprsm, " MPIM local usage identifier.         %9d\n", isec1[36]);
10524       fprintf(grprsm, " Type of ensemble forecast            %9d\n", isec1[37]);
10525       fprintf(grprsm, " Individual ensemble member           %9d\n", isec1[38]);
10526       fprintf(grprsm, " Number of forecasts in ensemble      %9d\n", isec1[39]);
10527     }
10528 }
10529 
printQuasi(int * isec2)10530 static void printQuasi(int *isec2)
10531 {
10532   /*
10533 
10534     Print the qusai-regular information in the Grid Description
10535     Section (Section 2) of decoded GRIB data.
10536 
10537     Input Parameters:
10538 
10539        isec2 - Array of decoded integers from Section 2.
10540 
10541     Comments:
10542 
10543        Only data representation types catered for are Gaussian
10544        grid, latitude/longitude grid, Spherical Harmonics,
10545        Polar stereographic and Space view perspective.
10546 
10547     Converted from EMOS routine PTQUASI.
10548 
10549        Uwe Schulzweida   MPIfM   01/04/2001
10550 
10551   */
10552 
10553   char yout[64];
10554 
10555   /*
10556     -----------------------------------------------------------------
10557     Section 1. Print quasi-grid data.
10558     -----------------------------------------------------------------
10559   */
10560   // See if scanning is north->south or south->north
10561   fprintf(grprsm, "  Number of points along a parallel varies.\n");
10562 
10563   int ntos = ( fmod((double) isec2[10], 128.) < 64 );
10564 
10565   if ( ntos )
10566     fprintf(grprsm, "  Number of points.   Parallel. (North to South)\n");
10567   else
10568     fprintf(grprsm, "  Number of points.   Parallel. (South to North)\n");
10569 
10570   // Display number of points for each latitude
10571   int latcnt  = isec2[2];
10572   int nextlat = 0;
10573   memset(yout, ' ', (size_t) 11);
10574 
10575   for (int j = 0; j < latcnt; j++)
10576     {
10577       nextlat = nextlat + 1;
10578       sprintf(yout, "%4d", nextlat);
10579 
10580       // Finished?
10581       if ( nextlat > latcnt ) break;
10582       if ( nextlat == latcnt )
10583 	{
10584 	  fprintf(grprsm, " %5d                %-12s\n", isec2[nextlat+21], yout);
10585 	  break;
10586 	}
10587       // Look for neighbouring latitudes with same number of points
10588       unsigned nrepeat = 0;
10589 
10590     LABEL110:
10591       // If neighbouring latitudes have same number of points increase the repeat count.
10592       if ( isec2[nextlat+21+1] == isec2[nextlat+21] )
10593 	{
10594           nrepeat = nrepeat + 1;
10595           nextlat = nextlat + 1;
10596 	  if ( nextlat < latcnt ) goto LABEL110;
10597 	}
10598       // Display neighbouring latitudes with same number of points as 'nn to mm'.
10599       if ( nrepeat >= 1 ) sprintf(yout+4, "to %5d", nextlat);
10600       fprintf(grprsm, " %5d                %-12s\n", isec2[nextlat+21], yout);
10601       memset(yout, ' ', (size_t) 11);
10602     }
10603 }
10604 
gribPrintSec2DP(int * isec0,int * isec2,double * fsec2)10605 void gribPrintSec2DP(int *isec0, int *isec2, double *fsec2)
10606 {
10607   /*
10608 
10609     Print the information in the Grid Description
10610     Section (Section 2) of decoded GRIB data.
10611 
10612     Input Parameters:
10613 
10614        isec0  - Array of decoded integers from Section 0
10615 
10616        isec2  - Array of decoded integers from Section 2
10617 
10618        fsec2  - Array of decoded floats from Section 2
10619 
10620     Comments:
10621 
10622        Only data representation types catered for are Gaussian
10623        grid, latitude/longitude grid, Spherical Harmonics,
10624        Polar stereographic and Space view perspective.
10625 
10626 
10627     Converted from EMOS routine GRPRS2.
10628 
10629        Uwe Schulzweida   MPIfM   01/04/2001
10630 
10631   */
10632 
10633   int i, ibit, iedit, ierr, iout, iresol;
10634 
10635   grsdef();
10636   /*
10637     -----------------------------------------------------------------
10638     Section 1 . Print GRIB Edition number.
10639     -----------------------------------------------------------------
10640   */
10641   iedit = isec0[1];
10642   fprintf(grprsm, " \n");
10643   fprintf(grprsm, " Section 2 - Grid Description Section.\n");
10644   fprintf(grprsm, " -------------------------------------\n");
10645   /*
10646     -----------------------------------------------------------------
10647     Section 2 . Print spherical harmonic data.
10648     -----------------------------------------------------------------
10649   */
10650   if ( isec2[0] == 50 || isec2[0] == 60 ||
10651        isec2[0] == 70 || isec2[0] == 80 )
10652     {
10653       fprintf(grprsm, " Data represent type = spectral     (Table 6) %9d\n", isec2[0]);
10654       fprintf(grprsm, " J - Pentagonal resolution parameter.         %9d\n", isec2[1]);
10655       fprintf(grprsm, " K - Pentagonal resolution parameter.         %9d\n", isec2[2]);
10656       fprintf(grprsm, " M - Pentagonal resolution parameter.         %9d\n", isec2[3]);
10657       fprintf(grprsm, " Representation type (Table 9)                %9d\n", isec2[4]);
10658       fprintf(grprsm, " Representation mode (Table 10).              %9d\n", isec2[5]);
10659       for (i = 7; i <= 11; i++)
10660         fprintf(grprsm, " Not used.                                    %9d\n", isec2[i-1]);
10661       fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
10662       goto LABEL800;
10663     }
10664   /*
10665     -----------------------------------------------------------------
10666     Section 3 . Print Gaussian grid data.
10667     -----------------------------------------------------------------
10668   */
10669   if ( isec2[0] ==  4 || isec2[0] == 14 ||
10670        isec2[0] == 24 || isec2[0] == 34 )
10671     {
10672       fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
10673       fprintf(grprsm, " Data represent type = gaussian     (Table 6) %9d\n", isec2[0]);
10674       /*
10675 	Quasi-regular grids introduced in Edition 1.
10676       */
10677       if ( isec2[16] == 0 || iedit < 1 )
10678 	fprintf(grprsm, " Number of points along a parallel.           %9d\n", isec2[1]);
10679       else
10680       	printQuasi(isec2);
10681 
10682       fprintf(grprsm, " Number of points along a meridian.           %9d\n", isec2[2]);
10683       fprintf(grprsm, " Latitude of first grid point.                %9d\n", isec2[3]);
10684       fprintf(grprsm, " Longitude of first grid point.               %9d\n", isec2[4]);
10685 
10686       ibit = 8;
10687       iresol = isec2[5] + isec2[17] + isec2[18];
10688       prtbin(iresol, ibit, &iout, &ierr);
10689 
10690       fprintf(grprsm, " Resolution and components flag.               %8.8d\n", iout);
10691       fprintf(grprsm, " Latitude of last grid point.                 %9d\n", isec2[6]);
10692       fprintf(grprsm, " Longitude of last grid point.                %9d\n", isec2[7]);
10693       /*
10694 	Print increment if given.
10695       */
10696       if ( isec2[5] == 128 )
10697 	fprintf(grprsm, " i direction (East-West) increment.           %9d\n", isec2[8]);
10698       else
10699 	fprintf(grprsm, " i direction (East-West) increment            Not given\n");
10700 
10701       fprintf(grprsm, " Number of parallels between pole and equator.%9d\n", isec2[9]);
10702 
10703       ibit = 8;
10704       prtbin(isec2[10], ibit, &iout, &ierr);
10705 
10706       fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
10707       fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
10708       goto LABEL800;
10709     }
10710   /*
10711     -----------------------------------------------------------------
10712     Section 4 . Print Latitude / longitude grid data.
10713     -----------------------------------------------------------------
10714   */
10715   if ( isec2[0] ==  0 || isec2[0] == 10 ||
10716        isec2[0] == 20 || isec2[0] == 30 )
10717     {
10718       fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
10719       fprintf(grprsm, " Data represent type = lat/long     (Table 6) %9d\n", isec2[0]);
10720       /*
10721 	Quasi-regular lat/long grids also possible.
10722       */
10723       if ( isec2[16] == 0 )
10724 	fprintf(grprsm, " Number of points along a parallel.           %9d\n", isec2[1]);
10725       else
10726         printQuasi(isec2);
10727 
10728       fprintf(grprsm, " Number of points along a meridian.           %9d\n", isec2[2]);
10729       fprintf(grprsm, " Latitude of first grid point.                %9d\n", isec2[3]);
10730       fprintf(grprsm, " Longitude of first grid point.               %9d\n", isec2[4]);
10731 
10732       ibit = 8;
10733       iresol = isec2[5] + isec2[17] + isec2[18];
10734       prtbin(iresol, ibit, &iout, &ierr);
10735 
10736       fprintf(grprsm, " Resolution and components flag.               %8.8d\n", iout);
10737       fprintf(grprsm, " Latitude of last grid point.                 %9d\n", isec2[6]);
10738       fprintf(grprsm, " Longitude of last grid point.                %9d\n", isec2[7]);
10739       /*
10740 	Print increment if given.
10741       */
10742       if ( isec2[8] < 0 )
10743 	fprintf(grprsm, " i direction (East-West) increment            Not given\n");
10744       else
10745 	fprintf(grprsm, " i direction (East-West) increment.           %9d\n", isec2[8]);
10746 
10747       if ( isec2[9] < 0 )
10748 	fprintf(grprsm, " j direction (North-South) increment          Not given\n");
10749       else
10750 	fprintf(grprsm, " j direction (North-South) increment.         %9d\n", isec2[9]);
10751 
10752       ibit = 8;
10753       prtbin(isec2[10], ibit, &iout, &ierr);
10754 
10755       fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
10756       fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
10757       goto LABEL800;
10758     }
10759   /*
10760     -----------------------------------------------------------------
10761     Section 5 . Print polar stereographic data.
10762     -----------------------------------------------------------------
10763   */
10764   if ( isec2[0] == 5 )
10765     {
10766       fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
10767       fprintf(grprsm, " Data represent type = polar stereo (Table 6) %9d\n", isec2[0]);
10768       fprintf(grprsm, " Number of points along X axis.               %9d\n", isec2[1]);
10769       fprintf(grprsm, " Number of points along Y axis.               %9d\n", isec2[2]);
10770       fprintf(grprsm, " Latitude of first grid point.                %9d\n", isec2[3]);
10771       fprintf(grprsm, " Longitude of first grid point.               %9d\n", isec2[4]);
10772       ibit = 8;
10773       iresol = isec2[17] + isec2[18];
10774       prtbin(iresol, ibit, &iout, &ierr);
10775       fprintf(grprsm, " Resolution and components flag.               %8.8d\n", iout);
10776       fprintf(grprsm, " Orientation of the grid.                     %9d\n", isec2[6]);
10777       fprintf(grprsm, " X direction increment.                       %9d\n", isec2[8]);
10778       fprintf(grprsm, " Y direction increment.                       %9d\n", isec2[9]);
10779       ibit = 8;
10780       prtbin(isec2[10], ibit, &iout, &ierr);
10781       fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
10782       fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
10783       fprintf(grprsm, " Projection centre flag.                      %9d\n", isec2[12]);
10784       goto LABEL800;
10785     }
10786   /*
10787     -----------------------------------------------------------------
10788     Section 6 . Print Lambert conformal data.
10789     -----------------------------------------------------------------
10790   */
10791   if ( isec2[0] == 3 )
10792     {
10793       fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
10794       fprintf(grprsm, " Data represent type = Lambert      (Table 6) %9d\n", isec2[0]);
10795       fprintf(grprsm, " Number of points along X axis.               %9d\n", isec2[1]);
10796       fprintf(grprsm, " Number of points along Y axis.               %9d\n", isec2[2]);
10797       fprintf(grprsm, " Latitude of first grid point.                %9d\n", isec2[3]);
10798       fprintf(grprsm, " Longitude of first grid point.               %9d\n", isec2[4]);
10799       ibit = 8;
10800       iresol = isec2[17] + isec2[18] + isec2[5];
10801       prtbin(iresol, ibit, &iout, &ierr);
10802       fprintf(grprsm, " Resolution and components flag.               %8.8d\n", iout);
10803       fprintf(grprsm, " Orientation of the grid.                     %9d\n", isec2[6]);
10804       fprintf(grprsm, " X direction increment.                       %9d\n", isec2[8]);
10805       fprintf(grprsm, " Y direction increment.                       %9d\n", isec2[9]);
10806       ibit = 8;
10807       prtbin(isec2[10], ibit, &iout, &ierr);
10808       fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
10809       fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
10810       fprintf(grprsm, " Projection centre flag.                      %9d\n", isec2[12]);
10811       fprintf(grprsm, " Latitude intersection 1 - Latin 1 -.         %9d\n", isec2[13]);
10812       fprintf(grprsm, " Latitude intersection 2 - Latin 2 -.         %9d\n", isec2[14]);
10813       fprintf(grprsm, " Latitude of Southern Pole.                   %9d\n", isec2[19]);
10814       fprintf(grprsm, " Longitude of Southern Pole.                  %9d\n", isec2[20]);
10815       goto LABEL800;
10816     }
10817   /*
10818     -----------------------------------------------------------------
10819     Section 7 . Print space view perspective or orthographic data.
10820     -----------------------------------------------------------------
10821   */
10822   if ( isec2[0] == 90 )
10823     {
10824       fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
10825       fprintf(grprsm, " Data represent type = space/ortho  (Table 6) %9d\n", isec2[0]);
10826       fprintf(grprsm, " Number of points along X axis.               %9d\n", isec2[1]);
10827       fprintf(grprsm, " Number of points along Y axis.               %9d\n", isec2[2]);
10828       fprintf(grprsm, " Latitude of sub-satellite point.             %9d\n", isec2[3]);
10829       fprintf(grprsm, " Longitude of sub-satellite point.            %9d\n", isec2[4]);
10830       //iresol = isec2[17] + isec2[18];
10831       fprintf(grprsm, " Diameter of the earth in x direction.        %9d\n", isec2[6]);
10832       fprintf(grprsm, " Y coordinate of sub-satellite point.         %9d\n", isec2[9]);
10833       ibit = 8;
10834       prtbin(isec2[10], ibit, &iout, &ierr);
10835       fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
10836       fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
10837       fprintf(grprsm, " Orientation of the grid.                     %9d\n", isec2[6]);
10838       fprintf(grprsm, " Altitude of the camera.                      %9d\n", isec2[13]);
10839       fprintf(grprsm, " Y coordinate of origin of sector image.      %9d\n", isec2[14]);
10840       fprintf(grprsm, " X coordinate of origin of sector image.      %9d\n", isec2[15]);
10841       goto LABEL800;
10842     }
10843   /*
10844     -----------------------------------------------------------------
10845     Section 7.5 . Print ocean data
10846     -----------------------------------------------------------------
10847   */
10848   /*
10849   if ( isec2[0] == 192 && ISEC1_CenterID == 98 )
10850     {
10851       fprintf(grprsm, " Data represent type = ECMWF ocean  (Table 6) %9d\n", isec2[0]);
10852       if ( isec2[1] ==  32767 )
10853 	fprintf(grprsm, " Number of points along the first axis.       Not used\n");
10854       else
10855 	fprintf(grprsm, " Number of points along the first axis.       %9d\n", isec2[1]);
10856 
10857       if ( isec2[2] ==  32767 )
10858 	fprintf(grprsm, " Number of points along the second axis.      Not used\n");
10859       else
10860 	fprintf(grprsm, " Number of points along the second axis.      %9d\n", isec2[2]);
10861 
10862       ibit = 8;
10863       prtbin(isec2[10], ibit, &iout, &ierr);
10864       fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
10865       goto LABEL800;
10866     }
10867     */
10868   /*
10869     -----------------------------------------------------------------
10870     Section 7.6 . Print triangular data
10871     -----------------------------------------------------------------
10872   */
10873   if ( isec2[0] == 192 /* && ISEC1_CenterID == 78 */ )
10874     {
10875       fprintf(grprsm, " Data represent type = triangular   (Table 6) %9d\n", isec2[0]);
10876       fprintf(grprsm, " Number of factor 2 in factorisation of Ni.   %9d\n", isec2[1]);
10877       fprintf(grprsm, " Number of factor 3 in factorisation of Ni.   %9d\n", isec2[2]);
10878       fprintf(grprsm, " Number of diamonds (Nd).                     %9d\n", isec2[3]);
10879       fprintf(grprsm, " Number of triangular subdivisions of the\n");
10880       fprintf(grprsm, "           icosahedron (Ni).                  %9d\n", isec2[4]);
10881       fprintf(grprsm, " Flag for orientation of diamonds (Table A).  %9d\n", isec2[5]);
10882       fprintf(grprsm, " Latitude of pole point.                      %9d\n", isec2[6]);
10883       fprintf(grprsm, " Longitude of pole point.                     %9d\n", isec2[7]);
10884       fprintf(grprsm, " Longitude of the first diamond.              %9d\n", isec2[8]);
10885       fprintf(grprsm, " Flag for storage sequence (Table B).         %9d\n", isec2[9]);
10886       fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
10887       goto LABEL800;
10888     }
10889   /*
10890     -----------------------------------------------------------------
10891     Drop through to here => representation type not catered for.
10892     -----------------------------------------------------------------
10893   */
10894   fprintf(grprsm, "GRPRS2 :Data representation type not catered for -%d\n", isec2[0]);
10895 
10896   goto LABEL900;
10897   /*
10898     -----------------------------------------------------------------
10899     Section 8 . Print vertical coordinate parameters,
10900                 rotated grid information,
10901                 stretched grid information, if any.
10902     -----------------------------------------------------------------
10903   */
10904  LABEL800:;
10905   /*
10906     Vertical coordinate parameters ...
10907   */
10908   if ( isec2[11] != 0 )
10909     {
10910       fprintf(grprsm, " \n");
10911       fprintf(grprsm, " Vertical Coordinate Parameters.\n");
10912       fprintf(grprsm, " -------------------------------\n");
10913       for ( i = 10; i < isec2[11]+10; i++ )
10914 	fprintf(grprsm, "    %20.12f\n", fsec2[i]);
10915     }
10916   /*
10917     Rotated and stretched grids introduced in Edition 1.
10918   */
10919   if ( iedit < 1 ) goto LABEL900;
10920   /*
10921     Rotated grid information ...
10922   */
10923   if ( isec2[0] == 10 || isec2[0] == 30 ||
10924        isec2[0] == 14 || isec2[0] == 34 ||
10925        isec2[0] == 60 || isec2[0] == 80 ||
10926        isec2[0] == 30 )
10927     {
10928       fprintf(grprsm, " \n");
10929       fprintf(grprsm, " Latitude of southern pole of rotation.       %9d\n", isec2[12]);
10930       fprintf(grprsm, " Longitude of southern pole of rotation.      %9d\n", isec2[13]);
10931       fprintf(grprsm, " Angle of rotation.                     %20.10f\n", fsec2[0]);
10932     }
10933   /*
10934     Stretched grid information ...
10935   */
10936   if ( isec2[0] == 20 || isec2[0] == 30 ||
10937        isec2[0] == 24 || isec2[0] == 34 ||
10938        isec2[0] == 70 || isec2[0] == 80 )
10939     {
10940       fprintf(grprsm, " \n");
10941       fprintf(grprsm, " Latitude of pole of stretching.              %9d\n", isec2[14]);
10942       fprintf(grprsm, " Longitude of pole of stretching.             %9d\n", isec2[15]);
10943       fprintf(grprsm, " Stretching factor.                     %20.10f\n", fsec2[1]);
10944     }
10945 
10946  LABEL900:;
10947 
10948   return;
10949 }
10950 
gribPrintSec2SP(int * isec0,int * isec2,float * fsec2sp)10951 void gribPrintSec2SP(int *isec0, int *isec2, float  *fsec2sp)
10952 {
10953   int inum;
10954   int j;
10955   double *fsec2;
10956 
10957   inum = 10 + isec2[11];
10958 
10959   fsec2 = (double*) Malloc((size_t)inum*sizeof(double));
10960   if ( fsec2 == NULL ) SysError("No Memory!");
10961 
10962   for ( j = 0; j < inum; j++ )
10963      fsec2[j] = fsec2sp[j];
10964 
10965   gribPrintSec2DP(isec0, isec2, fsec2);
10966 
10967   Free(fsec2);
10968 }
10969 
gribPrintSec3DP(int * isec0,int * isec3,double * fsec3)10970 void gribPrintSec3DP(int *isec0, int *isec3, double *fsec3)
10971 {
10972   /*
10973 
10974     Print the information in the Bit-Map Section
10975     (Section 3) of decoded GRIB data.
10976 
10977     Input Parameters:
10978 
10979        isec0  - Array of decoded integers from Section 0
10980 
10981        isec3  - Array of decoded integers from Section 3
10982 
10983        fsec3  - Array of decoded floats from Section 3
10984 
10985 
10986     Converted from EMOS routine GRPRS3.
10987 
10988        Uwe Schulzweida   MPIfM   01/04/2001
10989 
10990   */
10991 
10992   UNUSED(isec0);
10993 
10994   grsdef();
10995 
10996   fprintf(grprsm, " \n");
10997   fprintf(grprsm, " Section 3 - Bit-map Section.\n");
10998   fprintf(grprsm, " -------------------------------------\n");
10999 
11000   if ( isec3[0] != 0 )
11001     fprintf(grprsm, " Predetermined bit-map number.                %9d\n", isec3[0]);
11002   else
11003     fprintf(grprsm, " No predetermined bit-map.\n");
11004 
11005   fprintf(grprsm, " Missing data value for integer data.    %14d\n", isec3[1]);
11006 
11007   fprintf(grprsm, " Missing data value for real data. %20.6g\n", fsec3[1]);
11008 }
11009 
gribPrintSec3SP(int * isec0,int * isec3,float * fsec3sp)11010 void gribPrintSec3SP(int *isec0, int *isec3, float  *fsec3sp)
11011 {
11012   double fsec3[2];
11013 
11014   fsec3[0] = fsec3sp[0];
11015   fsec3[1] = fsec3sp[1];
11016 
11017   gribPrintSec3DP(isec0, isec3, fsec3);
11018 }
11019 
gribPrintSec4DP(int * isec0,int * isec4,double * fsec4)11020 void gribPrintSec4DP(int *isec0, int *isec4, double *fsec4)
11021 {
11022   /*
11023 
11024     Print the information in the Binary Data Section
11025     (Section 4) of decoded GRIB data.
11026 
11027     Input Parameters:
11028 
11029        isec0  - Array of decoded integers from Section 0
11030 
11031        isec4  - Array of decoded integers from Section 4
11032 
11033        fsec4  - Array of decoded floats from Section 4
11034 
11035 
11036     Converted from EMOS routine GRPRS4.
11037 
11038        Uwe Schulzweida   MPIfM   01/04/2001
11039 
11040   */
11041   int inum;
11042   int j;
11043 
11044   UNUSED(isec0);
11045 
11046   grsdef();
11047 
11048   /*
11049     -----------------------------------------------------------------
11050     Section 1 . Print integer information from isec4.
11051     -----------------------------------------------------------------
11052   */
11053   fprintf(grprsm, " \n");
11054   fprintf(grprsm, " Section 4 - Binary Data  Section.\n");
11055   fprintf(grprsm, " -------------------------------------\n");
11056 
11057   fprintf(grprsm, " Number of data values coded/decoded.         %9d\n", isec4[0]);
11058   fprintf(grprsm, " Number of bits per data value.               %9d\n", isec4[1]);
11059   fprintf(grprsm, " Type of data       (0=grid pt, 128=spectral).%9d\n", isec4[2]);
11060   fprintf(grprsm, " Type of packing    (0=simple, 64=complex).   %9d\n", isec4[3]);
11061   fprintf(grprsm, " Type of data       (0=float, 32=integer).    %9d\n", isec4[4]);
11062   fprintf(grprsm, " Additional flags   (0=none, 16=present).     %9d\n", isec4[5]);
11063   fprintf(grprsm, " Reserved.                                    %9d\n", isec4[6]);
11064   fprintf(grprsm, " Number of values   (0=single, 64=matrix).    %9d\n", isec4[7]);
11065   fprintf(grprsm, " Secondary bit-maps (0=none, 32=present).     %9d\n", isec4[8]);
11066   fprintf(grprsm, " Values width       (0=constant, 16=variable).%9d\n", isec4[9]);
11067   /*
11068     If complex packing ..
11069   */
11070   if ( isec4[3] == 64 )
11071     {
11072       if ( isec4[2] == 128 )
11073 	{
11074 	  fprintf(grprsm, " Byte offset of start of packed data (N).     %9d\n", isec4[15]);
11075 	  fprintf(grprsm, " Power (P * 1000).                            %9d\n", isec4[16]);
11076 	  fprintf(grprsm, " Pentagonal resolution parameter J for subset.%9d\n", isec4[17]);
11077 	  fprintf(grprsm, " Pentagonal resolution parameter K for subset.%9d\n", isec4[18]);
11078 	  fprintf(grprsm, " Pentagonal resolution parameter M for subset.%9d\n", isec4[19]);
11079 	}
11080       else
11081 	{
11082 	  fprintf(grprsm, " Bits number of 2nd order values    (none=>0).%9d\n", isec4[10]);
11083 	  fprintf(grprsm, " General extend. 2-order packing (0=no,8=yes).%9d\n", isec4[11]);
11084 	  fprintf(grprsm, " Boustrophedonic ordering        (0=no,4=yes).%9d\n", isec4[12]);
11085 	  fprintf(grprsm, " Spatial differencing order          (0=none).%9d\n", isec4[13]+isec4[14]);
11086         }
11087     }
11088   /*
11089     Number of non-missing values
11090   */
11091   if ( isec4[20] != 0 )
11092     fprintf(grprsm, " Number of non-missing values                 %9d\n", isec4[20]);
11093   /*
11094     Information on matrix of values , if present.
11095   */
11096   if ( isec4[7] == 64 )
11097     {
11098       fprintf(grprsm, " First dimension (rows) of each matrix.       %9d\n", isec4[49]);
11099       fprintf(grprsm, " Second dimension (columns) of each matrix.   %9d\n", isec4[50]);
11100       fprintf(grprsm, " First dimension coordinate values definition.%9d\n", isec4[51]);
11101       fprintf(grprsm, " (Code Table 12)\n");
11102       fprintf(grprsm, " NC1 - Number of coefficients for 1st dimension.%7d\n", isec4[52]);
11103       fprintf(grprsm, " Second dimension coordinate values definition.%8d\n", isec4[53]);
11104       fprintf(grprsm, " (Code Table 12)\n");
11105       fprintf(grprsm, " NC2 - Number of coefficients for 2nd dimension.%7d\n", isec4[54]);
11106       fprintf(grprsm, " 1st dimension physical signifance (Table 13). %8d\n", isec4[55]);
11107       fprintf(grprsm, " 2nd dimension physical signifance (Table 13).%8d\n", isec4[56]);
11108     }
11109   /*
11110     -----------------------------------------------------------------
11111     Section 2. Print values from fsec4.
11112     -----------------------------------------------------------------
11113   */
11114 
11115   inum = isec4[0];
11116   if ( inum <  0 ) inum = - inum;
11117   if ( inum > 20 ) inum = 20;
11118   /*
11119     Print first inum values.
11120   */
11121   fprintf(grprsm, " \n");
11122   fprintf(grprsm, " First %4d data values.\n", inum);
11123 
11124   if ( isec4[4] == 0 )
11125     {
11126       /*
11127 	Print real values ...
11128       */
11129       for ( j = 0; j < inum; j++ )
11130 	{
11131 	  if ( fabs(fsec4[j]) > 0 )
11132 	    {
11133 	      if ( fabs(fsec4[j]) >= 0.1 && fabs(fsec4[j]) <= 1.e8 )
11134 		fprintf(grprsm, " %#16.8G    \n", fsec4[j]);
11135 	      else
11136 		fprintf(grprsm, " %#20.8E\n", fsec4[j]);
11137 	    }
11138 	  else
11139 	    fprintf(grprsm, " %#16.0f    \n", fabs(fsec4[j]));
11140 	}
11141     }
11142   else
11143     {
11144       /*
11145 	Print integer values ...
11146       */
11147       fprintf(grprsm, " Print of integer values not supported\n");
11148       /*
11149         CALL SETPAR(IBIT,IDUM,IDUM)
11150         DO 212 J=1,INUM
11151            INSPT = 0
11152            CALL INXBIT(IVALUE,1,INSPT,FSEC4(J),1,IBIT,IBIT,'C',IRET)
11153            WRITE (*,9033) IVALUE
11154  9033 FORMAT(' ',I15)
11155   212   CONTINUE
11156       ENDIF
11157       */
11158     }
11159 }
11160 
gribPrintSec4SP(int * isec0,int * isec4,float * fsec4sp)11161 void gribPrintSec4SP(int *isec0, int *isec4, float  *fsec4sp)
11162 {
11163   int inum;
11164   int j;
11165   double fsec4[20];
11166 
11167   inum = isec4[0];
11168   if ( inum <  0 ) inum = -inum;
11169   if ( inum > 20 ) inum = 20;
11170 
11171   for ( j = 0; j < inum; j++ ) fsec4[j] = fsec4sp[j];
11172 
11173   gribPrintSec4DP(isec0, isec4, fsec4);
11174 }
11175 
gribPrintSec4Wave(int * isec4)11176 void gribPrintSec4Wave(int *isec4)
11177 {
11178   /*
11179 
11180     Print the wave coordinate information in the Binary Data
11181     Section (Section 4) of decoded GRIB data.
11182 
11183     Input Parameters:
11184 
11185        isec4 - Array of decoded integers from Section 4
11186 
11187     Comments:
11188 
11189        Wave coordinate information held in isec4 are 32-bit floats,
11190        hence the PTEMP and NTEMP used for printing are 4-byte variables.
11191 
11192 
11193     Converted from EMOS routine GRPRS4W.
11194 
11195        Uwe Schulzweida   MPIfM   01/04/2001
11196 
11197   */
11198   int    jloop;
11199   int    ntemp[100];
11200   float *ptemp;
11201 
11202   grsdef();
11203 
11204   /*
11205     -----------------------------------------------------------------
11206     Section 1 . Print integer information from isec4.
11207     -----------------------------------------------------------------
11208   */
11209   fprintf(grprsm, " Coefficients defining first dimension coordinates:\n");
11210   for ( jloop = 0; jloop < isec4[52]; jloop++ )
11211     {
11212       ntemp[jloop] = isec4[59 + jloop];
11213       ptemp = (float *) &ntemp[jloop];
11214       fprintf(grprsm, "%20.10f\n", *ptemp);
11215     }
11216   fprintf(grprsm, " Coefficients defining second dimension coordinates:\n");
11217   for ( jloop = 0; jloop < isec4[54]; jloop++ )
11218     {
11219       ntemp[jloop] = isec4[59 + isec4[52] + jloop];
11220       ptemp = (float *) &ntemp[jloop];
11221       fprintf(grprsm, "%20.10f\n", *ptemp);
11222     }
11223 }
11224 #if defined (HAVE_CONFIG_H)
11225 #endif
11226 
11227 #include <string.h>
11228 #include <ctype.h>
11229 
11230 
11231 
gribOpen(const char * filename,const char * mode)11232 int gribOpen(const char *filename, const char *mode)
11233 {
11234   int fileID = fileOpen(filename, mode);
11235 
11236 #if defined (__sun)
11237   if ( fileID != FILE_UNDEFID && tolower(*mode) == 'r' )
11238     {
11239       fileSetBufferType(fileID, FILE_BUFTYPE_MMAP);
11240     }
11241 #endif
11242 
11243   return fileID;
11244 }
11245 
11246 
gribClose(int fileID)11247 void gribClose(int fileID)
11248 {
11249   fileClose(fileID);
11250 }
11251 
11252 
gribGetPos(int fileID)11253 off_t gribGetPos(int fileID)
11254 {
11255   return fileGetPos(fileID);
11256 }
11257 
11258 
gribCheckSeek(int fileID,long * offset,int * version)11259 int gribCheckSeek(int fileID, long *offset, int *version)
11260 {
11261   int ierr = gribFileSeek(fileID, offset);
11262 
11263   *version = -1;
11264   if ( !ierr )
11265     {
11266       char buffer[4];
11267      if ( fileRead(fileID, buffer, 4) == 4 )
11268 	*version = buffer[3];
11269     }
11270 
11271   return ierr;
11272 }
11273 
11274 
gribFileSeek(int fileID,long * offset)11275 int gribFileSeek(int fileID, long *offset)
11276 {
11277   /* position file pointer after GRIB */
11278   const long GRIB = 0x47524942;
11279   long code = 0;
11280   int ch;
11281   int retry = 4096*4096;
11282 
11283   *offset = 0;
11284 
11285   void *fileptr = filePtr(fileID);
11286 
11287   while ( retry-- )
11288     {
11289       ch = filePtrGetc(fileptr);
11290       if ( ch == EOF ) return -1;
11291 
11292       code = ( (code << 8) + ch ) & 0xFFFFFFFF;
11293       if ( code == GRIB )
11294 	{
11295 	  if ( CGRIBEX_Debug ) Message("record offset = %ld", *offset);
11296 	  return 0;
11297 	}
11298 
11299       (*offset)++;
11300     }
11301 
11302   if ( CGRIBEX_Debug ) Message("record offset = %ld", *offset);
11303 
11304   return 1;
11305 }
11306 
11307 static inline
read3ByteMSBFirst(void * fileptr)11308 unsigned read3ByteMSBFirst(void *fileptr)
11309 {
11310   unsigned b1 = (unsigned)(filePtrGetc(fileptr));
11311   unsigned b2 = (unsigned)(filePtrGetc(fileptr));
11312   unsigned b3 = (unsigned)(filePtrGetc(fileptr));
11313   return GET_UINT3(b1, b2, b3);
11314 }
11315 
11316 
gribReadSize(int fileID)11317 size_t gribReadSize(int fileID)
11318 {
11319   size_t rgribsize = 0;
11320   void *fileptr = filePtr(fileID);
11321   off_t pos = fileGetPos(fileID);
11322 
11323   unsigned gribsize = read3ByteMSBFirst(fileptr);
11324 
11325   int gribversion = filePtrGetc(fileptr);
11326 
11327   if ( gribsize == 24 && gribversion != 1 && gribversion != 2 ) gribversion = 0;
11328 
11329   if ( CGRIBEX_Debug ) Message("gribversion = %d", gribversion);
11330 
11331   if ( gribversion == 0 )
11332     {
11333       unsigned gdssize = 0, bmssize = 0;
11334       unsigned issize = 4, essize = 4;
11335 
11336       unsigned pdssize = gribsize;
11337       fileSetPos(fileID, (off_t) 3, SEEK_CUR);
11338       if ( CGRIBEX_Debug ) Message("pdssize     = %u", pdssize);
11339       int flag = filePtrGetc(fileptr);
11340       if ( CGRIBEX_Debug ) Message("flag        = %d", flag);
11341 
11342       fileSetPos(fileID, (off_t) pdssize-8, SEEK_CUR);
11343 
11344       if ( flag & 128 )
11345 	{
11346 	  gdssize = read3ByteMSBFirst(fileptr);
11347 	  fileSetPos(fileID, (off_t) gdssize-3, SEEK_CUR);
11348 	  if ( CGRIBEX_Debug ) Message("gdssize     = %u", gdssize);
11349 	}
11350 
11351       if ( flag & 64 )
11352 	{
11353 	  bmssize = read3ByteMSBFirst(fileptr);
11354 	  fileSetPos(fileID, (off_t) bmssize-3, SEEK_CUR);
11355 	  if ( CGRIBEX_Debug ) Message("bmssize     = %u", bmssize);
11356 	}
11357 
11358       unsigned bdssize = read3ByteMSBFirst(fileptr);
11359       if ( CGRIBEX_Debug ) Message("bdssize     = %u", bdssize);
11360 
11361       gribsize = issize + pdssize + gdssize + bmssize + bdssize + essize;
11362       rgribsize = (size_t) gribsize;
11363     }
11364   else if ( gribversion == 1 )
11365     {
11366       if ( gribsize > JP23SET ) // Large GRIB record
11367 	{
11368 	  unsigned pdssize = read3ByteMSBFirst(fileptr);
11369 	  if ( CGRIBEX_Debug ) Message("pdssize     = %u", pdssize);
11370 
11371 	  int flag = 0;
11372 	  for ( int i = 0; i < 5; ++i ) flag = filePtrGetc(fileptr);
11373 	  if ( CGRIBEX_Debug ) Message("flag        = %d", flag);
11374 
11375 	  fileSetPos(fileID, (off_t) pdssize-8, SEEK_CUR);
11376 
11377           unsigned gdssize = 0;
11378 	  if ( flag & 128 )
11379 	    {
11380 	      gdssize = read3ByteMSBFirst(fileptr);
11381 	      fileSetPos(fileID, (off_t) gdssize-3, SEEK_CUR);
11382 	      if ( CGRIBEX_Debug ) Message("gdssize     = %u", gdssize);
11383 	    }
11384 
11385           unsigned bmssize = 0;
11386 	  if ( flag & 64 )
11387 	    {
11388 	      bmssize = read3ByteMSBFirst(fileptr);
11389 	      fileSetPos(fileID, (off_t) bmssize-3, SEEK_CUR);
11390 	      if ( CGRIBEX_Debug ) Message("bmssize     = %u", bmssize);
11391 	    }
11392 
11393 	  unsigned bdssize = read3ByteMSBFirst(fileptr);
11394 	  if ( CGRIBEX_Debug ) Message("bdssize     = %u", bdssize);
11395           if ( bdssize <= 120 )
11396             {
11397               const int issize = 4;
11398               gribsize &= JP23SET;
11399               gribsize *= 120;
11400               bdssize = correct_bdslen(bdssize, gribsize, issize+pdssize+gdssize+bmssize);
11401               if ( CGRIBEX_Debug ) Message("bdssize     = %u", bdssize);
11402 
11403               gribsize = issize + pdssize + gdssize + bmssize + bdssize + 4;
11404             }
11405 	}
11406       rgribsize = (size_t) gribsize;
11407     }
11408   else if ( gribversion == 2 )
11409     {
11410       /* we set gribsize the following way because it doesn't matter then
11411 	 whether int is 4 or 8 bytes long - we don't have to care if the size
11412 	 really fits: if it does not, the record can not be read at all */
11413       rgribsize = 0;
11414       for ( int i = 0; i < 8; i++ ) rgribsize = (rgribsize << 8) | filePtrGetc(fileptr);
11415     }
11416   else
11417     {
11418       rgribsize = 0;
11419       Warning("GRIB version %d unsupported!", gribversion);
11420     }
11421 
11422   if ( filePtrEOF(fileptr) ) rgribsize = 0;
11423 
11424   if ( CGRIBEX_Debug ) Message("gribsize = %zu", rgribsize);
11425 
11426   fileSetPos(fileID, pos, SEEK_SET);
11427 
11428   return rgribsize;
11429 }
11430 
11431 
gribGetSize(int fileID)11432 size_t gribGetSize(int fileID)
11433 {
11434   long offset;
11435   int ierr = gribFileSeek(fileID, &offset); // position file pointer after GRIB
11436   if ( ierr > 0 )
11437     {
11438       Warning("GRIB record not found!");
11439       return 0;
11440     }
11441 
11442   if      ( ierr == -1 ) return 0;
11443   else if ( ierr ==  1 ) return 0;
11444 
11445   size_t recSize = gribReadSize(fileID);
11446 
11447   if ( CGRIBEX_Debug ) Message("recsize = %zu", recSize);
11448 
11449   fileSetPos(fileID, (off_t) -4, SEEK_CUR);
11450 
11451   return recSize;
11452 }
11453 
11454 
gribRead(int fileID,unsigned char * buffer,size_t * buffersize)11455 int gribRead(int fileID, unsigned char *buffer, size_t *buffersize)
11456 {
11457   long offset;
11458   int ierr = gribFileSeek(fileID, &offset); // position file pointer after GRIB
11459   if ( ierr > 0 )
11460     {
11461       Warning("GRIB record not found!");
11462       return -2;
11463     }
11464 
11465   if      ( ierr == -1 ) { *buffersize = 0; return -1; }
11466   else if ( ierr ==  1 ) { *buffersize = 0; return -2; }
11467 
11468   size_t recSize  = gribReadSize(fileID);
11469   size_t readSize = recSize;
11470 
11471   if ( readSize > *buffersize )
11472     {
11473       readSize = *buffersize;
11474       ierr = -3;          // Tell the caller that the buffer was insufficient.
11475     }
11476 
11477   *buffersize = recSize;  // Inform the caller about the record size.
11478 
11479   // Write the stuff to the buffer that has already been read in gribFileSeek().
11480   buffer[0] = 'G';
11481   buffer[1] = 'R';
11482   buffer[2] = 'I';
11483   buffer[3] = 'B';
11484 
11485   readSize -= 4;
11486   // Read the rest of the record into the buffer.
11487   size_t nread = fileRead(fileID, &buffer[4], readSize);
11488 
11489   if ( nread != readSize ) ierr = 1;
11490 
11491   return ierr;
11492 }
11493 
11494 
gribWrite(int fileID,unsigned char * buffer,size_t buffersize)11495 int gribWrite(int fileID, unsigned char *buffer, size_t buffersize)
11496 {
11497   int nwrite = 0;
11498 
11499   if ( (nwrite = (int)(fileWrite(fileID, buffer, buffersize))) != (int) buffersize )
11500     {
11501       perror(__func__);
11502       nwrite = -1;
11503     }
11504 
11505   return nwrite;
11506 }
11507 #include <string.h>
11508 #include <ctype.h>
11509 
11510 
11511 FILE *grprsm = NULL;
11512 int CGRIBEX_grib_calendar = -1;
11513 
11514 
gribSetCalendar(int calendar)11515 void gribSetCalendar(int calendar)
11516 {
11517   CGRIBEX_grib_calendar = calendar;
11518 }
11519 
11520 
grsdef(void)11521 void grsdef(void)
11522 {
11523   /*
11524 C---->
11525 C**** GRSDEF - Initial (default) setting of common area variables
11526 C              for GRIBEX package.
11527 C
11528 C     Purpose.
11529 C     --------
11530 C
11531 C     Sets initial values for common area variables for all
11532 C     routines of GRIBEX package, if not already done.
11533 C
11534 C**   Interface.
11535 C     ----------
11536 C
11537 C     CALL GRSDEF
11538 C
11539 C     Input Parameters.
11540 C     -----------------
11541 C
11542 C     None.
11543 C
11544 C     Output Parameters.
11545 C     ------------------
11546 C
11547 C     None.
11548 C
11549 C     Method.
11550 C     -------
11551 C
11552 C     Self-explanatory.
11553 C
11554 C     Externals.
11555 C     ----------
11556 C
11557 C     None.
11558 C
11559 C     Reference.
11560 C     ----------
11561 C
11562 C     See subroutine GRIBEX.
11563 C
11564 C     Comments.
11565 C     ---------
11566 C
11567 C     None
11568 C
11569 C     Author.
11570 C     -------
11571 C
11572 C     J. Clochard, Meteo France, for ECMWF - March 1998.
11573 C
11574 C     Modifications.
11575 C     --------------
11576 C
11577 C     J. Clochard, Meteo France, for ECMWF - June 1999.
11578 C     Add variable NSUBCE.
11579 C     Use a static variable to determine if initialisation has already
11580 C     been done. NUSER removed .
11581 C     Reverse defaults for NEXT2O and NLOC2O, for consistency with
11582 C     version 13.023 of software .
11583 C
11584   */
11585   /*
11586 C     ----------------------------------------------------------------
11587 C*    Section 0 . Definition of variables.
11588 C     ----------------------------------------------------------------
11589   */
11590   char *envString;
11591   char *env_stream;
11592   static bool lfirst = true;
11593   extern int CGRIBEX_Const;
11594 
11595   if ( ! lfirst ) return;
11596 
11597   /*
11598     ----------------------------------------------------------------
11599     Section 1 . Set values, conditionally.
11600     ----------------------------------------------------------------
11601   */
11602   /*
11603     Common area variables have not been set. Set them.
11604   */
11605   /*
11606     Set GRIB calendar.
11607   */
11608   if ( CGRIBEX_grib_calendar == -1 )
11609     {
11610       CGRIBEX_grib_calendar = CALENDAR_PROLEPTIC;
11611 
11612       envString = getenv("GRIB_CALENDAR");
11613       if ( envString )
11614 	{
11615 	  if      ( strncmp(envString, "standard", 8) == 0 )
11616 	    CGRIBEX_grib_calendar = CALENDAR_STANDARD;
11617 	  else if ( strncmp(envString, "proleptic", 9) == 0 )
11618 	    CGRIBEX_grib_calendar = CALENDAR_PROLEPTIC;
11619 	  else if ( strncmp(envString, "360days", 7) == 0 )
11620 	    CGRIBEX_grib_calendar = CALENDAR_360DAYS;
11621 	  else if ( strncmp(envString, "365days", 7) == 0 )
11622 	    CGRIBEX_grib_calendar = CALENDAR_365DAYS;
11623 	  else if ( strncmp(envString, "366days", 7) == 0 )
11624 	    CGRIBEX_grib_calendar = CALENDAR_366DAYS;
11625 	  else if ( strncmp(envString, "none", 4) == 0 )
11626 	    CGRIBEX_grib_calendar = CALENDAR_NONE;
11627 	}
11628     }
11629   /*
11630     Set GRIBEX compatibility mode.
11631   */
11632   envString = getenv("GRIB_GRIBEX_MODE_ON");
11633   if ( envString != NULL )
11634     {
11635       if ( atoi(envString) == 1 ) CGRIBEX_Const = 0;
11636     }
11637 
11638   /*
11639     See if output stream needs changing
11640   */
11641   grprsm = stdout;
11642   env_stream = getenv("GRPRS_STREAM");
11643   if ( env_stream )
11644     {
11645       if ( isdigit((int) env_stream[0]) )
11646 	{
11647 	  int unit;
11648 	  unit = atoi(env_stream);
11649 	  if ( unit < 1 || unit > 99 )
11650 	    Warning("Invalid number for GRPRS_STREAM: %d", unit);
11651 	  else if ( unit == 2 )
11652 	    grprsm = stderr;
11653 	  else if ( unit == 6 )
11654 	    grprsm = stdout;
11655 	  else
11656 	    {
11657 	      char filename[] = "unit.00";
11658 	      sprintf(filename, "%2.2d", unit);
11659 	      grprsm = fopen(filename, "w");
11660 	      if ( ! grprsm )
11661 		SysError("GRPRS_STREAM = %d", unit);
11662 	    }
11663 	}
11664       else
11665 	{
11666 	  if ( env_stream[0] )
11667 	    {
11668 	      grprsm = fopen(env_stream, "w");
11669 	      if ( ! grprsm )
11670 		SysError("GRPRS_STREAM = %s", env_stream);
11671 	    }
11672 	}
11673     }
11674   /*
11675     Mark common area values set by user.
11676   */
11677   lfirst = false;
11678 }
11679 
11680 /* pack 8-bit bytes from 64-bit words to a packed buffer */
11681 /* same as : for ( int i = 0; i < bc; ++i ) cp[i] = (unsigned char) up[i]; */
11682 
packInt64(unsigned INT64 * up,unsigned char * cp,long bc,long tc)11683 long packInt64(unsigned INT64 *up, unsigned char *cp, long bc, long tc)
11684 {
11685 #if defined (CRAY)
11686   (void) _pack(up, cp, bc, tc);
11687 #else
11688   U_BYTEORDER;
11689   unsigned char *cp0;
11690   unsigned INT64 upi, *up0, *ip0, *ip1, *ip2, *ip3, *ip4, *ip5, *ip6, *ip7;
11691   long head, trail, inner, i, j;
11692   long ipack = sizeof(INT64);
11693 
11694   /* Bytes until first word boundary in destination buffer */
11695 
11696   head = ( (long) cp ) & (ipack-1);
11697   if ( head != 0 ) head = ipack - head;
11698 
11699   inner = bc - head;
11700 
11701   /* Trailing bytes which do not make a full word */
11702 
11703   trail = inner & (ipack-1);
11704 
11705   /* Number of bytes/words to be processed in fast loop */
11706 
11707   inner -= trail;
11708   inner /= ipack;
11709 
11710   ip0 = up + head;
11711   ip1 = ip0 + 1;
11712   ip2 = ip0 + 2;
11713   ip3 = ip0 + 3;
11714   ip4 = ip0 + 4;
11715   ip5 = ip0 + 5;
11716   ip6 = ip0 + 6;
11717   ip7 = ip0 + 7;
11718 
11719   up0 = (unsigned INT64 *)(void *)(cp + head);
11720 
11721   /* Here we should process any bytes until the first word boundary
11722    * of our destination buffer
11723    * That code is missing so far  because our output buffer is
11724    * word aligned by FORTRAN
11725    */
11726 
11727   j = 0;
11728 
11729   if ( IS_BIGENDIAN() )
11730     {
11731 #if defined (CRAY)
11732 #pragma _CRI ivdep
11733 #endif
11734 #if defined (SX)
11735 #pragma vdir nodep
11736 #endif
11737 #ifdef __uxpch__
11738 #pragma loop novrec
11739 #endif
11740       for ( i = 0 ; i < inner ; i++ )
11741 	{
11742 	  upi =             (   ip0[j]          << 56 )
11743 	                 |  ( ( ip1[j] & 0xFF ) << 48 )
11744 	                 |  ( ( ip2[j] & 0xFF ) << 40 )
11745 	                 |  ( ( ip3[j] & 0xFF ) << 32 )
11746 	                 |  ( ( ip4[j] & 0xFF ) << 24 ) ;
11747 	  up0[i] = upi   |  ( ( ip5[j] & 0xFF ) << 16 )
11748 	                 |  ( ( ip6[j] & 0xFF ) <<  8 )
11749 	                 |    ( ip7[j] & 0xFF ) ;
11750 	  j += ipack;
11751 	}
11752     }
11753   else
11754     {
11755       for ( i = 0 ; i < inner ; i++ )
11756 	{
11757 	  upi =             (   ip7[j]          << 56 )
11758 	                 |  ( ( ip6[j] & 0xFF ) << 48 )
11759                          |  ( ( ip5[j] & 0xFF ) << 40 )
11760                          |  ( ( ip4[j] & 0xFF ) << 32 )
11761                          |  ( ( ip3[j] & 0xFF ) << 24 ) ;
11762 	  up0[i] = upi   |  ( ( ip2[j] & 0xFF ) << 16 )
11763                          |  ( ( ip1[j] & 0xFF ) <<  8 )
11764                          |    ( ip0[j] & 0xFF ) ;
11765 	  j += ipack;
11766 	}
11767     }
11768 
11769   cp0 = (unsigned char *) ( up0 + inner );
11770   if ( trail > 0 )
11771     {
11772       up0[inner] = 0;
11773       for ( i = 0 ; i < trail ; i ++ )
11774 	{
11775 	  *cp0 = (unsigned char) ip0[ipack*inner+i];
11776 	  cp0++;
11777 	}
11778     }
11779 
11780   if ( tc != -1 )
11781     {
11782       bc++;
11783       *cp0 = (unsigned char) tc;
11784     }
11785 #endif
11786   return (bc);
11787 }
11788 
11789 /* unpack 8-bit bytes from a packed buffer with 64-bit words */
11790 /* same as : for ( int i = 0; i < bc; ++i ) up[i] = (INT64) cp[i]; */
11791 
unpackInt64(const unsigned char * cp,unsigned INT64 * up,long bc,long tc)11792 long unpackInt64(const unsigned char *cp, unsigned INT64 *up, long bc, long tc)
11793 {
11794   U_BYTEORDER;
11795   const unsigned char *cp0;
11796   unsigned INT64 *ip0, *ip1, *ip2, *ip3, *ip4, *ip5, *ip6, *ip7;
11797   long head, trail, inner, i, j;
11798   long offset;
11799   long ipack = sizeof(INT64);
11800 
11801   UNUSED(tc);
11802 
11803   /* Bytes until first word boundary in source buffer */
11804 
11805   head = ( (long) cp ) & (ipack-1);
11806   if ( head != 0 ) head = ipack - head;
11807   if ( head > bc ) head = bc;
11808 
11809   inner = bc - head;
11810 
11811   /* Trailing bytes which do not make a full word */
11812 
11813   trail = inner & (ipack-1);
11814 
11815   /* Number of bytes/words to be processed in fast loop */
11816 
11817   inner -= trail;
11818   inner /= ipack;
11819 
11820   ip0 = up + head;
11821   ip1 = ip0 + 1;
11822   ip2 = ip0 + 2;
11823   ip3 = ip0 + 3;
11824   ip4 = ip0 + 4;
11825   ip5 = ip0 + 5;
11826   ip6 = ip0 + 6;
11827   ip7 = ip0 + 7;
11828 
11829   const unsigned INT64 *up0 = (const unsigned INT64 *)(const void *)(cp + head);
11830 
11831   /* Process any bytes until the first word boundary
11832    * of our source buffer
11833    */
11834   for ( i = 0 ; i < head ; i++ ) up[i] = (unsigned INT64) cp[i];
11835 
11836   j = 0;
11837 
11838   if ( IS_BIGENDIAN() )
11839     {
11840 #if defined (CRAY)
11841 #pragma _CRI ivdep
11842 #endif
11843 #if defined (SX)
11844 #pragma vdir nodep
11845 #endif
11846 #ifdef __uxpch__
11847 #pragma loop novrec
11848 #endif
11849       for ( i = 0 ; i < inner ; i++ )
11850 	{
11851 	  ip0[j] = (up0[i] >> 56) & 0xFF;
11852 	  ip1[j] = (up0[i] >> 48) & 0xFF;
11853 	  ip2[j] = (up0[i] >> 40) & 0xFF;
11854 	  ip3[j] = (up0[i] >> 32) & 0xFF;
11855 	  ip4[j] = (up0[i] >> 24) & 0xFF;
11856 	  ip5[j] = (up0[i] >> 16) & 0xFF;
11857 	  ip6[j] = (up0[i] >>  8) & 0xFF;
11858 	  ip7[j] = (up0[i])       & 0xFF;
11859 
11860 	  j += ipack;
11861 	}
11862     }
11863   else
11864     {
11865       for ( i = 0 ; i < inner ; i++ )
11866 	{
11867 	  ip7[j] = (up0[i] >> 56) & 0xFF;
11868 	  ip6[j] = (up0[i] >> 48) & 0xFF;
11869 	  ip5[j] = (up0[i] >> 40) & 0xFF;
11870 	  ip4[j] = (up0[i] >> 32) & 0xFF;
11871 	  ip3[j] = (up0[i] >> 24) & 0xFF;
11872 	  ip2[j] = (up0[i] >> 16) & 0xFF;
11873 	  ip1[j] = (up0[i] >>  8) & 0xFF;
11874 	  ip0[j] = (up0[i])       & 0xFF;
11875 
11876 	  j += ipack;
11877 	}
11878     }
11879 
11880   if ( trail > 0 )
11881     {
11882       offset = head + ipack*inner;
11883       cp0 = cp + offset;
11884       for ( i = 0 ; i < trail ; i++ ) up[i+offset] = (unsigned INT64) cp0[i];
11885     }
11886   /*
11887   if ( tc != -1 ) {
11888     bc++;
11889     *cp0 = (unsigned char) tc;
11890   }
11891   */
11892   return (bc);
11893 }
11894 
11895 /* pack 8-bit bytes from 32-bit words to a packed buffer */
11896 /* same as : for ( int i = 0; i < bc; ++i ) cp[i] = (char) up[i]; */
11897 
11898 #ifdef  INT32
packInt32(unsigned INT32 * up,unsigned char * cp,long bc,long tc)11899 long packInt32(unsigned INT32 *up, unsigned char *cp, long bc, long tc)
11900 {
11901   U_BYTEORDER;
11902   unsigned char *cp0;
11903   unsigned INT32 *up0, *ip0, *ip1, *ip2, *ip3;
11904   long head, trail, inner, i, j;
11905   long ipack = sizeof(INT32);
11906 
11907   /* Bytes until first word boundary in destination buffer */
11908 
11909   head = ( (long) cp ) & (ipack-1);
11910   if ( head != 0 ) head = ipack - head;
11911 
11912   inner = bc - head;
11913 
11914   /* Trailing bytes which do not make a full word */
11915 
11916   trail = inner & (ipack-1);
11917 
11918   /* Number of bytes/words to be processed in fast loop */
11919 
11920   inner -= trail;
11921   inner /= ipack;
11922 
11923   ip0 = up + head;
11924   ip1 = ip0 + 1;
11925   ip2 = ip0 + 2;
11926   ip3 = ip0 + 3;
11927 
11928   up0 = (unsigned INT32 *)(void *)(cp + head);
11929 
11930   /* Here we should process any bytes until the first word boundary
11931    * of our destination buffer
11932    * That code is missing so far  because our output buffer is
11933    * word aligned by FORTRAN
11934    */
11935 
11936   j = 0;
11937 
11938   if ( IS_BIGENDIAN() )
11939     {
11940 #if defined (CRAY)
11941 #pragma _CRI ivdep
11942 #endif
11943 #if defined (SX)
11944 #pragma vdir nodep
11945 #endif
11946 #ifdef __uxpch__
11947 #pragma loop novrec
11948 #endif
11949       for ( i = 0 ; i < inner ; i++ )
11950 	{
11951 	  up0[i] =          (   ip0[j]          << 24 )
11952 	                 |  ( ( ip1[j] & 0xFF ) << 16 )
11953 	                 |  ( ( ip2[j] & 0xFF ) <<  8 )
11954 	                 |    ( ip3[j] & 0xFF ) ;
11955 	  j += ipack;
11956 	}
11957     }
11958   else
11959     {
11960       for ( i = 0 ; i < inner ; i++ )
11961 	{
11962 	  up0[i] =          (   ip3[j]          << 24 )
11963 	                 |  ( ( ip2[j] & 0xFF ) << 16 )
11964                          |  ( ( ip1[j] & 0xFF ) <<  8 )
11965                          |    ( ip0[j] & 0xFF ) ;
11966 	  j += ipack;
11967 	}
11968     }
11969 
11970   cp0 = (unsigned char *) ( up0 + inner );
11971   if ( trail > 0 )
11972     {
11973       up0[inner] = 0;
11974       for ( i = 0 ; i < trail ; i ++ )
11975 	{
11976 	  *cp0 = (unsigned char) ip0[ipack*inner+i];
11977 	  cp0++;
11978 	}
11979     }
11980 
11981   if ( tc != -1 )
11982     {
11983       bc++;
11984       *cp0 = (unsigned char) tc;
11985     }
11986 
11987   return (bc);
11988 }
11989 #endif
11990 
11991 /* unpack 8-bit bytes from a packed buffer with 32-bit words */
11992 /* same as : for ( int i = 0; i < bc; ++i ) up[i] = (INT32) cp[i]; */
11993 
11994 #ifdef  INT32
unpackInt32(const unsigned char * cp,unsigned INT32 * up,long bc,long tc)11995 long unpackInt32(const unsigned char *cp, unsigned INT32 *up, long bc, long tc)
11996 {
11997   U_BYTEORDER;
11998   const unsigned char *cp0;
11999   unsigned INT32 *ip0, *ip1, *ip2, *ip3;
12000   long head, trail, inner, i, j;
12001   long offset;
12002   long ipack = sizeof(INT32);
12003 
12004   UNUSED(tc);
12005 
12006   /* Bytes until first word boundary in source buffer */
12007 
12008   head = ( (long) cp ) & (ipack-1);
12009   if ( head != 0 ) head = ipack - head;
12010   if ( head > bc ) head = bc;
12011 
12012   inner = bc - head;
12013 
12014   /* Trailing bytes which do not make a full word */
12015 
12016   trail = inner & (ipack-1);
12017 
12018   /* Number of bytes/words to be processed in fast loop */
12019 
12020   inner -= trail;
12021   inner /= ipack;
12022 
12023   ip0 = up + head;
12024   ip1 = ip0 + 1;
12025   ip2 = ip0 + 2;
12026   ip3 = ip0 + 3;
12027 
12028   const unsigned INT32 *up0 = (const unsigned INT32 *)(const void *)(cp + head);
12029 
12030   /* Process any bytes until the first word boundary
12031    * of our source buffer
12032    */
12033   for ( i = 0 ; i < head ; i++ ) up[i] = (unsigned INT32) cp[i];
12034 
12035   j = 0;
12036 
12037   if ( IS_BIGENDIAN() )
12038     {
12039 #if defined (CRAY)
12040 #pragma _CRI ivdep
12041 #endif
12042 #if defined (SX)
12043 #pragma vdir nodep
12044 #endif
12045 #ifdef __uxpch__
12046 #pragma loop novrec
12047 #endif
12048       for ( i = 0 ; i < inner ; i++ )
12049 	{
12050 	  ip0[j] = (up0[i] >> 24) & 0xFF;
12051 	  ip1[j] = (up0[i] >> 16) & 0xFF;
12052 	  ip2[j] = (up0[i] >>  8) & 0xFF;
12053 	  ip3[j] = (up0[i])       & 0xFF;
12054 
12055 	  j += ipack;
12056 	}
12057     }
12058   else
12059     {
12060       for ( i = 0 ; i < inner ; i++ )
12061 	{
12062 	  ip3[j] = (up0[i] >> 24) & 0xFF;
12063 	  ip2[j] = (up0[i] >> 16) & 0xFF;
12064 	  ip1[j] = (up0[i] >>  8) & 0xFF;
12065 	  ip0[j] = (up0[i])       & 0xFF;
12066 
12067 	  j += ipack;
12068 	}
12069     }
12070 
12071   if ( trail > 0 )
12072     {
12073       offset = head + ipack*inner;
12074       cp0 = cp + offset;
12075       for ( i = 0 ; i < trail ; i++ ) up[i+offset] = (unsigned INT32) cp0[i];
12076     }
12077   /*
12078   if ( tc != -1 ) {
12079     bc++;
12080     *cp0 = (unsigned char) tc;
12081   }
12082   */
12083 
12084   return (bc);
12085 }
12086 #endif
12087 #include <stdio.h>
12088 
12089 
prtbin(int kin,int knbit,int * kout,int * kerr)12090 void prtbin(int kin, int knbit, int *kout, int *kerr)
12091 {
12092   /*
12093 
12094     Produces a decimal number with ones and zeroes
12095     corresponding to the ones and zeroes of the input
12096     binary number.
12097     eg input number 1011 binary, output number 1011 decimal.
12098 
12099 
12100     Input Parameters:
12101 
12102        kin   - Integer variable containing binary number.
12103 
12104        knbit - Number of bits in binary number.
12105 
12106     Output Parameters:
12107 
12108        kout  - Integer variable containing decimal value
12109                with ones and zeroes corresponding to those of
12110 	       the input binary number.
12111 
12112        kerr  - 0, If no error.
12113                1, Number of bits in binary number exceeds
12114 	          maximum allowed or is less than 1.
12115 
12116 
12117     Converted from EMOS routine PRTBIN.
12118 
12119        Uwe Schulzweida   MPIfM   01/04/2001
12120 
12121   */
12122   int idec;
12123   int ik;
12124   int itemp;
12125   int j;
12126 
12127   /*
12128     Check length of binary number to ensure decimal number
12129     generated will fit in the computer word - in this case will
12130     it fit in a Cray 48 bit integer?
12131   */
12132   if ( knbit < 1 || knbit > 14 )
12133     {
12134       *kerr = 1;
12135       printf(" prtbin : Error in binary number length - %3d bits.\n", knbit);
12136       return;
12137     }
12138   else
12139     *kerr = 0;
12140   /*
12141     -----------------------------------------------------------------
12142     Section 1. Generate required number.
12143     -----------------------------------------------------------------
12144   */
12145   *kout = 0;
12146   ik    = kin;
12147   idec  = 1;
12148 
12149   for ( j = 0; j < knbit; j++ )
12150     {
12151       itemp = ik - ( (ik/2)*2 );
12152       *kout = (*kout) + itemp * idec;
12153       ik    = ik / 2;
12154       idec  = idec * 10;
12155     }
12156 
12157   return;
12158 }
12159 
12160 
ref2ibm(double * pref,int kbits)12161 void ref2ibm(double *pref, int kbits)
12162 {
12163   /*
12164 
12165     Purpose:
12166     --------
12167 
12168     Code and check reference value in IBM format
12169 
12170     Input Parameters:
12171     -----------------
12172 
12173     pref       - Reference value
12174     kbits      - Number of bits per computer word.
12175 
12176     Output Parameters:
12177     ------------------
12178 
12179     pref       - Reference value
12180 
12181     Method:
12182     -------
12183 
12184     Codes in IBM format, then decides to ensure that reference
12185     value used for packing is not different from that stored
12186     because of packing differences.
12187 
12188     Externals.
12189     ----------
12190 
12191     confp3    - Encode into IBM floating point format.
12192     decfp2    - Decode from IBM floating point format.
12193 
12194     Reference:
12195     ----------
12196 
12197     None.
12198 
12199     Comments:
12200     --------
12201 
12202     None.
12203 
12204     Author:
12205     -------
12206 
12207     J.D.Chambers     ECMWF      17:05:94
12208 
12209     Modifications:
12210     --------------
12211 
12212     Uwe Schulzweida   MPIfM   01/04/2001
12213 
12214     Convert to C from EMOS library version 130
12215 
12216   */
12217 
12218   int itrnd;
12219   int kexp, kmant;
12220   double ztemp, zdumm;
12221   extern int CGRIBEX_Debug;
12222 
12223   /* ----------------------------------------------------------------- */
12224   /*   Section 1. Convert to and from IBM format.                      */
12225   /* ----------------------------------------------------------------- */
12226 
12227   /*  Convert floating point reference value to IBM representation. */
12228 
12229   itrnd = 1;
12230   zdumm = ztemp = *pref;
12231   confp3(zdumm, &kexp, &kmant, kbits, itrnd);
12232 
12233   if ( kexp == 0 && kmant == 0 ) return;
12234 
12235   /*  Set reference value to that actually stored in the GRIB code. */
12236 
12237   *pref = decfp2(kexp, kmant);
12238 
12239   /*  If the nearest number which can be represented in */
12240   /*  GRIB format is greater than the reference value,  */
12241   /*  find the nearest number in GRIB format lower      */
12242   /*  than the reference value.                         */
12243 
12244   if ( ztemp < *pref )
12245     {
12246       /*  Convert floating point to GRIB representation */
12247       /*  using truncation to ensure that the converted */
12248       /*  number is smaller than the original one.      */
12249 
12250       itrnd = 0;
12251       zdumm = ztemp;
12252       confp3(zdumm, &kexp, &kmant, kbits, itrnd);
12253 
12254       /*  Set reference value to that stored in the GRIB code. */
12255 
12256       *pref = decfp2(kexp, kmant);
12257 
12258       if ( ztemp < *pref )
12259 	{
12260 	  if ( CGRIBEX_Debug )
12261 	    {
12262 	      Message("Reference value error.");
12263 	      Message("Notify Met.Applications Section.");
12264 	      Message("ZTEMP = ", ztemp);
12265 	      Message("PREF = ", pref);
12266 	    }
12267 	  *pref = ztemp;
12268 	}
12269     }
12270 
12271   return;
12272 } /* ref2ibm */
12273 #include <math.h>
12274 #include <string.h>
12275 
12276 
correct_bdslen(unsigned bdslen,long recsize,long gribpos)12277 unsigned correct_bdslen(unsigned bdslen, long recsize, long gribpos)
12278 {
12279   /*
12280     If a very large product, the section 4 length field holds
12281     the number of bytes in the product after section 4 upto
12282     the end of the padding bytes.
12283     This is a fixup to get round the restriction on product lengths
12284     due to the count being only 24 bits. It is only possible because
12285     the (default) rounding for GRIB products is 120 bytes.
12286   */
12287   if ( recsize > JP23SET && bdslen <= 120 ) bdslen = (unsigned)(recsize - gribpos - bdslen);
12288   return bdslen;
12289 }
12290 
12291 
grib1Sections(unsigned char * gribbuffer,long gribbufsize,unsigned char ** pdsp,unsigned char ** gdsp,unsigned char ** bmsp,unsigned char ** bdsp,long * gribrecsize)12292 int grib1Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **pdsp,
12293 		  unsigned char **gdsp, unsigned char **bmsp, unsigned char **bdsp, long *gribrecsize)
12294 {
12295   *gribrecsize = 0;
12296   *pdsp = NULL;
12297   *gdsp = NULL;
12298   *bmsp = NULL;
12299   *bdsp = NULL;
12300 
12301   unsigned char *section = gribbuffer;
12302   unsigned char *is = gribbuffer;
12303   if ( ! GRIB_START(section) )
12304     {
12305       fprintf(stderr, "Wrong GRIB indicator section: found >%c%c%c%c<\n",
12306 	      section[0], section[1], section[2], section[3]);
12307       return -1;
12308     }
12309 
12310   unsigned recsize = GET_UINT3(section[4], section[5], section[6]);
12311 
12312   int gribversion = GRIB_EDITION(section);
12313   if ( gribversion != 0 && gribversion != 1 )
12314     {
12315       fprintf(stderr, "Error while decoding GRIB1 sections: GRIB edition %d records not supported!\n", gribversion);
12316       return -1;
12317     }
12318 
12319   unsigned grib1offset = (gribversion == 1) ? 4 : 0;
12320 
12321   unsigned char *pds = is + 4 + grib1offset;
12322   unsigned char *bufpointer = pds + PDS_Len;
12323   unsigned gribsize = 4 + grib1offset + PDS_Len;
12324 
12325   unsigned char *gds = NULL;
12326   if ( PDS_HAS_GDS )
12327     {
12328       gds = bufpointer;
12329       bufpointer += GDS_Len;
12330       gribsize += GDS_Len;
12331     }
12332 
12333   unsigned char *bms = NULL;
12334   if ( PDS_HAS_BMS )
12335     {
12336       bms = bufpointer;
12337       bufpointer += BMS_Len;
12338       gribsize += BMS_Len;
12339     }
12340 
12341   unsigned char *bds = bufpointer;
12342   unsigned bdslen = BDS_Len;
12343   if ( recsize > JP23SET && bdslen <= 120 )
12344     {
12345       recsize &= JP23SET;
12346       recsize *= 120;
12347       bdslen = correct_bdslen(bdslen, recsize, gribsize);
12348     }
12349   bufpointer += bdslen;
12350   gribsize += bdslen;
12351   gribsize += 4;
12352 
12353   *pdsp = pds;
12354   *gdsp = gds;
12355   *bmsp = bms;
12356   *bdsp = bds;
12357 
12358   *gribrecsize = gribsize;
12359   if ( gribbufsize < gribsize )
12360     {
12361       fprintf(stderr, "Inconsistent length of GRIB message (grib_buffer_size=%ld < grib_record_size=%u)!\n", gribbufsize, gribsize);
12362       return 1;
12363     }
12364 
12365   if ( !GRIB_FIN(bufpointer) ) // end section - "7777" in ASCII
12366     {
12367       fprintf(stderr, "Missing GRIB end section: found >%c%c%c%c<\n",
12368 	      bufpointer[0], bufpointer[1], bufpointer[2], bufpointer[3]);
12369       return -2;
12370     }
12371 
12372   return 0;
12373 }
12374 
12375 
grib2Sections(unsigned char * gribbuffer,long gribbufsize,unsigned char ** idsp,unsigned char ** lusp,unsigned char ** gdsp,unsigned char ** pdsp,unsigned char ** drsp,unsigned char ** bmsp,unsigned char ** bdsp)12376 int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **idsp,
12377 		  unsigned char **lusp, unsigned char **gdsp, unsigned char **pdsp,
12378 		  unsigned char **drsp, unsigned char **bmsp, unsigned char **bdsp)
12379 {
12380   UNUSED(gribbufsize);
12381 
12382   *idsp = NULL;
12383   *lusp = NULL;
12384   *gdsp = NULL;
12385   *pdsp = NULL;
12386   *drsp = NULL;
12387   *bmsp = NULL;
12388   *bdsp = NULL;
12389 
12390   unsigned char *section = gribbuffer;
12391   unsigned sec_len = 16;
12392 
12393   if ( !GRIB_START(section) )
12394     {
12395       fprintf(stderr, "wrong indicator section >%c%c%c%c<\n",
12396 	      section[0], section[1], section[2], section[3]);
12397       return -1;
12398     }
12399 
12400   int gribversion = GRIB_EDITION(section);
12401   if ( gribversion != 2 )
12402     {
12403       fprintf(stderr, "wrong GRIB version %d\n", gribversion);
12404       return -1;
12405     }
12406 
12407   unsigned gribsize = 0;
12408   for ( int i = 0; i < 8; i++ ) gribsize = (gribsize << 8) | section[8+i];
12409 
12410   unsigned grib_len = sec_len;
12411   section  += sec_len;
12412 
12413   /* section 1 */
12414   sec_len = GRIB2_SECLEN(section);
12415   int sec_num = GRIB2_SECNUM(section);
12416   //fprintf(stderr, "ids %d %ld\n", sec_num, sec_len);
12417 
12418   if ( sec_num != 1 )
12419     {
12420       fprintf(stderr, "Unexpected section1 number %d\n", sec_num);
12421       return -1;
12422     }
12423 
12424   *idsp = section;
12425 
12426   grib_len += sec_len;
12427   section  += sec_len;
12428 
12429   /* section 2 and 3 */
12430   sec_len = GRIB2_SECLEN(section);
12431   sec_num = GRIB2_SECNUM(section);
12432   //fprintf(stderr, "lus %d %ld\n", sec_num, sec_len);
12433 
12434   if ( sec_num == 2 )
12435     {
12436       *lusp = section;
12437 
12438       grib_len += sec_len;
12439       section  += sec_len;
12440 
12441       /* section 3 */
12442       sec_len = GRIB2_SECLEN(section);
12443       //sec_num = GRIB2_SECNUM(section);
12444       //fprintf(stderr, "gds %d %ld\n", sec_num, sec_len);
12445 
12446       *gdsp = section;
12447     }
12448   else if ( sec_num == 3 )
12449     {
12450       *gdsp = section;
12451     }
12452   else
12453     {
12454       fprintf(stderr, "Unexpected section3 number %d\n", sec_num);
12455       return -1;
12456     }
12457 
12458   grib_len += sec_len;
12459   section  += sec_len;
12460 
12461   /* section 4 */
12462   sec_len = GRIB2_SECLEN(section);
12463   sec_num = GRIB2_SECNUM(section);
12464   //fprintf(stderr, "pds %d %ld\n", sec_num, sec_len);
12465 
12466   if ( sec_num != 4 )
12467     {
12468       fprintf(stderr, "Unexpected section4 number %d\n", sec_num);
12469       return -1;
12470     }
12471 
12472   *pdsp = section;
12473 
12474   grib_len += sec_len;
12475   section  += sec_len;
12476 
12477   /* section 5 */
12478   sec_len = GRIB2_SECLEN(section);
12479   sec_num = GRIB2_SECNUM(section);
12480   //fprintf(stderr, "drs %d %ld\n", sec_num, sec_len);
12481 
12482   if ( sec_num != 5 )
12483     {
12484       fprintf(stderr, "Unexpected section5 number %d\n", sec_num);
12485       return -1;
12486     }
12487 
12488   *drsp = section;
12489 
12490   grib_len += sec_len;
12491   section  += sec_len;
12492 
12493   /* section 6 */
12494   sec_len = GRIB2_SECLEN(section);
12495   sec_num = GRIB2_SECNUM(section);
12496   //fprintf(stderr, "bms %d %ld\n", sec_num, sec_len);
12497 
12498   if ( sec_num != 6 )
12499     {
12500       fprintf(stderr, "Unexpected section6 number %d\n", sec_num);
12501       return -1;
12502     }
12503 
12504   *bmsp = section;
12505 
12506   grib_len += sec_len;
12507   section  += sec_len;
12508 
12509   /* section 7 */
12510   sec_len = GRIB2_SECLEN(section);
12511   sec_num = GRIB2_SECNUM(section);
12512   //fprintf(stderr, "bds %d %ld\n", sec_num, sec_len);
12513 
12514   if ( sec_num != 7 )
12515     {
12516       fprintf(stderr, "Unexpected section7 number %d\n", sec_num);
12517       return -1;
12518     }
12519 
12520   *bdsp = section;
12521 
12522   grib_len += sec_len;
12523   section  += sec_len;
12524 
12525   /* skip multi GRIB sections */
12526   int msec = 1;
12527   while ( !GRIB_FIN(section) )
12528     {
12529       sec_len = GRIB2_SECLEN(section);
12530       sec_num = GRIB2_SECNUM(section);
12531 
12532       if ( sec_num < 1 || sec_num > 7 ) break;
12533 
12534       if ( sec_num == 7 )
12535 	fprintf(stderr, "Skipped unsupported multi GRIB section %d!\n", ++msec);
12536 
12537       if ( (grib_len + sec_len) > gribsize ) break;
12538 
12539       grib_len += sec_len;
12540       section  += sec_len;
12541     }
12542 
12543   /* end section - "7777" in ASCII */
12544   if ( !GRIB_FIN(section) )
12545     {
12546       fprintf(stderr, "Missing end section >%2x %2x %2x %2x<\n",
12547 	      section[0], section[1], section[2], section[3]);
12548       return -2;
12549     }
12550 
12551   return 0;
12552 }
12553 
12554 
grib_info_for_grads(off_t recpos,long recsize,unsigned char * gribbuffer,int * intnum,float * fltnum,off_t * bignum)12555 int grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer,
12556 			int *intnum, float *fltnum, off_t *bignum)
12557 {
12558   long gribsize = 0;
12559   off_t bpos = 0;
12560 
12561   unsigned char *section = gribbuffer;
12562   unsigned char *is = gribbuffer;
12563   if ( ! GRIB_START(section) )
12564     {
12565       fprintf(stderr, "wrong indicator section >%c%c%c%c<\n",
12566 	      section[0], section[1], section[2], section[3]);
12567       return -1;
12568     }
12569 
12570   int gribversion = GRIB_EDITION(section);
12571   if ( recsize == 24 && gribversion == 0 ) gribversion = 0;
12572 
12573   unsigned grib1offset = (gribversion == 1) ? 4 : 0;
12574 
12575   unsigned char *pds = is + 4 + grib1offset;
12576   unsigned char *bufpointer = pds + PDS_Len;
12577   gribsize += 4 + grib1offset + PDS_Len;
12578 
12579   unsigned char *gds = NULL;
12580   if ( PDS_HAS_GDS )
12581     {
12582       gds = bufpointer;
12583       bufpointer += GDS_Len;
12584       gribsize += GDS_Len;
12585     }
12586 
12587   unsigned char *bms = NULL;
12588   if ( PDS_HAS_BMS )
12589     {
12590       bms = bufpointer;
12591       bufpointer += BMS_Len;
12592       bpos = recpos + gribsize + 6;
12593       gribsize += BMS_Len;
12594     }
12595 
12596   unsigned char *bds = bufpointer;
12597 
12598   off_t dpos = recpos + gribsize + 11;
12599 
12600   unsigned bdslen = BDS_Len;
12601   bdslen = correct_bdslen(bdslen, recsize, bds-gribbuffer);
12602   bufpointer += bdslen;
12603   gribsize += bdslen;
12604   gribsize += 4;
12605 
12606   if ( gribsize > recsize )
12607     {
12608       fprintf(stderr, "GRIB buffer size %ld too small! Min size = %ld\n", recsize, gribsize);
12609       return 1;
12610     }
12611 
12612   /* end section - "7777" in ascii */
12613   if ( !GRIB_FIN(bufpointer) )
12614     {
12615       fprintf(stderr, "Missing end section >%2x %2x %2x %2x<\n",
12616 	      bufpointer[0], bufpointer[1], bufpointer[2], bufpointer[3]);
12617     }
12618 
12619   int bs = BDS_BinScale;
12620   if ( bs > 32767 ) bs = 32768-bs;
12621   float bsf = ldexpf(1.0f, bs);
12622 
12623   bignum[0] = dpos;
12624   bignum[1] = bms ? bpos : -999;
12625   intnum[0] = BDS_NumBits;
12626 
12627   /*  fltnum[0] = 1.0; */
12628   fltnum[0] = powf(10.0f, (float)PDS_DecimalScale);
12629   fltnum[1] = bsf;
12630   fltnum[2] = (float)BDS_RefValue;
12631   /*
12632   printf("intnum %d %d %d\n", intnum[0], intnum[1], intnum[2]);
12633   printf("fltnum %g %g %g\n", fltnum[0], fltnum[1], fltnum[2]);
12634   */
12635   return 0;
12636 }
12637 
12638 static
get_level(unsigned char * pds)12639 int get_level(unsigned char *pds)
12640 {
12641   int level = 0;
12642 
12643   if ( PDS_LevelType == 100 )
12644     level = PDS_Level * 100;
12645   else if ( PDS_LevelType == 99 )
12646     level = PDS_Level;
12647   else if ( PDS_LevelType == 109 )
12648     level = PDS_Level;
12649   else
12650     level = PDS_Level1;
12651 
12652   return level;
12653 }
12654 
12655 static
get_cr(unsigned char * w1,unsigned char * w2)12656 double get_cr(unsigned char *w1, unsigned char *w2)
12657 {
12658   unsigned s1 = GET_UINT3(w1[0], w1[1], w1[2]);
12659   unsigned s2 = GET_UINT3(w2[0], w2[1], w2[2]);
12660   return ((double)s1)/s2;
12661 }
12662 
12663 
grib1PrintALL(int nrec,long offset,long recpos,long recsize,unsigned char * gribbuffer)12664 static void grib1PrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
12665 {
12666   static bool header = true;
12667   unsigned char *is = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
12668 
12669   if ( header )
12670     {
12671       fprintf(stdout,
12672       "  Rec : Off Position   Size : V PDS  GDS    BMS    BDS : Code Level :  LType GType: CR LL\n");
12673 /*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
12674       header = false;
12675     }
12676 
12677   is = gribbuffer;
12678 
12679   unsigned gribsize = GET_UINT3(is[4], is[5], is[6]);
12680 
12681   long gribrecsize;
12682   int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
12683   if ( nerr < 0 )
12684     {
12685       fprintf(stdout, "%5d :%4ld %8ld %6ld : GRIB message error\n", nrec, offset, recpos, recsize);
12686       return;
12687     }
12688 
12689   int GridType = (gds == NULL) ? -1 : (int)GDS_GridType;
12690 
12691   int level = get_level(pds);
12692 
12693   unsigned bdslen = BDS_Len;
12694 
12695   bool llarge = (gribsize > JP23SET && bdslen <= 120);
12696 
12697   bdslen = correct_bdslen(bdslen, recsize, bds-gribbuffer);
12698 
12699   double cr = (((BDS_Flag >> 4)&1) && (BDS_Z == 128 || BDS_Z == 130)) ? get_cr(&bds[14], &gribbuffer[4]) : 1;
12700 
12701   fprintf(stdout, "%5d :%4ld %8ld %6ld :%2d%4d%5d %6d %6d : %3d %6d : %5d %5d %6.4g  %c",
12702 	  nrec, offset, recpos, recsize, GRIB_EDITION(is),
12703 	  PDS_Len, GDS_Len, BMS_Len, bdslen,
12704 	  PDS_Parameter, level, PDS_LevelType, GridType, cr, llarge?'T':'F');
12705 
12706   if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
12707   fprintf(stdout, "\n");
12708 }
12709 
12710 
grib2PrintALL(int nrec,long offset,long recpos,long recsize,unsigned char * gribbuffer)12711 static void grib2PrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
12712 {
12713   static bool header = true;
12714   unsigned char *is  = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
12715   unsigned char *ids = NULL, *lus = NULL, *drs = NULL;
12716   long ids_len = 0, lus_len = 0, gds_len = 0, pds_len = 0, drs_len = 0, bms_len = 0, bds_len = 0;
12717   double cr = 1;
12718 
12719   if ( header )
12720     {
12721       fprintf(stdout,
12722       "  Rec : Off Position   Size : V IDS LUS GDS PDS  DRS    BMS    BDS : Parameter   Level :  LType GType: CR\n");
12723 /*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
12724       header = false;
12725     }
12726 
12727   is = gribbuffer;
12728 
12729   int nerr = grib2Sections(gribbuffer, recsize, &ids, &lus, &gds, &pds, &drs, &bms, &bds);
12730   if ( nerr )
12731     {
12732       fprintf(stdout, "%5d :%4ld %8ld %6ld : error\n", nrec, offset, recpos, recsize);
12733       return;
12734     }
12735 
12736   if ( ids ) ids_len = GRIB2_SECLEN(ids);
12737   if ( lus ) lus_len = GRIB2_SECLEN(lus);
12738   if ( gds ) gds_len = GRIB2_SECLEN(gds);
12739   if ( pds ) pds_len = GRIB2_SECLEN(pds);
12740   if ( drs ) drs_len = GRIB2_SECLEN(drs);
12741   if ( bms ) bms_len = GRIB2_SECLEN(bms);
12742   if ( bds ) bds_len = GRIB2_SECLEN(bds);
12743 
12744   // double cr = (((BDS_Flag >> 4)&1) && (BDS_Z == 128 || BDS_Z == 130)) ? get_cr(&bds[14], &gribbuffer[4]) : 1;
12745 
12746   int dis        = GET_UINT1(is[6]);
12747   int gridtype   = GET_UINT2(gds[12],gds[13]);
12748   int paramcat   = GET_UINT1(pds[9]);
12749   int paramnum   = GET_UINT1(pds[10]);
12750   int level1type = GET_UINT1(pds[22]);
12751   /* level1sf   = GET_UINT1(pds[23]); */
12752   int level1     = GET_UINT4(pds[24],pds[25],pds[26],pds[27]);
12753   /* level2type = GET_UINT1(pds[28]); */
12754   /* level2sf   = GET_UINT1(pds[29]); */
12755   /* level2     = GET_UINT4(pds[30],pds[31],pds[32],pds[33]); */
12756   /*
12757   printf("level %d %d %d %d %d %d %d\n", level1type, level1sf, level1, level1*level1sf, level2sf, level2, level2*level2sf);
12758   */
12759   char paramstr[16];
12760   sprintf(paramstr, "%d.%d.%d", paramnum, paramcat, dis);
12761   fprintf(stdout, "%5d :%4ld %8ld %6ld :%2d %3ld %3ld %3ld %3ld %4ld %6ld %6ld : %-9s %7d : %5d %5d %6.4g\n",
12762 	  nrec, offset, recpos, recsize, GRIB_EDITION(is),
12763 	  ids_len, lus_len, gds_len, pds_len, drs_len, bms_len, bds_len,
12764 	  paramstr, level1, level1type, gridtype, cr);
12765 }
12766 
12767 
gribPrintALL(int nrec,long offset,long recpos,long recsize,unsigned char * gribbuffer)12768 void gribPrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
12769 {
12770   int gribversion = gribVersion(gribbuffer, (size_t)recsize);
12771 
12772   if ( gribversion == 0 || gribversion == 1 )
12773     grib1PrintALL(nrec, offset, recpos, recsize, gribbuffer);
12774   else if ( gribversion == 2 )
12775     grib2PrintALL(nrec, offset, recpos, recsize, gribbuffer);
12776   else
12777     {
12778       fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
12779 	      nrec, offset, recpos, recsize, gribversion);
12780     }
12781 }
12782 
12783 
grib1PrintPDS(int nrec,long recpos,long recsize,unsigned char * gribbuffer)12784 static void grib1PrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
12785 {
12786   static int header = 1;
12787   unsigned char *is = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
12788   int century, subcenter, decimalscale;
12789   int fc_num = 0;
12790   int year = 0, date;
12791 
12792   UNUSED(recpos);
12793 
12794   if ( header )
12795     {
12796       fprintf(stdout,
12797       "  Rec : PDS Tab Cen Sub Ver Grid Code LTyp Level1 Level2    Date  Time P1 P2 TU TR NAVE Scale FCnum CT\n");
12798 /*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
12799       header = 0;
12800     }
12801 
12802   is = gribbuffer;
12803 
12804   long gribrecsize;
12805   int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
12806   if ( nerr < 0 )
12807     {
12808       fprintf(stdout, "%5d : GRIB message error\n", nrec);
12809       return;
12810     }
12811 
12812   switch(GRIB_EDITION(is))
12813     {
12814     case 0:
12815       year                = GET_UINT1(pds[12]);
12816       century             = 1;
12817       subcenter           = 0;
12818       decimalscale        = 0;
12819       break;
12820     case 1:
12821       year                = PDS_Year;
12822       century             = PDS_Century;
12823       subcenter           = PDS_Subcenter;
12824       decimalscale        = PDS_DecimalScale;
12825       break;
12826     default:
12827       fprintf(stderr, "Grib version %d not supported!", GRIB_EDITION(is));
12828       exit(EXIT_FAILURE);
12829     }
12830 
12831   if ( PDS_Len > 28 )
12832     if ( PDS_CenterID    == 98 || PDS_Subcenter == 98 ||
12833 	(PDS_CenterID    ==  7 && PDS_Subcenter == 98) )
12834       if ( pds[40] == 1 )
12835 	fc_num = GET_UINT1(pds[49]);
12836 
12837   if ( year < 0 )
12838     {
12839       date = (-year)*10000+PDS_Month*100+PDS_Day;
12840       century = -century;
12841     }
12842   else
12843     {
12844       date =    year*10000+PDS_Month*100+PDS_Day;
12845     }
12846 
12847   fprintf(stdout, "%5d :%4d%4d%4d%4d%4d %4d %4d%4d%7d%7d %8d%6d%3d%3d%3d%3d%5d%6d%5d%4d", nrec,
12848 	  PDS_Len,  PDS_CodeTable,   PDS_CenterID, subcenter, PDS_ModelID,
12849 	  PDS_GridDefinition, PDS_Parameter, PDS_LevelType, PDS_Level1, PDS_Level2,
12850 	  date, PDS_Time, PDS_TimePeriod1, PDS_TimePeriod2, PDS_TimeUnit, PDS_TimeRange,
12851 	  PDS_AvgNum, decimalscale, fc_num, century);
12852 
12853   if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
12854   fprintf(stdout, "\n");
12855 }
12856 
12857 
gribPrintPDS(int nrec,long recpos,long recsize,unsigned char * gribbuffer)12858 void gribPrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
12859 {
12860   int gribversion = gribVersion(gribbuffer, (size_t)recsize);
12861 
12862   if ( gribversion == 0 || gribversion == 1 )
12863     grib1PrintPDS(nrec, recpos, recsize, gribbuffer);
12864   /*
12865   else if ( gribversion == 2 )
12866     grib2PrintPDS(nrec, recpos, recsize, gribbuffer);
12867   */
12868   else
12869     {
12870       fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
12871 	      nrec, 0L, recpos, recsize, gribversion);
12872     }
12873 }
12874 
12875 
grib1PrintGDS(int nrec,long recpos,long recsize,unsigned char * gribbuffer)12876 static void grib1PrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
12877 {
12878   static int header = 1;
12879   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
12880 
12881   UNUSED(recpos);
12882 
12883   if ( header )
12884     {
12885       fprintf(stdout,
12886       "  Rec : GDS  NV PVPL Typ : xsize ysize   Lat1   Lon1   Lat2   Lon2    dx    dy\n");
12887 /*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
12888       header = 0;
12889     }
12890 
12891   long gribrecsize;
12892   int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
12893   if ( nerr < 0 )
12894     {
12895       fprintf(stdout, "%5d : GRIB message error\n", nrec);
12896       return;
12897     }
12898 
12899   fprintf(stdout, "%5d :", nrec);
12900 
12901   if ( gds )
12902     fprintf(stdout, "%4d%4d%4d %4d :%6d%6d%7d%7d%7d%7d%6d%6d",
12903 	    GDS_Len,  GDS_NV,   GDS_PVPL, GDS_GridType,
12904 	    GDS_NumLon,   GDS_NumLat,
12905 	    GDS_FirstLat, GDS_FirstLon,
12906 	    GDS_LastLat,  GDS_LastLon,
12907 	    GDS_LonIncr,  GDS_LatIncr);
12908   else
12909     fprintf(stdout, " Grid Description Section not defined");
12910 
12911   if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
12912   fprintf(stdout, "\n");
12913 }
12914 
12915 
gribPrintGDS(int nrec,long recpos,long recsize,unsigned char * gribbuffer)12916 void gribPrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
12917 {
12918   int gribversion = gribVersion(gribbuffer, (size_t)recsize);
12919 
12920   if ( gribversion == 0 || gribversion == 1 )
12921     grib1PrintGDS(nrec, recpos, recsize, gribbuffer);
12922   /*
12923   else if ( gribversion == 2 )
12924     grib2PrintGDS(nrec, recpos, recsize, gribbuffer);
12925   */
12926   else
12927     {
12928       fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
12929 	      nrec, 0L, recpos, recsize, gribversion);
12930     }
12931 }
12932 
12933 
grib1PrintBMS(int nrec,long recpos,long recsize,unsigned char * gribbuffer)12934 static void grib1PrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
12935 {
12936   static int header = 1;
12937   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
12938 
12939   UNUSED(recpos);
12940 
12941   if ( header )
12942     {
12943       fprintf(stdout,
12944       "  Rec : Code Level     BMS    Size\n");
12945 /*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
12946       header = 0;
12947     }
12948 
12949   long gribrecsize;
12950   int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
12951   if ( nerr < 0 )
12952     {
12953       fprintf(stdout, "%5d : GRIB message error\n", nrec);
12954       return;
12955     }
12956 
12957   int level = get_level(pds);
12958 
12959   fprintf(stdout, "%5d :", nrec);
12960 
12961   if ( bms )
12962     fprintf(stdout, "%4d%7d %7d %7d",
12963 	    PDS_Parameter, level, BMS_Len, BMS_BitmapSize);
12964   else
12965     fprintf(stdout, "%4d%7d Bit Map Section not defined", PDS_Parameter, level);
12966 
12967   if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
12968   fprintf(stdout, "\n");
12969 }
12970 
12971 
gribPrintBMS(int nrec,long recpos,long recsize,unsigned char * gribbuffer)12972 void gribPrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
12973 {
12974   int gribversion = gribVersion(gribbuffer, (size_t)recsize);
12975 
12976   if ( gribversion == 0 || gribversion == 1 )
12977     grib1PrintBMS(nrec, recpos, recsize, gribbuffer);
12978   /*
12979   else if ( gribversion == 2 )
12980     grib2PrintBMS(nrec, recpos, recsize, gribbuffer);
12981   */
12982   else
12983     {
12984       fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
12985 	      nrec, 0L, recpos, recsize, gribversion);
12986     }
12987 }
12988 
12989 
grib1PrintBDS(int nrec,long recpos,long recsize,unsigned char * gribbuffer)12990 static void grib1PrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
12991 {
12992   static int header = 1;
12993   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
12994   double scale;
12995 
12996   UNUSED(recpos);
12997 
12998   if ( header )
12999     {
13000       fprintf(stdout,
13001       "  Rec : Code Level     BDS Flag     Scale   RefValue Bits  CR\n");
13002 /*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
13003       header = 0;
13004     }
13005 
13006   long gribrecsize;
13007   int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
13008   if ( nerr < 0 )
13009     {
13010       fprintf(stdout, "%5d : GRIB message error\n", nrec);
13011       return;
13012     }
13013 
13014   int level = get_level(pds);
13015 
13016   double cr = (((BDS_Flag >> 4)&1) && BDS_Z == 128) ? get_cr(&bds[17], &bds[20]) : 1;
13017 
13018   double refval = BDS_RefValue;
13019 
13020   if ( BDS_BinScale < 0 )
13021     scale = 1.0/pow(2.0, (double) -BDS_BinScale);
13022   else
13023     scale = pow(2.0, (double) BDS_BinScale);
13024 
13025   if ( PDS_DecimalScale )
13026     {
13027       double decscale = pow(10.0, (double)-PDS_DecimalScale);
13028       refval *= decscale;
13029       scale  *= decscale;
13030     }
13031 
13032   fprintf(stdout, "%5d :", nrec);
13033 
13034   if ( bds )
13035     fprintf(stdout, "%4d%7d %7d %4d %8.5g %11.5g%4d %6.4g",
13036 	    PDS_Parameter, level,
13037 	    BDS_Len, BDS_Flag, scale, refval, BDS_NumBits, cr);
13038   else
13039     fprintf(stdout, " Binary Data Section not defined");
13040 
13041   if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
13042   fprintf(stdout, "\n");
13043 }
13044 
13045 
gribPrintBDS(int nrec,long recpos,long recsize,unsigned char * gribbuffer)13046 void gribPrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
13047 {
13048   int gribversion = gribVersion(gribbuffer, (size_t)recsize);
13049 
13050   if ( gribversion == 0 || gribversion == 1 )
13051     grib1PrintBDS(nrec, recpos, recsize, gribbuffer);
13052   /*
13053   else if ( gribversion == 2 )
13054     grib2PrintBDS(nrec, recpos, recsize, gribbuffer);
13055   */
13056   else
13057     {
13058       fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
13059 	      nrec, 0L, recpos, recsize, gribversion);
13060     }
13061 }
13062 
13063 
gribCheck1(int nrec,long recpos,long recsize,unsigned char * gribbuffer)13064 void gribCheck1(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
13065 {
13066   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
13067 
13068   UNUSED(recpos);
13069 
13070   long gribrecsize;
13071   int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
13072   if ( nerr < 0 )
13073     {
13074       fprintf(stdout, "%5d : GRIB message error\n", nrec);
13075       return;
13076     }
13077 
13078   if ( nerr > 0 )
13079     {
13080       fprintf(stdout, "%5d : <-- GRIB data corrupted!\n", nrec);
13081       return;
13082     }
13083 
13084   int level = get_level(pds);
13085 
13086   double cr = (((BDS_Flag >> 4)&1) && BDS_Z == 128) ? get_cr(&bds[17], &bds[20]) : 1;
13087 
13088   if ( IS_EQUAL(cr, 1) && BDS_NumBits == 24 )
13089     fprintf(stdout, "GRIB record %5d : code = %4d   level = %7d\n", nrec, PDS_Parameter, level);
13090 }
13091 
13092 
13093 static
repair1(unsigned char * gbuf,long gbufsize)13094 void repair1(unsigned char *gbuf, long gbufsize)
13095 {
13096   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
13097   /* int recLen; */
13098   unsigned char *source;
13099   size_t sourceLen;
13100   int bds_nbits, bds_flag, lspherc, lcomplex /*, lcompress */;
13101   int bds_head = 11;
13102   int bds_ext = 0, bds_ubits;
13103   int datstart = 0;
13104 
13105   long gribrecsize;
13106   int nerr = grib1Sections(gbuf, gbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
13107   if ( nerr < 0 )
13108     {
13109       fprintf(stdout, "GRIB message error\n");
13110       return;
13111     }
13112 
13113   if ( nerr > 0 )
13114     {
13115       fprintf(stdout, "GRIB data corrupted!\n");
13116       return;
13117     }
13118 
13119   unsigned bds_len   = BDS_Len;
13120   bds_nbits = BDS_NumBits;
13121   bds_flag  = BDS_Flag;
13122   bds_ubits = bds_flag & 15;
13123   lspherc   =  bds_flag >> 7;
13124   lcomplex  = (bds_flag >> 6)&1;
13125   /* lcompress = (bds_flag >> 4)&1; */
13126 
13127   if ( lspherc )
13128     {
13129       if ( lcomplex  )
13130 	{
13131 	  int jup, ioff;
13132 	  jup  = bds[15];
13133 	  ioff = (jup+1)*(jup+2);
13134 	  bds_ext = 4 + 3 + 4*ioff;
13135 	}
13136       else
13137 	{
13138 	  bds_ext = 4;
13139 	}
13140     }
13141 
13142   datstart = bds_head + bds_ext;
13143 
13144   source = bds + datstart;
13145 
13146   sourceLen = (size_t)(((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8);
13147 
13148   if ( bds_nbits == 24 )
13149     {
13150       unsigned char *pbuf = (unsigned char*) Malloc(sourceLen);;
13151       size_t nelem = sourceLen/3;
13152       for ( size_t i = 0; i < nelem; i++ )
13153 	{
13154 	  pbuf[3*i  ] = source[        i];
13155 	  pbuf[3*i+1] = source[  nelem+i];
13156 	  pbuf[3*i+2] = source[2*nelem+i];
13157 	}
13158       memcpy(source, pbuf, sourceLen);
13159       Free(pbuf);
13160     }
13161 }
13162 
13163 
gribRepair1(int nrec,long recsize,unsigned char * gribbuffer)13164 void gribRepair1(int nrec, long recsize, unsigned char *gribbuffer)
13165 {
13166   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
13167 
13168   long gribrecsize;
13169   int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
13170   if ( nerr < 0 )
13171     {
13172       fprintf(stdout, "%5d : GRIB message error\n", nrec);
13173       return;
13174     }
13175 
13176   if ( nerr > 0 )
13177     {
13178       fprintf(stdout, "%5d : <-- GRIB data corrupted!\n", nrec);
13179       return;
13180     }
13181 
13182   int level = get_level(pds);
13183 
13184   double cr = (((BDS_Flag >> 4)&1) && BDS_Z == 128) ? get_cr(&bds[17], &bds[20]) : 1;
13185 
13186   if ( IS_EQUAL(cr, 1) && BDS_NumBits == 24 )
13187     {
13188       fprintf(stdout, "Repair GRIB record %5d : code = %4d   level = %7d\n", nrec, PDS_Parameter, level);
13189       repair1(gribbuffer, recsize);
13190     }
13191 }
13192 #include <stdio.h>
13193 #include <string.h>
13194 
13195 #if defined (HAVE_CONFIG_H)
13196 #endif
13197 
13198 #if  defined (HAVE_LIBSZ)
13199 #if defined(__cplusplus)
13200 extern "C" {
13201 #endif
13202 #include <szlib.h>
13203 #ifdef  __cplusplus
13204 }
13205 #endif
13206 
13207 #define OPTIONS_MASK        (SZ_RAW_OPTION_MASK | SZ_MSB_OPTION_MASK | SZ_NN_OPTION_MASK)
13208 
13209 #define PIXELS_PER_BLOCK    (8)
13210 #define PIXELS_PER_SCANLINE (PIXELS_PER_BLOCK*128)
13211 
13212 #define MIN_COMPRESS        (0.95)
13213 #define MIN_SIZE            (256)
13214 #endif
13215 
13216 #define  Z_SZIP  128
13217 
13218 #if  defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC)
13219 #define SetLen3(var, offset, value) ((var[offset+0] = 0xFF & (value >> 16)), \
13220 				     (var[offset+1] = 0xFF & (value >>  8)), \
13221 				     (var[offset+2] = 0xFF & (value      )))
13222 #define SetLen4(var, offset, value) ((var[offset+0] = 0xFF & (value >> 24)), \
13223 				     (var[offset+1] = 0xFF & (value >> 16)), \
13224 				     (var[offset+2] = 0xFF & (value >>  8)), \
13225 				     (var[offset+3] = 0xFF & (value      )))
13226 #endif
13227 
gribGetZip(size_t recsize,unsigned char * gribbuffer,size_t * urecsize)13228 int gribGetZip(size_t recsize, unsigned char *gribbuffer, size_t *urecsize)
13229 {
13230   int compress = 0;
13231   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
13232 
13233   int gribversion = gribVersion(gribbuffer, recsize);
13234 
13235   if ( gribversion == 2 ) return compress;
13236 
13237   long gribrecsize;
13238   int nerr = grib1Sections(gribbuffer, (long)recsize, &pds, &gds, &bms, &bds, &gribrecsize);
13239   if ( nerr < 0 )
13240     {
13241       fprintf(stdout, "GRIB message error\n");
13242       return compress;
13243     }
13244 
13245   if ( nerr > 0 )
13246     {
13247       fprintf(stdout, "GRIB data corrupted!\n");
13248       return compress;
13249     }
13250 
13251   /* bds_len   = BDS_Len; */
13252   /* bds_nbits = BDS_NumBits; */
13253   int bds_flag  = BDS_Flag;
13254   /* lspherc   =  bds_flag >> 7; */
13255   /* lcomplex  = (bds_flag >> 6)&1; */
13256   int lcompress = (bds_flag >> 4)&1;
13257 
13258   size_t gribsize = 0;
13259   if ( lcompress )
13260     {
13261       compress = BDS_Z;
13262       if ( compress == Z_SZIP ) gribsize = (size_t) GET_UINT3(bds[14], bds[15], bds[16]);
13263     }
13264 
13265   *urecsize = gribsize;
13266 
13267   return compress;
13268 }
13269 
13270 
gribZip(unsigned char * dbuf,long dbufsize,unsigned char * sbuf,long sbufsize)13271 int gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize)
13272 {
13273 #if ! defined(HAVE_LIBSZ)
13274   static int libszwarn = 1;
13275 #endif
13276   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
13277   bool llarge = false;
13278 
13279   unsigned gribLen = GET_UINT3(dbuf[4], dbuf[5], dbuf[6]);
13280 
13281   int rec_len = gribLen;
13282 
13283   long gribrecsize;
13284   int nerr = grib1Sections(dbuf, dbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
13285   if ( nerr < 0 )
13286     {
13287       fprintf(stdout, "GRIB message error\n");
13288       return gribrecsize;
13289     }
13290 
13291   if ( nerr > 0 )
13292     {
13293       fprintf(stdout, "GRIB data corrupted!\n");
13294       return gribrecsize;
13295     }
13296 
13297    int bds_zoffset = 12;
13298 
13299    int bds_len   = BDS_Len;
13300    if ( gribLen > JP23SET && bds_len <= 120 )
13301      {
13302        gribLen &= JP23SET;
13303        gribLen *= 120;
13304        bds_len = correct_bdslen(bds_len, gribLen, bds-dbuf);
13305        llarge = true;
13306        bds_zoffset += 2;
13307      }
13308 
13309    if ( gribLen > JP24SET || llarge ) return gribLen;
13310 
13311 #if  defined(HAVE_LIBSZ)
13312   {
13313     int bds_zstart = 14;
13314     unsigned gribLenOld = 0;
13315     int bds_head = 11;
13316     int bds_ext = 0;
13317     unsigned char *pbuf = NULL;
13318 
13319     int bds_nbits = BDS_NumBits;
13320     int bds_flag  = BDS_Flag;
13321     int bds_ubits = bds_flag & 15;
13322     int lspherc   =  bds_flag >> 7;
13323     int lcomplex  = (bds_flag >> 6)&1;
13324     /* lcompress = (bds_flag >> 4)&1; */
13325 
13326     if ( bds_nbits != 8 && bds_nbits != 16 && bds_nbits != 24 && bds_nbits != 32 )
13327       {
13328 	static bool linfo = true;
13329 	if ( linfo && bds_nbits != 0 )
13330 	  {
13331 	    linfo = false;
13332 	    fprintf(stderr, "GRIB szip supports only 8, 16, 24 and 32 bit data!\n");
13333 	  }
13334 	return rec_len;
13335       }
13336 
13337     int bits_per_sample = (bds_nbits == 24) ? 8 : bds_nbits;
13338 
13339     SZ_com_t sz_param;          /* szip parameter block */
13340     sz_param.options_mask        = OPTIONS_MASK;
13341     sz_param.bits_per_pixel      = bits_per_sample;
13342     sz_param.pixels_per_block    = PIXELS_PER_BLOCK;
13343     sz_param.pixels_per_scanline = PIXELS_PER_SCANLINE;
13344 
13345     if ( lspherc )
13346       {
13347         bds_ext = 4;
13348 	if ( lcomplex )
13349 	  {
13350 	    int jup  = bds[15];
13351 	    int ioff = (jup+1)*(jup+2);
13352 	    bds_ext += 3 + 4*ioff;
13353 	  }
13354       }
13355 
13356     size_t datstart = bds_head + bds_ext;
13357 
13358     size_t datsize = ((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8;
13359 
13360     if ( datsize < MIN_SIZE ) return rec_len;
13361     /*
13362     fprintf(stderr, "%d %d %d %d\n", bds_len, datstart, bds_len - datstart, datsize);
13363     */
13364     size_t sourceLen = datsize;
13365     size_t destLen   = sbufsize;
13366 
13367     unsigned char *source = bds + datstart;
13368     unsigned char *dest = sbuf;
13369 
13370     if ( bds_nbits == 24 )
13371       {
13372 	long nelem = sourceLen/3;
13373 	pbuf = (unsigned char*) Malloc(sourceLen);
13374 	for ( long i = 0; i < nelem; i++ )
13375 	  {
13376 	    pbuf[        i] = source[3*i  ];
13377 	    pbuf[  nelem+i] = source[3*i+1];
13378 	    pbuf[2*nelem+i] = source[3*i+2];
13379 	  }
13380 	source = pbuf;
13381       }
13382 
13383     int status = SZ_BufftoBuffCompress(dest, &destLen, source, sourceLen, &sz_param);
13384     if ( status != SZ_OK )
13385       {
13386 	if ( status == SZ_NO_ENCODER_ERROR )
13387 	  Warning("SZ_NO_ENCODER_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
13388 	else if ( status == SZ_PARAM_ERROR )
13389 	  Warning("SZ_PARAM_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
13390 	else if ( status == SZ_MEM_ERROR )
13391 	  Warning("SZ_MEM_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
13392 	else if ( status == SZ_OUTBUFF_FULL )
13393 	  /*Warning("SZ_OUTBUFF_FULL code %3d level %3d", PDS_Parameter, PDS_Level2)*/;
13394 	else
13395 	  Warning("SZ ERROR: %d code %3d level %3d", status, PDS_Parameter, PDS_Level2);
13396       }
13397 
13398     if ( pbuf ) Free(pbuf);
13399     /*
13400     fprintf(stderr, "sourceLen, destLen %d %d\n", sourceLen, destLen);
13401     */
13402     if ( destLen < MIN_COMPRESS*sourceLen )
13403       {
13404 	source = bds + datstart + bds_zoffset;
13405 	memcpy(source, dest, destLen);
13406 
13407 	/* ----++++ number of unused bits at end of section) */
13408 
13409 	BDS_Flag -= bds_ubits;
13410 
13411 	gribLenOld = gribLen;
13412 
13413 	if ( bds_ext )
13414 	  for ( long i = bds_ext-1; i >= 0; --i )
13415 	    bds[bds_zoffset+bds_head+i] = bds[bds_head+i];
13416 
13417 	/*
13418 	fprintf(stderr, "destLen, datsize, datstart %d %d %d\n", destLen, datsize, datstart);
13419 	*/
13420 	/*	memcpy(bds + datstart + bds_zoffset, source, destLen); */
13421 	/*
13422 	  fprintf(stderr, "z>>> %d %d %d %d <<<\n", (int) bds[0+datstart+bds_zoffset],
13423 	    (int)bds[1+datstart+bds_zoffset], (int)bds[2+datstart+bds_zoffset], (int)bds[3+datstart+bds_zoffset]);
13424 	*/
13425 	if ( llarge )
13426 	  {
13427 	    if ( gribLenOld%120 )
13428 	      {
13429 		fprintf(stderr, "Internal problem, record length not multiple of 120!");
13430 		while ( gribLenOld%120 ) gribLenOld++;
13431 	      }
13432             // gribLenOld = gribLenOld / (-120);
13433 	    // gribLenOld = JP23SET - gribLenOld + 1;
13434 
13435 	    SetLen3(bds, bds_zstart, gribLenOld);
13436 	    SetLen4(bds, bds_zstart+3, sourceLen);
13437 	    SetLen4(bds, bds_zstart+7, destLen);
13438 	  }
13439 	else
13440 	  {
13441 	    SetLen3(bds, bds_zstart, gribLenOld);
13442 	    SetLen3(bds, bds_zstart+3, sourceLen);
13443 	    SetLen3(bds, bds_zstart+6, destLen);
13444 	  }
13445 
13446 	int bdsLen = datstart + bds_zoffset + destLen;
13447 
13448 	bds[11] = 0;
13449 	bds[12] = 0;
13450 
13451 	BDS_Z   = Z_SZIP;
13452 
13453 	BDS_Flag += 16;
13454 	if ( (bdsLen%2) == 1 )
13455 	  {
13456 	    BDS_Flag += 8;
13457 	    bds[bdsLen++] = 0;
13458 	  }
13459 
13460 	SetLen3(bds, 0, bdsLen);
13461 
13462 	gribLen = (bds - dbuf) + bdsLen;
13463 
13464 	dbuf[gribLen++] = '7';
13465 	dbuf[gribLen++] = '7';
13466 	dbuf[gribLen++] = '7';
13467 	dbuf[gribLen++] = '7';
13468 
13469 	if ( llarge )
13470 	  {
13471 	    long bdslen = gribLen - 4;
13472 
13473 	    /*
13474 	      If a very large product, the section 4 length field holds
13475 	      the number of bytes in the product after section 4 upto
13476 	      the end of the padding bytes.
13477 	      This is a fixup to get round the restriction on product lengths
13478 	      due to the count being only 24 bits. It is only possible because
13479 	      the (default) rounding for GRIB products is 120 bytes.
13480 	    */
13481 	    while ( gribLen%120 ) dbuf[gribLen++] = 0;
13482 
13483 	    long itemp = gribLen / (-120);
13484 	    itemp = JP23SET - itemp + 1;
13485 
13486 	    SetLen3(dbuf, 4, itemp);
13487 
13488 	    bdslen = gribLen - bdslen;
13489 
13490 	    SetLen3(bds, 0, bdslen);
13491 	  }
13492 	else
13493 	  {
13494 	    SetLen3(dbuf, 4, gribLen);
13495 	  }
13496       }
13497     else
13498       {
13499       }
13500     /*
13501     fprintf(stderr, "%3d %3d griblen in %6d  out %6d  CR %g   slen %6d dlen %6d  CR %g\n",
13502 	    PDS_Parameter, PDS_Level1, gribLenOld, gribLen,
13503 	    ((double)gribLenOld)/gribLen, sourceLen, destLen,
13504 	    ((double)sourceLen)/destLen);
13505     */
13506   }
13507 
13508 #else
13509 
13510   UNUSED(sbuf);
13511   UNUSED(sbufsize);
13512 
13513   if ( libszwarn )
13514     {
13515       Warning("Compression disabled, szlib not available!");
13516       libszwarn = 0;
13517     }
13518 #endif
13519 
13520   if ( llarge )
13521     while ( gribLen%120 ) dbuf[gribLen++] = 0;
13522   else
13523     while ( gribLen & 7 ) dbuf[gribLen++] = 0;
13524 
13525   rec_len = gribLen;
13526 
13527   return rec_len;
13528 }
13529 
13530 
gribUnzip(unsigned char * dbuf,long dbufsize,unsigned char * sbuf,long sbufsize)13531 int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize)
13532 {
13533 #if ! defined(HAVE_LIBSZ)
13534   static int libszwarn = 1;
13535 #endif
13536   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
13537   size_t gribLen = 0;
13538   size_t destLen, sourceLen;
13539   enum { bds_head = 11 };
13540   int bds_ext = 0;
13541 
13542   UNUSED(dbufsize);
13543 
13544   long gribrecsize;
13545   int nerr = grib1Sections(sbuf, sbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
13546   if ( nerr < 0 )
13547     {
13548       fprintf(stdout, "GRIB message error\n");
13549       return 0;
13550     }
13551 
13552   if ( nerr > 0 )
13553     {
13554       fprintf(stdout, "GRIB data corrupted!\n");
13555       return 0;
13556     }
13557 
13558   //unsigned bds_len = BDS_Len;
13559   bool llarge = false;
13560 
13561   int bds_zoffset = 12;
13562   if ( llarge ) bds_zoffset += 2;
13563 
13564   int bds_nbits = BDS_NumBits;
13565   int bds_flag  = BDS_Flag;
13566   int lspherc   =  bds_flag >> 7;
13567   int lcomplex  = (bds_flag >> 6)&1;
13568   /* lcompress = (bds_flag >> 4)&1; */
13569 
13570   if ( lspherc )
13571     {
13572       if ( lcomplex  )
13573 	{
13574 	  int jup  = bds[bds_zoffset+15];
13575 	  int ioff = (jup+1)*(jup+2);
13576 	  bds_ext = 4 + 3 + 4*ioff;
13577 	}
13578       else
13579 	{
13580 	  bds_ext = 4;
13581 	}
13582     }
13583 
13584   size_t datstart = bds_head + (size_t)bds_ext;
13585 
13586   unsigned char *source = bds + datstart + bds_zoffset;
13587   if ( llarge )
13588     sourceLen = ((size_t) ((bds[21]<<24)+(bds[22]<<16)+(bds[23]<<8)+bds[24]));
13589   else
13590     sourceLen = ((size_t) ((bds[20]<<16)+(bds[21]<<8)+bds[22]));
13591 
13592   nerr = grib1Sections(dbuf, sbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
13593   if ( nerr < 0 )
13594     {
13595       fprintf(stdout, "GRIB message error\n");
13596       return 0;
13597     }
13598 
13599   if ( nerr > 0 )
13600     {
13601       fprintf(stdout, "GRIB data corrupted!\n");
13602       return 0;
13603     }
13604 
13605   unsigned char *dest = bds + datstart;
13606   if ( llarge )
13607     destLen = ((size_t) ((bds[17]<<24)+(bds[18]<<16)+(bds[19]<<8)+bds[20]));
13608   else
13609     destLen = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
13610 
13611   BDS_Flag = (unsigned char)(BDS_Flag - 16);
13612 
13613   size_t bdsLen = datstart + destLen;
13614 
13615 #if  defined(HAVE_LIBSZ)
13616   {
13617     int bds_zstart = 14;
13618     unsigned recLen = GET_UINT3(bds[bds_zstart], bds[bds_zstart+1], bds[bds_zstart+2]);
13619 
13620     int bits_per_sample = (bds_nbits == 24) ? 8 : bds_nbits;
13621 
13622     SZ_com_t sz_param;          /* szip parameter block */
13623     sz_param.options_mask        = OPTIONS_MASK;
13624     sz_param.bits_per_pixel      = bits_per_sample;
13625     sz_param.pixels_per_block    = PIXELS_PER_BLOCK;
13626     sz_param.pixels_per_scanline = PIXELS_PER_SCANLINE;
13627 
13628     if ( bds_ext )
13629       for ( long i = 0; i < bds_ext; ++i )
13630 	bds[bds_head+i] = bds[bds_zoffset+bds_head+i];
13631 
13632     /*    fprintf(stderr, "gribUnzip: sourceLen %ld; destLen %ld\n", (long)sourceLen, (long)destLen);
13633     fprintf(stderr, "gribUnzip: sourceOff %d; destOff %d\n", bds[12], bds[11]);
13634     fprintf(stderr, "gribUnzip: reclen %d; bdslen %d\n", recLen, bdsLen);
13635     */
13636 
13637     size_t tmpLen = destLen;
13638 
13639     int status = SZ_BufftoBuffDecompress(dest, &tmpLen, source, sourceLen, &sz_param);
13640     if ( status != SZ_OK )
13641       {
13642 	if ( status == SZ_NO_ENCODER_ERROR )
13643 	  Warning("SZ_NO_ENCODER_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
13644 	else if ( status == SZ_PARAM_ERROR )
13645 	  Warning("SZ_PARAM_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
13646 	else if ( status == SZ_MEM_ERROR )
13647 	  Warning("SZ_MEM_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
13648 	else if ( status == SZ_OUTBUFF_FULL )
13649 	  Warning("SZ_OUTBUFF_FULL code %3d level %3d", PDS_Parameter, PDS_Level2);
13650 	else
13651 	  Warning("SZ ERROR: %d code %3d level %3d", status, PDS_Parameter, PDS_Level2);
13652       }
13653     /*
13654     fprintf(stderr, "gribUnzip: sl = %ld  dl = %ld   tl = %ld\n",
13655 	    (long)sourceLen, (long)destLen,(long) tmpLen);
13656     */
13657     if ( tmpLen != destLen )
13658       Warning("unzip size differ: code %3d level %3d  ibuflen %ld ubuflen %ld",
13659 	      PDS_Parameter, PDS_Level2, (long) destLen, (long) tmpLen);
13660 
13661     if ( bds_nbits == 24 )
13662       {
13663 	long nelem = tmpLen/3;
13664 	unsigned char *pbuf = (unsigned char*) Malloc(tmpLen);
13665 	for ( long i = 0; i < nelem; i++ )
13666 	  {
13667 	    pbuf[3*i  ] = dest[        i];
13668 	    pbuf[3*i+1] = dest[  nelem+i];
13669 	    pbuf[3*i+2] = dest[2*nelem+i];
13670 	  }
13671 	memcpy(dest, pbuf, tmpLen);
13672 	Free(pbuf);
13673       }
13674 
13675     int bds_ubits = BDS_Flag & 15;
13676     BDS_Flag -= bds_ubits;
13677 
13678     if ( (bdsLen%2) == 1 )
13679       {
13680 	BDS_Flag += 8;
13681 	bds[bdsLen++] = 0;
13682       }
13683 
13684     SetLen3(bds, 0, bdsLen);
13685 
13686     gribLen = (bds - dbuf) + bdsLen;
13687 
13688     dbuf[gribLen++] = '7';
13689     dbuf[gribLen++] = '7';
13690     dbuf[gribLen++] = '7';
13691     dbuf[gribLen++] = '7';
13692 
13693     if ( llarge )
13694       {
13695 	long itemp;
13696         bdsLen = gribLen - 4;
13697 	/*
13698 	  If a very large product, the section 4 length field holds
13699 	  the number of bytes in the product after section 4 upto
13700 	  the end of the padding bytes.
13701 	  This is a fixup to get round the restriction on product lengths
13702 	  due to the count being only 24 bits. It is only possible because
13703 	  the (default) rounding for GRIB products is 120 bytes.
13704 	*/
13705 	while ( gribLen%120 ) dbuf[gribLen++] = 0;
13706 
13707 	if ( gribLen != (size_t)recLen )
13708 	  fprintf(stderr, "Internal problem, recLen and gribLen differ!\n");
13709 
13710 	itemp = gribLen / (-120);
13711 	itemp = JP23SET - itemp + 1;
13712 
13713 	SetLen3(dbuf, 4, itemp);
13714 
13715 	bdsLen = gribLen - bdsLen;
13716 
13717 	SetLen3(bds, 0, bdsLen);
13718       }
13719     else
13720       {
13721 	SetLen3(dbuf, 4, recLen);
13722       }
13723     /*
13724     fprintf(stderr, "recLen, gribLen, bdsLen %d %d %d\n", recLen, gribLen, bdsLen);
13725     */
13726     if ( llarge )
13727       while ( gribLen%120 ) dbuf[gribLen++] = 0;
13728     else
13729       while ( gribLen & 7 ) dbuf[gribLen++] = 0;
13730     /*
13731     fprintf(stderr, "recLen, gribLen, bdsLen %d %d %d\n", recLen, gribLen, bdsLen);
13732     */
13733   }
13734 #else
13735   UNUSED(bds_nbits);
13736   UNUSED(sourceLen);
13737   UNUSED(source);
13738   UNUSED(bdsLen);
13739   UNUSED(dest);
13740 
13741   if ( libszwarn )
13742     {
13743       Warning("Decompression disabled, szlib not available!");
13744       libszwarn = 0;
13745     }
13746 #endif
13747 
13748   return (int)gribLen;
13749 }
13750 #include <stdio.h>
13751 #include <math.h>
13752 
13753 
13754 static void
13755 scm0_double(double *pdl, double *pdr, double *pfl, double *pfr, int klg);
13756 
13757 
13758 static
rowina2(double * p,int ko,int ki,double * pw,int kcode,double msval,int * kret)13759 int rowina2(double *p, int ko, int ki, double *pw,
13760 	    int kcode, double msval, int *kret)
13761 {
13762   /* System generated locals */
13763   int pw_dim1, pw_offset, i_1;
13764 
13765   /* Local variables */
13766   double zwt1, zrdi, zpos;
13767   int jl, ip;
13768   double zdo, zwt;
13769 
13770   /* Parameter adjustments */
13771   --p;
13772   pw_dim1 = ko + 3;
13773   pw_offset = pw_dim1;
13774   pw -= pw_offset;
13775 
13776   /* **** ROWINA2 - Interpolation of row of values. */
13777   /*     Input Parameters. */
13778   /*     ----------------- */
13779   /*     P      - Row of values to be interpolated. */
13780   /*              Dimension must be at least KO. */
13781   /*     KO     - Number of values required. */
13782   /*     KI     - Number of values in P on input. */
13783   /*     PW     - Working array. */
13784   /*              Dimension must be at least (0:KO+2,3). */
13785   /*     KCODE  - Interpolation required. */
13786   /*              1 , linear. */
13787   /*              3 , cubic. */
13788   /*     PMSVAL - Value used for missing data indicator. */
13789 
13790   /*     Output Parameters. */
13791   /*     ------------------ */
13792   /*     P     - Now contains KO values. */
13793   /*     KRET  - Return code */
13794   /*             0, OK */
13795   /*             Non-zero, error */
13796 
13797   /*     Author. */
13798   /*     ------- */
13799   /*     J.D.Chambers    ECMWF     22.07.94 */
13800 
13801   /*     ********************************    */
13802   /*     Section 1.  Linear interpolation .. */
13803   /*     ********************************    */
13804 
13805   *kret = 0;
13806 
13807   if ( kcode == 1 )
13808     {
13809       /*    Move input values to work array */
13810       for ( jl = 1; jl <= ki; ++jl )
13811 	pw[jl + pw_dim1] = p[jl];
13812 
13813       /*    Arrange wrap-around value in work array */
13814       pw[ki + 1 + pw_dim1] = p[1];
13815 
13816       /*    Set up constants to be used to figure out weighting for */
13817       /*    values in interpolation. */
13818       zrdi = (double) ki;
13819       zdo = 1.0 / (double) ko;
13820 
13821       /*    Loop through the output points */
13822       for ( jl = 1; jl <= ko; ++jl )
13823 	{
13824 
13825 	  /*    Calculate weight from the start of row */
13826 	  zpos = (jl - 1) * zdo;
13827 	  zwt = zpos * zrdi;
13828 
13829 	  /*    Get the current array position(minus 1) from the weight - */
13830 	  /*    note the implicit truncation. */
13831 	  ip = (int) zwt;
13832 
13833 	  /*    If the left value is missing, use the right value */
13834 	  if ( IS_EQUAL(pw[ip + 1 + pw_dim1], msval) )
13835 	    {
13836 	      p[jl] = pw[ip + 2 + pw_dim1];
13837 	    }
13838 	  /*    If the right value is missing, use the left value */
13839 	  else if ( IS_EQUAL(pw[ip + 2 + pw_dim1], msval) )
13840 	    {
13841 	      p[jl] = pw[ip + 1 + pw_dim1];
13842 	    }
13843 	  /*    If neither missing, interpolate ... */
13844 	  else
13845 	    {
13846 
13847 	      /*       Adjust the weight to range (0.0 to 1.0) */
13848 	      zwt -= ip;
13849 
13850 	      /*       Interpolate using the weighted values on either side */
13851 	      /*       of the output point position */
13852 	      p[jl] = (1.0 - zwt) * pw[ip + 1 + pw_dim1] +
13853 		zwt * pw[ip + 2 + pw_dim1];
13854 	    }
13855 	}
13856 
13857       /*     *******************************    */
13858       /*     Section 2.  Cubic interpolation .. */
13859       /*     *******************************    */
13860 
13861     }
13862   else if ( kcode == 3 )
13863     {
13864       i_1 = ki;
13865       for ( jl = 1; jl <= i_1; ++jl )
13866 	{
13867           if ( IS_EQUAL(p[jl], msval) )
13868 	    {
13869 	      fprintf(stderr," ROWINA2: ");
13870 	      fprintf(stderr," Cubic interpolation not supported");
13871 	      fprintf(stderr," for fields containing missing data.\n");
13872 	      *kret = 1;
13873 	      goto L900;
13874 	    }
13875           pw[jl + pw_dim1] = p[jl];
13876 	}
13877       pw[pw_dim1] = p[ki];
13878       pw[ki + 1 + pw_dim1] = p[1];
13879       pw[ki + 2 + pw_dim1] = p[2];
13880       i_1 = ki;
13881       for ( jl = 1; jl <= i_1; ++jl )
13882 	{
13883           pw[jl + (pw_dim1 << 1)] =
13884 	        - pw[jl - 1 + pw_dim1] / 3.0 -
13885 	          pw[jl     + pw_dim1] * 0.5 +
13886 	          pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0;
13887           pw[jl + 1 + pw_dim1 * 3] =
13888                   pw[jl - 1 + pw_dim1] / 6.0 -
13889                   pw[jl     + pw_dim1] +
13890                   pw[jl + 1 + pw_dim1] * 0.5 +
13891                   pw[jl + 2 + pw_dim1] / 3.0;
13892 	}
13893 
13894       scm0_double(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
13895 		  &pw[pw_dim1 + 1], &pw[pw_dim1 + 2], ki);
13896 
13897       zrdi = (double) ki;
13898       zdo = 1.0 / (double) ko;
13899       for ( jl = 1; jl <= ko; ++jl )
13900 	{
13901           zpos = (jl - 1) * zdo;
13902           zwt = zpos * zrdi;
13903           ip = (int) zwt + 1;
13904           zwt = zwt + 1.0 - ip;
13905           zwt1 = 1.0 - zwt;
13906           p[jl] = ((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
13907                   zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
13908                   ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
13909                   zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt;
13910 	}
13911 
13912     }
13913   else
13914     {
13915       /*    **************************************    */
13916       /*    Section 3.  Invalid interpolation code .. */
13917       /*    **************************************    */
13918       fprintf(stderr," ROWINA2:");
13919       fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
13920       *kret = 2;
13921     }
13922 
13923 L900:
13924     return 0;
13925 } /* rowina2 */
13926 
13927 
13928 
qu2reg2(double * pfield,int * kpoint,int klat,int klon,double * ztemp,double msval,int * kret)13929 int qu2reg2(double *pfield, int *kpoint, int klat, int klon,
13930 	    double *ztemp, double msval, int *kret)
13931 {
13932    /* System generated locals */
13933    int i_1, i_2;
13934    int kcode = 1;
13935 
13936    /* Local variables */
13937    int ilii, ilio, icode;
13938    double *zline = NULL;
13939    double *zwork = NULL;
13940    int iregno, iquano, j210, j220, j230, j240, j225;
13941 
13942 
13943    zline = (double*) Malloc(2*(size_t)klon*sizeof(double));
13944    if ( zline == NULL ) SysError("No Memory!");
13945 
13946    zwork = (double*) Malloc(3*(2*(size_t)klon+3)*sizeof(double));
13947    if ( zwork == NULL ) SysError("No Memory!");
13948 
13949    /* Parameter adjustments */
13950    --pfield;
13951    --kpoint;
13952 
13953 /* **** QU2REG - Convert quasi-regular grid data to regular. */
13954 /*     Input Parameters. */
13955 /*     ----------------- */
13956 /*     PFIELD     - Array containing quasi-regular grid */
13957 /*                  data. */
13958 /*     KPOINT     - Array containing list of the number of */
13959 /*                  points on each latitude (or longitude) of */
13960 /*                  the quasi-regular grid. */
13961 /*     KLAT       - Number of latitude lines */
13962 /*     KLON       - Number of longitude lines */
13963 /*     KCODE      - Interpolation required. */
13964 /*                  1 , linear - data quasi-regular on */
13965 /*                               latitude lines. */
13966 /*                  3 , cubic -  data quasi-regular on */
13967 /*                               latitude lines. */
13968 /*                  11, linear - data quasi-regular on */
13969 /*                               longitude lines. */
13970 /*                  13, cubic -  data quasi-regular on */
13971 /*                               longitude lines. */
13972 /*     PMSVAL     - Value used for missing data indicator. */
13973 /*     Output Parameters. */
13974 /*     ------------------ */
13975 /*     KRET       - return code */
13976 /*                  0 = OK */
13977 /*                  non-zero indicates fatal error */
13978 /*     PFIELD     - Array containing regular grid data. */
13979 /*     Author. */
13980 /*     ------- */
13981 /*     J.D.Chambers     ECMWF      22.07.94 */
13982 /*     J.D.Chambers     ECMWF      13.09.94 */
13983 /*     Add return code KRET and remove calls to ABORT. */
13984 
13985 
13986 /* ------------------------------ */
13987 /* Section 1. Set initial values. */
13988 /* ------------------------------ */
13989 
13990    *kret = 0;
13991 
13992 /* Check input parameters. */
13993 
13994    if (kcode != 1 && kcode != 3 && kcode != 11 && kcode != 13) {
13995       fprintf(stderr," QU2REG :");
13996       fprintf(stderr," Invalid interpolation type code = %2d\n",kcode);
13997       *kret = 1;
13998       goto L900;
13999    }
14000 
14001 /* Set array indices to 0. */
14002 
14003    ilii = 0;
14004    ilio = 0;
14005 
14006 /* Establish values of loop parameters. */
14007 
14008    if (kcode > 10) {
14009 
14010 /*    Quasi-regular along longitude lines. */
14011 
14012       iquano = klon;
14013       iregno = klat;
14014       icode = kcode - 10;
14015    } else {
14016 
14017 /*    Quasi-regular along latitude lines. */
14018 
14019       iquano = klat;
14020       iregno = klon;
14021       icode = kcode;
14022    }
14023 
14024 /*     -------------------------------------------------------- */
14025 /**    Section 2. Interpolate field from quasi to regular grid. */
14026 /*     -------------------------------------------------------- */
14027 
14028    i_1 = iquano;
14029    for (j230 = 1; j230 <= i_1; ++j230) {
14030 
14031       if (iregno != kpoint[j230]) {
14032 
14033 /*       Line contains less values than required,so */
14034 /*       extract quasi-regular grid values for a line */
14035 
14036          i_2 = kpoint[j230];
14037          for (j210 = 1; j210 <= i_2; ++j210) {
14038             ++ilii;
14039             zline[j210 - 1] = pfield[ilii];
14040          }
14041 
14042 /*       and interpolate this line. */
14043 
14044          rowina2(zline, iregno, kpoint[j230], zwork, icode, msval, kret);
14045          if (*kret != 0) goto L900;
14046 
14047 /*       Add regular grid values for this line to the
14048          temporary array. */
14049 
14050          i_2 = iregno;
14051          for (j220 = 1; j220 <= i_2; ++j220) {
14052             ++ilio;
14053             ztemp[ilio - 1] = zline[j220 - 1];
14054          }
14055 
14056       } else {
14057 
14058 /*       Line contains the required number of values, so add */
14059 /*       this line to the temporary array. */
14060 
14061          i_2 = iregno;
14062          for (j225 = 1; j225 <= i_2; ++j225) {
14063             ++ilio;
14064             ++ilii;
14065             ztemp[ilio - 1] = pfield[ilii];
14066          }
14067       }
14068    }
14069 
14070 /* Copy temporary array to user array. */
14071 
14072    i_1 = klon * klat;
14073    for (j240 = 1; j240 <= i_1; ++j240) {
14074       pfield[j240] = ztemp[j240 - 1];
14075    }
14076 
14077 /* -------------------------------------------------------- */
14078 /* Section 9. Return to calling routine. Format statements. */
14079 /* -------------------------------------------------------- */
14080 
14081 L900:
14082 
14083    Free(zline);
14084    Free(zwork);
14085 
14086    return 0;
14087 } /* qu2reg2 */
14088 
14089 
14090 
14091 #ifdef T
14092 #undef T
14093 #endif
14094 #define T double
14095 #ifdef T
14096 
14097 /* calculate_pfactor: source code from grib_api-1.8.0 */
TEMPLATE(calculate_pfactor,T)14098 double TEMPLATE(calculate_pfactor,T)(const T *spectralField, long fieldTruncation, long subsetTruncation)
14099 {
14100   /*long n_vals = ((fieldTruncation+1)*(fieldTruncation+2));*/
14101   long loop, index, m, n = 0;
14102   double zeps = 1.0e-15;
14103   long ismin = (subsetTruncation+1), ismax = (fieldTruncation+1);
14104   double weightedSumOverX = 0.0, weightedSumOverY = 0.0, sumOfWeights = 0.0;
14105   double numerator = 0.0, denominator = 0.0;
14106 
14107   // Setup the weights
14108 
14109   double range = (double) (ismax - ismin +1);
14110 
14111   double *weights = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
14112   for( loop = ismin; loop <= ismax; loop++ )
14113     weights[loop] = range / (double) (loop-ismin+1);
14114 
14115   // Compute norms
14116   // Handle values 2 at a time (real and imaginary parts).
14117   double *norms = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
14118 
14119   for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
14120 
14121   // Form norms for the rows which contain part of the unscaled subset.
14122 
14123   index = -2;
14124   for( m = 0; m < subsetTruncation; m++ )
14125     for( n = m; n <= fieldTruncation; n++ ) {
14126       index += 2;
14127       if( n >= subsetTruncation ) {
14128         double tval = spectralField[index];
14129         tval=tval<0?-tval:tval;
14130         norms[n] = norms[n] > tval ? norms[n] : tval;
14131         tval = spectralField[index+1];
14132         tval=tval<0?-tval:tval;
14133         norms[n] = norms[n] > tval ? norms[n] : tval;
14134       }
14135     }
14136 
14137   // Form norms for the rows which do not contain part of the unscaled subset.
14138 
14139   for( m = subsetTruncation; m <= fieldTruncation; m++ )
14140     for( n = m; n <= fieldTruncation; n++ ) {
14141       double tval = spectralField[index];
14142       index += 2;
14143       tval=tval<0?-tval:tval;
14144       norms[n] = norms[n] > tval ? norms[n] : tval;
14145       tval = spectralField[index+1];
14146       tval=tval<0?-tval:tval;
14147       norms[n] = norms[n] > tval ? norms[n] : tval;
14148     }
14149 
14150   // Ensure the norms have a value which is not too small in case of problems with math functions (e.g. LOG).
14151 
14152   for( loop = ismin; loop <= ismax; loop++ ) {
14153     norms[n] = norms[n] > zeps ? norms[n] : zeps;
14154     if( IS_EQUAL(norms[n], zeps) ) weights[n] = 100.0 * zeps;
14155   }
14156 
14157   // Do linear fit to find the slope
14158 
14159   for( loop = ismin; loop <= ismax; loop++ ) {
14160     double x = log( (double) (loop*(loop+1)) );
14161     double y = log( norms[loop] );
14162     weightedSumOverX += x * weights[loop];
14163     weightedSumOverY += y * weights[loop];
14164     sumOfWeights = sumOfWeights + weights[loop];
14165   }
14166   weightedSumOverX /= sumOfWeights;
14167   weightedSumOverY /= sumOfWeights;
14168 
14169   // Perform a least square fit for the equation
14170 
14171   for( loop = ismin; loop <= ismax; loop++ ) {
14172 
14173     double x = log( (double)(loop*(loop+1)) );
14174     double y = log( norms[loop] );
14175     numerator += weights[loop] * (y-weightedSumOverY) * (x-weightedSumOverX);
14176     denominator += weights[loop] * ((x-weightedSumOverX) * (x-weightedSumOverX));
14177   }
14178   double slope = numerator / denominator;
14179 
14180   Free(weights);
14181   Free(norms);
14182 
14183   double pFactor = -slope;
14184   if( pFactor < -9999.9 ) pFactor = -9999.9;
14185   if( pFactor > 9999.9 )  pFactor = 9999.9;
14186 
14187   return pFactor;
14188 }
14189 
TEMPLATE(scale_complex,T)14190 void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, int inv)
14191 {
14192 
14193   if ( pcScale < -10000 || pcScale > 10000 )
14194     {
14195       fprintf(stderr, " %s: Invalid power given %6d\n", __func__, pcScale);
14196       return;
14197     }
14198 
14199   /* Setup scaling factors = n(n+1)^^p for n = 1 to truncation */
14200 
14201   if ( pcScale != 0 )
14202     {
14203       double *scale = (double*) Malloc(((size_t)trunc+1)*sizeof(double));
14204       const double power = (double) pcScale / 1000.;
14205       scale[0] = 1.0;
14206 
14207       if (pcScale != 1000)
14208         for ( int n = 1; n <= trunc; n++ )
14209           scale[n] = pow((double) (n*(n+1)), power);
14210       else
14211         for ( int n = 1; n <= trunc; n++ )
14212           scale[n] =     (double) (n*(n+1));
14213 
14214       if ( inv )
14215         for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
14216 
14217       /* Scale the values */
14218 
14219       size_t index = 0;
14220 
14221       for ( int m = 0;   m < pcStart; m++ )
14222         for ( int n = m; n <= trunc; n++, index += 2 )
14223           if ( n >= pcStart )
14224             {
14225               fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
14226               fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
14227             }
14228 
14229       for ( int m = pcStart; m <= trunc; m++ )
14230         for ( int n = m;     n <= trunc; n++, index += 2 )
14231           {
14232             fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
14233             fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
14234           }
14235       Free(scale);
14236     }
14237 }
14238 
14239 
TEMPLATE(scatter_complex,T)14240 void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
14241 {
14242   T *fphelp = (T*) Malloc((size_t)nsp*sizeof(T));
14243   size_t inext = 0;
14244   size_t pcStart_ = pcStart >= 0 ? (size_t)pcStart : 0U;
14245   size_t trunc_ = trunc >= 0 ? (size_t)trunc : 0U;
14246   for ( size_t m = 0, index = 0; m <= pcStart_; m++ )
14247     {
14248       size_t n_copies = pcStart_ <= trunc_ ? (pcStart_ + 1 - m) * 2 : 0;
14249       for ( size_t i = 0; i < n_copies; ++i )
14250         fphelp[index + i] = fpdata[inext + i];
14251       inext += n_copies;
14252       index += m <= trunc_ ? (trunc_ - m + 1) * 2 : 0;
14253     }
14254   for ( size_t m = 0, index = 0; m <= trunc_; m++ )
14255     {
14256       size_t advIdx = m <= pcStart_ ? (pcStart_ - m + 1) * 2 : 0;
14257       index += advIdx;
14258       size_t copyStart = m > pcStart_ ? m : pcStart_ + 1;
14259       size_t n_copies = copyStart <= trunc_ ? (trunc_ - copyStart + 1) * 2 : 0;
14260       for ( size_t i = 0; i < n_copies; ++i )
14261         fphelp[index + i] = fpdata[inext + i];
14262       inext += n_copies;
14263       index += n_copies;
14264     }
14265   for ( size_t m = 0; m < (size_t)nsp; m++ ) fpdata[m] = fphelp[m];
14266 
14267   Free(fphelp);
14268 }
14269 
14270 
TEMPLATE(gather_complex,T)14271 void TEMPLATE(gather_complex,T)(T *fpdata, size_t pcStart, size_t trunc, size_t nsp)
14272 {
14273   T *restrict fphelp = (T*) Malloc(nsp*sizeof(T));
14274   size_t inext = 0;
14275 
14276   for ( size_t m = 0, index = 0;   m <= pcStart; m++ )
14277     for ( size_t n = m; n <= trunc; n++ )
14278       {
14279 	if ( pcStart >= n )
14280 	  {
14281 	    fphelp[inext++] = fpdata[index];
14282 	    fphelp[inext++] = fpdata[index+1];
14283 	  }
14284 	index += 2;
14285       }
14286 
14287   for ( size_t m = 0, index = 0; m <= trunc; m++ )
14288     for ( size_t n = m; n <= trunc; n++ )
14289       {
14290 	if ( n > pcStart )
14291 	  {
14292 	    fphelp[inext++] = fpdata[index];
14293 	    fphelp[inext++] = fpdata[index+1];
14294 	  }
14295 	index += 2;
14296       }
14297 
14298   for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
14299 
14300   Free(fphelp);
14301 }
14302 
14303 
TEMPLATE(scm0,T)14304 static void TEMPLATE(scm0,T)(T *pdl, T *pdr, T *pfl, T *pfr, int klg)
14305 {
14306   /* **** SCM0   - Apply SCM0 limiter to derivative estimates. */
14307   /* output: */
14308   /*   pdl   = the limited derivative at the left edge of the interval */
14309   /*   pdr   = the limited derivative at the right edge of the interval */
14310   /* inputs */
14311   /*   pdl   = the original derivative at the left edge */
14312   /*   pdr   = the original derivative at the right edge */
14313   /*   pfl   = function value at the left edge of the interval */
14314   /*   pfr   = function value at the right edge of the interval */
14315   /*   klg   = number of intervals where the derivatives are limited */
14316 
14317   /*  define constants */
14318 
14319   double zeps = 1.0e-12;
14320   double zfac = (1.0 - zeps) * 3.0;
14321 
14322   for ( int jl = 0; jl < klg; ++jl )
14323     {
14324       double r_1;
14325       if ( (r_1 = pfr[jl] - pfl[jl], fabs(r_1)) > zeps )
14326 	{
14327 	  double zalpha = pdl[jl] / (pfr[jl] - pfl[jl]);
14328 	  double zbeta  = pdr[jl] / (pfr[jl] - pfl[jl]);
14329 	  if ( zalpha <= 0.0 ) pdl[jl] = 0.0;
14330 	  if ( zbeta  <= 0.0 ) pdr[jl] = 0.0;
14331 	  if ( zalpha > zfac ) pdl[jl] = (T)(zfac * (pfr[jl] - pfl[jl]));
14332 	  if ( zbeta  > zfac ) pdr[jl] = (T)(zfac * (pfr[jl] - pfl[jl]));
14333 	}
14334       else
14335 	{
14336 	  pdl[jl] = 0.0;
14337 	  pdr[jl] = 0.0;
14338 	}
14339     }
14340 } /* scm0 */
14341 
14342 static
TEMPLATE(rowina3,T)14343 int TEMPLATE(rowina3,T)(T *p, int ko, int ki, T *pw,
14344 			int kcode, T msval, int *kret, int omisng, int operio, int oveggy)
14345 {
14346   /*
14347 C---->
14348 C**** ROWINA3 - Interpolation of row of values.
14349 C
14350 C     Purpose.
14351 C     --------
14352 C
14353 C     Interpolate a row of values.
14354 C
14355 C
14356 C**   Interface.
14357 C     ----------
14358 C
14359 C     CALL ROWINA3( P, KO, KI, PW, KCODE, PMSVAL, KRET, OMISNG, OPERIO)
14360 C
14361 C
14362 C     Input Parameters.
14363 C     -----------------
14364 C
14365 C     P      - Row of values to be interpolated.
14366 C              Dimension must be at least KO.
14367 C
14368 C     KO     - Number of values required.
14369 C
14370 C     KI     - Number of values in P on input.
14371 C
14372 C     PW     - Working array.
14373 C              Dimension must be at least (0:KO+2,3).
14374 C
14375 C     KCODE  - Interpolation required.
14376 C              1 , linear.
14377 C              3 , cubic.
14378 C
14379 C     PMSVAL - Value used for missing data indicator.
14380 C
14381 C     OMISNG - True if missing values are present in field.
14382 C
14383 C     OPERIO - True if input field is periodic.
14384 C
14385 C     OVEGGY - True if 'nearest neighbour' processing must be used
14386 C              for interpolation
14387 C
14388 C     Output Parameters.
14389 C     ------------------
14390 C
14391 C     P     - Now contains KO values.
14392 C     KRET  - Return code
14393 C             0, OK
14394 C             Non-zero, error
14395 C
14396 C
14397 C     Method.
14398 C     -------
14399 C
14400 C     Linear or cubic interpolation performed as required.
14401 C
14402 C     Comments.
14403 C     ---------
14404 C
14405 C     This is a version of ROWINA which allows for missing data
14406 C     values and hence for bitmapped fields.
14407 C
14408 C
14409 C     Author.
14410 C     -------
14411 C
14412 C     J.D.Chambers    ECMWF     22.07.94
14413 C
14414 C
14415 C     Modifications.
14416 C     --------------
14417 C
14418 C     J.D.Chambers    ECMWF     13.09.94
14419 C     Add return code KRET and remove calls to ABORT.
14420 C
14421 C     J. Clochard, Meteo France, for ECMWF - January 1998.
14422 C     Addition of OMISNG and OPERIO arguments.
14423 C
14424 C
14425 C     -----------------------------------------------------------------
14426 */
14427   /* System generated locals */
14428   int pw_dim1, pw_offset, i_1;
14429 
14430   /* Local variables */
14431   int jl, ip;
14432   double zwt1, zrdi, zpos;
14433   double zdo, zwt;
14434 
14435   UNUSED(omisng);
14436 
14437   /* Parameter adjustments */
14438   --p;
14439   pw_dim1 = ko + 3;
14440   pw_offset = pw_dim1;
14441   pw -= pw_offset;
14442 
14443   *kret = 0;
14444 
14445   if ( kcode == 1 )
14446     {
14447       /*    Move input values to work array */
14448       for ( jl = 1; jl <= ki; ++jl )
14449 	pw[jl + pw_dim1] = p[jl];
14450 
14451       if ( operio )
14452 	{
14453 	  /* Arrange wrap-around value in work array */
14454 	  pw[ki + 1 + pw_dim1] = p[1];
14455 
14456 	  /* Set up constants to be used to figure out weighting for */
14457 	  /* values in interpolation. */
14458 	  zrdi = (double) ki;
14459 	  zdo = 1.0 / (double) ko;
14460 	}
14461       else
14462 	{
14463 	  /* Repeat last value, to cope with "implicit truncation" below */
14464 	  pw[ki + 1 + pw_dim1] = p[ki];
14465 
14466 	  /* Set up constants to be used to figure out weighting for */
14467 	  /* values in interpolation. */
14468 	  zrdi = (double) (ki-1);
14469 	  zdo = 1.0 / (double) (ko-1);
14470  	}
14471 
14472       /*    Loop through the output points */
14473       for ( jl = 1; jl <= ko; ++jl )
14474 	{
14475 
14476 	  /* Calculate weight from the start of row */
14477 	  zpos = (jl - 1) * zdo;
14478 	  zwt = zpos * zrdi;
14479 
14480 	  /* Get the current array position(minus 1) from the weight - */
14481 	  /* note the implicit truncation. */
14482 	  ip = (int) zwt;
14483 
14484 	  /* Adjust the weight to range (0.0 to 1.0) */
14485 	  zwt -= ip;
14486 
14487           /* If 'nearest neighbour' processing must be used */
14488 	  if ( oveggy )
14489 	    {
14490               if ( zwt < 0.5 )
14491                 p[jl] = pw[ip + 1 + pw_dim1];
14492 	      else
14493 		p[jl] = pw[ip + 2 + pw_dim1];
14494 	    }
14495 	  else
14496 	    {
14497 	      /*    If the left value is missing, use the right value */
14498 	      if ( IS_EQUAL(pw[ip + 1 + pw_dim1], msval) )
14499 		{
14500 		  p[jl] = pw[ip + 2 + pw_dim1];
14501 		}
14502 	      /*    If the right value is missing, use the left value */
14503 	      else if ( IS_EQUAL(pw[ip + 2 + pw_dim1], msval) )
14504 		{
14505 		  p[jl] = pw[ip + 1 + pw_dim1];
14506 		}
14507 	      /*    If neither missing, interpolate ... */
14508 	      else
14509 		{
14510 		  /*  Interpolate using the weighted values on either side */
14511 		  /*  of the output point position */
14512 		  p[jl] = (T)((1.0 - zwt) * pw[ip+1 + pw_dim1]
14513                               + zwt * pw[ip+2 + pw_dim1]);
14514 		}
14515 	    }
14516 	}
14517     }
14518   else if ( kcode == 3 )
14519     {
14520       /*     *******************************    */
14521       /*     Section 2.  Cubic interpolation .. */
14522       /*     *******************************    */
14523       i_1 = ki;
14524       for ( jl = 1; jl <= i_1; ++jl )
14525 	{
14526           if ( IS_EQUAL(p[jl], msval) )
14527 	    {
14528 	      fprintf(stderr," ROWINA3: ");
14529 	      fprintf(stderr," Cubic interpolation not supported");
14530 	      fprintf(stderr," for fields containing missing data.\n");
14531 	      *kret = 1;
14532 	      goto L900;
14533 	    }
14534           pw[jl + pw_dim1] = p[jl];
14535 	}
14536       pw[pw_dim1] = p[ki];
14537       pw[ki + 1 + pw_dim1] = p[1];
14538       pw[ki + 2 + pw_dim1] = p[2];
14539       i_1 = ki;
14540       for ( jl = 1; jl <= i_1; ++jl )
14541 	{
14542           pw[jl + (pw_dim1 << 1)] =
14543             (T)(- pw[jl - 1 + pw_dim1] / 3.0 -
14544                 pw[jl     + pw_dim1] * 0.5 +
14545                 pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0);
14546           pw[jl + 1 + pw_dim1 * 3] =
14547             (T)(pw[jl - 1 + pw_dim1] / 6.0 -
14548                 pw[jl     + pw_dim1] +
14549                 pw[jl + 1 + pw_dim1] * 0.5 +
14550                 pw[jl + 2 + pw_dim1] / 3.0);
14551 	}
14552 
14553       TEMPLATE(scm0,T)(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
14554 		       &pw[pw_dim1 + 1], &pw[pw_dim1 + 2], ki);
14555 
14556       zrdi = (double) ki;
14557       zdo = 1.0 / (double) ko;
14558       for ( jl = 1; jl <= ko; ++jl )
14559 	{
14560           zpos = (jl - 1) * zdo;
14561           zwt = zpos * zrdi;
14562           ip = (int) zwt + 1;
14563           zwt = zwt + 1.0 - ip;
14564           zwt1 = 1.0 - zwt;
14565           p[jl] = (T)(((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
14566                        zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
14567                       ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
14568                        zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt);
14569 	}
14570 
14571     }
14572   else
14573     {
14574       /*    **************************************    */
14575       /*    Section 3.  Invalid interpolation code .. */
14576       /*    **************************************    */
14577       fprintf(stderr," ROWINA3:");
14578       fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
14579       *kret = 2;
14580     }
14581 
14582 L900:
14583     return 0;
14584 } /* rowina3 */
14585 
14586 
TEMPLATE(qu2reg3,T)14587 int TEMPLATE(qu2reg3,T)(T *pfield, int *kpoint, int klat, int klon,
14588 			T msval, int *kret, int omisng, int operio, int oveggy)
14589 {
14590   /*
14591 C**** QU2REG3 - Convert quasi-regular grid data to regular.
14592 C
14593 C     Purpose.
14594 C     --------
14595 C
14596 C     Convert quasi-regular grid data to regular,
14597 C     using either a linear or cubic interpolation.
14598 C
14599 C
14600 C**   Interface.
14601 C     ----------
14602 C
14603 C     CALL QU2REG3(PFIELD,KPOINT,KLAT,KLON,KCODE,PMSVAL,OMISNG,OPERIO,
14604 C    X            OVEGGY)
14605 C
14606 C
14607 C     Input Parameters.
14608 C     -----------------
14609 C
14610 C     PFIELD     - Array containing quasi-regular grid data.
14611 C
14612 C     KPOINT     - Array containing list of the number of
14613 C                  points on each latitude (or longitude) of
14614 C                  the quasi-regular grid.
14615 C
14616 C     KLAT       - Number of latitude lines
14617 C
14618 C     KLON       - Number of longitude lines
14619 C
14620 C     KCODE      - Interpolation required.
14621 C                  1 , linear - data quasi-regular on latitude lines.
14622 C                  3 , cubic -  data quasi-regular on latitude lines.
14623 C                  11, linear - data quasi-regular on longitude lines.
14624 C                  13, cubic -  data quasi-regular on longitude lines.
14625 C
14626 C     PMSVAL     - Value used for missing data indicator.
14627 C
14628 C     OMISNG     - True if missing values are present in field.
14629 C
14630 C     OPERIO     - True if input field is periodic.
14631 C
14632 C     OVEGGY     - True if 'nearest neighbour' processing must be used
14633 C                  for interpolation
14634 C
14635 C
14636 C     Output Parameters.
14637 C     ------------------
14638 C
14639 C     KRET       - return code
14640 C                  0 = OK
14641 C                  non-zero indicates fatal error
14642 C
14643 C
14644 C     Output Parameters.
14645 C     ------------------
14646 C
14647 C     PFIELD     - Array containing regular grid data.
14648 C
14649 C
14650 C     Method.
14651 C     -------
14652 C
14653 C     Data is interpolated and expanded into a temporary array,
14654 C     which is then copied back into the user's array.
14655 C     Returns an error code if an invalid interpolation is requested
14656 C     or field size exceeds array dimensions.
14657 C
14658 C     Comments.
14659 C     ---------
14660 C
14661 C     This routine is an adaptation of QU2REG to allow missing data
14662 C     values, and hence bit mapped fields.
14663 C
14664 C
14665 C     Author.
14666 C     -------
14667 C
14668 C     J.D.Chambers     ECMWF      22.07.94
14669 C
14670 C
14671 C     Modifications.
14672 C     --------------
14673 C
14674 C     J.D.Chambers     ECMWF      13.09.94
14675 C     Add return code KRET and remove calls to ABORT.
14676 C
14677 C     J.D.Chambers     ECMWF        Feb 1997
14678 C     Allow for 64-bit pointers
14679 C
14680 C     J. Clochard, Meteo France, for ECMWF - January 1998.
14681 C     Addition of OMISNG and OPERIO arguments.
14682 C     Fix message for longitude number out of bounds, and routine
14683 C     name in title and formats.
14684 C
14685 */
14686    /* System generated locals */
14687    int i_1, i_2;
14688    int kcode = 1;
14689 
14690    /* Local variables */
14691    int ilii, ilio, icode;
14692    int iregno, iquano, j210, j220, j230, j240, j225;
14693 
14694    T *ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
14695    T *zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
14696    T *zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
14697 
14698    /* Parameter adjustments */
14699    --pfield;
14700    --kpoint;
14701 
14702 /* ------------------------------ */
14703 /* Section 1. Set initial values. */
14704 /* ------------------------------ */
14705 
14706    *kret = 0;
14707 
14708 /* Check input parameters. */
14709 
14710    if (kcode != 1 && kcode != 3 && kcode != 11 && kcode != 13) {
14711       fprintf(stderr," QU2REG :");
14712       fprintf(stderr," Invalid interpolation type code = %2d\n",kcode);
14713       *kret = 1;
14714       goto L900;
14715    }
14716 
14717 /* Set array indices to 0. */
14718 
14719    ilii = 0;
14720    ilio = 0;
14721 
14722 /* Establish values of loop parameters. */
14723 
14724    if (kcode > 10) {
14725 
14726 /*    Quasi-regular along longitude lines. */
14727 
14728       iquano = klon;
14729       iregno = klat;
14730       icode = kcode - 10;
14731    } else {
14732 
14733 /*    Quasi-regular along latitude lines. */
14734 
14735       iquano = klat;
14736       iregno = klon;
14737       icode = kcode;
14738    }
14739 
14740 /*     -------------------------------------------------------- */
14741 /**    Section 2. Interpolate field from quasi to regular grid. */
14742 /*     -------------------------------------------------------- */
14743 
14744    i_1 = iquano;
14745    for (j230 = 1; j230 <= i_1; ++j230) {
14746 
14747       if (iregno != kpoint[j230]) {
14748 
14749 /*       Line contains less values than required,so */
14750 /*       extract quasi-regular grid values for a line */
14751 
14752          i_2 = kpoint[j230];
14753          for (j210 = 1; j210 <= i_2; ++j210) {
14754             ++ilii;
14755             zline[j210 - 1] = pfield[ilii];
14756          }
14757 
14758 /*       and interpolate this line. */
14759 
14760          TEMPLATE(rowina3,T)(zline, iregno, kpoint[j230], zwork, icode, msval, kret, omisng, operio , oveggy);
14761          if (*kret != 0) goto L900;
14762 
14763 /*       Add regular grid values for this line to the
14764          temporary array. */
14765 
14766          i_2 = iregno;
14767          for (j220 = 1; j220 <= i_2; ++j220) {
14768             ++ilio;
14769             ztemp[ilio - 1] = zline[j220 - 1];
14770          }
14771 
14772       } else {
14773 
14774 /*       Line contains the required number of values, so add */
14775 /*       this line to the temporary array. */
14776 
14777          i_2 = iregno;
14778          for (j225 = 1; j225 <= i_2; ++j225) {
14779             ++ilio;
14780             ++ilii;
14781             ztemp[ilio - 1] = pfield[ilii];
14782          }
14783       }
14784    }
14785 
14786 /* Copy temporary array to user array. */
14787 
14788    i_1 = klon * klat;
14789    for (j240 = 1; j240 <= i_1; ++j240) {
14790       pfield[j240] = ztemp[j240 - 1];
14791    }
14792 
14793 /* -------------------------------------------------------- */
14794 /* Section 9. Return to calling routine. Format statements. */
14795 /* -------------------------------------------------------- */
14796 
14797 L900:
14798 
14799    Free(zwork);
14800    Free(zline);
14801    Free(ztemp);
14802 
14803    return 0;
14804 } /* qu2reg3 */
14805 
14806 #endif /* T */
14807 
14808 /*
14809  * Local Variables:
14810  * mode: c
14811  * c-file-style: "Java"
14812  * c-basic-offset: 2
14813  * indent-tabs-mode: nil
14814  * show-trailing-whitespace: t
14815  * require-trailing-newline: t
14816  * End:
14817  */
14818 
14819 #ifdef T
14820 #undef T
14821 #endif
14822 #define T float
14823 #ifdef T
14824 
14825 /* calculate_pfactor: source code from grib_api-1.8.0 */
TEMPLATE(calculate_pfactor,T)14826 double TEMPLATE(calculate_pfactor,T)(const T *spectralField, long fieldTruncation, long subsetTruncation)
14827 {
14828   /*long n_vals = ((fieldTruncation+1)*(fieldTruncation+2));*/
14829   long loop, index, m, n = 0;
14830   double zeps = 1.0e-15;
14831   long ismin = (subsetTruncation+1), ismax = (fieldTruncation+1);
14832   double weightedSumOverX = 0.0, weightedSumOverY = 0.0, sumOfWeights = 0.0;
14833   double numerator = 0.0, denominator = 0.0;
14834 
14835   // Setup the weights
14836 
14837   double range = (double) (ismax - ismin +1);
14838 
14839   double *weights = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
14840   for( loop = ismin; loop <= ismax; loop++ )
14841     weights[loop] = range / (double) (loop-ismin+1);
14842 
14843   // Compute norms
14844   // Handle values 2 at a time (real and imaginary parts).
14845   double *norms = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
14846 
14847   for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
14848 
14849   // Form norms for the rows which contain part of the unscaled subset.
14850 
14851   index = -2;
14852   for( m = 0; m < subsetTruncation; m++ )
14853     for( n = m; n <= fieldTruncation; n++ ) {
14854       index += 2;
14855       if( n >= subsetTruncation ) {
14856         double tval = spectralField[index];
14857         tval=tval<0?-tval:tval;
14858         norms[n] = norms[n] > tval ? norms[n] : tval;
14859         tval = spectralField[index+1];
14860         tval=tval<0?-tval:tval;
14861         norms[n] = norms[n] > tval ? norms[n] : tval;
14862       }
14863     }
14864 
14865   // Form norms for the rows which do not contain part of the unscaled subset.
14866 
14867   for( m = subsetTruncation; m <= fieldTruncation; m++ )
14868     for( n = m; n <= fieldTruncation; n++ ) {
14869       double tval = spectralField[index];
14870       index += 2;
14871       tval=tval<0?-tval:tval;
14872       norms[n] = norms[n] > tval ? norms[n] : tval;
14873       tval = spectralField[index+1];
14874       tval=tval<0?-tval:tval;
14875       norms[n] = norms[n] > tval ? norms[n] : tval;
14876     }
14877 
14878   // Ensure the norms have a value which is not too small in case of problems with math functions (e.g. LOG).
14879 
14880   for( loop = ismin; loop <= ismax; loop++ ) {
14881     norms[n] = norms[n] > zeps ? norms[n] : zeps;
14882     if( IS_EQUAL(norms[n], zeps) ) weights[n] = 100.0 * zeps;
14883   }
14884 
14885   // Do linear fit to find the slope
14886 
14887   for( loop = ismin; loop <= ismax; loop++ ) {
14888     double x = log( (double) (loop*(loop+1)) );
14889     double y = log( norms[loop] );
14890     weightedSumOverX += x * weights[loop];
14891     weightedSumOverY += y * weights[loop];
14892     sumOfWeights = sumOfWeights + weights[loop];
14893   }
14894   weightedSumOverX /= sumOfWeights;
14895   weightedSumOverY /= sumOfWeights;
14896 
14897   // Perform a least square fit for the equation
14898 
14899   for( loop = ismin; loop <= ismax; loop++ ) {
14900 
14901     double x = log( (double)(loop*(loop+1)) );
14902     double y = log( norms[loop] );
14903     numerator += weights[loop] * (y-weightedSumOverY) * (x-weightedSumOverX);
14904     denominator += weights[loop] * ((x-weightedSumOverX) * (x-weightedSumOverX));
14905   }
14906   double slope = numerator / denominator;
14907 
14908   Free(weights);
14909   Free(norms);
14910 
14911   double pFactor = -slope;
14912   if( pFactor < -9999.9 ) pFactor = -9999.9;
14913   if( pFactor > 9999.9 )  pFactor = 9999.9;
14914 
14915   return pFactor;
14916 }
14917 
TEMPLATE(scale_complex,T)14918 void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, int inv)
14919 {
14920 
14921   if ( pcScale < -10000 || pcScale > 10000 )
14922     {
14923       fprintf(stderr, " %s: Invalid power given %6d\n", __func__, pcScale);
14924       return;
14925     }
14926 
14927   /* Setup scaling factors = n(n+1)^^p for n = 1 to truncation */
14928 
14929   if ( pcScale != 0 )
14930     {
14931       double *scale = (double*) Malloc(((size_t)trunc+1)*sizeof(double));
14932       const double power = (double) pcScale / 1000.;
14933       scale[0] = 1.0;
14934 
14935       if (pcScale != 1000)
14936         for ( int n = 1; n <= trunc; n++ )
14937           scale[n] = pow((double) (n*(n+1)), power);
14938       else
14939         for ( int n = 1; n <= trunc; n++ )
14940           scale[n] =     (double) (n*(n+1));
14941 
14942       if ( inv )
14943         for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
14944 
14945       /* Scale the values */
14946 
14947       size_t index = 0;
14948 
14949       for ( int m = 0;   m < pcStart; m++ )
14950         for ( int n = m; n <= trunc; n++, index += 2 )
14951           if ( n >= pcStart )
14952             {
14953               fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
14954               fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
14955             }
14956 
14957       for ( int m = pcStart; m <= trunc; m++ )
14958         for ( int n = m;     n <= trunc; n++, index += 2 )
14959           {
14960             fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
14961             fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
14962           }
14963       Free(scale);
14964     }
14965 }
14966 
14967 
TEMPLATE(scatter_complex,T)14968 void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
14969 {
14970   T *fphelp = (T*) Malloc((size_t)nsp*sizeof(T));
14971   size_t inext = 0;
14972   size_t pcStart_ = pcStart >= 0 ? (size_t)pcStart : 0U;
14973   size_t trunc_ = trunc >= 0 ? (size_t)trunc : 0U;
14974   for ( size_t m = 0, index = 0; m <= pcStart_; m++ )
14975     {
14976       size_t n_copies = pcStart_ <= trunc_ ? (pcStart_ + 1 - m) * 2 : 0;
14977       for ( size_t i = 0; i < n_copies; ++i )
14978         fphelp[index + i] = fpdata[inext + i];
14979       inext += n_copies;
14980       index += m <= trunc_ ? (trunc_ - m + 1) * 2 : 0;
14981     }
14982   for ( size_t m = 0, index = 0; m <= trunc_; m++ )
14983     {
14984       size_t advIdx = m <= pcStart_ ? (pcStart_ - m + 1) * 2 : 0;
14985       index += advIdx;
14986       size_t copyStart = m > pcStart_ ? m : pcStart_ + 1;
14987       size_t n_copies = copyStart <= trunc_ ? (trunc_ - copyStart + 1) * 2 : 0;
14988       for ( size_t i = 0; i < n_copies; ++i )
14989         fphelp[index + i] = fpdata[inext + i];
14990       inext += n_copies;
14991       index += n_copies;
14992     }
14993   for ( size_t m = 0; m < (size_t)nsp; m++ ) fpdata[m] = fphelp[m];
14994 
14995   Free(fphelp);
14996 }
14997 
14998 
TEMPLATE(gather_complex,T)14999 void TEMPLATE(gather_complex,T)(T *fpdata, size_t pcStart, size_t trunc, size_t nsp)
15000 {
15001   T *restrict fphelp = (T*) Malloc(nsp*sizeof(T));
15002   size_t inext = 0;
15003 
15004   for ( size_t m = 0, index = 0;   m <= pcStart; m++ )
15005     for ( size_t n = m; n <= trunc; n++ )
15006       {
15007 	if ( pcStart >= n )
15008 	  {
15009 	    fphelp[inext++] = fpdata[index];
15010 	    fphelp[inext++] = fpdata[index+1];
15011 	  }
15012 	index += 2;
15013       }
15014 
15015   for ( size_t m = 0, index = 0; m <= trunc; m++ )
15016     for ( size_t n = m; n <= trunc; n++ )
15017       {
15018 	if ( n > pcStart )
15019 	  {
15020 	    fphelp[inext++] = fpdata[index];
15021 	    fphelp[inext++] = fpdata[index+1];
15022 	  }
15023 	index += 2;
15024       }
15025 
15026   for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
15027 
15028   Free(fphelp);
15029 }
15030 
15031 
TEMPLATE(scm0,T)15032 static void TEMPLATE(scm0,T)(T *pdl, T *pdr, T *pfl, T *pfr, int klg)
15033 {
15034   /* **** SCM0   - Apply SCM0 limiter to derivative estimates. */
15035   /* output: */
15036   /*   pdl   = the limited derivative at the left edge of the interval */
15037   /*   pdr   = the limited derivative at the right edge of the interval */
15038   /* inputs */
15039   /*   pdl   = the original derivative at the left edge */
15040   /*   pdr   = the original derivative at the right edge */
15041   /*   pfl   = function value at the left edge of the interval */
15042   /*   pfr   = function value at the right edge of the interval */
15043   /*   klg   = number of intervals where the derivatives are limited */
15044 
15045   /*  define constants */
15046 
15047   double zeps = 1.0e-12;
15048   double zfac = (1.0 - zeps) * 3.0;
15049 
15050   for ( int jl = 0; jl < klg; ++jl )
15051     {
15052       double r_1;
15053       if ( (r_1 = pfr[jl] - pfl[jl], fabs(r_1)) > zeps )
15054 	{
15055 	  double zalpha = pdl[jl] / (pfr[jl] - pfl[jl]);
15056 	  double zbeta  = pdr[jl] / (pfr[jl] - pfl[jl]);
15057 	  if ( zalpha <= 0.0 ) pdl[jl] = 0.0;
15058 	  if ( zbeta  <= 0.0 ) pdr[jl] = 0.0;
15059 	  if ( zalpha > zfac ) pdl[jl] = (T)(zfac * (pfr[jl] - pfl[jl]));
15060 	  if ( zbeta  > zfac ) pdr[jl] = (T)(zfac * (pfr[jl] - pfl[jl]));
15061 	}
15062       else
15063 	{
15064 	  pdl[jl] = 0.0;
15065 	  pdr[jl] = 0.0;
15066 	}
15067     }
15068 } /* scm0 */
15069 
15070 static
TEMPLATE(rowina3,T)15071 int TEMPLATE(rowina3,T)(T *p, int ko, int ki, T *pw,
15072 			int kcode, T msval, int *kret, int omisng, int operio, int oveggy)
15073 {
15074   /*
15075 C---->
15076 C**** ROWINA3 - Interpolation of row of values.
15077 C
15078 C     Purpose.
15079 C     --------
15080 C
15081 C     Interpolate a row of values.
15082 C
15083 C
15084 C**   Interface.
15085 C     ----------
15086 C
15087 C     CALL ROWINA3( P, KO, KI, PW, KCODE, PMSVAL, KRET, OMISNG, OPERIO)
15088 C
15089 C
15090 C     Input Parameters.
15091 C     -----------------
15092 C
15093 C     P      - Row of values to be interpolated.
15094 C              Dimension must be at least KO.
15095 C
15096 C     KO     - Number of values required.
15097 C
15098 C     KI     - Number of values in P on input.
15099 C
15100 C     PW     - Working array.
15101 C              Dimension must be at least (0:KO+2,3).
15102 C
15103 C     KCODE  - Interpolation required.
15104 C              1 , linear.
15105 C              3 , cubic.
15106 C
15107 C     PMSVAL - Value used for missing data indicator.
15108 C
15109 C     OMISNG - True if missing values are present in field.
15110 C
15111 C     OPERIO - True if input field is periodic.
15112 C
15113 C     OVEGGY - True if 'nearest neighbour' processing must be used
15114 C              for interpolation
15115 C
15116 C     Output Parameters.
15117 C     ------------------
15118 C
15119 C     P     - Now contains KO values.
15120 C     KRET  - Return code
15121 C             0, OK
15122 C             Non-zero, error
15123 C
15124 C
15125 C     Method.
15126 C     -------
15127 C
15128 C     Linear or cubic interpolation performed as required.
15129 C
15130 C     Comments.
15131 C     ---------
15132 C
15133 C     This is a version of ROWINA which allows for missing data
15134 C     values and hence for bitmapped fields.
15135 C
15136 C
15137 C     Author.
15138 C     -------
15139 C
15140 C     J.D.Chambers    ECMWF     22.07.94
15141 C
15142 C
15143 C     Modifications.
15144 C     --------------
15145 C
15146 C     J.D.Chambers    ECMWF     13.09.94
15147 C     Add return code KRET and remove calls to ABORT.
15148 C
15149 C     J. Clochard, Meteo France, for ECMWF - January 1998.
15150 C     Addition of OMISNG and OPERIO arguments.
15151 C
15152 C
15153 C     -----------------------------------------------------------------
15154 */
15155   /* System generated locals */
15156   int pw_dim1, pw_offset, i_1;
15157 
15158   /* Local variables */
15159   int jl, ip;
15160   double zwt1, zrdi, zpos;
15161   double zdo, zwt;
15162 
15163   UNUSED(omisng);
15164 
15165   /* Parameter adjustments */
15166   --p;
15167   pw_dim1 = ko + 3;
15168   pw_offset = pw_dim1;
15169   pw -= pw_offset;
15170 
15171   *kret = 0;
15172 
15173   if ( kcode == 1 )
15174     {
15175       /*    Move input values to work array */
15176       for ( jl = 1; jl <= ki; ++jl )
15177 	pw[jl + pw_dim1] = p[jl];
15178 
15179       if ( operio )
15180 	{
15181 	  /* Arrange wrap-around value in work array */
15182 	  pw[ki + 1 + pw_dim1] = p[1];
15183 
15184 	  /* Set up constants to be used to figure out weighting for */
15185 	  /* values in interpolation. */
15186 	  zrdi = (double) ki;
15187 	  zdo = 1.0 / (double) ko;
15188 	}
15189       else
15190 	{
15191 	  /* Repeat last value, to cope with "implicit truncation" below */
15192 	  pw[ki + 1 + pw_dim1] = p[ki];
15193 
15194 	  /* Set up constants to be used to figure out weighting for */
15195 	  /* values in interpolation. */
15196 	  zrdi = (double) (ki-1);
15197 	  zdo = 1.0 / (double) (ko-1);
15198  	}
15199 
15200       /*    Loop through the output points */
15201       for ( jl = 1; jl <= ko; ++jl )
15202 	{
15203 
15204 	  /* Calculate weight from the start of row */
15205 	  zpos = (jl - 1) * zdo;
15206 	  zwt = zpos * zrdi;
15207 
15208 	  /* Get the current array position(minus 1) from the weight - */
15209 	  /* note the implicit truncation. */
15210 	  ip = (int) zwt;
15211 
15212 	  /* Adjust the weight to range (0.0 to 1.0) */
15213 	  zwt -= ip;
15214 
15215           /* If 'nearest neighbour' processing must be used */
15216 	  if ( oveggy )
15217 	    {
15218               if ( zwt < 0.5 )
15219                 p[jl] = pw[ip + 1 + pw_dim1];
15220 	      else
15221 		p[jl] = pw[ip + 2 + pw_dim1];
15222 	    }
15223 	  else
15224 	    {
15225 	      /*    If the left value is missing, use the right value */
15226 	      if ( IS_EQUAL(pw[ip + 1 + pw_dim1], msval) )
15227 		{
15228 		  p[jl] = pw[ip + 2 + pw_dim1];
15229 		}
15230 	      /*    If the right value is missing, use the left value */
15231 	      else if ( IS_EQUAL(pw[ip + 2 + pw_dim1], msval) )
15232 		{
15233 		  p[jl] = pw[ip + 1 + pw_dim1];
15234 		}
15235 	      /*    If neither missing, interpolate ... */
15236 	      else
15237 		{
15238 		  /*  Interpolate using the weighted values on either side */
15239 		  /*  of the output point position */
15240 		  p[jl] = (T)((1.0 - zwt) * pw[ip+1 + pw_dim1]
15241                               + zwt * pw[ip+2 + pw_dim1]);
15242 		}
15243 	    }
15244 	}
15245     }
15246   else if ( kcode == 3 )
15247     {
15248       /*     *******************************    */
15249       /*     Section 2.  Cubic interpolation .. */
15250       /*     *******************************    */
15251       i_1 = ki;
15252       for ( jl = 1; jl <= i_1; ++jl )
15253 	{
15254           if ( IS_EQUAL(p[jl], msval) )
15255 	    {
15256 	      fprintf(stderr," ROWINA3: ");
15257 	      fprintf(stderr," Cubic interpolation not supported");
15258 	      fprintf(stderr," for fields containing missing data.\n");
15259 	      *kret = 1;
15260 	      goto L900;
15261 	    }
15262           pw[jl + pw_dim1] = p[jl];
15263 	}
15264       pw[pw_dim1] = p[ki];
15265       pw[ki + 1 + pw_dim1] = p[1];
15266       pw[ki + 2 + pw_dim1] = p[2];
15267       i_1 = ki;
15268       for ( jl = 1; jl <= i_1; ++jl )
15269 	{
15270           pw[jl + (pw_dim1 << 1)] =
15271             (T)(- pw[jl - 1 + pw_dim1] / 3.0 -
15272                 pw[jl     + pw_dim1] * 0.5 +
15273                 pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0);
15274           pw[jl + 1 + pw_dim1 * 3] =
15275             (T)(pw[jl - 1 + pw_dim1] / 6.0 -
15276                 pw[jl     + pw_dim1] +
15277                 pw[jl + 1 + pw_dim1] * 0.5 +
15278                 pw[jl + 2 + pw_dim1] / 3.0);
15279 	}
15280 
15281       TEMPLATE(scm0,T)(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
15282 		       &pw[pw_dim1 + 1], &pw[pw_dim1 + 2], ki);
15283 
15284       zrdi = (double) ki;
15285       zdo = 1.0 / (double) ko;
15286       for ( jl = 1; jl <= ko; ++jl )
15287 	{
15288           zpos = (jl - 1) * zdo;
15289           zwt = zpos * zrdi;
15290           ip = (int) zwt + 1;
15291           zwt = zwt + 1.0 - ip;
15292           zwt1 = 1.0 - zwt;
15293           p[jl] = (T)(((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
15294                        zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
15295                       ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
15296                        zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt);
15297 	}
15298 
15299     }
15300   else
15301     {
15302       /*    **************************************    */
15303       /*    Section 3.  Invalid interpolation code .. */
15304       /*    **************************************    */
15305       fprintf(stderr," ROWINA3:");
15306       fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
15307       *kret = 2;
15308     }
15309 
15310 L900:
15311     return 0;
15312 } /* rowina3 */
15313 
15314 
TEMPLATE(qu2reg3,T)15315 int TEMPLATE(qu2reg3,T)(T *pfield, int *kpoint, int klat, int klon,
15316 			T msval, int *kret, int omisng, int operio, int oveggy)
15317 {
15318   /*
15319 C**** QU2REG3 - Convert quasi-regular grid data to regular.
15320 C
15321 C     Purpose.
15322 C     --------
15323 C
15324 C     Convert quasi-regular grid data to regular,
15325 C     using either a linear or cubic interpolation.
15326 C
15327 C
15328 C**   Interface.
15329 C     ----------
15330 C
15331 C     CALL QU2REG3(PFIELD,KPOINT,KLAT,KLON,KCODE,PMSVAL,OMISNG,OPERIO,
15332 C    X            OVEGGY)
15333 C
15334 C
15335 C     Input Parameters.
15336 C     -----------------
15337 C
15338 C     PFIELD     - Array containing quasi-regular grid data.
15339 C
15340 C     KPOINT     - Array containing list of the number of
15341 C                  points on each latitude (or longitude) of
15342 C                  the quasi-regular grid.
15343 C
15344 C     KLAT       - Number of latitude lines
15345 C
15346 C     KLON       - Number of longitude lines
15347 C
15348 C     KCODE      - Interpolation required.
15349 C                  1 , linear - data quasi-regular on latitude lines.
15350 C                  3 , cubic -  data quasi-regular on latitude lines.
15351 C                  11, linear - data quasi-regular on longitude lines.
15352 C                  13, cubic -  data quasi-regular on longitude lines.
15353 C
15354 C     PMSVAL     - Value used for missing data indicator.
15355 C
15356 C     OMISNG     - True if missing values are present in field.
15357 C
15358 C     OPERIO     - True if input field is periodic.
15359 C
15360 C     OVEGGY     - True if 'nearest neighbour' processing must be used
15361 C                  for interpolation
15362 C
15363 C
15364 C     Output Parameters.
15365 C     ------------------
15366 C
15367 C     KRET       - return code
15368 C                  0 = OK
15369 C                  non-zero indicates fatal error
15370 C
15371 C
15372 C     Output Parameters.
15373 C     ------------------
15374 C
15375 C     PFIELD     - Array containing regular grid data.
15376 C
15377 C
15378 C     Method.
15379 C     -------
15380 C
15381 C     Data is interpolated and expanded into a temporary array,
15382 C     which is then copied back into the user's array.
15383 C     Returns an error code if an invalid interpolation is requested
15384 C     or field size exceeds array dimensions.
15385 C
15386 C     Comments.
15387 C     ---------
15388 C
15389 C     This routine is an adaptation of QU2REG to allow missing data
15390 C     values, and hence bit mapped fields.
15391 C
15392 C
15393 C     Author.
15394 C     -------
15395 C
15396 C     J.D.Chambers     ECMWF      22.07.94
15397 C
15398 C
15399 C     Modifications.
15400 C     --------------
15401 C
15402 C     J.D.Chambers     ECMWF      13.09.94
15403 C     Add return code KRET and remove calls to ABORT.
15404 C
15405 C     J.D.Chambers     ECMWF        Feb 1997
15406 C     Allow for 64-bit pointers
15407 C
15408 C     J. Clochard, Meteo France, for ECMWF - January 1998.
15409 C     Addition of OMISNG and OPERIO arguments.
15410 C     Fix message for longitude number out of bounds, and routine
15411 C     name in title and formats.
15412 C
15413 */
15414    /* System generated locals */
15415    int i_1, i_2;
15416    int kcode = 1;
15417 
15418    /* Local variables */
15419    int ilii, ilio, icode;
15420    int iregno, iquano, j210, j220, j230, j240, j225;
15421 
15422    T *ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
15423    T *zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
15424    T *zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
15425 
15426    /* Parameter adjustments */
15427    --pfield;
15428    --kpoint;
15429 
15430 /* ------------------------------ */
15431 /* Section 1. Set initial values. */
15432 /* ------------------------------ */
15433 
15434    *kret = 0;
15435 
15436 /* Check input parameters. */
15437 
15438    if (kcode != 1 && kcode != 3 && kcode != 11 && kcode != 13) {
15439       fprintf(stderr," QU2REG :");
15440       fprintf(stderr," Invalid interpolation type code = %2d\n",kcode);
15441       *kret = 1;
15442       goto L900;
15443    }
15444 
15445 /* Set array indices to 0. */
15446 
15447    ilii = 0;
15448    ilio = 0;
15449 
15450 /* Establish values of loop parameters. */
15451 
15452    if (kcode > 10) {
15453 
15454 /*    Quasi-regular along longitude lines. */
15455 
15456       iquano = klon;
15457       iregno = klat;
15458       icode = kcode - 10;
15459    } else {
15460 
15461 /*    Quasi-regular along latitude lines. */
15462 
15463       iquano = klat;
15464       iregno = klon;
15465       icode = kcode;
15466    }
15467 
15468 /*     -------------------------------------------------------- */
15469 /**    Section 2. Interpolate field from quasi to regular grid. */
15470 /*     -------------------------------------------------------- */
15471 
15472    i_1 = iquano;
15473    for (j230 = 1; j230 <= i_1; ++j230) {
15474 
15475       if (iregno != kpoint[j230]) {
15476 
15477 /*       Line contains less values than required,so */
15478 /*       extract quasi-regular grid values for a line */
15479 
15480          i_2 = kpoint[j230];
15481          for (j210 = 1; j210 <= i_2; ++j210) {
15482             ++ilii;
15483             zline[j210 - 1] = pfield[ilii];
15484          }
15485 
15486 /*       and interpolate this line. */
15487 
15488          TEMPLATE(rowina3,T)(zline, iregno, kpoint[j230], zwork, icode, msval, kret, omisng, operio , oveggy);
15489          if (*kret != 0) goto L900;
15490 
15491 /*       Add regular grid values for this line to the
15492          temporary array. */
15493 
15494          i_2 = iregno;
15495          for (j220 = 1; j220 <= i_2; ++j220) {
15496             ++ilio;
15497             ztemp[ilio - 1] = zline[j220 - 1];
15498          }
15499 
15500       } else {
15501 
15502 /*       Line contains the required number of values, so add */
15503 /*       this line to the temporary array. */
15504 
15505          i_2 = iregno;
15506          for (j225 = 1; j225 <= i_2; ++j225) {
15507             ++ilio;
15508             ++ilii;
15509             ztemp[ilio - 1] = pfield[ilii];
15510          }
15511       }
15512    }
15513 
15514 /* Copy temporary array to user array. */
15515 
15516    i_1 = klon * klat;
15517    for (j240 = 1; j240 <= i_1; ++j240) {
15518       pfield[j240] = ztemp[j240 - 1];
15519    }
15520 
15521 /* -------------------------------------------------------- */
15522 /* Section 9. Return to calling routine. Format statements. */
15523 /* -------------------------------------------------------- */
15524 
15525 L900:
15526 
15527    Free(zwork);
15528    Free(zline);
15529    Free(ztemp);
15530 
15531    return 0;
15532 } /* qu2reg3 */
15533 
15534 #endif /* T */
15535 
15536 /*
15537  * Local Variables:
15538  * mode: c
15539  * c-file-style: "Java"
15540  * c-basic-offset: 2
15541  * indent-tabs-mode: nil
15542  * show-trailing-whitespace: t
15543  * require-trailing-newline: t
15544  * End:
15545  */
15546 #include <string.h>
15547 
15548 
15549 
gribVersion(unsigned char * is,size_t buffersize)15550 int gribVersion(unsigned char *is, size_t buffersize)
15551 {
15552   if ( buffersize < 8 )
15553     Error("Buffer too small (current size %d)!", (int) buffersize);
15554 
15555   return GRIB_EDITION(is);
15556 }
15557 
15558 static
GET_Real(unsigned char * grib)15559 double GET_Real(unsigned char *grib)
15560 {
15561   int iexp  = GET_UINT1(grib[0]);
15562   int imant = GET_UINT3(grib[1], grib[2], grib[3]);
15563 
15564   return decfp2(iexp, imant);
15565 }
15566 
15567 static
decodeIS(unsigned char * is,int * isec0,int * iret)15568 int decodeIS(unsigned char *is, int *isec0, int *iret)
15569 {
15570   // Octets 1 - 4 : The letters G R I B. Four 8 bit fields.
15571 
15572   // Check letters -> GRIB, BUDG or TIDE.
15573 
15574   // Check that 'GRIB' is found where expected.
15575   bool lgrib = GRIB_START(is);
15576 
15577   // ECMWF pseudo-grib data uses 'BUDG' and 'TIDE'.
15578   bool lbudg = BUDG_START(is);
15579   bool ltide = TIDE_START(is);
15580 
15581   // Data is not GRIB or pseudo-grib.
15582   if ( lgrib == false && lbudg == false && ltide == false )
15583     {
15584       *iret = 305;
15585       gprintf(__func__, "Input data is not GRIB or pseudo-grib.");
15586       gprintf(__func__, "Return code = %d", *iret);
15587     }
15588   if ( lbudg || ltide )
15589     {
15590       *iret = 305;
15591       gprintf(__func__, "Pseudo-grib data unsupported.");
15592       gprintf(__func__, "Return code = %d", *iret);
15593     }
15594 
15595   // Octets 5 - 7 : Length of message. One 24 bit field.
15596   ISEC0_GRIB_Len = GRIB1_SECLEN(is);
15597 
15598   // Octet 8 : GRIB Edition Number. One 8 bit field.
15599   ISEC0_GRIB_Version = GRIB_EDITION(is);
15600 
15601   if ( ISEC0_GRIB_Version > 1 )
15602     Error("GRIB version %d unsupported!", ISEC0_GRIB_Version);
15603 
15604   int grib1offset = ISEC0_GRIB_Version * 4;
15605 
15606   int isLen = 4 + grib1offset;
15607 
15608   return isLen;
15609 }
15610 
15611 static
decodePDS_ECMWF_local_Extension_1(unsigned char * pds,int * isec1)15612 void decodePDS_ECMWF_local_Extension_1(unsigned char *pds, int *isec1)
15613 {
15614   isec1[36] = GET_UINT1(pds[40]);         /* extension identifier       */
15615   isec1[37] = GET_UINT1(pds[41]);         /* Class                      */
15616   isec1[38] = GET_UINT1(pds[42]);         /* Type                       */
15617   isec1[39] = GET_UINT2(pds[43],pds[44]); /* Stream                     */
15618   /* isec1[40] = GET_UINT4(pds[45],pds[46],pds[47],pds[48]); */
15619   memcpy((char*) &isec1[40], &pds[45], 4);
15620   isec1[41] = GET_UINT1(pds[49]);         /* Forecast number            */
15621   isec1[42] = GET_UINT1(pds[50]);         /* Total number of forecasts  */
15622 }
15623 
15624 static
decodePDS_DWD_local_Extension_254(unsigned char * pds,int * isec1)15625 void decodePDS_DWD_local_Extension_254(unsigned char *pds, int *isec1)
15626 {
15627   isec1[36] = GET_UINT1(pds[40]); /* extension identifier */
15628   for ( int i = 0; i < 11; i++ )
15629     isec1[37+i] =  GET_UINT1(pds[41+i]);
15630 
15631   int isvn = GET_UINT2(pds[52],pds[53]);
15632 
15633   isec1[48] =  isvn % 0x8000;              /* DWD experiment identifier            */
15634   isec1[49] =  isvn >> 15;                 /* DWD run type (0=main, 2=ass, 3=test) */
15635 }
15636 
15637 static
decodePDS_DWD_local_Extension_253(unsigned char * pds,int * isec1)15638 void decodePDS_DWD_local_Extension_253(unsigned char *pds, int *isec1)
15639 {
15640   isec1[36] = GET_UINT1(pds[40]); /* extension identifier */
15641   for ( int i = 0; i < 11; i++ )
15642     isec1[37+i] =  GET_UINT1(pds[41+i]);
15643 
15644   int isvn = GET_UINT2(pds[52],pds[53]);
15645 
15646   isec1[48] =  isvn % 0x8000;              /* DWD experiment identifier            */
15647   isec1[49] =  isvn >> 15;                 /* DWD run type (0=main, 2=ass, 3=test) */
15648   isec1[50] =  GET_UINT1(pds[54]);         /* User id, specified by table          */
15649   isec1[51] =  GET_UINT2(pds[55],pds[56]); /* Experiment identifier                */
15650   isec1[52] =  GET_UINT2(pds[57],pds[58]); /* Ensemble identification by table     */
15651   isec1[53] =  GET_UINT2(pds[59],pds[60]); /* Number of ensemble members           */
15652   isec1[54] =  GET_UINT2(pds[61],pds[62]); /* Actual number of ensemble member     */
15653   isec1[55] =  GET_UINT1(pds[63]);         /* Model major version number           */
15654   isec1[56] =  GET_UINT1(pds[64]);         /* Model minor version number           */
15655 }
15656 
15657 static
decodePDS_MPIM_local_Extension_1(unsigned char * pds,int * isec1)15658 void decodePDS_MPIM_local_Extension_1(unsigned char *pds, int *isec1)
15659 {
15660   isec1[36] = GET_UINT1(pds[40]);         /* extension identifier            */
15661   isec1[37] = GET_UINT1(pds[41]);         /* type of ensemble forecast       */
15662   isec1[38] = GET_UINT2(pds[42],pds[43]); /* individual ensemble member      */
15663   isec1[39] = GET_UINT2(pds[44],pds[45]); /* number of forecasts in ensemble */
15664 }
15665 
15666 static
decodePDS(unsigned char * pds,int * isec0,int * isec1)15667 int decodePDS(unsigned char *pds, int *isec0, int *isec1)
15668 {
15669   int pdsLen = PDS_Len;
15670 
15671   ISEC1_CodeTable      = PDS_CodeTable;
15672   ISEC1_CenterID       = PDS_CenterID;
15673   ISEC1_ModelID        = PDS_ModelID;
15674   ISEC1_GridDefinition = PDS_GridDefinition;
15675   ISEC1_Sec2Or3Flag    = PDS_Sec2Or3Flag;
15676   ISEC1_Parameter      = PDS_Parameter;
15677   ISEC1_LevelType      = PDS_LevelType;
15678 
15679   if ( (ISEC1_LevelType !=  20) &&
15680        (ISEC1_LevelType != GRIB1_LTYPE_99)           &&
15681        (ISEC1_LevelType != GRIB1_LTYPE_ISOBARIC)     &&
15682        (ISEC1_LevelType != GRIB1_LTYPE_ISOBARIC_PA)  &&
15683        (ISEC1_LevelType != GRIB1_LTYPE_ALTITUDE)     &&
15684        (ISEC1_LevelType != GRIB1_LTYPE_HEIGHT)       &&
15685        (ISEC1_LevelType != GRIB1_LTYPE_SIGMA)        &&
15686        (ISEC1_LevelType != GRIB1_LTYPE_HYBRID)       &&
15687        (ISEC1_LevelType != GRIB1_LTYPE_LANDDEPTH)    &&
15688        (ISEC1_LevelType != GRIB1_LTYPE_ISENTROPIC)   &&
15689        (ISEC1_LevelType != 115) &&
15690        (ISEC1_LevelType != 117) &&
15691        (ISEC1_LevelType != 125) &&
15692        (ISEC1_LevelType != 127) &&
15693        (ISEC1_LevelType != GRIB1_LTYPE_SEADEPTH)     &&
15694        (ISEC1_LevelType != 210) )
15695     {
15696       ISEC1_Level1 = PDS_Level1;
15697       ISEC1_Level2 = PDS_Level2;
15698     }
15699   else
15700     {
15701       ISEC1_Level1 = PDS_Level;
15702       ISEC1_Level2 = 0;
15703     }
15704 
15705   /* ISEC1_Year        = PDS_Year; */
15706   ISEC1_Month          = PDS_Month;
15707   ISEC1_Day            = PDS_Day;
15708   ISEC1_Hour           = PDS_Hour;
15709   ISEC1_Minute         = PDS_Minute;
15710   ISEC1_TimeUnit       = PDS_TimeUnit;
15711   ISEC1_TimePeriod1    = PDS_TimePeriod1;
15712   ISEC1_TimePeriod2    = PDS_TimePeriod2;
15713   ISEC1_TimeRange      = PDS_TimeRange;
15714   ISEC1_AvgNum         = PDS_AvgNum;
15715   ISEC1_AvgMiss        = PDS_AvgMiss;
15716 
15717   if ( ISEC0_GRIB_Version == 1 )
15718     {
15719       ISEC1_Year           = PDS_Year;
15720       ISEC1_Century        = PDS_Century;
15721       ISEC1_SubCenterID    = PDS_Subcenter;
15722       ISEC1_DecScaleFactor = PDS_DecimalScale;
15723     }
15724   else
15725     {
15726       int year             = GET_UINT1(pds[12]);
15727       if ( year <= 100 )
15728 	{
15729 	  ISEC1_Year       = year;
15730 	  ISEC1_Century    = 1;
15731 	}
15732       else
15733 	{
15734 	  ISEC1_Year       = year%100;
15735 	  ISEC1_Century    = 1 + (year-ISEC1_Year)/100;
15736 	}
15737       ISEC1_SubCenterID    = 0;
15738       ISEC1_DecScaleFactor = 0;
15739     }
15740 
15741   if ( ISEC1_Year < 0 )
15742     {
15743       ISEC1_Year    = -ISEC1_Year;
15744       ISEC1_Century = -ISEC1_Century;
15745     }
15746 
15747   ISEC1_LocalFLag = 0;
15748   if ( pdsLen > 28 )
15749     {
15750       int localextlen = pdsLen-28;
15751 
15752       if ( localextlen > 4000 )
15753 	{
15754 	  Warning("PDS larger than 4000 bytes not supported!");
15755 	}
15756       else
15757 	{
15758 	  ISEC1_LocalFLag = 1;
15759 
15760 	  if ( ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250 )
15761 	    {
15762 	      if ( pds[40] == 254 )
15763                 decodePDS_DWD_local_Extension_254(pds, isec1);
15764 	      else if ( pds[40] == 253 )
15765                 decodePDS_DWD_local_Extension_253(pds, isec1);
15766 	    }
15767 	  else if ( (ISEC1_CenterID    == 98 && ISEC1_LocalFLag ==  1) ||
15768 		    (ISEC1_SubCenterID == 98 && ISEC1_LocalFLag ==  1) ||
15769 		    (ISEC1_CenterID    ==  7 && ISEC1_SubCenterID == 98) )
15770 	    {
15771 	      if ( pds[40] == 1 )
15772 		decodePDS_ECMWF_local_Extension_1(pds, isec1);
15773 	    }
15774 	  else if ( ISEC1_CenterID    == 252 && ISEC1_LocalFLag ==  1 )
15775 	    {
15776 	      if ( pds[40] == 1 )
15777 		decodePDS_MPIM_local_Extension_1(pds, isec1);
15778 	    }
15779 	  else
15780 	    {
15781 	      for ( int i = 0; i < localextlen; i++ )
15782                 isec1[24+i] = pds[28+i];
15783 	    }
15784 	}
15785     }
15786 
15787   return pdsLen;
15788 }
15789 
15790 
gribPrintSec2_double(int * isec0,int * isec2,double * fsec2)15791 static void gribPrintSec2_double(int *isec0, int *isec2, double *fsec2) {gribPrintSec2DP(isec0, isec2, fsec2);}
gribPrintSec3_double(int * isec0,int * isec3,double * fsec3)15792 static void gribPrintSec3_double(int *isec0, int *isec3, double *fsec3) {gribPrintSec3DP(isec0, isec3, fsec3);}
gribPrintSec4_double(int * isec0,int * isec4,double * fsec4)15793 static void gribPrintSec4_double(int *isec0, int *isec4, double *fsec4) {gribPrintSec4DP(isec0, isec4, fsec4);}
gribPrintSec2_float(int * isec0,int * isec2,float * fsec2)15794 static void gribPrintSec2_float(int *isec0, int *isec2, float *fsec2) {gribPrintSec2SP(isec0, isec2, fsec2);}
gribPrintSec3_float(int * isec0,int * isec3,float * fsec3)15795 static void gribPrintSec3_float(int *isec0, int *isec3, float *fsec3) {gribPrintSec3SP(isec0, isec3, fsec3);}
gribPrintSec4_float(int * isec0,int * isec4,float * fsec4)15796 static void gribPrintSec4_float(int *isec0, int *isec4, float *fsec4) {gribPrintSec4SP(isec0, isec4, fsec4);}
15797 
15798 
15799 #ifdef T
15800 #undef T
15801 #endif
15802 #define T double
15803 #ifdef T
15804 
15805 #include <inttypes.h>
15806 
15807 static
TEMPLATE(decode_array_common,T)15808 void TEMPLATE(decode_array_common,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
15809 				     T fmin, T zscale, T *restrict fpdata)
15810 {
15811   /* code from wgrib routine BDS_unpack */
15812   const unsigned char *bits = igrib;
15813   unsigned int tbits = 0;
15814   int n_bits = NumBits;
15815   int t_bits = 0;
15816 
15817   const unsigned jmask = (1U << n_bits) - 1U;
15818   for (long i = 0; i < jlend; i++)
15819     {
15820       if (n_bits - t_bits > 8)
15821 	{
15822 	  tbits = (tbits << 16) | ((unsigned)bits[0] << 8) | ((unsigned)bits[1]);
15823 	  bits += 2;
15824 	  t_bits += 16;
15825 	}
15826 
15827       while ( t_bits < n_bits )
15828 	{
15829 	  tbits = (tbits * 256) + *bits++;
15830 	  t_bits += 8;
15831 	}
15832       t_bits -= n_bits;
15833       fpdata[i] = (float)((tbits >> t_bits) & jmask);
15834     }
15835   /* at least this vectorizes :) */
15836   for (long i = 0; i < jlend; i++)
15837     fpdata[i] = fmin + zscale*fpdata[i];
15838 }
15839 
15840 static
TEMPLATE(decode_array_common2,T)15841 void TEMPLATE(decode_array_common2,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
15842 				      T fmin, T zscale, T *restrict fpdata)
15843 {
15844   static const unsigned mask[] = {0,1,3,7,15,31,63,127,255};
15845   static const double shift[9] = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
15846 
15847   /* code from wgrib routine BDS_unpack */
15848   const unsigned char *bits = igrib;
15849   int n_bits = NumBits;
15850   int c_bits, j_bits;
15851 
15852   /* older unoptimized code, not often used */
15853   c_bits = 8;
15854   for (long i = 0; i < jlend; i++)
15855     {
15856       double jj = 0.0;
15857       j_bits = n_bits;
15858       while (c_bits <= j_bits)
15859 	{
15860 	  if (c_bits == 8)
15861 	    {
15862 	      jj = jj * 256.0  + (double) (*bits++);
15863 	      j_bits -= 8;
15864 	    }
15865 	  else
15866 	    {
15867 	      jj = (jj * shift[c_bits]) + (double) (*bits & mask[c_bits]);
15868 	      bits++;
15869 	      j_bits -= c_bits;
15870 	      c_bits = 8;
15871 	    }
15872 	}
15873 
15874       if (j_bits)
15875 	{
15876 	  c_bits -= j_bits;
15877 	  jj = (jj * shift[j_bits]) + (double) (((unsigned)*bits >> c_bits) & mask[j_bits]);
15878 	}
15879       fpdata[i] = (T)(fmin + zscale*jj);
15880     }
15881 }
15882 
15883 static
TEMPLATE(decode_array_2byte,T)15884 void TEMPLATE(decode_array_2byte,T)(size_t jlend, const unsigned char *restrict igrib,
15885                                     T *fpdata, T fmin, T zscale)
15886 {
15887   U_BYTEORDER;
15888   const uint16_t *restrict sgrib = (const uint16_t *)(const void *)(igrib);
15889 
15890   if ( IS_BIGENDIAN() )
15891     {
15892       for ( size_t i = 0; i < jlend; i++ )
15893         {
15894           fpdata[i] = fmin + zscale * sgrib[i];
15895         }
15896     }
15897   else
15898     {
15899       for ( size_t i = 0; i < jlend; i++ )
15900         {
15901           uint16_t ui16 = gribSwapByteOrder_uint16(sgrib[i]);
15902           fpdata[i] = fmin + zscale * ui16;
15903         }
15904     }
15905 }
15906 
15907 static
TEMPLATE(decode_array,T)15908 void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, int numBits,
15909 			      T fmin, T zscale, T *restrict fpdata)
15910 {
15911 #if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
15912   uint64_t start_decode, end_decode;
15913 #endif
15914 
15915   long i;
15916 #ifdef VECTORCODE
15917   GRIBPACK *lgrib = NULL;
15918 
15919   if ( numBits%8 == 0 )
15920     {
15921       long jlenc = jlend * numBits / 8;
15922       if ( jlenc > 0 )
15923 	{
15924 	  lgrib = (GRIBPACK*) Malloc(jlenc*sizeof(GRIBPACK));
15925 	  if ( lgrib == NULL ) SysError("No Memory!");
15926 
15927 	  (void) UNPACK_GRIB(igrib, lgrib, jlenc, -1L);
15928 	}
15929     }
15930 
15931   if ( numBits ==  0 )
15932     {
15933       for ( i = 0; i < jlend; i++ )
15934 	fpdata[i] = fmin;
15935     }
15936   else if ( numBits ==  8 )
15937     for ( i = 0; i < jlend; i++ )
15938       {
15939 	T dval = (int)lgrib[i];
15940 	fpdata[i] = fmin + zscale * dval;
15941       }
15942   else if ( numBits == 16 )
15943     for ( i = 0; i < jlend; i++ )
15944       {
15945 	T dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
15946 	fpdata[i] = fmin + zscale * dval;
15947       }
15948   else if ( numBits == 24 )
15949     for ( i = 0; i < jlend; i++ )
15950       {
15951 	T dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
15952 	  	 (int)lgrib[3*i+2]);
15953 	fpdata[i] = fmin + zscale * dval;
15954       }
15955   else if ( numBits == 32 )
15956     for ( i = 0; i < jlend; i++ )
15957       {
15958 	T dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
15959 		((unsigned int)lgrib[4*i+2] <<  8) +  (unsigned int)lgrib[4*i+3]);
15960 	fpdata[i] = fmin + zscale * dval;
15961       }
15962   else if ( numBits <= 25 )
15963     {
15964       TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
15965     }
15966   else if ( numBits > 25 && numBits < 32 )
15967     {
15968       TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
15969     }
15970   else
15971     {
15972       Error("Unimplemented packing factor %d!", numBits);
15973     }
15974 
15975   if ( lgrib ) Free(lgrib);
15976 
15977 #else
15978   if ( numBits ==  0 )
15979     {
15980       for ( i = 0; i < jlend; i++ )
15981 	fpdata[i] = fmin;
15982     }
15983   else if ( numBits ==  8 )
15984     for ( i = 0; i < jlend; i++ )
15985       {
15986 	T dval = (int)igrib[i];
15987 	fpdata[i] = fmin + zscale * dval;
15988       }
15989   else if ( numBits == 16 )
15990     {
15991       TEMPLATE(decode_array_2byte,T)((size_t) jlend, igrib, fpdata, fmin, zscale);
15992     }
15993   else if ( numBits == 24 )
15994     for ( i = 0; i < jlend; i++ )
15995       {
15996 	T dval = (T)(((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
15997                      (int)igrib[3*i+2]);
15998 	fpdata[i] = fmin + zscale * dval;
15999       }
16000   else if ( numBits == 32 )
16001     for ( i = 0; i < jlend; i++ )
16002       {
16003 	T dval = (T)(((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
16004                      ((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
16005 	fpdata[i] = fmin + zscale * dval;
16006       }
16007   else if ( numBits <= 25 )
16008     {
16009       TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
16010     }
16011   else if ( numBits > 25 && numBits < 32 )
16012     {
16013       TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
16014     }
16015   else
16016     {
16017       Error("Unimplemented packing factor %d!", numBits);
16018     }
16019 #endif
16020 }
16021 
16022 #endif /* T */
16023 
16024 /*
16025  * Local Variables:
16026  * mode: c
16027  * End:
16028  */
16029 
16030 #ifdef T
16031 #undef T
16032 #endif
16033 #define T float
16034 #ifdef T
16035 
16036 #include <inttypes.h>
16037 
16038 static
TEMPLATE(decode_array_common,T)16039 void TEMPLATE(decode_array_common,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
16040 				     T fmin, T zscale, T *restrict fpdata)
16041 {
16042   /* code from wgrib routine BDS_unpack */
16043   const unsigned char *bits = igrib;
16044   unsigned int tbits = 0;
16045   int n_bits = NumBits;
16046   int t_bits = 0;
16047 
16048   const unsigned jmask = (1U << n_bits) - 1U;
16049   for (long i = 0; i < jlend; i++)
16050     {
16051       if (n_bits - t_bits > 8)
16052 	{
16053 	  tbits = (tbits << 16) | ((unsigned)bits[0] << 8) | ((unsigned)bits[1]);
16054 	  bits += 2;
16055 	  t_bits += 16;
16056 	}
16057 
16058       while ( t_bits < n_bits )
16059 	{
16060 	  tbits = (tbits * 256) + *bits++;
16061 	  t_bits += 8;
16062 	}
16063       t_bits -= n_bits;
16064       fpdata[i] = (float)((tbits >> t_bits) & jmask);
16065     }
16066   /* at least this vectorizes :) */
16067   for (long i = 0; i < jlend; i++)
16068     fpdata[i] = fmin + zscale*fpdata[i];
16069 }
16070 
16071 static
TEMPLATE(decode_array_common2,T)16072 void TEMPLATE(decode_array_common2,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
16073 				      T fmin, T zscale, T *restrict fpdata)
16074 {
16075   static const unsigned mask[] = {0,1,3,7,15,31,63,127,255};
16076   static const double shift[9] = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
16077 
16078   /* code from wgrib routine BDS_unpack */
16079   const unsigned char *bits = igrib;
16080   int n_bits = NumBits;
16081   int c_bits, j_bits;
16082 
16083   /* older unoptimized code, not often used */
16084   c_bits = 8;
16085   for (long i = 0; i < jlend; i++)
16086     {
16087       double jj = 0.0;
16088       j_bits = n_bits;
16089       while (c_bits <= j_bits)
16090 	{
16091 	  if (c_bits == 8)
16092 	    {
16093 	      jj = jj * 256.0  + (double) (*bits++);
16094 	      j_bits -= 8;
16095 	    }
16096 	  else
16097 	    {
16098 	      jj = (jj * shift[c_bits]) + (double) (*bits & mask[c_bits]);
16099 	      bits++;
16100 	      j_bits -= c_bits;
16101 	      c_bits = 8;
16102 	    }
16103 	}
16104 
16105       if (j_bits)
16106 	{
16107 	  c_bits -= j_bits;
16108 	  jj = (jj * shift[j_bits]) + (double) (((unsigned)*bits >> c_bits) & mask[j_bits]);
16109 	}
16110       fpdata[i] = (T)(fmin + zscale*jj);
16111     }
16112 }
16113 
16114 static
TEMPLATE(decode_array_2byte,T)16115 void TEMPLATE(decode_array_2byte,T)(size_t jlend, const unsigned char *restrict igrib,
16116                                     T *fpdata, T fmin, T zscale)
16117 {
16118   U_BYTEORDER;
16119   const uint16_t *restrict sgrib = (const uint16_t *)(const void *)(igrib);
16120 
16121   if ( IS_BIGENDIAN() )
16122     {
16123       for ( size_t i = 0; i < jlend; i++ )
16124         {
16125           fpdata[i] = fmin + zscale * sgrib[i];
16126         }
16127     }
16128   else
16129     {
16130       for ( size_t i = 0; i < jlend; i++ )
16131         {
16132           uint16_t ui16 = gribSwapByteOrder_uint16(sgrib[i]);
16133           fpdata[i] = fmin + zscale * ui16;
16134         }
16135     }
16136 }
16137 
16138 static
TEMPLATE(decode_array,T)16139 void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, int numBits,
16140 			      T fmin, T zscale, T *restrict fpdata)
16141 {
16142 #if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
16143   uint64_t start_decode, end_decode;
16144 #endif
16145 
16146   long i;
16147 #ifdef VECTORCODE
16148   GRIBPACK *lgrib = NULL;
16149 
16150   if ( numBits%8 == 0 )
16151     {
16152       long jlenc = jlend * numBits / 8;
16153       if ( jlenc > 0 )
16154 	{
16155 	  lgrib = (GRIBPACK*) Malloc(jlenc*sizeof(GRIBPACK));
16156 	  if ( lgrib == NULL ) SysError("No Memory!");
16157 
16158 	  (void) UNPACK_GRIB(igrib, lgrib, jlenc, -1L);
16159 	}
16160     }
16161 
16162   if ( numBits ==  0 )
16163     {
16164       for ( i = 0; i < jlend; i++ )
16165 	fpdata[i] = fmin;
16166     }
16167   else if ( numBits ==  8 )
16168     for ( i = 0; i < jlend; i++ )
16169       {
16170 	T dval = (int)lgrib[i];
16171 	fpdata[i] = fmin + zscale * dval;
16172       }
16173   else if ( numBits == 16 )
16174     for ( i = 0; i < jlend; i++ )
16175       {
16176 	T dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
16177 	fpdata[i] = fmin + zscale * dval;
16178       }
16179   else if ( numBits == 24 )
16180     for ( i = 0; i < jlend; i++ )
16181       {
16182 	T dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
16183 	  	 (int)lgrib[3*i+2]);
16184 	fpdata[i] = fmin + zscale * dval;
16185       }
16186   else if ( numBits == 32 )
16187     for ( i = 0; i < jlend; i++ )
16188       {
16189 	T dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
16190 		((unsigned int)lgrib[4*i+2] <<  8) +  (unsigned int)lgrib[4*i+3]);
16191 	fpdata[i] = fmin + zscale * dval;
16192       }
16193   else if ( numBits <= 25 )
16194     {
16195       TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
16196     }
16197   else if ( numBits > 25 && numBits < 32 )
16198     {
16199       TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
16200     }
16201   else
16202     {
16203       Error("Unimplemented packing factor %d!", numBits);
16204     }
16205 
16206   if ( lgrib ) Free(lgrib);
16207 
16208 #else
16209   if ( numBits ==  0 )
16210     {
16211       for ( i = 0; i < jlend; i++ )
16212 	fpdata[i] = fmin;
16213     }
16214   else if ( numBits ==  8 )
16215     for ( i = 0; i < jlend; i++ )
16216       {
16217 	T dval = (int)igrib[i];
16218 	fpdata[i] = fmin + zscale * dval;
16219       }
16220   else if ( numBits == 16 )
16221     {
16222       TEMPLATE(decode_array_2byte,T)((size_t) jlend, igrib, fpdata, fmin, zscale);
16223     }
16224   else if ( numBits == 24 )
16225     for ( i = 0; i < jlend; i++ )
16226       {
16227 	T dval = (T)(((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
16228                      (int)igrib[3*i+2]);
16229 	fpdata[i] = fmin + zscale * dval;
16230       }
16231   else if ( numBits == 32 )
16232     for ( i = 0; i < jlend; i++ )
16233       {
16234 	T dval = (T)(((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
16235                      ((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
16236 	fpdata[i] = fmin + zscale * dval;
16237       }
16238   else if ( numBits <= 25 )
16239     {
16240       TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
16241     }
16242   else if ( numBits > 25 && numBits < 32 )
16243     {
16244       TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
16245     }
16246   else
16247     {
16248       Error("Unimplemented packing factor %d!", numBits);
16249     }
16250 #endif
16251 }
16252 
16253 #endif /* T */
16254 
16255 /*
16256  * Local Variables:
16257  * mode: c
16258  * End:
16259  */
16260 
16261 
16262 #ifdef T
16263 #undef T
16264 #endif
16265 #define T double
16266 #ifdef T
16267 
16268 static
TEMPLATE(decodeGDS,T)16269 int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2, int *numGridVals)
16270 {
16271   // int imisng = 0;
16272   bool ReducedGrid = false, VertCoorTab = false;
16273 #ifdef VECTORCODE
16274   unsigned char *igrib;
16275   GRIBPACK *lgrib = NULL;
16276   size_t lGribLen = 0;
16277 #endif
16278 
16279   *numGridVals = 0;
16280 
16281   memset(isec2, 0, 22*sizeof(int));
16282 
16283   unsigned gdsLen = GDS_Len;
16284 
16285   unsigned ipvpl = GDS_PVPL;
16286   if ( ipvpl == 0 ) ipvpl = 0xFF;
16287 
16288   if ( ipvpl != 0xFF )
16289     { /* Either vct or reduced grid */
16290       if ( GDS_NV != 0 )
16291 	{ /* we have vct */
16292 	  VertCoorTab = true;
16293 	  unsigned ipl =  4*GDS_NV + ipvpl - 1;
16294 	  if ( ipl < gdsLen ) ReducedGrid = true;
16295 	}
16296       else
16297 	{
16298 	  VertCoorTab = false;
16299 	  ReducedGrid = true;
16300 	}
16301       /*	  ReducedGrid = (gdsLen - 32 - 4*GDS_NV); */
16302     }
16303 
16304   if ( ISEC0_GRIB_Version == 0 )
16305     {
16306       VertCoorTab = (gdsLen - 32) > 0;
16307     }
16308 
16309   if ( ReducedGrid )
16310     {
16311       unsigned locnl = GDS_PVPL - 1 + (VertCoorTab * 4 * GDS_NV);
16312       unsigned jlenl = (gdsLen - locnl)  >> 1;
16313       if ( jlenl == GDS_NumLat )
16314 	{
16315 	  *numGridVals = 0;
16316 	  ISEC2_Reduced = true;
16317 	  for ( unsigned i = 0; i < jlenl; i++ )
16318 	    {
16319 	      ISEC2_ReducedPoints(i) = GET_UINT2(gds[locnl+2*i], gds[locnl+2*i+1]);
16320 	      *numGridVals += ISEC2_ReducedPoints(i);
16321 	    }
16322 	}
16323       else
16324 	{
16325 	  ReducedGrid = false;
16326 	}
16327     }
16328 
16329   ISEC2_GridType = GDS_GridType;
16330 
16331   /*
16332      Gaussian grid definition.
16333   */
16334   if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
16335        ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
16336        ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
16337     {
16338       ISEC2_NumLat    = GDS_NumLat;
16339       if ( ! ReducedGrid )
16340 	{
16341 	  ISEC2_NumLon = GDS_NumLon;
16342 	  *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
16343 	}
16344       ISEC2_FirstLat  = GDS_FirstLat;
16345       ISEC2_FirstLon  = GDS_FirstLon;
16346       ISEC2_ResFlag   = GDS_ResFlag;
16347       ISEC2_LastLat   = GDS_LastLat;
16348       ISEC2_LastLon   = GDS_LastLon;
16349       ISEC2_LonIncr   = GDS_LonIncr;
16350 
16351       ISEC2_NumPar    = GDS_NumPar;
16352       ISEC2_ScanFlag  = GDS_ScanFlag;
16353       if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
16354 	{
16355 	  ISEC2_LatSP     = GDS_LatSP;
16356 	  ISEC2_LonSP     = GDS_LonSP;
16357 	  FSEC2_RotAngle  = (T)GDS_RotAngle;
16358 	}
16359       /*
16360 	if ( Lons != Longitudes || Lats != Latitudes )
16361 	Error("Latitude/Longitude Conflict");
16362       */
16363     }
16364   else if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN     ||
16365 	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_ROT ||
16366 	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_STR ||
16367 	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_ROTSTR )
16368     {
16369       // iret = decodeGDS_GG(gds, gdspos, isec0, isec2, imisng);
16370     }
16371   else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON     ||
16372 	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT ||
16373 	    ISEC2_GridType == GRIB1_GTYPE_LATLON_STR ||
16374 	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROTSTR )
16375     {
16376       // iret = decodeGDS_LL(gds, gdspos, isec0, isec2, imisng);
16377     }
16378   else if ( ISEC2_GridType == GRIB1_GTYPE_LCC )
16379     {
16380       ISEC2_NumLon    = GDS_NumLon;
16381       ISEC2_NumLat    = GDS_NumLat;
16382       *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
16383       ISEC2_FirstLat  = GDS_FirstLat;
16384       ISEC2_FirstLon  = GDS_FirstLon;
16385       ISEC2_ResFlag   = GDS_ResFlag;
16386       ISEC2_Lambert_Lov   = GDS_Lambert_Lov;
16387       ISEC2_Lambert_dx    = GDS_Lambert_dx;
16388       ISEC2_Lambert_dy    = GDS_Lambert_dy;
16389       ISEC2_Lambert_LatS1 = GDS_Lambert_LatS1;
16390       ISEC2_Lambert_LatS2 = GDS_Lambert_LatS2;
16391       ISEC2_Lambert_LatSP = GDS_Lambert_LatSP;
16392       ISEC2_Lambert_LonSP = GDS_Lambert_LonSP;
16393       ISEC2_Lambert_ProjFlag = GDS_Lambert_ProjFlag;
16394       ISEC2_ScanFlag      = GDS_ScanFlag;
16395     }
16396   else if ( ISEC2_GridType == GRIB1_GTYPE_SPECTRAL )
16397     {
16398       ISEC2_PentaJ  = GDS_PentaJ; /* Truncation */
16399       ISEC2_PentaK  = GDS_PentaK;
16400       ISEC2_PentaM  = GDS_PentaM;
16401       ISEC2_RepType = GDS_RepType;
16402       ISEC2_RepMode = GDS_RepMode;
16403       *numGridVals  = (ISEC2_PentaJ+1)*(ISEC2_PentaJ+2);
16404       isec2[ 6] = 0;
16405       isec2[ 7] = 0;
16406       isec2[ 8] = 0;
16407       isec2[ 9] = 0;
16408       isec2[10] = 0;
16409       // iret = decodeGDS_SH(gds, gdspos, isec0, isec2, imisng);
16410     }
16411   else if ( ISEC2_GridType == GRIB1_GTYPE_GME )
16412     {
16413       ISEC2_GME_NI2    = GDS_GME_NI2;
16414       ISEC2_GME_NI3    = GDS_GME_NI3;
16415       ISEC2_GME_ND     = GDS_GME_ND;
16416       ISEC2_GME_NI     = GDS_GME_NI;
16417       ISEC2_GME_AFlag  = GDS_GME_AFlag;
16418       ISEC2_GME_LatPP  = GDS_GME_LatPP;
16419       ISEC2_GME_LonPP  = GDS_GME_LonPP;
16420       ISEC2_GME_LonMPL = GDS_GME_LonMPL;
16421       ISEC2_GME_BFlag  = GDS_GME_BFlag;
16422       *numGridVals  = (ISEC2_GME_NI+1)*(ISEC2_GME_NI+1)*10;
16423       // iret = decodeGDS_TR(gds, gdspos, isec0, isec2, imisng);
16424     }
16425   else
16426     {
16427       static bool lwarn = true;
16428       ISEC2_NumLon = GDS_NumLon;
16429       ISEC2_NumLat = GDS_NumLat;
16430       *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
16431       if ( lwarn )
16432         {
16433           lwarn = false;
16434           Message("GRIB gridtype %d unsupported", ISEC2_GridType);
16435         }
16436     }
16437 
16438   /*    vertical coordinate parameters for hybrid levels.     */
16439   /*    get number of vertical coordinate parameters, if any. */
16440 
16441   ISEC2_NumVCP = 0;
16442 
16443   isec2[17] = 0;
16444   isec2[18] = 0;
16445 
16446   if ( VertCoorTab )
16447     {
16448       int locnv;
16449       if ( ISEC0_GRIB_Version  == 0 )
16450 	{
16451 	  locnv = 32;
16452 	  ISEC2_NumVCP = (gdsLen - 32) >> 2;
16453 	}
16454       else
16455 	{
16456 	  locnv = GDS_PVPL - 1;
16457 	  ISEC2_NumVCP = GDS_NV;
16458 	}
16459 #if defined (SX)
16460       lGribLen = 4*ISEC2_NumVCP;
16461       lgrib    = (GRIBPACK*) Malloc(lGribLen*sizeof(GRIBPACK));
16462 
16463       igrib = &gds[locnv];
16464       if ( ISEC2_NumVCP > 0 ) (void) UNPACK_GRIB(igrib, lgrib, lGribLen, -1L);
16465       for ( int i = 0; i < ISEC2_NumVCP; i++ )
16466 	{
16467 	  int iexp  = lgrib[4*i];
16468 	  int imant = GET_UINT3(lgrib[4*i+1], lgrib[4*i+2], lgrib[4*i+3]);
16469 	  fsec2[10+i] = POW_2_M24 * imant * ldexp(1.0, 4 * (iexp - 64));
16470 	}
16471 
16472       Free(lgrib);
16473 #else
16474       for ( int i = 0; i < ISEC2_NumVCP; i++ )
16475 	{
16476 	  int iexp  = gds[locnv+4*i];
16477 	  int imant = GET_UINT3(gds[locnv+4*i+1], gds[locnv+4*i+2], gds[locnv+4*i+3]);
16478 	  fsec2[10+i] = (T)decfp2(iexp,imant);
16479 	}
16480 #endif
16481     }
16482 
16483   return gdsLen;
16484 }
16485 
16486 #define ldexp_double ldexp
16487 #define ldexp_float  ldexpf
16488 #define pow_double pow
16489 #define pow_float powf
16490 
16491 static
TEMPLATE(decodeBDS,T)16492 void TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *isec4,
16493                            T *fsec4, int fsec4len, int dfunc, int bdsLen, int numGridVals, int *iret)
16494 {
16495   int ioff = 0;
16496   enum { bds_head = 11 };
16497   T zscale = 0.;
16498   T fmin = 0.;
16499   T *fpdata = fsec4;
16500 
16501   *iret = 0;
16502   unsigned char *igrib = bds;
16503 
16504   memset(isec4, 0, 42*sizeof(int));
16505 
16506   // 4 bit flag / 4 bit count of unused bits at end of block octet.
16507 
16508   int bds_flag = BDS_Flag;
16509 
16510   // 0------- grid point
16511   // 1------- spherical harmonics
16512 
16513   bool lspherc = (bds_flag >> 7)&1;
16514 
16515   if ( lspherc ) isec4[2] = 128;
16516   else           isec4[2] = 0;
16517 
16518   // -0------  simple packing
16519   // -1------ complex packing
16520 
16521   bool lcomplex = (bds_flag >> 6)&1;
16522 
16523   if ( lcomplex ) isec4[3] = 64;
16524   else            isec4[3] =  0;
16525 
16526   // ---0---- No additional flags
16527   // ---1---- No additional flags
16528 
16529   bool lcompress = (bds_flag >> 4)&1;
16530 
16531   unsigned zoff;
16532   if ( lcompress )
16533     { isec4[5] = 16; isec4[6] = BDS_Z; zoff = 12; }
16534   else
16535     { isec4[5] =  0; isec4[6] = 0;     zoff =  0; }
16536 
16537   // ----++++ number of unused bits at end of section)
16538 
16539   int bds_ubits = bds_flag & 0xF;
16540 
16541   // scale factor (2 bytes)
16542   int jscale = BDS_BinScale;
16543 
16544   // check for missing data indicators.
16545 
16546   int iexp  = bds[ 6];
16547   int imant = GET_UINT3(bds[ 7], bds[ 8], bds[ 9]);
16548 
16549   int imiss = (jscale == 0xFFFF && iexp == 0xFF && imant == 0xFFFFFF);
16550 
16551   // convert reference value and scale factor.
16552 
16553   if ( ! (dfunc == 'J') && imiss == 0 )
16554     {
16555       fmin = (T)BDS_RefValue;
16556       zscale = TEMPLATE(ldexp,T)((T)1.0, jscale);
16557     }
16558 
16559   // get number of bits in each data value.
16560 
16561   ISEC4_NumBits = BDS_NumBits;
16562 
16563   // octet number of start of packed data calculated from start of block 4 - 1
16564 
16565   unsigned locnd = zoff + bds_head;
16566 
16567   // if data is in spherical harmonic form, distinguish  between simple/complex packing (lcomplex = 0/1)
16568 
16569   if ( lspherc )
16570     {
16571       if ( !lcomplex )
16572 	{
16573 	  // no unpacked binary data present octet number of start of packed data
16574 	  // calculated from start of block 4 - 1
16575 
16576 	  ioff   = 1;
16577 	  locnd += 4*ioff;  // RealCoef
16578 
16579 	  // get real (0,0) coefficient in grib format and convert to floating point.
16580 	  if ( dfunc != 'J' )
16581 	    {
16582 	      if ( imiss ) *fpdata++ = 0.0;
16583 	      else         *fpdata++ = (T)BDS_RealCoef;
16584 	    }
16585 	}
16586       else // complex packed spherical harmonics
16587 	{
16588 	  isec4[15] = BDS_PackData;
16589 	  // scaling factor
16590 	  isec4[16] = BDS_Power;
16591 
16592 	  // pentagonal resolution parameters of the unpacked section of data field
16593 
16594 	  int jup = bds[zoff+15];
16595 	  int kup = bds[zoff+16];
16596 	  int mup = bds[zoff+17];
16597 
16598 	  isec4[zoff+17] = jup;
16599 	  isec4[zoff+18] = kup;
16600 	  isec4[zoff+19] = mup;
16601 
16602 	  // unpacked binary data
16603 
16604 	  locnd += 4; // 2 + power
16605 	  locnd += 3; // j, k, m
16606 	  ioff   = (jup+1)*(jup+2);
16607 
16608 	  if ( dfunc != 'J' )
16609 	    for ( int i = 0; i < ioff; i++ )
16610 	      {
16611 		if ( imiss )
16612 		  *fpdata++ = 0.0;
16613 		else
16614 		  {
16615 		    int iexp2  = (bds[locnd+4*i]);
16616 		    int imant2 = GET_UINT3(bds[locnd+4*i+1], bds[locnd+4*i+2], bds[locnd+4*i+3]);
16617 		    *fpdata++ = (T)decfp2(iexp2,imant2);
16618 		  }
16619 	      }
16620 
16621 	  locnd += 4*ioff;  /* RealCoef */
16622 	}
16623     }
16624   else
16625     {
16626       if ( lcomplex )
16627 	{
16628 	  *iret = 1999;
16629 	  gprintf(__func__, " Second order packed grids unsupported!");
16630 	  gprintf(__func__, " Return code =  %d", *iret);
16631 	  return;
16632 	}
16633     }
16634 
16635   /* Decode data values to floating point and store in fsec4.  */
16636   /* First calculate the number of data values.                */
16637   /* Take into account that spherical harmonics can be packed  */
16638   /* simple (lcomplex = 0) or complex (lcomplex = 1)           */
16639 
16640   int jlend = bdsLen - locnd;
16641 
16642   if ( ISEC4_NumBits == 0 )
16643     {
16644       if ( jlend > 1 )
16645 	{
16646 	  *iret = 2001;
16647 	  gprintf(__func__, " Number of bits per data value = 0!");
16648 	  gprintf(__func__, " Return code =  %d", *iret);
16649 	  return;
16650 	}
16651 
16652       if ( numGridVals == 0 )
16653 	{
16654 	  *iret = 2002;
16655 	  gprintf(__func__, " Constant field unsupported for this grid type!");
16656 	  gprintf(__func__, " Return code =  %d", *iret);
16657 	  return;
16658 	}
16659 
16660       jlend = numGridVals;
16661       jlend -= ioff;
16662     }
16663   else
16664     {
16665       jlend = (int) (((long)jlend*8 - bds_ubits) / ISEC4_NumBits);
16666     }
16667 
16668   ISEC4_NumValues        = jlend + ioff;
16669   ISEC4_NumNonMissValues = 0;
16670 
16671   if ( lcompress )
16672     {
16673       size_t len = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
16674 
16675       ISEC4_NumValues = (int)(len*8/(size_t)ISEC4_NumBits);
16676 
16677       if ( lspherc ) ISEC4_NumValues += lcomplex ? ioff : 1;
16678     }
16679 
16680   if ( dfunc == 'J' ) return;
16681 
16682   // check length of output array.
16683 
16684   if ( ISEC4_NumValues > fsec4len )
16685     {
16686       *iret = 710;
16687       gprintf(__func__, " Output array too small. Length = %d", fsec4len);
16688       gprintf(__func__, " Number of values = %d", ISEC4_NumValues);
16689       gprintf(__func__, " Return code =  %d", *iret);
16690       return;
16691     }
16692 
16693   if ( imiss ) memset((char *)fpdata, 0, (size_t)jlend*sizeof(T));
16694   else
16695     {
16696       igrib += locnd;
16697 
16698       TEMPLATE(decode_array,T)(igrib, jlend, ISEC4_NumBits, fmin, zscale, fpdata);
16699     }
16700 
16701   if ( lspherc && lcomplex )
16702     {
16703       int pcStart = isec4[19], pcScale = isec4[16];
16704       TEMPLATE(scatter_complex,T)(fsec4, pcStart, ISEC2_PentaJ, ISEC4_NumValues);
16705       TEMPLATE(scale_complex,T)(fsec4, pcStart, pcScale, ISEC2_PentaJ, 1);
16706     }
16707 
16708   if ( CGRIBEX_Fix_ZSE )  // Fix ZeroShiftError of simple packed spherical harmonics
16709     if ( lspherc && !lcomplex )
16710       {
16711         // 20100705: Fix ZeroShiftError - Edi Kirk
16712 	if ( IS_NOT_EQUAL(fsec4[1], 0.0) )
16713 	  {
16714 	    T zserr = fsec4[1];
16715 	    for ( int i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
16716 	  }
16717       }
16718 
16719   if ( decscale )
16720     {
16721       T scale = TEMPLATE(pow,T)((T)10.0, (T)-decscale);
16722       for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
16723     }
16724 }
16725 
16726 
TEMPLATE(grib_decode,T)16727 void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *isec3,
16728 			     T *fsec3, int *isec4, T *fsec4, int fsec4len, int *kgrib,
16729 			     int kleng, int *kword, int dfunc, int *iret)
16730 {
16731   UCHAR *bms = NULL;
16732   bool lsect2 = false, lsect3 = false;
16733   static bool lmissvalinfo = true;
16734 
16735   UNUSED(kleng);
16736 
16737   *iret = 0;
16738 
16739   grsdef();
16740 
16741   ISEC2_Reduced = false;
16742 
16743   // ----------------------------------------------------------------
16744   // IS Indicator Section (Section 0)
16745   // ----------------------------------------------------------------
16746   UCHAR *is = (UCHAR *) &kgrib[0];
16747   int isLen = decodeIS(is, isec0, iret);
16748 
16749   int gribLen = ISEC0_GRIB_Len;
16750 
16751   /*
16752     When decoding or calculating length, previous editions
16753     of the GRIB code must be taken into account.
16754 
16755     In the table below, covering sections 0 and 1 of the GRIB
16756     code, octet numbering is from the beginning of the GRIB
16757     message;
16758     * indicates that the value is not available in the code edition;
16759     R indicates reserved, should be set to 0;
16760     Experimental edition is considered as edition -1.
16761 
16762     GRIB code edition -1 has fixed length of 20 octets for
16763     section 1, the length not included in the message.
16764     GRIB code edition 0 has fixed length of 24 octets for
16765     section 1, the length being included in the message.
16766     GRIB code edition 1 can have different lengths for section
16767     1, the minimum being 28 octets, length being included in
16768     the message.
16769 
16770                                          Octet numbers for code
16771                                                   editions
16772 
16773                  Contents.                   -1      0      1
16774                  ---------                ----------------------
16775        Letters GRIB                          1-4    1-4    1-4
16776        Total length of GRIB message.          *      *     5-7
16777        GRIB code edition number               *      *      8
16778        Length of Section 1.                   *     5-7    9-11
16779        Reserved octet (R).                    *      8(R)   *
16780        Version no. of Code Table 2.           *      *     12
16781        Identification of centre.              5      9     13
16782        Generating process.                    6     10     14
16783        Grid definition .                      7     11     15
16784        Flag (Code Table 1).                   8     12     16
16785        Indicator of parameter.                9     13     17
16786        Indicator of type of level.           10     14     18
16787        Height, pressure etc of levels.      11-12  15-16  19-20
16788        Year of century.                      13     17     21
16789        Month.                                14     18     22
16790        Day.                                  15     19     23
16791        Hour.                                 16     20     24
16792        Minute.                               17     21     25
16793        Indicator of unit of time.            18     22     26
16794        P1 - Period of time.                  19     23     27
16795        P2 - Period of time                  20(R)   24     28
16796        or reserved octet (R).
16797        Time range indicator.                21(R)   25     29
16798        or reserved octet (R).
16799        Number included in average.       22-23(R)  26-27  30-31
16800        or reserved octet (R).
16801        Number missing from average.         24(R)  28(R)   32
16802        or reserved octet (R).
16803        Century of data.                       *      *     33
16804        Designates sub-centre if not 0.        *      *     34
16805        Decimal scale factor.                  *      *    35-36
16806        Reserved. Set to 0.                    *      *    37-48
16807        (Need not be present)
16808        For originating centre use only.       *      *    49-nn
16809        (Need not be present)
16810 
16811     Identify which GRIB code edition is being decoded.
16812 
16813     In GRIB edition 1, the edition number is in octet 8.
16814     In GRIB edition 0, octet 8 is reserved and set to 0.
16815     In GRIB edition -1, octet 8 is a flag field and can have a
16816     a valid value of 0, 1, 2 or 3.
16817 
16818     However, GRIB edition number 0 has a fixed
16819     length of 24, included in the message, for section 1, so
16820     if the value extracted from octets 5-7 is 24 and that from
16821     octet 8 is 0, it is safe to assume edition 0 of the code.
16822 
16823   */
16824   if ( ISEC0_GRIB_Len == 24 && ISEC0_GRIB_Version == 0 )
16825     {
16826       // Set length of GRIB message to missing data value.
16827       ISEC0_GRIB_Len = 0;
16828     }
16829 
16830   // ----------------------------------------------------------------
16831   // PDS Product Definition Section (Section 1)
16832   // ----------------------------------------------------------------
16833   UCHAR *pds = is + isLen;
16834   int pdsLen = decodePDS(pds, isec0, isec1);
16835 
16836   // ----------------------------------------------------------------
16837   // GDS Grid Description Section (Section 2)
16838   // ----------------------------------------------------------------
16839   int numGridVals = 0;
16840   bool gdsIncluded = ISEC1_Sec2Or3Flag & 128;
16841   int gdsLen = 0;
16842   if ( gdsIncluded )
16843     {
16844       UCHAR *gds = is + isLen + pdsLen;
16845       gdsLen = TEMPLATE(decodeGDS,T)(gds, isec0, isec2, fsec2, &numGridVals);
16846     }
16847 
16848   // ----------------------------------------------------------------
16849   // BMS Bit-Map Section Section (Section 3)
16850   // ----------------------------------------------------------------
16851   isec3[0] = 0;
16852   bool bmsIncluded = ISEC1_Sec2Or3Flag & 64;
16853   int bmsLen = 0, bitmapSize = 0, imaskSize = 0;
16854   if ( bmsIncluded )
16855     {
16856       bms = is + isLen + pdsLen + gdsLen;
16857       bmsLen = BMS_Len;
16858 
16859       imaskSize = (bmsLen - 6)<<3;
16860       bitmapSize = imaskSize - BMS_UnusedBits;
16861     }
16862 
16863   // ----------------------------------------------------------------
16864   // BDS Binary Data Section (Section 4)
16865   // ----------------------------------------------------------------
16866   UCHAR *bds = is + isLen + pdsLen + gdsLen + bmsLen;
16867   int bdsLen = BDS_Len;
16868   /*
16869     If a very large product, the section 4 length field holds
16870     the number of bytes in the product after section 4 upto
16871     the end of the padding bytes.
16872     This is a fixup to get round the restriction on product lengths
16873     due to the count being only 24 bits. It is only possible because
16874     the (default) rounding for GRIB products is 120 bytes.
16875   */
16876   bool llarge = (gribLen > JP23SET && bdsLen <= 120);
16877   if ( llarge )
16878     {
16879       gribLen &= JP23SET;
16880       gribLen *= 120;
16881       ISEC0_GRIB_Len = gribLen;
16882       bdsLen = correct_bdslen(bdsLen, gribLen, isLen+pdsLen+gdsLen+bmsLen);
16883     }
16884   TEMPLATE(decodeBDS,T)(ISEC1_DecScaleFactor, bds, isec2, isec4,
16885                         fsec4, fsec4len, dfunc, bdsLen, numGridVals, iret);
16886 
16887   if ( *iret != 0 ) return;
16888 
16889   ISEC4_NumNonMissValues = ISEC4_NumValues;
16890 
16891   if ( bitmapSize > 0 )
16892     {
16893       if ( dfunc != 'L' && dfunc != 'J' )
16894 	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
16895 	  {
16896 	    lmissvalinfo = false;
16897 	    FSEC3_MissVal = (T)GRIB_MISSVAL;
16898 	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
16899 	  }
16900 
16901       /* ISEC4_NumNonMissValues = ISEC4_NumValues; */
16902       ISEC4_NumValues = bitmapSize;
16903 
16904       if ( dfunc != 'J' || bitmapSize == ISEC4_NumNonMissValues )
16905 	{
16906 	  GRIBPACK bitmap;
16907 	  /*
16908 	  unsigned char *bitmap;
16909 	  bitmap = BMS_Bitmap;
16910 	  int j = ISEC4_NumNonMissValues;
16911 	  for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
16912 	    {
16913 	      if ( (bitmap[i/8]>>(7-(i&7)))&1 )
16914 		fsec4[i] = fsec4[--j];
16915 	      else
16916 		fsec4[i] = FSEC3_MissVal;
16917 	    }
16918 	  */
16919 
16920 	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
16921 
16922 #ifdef VECTORCODE
16923 	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
16924 	  GRIBPACK *pbitmap = imask;
16925 #else
16926 	  GRIBPACK *pbitmap = BMS_Bitmap;
16927 #endif
16928 
16929 #if defined (CRAY)
16930 #pragma _CRI ivdep
16931 #endif
16932 #if defined (SX)
16933 #pragma vdir nodep
16934 #endif
16935 #ifdef __uxpch__
16936 #pragma loop novrec
16937 #endif
16938 	  for ( int i = imaskSize/8-1; i >= 0; i-- )
16939 	    {
16940 	      bitmap = pbitmap[i];
16941 	      imask[i*8+0] = 1 & (bitmap >> 7);
16942 	      imask[i*8+1] = 1 & (bitmap >> 6);
16943 	      imask[i*8+2] = 1 & (bitmap >> 5);
16944 	      imask[i*8+3] = 1 & (bitmap >> 4);
16945 	      imask[i*8+4] = 1 & (bitmap >> 3);
16946 	      imask[i*8+5] = 1 & (bitmap >> 2);
16947 	      imask[i*8+6] = 1 & (bitmap >> 1);
16948 	      imask[i*8+7] = 1 & (bitmap);
16949 	    }
16950 
16951 	  int j = 0;
16952 	  for ( int i = 0; i < ISEC4_NumValues; i++ )
16953 	    if ( imask[i] ) j++;
16954 
16955 	  if ( ISEC4_NumNonMissValues != j )
16956 	    {
16957 	      if ( dfunc != 'J' && ISEC4_NumBits != 0 )
16958 		Warning("Bitmap (%d) and data (%d) section differ, using bitmap section!",
16959 			j, ISEC4_NumNonMissValues);
16960 
16961 	      ISEC4_NumNonMissValues = j;
16962 	    }
16963 
16964 	  if ( dfunc != 'J' )
16965 	    {
16966 #if defined (CRAY)
16967 #pragma _CRI ivdep
16968 #endif
16969 #if defined (SX)
16970 #pragma vdir nodep
16971 #endif
16972 #ifdef __uxpch__
16973 #pragma loop novrec
16974 #endif
16975 	      for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
16976 		fsec4[i] = imask[i] ? fsec4[--j] : FSEC3_MissVal;
16977 	    }
16978 
16979 	  Free(imask);
16980 	}
16981     }
16982 
16983   if ( ISEC2_Reduced )
16984     {
16985       int nvalues = 0;
16986       int nlat = ISEC2_NumLat;
16987       int nlon = ISEC2_ReducedPointsPtr[0];
16988       for ( int ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_ReducedPoints(ilat);
16989       for ( int ilat = 1; ilat < nlat; ++ilat )
16990 	if ( ISEC2_ReducedPoints(ilat) > nlon ) nlon = ISEC2_ReducedPoints(ilat);
16991 
16992       // int dlon = ISEC2_LastLon-ISEC2_FirstLon;
16993       // if ( dlon < 0 ) dlon += 360000;
16994 
16995       if ( nvalues != ISEC4_NumValues ) *iret = -801;
16996 
16997       //printf("nlat %d  nlon %d \n", nlat, nlon);
16998       //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
16999 
17000       if ( dfunc == 'R' && *iret == -801 )
17001 	gprintf(__func__, "Number of values (%d) and sum of lons per row (%d) differ, abort conversion to regular Gaussian grid!",
17002 		ISEC4_NumValues, nvalues);
17003 
17004       if ( dfunc == 'R' && *iret != -801 )
17005 	{
17006 	  ISEC2_Reduced = 0;
17007 	  ISEC2_NumLon = nlon;
17008 	  ISEC4_NumValues = nlon*nlat;
17009 
17010 	  lsect3 = bitmapSize > 0;
17011           int lperio = 1;
17012 	  int lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) &&
17013                       ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) ||
17014                        (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30) ||
17015                        (ISEC1_Parameter == 39) || (ISEC1_Parameter == 40) ||
17016                        (ISEC1_Parameter == 41) || (ISEC1_Parameter == 42) ||
17017                        (ISEC1_Parameter == 43));
17018 
17019 	  (void) TEMPLATE(qu2reg3,T)(fsec4, ISEC2_ReducedPointsPtr, nlat, nlon, FSEC3_MissVal, iret, lsect3, lperio, lveggy);
17020 
17021 	  if ( bitmapSize > 0 )
17022 	    {
17023 	      int j = 0;
17024 	      for ( int i = 0; i < ISEC4_NumValues; i++ )
17025 		if ( IS_NOT_EQUAL(fsec4[i], FSEC3_MissVal) ) j++;
17026 
17027 	      ISEC4_NumNonMissValues = j;
17028 	    }
17029 	}
17030     }
17031 
17032   if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
17033   const int esLen = 4;
17034   gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
17035 
17036   if ( !llarge && ISEC0_GRIB_Len && ISEC0_GRIB_Len < gribLen )
17037     Warning("Inconsistent length of GRIB message (grib_message_size=%d < grib_record_size=%d)!", ISEC0_GRIB_Len, gribLen);
17038 
17039   ISEC0_GRIB_Len = gribLen;
17040 
17041   *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
17042 
17043   // ----------------------------------------------------------------
17044   // Section 9 . Abort/return to calling routine.
17045   // ----------------------------------------------------------------
17046   bool ldebug = false, l_iorj = false;
17047   if ( ldebug )
17048     {
17049       gprintf(__func__, "Section 9.");
17050       gprintf(__func__, "Output values set -");
17051 
17052       gribPrintSec0(isec0);
17053       gribPrintSec1(isec0, isec1);
17054       // Print section 2 if present.
17055       if ( lsect2 ) TEMPLATE(gribPrintSec2,T)(isec0, isec2, fsec2);
17056 
17057       if ( ! l_iorj )
17058 	{
17059 	  // Print section 3 if present.
17060 	  if ( lsect3 ) TEMPLATE(gribPrintSec3,T)(isec0, isec3, fsec3);
17061 
17062 	  TEMPLATE(gribPrintSec4,T)(isec0, isec4, fsec4);
17063 	  // Special print for 2D spectra wave field real values in section 4
17064 	  if ( (isec1[ 0] ==  140) &&
17065 	       (isec1[ 1] ==   98) &&
17066 	       (isec1[23] ==    1) &&
17067 	       ((isec1[39] == 1045) || (isec1[39] == 1081))  &&
17068 	       ((isec1[ 5] ==  250) || (isec1[ 5] ==  251)) )
17069 	    gribPrintSec4Wave(isec4);
17070 	}
17071     }
17072 }
17073 
17074 #endif /* T */
17075 
17076 /*
17077  * Local Variables:
17078  * mode: c
17079  * End:
17080  */
17081 
17082 #ifdef T
17083 #undef T
17084 #endif
17085 #define T float
17086 #ifdef T
17087 
17088 static
TEMPLATE(decodeGDS,T)17089 int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2, int *numGridVals)
17090 {
17091   // int imisng = 0;
17092   bool ReducedGrid = false, VertCoorTab = false;
17093 #ifdef VECTORCODE
17094   unsigned char *igrib;
17095   GRIBPACK *lgrib = NULL;
17096   size_t lGribLen = 0;
17097 #endif
17098 
17099   *numGridVals = 0;
17100 
17101   memset(isec2, 0, 22*sizeof(int));
17102 
17103   unsigned gdsLen = GDS_Len;
17104 
17105   unsigned ipvpl = GDS_PVPL;
17106   if ( ipvpl == 0 ) ipvpl = 0xFF;
17107 
17108   if ( ipvpl != 0xFF )
17109     { /* Either vct or reduced grid */
17110       if ( GDS_NV != 0 )
17111 	{ /* we have vct */
17112 	  VertCoorTab = true;
17113 	  unsigned ipl =  4*GDS_NV + ipvpl - 1;
17114 	  if ( ipl < gdsLen ) ReducedGrid = true;
17115 	}
17116       else
17117 	{
17118 	  VertCoorTab = false;
17119 	  ReducedGrid = true;
17120 	}
17121       /*	  ReducedGrid = (gdsLen - 32 - 4*GDS_NV); */
17122     }
17123 
17124   if ( ISEC0_GRIB_Version == 0 )
17125     {
17126       VertCoorTab = (gdsLen - 32) > 0;
17127     }
17128 
17129   if ( ReducedGrid )
17130     {
17131       unsigned locnl = GDS_PVPL - 1 + (VertCoorTab * 4 * GDS_NV);
17132       unsigned jlenl = (gdsLen - locnl)  >> 1;
17133       if ( jlenl == GDS_NumLat )
17134 	{
17135 	  *numGridVals = 0;
17136 	  ISEC2_Reduced = true;
17137 	  for ( unsigned i = 0; i < jlenl; i++ )
17138 	    {
17139 	      ISEC2_ReducedPoints(i) = GET_UINT2(gds[locnl+2*i], gds[locnl+2*i+1]);
17140 	      *numGridVals += ISEC2_ReducedPoints(i);
17141 	    }
17142 	}
17143       else
17144 	{
17145 	  ReducedGrid = false;
17146 	}
17147     }
17148 
17149   ISEC2_GridType = GDS_GridType;
17150 
17151   /*
17152      Gaussian grid definition.
17153   */
17154   if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
17155        ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
17156        ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
17157     {
17158       ISEC2_NumLat    = GDS_NumLat;
17159       if ( ! ReducedGrid )
17160 	{
17161 	  ISEC2_NumLon = GDS_NumLon;
17162 	  *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
17163 	}
17164       ISEC2_FirstLat  = GDS_FirstLat;
17165       ISEC2_FirstLon  = GDS_FirstLon;
17166       ISEC2_ResFlag   = GDS_ResFlag;
17167       ISEC2_LastLat   = GDS_LastLat;
17168       ISEC2_LastLon   = GDS_LastLon;
17169       ISEC2_LonIncr   = GDS_LonIncr;
17170 
17171       ISEC2_NumPar    = GDS_NumPar;
17172       ISEC2_ScanFlag  = GDS_ScanFlag;
17173       if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
17174 	{
17175 	  ISEC2_LatSP     = GDS_LatSP;
17176 	  ISEC2_LonSP     = GDS_LonSP;
17177 	  FSEC2_RotAngle  = (T)GDS_RotAngle;
17178 	}
17179       /*
17180 	if ( Lons != Longitudes || Lats != Latitudes )
17181 	Error("Latitude/Longitude Conflict");
17182       */
17183     }
17184   else if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN     ||
17185 	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_ROT ||
17186 	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_STR ||
17187 	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_ROTSTR )
17188     {
17189       // iret = decodeGDS_GG(gds, gdspos, isec0, isec2, imisng);
17190     }
17191   else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON     ||
17192 	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT ||
17193 	    ISEC2_GridType == GRIB1_GTYPE_LATLON_STR ||
17194 	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROTSTR )
17195     {
17196       // iret = decodeGDS_LL(gds, gdspos, isec0, isec2, imisng);
17197     }
17198   else if ( ISEC2_GridType == GRIB1_GTYPE_LCC )
17199     {
17200       ISEC2_NumLon    = GDS_NumLon;
17201       ISEC2_NumLat    = GDS_NumLat;
17202       *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
17203       ISEC2_FirstLat  = GDS_FirstLat;
17204       ISEC2_FirstLon  = GDS_FirstLon;
17205       ISEC2_ResFlag   = GDS_ResFlag;
17206       ISEC2_Lambert_Lov   = GDS_Lambert_Lov;
17207       ISEC2_Lambert_dx    = GDS_Lambert_dx;
17208       ISEC2_Lambert_dy    = GDS_Lambert_dy;
17209       ISEC2_Lambert_LatS1 = GDS_Lambert_LatS1;
17210       ISEC2_Lambert_LatS2 = GDS_Lambert_LatS2;
17211       ISEC2_Lambert_LatSP = GDS_Lambert_LatSP;
17212       ISEC2_Lambert_LonSP = GDS_Lambert_LonSP;
17213       ISEC2_Lambert_ProjFlag = GDS_Lambert_ProjFlag;
17214       ISEC2_ScanFlag      = GDS_ScanFlag;
17215     }
17216   else if ( ISEC2_GridType == GRIB1_GTYPE_SPECTRAL )
17217     {
17218       ISEC2_PentaJ  = GDS_PentaJ; /* Truncation */
17219       ISEC2_PentaK  = GDS_PentaK;
17220       ISEC2_PentaM  = GDS_PentaM;
17221       ISEC2_RepType = GDS_RepType;
17222       ISEC2_RepMode = GDS_RepMode;
17223       *numGridVals  = (ISEC2_PentaJ+1)*(ISEC2_PentaJ+2);
17224       isec2[ 6] = 0;
17225       isec2[ 7] = 0;
17226       isec2[ 8] = 0;
17227       isec2[ 9] = 0;
17228       isec2[10] = 0;
17229       // iret = decodeGDS_SH(gds, gdspos, isec0, isec2, imisng);
17230     }
17231   else if ( ISEC2_GridType == GRIB1_GTYPE_GME )
17232     {
17233       ISEC2_GME_NI2    = GDS_GME_NI2;
17234       ISEC2_GME_NI3    = GDS_GME_NI3;
17235       ISEC2_GME_ND     = GDS_GME_ND;
17236       ISEC2_GME_NI     = GDS_GME_NI;
17237       ISEC2_GME_AFlag  = GDS_GME_AFlag;
17238       ISEC2_GME_LatPP  = GDS_GME_LatPP;
17239       ISEC2_GME_LonPP  = GDS_GME_LonPP;
17240       ISEC2_GME_LonMPL = GDS_GME_LonMPL;
17241       ISEC2_GME_BFlag  = GDS_GME_BFlag;
17242       *numGridVals  = (ISEC2_GME_NI+1)*(ISEC2_GME_NI+1)*10;
17243       // iret = decodeGDS_TR(gds, gdspos, isec0, isec2, imisng);
17244     }
17245   else
17246     {
17247       static bool lwarn = true;
17248       ISEC2_NumLon = GDS_NumLon;
17249       ISEC2_NumLat = GDS_NumLat;
17250       *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
17251       if ( lwarn )
17252         {
17253           lwarn = false;
17254           Message("GRIB gridtype %d unsupported", ISEC2_GridType);
17255         }
17256     }
17257 
17258   /*    vertical coordinate parameters for hybrid levels.     */
17259   /*    get number of vertical coordinate parameters, if any. */
17260 
17261   ISEC2_NumVCP = 0;
17262 
17263   isec2[17] = 0;
17264   isec2[18] = 0;
17265 
17266   if ( VertCoorTab )
17267     {
17268       int locnv;
17269       if ( ISEC0_GRIB_Version  == 0 )
17270 	{
17271 	  locnv = 32;
17272 	  ISEC2_NumVCP = (gdsLen - 32) >> 2;
17273 	}
17274       else
17275 	{
17276 	  locnv = GDS_PVPL - 1;
17277 	  ISEC2_NumVCP = GDS_NV;
17278 	}
17279 #if defined (SX)
17280       lGribLen = 4*ISEC2_NumVCP;
17281       lgrib    = (GRIBPACK*) Malloc(lGribLen*sizeof(GRIBPACK));
17282 
17283       igrib = &gds[locnv];
17284       if ( ISEC2_NumVCP > 0 ) (void) UNPACK_GRIB(igrib, lgrib, lGribLen, -1L);
17285       for ( int i = 0; i < ISEC2_NumVCP; i++ )
17286 	{
17287 	  int iexp  = lgrib[4*i];
17288 	  int imant = GET_UINT3(lgrib[4*i+1], lgrib[4*i+2], lgrib[4*i+3]);
17289 	  fsec2[10+i] = POW_2_M24 * imant * ldexp(1.0, 4 * (iexp - 64));
17290 	}
17291 
17292       Free(lgrib);
17293 #else
17294       for ( int i = 0; i < ISEC2_NumVCP; i++ )
17295 	{
17296 	  int iexp  = gds[locnv+4*i];
17297 	  int imant = GET_UINT3(gds[locnv+4*i+1], gds[locnv+4*i+2], gds[locnv+4*i+3]);
17298 	  fsec2[10+i] = (T)decfp2(iexp,imant);
17299 	}
17300 #endif
17301     }
17302 
17303   return gdsLen;
17304 }
17305 
17306 #define ldexp_double ldexp
17307 #define ldexp_float  ldexpf
17308 #define pow_double pow
17309 #define pow_float powf
17310 
17311 static
TEMPLATE(decodeBDS,T)17312 void TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *isec4,
17313                            T *fsec4, int fsec4len, int dfunc, int bdsLen, int numGridVals, int *iret)
17314 {
17315   int ioff = 0;
17316   enum { bds_head = 11 };
17317   T zscale = 0.;
17318   T fmin = 0.;
17319   T *fpdata = fsec4;
17320 
17321   *iret = 0;
17322   unsigned char *igrib = bds;
17323 
17324   memset(isec4, 0, 42*sizeof(int));
17325 
17326   // 4 bit flag / 4 bit count of unused bits at end of block octet.
17327 
17328   int bds_flag = BDS_Flag;
17329 
17330   // 0------- grid point
17331   // 1------- spherical harmonics
17332 
17333   bool lspherc = (bds_flag >> 7)&1;
17334 
17335   if ( lspherc ) isec4[2] = 128;
17336   else           isec4[2] = 0;
17337 
17338   // -0------  simple packing
17339   // -1------ complex packing
17340 
17341   bool lcomplex = (bds_flag >> 6)&1;
17342 
17343   if ( lcomplex ) isec4[3] = 64;
17344   else            isec4[3] =  0;
17345 
17346   // ---0---- No additional flags
17347   // ---1---- No additional flags
17348 
17349   bool lcompress = (bds_flag >> 4)&1;
17350 
17351   unsigned zoff;
17352   if ( lcompress )
17353     { isec4[5] = 16; isec4[6] = BDS_Z; zoff = 12; }
17354   else
17355     { isec4[5] =  0; isec4[6] = 0;     zoff =  0; }
17356 
17357   // ----++++ number of unused bits at end of section)
17358 
17359   int bds_ubits = bds_flag & 0xF;
17360 
17361   // scale factor (2 bytes)
17362   int jscale = BDS_BinScale;
17363 
17364   // check for missing data indicators.
17365 
17366   int iexp  = bds[ 6];
17367   int imant = GET_UINT3(bds[ 7], bds[ 8], bds[ 9]);
17368 
17369   int imiss = (jscale == 0xFFFF && iexp == 0xFF && imant == 0xFFFFFF);
17370 
17371   // convert reference value and scale factor.
17372 
17373   if ( ! (dfunc == 'J') && imiss == 0 )
17374     {
17375       fmin = (T)BDS_RefValue;
17376       zscale = TEMPLATE(ldexp,T)((T)1.0, jscale);
17377     }
17378 
17379   // get number of bits in each data value.
17380 
17381   ISEC4_NumBits = BDS_NumBits;
17382 
17383   // octet number of start of packed data calculated from start of block 4 - 1
17384 
17385   unsigned locnd = zoff + bds_head;
17386 
17387   // if data is in spherical harmonic form, distinguish  between simple/complex packing (lcomplex = 0/1)
17388 
17389   if ( lspherc )
17390     {
17391       if ( !lcomplex )
17392 	{
17393 	  // no unpacked binary data present octet number of start of packed data
17394 	  // calculated from start of block 4 - 1
17395 
17396 	  ioff   = 1;
17397 	  locnd += 4*ioff;  // RealCoef
17398 
17399 	  // get real (0,0) coefficient in grib format and convert to floating point.
17400 	  if ( dfunc != 'J' )
17401 	    {
17402 	      if ( imiss ) *fpdata++ = 0.0;
17403 	      else         *fpdata++ = (T)BDS_RealCoef;
17404 	    }
17405 	}
17406       else // complex packed spherical harmonics
17407 	{
17408 	  isec4[15] = BDS_PackData;
17409 	  // scaling factor
17410 	  isec4[16] = BDS_Power;
17411 
17412 	  // pentagonal resolution parameters of the unpacked section of data field
17413 
17414 	  int jup = bds[zoff+15];
17415 	  int kup = bds[zoff+16];
17416 	  int mup = bds[zoff+17];
17417 
17418 	  isec4[zoff+17] = jup;
17419 	  isec4[zoff+18] = kup;
17420 	  isec4[zoff+19] = mup;
17421 
17422 	  // unpacked binary data
17423 
17424 	  locnd += 4; // 2 + power
17425 	  locnd += 3; // j, k, m
17426 	  ioff   = (jup+1)*(jup+2);
17427 
17428 	  if ( dfunc != 'J' )
17429 	    for ( int i = 0; i < ioff; i++ )
17430 	      {
17431 		if ( imiss )
17432 		  *fpdata++ = 0.0;
17433 		else
17434 		  {
17435 		    int iexp2  = (bds[locnd+4*i]);
17436 		    int imant2 = GET_UINT3(bds[locnd+4*i+1], bds[locnd+4*i+2], bds[locnd+4*i+3]);
17437 		    *fpdata++ = (T)decfp2(iexp2,imant2);
17438 		  }
17439 	      }
17440 
17441 	  locnd += 4*ioff;  /* RealCoef */
17442 	}
17443     }
17444   else
17445     {
17446       if ( lcomplex )
17447 	{
17448 	  *iret = 1999;
17449 	  gprintf(__func__, " Second order packed grids unsupported!");
17450 	  gprintf(__func__, " Return code =  %d", *iret);
17451 	  return;
17452 	}
17453     }
17454 
17455   /* Decode data values to floating point and store in fsec4.  */
17456   /* First calculate the number of data values.                */
17457   /* Take into account that spherical harmonics can be packed  */
17458   /* simple (lcomplex = 0) or complex (lcomplex = 1)           */
17459 
17460   int jlend = bdsLen - locnd;
17461 
17462   if ( ISEC4_NumBits == 0 )
17463     {
17464       if ( jlend > 1 )
17465 	{
17466 	  *iret = 2001;
17467 	  gprintf(__func__, " Number of bits per data value = 0!");
17468 	  gprintf(__func__, " Return code =  %d", *iret);
17469 	  return;
17470 	}
17471 
17472       if ( numGridVals == 0 )
17473 	{
17474 	  *iret = 2002;
17475 	  gprintf(__func__, " Constant field unsupported for this grid type!");
17476 	  gprintf(__func__, " Return code =  %d", *iret);
17477 	  return;
17478 	}
17479 
17480       jlend = numGridVals;
17481       jlend -= ioff;
17482     }
17483   else
17484     {
17485       jlend = (int) (((long)jlend*8 - bds_ubits) / ISEC4_NumBits);
17486     }
17487 
17488   ISEC4_NumValues        = jlend + ioff;
17489   ISEC4_NumNonMissValues = 0;
17490 
17491   if ( lcompress )
17492     {
17493       size_t len = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
17494 
17495       ISEC4_NumValues = (int)(len*8/(size_t)ISEC4_NumBits);
17496 
17497       if ( lspherc ) ISEC4_NumValues += lcomplex ? ioff : 1;
17498     }
17499 
17500   if ( dfunc == 'J' ) return;
17501 
17502   // check length of output array.
17503 
17504   if ( ISEC4_NumValues > fsec4len )
17505     {
17506       *iret = 710;
17507       gprintf(__func__, " Output array too small. Length = %d", fsec4len);
17508       gprintf(__func__, " Number of values = %d", ISEC4_NumValues);
17509       gprintf(__func__, " Return code =  %d", *iret);
17510       return;
17511     }
17512 
17513   if ( imiss ) memset((char *)fpdata, 0, (size_t)jlend*sizeof(T));
17514   else
17515     {
17516       igrib += locnd;
17517 
17518       TEMPLATE(decode_array,T)(igrib, jlend, ISEC4_NumBits, fmin, zscale, fpdata);
17519     }
17520 
17521   if ( lspherc && lcomplex )
17522     {
17523       int pcStart = isec4[19], pcScale = isec4[16];
17524       TEMPLATE(scatter_complex,T)(fsec4, pcStart, ISEC2_PentaJ, ISEC4_NumValues);
17525       TEMPLATE(scale_complex,T)(fsec4, pcStart, pcScale, ISEC2_PentaJ, 1);
17526     }
17527 
17528   if ( CGRIBEX_Fix_ZSE )  // Fix ZeroShiftError of simple packed spherical harmonics
17529     if ( lspherc && !lcomplex )
17530       {
17531         // 20100705: Fix ZeroShiftError - Edi Kirk
17532 	if ( IS_NOT_EQUAL(fsec4[1], 0.0) )
17533 	  {
17534 	    T zserr = fsec4[1];
17535 	    for ( int i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
17536 	  }
17537       }
17538 
17539   if ( decscale )
17540     {
17541       T scale = TEMPLATE(pow,T)((T)10.0, (T)-decscale);
17542       for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
17543     }
17544 }
17545 
17546 
TEMPLATE(grib_decode,T)17547 void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *isec3,
17548 			     T *fsec3, int *isec4, T *fsec4, int fsec4len, int *kgrib,
17549 			     int kleng, int *kword, int dfunc, int *iret)
17550 {
17551   UCHAR *bms = NULL;
17552   bool lsect2 = false, lsect3 = false;
17553   static bool lmissvalinfo = true;
17554 
17555   UNUSED(kleng);
17556 
17557   *iret = 0;
17558 
17559   grsdef();
17560 
17561   ISEC2_Reduced = false;
17562 
17563   // ----------------------------------------------------------------
17564   // IS Indicator Section (Section 0)
17565   // ----------------------------------------------------------------
17566   UCHAR *is = (UCHAR *) &kgrib[0];
17567   int isLen = decodeIS(is, isec0, iret);
17568 
17569   int gribLen = ISEC0_GRIB_Len;
17570 
17571   /*
17572     When decoding or calculating length, previous editions
17573     of the GRIB code must be taken into account.
17574 
17575     In the table below, covering sections 0 and 1 of the GRIB
17576     code, octet numbering is from the beginning of the GRIB
17577     message;
17578     * indicates that the value is not available in the code edition;
17579     R indicates reserved, should be set to 0;
17580     Experimental edition is considered as edition -1.
17581 
17582     GRIB code edition -1 has fixed length of 20 octets for
17583     section 1, the length not included in the message.
17584     GRIB code edition 0 has fixed length of 24 octets for
17585     section 1, the length being included in the message.
17586     GRIB code edition 1 can have different lengths for section
17587     1, the minimum being 28 octets, length being included in
17588     the message.
17589 
17590                                          Octet numbers for code
17591                                                   editions
17592 
17593                  Contents.                   -1      0      1
17594                  ---------                ----------------------
17595        Letters GRIB                          1-4    1-4    1-4
17596        Total length of GRIB message.          *      *     5-7
17597        GRIB code edition number               *      *      8
17598        Length of Section 1.                   *     5-7    9-11
17599        Reserved octet (R).                    *      8(R)   *
17600        Version no. of Code Table 2.           *      *     12
17601        Identification of centre.              5      9     13
17602        Generating process.                    6     10     14
17603        Grid definition .                      7     11     15
17604        Flag (Code Table 1).                   8     12     16
17605        Indicator of parameter.                9     13     17
17606        Indicator of type of level.           10     14     18
17607        Height, pressure etc of levels.      11-12  15-16  19-20
17608        Year of century.                      13     17     21
17609        Month.                                14     18     22
17610        Day.                                  15     19     23
17611        Hour.                                 16     20     24
17612        Minute.                               17     21     25
17613        Indicator of unit of time.            18     22     26
17614        P1 - Period of time.                  19     23     27
17615        P2 - Period of time                  20(R)   24     28
17616        or reserved octet (R).
17617        Time range indicator.                21(R)   25     29
17618        or reserved octet (R).
17619        Number included in average.       22-23(R)  26-27  30-31
17620        or reserved octet (R).
17621        Number missing from average.         24(R)  28(R)   32
17622        or reserved octet (R).
17623        Century of data.                       *      *     33
17624        Designates sub-centre if not 0.        *      *     34
17625        Decimal scale factor.                  *      *    35-36
17626        Reserved. Set to 0.                    *      *    37-48
17627        (Need not be present)
17628        For originating centre use only.       *      *    49-nn
17629        (Need not be present)
17630 
17631     Identify which GRIB code edition is being decoded.
17632 
17633     In GRIB edition 1, the edition number is in octet 8.
17634     In GRIB edition 0, octet 8 is reserved and set to 0.
17635     In GRIB edition -1, octet 8 is a flag field and can have a
17636     a valid value of 0, 1, 2 or 3.
17637 
17638     However, GRIB edition number 0 has a fixed
17639     length of 24, included in the message, for section 1, so
17640     if the value extracted from octets 5-7 is 24 and that from
17641     octet 8 is 0, it is safe to assume edition 0 of the code.
17642 
17643   */
17644   if ( ISEC0_GRIB_Len == 24 && ISEC0_GRIB_Version == 0 )
17645     {
17646       // Set length of GRIB message to missing data value.
17647       ISEC0_GRIB_Len = 0;
17648     }
17649 
17650   // ----------------------------------------------------------------
17651   // PDS Product Definition Section (Section 1)
17652   // ----------------------------------------------------------------
17653   UCHAR *pds = is + isLen;
17654   int pdsLen = decodePDS(pds, isec0, isec1);
17655 
17656   // ----------------------------------------------------------------
17657   // GDS Grid Description Section (Section 2)
17658   // ----------------------------------------------------------------
17659   int numGridVals = 0;
17660   bool gdsIncluded = ISEC1_Sec2Or3Flag & 128;
17661   int gdsLen = 0;
17662   if ( gdsIncluded )
17663     {
17664       UCHAR *gds = is + isLen + pdsLen;
17665       gdsLen = TEMPLATE(decodeGDS,T)(gds, isec0, isec2, fsec2, &numGridVals);
17666     }
17667 
17668   // ----------------------------------------------------------------
17669   // BMS Bit-Map Section Section (Section 3)
17670   // ----------------------------------------------------------------
17671   isec3[0] = 0;
17672   bool bmsIncluded = ISEC1_Sec2Or3Flag & 64;
17673   int bmsLen = 0, bitmapSize = 0, imaskSize = 0;
17674   if ( bmsIncluded )
17675     {
17676       bms = is + isLen + pdsLen + gdsLen;
17677       bmsLen = BMS_Len;
17678 
17679       imaskSize = (bmsLen - 6)<<3;
17680       bitmapSize = imaskSize - BMS_UnusedBits;
17681     }
17682 
17683   // ----------------------------------------------------------------
17684   // BDS Binary Data Section (Section 4)
17685   // ----------------------------------------------------------------
17686   UCHAR *bds = is + isLen + pdsLen + gdsLen + bmsLen;
17687   int bdsLen = BDS_Len;
17688   /*
17689     If a very large product, the section 4 length field holds
17690     the number of bytes in the product after section 4 upto
17691     the end of the padding bytes.
17692     This is a fixup to get round the restriction on product lengths
17693     due to the count being only 24 bits. It is only possible because
17694     the (default) rounding for GRIB products is 120 bytes.
17695   */
17696   bool llarge = (gribLen > JP23SET && bdsLen <= 120);
17697   if ( llarge )
17698     {
17699       gribLen &= JP23SET;
17700       gribLen *= 120;
17701       ISEC0_GRIB_Len = gribLen;
17702       bdsLen = correct_bdslen(bdsLen, gribLen, isLen+pdsLen+gdsLen+bmsLen);
17703     }
17704   TEMPLATE(decodeBDS,T)(ISEC1_DecScaleFactor, bds, isec2, isec4,
17705                         fsec4, fsec4len, dfunc, bdsLen, numGridVals, iret);
17706 
17707   if ( *iret != 0 ) return;
17708 
17709   ISEC4_NumNonMissValues = ISEC4_NumValues;
17710 
17711   if ( bitmapSize > 0 )
17712     {
17713       if ( dfunc != 'L' && dfunc != 'J' )
17714 	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
17715 	  {
17716 	    lmissvalinfo = false;
17717 	    FSEC3_MissVal = (T)GRIB_MISSVAL;
17718 	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
17719 	  }
17720 
17721       /* ISEC4_NumNonMissValues = ISEC4_NumValues; */
17722       ISEC4_NumValues = bitmapSize;
17723 
17724       if ( dfunc != 'J' || bitmapSize == ISEC4_NumNonMissValues )
17725 	{
17726 	  GRIBPACK bitmap;
17727 	  /*
17728 	  unsigned char *bitmap;
17729 	  bitmap = BMS_Bitmap;
17730 	  int j = ISEC4_NumNonMissValues;
17731 	  for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
17732 	    {
17733 	      if ( (bitmap[i/8]>>(7-(i&7)))&1 )
17734 		fsec4[i] = fsec4[--j];
17735 	      else
17736 		fsec4[i] = FSEC3_MissVal;
17737 	    }
17738 	  */
17739 
17740 	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
17741 
17742 #ifdef VECTORCODE
17743 	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
17744 	  GRIBPACK *pbitmap = imask;
17745 #else
17746 	  GRIBPACK *pbitmap = BMS_Bitmap;
17747 #endif
17748 
17749 #if defined (CRAY)
17750 #pragma _CRI ivdep
17751 #endif
17752 #if defined (SX)
17753 #pragma vdir nodep
17754 #endif
17755 #ifdef __uxpch__
17756 #pragma loop novrec
17757 #endif
17758 	  for ( int i = imaskSize/8-1; i >= 0; i-- )
17759 	    {
17760 	      bitmap = pbitmap[i];
17761 	      imask[i*8+0] = 1 & (bitmap >> 7);
17762 	      imask[i*8+1] = 1 & (bitmap >> 6);
17763 	      imask[i*8+2] = 1 & (bitmap >> 5);
17764 	      imask[i*8+3] = 1 & (bitmap >> 4);
17765 	      imask[i*8+4] = 1 & (bitmap >> 3);
17766 	      imask[i*8+5] = 1 & (bitmap >> 2);
17767 	      imask[i*8+6] = 1 & (bitmap >> 1);
17768 	      imask[i*8+7] = 1 & (bitmap);
17769 	    }
17770 
17771 	  int j = 0;
17772 	  for ( int i = 0; i < ISEC4_NumValues; i++ )
17773 	    if ( imask[i] ) j++;
17774 
17775 	  if ( ISEC4_NumNonMissValues != j )
17776 	    {
17777 	      if ( dfunc != 'J' && ISEC4_NumBits != 0 )
17778 		Warning("Bitmap (%d) and data (%d) section differ, using bitmap section!",
17779 			j, ISEC4_NumNonMissValues);
17780 
17781 	      ISEC4_NumNonMissValues = j;
17782 	    }
17783 
17784 	  if ( dfunc != 'J' )
17785 	    {
17786 #if defined (CRAY)
17787 #pragma _CRI ivdep
17788 #endif
17789 #if defined (SX)
17790 #pragma vdir nodep
17791 #endif
17792 #ifdef __uxpch__
17793 #pragma loop novrec
17794 #endif
17795 	      for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
17796 		fsec4[i] = imask[i] ? fsec4[--j] : FSEC3_MissVal;
17797 	    }
17798 
17799 	  Free(imask);
17800 	}
17801     }
17802 
17803   if ( ISEC2_Reduced )
17804     {
17805       int nvalues = 0;
17806       int nlat = ISEC2_NumLat;
17807       int nlon = ISEC2_ReducedPointsPtr[0];
17808       for ( int ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_ReducedPoints(ilat);
17809       for ( int ilat = 1; ilat < nlat; ++ilat )
17810 	if ( ISEC2_ReducedPoints(ilat) > nlon ) nlon = ISEC2_ReducedPoints(ilat);
17811 
17812       // int dlon = ISEC2_LastLon-ISEC2_FirstLon;
17813       // if ( dlon < 0 ) dlon += 360000;
17814 
17815       if ( nvalues != ISEC4_NumValues ) *iret = -801;
17816 
17817       //printf("nlat %d  nlon %d \n", nlat, nlon);
17818       //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
17819 
17820       if ( dfunc == 'R' && *iret == -801 )
17821 	gprintf(__func__, "Number of values (%d) and sum of lons per row (%d) differ, abort conversion to regular Gaussian grid!",
17822 		ISEC4_NumValues, nvalues);
17823 
17824       if ( dfunc == 'R' && *iret != -801 )
17825 	{
17826 	  ISEC2_Reduced = 0;
17827 	  ISEC2_NumLon = nlon;
17828 	  ISEC4_NumValues = nlon*nlat;
17829 
17830 	  lsect3 = bitmapSize > 0;
17831           int lperio = 1;
17832 	  int lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) &&
17833                       ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) ||
17834                        (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30) ||
17835                        (ISEC1_Parameter == 39) || (ISEC1_Parameter == 40) ||
17836                        (ISEC1_Parameter == 41) || (ISEC1_Parameter == 42) ||
17837                        (ISEC1_Parameter == 43));
17838 
17839 	  (void) TEMPLATE(qu2reg3,T)(fsec4, ISEC2_ReducedPointsPtr, nlat, nlon, FSEC3_MissVal, iret, lsect3, lperio, lveggy);
17840 
17841 	  if ( bitmapSize > 0 )
17842 	    {
17843 	      int j = 0;
17844 	      for ( int i = 0; i < ISEC4_NumValues; i++ )
17845 		if ( IS_NOT_EQUAL(fsec4[i], FSEC3_MissVal) ) j++;
17846 
17847 	      ISEC4_NumNonMissValues = j;
17848 	    }
17849 	}
17850     }
17851 
17852   if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
17853   const int esLen = 4;
17854   gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
17855 
17856   if ( !llarge && ISEC0_GRIB_Len && ISEC0_GRIB_Len < gribLen )
17857     Warning("Inconsistent length of GRIB message (grib_message_size=%d < grib_record_size=%d)!", ISEC0_GRIB_Len, gribLen);
17858 
17859   ISEC0_GRIB_Len = gribLen;
17860 
17861   *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
17862 
17863   // ----------------------------------------------------------------
17864   // Section 9 . Abort/return to calling routine.
17865   // ----------------------------------------------------------------
17866   bool ldebug = false, l_iorj = false;
17867   if ( ldebug )
17868     {
17869       gprintf(__func__, "Section 9.");
17870       gprintf(__func__, "Output values set -");
17871 
17872       gribPrintSec0(isec0);
17873       gribPrintSec1(isec0, isec1);
17874       // Print section 2 if present.
17875       if ( lsect2 ) TEMPLATE(gribPrintSec2,T)(isec0, isec2, fsec2);
17876 
17877       if ( ! l_iorj )
17878 	{
17879 	  // Print section 3 if present.
17880 	  if ( lsect3 ) TEMPLATE(gribPrintSec3,T)(isec0, isec3, fsec3);
17881 
17882 	  TEMPLATE(gribPrintSec4,T)(isec0, isec4, fsec4);
17883 	  // Special print for 2D spectra wave field real values in section 4
17884 	  if ( (isec1[ 0] ==  140) &&
17885 	       (isec1[ 1] ==   98) &&
17886 	       (isec1[23] ==    1) &&
17887 	       ((isec1[39] == 1045) || (isec1[39] == 1081))  &&
17888 	       ((isec1[ 5] ==  250) || (isec1[ 5] ==  251)) )
17889 	    gribPrintSec4Wave(isec4);
17890 	}
17891     }
17892 }
17893 
17894 #endif /* T */
17895 
17896 /*
17897  * Local Variables:
17898  * mode: c
17899  * End:
17900  */
17901 
17902 /* GRIB block 0 - indicator block */
17903 static
encodeIS(GRIBPACK * lGrib,long * gribLen)17904 void encodeIS(GRIBPACK *lGrib, long *gribLen)
17905 {
17906   long z;
17907   // z = *gribLen;
17908 
17909   lGrib[0] = 'G';
17910   lGrib[1] = 'R';
17911   lGrib[2] = 'I';
17912   lGrib[3] = 'B';
17913 
17914   // lGrib[4]-lGrib[6] contains full length of grib record.
17915   // included before finished CODEGB
17916 
17917   z = 7;
17918   Put1Byte(1); /* grib version */
17919   z = 8;
17920 
17921   *gribLen = z;
17922 }
17923 
17924 /* GRIB block 5 - end block */
17925 static
encodeES(GRIBPACK * lGrib,long * gribLen,long bdsstart)17926 void encodeES(GRIBPACK *lGrib, long *gribLen, long bdsstart)
17927 {
17928   long z = *gribLen;
17929 
17930   lGrib[z++] = '7';
17931   lGrib[z++] = '7';
17932   lGrib[z++] = '7';
17933   lGrib[z++] = '7';
17934 
17935   if ( z > JP24SET )
17936     {
17937       long bdslen = z - 4;
17938       // fprintf(stderr, "Abort: GRIB record too large (max = %d)!\n", JP23SET);
17939       // exit(1);
17940       /*
17941 	If a very large product, the section 4 length field holds
17942 	the number of bytes in the product after section 4 upto
17943 	the end of the padding bytes.
17944 	This is a fixup to get round the restriction on product lengths
17945 	due to the count being only 24 bits. It is only possible because
17946 	the (default) rounding for GRIB products is 120 bytes.
17947       */
17948       while ( z%120 ) lGrib[z++] = 0;
17949 
17950       if ( z > JP23SET*120 )
17951 	{
17952 	  fprintf(stderr, "Abort: GRIB1 record too large (size = %ld; max = %d)!\n", z, JP23SET*120);
17953 	  exit(1);
17954 	}
17955 
17956       long itemp = z / (-120);
17957       itemp = JP23SET - itemp + 1;
17958 
17959       lGrib[4] = (GRIBPACK)(itemp >> 16);
17960       lGrib[5] = (GRIBPACK)(itemp >>  8);
17961       lGrib[6] = (GRIBPACK)itemp;
17962 
17963       bdslen = z - bdslen;
17964       lGrib[bdsstart  ] = (GRIBPACK)(bdslen >> 16);
17965       lGrib[bdsstart+1] = (GRIBPACK)(bdslen >>  8);
17966       lGrib[bdsstart+2] = (GRIBPACK)bdslen;
17967     }
17968   else
17969     {
17970       lGrib[4] = (GRIBPACK)(z >> 16);
17971       lGrib[5] = (GRIBPACK)(z >>  8);
17972       lGrib[6] = (GRIBPACK)z;
17973 
17974       while ( z%8 ) lGrib[z++] = 0;
17975     }
17976 
17977   *gribLen = z;
17978 }
17979 
17980 /* GRIB block 1 - product definition block. */
17981 
17982 #define DWD_extension_253_len 38
17983 #define DWD_extension_254_len 26
17984 #define ECMWF_extension_1_len 24
17985 #define MPIM_extension_1_len  18
17986 
17987 static
getLocalExtLen(int * isec1)17988 long getLocalExtLen(int *isec1)
17989 {
17990   long extlen = 0;
17991 
17992   if ( ISEC1_LocalFLag )
17993     {
17994       if ( ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250 )
17995 	{
17996 	  if      ( isec1[36] == 254 ) extlen = DWD_extension_254_len;
17997 	  else if ( isec1[36] == 253 ) extlen = DWD_extension_253_len;
17998 	}
17999       else if ( ISEC1_CenterID == 98 )
18000         {
18001 	  if ( isec1[36] == 1 )   extlen = ECMWF_extension_1_len;
18002         }
18003       else if ( ISEC1_CenterID == 252 )
18004         {
18005 	  if ( isec1[36] == 1 ) extlen = MPIM_extension_1_len;
18006         }
18007     }
18008 
18009   return extlen;
18010 }
18011 
18012 static
getPdsLen(int * isec1)18013 long getPdsLen(int *isec1)
18014 {
18015   long pdslen = 28;
18016 
18017   pdslen += getLocalExtLen(isec1);
18018 
18019   return pdslen;
18020 }
18021 
18022 static
encodePDS_DWD_local_Extension_254(GRIBPACK * lGrib,long * zs,int * isec1)18023 void encodePDS_DWD_local_Extension_254(GRIBPACK *lGrib, long *zs, int *isec1)
18024 {
18025   long z = *zs;
18026 
18027   long localextlen = getLocalExtLen(isec1);
18028   for ( long i = 0; i < localextlen-2; i++ ) Put1Byte(isec1[24+i]);
18029 
18030   int isvn = isec1[49] << 15 | isec1[48]; /* DWD experiment identifier    */
18031   Put2Byte(isvn);             /* DWD run type (0=main, 2=ass, 3=test) */
18032 
18033   *zs = z;
18034 }
18035 
18036 static
encodePDS_DWD_local_Extension_253(GRIBPACK * lGrib,long * zs,int * isec1)18037 void encodePDS_DWD_local_Extension_253(GRIBPACK *lGrib, long *zs, int *isec1)
18038 {
18039   long z = *zs;
18040 
18041   long localextlen = DWD_extension_254_len;
18042   for ( long i = 0; i < localextlen-2; i++ ) Put1Byte(isec1[24+i]);
18043 
18044   int isvn = isec1[49] << 15 | isec1[48]; /* DWD experiment identifier    */
18045   Put2Byte(isvn);             /* DWD run type (0=main, 2=ass, 3=test) */
18046   Put1Byte(isec1[50]);        /* 55 User id, specified by table       */
18047   Put2Byte(isec1[51]);        /* 56 Experiment identifier             */
18048   Put2Byte(isec1[52]);        /* 58 Ensemble identification by table  */
18049   Put2Byte(isec1[53]);        /* 60 Number of ensemble members        */
18050   Put2Byte(isec1[54]);        /* 62 Actual number of ensemble member  */
18051   Put1Byte(isec1[55]);        /* 64 Model major version number        */
18052   Put1Byte(isec1[56]);        /* 65 Model minor version number        */
18053   Put1Byte(0);                /* 66 Blank for even buffer length      */
18054 
18055   *zs = z;
18056 }
18057 
18058 static
encodePDS_ECMWF_local_Extension_1(GRIBPACK * lGrib,long * zs,int * isec1)18059 void encodePDS_ECMWF_local_Extension_1(GRIBPACK *lGrib, long *zs, int *isec1)
18060 {
18061   long z = *zs;
18062 
18063   long localextlen = getLocalExtLen(isec1);
18064   for ( long i = 0; i < localextlen-12; i++ ) Put1Byte(isec1[24+i]);
18065                               /* 12 bytes explicitly encoded below:         */
18066   Put1Byte(isec1[36]);        /* ECMWF local GRIB use definition identifier */
18067                               /*    1=MARS labelling or ensemble fcst. data */
18068   Put1Byte(isec1[37]);        /* Class                                      */
18069   Put1Byte(isec1[38]);        /* Type                                       */
18070   Put2Byte(isec1[39]);        /* Stream                                     */
18071 
18072   /* Version number or experiment identifier    */
18073   Put1Byte(((unsigned char*) &isec1[40])[0]);
18074   Put1Byte(((unsigned char*) &isec1[40])[1]);
18075   Put1Byte(((unsigned char*) &isec1[40])[2]);
18076   Put1Byte(((unsigned char*) &isec1[40])[3]);
18077 
18078   Put1Byte(isec1[41]);        /* Ensemble forecast number                   */
18079   Put1Byte(isec1[42]);        /* Total number of forecasts in ensemble      */
18080   Put1Byte(0);                /* (Spare)                                    */
18081 
18082   *zs = z;
18083 }
18084 
18085 static
encodePDS_MPIM_local_Extension_1(GRIBPACK * lGrib,long * zs,int * isec1)18086 void encodePDS_MPIM_local_Extension_1(GRIBPACK *lGrib, long *zs, int *isec1)
18087 {
18088   long z = *zs;
18089 
18090   long localextlen = getLocalExtLen(isec1);
18091   for ( long i = 0; i < localextlen-6; i++ ) Put1Byte(isec1[24+i]);
18092                               /* 6 bytes explicitly encoded below:          */
18093   Put1Byte(isec1[36]);        /* MPIM local GRIB use definition identifier  */
18094                               /*    (extension identifier)                  */
18095   Put1Byte(isec1[37]);        /* type of ensemble forecast                  */
18096   Put2Byte(isec1[38]);        /* individual ensemble member                 */
18097   Put2Byte(isec1[39]);        /* number of forecasts in ensemble            */
18098 
18099   *zs = z;
18100 }
18101 
18102 /* GRIB BLOCK 1 - PRODUCT DESCRIPTION SECTION */
18103 static
encodePDS(GRIBPACK * lpds,long pdsLen,int * isec1)18104 void encodePDS(GRIBPACK *lpds, long pdsLen, int *isec1)
18105 {
18106   GRIBPACK *lGrib = lpds;
18107   long z = 0;
18108   int ival;
18109 
18110   int century = ISEC1_Century;
18111   int year    = ISEC1_Year;
18112 
18113   if ( century < 0 )
18114     {
18115       century = -century;
18116       year    = -year;
18117     }
18118 
18119   Put3Byte(pdsLen);               /*  0 Length of Block 1        */
18120   Put1Byte(ISEC1_CodeTable);      /*  3 Local table number       */
18121   Put1Byte(ISEC1_CenterID);       /*  4 Identification of centre */
18122   Put1Byte(ISEC1_ModelID);        /*  5 Identification of model  */
18123   Put1Byte(ISEC1_GridDefinition); /*  6 Grid definition          */
18124   Put1Byte(ISEC1_Sec2Or3Flag);    /*  7 Block 2 included         */
18125   Put1Byte(ISEC1_Parameter);      /*  8 Parameter Code           */
18126   Put1Byte(ISEC1_LevelType);      /*  9 Type of level            */
18127   if ( (ISEC1_LevelType !=  20) &&
18128        (ISEC1_LevelType != GRIB1_LTYPE_99)           &&
18129        (ISEC1_LevelType != GRIB1_LTYPE_ISOBARIC)     &&
18130        (ISEC1_LevelType != GRIB1_LTYPE_ISOBARIC_PA)  &&
18131        (ISEC1_LevelType != GRIB1_LTYPE_ALTITUDE)     &&
18132        (ISEC1_LevelType != GRIB1_LTYPE_HEIGHT)       &&
18133        (ISEC1_LevelType != GRIB1_LTYPE_SIGMA)        &&
18134        (ISEC1_LevelType != GRIB1_LTYPE_HYBRID)       &&
18135        (ISEC1_LevelType != GRIB1_LTYPE_LANDDEPTH)    &&
18136        (ISEC1_LevelType != GRIB1_LTYPE_ISENTROPIC)   &&
18137        (ISEC1_LevelType != 115) &&
18138        (ISEC1_LevelType != 117) &&
18139        (ISEC1_LevelType != 125) &&
18140        (ISEC1_LevelType != 127) &&
18141        (ISEC1_LevelType != 160) &&
18142        (ISEC1_LevelType != 210) )
18143     {
18144       Put1Byte(ISEC1_Level1);
18145       Put1Byte(ISEC1_Level2);
18146     }
18147   else
18148     {
18149       Put2Byte(ISEC1_Level1);     /* 10 Level                    */
18150     }
18151 
18152   Put1Int(year);                  /* 12 Year of Century          */
18153   Put1Byte(ISEC1_Month);          /* 13 Month                    */
18154   Put1Byte(ISEC1_Day);            /* 14 Day                      */
18155   Put1Byte(ISEC1_Hour);           /* 15 Hour                     */
18156   Put1Byte(ISEC1_Minute);         /* 16 Minute                   */
18157 
18158   Put1Byte(ISEC1_TimeUnit);       /* 17 Time unit                */
18159   if ( ISEC1_TimeRange == 10 )
18160     {
18161       Put1Byte(ISEC1_TimePeriod1);
18162       Put1Byte(ISEC1_TimePeriod2);
18163     }
18164   else if ( ISEC1_TimeRange == 113 || ISEC1_TimeRange ==   0 )
18165     {
18166       Put1Byte(ISEC1_TimePeriod1);
18167       Put1Byte(0);
18168     }
18169   else if ( ISEC1_TimeRange ==   5 || ISEC1_TimeRange ==   4 ||
18170 	    ISEC1_TimeRange ==   3 || ISEC1_TimeRange ==   2 )
18171     {
18172       Put1Byte(ISEC1_TimePeriod1);
18173       Put1Byte(ISEC1_TimePeriod2);
18174     }
18175   else
18176     {
18177       Put1Byte(0);
18178       Put1Byte(0);
18179     }
18180   Put1Byte(ISEC1_TimeRange);      /* 20 Timerange flag           */
18181   Put2Byte(ISEC1_AvgNum);         /* 21 Average                  */
18182 
18183   Put1Byte(ISEC1_AvgMiss);        /* 23 Missing from averages    */
18184   Put1Byte(century);              /* 24 Century                  */
18185   Put1Byte(ISEC1_SubCenterID);    /* 25 Subcenter                */
18186   Put2Int(ISEC1_DecScaleFactor);  /* 26 Decimal scale factor     */
18187 
18188   if ( ISEC1_LocalFLag )
18189     {
18190       if ( ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250 )
18191 	{
18192 	  if      ( isec1[36] == 254 ) encodePDS_DWD_local_Extension_254(lGrib, &z, isec1);
18193 	  else if ( isec1[36] == 253 ) encodePDS_DWD_local_Extension_253(lGrib, &z, isec1);
18194 	}
18195       else if ( ISEC1_CenterID == 98 )
18196 	{
18197 	  if ( isec1[36] == 1 ) encodePDS_ECMWF_local_Extension_1(lGrib, &z, isec1);
18198 	}
18199       else if ( ISEC1_CenterID == 252 )
18200 	{
18201 	  if ( isec1[36] == 1 ) encodePDS_MPIM_local_Extension_1(lGrib, &z, isec1);
18202 	}
18203       else
18204 	{
18205 	  long i, localextlen;
18206 	  localextlen = getLocalExtLen(isec1);
18207 	  for ( i = 0; i < localextlen; i++ )
18208 	    {
18209 	      Put1Byte(isec1[24+i]);
18210 	    }
18211 	}
18212     }
18213 }
18214 
18215 
18216 
18217 
18218 #ifdef T
18219 #undef T
18220 #endif
18221 #define T double
18222 #ifdef T
18223 
18224 
18225 #define round_float roundf
18226 #define round_double round
18227 
18228 #if 0
18229 #define CGRIBEX_FPSCALE(data) (TEMPLATE(round,T)(((data) - zref) * factor))
18230 #else
18231 #define CGRIBEX_FPSCALE(data) (((data) - zref) * factor + (T)0.5)
18232 #endif
18233 
18234 static
TEMPLATE(encode_array_common,T)18235 void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datasize, GRIBPACK *lGrib,
18236 				     const T *data, T zref, T factor, size_t *gz)
18237 {
18238   size_t z = *gz;
18239   unsigned int ival;
18240   int cbits, jbits;
18241   unsigned int c;
18242 
18243   /* code from gribw routine flist2bitstream */
18244 
18245   cbits = 8;
18246   c = 0;
18247   for (size_t i = packStart; i < datasize; i++)
18248     {
18249       /* note float -> unsigned int .. truncate */
18250       ival = (unsigned int)(CGRIBEX_FPSCALE(data[i]));
18251       /*
18252 	if ( ival > max_nbpv_pow2 ) ival = max_nbpv_pow2;
18253 	if ( ival < 0 ) ival = 0;
18254       */
18255       jbits = numBits;
18256       while ( cbits <= jbits )
18257 	{
18258 	  if ( cbits == 8 )
18259 	    {
18260 	      jbits -= 8;
18261 	      lGrib[z++] = (ival >> jbits) & 0xFF;
18262 	    }
18263 	  else
18264 	    {
18265 	      jbits -= cbits;
18266 	      lGrib[z++] = (GRIBPACK)((c << cbits)
18267                                       + ((ival >> jbits) & ((1U << cbits) - 1)));
18268 	      cbits = 8;
18269 	      c = 0;
18270 	    }
18271 	}
18272       /* now jbits < cbits */
18273       if ( jbits )
18274 	{
18275 	  c = (c << jbits) + (ival & ((1U << jbits)-1));
18276 	  cbits -= jbits;
18277 	}
18278     }
18279   if ( cbits != 8 ) lGrib[z++] = (GRIBPACK)(c << cbits);
18280 
18281   *gz = z;
18282 }
18283 
18284 
18285 static
TEMPLATE(encode_array_2byte,T)18286 void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
18287 				    const T *restrict data, T zref, T factor, size_t *gz)
18288 {
18289   U_BYTEORDER;
18290   uint16_t *restrict sgrib = (uint16_t *)(void *)(lGrib+*gz);
18291 
18292   if ( IS_BIGENDIAN() )
18293     {
18294       for ( size_t i = 0; i < datasize; i++ )
18295         sgrib[i] = (uint16_t)(CGRIBEX_FPSCALE(data[i]));
18296     }
18297   else
18298     {
18299       uint16_t ui16;
18300       for ( size_t i = 0; i < datasize; i++ )
18301         {
18302           ui16 = (uint16_t)(CGRIBEX_FPSCALE(data[i]));
18303           sgrib[i] = gribSwapByteOrder_uint16(ui16);
18304         }
18305     }
18306 
18307   *gz += 2*datasize;
18308 }
18309 /*
18310 static
18311 void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
18312 				    const T *restrict data, T zref, T factor, size_t *gz)
18313 {
18314   size_t i, z = *gz;
18315   uint16_t ui16;
18316   T tmp;
18317 
18318 #if   defined (CRAY)
18319 #pragma _CRI ivdep
18320 #elif defined (SX)
18321 #pragma vdir nodep
18322 #elif defined (__uxp__)
18323 #pragma loop novrec
18324 #elif defined (__ICC)
18325 #pragma ivdep
18326 #endif
18327   for ( i = 0; i < datasize; i++ )
18328     {
18329       tmp = CGRIBEX_FPSCALE(data[i]);
18330       ui16 = (uint16_t) tmp;
18331       lGrib[z  ] = ui16 >>  8;
18332       lGrib[z+1] = ui16;
18333       z += 2;
18334     }
18335 
18336   *gz = z;
18337 }
18338 */
18339 static
TEMPLATE(encode_array,T)18340 void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
18341 			      GRIBPACK *restrict lGrib,
18342 			      const T *restrict data,
18343 			      T zref, T factor, size_t *gz)
18344 {
18345 #if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
18346   uint64_t start_minmax, end_minmax;
18347 #endif
18348   uint32_t ui32;
18349   size_t i, z = *gz;
18350   T tmp;
18351 
18352   data += packStart;
18353   datasize -= packStart;
18354 
18355   if      ( numBits ==  8 )
18356     {
18357 #ifdef _GET_IBM_COUNTER
18358       hpmStart(2, "pack 8 bit base");
18359 #endif
18360 
18361 #if defined (CRAY)
18362 #pragma _CRI ivdep
18363 #elif defined (SX)
18364 #pragma vdir nodep
18365 #elif defined (__uxp__)
18366 #pragma loop novrec
18367 #elif defined (__ICC)
18368 #pragma ivdep
18369 #endif
18370       for ( i = 0; i < datasize; i++ )
18371 	{
18372           tmp = CGRIBEX_FPSCALE(data[i]);
18373 	  lGrib[z  ] = (GRIBPACK)tmp;
18374           z++;
18375 	}
18376 
18377 #ifdef _GET_IBM_COUNTER
18378       hpmStop(2);
18379 #endif
18380     }
18381   else if ( numBits == 16 )
18382     {
18383 #ifdef _GET_IBM_COUNTER
18384       hpmStart(3, "pack 16 bit base");
18385 #elif defined _GET_X86_COUNTER
18386       start_minmax = _rdtsc();
18387 #elif defined _GET_MACH_COUNTER
18388       start_minmax = mach_absolute_time();
18389 #endif
18390       if ( sizeof(T) == sizeof(double) )
18391       	{
18392           grib_encode_array_2byte_double(datasize, lGrib, (const double *)(const void *)data, zref, factor, &z);
18393         }
18394       else
18395         {
18396           TEMPLATE(encode_array_2byte,T)(datasize, lGrib, data, zref, factor, &z);
18397         }
18398 
18399 #if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
18400 #if defined _GET_X86_COUNTER
18401       end_minmax = _rdtsc();
18402 #elif defined _GET_MACH_COUNTER
18403       end_minmax = mach_absolute_time();
18404 #endif
18405 #if defined _ENABLE_AVX
18406       printf("AVX encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
18407 #elif defined _ENABLE_SSE4_1
18408       printf("SSE 4.1 encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
18409 #else
18410       printf("loop encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
18411 #endif
18412 #endif
18413 
18414 #ifdef _GET_IBM_COUNTER
18415       hpmStop(3);
18416 #endif
18417     }
18418   else if ( numBits == 24 )
18419     {
18420 #ifdef _GET_IBM_COUNTER
18421       hpmStart(4, "pack 24 bit base");
18422 #endif
18423 
18424 #if   defined (CRAY)
18425 #pragma _CRI ivdep
18426 #elif defined (SX)
18427 #pragma vdir nodep
18428 #elif defined (__uxp__)
18429 #pragma loop novrec
18430 #elif defined (__ICC)
18431 #pragma ivdep
18432 #endif
18433       for ( i = 0; i < datasize; i++ )
18434 	{
18435           tmp = CGRIBEX_FPSCALE(data[i]);
18436           ui32 = (uint32_t) tmp;
18437           lGrib[z  ] =  (GRIBPACK)(ui32 >> 16);
18438           lGrib[z+1] =  (GRIBPACK)(ui32 >>  8);
18439           lGrib[z+2] =  (GRIBPACK)ui32;
18440           z += 3;
18441 	}
18442 
18443 #ifdef _GET_IBM_COUNTER
18444       hpmStop(4);
18445 #endif
18446     }
18447   else if ( numBits == 32 )
18448     {
18449 #ifdef _GET_IBM_COUNTER
18450       hpmStart(5, "pack 32 bit base");
18451 #endif
18452 
18453 #if   defined (CRAY)
18454 #pragma _CRI ivdep
18455 #elif defined (SX)
18456 #pragma vdir nodep
18457 #elif defined (__uxp__)
18458 #pragma loop novrec
18459 #elif defined (__ICC)
18460 #pragma ivdep
18461 #endif
18462       for ( i = 0; i < datasize; i++ )
18463 	{
18464           tmp = CGRIBEX_FPSCALE(data[i]);
18465           ui32 = (uint32_t) tmp;
18466           lGrib[z  ] =  (GRIBPACK)(ui32 >> 24);
18467           lGrib[z+1] =  (GRIBPACK)(ui32 >> 16);
18468           lGrib[z+2] =  (GRIBPACK)(ui32 >>  8);
18469           lGrib[z+3] =  (GRIBPACK)ui32;
18470           z += 4;
18471 	}
18472 
18473 #ifdef _GET_IBM_COUNTER
18474       hpmStop(5);
18475 #endif
18476     }
18477   else if ( numBits > 0 && numBits <= 32 )
18478     {
18479       TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
18480     }
18481   else if ( numBits == 0 )
18482     {
18483     }
18484   else
18485     {
18486       Error("Unimplemented packing factor %d!", numBits);
18487     }
18488 
18489   *gz = z;
18490 }
18491 
18492 static
TEMPLATE(encode_array_unrolled,T)18493 void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t datasize,
18494 				       GRIBPACK *restrict lGrib,
18495 				       const T *restrict data,
18496 				       T zref, T factor, size_t *gz)
18497 {
18498   U_BYTEORDER;
18499   size_t i, j, z = *gz;
18500 #ifdef _ARCH_PWR6
18501   enum { CGRIBEX__UNROLL_DEPTH_2 = 8 };
18502 #else
18503   enum { CGRIBEX__UNROLL_DEPTH_2 = 128 };
18504 #endif
18505   size_t residual;
18506   size_t ofs;
18507   T dval[CGRIBEX__UNROLL_DEPTH_2];
18508 
18509   data += packStart;
18510   datasize -= packStart;
18511   residual =  datasize % CGRIBEX__UNROLL_DEPTH_2;
18512   ofs = datasize - residual;
18513 
18514   // reducing FP operations to single FMA is slowing down on pwr6 ...
18515 
18516   if      ( numBits ==  8 )
18517     {
18518 #ifdef _GET_IBM_COUNTER
18519       hpmStart(2, "pack 8 bit unrolled");
18520 #endif
18521       unsigned char *cgrib = (unsigned char *) (lGrib + z);
18522       for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
18523 	{
18524 	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
18525 	    {
18526 	      dval[j] = CGRIBEX_FPSCALE(data[i+j]);
18527 	    }
18528 	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
18529 	    {
18530 #ifdef _ARCH_PWR6
18531 	      *cgrib++ =  (unsigned long) dval[j];
18532 #else
18533 	      *cgrib++ =  (unsigned char) dval[j];
18534 #endif
18535 	    }
18536 	  z += CGRIBEX__UNROLL_DEPTH_2;
18537 	}
18538       for (j = 0; j < residual; j++)
18539 	{
18540 	  dval[j] = CGRIBEX_FPSCALE(data[i+j]);
18541 	}
18542       for (j = 0; j < residual; j++)
18543 	{
18544 #ifdef _ARCH_PWR6
18545 	  *cgrib++ = (unsigned long) dval[j];
18546 #else
18547 	  *cgrib++ = (unsigned char) dval[j];
18548 #endif
18549 	}
18550       z += residual;
18551 
18552 #ifdef _GET_IBM_COUNTER
18553       hpmStop(2);
18554 #endif
18555     }
18556   else if ( numBits == 16 )
18557     {
18558 #ifdef _GET_IBM_COUNTER
18559       hpmStart(3, "pack 16 bit unrolled");
18560 #endif
18561 #ifdef _ARCH_PWR6
18562       unsigned long ival;
18563 #else
18564       uint16_t ival;
18565 #endif
18566       uint16_t *sgrib = (uint16_t *)(void *)(lGrib+z);
18567 
18568       for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
18569 	{
18570 	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
18571 	    dval[j] = CGRIBEX_FPSCALE(data[j]);
18572 	  if ( IS_BIGENDIAN() )
18573 	    {
18574 	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
18575 		{
18576 #ifdef _ARCH_PWR6
18577 		  *sgrib++ = (unsigned long) dval[j];
18578 #else
18579 		  *sgrib++ = (uint16_t) dval[j];
18580 #endif
18581 		}
18582 	      z += 2*CGRIBEX__UNROLL_DEPTH_2;
18583 	    }
18584 	  else
18585 	    {
18586 	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
18587 		{
18588 		  ival = (uint16_t) dval[j];
18589                   *sgrib++ = gribSwapByteOrder_uint16(ival);
18590 		}
18591 	      z += 2*CGRIBEX__UNROLL_DEPTH_2;
18592 	    }
18593 	}
18594       for (j = 0; j < residual; j++)
18595 	{
18596 	  dval[j] = CGRIBEX_FPSCALE(data[j]);
18597 	}
18598       if ( IS_BIGENDIAN() )
18599 	{
18600 	  for (j = 0; j < residual; j++)
18601 	    {
18602 #ifdef _ARCH_PWR6
18603 	      *sgrib++ = (unsigned long) dval[j];
18604 #else
18605               *sgrib++ = (uint16_t) dval[j];
18606 #endif
18607 	    }
18608 	  z += 2*residual;
18609 	}
18610       else
18611 	{
18612 	  for (j = 0; j < residual; j++)
18613 	    {
18614               ival = (uint16_t) dval[j];
18615 	      lGrib[z  ] = (GRIBPACK)(ival >>  8);
18616 	      lGrib[z+1] = (GRIBPACK)ival;
18617 	      z += 2;
18618 	    }
18619 	}
18620 #ifdef _GET_IBM_COUNTER
18621       hpmStop(3);
18622 #endif
18623     }
18624   else if ( numBits == 24 )
18625     {
18626 #ifdef _GET_IBM_COUNTER
18627       hpmStart(4, "pack 24 bit unrolled");
18628 #endif
18629 #ifdef _ARCH_PWR6
18630       unsigned long ival;
18631 #else
18632       uint32_t ival;
18633 #endif
18634       for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
18635 	{
18636 	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
18637 	    {
18638 	      dval[j] = CGRIBEX_FPSCALE(data[j]);
18639 	    }
18640 	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
18641 	    {
18642 #ifdef _ARCH_PWR6
18643 	      ival = (unsigned long) dval[j];
18644 #else
18645 	      ival = (uint32_t) dval[j];
18646 #endif
18647 	      lGrib[z  ] =  (GRIBPACK)(ival >> 16);
18648 	      lGrib[z+1] =  (GRIBPACK)(ival >>  8);
18649 	      lGrib[z+2] =  (GRIBPACK)ival;
18650 	      z += 3;
18651 	    }
18652 	}
18653       for (j = 0; j < residual; j++)
18654 	{
18655 	  dval[j] = CGRIBEX_FPSCALE(data[j]);
18656 	}
18657       for (j = 0; j < residual; j++)
18658 	{
18659 	  ival = (uint32_t) dval[j];
18660 	  lGrib[z  ] =  (GRIBPACK)(ival >> 16);
18661 	  lGrib[z+1] =  (GRIBPACK)(ival >>  8);
18662 	  lGrib[z+2] =  (GRIBPACK)ival;
18663 	  z += 3;
18664 	}
18665 #ifdef _GET_IBM_COUNTER
18666       hpmStop(4);
18667 #endif
18668     }
18669   else if ( numBits == 32 )
18670     {
18671 #ifdef _GET_IBM_COUNTER
18672       hpmStart(5, "pack 32 bit unrolled");
18673 #endif
18674 #ifdef _ARCH_PWR6
18675       unsigned long ival;
18676 #else
18677       uint32_t ival;
18678 #endif
18679       unsigned int *igrib = (unsigned int *)(void *)(lGrib + z);
18680       for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
18681         {
18682 	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
18683             dval[j] = CGRIBEX_FPSCALE(data[i+j]);
18684 	  if ( IS_BIGENDIAN() )
18685 	    {
18686 	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
18687 		{
18688 #ifdef _ARCH_PWR6
18689 		  *igrib = (unsigned long) dval[j];
18690 #else
18691 		  *igrib = (uint32_t) dval[j];
18692 #endif
18693 		  igrib++;
18694 		  z += 4;
18695 		}
18696 	    }
18697 	  else
18698 	    {
18699 	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
18700 		{
18701                   ival = (uint32_t) dval[j];
18702 		  lGrib[z  ] =  (GRIBPACK)(ival >> 24);
18703 		  lGrib[z+1] =  (GRIBPACK)(ival >> 16);
18704 		  lGrib[z+2] =  (GRIBPACK)(ival >>  8);
18705 		  lGrib[z+3] =  (GRIBPACK)ival;
18706 		  z += 4;
18707 		}
18708 	    }
18709 	}
18710       for (j = 0; j < residual; j++)
18711 	{
18712           dval[j] = CGRIBEX_FPSCALE(data[ofs+j]);
18713 	}
18714       if ( IS_BIGENDIAN() )
18715 	{
18716 	  for (j = 0; j < residual; j++)
18717 	    {
18718 #ifdef _ARCH_PWR6
18719 	      *igrib = (unsigned long) dval[j];
18720 #else
18721 	      *igrib = (uint32_t) dval[j];
18722 #endif
18723 	      igrib++;
18724 	      z += 4;
18725 	    }
18726 	}
18727       else
18728 	{
18729           for (j = 0; j < residual; j++)
18730 	    {
18731 	      ival = (uint32_t) dval[j];
18732 	      lGrib[z  ] =  (GRIBPACK)(ival >> 24);
18733 	      lGrib[z+1] =  (GRIBPACK)(ival >> 16);
18734 	      lGrib[z+2] =  (GRIBPACK)(ival >>  8);
18735 	      lGrib[z+3] =  (GRIBPACK)ival;
18736 	      z += 4;
18737 	    }
18738 	}
18739 #ifdef _GET_IBM_COUNTER
18740       hpmStop(5);
18741 #endif
18742     }
18743   else if ( numBits > 0 && numBits <= 32 )
18744     {
18745       TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
18746     }
18747   else if ( numBits == 0 )
18748     {
18749     }
18750   else
18751     {
18752       Error("Unimplemented packing factor %d!", numBits);
18753     }
18754 
18755   *gz = z;
18756 }
18757 
18758 #endif /* T */
18759 
18760 /*
18761  * Local Variables:
18762  * mode: c
18763  * End:
18764  */
18765 
18766 #ifdef T
18767 #undef T
18768 #endif
18769 #define T float
18770 #ifdef T
18771 
18772 
18773 #define round_float roundf
18774 #define round_double round
18775 
18776 #if 0
18777 #define CGRIBEX_FPSCALE(data) (TEMPLATE(round,T)(((data) - zref) * factor))
18778 #else
18779 #define CGRIBEX_FPSCALE(data) (((data) - zref) * factor + (T)0.5)
18780 #endif
18781 
18782 static
TEMPLATE(encode_array_common,T)18783 void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datasize, GRIBPACK *lGrib,
18784 				     const T *data, T zref, T factor, size_t *gz)
18785 {
18786   size_t z = *gz;
18787   unsigned int ival;
18788   int cbits, jbits;
18789   unsigned int c;
18790 
18791   /* code from gribw routine flist2bitstream */
18792 
18793   cbits = 8;
18794   c = 0;
18795   for (size_t i = packStart; i < datasize; i++)
18796     {
18797       /* note float -> unsigned int .. truncate */
18798       ival = (unsigned int)(CGRIBEX_FPSCALE(data[i]));
18799       /*
18800 	if ( ival > max_nbpv_pow2 ) ival = max_nbpv_pow2;
18801 	if ( ival < 0 ) ival = 0;
18802       */
18803       jbits = numBits;
18804       while ( cbits <= jbits )
18805 	{
18806 	  if ( cbits == 8 )
18807 	    {
18808 	      jbits -= 8;
18809 	      lGrib[z++] = (ival >> jbits) & 0xFF;
18810 	    }
18811 	  else
18812 	    {
18813 	      jbits -= cbits;
18814 	      lGrib[z++] = (GRIBPACK)((c << cbits)
18815                                       + ((ival >> jbits) & ((1U << cbits) - 1)));
18816 	      cbits = 8;
18817 	      c = 0;
18818 	    }
18819 	}
18820       /* now jbits < cbits */
18821       if ( jbits )
18822 	{
18823 	  c = (c << jbits) + (ival & ((1U << jbits)-1));
18824 	  cbits -= jbits;
18825 	}
18826     }
18827   if ( cbits != 8 ) lGrib[z++] = (GRIBPACK)(c << cbits);
18828 
18829   *gz = z;
18830 }
18831 
18832 
18833 static
TEMPLATE(encode_array_2byte,T)18834 void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
18835 				    const T *restrict data, T zref, T factor, size_t *gz)
18836 {
18837   U_BYTEORDER;
18838   uint16_t *restrict sgrib = (uint16_t *)(void *)(lGrib+*gz);
18839 
18840   if ( IS_BIGENDIAN() )
18841     {
18842       for ( size_t i = 0; i < datasize; i++ )
18843         sgrib[i] = (uint16_t)(CGRIBEX_FPSCALE(data[i]));
18844     }
18845   else
18846     {
18847       uint16_t ui16;
18848       for ( size_t i = 0; i < datasize; i++ )
18849         {
18850           ui16 = (uint16_t)(CGRIBEX_FPSCALE(data[i]));
18851           sgrib[i] = gribSwapByteOrder_uint16(ui16);
18852         }
18853     }
18854 
18855   *gz += 2*datasize;
18856 }
18857 /*
18858 static
18859 void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
18860 				    const T *restrict data, T zref, T factor, size_t *gz)
18861 {
18862   size_t i, z = *gz;
18863   uint16_t ui16;
18864   T tmp;
18865 
18866 #if   defined (CRAY)
18867 #pragma _CRI ivdep
18868 #elif defined (SX)
18869 #pragma vdir nodep
18870 #elif defined (__uxp__)
18871 #pragma loop novrec
18872 #elif defined (__ICC)
18873 #pragma ivdep
18874 #endif
18875   for ( i = 0; i < datasize; i++ )
18876     {
18877       tmp = CGRIBEX_FPSCALE(data[i]);
18878       ui16 = (uint16_t) tmp;
18879       lGrib[z  ] = ui16 >>  8;
18880       lGrib[z+1] = ui16;
18881       z += 2;
18882     }
18883 
18884   *gz = z;
18885 }
18886 */
18887 static
TEMPLATE(encode_array,T)18888 void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize,
18889 			      GRIBPACK *restrict lGrib,
18890 			      const T *restrict data,
18891 			      T zref, T factor, size_t *gz)
18892 {
18893 #if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
18894   uint64_t start_minmax, end_minmax;
18895 #endif
18896   uint32_t ui32;
18897   size_t i, z = *gz;
18898   T tmp;
18899 
18900   data += packStart;
18901   datasize -= packStart;
18902 
18903   if      ( numBits ==  8 )
18904     {
18905 #ifdef _GET_IBM_COUNTER
18906       hpmStart(2, "pack 8 bit base");
18907 #endif
18908 
18909 #if defined (CRAY)
18910 #pragma _CRI ivdep
18911 #elif defined (SX)
18912 #pragma vdir nodep
18913 #elif defined (__uxp__)
18914 #pragma loop novrec
18915 #elif defined (__ICC)
18916 #pragma ivdep
18917 #endif
18918       for ( i = 0; i < datasize; i++ )
18919 	{
18920           tmp = CGRIBEX_FPSCALE(data[i]);
18921 	  lGrib[z  ] = (GRIBPACK)tmp;
18922           z++;
18923 	}
18924 
18925 #ifdef _GET_IBM_COUNTER
18926       hpmStop(2);
18927 #endif
18928     }
18929   else if ( numBits == 16 )
18930     {
18931 #ifdef _GET_IBM_COUNTER
18932       hpmStart(3, "pack 16 bit base");
18933 #elif defined _GET_X86_COUNTER
18934       start_minmax = _rdtsc();
18935 #elif defined _GET_MACH_COUNTER
18936       start_minmax = mach_absolute_time();
18937 #endif
18938       if ( sizeof(T) == sizeof(double) )
18939       	{
18940           grib_encode_array_2byte_double(datasize, lGrib, (const double *)(const void *)data, zref, factor, &z);
18941         }
18942       else
18943         {
18944           TEMPLATE(encode_array_2byte,T)(datasize, lGrib, data, zref, factor, &z);
18945         }
18946 
18947 #if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
18948 #if defined _GET_X86_COUNTER
18949       end_minmax = _rdtsc();
18950 #elif defined _GET_MACH_COUNTER
18951       end_minmax = mach_absolute_time();
18952 #endif
18953 #if defined _ENABLE_AVX
18954       printf("AVX encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
18955 #elif defined _ENABLE_SSE4_1
18956       printf("SSE 4.1 encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
18957 #else
18958       printf("loop encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
18959 #endif
18960 #endif
18961 
18962 #ifdef _GET_IBM_COUNTER
18963       hpmStop(3);
18964 #endif
18965     }
18966   else if ( numBits == 24 )
18967     {
18968 #ifdef _GET_IBM_COUNTER
18969       hpmStart(4, "pack 24 bit base");
18970 #endif
18971 
18972 #if   defined (CRAY)
18973 #pragma _CRI ivdep
18974 #elif defined (SX)
18975 #pragma vdir nodep
18976 #elif defined (__uxp__)
18977 #pragma loop novrec
18978 #elif defined (__ICC)
18979 #pragma ivdep
18980 #endif
18981       for ( i = 0; i < datasize; i++ )
18982 	{
18983           tmp = CGRIBEX_FPSCALE(data[i]);
18984           ui32 = (uint32_t) tmp;
18985           lGrib[z  ] =  (GRIBPACK)(ui32 >> 16);
18986           lGrib[z+1] =  (GRIBPACK)(ui32 >>  8);
18987           lGrib[z+2] =  (GRIBPACK)ui32;
18988           z += 3;
18989 	}
18990 
18991 #ifdef _GET_IBM_COUNTER
18992       hpmStop(4);
18993 #endif
18994     }
18995   else if ( numBits == 32 )
18996     {
18997 #ifdef _GET_IBM_COUNTER
18998       hpmStart(5, "pack 32 bit base");
18999 #endif
19000 
19001 #if   defined (CRAY)
19002 #pragma _CRI ivdep
19003 #elif defined (SX)
19004 #pragma vdir nodep
19005 #elif defined (__uxp__)
19006 #pragma loop novrec
19007 #elif defined (__ICC)
19008 #pragma ivdep
19009 #endif
19010       for ( i = 0; i < datasize; i++ )
19011 	{
19012           tmp = CGRIBEX_FPSCALE(data[i]);
19013           ui32 = (uint32_t) tmp;
19014           lGrib[z  ] =  (GRIBPACK)(ui32 >> 24);
19015           lGrib[z+1] =  (GRIBPACK)(ui32 >> 16);
19016           lGrib[z+2] =  (GRIBPACK)(ui32 >>  8);
19017           lGrib[z+3] =  (GRIBPACK)ui32;
19018           z += 4;
19019 	}
19020 
19021 #ifdef _GET_IBM_COUNTER
19022       hpmStop(5);
19023 #endif
19024     }
19025   else if ( numBits > 0 && numBits <= 32 )
19026     {
19027       TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
19028     }
19029   else if ( numBits == 0 )
19030     {
19031     }
19032   else
19033     {
19034       Error("Unimplemented packing factor %d!", numBits);
19035     }
19036 
19037   *gz = z;
19038 }
19039 
19040 static
TEMPLATE(encode_array_unrolled,T)19041 void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t datasize,
19042 				       GRIBPACK *restrict lGrib,
19043 				       const T *restrict data,
19044 				       T zref, T factor, size_t *gz)
19045 {
19046   U_BYTEORDER;
19047   size_t i, j, z = *gz;
19048 #ifdef _ARCH_PWR6
19049   enum { CGRIBEX__UNROLL_DEPTH_2 = 8 };
19050 #else
19051   enum { CGRIBEX__UNROLL_DEPTH_2 = 128 };
19052 #endif
19053   size_t residual;
19054   size_t ofs;
19055   T dval[CGRIBEX__UNROLL_DEPTH_2];
19056 
19057   data += packStart;
19058   datasize -= packStart;
19059   residual =  datasize % CGRIBEX__UNROLL_DEPTH_2;
19060   ofs = datasize - residual;
19061 
19062   // reducing FP operations to single FMA is slowing down on pwr6 ...
19063 
19064   if      ( numBits ==  8 )
19065     {
19066 #ifdef _GET_IBM_COUNTER
19067       hpmStart(2, "pack 8 bit unrolled");
19068 #endif
19069       unsigned char *cgrib = (unsigned char *) (lGrib + z);
19070       for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
19071 	{
19072 	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
19073 	    {
19074 	      dval[j] = CGRIBEX_FPSCALE(data[i+j]);
19075 	    }
19076 	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
19077 	    {
19078 #ifdef _ARCH_PWR6
19079 	      *cgrib++ =  (unsigned long) dval[j];
19080 #else
19081 	      *cgrib++ =  (unsigned char) dval[j];
19082 #endif
19083 	    }
19084 	  z += CGRIBEX__UNROLL_DEPTH_2;
19085 	}
19086       for (j = 0; j < residual; j++)
19087 	{
19088 	  dval[j] = CGRIBEX_FPSCALE(data[i+j]);
19089 	}
19090       for (j = 0; j < residual; j++)
19091 	{
19092 #ifdef _ARCH_PWR6
19093 	  *cgrib++ = (unsigned long) dval[j];
19094 #else
19095 	  *cgrib++ = (unsigned char) dval[j];
19096 #endif
19097 	}
19098       z += residual;
19099 
19100 #ifdef _GET_IBM_COUNTER
19101       hpmStop(2);
19102 #endif
19103     }
19104   else if ( numBits == 16 )
19105     {
19106 #ifdef _GET_IBM_COUNTER
19107       hpmStart(3, "pack 16 bit unrolled");
19108 #endif
19109 #ifdef _ARCH_PWR6
19110       unsigned long ival;
19111 #else
19112       uint16_t ival;
19113 #endif
19114       uint16_t *sgrib = (uint16_t *)(void *)(lGrib+z);
19115 
19116       for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
19117 	{
19118 	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
19119 	    dval[j] = CGRIBEX_FPSCALE(data[j]);
19120 	  if ( IS_BIGENDIAN() )
19121 	    {
19122 	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
19123 		{
19124 #ifdef _ARCH_PWR6
19125 		  *sgrib++ = (unsigned long) dval[j];
19126 #else
19127 		  *sgrib++ = (uint16_t) dval[j];
19128 #endif
19129 		}
19130 	      z += 2*CGRIBEX__UNROLL_DEPTH_2;
19131 	    }
19132 	  else
19133 	    {
19134 	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
19135 		{
19136 		  ival = (uint16_t) dval[j];
19137                   *sgrib++ = gribSwapByteOrder_uint16(ival);
19138 		}
19139 	      z += 2*CGRIBEX__UNROLL_DEPTH_2;
19140 	    }
19141 	}
19142       for (j = 0; j < residual; j++)
19143 	{
19144 	  dval[j] = CGRIBEX_FPSCALE(data[j]);
19145 	}
19146       if ( IS_BIGENDIAN() )
19147 	{
19148 	  for (j = 0; j < residual; j++)
19149 	    {
19150 #ifdef _ARCH_PWR6
19151 	      *sgrib++ = (unsigned long) dval[j];
19152 #else
19153               *sgrib++ = (uint16_t) dval[j];
19154 #endif
19155 	    }
19156 	  z += 2*residual;
19157 	}
19158       else
19159 	{
19160 	  for (j = 0; j < residual; j++)
19161 	    {
19162               ival = (uint16_t) dval[j];
19163 	      lGrib[z  ] = (GRIBPACK)(ival >>  8);
19164 	      lGrib[z+1] = (GRIBPACK)ival;
19165 	      z += 2;
19166 	    }
19167 	}
19168 #ifdef _GET_IBM_COUNTER
19169       hpmStop(3);
19170 #endif
19171     }
19172   else if ( numBits == 24 )
19173     {
19174 #ifdef _GET_IBM_COUNTER
19175       hpmStart(4, "pack 24 bit unrolled");
19176 #endif
19177 #ifdef _ARCH_PWR6
19178       unsigned long ival;
19179 #else
19180       uint32_t ival;
19181 #endif
19182       for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
19183 	{
19184 	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
19185 	    {
19186 	      dval[j] = CGRIBEX_FPSCALE(data[j]);
19187 	    }
19188 	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
19189 	    {
19190 #ifdef _ARCH_PWR6
19191 	      ival = (unsigned long) dval[j];
19192 #else
19193 	      ival = (uint32_t) dval[j];
19194 #endif
19195 	      lGrib[z  ] =  (GRIBPACK)(ival >> 16);
19196 	      lGrib[z+1] =  (GRIBPACK)(ival >>  8);
19197 	      lGrib[z+2] =  (GRIBPACK)ival;
19198 	      z += 3;
19199 	    }
19200 	}
19201       for (j = 0; j < residual; j++)
19202 	{
19203 	  dval[j] = CGRIBEX_FPSCALE(data[j]);
19204 	}
19205       for (j = 0; j < residual; j++)
19206 	{
19207 	  ival = (uint32_t) dval[j];
19208 	  lGrib[z  ] =  (GRIBPACK)(ival >> 16);
19209 	  lGrib[z+1] =  (GRIBPACK)(ival >>  8);
19210 	  lGrib[z+2] =  (GRIBPACK)ival;
19211 	  z += 3;
19212 	}
19213 #ifdef _GET_IBM_COUNTER
19214       hpmStop(4);
19215 #endif
19216     }
19217   else if ( numBits == 32 )
19218     {
19219 #ifdef _GET_IBM_COUNTER
19220       hpmStart(5, "pack 32 bit unrolled");
19221 #endif
19222 #ifdef _ARCH_PWR6
19223       unsigned long ival;
19224 #else
19225       uint32_t ival;
19226 #endif
19227       unsigned int *igrib = (unsigned int *)(void *)(lGrib + z);
19228       for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
19229         {
19230 	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
19231             dval[j] = CGRIBEX_FPSCALE(data[i+j]);
19232 	  if ( IS_BIGENDIAN() )
19233 	    {
19234 	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
19235 		{
19236 #ifdef _ARCH_PWR6
19237 		  *igrib = (unsigned long) dval[j];
19238 #else
19239 		  *igrib = (uint32_t) dval[j];
19240 #endif
19241 		  igrib++;
19242 		  z += 4;
19243 		}
19244 	    }
19245 	  else
19246 	    {
19247 	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
19248 		{
19249                   ival = (uint32_t) dval[j];
19250 		  lGrib[z  ] =  (GRIBPACK)(ival >> 24);
19251 		  lGrib[z+1] =  (GRIBPACK)(ival >> 16);
19252 		  lGrib[z+2] =  (GRIBPACK)(ival >>  8);
19253 		  lGrib[z+3] =  (GRIBPACK)ival;
19254 		  z += 4;
19255 		}
19256 	    }
19257 	}
19258       for (j = 0; j < residual; j++)
19259 	{
19260           dval[j] = CGRIBEX_FPSCALE(data[ofs+j]);
19261 	}
19262       if ( IS_BIGENDIAN() )
19263 	{
19264 	  for (j = 0; j < residual; j++)
19265 	    {
19266 #ifdef _ARCH_PWR6
19267 	      *igrib = (unsigned long) dval[j];
19268 #else
19269 	      *igrib = (uint32_t) dval[j];
19270 #endif
19271 	      igrib++;
19272 	      z += 4;
19273 	    }
19274 	}
19275       else
19276 	{
19277           for (j = 0; j < residual; j++)
19278 	    {
19279 	      ival = (uint32_t) dval[j];
19280 	      lGrib[z  ] =  (GRIBPACK)(ival >> 24);
19281 	      lGrib[z+1] =  (GRIBPACK)(ival >> 16);
19282 	      lGrib[z+2] =  (GRIBPACK)(ival >>  8);
19283 	      lGrib[z+3] =  (GRIBPACK)ival;
19284 	      z += 4;
19285 	    }
19286 	}
19287 #ifdef _GET_IBM_COUNTER
19288       hpmStop(5);
19289 #endif
19290     }
19291   else if ( numBits > 0 && numBits <= 32 )
19292     {
19293       TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
19294     }
19295   else if ( numBits == 0 )
19296     {
19297     }
19298   else
19299     {
19300       Error("Unimplemented packing factor %d!", numBits);
19301     }
19302 
19303   *gz = z;
19304 }
19305 
19306 #endif /* T */
19307 
19308 /*
19309  * Local Variables:
19310  * mode: c
19311  * End:
19312  */
19313 
19314 
19315 #ifdef T
19316 #undef T
19317 #endif
19318 #define T double
19319 #ifdef T
19320 
19321 /* GRIB BLOCK 2 - GRID DESCRIPTION SECTION */
19322 static
TEMPLATE(encodeGDS,T)19323 void TEMPLATE(encodeGDS,T)(GRIBPACK *lGrib, long *gribLen, int *isec2, T *fsec2)
19324 {
19325   long z = *gribLen;
19326   int exponent, mantissa;
19327   int ival;
19328   int gdslen = 32;
19329 
19330   if ( ISEC2_GridType == GRIB1_GTYPE_LCC ) gdslen += 10;
19331 
19332   if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )  gdslen += 10;
19333 
19334   const int pvoffset = (ISEC2_NumVCP || ISEC2_Reduced) ? gdslen + 1 : 0xFF;
19335 
19336   if ( ISEC2_Reduced ) gdslen += 2 * ISEC2_NumLat;
19337 
19338   gdslen += ISEC2_NumVCP * 4;
19339 
19340   Put3Byte(gdslen);             /*  0- 2 Length of Block 2 Byte 0 */
19341   Put1Byte(ISEC2_NumVCP);       /*  3    NV */
19342   Put1Byte(pvoffset);           /*  4    PV */
19343   Put1Byte(ISEC2_GridType);     /*  5    LatLon=0 Gauss=4 Spectral=50 */
19344 
19345   if ( ISEC2_GridType == GRIB1_GTYPE_SPECTRAL )
19346     {
19347       Put2Byte(ISEC2_PentaJ);   /*  6- 7 Pentagonal resolution J  */
19348       Put2Byte(ISEC2_PentaK);   /*  8- 9 Pentagonal resolution K  */
19349       Put2Byte(ISEC2_PentaM);   /* 10-11 Pentagonal resolution M  */
19350       Put1Byte(ISEC2_RepType);  /* 12    Representation type      */
19351       Put1Byte(ISEC2_RepMode);  /* 13    Representation mode      */
19352       PutnZero(18);             /* 14-31 reserved                 */
19353     }
19354   else if ( ISEC2_GridType == GRIB1_GTYPE_GME )
19355     {
19356       Put2Byte(ISEC2_GME_NI2);
19357       Put2Byte(ISEC2_GME_NI3);
19358       Put3Byte(ISEC2_GME_ND);
19359       Put3Byte(ISEC2_GME_NI);
19360       Put1Byte(ISEC2_GME_AFlag);
19361       Put3Int(ISEC2_GME_LatPP);
19362       Put3Int(ISEC2_GME_LonPP);
19363       Put3Int(ISEC2_GME_LonMPL);
19364       Put1Byte(ISEC2_GME_BFlag);
19365       PutnZero(5);
19366     }
19367   else if ( ISEC2_GridType == GRIB1_GTYPE_LCC )
19368     {
19369       Put2Byte(ISEC2_NumLon);          /*  6- 7 Longitudes               */
19370 
19371       Put2Byte(ISEC2_NumLat);          /*  8- 9 Latitudes                */
19372       Put3Int(ISEC2_FirstLat);
19373       Put3Int(ISEC2_FirstLon);
19374       Put1Byte(ISEC2_ResFlag);         /* 16    Resolution flag          */
19375       Put3Int(ISEC2_Lambert_Lov);      /* 17-19 */
19376       Put3Int(ISEC2_Lambert_dx);       /* 20-22 */
19377       Put3Int(ISEC2_Lambert_dy);       /* 23-25 */
19378       Put1Byte(ISEC2_Lambert_ProjFlag);/* 26    Projection flag          */
19379       Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
19380       Put3Int(ISEC2_Lambert_LatS1);    /* 28-30 */
19381       Put3Int(ISEC2_Lambert_LatS2);    /* 31-33 */
19382       Put3Int(ISEC2_Lambert_LatSP);    /* 34-36 */
19383       Put3Int(ISEC2_Lambert_LonSP);    /* 37-39 */
19384       PutnZero(2);                     /* 34-41 */
19385     }
19386   else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
19387 	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
19388 	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
19389     {
19390       const int numlon = ISEC2_Reduced ? 0xFFFF : ISEC2_NumLon;
19391       Put2Byte(numlon);                /*  6- 7 Number of Longitudes     */
19392 
19393       Put2Byte(ISEC2_NumLat);          /*  8- 9 Number of Latitudes      */
19394       Put3Int(ISEC2_FirstLat);
19395       Put3Int(ISEC2_FirstLon);
19396       Put1Byte(ISEC2_ResFlag);         /* 16    Resolution flag          */
19397       Put3Int(ISEC2_LastLat);
19398       Put3Int(ISEC2_LastLon);
19399       const unsigned lonIncr = (ISEC2_ResFlag == 0) ? 0xFFFF : (unsigned)ISEC2_LonIncr;
19400       const unsigned latIncr = (ISEC2_ResFlag == 0) ? 0xFFFF : (unsigned)ISEC2_LatIncr;
19401       Put2Byte(lonIncr);               /* 23-24 i - direction increment  */
19402       if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN )
19403 	Put2Byte(ISEC2_NumPar);        /* 25-26 Latitudes Pole->Equator  */
19404       else
19405 	Put2Byte(latIncr);             /* 25-26 j - direction increment  */
19406 
19407       Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
19408       PutnZero(4);                     /* 28-31 reserved                 */
19409 
19410       if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
19411 	{
19412 	  Put3Int(ISEC2_LatSP);
19413 	  Put3Int(ISEC2_LonSP);
19414 	  Put1Real((double)(FSEC2_RotAngle));
19415 	}
19416     }
19417   else
19418     {
19419       Error("Unsupported grid type %d", ISEC2_GridType);
19420     }
19421 
19422 #if defined (SX)
19423 #pragma vdir novector     /* vectorization gives wrong results on NEC */
19424 #endif
19425   for ( long i = 0; i < ISEC2_NumVCP; ++i )
19426     {
19427       Put1Real((double)(fsec2[10+i]));
19428     }
19429 
19430   if ( ISEC2_Reduced )
19431     for ( long i = 0; i < ISEC2_NumLat; i++ ) Put2Byte(ISEC2_ReducedPoints(i));
19432 
19433   *gribLen = z;
19434 }
19435 
19436 /* GRIB BLOCK 3 - BIT MAP SECTION */
19437 static
TEMPLATE(encodeBMS,T)19438 void TEMPLATE(encodeBMS,T)(GRIBPACK *lGrib, long *gribLen, T *fsec3, int *isec4, T *data, long *datasize)
19439 {
19440   long z = *gribLen;
19441   static bool lmissvalinfo = true;
19442   //  unsigned int c, imask;
19443 
19444   if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo)
19445     {
19446       lmissvalinfo = false;
19447       Message("Missing value = NaN is unsupported!");
19448     }
19449 
19450   const long bitmapSize = ISEC4_NumValues;
19451   const long imaskSize = ((bitmapSize+7)>>3)<<3;
19452   GRIBPACK *bitmap = &lGrib[z+6];
19453   long fsec4size = 0;
19454 
19455 #ifdef VECTORCODE
19456   unsigned int *imask = (unsigned int*) Malloc(imaskSize*sizeof(unsigned int));
19457   memset(imask, 0, imaskSize*sizeof(int));
19458 
19459 #if defined (CRAY)
19460 #pragma _CRI ivdep
19461 #endif
19462 #if defined (SX)
19463 #pragma vdir nodep
19464 #endif
19465 #ifdef __uxpch__
19466 #pragma loop novrec
19467 #endif
19468   for ( long i = 0; i < bitmapSize; i++ )
19469     {
19470       if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
19471 	{
19472 	  data[fsec4size++] = data[i];
19473 	  imask[i] = 1;
19474 	}
19475     }
19476 
19477 #if defined (CRAY)
19478 #pragma _CRI ivdep
19479 #endif
19480 #if defined (SX)
19481 #pragma vdir nodep
19482 #endif
19483 #ifdef __uxpch__
19484 #pragma loop novrec
19485 #endif
19486   for ( long i = 0; i < imaskSize/8; i++ )
19487     {
19488       bitmap[i] = (imask[i*8+0] << 7) | (imask[i*8+1] << 6) |
19489 	          (imask[i*8+2] << 5) | (imask[i*8+3] << 4) |
19490 	          (imask[i*8+4] << 3) | (imask[i*8+5] << 2) |
19491 	          (imask[i*8+6] << 1) | (imask[i*8+7]);
19492     }
19493 
19494   Free(imask);
19495 #else
19496   for ( long i = 0; i < imaskSize/8; i++ ) bitmap[i] = 0;
19497 
19498   for ( long i = 0; i < bitmapSize; i++ )
19499     {
19500       if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
19501 	{
19502 	  data[fsec4size++] = data[i];
19503 	  bitmap[i/8] |= (GRIBPACK)(1<<(7-(i&7)));
19504 	}
19505     }
19506 #endif
19507 
19508   const long bmsLen = imaskSize/8 + 6;
19509   const long bmsUnusedBits = imaskSize - bitmapSize;
19510 
19511   Put3Byte(bmsLen);   /*  0- 2 Length of Block 3 Byte 0 */
19512   Put1Byte(bmsUnusedBits);
19513   Put2Byte(0);
19514 
19515   *gribLen += bmsLen;
19516 
19517   *datasize = fsec4size;
19518 }
19519 
19520 #define pow_double pow
19521 #define pow_float powf
19522 
19523 /* GRIB BLOCK 4 - BINARY DATA SECTION */
19524 static
TEMPLATE(encodeBDS,T)19525 int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *isec2, int *isec4, long datasize, T *data,
19526 			  long *datstart, long *datsize, int code)
19527 {
19528   // Uwe Schulzweida, 11/04/2003 : Check that number of bits per value is not exceeded
19529   // Uwe Schulzweida,  6/05/2003 : Copy result to fpval to prevent integer overflow
19530 
19531   size_t z = (size_t)*gribLen;
19532   int numBits;
19533   int ival;
19534   long PackStart = 0;
19535   int Flag = 0;
19536   int binscale = 0;
19537   int bds_head = 11;
19538   int bds_ext = 0;
19539   /* ibits = BitsPerInt; */
19540   int exponent, mantissa;
19541   bool lspherc = false;
19542   int isubset = 0, itemp = 0, itrunc = 0;
19543   T factor = 1, fmin, fmax;
19544   const double jpepsln = 1.0e-12; // -----> tolerance used to check equality
19545                                   //        of floating point numbers - needed
19546 		                  //        on some platforms (eg vpp700, linux)
19547   extern int CGRIBEX_Const;       // 1: Don't pack constant fields on regular grids
19548 
19549   if ( isec2 )
19550     {
19551       /* If section 2 is present, it says if data is spherical harmonic */
19552 
19553       lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
19554                    isec2[0] == 70 || isec2[0] == 80 );
19555 
19556       isec4[2] = lspherc ? 128 : 0;
19557     }
19558   else
19559     {
19560       /* Section 4 says if it's spherical harmonic data.. */
19561 
19562       lspherc = ( isec4[2] == 128 );
19563     }
19564 
19565   /* Complex packing supported for spherical harmonics. */
19566 
19567   const bool lcomplex = ( lspherc && ( isec4[3] == 64 ) ) ||
19568                        ( lspherc && isec2 && ( isec2[5] == 2 ) );
19569 
19570   /* Check input specification is consistent */
19571 
19572   if ( lcomplex && isec2 )
19573     {
19574       if ( ( isec4[3] != 64 ) && ( isec2[5] == 2 ) )
19575 	{
19576 	  gprintf(__func__, "  COMPLEX mismatch. isec4[3] = %d\n", isec4[3]);
19577 	  gprintf(__func__, "  COMPLEX mismatch. isec2[5] = %d\n", isec2[5]);
19578 	  return (807);
19579 	}
19580       else if ( ( isec4[3] == 64 ) && ( isec2[5] != 2 ) )
19581 	{
19582 	  gprintf(__func__, "  COMPLEX mismatch. isec4[3] = %d\n", isec4[3]);
19583 	  gprintf(__func__, "  COMPLEX mismatch. isec2[5] = %d\n", isec2[5]);
19584 	  return (807);
19585         }
19586       else if ( lcomplex )
19587 	{
19588 	  /*
19589 	    Truncation of full spectrum, which is supposed triangular,
19590 	    has to be diagnosed. Define also sub-set truncation.
19591 	  */
19592 	  isubset = isec4[17];
19593 	  // When encoding, use the total number of data.
19594 	  itemp   = isec4[0];
19595 	  itrunc  = (int) (sqrt(itemp*4 + 1.) - 3) / 2;
19596 	}
19597     }
19598 
19599   if ( decscale )
19600     {
19601       const T scale = TEMPLATE(pow,T)((T)10.0, (T)decscale);
19602       for ( long i = 0; i < datasize; ++i ) data[i] *= scale;
19603     }
19604 
19605   if ( lspherc )
19606     {
19607       if ( lcomplex )
19608 	{
19609 	  const int jup  = isubset;
19610 	  const int ioff = (jup+1)*(jup+2);
19611 	  bds_ext = 4 + 3 + 4*ioff;
19612 	  PackStart = ioff;
19613 	  Flag = 192;
19614 	}
19615       else
19616 	{
19617 	  bds_ext = 4;
19618 	  PackStart = 1;
19619 	  Flag = 128;
19620 	}
19621     }
19622 
19623   *datstart = bds_head + bds_ext;
19624 
19625   int nbpv = numBits = ISEC4_NumBits;
19626 
19627   if ( lspherc && lcomplex )
19628     {
19629       const int pcStart = isubset;
19630       const int pcScale = isec4[16];
19631       TEMPLATE(scale_complex,T)(data, pcStart, pcScale, itrunc, 0);
19632       TEMPLATE(gather_complex,T)(data, (size_t)pcStart, (size_t)itrunc, (size_t)datasize);
19633     }
19634 
19635   fmin = fmax = data[PackStart];
19636 
19637   TEMPLATE(minmax_val,T)(data+PackStart, datasize-PackStart, &fmin, &fmax);
19638 
19639   double zref = (double)fmin;
19640   if (!(zref < DBL_MAX && zref > -DBL_MAX))
19641     {
19642       gprintf(__func__, "Minimum value out of range: %g!", zref);
19643       return (707);
19644     }
19645 
19646   if ( CGRIBEX_Const && !lspherc )
19647     {
19648       if ( IS_EQUAL(fmin, fmax) ) nbpv = 0;
19649     }
19650 
19651   long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
19652   blockLength += blockLength & 1;
19653 
19654   const long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
19655 
19656   Flag += unused_bits;
19657 
19658 
19659   /*
19660     Adjust number of bits per value if full integer length to avoid hitting most significant bit (sign bit).
19661   */
19662   // if( nbpv == ibits ) nbpv = nbpv - 1;
19663   /*
19664     Calculate the binary scaling factor to spread the range of values over the number of bits per value.
19665     Limit scaling to 2**-126 to 2**127 (using IEEE 32-bit floatsas a guideline).
19666   */
19667   const double range = fabs(fmax - fmin);
19668 
19669   if ( fabs(fmin) < FLT_MIN ) fmin = 0;
19670   /*
19671     Have to allow tolerance in comparisons on some platforms (eg vpp700 and linux),
19672     such as 0.9999999999999999 = 1.0, to avoid clipping ranges which are a power of 2.
19673   */
19674   if ( range <= jpepsln )
19675     {
19676       binscale = 0;
19677     }
19678   else if ( IS_NOT_EQUAL(fmin, 0.0) && (fabs(range/fmin) <= jpepsln) )
19679     {
19680       binscale = 0;
19681     }
19682   else if ( fabs(range-1.0) <= jpepsln )
19683     {
19684       binscale = 1 - nbpv;
19685     }
19686   else if ( range > 1.0 )
19687     {
19688       const double rangec = range + jpepsln;
19689       double p2 = 2.0;
19690       int jloop = 1;
19691       while ( jloop < 128 && p2 <= rangec )
19692         {
19693           p2 *= 2.0;
19694           ++jloop;
19695         }
19696       if (jloop < 128)
19697         binscale = jloop - nbpv;
19698       else
19699         {
19700           gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
19701           gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
19702           return (707);
19703         }
19704     }
19705   else
19706     {
19707       const double rangec = range - jpepsln;
19708       double p05 = 0.5;
19709       int jloop = 1;
19710       while ( jloop < 127 && p05 >= rangec )
19711 	{
19712           p05 *= 0.5;
19713           jloop++;
19714 	}
19715       if ( jloop < 127 )
19716 	{
19717 	  binscale = 1 - jloop - nbpv;
19718 	}
19719       else
19720 	{
19721 	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
19722 	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
19723 	  return (707);
19724 	}
19725     }
19726 
19727   const uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
19728 
19729   if ( binscale != 0 )
19730     {
19731       while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
19732 
19733       factor = (T)intpow2(-binscale);
19734     }
19735 
19736   ref2ibm(&zref, BitsPerInt);
19737 
19738   Put3Byte(blockLength);      //  0-2 Length of Block 4
19739   Put1Byte(Flag);             //  3   Flag & Unused bits
19740   if ( binscale < 0 ) binscale = 32768 - binscale;
19741   Put2Byte(binscale);         //  4-5 Scale factor
19742   Put1Real(zref);             //  6-9 Reference value
19743   Put1Byte(nbpv);             //   10 Packing size
19744 
19745   if ( lspherc )
19746     {
19747       if ( lcomplex )
19748 	{
19749 	  const int jup = isubset;
19750 	  int ioff = (int)z + bds_ext;
19751 	  if ( ioff > 0xFFFF ) ioff = 0;
19752 	  Put2Byte(ioff);
19753 	  Put2Int(isec4[16]);
19754 	  Put1Byte(jup);
19755 	  Put1Byte(jup);
19756 	  Put1Byte(jup);
19757 	  for ( long i = 0; i < ((jup+1)*(jup+2)); i++ ) Put1Real((double)(data[i]));
19758 	}
19759       else
19760 	{
19761 	  Put1Real((double)(data[0]));
19762 	}
19763     }
19764 
19765   *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
19766 
19767 #if  defined  (_ARCH_PWR6)
19768   TEMPLATE(encode_array_unrolled,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
19769 #else
19770   TEMPLATE(encode_array,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
19771 #endif
19772 
19773   if ( unused_bits >= 8 ) Put1Byte(0);  //  Fillbyte
19774 
19775   *gribLen = (long)z;
19776 
19777   return 0;
19778 }
19779 
19780 
TEMPLATE(grib_encode,T)19781 void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *isec3,
19782 			     T *fsec3, int *isec4, T *fsec4, int klenp, int *kgrib,
19783 			     int kleng, int *kword, int efunc, int *kret)
19784 {
19785   long gribLen = 0; // Counter of GRIB length for output
19786   long fsec4size = 0;
19787   long datstart, datsize;
19788 
19789   UNUSED(isec3);
19790   UNUSED(efunc);
19791 
19792   grsdef();
19793 
19794   unsigned char *CGrib = (unsigned char *) kgrib;
19795 
19796   const bool gdsIncluded = ISEC1_Sec2Or3Flag & 128;
19797   const bool bmsIncluded = ISEC1_Sec2Or3Flag & 64;
19798 
19799   // set max header len
19800   size_t len = 16384;
19801 
19802   // add data len
19803   const size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
19804 
19805   len += numBytes*(size_t)klenp;
19806 
19807   // add bitmap len
19808   if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
19809 
19810 #ifdef VECTORCODE
19811   GRIBPACK *lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
19812   if ( lGrib == NULL ) SysError("No Memory!");
19813 #else
19814   GRIBPACK *lGrib = CGrib;
19815 #endif
19816 
19817   const long isLen = 8;
19818   encodeIS(lGrib, &gribLen);
19819   GRIBPACK *lpds = &lGrib[isLen];
19820   const long pdsLen = getPdsLen(isec1);
19821 
19822   encodePDS(lpds, pdsLen,  isec1);
19823   gribLen += pdsLen;
19824   /*
19825   if ( ( isec4[3] == 64 ) && ( isec2[5] == 2 ) )
19826     {
19827       static bool lwarn_cplx = true;
19828 
19829       if ( lwarn_cplx )
19830 	Message("Complex packing of spectral data unsupported, using simple packing!");
19831 
19832       isec2[5] = 1;
19833       isec4[3] = 0;
19834 
19835       lwarn_cplx = false;
19836     }
19837   */
19838   if ( gdsIncluded ) TEMPLATE(encodeGDS,T)(lGrib, &gribLen, isec2, fsec2);
19839   /*
19840     ----------------------------------------------------------------
19841     BMS Bit-Map Section Section (Section 3)
19842     ----------------------------------------------------------------
19843   */
19844   if ( bmsIncluded )
19845     {
19846       TEMPLATE(encodeBMS,T)(lGrib, &gribLen, fsec3, isec4, fsec4, &fsec4size);
19847     }
19848   else
19849     {
19850       fsec4size = ISEC4_NumValues;
19851     }
19852 
19853   const long bdsstart = gribLen;
19854   int status = TEMPLATE(encodeBDS,T)(lGrib, &gribLen, ISEC1_DecScaleFactor, isec2,
19855                                      isec4, fsec4size, fsec4, &datstart, &datsize, ISEC1_Parameter);
19856   if ( status )
19857     {
19858       *kret = status;
19859       return;
19860     }
19861 
19862   encodeES(lGrib, &gribLen, bdsstart);
19863 
19864   if ( (size_t) gribLen > (size_t)kleng*sizeof(int) )
19865     Error("kgrib buffer too small! kleng = %d  gribLen = %d", kleng, gribLen);
19866 
19867 #ifdef VECTORCODE
19868   if ( (size_t) gribLen > len )
19869     Error("lGrib buffer too small! len = %d  gribLen = %d", len, gribLen);
19870 
19871   (void) PACK_GRIB(lGrib, (unsigned char *)CGrib, gribLen, -1L);
19872 
19873   Free(lGrib);
19874 #endif
19875 
19876   ISEC0_GRIB_Len     = (int)gribLen;
19877   ISEC0_GRIB_Version = 1;
19878 
19879   *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
19880 
19881   *kret = status;
19882 }
19883 
19884 #endif /* T */
19885 
19886 /*
19887  * Local Variables:
19888  * mode: c
19889  * End:
19890  */
19891 
19892 #ifdef T
19893 #undef T
19894 #endif
19895 #define T float
19896 #ifdef T
19897 
19898 /* GRIB BLOCK 2 - GRID DESCRIPTION SECTION */
19899 static
TEMPLATE(encodeGDS,T)19900 void TEMPLATE(encodeGDS,T)(GRIBPACK *lGrib, long *gribLen, int *isec2, T *fsec2)
19901 {
19902   long z = *gribLen;
19903   int exponent, mantissa;
19904   int ival;
19905   int gdslen = 32;
19906 
19907   if ( ISEC2_GridType == GRIB1_GTYPE_LCC ) gdslen += 10;
19908 
19909   if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )  gdslen += 10;
19910 
19911   const int pvoffset = (ISEC2_NumVCP || ISEC2_Reduced) ? gdslen + 1 : 0xFF;
19912 
19913   if ( ISEC2_Reduced ) gdslen += 2 * ISEC2_NumLat;
19914 
19915   gdslen += ISEC2_NumVCP * 4;
19916 
19917   Put3Byte(gdslen);             /*  0- 2 Length of Block 2 Byte 0 */
19918   Put1Byte(ISEC2_NumVCP);       /*  3    NV */
19919   Put1Byte(pvoffset);           /*  4    PV */
19920   Put1Byte(ISEC2_GridType);     /*  5    LatLon=0 Gauss=4 Spectral=50 */
19921 
19922   if ( ISEC2_GridType == GRIB1_GTYPE_SPECTRAL )
19923     {
19924       Put2Byte(ISEC2_PentaJ);   /*  6- 7 Pentagonal resolution J  */
19925       Put2Byte(ISEC2_PentaK);   /*  8- 9 Pentagonal resolution K  */
19926       Put2Byte(ISEC2_PentaM);   /* 10-11 Pentagonal resolution M  */
19927       Put1Byte(ISEC2_RepType);  /* 12    Representation type      */
19928       Put1Byte(ISEC2_RepMode);  /* 13    Representation mode      */
19929       PutnZero(18);             /* 14-31 reserved                 */
19930     }
19931   else if ( ISEC2_GridType == GRIB1_GTYPE_GME )
19932     {
19933       Put2Byte(ISEC2_GME_NI2);
19934       Put2Byte(ISEC2_GME_NI3);
19935       Put3Byte(ISEC2_GME_ND);
19936       Put3Byte(ISEC2_GME_NI);
19937       Put1Byte(ISEC2_GME_AFlag);
19938       Put3Int(ISEC2_GME_LatPP);
19939       Put3Int(ISEC2_GME_LonPP);
19940       Put3Int(ISEC2_GME_LonMPL);
19941       Put1Byte(ISEC2_GME_BFlag);
19942       PutnZero(5);
19943     }
19944   else if ( ISEC2_GridType == GRIB1_GTYPE_LCC )
19945     {
19946       Put2Byte(ISEC2_NumLon);          /*  6- 7 Longitudes               */
19947 
19948       Put2Byte(ISEC2_NumLat);          /*  8- 9 Latitudes                */
19949       Put3Int(ISEC2_FirstLat);
19950       Put3Int(ISEC2_FirstLon);
19951       Put1Byte(ISEC2_ResFlag);         /* 16    Resolution flag          */
19952       Put3Int(ISEC2_Lambert_Lov);      /* 17-19 */
19953       Put3Int(ISEC2_Lambert_dx);       /* 20-22 */
19954       Put3Int(ISEC2_Lambert_dy);       /* 23-25 */
19955       Put1Byte(ISEC2_Lambert_ProjFlag);/* 26    Projection flag          */
19956       Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
19957       Put3Int(ISEC2_Lambert_LatS1);    /* 28-30 */
19958       Put3Int(ISEC2_Lambert_LatS2);    /* 31-33 */
19959       Put3Int(ISEC2_Lambert_LatSP);    /* 34-36 */
19960       Put3Int(ISEC2_Lambert_LonSP);    /* 37-39 */
19961       PutnZero(2);                     /* 34-41 */
19962     }
19963   else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
19964 	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
19965 	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
19966     {
19967       const int numlon = ISEC2_Reduced ? 0xFFFF : ISEC2_NumLon;
19968       Put2Byte(numlon);                /*  6- 7 Number of Longitudes     */
19969 
19970       Put2Byte(ISEC2_NumLat);          /*  8- 9 Number of Latitudes      */
19971       Put3Int(ISEC2_FirstLat);
19972       Put3Int(ISEC2_FirstLon);
19973       Put1Byte(ISEC2_ResFlag);         /* 16    Resolution flag          */
19974       Put3Int(ISEC2_LastLat);
19975       Put3Int(ISEC2_LastLon);
19976       const unsigned lonIncr = (ISEC2_ResFlag == 0) ? 0xFFFF : (unsigned)ISEC2_LonIncr;
19977       const unsigned latIncr = (ISEC2_ResFlag == 0) ? 0xFFFF : (unsigned)ISEC2_LatIncr;
19978       Put2Byte(lonIncr);               /* 23-24 i - direction increment  */
19979       if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN )
19980 	Put2Byte(ISEC2_NumPar);        /* 25-26 Latitudes Pole->Equator  */
19981       else
19982 	Put2Byte(latIncr);             /* 25-26 j - direction increment  */
19983 
19984       Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
19985       PutnZero(4);                     /* 28-31 reserved                 */
19986 
19987       if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
19988 	{
19989 	  Put3Int(ISEC2_LatSP);
19990 	  Put3Int(ISEC2_LonSP);
19991 	  Put1Real((double)(FSEC2_RotAngle));
19992 	}
19993     }
19994   else
19995     {
19996       Error("Unsupported grid type %d", ISEC2_GridType);
19997     }
19998 
19999 #if defined (SX)
20000 #pragma vdir novector     /* vectorization gives wrong results on NEC */
20001 #endif
20002   for ( long i = 0; i < ISEC2_NumVCP; ++i )
20003     {
20004       Put1Real((double)(fsec2[10+i]));
20005     }
20006 
20007   if ( ISEC2_Reduced )
20008     for ( long i = 0; i < ISEC2_NumLat; i++ ) Put2Byte(ISEC2_ReducedPoints(i));
20009 
20010   *gribLen = z;
20011 }
20012 
20013 /* GRIB BLOCK 3 - BIT MAP SECTION */
20014 static
TEMPLATE(encodeBMS,T)20015 void TEMPLATE(encodeBMS,T)(GRIBPACK *lGrib, long *gribLen, T *fsec3, int *isec4, T *data, long *datasize)
20016 {
20017   long z = *gribLen;
20018   static bool lmissvalinfo = true;
20019   //  unsigned int c, imask;
20020 
20021   if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo)
20022     {
20023       lmissvalinfo = false;
20024       Message("Missing value = NaN is unsupported!");
20025     }
20026 
20027   const long bitmapSize = ISEC4_NumValues;
20028   const long imaskSize = ((bitmapSize+7)>>3)<<3;
20029   GRIBPACK *bitmap = &lGrib[z+6];
20030   long fsec4size = 0;
20031 
20032 #ifdef VECTORCODE
20033   unsigned int *imask = (unsigned int*) Malloc(imaskSize*sizeof(unsigned int));
20034   memset(imask, 0, imaskSize*sizeof(int));
20035 
20036 #if defined (CRAY)
20037 #pragma _CRI ivdep
20038 #endif
20039 #if defined (SX)
20040 #pragma vdir nodep
20041 #endif
20042 #ifdef __uxpch__
20043 #pragma loop novrec
20044 #endif
20045   for ( long i = 0; i < bitmapSize; i++ )
20046     {
20047       if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
20048 	{
20049 	  data[fsec4size++] = data[i];
20050 	  imask[i] = 1;
20051 	}
20052     }
20053 
20054 #if defined (CRAY)
20055 #pragma _CRI ivdep
20056 #endif
20057 #if defined (SX)
20058 #pragma vdir nodep
20059 #endif
20060 #ifdef __uxpch__
20061 #pragma loop novrec
20062 #endif
20063   for ( long i = 0; i < imaskSize/8; i++ )
20064     {
20065       bitmap[i] = (imask[i*8+0] << 7) | (imask[i*8+1] << 6) |
20066 	          (imask[i*8+2] << 5) | (imask[i*8+3] << 4) |
20067 	          (imask[i*8+4] << 3) | (imask[i*8+5] << 2) |
20068 	          (imask[i*8+6] << 1) | (imask[i*8+7]);
20069     }
20070 
20071   Free(imask);
20072 #else
20073   for ( long i = 0; i < imaskSize/8; i++ ) bitmap[i] = 0;
20074 
20075   for ( long i = 0; i < bitmapSize; i++ )
20076     {
20077       if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
20078 	{
20079 	  data[fsec4size++] = data[i];
20080 	  bitmap[i/8] |= (GRIBPACK)(1<<(7-(i&7)));
20081 	}
20082     }
20083 #endif
20084 
20085   const long bmsLen = imaskSize/8 + 6;
20086   const long bmsUnusedBits = imaskSize - bitmapSize;
20087 
20088   Put3Byte(bmsLen);   /*  0- 2 Length of Block 3 Byte 0 */
20089   Put1Byte(bmsUnusedBits);
20090   Put2Byte(0);
20091 
20092   *gribLen += bmsLen;
20093 
20094   *datasize = fsec4size;
20095 }
20096 
20097 #define pow_double pow
20098 #define pow_float powf
20099 
20100 /* GRIB BLOCK 4 - BINARY DATA SECTION */
20101 static
TEMPLATE(encodeBDS,T)20102 int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *isec2, int *isec4, long datasize, T *data,
20103 			  long *datstart, long *datsize, int code)
20104 {
20105   // Uwe Schulzweida, 11/04/2003 : Check that number of bits per value is not exceeded
20106   // Uwe Schulzweida,  6/05/2003 : Copy result to fpval to prevent integer overflow
20107 
20108   size_t z = (size_t)*gribLen;
20109   int numBits;
20110   int ival;
20111   long PackStart = 0;
20112   int Flag = 0;
20113   int binscale = 0;
20114   int bds_head = 11;
20115   int bds_ext = 0;
20116   /* ibits = BitsPerInt; */
20117   int exponent, mantissa;
20118   bool lspherc = false;
20119   int isubset = 0, itemp = 0, itrunc = 0;
20120   T factor = 1, fmin, fmax;
20121   const double jpepsln = 1.0e-12; // -----> tolerance used to check equality
20122                                   //        of floating point numbers - needed
20123 		                  //        on some platforms (eg vpp700, linux)
20124   extern int CGRIBEX_Const;       // 1: Don't pack constant fields on regular grids
20125 
20126   if ( isec2 )
20127     {
20128       /* If section 2 is present, it says if data is spherical harmonic */
20129 
20130       lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
20131                    isec2[0] == 70 || isec2[0] == 80 );
20132 
20133       isec4[2] = lspherc ? 128 : 0;
20134     }
20135   else
20136     {
20137       /* Section 4 says if it's spherical harmonic data.. */
20138 
20139       lspherc = ( isec4[2] == 128 );
20140     }
20141 
20142   /* Complex packing supported for spherical harmonics. */
20143 
20144   const bool lcomplex = ( lspherc && ( isec4[3] == 64 ) ) ||
20145                        ( lspherc && isec2 && ( isec2[5] == 2 ) );
20146 
20147   /* Check input specification is consistent */
20148 
20149   if ( lcomplex && isec2 )
20150     {
20151       if ( ( isec4[3] != 64 ) && ( isec2[5] == 2 ) )
20152 	{
20153 	  gprintf(__func__, "  COMPLEX mismatch. isec4[3] = %d\n", isec4[3]);
20154 	  gprintf(__func__, "  COMPLEX mismatch. isec2[5] = %d\n", isec2[5]);
20155 	  return (807);
20156 	}
20157       else if ( ( isec4[3] == 64 ) && ( isec2[5] != 2 ) )
20158 	{
20159 	  gprintf(__func__, "  COMPLEX mismatch. isec4[3] = %d\n", isec4[3]);
20160 	  gprintf(__func__, "  COMPLEX mismatch. isec2[5] = %d\n", isec2[5]);
20161 	  return (807);
20162         }
20163       else if ( lcomplex )
20164 	{
20165 	  /*
20166 	    Truncation of full spectrum, which is supposed triangular,
20167 	    has to be diagnosed. Define also sub-set truncation.
20168 	  */
20169 	  isubset = isec4[17];
20170 	  // When encoding, use the total number of data.
20171 	  itemp   = isec4[0];
20172 	  itrunc  = (int) (sqrt(itemp*4 + 1.) - 3) / 2;
20173 	}
20174     }
20175 
20176   if ( decscale )
20177     {
20178       const T scale = TEMPLATE(pow,T)((T)10.0, (T)decscale);
20179       for ( long i = 0; i < datasize; ++i ) data[i] *= scale;
20180     }
20181 
20182   if ( lspherc )
20183     {
20184       if ( lcomplex )
20185 	{
20186 	  const int jup  = isubset;
20187 	  const int ioff = (jup+1)*(jup+2);
20188 	  bds_ext = 4 + 3 + 4*ioff;
20189 	  PackStart = ioff;
20190 	  Flag = 192;
20191 	}
20192       else
20193 	{
20194 	  bds_ext = 4;
20195 	  PackStart = 1;
20196 	  Flag = 128;
20197 	}
20198     }
20199 
20200   *datstart = bds_head + bds_ext;
20201 
20202   int nbpv = numBits = ISEC4_NumBits;
20203 
20204   if ( lspherc && lcomplex )
20205     {
20206       const int pcStart = isubset;
20207       const int pcScale = isec4[16];
20208       TEMPLATE(scale_complex,T)(data, pcStart, pcScale, itrunc, 0);
20209       TEMPLATE(gather_complex,T)(data, (size_t)pcStart, (size_t)itrunc, (size_t)datasize);
20210     }
20211 
20212   fmin = fmax = data[PackStart];
20213 
20214   TEMPLATE(minmax_val,T)(data+PackStart, datasize-PackStart, &fmin, &fmax);
20215 
20216   double zref = (double)fmin;
20217   if (!(zref < DBL_MAX && zref > -DBL_MAX))
20218     {
20219       gprintf(__func__, "Minimum value out of range: %g!", zref);
20220       return (707);
20221     }
20222 
20223   if ( CGRIBEX_Const && !lspherc )
20224     {
20225       if ( IS_EQUAL(fmin, fmax) ) nbpv = 0;
20226     }
20227 
20228   long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
20229   blockLength += blockLength & 1;
20230 
20231   const long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
20232 
20233   Flag += unused_bits;
20234 
20235 
20236   /*
20237     Adjust number of bits per value if full integer length to avoid hitting most significant bit (sign bit).
20238   */
20239   // if( nbpv == ibits ) nbpv = nbpv - 1;
20240   /*
20241     Calculate the binary scaling factor to spread the range of values over the number of bits per value.
20242     Limit scaling to 2**-126 to 2**127 (using IEEE 32-bit floatsas a guideline).
20243   */
20244   const double range = fabs(fmax - fmin);
20245 
20246   if ( fabs(fmin) < FLT_MIN ) fmin = 0;
20247   /*
20248     Have to allow tolerance in comparisons on some platforms (eg vpp700 and linux),
20249     such as 0.9999999999999999 = 1.0, to avoid clipping ranges which are a power of 2.
20250   */
20251   if ( range <= jpepsln )
20252     {
20253       binscale = 0;
20254     }
20255   else if ( IS_NOT_EQUAL(fmin, 0.0) && (fabs(range/fmin) <= jpepsln) )
20256     {
20257       binscale = 0;
20258     }
20259   else if ( fabs(range-1.0) <= jpepsln )
20260     {
20261       binscale = 1 - nbpv;
20262     }
20263   else if ( range > 1.0 )
20264     {
20265       const double rangec = range + jpepsln;
20266       double p2 = 2.0;
20267       int jloop = 1;
20268       while ( jloop < 128 && p2 <= rangec )
20269         {
20270           p2 *= 2.0;
20271           ++jloop;
20272         }
20273       if (jloop < 128)
20274         binscale = jloop - nbpv;
20275       else
20276         {
20277           gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
20278           gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
20279           return (707);
20280         }
20281     }
20282   else
20283     {
20284       const double rangec = range - jpepsln;
20285       double p05 = 0.5;
20286       int jloop = 1;
20287       while ( jloop < 127 && p05 >= rangec )
20288 	{
20289           p05 *= 0.5;
20290           jloop++;
20291 	}
20292       if ( jloop < 127 )
20293 	{
20294 	  binscale = 1 - jloop - nbpv;
20295 	}
20296       else
20297 	{
20298 	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
20299 	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
20300 	  return (707);
20301 	}
20302     }
20303 
20304   const uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
20305 
20306   if ( binscale != 0 )
20307     {
20308       while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
20309 
20310       factor = (T)intpow2(-binscale);
20311     }
20312 
20313   ref2ibm(&zref, BitsPerInt);
20314 
20315   Put3Byte(blockLength);      //  0-2 Length of Block 4
20316   Put1Byte(Flag);             //  3   Flag & Unused bits
20317   if ( binscale < 0 ) binscale = 32768 - binscale;
20318   Put2Byte(binscale);         //  4-5 Scale factor
20319   Put1Real(zref);             //  6-9 Reference value
20320   Put1Byte(nbpv);             //   10 Packing size
20321 
20322   if ( lspherc )
20323     {
20324       if ( lcomplex )
20325 	{
20326 	  const int jup = isubset;
20327 	  int ioff = (int)z + bds_ext;
20328 	  if ( ioff > 0xFFFF ) ioff = 0;
20329 	  Put2Byte(ioff);
20330 	  Put2Int(isec4[16]);
20331 	  Put1Byte(jup);
20332 	  Put1Byte(jup);
20333 	  Put1Byte(jup);
20334 	  for ( long i = 0; i < ((jup+1)*(jup+2)); i++ ) Put1Real((double)(data[i]));
20335 	}
20336       else
20337 	{
20338 	  Put1Real((double)(data[0]));
20339 	}
20340     }
20341 
20342   *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
20343 
20344 #if  defined  (_ARCH_PWR6)
20345   TEMPLATE(encode_array_unrolled,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
20346 #else
20347   TEMPLATE(encode_array,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
20348 #endif
20349 
20350   if ( unused_bits >= 8 ) Put1Byte(0);  //  Fillbyte
20351 
20352   *gribLen = (long)z;
20353 
20354   return 0;
20355 }
20356 
20357 
TEMPLATE(grib_encode,T)20358 void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *isec3,
20359 			     T *fsec3, int *isec4, T *fsec4, int klenp, int *kgrib,
20360 			     int kleng, int *kword, int efunc, int *kret)
20361 {
20362   long gribLen = 0; // Counter of GRIB length for output
20363   long fsec4size = 0;
20364   long datstart, datsize;
20365 
20366   UNUSED(isec3);
20367   UNUSED(efunc);
20368 
20369   grsdef();
20370 
20371   unsigned char *CGrib = (unsigned char *) kgrib;
20372 
20373   const bool gdsIncluded = ISEC1_Sec2Or3Flag & 128;
20374   const bool bmsIncluded = ISEC1_Sec2Or3Flag & 64;
20375 
20376   // set max header len
20377   size_t len = 16384;
20378 
20379   // add data len
20380   const size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
20381 
20382   len += numBytes*(size_t)klenp;
20383 
20384   // add bitmap len
20385   if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
20386 
20387 #ifdef VECTORCODE
20388   GRIBPACK *lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
20389   if ( lGrib == NULL ) SysError("No Memory!");
20390 #else
20391   GRIBPACK *lGrib = CGrib;
20392 #endif
20393 
20394   const long isLen = 8;
20395   encodeIS(lGrib, &gribLen);
20396   GRIBPACK *lpds = &lGrib[isLen];
20397   const long pdsLen = getPdsLen(isec1);
20398 
20399   encodePDS(lpds, pdsLen,  isec1);
20400   gribLen += pdsLen;
20401   /*
20402   if ( ( isec4[3] == 64 ) && ( isec2[5] == 2 ) )
20403     {
20404       static bool lwarn_cplx = true;
20405 
20406       if ( lwarn_cplx )
20407 	Message("Complex packing of spectral data unsupported, using simple packing!");
20408 
20409       isec2[5] = 1;
20410       isec4[3] = 0;
20411 
20412       lwarn_cplx = false;
20413     }
20414   */
20415   if ( gdsIncluded ) TEMPLATE(encodeGDS,T)(lGrib, &gribLen, isec2, fsec2);
20416   /*
20417     ----------------------------------------------------------------
20418     BMS Bit-Map Section Section (Section 3)
20419     ----------------------------------------------------------------
20420   */
20421   if ( bmsIncluded )
20422     {
20423       TEMPLATE(encodeBMS,T)(lGrib, &gribLen, fsec3, isec4, fsec4, &fsec4size);
20424     }
20425   else
20426     {
20427       fsec4size = ISEC4_NumValues;
20428     }
20429 
20430   const long bdsstart = gribLen;
20431   int status = TEMPLATE(encodeBDS,T)(lGrib, &gribLen, ISEC1_DecScaleFactor, isec2,
20432                                      isec4, fsec4size, fsec4, &datstart, &datsize, ISEC1_Parameter);
20433   if ( status )
20434     {
20435       *kret = status;
20436       return;
20437     }
20438 
20439   encodeES(lGrib, &gribLen, bdsstart);
20440 
20441   if ( (size_t) gribLen > (size_t)kleng*sizeof(int) )
20442     Error("kgrib buffer too small! kleng = %d  gribLen = %d", kleng, gribLen);
20443 
20444 #ifdef VECTORCODE
20445   if ( (size_t) gribLen > len )
20446     Error("lGrib buffer too small! len = %d  gribLen = %d", len, gribLen);
20447 
20448   (void) PACK_GRIB(lGrib, (unsigned char *)CGrib, gribLen, -1L);
20449 
20450   Free(lGrib);
20451 #endif
20452 
20453   ISEC0_GRIB_Len     = (int)gribLen;
20454   ISEC0_GRIB_Version = 1;
20455 
20456   *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
20457 
20458   *kret = status;
20459 }
20460 
20461 #endif /* T */
20462 
20463 /*
20464  * Local Variables:
20465  * mode: c
20466  * End:
20467  */
20468 
20469 void encode_dummy(void);
encode_dummy(void)20470 void encode_dummy(void)
20471 {
20472   (void) encode_array_unrolled_double(0, 0, 0, NULL, NULL, 0, 0, NULL);
20473   (void) encode_array_unrolled_float(0, 0, 0, NULL, NULL, 0, 0, NULL);
20474 }
20475 static const char grb_libvers[] = "1.9.5";
20476 const char *
cgribexLibraryVersion(void)20477 cgribexLibraryVersion(void)
20478 {
20479   return (grb_libvers);
20480 }
20481 
20482 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
20483 #pragma GCC diagnostic pop
20484 #endif
20485 
20486 #ifdef HAVE_CONFIG_H
20487 #endif
20488 
20489 #include <inttypes.h>
20490 #include <stdlib.h>
20491 #include <sys/types.h>
20492 #ifdef WORDS_BIGENDIAN
20493 #include <limits.h>
20494 #endif
20495 
20496 
20497 static const uint32_t crctab[] = {
20498   0x00000000,
20499   0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
20500   0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
20501   0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
20502   0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
20503   0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
20504   0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
20505   0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
20506   0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
20507   0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
20508   0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
20509   0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
20510   0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
20511   0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
20512   0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
20513   0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
20514   0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
20515   0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
20516   0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
20517   0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
20518   0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
20519   0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
20520   0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
20521   0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
20522   0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
20523   0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
20524   0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
20525   0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
20526   0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
20527   0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
20528   0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
20529   0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
20530   0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
20531   0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
20532   0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
20533   0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
20534   0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
20535   0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
20536   0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
20537   0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
20538   0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
20539   0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
20540   0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
20541   0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
20542   0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
20543   0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
20544   0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
20545   0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
20546   0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
20547   0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
20548   0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
20549   0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
20550 };
20551 
20552 
20553 uint32_t
memcrc(const unsigned char * b,size_t n)20554 memcrc(const unsigned char *b, size_t n)
20555 {
20556 /*  Input arguments:
20557  *  const char*   b == byte sequence to checksum
20558  *  size_t        n == length of sequence
20559  */
20560 
20561 
20562   uint32_t s = 0;
20563 
20564   memcrc_r(&s, b, n);
20565 
20566   /* Extend with the length of the string. */
20567   while (n != 0) {
20568     register uint32_t c = n & 0377;
20569     n >>= 8;
20570     s = (s << 8) ^ crctab[(s >> 24) ^ c];
20571   }
20572 
20573 
20574   return ~s;
20575 }
20576 
20577 void
memcrc_r(uint32_t * state,const unsigned char * block,size_t block_len)20578 memcrc_r(uint32_t *state, const unsigned char *block, size_t block_len)
20579 {
20580 /*  Input arguments:
20581  *  const char*   b == byte sequence to checksum
20582  *  size_t        n == length of sequence
20583  */
20584 
20585 
20586   register uint32_t c, s = *state;
20587   register size_t n = block_len;
20588   register const unsigned char *b = block;
20589 
20590   for (; n > 0; --n) {
20591     c = (uint32_t)(*b++);
20592     s = (s << 8) ^ crctab[(s >> 24) ^ c];
20593   }
20594 
20595   *state = s;
20596 }
20597 
20598 #ifdef WORDS_BIGENDIAN
20599 #define SWAP_CSUM(BITWIDTH,BYTEWIDTH,NACC)                              \
20600   do {                                                                  \
20601     register const uint##BITWIDTH##_t *b = (uint##BITWIDTH##_t *)elems; \
20602     for (size_t i = 0; i < num_elems; ++i) {                            \
20603       for(size_t aofs = NACC; aofs > 0; --aofs) {                       \
20604         uint##BITWIDTH##_t accum = b[i + aofs - 1];                     \
20605         for (size_t j = 0; j < BYTEWIDTH; ++j) {                        \
20606           uint32_t c = (uint32_t)(accum & UCHAR_MAX);                   \
20607           s = (s << 8) ^ crctab[(s >> 24) ^ c];                         \
20608           accum >>= 8;                                                  \
20609         }                                                               \
20610       }                                                                 \
20611     }                                                                   \
20612   } while (0)
20613 #endif
20614 
20615 
20616 /**
20617  *  Does endian-swapping prior to checksumming in case platform is big-endian
20618  *
20619  *  @param elems points to first first element with alignment elem_size
20620  *  @param num_elems number of elements to process
20621  *  @param elem_size size of each element in bytes
20622  */
20623 void
memcrc_r_eswap(uint32_t * state,const unsigned char * elems,size_t num_elems,size_t elem_size)20624 memcrc_r_eswap(uint32_t *state, const unsigned char *elems, size_t num_elems,
20625                size_t elem_size)
20626 {
20627 #ifdef WORDS_BIGENDIAN
20628   register uint32_t s = *state;
20629 
20630   switch (elem_size)
20631   {
20632   case 1:
20633     memcrc_r(state, elems, num_elems * elem_size);
20634     return;
20635   case 2:
20636     SWAP_CSUM(16,2,1);
20637     break;
20638   case 4:
20639     SWAP_CSUM(32,4,1);
20640     break;
20641   case 8:
20642     SWAP_CSUM(64,8,1);
20643     break;
20644   case 16:
20645     SWAP_CSUM(64,8,2);
20646     break;
20647   }
20648   *state = s;
20649 #else
20650   memcrc_r(state, elems, num_elems * elem_size);
20651 #endif
20652 }
20653 
20654 
20655 uint32_t
memcrc_finish(uint32_t * state,off_t total_size)20656 memcrc_finish(uint32_t *state, off_t total_size)
20657 {
20658   register uint32_t c, s = *state;
20659   register uint64_t n = (uint64_t)total_size;
20660 
20661   /* Extend with the length of the string. */
20662   while (n != 0) {
20663     c = n & 0377;
20664     n >>= 8;
20665     s = (s << 8) ^ crctab[(s >> 24) ^ c];
20666   }
20667 
20668   return ~s;
20669 }
20670 
20671 /*
20672  * Local Variables:
20673  * c-file-style: "Java"
20674  * c-basic-offset: 2
20675  * indent-tabs-mode: nil
20676  * show-trailing-whitespace: t
20677  * require-trailing-newline: t
20678  * End:
20679  */
20680 #ifdef HAVE_CONFIG_H
20681 #endif
20682 
20683 #include <stdio.h>
20684 #include <string.h>
20685 #include <stdlib.h>
20686 #include <ctype.h>
20687 #include <stdarg.h>
20688 #include <errno.h>
20689 
20690 #if !defined(HAVE_CONFIG_H) && !defined(HAVE_MALLOC_H) && defined(SX)
20691 #  define  HAVE_MALLOC_H
20692 #endif
20693 
20694 #if  defined(HAVE_MALLOC_H)
20695 #  include <malloc.h>
20696 #endif
20697 
20698 
20699 enum             {MALLOC_FUNC=0, CALLOC_FUNC, REALLOC_FUNC, FREE_FUNC};
20700 static const char *memfunc[] = {"Malloc", "Calloc", "Realloc", "Free"};
20701 
20702 #undef   MEM_UNDEFID
20703 #define  MEM_UNDEFID  -1
20704 
20705 #define  MEM_MAXNAME  32   /* Min = 8, for  "unknown" ! */
20706 
20707 static int dmemory_ExitOnError = 1;
20708 
20709 typedef struct
20710 {
20711   void     *ptr;
20712   size_t    size;
20713   size_t    nobj;
20714   int       item;
20715   int       mtype;
20716   int       line;
20717   char      filename[MEM_MAXNAME];
20718   char      functionname[MEM_MAXNAME];
20719 }
20720 MemTable_t;
20721 
20722 static MemTable_t *memTable;
20723 static size_t  memTableSize  = 0;
20724 static long    memAccess     = 0;
20725 
20726 static size_t  MemObjs       = 0;
20727 static size_t  MaxMemObjs    = 0;
20728 static size_t  MemUsed       = 0;
20729 static size_t  MaxMemUsed    = 0;
20730 
20731 static int     MEM_Debug     = 0;   /* If set to 1, debugging */
20732 static int     MEM_Info      = 0;   /* If set to 1, print mem table at exit */
20733 
20734 static
get_filename(const char * file)20735 const char *get_filename(const char *file)
20736 {
20737   const char *fnptr = strrchr(file, '/');
20738   if ( fnptr ) fnptr++;
20739   else         fnptr = (char *) file;
20740 
20741   return fnptr;
20742 }
20743 
20744 
memDebug(int debug)20745 void memDebug(int debug)
20746 {
20747   MEM_Debug = debug;
20748 }
20749 
20750 /* If we're not using GNU C, elide __attribute__ */
20751 #if ! defined __GNUC__ && ! defined __attribute__
20752 #  define  __attribute__(x)  /*NOTHING*/
20753 #endif
20754 
20755 static
20756 void memInternalProblem(const char *caller, const char *fmt, ...)
20757   __attribute__((noreturn));
20758 static
20759 void memError(const char *caller, const char *file, int line, size_t size)
20760   __attribute__((noreturn));
20761 
20762 static
memInternalProblem(const char * functionname,const char * fmt,...)20763 void memInternalProblem(const char *functionname, const char *fmt, ...)
20764 {
20765   va_list args;
20766 
20767   va_start(args, fmt);
20768 
20769   printf("\n");
20770    fprintf(stderr, "Internal problem (%s) : ", functionname);
20771   vfprintf(stderr, fmt, args);
20772    fprintf(stderr, "\n");
20773 
20774   va_end(args);
20775 
20776   exit(EXIT_FAILURE);
20777 }
20778 
20779 static
memError(const char * functionname,const char * file,int line,size_t size)20780 void memError(const char *functionname, const char *file, int line, size_t size)
20781 {
20782   fputs("\n", stdout);
20783   fprintf(stderr, "Error (%s) : Allocation of %zu bytes failed. [ line %d file %s ]\n",
20784 	  functionname, size, line, get_filename(file));
20785 
20786   if ( errno ) perror("System error message ");
20787 
20788   exit(EXIT_FAILURE);
20789 }
20790 
20791 static
memListPrintEntry(int mtype,int item,size_t size,void * ptr,const char * functionname,const char * file,int line)20792 void memListPrintEntry(int mtype, int item, size_t size, void *ptr,
20793 		       const char *functionname, const char *file, int line)
20794 {
20795   fprintf(stderr, "[%-7s ", memfunc[mtype]);
20796 
20797   fprintf(stderr, "memory item %3d ", item);
20798   fprintf(stderr, "(%6zu byte) ", size);
20799   fprintf(stderr, "at %p", ptr);
20800   if ( file != NULL )
20801     {
20802       fprintf(stderr, " line %4d", line);
20803       fprintf(stderr, " file %s", get_filename(file));
20804     }
20805   if ( functionname != NULL )
20806     fprintf(stderr, " (%s)", functionname);
20807   fprintf(stderr, "]\n");
20808 }
20809 
20810 static
memListPrintTable(void)20811 void memListPrintTable(void)
20812 {
20813   if ( MemObjs ) fprintf(stderr, "\nMemory table:\n");
20814 
20815   for ( size_t memID = 0; memID < memTableSize; memID++ )
20816     {
20817       if ( memTable[memID].item != MEM_UNDEFID )
20818         memListPrintEntry(memTable[memID].mtype, memTable[memID].item,
20819                           memTable[memID].size*memTable[memID].nobj,
20820                           memTable[memID].ptr, memTable[memID].functionname,
20821                           memTable[memID].filename, memTable[memID].line);
20822     }
20823 
20824   if ( MemObjs )
20825     {
20826       fprintf(stderr, "  Memory access             : %6u\n", (unsigned) memAccess);
20827       fprintf(stderr, "  Maximum objects           : %6zu\n", memTableSize);
20828       fprintf(stderr, "  Objects used              : %6u\n", (unsigned) MaxMemObjs);
20829       fprintf(stderr, "  Objects in use            : %6u\n", (unsigned) MemObjs);
20830       fprintf(stderr, "  Memory allocated          : ");
20831       if (MemUsed > 1024*1024*1024)
20832 	fprintf(stderr, " %5d GB\n",   (int) (MemUsed/(1024*1024*1024)));
20833       else if (MemUsed > 1024*1024)
20834 	fprintf(stderr, " %5d MB\n",   (int) (MemUsed/(1024*1024)));
20835       else if (MemUsed > 1024)
20836 	fprintf(stderr, " %5d KB\n",   (int) (MemUsed/(1024)));
20837       else
20838 	fprintf(stderr, " %5d Byte\n", (int)  MemUsed);
20839     }
20840 
20841   if ( MaxMemUsed )
20842     {
20843       fprintf(stderr, "  Maximum memory allocated  : ");
20844       if (MaxMemUsed > 1024*1024*1024)
20845 	fprintf(stderr, " %5d GB\n",   (int) (MaxMemUsed/(1024*1024*1024)));
20846       else if (MaxMemUsed > 1024*1024)
20847 	fprintf(stderr, " %5d MB\n",   (int) (MaxMemUsed/(1024*1024)));
20848       else if (MaxMemUsed > 1024)
20849 	fprintf(stderr, " %5d KB\n",   (int) (MaxMemUsed/(1024)));
20850       else
20851 	fprintf(stderr, " %5d Byte\n", (int)  MaxMemUsed);
20852     }
20853 }
20854 
20855 static
memGetDebugLevel(void)20856 void memGetDebugLevel(void)
20857 {
20858   const char *envstr;
20859 
20860   envstr = getenv("MEMORY_INFO");
20861   if ( envstr && isdigit((int) envstr[0]) ) MEM_Info = atoi(envstr);
20862 
20863   envstr = getenv("MEMORY_DEBUG");
20864   if ( envstr && isdigit((int) envstr[0]) ) MEM_Debug = atoi(envstr);
20865 
20866   if ( MEM_Debug && !MEM_Info ) MEM_Info = 1;
20867 
20868   if ( MEM_Info ) atexit(memListPrintTable);
20869 }
20870 
20871 static
memInit(void)20872 void memInit(void)
20873 {
20874   static int initDebugLevel = 0;
20875 
20876   if ( ! initDebugLevel )
20877     {
20878       memGetDebugLevel();
20879       initDebugLevel = 1;
20880     }
20881 }
20882 
20883 static
memListDeleteEntry(void * ptr,size_t * size)20884 int memListDeleteEntry(void *ptr, size_t *size)
20885 {
20886   int item = MEM_UNDEFID;
20887   size_t memID;
20888 
20889   for ( memID = 0; memID < memTableSize; memID++ )
20890     {
20891       if ( memTable[memID].item == MEM_UNDEFID ) continue;
20892       if ( memTable[memID].ptr == ptr ) break;
20893     }
20894 
20895   if ( memID != memTableSize )
20896     {
20897       MemObjs--;
20898       MemUsed -= memTable[memID].size * memTable[memID].nobj;
20899       *size = memTable[memID].size * memTable[memID].nobj;
20900       item = memTable[memID].item;
20901       memTable[memID].item = MEM_UNDEFID;
20902     }
20903 
20904   return item;
20905 }
20906 
20907 static
memTableInitEntry(size_t memID)20908 void memTableInitEntry(size_t memID)
20909 {
20910   if ( memID >= memTableSize )
20911     memInternalProblem(__func__, "memID %d undefined!", memID);
20912 
20913   memTable[memID].ptr    = NULL;
20914   memTable[memID].item   = MEM_UNDEFID;
20915   memTable[memID].size   = 0;
20916   memTable[memID].nobj   = 0;
20917   memTable[memID].mtype  = MEM_UNDEFID;
20918   memTable[memID].line   = MEM_UNDEFID;
20919 }
20920 
20921 static
memListNewEntry(int mtype,void * ptr,size_t size,size_t nobj,const char * functionname,const char * file,int line)20922 int memListNewEntry(int mtype, void *ptr, size_t size, size_t nobj,
20923 		    const char *functionname, const char *file, int line)
20924 {
20925   static int item = 0;
20926   size_t memID = 0;
20927 
20928   /*
20929     Look for a free slot in memTable.
20930     (Create the table the first time through).
20931   */
20932   if ( memTableSize == 0 )
20933     {
20934       memTableSize = 8;
20935       size_t memSize = memTableSize * sizeof(MemTable_t);
20936       memTable = (MemTable_t *) malloc(memSize);
20937       if( memTable == NULL ) memError(__func__, __FILE__, __LINE__, memSize);
20938 
20939       for ( size_t i = 0; i < memTableSize; i++ )
20940 	memTableInitEntry(i);
20941     }
20942   else
20943     {
20944       while ( memID < memTableSize )
20945 	{
20946 	  if ( memTable[memID].item == MEM_UNDEFID ) break;
20947 	  memID++;
20948 	}
20949     }
20950   /*
20951     If the table overflows, double its size.
20952   */
20953   if ( memID == memTableSize )
20954     {
20955       memTableSize = 2*memTableSize;
20956       size_t memSize = memTableSize*sizeof(MemTable_t);
20957       memTable = (MemTable_t*) realloc(memTable, memSize);
20958       if ( memTable == NULL ) memError(__func__, __FILE__, __LINE__, memSize);
20959 
20960       for ( size_t i = memID; i < memTableSize; i++ )
20961 	memTableInitEntry(i);
20962     }
20963 
20964   memTable[memID].item  = item;
20965   memTable[memID].ptr   = ptr;
20966   memTable[memID].size  = size;
20967   memTable[memID].nobj  = nobj;
20968   memTable[memID].mtype = mtype;
20969   memTable[memID].line  = line;
20970 
20971   if ( file )
20972     {
20973       const char *filename = get_filename(file);
20974       size_t len = strlen(filename);
20975       if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
20976 
20977       (void) memcpy(memTable[memID].filename, filename, len);
20978       memTable[memID].filename[len] = '\0';
20979     }
20980   else
20981     {
20982       (void) strcpy(memTable[memID].filename, "unknown");
20983     }
20984 
20985   if ( functionname )
20986     {
20987       size_t len = strlen(functionname);
20988       if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
20989 
20990       (void) memcpy(memTable[memID].functionname, functionname, len);
20991       memTable[memID].functionname[len] = '\0';
20992     }
20993   else
20994     {
20995       (void) strcpy(memTable[memID].functionname, "unknown");
20996     }
20997 
20998   MaxMemObjs++;
20999   MemObjs++;
21000   MemUsed += size*nobj;
21001   if ( MemUsed > MaxMemUsed ) MaxMemUsed = MemUsed;
21002 
21003   return item++;
21004 }
21005 
21006 static
memListChangeEntry(void * ptrold,void * ptr,size_t size,const char * functionname,const char * file,int line)21007 int memListChangeEntry(void *ptrold, void *ptr, size_t size,
21008 		       const char *functionname, const char *file, int line)
21009 {
21010   int item = MEM_UNDEFID;
21011   size_t memID = 0;
21012 
21013   while( memID < memTableSize )
21014     {
21015       if ( memTable[memID].item != MEM_UNDEFID )
21016 	if ( memTable[memID].ptr == ptrold ) break;
21017       memID++;
21018     }
21019 
21020   if ( memID == memTableSize )
21021     {
21022       if ( ptrold != NULL )
21023 	memInternalProblem(__func__, "Item at %p not found.", ptrold);
21024     }
21025   else
21026     {
21027       item = memTable[memID].item;
21028 
21029       size_t sizeold = memTable[memID].size*memTable[memID].nobj;
21030 
21031       memTable[memID].ptr   = ptr;
21032       memTable[memID].size  = size;
21033       memTable[memID].nobj  = 1;
21034       memTable[memID].mtype = REALLOC_FUNC;
21035       memTable[memID].line  = line;
21036 
21037       if ( file )
21038 	{
21039           const char *filename = get_filename(file);
21040 	  size_t len = strlen(filename);
21041 	  if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
21042 
21043 	  (void) memcpy(memTable[memID].filename, filename, len);
21044 	  memTable[memID].filename[len] = '\0';
21045 	}
21046       else
21047 	{
21048 	  (void) strcpy(memTable[memID].filename, "unknown");
21049 	}
21050 
21051       if ( functionname )
21052 	{
21053 	  size_t len = strlen(functionname);
21054 	  if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
21055 
21056 	  (void) memcpy(memTable[memID].functionname, functionname, len);
21057 	  memTable[memID].functionname[len] = '\0';
21058 	}
21059       else
21060 	{
21061 	  (void) strcpy(memTable[memID].functionname, "unknown");
21062 	}
21063 
21064       MemUsed -= sizeold;
21065       MemUsed += size;
21066       if ( MemUsed > MaxMemUsed ) MaxMemUsed = MemUsed;
21067     }
21068 
21069   return item;
21070 }
21071 
21072 
memCalloc(size_t nobjs,size_t size,const char * file,const char * functionname,int line)21073 void *memCalloc(size_t nobjs, size_t size, const char *file, const char *functionname, int line)
21074 {
21075   void *ptr = NULL;
21076 
21077   memInit();
21078 
21079   if ( nobjs*size > 0 )
21080     {
21081       ptr = calloc(nobjs, size);
21082 
21083       if ( MEM_Info )
21084 	{
21085 	  memAccess++;
21086 
21087           int item = MEM_UNDEFID;
21088 	  if ( ptr ) item = memListNewEntry(CALLOC_FUNC, ptr, size, nobjs, functionname, file, line);
21089 
21090 	  if ( MEM_Debug ) memListPrintEntry(CALLOC_FUNC, item, size*nobjs, ptr, functionname, file, line);
21091 	}
21092 
21093       if ( ptr == NULL && dmemory_ExitOnError )
21094 	memError(functionname, file, line, size*nobjs);
21095     }
21096   else
21097     fprintf(stderr, "Warning (%s) : Allocation of 0 bytes! [ line %d file %s ]\n", functionname, line, file);
21098 
21099   return ptr;
21100 }
21101 
21102 
memMalloc(size_t size,const char * file,const char * functionname,int line)21103 void *memMalloc(size_t size, const char *file, const char *functionname, int line)
21104 {
21105   void *ptr = NULL;
21106 
21107   memInit();
21108 
21109   if ( size > 0 )
21110     {
21111       ptr = malloc(size);
21112 
21113       if ( MEM_Info )
21114 	{
21115 	  memAccess++;
21116 
21117           int item = MEM_UNDEFID;
21118 	  if ( ptr ) item = memListNewEntry(MALLOC_FUNC, ptr, size, 1, functionname, file, line);
21119 
21120 	  if ( MEM_Debug ) memListPrintEntry(MALLOC_FUNC, item, size, ptr, functionname, file, line);
21121 	}
21122 
21123       if ( ptr == NULL && dmemory_ExitOnError )
21124 	memError(functionname, file, line, size);
21125     }
21126   else
21127     fprintf(stderr, "Warning (%s) : Allocation of 0 bytes! [ line %d file %s ]\n", functionname, line, file);
21128 
21129   return ptr;
21130 }
21131 
21132 
memRealloc(void * ptrold,size_t size,const char * file,const char * functionname,int line)21133 void *memRealloc(void *ptrold, size_t size, const char *file, const char *functionname, int line)
21134 {
21135   void *ptr = NULL;
21136 
21137   memInit();
21138 
21139   if ( size > 0 )
21140     {
21141       ptr = realloc(ptrold, size);
21142 
21143       if ( MEM_Info )
21144 	{
21145 	  memAccess++;
21146 
21147           int item = MEM_UNDEFID;
21148 	  if ( ptr )
21149 	    {
21150 	      item = memListChangeEntry(ptrold, ptr, size, functionname, file, line);
21151 
21152 	      if ( item == MEM_UNDEFID ) item = memListNewEntry(REALLOC_FUNC, ptr, size, 1, functionname, file, line);
21153 	    }
21154 
21155 	  if ( MEM_Debug ) memListPrintEntry(REALLOC_FUNC, item, size, ptr, functionname, file, line);
21156 	}
21157 
21158       if ( ptr == NULL && dmemory_ExitOnError )
21159 	memError(functionname, file, line, size);
21160     }
21161   else
21162     fprintf(stderr, "Warning (%s) : Allocation of 0 bytes! [ line %d file %s ]\n", functionname, line, get_filename(file));
21163 
21164   return ptr;
21165 }
21166 
21167 
memFree(void * ptr,const char * file,const char * functionname,int line)21168 void memFree(void *ptr, const char *file, const char *functionname, int line)
21169 {
21170   memInit();
21171 
21172   if ( MEM_Info )
21173     {
21174       int item;
21175       size_t size;
21176 
21177       if ( (item = memListDeleteEntry(ptr, &size)) >= 0 )
21178 	{
21179 	  if ( MEM_Debug ) memListPrintEntry(FREE_FUNC, item, size, ptr, functionname, file, line);
21180 	}
21181       else
21182 	{
21183 	  if ( ptr && MEM_Debug  )
21184 	    fprintf(stderr, "%s info: memory entry at %p not found. [line %4d file %s (%s)]\n",
21185 		    __func__, ptr, line, get_filename(file), functionname);
21186 	}
21187     }
21188 
21189   free(ptr);
21190 }
21191 
21192 
memTotal(void)21193 size_t memTotal(void)
21194 {
21195   size_t memtotal = 0;
21196 #if  defined  (HAVE_MALLINFO)
21197   struct mallinfo meminfo = mallinfo();
21198   if ( MEM_Debug )
21199     {
21200       fprintf(stderr, "arena      %8zu (non-mmapped space allocated from system)\n", (size_t)meminfo.arena);
21201       fprintf(stderr, "ordblks    %8zu (number of free chunks)\n", (size_t)meminfo.ordblks);
21202       fprintf(stderr, "smblks     %8zu (number of fastbin blocks)\n", (size_t) meminfo.smblks);
21203       fprintf(stderr, "hblks      %8zu (number of mmapped regions)\n", (size_t) meminfo.hblks);
21204       fprintf(stderr, "hblkhd     %8zu (space in mmapped regions)\n", (size_t) meminfo.hblkhd);
21205       fprintf(stderr, "usmblks    %8zu (maximum total allocated space)\n", (size_t) meminfo.usmblks);
21206       fprintf(stderr, "fsmblks    %8zu (maximum total allocated space)\n", (size_t) meminfo.fsmblks);
21207       fprintf(stderr, "uordblks   %8zu (total allocated space)\n", (size_t) meminfo.uordblks);
21208       fprintf(stderr, "fordblks   %8zu (total free space)\n", (size_t) meminfo.fordblks);
21209       fprintf(stderr, "Memory in use:   %8zu bytes\n", (size_t) meminfo.usmblks + (size_t)meminfo.uordblks);
21210       fprintf(stderr, "Total heap size: %8zu bytes\n", (size_t) meminfo.arena);
21211 
21212       /* malloc_stats(); */
21213     }
21214   memtotal = (size_t)meminfo.arena;
21215 #endif
21216 
21217   return memtotal;
21218 }
21219 
21220 
memExitOnError(void)21221 void memExitOnError(void)
21222 {
21223   dmemory_ExitOnError = 1;
21224 }
21225 /*
21226  * Local Variables:
21227  * c-file-style: "Java"
21228  * c-basic-offset: 2
21229  * indent-tabs-mode: nil
21230  * show-trailing-whitespace: t
21231  * require-trailing-newline: t
21232  * End:
21233  */
21234 #include <stdio.h>
21235 #include <stdlib.h>
21236 #include <stdarg.h>
21237 #include <errno.h>
21238 
21239 #if !defined (NAMESPACE_H)
21240 #endif
21241 
21242 int _ExitOnError   = 1;	/* If set to 1, exit on error       */
21243 int _Verbose = 1;	/* If set to 1, errors are reported */
21244 int _Debug   = 0;       /* If set to 1, debugging           */
21245 
21246 /* If we're not using GNU C, elide __attribute__ */
21247 #if ! defined __GNUC__ && ! defined __attribute__
21248 #  define  __attribute__(x)  /*NOTHING*/
21249 #endif
21250 
21251 void SysError_(const char *caller, const char *fmt, ...)
21252   __attribute__((noreturn));
21253 
SysError_(const char * caller,const char * fmt,...)21254 void SysError_(const char *caller, const char *fmt, ...)
21255 {
21256   va_list args;
21257   int saved_errno = errno;
21258 
21259   va_start(args, fmt);
21260 
21261   printf("\n");
21262    fprintf(stderr, "Error (%s): ", caller);
21263   vfprintf(stderr, fmt, args);
21264    fprintf(stderr, "\n");
21265 
21266   va_end(args);
21267 
21268   if ( saved_errno )
21269     {
21270       errno = saved_errno;
21271       perror("System error message");
21272     }
21273 
21274   exit(EXIT_FAILURE);
21275 }
21276 
21277 
Error_(const char * caller,const char * fmt,...)21278 void Error_(const char *caller, const char *fmt, ...)
21279 {
21280   va_list args;
21281 
21282   va_start(args, fmt);
21283 
21284   printf("\n");
21285    fprintf(stderr, "Error (%s): ", caller);
21286   vfprintf(stderr, fmt, args);
21287    fprintf(stderr, "\n");
21288 
21289   va_end(args);
21290 
21291   if ( _ExitOnError ) exit(EXIT_FAILURE);
21292 }
21293 
21294 typedef void (*cdiAbortCFunc)(const char * caller, const char * filename,
21295                               const char *functionname, int line,
21296                               const char * errorString, va_list ap)
21297 #ifdef __GNUC__
21298   __attribute__((noreturn))
21299 #endif
21300 ;
21301 
cdiAbortC(const char * caller,const char * filename,const char * functionname,int line,const char * errorString,...)21302 void cdiAbortC(const char * caller, const char * filename,
21303                const char *functionname, int line,
21304                const char * errorString, ... )
21305 {
21306   va_list ap;
21307   va_start(ap, errorString);
21308   cdiAbortCFunc cdiAbortC_p
21309     = (cdiAbortCFunc)namespaceSwitchGet(NSSWITCH_ABORT).func;
21310   cdiAbortC_p(caller, filename, functionname, line, errorString, ap);
21311   va_end(ap);
21312 }
21313 
21314 void
cdiAbortC_serial(const char * caller,const char * filename,const char * functionname,int line,const char * errorString,va_list ap)21315 cdiAbortC_serial(const char *caller, const char *filename,
21316                  const char *functionname, int line,
21317                  const char *errorString, va_list ap)
21318 {
21319   fprintf(stderr, "ERROR, %s, %s, line %d%s%s\nerrorString: \"",
21320           functionname, filename, line, caller?", called from ":"",
21321           caller?caller:"");
21322   vfprintf(stderr, errorString, ap);
21323   fputs("\"\n", stderr);
21324   exit(EXIT_FAILURE);
21325 }
21326 
21327 typedef void (*cdiWarningFunc)(const char * caller, const char * fmt,
21328                                va_list ap);
21329 
Warning_(const char * caller,const char * fmt,...)21330 void Warning_(const char *caller, const char *fmt, ...)
21331 {
21332   va_list args;
21333 
21334   va_start(args, fmt);
21335 
21336   if ( _Verbose )
21337     {
21338       cdiWarningFunc cdiWarning_p
21339         = (cdiWarningFunc)namespaceSwitchGet(NSSWITCH_WARNING).func;
21340       cdiWarning_p(caller, fmt, args);
21341     }
21342 
21343   va_end(args);
21344 }
21345 
cdiWarning(const char * caller,const char * fmt,va_list ap)21346 void cdiWarning(const char *caller, const char *fmt, va_list ap)
21347 {
21348   fprintf(stderr, "Warning (%s): ", caller);
21349   vfprintf(stderr, fmt, ap);
21350   fputc('\n', stderr);
21351 }
21352 
21353 
Message_(const char * caller,const char * fmt,...)21354 void Message_(const char *caller, const char *fmt, ...)
21355 {
21356   va_list args;
21357 
21358   va_start(args, fmt);
21359 
21360    fprintf(stdout, "%-18s: ", caller);
21361   vfprintf(stdout, fmt, args);
21362    fprintf(stdout, "\n");
21363 
21364   va_end(args);
21365 }
21366 /*
21367  * Local Variables:
21368  * c-file-style: "Java"
21369  * c-basic-offset: 2
21370  * indent-tabs-mode: nil
21371  * show-trailing-whitespace: t
21372  * require-trailing-newline: t
21373  * End:
21374  */
21375 #ifndef EXSE_H
21376 #define EXSE_H
21377 
21378 enum {
21379   EXSE_SINGLE_PRECISION = 4,
21380   EXSE_DOUBLE_PRECISION = 8,
21381 };
21382 
21383 #endif
21384 #include <stdio.h>
21385 #include <stdlib.h>
21386 #include <string.h>
21387 #include <ctype.h>
21388 
21389 
21390 
21391 enum {
21392   EXT_HEADER_LEN = 4,
21393 };
21394 
21395 
21396 static int initExtLib       = 0;
21397 static int extDefaultPrec   = 0;
21398 static int extDefaultNumber = EXT_REAL;
21399 
21400 
21401 /*
21402  * A version string.
21403  */
21404 #undef  LIBVERSION
21405 #define LIBVERSION      1.4.1
21406 #define XSTRING(x)	#x
21407 #define STRING(x)	XSTRING(x)
21408 static const char ext_libvers[] = STRING(LIBVERSION);
21409 
extLibraryVersion(void)21410 const char *extLibraryVersion(void)
21411 {
21412   return ext_libvers;
21413 }
21414 
21415 
21416 static int EXT_Debug = 0;    /* If set to 1, debugging */
21417 
21418 
extDebug(int debug)21419 void extDebug(int debug)
21420 {
21421   EXT_Debug = debug;
21422   if (EXT_Debug) Message("debug level %d", debug);
21423 }
21424 
21425 
21426 static
extLibInit()21427 void extLibInit()
21428 {
21429   const char *envName = "EXT_PRECISION";
21430 
21431   char *envString = getenv(envName);
21432   if ( envString )
21433     {
21434       if ( strlen(envString) == 2  )
21435 	{
21436 	  switch ( tolower((int) envString[0]) )
21437 	    {
21438 	    case 'r':
21439 	      {
21440 		extDefaultNumber = EXT_REAL;
21441 		switch ( (int) envString[1] )
21442 		  {
21443 		  case '4': extDefaultPrec = EXSE_SINGLE_PRECISION; break;
21444 		  case '8': extDefaultPrec = EXSE_DOUBLE_PRECISION; break;
21445 		  default:
21446 		    Message("Invalid digit in %s: %s", envName, envString);
21447 		  }
21448 		break;
21449 	      }
21450 	    case 'c':
21451 	      {
21452 		extDefaultNumber = EXT_COMP;
21453 		switch ( (int) envString[1] )
21454 		  {
21455 		  case '4': extDefaultPrec = EXSE_SINGLE_PRECISION; break;
21456 		  case '8': extDefaultPrec = EXSE_DOUBLE_PRECISION; break;
21457 		  default:
21458 		    Message("Invalid digit in %s: %s", envName, envString);
21459 		  }
21460 		break;
21461 	      }
21462 	    default:
21463               {
21464                 Message("Invalid character in %s: %s", envName, envString);
21465                 break;
21466               }
21467             }
21468 	}
21469     }
21470 
21471   initExtLib = 1;
21472 }
21473 
21474 static
extInit(extrec_t * extp)21475 void extInit(extrec_t *extp)
21476 {
21477   extp->checked    = 0;
21478   extp->byteswap   = 0;
21479   extp->prec       = 0;
21480   extp->number     = extDefaultNumber;
21481   extp->datasize   = 0;
21482   extp->buffersize = 0;
21483   extp->buffer     = NULL;
21484 }
21485 
21486 
extNew(void)21487 void *extNew(void)
21488 {
21489   if ( ! initExtLib ) extLibInit();
21490 
21491   extrec_t *extp = (extrec_t *) Malloc(sizeof(extrec_t));
21492 
21493   extInit(extp);
21494 
21495   return (void*)extp;
21496 }
21497 
21498 
extDelete(void * ext)21499 void extDelete(void *ext)
21500 {
21501   extrec_t *extp = (extrec_t *) ext;
21502 
21503   if ( extp )
21504     {
21505       if ( extp->buffer ) Free(extp->buffer);
21506       Free(extp);
21507     }
21508 }
21509 
21510 
extCheckFiletype(int fileID,int * swap)21511 int extCheckFiletype(int fileID, int *swap)
21512 {
21513   size_t fact = 0;
21514   size_t data =  0;
21515   size_t dimxy = 0;
21516   unsigned char buffer[40], *pbuf;
21517 
21518   if ( fileRead(fileID, buffer, 4) != 4 ) return 0;
21519 
21520   size_t blocklen  = (size_t) get_UINT32(buffer);
21521   size_t sblocklen = (size_t) get_SUINT32(buffer);
21522 
21523   if ( EXT_Debug )
21524     Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
21525 
21526   if ( blocklen == 16 )
21527     {
21528      *swap = 0;
21529       fact = blocklen/4;
21530       if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return 0;
21531       pbuf = buffer+3*fact;      dimxy = (size_t) get_UINT32(pbuf);
21532       pbuf = buffer+blocklen+4;  data  = (size_t) get_UINT32(pbuf);
21533     }
21534   else if ( blocklen == 32 )
21535     {
21536      *swap = 0;
21537       fact = blocklen/4;
21538       if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return 0;
21539       pbuf = buffer+3*fact;      dimxy = (size_t) get_UINT64(pbuf);
21540       pbuf = buffer+blocklen+4;  data  = (size_t) get_UINT32(pbuf);
21541     }
21542   else if ( sblocklen == 16 )
21543     {
21544      *swap = 1;
21545       fact = sblocklen/4;
21546       if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return 0;
21547       pbuf = buffer+3*fact;       dimxy = (size_t) get_SUINT32(pbuf);
21548       pbuf = buffer+sblocklen+4;  data  = (size_t) get_SUINT32(pbuf);
21549     }
21550   else if ( sblocklen == 32 )
21551     {
21552      *swap = 1;
21553       fact = sblocklen/4;
21554       if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return 0;
21555       pbuf = buffer+3*fact;       dimxy = (size_t) get_SUINT64(pbuf);
21556       pbuf = buffer+sblocklen+4;  data  = (size_t) get_SUINT32(pbuf);
21557     }
21558 
21559   fileRewind(fileID);
21560 
21561   if ( EXT_Debug )
21562     {
21563       Message("swap = %d fact = %d", *swap, fact);
21564       Message("dimxy = %lu data = %lu", dimxy, data);
21565     }
21566 
21567   int found = data && (dimxy*fact == data || dimxy*fact*2 == data);
21568   return found;
21569 }
21570 
21571 
extInqHeader(void * ext,int * header)21572 int extInqHeader(void *ext, int *header)
21573 {
21574   extrec_t *extp = (extrec_t *) ext;
21575 
21576   for (size_t i = 0; i < EXT_HEADER_LEN; i++) header[i] = extp->header[i];
21577 
21578   if ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
21579 
21580   return 0;
21581 }
21582 
21583 
extDefHeader(void * ext,const int * header)21584 int extDefHeader(void *ext, const int *header)
21585 {
21586   extrec_t *extp = (extrec_t *) ext;
21587 
21588   for (size_t i = 0; i < EXT_HEADER_LEN; i++) extp->header[i] = header[i];
21589 
21590   extp->datasize = (size_t)header[3];
21591   if ( extp->number == EXT_COMP ) extp->datasize *= 2;
21592 
21593   if (EXT_Debug) Message("datasize = %lu", extp->datasize);
21594 
21595   return 0;
21596 }
21597 
21598 static
extInqData(extrec_t * extp,int prec,void * data)21599 int extInqData(extrec_t *extp, int prec, void *data)
21600 {
21601   int ierr = 0;
21602   int byteswap = extp->byteswap;
21603   size_t datasize = extp->datasize;
21604   void *buffer   = extp->buffer;
21605   int rprec    = extp->prec;
21606 
21607   switch ( rprec )
21608     {
21609     case EXSE_SINGLE_PRECISION:
21610       {
21611 	if ( sizeof(FLT32) == 4 )
21612 	  {
21613 	    if ( byteswap ) swap4byte(buffer, datasize);
21614 
21615 	    if ( rprec == prec )
21616 	      memcpy(data, buffer, datasize*sizeof(FLT32));
21617 	    else
21618 	      for (size_t i = 0; i < datasize; ++i)
21619 		((double *) data)[i] = (double) ((float *) buffer)[i];
21620 	  }
21621 	else
21622 	  {
21623 	    Error("not implemented for %d byte float", sizeof(FLT32));
21624 	  }
21625 	break;
21626       }
21627     case EXSE_DOUBLE_PRECISION:
21628 	if ( sizeof(FLT64) == 8 )
21629 	  {
21630 	    if ( byteswap ) swap8byte(buffer, datasize);
21631 
21632 	    if ( rprec == prec )
21633 	      memcpy(data, buffer, datasize*sizeof(FLT64));
21634 	    else
21635 	      for (size_t i = 0; i < datasize; ++i)
21636 		((float *) data)[i] = (float) ((double *) buffer)[i];
21637 	  }
21638 	else
21639 	  {
21640 	    Error("not implemented for %d byte float", sizeof(FLT64));
21641 	  }
21642 	break;
21643     default:
21644       {
21645 	Error("unexpected data precision %d", rprec);
21646 	break;
21647       }
21648     }
21649 
21650   return ierr;
21651 }
21652 
21653 
extInqDataSP(void * ext,float * data)21654 int extInqDataSP(void *ext, float *data)
21655 {
21656   return extInqData((extrec_t *)ext, EXSE_SINGLE_PRECISION, (void *) data);
21657 }
21658 
21659 
extInqDataDP(void * ext,double * data)21660 int extInqDataDP(void *ext, double *data)
21661 {
21662   return extInqData((extrec_t *)ext, EXSE_DOUBLE_PRECISION, (void *) data);
21663 }
21664 
21665 
extDefData(void * ext,int prec,const void * data)21666 static int extDefData(void *ext, int prec, const void *data)
21667 {
21668   extrec_t *extp = (extrec_t *) ext;
21669 
21670   int rprec = extDefaultPrec ? extDefaultPrec : extp->prec;
21671   extp->prec = rprec ? rprec : prec;
21672 
21673   int *header = extp->header;
21674 
21675   size_t datasize = (size_t)header[3];
21676   if ( extp->number == EXT_COMP ) datasize *= 2;
21677   size_t blocklen = datasize * (size_t)rprec;
21678 
21679   extp->datasize = datasize;
21680 
21681   void *buffer = extp->buffer;
21682   size_t buffersize = extp->buffersize;
21683 
21684   if ( buffersize != blocklen )
21685     {
21686       buffersize = blocklen;
21687       buffer = Realloc(buffer, buffersize);
21688       extp->buffer = buffer;
21689       extp->buffersize = buffersize;
21690     }
21691 
21692   switch ( rprec )
21693     {
21694     case EXSE_SINGLE_PRECISION:
21695       {
21696 	if ( rprec == prec )
21697 	  memcpy(buffer, data, datasize*sizeof(FLT32));
21698 	else
21699 	  for (size_t i = 0; i < datasize; i++)
21700 	    ((float *) buffer)[i] = (float) ((double *) data)[i];
21701 
21702 	break;
21703       }
21704     case EXSE_DOUBLE_PRECISION:
21705       {
21706 	if ( rprec == prec )
21707 	  memcpy(buffer, data, datasize*sizeof(FLT64));
21708 	else
21709 	  for (size_t i = 0; i < datasize; i++)
21710 	    ((double *) buffer)[i] = (double) ((float *) data)[i];
21711 
21712 	break;
21713       }
21714     default:
21715       {
21716 	Error("unexpected data precision %d", rprec);
21717         break;
21718       }
21719     }
21720 
21721   return 0;
21722 }
21723 
21724 
extDefDataSP(void * ext,const float * data)21725 int extDefDataSP(void *ext, const float *data)
21726 {
21727   return extDefData(ext, EXSE_SINGLE_PRECISION, (void *) data);
21728 }
21729 
21730 
extDefDataDP(void * ext,const double * data)21731 int extDefDataDP(void *ext, const double *data)
21732 {
21733   return extDefData(ext, EXSE_DOUBLE_PRECISION, (void *) data);
21734 }
21735 
21736 
extRead(int fileID,void * ext)21737 int extRead(int fileID, void *ext)
21738 {
21739   extrec_t *extp = (extrec_t *) ext;
21740 
21741   if ( ! extp->checked )
21742     {
21743       int status = extCheckFiletype(fileID, &extp->byteswap);
21744       if ( status == 0 ) Error("Not a EXTRA file!");
21745       extp->checked = 1;
21746     }
21747 
21748   int byteswap = extp->byteswap;
21749 
21750   /* read header record */
21751   size_t blocklen = binReadF77Block(fileID, byteswap);
21752 
21753   if ( fileEOF(fileID) ) return -1;
21754 
21755   if ( EXT_Debug ) Message("blocklen = %lu", blocklen);
21756 
21757   size_t hprec = blocklen / EXT_HEADER_LEN;
21758 
21759   extp->prec = (int)hprec;
21760 
21761   switch ( hprec )
21762     {
21763     case EXSE_SINGLE_PRECISION:
21764       {
21765         INT32 tempheader[4];
21766 	binReadInt32(fileID, byteswap, EXT_HEADER_LEN, tempheader);
21767 
21768 	for (size_t i = 0; i < EXT_HEADER_LEN; i++)
21769           extp->header[i] = (int)tempheader[i];
21770 
21771 	break;
21772       }
21773     case EXSE_DOUBLE_PRECISION:
21774       {
21775         INT64 tempheader[4];
21776 	binReadInt64(fileID, byteswap, EXT_HEADER_LEN, tempheader);
21777 
21778 	for (size_t i = 0; i < EXT_HEADER_LEN; i++)
21779           extp->header[i] = (int)tempheader[i];
21780 
21781 	break;
21782       }
21783     default:
21784       {
21785 	Error("Unexpected header precision %d", hprec);
21786         break;
21787       }
21788     }
21789 
21790   size_t blocklen2 = binReadF77Block(fileID, byteswap);
21791 
21792   if ( blocklen2 != blocklen )
21793     {
21794       Warning("Header blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
21795       if ( blocklen2 != 0 ) return -1;
21796     }
21797 
21798   extp->datasize = (size_t)extp->header[3];
21799 
21800   if ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
21801 
21802   blocklen = binReadF77Block(fileID, byteswap);
21803 
21804   void *buffer = extp->buffer;
21805   size_t buffersize = (size_t)extp->buffersize;
21806 
21807   if ( buffersize < blocklen )
21808     {
21809       buffersize = blocklen;
21810       buffer = Realloc(buffer, buffersize);
21811       extp->buffer = buffer;
21812       extp->buffersize = buffersize;
21813     }
21814 
21815   size_t dprec = blocklen / extp->datasize;
21816 
21817   if ( dprec == hprec )
21818     {
21819       extp->number = EXT_REAL;
21820     }
21821   else if ( dprec == 2*hprec )
21822     {
21823       dprec /= 2;
21824       extp->datasize *= 2;
21825       extp->number = EXT_COMP;
21826     }
21827 
21828   if ( dprec != EXSE_SINGLE_PRECISION && dprec != EXSE_DOUBLE_PRECISION )
21829     {
21830       Warning("Unexpected data precision %d", dprec);
21831       return -1;
21832     }
21833 
21834   fileRead(fileID, buffer, blocklen);
21835 
21836   blocklen2 = binReadF77Block(fileID, byteswap);
21837 
21838   if ( blocklen2 != blocklen )
21839     {
21840       Warning("Data blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
21841       if ( blocklen2 != 0 ) return -1;
21842     }
21843 
21844   return 0;
21845 }
21846 
21847 
extWrite(int fileID,void * ext)21848 int extWrite(int fileID, void *ext)
21849 {
21850   extrec_t *extp = (extrec_t *) ext;
21851   union { INT32 i32[EXT_HEADER_LEN]; INT64 i64[EXT_HEADER_LEN]; } tempheader;
21852   int byteswap = extp->byteswap;
21853   int rprec  = extp->prec;
21854   int number = extp->number;
21855   int *header = extp->header;
21856 
21857   /* write header record */
21858   size_t blocklen = EXT_HEADER_LEN * (size_t)rprec;
21859 
21860   binWriteF77Block(fileID, byteswap, blocklen);
21861 
21862   switch ( rprec )
21863     {
21864     case EXSE_SINGLE_PRECISION:
21865       {
21866 	for (size_t i = 0; i < EXT_HEADER_LEN; i++)
21867           tempheader.i32[i] = (INT32) header[i];
21868 
21869 	binWriteInt32(fileID, byteswap, EXT_HEADER_LEN, tempheader.i32);
21870 
21871 	break;
21872       }
21873     case EXSE_DOUBLE_PRECISION:
21874       {
21875 	for (size_t i = 0; i < EXT_HEADER_LEN; i++)
21876           tempheader.i64[i] = (INT64) header[i];
21877 
21878 	binWriteInt64(fileID, byteswap, EXT_HEADER_LEN, tempheader.i64);
21879 
21880 	break;
21881       }
21882     default:
21883       {
21884 	Error("unexpected header precision %d", rprec);
21885         break;
21886       }
21887     }
21888 
21889   binWriteF77Block(fileID, byteswap, blocklen);
21890 
21891   size_t datasize = (size_t)header[3];
21892   if ( number == EXT_COMP ) datasize *= 2;
21893   blocklen = datasize * (size_t)rprec;
21894 
21895   binWriteF77Block(fileID, byteswap, blocklen);
21896 
21897   extp->datasize = datasize;
21898 
21899   void *buffer = extp->buffer;
21900 
21901   switch ( rprec )
21902     {
21903     case EXSE_SINGLE_PRECISION:
21904       {
21905 	binWriteFlt32(fileID, byteswap, datasize, (FLT32 *) buffer);
21906 	break;
21907       }
21908     case EXSE_DOUBLE_PRECISION:
21909       {
21910 	binWriteFlt64(fileID, byteswap, datasize, (FLT64 *) buffer);
21911 	break;
21912       }
21913     default:
21914       {
21915 	Error("unexpected data precision %d", rprec);
21916         break;
21917       }
21918     }
21919 
21920   binWriteF77Block(fileID, byteswap, blocklen);
21921 
21922   return 0;
21923 }
21924 /*
21925  * Local Variables:
21926  * c-file-style: "Java"
21927  * c-basic-offset: 2
21928  * indent-tabs-mode: nil
21929  * show-trailing-whitespace: t
21930  * require-trailing-newline: t
21931  * End:
21932  */
21933 #ifdef HAVE_CONFIG_H
21934 #endif
21935 
21936 #ifdef HAVE_UNISTD_H
21937 #include <unistd.h>
21938 #endif
21939 
21940 #include <assert.h>
21941 #include <ctype.h>
21942 #include <errno.h>
21943 #include <fcntl.h>
21944 #include <limits.h>
21945 #include <stdio.h>
21946 #include <stdlib.h>
21947 #include <stdbool.h>
21948 #include <string.h>
21949 #include <sys/types.h>
21950 #include <sys/stat.h>
21951 
21952 #ifdef HAVE_SYS_TIME_H
21953 #include <sys/time.h>  // gettimeofday()
21954 #endif
21955 
21956 
21957 #ifdef CDI
21958 #endif
21959 
21960 #ifndef O_BINARY
21961 #define O_BINARY 0
21962 #endif
21963 
21964 #ifndef strdup
21965 char *strdup(const char *s);
21966 #endif
21967 
21968 #ifdef HAVE_MMAP
21969 #include <sys/mman.h>  // mmap() is defined in this header
21970 #endif
21971 
21972 #define MAX_FILES 8192
21973 static int _file_max = MAX_FILES;
21974 
21975 static void file_initialize(void);
21976 
21977 static bool _file_init = false;
21978 
21979 #ifdef HAVE_LIBPTHREAD
21980 #include <pthread.h>
21981 
21982 static pthread_once_t _file_init_thread = PTHREAD_ONCE_INIT;
21983 static pthread_mutex_t _file_mutex;
21984 
21985 #define FILE_LOCK() pthread_mutex_lock(&_file_mutex)
21986 #define FILE_UNLOCK() pthread_mutex_unlock(&_file_mutex)
21987 #define FILE_INIT() \
21988   if (_file_init == false) pthread_once(&_file_init_thread, file_initialize)
21989 
21990 #else
21991 
21992 #define FILE_LOCK()
21993 #define FILE_UNLOCK()
21994 #define FILE_INIT() \
21995   if (_file_init == false) file_initialize()
21996 #endif
21997 
21998 typedef struct
21999 {
22000   int self;
22001   int flag;            // access and error flag
22002   int eof;             // end of file flag
22003   int fd;              // file descriptor used for read
22004   FILE *fp;            // FILE pointer used for write
22005   char *name;          // file name
22006   off_t size;          // file size
22007   off_t position;      // file position
22008   long access;         // file access
22009   off_t byteTrans;     //
22010   size_t blockSize;    // file block size
22011   int mode;            // file access mode
22012   int type;            // file type [1:open  2:fopen]
22013   int bufferType;      // buffer type [1:std  2:mmap]
22014   size_t bufferSize;   // file buffer size
22015   size_t mappedSize;   // mmap buffer size
22016   char *buffer;        // file buffer
22017   long bufferNumFill;  // number of buffer fill
22018   char *bufferPtr;     // file buffer pointer
22019   off_t bufferPos;
22020   off_t bufferStart;
22021   off_t bufferEnd;
22022   size_t bufferCnt;
22023   double time_in_sec;
22024 } bfile_t;
22025 
22026 enum FILE_Flags
22027 {
22028   FILE_EOF = 010,
22029   FILE_ERROR = 020
22030 };
22031 
22032 #ifndef MIN_BUF_SIZE
22033 #define MIN_BUF_SIZE 131072L
22034 #endif
22035 
22036 static const char *fbtname[] = { "unknown", "standard", "mmap" };
22037 static const char *ftname[] = { "unknown", "open", "fopen" };
22038 
22039 static size_t FileBufferSizeMin = MIN_BUF_SIZE;
22040 static long FileBufferSizeEnv = -1;
22041 static int FileBufferTypeEnv = 0;
22042 
22043 static int FileTypeRead = FILE_TYPE_OPEN;
22044 static int FileTypeWrite = FILE_TYPE_FOPEN;
22045 static int FileFlagWrite = 0;
22046 
22047 static int FileDebug = 0; // If set to 1, debugging
22048 static bool FileInfo = false;
22049 
22050 static void file_table_print(void);
22051 
22052 // A version string.
22053 #undef LIBVERSION
22054 #define LIBVERSION 1.9.1
22055 #define XSTRING(x) #x
22056 #define STRING(x) XSTRING(x)
22057 static const char file_libvers[] = STRING(LIBVERSION);
22058 
22059 /*
22060   21/05/2004  1.3.2 set min I/O Buffersize to 128k
22061   31/05/2005  1.4.0 replace fileTable by _fileList
22062   26/08/2005  1.4.1 fileClose with return value
22063                     checks for all fileptr
22064   01/09/2005  1.5.0 thread safe version
22065   06/11/2005  1.5.1 add filePtrEOF, filePtr, filePtrGetc
22066   03/02/2006  1.5.2 ansi C: define getpagesize and strdupx
22067   27/12/2007  1.6.0 add FILE_TYPE_FOPEN
22068   24/03/2008  1.6.1 add O_BINARY if available
22069                     remove default HAVE_MMAP
22070                     use HAVE_STRUCT_STAT_ST_BLKSIZE
22071   22/08/2010  1.7.0 refactor
22072   11/11/2010  1.7.1 update for changed interface of error.h
22073   02/02/2012  1.8.0 cleanup
22074   16/11/2012  1.8.1 added support for unbuffered write
22075   27/06/2013  1.8.2 added env. var. FILE_TYPE_WRITE (1:open; 2:fopen)
22076   29/04/2020  1.9.0 fileSetPos(): refactored
22077   30/04/2020  1.9.1 fileSetPos(): not initialized correctly (bug fix)
22078  */
22079 
22080 typedef struct _filePtrToIdx
22081 {
22082   int idx;
22083   bfile_t *ptr;
22084   struct _filePtrToIdx *next;
22085 } filePtrToIdx;
22086 
22087 static filePtrToIdx *_fileList = NULL;
22088 static filePtrToIdx *_fileAvail = NULL;
22089 
22090 static void
file_list_new(void)22091 file_list_new(void)
22092 {
22093   assert(_fileList == NULL);
22094 
22095   _fileList = (filePtrToIdx *) malloc((size_t) _file_max * sizeof(filePtrToIdx));
22096 }
22097 
22098 static void
file_list_delete(void)22099 file_list_delete(void)
22100 {
22101   if (_fileList)
22102     {
22103       free(_fileList);
22104       _fileList = NULL;
22105     }
22106 }
22107 
22108 static void
file_init_pointer(void)22109 file_init_pointer(void)
22110 {
22111   for (int i = 0; i < _file_max; i++)
22112     {
22113       _fileList[i].next = _fileList + i + 1;
22114       _fileList[i].idx = i;
22115       _fileList[i].ptr = 0;
22116     }
22117 
22118   _fileList[_file_max - 1].next = 0;
22119 
22120   _fileAvail = _fileList;
22121 }
22122 
22123 static bfile_t *
file_to_pointer(int idx)22124 file_to_pointer(int idx)
22125 {
22126   bfile_t *fileptr = NULL;
22127 
22128   FILE_INIT();
22129 
22130   if (idx >= 0 && idx < _file_max)
22131     {
22132       FILE_LOCK();
22133       fileptr = _fileList[idx].ptr;
22134       FILE_UNLOCK();
22135     }
22136   else
22137     Error("file index %d undefined!", idx);
22138 
22139   return fileptr;
22140 }
22141 
22142 // Create an index from a pointer
22143 static int
file_from_pointer(bfile_t * ptr)22144 file_from_pointer(bfile_t *ptr)
22145 {
22146   int idx = -1;
22147 
22148   if (ptr)
22149     {
22150       FILE_LOCK();
22151 
22152       if (_fileAvail)
22153         {
22154           filePtrToIdx *newptr = _fileAvail;
22155           _fileAvail = _fileAvail->next;
22156           newptr->next = 0;
22157           idx = newptr->idx;
22158           newptr->ptr = ptr;
22159 
22160           if (FileDebug) Message("Pointer %p has idx %d from file list", ptr, idx);
22161         }
22162       else
22163         {
22164           Warning("Too many open files (limit is %d)!", _file_max);
22165           idx = -2;
22166         }
22167 
22168       FILE_UNLOCK();
22169     }
22170   else
22171     Error("Internal problem (pointer %p undefined)", ptr);
22172 
22173   return idx;
22174 }
22175 
22176 static void
file_init_entry(bfile_t * fileptr)22177 file_init_entry(bfile_t *fileptr)
22178 {
22179   fileptr->self = file_from_pointer(fileptr);
22180 
22181   fileptr->flag = 0;
22182   fileptr->fd = -1;
22183   fileptr->fp = NULL;
22184   fileptr->mode = 0;
22185   fileptr->size = 0;
22186   fileptr->name = NULL;
22187   fileptr->access = 0;
22188   fileptr->position = 0;
22189   fileptr->byteTrans = 0;
22190   fileptr->type = 0;
22191   fileptr->bufferType = 0;
22192   fileptr->bufferSize = 0;
22193   fileptr->mappedSize = 0;
22194   fileptr->buffer = NULL;
22195   fileptr->bufferNumFill = 0;
22196   fileptr->bufferStart = 0;
22197   fileptr->bufferEnd = -1;
22198   fileptr->bufferPos = 0;
22199   fileptr->bufferCnt = 0;
22200   fileptr->bufferPtr = NULL;
22201   fileptr->time_in_sec = 0.0;
22202 }
22203 
22204 static bfile_t *
file_new_entry(void)22205 file_new_entry(void)
22206 {
22207   bfile_t *fileptr = (bfile_t *) malloc(sizeof(bfile_t));
22208   if (fileptr) file_init_entry(fileptr);
22209   return fileptr;
22210 }
22211 
22212 static void
file_delete_entry(bfile_t * fileptr)22213 file_delete_entry(bfile_t *fileptr)
22214 {
22215   const int idx = fileptr->self;
22216 
22217   FILE_LOCK();
22218 
22219   free(fileptr);
22220 
22221   _fileList[idx].next = _fileAvail;
22222   _fileList[idx].ptr = 0;
22223   _fileAvail = &_fileList[idx];
22224 
22225   FILE_UNLOCK();
22226 
22227   if (FileDebug) Message("Removed idx %d from file list", idx);
22228 }
22229 
22230 const char *
fileLibraryVersion(void)22231 fileLibraryVersion(void)
22232 {
22233   return file_libvers;
22234 }
22235 
22236 static int
file_pagesize(void)22237 file_pagesize(void)
22238 {
22239 #ifdef _SC_PAGESIZE
22240   return (int) sysconf(_SC_PAGESIZE);
22241 #else
22242 #ifndef POSIXIO_DEFAULT_PAGESIZE
22243 #define POSIXIO_DEFAULT_PAGESIZE 4096
22244 #endif
22245   return (int) POSIXIO_DEFAULT_PAGESIZE;
22246 #endif
22247 }
22248 
22249 static double
file_time()22250 file_time()
22251 {
22252 #ifdef HAVE_SYS_TIME_H
22253   struct timeval mytime;
22254   gettimeofday(&mytime, NULL);
22255   return (double) mytime.tv_sec + (double) mytime.tv_usec * 1.0e-6;
22256 #else
22257   return 0;
22258 #endif
22259 }
22260 
22261 void
fileDebug(int debug)22262 fileDebug(int debug)
22263 {
22264   FileDebug = debug;
22265   if (FileDebug) Message("Debug level %d", debug);
22266 }
22267 
22268 void *
filePtr(int fileID)22269 filePtr(int fileID)
22270 {
22271   return (void *) file_to_pointer(fileID);
22272 }
22273 
22274 static void
file_pointer_info(const char * caller,int fileID)22275 file_pointer_info(const char *caller, int fileID)
22276 {
22277   if (FileDebug)
22278     {
22279       fprintf(stdout, "%-18s : ", caller);
22280       fprintf(stdout, "The fileID %d underlying pointer is not valid!", fileID);
22281       fprintf(stdout, "\n");
22282     }
22283 }
22284 
22285 int
fileSetBufferType(int fileID,int type)22286 fileSetBufferType(int fileID, int type)
22287 {
22288   int ret = 0;
22289 
22290   bfile_t *fileptr = file_to_pointer(fileID);
22291   if (fileptr)
22292     {
22293       switch (type)
22294         {
22295         case FILE_BUFTYPE_STD:
22296         case FILE_BUFTYPE_MMAP: fileptr->bufferType = type; break;
22297         default: Error("File type %d not implemented!", type);
22298         }
22299     }
22300 
22301 #ifndef HAVE_MMAP
22302   if (type == FILE_BUFTYPE_MMAP) ret = 1;
22303 #endif
22304 
22305   return ret;
22306 }
22307 
22308 int
fileFlush(int fileID)22309 fileFlush(int fileID)
22310 {
22311   bfile_t *fileptr = file_to_pointer(fileID);
22312   return fileptr ? fflush(fileptr->fp) : 0;
22313 }
22314 
22315 void
fileClearerr(int fileID)22316 fileClearerr(int fileID)
22317 {
22318   bfile_t *fileptr = file_to_pointer(fileID);
22319   if (fileptr)
22320     {
22321       if (fileptr->mode != 'r') clearerr(fileptr->fp);
22322     }
22323 }
22324 
22325 int
filePtrEOF(void * vfileptr)22326 filePtrEOF(void *vfileptr)
22327 {
22328   bfile_t *fileptr = (bfile_t *) vfileptr;
22329   return fileptr ? (fileptr->flag & FILE_EOF) != 0 : 0;
22330 }
22331 
22332 int
fileEOF(int fileID)22333 fileEOF(int fileID)
22334 {
22335   bfile_t *fileptr = file_to_pointer(fileID);
22336   return fileptr ? (fileptr->flag & FILE_EOF) != 0 : 0;
22337 }
22338 
22339 void
fileRewind(int fileID)22340 fileRewind(int fileID)
22341 {
22342   fileSetPos(fileID, (off_t) 0, SEEK_SET);
22343   fileClearerr(fileID);
22344 }
22345 
22346 off_t
fileGetPos(int fileID)22347 fileGetPos(int fileID)
22348 {
22349   off_t filepos = 0;
22350 
22351   bfile_t *fileptr = file_to_pointer(fileID);
22352   if (fileptr)
22353     {
22354       if (fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN)
22355         filepos = fileptr->position;
22356       else
22357         filepos = ftell(fileptr->fp);
22358     }
22359 
22360   if (FileDebug) Message("Position %ld", filepos);
22361 
22362   return filepos;
22363 }
22364 
22365 static int
file_set_buffer_pos(bfile_t * fileptr)22366 file_set_buffer_pos(bfile_t *fileptr)
22367 {
22368   const off_t position = fileptr->position;
22369   if (position < fileptr->bufferStart || position > fileptr->bufferEnd)
22370     {
22371       if (fileptr->bufferType == FILE_BUFTYPE_STD)
22372         fileptr->bufferPos = position;
22373       else
22374         fileptr->bufferPos = position - position % file_pagesize();
22375 
22376       fileptr->bufferCnt = 0;
22377       fileptr->bufferPtr = NULL;
22378 
22379       return 1;
22380     }
22381 
22382   return 0;
22383 }
22384 
22385 static void
file_check_buffer_pos(bfile_t * fileptr)22386 file_check_buffer_pos(bfile_t *fileptr)
22387 {
22388   if (fileptr->bufferPos != fileptr->bufferEnd + 1)
22389     {
22390       if (FileDebug) Message("Reset buffer pos from %ld to %ld", fileptr->bufferPos, fileptr->bufferEnd + 1);
22391 
22392       fileptr->bufferPos = fileptr->bufferEnd + 1;
22393     }
22394 }
22395 
22396 static void
file_seek_buffer(bfile_t * fileptr,off_t offset,int whence)22397 file_seek_buffer(bfile_t *fileptr, off_t offset, int whence)
22398 {
22399   if (whence == SEEK_SET)
22400     {
22401       fileptr->position = offset;
22402       if (!file_set_buffer_pos(fileptr))
22403         {
22404           file_check_buffer_pos(fileptr);
22405           fileptr->bufferCnt = (size_t)(fileptr->bufferEnd - fileptr->position) + 1;
22406           fileptr->bufferPtr = fileptr->buffer + fileptr->position - fileptr->bufferStart;
22407         }
22408     }
22409   else if (whence == SEEK_CUR)
22410     {
22411       fileptr->position += offset;
22412       if (!file_set_buffer_pos(fileptr))
22413         {
22414           file_check_buffer_pos(fileptr);
22415           fileptr->bufferCnt -= (size_t) offset;
22416           fileptr->bufferPtr += offset;
22417         }
22418     }
22419 }
22420 
22421 int
fileSetPos(int fileID,off_t offset,int whence)22422 fileSetPos(int fileID, off_t offset, int whence)
22423 {
22424   int status = 0;
22425 
22426   if (FileDebug) Message("Offset %8ld  Whence %3d", (long) offset, whence);
22427 
22428   bfile_t *fileptr = file_to_pointer(fileID);
22429   if (fileptr == 0)
22430     {
22431       file_pointer_info(__func__, fileID);
22432       return 1;
22433     }
22434 
22435   if (whence != SEEK_SET && whence != SEEK_CUR) Error("Whence = %d not implemented", whence);
22436 
22437   if (fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN)
22438     file_seek_buffer(fileptr, offset, whence);
22439   else
22440     status = fseek(fileptr->fp, offset, whence);
22441 
22442   if (fileptr->position < fileptr->size)
22443     if ((fileptr->flag & FILE_EOF) != 0) fileptr->flag -= FILE_EOF;
22444 
22445   return status;
22446 }
22447 
22448 static void
file_table_print(void)22449 file_table_print(void)
22450 {
22451   int lprintHeader = 1;
22452 
22453   for (int fileID = 0; fileID < _file_max; fileID++)
22454     {
22455       bfile_t *fileptr = file_to_pointer(fileID);
22456       if (fileptr)
22457         {
22458           if (lprintHeader)
22459             {
22460               fprintf(stderr, "\nFile table:\n");
22461               fprintf(stderr, "+-----+---------+");
22462               fprintf(stderr, "----------------------------------------------------+\n");
22463               fprintf(stderr, "|  ID |  Mode   |");
22464               fprintf(stderr, "  Name                                              |\n");
22465               fprintf(stderr, "+-----+---------+");
22466               fprintf(stderr, "----------------------------------------------------+\n");
22467               lprintHeader = 0;
22468             }
22469 
22470           fprintf(stderr, "| %3d | ", fileID);
22471 
22472           switch (fileptr->mode)
22473             {
22474             case 'r': fprintf(stderr, "read   "); break;
22475             case 'w': fprintf(stderr, "write  "); break;
22476             case 'a': fprintf(stderr, "append "); break;
22477             default: fprintf(stderr, "unknown");
22478             }
22479 
22480           fprintf(stderr, " | %-51s|\n", fileptr->name);
22481         }
22482     }
22483 
22484   if (lprintHeader == 0)
22485     {
22486       fprintf(stderr, "+-----+---------+");
22487       fprintf(stderr, "----------------------------------------------------+\n");
22488     }
22489 }
22490 
22491 char *
fileInqName(int fileID)22492 fileInqName(int fileID)
22493 {
22494   bfile_t *fileptr = file_to_pointer(fileID);
22495   return fileptr ? fileptr->name : NULL;
22496 }
22497 
22498 int
fileInqMode(int fileID)22499 fileInqMode(int fileID)
22500 {
22501   bfile_t *fileptr = file_to_pointer(fileID);
22502   return fileptr ? fileptr->mode : 0;
22503 }
22504 
22505 static long
file_getenv(const char * envName)22506 file_getenv(const char *envName)
22507 {
22508   long envValue = -1;
22509   char *envString = getenv(envName);
22510   if (envString)
22511     {
22512       long fact = 1;
22513       for (int i = 0; i < (int) strlen(envString); i++)
22514         {
22515           if (!isdigit((int) envString[i]))
22516             {
22517               switch (tolower((int) envString[i]))
22518                 {
22519                 case 'k': fact = 1024; break;
22520                 case 'm': fact = 1048576; break;
22521                 case 'g': fact = 1073741824; break;
22522                 default:
22523                   fact = 0;
22524                   Message("Invalid number string in %s: %s", envName, envString);
22525                   Warning("%s must comprise only digits [0-9].", envName);
22526                 }
22527               break;
22528             }
22529         }
22530 
22531       if (fact) envValue = fact * atol(envString);
22532 
22533       if (FileDebug) Message("Set %s to %ld", envName, envValue);
22534     }
22535 
22536   return envValue;
22537 }
22538 
22539 static void
file_initialize(void)22540 file_initialize(void)
22541 {
22542 #ifdef HAVE_LIBPTHREAD
22543   // initialize global API mutex lock
22544   pthread_mutex_init(&_file_mutex, NULL);
22545 #endif
22546 
22547   long value;
22548 
22549   FileInfo = file_getenv("FILE_INFO") > 0;
22550 
22551   value = file_getenv("FILE_DEBUG");
22552   if (value >= 0) FileDebug = (int) value;
22553 
22554   value = file_getenv("FILE_MAX");
22555   if (value >= 0) _file_max = (int) value;
22556 
22557   if (FileInfo) fprintf(stderr, "FILE_MAX = %d\n", _file_max);
22558 
22559   value = file_getenv("FILE_BUFSIZE");
22560   if (value >= 0)
22561     FileBufferSizeEnv = value;
22562   else
22563     {
22564       value = file_getenv("GRIB_API_IO_BUFFER_SIZE");
22565       if (value >= 0) FileBufferSizeEnv = value;
22566     }
22567 
22568   if (FileInfo) fprintf(stderr, "FILE_BUFSIZE = %ld\n", FileBufferSizeEnv);
22569 
22570   value = file_getenv("FILE_TYPE_READ");
22571   if (value > 0)
22572     {
22573       switch (value)
22574         {
22575         case FILE_TYPE_OPEN:
22576         case FILE_TYPE_FOPEN: FileTypeRead = (int) value; break;
22577         default: Warning("File type %ld not implemented!", value);
22578         }
22579     }
22580 
22581   if (FileInfo) fprintf(stderr, "FILE_TYPE_READ = %d [%d:%s  %d:%s]\n", FileTypeRead,
22582                         FILE_TYPE_OPEN, ftname[FILE_TYPE_OPEN], FILE_TYPE_FOPEN, ftname[FILE_TYPE_FOPEN]);
22583 
22584   value = file_getenv("FILE_TYPE_WRITE");
22585   if (value > 0)
22586     {
22587       switch (value)
22588         {
22589         case FILE_TYPE_OPEN:
22590         case FILE_TYPE_FOPEN: FileTypeWrite = (int) value; break;
22591         default: Warning("File type %ld not implemented!", value);
22592         }
22593     }
22594 
22595   if (FileInfo) fprintf(stderr, "FILE_TYPE_WRITE = %d [%d:%s  %d:%s]\n", FileTypeWrite,
22596                         FILE_TYPE_OPEN, ftname[FILE_TYPE_OPEN], FILE_TYPE_FOPEN, ftname[FILE_TYPE_FOPEN]);
22597 
22598 #ifdef O_NONBLOCK
22599   FileFlagWrite = O_NONBLOCK;
22600 #endif
22601   char *envString = getenv("FILE_FLAG_WRITE");
22602   if (envString)
22603     {
22604 #ifdef O_NONBLOCK
22605       if (strcmp(envString, "NONBLOCK") == 0) FileFlagWrite = O_NONBLOCK;
22606 #endif
22607     }
22608 
22609   value = file_getenv("FILE_BUFTYPE");
22610 #ifndef HAVE_MMAP
22611   if (value == FILE_BUFTYPE_MMAP)
22612     {
22613       Warning("MMAP not available!");
22614       value = 0;
22615     }
22616 #endif
22617   if (value > 0)
22618     {
22619       switch (value)
22620         {
22621         case FILE_BUFTYPE_STD:
22622         case FILE_BUFTYPE_MMAP: FileBufferTypeEnv = (int) value; break;
22623         default: Warning("File buffer type %ld not implemented!", value);
22624         }
22625     }
22626 
22627   if (FileInfo) fprintf(stderr, "FILE_BUFTYPE = %d [%d:%s  %d:%s]\n", FileBufferTypeEnv,
22628                         FILE_BUFTYPE_STD, fbtname[FILE_BUFTYPE_STD], FILE_BUFTYPE_MMAP, fbtname[FILE_BUFTYPE_MMAP]);
22629 
22630   file_list_new();
22631   atexit(file_list_delete);
22632 
22633   FILE_LOCK();
22634   file_init_pointer();
22635   FILE_UNLOCK();
22636 
22637   if (FileDebug) atexit(file_table_print);
22638 
22639   _file_init = true;
22640 }
22641 
22642 static size_t
file_get_buffersize(bfile_t * fileptr)22643 file_get_buffersize(bfile_t *fileptr)
22644 {
22645   size_t buffersize = 0;
22646 
22647   if (FileBufferSizeEnv >= 0)
22648     buffersize = (size_t) FileBufferSizeEnv;
22649   else if (fileptr->bufferSize > 0)
22650     buffersize = fileptr->bufferSize;
22651   else
22652     {
22653       buffersize = fileptr->blockSize * 4;
22654       if (buffersize < FileBufferSizeMin) buffersize = FileBufferSizeMin;
22655     }
22656 
22657   return buffersize;
22658 }
22659 
22660 static void
file_set_buffer(bfile_t * fileptr)22661 file_set_buffer(bfile_t *fileptr)
22662 {
22663   size_t buffersize = 0;
22664 
22665   if (fileptr->mode == 'r')
22666     {
22667       if (FileBufferTypeEnv)
22668         fileptr->bufferType = FileBufferTypeEnv;
22669       else if (fileptr->bufferType == 0)
22670         fileptr->bufferType = FILE_BUFTYPE_STD;
22671 
22672       buffersize = file_get_buffersize(fileptr);
22673 
22674       if ((size_t) fileptr->size < buffersize) buffersize = (size_t) fileptr->size;
22675 
22676       if (fileptr->bufferType == FILE_BUFTYPE_MMAP)
22677         {
22678           size_t blocksize = (size_t) file_pagesize();
22679           size_t minblocksize = 4 * blocksize;
22680           buffersize = buffersize - buffersize % minblocksize;
22681 
22682           if (buffersize < (size_t) fileptr->size && buffersize < minblocksize) buffersize = minblocksize;
22683         }
22684 
22685       if (buffersize == 0) buffersize = 1;
22686     }
22687   else
22688     {
22689       fileptr->bufferType = FILE_BUFTYPE_STD;
22690       buffersize = file_get_buffersize(fileptr);
22691     }
22692 
22693   if (fileptr->bufferType == FILE_BUFTYPE_STD || fileptr->type == FILE_TYPE_FOPEN)
22694     {
22695       if (buffersize > 0)
22696         {
22697           fileptr->buffer = (char *) malloc(buffersize);
22698           if (fileptr->buffer == NULL) SysError("Allocation of file buffer failed!");
22699         }
22700     }
22701 
22702   if (fileptr->type == FILE_TYPE_FOPEN)
22703     if (setvbuf(fileptr->fp, fileptr->buffer, fileptr->buffer ? _IOFBF : _IONBF, buffersize)) SysError("setvbuf failed!");
22704 
22705   fileptr->bufferSize = buffersize;
22706 }
22707 
22708 static int
file_fill_buffer(bfile_t * fileptr)22709 file_fill_buffer(bfile_t *fileptr)
22710 {
22711   ssize_t nread;
22712   long offset = 0;
22713 
22714   if (FileDebug) Message("file ptr = %p  Cnt = %ld", fileptr, fileptr->bufferCnt);
22715 
22716   if ((fileptr->flag & FILE_EOF) != 0) return EOF;
22717 
22718   if (fileptr->buffer == NULL) file_set_buffer(fileptr);
22719 
22720   if (fileptr->bufferSize == 0) return EOF;
22721 
22722   const int fd = fileptr->fd;
22723 
22724 #ifdef HAVE_MMAP
22725   if (fileptr->bufferType == FILE_BUFTYPE_MMAP)
22726     {
22727       if (fileptr->bufferPos >= fileptr->size)
22728         {
22729           nread = 0;
22730         }
22731       else
22732         {
22733 #ifdef CDI
22734           xassert(fileptr->bufferSize <= SSIZE_MAX);
22735 #endif
22736           nread = (ssize_t) fileptr->bufferSize;
22737           if ((nread + fileptr->bufferPos) > fileptr->size) nread = fileptr->size - fileptr->bufferPos;
22738 
22739           if (fileptr->buffer)
22740             {
22741               const int ret = munmap(fileptr->buffer, fileptr->mappedSize);
22742               if (ret == -1) SysError("munmap error for read %s", fileptr->name);
22743               fileptr->buffer = NULL;
22744             }
22745 
22746           fileptr->mappedSize = (size_t) nread;
22747 
22748           fileptr->buffer = (char *) mmap(NULL, (size_t) nread, PROT_READ, MAP_PRIVATE, fd, fileptr->bufferPos);
22749 
22750           if (fileptr->buffer == MAP_FAILED) SysError("mmap error for read %s", fileptr->name);
22751 
22752           offset = fileptr->position - fileptr->bufferPos;
22753         }
22754     }
22755   else
22756 #endif
22757     {
22758       const off_t retseek = lseek(fileptr->fd, fileptr->bufferPos, SEEK_SET);
22759       if (retseek == (off_t) -1) SysError("lseek error at pos %ld file %s", (long) fileptr->bufferPos, fileptr->name);
22760 
22761       nread = read(fd, fileptr->buffer, fileptr->bufferSize);
22762       if (nread > 0) offset = fileptr->position - fileptr->bufferPos;
22763     }
22764 
22765   if (nread <= 0)
22766     {
22767       fileptr->flag |= (nread == 0) ? FILE_EOF : FILE_ERROR;
22768       fileptr->bufferCnt = 0;
22769       return EOF;
22770     }
22771 
22772   fileptr->bufferPtr = fileptr->buffer;
22773   fileptr->bufferCnt = (size_t) nread;
22774 
22775   fileptr->bufferStart = fileptr->bufferPos;
22776   fileptr->bufferPos += nread;
22777   fileptr->bufferEnd = fileptr->bufferPos - 1;
22778 
22779   if (FileDebug)
22780     {
22781       Message("fileID = %d  Val     = %d", fileptr->self, (int) fileptr->buffer[0]);
22782       Message("fileID = %d  Start   = %ld", fileptr->self, fileptr->bufferStart);
22783       Message("fileID = %d  End     = %ld", fileptr->self, fileptr->bufferEnd);
22784       Message("fileID = %d  nread   = %ld", fileptr->self, nread);
22785       Message("fileID = %d  offset  = %ld", fileptr->self, offset);
22786       Message("fileID = %d  Pos     = %ld", fileptr->self, fileptr->bufferPos);
22787       Message("fileID = %d  postion = %ld", fileptr->self, fileptr->position);
22788     }
22789 
22790   if (offset > 0)
22791     {
22792       if (offset > nread) Error("Internal problem with buffer handling. nread = %d offset = %d", nread, offset);
22793 
22794       fileptr->bufferPtr += offset;
22795       fileptr->bufferCnt -= (size_t) offset;
22796     }
22797 
22798   fileptr->bufferNumFill++;
22799 
22800   return (unsigned char) *fileptr->bufferPtr;
22801 }
22802 
22803 static void
file_copy_from_buffer(bfile_t * fileptr,void * ptr,size_t size)22804 file_copy_from_buffer(bfile_t *fileptr, void *ptr, size_t size)
22805 {
22806   if (FileDebug) Message("size = %ld  Cnt = %ld", size, fileptr->bufferCnt);
22807 
22808   if (fileptr->bufferCnt < size) Error("Buffer too small. bufferCnt = %d", fileptr->bufferCnt);
22809 
22810   if (size == 1)
22811     {
22812       ((char *) ptr)[0] = fileptr->bufferPtr[0];
22813 
22814       fileptr->bufferPtr++;
22815       fileptr->bufferCnt--;
22816     }
22817   else
22818     {
22819       memcpy(ptr, fileptr->bufferPtr, size);
22820 
22821       fileptr->bufferPtr += size;
22822       fileptr->bufferCnt -= size;
22823     }
22824 }
22825 
22826 static size_t
file_read_from_buffer(bfile_t * fileptr,void * ptr,size_t size)22827 file_read_from_buffer(bfile_t *fileptr, void *ptr, size_t size)
22828 {
22829   size_t nread;
22830   size_t offset = 0;
22831 
22832   if (FileDebug) Message("size = %ld  Cnt = %ld", size, (long) fileptr->bufferCnt);
22833 
22834   if (((long) fileptr->bufferCnt) < 0L) Error("Internal problem. bufferCnt = %ld", (long) fileptr->bufferCnt);
22835 
22836   size_t rsize = size;
22837 
22838   while (fileptr->bufferCnt < rsize)
22839     {
22840       nread = fileptr->bufferCnt;
22841       // fprintf(stderr, "rsize = %d nread = %d\n", (int) rsize, (int) nread);
22842       if (nread > (size_t) 0) file_copy_from_buffer(fileptr, (char *) ptr + offset, nread);
22843       offset += nread;
22844       rsize = (nread < rsize) ? rsize - nread : 0;
22845 
22846       if (file_fill_buffer(fileptr) == EOF) break;
22847     }
22848 
22849   nread = size - offset;
22850 
22851   if (fileptr->bufferCnt < nread) nread = fileptr->bufferCnt;
22852 
22853   if (nread > (unsigned) 0) file_copy_from_buffer(fileptr, (char *) ptr + offset, nread);
22854 
22855   return (nread + offset);
22856 }
22857 
22858 void
fileSetBufferSize(int fileID,long buffersize)22859 fileSetBufferSize(int fileID, long buffersize)
22860 {
22861 #ifdef CDI
22862   xassert(buffersize >= 0);
22863 #endif
22864   bfile_t *fileptr = file_to_pointer(fileID);
22865   if (fileptr) fileptr->bufferSize = (size_t) buffersize;
22866 }
22867 
22868 /*
22869  *   Open a file. Returns file ID, or -1 on error
22870  */
22871 int
fileOpen(const char * filename,const char * mode)22872 fileOpen(const char *filename, const char *mode)
22873 #ifdef CDI
22874 {
22875   int (*myFileOpen)(const char *filename, const char *mode)
22876       = (int (*)(const char *, const char *)) namespaceSwitchGet(NSSWITCH_FILE_OPEN).func;
22877   return myFileOpen(filename, mode);
22878 }
22879 
22880 int
fileOpen_serial(const char * filename,const char * mode)22881 fileOpen_serial(const char *filename, const char *mode)
22882 #endif
22883 {
22884   FILE *fp = NULL;  // file pointer    (used for write)
22885   int fd = -1;      // file descriptor (used for read)
22886   int fileID = FILE_UNDEFID;
22887   struct stat filestat;
22888   bfile_t *fileptr = NULL;
22889 
22890   FILE_INIT();
22891 
22892   const int fmode = tolower((int) mode[0]);
22893 
22894   switch (fmode)
22895     {
22896     case 'r':
22897       if (FileTypeRead == FILE_TYPE_FOPEN)
22898         fp = fopen(filename, "rb");
22899       else
22900         fd = open(filename, O_RDONLY | O_BINARY);
22901       break;
22902     case 'x': fp = fopen(filename, "rb"); break;
22903     case 'w':
22904       if (FileTypeWrite == FILE_TYPE_FOPEN)
22905         fp = fopen(filename, "wb");
22906       else
22907         fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY | FileFlagWrite, 0666);
22908       break;
22909     case 'a': fp = fopen(filename, "ab"); break;
22910     default: Error("Mode %c unexpected!", fmode);
22911     }
22912 
22913   if (FileDebug)
22914     if (fp == NULL && fd == -1) Message("Open failed on %s mode %c errno %d", filename, fmode, errno);
22915 
22916   if (fp)
22917     {
22918       if (stat(filename, &filestat) != 0) return fileID;
22919 
22920       fileptr = file_new_entry();
22921       if (fileptr)
22922         {
22923           fileID = fileptr->self;
22924           fileptr->fp = fp;
22925         }
22926     }
22927   else if (fd >= 0)
22928     {
22929       if (fstat(fd, &filestat) != 0) return fileID;
22930 
22931       fileptr = file_new_entry();
22932       if (fileptr)
22933         {
22934           fileID = fileptr->self;
22935           fileptr->fd = fd;
22936         }
22937     }
22938 
22939   if (fileID >= 0)
22940     {
22941       fileptr->mode = fmode;
22942       fileptr->name = strdup(filename);
22943 
22944 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
22945       fileptr->blockSize = (size_t) filestat.st_blksize;
22946 #else
22947       fileptr->blockSize = (size_t) 4096;
22948 #endif
22949 
22950       // clang-format off
22951       if      (fmode == 'r') fileptr->type = FileTypeRead;
22952       else if (fmode == 'w') fileptr->type = FileTypeWrite;
22953       else                   fileptr->type = FILE_TYPE_FOPEN;
22954       // clang-format on
22955 
22956       if (fmode == 'r') fileptr->size = filestat.st_size;
22957 
22958       // if (fileptr->type == FILE_TYPE_FOPEN) file_set_buffer(fileptr);
22959       file_set_buffer(fileptr);
22960 
22961       if (FileDebug) Message("File %s opened with ID %d", filename, fileID);
22962     }
22963 
22964   return fileID;
22965 }
22966 
22967 /*
22968  *   Close a file.
22969  */
22970 int
fileClose(int fileID)22971 fileClose(int fileID)
22972 #ifdef CDI
22973 {
22974   int (*myFileClose)(int fileID) = (int (*)(int)) namespaceSwitchGet(NSSWITCH_FILE_CLOSE).func;
22975   return myFileClose(fileID);
22976 }
22977 
22978 int
fileClose_serial(int fileID)22979 fileClose_serial(int fileID)
22980 #endif
22981 {
22982   int ret;
22983   double rout = 0;
22984 
22985   bfile_t *fileptr = file_to_pointer(fileID);
22986   if (fileptr == NULL)
22987     {
22988       file_pointer_info(__func__, fileID);
22989       return 1;
22990     }
22991 
22992   const char *name = fileptr->name;
22993 
22994   if (FileDebug) Message("fileID = %d  filename = %s", fileID, name);
22995 
22996   if (FileInfo)
22997     {
22998       fprintf(stderr, "____________________________________________\n");
22999       fprintf(stderr, " file ID          : %d\n", fileID);
23000       fprintf(stderr, " file name        : %s\n", fileptr->name);
23001       fprintf(stderr, " file type        : %d (%s)\n", fileptr->type, ftname[fileptr->type]);
23002 
23003       if (fileptr->type == FILE_TYPE_FOPEN)
23004         fprintf(stderr, " file pointer     : %p\n", (void *) fileptr->fp);
23005       else
23006         {
23007           fprintf(stderr, " file descriptor  : %d\n", fileptr->fd);
23008           fprintf(stderr, " file flag        : %d\n", FileFlagWrite);
23009         }
23010       fprintf(stderr, " file mode        : %c\n", fileptr->mode);
23011 
23012       if (sizeof(off_t) > sizeof(long))
23013         {
23014 #ifdef _WIN32
23015           fprintf(stderr, " file size        : %I64d\n", (long long) fileptr->size);
23016           if (fileptr->type == FILE_TYPE_OPEN) fprintf(stderr, " file position    : %I64d\n", (long long) fileptr->position);
23017           fprintf(stderr, " bytes transfered : %I64d\n", (long long) fileptr->byteTrans);
23018 #else
23019           fprintf(stderr, " file size        : %lld\n", (long long) fileptr->size);
23020           if (fileptr->type == FILE_TYPE_OPEN) fprintf(stderr, " file position    : %lld\n", (long long) fileptr->position);
23021           fprintf(stderr, " bytes transfered : %lld\n", (long long) fileptr->byteTrans);
23022 #endif
23023         }
23024       else
23025         {
23026           fprintf(stderr, " file size        : %ld\n", (long) fileptr->size);
23027           if (fileptr->type == FILE_TYPE_OPEN) fprintf(stderr, " file position    : %ld\n", (long) fileptr->position);
23028           fprintf(stderr, " bytes transfered : %ld\n", (long) fileptr->byteTrans);
23029         }
23030 
23031       if (fileptr->time_in_sec > 0) rout = (double) fileptr->byteTrans / (1024. * 1024. * fileptr->time_in_sec);
23032 
23033       fprintf(stderr, " wall time [s]    : %.2f\n", fileptr->time_in_sec);
23034       fprintf(stderr, " data rate [MB/s] : %.1f\n", rout);
23035 
23036       fprintf(stderr, " file access      : %ld\n", fileptr->access);
23037       if (fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN)
23038         {
23039           fprintf(stderr, " buffer type      : %d (%s)\n", fileptr->bufferType, fbtname[fileptr->bufferType]);
23040           fprintf(stderr, " num buffer fill  : %ld\n", fileptr->bufferNumFill);
23041         }
23042       fprintf(stderr, " buffer size      : %lu\n", (unsigned long) fileptr->bufferSize);
23043       fprintf(stderr, " block size       : %lu\n", (unsigned long) fileptr->blockSize);
23044       fprintf(stderr, " page size        : %d\n", file_pagesize());
23045       fprintf(stderr, "--------------------------------------------\n");
23046     }
23047 
23048   if (fileptr->type == FILE_TYPE_FOPEN)
23049     {
23050       ret = fclose(fileptr->fp);
23051       if (ret == EOF) SysError("EOF returned for close of %s!", name);
23052     }
23053   else
23054     {
23055 #ifdef HAVE_MMAP
23056       if (fileptr->buffer && fileptr->mappedSize)
23057         {
23058           ret = munmap(fileptr->buffer, fileptr->mappedSize);
23059           if (ret == -1) SysError("munmap error for close %s", fileptr->name);
23060           fileptr->buffer = NULL;
23061         }
23062 #endif
23063       ret = close(fileptr->fd);
23064       if (ret == -1) SysError("EOF returned for close of %s!", name);
23065     }
23066 
23067   if (fileptr->name) free((void *) fileptr->name);
23068   if (fileptr->buffer) free((void *) fileptr->buffer);
23069 
23070   file_delete_entry(fileptr);
23071 
23072   return 0;
23073 }
23074 
23075 int
filePtrGetc(void * vfileptr)23076 filePtrGetc(void *vfileptr)
23077 {
23078   int ivalue = EOF;
23079 
23080   bfile_t *fileptr = (bfile_t *) vfileptr;
23081   if (fileptr)
23082     {
23083       if (fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN)
23084         {
23085           int fillret = (fileptr->bufferCnt == 0) ? file_fill_buffer(fileptr) : 0;
23086           if (fillret >= 0)
23087             {
23088               ivalue = (unsigned char) *fileptr->bufferPtr++;
23089               fileptr->bufferCnt--;
23090               fileptr->position++;
23091 
23092               fileptr->byteTrans++;
23093               fileptr->access++;
23094             }
23095         }
23096       else
23097         {
23098           ivalue = fgetc(fileptr->fp);
23099           if (ivalue >= 0)
23100             {
23101               fileptr->byteTrans++;
23102               fileptr->access++;
23103             }
23104           else
23105             fileptr->flag |= FILE_EOF;
23106         }
23107     }
23108 
23109   return ivalue;
23110 }
23111 
23112 int
fileGetc(int fileID)23113 fileGetc(int fileID)
23114 {
23115   bfile_t *fileptr = file_to_pointer(fileID);
23116   return filePtrGetc((void *) fileptr);
23117 }
23118 
23119 size_t
filePtrRead(void * vfileptr,void * restrict ptr,size_t size)23120 filePtrRead(void *vfileptr, void *restrict ptr, size_t size)
23121 {
23122   size_t nread = 0;
23123 
23124   bfile_t *fileptr = (bfile_t *) vfileptr;
23125   if (fileptr)
23126     {
23127       if (fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN)
23128         {
23129           nread = file_read_from_buffer(fileptr, ptr, size);
23130         }
23131       else
23132         {
23133           nread = fread(ptr, 1, size, fileptr->fp);
23134           if (nread != size) fileptr->flag |= (nread == 0) ? FILE_EOF : FILE_ERROR;
23135         }
23136 
23137       fileptr->position += (off_t) nread;
23138       fileptr->byteTrans += (off_t) nread;
23139       fileptr->access++;
23140     }
23141 
23142   if (FileDebug) Message("size %ld  nread %ld", size, nread);
23143 
23144   return nread;
23145 }
23146 
23147 size_t
fileRead(int fileID,void * restrict ptr,size_t size)23148 fileRead(int fileID, void *restrict ptr, size_t size)
23149 {
23150   size_t nread = 0;
23151 
23152   bfile_t *fileptr = file_to_pointer(fileID);
23153   if (fileptr)
23154     {
23155       double t_begin = 0.0;
23156 
23157       if (FileInfo) t_begin = file_time();
23158 
23159       if (fileptr->type == FILE_TYPE_OPEN)
23160         {
23161           nread = file_read_from_buffer(fileptr, ptr, size);
23162         }
23163       else
23164         {
23165           nread = fread(ptr, 1, size, fileptr->fp);
23166           if (nread != size) fileptr->flag |= (nread == 0) ? FILE_EOF : FILE_ERROR;
23167         }
23168 
23169       if (FileInfo) fileptr->time_in_sec += file_time() - t_begin;
23170 
23171       fileptr->position += (off_t) nread;
23172       fileptr->byteTrans += (off_t) nread;
23173       fileptr->access++;
23174     }
23175 
23176   if (FileDebug) Message("size %ld  nread %ld", size, nread);
23177 
23178   return nread;
23179 }
23180 
23181 size_t
fileWrite(int fileID,const void * restrict ptr,size_t size)23182 fileWrite(int fileID, const void *restrict ptr, size_t size)
23183 {
23184   size_t nwrite = 0;
23185 
23186   bfile_t *fileptr = file_to_pointer(fileID);
23187   if (fileptr)
23188     {
23189       double t_begin = 0.0;
23190 
23191       if (FileInfo) t_begin = file_time();
23192 
23193       if (fileptr->type == FILE_TYPE_FOPEN)
23194         {
23195           nwrite = fwrite(ptr, 1, size, fileptr->fp);
23196         }
23197       else
23198         {
23199           ssize_t temp = write(fileptr->fd, ptr, size);
23200           if (temp == -1) perror("error writing to file");
23201           nwrite = (temp == -1) ? 0 : (size_t) temp;
23202         }
23203 
23204       if (FileInfo) fileptr->time_in_sec += file_time() - t_begin;
23205 
23206       fileptr->position += (off_t) nwrite;
23207       fileptr->byteTrans += (off_t) nwrite;
23208       fileptr->access++;
23209     }
23210 
23211   return nwrite;
23212 }
23213 /*
23214  * Local Variables:
23215  * c-file-style: "Java"
23216  * c-basic-offset: 2
23217  * indent-tabs-mode: nil
23218  * show-trailing-whitespace: t
23219  * require-trailing-newline: t
23220  * End:
23221  */
23222 #ifdef  HAVE_CONFIG_H
23223 #endif
23224 
23225 #include <stdio.h>
23226 #include <float.h>
23227 #include <math.h>
23228 
23229 #ifndef  M_SQRT2
23230 #define  M_SQRT2  1.41421356237309504880168872420969808
23231 #endif
23232 
23233 
23234 
23235 static
cpledn(size_t kn,size_t kodd,double * pfn,double pdx,int kflag,double * pw,double * pdxn,double * pxmod)23236 void cpledn(size_t kn, size_t kodd, double *pfn, double pdx, int kflag,
23237             double *pw, double *pdxn, double *pxmod)
23238 {
23239   /* 1.0 Newton iteration step */
23240 
23241   double zdlx = pdx;
23242   double zdlk = 0.0;
23243   if ( kodd == 0 ) zdlk = 0.5*pfn[0];
23244   double zdlxn  = 0.0;
23245   double zdlldn = 0.0;
23246 
23247   size_t ik = 1;
23248 
23249   if ( kflag == 0 )
23250     {
23251       for ( size_t jn = 2-kodd; jn <= kn; jn += 2 )
23252 	{
23253 	  /* normalised ordinary Legendre polynomial == \overbar{p_n}^0 */
23254 	  zdlk   = zdlk + pfn[ik]*cos((double)(jn)*zdlx);
23255 	  /* normalised derivative == d/d\theta(\overbar{p_n}^0) */
23256 	  zdlldn = zdlldn - pfn[ik]*(double)(jn)*sin((double)(jn)*zdlx);
23257 	  ik++;
23258 	}
23259       /* Newton method */
23260       double zdlmod = -(zdlk/zdlldn);
23261       zdlxn = zdlx + zdlmod;
23262       *pdxn = zdlxn;
23263       *pxmod = zdlmod;
23264     }
23265 
23266   /* 2.0 Compute weights */
23267 
23268   if ( kflag == 1 )
23269     {
23270       for ( size_t jn = 2-kodd; jn <= kn; jn += 2 )
23271 	{
23272 	  /* normalised derivative */
23273 	  zdlldn = zdlldn - pfn[ik]*(double)(jn)*sin((double)(jn)*zdlx);
23274 	  ik++;
23275 	}
23276       *pw = (double)(2*kn+1)/(zdlldn*zdlldn);
23277     }
23278 
23279   return;
23280 }
23281 
23282 static
gawl(double * pfn,double * pl,double * pw,size_t kn)23283 void gawl(double *pfn, double *pl, double *pw, size_t kn)
23284 {
23285   double pmod = 0;
23286   double zw = 0;
23287   double zdlxn = 0;
23288 
23289   /* 1.0 Initizialization */
23290 
23291   int iflag  =  0;
23292   int itemax = 20;
23293 
23294   size_t iodd   = (kn % 2);
23295 
23296   double zdlx   =  *pl;
23297 
23298   /* 2.0 Newton iteration */
23299 
23300   for ( int jter = 1; jter <= itemax+1; jter++ )
23301     {
23302       cpledn(kn, iodd, pfn, zdlx, iflag, &zw, &zdlxn, &pmod);
23303       zdlx = zdlxn;
23304       if (iflag == 1) break;
23305       if (fabs(pmod) <= DBL_EPSILON*1000.0) iflag = 1;
23306     }
23307 
23308   *pl = zdlxn;
23309   *pw = zw;
23310 
23311   return;
23312 }
23313 
23314 static
gauaw(size_t kn,double * restrict pl,double * restrict pw)23315 void gauaw(size_t kn, double *restrict pl, double *restrict pw)
23316 {
23317   /*
23318    * 1.0 Initialize Fourier coefficients for ordinary Legendre polynomials
23319    *
23320    * Belousov, Swarztrauber, and ECHAM use zfn(0,0) = sqrt(2)
23321    * IFS normalisation chosen to be 0.5*Integral(Pnm**2) = 1 (zfn(0,0) = 2.0)
23322    */
23323   double *zfn    = (double *) Malloc((kn+1) * (kn+1) * sizeof(double));
23324   double *zfnlat = (double *) Malloc((kn/2+1+1)*sizeof(double));
23325 
23326   zfn[0] = M_SQRT2;
23327   for ( size_t jn = 1; jn <= kn; jn++ )
23328     {
23329       double zfnn = zfn[0];
23330       for (size_t jgl = 1; jgl <= jn; jgl++)
23331 	{
23332 	  zfnn *= sqrt(1.0-0.25/((double)(jgl*jgl)));
23333 	}
23334 
23335       zfn[jn*(kn+1)+jn] = zfnn;
23336 
23337       size_t iodd = jn % 2;
23338       for ( size_t jgl = 2; jgl <= jn-iodd; jgl += 2 )
23339 	{
23340 	  zfn[jn*(kn+1)+jn-jgl] = zfn[jn*(kn+1)+jn-jgl+2]
23341 	    *((double)((jgl-1)*(2*jn-jgl+2)))/((double)(jgl*(2*jn-jgl+1)));
23342 	}
23343     }
23344 
23345 
23346   /* 2.0 Gaussian latitudes and weights */
23347 
23348   size_t iodd = kn % 2;
23349   size_t ik = iodd;
23350   for ( size_t jgl = iodd; jgl <= kn; jgl += 2 )
23351     {
23352       zfnlat[ik] = zfn[kn*(kn+1)+jgl];
23353       ik++;
23354     }
23355 
23356   /* 2.1 Find first approximation of the roots of the Legendre polynomial of degree kn */
23357 
23358   size_t ins2 = kn/2+(kn % 2);
23359   double z;
23360 
23361   for ( size_t jgl = 1; jgl <= ins2; jgl++ )
23362     {
23363       z = ((double)(4*jgl-1))*M_PI/((double)(4*kn+2));
23364       pl[jgl-1] = z+1.0/(tan(z)*((double)(8*kn*kn)));
23365     }
23366 
23367   /* 2.2 Computes roots and weights for transformed theta */
23368 
23369   for ( size_t jgl = ins2; jgl >= 1 ; jgl-- )
23370     {
23371       size_t jglm1 = jgl-1;
23372       gawl(zfnlat, &(pl[jglm1]), &(pw[jglm1]), kn);
23373     }
23374 
23375   /* convert to physical latitude */
23376 
23377   for ( size_t jgl = 0; jgl < ins2; jgl++ )
23378     {
23379       pl[jgl] = cos(pl[jgl]);
23380     }
23381 
23382   for ( size_t jgl = 1; jgl <= kn/2; jgl++ )
23383     {
23384       size_t jglm1 = jgl-1;
23385       size_t isym =  kn-jgl;
23386       pl[isym] =  -pl[jglm1];
23387       pw[isym] =  pw[jglm1];
23388     }
23389 
23390   Free(zfnlat);
23391   Free(zfn);
23392 
23393   return;
23394 }
23395 
23396 
gaussianLatitudes(double * latitudes,double * weights,size_t nlat)23397 void gaussianLatitudes(double *latitudes, double *weights, size_t nlat)
23398 {
23399   //gauaw_old(latitudes, weights, nlat);
23400   gauaw(nlat, latitudes, weights);
23401 }
23402 
23403 
isGaussGrid(size_t ysize,double yinc,const double * yvals)23404 bool isGaussGrid(size_t ysize, double yinc, const double *yvals)
23405 {
23406   bool lgauss = false;
23407 
23408   if ( IS_EQUAL(yinc, 0) && ysize > 2 ) // check if gaussian
23409     {
23410       size_t i;
23411       double *yv = (double *) Malloc(ysize*sizeof(double));
23412       double *yw = (double *) Malloc(ysize*sizeof(double));
23413       gaussianLatitudes(yv, yw, ysize);
23414       Free(yw);
23415       for ( i = 0; i < ysize; i++ )
23416         yv[i] = asin(yv[i])/M_PI*180.0;
23417 
23418       for ( i = 0; i < ysize; i++ )
23419         if ( fabs(yv[i] - yvals[i]) > ((yv[0] - yv[1])/500) ) break;
23420 
23421       if ( i == ysize ) lgauss = true;
23422 
23423       // check S->N
23424       if ( lgauss == false )
23425         {
23426           for ( i = 0; i < ysize; i++ )
23427             if ( fabs(yv[i] - yvals[ysize-i-1]) > ((yv[0] - yv[1])/500) ) break;
23428 
23429           if ( i == ysize ) lgauss = true;
23430         }
23431 
23432       Free(yv);
23433     }
23434 
23435   return lgauss;
23436 }
23437 
23438 /*
23439 #define NGL  48
23440 
23441 int main (int rgc, char *argv[])
23442 {
23443   int ngl = NGL;
23444   double plo[NGL], pwo[NGL];
23445   double pl[NGL], pw[NGL];
23446 
23447   int i;
23448 
23449   gauaw(ngl, pl, pw);
23450   for (i = 0; i < ngl; i++)
23451     {
23452       pl[i]  = asin(pl[i])/M_PI*180.0;
23453       plo[i] = asin(plo[i])/M_PI*180.0;
23454     }
23455 
23456   for (i = 0; i < ngl; i++)
23457     {
23458       fprintf(stderr, "%4d%25.18f%25.18f%25.18f%25.18f\n", i+1, pl[i], pw[i], pl[i]-plo[i], pw[i]-pwo[i]);
23459     }
23460 
23461   return 0;
23462 }
23463 */
23464 /*
23465  * Local Variables:
23466  * c-file-style: "Java"
23467  * c-basic-offset: 2
23468  * indent-tabs-mode: nil
23469  * show-trailing-whitespace: t
23470  * require-trailing-newline: t
23471  * End:
23472  */
23473 #ifdef HAVE_CONFIG_H
23474 #endif
23475 
23476 #ifdef HAVE_LIBGRIB_API
23477 #include <grib_api.h>
23478 #endif
23479 
23480 #include <stdio.h>
23481 
23482 
23483 static char gribapi_libvers[64] = "";
23484 #ifdef HAVE_LIBGRIB_API
23485 static bool gribapi_libvers_init;
23486 #endif
23487 
23488 
gribapiLibraryVersion(int * major_version,int * minor_version,int * revision_version)23489 void gribapiLibraryVersion(int* major_version, int* minor_version, int* revision_version)
23490 {
23491 #ifdef HAVE_LIBGRIB_API
23492   long version = grib_get_api_version();
23493   (*major_version)    = (int)(version/10000);
23494   (*minor_version)    = (int)((version-(*major_version)*10000)/100);
23495   (*revision_version) = (int)(version-(*major_version)*10000-(*minor_version)*100);
23496 #else
23497   (*major_version)    = 0;
23498   (*minor_version)    = 0;
23499   (*revision_version) = 0;
23500 #endif
23501 }
23502 
gribapiLibraryVersionString(void)23503 const char *gribapiLibraryVersionString(void)
23504 {
23505 #ifdef HAVE_LIBGRIB_API
23506   if (!gribapi_libvers_init)
23507     {
23508       int major_version, minor_version, revision_version;
23509 
23510       gribapiLibraryVersion(&major_version, &minor_version, &revision_version);
23511 
23512       sprintf(gribapi_libvers, "%d.%d.%d", major_version, minor_version, revision_version);
23513       gribapi_libvers_init = true;
23514     }
23515 #endif
23516 
23517   return (gribapi_libvers);
23518 }
23519 
23520 
gribContainersNew(stream_t * streamptr)23521 void gribContainersNew(stream_t * streamptr)
23522 {
23523   const int editionNumber = (streamptr->filetype == CDI_FILETYPE_GRB) ? 1 : 2;
23524 
23525 #ifdef HAVE_LIBCGRIBEX
23526   if ( editionNumber == 1 && !CDI_gribapi_grib1 )
23527     {
23528     }
23529   else
23530 #endif
23531     {
23532       const int nvars = streamptr->nvars;
23533 
23534 #ifdef GRIBCONTAINER2D
23535       gribContainer_t **gribContainers;
23536       gribContainers = (gribContainer_t **) Malloc(nvars*sizeof(gribContainer_t *));
23537 
23538       for ( int varID = 0; varID < nvars; ++varID )
23539         {
23540           const int nlevs = streamptr->vars[varID].nlevs;
23541           gribContainers[varID] = (gribContainer_t *) Malloc(nlevs*sizeof(gribContainer_t));
23542 
23543           for ( int levelID = 0; levelID < nlevs; ++levelID )
23544             {
23545               gribContainers[varID][levelID].gribHandle = gribHandleNew(editionNumber);
23546               gribContainers[varID][levelID].init = false;
23547             }
23548 	}
23549 
23550       streamptr->gribContainers = (void **) gribContainers;
23551 #else
23552       gribContainer_t *gribContainers
23553         = (gribContainer_t *) Malloc((size_t)nvars*sizeof(gribContainer_t));
23554 
23555       for ( int varID = 0; varID < nvars; ++varID )
23556         {
23557           gribContainers[varID].gribHandle = gribHandleNew(editionNumber);
23558           gribContainers[varID].init = false;
23559 	}
23560 
23561       streamptr->gribContainers = (void *) gribContainers;
23562 #endif
23563     }
23564 }
23565 
23566 
gribContainersDelete(stream_t * streamptr)23567 void gribContainersDelete(stream_t * streamptr)
23568 {
23569   if ( streamptr->gribContainers )
23570     {
23571       const int nvars = streamptr->nvars;
23572 
23573 #ifdef GRIBCONTAINER2D
23574       gribContainer_t **gribContainers = (gribContainer_t **) streamptr->gribContainers;
23575 
23576       for ( int varID = 0; varID < nvars; ++varID )
23577 	{
23578           const int nlevs = streamptr->vars[varID].nlevs;
23579           for ( int levelID = 0; levelID < nlevs; ++levelID )
23580             {
23581               gribHandleDelete(gribContainers[varID][levelID].gribHandle);
23582             }
23583           Free(gribContainers[varID]);
23584 	}
23585 #else
23586       gribContainer_t *gribContainers = (gribContainer_t *) streamptr->gribContainers;
23587 
23588       for ( int varID = 0; varID < nvars; ++varID )
23589 	{
23590           gribHandleDelete(gribContainers[varID].gribHandle);
23591 	}
23592 #endif
23593 
23594       Free(gribContainers);
23595 
23596       streamptr->gribContainers = NULL;
23597     }
23598 }
23599 /*
23600  * Local Variables:
23601  * c-file-style: "Java"
23602  * c-basic-offset: 2
23603  * indent-tabs-mode: nil
23604  * show-trailing-whitespace: t
23605  * require-trailing-newline: t
23606  * End:
23607  */
23608 #ifndef INCLUDE_GUARD_CDI_GRIBAPI_UTILITIES_H
23609 #define INCLUDE_GUARD_CDI_GRIBAPI_UTILITIES_H
23610 
23611 #ifdef HAVE_LIBGRIB_API
23612 
23613 
23614 #include <grib_api.h>
23615 
23616 #include <stdbool.h>
23617 
23618 char* gribCopyString(grib_handle* gribHandle, const char* key);
23619 bool gribCheckString(grib_handle* gribHandle, const char* key, const char* expectedValue);
23620 
23621 bool gribCheckLong(grib_handle* gribHandle, const char* key, long expectedValue);
23622 long gribGetLong(grib_handle* gh, const char* key);
23623 long gribGetLongDefault(grib_handle* gribHandle, const char* key, long defaultValue);
23624 
23625 double gribGetDouble(grib_handle* gh, const char* key);
23626 double gribGetDoubleDefault(grib_handle* gribHandle, const char* key, double defaultValue);
23627 
23628 size_t gribGetArraySize(grib_handle* gribHandle, const char* key);
23629 void gribGetDoubleArray(grib_handle* gribHandle, const char* key, double* array);       //The caller is responsible to ensure a sufficiently large buffer.
23630 void gribGetLongArray(grib_handle* gribHandle, const char* key, long* array);   //The caller is responsible to ensure a sufficiently large buffer.
23631 
23632 long gribEditionNumber(grib_handle* gh);
23633 char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType);     //Returns NULL if timeType is kCdiTimeType_endTime and the field does not have an integration period (statistical data).
23634 int gribapiTimeIsFC(grib_handle *gh);
23635 int gribapiGetTsteptype(grib_handle *gh);
23636 int gribGetDatatype(grib_handle* gribHandle);
23637 int gribapiGetParam(grib_handle *gh);
23638 int gribapiGetGridType(grib_handle *gh);
23639 bool gribapiGetGrid(grib_handle *gh, grid_t *grid);
23640 size_t gribapiGetGridsize(grib_handle *gh);
23641 
23642 
23643 #ifdef HIRLAM_EXTENSIONS
23644 void gribapiSetDataTimeRangeIndicator(grib_handle *gh, int timeRangeIndicator);
23645 void gribapiGetDataTimeRangeIndicator(grib_handle *gh, int *timeRangeIndicator);
23646 #endif // #ifdef HIRLAM_EXTENSIONS
23647 
23648 extern struct cdiGribAPI_ts_str_map_elem {
23649   long productionTemplate;
23650   const char sname[8];
23651 } cdiGribAPI_ts_str_map[];
23652 
23653 #endif
23654 
23655 #endif
23656 
23657 /*
23658  * Local Variables:
23659  * c-file-style: "Java"
23660  * c-basic-offset: 2
23661  * indent-tabs-mode: nil
23662  * show-trailing-whitespace: t
23663  * require-trailing-newline: t
23664  * End:
23665  */
23666 #ifdef HAVE_CONFIG_H
23667 #endif
23668 
23669 #ifdef HAVE_LIBGRIB_API
23670 
23671 
23672 
23673 #include <assert.h>
23674 #include <time.h>
23675 
23676 #define FAIL_ON_GRIB_ERROR(function, gribHandle, key, ...) do\
23677 {\
23678   const int errorCode = (int)function(gribHandle, key, __VA_ARGS__);  \
23679   if(errorCode)\
23680     {\
23681       fprintf(stderr, "%s:%d: Error in function `%s`: `%s` returned error code %d for key \"%s\"", __FILE__, __LINE__, __func__, #function, errorCode, key);\
23682       exit(errorCode);\
23683     }\
23684 } while(0)
23685 
23686 //A simple wrapper for grib_get_string() that returns a newly allocated string.
gribCopyString(grib_handle * gribHandle,const char * key)23687 char* gribCopyString(grib_handle* gribHandle, const char* key)
23688 {
23689   size_t length;
23690 #ifdef HAVE_GRIB_GET_LENGTH
23691   if (!grib_get_length(gribHandle, key, &length))
23692     {
23693       char *result = (char *)Malloc(length);
23694       if (!grib_get_string(gribHandle, key, result, &length))
23695         result = (char *) Realloc(result, length);
23696       else
23697         {
23698           Free(result);
23699           result = NULL;
23700         }
23701       return result;
23702     }
23703   else
23704     return NULL;
23705 #else
23706   length = 1024;         /* there's an implementation limit
23707                           * that makes strings longer than
23708                           * this unlikely in grib_api versions
23709                           * not providing grib_get_length */
23710   int rc;
23711   char *result = (char *) Malloc(length);
23712   while ((rc = grib_get_string(gribHandle, key, result, &length))
23713          == GRIB_BUFFER_TOO_SMALL || rc == GRIB_ARRAY_TOO_SMALL)
23714     {
23715       if (length <= 1024UL * 1024UL)
23716         {
23717           length *= 2;
23718           result = Realloc(result, length);
23719         }
23720       else
23721         break;
23722     }
23723   if (!rc)
23724     result = Realloc(result, length);
23725   else
23726     {
23727       Free(result);
23728       result = NULL;
23729     }
23730   return result;
23731 #endif
23732 }
23733 
23734 //A simple wrapper for grib_get_string() for the usecase that the result is only compared to a given constant string.
23735 //Returns true if the key exists and the value is equal to the given string.
gribCheckString(grib_handle * gribHandle,const char * key,const char * expectedValue)23736 bool gribCheckString(grib_handle* gribHandle, const char* key, const char* expectedValue)
23737 {
23738   size_t expectedLength = strlen(expectedValue) + 1;
23739 #ifdef HAVE_GRIB_GET_LENGTH
23740   size_t length;
23741   if(grib_get_length(gribHandle, key, &length)) return false;
23742   if(length != expectedLength) return false;
23743   char *value = (char *) Malloc(length);
23744   if(grib_get_string(gribHandle, key, value, &length)) return false;
23745   int rc = !strcmp(value, expectedValue);
23746   Free(value);
23747 #else
23748   char *value = gribCopyString(gribHandle, key);
23749   int rc = value ? (strlen(value) + 1 == expectedLength ? !strcmp(value, expectedValue) : false) : false;
23750   Free(value);
23751 #endif
23752   return rc;
23753 }
23754 
23755 //A simple wrapper for grib_get_long() for the usecase that the result is only compared to a given constant value.
23756 //Returns true if the key exists and the value is equal to the given one.
gribCheckLong(grib_handle * gribHandle,const char * key,long expectedValue)23757 bool gribCheckLong(grib_handle* gribHandle, const char* key, long expectedValue)
23758 {
23759   long value;
23760   if(grib_get_long(gribHandle, key, &value)) return false;
23761   return value == expectedValue;
23762 }
23763 
23764 //A simple wrapper for grib_get_long() for the usecase that failure to fetch the value is fatal.
gribGetLong(grib_handle * gh,const char * key)23765 long gribGetLong(grib_handle* gh, const char* key)
23766 {
23767   long result;
23768   FAIL_ON_GRIB_ERROR(grib_get_long, gh, key, &result);
23769   return result;
23770 }
23771 
23772 //A simple wrapper for grib_get_long() for the usecase that a default value is used in the case that the operation fails.
gribGetLongDefault(grib_handle * gribHandle,const char * key,long defaultValue)23773 long gribGetLongDefault(grib_handle* gribHandle, const char* key, long defaultValue)
23774 {
23775   long result;
23776   if ( grib_get_long(gribHandle, key, &result) || result == GRIB_MISSING_LONG )
23777     result = defaultValue;
23778   return result;
23779 }
23780 
23781 //A simple wrapper for grib_get_double() for the usecase that failure to fetch the value is fatal.
gribGetDouble(grib_handle * gh,const char * key)23782 double gribGetDouble(grib_handle* gh, const char* key)
23783 {
23784   double result;
23785   FAIL_ON_GRIB_ERROR(grib_get_double, gh, key, &result);
23786   return result;
23787 }
23788 
23789 //A sample wrapper for grib_get_double() for the usecase that a default value is used in the case that the operation fails.
gribGetDoubleDefault(grib_handle * gribHandle,const char * key,double defaultValue)23790 double gribGetDoubleDefault(grib_handle* gribHandle, const char* key, double defaultValue)
23791 {
23792   double result;
23793   if ( grib_get_double(gribHandle, key, &result)
23794        || IS_EQUAL(result, GRIB_MISSING_DOUBLE) )
23795     result = defaultValue;
23796   return result;
23797 }
23798 
23799 //A simple wrapper for grib_get_size() for the usecase that failure to fetch the value is fatal.
gribGetArraySize(grib_handle * gribHandle,const char * key)23800 size_t gribGetArraySize(grib_handle* gribHandle, const char* key)
23801 {
23802   size_t result;
23803   FAIL_ON_GRIB_ERROR(grib_get_size, gribHandle, key, &result);
23804   return result;
23805 }
23806 
23807 //A simple wrapper for grib_get_double_array() for the usecase that failure to fetch the data is fatal.
gribGetDoubleArray(grib_handle * gribHandle,const char * key,double * array)23808 void gribGetDoubleArray(grib_handle* gribHandle, const char* key, double* array)
23809 {
23810   size_t valueCount = gribGetArraySize(gribHandle, key);
23811   FAIL_ON_GRIB_ERROR(grib_get_double_array, gribHandle, key, array, &valueCount);
23812 }
23813 
23814 //A simple wrapper for grib_get_long_array() for the usecase that failure to fetch the data is fatal.
gribGetLongArray(grib_handle * gribHandle,const char * key,long * array)23815 void gribGetLongArray(grib_handle* gribHandle, const char* key, long* array)
23816 {
23817   size_t valueCount = gribGetArraySize(gribHandle, key);
23818   FAIL_ON_GRIB_ERROR(grib_get_long_array, gribHandle, key, array, &valueCount);
23819 }
23820 
23821 
23822 //We need the edition number so frequently, that it's convenient to give it its own function.
gribEditionNumber(grib_handle * gh)23823 long gribEditionNumber(grib_handle* gh)
23824 {
23825   return gribGetLong(gh, "editionNumber");
23826 }
23827 
23828 //This return value of this should be passed to a call to resetTz(), it is a malloc'ed string with the content of the TZ environment variable before the call (or NULL if that was not set).
setUtc()23829 static char* setUtc()
23830 {
23831   char* temp = getenv("TZ"), *result = NULL;
23832   if(temp) result = strdup(temp);
23833   setenv("TZ", "UTC", 1);
23834   return result;
23835 }
23836 
23837 //Undoes the effect of setUtc(), pass to it the return value of the corresponding setUtc() call, it will free the string.
resetTz(char * savedTz)23838 static void resetTz(char* savedTz)
23839 {
23840   if(savedTz)
23841     {
23842       setenv("TZ", savedTz, 1);
23843       Free(savedTz);
23844     }
23845   else
23846     {
23847       unsetenv("TZ");
23848     }
23849 }
23850 
23851 //This function uses the system functions to normalize the date representation according to the gregorian calendar.
23852 //Returns zero on success.
normalizeDays(struct tm * me)23853 static int normalizeDays(struct tm* me)
23854 {
23855   char* savedTz = setUtc();     //Ensure that mktime() does not interprete the date according to our local time zone.
23856 
23857   int result = mktime(me) == (time_t)-1;        //This does all the heavy lifting.
23858 
23859   resetTz(savedTz);
23860   return result;
23861 }
23862 
23863 //Returns zero on success.
addSecondsToDate(struct tm * me,long long amount)23864 static int addSecondsToDate(struct tm* me, long long amount)
23865 {
23866   //It is irrelevant here whether days are zero or one based, the correction would have be undone again so that it is effectless.
23867   long long seconds = ((me->tm_mday*24ll + me->tm_hour)*60 + me->tm_min)*60 + me->tm_sec;    //The portion of the date that uses fixed increments.
23868   seconds += amount;
23869   me->tm_mday = (int)(seconds / 24 / 60 / 60);
23870   seconds -= (long long)me->tm_mday * 24 * 60 * 60;
23871   me->tm_hour = (int)(seconds / 60 / 60);
23872   seconds -= (long long)me->tm_hour * 60 * 60;
23873   me->tm_min = (int)(seconds / 60);
23874   seconds -= (long long)(me->tm_min * 60);
23875   me->tm_sec = (int)seconds;
23876   return normalizeDays(me);
23877 }
23878 
addMonthsToDate(struct tm * me,long long amount)23879 static void addMonthsToDate(struct tm* me, long long amount)
23880 {
23881   long long months = me->tm_year*12ll + me->tm_mon;
23882   months += amount;
23883   me->tm_year = (int)(months/12);
23884   months -= (long long)me->tm_year*12;
23885   me->tm_mon = (int)months;
23886 }
23887 
23888 //unit is a value according to code table 4.4 of the GRIB2 specification, returns non-zero on error
addToDate(struct tm * me,long long amount,long unit)23889 static int addToDate(struct tm* me, long long amount, long unit)
23890 {
23891   switch(unit)
23892     {
23893       case 0: return addSecondsToDate(me,       60*amount);   // minute
23894       case 1: return addSecondsToDate(me,    60*60*amount);   // hour
23895       case 2: return addSecondsToDate(me, 24*60*60*amount);   // day
23896 
23897       case 3: addMonthsToDate(me,        amount); return 0;   // month
23898       case 4: addMonthsToDate(me,     12*amount); return 0;   // year
23899       case 5: addMonthsToDate(me,  10*12*amount); return 0;   // decade
23900       case 6: addMonthsToDate(me,  30*12*amount); return 0;   // normal
23901       case 7: addMonthsToDate(me, 100*12*amount); return 0;   // century
23902 
23903       case 10: return addSecondsToDate(me,  3*60*60*amount);  // eighth of a day
23904       case 11: return addSecondsToDate(me,  6*60*60*amount);  // quarter day
23905       case 12: return addSecondsToDate(me, 12*60*60*amount);  // half day
23906       case 13: return addSecondsToDate(me,          amount);  // second
23907 
23908       default: return 1;        //reserved, unknown, or missing
23909     }
23910 }
23911 
makeDateString(struct tm * me)23912 static char *makeDateString(struct tm *me)
23913 {
23914   char *result= (char *) Malloc(4+1+ 2+1+ 2+1+ 2+1+ 2+1+ 2+ 4+ 1);
23915   sprintf(result, "%04d-%02d-%02dT%02d:%02d:%02d.000", me->tm_year + 1900, me->tm_mon + 1, me->tm_mday, me->tm_hour, me->tm_min, me->tm_sec);
23916   return result;
23917 }
23918 
23919 //FIXME: This ignores any calendar definition that might be present.
23920 //XXX: Identification templates are not implemented in grib_api-1.12.3, so even if I implemented the other calendars now, it wouldn't be possible to use them.
getAvailabilityOfRelativeTimes(grib_handle * gh,bool * outHaveForecastTime,bool * outHaveTimeRange)23921 static int getAvailabilityOfRelativeTimes(grib_handle* gh, bool* outHaveForecastTime, bool* outHaveTimeRange)
23922 {
23923   switch(gribGetLong(gh, "productDefinitionTemplateNumber"))
23924     {
23925       case 20: case 30: case 31: case 254: case 311: case 2000:
23926         *outHaveForecastTime = false, *outHaveTimeRange = false;
23927         return 0;
23928 
23929       //case 55 and case 40455 are the same: 55 is the proposed standard value, 40455 is the value in the local use range that is used by the dwd until the standard is updated.
23930       case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
23931       case 15: case 32: case 33: case 40: case 41: case 44: case 45: case 48:
23932       case 51: case 53: case 54: case 55: case 56: case 57: case 58: case 60:
23933       case 1000: case 1002: case 1100: case 40033: case 40455: case 40456:
23934         *outHaveForecastTime = true, *outHaveTimeRange = false;
23935         return 0;
23936 
23937       case 8: case 9: case 10: case 11: case 12: case 13: case 14:
23938       case 34: case 42: case 43: case 46: case 47: case 61: case 67: case 68: case 91:
23939       case 1001: case 1101: case 40034:
23940         *outHaveForecastTime = true, *outHaveTimeRange = true;
23941         return 0;
23942 
23943       default:
23944         return 1;
23945     }
23946 }
23947 
23948 
gribMakeTimeString(grib_handle * gh,CdiTimeType timeType)23949 char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType)
23950 {
23951   // Get the parts of the reference date.
23952   struct tm date;
23953   date.tm_mon = (int)gribGetLong(gh, "month") - 1;   // months are zero based in struct tm and one based in GRIB
23954   date.tm_mday = (int)gribGetLong(gh, "day");
23955   date.tm_hour = (int)gribGetLong(gh, "hour");
23956   date.tm_min = (int)gribGetLong(gh, "minute");
23957   date.tm_isdst = 0;
23958 
23959   if(gribEditionNumber(gh) == 1)
23960     {
23961       date.tm_year = (int)gribGetLong(gh, "yearOfCentury");  // years are -1900 based both in struct tm and GRIB1
23962     }
23963   else
23964     {
23965       date.tm_year = (int)gribGetLong(gh, "year") - 1900;   // years are -1900 based in struct tm and zero based in GRIB2
23966       date.tm_sec = (int)gribGetLong(gh, "second");
23967 
23968       // If the start or end time are requested, we need to take the relative times into account.
23969       if(timeType != kCdiTimeType_referenceTime)
23970         {
23971           // Determine whether we have a forecast time and a time range.
23972           bool haveForecastTime, haveTimeRange;
23973           if(getAvailabilityOfRelativeTimes(gh, &haveForecastTime, &haveTimeRange)) return NULL;
23974           if(timeType == kCdiTimeType_endTime && !haveTimeRange) return NULL;     //tell the caller that the requested time does not exist
23975 
23976           // If we have relative times, apply the relative times to the date
23977           if(haveForecastTime)
23978             {
23979               long offset = gribGetLongDefault(gh, "forecastTime", 0);  // if(stepUnits == indicatorOfUnitOfTimeRange) assert(startStep == forecastTime)
23980               long offsetUnit = gribGetLongDefault(gh, "indicatorOfUnitOfTimeRange", 255);
23981               if(addToDate(&date, offset, offsetUnit)) return NULL;
23982               if(timeType == kCdiTimeType_endTime)
23983                 {
23984                   assert(haveTimeRange);
23985                   long range = gribGetLongDefault(gh, "lengthOfTimeRange", 0);       // if(stepUnits == indicatorOfUnitForTimeRange) assert(endStep == startStep + lengthOfTimeRange)
23986                   long rangeUnit = gribGetLongDefault(gh, "indicatorOfUnitForTimeRange", 255);
23987                   if(addToDate(&date, range, rangeUnit)) return NULL;
23988                 }
23989             }
23990         }
23991     }
23992 
23993   //Bake the date into a string.
23994   return makeDateString(&date);
23995 }
23996 
23997 
gribapiTimeIsFC(grib_handle * gh)23998 int gribapiTimeIsFC(grib_handle *gh)
23999 {
24000   if (gribEditionNumber(gh) <= 1) return true;
24001 
24002   long sigofrtime;
24003   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "significanceOfReferenceTime", &sigofrtime);
24004   return sigofrtime != 3;
24005 }
24006 
24007 
24008 struct cdiGribAPI_ts_str_map_elem cdiGribAPI_ts_str_map[] = {
24009   // clang-format off
24010   [TSTEP_INSTANT] = {  0, "instant" },
24011   [TSTEP_AVG]     = {  8, "avg" },
24012   [TSTEP_ACCUM]   = {  8, "accum" },
24013   [TSTEP_MAX]     = {  8, "max" },
24014   [TSTEP_MIN]     = {  8, "min" },
24015   [TSTEP_DIFF]    = {  8, "diff" },
24016   [TSTEP_RMS]     = {  8, "rms" },
24017   [TSTEP_SD]      = {  8, "sd" },
24018   [TSTEP_COV]     = {  8, "cov" },
24019   [TSTEP_RATIO]   = {  8, "ratio" },
24020   [TSTEP_SUM]     = {  8, "sum" },
24021                     {  0, "" }
24022   // clang-format on
24023 };
24024 
24025 
24026 //Fetches the value of the "stepType" key and converts it into a constant in the TSTEP_* range.
gribapiGetTsteptype(grib_handle * gh)24027 int gribapiGetTsteptype(grib_handle *gh)
24028 {
24029   size_t len = 256;
24030   char stepType[256];
24031   int tsteptype = TSTEP_INSTANT;
24032   static bool lprint = true;
24033 
24034   if ( gribapiTimeIsFC(gh) )
24035     {
24036       const int status = grib_get_string(gh, "stepType", stepType, &len);
24037       if ( status == 0 && len > 1 && len < 256 )
24038         {
24039           for (int i = TSTEP_INSTANT; cdiGribAPI_ts_str_map[i].sname[0]; ++i)
24040             if ( strncmp(cdiGribAPI_ts_str_map[i].sname, stepType, len) == 0 )
24041               {
24042                 tsteptype = i;
24043                 goto tsteptypeFound;
24044               }
24045 
24046           if ( lprint )
24047             {
24048               Message("Time stepType %s unsupported, set to instant!", stepType);
24049               lprint = false;
24050             }
24051           // printf("stepType: %s %ld %d\n", stepType, len, tsteptype);
24052         }
24053 
24054 #ifdef HIRLAM_EXTENSIONS
24055       {
24056       // Normaly cdo looks in grib for attribute called "stepType", see above.
24057       // BUT NWP models such as Hirlam and Harmonie 37h1.2, use "timeRangeIndicator" instead!
24058       // Where for example:       0: for instanteneous fields; 4: for accumulated fields
24059       //  0:   Forecast product valid at reference time + P1
24060       //  2:   Product with a valid time ranging between reference time + P1 and reference time + P2
24061       //  4:   Accumulation (reference time + P1 to reference time + P2)
24062       //  5:   Difference(reference time + P2 minus reference time + P1) product considered valid at reference time + P2
24063       // More details on WMO standards:
24064       //               http://www.wmo.int/pages/prog/www/WDM/Guides/Guide-binary-2.html
24065       //tsteptype = TSTEP_INSTANT;  // default value for any case
24066       long timeRangeIND = 0; // typically 0: for instanteneous fields; 4: for accumulated fields
24067       int rc = grib_get_long(gh, "timeRangeIndicator", &timeRangeIND);
24068       if (rc != 0) {
24069             //if ( lprint )
24070             Warning("Could not get 'stepType' either 'timeRangeIndicator'. Using default!");
24071             return tsteptype;
24072       }
24073       extern int cdiGribUseTimeRangeIndicator;
24074       cdiGribUseTimeRangeIndicator = 1;
24075       switch ( timeRangeIND )
24076           {
24077               case 0:  tsteptype = TSTEP_INSTANT; break;
24078               case 2:  tsteptype = TSTEP_INSTANT2;
24079                        strcpy(stepType, "instant2");  // was incorrectly set before into accum
24080                        break;
24081               case 4:  tsteptype = TSTEP_ACCUM; break;
24082               case 5:  tsteptype = TSTEP_DIFF; break;
24083               default:
24084                 if ( lprint )
24085                 {
24086                   if (CDI_Debug)
24087                       Warning("timeRangeIND = %d;  stepType= %s; tsteptype=%d unsupported timeRangeIND at the moment, set to instant!", timeRangeIND, stepType, tsteptype);
24088                   lprint = false;
24089                 }
24090                 break;
24091           }
24092       if (CDI_Debug)
24093           Warning("timeRangeIND = %d;  stepType= %s; tsteptype=%d", timeRangeIND, stepType, tsteptype);
24094       }
24095 #endif // HIRLAM_EXTENSIONS
24096     }
24097 
24098   tsteptypeFound:
24099   return tsteptype;
24100 }
24101 
24102 
gribGetDatatype(grib_handle * gribHandle)24103 int gribGetDatatype(grib_handle* gribHandle)
24104 {
24105   int datatype;
24106   if(gribEditionNumber(gribHandle) > 1 && gribCheckString(gribHandle, "packingType", "grid_ieee"))
24107     {
24108       datatype = gribCheckLong(gribHandle, "precision", 1) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64;
24109     }
24110   else
24111     {
24112       long bitsPerValue;
24113       datatype = (!grib_get_long(gribHandle, "bitsPerValue", &bitsPerValue) && bitsPerValue > 0 && bitsPerValue <= 32) ? (int)bitsPerValue : CDI_DATATYPE_PACK;
24114     }
24115   return datatype;
24116 }
24117 
24118 
gribapiGetParam(grib_handle * gh)24119 int gribapiGetParam(grib_handle *gh)
24120 {
24121   long pdis, pcat, pnum;
24122   if ( gribEditionNumber(gh) <= 1 )
24123     {
24124       pdis = 255;
24125       FAIL_ON_GRIB_ERROR(grib_get_long, gh, "table2Version", &pcat);
24126       FAIL_ON_GRIB_ERROR(grib_get_long, gh, "indicatorOfParameter", &pnum);
24127     }
24128   else
24129     {
24130       FAIL_ON_GRIB_ERROR(grib_get_long, gh, "discipline", &pdis);
24131       if(grib_get_long(gh, "parameterCategory", &pcat)) pcat = 0;
24132       if(grib_get_long(gh, "parameterNumber", &pnum)) pnum = 0;
24133     }
24134   return cdiEncodeParam((int)pnum, (int)pcat, (int)pdis);
24135 }
24136 
24137 
gribapiGetGridType(grib_handle * gh)24138 int gribapiGetGridType(grib_handle *gh)
24139 {
24140   int gridtype = GRID_GENERIC;
24141   const long gridDefinitionTemplateNumber = gribGetLongDefault(gh, "gridDefinitionTemplateNumber", -1);
24142   switch (gridDefinitionTemplateNumber)
24143     {
24144       case  GRIB2_GTYPE_LATLON:
24145         gridtype = ( gribGetLong(gh, "Ni") == (long) GRIB_MISSING_LONG ) ? GRID_GENERIC : GRID_LONLAT;
24146         break;
24147       case  GRIB2_GTYPE_GAUSSIAN:
24148         gridtype = ( gribGetLong(gh, "Ni") == (long) GRIB_MISSING_LONG ) ? GRID_GAUSSIAN_REDUCED : GRID_GAUSSIAN;
24149         break;
24150       case GRIB2_GTYPE_LATLON_ROT:   gridtype = GRID_PROJECTION; break;
24151       case GRIB2_GTYPE_LCC:          gridtype = CDI_PROJ_LCC; break;
24152       case GRIB2_GTYPE_STERE:        gridtype = CDI_PROJ_STERE; break;
24153       case GRIB2_GTYPE_SPECTRAL:     gridtype = GRID_SPECTRAL; break;
24154       case GRIB2_GTYPE_GME:          gridtype = GRID_GME; break;
24155       case GRIB2_GTYPE_UNSTRUCTURED: gridtype = GRID_UNSTRUCTURED; break;
24156       default:
24157         {
24158           char mesg[256];
24159           size_t len = sizeof(mesg);
24160           if (grib_get_string(gh, "gridType", mesg, &len) != 0) mesg[0] = 0;
24161           Warning("gridDefinitionTemplateNumber %d unsupported (gridType=%s)!", gridDefinitionTemplateNumber, mesg);
24162         }
24163     }
24164 
24165   return gridtype;
24166 }
24167 
24168 static
gribapiGetIsRotated(grib_handle * gh)24169 int gribapiGetIsRotated(grib_handle *gh)
24170 {
24171   return gribGetLongDefault(gh, "gridDefinitionTemplateNumber", -1) == GRIB2_GTYPE_LATLON_ROT;
24172 }
24173 
24174 
gribapiGetGridsize(grib_handle * gh)24175 size_t gribapiGetGridsize(grib_handle *gh)
24176 {
24177   size_t gridsize;
24178   FAIL_ON_GRIB_ERROR(grib_get_size, gh, "values", &gridsize);
24179   return gridsize;
24180 }
24181 
24182 static
gribapiGetGridGaussianReduced(grib_handle * gh,grid_t * grid,int editionNumber,size_t numberOfPoints)24183 void gribapiGetGridGaussianReduced(grib_handle *gh, grid_t *grid, int editionNumber, size_t numberOfPoints)
24184 {
24185   long lpar;
24186   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfParallelsBetweenAPoleAndTheEquator", &lpar);
24187   grid->np = (int)lpar;
24188 
24189   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nj", &lpar);
24190   size_t nlat = (size_t)lpar;
24191 
24192   grid->size = numberOfPoints;
24193 
24194   grid->reducedPointsSize = (int)nlat;
24195   grid->reducedPoints = (int *) Malloc(nlat * sizeof(int));
24196   long *pl     = (long *) Malloc(nlat * sizeof(long));
24197   size_t dummy = nlat;
24198   FAIL_ON_GRIB_ERROR(grib_get_long_array, gh, "pl", pl, &dummy);
24199   for ( size_t i = 0; i < nlat; ++i ) grid->reducedPoints[i] = (int)pl[i];
24200   Free(pl);
24201 
24202   grid->y.size  = nlat;
24203   grid->x.inc   = 0;
24204   grid->y.inc   = 0;
24205   grid->x.flag  = 0;
24206   FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfFirstGridPointInDegrees", &grid->x.first);
24207   FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfLastGridPointInDegrees",  &grid->x.last);
24208   FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfFirstGridPointInDegrees",  &grid->y.first);
24209   FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfLastGridPointInDegrees",   &grid->y.last);
24210 
24211   // FAIL_ON_GRIB_ERROR(grib_get_double, gh, "iDirectionIncrementInDegrees", &grid->x.inc);
24212   // if ( IS_EQUAL(grid->x.inc, GRIB_MISSING_DOUBLE) ) grid->x.inc = 0;
24213 
24214   /* if ( IS_NOT_EQUAL(grid->x.first, 0) || IS_NOT_EQUAL(grid->x.last, 0) ) */
24215   {
24216     if ( grid->x.size > 1 )
24217       {
24218         if ( (grid->x.first > grid->x.last) && (grid->x.first >= 180) ) grid->x.first -= 360;
24219 
24220         if ( editionNumber <= 1 )
24221           {
24222             /* correct xinc if necessary */
24223             if ( IS_EQUAL(grid->x.first, 0) && grid->x.last > 354 )
24224               {
24225                 double xinc = 360. / grid->x.size;
24226                 if ( fabs(grid->x.inc-xinc) > 0.0 )
24227                   {
24228                     grid->x.inc = xinc;
24229                     if ( CDI_Debug ) Message("set xinc to %g", grid->x.inc);
24230                   }
24231               }
24232           }
24233       }
24234     grid->x.flag = 2;
24235   }
24236   grid->y.flag = 0;
24237   /* if ( IS_NOT_EQUAL(grid->y.first, 0) || IS_NOT_EQUAL(grid->y.last, 0) ) */
24238   {
24239     if ( grid->y.size > 1 )
24240       {
24241         if ( editionNumber <= 1 )
24242           {
24243           }
24244       }
24245     grid->y.flag = 2;
24246   }
24247 }
24248 
24249 static
gribapiGetGridRegular(grib_handle * gh,grid_t * grid,int editionNumber,int gridtype,size_t numberOfPoints)24250 void gribapiGetGridRegular(grib_handle *gh, grid_t *grid, int editionNumber, int gridtype, size_t numberOfPoints)
24251 {
24252   long lpar;
24253   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Ni", &lpar);
24254   const size_t nlon = (size_t) lpar;
24255   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nj", &lpar);
24256   const size_t nlat = (size_t) lpar;
24257 
24258   if ( gridtype == GRID_GAUSSIAN )
24259     {
24260       FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfParallelsBetweenAPoleAndTheEquator", &lpar);
24261       grid->np = (int)lpar;
24262     }
24263 
24264   if ( numberOfPoints != nlon*nlat )
24265     Error("numberOfPoints (%zu) and gridSize (%zu) differ!", numberOfPoints, nlon*nlat);
24266 
24267   grid->size   = numberOfPoints;
24268   grid->x.size = nlon;
24269   grid->y.size = nlat;
24270   grid->x.inc  = 0;
24271   grid->y.inc  = 0;
24272   grid->x.flag = 0;
24273   FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfFirstGridPointInDegrees", &grid->x.first);
24274   FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfLastGridPointInDegrees",  &grid->x.last);
24275   FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfFirstGridPointInDegrees",  &grid->y.first);
24276   FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfLastGridPointInDegrees",   &grid->y.last);
24277   if ( nlon > 1 )
24278     FAIL_ON_GRIB_ERROR(grib_get_double, gh, "iDirectionIncrementInDegrees", &grid->x.inc);
24279   if ( gridtype == GRID_LONLAT && nlat > 1 )
24280     FAIL_ON_GRIB_ERROR(grib_get_double, gh, "jDirectionIncrementInDegrees", &grid->y.inc);
24281 
24282   long iscan = 0, jscan = 0;
24283   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "iScansNegatively", &iscan);
24284   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "jScansPositively", &jscan);
24285   if (  iscan ) grid->x.inc = - grid->x.inc;
24286   if ( !jscan ) grid->y.inc = - grid->y.inc;
24287 
24288   if ( grid->x.inc < -999 || grid->x.inc > 999 ) grid->x.inc = 0;
24289   if ( grid->y.inc < -999 || grid->y.inc > 999 ) grid->y.inc = 0;
24290 
24291   /* if ( IS_NOT_EQUAL(grid->x.first, 0) || IS_NOT_EQUAL(grid->x.last, 0) ) */
24292   {
24293     if ( grid->x.size > 1 )
24294       {
24295         //if ( editionNumber <= 1 )
24296         {
24297           if ( grid->x.last < grid->x.first )
24298             {
24299               if ( grid->x.first >= 180 )
24300                 grid->x.first -= 360;
24301               else
24302                 grid->x.last += 360;
24303             }
24304 
24305           // correct xinc if necessary
24306           if ( IS_EQUAL(grid->x.first, 0) && grid->x.last > 354 && grid->x.last < 360 )
24307             {
24308               double xinc = 360. / grid->x.size;
24309               if ( fabs(grid->x.inc-xinc) > 0.0 )
24310                 {
24311                   grid->x.inc = xinc;
24312                   if ( CDI_Debug ) Message("set xinc to %g", grid->x.inc);
24313                 }
24314             }
24315         }
24316       }
24317     grid->x.flag = 2;
24318   }
24319 
24320   grid->y.flag = 0;
24321   /* if ( IS_NOT_EQUAL(grid->y.first, 0) || IS_NOT_EQUAL(grid->y.last, 0) ) */
24322   {
24323     if ( grid->y.size > 1 )
24324       {
24325         if ( editionNumber <= 1 )
24326           {
24327           }
24328       }
24329     grid->y.flag = 2;
24330   }
24331 }
24332 
24333 static
gribapiGetGridProj(grib_handle * gh,grid_t * grid,size_t numberOfPoints)24334 void gribapiGetGridProj(grib_handle *gh, grid_t *grid, size_t numberOfPoints)
24335 {
24336   long lpar;
24337   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nx", &lpar);
24338   const size_t nlon = (size_t)lpar;
24339   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Ny", &lpar);
24340   const size_t nlat = (size_t)lpar;
24341 
24342   if ( numberOfPoints != nlon*nlat )
24343     Error("numberOfPoints (%zu) and gridSize (%zu) differ!", numberOfPoints, nlon*nlat);
24344 
24345   grid->size  = numberOfPoints;
24346   grid->x.size = nlon;
24347   grid->y.size = nlat;
24348 
24349   double xinc, yinc;
24350   FAIL_ON_GRIB_ERROR(grib_get_double, gh, "DxInMetres", &xinc);
24351   FAIL_ON_GRIB_ERROR(grib_get_double, gh, "DyInMetres", &yinc);
24352 
24353   grid->x.first = 0;
24354   grid->x.last  = 0;
24355   grid->x.inc   = xinc;
24356   grid->y.first = 0;
24357   grid->y.last  = 0;
24358   grid->y.inc   = yinc;
24359   grid->x.flag  = 2;
24360   grid->y.flag  = 2;
24361 }
24362 
24363 static
gribapiGetGridSpectral(grib_handle * gh,grid_t * grid,size_t datasize)24364 void gribapiGetGridSpectral(grib_handle *gh, grid_t *grid, size_t datasize)
24365 {
24366   size_t len = 256;
24367   char typeOfPacking[256];
24368   FAIL_ON_GRIB_ERROR(grib_get_string, gh, "packingType", typeOfPacking, &len);
24369   grid->lcomplex = 0;
24370   if ( strncmp(typeOfPacking, "spectral_complex", len) == 0 ) grid->lcomplex = 1;
24371 
24372   grid->size = datasize;
24373 
24374   long lpar;
24375   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "J", &lpar);
24376   grid->trunc = (int)lpar;
24377 }
24378 
24379 static
gribapiGetGridGME(grib_handle * gh,grid_t * grid,size_t numberOfPoints)24380 void gribapiGetGridGME(grib_handle *gh, grid_t *grid, size_t numberOfPoints)
24381 {
24382   grid->size = numberOfPoints;
24383 
24384   long lpar;
24385   if ( grib_get_long(gh, "nd", &lpar) == 0 ) grid->gme.nd  = (int)lpar;
24386   if ( grib_get_long(gh, "Ni", &lpar) == 0 ) grid->gme.ni  = (int)lpar;
24387   if ( grib_get_long(gh, "n2", &lpar) == 0 ) grid->gme.ni2 = (int)lpar;
24388   if ( grib_get_long(gh, "n3", &lpar) == 0 ) grid->gme.ni3 = (int)lpar;
24389 }
24390 
24391 static
gribapiGetGridUnstructured(grib_handle * gh,grid_t * grid,size_t numberOfPoints)24392 void gribapiGetGridUnstructured(grib_handle *gh, grid_t *grid, size_t numberOfPoints)
24393 {
24394   unsigned char uuid[CDI_UUID_SIZE];
24395   /*
24396     char reference_link[8192];
24397     size_t len = sizeof(reference_link);
24398     reference_link[0] = 0;
24399   */
24400   grid->size = numberOfPoints;
24401 
24402   long lpar;
24403   if ( grib_get_long(gh, "numberOfGridUsed", &lpar) == 0 )
24404     {
24405       cdiDefVarKeyInt(&grid->keys, CDI_KEY_NUMBEROFGRIDUSED, (int)lpar);
24406       if ( grib_get_long(gh, "numberOfGridInReference", &lpar) == 0 )
24407         cdiDefVarKeyInt(&grid->keys, CDI_KEY_NUMBEROFGRIDINREFERENCE, (int)lpar);
24408       /*
24409         if ( grib_get_string(gh, "gridDescriptionFile", reference_link, &len) == 0 )
24410         {
24411         if ( strncmp(reference_link, "file://", 7) == 0 )
24412         grid->reference = strdupx(reference_link);
24413         }
24414       */
24415       size_t len = (size_t)CDI_UUID_SIZE;
24416       if ( grib_get_bytes(gh, "uuidOfHGrid", uuid, &len) == 0)
24417         cdiDefVarKeyBytes(&grid->keys, CDI_KEY_UUID, uuid, CDI_UUID_SIZE);
24418     }
24419 }
24420 
24421 static
gribapiGetGridGeneric(grib_handle * gh,grid_t * grid,size_t numberOfPoints)24422 void gribapiGetGridGeneric(grib_handle *gh, grid_t *grid, size_t numberOfPoints)
24423 {
24424   long lpar;
24425   const size_t nlon = (grib_get_long(gh, "Ni", &lpar) == 0) ? (size_t)lpar : 0;
24426   const size_t nlat = (grib_get_long(gh, "Nj", &lpar) == 0) ? (size_t)lpar : 0;
24427 
24428   grid->size = numberOfPoints;
24429 
24430   const bool lgeneric = (nlon > 0 && nlat > 0 && nlon*nlat == numberOfPoints);
24431   grid->x.size = lgeneric ? nlon : 0;
24432   grid->y.size = lgeneric ? nlat : 0;
24433 }
24434 
24435 //TODO: Simplify by use of the convenience functions (gribGetLong(), gribGetLongDefault(), etc.).
gribapiGetGrid(grib_handle * gh,grid_t * grid)24436 bool gribapiGetGrid(grib_handle *gh, grid_t *grid)
24437 {
24438   bool uvRelativeToGrid = false;
24439   const long editionNumber = gribEditionNumber(gh);
24440   int gridtype = gribapiGetGridType(gh);
24441   int projtype = (gridtype == GRID_PROJECTION && gribapiGetIsRotated(gh)) ? CDI_PROJ_RLL : CDI_UNDEFID;
24442   if (gridtype == CDI_PROJ_LCC || gridtype == CDI_PROJ_STERE)
24443     {
24444       projtype = gridtype;
24445       gridtype = GRID_PROJECTION;
24446     }
24447   /*
24448   if ( streamptr->unreduced && gridtype == GRID_GAUSSIAN_REDUCED )
24449     {
24450       gridtype = GRID_GAUSSIAN;
24451       ISEC2_NumLon = 2*ISEC2_NumLat;
24452       ISEC4_NumValues = ISEC2_NumLon*ISEC2_NumLat;
24453     }
24454   */
24455   grid_init(grid);
24456   cdiGridTypeInit(grid, gridtype, 0);
24457 
24458   size_t datasize;
24459   FAIL_ON_GRIB_ERROR(grib_get_size, gh, "values", &datasize);
24460   long lpar;
24461   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfPoints", &lpar);
24462   size_t numberOfPoints = (size_t) lpar;
24463 
24464   if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || projtype == CDI_PROJ_RLL )
24465     {
24466       gribapiGetGridRegular(gh, grid, editionNumber, gridtype, numberOfPoints);
24467     }
24468   else if ( gridtype == GRID_GAUSSIAN_REDUCED )
24469     {
24470       gribapiGetGridGaussianReduced(gh, grid, editionNumber, numberOfPoints);
24471     }
24472   else if ( projtype == CDI_PROJ_LCC )
24473     {
24474       gribapiGetGridProj(gh, grid, numberOfPoints);
24475     }
24476   else if ( projtype == CDI_PROJ_STERE )
24477     {
24478       gribapiGetGridProj(gh, grid, numberOfPoints);
24479     }
24480   else if ( gridtype == GRID_SPECTRAL )
24481     {
24482       gribapiGetGridSpectral(gh, grid, datasize);
24483     }
24484   else if ( gridtype == GRID_GME )
24485     {
24486       gribapiGetGridGME(gh, grid, numberOfPoints);
24487     }
24488   else if ( gridtype == GRID_UNSTRUCTURED )
24489     {
24490       gribapiGetGridUnstructured(gh, grid, numberOfPoints);
24491     }
24492   else if ( gridtype == GRID_GENERIC )
24493     {
24494       gribapiGetGridGeneric(gh, grid, numberOfPoints);
24495     }
24496   else
24497     {
24498       Error("Unsupported grid type: %s", gridNamePtr(gridtype));
24499     }
24500 
24501   if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_LONLAT || projtype == CDI_PROJ_RLL || projtype == CDI_PROJ_LCC )
24502     {
24503       long temp;
24504       GRIB_CHECK(grib_get_long(gh, "uvRelativeToGrid", &temp), 0);
24505       assert(temp == 0 || temp == 1);
24506       uvRelativeToGrid = (bool)temp;
24507     }
24508 
24509   if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_LONLAT || gridtype == GRID_PROJECTION )
24510     {
24511       long iScansNegatively, jScansPositively, jPointsAreConsecutive;
24512       GRIB_CHECK(grib_get_long(gh, "iScansNegatively", &iScansNegatively), 0);
24513       GRIB_CHECK(grib_get_long(gh, "jScansPositively", &jScansPositively), 0);
24514       GRIB_CHECK(grib_get_long(gh, "jPointsAreConsecutive", &jPointsAreConsecutive), 0);
24515 
24516       int scanningMode = 128*iScansNegatively + 64*jScansPositively + 32*jPointsAreConsecutive;
24517       cdiDefVarKeyInt(&grid->keys, CDI_KEY_SCANNINGMODE, scanningMode);
24518       /* scanningMode  = 128 * iScansNegatively + 64 * jScansPositively + 32 * jPointsAreConsecutive;
24519                    64  = 128 * 0                + 64 *        1         + 32 * 0
24520                    00  = 128 * 0                + 64 *        0         + 32 * 0
24521                    96  = 128 * 0                + 64 *        1         + 32 * 1
24522          Default / implicit scanning mode is 64:
24523                             i and j scan positively, i points are consecutive (row-major)        */
24524 #ifdef HIRLAM_EXTENSIONS
24525       if (cdiDebugExt>=30)
24526       {
24527         //  indicatorOfParameter=33,indicatorOfTypeOfLevel=105,level
24528         long paramId, levelTypeId, levelId;
24529         GRIB_CHECK(grib_get_long(gh, "indicatorOfParameter", &paramId), 0);
24530         GRIB_CHECK(grib_get_long(gh, "indicatorOfTypeOfLevel", &levelTypeId), 0);
24531         GRIB_CHECK(grib_get_long(gh, "level", &levelId), 0);
24532         Message("(param,ltype,level) = (%3d,%3d,%4d); Scanning mode = %02d -> bits:(%1d.%1d.%1d)*32;  uvRelativeToGrid = %02d",\
24533                 (int)paramId, (int)levelTypeId, (int)levelId,
24534                 scanningMode, jPointsAreConsecutive, jScansPositively, iScansNegatively, uvRelativeToGrid);
24535       }
24536 #endif //HIRLAM_EXTENSIONS
24537     }
24538 
24539   grid->type  = gridtype;
24540   grid->projtype  = projtype;
24541 
24542   return uvRelativeToGrid;
24543 }
24544 #endif
24545 /*
24546  * Local Variables:
24547  * c-file-style: "Java"
24548  * c-basic-offset: 2
24549  * indent-tabs-mode: nil
24550  * show-trailing-whitespace: t
24551  * require-trailing-newline: t
24552  * End:
24553  */
24554 #ifndef CDI_UUID_H
24555 #define CDI_UUID_H
24556 
24557 #ifdef HAVE_CONFIG_H
24558 #endif
24559 
24560 
24561 
24562 #ifdef __cplusplus
24563 extern "C" {
24564 #endif
24565 
cdiUUIDIsNull(const unsigned char uuid[])24566 static inline int cdiUUIDIsNull(const unsigned char uuid[])
24567 {
24568   int isNull = 1;
24569   for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
24570     isNull &= (uuid[i] == 0);
24571   return isNull;
24572 }
24573 
24574 void cdiCreateUUID(unsigned char uuid[CDI_UUID_SIZE]);
24575 
24576 void cdiUUID2Str(const unsigned char uuid[], char uuidstr[]);
24577 int cdiStr2UUID(const char *uuidstr, unsigned char uuid[]);
24578 
24579 #if defined (__cplusplus)
24580 }
24581 #endif
24582 
24583 #endif
24584 
24585 /*
24586  * Local Variables:
24587  * c-file-style: "Java"
24588  * c-basic-offset: 2
24589  * indent-tabs-mode: nil
24590  * show-trailing-whitespace: t
24591  * require-trailing-newline: t
24592  * End:
24593  */
24594 #ifndef RESOURCE_UNPACK_H
24595 #define RESOURCE_UNPACK_H
24596 
24597 #ifdef HAVE_CONFIG_H
24598 #endif
24599 
24600 enum
24601 { GRID      = 1,
24602   ZAXIS     = 2,
24603   TAXIS     = 3,
24604   INSTITUTE = 4,
24605   MODEL     = 5,
24606   STREAM    = 6,
24607   VLIST     = 7,
24608   RESH_DELETE,
24609   START     = 55555555,
24610   END       = 99999999
24611 };
24612 
24613 int reshUnpackResources(char * unpackBuffer, int unpackBufferSize,
24614                         void *context);
24615 
24616 #endif
24617 
24618 /*
24619  * Local Variables:
24620  * c-file-style: "Java"
24621  * c-basic-offset: 2
24622  * indent-tabs-mode: nil
24623  * show-trailing-whitespace: t
24624  * require-trailing-newline: t
24625  * End:
24626  */
24627 #ifndef  VLIST_H
24628 #define  VLIST_H
24629 
24630 #ifdef  HAVE_CONFIG_H
24631 #endif
24632 
24633 #ifndef  ERROR_H
24634 #endif
24635 
24636 #include <stddef.h>  /* size_t */
24637 
24638 #ifndef  CDI_LIMITS_H
24639 #endif
24640 
24641 #define VALIDMISS 1.e+303
24642 
24643 
24644 typedef struct
24645 {
24646   bool     flag;
24647   int      index;
24648   int      mlevelID;
24649   int      flevelID;
24650 }
24651 levinfo_t;
24652 
24653 #define DEFAULT_LEVINFO(levID) \
24654   (levinfo_t){ 0, -1, levID, levID}
24655 /*
24656 #define DEFAULT_LEVINFO(levID) \
24657   (levinfo_t){ .flag = 0, .index = -1, .flevelID = levID, .mlevelID = levID}
24658 */
24659 typedef struct
24660 {
24661   int ens_index;
24662   int ens_count;
24663   int forecast_init_type;
24664 }
24665 ensinfo_t;
24666 
24667 
24668 
24669 typedef struct
24670 {
24671   bool        isUsed;
24672   bool        flag;
24673   int         mvarID;
24674   int         fvarID;
24675   int         param;
24676   int         gridID;
24677   int         zaxisID;
24678   int         timetype;  // TIME_*
24679   int         tsteptype; // TSTEP_*
24680   int         datatype;  // CDI_DATATYPE_PACKX for GRIB data, else CDI_DATATYPE_FLT32 or CDI_DATATYPE_FLT64
24681   int         instID;
24682   int         modelID;
24683   int         tableID;
24684   int         timave;
24685   int         chunktype;
24686   int         xyz;
24687   bool        missvalused; // true if missval is defined
24688   bool        lvalidrange;
24689   char       *extra;
24690   double      missval;
24691   double      scalefactor;
24692   double      addoffset;
24693   double      validrange[2];
24694   levinfo_t  *levinfo;
24695   int         comptype;     // compression type
24696   int         complevel;    // compression level
24697   cdi_keys_t  keys;
24698   cdi_atts_t  atts;
24699   int         iorank;
24700 
24701   int         subtypeID;   // subtype ID for tile-related meta-data, currently for GRIB-API only.
24702 
24703   int                 opt_grib_nentries;       // current no. key-value pairs
24704   int                 opt_grib_kvpair_size;    // current allocated size
24705   opt_key_val_pair_t *opt_grib_kvpair;         // (optional) list of keyword/value pairs
24706 }
24707 var_t;
24708 
24709 
24710 typedef struct
24711 {
24712   //set when a vlist is passed to streamDefVlist() to safeguard against modifications of the wrong vlist object
24713   bool        immutable;
24714   //set if this vlist has been created by CDI itself, and must not be destroyed by the user, consequently
24715   bool        internal;
24716   int         self;
24717   int         nvars;        /* number of variables                */
24718   int         ngrids;
24719   int         nzaxis;
24720   int         nsubtypes;    /* no. of variable subtypes (e.g. sets of tiles) */
24721   long        ntsteps;
24722   int         taxisID;
24723   int         tableID;
24724   int         instID;
24725   int         modelID;
24726   int         varsAllocated;
24727   int         gridIDs[MAX_GRIDS_PS];
24728   int         zaxisIDs[MAX_ZAXES_PS];
24729   int         subtypeIDs[MAX_SUBTYPES_PS];
24730   var_t      *vars;
24731   cdi_keys_t  keys;
24732   cdi_atts_t  atts;
24733 }
24734 vlist_t;
24735 
24736 
24737 vlist_t *vlist_to_pointer(int vlistID);
24738 void cdiVlistMakeInternal(int vlistID);
24739 void cdiVlistMakeImmutable(int vlistID);
24740 void vlistCheckVarID(const char *caller, int vlistID, int varID);
24741 void     cdiVlistDestroy_(int vlistID);
24742 int      vlistInqVarMissvalUsed(int vlistID, int varID);
24743 int      vlistHasTime(int vlistID);
24744 
24745 void     vlistUnpack(char * buffer, int bufferSize, int * pos,
24746                      int originNamespace, void *context, int force_id);
24747 
24748 /*      vlistDefVarValidrange: Define the valid range of a Variable */
24749 void    vlistDefVarValidrange(int vlistID, int varID, const double *validrange);
24750 
24751 /*      vlistInqVarValidrange: Get the valid range of a Variable */
24752 int     vlistInqVarValidrange(int vlistID, int varID, double *validrange);
24753 
24754 void vlistInqVarDimorder(int vlistID, int varID, int (*outDimorder)[3]);
24755 
24756 void resize_opt_grib_entries(var_t *var, int nentries);
24757 
24758 
24759 
24760 static inline
vlistAdd2GridIDs(vlist_t * vlistptr,int gridID)24761 void vlistAdd2GridIDs(vlist_t *vlistptr, int gridID)
24762 {
24763   int index, ngrids = vlistptr->ngrids;
24764   for ( index = 0; index < ngrids; index++ )
24765     {
24766       if ( vlistptr->gridIDs[index] == gridID ) break;
24767       //      if ( gridIsEqual(vlistptr->gridIDs[index], gridID) ) break;
24768     }
24769 
24770   if ( index == ngrids )
24771     {
24772       if ( ngrids >= MAX_GRIDS_PS )
24773         Error("Internal limit exceeded: more than %d grids.", MAX_GRIDS_PS);
24774       vlistptr->gridIDs[ngrids] = gridID;
24775       ++(vlistptr->ngrids);
24776     }
24777 }
24778 
24779 static inline
vlistAdd2ZaxisIDs(vlist_t * vlistptr,int zaxisID)24780 void vlistAdd2ZaxisIDs(vlist_t *vlistptr, int zaxisID)
24781 {
24782   int index, nzaxis = vlistptr->nzaxis;
24783   for ( index = 0; index < nzaxis; index++ )
24784     if ( zaxisID == vlistptr->zaxisIDs[index] ) break;
24785 
24786   if ( index == nzaxis )
24787     {
24788       if ( nzaxis >= MAX_ZAXES_PS )
24789 	Error("Internal limit exceeded: more than %d zaxis.", MAX_ZAXES_PS);
24790       vlistptr->zaxisIDs[nzaxis] = zaxisID;
24791       ++(vlistptr->nzaxis);
24792     }
24793 }
24794 
24795 static inline
vlistAdd2SubtypeIDs(vlist_t * vlistptr,int subtypeID)24796 void vlistAdd2SubtypeIDs(vlist_t *vlistptr, int subtypeID)
24797 {
24798   if ( subtypeID == CDI_UNDEFID ) return;
24799 
24800   int index, nsubs = vlistptr->nsubtypes;
24801   for ( index = 0; index < nsubs; index++ )
24802     if ( vlistptr->subtypeIDs[index] == subtypeID ) break;
24803 
24804   if ( index == nsubs )
24805     {
24806       if ( nsubs >= MAX_SUBTYPES_PS )
24807         Error("Internal limit exceeded: more than %d subs.", MAX_SUBTYPES_PS);
24808       vlistptr->subtypeIDs[nsubs] = subtypeID;
24809       ++(vlistptr->nsubtypes);
24810     }
24811 }
24812 
24813 
24814 
24815 #ifdef HAVE_LIBGRIB_API
24816 extern int   cdiNAdditionalGRIBKeys;
24817 extern char* cdiAdditionalGRIBKeys[];
24818 #endif
24819 
24820 extern
24821 #ifndef __cplusplus
24822 const
24823 #endif
24824 resOps vlistOps;
24825 
24826 #endif  /* VLIST_H */
24827 /*
24828  * Local Variables:
24829  * c-file-style: "Java"
24830  * c-basic-offset: 2
24831  * indent-tabs-mode: nil
24832  * show-trailing-whitespace: t
24833  * require-trailing-newline: t
24834  * End:
24835  */
24836 #ifdef HAVE_CONFIG_H
24837 #endif
24838 
24839 #include <assert.h>
24840 #include <string.h>
24841 
24842 
24843 int (*proj_lonlat_to_lcc_func)() = NULL;
24844 int (*proj_lcc_to_lonlat_func)() = NULL;
24845 int (*proj_lonlat_to_stere_func)() = NULL;
24846 int (*proj_stere_to_lonlat_func)() = NULL;
24847 
24848 /* the value in the second pair of brackets must match the length of
24849  * the longest string (including terminating NUL) */
24850 static const char Grids[][17] = {
24851   /*  0 */  "undefined",
24852   /*  1 */  "generic",
24853   /*  2 */  "gaussian",
24854   /*  3 */  "gaussian_reduced",
24855   /*  4 */  "lonlat",
24856   /*  5 */  "spectral",
24857   /*  6 */  "fourier",
24858   /*  7 */  "gme",
24859   /*  8 */  "trajectory",
24860   /*  9 */  "unstructured",
24861   /* 10 */  "curvilinear",
24862   /* 11 */  "lcc",
24863   /* 12 */  "projection",
24864   /* 13 */  "characterXY",
24865 };
24866 
24867 /* must match table below */
24868 enum xystdname_idx {
24869   grid_xystdname_grid_latlon,
24870   grid_xystdname_latlon,
24871   grid_xystdname_projection,
24872   grid_xystdname_char,
24873 };
24874 static const char xystdname_tab[][2][24] = {
24875   [grid_xystdname_grid_latlon] = { "grid_longitude",
24876                                    "grid_latitude" },
24877   [grid_xystdname_latlon] = { "longitude",
24878                               "latitude" },
24879   [grid_xystdname_projection] = { "projection_x_coordinate",
24880                                   "projection_y_coordinate" },
24881   [grid_xystdname_char] = { "region",
24882                             "region" },
24883 };
24884 
24885 
24886 
24887 static int    gridCompareP    ( void * gridptr1, void * gridptr2 );
24888 static void   gridDestroyP    ( void * gridptr );
24889 static void   gridPrintP      ( void * gridptr, FILE * fp );
24890 static int    gridGetPackSize ( void * gridptr, void *context);
24891 static void   gridPack        ( void * gridptr, void * buff, int size, int *position, void *context);
24892 static int    gridTxCode      ( void );
24893 
24894 static const resOps gridOps = {
24895   gridCompareP,
24896   gridDestroyP,
24897   gridPrintP,
24898   gridGetPackSize,
24899   gridPack,
24900   gridTxCode
24901 };
24902 
24903 static int  GRID_Debug = 0;   /* If set to 1, debugging */
24904 
24905 
grid_to_pointer(int gridID)24906 grid_t *grid_to_pointer(int gridID)
24907 {
24908   return (grid_t *)reshGetVal(gridID, &gridOps);
24909 }
24910 
24911 #define gridMark4Update(gridID) reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE)
24912 
24913 static
cdiInqAttConvertedToFloat(int gridID,int atttype,const char * attname,int attlen,double * attflt)24914 bool cdiInqAttConvertedToFloat(int gridID, int atttype, const char *attname, int attlen, double *attflt)
24915 {
24916   bool status = true;
24917 
24918   if ( atttype == CDI_DATATYPE_INT32 )
24919     {
24920       int attint;
24921       int *pattint = attlen > 1 ? (int*) malloc(attlen*sizeof(int)) : &attint;
24922       cdiInqAttInt(gridID, CDI_GLOBAL, attname, attlen, pattint);
24923       for ( int i = 0; i < attlen; ++i ) attflt[i] = (double)pattint[i];
24924       if (attlen > 1) free(pattint);
24925     }
24926   else if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
24927     {
24928       cdiInqAttFlt(gridID, CDI_GLOBAL, attname, attlen, attflt);
24929     }
24930   else
24931     {
24932       status = false;
24933     }
24934 
24935   return status;
24936 }
24937 
24938 static
grid_axis_init(struct gridaxis_t * axisptr)24939 void grid_axis_init(struct gridaxis_t *axisptr)
24940 {
24941   axisptr->size           = 0;
24942   axisptr->vals           = NULL;
24943   axisptr->bounds         = NULL;
24944   axisptr->flag           = 0;
24945   axisptr->first          = 0.0;
24946   axisptr->last           = 0.0;
24947   axisptr->inc            = 0.0;
24948 #ifndef USE_MPI
24949   axisptr->clength        = 0;
24950   axisptr->cvals          = NULL;
24951 #endif
24952   cdiInitKeys(&axisptr->keys);
24953 }
24954 
grid_init(grid_t * gridptr)24955 void grid_init(grid_t *gridptr)
24956 {
24957   gridptr->self           = CDI_UNDEFID;
24958   gridptr->type           = CDI_UNDEFID;
24959   gridptr->proj           = CDI_UNDEFID;
24960   gridptr->projtype       = CDI_UNDEFID;
24961   gridptr->mask           = NULL;
24962   gridptr->mask_gme       = NULL;
24963   gridptr->size           = 0;
24964 
24965   grid_axis_init(&gridptr->x);
24966   grid_axis_init(&gridptr->y);
24967 
24968   gridptr->area           = NULL;
24969   gridptr->reducedPoints  = NULL;
24970   gridptr->reducedPointsSize = 0;
24971 
24972   gridptr->gme.nd         = 0;
24973   gridptr->gme.ni         = 0;
24974   gridptr->gme.ni2        = 0;
24975   gridptr->gme.ni3        = 0;
24976 
24977   gridptr->trunc          = 0;
24978   gridptr->nvertex        = 0;
24979   gridptr->datatype       = CDI_DATATYPE_FLT64;
24980   gridptr->np             = 0;
24981   gridptr->isCyclic       = CDI_UNDEFID;
24982 
24983   gridptr->lcomplex       = false;
24984   gridptr->hasdims        = true;
24985   gridptr->name           = NULL;
24986   gridptr->vtable         = &cdiGridVtable;
24987   cdiInitKeys(&gridptr->keys);
24988   gridptr->atts.nalloc    = MAX_ATTRIBUTES;
24989   gridptr->atts.nelems    = 0;
24990 
24991   cdiDefVarKeyInt(&gridptr->keys, CDI_KEY_SCANNINGMODE, 64);
24992 }
24993 
24994 
24995 static
grid_free_components(grid_t * gridptr)24996 void grid_free_components(grid_t *gridptr)
24997 {
24998   void *p2free[] = { gridptr->mask, gridptr->mask_gme,
24999                      gridptr->x.vals, gridptr->y.vals,
25000 #ifndef USE_MPI
25001                      gridptr->x.cvals, gridptr->y.cvals,
25002 #endif
25003                      gridptr->x.bounds, gridptr->y.bounds,
25004                      gridptr->reducedPoints, gridptr->area,
25005                      gridptr->name};
25006 
25007   for ( size_t i = 0; i < sizeof(p2free)/sizeof(p2free[0]); ++i )
25008     if ( p2free[i] ) Free(p2free[i]);
25009 
25010   /*
25011   int gridID = gridptr->self;
25012   cdiDeleteKeys(gridID, CDI_XAXIS);
25013   cdiDeleteKeys(gridID, CDI_YAXIS);
25014   cdiDeleteKeys(gridID, CDI_GLOBAL);
25015   cdiDeleteAtts(gridID, CDI_GLOBAL);
25016   */
25017 }
25018 
grid_free(grid_t * gridptr)25019 void grid_free(grid_t *gridptr)
25020 {
25021   grid_free_components(gridptr);
25022   grid_init(gridptr);
25023 }
25024 
25025 static
gridNewEntry(cdiResH resH)25026 grid_t *gridNewEntry(cdiResH resH)
25027 {
25028   grid_t *gridptr = (grid_t*) Malloc(sizeof(grid_t));
25029   grid_init(gridptr);
25030 
25031   if ( resH == CDI_UNDEFID )
25032     gridptr->self = reshPut(gridptr, &gridOps);
25033   else
25034     {
25035       gridptr->self = resH;
25036       reshReplace(resH, gridptr, &gridOps);
25037     }
25038 
25039   return gridptr;
25040 }
25041 
25042 static
gridInit(void)25043 void gridInit(void)
25044 {
25045   static bool gridInitialized = false;
25046   if ( gridInitialized ) return;
25047   gridInitialized = true;
25048 
25049   const char *env = getenv("GRID_DEBUG");
25050   if ( env ) GRID_Debug = atoi(env);
25051 }
25052 
25053 static
grid_copy_base_scalar_fields(grid_t * gridptrOrig,grid_t * gridptrDup)25054 void grid_copy_base_scalar_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
25055 {
25056   memcpy(gridptrDup, gridptrOrig, sizeof(grid_t));
25057   gridptrDup->self = CDI_UNDEFID;
25058   cdiInitKeys(&gridptrDup->keys);
25059   cdiCopyVarKeys(&gridptrOrig->keys, &gridptrDup->keys);
25060   cdiInitKeys(&gridptrDup->x.keys);
25061   cdiCopyVarKeys(&gridptrOrig->x.keys, &gridptrDup->x.keys);
25062   cdiInitKeys(&gridptrDup->y.keys);
25063   cdiCopyVarKeys(&gridptrOrig->y.keys, &gridptrDup->y.keys);
25064 }
25065 
25066 
25067 static
grid_copy_base(grid_t * gridptrOrig)25068 grid_t *grid_copy_base(grid_t *gridptrOrig)
25069 {
25070   grid_t *gridptrDup = (grid_t *)Malloc(sizeof (*gridptrDup));
25071   gridptrOrig->vtable->copyScalarFields(gridptrOrig, gridptrDup);
25072   gridptrOrig->vtable->copyArrayFields(gridptrOrig, gridptrDup);
25073   return gridptrDup;
25074 }
25075 
25076 
cdiGridCount(void)25077 unsigned cdiGridCount(void)
25078 {
25079   return reshCountType(&gridOps);
25080 }
25081 
25082 static inline
gridaxisSetKey(struct gridaxis_t * axisptr,int key,const char * name)25083 void gridaxisSetKey(struct gridaxis_t *axisptr, int key, const char *name)
25084 {
25085   if (find_key(&axisptr->keys, key) == NULL)
25086     cdiDefVarKeyBytes(&axisptr->keys, key, (const unsigned char*)name, (int)strlen(name)+1);
25087 }
25088 
cdiGridTypeInit(grid_t * gridptr,int gridtype,size_t size)25089 void cdiGridTypeInit(grid_t *gridptr, int gridtype, size_t size)
25090 {
25091   gridptr->type = gridtype;
25092   gridptr->size = size;
25093 
25094   if      ( gridtype == GRID_LONLAT   ) gridptr->nvertex = 2;
25095   else if ( gridtype == GRID_GAUSSIAN ) gridptr->nvertex = 2;
25096   else if ( gridtype == GRID_GAUSSIAN_REDUCED ) gridptr->nvertex = 2;
25097   else if ( gridtype == GRID_CURVILINEAR  ) gridptr->nvertex = 4;
25098   else if ( gridtype == GRID_UNSTRUCTURED ) gridptr->x.size = size;
25099 
25100   switch (gridtype)
25101     {
25102     case GRID_LONLAT:
25103     case GRID_GAUSSIAN:
25104     case GRID_GAUSSIAN_REDUCED:
25105     case GRID_TRAJECTORY:
25106     case GRID_CURVILINEAR:
25107     case GRID_UNSTRUCTURED:
25108     case GRID_GME:
25109       {
25110         if ( gridtype == GRID_TRAJECTORY )
25111           {
25112             gridaxisSetKey(&gridptr->x, CDI_KEY_NAME, "tlon");
25113             gridaxisSetKey(&gridptr->y, CDI_KEY_NAME, "tlat");
25114           }
25115         else
25116           {
25117             gridaxisSetKey(&gridptr->x, CDI_KEY_NAME, "lon");
25118             gridaxisSetKey(&gridptr->y, CDI_KEY_NAME, "lat");
25119           }
25120 
25121         gridaxisSetKey(&gridptr->x, CDI_KEY_LONGNAME, "longitude");
25122         gridaxisSetKey(&gridptr->y, CDI_KEY_LONGNAME, "latitude");
25123 
25124         gridaxisSetKey(&gridptr->x, CDI_KEY_UNITS, "degrees_east");
25125         gridaxisSetKey(&gridptr->y, CDI_KEY_UNITS, "degrees_north");
25126 
25127         gridaxisSetKey(&gridptr->x, CDI_KEY_STDNAME, xystdname_tab[grid_xystdname_latlon][0]);
25128         gridaxisSetKey(&gridptr->y, CDI_KEY_STDNAME, xystdname_tab[grid_xystdname_latlon][1]);
25129 
25130         break;
25131       }
25132 #ifndef USE_MPI
25133     case GRID_CHARXY:
25134       {
25135         if ( gridptr->x.cvals ) gridaxisSetKey(&gridptr->x, CDI_KEY_STDNAME, xystdname_tab[grid_xystdname_char][0]);
25136         if ( gridptr->y.cvals ) gridaxisSetKey(&gridptr->y, CDI_KEY_STDNAME, xystdname_tab[grid_xystdname_char][1]);
25137 
25138         break;
25139       }
25140 #endif
25141     case GRID_GENERIC:
25142     case GRID_PROJECTION:
25143       {
25144         gridaxisSetKey(&gridptr->x, CDI_KEY_NAME, "x");
25145         gridaxisSetKey(&gridptr->y, CDI_KEY_NAME, "y");
25146         if ( gridtype == GRID_PROJECTION )
25147           {
25148             const char gmapname[] = "Projection";
25149             cdiDefVarKeyBytes(&gridptr->keys, CDI_KEY_GRIDMAP_NAME, (const unsigned char *)gmapname, (int)sizeof(gmapname));
25150 
25151             gridaxisSetKey(&gridptr->x, CDI_KEY_STDNAME,  xystdname_tab[grid_xystdname_projection][0]);
25152             gridaxisSetKey(&gridptr->y, CDI_KEY_STDNAME,  xystdname_tab[grid_xystdname_projection][1]);
25153             gridaxisSetKey(&gridptr->x, CDI_KEY_UNITS, "m");
25154             gridaxisSetKey(&gridptr->y, CDI_KEY_UNITS, "m");
25155           }
25156         break;
25157       }
25158     }
25159 }
25160 
25161 
25162 // used also in CDO
gridGenXvals(int xsize,double xfirst,double xlast,double xinc,double * restrict xvals)25163 void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *restrict xvals)
25164 {
25165   if (fabs(xinc) <= 0 && xsize > 1)
25166     {
25167       if ( xfirst >= xlast )
25168         {
25169           while ( xfirst >= xlast ) xlast += 360;
25170           xinc = (xlast-xfirst)/(xsize);
25171         }
25172       else
25173         {
25174           xinc = (xlast-xfirst)/(xsize-1);
25175         }
25176     }
25177 
25178   for ( int i = 0; i < xsize; ++i )
25179     xvals[i] = xfirst + i*xinc;
25180 }
25181 
25182 static
calc_gaussgrid(double * restrict yvals,size_t ysize,double yfirst,double ylast)25183 void calc_gaussgrid(double *restrict yvals, size_t ysize, double yfirst, double ylast)
25184 {
25185   double *restrict yw = (double *) Malloc(ysize * sizeof(double));
25186   gaussianLatitudes(yvals, yw, ysize);
25187   Free(yw);
25188   for (size_t i = 0; i < ysize; i++ )
25189     yvals[i] = asin(yvals[i])/M_PI*180.0;
25190 
25191   if ( yfirst < ylast && yfirst > -90.0 && ylast < 90.0 )
25192     {
25193       const size_t yhsize = ysize/2;
25194       for (size_t i = 0; i < yhsize; i++ )
25195         {
25196           const double ytmp = yvals[i];
25197           yvals[i] = yvals[ysize-i-1];
25198           yvals[ysize-i-1] = ytmp;
25199         }
25200     }
25201 }
25202 
25203 static
gridGenYvalsGaussian(int ysize,double yfirst,double ylast,double * restrict yvals)25204 void gridGenYvalsGaussian(int ysize, double yfirst, double ylast, double *restrict yvals)
25205 {
25206   const double deleps = 0.002;
25207 
25208   calc_gaussgrid(yvals, ysize, yfirst, ylast);
25209 
25210   if ( ! (IS_EQUAL(yfirst, 0) && IS_EQUAL(ylast, 0)) )
25211     if ( fabs(yvals[0] - yfirst) > deleps || fabs(yvals[ysize-1] - ylast) > deleps )
25212       {
25213         bool lfound = false;
25214         int ny = (int) (180./(fabs(ylast-yfirst)/(ysize-1)) + 0.5);
25215         ny -= ny%2;
25216         if ( ny > ysize && ny < 4096 )
25217           {
25218             double *ytmp = (double *) Malloc((size_t)ny * sizeof (double));
25219             calc_gaussgrid(ytmp, ny, yfirst, ylast);
25220 
25221             int i;
25222             for ( i = 0; i < (ny-ysize); i++ )
25223               if ( fabs(ytmp[i] - yfirst) < deleps ) break;
25224             int nstart = i;
25225 
25226             lfound = (nstart+ysize-1) < ny && fabs(ytmp[nstart+ysize-1] - ylast) < deleps;
25227             if ( lfound )
25228               {
25229                 for (i = 0; i < ysize; i++) yvals[i] = ytmp[i+nstart];
25230               }
25231 
25232             if ( ytmp ) Free(ytmp);
25233           }
25234 
25235         if ( !lfound )
25236           {
25237             Warning("Cannot calculate gaussian latitudes for lat1 = %g latn = %g!", yfirst, ylast);
25238             for (int i = 0; i < ysize; i++ ) yvals[i] = 0;
25239             yvals[0] = yfirst;
25240             yvals[ysize-1] = ylast;
25241           }
25242       }
25243 }
25244 
25245 static
gridGenYvalsRegular(int ysize,double yfirst,double ylast,double yinc,double * restrict yvals)25246 void gridGenYvalsRegular(int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
25247 {
25248   if (fabs(yinc) <= 0 && ysize > 1)
25249     {
25250       if ( IS_EQUAL(yfirst, ylast) && IS_NOT_EQUAL(yfirst, 0) ) ylast *= -1;
25251 
25252       if ( yfirst > ylast )
25253         yinc = (yfirst-ylast)/(ysize-1);
25254       else if ( yfirst < ylast )
25255         yinc = (ylast-yfirst)/(ysize-1);
25256       else
25257         {
25258           if ( ysize%2 != 0 )
25259             {
25260               yinc = 180.0/(ysize-1);
25261               yfirst = -90;
25262             }
25263           else
25264             {
25265               yinc = 180.0/ysize;
25266               yfirst = -90 + yinc/2;
25267             }
25268         }
25269     }
25270 
25271   if ( yfirst > ylast && yinc > 0 ) yinc = -yinc;
25272 
25273   for (int i = 0; i < ysize; i++ )
25274     yvals[i] = yfirst + i*yinc;
25275 }
25276 
25277 // used also in CDO
gridGenYvals(int gridtype,int ysize,double yfirst,double ylast,double yinc,double * restrict yvals)25278 void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
25279 {
25280   if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
25281     {
25282       if ( ysize > 2 )
25283 	{
25284           gridGenYvalsGaussian(ysize, yfirst, ylast, yvals);
25285 	}
25286       else
25287         {
25288           yvals[0] = yfirst;
25289           yvals[ysize-1] = ylast;
25290         }
25291     }
25292   /*     else if ( gridtype == GRID_LONLAT || gridtype == GRID_GENERIC ) */
25293   else
25294     {
25295       gridGenYvalsRegular(ysize, yfirst, ylast, yinc, yvals);
25296     }
25297    /*
25298     else
25299     Error("unable to calculate values for %s grid!", gridNamePtr(gridtype));
25300   */
25301 }
25302 
25303 /*
25304 @Function  gridCreate
25305 @Title     Create a horizontal Grid
25306 
25307 @Prototype int gridCreate(int gridtype, size_t size)
25308 @Parameter
25309     @Item  gridtype  The type of the grid, one of the set of predefined CDI grid types.
25310                      The valid CDI grid types are @func{GRID_GENERIC}, @func{GRID_LONLAT},
25311                      @func{GRID_GAUSSIAN}, @func{GRID_PROJECTION}, @func{GRID_SPECTRAL},
25312                      @func{GRID_GME}, @func{GRID_CURVILINEAR} and @func{GRID_UNSTRUCTURED}.
25313     @Item  size      Number of gridpoints.
25314 
25315 @Description
25316 The function @func{gridCreate} creates a horizontal Grid.
25317 
25318 @Result
25319 @func{gridCreate} returns an identifier to the Grid.
25320 
25321 @Example
25322 Here is an example using @func{gridCreate} to create a regular lon/lat Grid:
25323 
25324 @Source
25325    ...
25326 #define  nlon  12
25327 #define  nlat   6
25328    ...
25329 double lons[nlon] = {0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330};
25330 double lats[nlat] = {-75, -45, -15, 15, 45, 75};
25331 int gridID;
25332    ...
25333 gridID = gridCreate(GRID_LONLAT, nlon*nlat);
25334 gridDefXsize(gridID, nlon);
25335 gridDefYsize(gridID, nlat);
25336 gridDefXvals(gridID, lons);
25337 gridDefYvals(gridID, lats);
25338    ...
25339 @EndSource
25340 @EndFunction
25341 */
gridCreate(int gridtype,size_t size)25342 int gridCreate(int gridtype, size_t size)
25343 {
25344   if ( CDI_Debug ) Message("gridtype=%s  size=%zu", gridNamePtr(gridtype), size);
25345 
25346   xassert(size);
25347   gridInit();
25348 
25349   grid_t *gridptr = gridNewEntry(CDI_UNDEFID);
25350   if ( ! gridptr ) Error("No memory");
25351 
25352   const int gridID = gridptr->self;
25353 
25354   if ( CDI_Debug ) Message("gridID: %d", gridID);
25355 
25356   cdiGridTypeInit(gridptr, gridtype, size);
25357 
25358   return gridID;
25359 }
25360 
25361 static
gridDestroyKernel(grid_t * gridptr)25362 void gridDestroyKernel( grid_t * gridptr )
25363 {
25364   xassert ( gridptr );
25365 
25366   const int id = gridptr->self;
25367 
25368   grid_free_components(gridptr);
25369   Free( gridptr );
25370 
25371   reshRemove( id, &gridOps );
25372 }
25373 
25374 /*
25375 @Function  gridDestroy
25376 @Title     Destroy a horizontal Grid
25377 
25378 @Prototype void gridDestroy(int gridID)
25379 @Parameter
25380     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
25381 
25382 @EndFunction
25383 */
gridDestroy(int gridID)25384 void gridDestroy(int gridID)
25385 {
25386   //cdiDeleteKeys(gridID, CDI_GLOBAL);
25387   //cdiDeleteAtts(gridID, CDI_GLOBAL);
25388 
25389   grid_t *gridptr = grid_to_pointer(gridID);
25390   gridptr->vtable->destroy(gridptr);
25391 }
25392 
25393 static
gridDestroyP(void * gridptr)25394 void gridDestroyP(void * gridptr)
25395 {
25396   ((grid_t *)gridptr)->vtable->destroy((grid_t *)gridptr);
25397 }
25398 
25399 
gridNamePtr(int gridtype)25400 const char *gridNamePtr(int gridtype)
25401 {
25402   const int size = (int) (sizeof(Grids)/sizeof(Grids[0]));
25403 
25404   const char *name = (gridtype >= 0 && gridtype < size) ? Grids[gridtype] : Grids[GRID_GENERIC];
25405 
25406   return name;
25407 }
25408 
25409 
gridName(int gridtype,char * gridname)25410 void gridName(int gridtype, char *gridname)
25411 {
25412   strcpy(gridname, gridNamePtr(gridtype));
25413 }
25414 
25415 /*
25416 @Function  gridDefXname
25417 @Title     Define the name of a X-axis
25418 
25419 @Prototype void gridDefXname(int gridID, const char *name)
25420 @Parameter
25421     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
25422     @Item  name     Name of the X-axis.
25423 
25424 @Description
25425 The function @func{gridDefXname} defines the name of a X-axis.
25426 
25427 @EndFunction
25428 */
gridDefXname(int gridID,const char * name)25429 void gridDefXname(int gridID, const char *name)
25430 {
25431   (void)cdiDefKeyString(gridID, CDI_XAXIS, CDI_KEY_NAME, name);
25432 }
25433 
25434 /*
25435 @Function  gridDefXlongname
25436 @Title     Define the longname of a X-axis
25437 
25438 @Prototype void gridDefXlongname(int gridID, const char *longname)
25439 @Parameter
25440     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
25441     @Item  longname Longname of the X-axis.
25442 
25443 @Description
25444 The function @func{gridDefXlongname} defines the longname of a X-axis.
25445 
25446 @EndFunction
25447 */
gridDefXlongname(int gridID,const char * longname)25448 void gridDefXlongname(int gridID, const char *longname)
25449 {
25450   (void)cdiDefKeyString(gridID, CDI_XAXIS, CDI_KEY_LONGNAME, longname);
25451 }
25452 
25453 /*
25454 @Function  gridDefXunits
25455 @Title     Define the units of a X-axis
25456 
25457 @Prototype void gridDefXunits(int gridID, const char *units)
25458 @Parameter
25459     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
25460     @Item  units    Units of the X-axis.
25461 
25462 @Description
25463 The function @func{gridDefXunits} defines the units of a X-axis.
25464 
25465 @EndFunction
25466 */
gridDefXunits(int gridID,const char * units)25467 void gridDefXunits(int gridID, const char *units)
25468 {
25469   (void)cdiDefKeyString(gridID, CDI_XAXIS, CDI_KEY_UNITS, units);
25470 }
25471 
25472 /*
25473 @Function  gridDefYname
25474 @Title     Define the name of a Y-axis
25475 
25476 @Prototype void gridDefYname(int gridID, const char *name)
25477 @Parameter
25478     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
25479     @Item  name     Name of the Y-axis.
25480 
25481 @Description
25482 The function @func{gridDefYname} defines the name of a Y-axis.
25483 
25484 @EndFunction
25485 */
gridDefYname(int gridID,const char * name)25486 void gridDefYname(int gridID, const char *name)
25487 {
25488   (void)cdiDefKeyString(gridID, CDI_YAXIS, CDI_KEY_NAME, name);
25489 }
25490 
25491 /*
25492 @Function  gridDefYlongname
25493 @Title     Define the longname of a Y-axis
25494 
25495 @Prototype void gridDefYlongname(int gridID, const char *longname)
25496 @Parameter
25497     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
25498     @Item  longname Longname of the Y-axis.
25499 
25500 @Description
25501 The function @func{gridDefYlongname} defines the longname of a Y-axis.
25502 
25503 @EndFunction
25504 */
gridDefYlongname(int gridID,const char * longname)25505 void gridDefYlongname(int gridID, const char *longname)
25506 {
25507   (void)cdiDefKeyString(gridID, CDI_YAXIS, CDI_KEY_LONGNAME, longname);
25508 }
25509 
25510 /*
25511 @Function  gridDefYunits
25512 @Title     Define the units of a Y-axis
25513 
25514 @Prototype void gridDefYunits(int gridID, const char *units)
25515 @Parameter
25516     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
25517     @Item  units    Units of the Y-axis.
25518 
25519 @Description
25520 The function @func{gridDefYunits} defines the units of a Y-axis.
25521 
25522 @EndFunction
25523 */
gridDefYunits(int gridID,const char * units)25524 void gridDefYunits(int gridID, const char *units)
25525 {
25526   (void)cdiDefKeyString(gridID, CDI_YAXIS, CDI_KEY_UNITS, units);
25527 }
25528 
25529 /*
25530 @Function  gridInqXname
25531 @Title     Get the name of a X-axis
25532 
25533 @Prototype void gridInqXname(int gridID, char *name)
25534 @Parameter
25535     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
25536     @Item  name     Name of the X-axis. The caller must allocate space for the
25537                     returned string. The maximum possible length, in characters, of
25538                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
25539 
25540 @Description
25541 The function @func{gridInqXname} returns the name of a X-axis.
25542 
25543 @Result
25544 @func{gridInqXname} returns the name of the X-axis to the parameter name.
25545 
25546 @EndFunction
25547 */
gridInqXname(int gridID,char * name)25548 void gridInqXname(int gridID, char *name)
25549 {
25550   int length = CDI_MAX_NAME;
25551   (void)cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_NAME, name, &length);
25552 }
25553 
25554 /*
25555 @Function  gridInqXlongname
25556 @Title     Get the longname of a X-axis
25557 
25558 @Prototype void gridInqXlongname(int gridID, char *longname)
25559 @Parameter
25560     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
25561     @Item  longname Longname of the X-axis. The caller must allocate space for the
25562                     returned string. The maximum possible length, in characters, of
25563                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
25564 
25565 @Description
25566 The function @func{gridInqXlongname} returns the longname of a X-axis.
25567 
25568 @Result
25569 @func{gridInqXlongname} returns the longname of the X-axis to the parameter longname.
25570 
25571 @EndFunction
25572 */
gridInqXlongname(int gridID,char * longname)25573 void gridInqXlongname(int gridID, char *longname)
25574 {
25575   int length = CDI_MAX_NAME;
25576   (void)cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_LONGNAME, longname, &length);
25577 }
25578 
25579 /*
25580 @Function  gridInqXunits
25581 @Title     Get the units of a X-axis
25582 
25583 @Prototype void gridInqXunits(int gridID, char *units)
25584 @Parameter
25585     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
25586     @Item  units    Units of the X-axis. The caller must allocate space for the
25587                     returned string. The maximum possible length, in characters, of
25588                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
25589 
25590 @Description
25591 The function @func{gridInqXunits} returns the units of a X-axis.
25592 
25593 @Result
25594 @func{gridInqXunits} returns the units of the X-axis to the parameter units.
25595 
25596 @EndFunction
25597 */
gridInqXunits(int gridID,char * units)25598 void gridInqXunits(int gridID, char *units)
25599 {
25600   int length = CDI_MAX_NAME;
25601   (void)cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_UNITS, units, &length);
25602 }
25603 
25604 /*
25605 @Function  gridInqYname
25606 @Title     Get the name of a Y-axis
25607 
25608 @Prototype void gridInqYname(int gridID, char *name)
25609 @Parameter
25610     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
25611     @Item  name     Name of the Y-axis. The caller must allocate space for the
25612                     returned string. The maximum possible length, in characters, of
25613                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
25614 
25615 @Description
25616 The function @func{gridInqYname} returns the name of a Y-axis.
25617 
25618 @Result
25619 @func{gridInqYname} returns the name of the Y-axis to the parameter name.
25620 
25621 @EndFunction
25622 */
gridInqYname(int gridID,char * name)25623 void gridInqYname(int gridID, char *name)
25624 {
25625   int length = CDI_MAX_NAME;
25626   (void)cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_NAME, name, &length);
25627 }
25628 
25629 /*
25630 @Function  gridInqYlongname
25631 @Title     Get the longname of a Y-axis
25632 
25633 @Prototype void gridInqYlongname(int gridID, char *longname)
25634 @Parameter
25635     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
25636     @Item  longname Longname of the Y-axis. The caller must allocate space for the
25637                     returned string. The maximum possible length, in characters, of
25638                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
25639 
25640 @Description
25641 The function @func{gridInqYlongname} returns the longname of a Y-axis.
25642 
25643 @Result
25644 @func{gridInqYlongname} returns the longname of the Y-axis to the parameter longname.
25645 
25646 @EndFunction
25647 */
gridInqYlongname(int gridID,char * longname)25648 void gridInqYlongname(int gridID, char *longname)
25649 {
25650   int length = CDI_MAX_NAME;
25651   (void)cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_LONGNAME, longname, &length);
25652 }
25653 
25654 /*
25655 @Function  gridInqYunits
25656 @Title     Get the units of a Y-axis
25657 
25658 @Prototype void gridInqYunits(int gridID, char *units)
25659 @Parameter
25660     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
25661     @Item  units    Units of the Y-axis. The caller must allocate space for the
25662                     returned string. The maximum possible length, in characters, of
25663                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
25664 
25665 @Description
25666 The function @func{gridInqYunits} returns the units of a Y-axis.
25667 
25668 @Result
25669 @func{gridInqYunits} returns the units of the Y-axis to the parameter units.
25670 
25671 @EndFunction
25672 */
gridInqYunits(int gridID,char * units)25673 void gridInqYunits(int gridID, char *units)
25674 {
25675   int length = CDI_MAX_NAME;
25676   (void)cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_UNITS, units, &length);
25677 }
25678 
25679 
gridDefProj(int gridID,int projID)25680 void gridDefProj(int gridID, int projID)
25681 {
25682   grid_t *gridptr = grid_to_pointer(gridID);
25683   gridptr->proj = projID;
25684 
25685   if ( gridptr->type == GRID_CURVILINEAR )
25686     {
25687       grid_t *projptr = grid_to_pointer(projID);
25688       const char *xdimname = cdiInqVarKeyStringPtr(&gridptr->x.keys, CDI_KEY_DIMNAME);
25689       const char *ydimname = cdiInqVarKeyStringPtr(&gridptr->y.keys, CDI_KEY_DIMNAME);
25690       if (xdimname && find_key(&projptr->x.keys, CDI_KEY_NAME)) cdiDefKeyString(projID, CDI_XAXIS, CDI_KEY_NAME, xdimname);
25691       if (ydimname && find_key(&projptr->y.keys, CDI_KEY_NAME)) cdiDefKeyString(projID, CDI_YAXIS, CDI_KEY_NAME, ydimname);
25692     }
25693 }
25694 
25695 
gridInqProj(int gridID)25696 int gridInqProj(int gridID)
25697 {
25698   grid_t *gridptr = grid_to_pointer(gridID);
25699   return gridptr->proj;
25700 }
25701 
25702 
gridInqProjType(int gridID)25703 int gridInqProjType(int gridID)
25704 {
25705   grid_t *gridptr = grid_to_pointer(gridID);
25706 
25707   int projtype = gridptr->projtype;
25708   if ( projtype == -1 )
25709     {
25710       char gmapname[CDI_MAX_NAME];
25711       int length = CDI_MAX_NAME;
25712       cdiInqKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_NAME, gmapname, &length);
25713       if ( gmapname[0] )
25714         {
25715           // clang-format off
25716           if      ( strIsEqual(gmapname, "rotated_latitude_longitude") )   projtype = CDI_PROJ_RLL;
25717           else if ( strIsEqual(gmapname, "lambert_azimuthal_equal_area") ) projtype = CDI_PROJ_LAEA;
25718           else if ( strIsEqual(gmapname, "lambert_conformal_conic") )      projtype = CDI_PROJ_LCC;
25719           else if ( strIsEqual(gmapname, "sinusoidal") )                   projtype = CDI_PROJ_SINU;
25720           else if ( strIsEqual(gmapname, "polar_stereographic") )          projtype = CDI_PROJ_STERE;
25721           // clang-format on
25722           gridptr->projtype = projtype;
25723         }
25724     }
25725 
25726   return projtype;
25727 }
25728 
25729 
gridVerifyProj(int gridID)25730 void gridVerifyProj(int gridID)
25731 {
25732   grid_t *gridptr = grid_to_pointer(gridID);
25733 
25734   const int projtype = gridInqProjType(gridID);
25735   if ( projtype == CDI_PROJ_RLL )
25736     {
25737       gridaxisSetKey(&gridptr->x, CDI_KEY_STDNAME, xystdname_tab[grid_xystdname_grid_latlon][0]);
25738       gridaxisSetKey(&gridptr->y, CDI_KEY_STDNAME, xystdname_tab[grid_xystdname_grid_latlon][1]);
25739       gridaxisSetKey(&gridptr->x, CDI_KEY_UNITS, "degrees");
25740       gridaxisSetKey(&gridptr->y, CDI_KEY_UNITS, "degrees");
25741     }
25742   else if ( projtype == CDI_PROJ_LCC )
25743     {
25744       gridaxisSetKey(&gridptr->x, CDI_KEY_STDNAME, xystdname_tab[grid_xystdname_projection][0]);
25745       gridaxisSetKey(&gridptr->y, CDI_KEY_STDNAME, xystdname_tab[grid_xystdname_projection][1]);
25746       gridaxisSetKey(&gridptr->x, CDI_KEY_UNITS, "m");
25747       gridaxisSetKey(&gridptr->y, CDI_KEY_UNITS, "m");
25748     }
25749 }
25750 
25751 /*
25752 @Function  gridInqType
25753 @Title     Get the type of a Grid
25754 
25755 @Prototype int gridInqType(int gridID)
25756 @Parameter
25757     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
25758 
25759 @Description
25760 The function @func{gridInqType} returns the type of a Grid.
25761 
25762 @Result
25763 @func{gridInqType} returns the type of the grid,
25764 one of the set of predefined CDI grid types.
25765 The valid CDI grid types are @func{GRID_GENERIC}, @func{GRID_LONLAT},
25766 @func{GRID_GAUSSIAN}, @func{GRID_PROJECTION}, @func{GRID_SPECTRAL}, @func{GRID_GME},
25767 @func{GRID_CURVILINEAR} and @func{GRID_UNSTRUCTURED}.
25768 
25769 @EndFunction
25770 */
gridInqType(int gridID)25771 int gridInqType(int gridID)
25772 {
25773   grid_t *gridptr = grid_to_pointer(gridID);
25774   return gridptr->type;
25775 }
25776 
25777 
25778 /*
25779 @Function  gridInqSize
25780 @Title     Get the size of a Grid
25781 
25782 @Prototype size_t gridInqSize(int gridID)
25783 @Parameter
25784     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
25785 
25786 @Description
25787 The function @func{gridInqSize} returns the size of a Grid.
25788 
25789 @Result
25790 @func{gridInqSize} returns the number of grid points of a Grid.
25791 
25792 @EndFunction
25793 */
gridInqSize(int gridID)25794 size_t gridInqSize(int gridID)
25795 {
25796   grid_t *gridptr = grid_to_pointer(gridID);
25797 
25798   size_t size = gridptr->size;
25799   if ( size == 0 )
25800     {
25801       size_t xsize = gridptr->x.size;
25802       size_t ysize = gridptr->y.size;
25803 
25804       size = ysize ? xsize * ysize : xsize;
25805 
25806       gridptr->size = size;
25807     }
25808 
25809   return size;
25810 }
25811 
25812 static
nsp2trunc(int nsp)25813 int nsp2trunc(int nsp)
25814 {
25815   /*  nsp = (trunc+1)*(trunc+1)              */
25816   /*      => trunc^2 + 3*trunc - (x-2) = 0   */
25817   /*                                         */
25818   /*  with:  y^2 + p*y + q = 0               */
25819   /*         y = -p/2 +- sqrt((p/2)^2 - q)   */
25820   /*         p = 3 and q = - (x-2)           */
25821   int trunc = (int) (sqrt(nsp*4 + 1.) - 3) / 2;
25822   return trunc;
25823 }
25824 
25825 
gridInqTrunc(int gridID)25826 int gridInqTrunc(int gridID)
25827 {
25828   grid_t *gridptr = grid_to_pointer(gridID);
25829 
25830   if ( gridptr->trunc == 0 )
25831     {
25832       if ( gridptr->type == GRID_SPECTRAL )
25833         gridptr->trunc = nsp2trunc(gridptr->size);
25834       /*
25835       else if      ( gridptr->type == GRID_GAUSSIAN )
25836         gridptr->trunc = nlat2trunc(gridptr->y.size);
25837       */
25838     }
25839 
25840   return gridptr->trunc;
25841 }
25842 
25843 
gridDefTrunc(int gridID,int trunc)25844 void gridDefTrunc(int gridID, int trunc)
25845 {
25846   grid_t *gridptr = grid_to_pointer(gridID);
25847 
25848   if ( gridptr->trunc != trunc )
25849     {
25850       gridMark4Update(gridID);
25851       gridptr->trunc = trunc;
25852     }
25853 }
25854 
25855 /*
25856 @Function  gridDefXsize
25857 @Title     Define the number of values of a X-axis
25858 
25859 @Prototype void gridDefXsize(int gridID, size_t xsize)
25860 @Parameter
25861     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
25862     @Item  xsize    Number of values of a X-axis.
25863 
25864 @Description
25865 The function @func{gridDefXsize} defines the number of values of a X-axis.
25866 
25867 @EndFunction
25868 */
gridDefXsize(int gridID,size_t xsize)25869 void gridDefXsize(int gridID, size_t xsize)
25870 {
25871   grid_t *gridptr = grid_to_pointer(gridID);
25872 
25873   const size_t gridSize = gridInqSize(gridID);
25874   if ( xsize > gridSize )
25875     Error("xsize %zu is greater then gridsize %zu", xsize, gridSize);
25876 
25877   const int gridType = gridInqType(gridID);
25878   if ( gridType == GRID_UNSTRUCTURED && xsize != gridSize )
25879     Error("xsize %zu must be equal to gridsize %zu for gridtype: %s", xsize, gridSize, gridNamePtr(gridType));
25880   if ( gridType == GRID_GAUSSIAN_REDUCED && xsize != 2 && xsize != gridSize )
25881     Error("xsize %zu must be equal to gridsize %zu for gridtype: %s", xsize, gridSize, gridNamePtr(gridType));
25882 
25883   if ( gridptr->x.size != xsize )
25884     {
25885       gridMark4Update(gridID);
25886       gridptr->x.size = xsize;
25887     }
25888 
25889   if ( gridType != GRID_UNSTRUCTURED && gridType != GRID_GAUSSIAN_REDUCED && gridType != GRID_PROJECTION )
25890     {
25891       const size_t axisproduct = gridptr->x.size*gridptr->y.size;
25892       if ( axisproduct > 0 && axisproduct != gridSize )
25893         Error("Inconsistent grid declaration! (xsize=%zu ysize=%zu gridsize=%zu)",
25894               gridptr->x.size, gridptr->y.size, gridSize);
25895     }
25896 }
25897 
25898 /*
25899 @Function
25900 @Title
25901 
25902 @Prototype
25903 @Parameter
25904     @Item  Grid identifier
25905 
25906 @EndFunction
25907 */
gridDefDatatype(int gridID,int datatype)25908 void gridDefDatatype(int gridID, int datatype)
25909 {
25910   grid_t *gridptr = grid_to_pointer(gridID);
25911 
25912   if ( gridptr->datatype != datatype )
25913     {
25914       gridMark4Update(gridID);
25915       gridptr->datatype = datatype;
25916     }
25917 }
25918 
25919 /*
25920 @Function
25921 @Title
25922 
25923 @Prototype
25924 @Parameter
25925     @Item  Grid identifier
25926 
25927 @EndFunction
25928 */
gridInqDatatype(int gridID)25929 int gridInqDatatype(int gridID)
25930 {
25931   grid_t *gridptr = grid_to_pointer(gridID);
25932   return gridptr->datatype;
25933 }
25934 
25935 /*
25936 @Function  gridInqXsize
25937 @Title     Get the number of values of a X-axis
25938 
25939 @Prototype size_t gridInqXsize(int gridID)
25940 @Parameter
25941     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
25942 
25943 @Description
25944 The function @func{gridInqXsize} returns the number of values of a X-axis.
25945 
25946 @Result
25947 @func{gridInqXsize} returns the number of values of a X-axis.
25948 
25949 @EndFunction
25950 */
gridInqXsize(int gridID)25951 size_t gridInqXsize(int gridID)
25952 {
25953   grid_t *gridptr = grid_to_pointer(gridID);
25954   return gridptr->x.size;
25955 }
25956 
25957 /*
25958 @Function  gridDefYsize
25959 @Title     Define the number of values of a Y-axis
25960 
25961 @Prototype void gridDefYsize(int gridID, size_t ysize)
25962 @Parameter
25963     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
25964     @Item  ysize    Number of values of a Y-axis.
25965 
25966 @Description
25967 The function @func{gridDefYsize} defines the number of values of a Y-axis.
25968 
25969 @EndFunction
25970 */
gridDefYsize(int gridID,size_t ysize)25971 void gridDefYsize(int gridID, size_t ysize)
25972 {
25973   grid_t *gridptr = grid_to_pointer(gridID);
25974 
25975   const size_t gridSize = gridInqSize(gridID);
25976 
25977   if ( ysize > gridSize )
25978     Error("ysize %zu is greater then gridsize %zu", ysize, gridSize);
25979 
25980   const int gridType = gridInqType(gridID);
25981   if ( gridType == GRID_UNSTRUCTURED && ysize != gridSize )
25982     Error("ysize %zu must be equal gridsize %zu for gridtype: %s", gridNamePtr(gridType), ysize, gridSize);
25983 
25984   if ( gridptr->y.size != ysize )
25985     {
25986       gridMark4Update(gridID);
25987       gridptr->y.size = ysize;
25988     }
25989 
25990   if ( gridType != GRID_UNSTRUCTURED && gridType != GRID_GAUSSIAN_REDUCED && gridType != GRID_PROJECTION )
25991     {
25992       const size_t axisproduct = gridptr->x.size*gridptr->y.size;
25993       if ( axisproduct > 0 && axisproduct != gridSize )
25994         Error("Inconsistent grid declaration! (xsize=%zu ysize=%zu gridsize=%zu)",
25995               gridptr->x.size, gridptr->y.size, gridSize);
25996     }
25997 }
25998 
25999 /*
26000 @Function  gridInqYsize
26001 @Title     Get the number of values of a Y-axis
26002 
26003 @Prototype size_t gridInqYsize(int gridID)
26004 @Parameter
26005     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
26006 
26007 @Description
26008 The function @func{gridInqYsize} returns the number of values of a Y-axis.
26009 
26010 @Result
26011 @func{gridInqYsize} returns the number of values of a Y-axis.
26012 
26013 @EndFunction
26014 */
gridInqYsize(int gridID)26015 size_t gridInqYsize(int gridID)
26016 {
26017   grid_t *gridptr = grid_to_pointer(gridID);
26018   return gridptr->y.size;
26019 }
26020 
26021 /*
26022 @Function  gridDefNP
26023 @Title     Define the number of parallels between a pole and the equator
26024 
26025 @Prototype void gridDefNP(int gridID, int np)
26026 @Parameter
26027     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
26028     @Item  np       Number of parallels between a pole and the equator.
26029 
26030 @Description
26031 The function @func{gridDefNP} defines the number of parallels between a pole and the equator
26032 of a Gaussian grid.
26033 
26034 @EndFunction
26035 */
gridDefNP(int gridID,int np)26036 void gridDefNP(int gridID, int np)
26037 {
26038   grid_t *gridptr = grid_to_pointer(gridID);
26039 
26040   if ( gridptr->np != np )
26041     {
26042       gridMark4Update(gridID);
26043       gridptr->np = np;
26044     }
26045 }
26046 
26047 /*
26048 @Function  gridInqNP
26049 @Title     Get the number of parallels between a pole and the equator
26050 
26051 @Prototype int gridInqNP(int gridID)
26052 @Parameter
26053     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
26054 
26055 @Description
26056 The function @func{gridInqNP} returns the number of parallels between a pole and the equator
26057 of a Gaussian grid.
26058 
26059 @Result
26060 @func{gridInqNP} returns the number of parallels between a pole and the equator.
26061 
26062 @EndFunction
26063 */
gridInqNP(int gridID)26064 int gridInqNP(int gridID)
26065 {
26066   grid_t *gridptr = grid_to_pointer(gridID);
26067   return gridptr->np;
26068 }
26069 
26070 /*
26071 @Function
26072 @Title
26073 
26074 @Prototype
26075 @Parameter
26076     @Item  Grid identifier
26077 
26078 @EndFunction
26079 */
gridDefReducedPoints(int gridID,int reducedPointsSize,const int reducedPoints[])26080 void gridDefReducedPoints(int gridID, int reducedPointsSize, const int reducedPoints[])
26081 {
26082   grid_t *gridptr = grid_to_pointer(gridID);
26083 
26084   gridptr->reducedPoints = (int *) Malloc((size_t)reducedPointsSize * sizeof(int));
26085   gridptr->reducedPointsSize = reducedPointsSize;
26086   memcpy(gridptr->reducedPoints, reducedPoints, (size_t)reducedPointsSize * sizeof(int));
26087   gridMark4Update(gridID);
26088 }
26089 
26090 /*
26091 @Function
26092 @Title
26093 
26094 @Prototype
26095 @Parameter
26096     @Item  Grid identifier
26097 
26098 @EndFunction
26099 */
gridInqReducedPoints(int gridID,int * reducedPoints)26100 void gridInqReducedPoints(int gridID, int *reducedPoints)
26101 {
26102   grid_t *gridptr = grid_to_pointer(gridID);
26103 
26104   if ( gridptr->reducedPoints == 0 )  Error("undefined pointer!");
26105 
26106   memcpy(reducedPoints, gridptr->reducedPoints, (size_t)gridptr->reducedPointsSize * sizeof(int));
26107 }
26108 
26109 static size_t
gridInqMaskSerialGeneric(grid_t * gridptr,mask_t ** internalMask,int * restrict mask)26110 gridInqMaskSerialGeneric(grid_t *gridptr, mask_t **internalMask,
26111                         int *restrict mask)
26112 {
26113   size_t size = gridptr->size;
26114 
26115   if ( CDI_Debug && size == 0 )
26116     Warning("Size undefined for gridID = %d", gridptr->self);
26117 
26118   const mask_t *restrict mask_src = *internalMask;
26119   if ( mask_src )
26120     {
26121       if (mask && size > 0)
26122         for (size_t i = 0; i < size; ++i)
26123           mask[i] = (int)mask_src[i];
26124     }
26125   else
26126     size = 0;
26127 
26128   return size;
26129 }
26130 
26131 static size_t
gridInqMaskSerial(grid_t * gridptr,int * mask)26132 gridInqMaskSerial(grid_t *gridptr, int *mask)
26133 {
26134   return gridInqMaskSerialGeneric(gridptr, &gridptr->mask, mask);
26135 }
26136 
26137 
gridInqMask(int gridID,int * mask)26138 int gridInqMask(int gridID, int *mask)
26139 {
26140   grid_t *gridptr = grid_to_pointer(gridID);
26141   return gridptr->vtable->inqMask(gridptr, mask);
26142 }
26143 
26144 static void
gridDefMaskSerial(grid_t * gridptr,const int * mask)26145 gridDefMaskSerial(grid_t *gridptr, const int *mask)
26146 {
26147   const size_t size = gridptr->size;
26148   if ( size == 0 ) Error("Size undefined for gridID = %d", gridptr->self);
26149 
26150   if ( mask == NULL )
26151     {
26152       if ( gridptr->mask )
26153 	{
26154 	  Free(gridptr->mask);
26155 	  gridptr->mask = NULL;
26156 	}
26157     }
26158   else
26159     {
26160       if ( gridptr->mask == NULL )
26161 	gridptr->mask = (mask_t *) Malloc(size*sizeof(mask_t));
26162       else if ( CDI_Debug )
26163 	Warning("grid mask already defined!");
26164 
26165       for (size_t i = 0; i < size; ++i )
26166 	gridptr->mask[i] = (mask_t)(mask[i] != 0);
26167     }
26168 }
26169 
gridDefMask(int gridID,const int * mask)26170 void gridDefMask(int gridID, const int *mask)
26171 {
26172   grid_t *gridptr = grid_to_pointer(gridID);
26173   gridptr->vtable->defMask(gridptr, mask);
26174   gridMark4Update(gridID);
26175 }
26176 
26177 static int
gridInqMaskGMESerial(grid_t * gridptr,int * mask_gme)26178 gridInqMaskGMESerial(grid_t *gridptr, int *mask_gme)
26179 {
26180   return gridInqMaskSerialGeneric(gridptr, &gridptr->mask_gme, mask_gme);
26181 }
26182 
gridInqMaskGME(int gridID,int * mask)26183 int gridInqMaskGME(int gridID, int *mask)
26184 {
26185   grid_t *gridptr = grid_to_pointer(gridID);
26186   return gridptr->vtable->inqMaskGME(gridptr, mask);
26187 }
26188 
26189 static void
gridDefMaskGMESerial(grid_t * gridptr,const int * mask)26190 gridDefMaskGMESerial(grid_t *gridptr, const int *mask)
26191 {
26192   const size_t size = gridptr->size;
26193   if ( size == 0 ) Error("Size undefined for gridID = %d", gridptr->self);
26194 
26195   if ( gridptr->mask_gme == NULL )
26196     gridptr->mask_gme = (mask_t *) Malloc(size * sizeof (mask_t));
26197   else if ( CDI_Debug )
26198     Warning("mask already defined!");
26199 
26200   for (size_t i = 0; i < size; ++i)
26201     gridptr->mask_gme[i] = (mask_t)(mask[i] != 0);
26202 }
26203 
gridDefMaskGME(int gridID,const int * mask)26204 void gridDefMaskGME(int gridID, const int *mask)
26205 {
26206   grid_t *gridptr = grid_to_pointer(gridID);
26207   gridptr->vtable->defMaskGME(gridptr, mask);
26208   gridMark4Update(gridID);
26209 }
26210 
26211 static
gridInqXValsSerial(grid_t * gridptr,double * xvals)26212 size_t gridInqXValsSerial(grid_t *gridptr, double *xvals)
26213 {
26214   size_t size;
26215   if ( gridptr->type == GRID_CURVILINEAR || gridptr->type == GRID_UNSTRUCTURED )
26216     size = gridptr->size;
26217   else
26218     size = gridptr->x.size;
26219 
26220   if ( CDI_Debug && size == 0 )
26221     Warning("size undefined for gridID = %d", gridptr->self);
26222 
26223   if ( gridptr->x.vals )
26224     {
26225       if ( size && xvals )
26226         {
26227           const double *gridptr_xvals = gridptr->vtable->inqXValsPtr(gridptr);
26228           memcpy(xvals, gridptr_xvals, size * sizeof (double));
26229         }
26230     }
26231   else
26232     size = 0;
26233 
26234   return size;
26235 }
26236 
26237 static
gridInqXValsPartSerial(grid_t * gridptr,int start,size_t length,double * xvals)26238 size_t gridInqXValsPartSerial(grid_t *gridptr, int start, size_t length, double *xvals)
26239 {
26240   size_t size;
26241   if ( gridptr->type == GRID_CURVILINEAR || gridptr->type == GRID_UNSTRUCTURED )
26242     size = gridptr->size;
26243   else
26244     size = gridptr->x.size;
26245 
26246   if ( CDI_Debug && size == 0 )
26247     Warning("size undefined for gridID = %d", gridptr->self);
26248 
26249   if ( gridptr->x.vals )
26250     {
26251       if ( size && xvals && length <= size )
26252         {
26253           const double *gridptr_xvals = gridptr->vtable->inqXValsPtr(gridptr);
26254           memcpy(xvals, gridptr_xvals+start, length * sizeof (double));
26255         }
26256     }
26257   else
26258     size = 0;
26259 
26260   return size;
26261 }
26262 
26263 #ifndef USE_MPI
26264 static
gridInqXCvalsSerial(grid_t * gridptr,char ** xcvals)26265 size_t gridInqXCvalsSerial(grid_t *gridptr, char **xcvals)
26266 {
26267   if ( gridptr->type != GRID_CHARXY )
26268     Error("Function only valid for grid type 'GRID_CHARXY'.");
26269 
26270   const size_t size = gridptr->x.size;
26271   size_t maxclength = 0;
26272 
26273   const char **gridptr_xcvals = gridptr->vtable->inqXCvalsPtr(gridptr);
26274   if ( gridptr_xcvals && size && xcvals )
26275     {
26276       maxclength = gridptr->x.clength;
26277       for ( size_t i = 0; i < size; i++ )
26278         memcpy(xcvals[i], gridptr_xcvals[i], maxclength*sizeof(char));
26279     }
26280 
26281   return maxclength;
26282 }
26283 
26284 static
gridInqXIscSerial(grid_t * gridptr)26285 int gridInqXIscSerial(grid_t *gridptr)
26286 {
26287   /*
26288   if ( gridptr->type != GRID_CHARXY )
26289     Error("Axis type is 'char' but grid is not type 'GRID_CHARXY'.");
26290   */
26291   return gridptr->x.clength;
26292 }
26293 #endif
26294 
26295 /*
26296 @Function  gridInqXvals
26297 @Title     Get all values of a X-axis
26298 
26299 @Prototype size_t gridInqXvals(int gridID, double *xvals)
26300 @Parameter
26301     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
26302     @Item  xvals    Pointer to the location into which the X-values are read.
26303                     The caller must allocate space for the returned values.
26304 
26305 @Description
26306 The function @func{gridInqXvals} returns all values of the X-axis.
26307 
26308 @Result
26309 Upon successful completion @func{gridInqXvals} returns the number of values and
26310 the values are stored in @func{xvals}.
26311 Otherwise, 0 is returned and @func{xvals} is empty.
26312 
26313 @EndFunction
26314 */
gridInqXvals(int gridID,double * xvals)26315 size_t gridInqXvals(int gridID, double *xvals)
26316 {
26317   grid_t *gridptr = grid_to_pointer(gridID);
26318   return gridptr->vtable->inqXVals(gridptr, xvals);
26319 }
26320 
26321 
gridInqXvalsPart(int gridID,int start,size_t length,double * xvals)26322 size_t gridInqXvalsPart(int gridID, int start, size_t length, double *xvals)
26323 {
26324   grid_t *gridptr = grid_to_pointer(gridID);
26325   return gridptr->vtable->inqXValsPart(gridptr, start, length, xvals);
26326 }
26327 
26328 
gridInqXCvals(int gridID,char ** xcvals)26329 size_t gridInqXCvals(int gridID, char **xcvals)
26330 {
26331   grid_t *gridptr = grid_to_pointer(gridID);
26332 #ifndef USE_MPI
26333   return gridptr->vtable->inqXCvals(gridptr, xcvals);
26334 #else
26335   return 0;
26336 #endif
26337 }
26338 
26339 
gridInqXIsc(int gridID)26340 int gridInqXIsc(int gridID)
26341 {
26342   grid_t *gridptr = grid_to_pointer(gridID);
26343 #ifndef USE_MPI
26344   return gridptr->vtable->inqXIsc(gridptr);
26345 #else
26346   return 0;
26347 #endif
26348 }
26349 
26350 static
gridDefXValsSerial(grid_t * gridptr,const double * xvals)26351 void gridDefXValsSerial(grid_t *gridptr, const double *xvals)
26352 {
26353   const int gridtype = gridptr->type;
26354 
26355   size_t size;
26356   if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
26357     size = gridptr->size;
26358   else
26359     size = gridptr->x.size;
26360 
26361   if ( size == 0 ) Error("Size undefined for gridID = %d", gridptr->self);
26362 
26363   if (gridptr->x.vals && CDI_Debug)
26364     Warning("values already defined!");
26365   gridptr->x.vals = (double *)Realloc(gridptr->x.vals, size * sizeof(double));
26366   memcpy(gridptr->x.vals, xvals, size * sizeof (double));
26367 }
26368 
26369 #ifndef USE_MPI
26370 static
gridInqYCvalsSerial(grid_t * gridptr,char ** ycvals)26371 size_t gridInqYCvalsSerial(grid_t *gridptr, char **ycvals)
26372 {
26373   if ( gridptr->type != GRID_CHARXY )
26374     Error("Function only valid for grid type 'GRID_CHARXY'.");
26375 
26376   const size_t size = gridptr->y.size;
26377   size_t maxclength = 0;
26378 
26379   const char **gridptr_ycvals = gridptr->vtable->inqYCvalsPtr(gridptr);
26380   if ( gridptr_ycvals && size && ycvals )
26381     {
26382       maxclength = gridptr->y.clength;
26383       for ( size_t i = 0; i < size; i++ )
26384         memcpy(ycvals[i], gridptr_ycvals[i], maxclength*sizeof(char));
26385     }
26386 
26387   return maxclength;
26388 }
26389 
26390 static
gridInqYIscSerial(grid_t * gridptr)26391 int gridInqYIscSerial(grid_t *gridptr)
26392 {
26393   /*
26394   if ( gridptr->type != GRID_CHARXY )
26395     Error("Axis type is 'char' but grid is not type 'GRID_CHARXY'.");
26396   */
26397   return gridptr->y.clength;
26398 }
26399 #endif
26400 
26401 /*
26402 @Function  gridDefXvals
26403 @Title     Define the values of a X-axis
26404 
26405 @Prototype void gridDefXvals(int gridID, const double *xvals)
26406 @Parameter
26407     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
26408     @Item  xvals    X-values of the grid.
26409 
26410 @Description
26411 The function @func{gridDefXvals} defines all values of the X-axis.
26412 
26413 @EndFunction
26414 */
gridDefXvals(int gridID,const double * xvals)26415 void gridDefXvals(int gridID, const double *xvals)
26416 {
26417   grid_t *gridptr = grid_to_pointer(gridID);
26418   gridptr->vtable->defXVals(gridptr, xvals);
26419   gridMark4Update(gridID);
26420 }
26421 
26422 static
gridInqYValsSerial(grid_t * gridptr,double * yvals)26423 size_t gridInqYValsSerial(grid_t *gridptr, double *yvals)
26424 {
26425   const int gridtype = gridptr->type;
26426   size_t size = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
26427             ? gridptr->size : gridptr->y.size;
26428 
26429   if ( CDI_Debug && size == 0 )
26430     Warning("size undefined for gridID = %d!", gridptr->self);
26431 
26432   if ( gridptr->y.vals )
26433     {
26434       if ( size && yvals )
26435         {
26436           const double *gridptr_yvals = gridptr->vtable->inqYValsPtr(gridptr);
26437           memcpy(yvals, gridptr_yvals, size * sizeof (double));
26438         }
26439     }
26440   else
26441     size = 0;
26442 
26443   return size;
26444 }
26445 
26446 static
gridInqYValsPartSerial(grid_t * gridptr,int start,size_t length,double * yvals)26447 size_t gridInqYValsPartSerial(grid_t *gridptr, int start, size_t length, double *yvals)
26448 {
26449   const int gridtype = gridptr->type;
26450   size_t size = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
26451             ? gridptr->size : gridptr->y.size;
26452 
26453   if ( CDI_Debug && size == 0 )
26454     Warning("size undefined for gridID = %d!", gridptr->self);
26455 
26456   if ( gridptr->y.vals )
26457     {
26458       if ( size && yvals && length <= size )
26459         {
26460           const double *gridptr_yvals = gridptr->vtable->inqYValsPtr(gridptr);
26461           memcpy(yvals, gridptr_yvals+start, length * sizeof (double));
26462         }
26463     }
26464   else
26465     size = 0;
26466 
26467   return size;
26468 }
26469 
26470 /*
26471 @Function  gridInqYvals
26472 @Title     Get all values of a Y-axis
26473 
26474 @Prototype size_t gridInqYvals(int gridID, double *yvals)
26475 @Parameter
26476     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
26477     @Item  yvals    Pointer to the location into which the Y-values are read.
26478                     The caller must allocate space for the returned values.
26479 
26480 @Description
26481 The function @func{gridInqYvals} returns all values of the Y-axis.
26482 
26483 @Result
26484 Upon successful completion @func{gridInqYvals} returns the number of values and
26485 the values are stored in @func{yvals}.
26486 Otherwise, 0 is returned and @func{yvals} is empty.
26487 
26488 @EndFunction
26489 */
gridInqYvals(int gridID,double * yvals)26490 size_t gridInqYvals(int gridID, double *yvals)
26491 {
26492   grid_t *gridptr = grid_to_pointer(gridID);
26493   return gridptr->vtable->inqYVals(gridptr, yvals);
26494 }
26495 
26496 
gridInqYvalsPart(int gridID,int start,size_t size,double * yvals)26497 size_t gridInqYvalsPart(int gridID, int start, size_t size, double *yvals)
26498 {
26499   grid_t *gridptr = grid_to_pointer(gridID);
26500   return gridptr->vtable->inqYValsPart(gridptr, start, size, yvals);
26501 }
26502 
26503 
gridInqYCvals(int gridID,char ** ycvals)26504 size_t gridInqYCvals(int gridID, char **ycvals)
26505 {
26506   grid_t *gridptr = grid_to_pointer(gridID);
26507 #ifndef USE_MPI
26508   return gridptr->vtable->inqYCvals(gridptr, ycvals);
26509 #else
26510   return 0;
26511 #endif
26512 }
26513 
26514 
gridInqYIsc(int gridID)26515 int gridInqYIsc(int gridID)
26516 {
26517   grid_t *gridptr = grid_to_pointer(gridID);
26518 #ifndef USE_MPI
26519   return gridptr->vtable->inqYIsc(gridptr);
26520 #else
26521   return 0;
26522 #endif
26523 }
26524 
26525 static
gridDefYValsSerial(grid_t * gridptr,const double * yvals)26526 void gridDefYValsSerial(grid_t *gridptr, const double *yvals)
26527 {
26528   const int gridtype = gridptr->type;
26529   const size_t size = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
26530                     ? gridptr->size : gridptr->y.size;
26531 
26532   if ( size == 0 )
26533     Error("Size undefined for gridID = %d!", gridptr->self);
26534 
26535   if ( gridptr->y.vals && CDI_Debug )
26536     Warning("Values already defined!");
26537 
26538   gridptr->y.vals = (double *)Realloc(gridptr->y.vals, size * sizeof (double));
26539   memcpy(gridptr->y.vals, yvals, size * sizeof (double));
26540 }
26541 
26542 
26543 /*
26544 @Function  gridDefYvals
26545 @Title     Define the values of a Y-axis
26546 
26547 @Prototype void gridDefYvals(int gridID, const double *yvals)
26548 @Parameter
26549     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
26550     @Item  yvals    Y-values of the grid.
26551 
26552 @Description
26553 The function @func{gridDefYvals} defines all values of the Y-axis.
26554 
26555 @EndFunction
26556 */
gridDefYvals(int gridID,const double * yvals)26557 void gridDefYvals(int gridID, const double *yvals)
26558 {
26559   grid_t *gridptr = grid_to_pointer(gridID);
26560   gridptr->vtable->defYVals(gridptr, yvals);
26561   gridMark4Update(gridID);
26562 }
26563 
26564 static double
gridInqXValSerial(grid_t * gridptr,size_t index)26565 gridInqXValSerial(grid_t *gridptr, size_t index)
26566 {
26567   const double xval = gridptr->x.vals ? gridptr->x.vals[index] : 0;
26568   return xval;
26569 }
26570 
26571 
gridInqXval(int gridID,size_t index)26572 double gridInqXval(int gridID, size_t index)
26573 {
26574   grid_t *gridptr = grid_to_pointer(gridID);
26575   return gridptr->vtable->inqXVal(gridptr, index);
26576 }
26577 
26578 static double
gridInqYValSerial(grid_t * gridptr,size_t index)26579 gridInqYValSerial(grid_t *gridptr, size_t index)
26580 {
26581   const double yval = gridptr->y.vals ? gridptr->y.vals[index] : 0;
26582   return yval;
26583 }
26584 
26585 /*
26586 @Function
26587 @Title
26588 
26589 @Prototype
26590 @Parameter
26591     @Item  Grid identifier
26592 
26593 @EndFunction
26594 */
gridInqYval(int gridID,size_t index)26595 double gridInqYval(int gridID, size_t index)
26596 {
26597   grid_t *gridptr = grid_to_pointer(gridID);
26598   return gridptr->vtable->inqYVal(gridptr, index);
26599 }
26600 
26601 static
grid_calc_increment(size_t size,const double * vals)26602 double grid_calc_increment(size_t size, const double *vals)
26603 {
26604   if ( size > 1 )
26605     {
26606       double inc = (vals[size-1] - vals[0])/(size-1);
26607       const double abs_inc = fabs(inc);
26608       for ( size_t i = 1; i < size; ++i )
26609         if ( fabs(fabs(vals[i-1] - vals[i]) - abs_inc) > 0.01*abs_inc )
26610           {
26611             inc = 0;
26612             break;
26613           }
26614 
26615       return inc;
26616     }
26617 
26618   return 0;
26619 }
26620 
26621 /*
26622 @Function
26623 @Title
26624 
26625 @Prototype
26626 @Parameter
26627     @Item  Grid identifier
26628 
26629 @EndFunction
26630 */
gridInqXinc(int gridID)26631 double gridInqXinc(int gridID)
26632 {
26633   grid_t *gridptr = grid_to_pointer(gridID);
26634   const double *restrict xvals = gridptr->vtable->inqXValsPtr(gridptr);
26635 
26636   if (fabs(gridptr->x.inc) <= 0 && xvals)
26637     {
26638       const size_t xsize = gridptr->x.size;
26639       if ( xsize > 1 ) gridptr->x.inc = grid_calc_increment(xsize, xvals);
26640     }
26641 
26642   return gridptr->x.inc;
26643 }
26644 
26645 /*
26646 @Function
26647 @Title
26648 
26649 @Prototype
26650 @Parameter
26651     @Item  Grid identifier
26652 
26653 @EndFunction
26654 */
gridInqYinc(int gridID)26655 double gridInqYinc(int gridID)
26656 {
26657   grid_t *gridptr = grid_to_pointer(gridID);
26658   const double *yvals = gridptr->vtable->inqYValsPtr(gridptr);
26659 
26660   if (fabs(gridptr->y.inc) <= 0 && yvals)
26661     {
26662       const size_t ysize = gridptr->y.size;
26663       if ( ysize > 1 ) gridptr->y.inc = grid_calc_increment(ysize, yvals);
26664     }
26665 
26666   return gridptr->y.inc;
26667 }
26668 
26669 /*
26670 @Function
26671 @Title
26672 
26673 @Prototype
26674 @Parameter
26675     @Item  Grid identifier
26676 
26677 @EndFunction
26678 */
gridInqParamRLL(int gridID,double * xpole,double * ypole,double * angle)26679 void gridInqParamRLL(int gridID, double *xpole, double *ypole, double *angle)
26680 {
26681   *xpole = 0; *ypole = 0; *angle = 0;
26682 
26683   const char *projection = "rotated_latitude_longitude";
26684   char gmapname[CDI_MAX_NAME];
26685   int length = CDI_MAX_NAME;
26686   cdiInqKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_NAME, gmapname, &length);
26687   if ( gmapname[0] && strIsEqual(gmapname, projection) )
26688     {
26689       int atttype, attlen;
26690       char attname[CDI_MAX_NAME+1];
26691 
26692       int natts;
26693       cdiInqNatts(gridID, CDI_GLOBAL, &natts);
26694 
26695       for ( int iatt = 0; iatt < natts; ++iatt )
26696         {
26697           cdiInqAtt(gridID, CDI_GLOBAL, iatt, attname, &atttype, &attlen);
26698           if ( attlen != 1 ) continue;
26699 
26700           double attflt;
26701           if ( cdiInqAttConvertedToFloat(gridID, atttype, attname, attlen, &attflt) )
26702             {
26703               if      ( strIsEqual(attname, "grid_north_pole_longitude") ) *xpole = attflt;
26704               else if ( strIsEqual(attname, "grid_north_pole_latitude")  ) *ypole = attflt;
26705               else if ( strIsEqual(attname, "north_pole_grid_longitude") ) *angle = attflt;
26706             }
26707         }
26708     }
26709   else
26710     Warning("%s mapping parameter missing!", projection);
26711 }
26712 
26713 /*
26714 @Function
26715 @Title
26716 
26717 @Prototype
26718 @Parameter
26719     @Item  Grid identifier
26720 
26721 @EndFunction
26722 */
gridDefParamRLL(int gridID,double xpole,double ypole,double angle)26723 void gridDefParamRLL(int gridID, double xpole, double ypole, double angle)
26724 {
26725   cdiDefKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_VARNAME, "rotated_pole");
26726 
26727   const char *gmapname = "rotated_latitude_longitude";
26728   cdiDefKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_NAME, gmapname);
26729   cdiDefAttTxt(gridID, CDI_GLOBAL, "grid_mapping_name", (int)(strlen(gmapname)), gmapname);
26730   cdiDefAttFlt(gridID, CDI_GLOBAL, "grid_north_pole_longitude", CDI_DATATYPE_FLT64, 1, &xpole);
26731   cdiDefAttFlt(gridID, CDI_GLOBAL, "grid_north_pole_latitude", CDI_DATATYPE_FLT64, 1, &ypole);
26732   if ( IS_NOT_EQUAL(angle, 0) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "north_pole_grid_longitude", CDI_DATATYPE_FLT64, 1, &angle);
26733 
26734   grid_t *gridptr = grid_to_pointer(gridID);
26735   gridptr->projtype = CDI_PROJ_RLL;
26736 
26737   gridVerifyProj(gridID);
26738 }
26739 
26740 /*
26741 @Function
26742 @Title
26743 
26744 @Prototype
26745 @Parameter
26746     @Item  Grid identifier
26747 
26748 @EndFunction
26749 */
gridInqParamGME(int gridID,int * nd,int * ni,int * ni2,int * ni3)26750 void gridInqParamGME(int gridID, int *nd, int *ni, int *ni2, int *ni3)
26751 {
26752   grid_t *gridptr = grid_to_pointer(gridID);
26753 
26754   *nd  = gridptr->gme.nd;
26755   *ni  = gridptr->gme.ni;
26756   *ni2 = gridptr->gme.ni2;
26757   *ni3 = gridptr->gme.ni3;
26758 }
26759 
26760 /*
26761 @Function
26762 @Title
26763 
26764 @Prototype
26765 @Parameter
26766     @Item  Grid identifier
26767 
26768 @EndFunction
26769 */
gridDefParamGME(int gridID,int nd,int ni,int ni2,int ni3)26770 void gridDefParamGME(int gridID, int nd, int ni, int ni2, int ni3)
26771 {
26772   grid_t *gridptr = grid_to_pointer(gridID);
26773 
26774   if ( gridptr->gme.nd != nd )
26775     {
26776       gridptr->gme.nd  = nd;
26777       gridptr->gme.ni  = ni;
26778       gridptr->gme.ni2 = ni2;
26779       gridptr->gme.ni3 = ni3;
26780       gridMark4Update(gridID);
26781     }
26782 }
26783 
26784 /*
26785 @Function
26786 @Title
26787 
26788 @Prototype
26789 @Parameter
26790     @Item  Grid identifier
26791 
26792 @EndFunction
26793 */
gridChangeType(int gridID,int gridtype)26794 void gridChangeType(int gridID, int gridtype)
26795 {
26796   grid_t *gridptr = grid_to_pointer(gridID);
26797 
26798   if ( CDI_Debug )
26799     Message("Changed grid type from %s to %s", gridNamePtr(gridptr->type), gridNamePtr(gridtype));
26800 
26801   if (gridptr->type != gridtype)
26802     {
26803       gridptr->type = gridtype;
26804       gridMark4Update(gridID);
26805     }
26806 }
26807 
26808 static
grid_check_cyclic(grid_t * gridptr)26809 void grid_check_cyclic(grid_t *gridptr)
26810 {
26811   gridptr->isCyclic = 0;
26812   enum { numVertices = 4 };
26813   size_t xsize = gridptr->x.size,
26814          ysize = gridptr->y.size;
26815   const double *xvals = gridptr->vtable->inqXValsPtr(gridptr),
26816                *yvals = gridptr->vtable->inqYValsPtr(gridptr),
26817     (*xbounds)[numVertices]
26818     = (const double (*)[numVertices])gridptr->vtable->inqXBoundsPtr(gridptr);
26819 
26820   if ( gridptr->type == GRID_GAUSSIAN || gridptr->type == GRID_LONLAT )
26821     {
26822       if ( xvals && xsize > 1 )
26823         {
26824           double xval1 = xvals[0];
26825           double xval2 = xvals[1];
26826           double xvaln = xvals[xsize-1];
26827           if ( xval2 < xval1 ) xval2 += 360;
26828           if ( xvaln < xval1 ) xvaln += 360;
26829 
26830           if ( IS_NOT_EQUAL(xval1, xvaln) )
26831             {
26832               double xinc = xval2 - xval1;
26833               if ( IS_EQUAL(xinc, 0) ) xinc = (xvaln - xval1)/(xsize-1);
26834 
26835               const double x0 = xvaln + xinc - 360;
26836 
26837               if ( fabs(x0 - xval1) < 0.01*xinc ) gridptr->isCyclic = 1;
26838             }
26839         }
26840     }
26841   else if ( gridptr->type == GRID_CURVILINEAR )
26842     {
26843       bool lcheck = true;
26844       if ( yvals && xvals )
26845         {
26846           if ( (fabs(yvals[0] - yvals[xsize-1]) > fabs(yvals[0] - yvals[xsize*ysize-xsize])) &&
26847                (fabs(yvals[xsize*ysize-xsize] - yvals[xsize*ysize-1]) > fabs(yvals[xsize-1] - yvals[xsize*ysize-1])) )
26848             lcheck = false;
26849         }
26850       else lcheck = false;
26851 
26852       if ( lcheck && xvals && xsize > 1 )
26853         {
26854           size_t nc = 0;
26855           for ( size_t j = 0; j < ysize; ++j )
26856             {
26857               size_t i1 = j*xsize,
26858                      i2 = j*xsize+1,
26859                      in = j*xsize+(xsize-1);
26860               double val1 = xvals[i1],
26861                      val2 = xvals[i2],
26862                      valn = xvals[in];
26863               double xinc = fabs(val2-val1);
26864 
26865 	      if ( val1 <    1 && valn > 300 ) val1 += 360;
26866 	      if ( valn <    1 && val1 > 300 ) valn += 360;
26867 	      if ( val1 < -179 && valn > 120 ) val1 += 360;
26868 	      if ( valn < -179 && val1 > 120 ) valn += 360;
26869               if ( fabs(valn-val1) > 180 ) val1 += 360;
26870 
26871               double x0 = valn + copysign(xinc, val1 - valn);
26872 
26873               nc += fabs(x0-val1) < 0.5*xinc;
26874             }
26875           gridptr->isCyclic = nc > ysize/2;
26876         }
26877 
26878       if ( lcheck && xbounds && xsize > 1 )
26879 	{
26880           bool isCyclic = true;
26881 	  for ( size_t j = 0; j < ysize; ++j )
26882 	    {
26883 	      size_t i1 = j*xsize,
26884                      i2 = j*xsize+(xsize-1);
26885 	      for (size_t k1 = 0; k1 < numVertices; ++k1 )
26886 		{
26887 		  double val1 = xbounds[i1][k1];
26888 		  for (size_t k2 = 0; k2 < numVertices; ++k2 )
26889 		    {
26890 		      double val2 = xbounds[i2][k2];
26891 
26892 		      if ( val1 <    1 && val2 > 300 ) val1 += 360;
26893 		      if ( val2 <    1 && val1 > 300 ) val2 += 360;
26894 		      if ( val1 < -179 && val2 > 120 ) val1 += 360;
26895 		      if ( val2 < -179 && val1 > 120 ) val2 += 360;
26896                       if ( fabs(val2-val1) > 180 ) val1 += 360;
26897 
26898 		      if ( fabs(val1-val2) < 0.001 )
26899                         goto foundCloseVertices;
26900 		    }
26901 		}
26902               /* all vertices more than 0.001 degrees apart */
26903               isCyclic = false;
26904               break;
26905               foundCloseVertices:
26906               ;
26907 	    }
26908           gridptr->isCyclic = isCyclic;
26909 	}
26910     }
26911 }
26912 
26913 
gridIsCircular(int gridID)26914 int gridIsCircular(int gridID)
26915 {
26916   grid_t *gridptr = grid_to_pointer(gridID);
26917 
26918   if ( gridptr->isCyclic == CDI_UNDEFID ) grid_check_cyclic(gridptr);
26919 
26920   return gridptr->isCyclic;
26921 }
26922 
26923 static
compareXYvals(grid_t * gridRef,grid_t * gridTest)26924 bool compareXYvals(grid_t *gridRef, grid_t *gridTest)
26925 {
26926   bool differ = false;
26927 
26928   size_t xsizeTest = gridTest->x.size, ysizeTest = gridTest->y.size;
26929   if ( !differ && xsizeTest > 0 && xsizeTest == gridRef->vtable->inqXVals(gridRef, NULL) )
26930     {
26931       const double *restrict xvalsRef = gridRef->vtable->inqXValsPtr(gridRef),
26932         *restrict xvalsTest = gridTest->vtable->inqXValsPtr(gridTest);
26933 
26934       for ( size_t i = 0; i < xsizeTest; ++i )
26935 	if ( fabs(xvalsTest[i] - xvalsRef[i]) > 1.e-10 )
26936 	  {
26937 	    differ = true;
26938 	    break;
26939 	  }
26940     }
26941 
26942   if ( !differ && ysizeTest > 0 && ysizeTest == gridRef->vtable->inqYVals(gridRef, NULL) )
26943     {
26944       const double *restrict yvalsRef = gridRef->vtable->inqYValsPtr(gridRef),
26945         *restrict yvalsTest = gridTest->vtable->inqYValsPtr(gridTest);
26946       for ( size_t i = 0; i < ysizeTest; ++i )
26947 	if ( fabs(yvalsTest[i] - yvalsRef[i]) > 1.e-10 )
26948 	  {
26949 	    differ = true;
26950 	    break;
26951 	  }
26952     }
26953 
26954   return differ;
26955 }
26956 
26957 static
compareXYvals2(grid_t * gridRef,grid_t * gridTest)26958 bool compareXYvals2(grid_t *gridRef, grid_t *gridTest)
26959 {
26960   size_t gridsize = gridTest->size;
26961   bool differ = ((gridTest->x.vals == NULL) ^ (gridRef->x.vals == NULL))
26962              || ((gridTest->y.vals == NULL) ^ (gridRef->y.vals == NULL))
26963              || ((gridTest->x.bounds == NULL) ^ (gridRef->x.bounds == NULL))
26964              || ((gridTest->y.bounds == NULL) ^ (gridRef->y.bounds == NULL));
26965 
26966   typedef double (*inqVal)(grid_t *grid, size_t index);
26967   inqVal inqXValRef = gridRef->vtable->inqXVal,
26968          inqYValRef = gridRef->vtable->inqYVal,
26969          inqXValTest = gridTest->vtable->inqXVal,
26970          inqYValTest = gridTest->vtable->inqYVal;
26971 
26972   if ( !differ && gridTest->x.vals )
26973     differ = fabs(inqXValTest(gridTest, 0) - inqXValRef(gridRef, 0)) > 1.e-9
26974           || fabs(inqXValTest(gridTest, gridsize-1) - inqXValRef(gridRef, gridsize-1)) > 1.e-9;
26975 
26976   if ( !differ && gridTest->y.vals )
26977     differ = fabs(inqYValTest(gridTest, 0) - inqYValRef(gridRef, 0)) > 1.e-9
26978           || fabs(inqYValTest(gridTest, gridsize-1) - inqYValRef(gridRef, gridsize-1)) > 1.e-9;
26979 
26980   return differ;
26981 }
26982 
26983 static
gridCompare(int gridID,const grid_t * grid,bool coord_compare)26984 bool gridCompare(int gridID, const grid_t *grid, bool coord_compare)
26985 {
26986   bool differ = true;
26987   const grid_t *gridRef = grid_to_pointer(gridID);
26988 
26989   if ( grid->type == gridRef->type || grid->type == GRID_GENERIC )
26990     {
26991       if ( grid->size == gridRef->size )
26992 	{
26993 	  differ = false;
26994 	  if ( grid->type == GRID_LONLAT || grid->type == GRID_PROJECTION )
26995 	    {
26996 	      /*
26997 	      printf("gridID      %d\n", gridID);
26998 	      printf("grid.xdef   %d\n", grid->x.flag);
26999 	      printf("grid.ydef   %d\n", grid->y.flag);
27000 	      printf("grid.xsize  %zu\n", grid->x.size);
27001 	      printf("grid.ysize  %zu\n", grid->y.size);
27002 	      printf("grid.xfirst %f\n", grid->x.first);
27003 	      printf("grid.yfirst %f\n", grid->y.first);
27004 	      printf("grid.xfirst %f\n", gridInqXval(gridID, 0));
27005 	      printf("grid.yfirst %f\n", gridInqYval(gridID, 0));
27006 	      printf("grid.xinc   %f\n", grid->x.inc);
27007 	      printf("grid.yinc   %f\n", grid->y.inc);
27008 	      printf("grid.xinc   %f\n", gridInqXinc(gridID));
27009 	      printf("grid.yinc   %f\n", gridInqYinc(gridID));
27010 	      */
27011 	      if ( grid->x.size == gridRef->x.size && grid->y.size == gridRef->y.size )
27012 		{
27013 		  if ( grid->x.flag == 2 && grid->y.flag == 2 )
27014 		    {
27015 		      if ( ! (IS_EQUAL(grid->x.first, 0) && IS_EQUAL(grid->x.last, 0) && IS_EQUAL(grid->x.inc, 0)) &&
27016 			   ! (IS_EQUAL(grid->y.first, 0) && IS_EQUAL(grid->y.last, 0) && IS_EQUAL(grid->y.inc, 0)) &&
27017 			   IS_NOT_EQUAL(grid->x.first, grid->x.last) && IS_NOT_EQUAL(grid->y.first, grid->y.last) )
27018 			{
27019 			  if ( IS_NOT_EQUAL(grid->x.first, gridInqXval(gridID, 0)) ||
27020 			       IS_NOT_EQUAL(grid->y.first, gridInqYval(gridID, 0)))
27021 			    {
27022 			      differ = true;
27023 			    }
27024 			  if ( !differ && fabs(grid->x.inc) > 0 &&
27025 			       fabs(fabs(grid->x.inc) - fabs(gridRef->x.inc)) > fabs(grid->x.inc/1000))
27026 			    {
27027 			      differ = true;
27028 			    }
27029 			  if ( !differ && fabs(grid->y.inc) > 0 &&
27030 			       fabs(fabs(grid->y.inc) - fabs(gridRef->y.inc)) > fabs(grid->y.inc/1000))
27031 			    {
27032 			      differ = true;
27033 			    }
27034 			}
27035 		    }
27036 		  else if ( grid->x.vals && grid->y.vals )
27037                     differ = gridRef->vtable->compareXYFull((grid_t *)gridRef, (grid_t *)grid);
27038 		}
27039 	      else
27040 		differ = true;
27041 	    }
27042 	  else if ( grid->type == GRID_GENERIC )
27043 	    {
27044 	      if ( grid->x.size == gridRef->x.size && grid->y.size == gridRef->y.size )
27045 		{
27046 		  if ( grid->x.flag == 1 && grid->y.flag == 1
27047                        && grid->x.vals && grid->y.vals )
27048                     differ = gridRef->vtable->compareXYFull((grid_t *)gridRef, (grid_t *)grid);
27049 		}
27050 	      else if ( (grid->y.size == 0 || grid->y.size == 1) &&
27051 			grid->x.size == gridRef->x.size*gridRef->y.size )
27052 		{
27053 		}
27054 	      else
27055 		differ = true;
27056 	    }
27057 	  else if ( grid->type == GRID_GAUSSIAN )
27058 	    {
27059 	      if ( grid->x.size == gridRef->x.size && grid->y.size == gridRef->y.size )
27060 		{
27061 		  if ( grid->x.flag == 2 && grid->y.flag == 2 )
27062 		    {
27063 		      if ( ! (IS_EQUAL(grid->x.first, 0) && IS_EQUAL(grid->x.last, 0) && IS_EQUAL(grid->x.inc, 0)) &&
27064 			   ! (IS_EQUAL(grid->y.first, 0) && IS_EQUAL(grid->y.last, 0)) )
27065 			if ( fabs(grid->x.first - gridInqXval(gridID, 0)) > 0.0015 ||
27066 			     fabs(grid->y.first - gridInqYval(gridID, 0)) > 0.0015 ||
27067 			     (fabs(grid->x.inc)>0 && fabs(fabs(grid->x.inc) - fabs(gridRef->x.inc)) > fabs(grid->x.inc/1000)) )
27068 			  {
27069 			    differ = true;
27070 			  }
27071 		    }
27072 		  else if ( grid->x.vals && grid->y.vals )
27073                     differ = gridRef->vtable->compareXYFull((grid_t *)gridRef, (grid_t *)grid);
27074 		}
27075 	      else
27076 		differ = true;
27077 	    }
27078 	  else if ( grid->type == GRID_CURVILINEAR )
27079 	    {
27080 	      /*
27081 	      printf("gridID      %d\n", gridID);
27082 	      printf("grid.xsize  %d\n", grid->x.size);
27083 	      printf("grid.ysize  %d\n", grid->y.size);
27084 	      printf("grid.xfirst %f\n", grid->x.vals[0]);
27085 	      printf("grid.yfirst %f\n", grid->y.vals[0]);
27086 	      printf("grid xfirst %f\n", gridInqXval(gridID, 0));
27087 	      printf("grid yfirst %f\n", gridInqYval(gridID, 0));
27088 	      printf("grid.xlast  %f\n", grid->x.vals[grid->size-1]);
27089 	      printf("grid.ylast  %f\n", grid->y.vals[grid->size-1]);
27090 	      printf("grid xlast  %f\n", gridInqXval(gridID, grid->size-1));
27091 	      printf("grid ylast  %f\n", gridInqYval(gridID, grid->size-1));
27092 	      printf("grid.nv     %d\n", grid->nvertex);
27093 	      printf("grid nv     %d\n", gridInqNvertex(gridID));
27094 	      */
27095 	      if ( grid->x.size == gridRef->x.size && grid->y.size == gridRef->y.size )
27096                 differ = gridRef->vtable->compareXYAO((grid_t *)gridRef, (grid_t *)grid);
27097 	    }
27098 	  else if ( grid->type == GRID_UNSTRUCTURED )
27099 	    {
27100               unsigned char uuid1[CDI_UUID_SIZE]; memset(uuid1, 0, CDI_UUID_SIZE);
27101               unsigned char uuid2[CDI_UUID_SIZE]; memset(uuid2, 0, CDI_UUID_SIZE);
27102               int length = CDI_UUID_SIZE;
27103               cdiInqVarKeyBytes(&gridRef->keys, CDI_KEY_UUID, uuid1, &length);
27104               length = CDI_UUID_SIZE;
27105               cdiInqVarKeyBytes(&grid->keys, CDI_KEY_UUID, uuid2, &length);
27106               differ = ((uuid1[0] || uuid2[0]) && memcmp(uuid1, uuid2, CDI_UUID_SIZE));
27107               if (!differ)
27108                 {
27109                   int numberA = cdiInqVarKeyInt(&grid->keys, CDI_KEY_NUMBEROFGRIDUSED);
27110                   int numberB = cdiInqVarKeyInt(&gridRef->keys, CDI_KEY_NUMBEROFGRIDUSED);
27111                   int positionA = cdiInqVarKeyInt(&grid->keys, CDI_KEY_NUMBEROFGRIDINREFERENCE);
27112                   int positionB = cdiInqVarKeyInt(&gridRef->keys, CDI_KEY_NUMBEROFGRIDINREFERENCE);
27113                   if ( coord_compare )
27114                     {
27115                       differ = grid->nvertex != gridRef->nvertex
27116                         || (numberA > 0 && positionA != positionB)
27117                         || gridRef->vtable->compareXYAO((grid_t *)gridRef, (grid_t *)grid);
27118                     }
27119                   else
27120                     {
27121                       if ( ((grid->x.vals == NULL) ^ (gridRef->x.vals == NULL)) &&
27122                            ((grid->y.vals == NULL) ^ (gridRef->y.vals == NULL)) )
27123                         {
27124                           int nvertexA = grid->nvertex, nvertexB = gridRef->nvertex;
27125                           differ = ( nvertexA && nvertexB && (nvertexA != nvertexB) )
27126                             || (( numberA && numberB && (numberA != numberB) )
27127                                 || ( numberA && numberB && positionA != positionB ) );
27128                         }
27129                       else
27130                         {
27131                           differ = grid->nvertex != gridRef->nvertex
27132                             || numberA != numberB
27133                             || (numberA > 0 && positionA != positionB)
27134                             || gridRef->vtable->compareXYAO((grid_t *)gridRef, (grid_t *)grid);
27135                         }
27136                     }
27137                 }
27138             }
27139 	}
27140     }
27141 
27142   int scanningModeA = cdiInqVarKeyInt(&grid->keys, CDI_KEY_SCANNINGMODE);
27143   int scanningModeB = cdiInqVarKeyInt(&gridRef->keys, CDI_KEY_SCANNINGMODE);
27144   if ( scanningModeA != scanningModeB )
27145     {
27146       // often grid definition may differ in UV-relativeToGrid
27147       differ = 1;
27148 #ifdef HIRLAM_EXTENSIONS
27149       if ( cdiDebugExt>=200 )
27150         printf("gridCompare(gridID=%d): Differs: scanningModeA [%d] != scanningModeB(gridID) [%d]\n",
27151                gridID, scanningModeA, scanningModeB);
27152 #endif // HIRLAM_EXTENSIONS
27153     }
27154 
27155   return differ;
27156 }
27157 
27158 
cmp_key_int(const cdi_keys_t * keysp1,const cdi_keys_t * keysp2,int key)27159 int cmp_key_int(const cdi_keys_t *keysp1, const cdi_keys_t *keysp2, int key)
27160 {
27161   int v1 = cdiInqVarKeyInt(keysp1, key);
27162   int v2 = cdiInqVarKeyInt(keysp2, key);
27163   if (v1 != v2) return 1;
27164   return 0;
27165 }
27166 
27167 
gridCompareP(void * gridptr1,void * gridptr2)27168 int gridCompareP(void *gridptr1, void *gridptr2)
27169 {
27170   grid_t *g1 = ( grid_t * ) gridptr1;
27171   grid_t *g2 = ( grid_t * ) gridptr2;
27172   enum { equal = 0,
27173          differ = -1 };
27174   size_t i, size;
27175 
27176   xassert ( g1 );
27177   xassert ( g2 );
27178 
27179   if ( g1->type          != g2->type         ) return differ;
27180   if ( g1->datatype      != g2->datatype     ) return differ;
27181   if ( g1->isCyclic      != g2->isCyclic     ) return differ;
27182   if ( g1->x.flag        != g2->x.flag       ) return differ;
27183   if ( g1->y.flag        != g2->y.flag       ) return differ;
27184   if ( g1->gme.nd        != g2->gme.nd       ) return differ;
27185   if ( g1->gme.ni        != g2->gme.ni       ) return differ;
27186   if ( g1->gme.ni2       != g2->gme.ni2      ) return differ;
27187   if ( g1->gme.ni3       != g2->gme.ni3      ) return differ;
27188   if ( cmp_key_int(&g1->keys, &g2->keys, CDI_KEY_NUMBEROFGRIDUSED) ) return differ;
27189   if ( cmp_key_int(&g1->keys, &g2->keys, CDI_KEY_NUMBEROFGRIDINREFERENCE) ) return differ;
27190   if ( g1->trunc         != g2->trunc        ) return differ;
27191   if ( g1->nvertex       != g2->nvertex      ) return differ;
27192   if ( g1->reducedPointsSize       != g2->reducedPointsSize      ) return differ;
27193   if ( g1->size          != g2->size         ) return differ;
27194   if ( g1->x.size        != g2->x.size       ) return differ;
27195   if ( g1->y.size        != g2->y.size       ) return differ;
27196   if ( g1->lcomplex      != g2->lcomplex     ) return differ;
27197 
27198   if ( IS_NOT_EQUAL(g1->x.first       , g2->x.first)       ) return differ;
27199   if ( IS_NOT_EQUAL(g1->y.first	      , g2->y.first)       ) return differ;
27200   if ( IS_NOT_EQUAL(g1->x.last        , g2->x.last)        ) return differ;
27201   if ( IS_NOT_EQUAL(g1->y.last        , g2->y.last)        ) return differ;
27202   if ( IS_NOT_EQUAL(g1->x.inc	      , g2->x.inc)         ) return differ;
27203   if ( IS_NOT_EQUAL(g1->y.inc	      , g2->y.inc)         ) return differ;
27204   if ( cmp_key_int(&g1->keys, &g2->keys, CDI_KEY_SCANNINGMODE) ) return differ;
27205 
27206   const double *restrict g1_xvals = g1->vtable->inqXValsPtr(g1),
27207                *restrict g2_xvals = g2->vtable->inqXValsPtr(g2);
27208   if ( g1_xvals )
27209     {
27210       if ( g1->type == GRID_UNSTRUCTURED || g1->type == GRID_CURVILINEAR )
27211         size = g1->size;
27212       else
27213         size = g1->x.size;
27214       xassert ( size );
27215 
27216       if ( !g2_xvals ) return differ;
27217 
27218       for ( i = 0; i < size; i++ )
27219         if ( IS_NOT_EQUAL(g1_xvals[i], g2_xvals[i]) ) return differ;
27220     }
27221   else if ( g2_xvals )
27222     return differ;
27223 
27224   const double *restrict g1_yvals = g1->vtable->inqYValsPtr(g1),
27225                *restrict g2_yvals = g2->vtable->inqYValsPtr(g2);
27226   if ( g1_yvals )
27227     {
27228       if ( g1->type == GRID_UNSTRUCTURED || g1->type == GRID_CURVILINEAR )
27229 	size = g1->size;
27230       else
27231 	size = g1->y.size;
27232       xassert ( size );
27233 
27234       if ( !g2_yvals ) return differ;
27235 
27236       for ( i = 0; i < size; i++ )
27237         if ( IS_NOT_EQUAL(g1_yvals[i], g2_yvals[i]) ) return differ;
27238     }
27239   else if ( g2_yvals )
27240     return differ;
27241 
27242   const double *restrict g1_area = g1->vtable->inqAreaPtr(g1),
27243                *restrict g2_area = g2->vtable->inqAreaPtr(g2);
27244   if ( g1_area )
27245     {
27246       xassert ( g1->size );
27247 
27248       if ( !g2_area ) return differ;
27249 
27250       for ( i = 0; i < g1->size; i++ )
27251 	if ( IS_NOT_EQUAL(g1_area[i], g2_area[i]) ) return differ;
27252     }
27253   else if ( g2_area )
27254     return differ;
27255 
27256   {
27257     const double *restrict g1_xbounds, *restrict g2_xbounds;
27258     if ( (g1_xbounds = g1->vtable->inqXBoundsPtr(g1)) )
27259       {
27260         xassert ( g1->nvertex );
27261         if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
27262           size = g1->nvertex * g1->size;
27263         else
27264           size = g1->nvertex * g1->x.size;
27265         xassert ( size );
27266 
27267         if ( !(g2_xbounds = g2->vtable->inqXBoundsPtr(g2)) ) return differ;
27268 
27269         for ( i = 0; i < size; i++ )
27270           if ( IS_NOT_EQUAL(g1_xbounds[i], g2_xbounds[i]) ) return differ;
27271       }
27272     else if ( g2->vtable->inqXBoundsPtr(g2) )
27273       return differ;
27274   }
27275 
27276   {
27277     const double *restrict g1_ybounds, *restrict g2_ybounds;
27278     if ( (g1_ybounds = g1->vtable->inqYBoundsPtr(g1)) )
27279       {
27280         xassert ( g1->nvertex );
27281         if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
27282           size = g1->nvertex * g1->size;
27283         else
27284           size = g1->nvertex * g1->y.size;
27285         xassert ( size );
27286 
27287         if ( ! (g2_ybounds = g2->vtable->inqYBoundsPtr(g2)) ) return differ;
27288 
27289         for ( i = 0; i < size; i++ )
27290           if ( IS_NOT_EQUAL(g1->y.bounds[i], g2->y.bounds[i]) ) return differ;
27291       }
27292     else if ( g2->vtable->inqYBoundsPtr(g2) )
27293       return differ;
27294   }
27295 
27296   if (strcmp(cdiInqVarKeyString(&g1->x.keys, CDI_KEY_NAME), cdiInqVarKeyString(&g2->x.keys, CDI_KEY_NAME))) return differ;
27297   if (strcmp(cdiInqVarKeyString(&g1->y.keys, CDI_KEY_NAME), cdiInqVarKeyString(&g2->y.keys, CDI_KEY_NAME))) return differ;
27298   if (strcmp(cdiInqVarKeyString(&g1->x.keys, CDI_KEY_LONGNAME), cdiInqVarKeyString(&g2->x.keys, CDI_KEY_LONGNAME))) return differ;
27299   if (strcmp(cdiInqVarKeyString(&g1->y.keys, CDI_KEY_LONGNAME), cdiInqVarKeyString(&g2->y.keys, CDI_KEY_LONGNAME))) return differ;
27300   if (strcmp(cdiInqVarKeyString(&g1->x.keys, CDI_KEY_UNITS), cdiInqVarKeyString(&g2->x.keys, CDI_KEY_UNITS))) return differ;
27301   if (strcmp(cdiInqVarKeyString(&g1->y.keys, CDI_KEY_UNITS), cdiInqVarKeyString(&g2->y.keys, CDI_KEY_UNITS))) return differ;
27302   if (strcmp(cdiInqVarKeyString(&g1->x.keys, CDI_KEY_STDNAME), cdiInqVarKeyString(&g2->x.keys, CDI_KEY_STDNAME))) return differ;
27303   if (strcmp(cdiInqVarKeyString(&g1->y.keys, CDI_KEY_STDNAME), cdiInqVarKeyString(&g2->y.keys, CDI_KEY_STDNAME))) return differ;
27304 
27305   if (strcmp(cdiInqVarKeyString(&g1->y.keys, CDI_KEY_REFERENCEURI), cdiInqVarKeyString(&g2->y.keys, CDI_KEY_REFERENCEURI))) return differ;
27306 
27307   if ( g1->mask )
27308     {
27309       xassert ( g1->size );
27310       if ( !g2->mask ) return differ;
27311       if ( memcmp ( g1->mask, g2->mask, g1->size * sizeof(mask_t)) ) return differ;
27312     }
27313   else if ( g2->mask )
27314     return differ;
27315 
27316   if ( g1->mask_gme )
27317     {
27318       xassert ( g1->size );
27319       if ( !g2->mask_gme ) return differ;
27320       if ( memcmp ( g1->mask_gme, g2->mask_gme, g1->size * sizeof(mask_t)) ) return differ;
27321     }
27322   else if ( g2->mask_gme )
27323     return differ;
27324 
27325   unsigned char uuid1[CDI_UUID_SIZE]; memset(uuid1, 0, CDI_UUID_SIZE);
27326   unsigned char uuid2[CDI_UUID_SIZE]; memset(uuid2, 0, CDI_UUID_SIZE);
27327   int length = CDI_UUID_SIZE;
27328   cdiInqVarKeyBytes(&g1->keys, CDI_KEY_UUID, uuid1, &length);
27329   length = CDI_UUID_SIZE;
27330   cdiInqVarKeyBytes(&g2->keys, CDI_KEY_UUID, uuid2, &length);
27331   if ( memcmp(uuid1, uuid2, CDI_UUID_SIZE) ) return differ;
27332 
27333   return equal;
27334 }
27335 
27336 static
gridComplete(grid_t * grid)27337 void gridComplete(grid_t *grid)
27338 {
27339   const int gridID = grid->self;
27340   gridDefDatatype(gridID, grid->datatype);
27341 
27342   const int gridtype = grid->type;
27343   switch (gridtype)
27344     {
27345     case GRID_LONLAT:
27346     case GRID_GAUSSIAN:
27347     case GRID_UNSTRUCTURED:
27348     case GRID_CURVILINEAR:
27349     case GRID_GENERIC:
27350     case GRID_PROJECTION:
27351     case GRID_CHARXY:
27352       {
27353 	if ( grid->x.size > 0 ) gridDefXsize(gridID, grid->x.size);
27354 	if ( grid->y.size > 0 ) gridDefYsize(gridID, grid->y.size);
27355 
27356         if ( gridtype == GRID_GAUSSIAN ) gridDefNP(gridID, grid->np);
27357 
27358 	if ( grid->nvertex > 0 )
27359 	  gridDefNvertex(gridID, grid->nvertex);
27360 
27361 	if ( grid->x.flag == 2 )
27362 	  {
27363             assert(gridtype != GRID_UNSTRUCTURED && gridtype != GRID_CURVILINEAR);
27364 	    double *xvals = (double *) Malloc(grid->x.size * sizeof (double));
27365 	    gridGenXvals(grid->x.size, grid->x.first, grid->x.last, grid->x.inc, xvals);
27366 	    grid->x.vals = xvals;
27367 	    // gridDefXinc(gridID, grid->x.inc);
27368 	  }
27369 
27370 	if ( grid->y.flag == 2 )
27371 	  {
27372             assert(gridtype != GRID_UNSTRUCTURED && gridtype != GRID_CURVILINEAR);
27373 	    double *yvals = (double *) Malloc(grid->y.size * sizeof (double));
27374 	    gridGenYvals(gridtype, grid->y.size, grid->y.first, grid->y.last, grid->y.inc, yvals);
27375 	    grid->y.vals = yvals;
27376 	    // gridDefYinc(gridID, grid->y.inc);
27377 	  }
27378 
27379 	if ( grid->projtype == CDI_PROJ_RLL )
27380 	  {
27381             const char *name = cdiInqVarKeyString(&grid->x.keys, CDI_KEY_NAME);
27382 	    if ( name[0] == 0 || name[0] == 'x' ) cdiDefKeyString(gridID, CDI_XAXIS, CDI_KEY_NAME, "rlon");
27383             name = cdiInqVarKeyString(&grid->y.keys, CDI_KEY_NAME);
27384 	    if ( name[0] == 0 || name[0] == 'y' ) cdiDefKeyString(gridID, CDI_YAXIS, CDI_KEY_NAME, "rlat");
27385             name = cdiInqVarKeyString(&grid->x.keys, CDI_KEY_LONGNAME);
27386 	    if ( name[0] == 0 ) cdiDefKeyString(gridID, CDI_XAXIS, CDI_KEY_LONGNAME, "longitude in rotated pole grid");
27387             name = cdiInqVarKeyString(&grid->y.keys, CDI_KEY_LONGNAME);
27388 	    if ( name[0] == 0 ) cdiDefKeyString(gridID, CDI_YAXIS, CDI_KEY_LONGNAME, "latitude in rotated pole grid");
27389             name = cdiInqVarKeyString(&grid->x.keys, CDI_KEY_UNITS);
27390 	    if ( name[0] == 0 ) cdiDefKeyString(gridID, CDI_XAXIS, CDI_KEY_UNITS, "degrees");
27391             name = cdiInqVarKeyString(&grid->y.keys, CDI_KEY_UNITS);
27392 	    if ( name[0] == 0 ) cdiDefKeyString(gridID, CDI_YAXIS, CDI_KEY_UNITS, "degrees");
27393             cdiDefKeyString(gridID, CDI_XAXIS, CDI_KEY_STDNAME, xystdname_tab[grid_xystdname_grid_latlon][0]);
27394             cdiDefKeyString(gridID, CDI_YAXIS, CDI_KEY_STDNAME, xystdname_tab[grid_xystdname_grid_latlon][1]);
27395 	  }
27396 
27397         if ( gridtype == GRID_UNSTRUCTURED )
27398           {
27399             int number = cdiInqVarKeyInt(&grid->keys, CDI_KEY_NUMBEROFGRIDUSED);
27400             if ( number > 0 )
27401               {
27402                 cdiDefKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDUSED, number);
27403                 int position = cdiInqVarKeyInt(&grid->keys, CDI_KEY_NUMBEROFGRIDINREFERENCE);
27404                 if ( position > 0 ) cdiDefKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDINREFERENCE, position);
27405               }
27406           }
27407 
27408 	break;
27409       }
27410     case GRID_GAUSSIAN_REDUCED:
27411       {
27412 	gridDefNP(gridID, grid->np);
27413 	gridDefYsize(gridID, grid->y.size);
27414         if ( grid->x.flag == 2 )
27415           {
27416             double xvals[2] = { grid->x.first, grid->x.last };
27417             gridDefXsize(gridID, 2);
27418             gridDefXvals(gridID, xvals);
27419           }
27420 
27421         if ( grid->y.flag == 2 )
27422 	  {
27423 	    double *yvals = (double *) Malloc(grid->y.size * sizeof (double));
27424 	    gridGenYvals(gridtype, grid->y.size, grid->y.first, grid->y.last, grid->y.inc, yvals);
27425             grid->y.vals = yvals;
27426 	    /*
27427 	    gridDefYinc(gridID, grid->y.inc);
27428 	    */
27429 	  }
27430 	break;
27431       }
27432     case GRID_SPECTRAL:
27433       {
27434         gridDefTrunc(gridID, grid->trunc);
27435         if ( grid->lcomplex ) gridDefComplexPacking(gridID, 1);
27436         break;
27437       }
27438     case GRID_FOURIER:
27439       {
27440 	gridDefTrunc(gridID, grid->trunc);
27441 	break;
27442       }
27443     case GRID_GME:
27444       {
27445         gridDefParamGME(gridID, grid->gme.nd, grid->gme.ni, grid->gme.ni2, grid->gme.ni3);
27446         break;
27447       }
27448       /*
27449     case GRID_GENERIC:
27450       {
27451         if ( grid->x.size > 0 && grid->y.size > 0 )
27452           {
27453             gridDefXsize(gridID, grid->x.size);
27454             gridDefYsize(gridID, grid->y.size);
27455             if ( grid->x.vals ) gridDefXvals(gridID, grid->x.vals);
27456             if ( grid->y.vals ) gridDefYvals(gridID, grid->y.vals);
27457           }
27458         break;
27459       }
27460       */
27461     case GRID_TRAJECTORY:
27462       {
27463         gridDefXsize(gridID, 1);
27464         gridDefYsize(gridID, 1);
27465         break;
27466       }
27467     default:
27468       {
27469 	Error("Gridtype %s unsupported!", gridNamePtr(gridtype));
27470 	break;
27471       }
27472     }
27473 }
27474 
27475 // Used only in iterator_grib.c
gridGenerate(const grid_t * grid)27476 int gridGenerate(const grid_t *grid)
27477 {
27478   int gridtype = grid->type;
27479   int gridID = gridCreate(gridtype, grid->size);
27480   grid_t *restrict gridptr = grid_to_pointer(gridID);
27481   gridptr->datatype = grid->datatype;
27482   gridptr->x.size = grid->x.size;
27483   gridptr->y.size = grid->y.size;
27484   gridptr->np = grid->np;
27485   gridptr->nvertex = grid->nvertex;
27486   gridptr->x.flag = grid->x.flag;
27487   int valdef_group1 = 0;
27488   static const int valdef_group1_tab[] = {
27489     GRID_LONLAT, GRID_GAUSSIAN, GRID_UNSTRUCTURED, GRID_CURVILINEAR,
27490     GRID_GENERIC, GRID_PROJECTION
27491   };
27492   for ( size_t i = 0; i < sizeof (valdef_group1_tab) / sizeof (valdef_group1_tab[0]); ++i)
27493     valdef_group1 |= (gridtype == valdef_group1_tab[i]);
27494   if ( valdef_group1 && grid->x.flag == 1 )
27495     {
27496       gridDefXvals(gridID, grid->x.vals);
27497       if ( grid->x.bounds )
27498         gridDefXbounds(gridID, grid->x.bounds);
27499     }
27500   gridptr->x.first = grid->x.first;
27501   gridptr->x.last = grid->x.last;
27502   gridptr->x.inc = grid->x.inc;
27503   gridptr->y.flag = grid->y.flag;
27504   if ( (valdef_group1 || gridtype == GRID_GAUSSIAN_REDUCED) && grid->y.flag == 1)
27505     {
27506       gridDefYvals(gridID, grid->y.vals);
27507       if ( grid->y.bounds )
27508         gridDefYbounds(gridID, grid->y.bounds);
27509     }
27510   gridptr->y.first = grid->y.first;
27511   gridptr->y.last = grid->y.last;
27512   gridptr->y.inc = grid->y.inc;
27513   if ( valdef_group1 && grid->area)
27514     gridDefArea(gridID, grid->area);
27515 
27516   cdiCopyVarKey(&grid->keys, CDI_KEY_NUMBEROFGRIDUSED, &gridptr->keys);
27517   cdiCopyVarKey(&grid->keys, CDI_KEY_NUMBEROFGRIDINREFERENCE, &gridptr->keys);
27518   cdiCopyVarKey(&grid->keys, CDI_KEY_REFERENCEURI, &gridptr->keys);
27519 
27520   cdiCopyVarKey(&grid->keys, CDI_KEY_SCANNINGMODE, &gridptr->keys);
27521 
27522   if ( gridtype == GRID_PROJECTION )
27523     gridptr->name = strdup(grid->name);
27524   if ( gridtype == GRID_GAUSSIAN_REDUCED )
27525     gridDefReducedPoints(gridID, grid->y.size, grid->reducedPoints);
27526   gridptr->trunc = grid->trunc;
27527   gridptr->lcomplex = grid->lcomplex;
27528   gridptr->gme.nd = grid->gme.nd;
27529   gridptr->gme.ni = grid->gme.ni;
27530   gridptr->gme.ni2 = grid->gme.ni2;
27531   gridptr->gme.ni3 = grid->gme.ni3;
27532 
27533   gridComplete(gridptr);
27534 
27535   return gridID;
27536 }
27537 
27538 static void
grid_copy_base_array_fields(grid_t * gridptrOrig,grid_t * gridptrDup)27539 grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
27540 {
27541   size_t reducedPointsSize = (size_t)gridptrOrig->reducedPointsSize;
27542   size_t gridsize = gridptrOrig->size;
27543   int gridtype = gridptrOrig->type;
27544   int irregular = gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED;
27545   if ( reducedPointsSize )
27546     {
27547       gridptrDup->reducedPoints = (int*) Malloc(reducedPointsSize * sizeof(int));
27548       memcpy(gridptrDup->reducedPoints, gridptrOrig->reducedPoints, reducedPointsSize * sizeof(int));
27549     }
27550 
27551   if ( gridptrOrig->x.vals != NULL )
27552     {
27553       size_t size = irregular ? gridsize : gridptrOrig->x.size;
27554       gridptrDup->x.vals = (double *)Malloc(size * sizeof (double));
27555       memcpy(gridptrDup->x.vals, gridptrOrig->x.vals, size * sizeof (double));
27556     }
27557 
27558   if ( gridptrOrig->y.vals != NULL )
27559     {
27560       size_t size  = irregular ? gridsize : gridptrOrig->y.size;
27561       gridptrDup->y.vals = (double *)Malloc(size * sizeof (double));
27562       memcpy(gridptrDup->y.vals, gridptrOrig->y.vals, size * sizeof (double));
27563     }
27564 
27565   if ( gridptrOrig->x.bounds != NULL )
27566     {
27567       size_t size  = (irregular ? gridsize : gridptrOrig->x.size)
27568         * gridptrOrig->nvertex;
27569 
27570       gridptrDup->x.bounds = (double *)Malloc(size * sizeof (double));
27571       memcpy(gridptrDup->x.bounds, gridptrOrig->x.bounds, size * sizeof (double));
27572     }
27573 
27574   if ( gridptrOrig->y.bounds != NULL )
27575     {
27576       size_t size = (irregular ? gridsize : gridptrOrig->y.size)
27577         * gridptrOrig->nvertex;
27578 
27579       gridptrDup->y.bounds = (double *)Malloc(size * sizeof (double));
27580       memcpy(gridptrDup->y.bounds, gridptrOrig->y.bounds, size * sizeof (double));
27581     }
27582 
27583   {
27584     const double *gridptrOrig_area
27585       = gridptrOrig->vtable->inqAreaPtr(gridptrOrig);
27586     if ( gridptrOrig_area != NULL )
27587       {
27588         size_t size = gridsize;
27589         gridptrDup->area = (double *)Malloc(size * sizeof (double));
27590         memcpy(gridptrDup->area, gridptrOrig_area, size * sizeof (double));
27591       }
27592   }
27593 
27594   if ( gridptrOrig->mask != NULL )
27595     {
27596       size_t size = gridsize;
27597       gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
27598       memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
27599     }
27600 
27601   if ( gridptrOrig->mask_gme != NULL )
27602     {
27603       size_t size = gridsize;
27604       gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
27605       memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
27606     }
27607 }
27608 
27609 
27610 /*
27611 @Function  gridDuplicate
27612 @Title     Duplicate a horizontal Grid
27613 
27614 @Prototype int gridDuplicate(int gridID)
27615 @Parameter
27616     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
27617 
27618 @Description
27619 The function @func{gridDuplicate} duplicates a horizontal Grid.
27620 
27621 @Result
27622 @func{gridDuplicate} returns an identifier to the duplicated Grid.
27623 
27624 @EndFunction
27625 */
gridDuplicate(int gridID)27626 int gridDuplicate(int gridID)
27627 {
27628   grid_t *gridptr = grid_to_pointer(gridID);
27629   grid_t *gridptrnew = gridptr->vtable->copy(gridptr);
27630   int gridIDnew = reshPut(gridptrnew, &gridOps);
27631   gridptrnew->self = gridIDnew;
27632   return gridIDnew;
27633 }
27634 
27635 
gridCompress(int gridID)27636 void gridCompress(int gridID)
27637 {
27638   grid_t *gridptr = grid_to_pointer(gridID);
27639 
27640   int gridtype = gridInqType(gridID);
27641   if ( gridtype == GRID_UNSTRUCTURED )
27642     {
27643       if ( gridptr->mask_gme != NULL )
27644 	{
27645           size_t gridsize = gridInqSize(gridID);
27646 	  size_t nv = (size_t)gridptr->nvertex;
27647           double *restrict area
27648             = (double *)gridptr->vtable->inqAreaPtr(gridptr),
27649             *restrict xvals = (double *)gridptr->vtable->inqXValsPtr(gridptr),
27650             *restrict yvals = (double *)gridptr->vtable->inqYValsPtr(gridptr),
27651             *restrict xbounds = (double *)gridptr->vtable->inqXBoundsPtr(gridptr),
27652             *restrict ybounds = (double *)gridptr->vtable->inqYBoundsPtr(gridptr);
27653           mask_t *restrict mask_gme = gridptr->mask_gme;
27654           size_t *restrict selection = (size_t *)Malloc(gridsize * sizeof (selection[0]));
27655           size_t nselect;
27656           {
27657             size_t j = 0;
27658             for (size_t i = 0; i < gridsize; i++ )
27659               selection[j] = i, j += (mask_gme[i] != 0);
27660             nselect = j;
27661           }
27662           selection = (size_t *)Realloc(selection, nselect * sizeof (selection[0]));
27663           if (xvals)
27664             for (size_t i = 0; i < nselect; i++ )
27665 	      xvals[i] = xvals[selection[i]];
27666           if (yvals)
27667             for (size_t i = 0; i < nselect; i++ )
27668               yvals[i] = yvals[selection[i]];
27669           if (area)
27670             for (size_t i = 0; i < nselect; i++ )
27671               area[i] = area[selection[i]];
27672           if (xbounds)
27673             for (size_t i = 0; i < nselect; i++ )
27674               for (size_t iv = 0; iv < nv; iv++)
27675                 xbounds[i * nv + iv] = xbounds[selection[i] * nv + iv];
27676           if (ybounds)
27677             for (size_t i = 0; i < nselect; i++ )
27678               for (size_t iv = 0; iv < nv; iv++)
27679                 ybounds[i * nv + iv] = ybounds[selection[i] * nv + iv];
27680           Free(selection);
27681 
27682 	  /* fprintf(stderr, "grid compress %d %d %d\n", i, j, gridsize); */
27683 	  gridsize = nselect;
27684 	  gridptr->size  = (int)gridsize;
27685 	  gridptr->x.size = (int)gridsize;
27686 	  gridptr->y.size = (int)gridsize;
27687 
27688           double **resizeP[] = { &gridptr->x.vals, &gridptr->y.vals,
27689                                  &gridptr->area,
27690                                  &gridptr->x.bounds, &gridptr->y.bounds };
27691           size_t newSize[] = { gridsize, gridsize, gridsize, nv*gridsize,
27692                                nv*gridsize };
27693           for ( size_t i = 0; i < sizeof (resizeP) / sizeof (resizeP[0]); ++i)
27694             if ( *(resizeP[i]) )
27695               *(resizeP[i]) = (double *)Realloc(*(resizeP[i]), newSize[i]*sizeof(double));
27696 
27697 	  Free(gridptr->mask_gme);
27698 	  gridptr->mask_gme = NULL;
27699           gridMark4Update(gridID);
27700 	}
27701     }
27702   else
27703     Warning("Unsupported grid type: %s", gridNamePtr(gridtype));
27704 }
27705 
27706 static void
gridDefAreaSerial(grid_t * gridptr,const double * area)27707 gridDefAreaSerial(grid_t *gridptr, const double *area)
27708 {
27709   size_t size = gridptr->size;
27710 
27711   if ( size == 0 )
27712     Error("size undefined for gridID = %d", gridptr->self);
27713 
27714   if ( gridptr->area == NULL )
27715     gridptr->area = (double *) Malloc(size*sizeof(double));
27716   else if ( CDI_Debug )
27717     Warning("values already defined!");
27718 
27719   memcpy(gridptr->area, area, size * sizeof(double));
27720 }
27721 
27722 
gridDefArea(int gridID,const double * area)27723 void gridDefArea(int gridID, const double *area)
27724 {
27725   grid_t *gridptr = grid_to_pointer(gridID);
27726   gridptr->vtable->defArea(gridptr, area);
27727   gridMark4Update(gridID);
27728 }
27729 
27730 static void
gridInqAreaSerial(grid_t * gridptr,double * area)27731 gridInqAreaSerial(grid_t *gridptr, double *area)
27732 {
27733   if (gridptr->area)
27734     memcpy(area, gridptr->area, gridptr->size * sizeof (double));
27735 }
27736 
27737 
gridInqArea(int gridID,double * area)27738 void gridInqArea(int gridID, double *area)
27739 {
27740   grid_t *gridptr = grid_to_pointer(gridID);
27741   gridptr->vtable->inqArea(gridptr, area);
27742 }
27743 
27744 static int
gridHasAreaBase(grid_t * gridptr)27745 gridHasAreaBase(grid_t *gridptr)
27746 {
27747   return gridptr->area != NULL;
27748 }
27749 
gridHasArea(int gridID)27750 int gridHasArea(int gridID)
27751 {
27752   grid_t *gridptr = grid_to_pointer(gridID);
27753   return gridptr->vtable->hasArea(gridptr);
27754 }
27755 
27756 
gridInqAreaPtrBase(grid_t * gridptr)27757 static const double *gridInqAreaPtrBase(grid_t *gridptr)
27758 {
27759   return gridptr->area;
27760 }
27761 
gridInqAreaPtr(int gridID)27762 const double *gridInqAreaPtr(int gridID)
27763 {
27764   grid_t *gridptr = grid_to_pointer(gridID);
27765   return gridptr->vtable->inqAreaPtr(gridptr);
27766 }
27767 
27768 
gridDefNvertex(int gridID,int nvertex)27769 void gridDefNvertex(int gridID, int nvertex)
27770 {
27771   grid_t *gridptr = grid_to_pointer(gridID);
27772 
27773   if (gridptr->nvertex != nvertex)
27774     {
27775       gridptr->nvertex = nvertex;
27776       gridMark4Update(gridID);
27777     }
27778 }
27779 
27780 
gridInqNvertex(int gridID)27781 int gridInqNvertex(int gridID)
27782 {
27783   grid_t *gridptr = grid_to_pointer(gridID);
27784   return gridptr->nvertex;
27785 }
27786 
27787 static void
gridDefBoundsGeneric(grid_t * gridptr,const double * bounds,size_t regularSize,double ** field)27788 gridDefBoundsGeneric(grid_t *gridptr, const double *bounds, size_t regularSize,
27789                      double **field)
27790 {
27791   const int irregular = gridptr->type == GRID_CURVILINEAR || gridptr->type == GRID_UNSTRUCTURED;
27792   const size_t nvertex = (size_t)gridptr->nvertex;
27793   if ( nvertex == 0 )
27794     {
27795       Warning("nvertex undefined for gridID = %d. Cannot define bounds!", gridptr->self);
27796       return;
27797     }
27798 
27799   const size_t size = nvertex * (irregular ? gridptr->size : regularSize);
27800   if ( size == 0 )
27801     Error("size undefined for gridID = %d", gridptr->self);
27802 
27803   if (*field == NULL && size)
27804     *field = (double *)Malloc(size * sizeof (double));
27805   else if ( CDI_Debug )
27806     Warning("values already defined!");
27807 
27808   memcpy(*field, bounds, size * sizeof (double));
27809 }
27810 
27811 
27812 static void
gridDefXBoundsSerial(grid_t * gridptr,const double * xbounds)27813 gridDefXBoundsSerial(grid_t *gridptr, const double *xbounds)
27814 {
27815   gridDefBoundsGeneric(gridptr, xbounds, gridptr->x.size, &gridptr->x.bounds);
27816 }
27817 
27818 /*
27819 @Function  gridDefXbounds
27820 @Title     Define the bounds of a X-axis
27821 
27822 @Prototype void gridDefXbounds(int gridID, const double *xbounds)
27823 @Parameter
27824     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
27825     @Item  xbounds  X-bounds of the grid.
27826 
27827 @Description
27828 The function @func{gridDefXbounds} defines all bounds of the X-axis.
27829 
27830 @EndFunction
27831 */
gridDefXbounds(int gridID,const double * xbounds)27832 void gridDefXbounds(int gridID, const double *xbounds)
27833 {
27834   grid_t *gridptr = grid_to_pointer(gridID);
27835   gridptr->vtable->defXBounds(gridptr, xbounds);
27836   gridMark4Update(gridID);
27837 }
27838 
27839 static size_t
gridInqXBoundsSerial(grid_t * gridptr,double * xbounds)27840 gridInqXBoundsSerial(grid_t *gridptr, double *xbounds)
27841 {
27842   size_t nvertex = (size_t)gridptr->nvertex;
27843 
27844   int irregular = gridptr->type == GRID_CURVILINEAR
27845     || gridptr->type == GRID_UNSTRUCTURED;
27846   size_t size = nvertex * (irregular ? gridptr->size : gridptr->x.size);
27847 
27848   const double *gridptr_xbounds = gridptr->vtable->inqXBoundsPtr(gridptr);
27849   if ( gridptr_xbounds )
27850     {
27851       if ( size && xbounds )
27852         memcpy(xbounds, gridptr_xbounds, size * sizeof (double));
27853     }
27854   else
27855     size = 0;
27856 
27857   return size;
27858 }
27859 
27860 /*
27861 @Function  gridInqXbounds
27862 @Title     Get the bounds of a X-axis
27863 
27864 @Prototype size_t gridInqXbounds(int gridID, double *xbounds)
27865 @Parameter
27866     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
27867     @Item  xbounds  Pointer to the location into which the X-bounds are read.
27868                     The caller must allocate space for the returned values.
27869 
27870 @Description
27871 The function @func{gridInqXbounds} returns the bounds of the X-axis.
27872 
27873 @Result
27874 Upon successful completion @func{gridInqXbounds} returns the number of bounds and
27875 the bounds are stored in @func{xbounds}.
27876 Otherwise, 0 is returned and @func{xbounds} is empty.
27877 
27878 @EndFunction
27879 */
gridInqXbounds(int gridID,double * xbounds)27880 size_t gridInqXbounds(int gridID, double *xbounds)
27881 {
27882   grid_t *gridptr = grid_to_pointer(gridID);
27883   return gridptr->vtable->inqXBounds(gridptr, xbounds);
27884 }
27885 
27886 static const double *
gridInqXBoundsPtrSerial(grid_t * gridptr)27887 gridInqXBoundsPtrSerial(grid_t *gridptr)
27888 {
27889   return gridptr->x.bounds;
27890 }
27891 
27892 
gridInqXboundsPtr(int gridID)27893 const double *gridInqXboundsPtr(int gridID)
27894 {
27895   grid_t *gridptr = grid_to_pointer(gridID);
27896   return gridptr->vtable->inqXBoundsPtr(gridptr);
27897 }
27898 
27899 static void
gridDefYBoundsSerial(grid_t * gridptr,const double * ybounds)27900 gridDefYBoundsSerial(grid_t *gridptr, const double *ybounds)
27901 {
27902   gridDefBoundsGeneric(gridptr, ybounds, gridptr->y.size, &gridptr->y.bounds);
27903 }
27904 
27905 //----------------------------------------------------------------------------
27906 // Parallel Version
27907 //----------------------------------------------------------------------------
27908 
gridInqXboundsPart(int gridID,int start,size_t size,double * xbounds)27909 size_t gridInqXboundsPart(int gridID, int start, size_t size, double *xbounds)
27910 {
27911   grid_t *gridptr = grid_to_pointer(gridID);
27912   const double *gridptr_xbounds = gridptr->vtable->inqXBoundsPtr(gridptr);
27913   if ( gridptr_xbounds )
27914     if ( size && xbounds )
27915       memcpy(xbounds, gridptr_xbounds+start, size * sizeof (double));
27916 
27917   return size;
27918 }
27919 
gridInqYboundsPart(int gridID,int start,size_t size,double * ybounds)27920 size_t gridInqYboundsPart(int gridID, int start, size_t size, double *ybounds)
27921 {
27922   grid_t *gridptr = grid_to_pointer(gridID);
27923   const double *gridptr_ybounds = gridptr->vtable->inqYBoundsPtr(gridptr);
27924   if ( gridptr_ybounds )
27925     if ( size && ybounds )
27926       memcpy(ybounds, gridptr_ybounds+start, size * sizeof (double));
27927 
27928   return size;
27929 }
27930 
27931 /*
27932 @Function  gridDefYbounds
27933 @Title     Define the bounds of a Y-axis
27934 
27935 @Prototype void gridDefYbounds(int gridID, const double *ybounds)
27936 @Parameter
27937     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
27938     @Item  ybounds  Y-bounds of the grid.
27939 
27940 @Description
27941 The function @func{gridDefYbounds} defines all bounds of the Y-axis.
27942 
27943 @EndFunction
27944 */
gridDefYbounds(int gridID,const double * ybounds)27945 void gridDefYbounds(int gridID, const double *ybounds)
27946 {
27947   grid_t *gridptr = grid_to_pointer(gridID);
27948   gridptr->vtable->defYBounds(gridptr, ybounds);
27949   gridMark4Update(gridID);
27950 }
27951 
27952 static size_t
gridInqYBoundsSerial(grid_t * gridptr,double * ybounds)27953 gridInqYBoundsSerial(grid_t *gridptr, double *ybounds)
27954 {
27955   size_t nvertex = (size_t)gridptr->nvertex;
27956 
27957   int irregular = gridptr->type == GRID_CURVILINEAR
27958     || gridptr->type == GRID_UNSTRUCTURED;
27959   size_t size = nvertex * (irregular ? gridptr->size : gridptr->y.size);
27960 
27961   const double *gridptr_ybounds = gridptr->vtable->inqYBoundsPtr(gridptr);
27962   if ( gridptr_ybounds )
27963     {
27964       if ( size && ybounds )
27965         memcpy(ybounds, gridptr_ybounds, size * sizeof (double));
27966     }
27967   else
27968     size = 0;
27969 
27970   return size;
27971 }
27972 
27973 
27974 /*
27975 @Function  gridInqYbounds
27976 @Title     Get the bounds of a Y-axis
27977 
27978 @Prototype size_t gridInqYbounds(int gridID, double *ybounds)
27979 @Parameter
27980     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
27981     @Item  ybounds  Pointer to the location into which the Y-bounds are read.
27982                     The caller must allocate space for the returned values.
27983 
27984 @Description
27985 The function @func{gridInqYbounds} returns the bounds of the Y-axis.
27986 
27987 @Result
27988 Upon successful completion @func{gridInqYbounds} returns the number of bounds and
27989 the bounds are stored in @func{ybounds}.
27990 Otherwise, 0 is returned and @func{ybounds} is empty.
27991 
27992 @EndFunction
27993 */
gridInqYbounds(int gridID,double * ybounds)27994 size_t gridInqYbounds(int gridID, double *ybounds)
27995 {
27996   grid_t *gridptr = grid_to_pointer(gridID);
27997   return gridptr->vtable->inqYBounds(gridptr, ybounds);
27998 }
27999 
28000 static const double *
gridInqYBoundsPtrSerial(grid_t * gridptr)28001 gridInqYBoundsPtrSerial(grid_t *gridptr)
28002 {
28003   return gridptr->y.bounds;
28004 }
28005 
28006 
gridInqYboundsPtr(int gridID)28007 const double *gridInqYboundsPtr(int gridID)
28008 {
28009   grid_t *gridptr = grid_to_pointer(gridID);
28010   return gridptr->vtable->inqYBoundsPtr(gridptr);
28011 }
28012 
28013 static void
printDblsPrefixAutoBrk(FILE * fp,int dig,const char prefix[],size_t nbyte0,size_t n,const double vals[])28014 printDblsPrefixAutoBrk(FILE *fp, int dig, const char prefix[], size_t nbyte0,
28015                        size_t n, const double vals[])
28016 {
28017   fputs(prefix, fp);
28018   size_t nbyte = nbyte0;
28019   for ( size_t i = 0; i < n; i++ )
28020     {
28021       if ( nbyte > 80 )
28022         {
28023           fprintf(fp, "\n%*s", (int)nbyte0, "");
28024           nbyte = nbyte0;
28025         }
28026       nbyte += (size_t)fprintf(fp, "%.*g ", dig, vals[i]);
28027     }
28028   fputs("\n", fp);
28029 }
28030 
28031 static inline
resizeBuffer(void ** buf,size_t * bufSize,size_t reqSize)28032 void *resizeBuffer(void **buf, size_t *bufSize, size_t reqSize)
28033 {
28034   if (reqSize > *bufSize)
28035     {
28036       *buf = Realloc(*buf, reqSize);
28037       *bufSize = reqSize;
28038     }
28039   return *buf;
28040 }
28041 
28042 static
gridPrintAttributes(FILE * fp,int gridID)28043 void gridPrintAttributes(FILE *fp, int gridID)
28044 {
28045   int cdiID = gridID;
28046   int varID = CDI_GLOBAL;
28047   int atttype, attlen;
28048   char attname[CDI_MAX_NAME+1];
28049   void *attBuf = NULL;
28050   size_t attBufSize = 0;
28051 
28052   int natts;
28053   cdiInqNatts(cdiID, varID, &natts);
28054 
28055   for ( int iatt = 0; iatt < natts; ++iatt )
28056     {
28057       cdiInqAtt(cdiID, varID, iatt, attname, &atttype, &attlen);
28058 
28059       if ( attlen == 0 ) continue;
28060 
28061       if ( atttype == CDI_DATATYPE_TXT )
28062         {
28063           size_t attSize = (size_t)(attlen+1)*sizeof(char);
28064           char *atttxt = (char *)resizeBuffer(&attBuf, &attBufSize, attSize);
28065           cdiInqAttTxt(cdiID, varID, attname, attlen, atttxt);
28066           atttxt[attlen] = 0;
28067           fprintf(fp, "ATTR_TXT: %s = \"%s\"\n", attname, atttxt);
28068         }
28069       else if ( atttype == CDI_DATATYPE_INT8  || atttype == CDI_DATATYPE_UINT8  ||
28070                 atttype == CDI_DATATYPE_INT16 || atttype == CDI_DATATYPE_UINT16 ||
28071                 atttype == CDI_DATATYPE_INT32 || atttype == CDI_DATATYPE_UINT32 )
28072         {
28073           size_t attSize = (size_t)attlen*sizeof(int);
28074           int *attint = (int *)resizeBuffer(&attBuf, &attBufSize, attSize);
28075           cdiInqAttInt(cdiID, varID, attname, attlen, &attint[0]);
28076           if ( attlen == 1 )
28077             fprintf(fp, "ATTR_INT: %s =", attname);
28078           else
28079             fprintf(fp, "ATTR_INT_%d: %s =", attlen, attname);
28080           for ( int i = 0; i < attlen; ++i ) fprintf(fp, " %d", attint[i]);
28081           fprintf(fp, "\n");
28082         }
28083       else if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
28084         {
28085           size_t attSize = (size_t)attlen * sizeof(double);
28086           double *attflt = (double *)resizeBuffer(&attBuf, &attBufSize, attSize);
28087           int dig = (atttype == CDI_DATATYPE_FLT64) ? 15 : 7;
28088           cdiInqAttFlt(cdiID, varID, attname, attlen, attflt);
28089           if ( attlen == 1 )
28090             fprintf(fp, "ATTR_FLT: %s =", attname);
28091           else
28092             fprintf(fp, "ATTR_FLT_%d: %s =", attlen, attname);
28093           for ( int i = 0; i < attlen; ++i ) fprintf(fp, " %.*g", dig, attflt[i]);
28094           fprintf(fp, "\n");
28095         }
28096     }
28097 
28098   Free(attBuf);
28099 }
28100 
28101 static
gridPrintKernel(int gridID,int opt,FILE * fp)28102 void gridPrintKernel(int gridID, int opt, FILE *fp)
28103 {
28104   char attstr[CDI_MAX_NAME];
28105   char attstr2[CDI_MAX_NAME];
28106   size_t nxvals = gridInqXvals(gridID, NULL);
28107   size_t nyvals = gridInqYvals(gridID, NULL);
28108 
28109   int type     = gridInqType(gridID);
28110   size_t gridsize = gridInqSize(gridID);
28111   size_t xsize    = gridInqXsize(gridID);
28112   size_t ysize    = gridInqYsize(gridID);
28113   int nvertex  = gridInqNvertex(gridID);
28114   int datatype = gridInqDatatype(gridID);
28115 
28116   int dig = (datatype == CDI_DATATYPE_FLT64) ? 15 : 7;
28117 
28118   fprintf(fp, "gridtype  = %s\n" "gridsize  = %zu\n", gridNamePtr(type), gridsize);
28119 
28120   if ( type != GRID_GME )
28121     {
28122       if ( type != GRID_UNSTRUCTURED && type != GRID_SPECTRAL && type != GRID_FOURIER )
28123         {
28124           if ( xsize > 0 ) fprintf(fp, "xsize     = %zu\n", xsize);
28125           if ( ysize > 0 ) fprintf(fp, "ysize     = %zu\n", ysize);
28126         }
28127 
28128       if ( nxvals > 0 )
28129         {
28130           int length = CDI_MAX_NAME;
28131           cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_NAME, attstr, &length);
28132           if ( attstr[0] )  fprintf(fp, "xname     = %s\n", attstr);
28133           length = CDI_MAX_NAME;
28134           cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_DIMNAME, attstr2, &length);
28135           if ( attstr2[0] && strcmp(attstr, attstr2) )  fprintf(fp, "xdimname  = %s\n", attstr2);
28136           length = CDI_MAX_NAME;
28137           cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_LONGNAME, attstr, &length);
28138           if ( attstr[0] )  fprintf(fp, "xlongname = %s\n", attstr);
28139           length = CDI_MAX_NAME;
28140           cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_UNITS, attstr, &length);
28141           if ( attstr[0] )  fprintf(fp, "xunits    = %s\n", attstr);
28142         }
28143 
28144       if ( nyvals > 0 )
28145         {
28146           int length = CDI_MAX_NAME;
28147           cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_NAME, attstr, &length);
28148           if ( attstr[0] )  fprintf(fp, "yname     = %s\n", attstr);
28149           length = CDI_MAX_NAME;
28150           cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_DIMNAME, attstr2, &length);
28151           if ( attstr2[0] && strcmp(attstr, attstr2) )  fprintf(fp, "ydimname  = %s\n", attstr2);
28152           length = CDI_MAX_NAME;
28153           cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_LONGNAME, attstr, &length);
28154           if ( attstr[0] )  fprintf(fp, "ylongname = %s\n", attstr);
28155           length = CDI_MAX_NAME;
28156           cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_UNITS, attstr, &length);
28157           if ( attstr[0] )  fprintf(fp, "yunits    = %s\n", attstr);
28158         }
28159 
28160       if ( type == GRID_UNSTRUCTURED && nvertex > 0 ) fprintf(fp, "nvertex   = %d\n", nvertex);
28161     }
28162 
28163   switch (type)
28164     {
28165     case GRID_LONLAT:
28166     case GRID_GAUSSIAN:
28167     case GRID_GAUSSIAN_REDUCED:
28168     case GRID_GENERIC:
28169     case GRID_PROJECTION:
28170     case GRID_CURVILINEAR:
28171     case GRID_UNSTRUCTURED:
28172     case GRID_CHARXY:
28173       {
28174         if ( type == GRID_GAUSSIAN || type == GRID_GAUSSIAN_REDUCED ) fprintf(fp, "np        = %d\n", gridInqNP(gridID));
28175 
28176 	if ( type == GRID_UNSTRUCTURED )
28177           {
28178             int number = 0;
28179             cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDUSED, &number);
28180             if ( number > 0 )
28181               {
28182                 fprintf(fp, "number    = %d\n", number);
28183                 int position = 0;
28184                 cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDINREFERENCE, &position);
28185                 if ( position >= 0 ) fprintf(fp, "position  = %d\n", position);
28186               }
28187 
28188             int length;
28189             if (CDI_NOERR == cdiInqKeyLen(gridID, CDI_GLOBAL, CDI_KEY_REFERENCEURI, &length))
28190               {
28191                 char reference_link[8192];
28192                 length = sizeof(reference_link);
28193                 cdiInqKeyString(gridID, CDI_GLOBAL, CDI_KEY_REFERENCEURI, reference_link, &length);
28194                 fprintf(fp, "uri       = %s\n", reference_link);
28195               }
28196           }
28197 
28198 	if ( nxvals > 0 )
28199 	  {
28200 	    double xfirst = 0.0, xinc = 0.0;
28201 
28202 	    if ( type == GRID_LONLAT     || type == GRID_GAUSSIAN ||
28203 		 type == GRID_PROJECTION || type == GRID_GENERIC )
28204 	      {
28205 		xfirst = gridInqXval(gridID, 0);
28206 		xinc   = gridInqXinc(gridID);
28207 	      }
28208 
28209 	    if ( IS_NOT_EQUAL(xinc, 0) && opt )
28210 	      {
28211                 fprintf(fp, "xfirst    = %.*g\n"
28212                         "xinc      = %.*g\n", dig, xfirst, dig, xinc);
28213 	      }
28214 	    else
28215 	      {
28216                 double *xvals = (double*) Malloc(nxvals*sizeof(double));
28217                 gridInqXvals(gridID, xvals);
28218                 static const char prefix[] = "xvals     = ";
28219                 printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1, nxvals, xvals);
28220                 Free(xvals);
28221 	      }
28222 	  }
28223 
28224 	if ( nyvals > 0 )
28225 	  {
28226 	    double yfirst = 0.0, yinc = 0.0;
28227 
28228 	    if ( type == GRID_LONLAT || type == GRID_GENERIC ||
28229                  type == GRID_PROJECTION || type == GRID_GENERIC )
28230 	      {
28231 		yfirst = gridInqYval(gridID, 0);
28232 		yinc   = gridInqYinc(gridID);
28233 	      }
28234 
28235 	    if ( IS_NOT_EQUAL(yinc, 0) && opt )
28236 	      {
28237 	  	fprintf(fp, "yfirst    = %.*g\n"
28238                         "yinc      = %.*g\n", dig, yfirst, dig, yinc);
28239 	      }
28240 	    else
28241 	      {
28242                 double *yvals = (double*) Malloc(nyvals*sizeof(double));
28243                 gridInqYvals(gridID, yvals);
28244                 static const char prefix[] = "yvals     = ";
28245                 printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1, nyvals, yvals);
28246                 Free(yvals);
28247 	      }
28248 	  }
28249 
28250         if ( type == GRID_PROJECTION ) gridPrintAttributes(fp, gridID);
28251 
28252 	break;
28253       }
28254     case GRID_SPECTRAL:
28255       {
28256         fprintf(fp, "truncation = %d\n"
28257                 "complexpacking = %d\n", gridInqTrunc(gridID), gridInqComplexPacking(gridID) );
28258         break;
28259       }
28260     case GRID_FOURIER:
28261       {
28262 	fprintf(fp, "truncation = %d\n", gridInqTrunc(gridID));
28263 	break;
28264       }
28265     case GRID_GME:
28266       {
28267         int nd, ni, ni2, ni3;
28268         gridInqParamGME(gridID, &nd, &ni, &ni2, &ni3);
28269         fprintf(fp, "ni        = %d\n", ni );
28270         break;
28271       }
28272    default:
28273       {
28274 	fprintf(stderr, "Unsupported grid type: %s\n", gridNamePtr(type));
28275         break;
28276       }
28277     }
28278 }
28279 
28280 
gridPrintP(void * voidptr,FILE * fp)28281 void gridPrintP(void *voidptr, FILE *fp)
28282 {
28283   grid_t *gridptr = (grid_t *) voidptr;
28284   int gridID = gridptr->self;
28285 
28286   xassert( gridptr );
28287 
28288   gridPrintKernel(gridID, 0, fp);
28289 
28290   fprintf(fp,
28291           "datatype  = %d\n"
28292           "nd        = %d\n"
28293           "ni        = %d\n"
28294           "ni2       = %d\n"
28295           "ni3       = %d\n"
28296           "trunc     = %d\n"
28297           "lcomplex  = %d\n"
28298           "reducedPointsSize   = %d\n",
28299           gridptr->datatype, gridptr->gme.nd, gridptr->gme.ni, gridptr->gme.ni2,
28300           gridptr->gme.ni3, gridptr->trunc,
28301           gridptr->lcomplex, gridptr->reducedPointsSize );
28302 }
28303 
gridInqXValsPtrSerial(grid_t * gridptr)28304 static const double *gridInqXValsPtrSerial(grid_t *gridptr)
28305 {
28306   return gridptr->x.vals;
28307 }
28308 
28309 #ifndef USE_MPI
gridInqXCvalsPtrSerial(grid_t * gridptr)28310 static const char **gridInqXCvalsPtrSerial(grid_t *gridptr)
28311 {
28312   return (const char **) gridptr->x.cvals;
28313 }
28314 #endif
28315 
gridInqXvalsPtr(int gridID)28316 const double *gridInqXvalsPtr(int gridID)
28317 {
28318   grid_t *gridptr = grid_to_pointer(gridID);
28319   return gridptr->vtable->inqXValsPtr(gridptr);
28320 }
28321 
28322 #ifndef USE_MPI
gridInqXCvalsPtr(int gridID)28323 const char **gridInqXCvalsPtr(int gridID)
28324 {
28325   grid_t *gridptr = grid_to_pointer(gridID);
28326   return gridptr->vtable->inqXCvalsPtr(gridptr);
28327 }
28328 #endif
28329 
gridInqYValsPtrSerial(grid_t * gridptr)28330 static const double *gridInqYValsPtrSerial(grid_t *gridptr)
28331 {
28332   return gridptr->y.vals;
28333 }
28334 
28335 #ifndef USE_MPI
gridInqYCvalsPtrSerial(grid_t * gridptr)28336 static const char **gridInqYCvalsPtrSerial(grid_t *gridptr)
28337 {
28338   return (const char **) gridptr->y.cvals;
28339 }
28340 #endif
28341 
gridInqYvalsPtr(int gridID)28342 const double *gridInqYvalsPtr(int gridID)
28343 {
28344   grid_t *gridptr = grid_to_pointer(gridID);
28345   return gridptr->vtable->inqYValsPtr(gridptr);
28346 }
28347 
28348 #ifndef USE_MPI
gridInqYCvalsPtr(int gridID)28349 const char **gridInqYCvalsPtr(int gridID)
28350 {
28351   grid_t *gridptr = grid_to_pointer(gridID);
28352   return gridptr->vtable->inqYCvalsPtr(gridptr);
28353 }
28354 #endif
28355 
28356 /*
28357 @Function  gridDefParamLCC
28358 @Title     Define the parameter of a Lambert Conformal Conic grid
28359 
28360 @Prototype void gridDefParamLCC(int gridID, double missval, double lon_0, double lat_0, double lat_1, double lat_2, double a, double rf, double xval_0, double yval_0, double x_0, double y_0)
28361 @Parameter
28362     @Item  gridID    Grid ID, from a previous call to @fref{gridCreate}.
28363     @Item  missval   Missing value.
28364     @Item  lon_0     The East longitude of the meridian which is parallel to the Y-axis.
28365     @Item  lat_0     Latitude of the projection origin.
28366     @Item  lat_1     First latitude from the pole at which the secant cone cuts the sphere.
28367     @Item  lat_2     Second latitude at which the secant cone cuts the sphere.
28368     @Item  a         Earth radius in metres (optional).
28369     @Item  rf        Inverse flattening (1/f) (optional).
28370     @Item  xval_0    Longitude of the first grid point in degree (optional).
28371     @Item  yval_0    Latitude of the first grid point in degree (optional).
28372     @Item  x_0       False easting (optional).
28373     @Item  y_0       False northing (optional).
28374 
28375 @Description
28376 The function @func{gridDefParamLCC} defines the parameter of a Lambert Conformal Conic grid.
28377 
28378 @EndFunction
28379 */
gridDefParamLCC(int gridID,double missval,double lon_0,double lat_0,double lat_1,double lat_2,double a,double rf,double xval_0,double yval_0,double x_0,double y_0)28380 void gridDefParamLCC(int gridID, double missval, double lon_0, double lat_0, double lat_1, double lat_2,
28381                      double a, double rf, double xval_0, double yval_0, double x_0, double y_0)
28382 {
28383   (void)lat_0;
28384   cdiDefKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_VARNAME, "Lambert_Conformal");
28385 
28386   const char *gmapname = "lambert_conformal_conic";
28387   cdiDefKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_NAME, gmapname);
28388   cdiDefAttTxt(gridID, CDI_GLOBAL, "grid_mapping_name", (int)(strlen(gmapname)), gmapname);
28389   int nlats = 0;
28390   double lats[2];
28391   lats[nlats++] = lat_1;
28392   if ( IS_NOT_EQUAL(lat_1, lat_2) ) lats[nlats++] = lat_2;
28393   cdiDefAttFlt(gridID, CDI_GLOBAL, "standard_parallel", CDI_DATATYPE_FLT64, nlats, lats);
28394   cdiDefAttFlt(gridID, CDI_GLOBAL, "longitude_of_central_meridian", CDI_DATATYPE_FLT64, 1, &lon_0);
28395   cdiDefAttFlt(gridID, CDI_GLOBAL, "latitude_of_projection_origin", CDI_DATATYPE_FLT64, 1, &lat_2);
28396   if ( a > 0 ) cdiDefAttFlt(gridID, CDI_GLOBAL, "earth_radius", CDI_DATATYPE_FLT64, 1, &a);
28397   if ( rf > 0 ) cdiDefAttFlt(gridID, CDI_GLOBAL, "inverse_flattening", CDI_DATATYPE_FLT64, 1, &rf);
28398   if ( IS_NOT_EQUAL(x_0, missval) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "false_easting", CDI_DATATYPE_FLT64, 1, &x_0);
28399   if ( IS_NOT_EQUAL(y_0, missval) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "false_northing", CDI_DATATYPE_FLT64, 1, &y_0);
28400   if ( IS_NOT_EQUAL(xval_0, missval) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "longitudeOfFirstGridPointInDegrees", CDI_DATATYPE_FLT64, 1, &xval_0);
28401   if ( IS_NOT_EQUAL(yval_0, missval) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "latitudeOfFirstGridPointInDegrees", CDI_DATATYPE_FLT64, 1, &yval_0);
28402 
28403   grid_t *gridptr = grid_to_pointer(gridID);
28404   gridptr->projtype = CDI_PROJ_LCC;
28405 
28406   if (gridptr->type != GRID_PROJECTION) gridptr->type = GRID_PROJECTION;
28407 
28408   gridVerifyProj(gridID);
28409 }
28410 
28411 /*
28412 @Function  gridInqParamLCC
28413 @Title     Get the parameter of a Lambert Conformal Conic grid
28414 
28415 @Prototype void gridInqParamLCC(int gridID, double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2, double *a, double *rf, double *xval_0, double *yval_0, double *x_0, double *y_0)
28416 @Parameter
28417     @Item  gridID    Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
28418     @Item  missval   Missing value
28419     @Item  lon_0     The East longitude of the meridian which is parallel to the Y-axis.
28420     @Item  lat_0     Latitude of the projection origin.
28421     @Item  lat_1     First latitude from the pole at which the secant cone cuts the sphere.
28422     @Item  lat_2     Second latitude at which the secant cone cuts the sphere.
28423     @Item  a         Earth radius in metres (optional).
28424     @Item  rf        Inverse flattening (1/f) (optional).
28425     @Item  xval_0    Longitude of the first grid point in degree (optional).
28426     @Item  yval_0    Latitude of the first grid point in degree (optional).
28427     @Item  x_0       False easting (optional).
28428     @Item  y_0       False northing (optional).
28429 
28430 @Description
28431 The function @func{gridInqParamLCC} returns the parameter of a Lambert Conformal Conic grid.
28432 
28433 @EndFunction
28434 */
gridInqParamLCC(int gridID,double missval,double * lon_0,double * lat_0,double * lat_1,double * lat_2,double * a,double * rf,double * xval_0,double * yval_0,double * x_0,double * y_0)28435 int gridInqParamLCC(int gridID, double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2,
28436                     double *a, double *rf, double *xval_0, double *yval_0, double *x_0, double *y_0)
28437 {
28438   *a = 0; *rf = 0;
28439   *lon_0 = missval; *lat_0 = missval, *lat_1 = missval, *lat_2 = missval;
28440   *xval_0 = missval; *yval_0 = missval; *x_0 = missval, *y_0 = missval;
28441 
28442   int status = -1;
28443   if ( gridInqType(gridID) != GRID_PROJECTION ) return status;
28444 
28445   status = -2;
28446   const char *projection = "lambert_conformal_conic";
28447   char gmapname[CDI_MAX_NAME];
28448   int length = CDI_MAX_NAME;
28449   cdiInqKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_NAME, gmapname, &length);
28450   if ( gmapname[0] && strIsEqual(gmapname, projection) )
28451     {
28452       int atttype, attlen;
28453       char attname[CDI_MAX_NAME+1];
28454 
28455       int natts;
28456       cdiInqNatts(gridID, CDI_GLOBAL, &natts);
28457 
28458       if ( natts ) status = 0;
28459 
28460       for ( int iatt = 0; iatt < natts; ++iatt )
28461         {
28462           cdiInqAtt(gridID, CDI_GLOBAL, iatt, attname, &atttype, &attlen);
28463           if ( attlen > 2 ) continue;
28464 
28465           double attflt[2];
28466           if ( cdiInqAttConvertedToFloat(gridID, atttype, attname, attlen, attflt) )
28467             {
28468               if      ( strIsEqual(attname, "earth_radius") )                       *a      = attflt[0];
28469               else if ( strIsEqual(attname, "semi_major_axis") )                    *a      = attflt[0];
28470               else if ( strIsEqual(attname, "inverse_flattening") )                 *rf     = attflt[0];
28471               else if ( strIsEqual(attname, "longitude_of_central_meridian") )      *lon_0  = attflt[0];
28472               else if ( strIsEqual(attname, "latitude_of_projection_origin") )      *lat_0  = attflt[0];
28473               else if ( strIsEqual(attname, "false_easting")  )                     *x_0    = attflt[0];
28474               else if ( strIsEqual(attname, "false_northing") )                     *y_0    = attflt[0];
28475               else if ( strIsEqual(attname, "longitudeOfFirstGridPointInDegrees") ) *xval_0 = attflt[0];
28476               else if ( strIsEqual(attname, "latitudeOfFirstGridPointInDegrees")  ) *yval_0 = attflt[0];
28477               else if ( strIsEqual(attname, "standard_parallel") )
28478                 {
28479                   *lat_1 = attflt[0];
28480                   *lat_2 = (attlen == 2) ? attflt[1] : attflt[0];
28481                 }
28482             }
28483         }
28484     }
28485 
28486   return status;
28487 }
28488 
28489 
gridVerifyGribParamLCC(double missval,double * lon_0,double * lat_0,double * lat_1,double * lat_2,double * a,double * rf,double * xval_0,double * yval_0,double * x_0,double * y_0)28490 int gridVerifyGribParamLCC(double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2,
28491                            double *a, double *rf, double *xval_0, double *yval_0, double *x_0, double *y_0)
28492 {
28493   static bool lwarn = true;
28494 
28495   if ( lwarn )
28496     {
28497       // lwarn = false;
28498       const char *projection = "lambert_conformal_conic";
28499       if ( IS_EQUAL(*lon_0, missval) ) { Warning("%s mapping parameter %s missing!", projection, "longitude_of_central_meridian"); }
28500       if ( IS_EQUAL(*lat_0, missval) ) { Warning("%s mapping parameter %s missing!", projection, "latitude_of_central_meridian"); }
28501       if ( IS_EQUAL(*lat_1, missval) ) { Warning("%s mapping parameter %s missing!", projection, "standard_parallel"); }
28502       if ( IS_NOT_EQUAL(*x_0, missval) && IS_NOT_EQUAL(*y_0, missval) && (IS_EQUAL(*xval_0, missval) || IS_EQUAL(*yval_0, missval)) )
28503         {
28504           if ( proj_lcc_to_lonlat_func )
28505             {
28506               *xval_0 = -(*x_0); *yval_0 = -(*y_0);
28507               proj_lcc_to_lonlat_func(missval, *lon_0, *lat_0, *lat_1, *lat_2, *a, *rf, 0.0, 0.0, (size_t)1, xval_0, yval_0);
28508             }
28509           if ( IS_EQUAL(*xval_0, missval) || IS_EQUAL(*yval_0, missval) )
28510             Warning("%s mapping parameter %s missing!", projection, "longitudeOfFirstGridPointInDegrees and latitudeOfFirstGridPointInDegrees");
28511         }
28512     }
28513 
28514   return 0;
28515 }
28516 
28517 
gridVerifyGribParamSTERE(double missval,double * lon_0,double * lat_ts,double * lat_0,double * a,double * xval_0,double * yval_0,double * x_0,double * y_0)28518 int gridVerifyGribParamSTERE(double missval, double *lon_0, double *lat_ts, double *lat_0,
28519                              double *a, double *xval_0, double *yval_0, double *x_0, double *y_0)
28520 {
28521   static bool lwarn = true;
28522 
28523   if ( lwarn )
28524     {
28525       // lwarn = false;
28526       const char *projection = "lambert_conformal_conic";
28527       if ( IS_EQUAL(*lon_0, missval) ) { Warning("%s mapping parameter %s missing!", projection, "straight_vertical_longitude_from_pole"); }
28528       if ( IS_EQUAL(*lat_0, missval) ) { Warning("%s mapping parameter %s missing!", projection, "latitude_of_projection_origin"); }
28529       if ( IS_EQUAL(*lat_ts, missval) ) { Warning("%s mapping parameter %s missing!", projection, "standard_parallel"); }
28530       if ( IS_NOT_EQUAL(*x_0, missval) && IS_NOT_EQUAL(*y_0, missval) && (IS_EQUAL(*xval_0, missval) || IS_EQUAL(*yval_0, missval)) )
28531         {
28532           if ( proj_stere_to_lonlat_func )
28533             {
28534               *xval_0 = -(*x_0); *yval_0 = -(*y_0);
28535               proj_stere_to_lonlat_func(missval, *lon_0, *lat_ts, *lat_0, *a, 0.0, 0.0, (size_t)1, xval_0, yval_0);
28536             }
28537           if ( IS_EQUAL(*xval_0, missval) || IS_EQUAL(*yval_0, missval) )
28538             Warning("%s mapping parameter %s missing!", projection, "longitudeOfFirstGridPointInDegrees and latitudeOfFirstGridPointInDegrees");
28539         }
28540     }
28541 
28542   return 0;
28543 }
28544 
28545 /*
28546 @Function  gridDefParamSTERE
28547 @Title     Define the parameter of a Polar stereographic grid
28548 
28549 @Prototype void gridDefParamSTERE(int gridID, double missval, double lon_0, double lat_ts, double lat_0, double a, double xval_0, double yval_0, double x_0, double y_0)
28550 @Parameter
28551     @Item  gridID    Grid ID, from a previous call to @fref{gridCreate}.
28552     @Item  missval   Missing value.
28553     @Item  lon_0     Longitude at natural origin.
28554     @Item  lat_ts    Latitude of the projection origin.
28555     @Item  lat_0     First latitude from the pole at which the secant cone cuts the sphere.
28556     @Item  a         Earth radius in metres (optional).
28557     @Item  xval_0    Longitude of the first grid point in degree (optional).
28558     @Item  yval_0    Latitude of the first grid point in degree (optional).
28559     @Item  x_0       False easting (optional).
28560     @Item  y_0       False northing (optional).
28561 
28562 @Description
28563 The function @func{gridDefParamSTERE} defines the parameter of a Polar stereographic grid.
28564 
28565 @EndFunction
28566 */
gridDefParamSTERE(int gridID,double missval,double lon_0,double lat_ts,double lat_0,double a,double xval_0,double yval_0,double x_0,double y_0)28567 void gridDefParamSTERE(int gridID, double missval, double lon_0, double lat_ts, double lat_0,
28568                        double a, double xval_0, double yval_0, double x_0, double y_0)
28569 {
28570   cdiDefKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_VARNAME, "Polar_Stereographic");
28571 
28572   const char *gmapname = "polar_stereographic";
28573   cdiDefKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_NAME, gmapname);
28574   cdiDefAttTxt(gridID, CDI_GLOBAL, "grid_mapping_name", (int)(strlen(gmapname)), gmapname);
28575   cdiDefAttFlt(gridID, CDI_GLOBAL, "standard_parallel", CDI_DATATYPE_FLT64, 1, &lat_ts);
28576   cdiDefAttFlt(gridID, CDI_GLOBAL, "straight_vertical_longitude_from_pole", CDI_DATATYPE_FLT64, 1, &lon_0);
28577   cdiDefAttFlt(gridID, CDI_GLOBAL, "latitude_of_projection_origin", CDI_DATATYPE_FLT64, 1, &lat_0);
28578   if ( a > 0 ) cdiDefAttFlt(gridID, CDI_GLOBAL, "earth_radius", CDI_DATATYPE_FLT64, 1, &a);
28579   if ( IS_NOT_EQUAL(x_0, missval) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "false_easting", CDI_DATATYPE_FLT64, 1, &x_0);
28580   if ( IS_NOT_EQUAL(y_0, missval) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "false_northing", CDI_DATATYPE_FLT64, 1, &y_0);
28581   if ( IS_NOT_EQUAL(xval_0, missval) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "longitudeOfFirstGridPointInDegrees", CDI_DATATYPE_FLT64, 1, &xval_0);
28582   if ( IS_NOT_EQUAL(yval_0, missval) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "latitudeOfFirstGridPointInDegrees", CDI_DATATYPE_FLT64, 1, &yval_0);
28583 
28584   grid_t *gridptr = grid_to_pointer(gridID);
28585   gridptr->projtype = CDI_PROJ_STERE;
28586 
28587   gridVerifyProj(gridID);
28588 }
28589 
28590 /*
28591 @Function  gridInqParamSTERE
28592 @Title     Get the parameter of a Polar stereographic grid
28593 
28594 @Prototype void gridInqParamSTERE(int gridID, double missval, double *lon_0, double *lat_ts, double *lat_0, double *a, double *xval_0, double *yval_0, double *x_0, double *y_0)
28595 @Parameter
28596     @Item  gridID    Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
28597     @Item  missval   Missing value
28598     @Item  lon_0     Longitude at natural origin.
28599     @Item  lat_ts    Latitude of the projection origin.
28600     @Item  lat_0     First latitude from the pole at which the secant cone cuts the sphere.
28601     @Item  a         Earth radius in metres (optional).
28602     @Item  xval_0    Longitude of the first grid point in degree (optional).
28603     @Item  yval_0    Latitude of the first grid point in degree (optional).
28604     @Item  x_0       False easting (optional).
28605     @Item  y_0       False northing (optional).
28606 
28607 @Description
28608 The function @func{gridInqParamSTERE} returns the parameter of a Polar stereographic grid.
28609 
28610 @EndFunction
28611 */
gridInqParamSTERE(int gridID,double missval,double * lon_0,double * lat_ts,double * lat_0,double * a,double * xval_0,double * yval_0,double * x_0,double * y_0)28612 int gridInqParamSTERE(int gridID, double missval, double *lon_0, double *lat_ts, double *lat_0,
28613                       double *a, double *xval_0, double *yval_0, double *x_0, double *y_0)
28614 {
28615   *a = 0;
28616   *lon_0 = missval; *lat_ts = missval, *lat_0 = missval;
28617   *xval_0 = missval; *yval_0 = missval; *x_0 = missval, *y_0 = missval;
28618 
28619   int status = -1;
28620   if ( gridInqType(gridID) != GRID_PROJECTION ) return status;
28621 
28622   status = -2;
28623   const char *projection = "polar_stereographic";
28624   char gmapname[CDI_MAX_NAME];
28625   int length = CDI_MAX_NAME;
28626   cdiInqKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_NAME, gmapname, &length);
28627   if ( gmapname[0] && strIsEqual(gmapname, projection) )
28628     {
28629       int atttype, attlen;
28630       char attname[CDI_MAX_NAME+1];
28631 
28632       int natts;
28633       cdiInqNatts(gridID, CDI_GLOBAL, &natts);
28634 
28635       if ( natts ) status = 0;
28636 
28637       for ( int iatt = 0; iatt < natts; ++iatt )
28638         {
28639           cdiInqAtt(gridID, CDI_GLOBAL, iatt, attname, &atttype, &attlen);
28640           if ( attlen > 2 ) continue;
28641 
28642           double attflt[2];
28643           if ( cdiInqAttConvertedToFloat(gridID, atttype, attname, attlen, attflt) )
28644             {
28645               if      ( strIsEqual(attname, "earth_radius") )                          *a      = attflt[0];
28646               else if ( strIsEqual(attname, "standard_parallel") )                     *lat_ts = attflt[0];
28647               else if ( strIsEqual(attname, "straight_vertical_longitude_from_pole") ) *lon_0  = attflt[0];
28648               else if ( strIsEqual(attname, "latitude_of_projection_origin") )         *lat_0  = attflt[0];
28649               else if ( strIsEqual(attname, "false_easting")  )                        *x_0    = attflt[0];
28650               else if ( strIsEqual(attname, "false_northing") )                        *y_0    = attflt[0];
28651               else if ( strIsEqual(attname, "longitudeOfFirstGridPointInDegrees") )    *xval_0 = attflt[0];
28652               else if ( strIsEqual(attname, "latitudeOfFirstGridPointInDegrees")  )    *yval_0 = attflt[0];
28653             }
28654         }
28655     }
28656 
28657   return status;
28658 }
28659 
28660 
gridDefComplexPacking(int gridID,int lcomplex)28661 void gridDefComplexPacking(int gridID, int lcomplex)
28662 {
28663   grid_t *gridptr = grid_to_pointer(gridID);
28664 
28665   if (gridptr->lcomplex != lcomplex)
28666     {
28667       gridptr->lcomplex = lcomplex != 0;
28668       gridMark4Update(gridID);
28669     }
28670 }
28671 
28672 
gridInqComplexPacking(int gridID)28673 int gridInqComplexPacking(int gridID)
28674 {
28675   grid_t* gridptr = grid_to_pointer(gridID);
28676 
28677   return (int)gridptr->lcomplex;
28678 }
28679 
28680 
gridDefHasDims(int gridID,int hasdims)28681 void gridDefHasDims(int gridID, int hasdims)
28682 {
28683   grid_t* gridptr = grid_to_pointer(gridID);
28684 
28685   if ( gridptr->hasdims != (hasdims != 0) )
28686     {
28687       gridptr->hasdims = hasdims != 0;
28688       gridMark4Update(gridID);
28689     }
28690 }
28691 
28692 
gridInqHasDims(int gridID)28693 int gridInqHasDims(int gridID)
28694 {
28695   grid_t* gridptr = grid_to_pointer(gridID);
28696 
28697   return (int)gridptr->hasdims;
28698 }
28699 
28700 /*
28701 @Function  gridDefNumber
28702 @Title     Define the reference number for an unstructured grid
28703 
28704 @Prototype void gridDefNumber(int gridID, const int number)
28705 @Parameter
28706     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
28707     @Item  number   Reference number for an unstructured grid.
28708 
28709 @Description
28710 The function @func{gridDefNumber} defines the reference number for an unstructured grid.
28711 
28712 @EndFunction
28713 */
gridDefNumber(int gridID,int number)28714 void gridDefNumber(int gridID, int number)
28715 {
28716   cdiDefKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDUSED, number);
28717 }
28718 
28719 /*
28720 @Function  gridInqNumber
28721 @Title     Get the reference number to an unstructured grid
28722 
28723 @Prototype int gridInqNumber(int gridID)
28724 @Parameter
28725     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
28726 
28727 @Description
28728 The function @func{gridInqNumber} returns the reference number to an unstructured grid.
28729 
28730 @Result
28731 @func{gridInqNumber} returns the reference number to an unstructured grid.
28732 @EndFunction
28733 */
gridInqNumber(int gridID)28734 int gridInqNumber(int gridID)
28735 {
28736   int number = 0;
28737   cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDUSED, &number);
28738   return number;
28739 }
28740 
28741 /*
28742 @Function  gridDefPosition
28743 @Title     Define the position of grid in the reference file
28744 
28745 @Prototype void gridDefPosition(int gridID, const int position)
28746 @Parameter
28747     @Item  gridID     Grid ID, from a previous call to @fref{gridCreate}.
28748     @Item  position   Position of grid in the reference file.
28749 
28750 @Description
28751 The function @func{gridDefPosition} defines the position of grid in the reference file.
28752 
28753 @EndFunction
28754 */
gridDefPosition(int gridID,int position)28755 void gridDefPosition(int gridID, int position)
28756 {
28757   cdiDefKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDINREFERENCE, position);
28758 }
28759 
28760 /*
28761 @Function  gridInqPosition
28762 @Title     Get the position of grid in the reference file
28763 
28764 @Prototype int gridInqPosition(int gridID)
28765 @Parameter
28766     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
28767 
28768 @Description
28769 The function @func{gridInqPosition} returns the position of grid in the reference file.
28770 
28771 @Result
28772 @func{gridInqPosition} returns the position of grid in the reference file.
28773 @EndFunction
28774 */
gridInqPosition(int gridID)28775 int gridInqPosition(int gridID)
28776 {
28777   int position = 0;
28778   cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDINREFERENCE, &position);
28779   return position;
28780 }
28781 
28782 /*
28783 @Function  gridDefReference
28784 @Title     Define the reference URI for an unstructured grid
28785 
28786 @Prototype void gridDefReference(int gridID, const char *reference)
28787 @Parameter
28788     @Item  gridID      Grid ID, from a previous call to @fref{gridCreate}.
28789     @Item  reference   Reference URI for an unstructured grid.
28790 
28791 @Description
28792 The function @func{gridDefReference} defines the reference URI for an unstructured grid.
28793 
28794 @EndFunction
28795 */
gridDefReference(int gridID,const char * reference)28796 void gridDefReference(int gridID, const char *reference)
28797 {
28798   if (reference)
28799     {
28800       cdiDefKeyString(gridID, CDI_GLOBAL, CDI_KEY_REFERENCEURI, reference);
28801       gridMark4Update(gridID);
28802     }
28803 }
28804 
28805 /*
28806 @Function  gridInqReference
28807 @Title     Get the reference URI to an unstructured grid
28808 
28809 @Prototype char *gridInqReference(int gridID, char *reference)
28810 @Parameter
28811     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
28812 
28813 @Description
28814 The function @func{gridInqReference} returns the reference URI to an unstructured grid.
28815 
28816 @Result
28817 @func{gridInqReference} returns the reference URI to an unstructured grid.
28818 @EndFunction
28819 */
gridInqReference(int gridID,char * reference)28820 int gridInqReference(int gridID, char *reference)
28821 {
28822   int length = 0;
28823   if (CDI_NOERR == cdiInqKeyLen(gridID, CDI_GLOBAL, CDI_KEY_REFERENCEURI, &length))
28824     {
28825       if (reference)
28826         cdiInqKeyString(gridID, CDI_GLOBAL, CDI_KEY_REFERENCEURI, reference, &length);
28827     }
28828 
28829   return length;
28830 }
28831 
28832 /*
28833 @Function  gridDefUUID
28834 @Title     Define the UUID for an unstructured grid
28835 
28836 @Prototype void gridDefUUID(int gridID, const char *uuid)
28837 @Parameter
28838     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
28839     @Item  uuid     UUID for an unstructured grid.
28840 
28841 @Description
28842 The function @func{gridDefUUID} defines the UUID for an unstructured grid.
28843 
28844 @EndFunction
28845 */
gridDefUUID(int gridID,const unsigned char uuid[CDI_UUID_SIZE])28846 void gridDefUUID(int gridID, const unsigned char uuid[CDI_UUID_SIZE])
28847 {
28848   cdiDefKeyBytes(gridID, CDI_GLOBAL, CDI_KEY_UUID, uuid, CDI_UUID_SIZE);
28849 
28850   gridMark4Update(gridID);
28851 }
28852 
28853 /*
28854 @Function  gridInqUUID
28855 @Title     Get the UUID to an unstructured grid
28856 
28857 @Prototype void gridInqUUID(int gridID, char *uuid)
28858 @Parameter
28859     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
28860 
28861 @Description
28862 The function @func{gridInqUUID} returns the UUID to an unstructured grid.
28863 
28864 @Result
28865 @func{gridInqUUID} returns the UUID to an unstructured grid to the parameter uuid.
28866 @EndFunction
28867 */
gridInqUUID(int gridID,unsigned char uuid[CDI_UUID_SIZE])28868 void gridInqUUID(int gridID, unsigned char uuid[CDI_UUID_SIZE])
28869 {
28870   memset(uuid, 0, CDI_UUID_SIZE);
28871   int length = CDI_UUID_SIZE;
28872   cdiInqKeyBytes(gridID, CDI_GLOBAL, CDI_KEY_UUID, uuid, &length);
28873 }
28874 
28875 
cdiGridGetIndexList(unsigned ngrids,int * gridIndexList)28876 void cdiGridGetIndexList(unsigned ngrids, int * gridIndexList)
28877 {
28878   reshGetResHListOfType(ngrids, gridIndexList, &gridOps);
28879 }
28880 
28881 static int
gridTxCode()28882 gridTxCode ()
28883 {
28884   return GRID;
28885 }
28886 
28887 enum {
28888   GRID_PACK_INT_IDX_SELF,
28889   GRID_PACK_INT_IDX_TYPE,
28890   GRID_PACK_INT_IDX_DATATYPE,
28891   GRID_PACK_INT_IDX_IS_CYCLIC,
28892   GRID_PACK_INT_IDX_X_FLAG,
28893   GRID_PACK_INT_IDX_Y_FLAG,
28894   GRID_PACK_INT_IDX_GME_ND,
28895   GRID_PACK_INT_IDX_GME_NI,
28896   GRID_PACK_INT_IDX_GME_NI2,
28897   GRID_PACK_INT_IDX_GME_NI3,
28898   GRID_PACK_INT_IDX_TRUNC,
28899   GRID_PACK_INT_IDX_NVERTEX,
28900   REDUCEDPOINTSSIZE,
28901   GRID_PACK_INT_IDX_SIZE,
28902   GRID_PACK_INT_IDX_X_SIZE,
28903   GRID_PACK_INT_IDX_Y_SIZE,
28904   GRID_PACK_INT_IDX_LCOMPLEX,
28905   GRID_PACK_INT_IDX_MEMBERMASK,
28906   GRID_PACK_INT_IDX_XTSTDNNAME,
28907   GRID_PACK_INT_IDX_YTSTDNNAME,
28908   /*
28909   GRID_PACK_INT_IDX_ISCANSNEGATIVELY,
28910   GRID_PACK_INT_IDX_JSCANSPOSITIVELY,
28911   GRID_PACK_INT_IDX_JPOINTSARECONSECUTIVE,
28912   */
28913   gridNint
28914 };
28915 
28916 enum {
28917   GRID_PACK_DBL_IDX_X_FIRST,
28918   GRID_PACK_DBL_IDX_Y_FIRST,
28919   GRID_PACK_DBL_IDX_X_LAST,
28920   GRID_PACK_DBL_IDX_Y_LAST,
28921   GRID_PACK_DBL_IDX_X_INC,
28922   GRID_PACK_DBL_IDX_Y_INC,
28923   gridNdouble
28924 };
28925 
28926 enum {
28927        gridHasMaskFlag = 1 << 0,
28928        gridHasGMEMaskFlag = 1 << 1,
28929        gridHasXValsFlag = 1 << 2,
28930        gridHasYValsFlag = 1 << 3,
28931        gridHasAreaFlag = 1 << 4,
28932        gridHasXBoundsFlag = 1 << 5,
28933        gridHasYBoundsFlag = 1 << 6,
28934        gridHasReducedPointsFlag = 1 << 7,
28935 };
28936 
28937 
gridGetComponentFlags(const grid_t * gridP)28938 static int gridGetComponentFlags(const grid_t * gridP)
28939 {
28940   int flags = (gridHasMaskFlag & (int)((unsigned)(gridP->mask == NULL) - 1U))
28941     | (gridHasGMEMaskFlag & (int)((unsigned)(gridP->mask_gme == NULL) - 1U))
28942     | (gridHasXValsFlag & (int)((unsigned)(gridP->vtable->inqXValsPtr((grid_t *)gridP) == NULL) - 1U))
28943     | (gridHasYValsFlag & (int)((unsigned)(gridP->vtable->inqYValsPtr((grid_t *)gridP) == NULL) - 1U))
28944     | (gridHasAreaFlag & (int)((unsigned)(gridP->vtable->inqAreaPtr((grid_t *)gridP) == NULL) - 1U))
28945     | (gridHasXBoundsFlag & (int)((unsigned)(gridP->x.bounds == NULL) - 1U))
28946     | (gridHasYBoundsFlag & (int)((unsigned)(gridP->y.bounds == NULL) - 1U))
28947     | (gridHasReducedPointsFlag & (int)((unsigned)(gridP->reducedPoints == NULL) - 1U));
28948   return flags;
28949 }
28950 
28951 static int
gridGetPackSize(void * voidP,void * context)28952 gridGetPackSize(void * voidP, void *context)
28953 {
28954   grid_t * gridP = ( grid_t * ) voidP;
28955   int packBuffSize = 0, count;
28956 
28957   packBuffSize += serializeGetSize(gridNint, CDI_DATATYPE_INT, context)
28958     + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
28959 
28960   if (gridP->reducedPoints)
28961     {
28962       xassert(gridP->reducedPointsSize);
28963       packBuffSize += serializeGetSize(gridP->reducedPointsSize, CDI_DATATYPE_INT, context)
28964         + serializeGetSize( 1, CDI_DATATYPE_UINT32, context);
28965     }
28966 
28967   packBuffSize += serializeGetSize(gridNdouble, CDI_DATATYPE_FLT64, context);
28968 
28969   if (gridP->vtable->inqXValsPtr(gridP))
28970     {
28971       if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
28972 	count = gridP->size;
28973       else
28974 	count = gridP->x.size;
28975       xassert(count);
28976       packBuffSize += serializeGetSize(count, CDI_DATATYPE_FLT64, context)
28977         + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
28978     }
28979 
28980   if (gridP->vtable->inqYValsPtr(gridP))
28981     {
28982       if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
28983 	count = gridP->size;
28984       else
28985 	count = gridP->y.size;
28986       xassert(count);
28987       packBuffSize += serializeGetSize(count, CDI_DATATYPE_FLT64, context)
28988         + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
28989     }
28990 
28991   if (gridP->vtable->inqAreaPtr(gridP))
28992     {
28993       xassert(gridP->size);
28994       packBuffSize +=
28995         serializeGetSize(gridP->size, CDI_DATATYPE_FLT64, context)
28996         + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
28997     }
28998 
28999   if (gridP->x.bounds)
29000     {
29001       xassert(gridP->nvertex);
29002       if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
29003 	count = gridP->size;
29004       else
29005 	count = gridP->x.size;
29006       xassert(count);
29007       packBuffSize
29008         += (serializeGetSize(gridP->nvertex * count, CDI_DATATYPE_FLT64, context)
29009             + serializeGetSize(1, CDI_DATATYPE_UINT32, context));
29010     }
29011 
29012   if (gridP->y.bounds)
29013     {
29014       xassert(gridP->nvertex);
29015       if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
29016 	count = gridP->size;
29017       else
29018 	count = gridP->y.size;
29019       xassert(count);
29020       packBuffSize
29021         += (serializeGetSize(gridP->nvertex * count, CDI_DATATYPE_FLT64, context)
29022             + serializeGetSize(1, CDI_DATATYPE_UINT32, context));
29023     }
29024 
29025   packBuffSize += serializeKeysGetPackSize(&gridP->keys, context);
29026   packBuffSize += serializeKeysGetPackSize(&gridP->x.keys, context);
29027   packBuffSize += serializeKeysGetPackSize(&gridP->y.keys, context);
29028 
29029   if (gridP->mask)
29030     {
29031       xassert(gridP->size);
29032       packBuffSize
29033         += serializeGetSize(gridP->size, CDI_DATATYPE_UCHAR, context)
29034         + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
29035     }
29036 
29037   if (gridP->mask_gme)
29038     {
29039       xassert(gridP->size);
29040       packBuffSize += serializeGetSize(gridP->size, CDI_DATATYPE_UCHAR, context)
29041         + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
29042     }
29043 
29044   return packBuffSize;
29045 }
29046 
29047 void
gridUnpack(char * unpackBuffer,int unpackBufferSize,int * unpackBufferPos,int originNamespace,void * context,int force_id)29048 gridUnpack(char * unpackBuffer, int unpackBufferSize,
29049            int * unpackBufferPos, int originNamespace, void *context,
29050            int force_id)
29051 {
29052   grid_t * gridP;
29053   uint32_t d;
29054   int memberMask, size;
29055 
29056   gridInit();
29057 
29058   {
29059     int intBuffer[gridNint];
29060     serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29061                     intBuffer, gridNint, CDI_DATATYPE_INT, context);
29062     serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29063                     &d, 1, CDI_DATATYPE_UINT32, context);
29064 
29065     xassert(cdiCheckSum(CDI_DATATYPE_INT, gridNint, intBuffer) == d);
29066     int targetID = namespaceAdaptKey(intBuffer[0], originNamespace);
29067     gridP = gridNewEntry(force_id?targetID:CDI_UNDEFID);
29068 
29069     xassert(!force_id || targetID == gridP->self);
29070 
29071     gridP->type          =   intBuffer[GRID_PACK_INT_IDX_TYPE];
29072     gridP->datatype      =   intBuffer[GRID_PACK_INT_IDX_DATATYPE];
29073     gridP->isCyclic      =   (signed char)intBuffer[GRID_PACK_INT_IDX_IS_CYCLIC];
29074     gridP->x.flag        =   (short)intBuffer[GRID_PACK_INT_IDX_X_FLAG];
29075     gridP->y.flag        =   (short)intBuffer[GRID_PACK_INT_IDX_Y_FLAG];
29076     gridP->gme.nd        =   intBuffer[GRID_PACK_INT_IDX_GME_ND];
29077     gridP->gme.ni        =   intBuffer[GRID_PACK_INT_IDX_GME_NI];
29078     gridP->gme.ni2       =   intBuffer[GRID_PACK_INT_IDX_GME_NI2];
29079     gridP->gme.ni3       =   intBuffer[GRID_PACK_INT_IDX_GME_NI3];
29080     gridP->trunc         =   intBuffer[GRID_PACK_INT_IDX_TRUNC];
29081     gridP->nvertex       =   intBuffer[GRID_PACK_INT_IDX_NVERTEX];
29082     gridP->reducedPointsSize =   intBuffer[REDUCEDPOINTSSIZE];
29083     gridP->size          =   intBuffer[GRID_PACK_INT_IDX_SIZE];
29084     gridP->x.size        =   intBuffer[GRID_PACK_INT_IDX_X_SIZE];
29085     gridP->y.size        =   intBuffer[GRID_PACK_INT_IDX_Y_SIZE];
29086     gridP->lcomplex      =   (bool)intBuffer[GRID_PACK_INT_IDX_LCOMPLEX];
29087     memberMask           =   intBuffer[GRID_PACK_INT_IDX_MEMBERMASK];
29088   }
29089 
29090   if (memberMask & gridHasReducedPointsFlag)
29091     {
29092       xassert(gridP->reducedPointsSize);
29093       gridP->reducedPoints = (int *) Malloc((size_t)gridP->reducedPointsSize * sizeof (int));
29094       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29095                       gridP->reducedPoints, gridP->reducedPointsSize , CDI_DATATYPE_INT, context);
29096       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29097                       &d, 1, CDI_DATATYPE_UINT32, context);
29098       xassert(cdiCheckSum(CDI_DATATYPE_INT, gridP->reducedPointsSize, gridP->reducedPoints) == d);
29099     }
29100 
29101   {
29102     double doubleBuffer[gridNdouble];
29103     serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29104                     doubleBuffer, gridNdouble, CDI_DATATYPE_FLT64, context);
29105     serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29106                     &d, 1, CDI_DATATYPE_UINT32, context);
29107     xassert(d == cdiCheckSum(CDI_DATATYPE_FLT, gridNdouble, doubleBuffer));
29108 
29109     gridP->x.first = doubleBuffer[GRID_PACK_DBL_IDX_X_FIRST];
29110     gridP->y.first = doubleBuffer[GRID_PACK_DBL_IDX_Y_FIRST];
29111     gridP->x.last = doubleBuffer[GRID_PACK_DBL_IDX_X_LAST];
29112     gridP->y.last = doubleBuffer[GRID_PACK_DBL_IDX_Y_LAST];
29113     gridP->x.inc = doubleBuffer[GRID_PACK_DBL_IDX_X_INC];
29114     gridP->y.inc = doubleBuffer[GRID_PACK_DBL_IDX_Y_INC];
29115   }
29116 
29117   bool irregular = gridP->type == GRID_UNSTRUCTURED
29118     || gridP->type == GRID_CURVILINEAR;
29119   if (memberMask & gridHasXValsFlag)
29120     {
29121       size = irregular ? gridP->size : gridP->x.size;
29122 
29123       gridP->x.vals = (double *) Malloc(size * sizeof (double));
29124       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29125                       gridP->x.vals, size, CDI_DATATYPE_FLT64, context);
29126       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29127                       &d, 1, CDI_DATATYPE_UINT32, context);
29128       xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->x.vals) == d );
29129     }
29130 
29131   if (memberMask & gridHasYValsFlag)
29132     {
29133       size = irregular ? gridP->size : gridP->y.size;
29134 
29135       gridP->y.vals = (double *) Malloc(size * sizeof (double));
29136       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29137                       gridP->y.vals, size, CDI_DATATYPE_FLT64, context);
29138       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29139                       &d, 1, CDI_DATATYPE_UINT32, context);
29140       xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->y.vals) == d);
29141     }
29142 
29143   if (memberMask & gridHasAreaFlag)
29144     {
29145       size = gridP->size;
29146       xassert(size);
29147       gridP->area = (double *) Malloc(size * sizeof (double));
29148       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29149                       gridP->area, size, CDI_DATATYPE_FLT64, context);
29150       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29151                       &d, 1, CDI_DATATYPE_UINT32, context);
29152       xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->area) == d);
29153     }
29154 
29155   if (memberMask & gridHasXBoundsFlag)
29156     {
29157       size = gridP->nvertex * (irregular ? gridP->size : gridP->x.size);
29158       xassert(size);
29159 
29160       gridP->x.bounds = (double *) Malloc(size * sizeof (double));
29161       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29162                       gridP->x.bounds, size, CDI_DATATYPE_FLT64, context);
29163       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29164                       &d, 1, CDI_DATATYPE_UINT32, context);
29165       xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->x.bounds) == d);
29166     }
29167 
29168   if (memberMask & gridHasYBoundsFlag)
29169     {
29170       size = gridP->nvertex * (irregular ? gridP->size : gridP->y.size);
29171       xassert(size);
29172 
29173       gridP->y.bounds = (double *) Malloc(size * sizeof (double));
29174       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29175 			  gridP->y.bounds, size, CDI_DATATYPE_FLT64, context);
29176       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29177                       &d, 1, CDI_DATATYPE_UINT32, context);
29178       xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->y.bounds) == d);
29179     }
29180 
29181   serializeKeysUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos, &gridP->keys, context);
29182   serializeKeysUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos, &gridP->x.keys, context);
29183   serializeKeysUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos, &gridP->y.keys, context);
29184 
29185   if (memberMask & gridHasMaskFlag)
29186     {
29187       xassert((size = gridP->size));
29188       gridP->mask = (mask_t *) Malloc(size * sizeof (mask_t));
29189       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29190                       gridP->mask, gridP->size, CDI_DATATYPE_UCHAR, context);
29191       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29192                       &d, 1, CDI_DATATYPE_UINT32, context);
29193       xassert(cdiCheckSum(CDI_DATATYPE_UCHAR, gridP->size, gridP->mask) == d);
29194     }
29195 
29196   if (memberMask & gridHasGMEMaskFlag)
29197     {
29198       xassert((size = gridP->size));
29199       gridP->mask_gme = (mask_t *) Malloc(size * sizeof (mask_t));
29200       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29201                       gridP->mask_gme, gridP->size, CDI_DATATYPE_UCHAR, context);
29202       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
29203                       &d, 1, CDI_DATATYPE_UINT32, context);
29204       xassert(cdiCheckSum(CDI_DATATYPE_UCHAR, gridP->size, gridP->mask_gme) == d);
29205     }
29206 
29207   reshSetStatus(gridP->self, &gridOps,
29208                 reshGetStatus(gridP->self, &gridOps) & ~RESH_SYNC_BIT);
29209 }
29210 
29211 
29212 static void
gridPack(void * voidP,void * packBuffer,int packBufferSize,int * packBufferPos,void * context)29213 gridPack(void * voidP, void * packBuffer, int packBufferSize,
29214          int * packBufferPos, void *context)
29215 {
29216   grid_t   * gridP = ( grid_t * )   voidP;
29217   int size;
29218   uint32_t d;
29219   int memberMask;
29220 
29221   {
29222     int intBuffer[gridNint];
29223 
29224     intBuffer[GRID_PACK_INT_IDX_SELF]         = gridP->self;
29225     intBuffer[GRID_PACK_INT_IDX_TYPE]         = gridP->type;
29226     intBuffer[GRID_PACK_INT_IDX_DATATYPE]     = gridP->datatype;
29227     intBuffer[GRID_PACK_INT_IDX_IS_CYCLIC]    = gridP->isCyclic;
29228     intBuffer[GRID_PACK_INT_IDX_X_FLAG]       = gridP->x.flag;
29229     intBuffer[GRID_PACK_INT_IDX_Y_FLAG]       = gridP->y.flag;
29230     intBuffer[GRID_PACK_INT_IDX_GME_ND]       = gridP->gme.nd;
29231     intBuffer[GRID_PACK_INT_IDX_GME_NI]       = gridP->gme.ni;
29232     intBuffer[GRID_PACK_INT_IDX_GME_NI2]      = gridP->gme.ni2;
29233     intBuffer[GRID_PACK_INT_IDX_GME_NI3]      = gridP->gme.ni3;
29234     intBuffer[GRID_PACK_INT_IDX_TRUNC]        = gridP->trunc;
29235     intBuffer[GRID_PACK_INT_IDX_NVERTEX]      = gridP->nvertex;
29236     intBuffer[REDUCEDPOINTSSIZE]      = gridP->reducedPointsSize;
29237     intBuffer[GRID_PACK_INT_IDX_SIZE]         = gridP->size;
29238     intBuffer[GRID_PACK_INT_IDX_X_SIZE]       = gridP->x.size;
29239     intBuffer[GRID_PACK_INT_IDX_Y_SIZE]       = gridP->y.size;
29240     intBuffer[GRID_PACK_INT_IDX_LCOMPLEX]     = gridP->lcomplex;
29241     intBuffer[GRID_PACK_INT_IDX_MEMBERMASK]   = memberMask
29242                                               = gridGetComponentFlags(gridP);
29243 
29244     serializePack(intBuffer, gridNint, CDI_DATATYPE_INT,
29245                   packBuffer, packBufferSize, packBufferPos, context);
29246     d = cdiCheckSum(CDI_DATATYPE_INT, gridNint, intBuffer);
29247     serializePack(&d, 1, CDI_DATATYPE_UINT32,
29248                   packBuffer, packBufferSize, packBufferPos, context);
29249   }
29250 
29251   if (memberMask & gridHasReducedPointsFlag)
29252     {
29253       size = gridP->reducedPointsSize;
29254       xassert(size > 0);
29255       serializePack(gridP->reducedPoints, size, CDI_DATATYPE_INT,
29256                     packBuffer, packBufferSize, packBufferPos, context);
29257       d = cdiCheckSum(CDI_DATATYPE_INT , size, gridP->reducedPoints);
29258       serializePack(&d, 1, CDI_DATATYPE_UINT32,
29259                     packBuffer, packBufferSize, packBufferPos, context);
29260     }
29261 
29262   {
29263     double doubleBuffer[gridNdouble];
29264 
29265     doubleBuffer[GRID_PACK_DBL_IDX_X_FIRST] = gridP->x.first;
29266     doubleBuffer[GRID_PACK_DBL_IDX_Y_FIRST] = gridP->y.first;
29267     doubleBuffer[GRID_PACK_DBL_IDX_X_LAST]  = gridP->x.last;
29268     doubleBuffer[GRID_PACK_DBL_IDX_Y_LAST]  = gridP->y.last;
29269     doubleBuffer[GRID_PACK_DBL_IDX_X_INC]   = gridP->x.inc;
29270     doubleBuffer[GRID_PACK_DBL_IDX_Y_INC]   = gridP->y.inc;
29271 
29272     serializePack(doubleBuffer, gridNdouble, CDI_DATATYPE_FLT64,
29273                   packBuffer, packBufferSize, packBufferPos, context);
29274     d = cdiCheckSum(CDI_DATATYPE_FLT, gridNdouble, doubleBuffer);
29275     serializePack(&d, 1, CDI_DATATYPE_UINT32,
29276                   packBuffer, packBufferSize, packBufferPos, context);
29277   }
29278 
29279   if (memberMask & gridHasXValsFlag)
29280     {
29281       if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
29282 	size = gridP->size;
29283       else
29284 	size = gridP->x.size;
29285       xassert(size);
29286 
29287       const double *gridP_xvals = gridP->vtable->inqXValsPtr(gridP);
29288       serializePack(gridP_xvals, size, CDI_DATATYPE_FLT64,
29289                     packBuffer, packBufferSize, packBufferPos, context);
29290       d = cdiCheckSum(CDI_DATATYPE_FLT, size, gridP_xvals);
29291       serializePack(&d, 1, CDI_DATATYPE_UINT32,
29292                     packBuffer, packBufferSize, packBufferPos, context);
29293     }
29294 
29295   if (memberMask & gridHasYValsFlag)
29296     {
29297       if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR )
29298 	size = gridP->size;
29299       else
29300 	size = gridP->y.size;
29301       xassert(size);
29302       const double *gridP_yvals = gridP->vtable->inqYValsPtr(gridP);
29303       serializePack(gridP_yvals, size, CDI_DATATYPE_FLT64,
29304                     packBuffer, packBufferSize, packBufferPos, context);
29305       d = cdiCheckSum(CDI_DATATYPE_FLT, size, gridP_yvals);
29306       serializePack(&d, 1, CDI_DATATYPE_UINT32,
29307                     packBuffer, packBufferSize, packBufferPos, context);
29308     }
29309 
29310   if (memberMask & gridHasAreaFlag)
29311     {
29312       xassert(gridP->size);
29313 
29314       serializePack(gridP->area, gridP->size, CDI_DATATYPE_FLT64,
29315                     packBuffer, packBufferSize, packBufferPos, context);
29316       d = cdiCheckSum(CDI_DATATYPE_FLT, gridP->size, gridP->area);
29317       serializePack(&d, 1, CDI_DATATYPE_UINT32,
29318                     packBuffer, packBufferSize, packBufferPos, context);
29319     }
29320 
29321   if (memberMask & gridHasXBoundsFlag)
29322     {
29323       xassert ( gridP->nvertex );
29324       if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
29325 	size = gridP->nvertex * gridP->size;
29326       else
29327 	size = gridP->nvertex * gridP->x.size;
29328       xassert ( size );
29329 
29330       serializePack(gridP->x.bounds, size, CDI_DATATYPE_FLT64,
29331                     packBuffer, packBufferSize, packBufferPos, context);
29332       d = cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->x.bounds);
29333       serializePack(&d, 1, CDI_DATATYPE_UINT32,
29334                     packBuffer, packBufferSize, packBufferPos, context);
29335     }
29336 
29337   if (memberMask & gridHasYBoundsFlag)
29338     {
29339       xassert(gridP->nvertex);
29340       if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
29341 	size = gridP->nvertex * gridP->size;
29342       else
29343 	size = gridP->nvertex * gridP->y.size;
29344       xassert ( size );
29345 
29346       serializePack(gridP->y.bounds, size, CDI_DATATYPE_FLT64,
29347                     packBuffer, packBufferSize, packBufferPos, context);
29348       d = cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->y.bounds);
29349       serializePack(&d, 1, CDI_DATATYPE_UINT32,
29350                     packBuffer, packBufferSize, packBufferPos, context);
29351     }
29352 
29353   serializeKeysPack(&gridP->keys, packBuffer, packBufferSize, packBufferPos, context);
29354   serializeKeysPack(&gridP->x.keys, packBuffer, packBufferSize, packBufferPos, context);
29355   serializeKeysPack(&gridP->y.keys, packBuffer, packBufferSize, packBufferPos, context);
29356 
29357   if (memberMask & gridHasMaskFlag)
29358     {
29359       xassert((size = gridP->size));
29360       serializePack(gridP->mask, size, CDI_DATATYPE_UCHAR,
29361                     packBuffer, packBufferSize, packBufferPos, context);
29362       d = cdiCheckSum(CDI_DATATYPE_UCHAR, size, gridP->mask);
29363       serializePack(&d, 1, CDI_DATATYPE_UINT32,
29364                     packBuffer, packBufferSize, packBufferPos, context);
29365     }
29366 
29367   if (memberMask & gridHasGMEMaskFlag)
29368     {
29369       xassert((size = gridP->size));
29370 
29371       serializePack(gridP->mask_gme, size, CDI_DATATYPE_UCHAR,
29372                     packBuffer, packBufferSize, packBufferPos, context);
29373       d = cdiCheckSum(CDI_DATATYPE_UCHAR, size, gridP->mask_gme);
29374       serializePack(&d, 1, CDI_DATATYPE_UINT32,
29375                     packBuffer, packBufferSize, packBufferPos, context);
29376     }
29377 }
29378 
29379 
29380 struct gridCompareSearchState
29381 {
29382   int resIDValue;
29383   const grid_t *queryKey;
29384 };
29385 
29386 static enum cdiApplyRet
gridCompareSearch(int id,void * res,void * data)29387 gridCompareSearch(int id, void *res, void *data)
29388 {
29389   struct gridCompareSearchState *state = (struct gridCompareSearchState*)data;
29390   (void)res;
29391   if ( gridCompare(id, state->queryKey, true) == false )
29392     {
29393       state->resIDValue = id;
29394       return CDI_APPLY_STOP;
29395     }
29396   else
29397     return CDI_APPLY_GO_ON;
29398 }
29399 
29400 /* Add grid (which must be Malloc'ed to vlist if not already found) */
cdiVlistAddGridIfNew(int vlistID,grid_t * grid,int mode)29401 struct addIfNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
29402 {
29403   /*
29404     mode: 0 search in vlist and grid table
29405           1 search in grid table only
29406           2 search in grid table only and don't store the grid in vlist
29407    */
29408   bool gridglobdefined = false;
29409   bool griddefined = false;
29410   int gridID = CDI_UNDEFID;
29411   vlist_t *vlistptr = vlist_to_pointer(vlistID);
29412 
29413   unsigned ngrids = (unsigned)vlistptr->ngrids;
29414 
29415   if ( mode == 0 )
29416     for ( unsigned index = 0; index < ngrids; index++ )
29417       {
29418 	if ( (gridID = vlistptr->gridIDs[index]) != CDI_UNDEFID )
29419           {
29420             if ( gridCompare(gridID, grid, false) == false )
29421               {
29422                 griddefined = true;
29423                 break;
29424               }
29425           }
29426         else
29427           Error("Internal problem: undefined gridID in vlist %d, position %u!", vlistID, index);
29428       }
29429 
29430   if ( ! griddefined )
29431     {
29432       struct gridCompareSearchState query;
29433       query.queryKey = grid;// = { .queryKey = grid };
29434       if ( (gridglobdefined = (cdiResHFilterApply(&gridOps, gridCompareSearch, &query) == CDI_APPLY_STOP)) )
29435         gridID = query.resIDValue;
29436 
29437       if ( mode == 1 && gridglobdefined )
29438 	for ( unsigned index = 0; index < ngrids; index++ )
29439 	  if ( vlistptr->gridIDs[index] == gridID )
29440 	    {
29441 	      gridglobdefined = false;
29442 	      break;
29443 	    }
29444     }
29445 
29446   if ( ! griddefined )
29447     {
29448       if ( ! gridglobdefined )
29449         {
29450           grid->self = gridID = reshPut(grid, &gridOps);
29451           gridComplete(grid);
29452         }
29453       if ( mode < 2 )
29454         {
29455           if (ngrids >= MAX_GRIDS_PS)
29456             Error("Internal limit exceeded, MAX_GRIDS_PS=%d needs to be increased!", MAX_GRIDS_PS);
29457           vlistptr->gridIDs[ngrids] = gridID;
29458           vlistptr->ngrids++;
29459         }
29460     }
29461 
29462   return (struct addIfNewRes){ .Id = gridID, .isNew = !griddefined && !gridglobdefined };
29463 }
29464 
29465 
29466 const struct gridVirtTable cdiGridVtable
29467   = {
29468   .destroy = gridDestroyKernel,
29469   .copy = grid_copy_base,
29470   .copyScalarFields = grid_copy_base_scalar_fields,
29471   .copyArrayFields = grid_copy_base_array_fields,
29472   .defXVals = gridDefXValsSerial,
29473   .defYVals = gridDefYValsSerial,
29474   .defMask = gridDefMaskSerial,
29475   .defMaskGME = gridDefMaskGMESerial,
29476   .defXBounds = gridDefXBoundsSerial,
29477   .defYBounds = gridDefYBoundsSerial,
29478   .defArea = gridDefAreaSerial,
29479   .inqXVal = gridInqXValSerial,
29480   .inqYVal = gridInqYValSerial,
29481   .inqXVals = gridInqXValsSerial,
29482   .inqXValsPart = gridInqXValsPartSerial,
29483   .inqYVals = gridInqYValsSerial,
29484   .inqYValsPart = gridInqYValsPartSerial,
29485   .inqXValsPtr = gridInqXValsPtrSerial,
29486   .inqYValsPtr = gridInqYValsPtrSerial,
29487 #ifndef USE_MPI
29488   .inqXIsc = gridInqXIscSerial,
29489   .inqYIsc = gridInqYIscSerial,
29490   .inqXCvals = gridInqXCvalsSerial,
29491   .inqYCvals = gridInqYCvalsSerial,
29492   .inqXCvalsPtr = gridInqXCvalsPtrSerial,
29493   .inqYCvalsPtr = gridInqYCvalsPtrSerial,
29494 #endif
29495   .compareXYFull = compareXYvals,
29496   .compareXYAO = compareXYvals2,
29497   .inqArea = gridInqAreaSerial,
29498   .inqAreaPtr = gridInqAreaPtrBase,
29499   .hasArea = gridHasAreaBase,
29500   .inqMask = gridInqMaskSerial,
29501   .inqMaskGME = gridInqMaskGMESerial,
29502   .inqXBounds = gridInqXBoundsSerial,
29503   .inqYBounds = gridInqYBoundsSerial,
29504   .inqXBoundsPtr = gridInqXBoundsPtrSerial,
29505   .inqYBoundsPtr = gridInqYBoundsPtrSerial,
29506 };
29507 
29508 /*
29509  * Local Variables:
29510  * c-file-style: "Java"
29511  * c-basic-offset: 2
29512  * indent-tabs-mode: nil
29513  * show-trailing-whitespace: t
29514  * require-trailing-newline: t
29515  * End:
29516  */
29517 #include <stdio.h>
29518 #include <stdlib.h>
29519 #include <string.h>
29520 #include <ctype.h>
29521 
29522 
29523 
29524 static int initIegLib      = 0;
29525 static int iegDefaultDprec = 0;
29526 
29527 
29528 /*
29529  * A version string.
29530  */
29531 #undef  LIBVERSION
29532 #define LIBVERSION      1.4.1
29533 #define XSTRING(x)	#x
29534 #define STRING(x)	XSTRING(x)
29535 static const char ieg_libvers[] = STRING(LIBVERSION);
29536 
iegLibraryVersion(void)29537 const char *iegLibraryVersion(void)
29538 {
29539   return ieg_libvers;
29540 }
29541 
29542 
29543 static int IEG_Debug = 0;    /* If set to 1, debugging */
29544 
29545 static
iegLibInit(void)29546 void iegLibInit(void)
29547 {
29548   const char *envName = "IEG_PRECISION";
29549 
29550   char *envString = getenv(envName);
29551   if ( envString )
29552     {
29553       int nrun = (strlen(envString) == 2) ? 1 : 2;
29554 
29555       int pos = 0;
29556       while ( nrun-- )
29557 	{
29558 	  switch ( tolower((int) envString[pos]) )
29559 	    {
29560 	    case 'r':
29561 	      {
29562 		switch ( (int) envString[pos+1] )
29563 		  {
29564 		  case '4': iegDefaultDprec = EXSE_SINGLE_PRECISION; break;
29565 		  case '8': iegDefaultDprec = EXSE_DOUBLE_PRECISION; break;
29566 		  default:
29567 		    Message("Invalid digit in %s: %s", envName, envString);
29568 		  }
29569 		break;
29570 	      }
29571 	    default:
29572               {
29573                 Message("Invalid character in %s: %s", envName, envString);
29574                 break;
29575               }
29576             }
29577 	  pos += 2;
29578 	}
29579     }
29580 
29581   initIegLib = 1;
29582 }
29583 
29584 
iegDebug(int debug)29585 void iegDebug(int debug)
29586 {
29587   IEG_Debug = debug;
29588   if (IEG_Debug) Message("debug level %d", debug);
29589 }
29590 
29591 static
iegInit(iegrec_t * iegp)29592 void iegInit(iegrec_t *iegp)
29593 {
29594   iegp->checked    = 0;
29595   iegp->byteswap   = 0;
29596   iegp->dprec      = 0;
29597   iegp->refval     = 0;
29598   iegp->datasize   = 0;
29599   iegp->buffersize = 0;
29600   iegp->buffer     = NULL;
29601 }
29602 
29603 
iegInitMem(void * ieg)29604 void iegInitMem(void *ieg)
29605 {
29606   iegrec_t *iegp = (iegrec_t *) ieg;
29607 
29608   memset(iegp->ipdb, 0, sizeof(iegp->ipdb));
29609   memset(iegp->igdb, 0, sizeof(iegp->igdb));
29610   memset(iegp->vct,  0, sizeof(iegp->vct));
29611 }
29612 
29613 
iegNew(void)29614 void *iegNew(void)
29615 {
29616   if ( ! initIegLib ) iegLibInit();
29617 
29618   iegrec_t *iegp = (iegrec_t *) Malloc(sizeof(iegrec_t));
29619 
29620   iegInit(iegp);
29621   iegInitMem(iegp);
29622 
29623   return (void*)iegp;
29624 }
29625 
29626 
iegDelete(void * ieg)29627 void iegDelete(void *ieg)
29628 {
29629   iegrec_t *iegp = (iegrec_t *) ieg;
29630 
29631   if ( iegp )
29632     {
29633       if ( iegp->buffer ) Free(iegp->buffer);
29634       Free(iegp);
29635     }
29636 }
29637 
29638 
iegCheckFiletype(int fileID,int * swap)29639 int iegCheckFiletype(int fileID, int *swap)
29640 {
29641   size_t data = 0;
29642   size_t dimx = 0, dimy = 0;
29643   size_t fact = 0;
29644   unsigned char buffer[1048], *pbuf;
29645 
29646   if ( fileRead(fileID, buffer, 4) != 4 ) return 0;
29647 
29648   size_t blocklen  = get_UINT32(buffer);
29649   size_t sblocklen = get_SUINT32(buffer);
29650 
29651   if ( IEG_Debug ) Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
29652 
29653   if ( blocklen == 636 || blocklen == 640 )
29654     {
29655      *swap = 0;
29656       fact = 4;
29657       if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return 0;
29658       pbuf = buffer+(37+4)*4;    dimx = (size_t) get_UINT32(pbuf);
29659       pbuf = buffer+(37+5)*4;    dimy = (size_t) get_UINT32(pbuf);
29660       pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
29661     }
29662   else if ( blocklen == 1040 || blocklen == 1036 )
29663     {
29664      *swap = 0;
29665       fact = 8;
29666       if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return 0;
29667       pbuf = buffer+(37+4)*4;    dimx = (size_t) get_UINT32(pbuf);
29668       pbuf = buffer+(37+5)*4;    dimy = (size_t) get_UINT32(pbuf);
29669       pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
29670     }
29671   else if ( sblocklen == 636 || sblocklen == 640 )
29672     {
29673      *swap = 1;
29674       fact = 4;
29675       if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return 0;
29676       pbuf = buffer+(37+4)*4;     dimx = (size_t) get_SUINT32(pbuf);
29677       pbuf = buffer+(37+5)*4;     dimy = (size_t) get_SUINT32(pbuf);
29678       pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
29679     }
29680   else if ( sblocklen == 1040 || sblocklen == 1036 )
29681     {
29682      *swap = 1;
29683       fact = 8;
29684       if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return 0;
29685       pbuf = buffer+(37+4)*4;     dimx = (size_t) get_SUINT32(pbuf);
29686       pbuf = buffer+(37+5)*4;     dimy = (size_t) get_SUINT32(pbuf);
29687       pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
29688     }
29689 
29690   fileRewind(fileID);
29691 
29692   if ( IEG_Debug )
29693     {
29694       Message("swap = %d fact = %d", *swap, fact);
29695       Message("dimx = %lu dimy = %lu data = %lu", dimx, dimy, data);
29696     }
29697 
29698   int found = data && (dimx*dimy*fact == data || dimx*dimy*8 == data);
29699   return found;
29700 }
29701 
29702 
iegCopyMeta(void * dieg,void * sieg)29703 void iegCopyMeta(void *dieg, void *sieg)
29704 {
29705   iegrec_t *diegp = (iegrec_t *) dieg;
29706   iegrec_t *siegp = (iegrec_t *) sieg;
29707 
29708   /*  diegp->byteswap = siegp->byteswap; */
29709   diegp->dprec    = siegp->dprec;
29710   diegp->refval   = siegp->refval;
29711 
29712   memcpy(diegp->ipdb, siegp->ipdb, sizeof(siegp->ipdb));
29713   memcpy(diegp->igdb, siegp->igdb, sizeof(siegp->igdb));
29714   memcpy(diegp->vct,  siegp->vct,  sizeof(siegp->vct));
29715 }
29716 
29717 static
iegInqData(void * ieg,int prec,void * data)29718 int iegInqData(void *ieg, int prec, void *data)
29719 {
29720   iegrec_t *iegp = (iegrec_t *) ieg;
29721   int ierr = 0;
29722   int byteswap = iegp->byteswap;
29723   size_t datasize = iegp->datasize;
29724   void *buffer = iegp->buffer;
29725   int dprec = iegp->dprec;
29726 
29727   switch ( dprec )
29728     {
29729     case EXSE_SINGLE_PRECISION:
29730       {
29731 	if ( sizeof(FLT32) == 4 )
29732 	  {
29733 	    if ( byteswap ) swap4byte(buffer, datasize);
29734 
29735 	    if ( dprec == prec )
29736 	      memcpy(data, buffer, datasize*sizeof(FLT32));
29737 	    else
29738               {
29739                 const float *restrict p = (float *)buffer;
29740                 double *restrict q = (double *)data;
29741                 for (size_t i = 0; i < datasize; i++) q[i] = p[i];
29742               }
29743 	  }
29744 	else
29745 	  {
29746 	    Error("not implemented for %d byte float", sizeof(FLT32));
29747 	  }
29748 	break;
29749       }
29750     case EXSE_DOUBLE_PRECISION:
29751 	if ( sizeof(FLT64) == 8 )
29752 	  {
29753 	    if ( byteswap ) swap8byte(buffer, datasize);
29754 
29755 	    if ( dprec == prec )
29756 	      memcpy(data, buffer, datasize*sizeof(FLT64));
29757 	    else
29758               {
29759                 const double *restrict p = (double *)buffer;
29760                 float *restrict q = (float *)data;
29761                 for (size_t i = 0; i < datasize; i++) q[i] = (float)p[i];
29762               }
29763 	  }
29764 	else
29765 	  {
29766 	    Error("not implemented for %d byte float", sizeof(FLT64));
29767 	  }
29768 	break;
29769     default:
29770       {
29771 	Error("unexpected data precision %d", dprec);
29772         break;
29773       }
29774     }
29775 
29776   return ierr;
29777 }
29778 
29779 
iegInqDataSP(void * ieg,float * data)29780 int iegInqDataSP(void *ieg, float *data)
29781 {
29782   return iegInqData(ieg, EXSE_SINGLE_PRECISION, (void *) data);
29783 }
29784 
29785 
iegInqDataDP(void * ieg,double * data)29786 int iegInqDataDP(void *ieg, double *data)
29787 {
29788   return iegInqData(ieg, EXSE_DOUBLE_PRECISION, (void *) data);
29789 }
29790 
29791 
29792 static int
iegDefData(iegrec_t * iegp,int prec,const void * data)29793 iegDefData(iegrec_t *iegp, int prec, const void *data)
29794 {
29795   int dprec = iegDefaultDprec ? iegDefaultDprec : iegp->dprec;
29796   iegp->dprec = dprec ? dprec : prec;
29797 
29798   size_t datasize = (size_t)IEG_G_NumLon(iegp->igdb) * (size_t)IEG_G_NumLat(iegp->igdb);
29799   size_t blocklen = datasize * (size_t)dprec;
29800 
29801   iegp->datasize = datasize;
29802 
29803   void *buffer = iegp->buffer;
29804   size_t buffersize = iegp->buffersize;
29805   if ( buffersize != blocklen )
29806     {
29807       buffersize = blocklen;
29808       buffer = Realloc(buffer, buffersize);
29809       iegp->buffer = buffer;
29810       iegp->buffersize = buffersize;
29811     }
29812 
29813   switch ( dprec )
29814     {
29815     case EXSE_SINGLE_PRECISION:
29816       {
29817 	if ( dprec == prec )
29818 	  memcpy(buffer, data, datasize*sizeof(FLT32));
29819 	else
29820           {
29821             const double *restrict p = (const double *)data;
29822             float *restrict q = (float *)buffer;
29823             for (size_t i = 0; i < datasize; i++) q[i] = (float)p[i];
29824           }
29825 	break;
29826       }
29827     case EXSE_DOUBLE_PRECISION:
29828       {
29829 	if ( dprec == prec )
29830 	  memcpy(buffer, data, datasize*sizeof(FLT64));
29831 	else
29832           {
29833             const float *restrict p = (const float *)data;
29834             double *restrict q = (double *)buffer;
29835             for ( size_t i = 0; i < datasize; i++) q[i] = p[i];
29836           }
29837 	break;
29838       }
29839     default:
29840       {
29841 	Error("unexpected data precision %d", dprec);
29842         break;
29843       }
29844     }
29845 
29846   return 0;
29847 }
29848 
29849 
iegDefDataSP(void * ieg,const float * data)29850 int iegDefDataSP(void *ieg, const float *data)
29851 {
29852   return iegDefData((iegrec_t *)ieg, EXSE_SINGLE_PRECISION, (void *) data);
29853 }
29854 
29855 
iegDefDataDP(void * ieg,const double * data)29856 int iegDefDataDP(void *ieg, const double *data)
29857 {
29858   return iegDefData((iegrec_t *)ieg, EXSE_DOUBLE_PRECISION, (void *) data);
29859 }
29860 
29861 
iegRead(int fileID,void * ieg)29862 int iegRead(int fileID, void *ieg)
29863 {
29864   iegrec_t *iegp = (iegrec_t *) ieg;
29865   union { double d[200]; float f[200]; int32_t i32[200]; } buf;
29866 
29867   if ( ! iegp->checked )
29868     {
29869       int status = iegCheckFiletype(fileID, &iegp->byteswap);
29870       if ( status == 0 ) Error("Not a IEG file!");
29871       iegp->checked = 1;
29872     }
29873 
29874   int byteswap = iegp->byteswap;
29875 
29876   /* read header record */
29877   size_t blocklen = binReadF77Block(fileID, byteswap);
29878 
29879   if ( fileEOF(fileID) ) return -1;
29880 
29881   if ( IEG_Debug )
29882     Message("blocklen = %lu", blocklen);
29883 
29884   int dprec = 0;
29885   if ( blocklen == 636 || blocklen == 640 )
29886     dprec = 4;
29887   else if ( blocklen == 1040 || blocklen == 1036 )
29888     dprec = 8;
29889   else
29890     {
29891       Warning("unexpecteted header size %d!", (int) blocklen);
29892       return -1;
29893     }
29894 
29895   iegp->dprec = dprec;
29896 
29897   binReadInt32(fileID, byteswap, 37, buf.i32);
29898   for ( size_t i = 0; i < 37; i++ ) iegp->ipdb[i] = (int)buf.i32[i];
29899 
29900   binReadInt32(fileID, byteswap, 18, buf.i32);
29901   for ( size_t i = 0; i < 18; i++ ) iegp->igdb[i] = (int)buf.i32[i];
29902 
29903   if ( blocklen == 636 || blocklen == 1036 )
29904     {
29905       fileRead(fileID, buf.f, 4);
29906       if ( byteswap ) swap4byte(buf.f, 1);
29907       iegp->refval = (double)buf.f[0];
29908     }
29909   else
29910     {
29911       fileRead(fileID, buf.d, 8);
29912       if ( byteswap ) swap8byte(buf.d, 1);
29913       iegp->refval = (double)buf.d[0];
29914     }
29915 
29916   binReadInt32(fileID, byteswap, 3, buf.i32);
29917   for ( size_t i = 0; i < 3; i++ ) iegp->igdb[18+i] = (int)buf.i32[i];
29918 
29919   if ( dprec == EXSE_SINGLE_PRECISION )
29920     {
29921       fileRead(fileID, buf.f, 400);
29922       if ( byteswap ) swap4byte(buf.f, 100);
29923       for ( size_t i = 0; i < 100; i++ )
29924 	iegp->vct[i] = (double)buf.f[i];
29925     }
29926   else
29927     {
29928       fileRead(fileID, buf.d, 800);
29929       if ( byteswap ) swap8byte(buf.d, 100);
29930       for ( size_t i = 0; i < 100; i++ )
29931 	iegp->vct[i] = buf.d[i];
29932     }
29933 
29934   size_t blocklen2 = binReadF77Block(fileID, byteswap);
29935 
29936   if ( blocklen2 != blocklen )
29937     {
29938       Warning("header blocklen differ!");
29939       return -1;
29940     }
29941 
29942   size_t datasize = iegp->datasize
29943     = (size_t)IEG_G_NumLon(iegp->igdb) * (size_t)IEG_G_NumLat(iegp->igdb);
29944 
29945   if ( IEG_Debug ) Message("datasize = %lu", iegp->datasize);
29946 
29947   blocklen = binReadF77Block(fileID, byteswap);
29948 
29949   void *buffer = iegp->buffer;
29950   if ( iegp->buffersize < blocklen )
29951     {
29952       iegp->buffer = buffer = Realloc(buffer, blocklen);
29953       iegp->buffersize = blocklen;
29954     }
29955 
29956   if ( dprec != (int) (blocklen/datasize) )
29957     {
29958       Warning("data precision differ! (h = %d; d = %d)",
29959 	      (int) dprec, (int) (blocklen/datasize));
29960       return -1;
29961     }
29962 
29963   fileRead(fileID, buffer, blocklen);
29964 
29965   blocklen2 = binReadF77Block(fileID, byteswap);
29966 
29967   if ( blocklen2 != blocklen )
29968     {
29969       Warning("data blocklen differ!");
29970       return -1;
29971     }
29972 
29973   return 0;
29974 }
29975 
29976 
iegWrite(int fileID,void * ieg)29977 int iegWrite(int fileID, void *ieg)
29978 {
29979   iegrec_t *iegp = (iegrec_t *) ieg;
29980   union { INT32 i32[200]; float fvct[100]; } buf;
29981   int dprec  = iegp->dprec;
29982   int byteswap = iegp->byteswap;
29983 
29984   /* write header record */
29985   size_t blocklen = ( dprec == EXSE_SINGLE_PRECISION ) ? 636 : 1040;
29986 
29987   binWriteF77Block(fileID, byteswap, blocklen);
29988 
29989   for ( size_t i = 0; i < 37; i++ ) buf.i32[i] = (INT32) iegp->ipdb[i];
29990   binWriteInt32(fileID, byteswap, 37, buf.i32);
29991 
29992   for ( size_t i = 0; i < 18; i++ ) buf.i32[i] = (INT32) iegp->igdb[i];
29993   binWriteInt32(fileID, byteswap, 18, buf.i32);
29994 
29995   FLT64 refval = (FLT64)iegp->refval;
29996   FLT32 refvalf = (FLT32)iegp->refval;
29997   if ( dprec == EXSE_SINGLE_PRECISION )
29998     binWriteFlt32(fileID, byteswap, 1, &refvalf);
29999   else
30000     binWriteFlt64(fileID, byteswap, 1, &refval);
30001 
30002   for ( size_t i = 0; i < 3; i++ ) buf.i32[i] = (INT32) iegp->igdb[18+i];
30003   binWriteInt32(fileID, byteswap, 3, buf.i32);
30004 
30005   if ( dprec == EXSE_SINGLE_PRECISION )
30006     {
30007       for ( size_t i = 0; i < 100; i++ ) buf.fvct[i] = (float) iegp->vct[i];
30008       binWriteFlt32(fileID, byteswap, 100, buf.fvct);
30009     }
30010   else
30011     {
30012       binWriteFlt64(fileID, byteswap, 100, iegp->vct);
30013     }
30014 
30015   binWriteF77Block(fileID, byteswap, blocklen);
30016 
30017   size_t datasize = (size_t)iegp->igdb[4] * (size_t)iegp->igdb[5];
30018   blocklen = datasize * (size_t)dprec;
30019 
30020   binWriteF77Block(fileID, byteswap, blocklen);
30021 
30022   iegp->datasize = datasize;
30023 
30024   void *buffer = iegp->buffer;
30025 
30026   switch ( dprec )
30027     {
30028     case EXSE_SINGLE_PRECISION:
30029       {
30030 	binWriteFlt32(fileID, byteswap, datasize, (FLT32 *) buffer);
30031 	break;
30032       }
30033     case EXSE_DOUBLE_PRECISION:
30034       {
30035 	binWriteFlt64(fileID, byteswap, datasize, (FLT64 *) buffer);
30036 	break;
30037       }
30038     default:
30039       {
30040 	Error("unexpected data precision %d", dprec);
30041         break;
30042       }
30043     }
30044 
30045   binWriteF77Block(fileID, byteswap, blocklen);
30046 
30047   return 0;
30048 }
30049 /*
30050  * Local Variables:
30051  * c-file-style: "Java"
30052  * c-basic-offset: 2
30053  * indent-tabs-mode: nil
30054  * show-trailing-whitespace: t
30055  * require-trailing-newline: t
30056  * End:
30057  */
30058 #ifndef INCLUDE_GUARD_CDI_REFERENCE_COUNTING
30059 #define INCLUDE_GUARD_CDI_REFERENCE_COUNTING
30060 
30061 
30062 #include <sys/types.h>
30063 #include <stdlib.h>
30064 
30065 /*
30066 This is a base class for all objects that need reference counting.
30067 A CdiReferencedObject has a reference count of one when it is constructed, refObjectRetain() increments the reference count, refObject Release() decrements it.
30068 When the reference count reaches zero, the destructor function is called before the memory of the object is deallocated with Free().
30069 
30070 >>> Warning <<<
30071 This code is currently not thread-safe.
30072 
30073 We are currently using the C99 standard, which does not have atomic types.
30074 Also, there are still tons of systems out there that have a gcc without wrong C11 atomics support
30075 (__STDC_NO_ATOMICS__ not defined even though stdatomics.h is not even present).
30076 Consequently, it is impossible to write preprocessor code to even check for the presence of atomic types.
30077 So, we have two options: provide multithreading support by means of locks, or wait a year or two before doing this right.
30078 I, for one, prefer doing things right.
30079 */
30080 typedef struct CdiReferencedObject CdiReferencedObject;
30081 struct CdiReferencedObject {
30082   //protected:
30083     void (*destructor)(CdiReferencedObject* me);  //Subclass constructors should set this to their own destructor.
30084 
30085   //private:    //Subclasses may read it to determine whether there is only one reference, though.
30086     size_t refCount;
30087 };
30088 
30089 void cdiRefObject_construct(CdiReferencedObject* me);
30090 void cdiRefObject_retain(CdiReferencedObject* me);
30091 void cdiRefObject_release(CdiReferencedObject* me);
30092 void cdiRefObject_destruct(CdiReferencedObject* me);
30093 
30094 #endif
30095 
30096 /*
30097  * Local Variables:
30098  * c-file-style: "Java"
30099  * c-basic-offset: 2
30100  * indent-tabs-mode: nil
30101  * show-trailing-whitespace: t
30102  * require-trailing-newline: t
30103  * End:
30104  */
30105 #ifndef INCLUDE_GUARD_CDI_GRIB_FILE_H
30106 #define INCLUDE_GUARD_CDI_GRIB_FILE_H
30107 
30108 
30109 /*
30110 CdiInputFile is a file abstraction that allows accessing an input file through any number of channels:
30111 It is reference counted, so that it is closed at the right place,
30112 and it is stateless, so that accesses from different callers cannot interfere with each other.
30113 Once the reference counting code is threadsafe, CdiInputFile will also be threadsafe.
30114 */
30115 typedef struct CdiInputFile {
30116   //public:
30117     CdiReferencedObject super;
30118 
30119   //private:
30120     char* path;
30121     int fileDescriptor;
30122 } CdiInputFile;
30123 
30124 //Final class, the constructor is private and not defined here.
30125 CdiInputFile* cdiInputFile_make(const char* path);   //The caller is responsible to call cdiRefObject_release() on the returned object.
30126 int cdiInputFile_read(const CdiInputFile* me, off_t readPosition, size_t readSize, size_t* outActualReadSize, void* buffer);       //Returns one of CDI_EINVAL, CDI_ESYSTEM, CDI_EEOF, OR CDI_NOERR.
30127 /* Returns path string, don't use after destruction of CdiInputFile
30128  * object */
30129 const char* cdiInputFile_getPath(const CdiInputFile* me);
30130 //Destructor is private as well.
30131 
30132 #endif
30133 
30134 /*
30135  * Local Variables:
30136  * c-file-style: "Java"
30137  * c-basic-offset: 2
30138  * indent-tabs-mode: nil
30139  * show-trailing-whitespace: t
30140  * require-trailing-newline: t
30141  * End:
30142  */
30143 #define _XOPEN_SOURCE 600
30144 
30145 
30146 #include <errno.h>
30147 #include <fcntl.h>
30148 #include <pthread.h>
30149 #include <string.h>
30150 #include <unistd.h>
30151 
30152 static void cdiInputFile_destruct(CdiInputFile* me);
30153 
30154 //For an explanation of the condestruct() pattern, see the comment in iterator_grib.c
30155 //path != NULL -> construction
30156 //path = NULL -> destruction
cdiInputFile_condestruct(CdiInputFile * me,const char * path)30157 static CdiInputFile* cdiInputFile_condestruct(CdiInputFile* me, const char* path)
30158 {
30159   #define super() (&me->super)
30160   if(!path) goto destruct;
30161   cdiRefObject_construct(super());
30162   me->path = strdup(path);
30163   if(!me->path) goto destructSuper;
30164   do
30165     {
30166       me->fileDescriptor = open(me->path, O_RDONLY);
30167     }
30168   while(me->fileDescriptor == -1 && (errno == EINTR || errno == EAGAIN));
30169   if(me->fileDescriptor == -1) goto freePath;
30170   //construction successfull, now we can set our own destructor
30171   super()->destructor = (void(*)(CdiReferencedObject*))cdiInputFile_destruct;
30172   goto success;
30173 
30174 // ^        constructor code       ^
30175 // |                               |
30176 // v destructor/error-cleanup code v
30177 
30178 destruct:
30179   close(me->fileDescriptor);
30180 freePath:
30181   Free(me->path);
30182 destructSuper:
30183   cdiRefObject_destruct(super());
30184   me = NULL;
30185 
30186 success:
30187   return me;
30188   #undef super
30189 }
30190 
30191 static CdiInputFile **openFileList = NULL;
30192 static size_t openFileCount = 0, openFileListSize = 0;
30193 static pthread_mutex_t openFileListLock = PTHREAD_MUTEX_INITIALIZER;
30194 
30195 //This either returns a new object, or retains and returns a preexisting open file.
cdiInputFile_make(const char * path)30196 CdiInputFile* cdiInputFile_make(const char* path)
30197 {
30198   CdiInputFile* result = NULL;
30199   xassert(path);
30200   int error = pthread_mutex_lock(&openFileListLock);
30201   xassert(!error);
30202     {
30203       //Check the list of open files for the given path.
30204       for(size_t i = openFileCount; i-- && !result; )
30205         {
30206           if(!strcmp(path, openFileList[i]->path)) result = openFileList[i];
30207         }
30208       //If no open file was found, we open one, otherwise we just retain the existing one one more time.
30209       if(result)
30210         {
30211           cdiRefObject_retain(&result->super);
30212         }
30213       else
30214         {
30215           result = (CdiInputFile *) Malloc(sizeof(*result));
30216           if(!cdiInputFile_condestruct(result, path))
30217             {
30218               //An error occured during construction, avoid a memory leak.
30219               Free(result);
30220               result = NULL;
30221             }
30222           else
30223             {
30224               //Add the new file to the list of open files.
30225               if(openFileCount == openFileListSize)
30226                 {
30227                   openFileListSize *= 2;
30228                   if(openFileListSize < 16) openFileListSize = 16;
30229                   openFileList = (CdiInputFile **) Realloc(openFileList, openFileListSize);
30230                 }
30231               xassert(openFileCount < openFileListSize);
30232               openFileList[openFileCount++] = result;
30233             }
30234         }
30235     }
30236   error = pthread_mutex_unlock(&openFileListLock);
30237   xassert(!error);
30238   return result;
30239 }
30240 
cdiInputFile_read(const CdiInputFile * me,off_t readPosition,size_t readSize,size_t * outActualReadSize,void * buffer)30241 int cdiInputFile_read(const CdiInputFile* me, off_t readPosition, size_t readSize, size_t* outActualReadSize, void* buffer)
30242 {
30243   char* byteBuffer = (char *)buffer;
30244   size_t trash;
30245   if(!outActualReadSize) outActualReadSize = &trash;
30246   *outActualReadSize = 0;
30247   while(readSize)
30248     {
30249       ssize_t bytesRead = pread(me->fileDescriptor, byteBuffer, readSize, readPosition);
30250       if(bytesRead == -1) return (errno == EINVAL) ?  CDI_EINVAL : CDI_ESYSTEM;
30251       if(bytesRead == 0) return CDI_EEOF;
30252       byteBuffer += bytesRead;
30253       readPosition += bytesRead;
30254       readSize -= (size_t)bytesRead;
30255       *outActualReadSize += (size_t)bytesRead;
30256     }
30257   return CDI_NOERR;
30258 }
30259 
cdiInputFile_getPath(const CdiInputFile * me)30260 const char* cdiInputFile_getPath(const CdiInputFile* me)
30261 {
30262   return me->path;
30263 }
30264 
cdiInputFile_destruct(CdiInputFile * me)30265 void cdiInputFile_destruct(CdiInputFile* me)
30266 {
30267   int error = pthread_mutex_lock(&openFileListLock);
30268   xassert(!error);
30269     {
30270       //Find the position of me in the list of open files.
30271       ssize_t position = (ssize_t)openFileCount;
30272       while (position > 0 && openFileList[--position] != me);
30273       //Remove me from the list
30274       openFileList[position] = openFileList[--openFileCount];
30275     }
30276   error = pthread_mutex_unlock(&openFileListLock);
30277   xassert(!error);
30278   cdiInputFile_condestruct(me, NULL);
30279 }
30280 
30281 /*
30282  * Local Variables:
30283  * c-file-style: "Java"
30284  * c-basic-offset: 2
30285  * indent-tabs-mode: nil
30286  * show-trailing-whitespace: t
30287  * require-trailing-newline: t
30288  * End:
30289  */
30290 #ifndef INSTITUTION_H
30291 #define INSTITUTION_H
30292 
30293 int
30294 instituteUnpack(void *buf, int size, int *position, int originNamespace,
30295                 void *context, int force_id);
30296 
30297 void instituteDefaultEntries(void);
30298 
30299 #endif
30300 
30301 /*
30302  * Local Variables:
30303  * c-file-style: "Java"
30304  * c-basic-offset: 2
30305  * indent-tabs-mode: nil
30306  * show-trailing-whitespace: t
30307  * require-trailing-newline: t
30308  * End:
30309  */
30310 #include <assert.h>
30311 #include <limits.h>
30312 
30313 
30314 
30315 typedef struct
30316 {
30317   int    self;
30318   int    used;
30319   int    center;
30320   int    subcenter;
30321   char  *name;
30322   char  *longname;
30323 }
30324 institute_t;
30325 
30326 
30327 static int instituteCompareKernel(institute_t *ip1, institute_t *ip2);
30328 static void instituteDestroyP(institute_t *instituteptr);
30329 static void   institutePrintP(institute_t *instituteptr, FILE * fp);
30330 static int instituteGetPackSize(institute_t *instituteptr, void *context);
30331 static void   institutePackP    ( void * instituteptr, void *buf, int size, int *position, void *context );
30332 static int    instituteTxCode   ( void );
30333 
30334 static const resOps instituteOps = {
30335   (int (*)(void *, void *))instituteCompareKernel,
30336   (void (*)(void *))instituteDestroyP,
30337   (void (*)(void *, FILE *))institutePrintP,
30338   (int (*)(void *, void *))instituteGetPackSize,
30339   institutePackP,
30340   instituteTxCode
30341 };
30342 
30343 static
instituteDefaultValue(institute_t * instituteptr)30344 void instituteDefaultValue(institute_t *instituteptr)
30345 {
30346   instituteptr->self       = CDI_UNDEFID;
30347   instituteptr->used       = 0;
30348   instituteptr->center     = CDI_UNDEFID;
30349   instituteptr->subcenter  = CDI_UNDEFID;
30350   instituteptr->name       = NULL;
30351   instituteptr->longname   = NULL;
30352 }
30353 
instituteDefaultEntries(void)30354 void instituteDefaultEntries(void)
30355 {
30356   cdiResH resH[]
30357     = { institutDef( 98,   0, "ECMWF",     "European Centre for Medium-Range Weather Forecasts"),
30358         institutDef(252,   1, "MPIMET",    "Max Planck Institute for Meteorology"),
30359         institutDef( 98, 232, "MPIMET",    "Max Planck Institute for Meteorology"),
30360         institutDef( 98, 255, "MPIMET",    "Max-Planck-Institute for Meteorology"),
30361         institutDef( 78, 255, "DWD",       "Deutscher Wetterdienst"),
30362         institutDef( 78,   0, "DWD",       "Deutscher Wetterdienst"),
30363         institutDef(215, 255, "MCH",       "MeteoSwiss"),
30364         institutDef(  7,   0, "NCEP",      "National Centers for Environmental Prediction"),
30365         institutDef(  7,   1, "NCEP",      "National Centers for Environmental Prediction"),
30366         institutDef( 60,   0, "NCAR",      "National Center for Atmospheric Research"),
30367         institutDef( 74,   0, "METOFFICE", "U.K. Met Office"),
30368         institutDef( 97,   0, "ESA",       "European Space Agency"),
30369         institutDef( 99,   0, "KNMI",      "Royal Netherlands Meteorological Institute"),
30370         institutDef( 80,   0, "CNMC",      "Reparto per la Meteorologia, Rome (REMET)"),
30371         // institutDef(  0,   0, "IPSL", "IPSL (Institut Pierre Simon Laplace, Paris, France)");
30372   };
30373 
30374   const size_t n = sizeof(resH)/sizeof(*resH);
30375   for (size_t i = 0; i < n ; i++ )
30376     reshSetStatus(resH[i], &instituteOps, RESH_IN_USE);
30377 }
30378 
30379 
30380 static int
instituteCompareKernel(institute_t * ip1,institute_t * ip2)30381 instituteCompareKernel(institute_t *ip1, institute_t *ip2)
30382 {
30383   int differ = 0;
30384 
30385   if ( ip1->name )
30386     {
30387       if ( ip1->center    > 0 && ip2->center    != ip1->center )    differ = 1;
30388       if ( ip1->subcenter > 0 && ip2->subcenter != ip1->subcenter ) differ = 1;
30389 
30390       if ( !differ )
30391         {
30392           if ( ip2->name )
30393             {
30394               const size_t len1 = strlen(ip1->name);
30395               const size_t len2 = strlen(ip2->name);
30396               if ( (len1 != len2) || memcmp(ip2->name, ip1->name, len2) ) differ = 1;
30397             }
30398         }
30399     }
30400   else if ( ip1->longname )
30401     {
30402       if ( ip2->longname )
30403         {
30404           const size_t len1 = strlen(ip1->longname);
30405           const size_t len2 = strlen(ip2->longname);
30406           if ( (len1 < len2) || memcmp(ip2->longname, ip1->longname, len2) ) differ = 1;
30407         }
30408     }
30409   else
30410     {
30411       if ( !( ip2->center    == ip1->center &&
30412               ip2->subcenter == ip1->subcenter )) differ = 1;
30413       if (ip1->subcenter > 0 && ip1->subcenter != 255 && ip2->subcenter != ip1->subcenter) differ = 1;
30414     }
30415 
30416   return differ;
30417 }
30418 
30419 
30420 struct instLoc
30421 {
30422   institute_t *ip;
30423   int id;
30424 };
30425 
30426 static enum cdiApplyRet
findInstitute(int id,void * res,void * data)30427 findInstitute(int id, void *res, void *data)
30428 {
30429   institute_t * ip1 = ((struct instLoc *)data)->ip;
30430   institute_t * ip2 = (institute_t*) res;
30431   if (ip2->used && !instituteCompareKernel(ip1, ip2))
30432     {
30433       ((struct instLoc *)data)->id = id;
30434       return CDI_APPLY_STOP;
30435     }
30436   else
30437     return CDI_APPLY_GO_ON;
30438 }
30439 
30440 
institutInq(int center,int subcenter,const char * name,const char * longname)30441 int institutInq(int center, int subcenter, const char *name, const char *longname)
30442 {
30443   institute_t * ip_ref = (institute_t *) Malloc(sizeof (*ip_ref));
30444   ip_ref->self       = CDI_UNDEFID;
30445   ip_ref->used       = 0;
30446   ip_ref->center     = center;
30447   ip_ref->subcenter  = subcenter;
30448   ip_ref->name       = name && name[0] ? (char *)name : NULL;
30449   ip_ref->longname   = longname && longname[0] ? (char *)longname : NULL;
30450 
30451   struct instLoc state = { .ip = ip_ref, .id = CDI_UNDEFID };
30452   cdiResHFilterApply(&instituteOps, findInstitute, &state);
30453 
30454   Free(ip_ref);
30455 
30456   return state.id;
30457 }
30458 
30459 static
instituteNewEntry(cdiResH resH,int center,int subcenter,const char * name,const char * longname)30460 institute_t *instituteNewEntry(cdiResH resH, int center, int subcenter,
30461                                const char *name, const char *longname)
30462 {
30463   institute_t *instituteptr = (institute_t*) Malloc(sizeof(institute_t));
30464   instituteDefaultValue(instituteptr);
30465   if (resH == CDI_UNDEFID)
30466     instituteptr->self = reshPut(instituteptr, &instituteOps);
30467   else
30468     {
30469       instituteptr->self = resH;
30470       reshReplace(resH, instituteptr, &instituteOps);
30471     }
30472   instituteptr->used = 1;
30473   instituteptr->center = center;
30474   instituteptr->subcenter = subcenter;
30475   if ( name && *name )
30476     instituteptr->name = strdupx(name);
30477   if (longname && *longname)
30478     instituteptr->longname = strdupx(longname);
30479   return  instituteptr;
30480 }
30481 
30482 
institutDef(int center,int subcenter,const char * name,const char * longname)30483 int institutDef(int center, int subcenter, const char *name, const char *longname)
30484 {
30485   institute_t *instituteptr = instituteNewEntry(CDI_UNDEFID, center, subcenter, name, longname);
30486   return instituteptr->self;
30487 }
30488 
30489 
institutInqCenter(int instID)30490 int institutInqCenter(int instID)
30491 {
30492   institute_t * instituteptr = NULL;
30493 
30494   if ( instID != CDI_UNDEFID )
30495     instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
30496 
30497   return  instituteptr ? instituteptr->center : CDI_UNDEFID;
30498 }
30499 
30500 
institutInqSubcenter(int instID)30501 int institutInqSubcenter(int instID)
30502 {
30503   institute_t * instituteptr = NULL;
30504 
30505   if ( instID != CDI_UNDEFID )
30506     instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
30507 
30508   return instituteptr ? instituteptr->subcenter: CDI_UNDEFID;
30509 }
30510 
30511 
institutInqNamePtr(int instID)30512 const char *institutInqNamePtr(int instID)
30513 {
30514   institute_t * instituteptr = NULL;
30515 
30516   if ( instID != CDI_UNDEFID )
30517     instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
30518 
30519   return instituteptr ? instituteptr->name : NULL;
30520 }
30521 
30522 
institutInqLongnamePtr(int instID)30523 const char *institutInqLongnamePtr(int instID)
30524 {
30525   institute_t * instituteptr = NULL;
30526 
30527   if ( instID != CDI_UNDEFID )
30528     instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
30529 
30530   return instituteptr ? instituteptr->longname : NULL;
30531 }
30532 
30533 static enum cdiApplyRet
activeInstitutes(int id,void * res,void * data)30534 activeInstitutes(int id, void *res, void *data)
30535 {
30536   (void)id;
30537   if (res && ((institute_t *)res)->used)
30538     ++(*(int *)data);
30539   return CDI_APPLY_GO_ON;
30540 }
30541 
institutInqNumber(void)30542 int institutInqNumber(void)
30543 {
30544   int instNum = 0;
30545 
30546   cdiResHFilterApply(&instituteOps, activeInstitutes, &instNum);
30547   return instNum;
30548 }
30549 
30550 
30551 static void
instituteDestroyP(institute_t * instituteptr)30552 instituteDestroyP(institute_t *instituteptr)
30553 {
30554   xassert(instituteptr);
30555 
30556   int instituteID = instituteptr->self;
30557   Free(instituteptr->name);
30558   Free(instituteptr->longname);
30559   reshRemove(instituteID, &instituteOps);
30560   Free(instituteptr);
30561 }
30562 
30563 
institutePrintP(institute_t * ip,FILE * fp)30564 static void institutePrintP(institute_t *ip, FILE * fp )
30565 {
30566   if (ip)
30567     fprintf(fp, "#\n"
30568             "# instituteID %d\n"
30569             "#\n"
30570             "self          = %d\n"
30571             "used          = %d\n"
30572             "center        = %d\n"
30573             "subcenter     = %d\n"
30574             "name          = %s\n"
30575             "longname      = %s\n",
30576             ip->self, ip->self, ip->used, ip->center, ip->subcenter,
30577             ip->name ? ip->name : "NN",
30578             ip->longname ? ip->longname : "NN");
30579 }
30580 
30581 
30582 static int
instituteTxCode(void)30583 instituteTxCode ( void )
30584 {
30585   return INSTITUTE;
30586 }
30587 
30588 enum {
30589   institute_nints = 5,
30590 };
30591 
instituteGetPackSize(institute_t * ip,void * context)30592 static int instituteGetPackSize(institute_t *ip, void *context)
30593 {
30594   size_t namelen = strlen(ip->name), longnamelen = strlen(ip->longname);
30595   xassert(namelen < INT_MAX && longnamelen < INT_MAX);
30596   size_t txsize = (size_t)serializeGetSize(institute_nints, CDI_DATATYPE_INT, context)
30597     + (size_t)serializeGetSize((int)namelen + 1, CDI_DATATYPE_TXT, context)
30598     + (size_t)serializeGetSize((int)longnamelen + 1, CDI_DATATYPE_TXT, context);
30599   xassert(txsize <= INT_MAX);
30600   return (int)txsize;
30601 }
30602 
institutePackP(void * instituteptr,void * buf,int size,int * position,void * context)30603 static void institutePackP(void * instituteptr, void *buf, int size, int *position, void *context)
30604 {
30605   institute_t *p = (institute_t*) instituteptr;
30606   int tempbuf[institute_nints];
30607   tempbuf[0] = p->self;
30608   tempbuf[1] = p->center;
30609   tempbuf[2] = p->subcenter;
30610   tempbuf[3] = (int)strlen(p->name) + 1;
30611   tempbuf[4] = (int)strlen(p->longname) + 1;
30612   serializePack(tempbuf, institute_nints, CDI_DATATYPE_INT, buf, size, position, context);
30613   serializePack(p->name, tempbuf[3], CDI_DATATYPE_TXT, buf, size, position, context);
30614   serializePack(p->longname, tempbuf[4], CDI_DATATYPE_TXT, buf, size, position, context);
30615 }
30616 
instituteUnpack(void * buf,int size,int * position,int originNamespace,void * context,int force_id)30617 int instituteUnpack(void *buf, int size, int *position, int originNamespace,
30618                     void *context, int force_id)
30619 {
30620   int tempbuf[institute_nints];
30621   int instituteID;
30622   serializeUnpack(buf, size, position, tempbuf, institute_nints, CDI_DATATYPE_INT, context);
30623   char *name = (char *) Malloc((size_t)tempbuf[3] + (size_t)tempbuf[4]);
30624   char *longname = name + tempbuf[3];
30625   serializeUnpack(buf, size, position, name, tempbuf[3], CDI_DATATYPE_TXT, context);
30626   serializeUnpack(buf, size, position, longname, tempbuf[4], CDI_DATATYPE_TXT, context);
30627   int targetID = namespaceAdaptKey(tempbuf[0], originNamespace);
30628   institute_t *ip = instituteNewEntry(force_id?targetID:CDI_UNDEFID,
30629                                       tempbuf[1], tempbuf[2], name, longname);
30630   instituteID = ip->self;
30631   xassert(!force_id || instituteID == targetID);
30632   Free(name);
30633   reshSetStatus(instituteID, &instituteOps,
30634                 reshGetStatus(instituteID, &instituteOps) & ~RESH_SYNC_BIT);
30635   return instituteID;
30636 }
30637 
30638 /*
30639  * Local Variables:
30640  * c-file-style: "Java"
30641  * c-basic-offset: 2
30642  * indent-tabs-mode: nil
30643  * show-trailing-whitespace: t
30644  * require-trailing-newline: t
30645  * End:
30646  */
30647 /*
30648  * This file is for the use of iterator.c and the CdiIterator subclasses only.
30649  */
30650 
30651 #ifndef INCLUDE_GUARD_CDI_ITERATOR_INT_H
30652 #define INCLUDE_GUARD_CDI_ITERATOR_INT_H
30653 
30654 
30655 #include <stdbool.h>
30656 
30657 /*
30658 class CdiIterator
30659 
30660 An iterator is an object that identifies the position of one record in a file, where a record is defined as the data belonging to one level, timestep, and variable.
30661 Using iterators to read a file can be significantly faster than using streams, because they can avoid building an index of the file.
30662 For file formats like grib that do not provide an index within the file, this makes the difference between reading the file once or reading the file twice.
30663 
30664 CdiIterator is an abstract base class. Which derived class is used depends on the type of the file. The class hierarchy currently looks like this:
30665 
30666     CdiIterator <|--+-- CdiFallbackIterator
30667                     |
30668                     +-- CdiGribIterator
30669 
30670 The fallback implementation currently uses the stream interface of CDI under the hood to provide full functionality for all filetypes for which no iterator implementation exists yet.
30671 */
30672 //TODO[NH]: Debug messages, print function.
30673 
30674 struct CdiIterator {
30675   int filetype;      //This is used to dispatch calls to the correct subclass.
30676   bool isAdvanced;    //Used to catch inquiries before the first call to CdiIteratorNextField(). //XXX: Advanced is probably not a good word (initialized?)
30677 
30678   //The metadata that can be accessed by the inquiry calls.
30679   //While theoretically redundant, these fields allow the handling of most inquiry calls within the base class.
30680   //Only the name is excempted because it needs an allocation.
30681   //These fields are set by the subclasses in the xxxIterNextField() method.
30682   int datatype, timesteptype;
30683   int gridId;
30684   CdiParam param;
30685 
30686   //The status information for reading/advancing is added in the subclasses.
30687 };
30688 
30689 void baseIterConstruct(CdiIterator *me, int filetype);
30690 const char* baseIter_constructFromString(CdiIterator *me, const char *description);     //Returns a pointer past the end of the parsed portion of the description string.
30691 void baseIterDestruct(CdiIterator *me);
30692 
30693 #endif
30694 
30695 /*
30696  * Local Variables:
30697  * c-file-style: "Java"
30698  * c-basic-offset: 2
30699  * indent-tabs-mode: nil
30700  * show-trailing-whitespace: t
30701  * require-trailing-newline: t
30702  * End:
30703  */
30704 /*
30705  * A fallback implementation of the iterator interface that opens a stream under the hood.
30706  *
30707  * This implementation is mainly available to provide iterator access to file formats that don't support iterator access natively,
30708  * nevertheless, it allows the file to dictate the order in which data is read, possibly providing performance benefits.
30709  */
30710 
30711 #ifndef INCLUDE_GUARD_CDI_ITERATOR_FALLBACK_H
30712 #define INCLUDE_GUARD_CDI_ITERATOR_FALLBACK_H
30713 
30714 #ifdef HAVE_CONFIG_H
30715 #endif
30716 
30717 #include <stdlib.h>
30718 
30719 
30720 typedef struct CdiFallbackIterator CdiFallbackIterator;
30721 
30722 CdiIterator *cdiFallbackIterator_new(const char *path, int filetype);
30723 CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *me);
30724 CdiIterator *cdiFallbackIterator_getSuper(CdiFallbackIterator *me);
30725 char *cdiFallbackIterator_serialize(CdiIterator *me);
30726 CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *me);
30727 
30728 int cdiFallbackIterator_nextField(CdiIterator *me);
30729 
30730 char *cdiFallbackIterator_inqTime(CdiIterator *me, CdiTimeType timeType);
30731 int cdiFallbackIterator_levelType(CdiIterator *me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit);
30732 int cdiFallbackIterator_level(CdiIterator *me, int levelSelector, double *outValue1, double *outValue2);
30733 int cdiFallbackIterator_zaxisUuid(CdiIterator *me, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE]);
30734 char *cdiFallbackIterator_copyVariableName(CdiIterator *me);
30735 int cdiFallbackIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute);
30736 int cdiFallbackIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount);
30737 
30738 void cdiFallbackIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
30739 void cdiFallbackIterator_readFieldF(CdiIterator *me, float *buffer, size_t *nmiss);
30740 
30741 void cdiFallbackIterator_delete(CdiIterator *super);
30742 
30743 #endif
30744 
30745 /*
30746  * Local Variables:
30747  * c-file-style: "Java"
30748  * c-basic-offset: 2
30749  * indent-tabs-mode: nil
30750  * show-trailing-whitespace: t
30751  * require-trailing-newline: t
30752  * End:
30753  */
30754 /*
30755  * An implementation of the iterator interface for GRIB files.
30756  * Since GRIB files do not contain an index, this avoids scanning the entire file to generate an in-memory index as streamOpenRead() does.
30757  * Consequently, using this interface is much more efficient for GRIB files.
30758  */
30759 
30760 #ifndef INCLUDE_GUARD_CDI_ITERATOR_GRIB_H
30761 #define INCLUDE_GUARD_CDI_ITERATOR_GRIB_H
30762 
30763 #ifdef HAVE_CONFIG_H
30764 #endif
30765 
30766 
30767 #ifdef HAVE_LIBGRIB_API
30768 #include <grib_api.h>
30769 #endif
30770 
30771 typedef struct recordList recordList;
30772 
30773 CdiIterator *cdiGribIterator_new(const char *path, int filetype);
30774 CdiGribIterator *cdiGribIterator_makeClone(CdiIterator *me);
30775 CdiIterator *cdiGribIterator_getSuper(CdiGribIterator *me);
30776 char *cdiGribIterator_serialize(CdiIterator *me);
30777 CdiGribIterator *cdiGribIterator_deserialize(const char *me);
30778 
30779 int cdiGribIterator_nextField(CdiIterator *me);
30780 
30781 char *cdiGribIterator_inqTime(CdiIterator *me, CdiTimeType timeType);
30782 int cdiGribIterator_levelType(CdiIterator *me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit);
30783 int cdiGribIterator_level(CdiIterator *me, int levelSelector, double *outValue1, double *outValue2);
30784 int cdiGribIterator_zaxisUuid(CdiIterator *me, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE]);
30785 int cdiGribIterator_inqTile(CdiIterator *me, int *outTileIndex, int *outTileAttribute);
30786 int cdiGribIterator_inqTileCount(CdiIterator *me, int *outTileCount, int *outTileAttributeCount);
30787 char *cdiGribIterator_copyVariableName(CdiIterator *me);
30788 
30789 void cdiGribIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
30790 void cdiGribIterator_readFieldF(CdiIterator *me, float *buffer, size_t *nmiss);
30791 
30792 #endif
30793 
30794 /*
30795  * Local Variables:
30796  * c-file-style: "Java"
30797  * c-basic-offset: 2
30798  * indent-tabs-mode: nil
30799  * show-trailing-whitespace: t
30800  * require-trailing-newline: t
30801  * End:
30802  */
30803 
30804 #include <assert.h>
30805 #include <ctype.h>
30806 
30807 static const char kUnexpectedFileTypeMessage[]
30808   = "Internal error: Unexpected file type encountered in iterator.\n"
30809   "This is either due to an illegal memory access by the application\n"
30810   " or an internal logical error in CDI (unlikely, but possible).";
30811 static const char kAdvancedString[] = "advanced";
30812 static const char kUnadvancedString[] = "unadvanced";
30813 
30814 //Returns a static string.
fileType2String(int fileType)30815 static const char* fileType2String(int fileType)
30816 {
30817   switch(fileType)
30818     {
30819 #ifdef HAVE_LIBGRIB_API
30820         case CDI_FILETYPE_GRB: return "CDI::Iterator::GRIB1";
30821         case CDI_FILETYPE_GRB2: return "CDI::Iterator::GRIB2";
30822 #endif
30823 #ifdef HAVE_LIBNETCDF
30824         case CDI_FILETYPE_NC: return "CDI::Iterator::NetCDF";
30825         case CDI_FILETYPE_NC2: return "CDI::Iterator::NetCDF2";
30826         case CDI_FILETYPE_NC4: return "CDI::Iterator::NetCDF4";
30827         case CDI_FILETYPE_NC4C: return "CDI::Iterator::NetCDF4C";
30828         case CDI_FILETYPE_NC5: return "CDI::Iterator::NetCDF5";
30829 #endif
30830 #ifdef HAVE_LIBSERVICE
30831         case CDI_FILETYPE_SRV: return "CDI::Iterator::SRV";
30832 #endif
30833 #ifdef HAVE_LIBEXTRA
30834         case CDI_FILETYPE_EXT: return "CDI::Iterator::EXT";
30835 #endif
30836 #ifdef HAVE_LIBIEG
30837         case CDI_FILETYPE_IEG: return "CDI::Iterator::IEG";
30838 #endif
30839 
30840       default: return NULL;
30841     }
30842 }
30843 
string2FileType(const char * fileType,const char ** outRestString)30844 static int string2FileType(const char* fileType, const char **outRestString)
30845 {
30846   //This first part unconditionally checks all known type strings, and only if the given string matches one of these strings, we use fileType2string() to check whether support for this type has been compiled in. This is to avoid throwing "invalid type string" errors when we just have a library version mismatch.
30847 #define check(givenString, typeString, typeConstant) do \
30848     { \
30849       if(givenString == strstr(givenString, typeString)) \
30850         { \
30851           if(outRestString) *outRestString = givenString + strlen(typeString); \
30852           if(fileType2String(typeConstant)) return typeConstant; \
30853           Error("Support for " typeString " not compiled in. Please check that the result of `cdiIterator_serialize()` is only passed to a `cdiIterator_deserialize()` implementation of the same CDI library version."); \
30854           return CDI_FILETYPE_UNDEF; \
30855         } \
30856     } while(0)
30857   check(fileType, "CDI::Iterator::GRIB1", CDI_FILETYPE_GRB);
30858   check(fileType, "CDI::Iterator::GRIB2", CDI_FILETYPE_GRB2);
30859   check(fileType, "CDI::Iterator::NetCDF", CDI_FILETYPE_NC);
30860   check(fileType, "CDI::Iterator::NetCDF2", CDI_FILETYPE_NC2);
30861   check(fileType, "CDI::Iterator::NetCDF4", CDI_FILETYPE_NC4);
30862   check(fileType, "CDI::Iterator::NetCDF4C", CDI_FILETYPE_NC4C);
30863   check(fileType, "CDI::Iterator::NetCDF5", CDI_FILETYPE_NC5);
30864   check(fileType, "CDI::Iterator::SRV", CDI_FILETYPE_SRV);
30865   check(fileType, "CDI::Iterator::EXT", CDI_FILETYPE_EXT);
30866   check(fileType, "CDI::Iterator::IEG", CDI_FILETYPE_IEG);
30867 #undef check
30868 
30869   //If this point is reached, the given string does not seem to be produced by a cdiIterator_serialize() call.
30870   Error("The string \"%s\" does not start with a valid iterator type. Please check the source of this string.", fileType);
30871   *outRestString = fileType;
30872   return CDI_FILETYPE_UNDEF;
30873 }
30874 
30875 /*
30876 @Function cdiIterator_new
30877 @Title Create an iterator for an input file
30878 
30879 @Prototype CdiIterator* cdiIterator_new(const char* path)
30880 @Parameter
30881     @item path Path to the file that is to be read.
30882 
30883 @Result An iterator for the given file.
30884 
30885 @Description
30886     Combined allocator and constructor for CdiIterator.
30887 
30888     The returned iterator does not point to the first field yet,
30889     it must first be advanced once before the first field can be introspected.
30890     This design decision has two benefits: 1. Empty files require no special
30891     cases, 2. Users can start a while(!cdiIterator_nextField(iterator)) loop
30892     right after the call to cdiIterator_new().
30893 */
cdiIterator_new(const char * path)30894 CdiIterator* cdiIterator_new(const char* path)
30895 {
30896   int trash;
30897   int filetype = cdiGetFiletype(path, &trash);
30898   switch(filetype)
30899     {
30900       case CDI_FILETYPE_UNDEF:
30901         Warning("Can't open file \"%s\": unknown format\n", path);
30902         return NULL;
30903 
30904 #ifdef HAVE_LIBGRIB_API
30905         case CDI_FILETYPE_GRB:
30906         case CDI_FILETYPE_GRB2:
30907           return cdiGribIterator_new(path, filetype);
30908 #endif
30909 
30910 #ifdef HAVE_LIBNETCDF
30911         case CDI_FILETYPE_NC:
30912         case CDI_FILETYPE_NC2:
30913         case CDI_FILETYPE_NC4:
30914         case CDI_FILETYPE_NC4C:
30915         case CDI_FILETYPE_NC5:
30916 #endif
30917 #ifdef HAVE_LIBSERVICE
30918         case CDI_FILETYPE_SRV:
30919 #endif
30920 #ifdef HAVE_LIBEXTRA
30921         case CDI_FILETYPE_EXT:
30922 #endif
30923 #ifdef HAVE_LIBIEG
30924         case CDI_FILETYPE_IEG:
30925 #endif
30926           return cdiFallbackIterator_new(path, filetype);
30927 
30928       default:
30929         Warning("the file \"%s\" is of type %s, but support for this format is not compiled in!", path, strfiletype(filetype));
30930         return NULL;
30931     }
30932 }
30933 
baseIterConstruct(CdiIterator * me,int filetype)30934 void baseIterConstruct(CdiIterator* me, int filetype)
30935 {
30936   me->filetype = filetype;
30937   me->isAdvanced = false;
30938 }
30939 
baseIter_constructFromString(CdiIterator * me,const char * description)30940 const char* baseIter_constructFromString(CdiIterator* me, const char* description)
30941 {
30942   const char* result = description;
30943   me->filetype = string2FileType(result, &result);
30944   assert(me->filetype != CDI_FILETYPE_UNDEF && "Please report this error.");        //This condition should have been checked for in a calling function.
30945   for(; *result && isspace(*result); result++);
30946   if(result == strstr(result, kAdvancedString))
30947     {
30948       me->isAdvanced = true;
30949       result += sizeof (kAdvancedString) - 1;
30950     }
30951   else if(result == strstr(result, kUnadvancedString))
30952     {
30953       me->isAdvanced = false;
30954       result += sizeof (kUnadvancedString) - 1;
30955     }
30956   else
30957     {
30958       Error("Invalid iterator description string \"%s\". Please check the origin of this string.", description);
30959       return NULL;
30960     }
30961   return result;
30962 }
30963 
30964 #define sanityCheck(me) do { \
30965     if(!me) xabort("NULL was passed to %s as an iterator. Please check the return value of cdiIterator_new().", __func__); \
30966     if(!me->isAdvanced) xabort("Calling %s is not allowed without calling cdiIterator_nextField() first.", __func__); \
30967 } while(0)
30968 
30969 /*
30970 @Function cdiIterator_clone
30971 @Title Make a copy of an iterator
30972 
30973 @Prototype CdiIterator* cdiIterator_clone(CdiIterator* me)
30974 @Parameter
30975     @item iterator The iterator to copy.
30976 
30977 @Result The clone.
30978 
30979 @Description
30980     Clones the given iterator. Make sure to call cdiIterator_delete() on both
30981     the copy and the original.
30982 
30983     This is not a cheap operation: Depending on the type of the file, it will
30984     either make a copy of the current field in memory (GRIB files), or reopen
30985     the file (all other file types). Use it sparingly. And if you do, try to
30986     avoid keeping too many clones around: their memory footprint is
30987     significant.
30988 */
cdiIterator_clone(CdiIterator * me)30989 CdiIterator* cdiIterator_clone(CdiIterator* me)
30990 {
30991   sanityCheck(me);
30992   switch(me->filetype)
30993     {
30994 #ifdef HAVE_LIBGRIB_API
30995         case CDI_FILETYPE_GRB:
30996         case CDI_FILETYPE_GRB2:
30997           return cdiGribIterator_getSuper(cdiGribIterator_clone(me));
30998 #endif
30999 
31000 #ifdef HAVE_LIBNETCDF
31001         case CDI_FILETYPE_NC:
31002         case CDI_FILETYPE_NC2:
31003         case CDI_FILETYPE_NC4:
31004         case CDI_FILETYPE_NC4C:
31005         case CDI_FILETYPE_NC5:
31006 #endif
31007 #ifdef HAVE_LIBSERVICE
31008         case CDI_FILETYPE_SRV:
31009 #endif
31010 #ifdef HAVE_LIBEXTRA
31011         case CDI_FILETYPE_EXT:
31012 #endif
31013 #ifdef HAVE_LIBIEG
31014         case CDI_FILETYPE_IEG:
31015 #endif
31016           return cdiFallbackIterator_getSuper(cdiFallbackIterator_clone(me));
31017 
31018       default:
31019         Error(kUnexpectedFileTypeMessage);
31020         return NULL;
31021     }
31022 }
31023 
31024 /*
31025 @Function cdiGribIterator_clone
31026 @Title Gain access to GRIB specific functionality
31027 
31028 @Prototype CdiGribIterator* cdiGribIterator_clone(CdiIterator* me)
31029 @Parameter
31030     @item iterator The iterator to operate on.
31031 
31032 @Result A clone that allows access to GRIB specific functionality, or NULL if the underlying file is not a GRIB file.
31033 
31034 @Description
31035     Clones the given iterator iff the underlying file is a GRIB file, the returned iterator allows access to GRIB specific functionality.
31036     Make sure to check that the return value is not NULL, and to call cdiGribIterator_delete() on the copy.
31037 
31038     This is not a cheap operation: It will make a copy of the current field in memory. Use it sparingly. And if you do, try to avoid keeping too many clones around, their memory footprint is significant.
31039 */
cdiGribIterator_clone(CdiIterator * me)31040 CdiGribIterator* cdiGribIterator_clone(CdiIterator* me)
31041 {
31042   sanityCheck(me);
31043   switch(me->filetype)
31044     {
31045 #ifdef HAVE_LIBGRIB_API
31046         case CDI_FILETYPE_GRB:
31047         case CDI_FILETYPE_GRB2:
31048           return cdiGribIterator_makeClone(me);
31049 #endif
31050 
31051       default:
31052         return NULL;
31053     }
31054 }
31055 
31056 /*
31057 @Function cdiIterator_serialize
31058 @Title Serialize an iterator for sending it to another process
31059 
31060 @Prototype char* cdiIterator_serialize(CdiIterator* me)
31061 @Parameter
31062     @item iterator The iterator to operate on.
31063 
31064 @Result A malloc'ed string that contains the full description of the iterator.
31065 
31066 @Description
31067     Make sure to call Free() on the resulting string.
31068 */
cdiIterator_serialize(CdiIterator * me)31069 char* cdiIterator_serialize(CdiIterator* me)
31070 {
31071   if(!me) xabort("NULL was passed to %s as an iterator. Please check the return value of cdiIterator_new().", __func__); \
31072   char* subclassDescription = NULL;
31073   switch(me->filetype)
31074     {
31075 #ifdef HAVE_LIBGRIB_API
31076         case CDI_FILETYPE_GRB:
31077         case CDI_FILETYPE_GRB2:
31078           subclassDescription = cdiGribIterator_serialize(me);
31079           break;
31080 #endif
31081 
31082 #ifdef HAVE_LIBNETCDF
31083         case CDI_FILETYPE_NC:
31084         case CDI_FILETYPE_NC2:
31085         case CDI_FILETYPE_NC4:
31086         case CDI_FILETYPE_NC4C:
31087         case CDI_FILETYPE_NC5:
31088 #endif
31089 #ifdef HAVE_LIBSERVICE
31090         case CDI_FILETYPE_SRV:
31091 #endif
31092 #ifdef HAVE_LIBEXTRA
31093         case CDI_FILETYPE_EXT:
31094 #endif
31095 #ifdef HAVE_LIBIEG
31096         case CDI_FILETYPE_IEG:
31097 #endif
31098           subclassDescription = cdiFallbackIterator_serialize(me);
31099           break;
31100 
31101       default:
31102         Error(kUnexpectedFileTypeMessage);
31103         return NULL;
31104     }
31105 
31106   const char *ftypeStr = fileType2String(me->filetype),
31107     *advStr = me->isAdvanced ? kAdvancedString : kUnadvancedString;
31108   char* result = (char *) Malloc(strlen(ftypeStr) + 1 + strlen(advStr) + 1
31109                          + strlen(subclassDescription) + 1);
31110   sprintf(result, "%s %s %s", ftypeStr, advStr, subclassDescription);
31111   Free(subclassDescription);
31112   return result;
31113 }
31114 
31115 /*
31116 @Function cdiIterator_deserialize
31117 @Title Recreate an iterator from its textual description
31118 
31119 @Prototype CdiIterator* cdiIterator_deserialize(const char* description)
31120 @Parameter
31121     @item description The result of a call to cdiIterator_serialize().
31122 
31123 @Result A clone of the original iterator.
31124 
31125 @Description
31126     A pair of cdiIterator_serialize() and cdiIterator_deserialize() is functionally equivalent to a call to cdiIterator_clone()
31127 
31128     This function will reread the current field from disk, so don't expect immediate return.
31129 */
31130 //This only checks the type of the iterator and calls the corresponding subclass function,
31131 //the real deserialization is done in baseIter_constructFromString().
cdiIterator_deserialize(const char * description)31132 CdiIterator* cdiIterator_deserialize(const char* description)
31133 {
31134   switch(string2FileType(description, NULL))
31135     {
31136 #ifdef HAVE_LIBGRIB_API
31137         case CDI_FILETYPE_GRB:
31138         case CDI_FILETYPE_GRB2:
31139           return cdiGribIterator_getSuper(cdiGribIterator_deserialize(description));
31140 #endif
31141 
31142 #ifdef HAVE_LIBNETCDF
31143         case CDI_FILETYPE_NC:
31144         case CDI_FILETYPE_NC2:
31145         case CDI_FILETYPE_NC4:
31146         case CDI_FILETYPE_NC4C:
31147         case CDI_FILETYPE_NC5:
31148 #endif
31149 #ifdef HAVE_LIBSERVICE
31150         case CDI_FILETYPE_SRV:
31151 #endif
31152 #ifdef HAVE_LIBEXTRA
31153         case CDI_FILETYPE_EXT:
31154 #endif
31155 #ifdef HAVE_LIBIEG
31156         case CDI_FILETYPE_IEG:
31157 #endif
31158           return cdiFallbackIterator_getSuper(cdiFallbackIterator_deserialize(description));
31159 
31160       default:
31161         Error(kUnexpectedFileTypeMessage);
31162         return NULL;
31163     }
31164 }
31165 
31166 
31167 /*
31168 @Function cdiIterator_print
31169 @Title Print a textual description of the iterator to a stream
31170 
31171 @Prototype void cdiIterator_print(CdiIterator* iterator, FILE* stream);
31172 @Parameter
31173     @item iterator The iterator to print.
31174     @item stream The stream to print to.
31175 
31176 @Description
31177     Use for debugging output.
31178 */
cdiIterator_print(CdiIterator * me,FILE * stream)31179 void cdiIterator_print(CdiIterator* me, FILE* stream)
31180 {
31181   char* description = cdiIterator_serialize(me);
31182   fprintf(stream, "%s\n", description);
31183   Free(description);
31184 }
31185 
31186 
31187 /*
31188 @Function cdiIterator_nextField
31189 @Title Advance an iterator to the next field in the file
31190 
31191 @Prototype int cdiIterator_nextField(CdiIterator* iterator)
31192 @Parameter
31193     @item iterator The iterator to operate on.
31194 
31195 @Result An error code. May be one of:
31196   * CDI_NOERR: The iterator has successfully been advanced to the next field.
31197   * CDI_EEOF: No more fields to read in this file.
31198 
31199 @Description
31200     One call to cdiIterator_nextField() is required before the metadata of the first field can be examined.
31201     Usually, it will be used directly as the condition for a while() loop.
31202 */
cdiIterator_nextField(CdiIterator * me)31203 int cdiIterator_nextField(CdiIterator* me)
31204 {
31205   if(!me) xabort("NULL was passed in as an iterator. Please check the return value of cdiIterator_new().");
31206   me->isAdvanced = true;
31207   switch(me->filetype)
31208     {
31209 #ifdef HAVE_LIBGRIB_API
31210         case CDI_FILETYPE_GRB:
31211         case CDI_FILETYPE_GRB2:
31212           return cdiGribIterator_nextField(me);
31213 #endif
31214 
31215 #ifdef HAVE_LIBNETCDF
31216         case CDI_FILETYPE_NC:
31217         case CDI_FILETYPE_NC2:
31218         case CDI_FILETYPE_NC4:
31219         case CDI_FILETYPE_NC4C:
31220         case CDI_FILETYPE_NC5:
31221 #endif
31222 #ifdef HAVE_LIBSERVICE
31223         case CDI_FILETYPE_SRV:
31224 #endif
31225 #ifdef HAVE_LIBEXTRA
31226         case CDI_FILETYPE_EXT:
31227 #endif
31228 #ifdef HAVE_LIBIEG
31229         case CDI_FILETYPE_IEG:
31230 #endif
31231           return cdiFallbackIterator_nextField(me);
31232 
31233       default:
31234         Error(kUnexpectedFileTypeMessage);
31235         return CDI_EINVAL;
31236     }
31237 }
31238 
cdiIterator_inqTime(CdiIterator * me,CdiTimeType timeType)31239 static char* cdiIterator_inqTime(CdiIterator* me, CdiTimeType timeType)
31240 {
31241   sanityCheck(me);
31242   switch(me->filetype)
31243     {
31244 #ifdef HAVE_LIBGRIB_API
31245         case CDI_FILETYPE_GRB:
31246         case CDI_FILETYPE_GRB2:
31247           return cdiGribIterator_inqTime(me, timeType);
31248 #endif
31249 
31250 #ifdef HAVE_LIBNETCDF
31251         case CDI_FILETYPE_NC:
31252         case CDI_FILETYPE_NC2:
31253         case CDI_FILETYPE_NC4:
31254         case CDI_FILETYPE_NC4C:
31255         case CDI_FILETYPE_NC5:
31256 #endif
31257 #ifdef HAVE_LIBSERVICE
31258         case CDI_FILETYPE_SRV:
31259 #endif
31260 #ifdef HAVE_LIBEXTRA
31261         case CDI_FILETYPE_EXT:
31262 #endif
31263 #ifdef HAVE_LIBIEG
31264         case CDI_FILETYPE_IEG:
31265 #endif
31266           return cdiFallbackIterator_inqTime(me, timeType);
31267 
31268       default:
31269         Error(kUnexpectedFileTypeMessage);
31270         return NULL;
31271     }
31272 }
31273 
31274 /*
31275 @Function cdiIterator_inqStartTime
31276 @Title Get the start time of a measurement
31277 
31278 @Prototype char* cdiIterator_inqStartTime(CdiIterator* me)
31279 @Parameter
31280     @item iterator The iterator to operate on.
31281 
31282 @Result A malloc'ed string containing the (start) time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
31283 
31284 @Description
31285 The returned time is either the time of the data (fields defined at a time point),
31286 or the start time of an integration time range (statistical fields).
31287 
31288 Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
31289 The caller is responsible to Free() the resulting string.
31290 
31291 If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
31292 as it is implemented by the standard C mktime() function.
31293 This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
31294 */
cdiIterator_inqStartTime(CdiIterator * me)31295 char* cdiIterator_inqStartTime(CdiIterator* me)
31296 {
31297   return cdiIterator_inqTime(me, kCdiTimeType_startTime);
31298 }
31299 
31300 /*
31301 @Function cdiIterator_inqEndTime
31302 @Title Get the end time of a measurement
31303 
31304 @Prototype char* cdiIterator_inqEndTime(CdiIterator* me)
31305 @Parameter
31306     @item iterator The iterator to operate on.
31307 
31308 @Result A malloc'ed string containing the end time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm", or NULL if no such time is defined.
31309 
31310 @Description
31311 The returned time is the end time of an integration period if such a time exists (statistical fields).
31312 Otherwise, NULL is returned.
31313 
31314 Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
31315 The caller is responsible to Free() the resulting string.
31316 
31317 If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
31318 as it is implemented by the standard C mktime() function.
31319 This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
31320 */
cdiIterator_inqEndTime(CdiIterator * me)31321 char* cdiIterator_inqEndTime(CdiIterator* me)
31322 {
31323   return cdiIterator_inqTime(me, kCdiTimeType_endTime);
31324 }
31325 
31326 /*
31327 @Function cdiIterator_inqRTime
31328 @Title Get the validity time of the current field
31329 
31330 @Prototype char* cdiIterator_inqRTime(CdiIterator* me)
31331 @Parameter
31332     @item iterator The iterator to operate on.
31333 
31334 @Result A malloc'ed string containing the validity time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
31335 
31336 @Description
31337 The returned time is the validity time as it is returned by taxisInqVtime(), only more precise.
31338 That is, if the field is a time point, its time is returned,
31339 if it is a statistical field with an integration period, the end time of the integration period is returned.
31340 
31341 Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
31342 The caller is responsible to Free() the resulting string.
31343 
31344 If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
31345 as it is implemented by the standard C mktime() function.
31346 This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
31347 */
cdiIterator_inqRTime(CdiIterator * me)31348 char* cdiIterator_inqRTime(CdiIterator* me)
31349 {
31350   return cdiIterator_inqTime(me, kCdiTimeType_referenceTime);
31351 }
31352 
31353 /*
31354 @Function cdiIterator_inqVTime
31355 @Title Get the validity time of the current field
31356 
31357 @Prototype char* cdiIterator_inqVTime(CdiIterator* me)
31358 @Parameter
31359     @item iterator The iterator to operate on.
31360 
31361 @Result A malloc'ed string containing the validity time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
31362 
31363 @Description
31364 The returned time is the validity time as it is returned by taxisInqVtime(), only more precise.
31365 That is, if the field is a time point, its time is returned,
31366 if it is a statistical field with an integration period, the end time of the integration period is returned.
31367 
31368 Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
31369 The caller is responsible to Free() the resulting string.
31370 
31371 If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
31372 as it is implemented by the standard C mktime() function.
31373 This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
31374 */
cdiIterator_inqVTime(CdiIterator * me)31375 char* cdiIterator_inqVTime(CdiIterator* me)
31376 {
31377   char* result = cdiIterator_inqEndTime(me);
31378   return (result) ? result : cdiIterator_inqStartTime(me);
31379 }
31380 
31381 /*
31382 @Function cdiIterator_inqLevelType
31383 @Title Get the type of a level
31384 
31385 @Prototype int cdiIterator_inqLevelType(CdiIterator* me, int levelSelector, char **outName = NULL, char **outLongName = NULL, char **outStdName = NULL, char **outUnit = NULL)
31386 @Parameter
31387     @item iterator The iterator to operate on.
31388     @item levelSelector Zero for the top level, one for the bottom level
31389     @item outName Will be set to a Malloc()'ed string with the name of the level if not NULL.
31390     @item outLongName Will be set to a Malloc()'ed string with the long name of the level if not NULL.
31391     @item outStdName Will be set to a Malloc()'ed string with the standard name of the level if not NULL.
31392     @item outUnit Will be set to a Malloc()'ed string with the unit of the level if not NULL.
31393 
31394 @Result An integer indicating the type of the level.
31395 
31396 @Description
31397 Find out some basic information about the given level, the levelSelector selects the function of the requested level.
31398 If the requested level does not exist, this returns CDI_UNDEFID.
31399 */
cdiIterator_inqLevelType(CdiIterator * me,int levelSelector,char ** outName,char ** outLongName,char ** outStdName,char ** outUnit)31400 int cdiIterator_inqLevelType(CdiIterator* me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
31401 {
31402   sanityCheck(me);
31403   switch(me->filetype)
31404     {
31405 #ifdef HAVE_LIBGRIB_API
31406         case CDI_FILETYPE_GRB:
31407         case CDI_FILETYPE_GRB2:
31408           return cdiGribIterator_levelType(me, levelSelector, outName, outLongName, outStdName, outUnit);
31409 #endif
31410 
31411 #ifdef HAVE_LIBNETCDF
31412         case CDI_FILETYPE_NC:
31413         case CDI_FILETYPE_NC2:
31414         case CDI_FILETYPE_NC4:
31415         case CDI_FILETYPE_NC4C:
31416         case CDI_FILETYPE_NC5:
31417 #endif
31418 #ifdef HAVE_LIBSERVICE
31419         case CDI_FILETYPE_SRV:
31420 #endif
31421 #ifdef HAVE_LIBEXTRA
31422         case CDI_FILETYPE_EXT:
31423 #endif
31424 #ifdef HAVE_LIBIEG
31425         case CDI_FILETYPE_IEG:
31426 #endif
31427           return cdiFallbackIterator_levelType(me, levelSelector, outName, outLongName, outStdName, outUnit);
31428 
31429       default:
31430         Error(kUnexpectedFileTypeMessage);
31431         return CDI_UNDEFID;
31432     }
31433 }
31434 
31435 /*
31436 @Function cdiIterator_inqLevel
31437 @Title Get the value of the z-coordinate
31438 
31439 @Prototype void cdiIterator_inqLevel(CdiIterator* me, int levelSelector, double* outValue1, double* outValue2 = NULL)
31440 @Parameter
31441     @item iterator The iterator to operate on.
31442     @item levelSelector Zero for the top level, one for the bottom level
31443     @item outValue1 For "normal" levels this returns the value, for hybrid levels the first coordinate, for generalized levels the level number.
31444     @item outValue2 Zero for "normal" levels, for hybrid levels, this returns the second coordinate, for generalized levels the level count.
31445 
31446 @Result An error code.
31447 
31448 @Description
31449 Returns the value of the z-coordinate, whatever that may be.
31450 */
cdiIterator_inqLevel(CdiIterator * me,int levelSelector,double * outValue1,double * outValue2)31451 int cdiIterator_inqLevel(CdiIterator* me, int levelSelector, double* outValue1, double* outValue2)
31452 {
31453   sanityCheck(me);
31454   switch(me->filetype)
31455     {
31456 #ifdef HAVE_LIBGRIB_API
31457         case CDI_FILETYPE_GRB:
31458         case CDI_FILETYPE_GRB2:
31459           return cdiGribIterator_level(me, levelSelector, outValue1, outValue2);
31460 #endif
31461 
31462 #ifdef HAVE_LIBNETCDF
31463         case CDI_FILETYPE_NC:
31464         case CDI_FILETYPE_NC2:
31465         case CDI_FILETYPE_NC4:
31466         case CDI_FILETYPE_NC4C:
31467         case CDI_FILETYPE_NC5:
31468 #endif
31469 #ifdef HAVE_LIBSERVICE
31470         case CDI_FILETYPE_SRV:
31471 #endif
31472 #ifdef HAVE_LIBEXTRA
31473         case CDI_FILETYPE_EXT:
31474 #endif
31475 #ifdef HAVE_LIBIEG
31476         case CDI_FILETYPE_IEG:
31477 #endif
31478           return cdiFallbackIterator_level(me, levelSelector, outValue1, outValue2);
31479 
31480       default:
31481         Error(kUnexpectedFileTypeMessage);
31482         return CDI_EINVAL;
31483     }
31484 }
31485 
31486 /*
31487 @Function cdiIterator_inqLevelUuid
31488 @Title Get the UUID of the z-axis used by this field
31489 
31490 @Prototype int cdiIterator_inqLevelUuid(CdiIterator* me, int levelSelector, unsigned char (*outUuid)[16])
31491 @Parameter
31492     @item iterator The iterator to operate on.
31493     @item outVgridNumber The number of the associated vertical grid description.
31494     @item outLevelCount The number of levels in the associated vertical grid description.
31495     @item outUuid A pointer to a user supplied buffer of 16 bytes to store the UUID in.
31496 
31497 @Result An error code.
31498 
31499 @Description
31500 Returns identifying information for the external z-axis description. May only be called for generalized levels.
31501 */
cdiIterator_inqLevelUuid(CdiIterator * me,int * outVgridNumber,int * outLevelCount,unsigned char outUuid[CDI_UUID_SIZE])31502 int cdiIterator_inqLevelUuid(CdiIterator* me, int* outVgridNumber, int* outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
31503 {
31504   sanityCheck(me);
31505   switch(me->filetype)
31506     {
31507 #ifdef HAVE_LIBGRIB_API
31508         case CDI_FILETYPE_GRB:
31509         case CDI_FILETYPE_GRB2:
31510           return cdiGribIterator_zaxisUuid(me, outVgridNumber, outLevelCount, outUuid);
31511 #endif
31512 
31513 #ifdef HAVE_LIBNETCDF
31514         case CDI_FILETYPE_NC:
31515         case CDI_FILETYPE_NC2:
31516         case CDI_FILETYPE_NC4:
31517         case CDI_FILETYPE_NC4C:
31518         case CDI_FILETYPE_NC5:
31519 #endif
31520 #ifdef HAVE_LIBSERVICE
31521         case CDI_FILETYPE_SRV:
31522 #endif
31523 #ifdef HAVE_LIBEXTRA
31524         case CDI_FILETYPE_EXT:
31525 #endif
31526 #ifdef HAVE_LIBIEG
31527         case CDI_FILETYPE_IEG:
31528 #endif
31529           return cdiFallbackIterator_zaxisUuid(me, outVgridNumber, outLevelCount, outUuid);
31530 
31531       default:
31532         Error(kUnexpectedFileTypeMessage);
31533         return CDI_ELIBNAVAIL;
31534     }
31535 }
31536 
31537 /*
31538 @Function cdiIterator_inqTile
31539 @Title Inquire the tile information for the current field
31540 
31541 @Prototype int cdiIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute)
31542 @Parameter
31543     @item iterator The iterator to operate on.
31544     @item outTileIndex The index of the current tile, -1 if no tile information is available.
31545     @item outTileAttribute The attribute of the current tile, -1 if no tile information is available.
31546 
31547 @Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
31548 
31549 @Description
31550 Inquire the tile index and attribute for the current field.
31551 */
cdiIterator_inqTile(CdiIterator * me,int * outTileIndex,int * outTileAttribute)31552 int cdiIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute)
31553 {
31554   sanityCheck(me);
31555   switch(me->filetype)
31556     {
31557       #ifdef HAVE_LIBGRIB_API
31558         case CDI_FILETYPE_GRB:
31559         case CDI_FILETYPE_GRB2:
31560           return cdiGribIterator_inqTile(me, outTileIndex, outTileAttribute);
31561       #endif
31562 
31563       #ifdef HAVE_LIBNETCDF
31564         case CDI_FILETYPE_NC:
31565         case CDI_FILETYPE_NC2:
31566         case CDI_FILETYPE_NC4:
31567         case CDI_FILETYPE_NC4C:
31568         case CDI_FILETYPE_NC5:
31569       #endif
31570       #ifdef HAVE_LIBSERVICE
31571         case CDI_FILETYPE_SRV:
31572       #endif
31573       #ifdef HAVE_LIBEXTRA
31574         case CDI_FILETYPE_EXT:
31575       #endif
31576       #ifdef HAVE_LIBIEG
31577         case CDI_FILETYPE_IEG:
31578       #endif
31579           return cdiFallbackIterator_inqTile(me, outTileIndex, outTileAttribute);
31580 
31581       default:
31582         Error(kUnexpectedFileTypeMessage);
31583         return CDI_ELIBNAVAIL;
31584     }
31585 }
31586 
31587 /**
31588 @Function cdiIterator_inqTileCount
31589 @Title Inquire the tile count and tile attribute counts for the current field
31590 
31591 @Prototype int cdiIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount)
31592 @Parameter
31593     @item iterator The iterator to operate on.
31594     @item outTileCount The number of tiles used for this variable, zero if no tile information is available.
31595     @item outTileAttributeCount The number of attributes available for the tile of this field, zero if no tile information is available.
31596           Note: This is not the global attribute count, which would be impossible to infer without reading the entire file if it's a GRIB file.
31597 
31598 @Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
31599 
31600 @Description
31601 Inquire the tile count and tile attribute counts for the current field.
31602 */
cdiIterator_inqTileCount(CdiIterator * me,int * outTileCount,int * outTileAttributeCount)31603 int cdiIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount)
31604 {
31605   sanityCheck(me);
31606   switch(me->filetype)
31607     {
31608       #ifdef HAVE_LIBGRIB_API
31609         case CDI_FILETYPE_GRB:
31610         case CDI_FILETYPE_GRB2:
31611           return cdiGribIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
31612       #endif
31613 
31614       #ifdef HAVE_LIBNETCDF
31615         case CDI_FILETYPE_NC:
31616         case CDI_FILETYPE_NC2:
31617         case CDI_FILETYPE_NC4:
31618         case CDI_FILETYPE_NC4C:
31619         case CDI_FILETYPE_NC5:
31620       #endif
31621       #ifdef HAVE_LIBSERVICE
31622         case CDI_FILETYPE_SRV:
31623       #endif
31624       #ifdef HAVE_LIBEXTRA
31625         case CDI_FILETYPE_EXT:
31626       #endif
31627       #ifdef HAVE_LIBIEG
31628         case CDI_FILETYPE_IEG:
31629       #endif
31630           return cdiFallbackIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
31631 
31632       default:
31633         Error(kUnexpectedFileTypeMessage);
31634         return CDI_ELIBNAVAIL;
31635     }
31636 }
31637 
31638 /*
31639 @Function cdiIterator_inqParam
31640 @Title Get discipline, category, and number
31641 
31642 @Prototype CdiParam cdiIterator_inqParam(CdiIterator* iterator)
31643 @Parameter
31644     @item iterator The iterator to operate on.
31645 
31646 @Result A struct containing the requested information.
31647 
31648 @Description
31649     Simple metadata inspection function.
31650 */
cdiIterator_inqParam(CdiIterator * me)31651 CdiParam cdiIterator_inqParam(CdiIterator* me)
31652 {
31653   sanityCheck(me);
31654   return me->param;
31655 }
31656 
31657 /*
31658 @Function cdiIterator_inqParamParts
31659 @Title Get discipline, category, and number
31660 
31661 @Prototype void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber)
31662 @Parameter
31663     @item iterator The iterator to operate on.
31664     @item outDiscipline This is used to return the discipline.
31665     @item outCategory This is used to return the category.
31666     @item outNumber This is used to return the number.
31667 
31668 @Description
31669     Simple metadata inspection function.
31670 
31671     Some FORTRAN compilers produce wrong code for the cdiIterator_inqParam()-wrapper,
31672     rendering it unusable from FORTRAN. This function is the workaround.
31673 */
cdiIterator_inqParamParts(CdiIterator * me,int * outDiscipline,int * outCategory,int * outNumber)31674 void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber)
31675 {
31676   CdiParam result = cdiIterator_inqParam(me);
31677   if(outDiscipline) *outDiscipline = result.discipline;
31678   if(outCategory) *outCategory = result.category;
31679   if(outNumber) *outNumber = result.number;
31680 }
31681 
31682 /*
31683 @Function cdiIterator_inqDatatype
31684 @Title Get the datatype of the current field
31685 
31686 @Prototype int cdiIterator_inqDatatype(CdiIterator* iterator)
31687 @Parameter
31688     @item iterator The iterator to operate on.
31689 
31690 @Result The datatype that is used to store this field on disk.
31691 
31692 @Description
31693     Simple metadata inspection function.
31694 */
cdiIterator_inqDatatype(CdiIterator * me)31695 int cdiIterator_inqDatatype(CdiIterator* me)
31696 {
31697   sanityCheck(me);
31698   return me->datatype;
31699 }
31700 
31701 /*
31702 @Function cdiIterator_inqFiletype
31703 @Title Get the filetype of the current field
31704 
31705 @Prototype int cdiIterator_inqFiletype(CdiIterator* iterator)
31706 @Parameter
31707     @item iterator The iterator to operate on.
31708 
31709 @Result The filetype that is used to store this field on disk.
31710 
31711 @Description
31712     Simple metadata inspection function.
31713 */
cdiIterator_inqFiletype(CdiIterator * me)31714 int cdiIterator_inqFiletype(CdiIterator* me)
31715 {
31716   return me->filetype;
31717 }
31718 
31719 /*
31720 @Function cdiIterator_inqTsteptype
31721 @Title Get the timestep type
31722 
31723 @Prototype int cdiIterator_inqTsteptype(CdiIterator* iterator)
31724 @Parameter
31725     @item iterator The iterator to operate on.
31726 
31727 @Result The timestep type.
31728 
31729 @Description
31730     Simple metadata inspection function.
31731 */
cdiIterator_inqTsteptype(CdiIterator * me)31732 int cdiIterator_inqTsteptype(CdiIterator* me)
31733 {
31734   sanityCheck(me);
31735   return me->timesteptype;
31736 }
31737 
31738 /*
31739 @Function cdiIterator_inqVariableName
31740 @Title Get the variable name of the current field
31741 
31742 @Prototype char* cdiIterator_inqVariableName(CdiIterator* iterator)
31743 @Parameter
31744     @item iterator The iterator to operate on.
31745 
31746 @Result A pointer to a C-string containing the name. The storage for this string is allocated with Malloc(), and it is the responsibility of the caller to Free() it.
31747 
31748 @Description
31749     Allocates a buffer to hold the string, copies the current variable name into this buffer, and returns the buffer.
31750     The caller is responsible to make the corresponding Free() call.
31751 */
cdiIterator_inqVariableName(CdiIterator * me)31752 char* cdiIterator_inqVariableName(CdiIterator* me)
31753 {
31754   sanityCheck(me);
31755   switch(me->filetype)
31756     {
31757 #ifdef HAVE_LIBGRIB_API
31758         case CDI_FILETYPE_GRB:
31759         case CDI_FILETYPE_GRB2:
31760           return cdiGribIterator_copyVariableName(me);
31761 #endif
31762 
31763 #ifdef HAVE_LIBNETCDF
31764         case CDI_FILETYPE_NC:
31765         case CDI_FILETYPE_NC2:
31766         case CDI_FILETYPE_NC4:
31767         case CDI_FILETYPE_NC4C:
31768         case CDI_FILETYPE_NC5:
31769 #endif
31770 #ifdef HAVE_LIBSERVICE
31771         case CDI_FILETYPE_SRV:
31772 #endif
31773 #ifdef HAVE_LIBEXTRA
31774         case CDI_FILETYPE_EXT:
31775 #endif
31776 #ifdef HAVE_LIBIEG
31777         case CDI_FILETYPE_IEG:
31778 #endif
31779           return cdiFallbackIterator_copyVariableName(me);
31780 
31781       default:
31782         Error(kUnexpectedFileTypeMessage);
31783         return NULL;
31784     }
31785 }
31786 
31787 /*
31788 @Function cdiIterator_inqGridId
31789 @Title Get the ID of the current grid
31790 
31791 @Prototype int cdiIterator_inqGridId(CdiIterator* iterator)
31792 @Parameter
31793     @item iterator The iterator to operate on.
31794 
31795 @Result A gridId that can be used for further introspection.
31796 
31797 @Description
31798     This provides access to the grid related metadata.
31799     The resulting ID is only valid until the next time cdiIterator_nextField() is called.
31800 */
cdiIterator_inqGridId(CdiIterator * me)31801 int cdiIterator_inqGridId(CdiIterator* me)
31802 {
31803   sanityCheck(me);
31804   return me->gridId;
31805 }
31806 
31807 /*
31808 @Function cdiIterator_readField
31809 @Title Read the whole field into a double buffer
31810 
31811 @Prototype void cdiIterator_readField(CdiIterator* me, double* buffer, size_t* nmiss)
31812 @Parameter
31813     @item iterator The iterator to operate on.
31814     @item buffer A pointer to the double array that the data should be written to.
31815     @item nmiss A pointer to a variable where the count of missing values will be stored. May be NULL.
31816 
31817 @Description
31818     It is assumed that the caller first analyses the return value of cdiIterator_inqGridId to determine the required size of the buffer.
31819     Failing to do so results in undefined behavior. You have been warned.
31820 */
cdiIterator_readField(CdiIterator * me,double * buffer,size_t * nmiss)31821 void cdiIterator_readField(CdiIterator* me, double* buffer, size_t* nmiss)
31822 {
31823   sanityCheck(me);
31824   if(!buffer) xabort("NULL was passed in a buffer. Please provide a suitable buffer.");
31825   switch(me->filetype)
31826     {
31827 #ifdef HAVE_LIBGRIB_API
31828         case CDI_FILETYPE_GRB:
31829         case CDI_FILETYPE_GRB2:
31830           cdiGribIterator_readField(me, buffer, nmiss);
31831 	  return;
31832 #endif
31833 
31834 #ifdef HAVE_LIBNETCDF
31835         case CDI_FILETYPE_NC:
31836         case CDI_FILETYPE_NC2:
31837         case CDI_FILETYPE_NC4:
31838         case CDI_FILETYPE_NC4C:
31839         case CDI_FILETYPE_NC5:
31840 #endif
31841 #ifdef HAVE_LIBSERVICE
31842         case CDI_FILETYPE_SRV:
31843 #endif
31844 #ifdef HAVE_LIBEXTRA
31845         case CDI_FILETYPE_EXT:
31846 #endif
31847 #ifdef HAVE_LIBIEG
31848         case CDI_FILETYPE_IEG:
31849 #endif
31850           cdiFallbackIterator_readField(me, buffer, nmiss);
31851           return;
31852       default:
31853         Error(kUnexpectedFileTypeMessage);
31854     }
31855 }
31856 
31857 /*
31858 @Function cdiIterator_readFieldF
31859 @Title Read the whole field into a double buffer
31860 
31861 @Prototype void cdiIterator_readFieldF(CdiIterator* me, float* buffer, size_t* nmiss)
31862 @Parameter
31863     @item iterator The iterator to operate on.
31864     @item buffer A pointer to the double array that the data should be written to.
31865     @item nmiss A pointer to a variable where the count of missing values will be stored. May be NULL.
31866 
31867 @Description
31868     It is assumed that the caller first analyses the return value of cdiIterator_inqGridId to determine the required size of the buffer.
31869     Failing to do so results in undefined behavior. You have been warned.
31870 */
cdiIterator_readFieldF(CdiIterator * me,float * buffer,size_t * nmiss)31871 void cdiIterator_readFieldF(CdiIterator* me, float* buffer, size_t* nmiss)
31872 {
31873   sanityCheck(me);
31874   if(!buffer) xabort("NULL was passed in a buffer. Please provide a suitable buffer.");
31875   switch(me->filetype)
31876     {
31877 #ifdef HAVE_LIBGRIB_API
31878         case CDI_FILETYPE_GRB:
31879         case CDI_FILETYPE_GRB2:
31880           cdiGribIterator_readFieldF(me, buffer, nmiss);
31881 	  return;
31882 #endif
31883 
31884 #ifdef HAVE_LIBNETCDF
31885         case CDI_FILETYPE_NC:
31886         case CDI_FILETYPE_NC2:
31887         case CDI_FILETYPE_NC4:
31888         case CDI_FILETYPE_NC4C:
31889         case CDI_FILETYPE_NC5:
31890 #endif
31891 #ifdef HAVE_LIBSERVICE
31892         case CDI_FILETYPE_SRV:
31893 #endif
31894 #ifdef HAVE_LIBEXTRA
31895         case CDI_FILETYPE_EXT:
31896 #endif
31897 #ifdef HAVE_LIBIEG
31898         case CDI_FILETYPE_IEG:
31899 #endif
31900           cdiFallbackIterator_readFieldF(me, buffer, nmiss);
31901           return;
31902       default:
31903         Error(kUnexpectedFileTypeMessage);
31904     }
31905 }
31906 
31907 /*
31908 @Function cdiIterator_delete
31909 @Title Destroy an iterator
31910 
31911 @Prototype void cdiIterator_delete(CdiIterator* iterator)
31912 @Parameter
31913     @item iterator The iterator to operate on.
31914 
31915 @Description
31916     Combined destructor & deallocator.
31917 */
cdiIterator_delete(CdiIterator * me)31918 void cdiIterator_delete(CdiIterator* me)
31919 {
31920   if(!me) xabort("NULL was passed in as an iterator. Please check the return value of cdiIterator_new().");
31921   switch(me->filetype)
31922     {
31923 #ifdef HAVE_LIBGRIB_API
31924         case CDI_FILETYPE_GRB:
31925         case CDI_FILETYPE_GRB2:
31926           cdiGribIterator_delete((CdiGribIterator*)me);
31927           break;
31928 #endif
31929 
31930 #ifdef HAVE_LIBNETCDF
31931         case CDI_FILETYPE_NC:
31932         case CDI_FILETYPE_NC2:
31933         case CDI_FILETYPE_NC4:
31934         case CDI_FILETYPE_NC4C:
31935         case CDI_FILETYPE_NC5:
31936 #endif
31937 #ifdef HAVE_LIBSERVICE
31938         case CDI_FILETYPE_SRV:
31939 #endif
31940 #ifdef HAVE_LIBEXTRA
31941         case CDI_FILETYPE_EXT:
31942 #endif
31943 #ifdef HAVE_LIBIEG
31944         case CDI_FILETYPE_IEG:
31945 #endif
31946           cdiFallbackIterator_delete(me);
31947           break;
31948 
31949       default:
31950         Error(kUnexpectedFileTypeMessage);
31951     }
31952 }
31953 
baseIterDestruct(CdiIterator * me)31954 void baseIterDestruct(CdiIterator* me)
31955 {
31956   /*currently empty, but that's no reason not to call it*/
31957   (void)me;
31958 }
31959 
31960 /*
31961  * Local Variables:
31962  * c-file-style: "Java"
31963  * c-basic-offset: 2
31964  * indent-tabs-mode: nil
31965  * show-trailing-whitespace: t
31966  * require-trailing-newline: t
31967  * End:
31968  */
31969 
31970 
31971 #include <assert.h>
31972 #include <limits.h>
31973 #include <stdlib.h>
31974 
31975 struct CdiFallbackIterator {
31976   CdiIterator super;
31977   int streamId, vlistId, subtypeId;
31978   char *path;   //needed for clone() & serialize()
31979 
31980   int variableCount, curVariable;
31981   int curLevelCount, curLevel;
31982   int curSubtypeCount, curSubtype;
31983   int curTimestep;
31984 };
31985 
cdiFallbackIterator_getSuper(CdiFallbackIterator * me)31986 CdiIterator *cdiFallbackIterator_getSuper(CdiFallbackIterator *me)
31987 {
31988   return &me->super;
31989 }
31990 
31991 
31992 //For more information on the condestruct() pattern, see comment in src/iterator_grib.c
cdiFallbackIterator_condestruct(CdiFallbackIterator * me,const char * path,int filetype)31993 static CdiFallbackIterator *cdiFallbackIterator_condestruct(CdiFallbackIterator *me, const char *path, int filetype)
31994 {
31995   if(me) goto destruct;
31996 
31997   me = (CdiFallbackIterator *) Malloc(sizeof(*me));
31998   baseIterConstruct(&me->super, filetype);
31999 
32000   me->streamId = streamOpenRead(path);
32001   if(me->streamId == CDI_UNDEFID) goto destructSuper;
32002   me->vlistId = streamInqVlist(me->streamId);
32003   if(me->vlistId == CDI_UNDEFID) goto closeStream;
32004   me->variableCount = vlistNvars(me->vlistId);
32005   if(me->variableCount <= 0) goto closeStream;
32006   me->subtypeId = CDI_UNDEFID;   //Will be set in cdiFallbackIterator_nextField()
32007   me->curSubtypeCount = -1;      //Will be set in cdiFallbackIterator_nextField()
32008   me->curLevelCount = -1;        //Will be set in cdiFallbackIterator_nextField()
32009 
32010   //These values are chosen so that the natural increment at the start of cdiFallbackIterator_nextField() will correctly position us at the first slice.
32011   me->curTimestep = 0;
32012   if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
32013   me->curVariable = -1;
32014   me->curSubtype = -1;
32015   me->curLevel = -1;
32016   me->path = path ? strdup(path) : NULL;
32017   if(!me->path) goto closeStream;
32018 
32019   return me;
32020 
32021 // ^        constructor code        ^
32022 // |                                |
32023 // v destructor/error-cleanup code  v
32024 
32025 destruct:
32026   Free(me->path);
32027 closeStream:
32028   streamClose(me->streamId);
32029 destructSuper:
32030   baseIterDestruct(&me->super);
32031   Free(me);
32032   return NULL;
32033 }
32034 
cdiFallbackIterator_new(const char * path,int filetype)32035 CdiIterator *cdiFallbackIterator_new(const char *path, int filetype)
32036 {
32037   return &cdiFallbackIterator_condestruct(NULL, path, filetype)->super;
32038 }
32039 
32040 //Fetches the info that is derived from the current variable. Most of this is published by the data members in the base class.
fetchVariableInfo(CdiFallbackIterator * me)32041 static void fetchVariableInfo(CdiFallbackIterator *me)
32042 {
32043   //Fetch data that's published via base class data members.
32044   me->super.datatype = vlistInqVarDatatype(me->vlistId, me->curVariable);
32045   me->super.timesteptype = vlistInqVarTsteptype(me->vlistId, me->curVariable);
32046   me->super.gridId = vlistInqVarGrid(me->vlistId, me->curVariable);
32047   int param = vlistInqVarParam(me->vlistId, me->curVariable);
32048   cdiDecodeParam(param, &me->super.param.number, &me->super.param.category, &me->super.param.discipline);
32049 
32050   //Fetch the current level and subtype counts.
32051   me->curLevelCount = zaxisInqSize(vlistInqVarZaxis(me->vlistId, me->curVariable));
32052   me->subtypeId = vlistInqVarSubtype(me->vlistId, me->curVariable);
32053   me->curSubtypeCount = (me->subtypeId == CDI_UNDEFID) ? 1 : subtypeInqSize(me->subtypeId);
32054 }
32055 
cdiFallbackIterator_clone(CdiIterator * super)32056 CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *super)
32057 {
32058   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
32059 
32060   //Make another stream for this file. This yields an unadvanced iterator.
32061   CdiFallbackIterator *clone = cdiFallbackIterator_condestruct(NULL, me->path, me->super.filetype);
32062   if(!clone) return NULL;
32063 
32064   //Point the clone to the same position in the file.
32065   clone->variableCount = me->variableCount;
32066   clone->curVariable = me->curVariable;
32067   clone->curLevelCount = me->curLevelCount;
32068   clone->curLevel = me->curLevel;
32069   clone->curSubtypeCount = me->curSubtypeCount;
32070   clone->curSubtype = me->curSubtype;
32071   clone->curTimestep = me->curTimestep;
32072 
32073   clone->super.isAdvanced = super->isAdvanced;
32074   if(super->isAdvanced) fetchVariableInfo(clone);
32075 
32076   return clone;
32077 }
32078 
cdiFallbackIterator_serialize(CdiIterator * super)32079 char *cdiFallbackIterator_serialize(CdiIterator *super)
32080 {
32081   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
32082 
32083   char *escapedPath = cdiEscapeSpaces(me->path);
32084   char *result = (char *) Malloc(strlen(escapedPath)
32085                          + 7 * (3 * sizeof (int) * CHAR_BIT / 8 + 1) + 1);
32086   sprintf(result, "%s %d %d %d %d %d %d %d", escapedPath, me->variableCount, me->curVariable, me->curLevelCount, me->curLevel, me->curSubtypeCount, me->curSubtype, me->curTimestep);
32087   Free(escapedPath);
32088   return result;
32089 }
32090 
cdiFallbackIterator_deserialize(const char * description)32091 CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *description)
32092 {
32093   CdiFallbackIterator *me = (CdiFallbackIterator *) Malloc(sizeof(*me));
32094   if(!me) goto fail;
32095 
32096   description = baseIter_constructFromString(&me->super, description);
32097 
32098   while(*description == ' ') description++;
32099   me->path = cdiUnescapeSpaces(description, &description);
32100   if(!me->path) goto destructSuper;
32101 
32102   me->streamId = streamOpenRead(me->path);
32103   if(me->streamId == CDI_UNDEFID) goto freePath;
32104   me->vlistId = streamInqVlist(me->streamId);
32105   if(me->vlistId == CDI_UNDEFID) goto closeStream;
32106 
32107   //This reads one variable from the description string, does error checking, and advances the given string pointer.
32108 #define decodeValue(variable, description) do \
32109     { \
32110       const char *savedStart = description; \
32111       long long decodedValue = strtoll(description, (char**)&description, 0);   /*The cast is a workaround for the wrong signature of strtoll().*/ \
32112       variable = (int)decodedValue; \
32113       if(savedStart == description) goto closeStream; \
32114       if((long long)decodedValue != (long long)variable) goto closeStream; \
32115     } while(0)
32116   decodeValue(me->variableCount, description);
32117   decodeValue(me->curVariable, description);
32118   decodeValue(me->curLevelCount, description);
32119   decodeValue(me->curLevel, description);
32120   decodeValue(me->curSubtypeCount, description);
32121   decodeValue(me->curSubtype, description);
32122   decodeValue(me->curTimestep, description);
32123 #undef decodeValue
32124 
32125   if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
32126   if(me->super.isAdvanced) fetchVariableInfo(me);
32127 
32128   return me;
32129 
32130 closeStream:
32131   streamClose(me->streamId);
32132 freePath:
32133   Free(me->path);
32134 destructSuper:
32135   baseIterDestruct(&me->super);
32136   Free(me);
32137 fail:
32138   return NULL;
32139 }
32140 
advance(CdiFallbackIterator * me)32141 static int advance(CdiFallbackIterator *me)
32142 {
32143   me->curLevel++;
32144   if(me->curLevel >= me->curLevelCount)
32145     {
32146       me->curLevel = 0;
32147       me->curSubtype++;
32148       if(me->curSubtype >= me->curSubtypeCount)
32149         {
32150           me->curSubtype = 0;
32151           me->curVariable++;
32152           if(me->curVariable >= me->variableCount)
32153             {
32154               me->curVariable = 0;
32155               me->curTimestep++;
32156               if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) return CDI_EEOF;
32157             }
32158         }
32159     }
32160   return CDI_NOERR;
32161 }
32162 
cdiFallbackIterator_nextField(CdiIterator * super)32163 int cdiFallbackIterator_nextField(CdiIterator *super)
32164 {
32165   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
32166   int result = advance(me);
32167   if(result) return result;
32168 
32169   if(!me->curLevel && !me->curSubtype) fetchVariableInfo(me);   //Check whether we are processing a new variable/timestep and fetch the information that may have changed in this case.
32170   return CDI_NOERR;
32171 }
32172 
cdiFallbackIterator_inqTime(CdiIterator * super,CdiTimeType timeType)32173 char *cdiFallbackIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
32174 {
32175   CdiFallbackIterator *me = (CdiFallbackIterator *)(void *)super;
32176 
32177   //retrieve the time information
32178   int taxisId = vlistInqTaxis(me->vlistId);
32179   int date = 0, time = 0;
32180   switch(timeType)
32181     {
32182       case kCdiTimeType_referenceTime:
32183         date = taxisInqRdate(taxisId);
32184         time = taxisInqRtime(taxisId);
32185         break;
32186 
32187       case kCdiTimeType_startTime:
32188         date = taxisInqVdate(taxisId);
32189         time = taxisInqVtime(taxisId);
32190         break;
32191 
32192       case kCdiTimeType_endTime:
32193         return NULL;   //The stream interface does not export the start/end times of statistical fields, so we treat all data as point of time data, returning the validity time as the start time.
32194 
32195       default:
32196         assert(0 && "internal error, please report this bug");
32197     }
32198 
32199   //decode the time information and reencode it into an ISO-compliant string
32200   int year, month, day, hour, minute, second;
32201   cdiDecodeDate(date, &year, &month, &day);
32202   cdiDecodeTime(time, &hour, &minute, &second);
32203   char *result
32204     = (char *) Malloc(   4+1 +2+1 +2+1 +2+1 +2+1 +2+4+1);
32205   sprintf(result,     "%04d-%02d-%02dT%02d:%02d:%02d.000", year, month, day, hour, minute, second);
32206   return result;
32207 }
32208 
cdiFallbackIterator_levelType(CdiIterator * super,int levelSelector,char ** outName,char ** outLongName,char ** outStdName,char ** outUnit)32209 int cdiFallbackIterator_levelType(CdiIterator *super, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
32210 {
32211   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
32212   int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
32213   (void)levelSelector;
32214 #define copyString(outPointer, key) do \
32215     { \
32216       if(outPointer) \
32217         { \
32218           char tempBuffer[CDI_MAX_NAME]; \
32219           int length = CDI_MAX_NAME;     \
32220           cdiInqKeyString(zaxisId, CDI_GLOBAL, key, tempBuffer, &length); \
32221           *outPointer = strdup(tempBuffer); \
32222         } \
32223     } \
32224   while(0)
32225   copyString(outName, CDI_KEY_NAME);
32226   copyString(outLongName, CDI_KEY_LONGNAME);
32227   copyString(outStdName, CDI_KEY_STDNAME);
32228   copyString(outUnit, CDI_KEY_UNITS);
32229 #undef copyString
32230   int ltype = 0;
32231   cdiInqKeyInt(zaxisId, CDI_GLOBAL, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE, &ltype);
32232   return ltype;
32233 }
32234 
cdiFallbackIterator_level(CdiIterator * super,int levelSelector,double * outValue1,double * outValue2)32235 int cdiFallbackIterator_level(CdiIterator *super, int levelSelector, double *outValue1, double *outValue2)
32236 {
32237   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
32238   int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
32239 
32240   //handle NULL pointers once and for all
32241   double trash;
32242   if(!outValue1) outValue1 = &trash;
32243   if(!outValue2) outValue2 = &trash;
32244 
32245   //get the level value
32246   if(levelSelector)
32247     {
32248       *outValue1 = (zaxisInqLbounds(zaxisId, NULL))
32249                  ? zaxisInqLbound(zaxisId, me->curLevel)
32250                  : zaxisInqLevel(zaxisId, me->curLevel);
32251     }
32252   else
32253     {
32254       *outValue1 = (zaxisInqUbounds(zaxisId, NULL))
32255                  ? zaxisInqUbound(zaxisId, me->curLevel)
32256                  : zaxisInqLevel(zaxisId, me->curLevel);
32257     }
32258   *outValue2 = 0.0;
32259 
32260   //if this is a hybrid zaxis, lookup the coordinates in the vertical coordinate table
32261   ssize_t intLevel = (ssize_t)(2**outValue1);
32262   if(0 <= intLevel && intLevel < zaxisInqVctSize(zaxisId) - 1)
32263     {
32264       const double *coordinateTable = zaxisInqVctPtr(zaxisId);
32265       *outValue1 = coordinateTable[intLevel];
32266       *outValue2 = coordinateTable[intLevel + 1];
32267     }
32268   return CDI_NOERR;
32269 }
32270 
cdiFallbackIterator_zaxisUuid(CdiIterator * super,int * outVgridNumber,int * outLevelCount,unsigned char outUuid[CDI_UUID_SIZE])32271 int cdiFallbackIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
32272 {
32273   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
32274   int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
32275   int ltype = 0;
32276   cdiInqKeyInt(zaxisId, CDI_GLOBAL, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE, &ltype);
32277   if (ltype != ZAXIS_HYBRID) return CDI_EINVAL;
32278   if (outVgridNumber)
32279     {
32280       *outVgridNumber = 0;
32281       cdiInqKeyInt(zaxisId, CDI_GLOBAL, CDI_KEY_NUMBEROFVGRIDUSED, outVgridNumber);
32282     }
32283   if (outLevelCount)
32284     {
32285       *outLevelCount = 0;
32286       cdiInqKeyInt(zaxisId, CDI_GLOBAL, CDI_KEY_NLEV, outLevelCount);
32287     }
32288   if (outUuid)
32289     {
32290       int length = CDI_UUID_SIZE;
32291       memset(outUuid, 0, length);
32292       cdiInqKeyBytes(zaxisId, CDI_GLOBAL, CDI_KEY_UUID, outUuid, &length);
32293     }
32294   return CDI_NOERR;
32295 }
32296 
cdiFallbackIterator_inqTile(CdiIterator * super,int * outTileIndex,int * outTileAttribute)32297 int cdiFallbackIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
32298 {
32299   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
32300 #ifndef __cplusplus
32301   if(!outTileIndex) outTileIndex = &(int){0};
32302   if(!outTileAttribute) outTileAttribute = &(int){0};
32303 #else
32304   int dummy = 0;
32305   if(!outTileIndex) outTileIndex = &dummy;
32306   if(!outTileAttribute) outTileAttribute = &dummy;
32307 #endif
32308 
32309   int error = CDI_NOERR;
32310   if(me->subtypeId == CDI_UNDEFID)	//must not call subtypeInqAttribute() with an invalid subtype ID, because it would abort the program instead of returning an error
32311     {
32312       error = CDI_EINVAL;
32313     }
32314   else
32315     {
32316       if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "tileIndex", outTileIndex)) error = CDI_EINVAL;
32317       if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "tileAttribute", outTileAttribute)) error = CDI_EINVAL;
32318     }
32319   if(error) *outTileIndex = *outTileAttribute = -1; //Guarantee defined values in case of an error.
32320   return error;
32321 }
32322 
cdiFallbackIterator_inqTileCount(CdiIterator * super,int * outTileCount,int * outTileAttributeCount)32323 int cdiFallbackIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
32324 {
32325   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
32326 #ifndef __cplusplus
32327   if(!outTileCount) outTileCount = &(int){0};
32328   if(!outTileAttributeCount) outTileAttributeCount = &(int){0};
32329 #else
32330   int temp = 0;
32331   if(!outTileCount) outTileCount = &temp;
32332   if(!outTileAttributeCount) outTileAttributeCount = &temp;
32333 #endif
32334 
32335   int error = CDI_NOERR;
32336   if(me->subtypeId == CDI_UNDEFID)	//must not call subtypeInqAttribute() with an invalid subtype ID, because it would abort the program instead of returning an error
32337     {
32338       error = CDI_EINVAL;
32339     }
32340   else
32341     {
32342       if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "numberOfTiles", outTileCount)) error = CDI_EINVAL;
32343       if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "numberOfTileAttributes", outTileAttributeCount)) error = CDI_EINVAL;
32344     }
32345   if(error) *outTileCount = *outTileAttributeCount = -1; //Guarantee defined values in case of an error.
32346   return CDI_NOERR;
32347 }
32348 
cdiFallbackIterator_copyVariableName(CdiIterator * super)32349 char *cdiFallbackIterator_copyVariableName(CdiIterator *super)
32350 {
32351   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
32352   return vlistCopyVarName(me->vlistId, me->curVariable);
32353 }
32354 
cdiFallbackIterator_readField(CdiIterator * super,double * buffer,size_t * nmiss)32355 void cdiFallbackIterator_readField(CdiIterator *super, double *buffer, size_t *nmiss)
32356 {
32357   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
32358   size_t missingValues = 0;
32359   streamReadVarSlice(me->streamId, me->curVariable, me->curLevel, buffer, &missingValues);
32360   if(nmiss) *nmiss = (size_t)missingValues;
32361 }
32362 
cdiFallbackIterator_readFieldF(CdiIterator * super,float * buffer,size_t * nmiss)32363 void cdiFallbackIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss)
32364 {
32365   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
32366   size_t missingValues = 0;
32367   streamReadVarSliceF(me->streamId, me->curVariable, me->curLevel, buffer, &missingValues);
32368   if(nmiss) *nmiss = (size_t)missingValues;
32369 }
32370 
cdiFallbackIterator_delete(CdiIterator * super)32371 void cdiFallbackIterator_delete(CdiIterator *super)
32372 {
32373   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
32374   cdiFallbackIterator_condestruct(me, NULL, 0);
32375 }
32376 
32377 /*
32378  * Local Variables:
32379  * c-file-style: "Java"
32380  * c-basic-offset: 2
32381  * indent-tabs-mode: nil
32382  * show-trailing-whitespace: t
32383  * require-trailing-newline: t
32384  * End:
32385  */
32386 #ifndef STREAM_GRB_H
32387 #define STREAM_GRB_H
32388 
32389 void ensureBufferSize(size_t requiredSize, size_t *curSize, void **buffer);
32390 int grbDecompress(size_t recsize, size_t *buffersize, void **gribbuffer);
32391 
gribbyte_get_bit(int number,int bit)32392 static inline bool gribbyte_get_bit(int number, int bit) { return (bool)((number >> (8-bit)) & 1); }
gribbyte_set_bit(int * number,int bit)32393 static inline void gribbyte_set_bit(int *number, int bit) { *number |= 1 << (8-bit); }
gribbyte_clear_bit(int * number,int bit)32394 static inline void gribbyte_clear_bit(int *number, int bit) { *number &= ~(1 << (8-bit)); }
32395 
32396 int   grbBitsPerValue(int datatype);
32397 
32398 int   grbInqContents(stream_t *streamptr);
32399 int   grbInqTimestep(stream_t *streamptr, int tsID);
32400 
32401 int   grbInqRecord(stream_t *streamptr, int *varID, int *levelID);
32402 void  grbDefRecord(stream_t *streamptr);
32403 void  grb_read_record(stream_t *streamptr, int memtype, void *data, size_t *nmiss);
32404 void  grb_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss);
32405 void  grbCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
32406 
32407 void  grb_read_var(stream_t *streamptr, int varID, int memtype, void *data, size_t *nmiss);
32408 void  grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss);
32409 
32410 void  grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, size_t *nmiss);
32411 void  grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss);
32412 
32413 int   grib1ltypeToZaxisType(int grib_ltype);
32414 int   grib2ltypeToZaxisType(int grib_ltype);
32415 
32416 int   zaxisTypeToGrib1ltype(int zaxistype);
32417 int   zaxisTypeToGrib2ltype(int zaxistype);
32418 
32419 int grbGetGridtype(int *gridID, size_t gridsize, bool *gridIsRotated, bool *gridIsCurvilinear);
32420 
32421 struct cdiGribParamChange
32422 {
32423   int code, ltype, lev;
32424   bool active;
32425 };
32426 
32427 struct cdiGribScanModeChange
32428 {
32429   int value;
32430   bool active;
32431 };
32432 
32433 extern struct cdiGribParamChange cdiGribChangeParameterID;
32434 extern struct cdiGribScanModeChange cdiGribDataScanningMode;
32435 
32436 // Used in CDO
32437 void streamGrbChangeParameterIdentification(int code, int ltype, int lev);
32438 void streamGrbDefDataScanningMode(int scanmode);
32439 
32440 #endif  /* STREAM_GRB_H */
32441 /*
32442  * Local Variables:
32443  * c-file-style: "Java"
32444  * c-basic-offset: 2
32445  * indent-tabs-mode: nil
32446  * show-trailing-whitespace: t
32447  * require-trailing-newline: t
32448  * End:
32449  */
32450 #ifndef  ZAXIS_H
32451 #define  ZAXIS_H
32452 
32453 #ifdef  HAVE_CONFIG_H
32454 #endif
32455 
32456 
32457 
32458 typedef struct {
32459   double    *vals;
32460 #ifndef USE_MPI
32461   char     **cvals;
32462   int        clength;
32463 #endif
32464   double    *lbounds;
32465   double    *ubounds;
32466   double    *weights;
32467   int        self;
32468   int        datatype;
32469   int        scalar;
32470   int        type;
32471   int        size;
32472   int        direction;
32473   int        vctsize;
32474   unsigned   positive;
32475   double    *vct;
32476   cdi_keys_t keys;
32477   cdi_atts_t atts;
32478 }
32479 zaxis_t;
32480 
32481 
32482 void zaxisGetTypeDescription(int zaxisType, int* outPositive, const char** outName, const char** outLongName, const char** outStdName, const char** outUnit);  //The returned const char* point to static storage. Don't free or modify them.
32483 
32484 unsigned cdiZaxisCount(void);
32485 
32486 zaxis_t *zaxis_to_pointer(int zaxisID);
32487 
32488 void cdiZaxisGetIndexList(unsigned numIDs, int *IDs);
32489 
32490 void
32491 zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
32492             int * unpackBufferPos, int originNamespace, void *context,
32493             int force_id);
32494 
32495 const resOps *getZaxisOps(void);
32496 
32497 const char *zaxisInqNamePtr(int zaxisID);
32498 
32499 const double *zaxisInqLevelsPtr(int zaxisID);
32500 #ifndef USE_MPI
32501 char **zaxisInqCValsPtr(int zaxisID);
32502 #endif
32503 void zaxisResize(int zaxisID, int size);
32504 
32505 #endif
32506 
32507 /*
32508  * Local Variables:
32509  * c-file-style: "Java"
32510  * c-basic-offset: 2
32511  * indent-tabs-mode: nil
32512  * show-trailing-whitespace: t
32513  * require-trailing-newline: t
32514  * End:
32515  */
32516 #ifdef HAVE_CONFIG_H
32517 #endif
32518 
32519 
32520 
32521 #include <assert.h>
32522 #include <limits.h>
32523 #include <stdlib.h>
32524 #include <string.h>
32525 
32526 
32527 #ifdef HAVE_LIBGRIB_API
32528 
32529 struct CdiGribIterator {
32530   CdiIterator super;
32531 
32532   CdiInputFile *file;
32533   off_t fileOffset;
32534   unsigned char *gribBuffer;
32535   size_t bufferSize, curRecordSize;
32536   grib_handle *gribHandle;
32537 };
32538 
cdiGribIterator_getSuper(CdiGribIterator * me)32539 CdiIterator *cdiGribIterator_getSuper(CdiGribIterator *me)
32540 {
32541   return &me->super;
32542 }
32543 
32544 //Since the error handling in constructors is usually very closely related to the workings of a destructor,
32545 //this function combines both functions in one, using a centralized exit.
32546 //The mode of operation depends on whether me is a NULL pointer on entry:
32547 //If it is NULL, a new object is allocated and constructed, which is returned if construction is successful.
32548 //If a non-NULL pointer is passed in, the object is destructed and NULL is returned. In this case, the other arguments are ignored.
cdiGribIterator_condestruct(CdiGribIterator * me,const char * path,int filetype)32549 static CdiGribIterator *cdiGribIterator_condestruct(CdiGribIterator *me, const char *path, int filetype)
32550 {
32551 #define super() (&me->super)
32552   if(me) goto destruct;
32553   me = (CdiGribIterator *) Malloc(sizeof(*me));
32554   baseIterConstruct(super(), filetype);
32555 
32556   me->file = cdiInputFile_make(path);
32557   if(!me->file) goto destructSuper;
32558   me->fileOffset = 0;
32559   me->gribHandle = NULL;
32560   me->gribBuffer = NULL;
32561   me->bufferSize = me->curRecordSize = 0;
32562   me->super.gridId = CDI_UNDEFID;
32563 
32564   goto success;
32565 
32566 // ^        constructor code        ^
32567 // |                                |
32568 // v destructor/error-cleanup code  v
32569 
32570 destruct:
32571   if(me->super.gridId != CDI_UNDEFID) gridDestroy(me->super.gridId);
32572   if(me->gribHandle) grib_handle_delete((struct grib_handle *)me->gribHandle);
32573   Free(me->gribBuffer);
32574   cdiRefObject_release(&me->file->super);
32575 destructSuper:
32576   baseIterDestruct(super());
32577   Free(me);
32578   me = NULL;
32579 
32580 success:
32581   return me;
32582 #undef super
32583 }
32584 
cdiGribIterator_new(const char * path,int filetype)32585 CdiIterator *cdiGribIterator_new(const char *path, int filetype)
32586 {
32587   return &cdiGribIterator_condestruct(NULL, path, filetype)->super;
32588 }
32589 
cdiGribIterator_makeClone(CdiIterator * super)32590 CdiGribIterator *cdiGribIterator_makeClone(CdiIterator *super)
32591 {
32592   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
32593 
32594   //Allocate memory and copy data. (operations that may fail)
32595   CdiGribIterator *result = (struct CdiGribIterator *) Malloc(sizeof(*result));
32596   if(!result) goto fail;
32597 
32598   result->file = me->file;
32599   result->fileOffset = me->fileOffset;
32600   result->gribBuffer = NULL;
32601   result->bufferSize = me->bufferSize;
32602   result->curRecordSize = me->curRecordSize;
32603   result->gribHandle = NULL;
32604 
32605   if(me->gribBuffer)
32606     {
32607       result->gribBuffer = (unsigned char *) Malloc(me->bufferSize);
32608       if(!result->gribBuffer) goto freeResult;
32609       memcpy(result->gribBuffer, me->gribBuffer, me->curRecordSize);
32610     }
32611   if(me->gribHandle)
32612     {
32613       result->gribHandle = grib_handle_new_from_message(NULL, result->gribBuffer, result->curRecordSize);
32614       if(!result->gribHandle) goto freeBuffer;
32615     }
32616   if(super->gridId != CDI_UNDEFID)
32617     {
32618       result->super.gridId = gridDuplicate(super->gridId);
32619       if(result->super.gridId == CDI_UNDEFID) goto deleteGribHandle;
32620     }
32621 
32622   //Finish construction. (operations that cannot fail)
32623   baseIterConstruct(&result->super, super->filetype);
32624   result->super.datatype = super->datatype;
32625   result->super.timesteptype = super->timesteptype;
32626   result->super.param = super->param;
32627   cdiRefObject_retain(&result->file->super);
32628 
32629   return result;
32630 
32631   //Error handling.
32632 deleteGribHandle:
32633   if(result->gribHandle) grib_handle_delete(result->gribHandle);
32634 freeBuffer:
32635   Free(result->gribBuffer);
32636 freeResult:
32637   Free(result);
32638 fail:
32639   return NULL;
32640 }
32641 
cdiGribIterator_serialize(CdiIterator * super)32642 char *cdiGribIterator_serialize(CdiIterator *super)
32643 {
32644   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
32645 
32646   const char *path = cdiInputFile_getPath(me->file);
32647   char *escapedPath = cdiEscapeSpaces(path);
32648   char *result = (char *) Malloc(strlen(escapedPath) + 3 * sizeof(int) * CHAR_BIT/8);
32649   sprintf(result, "%s %zu", escapedPath, (size_t)me->fileOffset);
32650   Free(escapedPath);
32651   return result;
32652 }
32653 
32654 
cdiGribIterator_deserialize(const char * description)32655 CdiGribIterator *cdiGribIterator_deserialize(const char *description)
32656 {
32657   char *path;
32658   CdiGribIterator *me = (CdiGribIterator *) Malloc(sizeof(*me));
32659   if(!me) goto fail;
32660 
32661   description = baseIter_constructFromString(&me->super, description);
32662 
32663   while(*description == ' ') description++;
32664   path = cdiUnescapeSpaces(description, &description);
32665   if(!path) goto destructSuper;
32666 
32667   me->file = cdiInputFile_make(path);
32668   Free(path);
32669   if(!me->file) goto destructSuper;
32670 
32671   {
32672     const char *savedStart = description;
32673     char *description_ = (char *)description;
32674     long long decodedOffset = strtoll(description, &description_, 0);
32675     description = description_;
32676     me->fileOffset = (off_t)decodedOffset;
32677     if(savedStart == description) goto closeFile;
32678     if((unsigned long long)decodedOffset > (unsigned long long)me->fileOffset) goto closeFile;
32679   }
32680 
32681   me->gribBuffer = NULL;
32682   me->bufferSize = me->curRecordSize = 0;
32683   me->gribHandle = NULL;
32684   me->super.gridId = CDI_UNDEFID;
32685   if(me->super.isAdvanced && cdiGribIterator_nextField(&me->super)) goto closeFile;
32686 
32687   return me;
32688 
32689 
32690 closeFile:
32691   cdiRefObject_release(&me->file->super);
32692 destructSuper:
32693   baseIterDestruct(&me->super);
32694   Free(me);
32695 fail:
32696   return NULL;
32697 }
32698 
cdiGribIterator_ensureBuffer(CdiGribIterator * me,size_t requiredSize)32699 static void cdiGribIterator_ensureBuffer(CdiGribIterator *me, size_t requiredSize)
32700 {
32701   if(me->bufferSize < requiredSize)
32702     {
32703       me->bufferSize *= 2;
32704       if(me->bufferSize < requiredSize) me->bufferSize = requiredSize;
32705       me->gribBuffer = (unsigned char *) Realloc(me->gribBuffer, me->bufferSize);
32706     }
32707 }
32708 
isGrib1DualLevel(int levelType)32709 static bool isGrib1DualLevel(int levelType)
32710 {
32711   switch(levelType)
32712     {
32713       case 101: case 104: case 106: case 108: case 110: case 112:
32714       case 114: case 116: case 120: case 121: case 128: case 141:   //This is the complete list after grib_api-1.12.3/definitions/grib1/sections.1.def:106-117:, the code in cdi/src/stream_gribapi.c:grib1GetLevel() seems to be incomplete.
32715         return true;
32716       default:
32717         return false;
32718     }
32719 }
32720 
positionOfGribMarker(const unsigned char * data,size_t size)32721 static const unsigned char *positionOfGribMarker(const unsigned char *data, size_t size)
32722 {
32723   for(const unsigned char *currentPosition = data, *end = data + size; currentPosition < end; currentPosition++)
32724     {
32725       currentPosition = (unsigned char *)memchr(currentPosition, 'G', size - (size_t)(currentPosition - data) - 3);      //-3 to ensure that we don't overrun the buffer during the strncmp() call.
32726       if(!currentPosition) return NULL;
32727       if(!strncmp((const char*)currentPosition, "GRIB", 4)) return currentPosition;
32728     }
32729   return NULL;
32730 }
32731 
32732 //This clobbers the contents of the gribBuffer!
32733 //Returns the file offset of the next 'GRIB' marker.
scanToGribMarker(CdiGribIterator * me)32734 static ssize_t scanToGribMarker(CdiGribIterator *me)
32735 {
32736   cdiGribIterator_ensureBuffer(me, 8*1024);
32737   const size_t kMaxScanSize = 16*1024*1024;
32738   for(size_t scannedBytes = 0, scanSize; scannedBytes < kMaxScanSize; scannedBytes += scanSize)
32739     {
32740       //Load a chunk of data into our buffer.
32741       scanSize = me->bufferSize;
32742       if(scannedBytes + scanSize > kMaxScanSize) scanSize = kMaxScanSize - scannedBytes;
32743       assert(scanSize <= me->bufferSize);
32744       int status = cdiInputFile_read(me->file, me->fileOffset + (off_t)scannedBytes, scanSize, &scanSize, me->gribBuffer);
32745       if(status != CDI_NOERR && status != CDI_EEOF) return -1;
32746 
32747       const unsigned char *startPosition = positionOfGribMarker(me->gribBuffer, scanSize);
32748       if(startPosition)
32749         {
32750           return (ssize_t)(me->fileOffset + (off_t)scannedBytes + (off_t)(startPosition - me->gribBuffer));
32751         }
32752 
32753       //Get the offset for the next iteration if there is a next iteration.
32754       scanSize -= 3;        //so that we won't miss a 'GRIB' sequence that happens to be cut off
32755       scanSize &= ~(size_t)0xf; //make 16 bytes aligned
32756       if((ssize_t)scanSize <= 0) return -1; //ensure that we make progress
32757     }
32758   return -1;
32759 }
32760 
decode24(void * beData)32761 static unsigned decode24(void *beData)
32762 {
32763   unsigned char *bytes = (unsigned char *)beData;
32764   return ((unsigned)bytes[0] << 16) + ((unsigned)bytes[1] << 8) + (unsigned)bytes[2];
32765 }
32766 
decode64(void * beData)32767 static uint64_t decode64(void *beData)
32768 {
32769   unsigned char *bytes = (unsigned char *)beData;
32770   uint64_t result = 0;
32771   for(size_t i = 0; i < 8; i++) result = (result << 8) + bytes[i];
32772   return result;
32773 }
32774 
32775 //Determine the size of the GRIB record that begins at the given file offset.
getRecordSize(CdiGribIterator * me,off_t gribFileOffset,size_t * outRecordSize)32776 static int getRecordSize(CdiGribIterator *me, off_t gribFileOffset, size_t *outRecordSize)
32777 {
32778   char buffer[16];
32779   size_t readSize;
32780   int status = cdiInputFile_read(me->file, gribFileOffset, sizeof(buffer), &readSize, buffer);
32781   if(status != CDI_NOERR && status != CDI_EEOF) return status;
32782   if(readSize < sizeof(buffer)) return CDI_EEOF;
32783   *outRecordSize = 0;
32784   switch(buffer[7])
32785     {
32786       case 1:
32787         *outRecordSize = decode24(&buffer[4]);
32788         if(*outRecordSize & (1 << 23))
32789           {
32790             *outRecordSize = 120*(*outRecordSize & ((1 << 23) - 1));    //Rescaling for long records.
32791             //The corresponding code in cgribexlib.c:4532-4570: is much more complicated
32792             //due to the fact that it subtracts the padding bytes that are inserted after section 4.
32793             //However, we are only interested in the total size of data we need to read here,
32794             //so we can ignore the presence of some padding bytes.
32795           }
32796         return CDI_NOERR;
32797 
32798       case 2:
32799         *outRecordSize =  decode64(&buffer[8]);
32800         return CDI_NOERR;
32801 
32802       default:
32803         return CDI_EUFTYPE;
32804     }
32805 }
32806 
32807 #if 0
32808 static void hexdump(void *data, size_t size)
32809 {
32810   unsigned char *charData = data;
32811   for(size_t offset = 0; offset < size; )
32812     {
32813       printf("%016zx:", offset);
32814       for(size_t i = 0; i < 64 && offset < size; i++, offset++)
32815         {
32816           if((i & 63) && !(i & 15)) printf(" |");
32817           if((i & 15) && !(i & 3)) printf("  ");
32818           printf(" %02x", charData[offset]);
32819         }
32820       printf("\n");
32821     }
32822 }
32823 #endif
32824 
32825 //Read a record into memory and wrap it in a grib_handle.
32826 //XXX: I have omitted checking for szip compression as it is done in grbReadVarDP() & friends since that appears to be a non-standard extension of the GRIB1 standard: bit 1 in octet 14 of the binary data section which is used to signal szip compressio is defined to be reserved in the standard. As such, it seems prudent not to support this and to encourage people with such szip compressed files to switch to the GRIB2/JPEG2000 format. However, in the case that this reasoning is wrong, this function is probably the place to add the check for zsip compression.
readMessage(CdiGribIterator * me)32827 static int readMessage(CdiGribIterator *me)
32828 {
32829   //Destroy the old grib_handle.
32830   if(me->gribHandle) grib_handle_delete(me->gribHandle), me->gribHandle = NULL;
32831   me->fileOffset += (off_t)me->curRecordSize;
32832 
32833   //Find the next record and determine its size.
32834   ssize_t gribFileOffset = scanToGribMarker(me);
32835   int result = CDI_EEOF;
32836   if(gribFileOffset < 0) goto fail;
32837   result = getRecordSize(me, gribFileOffset, &me->curRecordSize);
32838   if(result) goto fail;
32839 
32840   //Load the whole record into our buffer and create a grib_handle for it.
32841   cdiGribIterator_ensureBuffer(me, me->curRecordSize);
32842   result = cdiInputFile_read(me->file, gribFileOffset, me->curRecordSize, NULL, me->gribBuffer);
32843   if(result) goto fail;
32844   me->gribHandle = grib_handle_new_from_message(NULL, me->gribBuffer, me->curRecordSize);
32845   result = CDI_EUFSTRUCT;
32846   if(!me->gribHandle) goto fail;
32847 
32848   return CDI_NOERR;
32849 
32850 fail:
32851   me->curRecordSize = 0;        //This ensures that we won't jump to an uncontrolled file position if cdiGribIterator_nextField() is called another time after it has returned an error.
32852   return result;
32853 }
32854 
cdiGribIterator_nextField(CdiIterator * super)32855 int cdiGribIterator_nextField(CdiIterator *super)
32856 {
32857   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
32858 
32859   if(super->gridId != CDI_UNDEFID) gridDestroy(super->gridId), super->gridId = CDI_UNDEFID;
32860 
32861   //Get the next GRIB message into our buffer.
32862   int result = readMessage(me);
32863   if(result) return result;
32864 
32865   //Get the metadata that's published as variables in the base class.
32866   super->datatype = gribGetDatatype(me->gribHandle);
32867   super->timesteptype = gribapiGetTsteptype(me->gribHandle);
32868   cdiDecodeParam(gribapiGetParam(me->gribHandle), &super->param.number, &super->param.category, &super->param.discipline);
32869   grid_t grid;
32870   gribapiGetGrid(me->gribHandle, &grid);
32871   super->gridId = gridGenerate(&grid);
32872 
32873   return CDI_NOERR;
32874 }
32875 
cdiGribIterator_inqTime(CdiIterator * super,CdiTimeType timeType)32876 char *cdiGribIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
32877 {
32878   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
32879   return gribMakeTimeString(me->gribHandle, timeType);
32880 }
32881 
cdiGribIterator_levelType(CdiIterator * super,int levelSelector,char ** outName,char ** outLongName,char ** outStdName,char ** outUnit)32882 int cdiGribIterator_levelType(CdiIterator *super, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
32883 {
32884   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
32885 
32886   //First determine the zaxis type corresponding to the given level.
32887   int zaxisType = ZAXIS_GENERIC;
32888   if(gribEditionNumber(me->gribHandle) <= 1)
32889     {
32890       int levelType = (int)gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", 255);
32891       if(levelSelector && !isGrib1DualLevel(levelType)) levelType = 255;
32892       zaxisType = grib1ltypeToZaxisType(levelType);
32893     }
32894   else
32895     {
32896       int levelType = (int)gribGetLongDefault(me->gribHandle, levelSelector ? "typeOfSecondFixedSurface" : "typeOfFirstFixedSurface", 255);
32897       zaxisType = grib2ltypeToZaxisType(levelType);
32898     }
32899 
32900   //Then lookup the requested names.
32901   const char *name, *longName, *stdName, *unit;
32902   zaxisGetTypeDescription(zaxisType, NULL, &name, &longName, &stdName, &unit);
32903   if(outName) *outName = strdup(name);
32904   if(outLongName) *outLongName = strdup(longName);
32905   if(outStdName) *outStdName = strdup(stdName);
32906   if(outUnit) *outUnit = strdup(unit);
32907 
32908   return zaxisType;
32909 }
32910 
logicalLevelValue2(long gribType,long storedValue,long power)32911 static double logicalLevelValue2(long gribType, long storedValue, long power)
32912 {
32913   double factor = 1;
32914   assert(power >= 0);
32915   while(power--) factor *= 10;      //this is precise up to factor == 22.
32916   switch(gribType)
32917     {
32918       case GRIB2_LTYPE_LANDDEPTH:
32919       case GRIB2_LTYPE_ISOBARIC:
32920       case GRIB2_LTYPE_SIGMA:
32921         return (double)storedValue * (1000.0/factor);      //The evaluation order allows the factors of ten to cancel out before rounding.
32922 
32923       case 255:
32924         return 0;
32925 
32926       default:
32927         return (double)storedValue/factor;
32928     }
32929 }
32930 
32931 //The output values must be preinitialized, this function does not always write them.
readLevel2(grib_handle * gribHandle,const char * levelTypeKey,const char * powerKey,const char * valueKey,double * outValue1,double * outValue2)32932 static int readLevel2(grib_handle *gribHandle, const char *levelTypeKey, const char *powerKey, const char *valueKey, double *outValue1, double *outValue2)
32933 {
32934   assert(levelTypeKey && powerKey && valueKey && outValue1 && outValue2);
32935 
32936   long levelType = gribGetLongDefault(gribHandle, levelTypeKey, 255);   //1 byte
32937   switch(levelType)
32938     {
32939       case 255: break;
32940 
32941       case 105: case 113:
32942         {
32943           unsigned long value = (unsigned long)gribGetLongDefault(gribHandle, valueKey, 0);
32944           unsigned long coordinateCount = (unsigned long)gribGetLongDefault(gribHandle, "numberOfCoordinatesValues", 0);
32945           if(value >= coordinateCount/2)
32946             {
32947               Error("Invalid level coordinate: Level has the hybrid coordinate index %lu, but only %lu coordinate pairs are present.", value, coordinateCount/2);
32948               return CDI_EUFSTRUCT;
32949             }
32950           int status;
32951           //XXX: I'm not 100% sure about how the coordinate pairs are stored in the file.
32952           //     I'm assuming an array of pairs due to the example code in grib_api-1.12.3/examples/F90/set_pv.f90, but that may be wrong.
32953           if((status = grib_get_double_element(gribHandle, "pv", (int)value*2    , outValue1))) return status;
32954           if((status = grib_get_double_element(gribHandle, "pv", (int)value*2 + 1, outValue2))) return status;
32955           break;
32956         }
32957 
32958       default:
32959         {
32960           long power = 255 & gribGetLongDefault(gribHandle, powerKey, 0);  //1 byte
32961           if(power == 255) power = 0;
32962           long value = gribGetLongDefault(gribHandle, valueKey, 0);   //4 bytes
32963           *outValue1 = logicalLevelValue2(levelType, value, power);
32964         }
32965     }
32966   return CDI_NOERR;
32967 }
32968 
cdiGribIterator_level(CdiIterator * super,int levelSelector,double * outValue1,double * outValue2)32969 int cdiGribIterator_level(CdiIterator *super, int levelSelector, double *outValue1, double *outValue2)
32970 {
32971   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
32972   double trash;
32973   if(!outValue1) outValue1 = &trash;
32974   if(!outValue2) outValue2 = &trash;
32975   *outValue1 = *outValue2 = 0;
32976 
32977   if(gribEditionNumber(me->gribHandle) > 1)
32978     {
32979       if(levelSelector)
32980         {
32981           return readLevel2(me->gribHandle, "typeOfFirstFixedSurface", "scaleFactorOfFirstFixedSurface", "scaledValueOfFirstFixedSurface", outValue1, outValue2);
32982         }
32983       else
32984         {
32985           return readLevel2(me->gribHandle, "typeOfSecondFixedSurface", "scaleFactorOfSecondFixedSurface", "scaledValueOfSecondFixedSurface", outValue1, outValue2);
32986         }
32987     }
32988   else
32989     {
32990       long levelType = (uint8_t)gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", -1);    //1 byte
32991       if(levelType == 255)
32992         {}
32993       else if(isGrib1DualLevel((int)levelType))
32994         {
32995           *outValue1 = (double)(gribGetLongDefault(me->gribHandle, (levelSelector ? "bottomLevel" : "topLevel"), 0));
32996         }
32997       else if(levelType == 100)
32998         {
32999           *outValue1 = 100 * (double)(gribGetLongDefault(me->gribHandle, "level", 0));        //2 bytes
33000         }
33001       else
33002         {
33003           *outValue1 = (double)(gribGetLongDefault(me->gribHandle, "level", 0));        //2 bytes
33004         }
33005     }
33006   return CDI_NOERR;
33007 }
33008 
cdiGribIterator_zaxisUuid(CdiIterator * super,int * outVgridNumber,int * outLevelCount,unsigned char outUuid[CDI_UUID_SIZE])33009 int cdiGribIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
33010 {
33011   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
33012 
33013   if(outVgridNumber)
33014     {
33015       long temp;
33016       if(grib_get_long(me->gribHandle, "numberOfVGridUsed", &temp)) return CDI_EINVAL;
33017       *outVgridNumber = (int)temp;
33018     }
33019   if(outLevelCount)
33020     {
33021       long temp;
33022       if(grib_get_long(me->gribHandle, "nlev", &temp)) return CDI_EINVAL;
33023       *outLevelCount = (int)temp;
33024     }
33025   if(outUuid)
33026     {
33027       size_t size = CDI_UUID_SIZE;
33028       if(grib_get_bytes(me->gribHandle, "uuidOfVGrid", outUuid, &size)) return CDI_EINVAL;
33029       if(size != CDI_UUID_SIZE) return CDI_EUFSTRUCT;
33030     }
33031 
33032   return CDI_NOERR;
33033 }
33034 
cdiGribIterator_inqTile(CdiIterator * super,int * outTileIndex,int * outTileAttribute)33035 int cdiGribIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
33036 {
33037   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
33038   int trash;
33039   if(!outTileIndex) outTileIndex = &trash;
33040   if(!outTileAttribute) outTileAttribute = &trash;
33041 
33042   //Get the values if possible.
33043   int error = CDI_NOERR;
33044   long value;
33045   if(grib_get_long(me->gribHandle, "tileIndex", &value)) error = CDI_EINVAL;
33046   *outTileIndex = (int)value;
33047   if(grib_get_long(me->gribHandle, "tileAttribute", &value)) error = CDI_EINVAL;
33048   *outTileAttribute = (int)value;
33049 
33050   //Ensure defined return values in case of failure.
33051   if(error) *outTileIndex = *outTileAttribute = -1;
33052   return error;
33053 }
33054 
cdiGribIterator_inqTileCount(CdiIterator * super,int * outTileCount,int * outTileAttributeCount)33055 int cdiGribIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
33056 {
33057   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
33058   int trash;
33059   if(!outTileCount) outTileCount = &trash;
33060   if(!outTileAttributeCount) outTileAttributeCount = &trash;
33061 
33062   //Get the values if possible.
33063   int error = CDI_NOERR;
33064   long value;
33065   if(grib_get_long(me->gribHandle, "numberOfTiles", &value)) error = CDI_EINVAL;
33066   *outTileCount = (int)value;
33067   if(grib_get_long(me->gribHandle, "numberOfTileAttributes", &value)) error = CDI_EINVAL;
33068   *outTileAttributeCount = (int)value;
33069 
33070   //Ensure defined return values in case of failure.
33071   if(error) *outTileCount = *outTileAttributeCount = 0;
33072   return error;
33073 }
33074 
cdiGribIterator_copyVariableName(CdiIterator * super)33075 char *cdiGribIterator_copyVariableName(CdiIterator *super)
33076 {
33077   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
33078   return gribCopyString(me->gribHandle, "shortName");
33079 }
33080 
cdiGribIterator_readField(CdiIterator * super,double * buffer,size_t * nmiss)33081 void cdiGribIterator_readField(CdiIterator *super, double *buffer, size_t *nmiss)
33082 {
33083   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
33084 
33085   GRIB_CHECK(my_grib_set_double(me->gribHandle, "missingValue", CDI_Default_Missval), 0);
33086   gribGetDoubleArray(me->gribHandle, "values", buffer);
33087   long gridType = gribGetLong(me->gribHandle, "gridDefinitionTemplateNumber");
33088   if(nmiss)
33089     {
33090       *nmiss = (gridType >= 50 && gridType <= 53) ? (size_t)0 : (size_t)gribGetLong(me->gribHandle, "numberOfMissing");        //The condition excludes harmonic data.
33091     }
33092 }
33093 
cdiGribIterator_readFieldF(CdiIterator * super,float * buffer,size_t * nmiss)33094 void cdiGribIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss)
33095 {
33096   CdiGribIterator *me = (CdiGribIterator*)(void *)super;
33097 
33098   size_t valueCount = gribGetArraySize(me->gribHandle, "values");
33099   double *temp = (double *) Malloc(valueCount*sizeof(*temp));
33100   cdiGribIterator_readField(super, temp, nmiss);
33101   for(size_t i = valueCount; i--; ) buffer[i] = (float)temp[i];
33102   Free(temp);
33103 }
33104 #endif
33105 
33106 /*
33107 @Function cdiGribIterator_delete
33108 @Title Dispose off a CdiGribIterator instance.
33109 
33110 @Prototype void cdiGribIterator_delete(CdiGribIterator *me)
33111 @Parameter
33112     @item me The iterator to delete.
33113 
33114 @Description
33115     Combined destructor and deallocator. Make sure to match every call to cdiGribIterator_clone() with a call to this function.
33116 */
cdiGribIterator_delete(CdiGribIterator * me)33117 void cdiGribIterator_delete(CdiGribIterator *me)
33118 {
33119 #ifdef HAVE_LIBGRIB_API
33120   if(me) cdiGribIterator_condestruct(me, NULL, 0);
33121 #else
33122   if (me)
33123     xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33124 #endif
33125 }
33126 
33127 
33128 ////////////////////////////////////////////////////////////////////////////////////////////////////
33129 // callthroughs to provide direct access to the grib keys //////////////////////////////////////////
33130 ////////////////////////////////////////////////////////////////////////////////////////////////////
33131 
33132 /*
33133 @Function cdiGribIterator_inqEdition
33134 @Title Get the version of the GRIB standard that is used
33135 
33136 @Prototype int cdiGribIterator_inqEdition(CdiGribIterator *me)
33137 @Parameter
33138     @item me The iterator to operate on.
33139 
33140 @Result The GRIB version.
33141 
33142 @Description
33143     Returns the version of the file format.
33144 */
cdiGribIterator_inqEdition(CdiGribIterator * me)33145 int cdiGribIterator_inqEdition(CdiGribIterator *me)
33146 {
33147 #ifdef HAVE_LIBGRIB_API
33148   return (int)gribEditionNumber(me->gribHandle);
33149 #else
33150   (void)me;
33151   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33152   return -4;
33153 #endif
33154 }
33155 
33156 /*
33157 @Function cdiGribIterator_getLong
33158 @Title Access to grib_get_long()
33159 
33160 @Prototype int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *result)
33161 @Parameter
33162     @item me The iterator to operate on.
33163     @item ... The arguments to the underlying GRIB-API function.
33164 
33165 @Result An error code.
33166 
33167 @Description
33168     Callthrough to grib_get_long().
33169 */
cdiGribIterator_getLong(CdiGribIterator * me,const char * key,long * result)33170 int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *result)
33171 {
33172 #ifdef HAVE_LIBGRIB_API
33173   return grib_get_long(me->gribHandle, key, result);
33174 #else
33175   (void)me;
33176   (void)key;
33177   (void)result;
33178   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33179   return -4;
33180 #endif
33181 }
33182 
33183 /*
33184 @Function cdiGribIterator_getLength
33185 @Title Access to grib_get_length()
33186 
33187 @Prototype int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *result)
33188 @Parameter
33189     @item me The iterator to operate on.
33190     @item ... The arguments to the underlying GRIB-API function.
33191 
33192 @Result An error code.
33193 
33194 @Description
33195     Callthrough to grib_get_length().
33196 */
cdiGribIterator_getLength(CdiGribIterator * me,const char * key,size_t * result)33197 int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *result)
33198 {
33199 #ifdef HAVE_LIBGRIB_API
33200 #ifdef HAVE_GRIB_GET_LENGTH
33201   return grib_get_length(me->gribHandle, key, result);
33202 #else
33203   (void)me;
33204   (void)key;
33205   (void)result;
33206   Error("grib_get_length() is not available, so cdiGribIterator_getLength() can't be used");
33207   return -1;
33208 #endif
33209 #else
33210   (void)me;
33211   (void)key;
33212   (void)result;
33213   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33214   return -4;
33215 #endif
33216 }
33217 
33218 /*
33219 @Function cdiGribIterator_getString
33220 @Title Access to grib_get_string()
33221 
33222 @Prototype int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *result, size_t *length)
33223 @Parameter
33224     @item me The iterator to operate on.
33225     @item ... The arguments to the underlying GRIB-API function.
33226 
33227 @Result An error code.
33228 
33229 @Description
33230     Callthrough to grib_get_string().
33231 */
cdiGribIterator_getString(CdiGribIterator * me,const char * key,char * result,size_t * length)33232 int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *result, size_t *length)
33233 {
33234 #ifdef HAVE_LIBGRIB_API
33235   return grib_get_string(me->gribHandle, key, result, length);
33236 #else
33237   (void)me;
33238   (void)key;
33239   (void)result;
33240   (void)length;
33241   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33242   return -4;
33243 #endif
33244 }
33245 
33246 /*
33247 @Function cdiGribIterator_inqLongValue
33248 @Title Get the value of a GRIB-API key as a long
33249 
33250 @Prototype long cdiGribIterator_inqLongValue(CdiGribIterator *me, const char *key)
33251 @Parameter
33252     @item me The iterator to operate on.
33253     @item key The GRIB-API key to retrieve.
33254 
33255 @Result The value of the key.
33256 
33257 @Description
33258     Use this to fetch a grib value if you are certain that the given key must be present.
33259     This will abort the process if the key cannot be retrieved.
33260 */
cdiGribIterator_inqLongValue(CdiGribIterator * me,const char * key)33261 long cdiGribIterator_inqLongValue(CdiGribIterator *me, const char *key)
33262 {
33263 #ifdef HAVE_LIBGRIB_API
33264   return gribGetLong(me->gribHandle, key);
33265 #else
33266   (void)me;
33267   (void)key;
33268   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33269   return -4;
33270 #endif
33271 }
33272 
33273 /*
33274 @Function cdiGribIterator_inqLongDefaultValue
33275 @Title Get the value of a GRIB-API key as a long
33276 
33277 @Prototype long cdiGribIterator_inqLongDefaultValue(CdiGribIterator *me, const char *key, long defaultValue)
33278 @Parameter
33279     @item me The iterator to operate on.
33280     @item key The GRIB-API key to retrieve.
33281     @item defaultValue The value to return if the key is not present.
33282 
33283 @Result The value of the key or the given default value.
33284 
33285 @Description
33286     Use this if you can handle failure to fetch the key by supplying a default value.
33287     This function cannot fail.
33288 */
cdiGribIterator_inqLongDefaultValue(CdiGribIterator * me,const char * key,long defaultValue)33289 long cdiGribIterator_inqLongDefaultValue(CdiGribIterator *me, const char *key, long defaultValue)
33290 {
33291 #ifdef HAVE_LIBGRIB_API
33292   return gribGetLongDefault(me->gribHandle, key, defaultValue);
33293 #else
33294   (void)me;
33295   (void)key;
33296   (void)defaultValue;
33297   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33298   return -4;
33299 #endif
33300 }
33301 
33302 /*
33303 @Function cdiGribIterator_inqStringValue
33304 @Title Safely retrieve a GRIB-API key with a string value
33305 
33306 @Prototype char *cdiGribIterator_inqStringValue(CdiGribIterator *me, const char *key)
33307 @Parameter
33308     @item me The iterator to operate on.
33309     @item key The GRIB-API key to retrieve.
33310 
33311 @Result A malloc'ed string or NULL.
33312 
33313 @Description
33314     This will first call grib_get_length() to inquire the actual size of the string,
33315     allocate memory accordingly, call grib_get_string(), and return the pointer to the new string.
33316     Returns NULL on failure.
33317 */
cdiGribIterator_inqStringValue(CdiGribIterator * me,const char * key)33318 char *cdiGribIterator_inqStringValue(CdiGribIterator *me, const char *key)
33319 {
33320 #ifdef HAVE_LIBGRIB_API
33321   return gribCopyString(me->gribHandle, key);
33322 #else
33323   (void)me;
33324   (void)key;
33325   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33326   return NULL;
33327 #endif
33328 }
33329 
33330 /*
33331 @Function cdiGribIterator_getDouble
33332 @Title Access to grib_get_double()
33333 
33334 @Prototype int cdiGribIterator_getDouble(CdiGribIterator *me, const char *key, double *result)
33335 @Parameter
33336     @item me The iterator to operate on.
33337     @item ... The arguments to the underlying GRIB-API function.
33338 
33339 @Result An error code.
33340 
33341 @Description
33342     Callthrough to grib_get_double().
33343 */
cdiGribIterator_getDouble(CdiGribIterator * me,const char * key,double * result)33344 int cdiGribIterator_getDouble(CdiGribIterator *me, const char *key, double *result)
33345 {
33346 #ifdef HAVE_LIBGRIB_API
33347   return grib_get_double(me->gribHandle, key, result);
33348 #else
33349   (void)me;
33350   (void)key;
33351   (void)result;
33352   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33353   return -4;
33354 #endif
33355 }
33356 
33357 /*
33358 @Function cdiGribIterator_getSize
33359 @Title Access to grib_get_size()
33360 
33361 @Prototype int cdiGribIterator_getSize(CdiGribIterator *me, const char *key, size_t *result)
33362 @Parameter
33363     @item me The iterator to operate on.
33364     @item ... The arguments to the underlying GRIB-API function.
33365 
33366 @Result An error code.
33367 
33368 @Description
33369     Callthrough to grib_get_size().
33370 */
cdiGribIterator_getSize(CdiGribIterator * me,const char * key,size_t * result)33371 int cdiGribIterator_getSize(CdiGribIterator *me, const char *key, size_t *result)
33372 {
33373 #ifdef HAVE_LIBGRIB_API
33374   return grib_get_size(me->gribHandle, key, result);
33375 #else
33376   (void)me;
33377   (void)key;
33378   (void)result;
33379   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33380   return -4;
33381 #endif
33382 }
33383 
33384 /*
33385 @Function cdiGribIterator_getLongArray
33386 @Title Access to grib_get_long_array()
33387 
33388 @Prototype int cdiGribIterator_getLongArray(CdiGribIterator *me, const char *key, long *result, size_t *size)
33389 @Parameter
33390     @item me The iterator to operate on.
33391     @item ... The arguments to the underlying GRIB-API function.
33392 
33393 @Result An error code.
33394 
33395 @Description
33396     Callthrough to grib_get_long_array().
33397 */
cdiGribIterator_getLongArray(CdiGribIterator * me,const char * key,long * result,size_t * size)33398 int cdiGribIterator_getLongArray(CdiGribIterator *me, const char *key, long *result, size_t *size)
33399 {
33400 #ifdef HAVE_LIBGRIB_API
33401   return grib_get_long_array(me->gribHandle, key, result, size);
33402 #else
33403   (void)me;
33404   (void)key;
33405   (void)result;
33406   (void)size;
33407   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33408   return -4;
33409 #endif
33410 }
33411 
33412 /*
33413 @Function cdiGribIterator_getDoubleArray
33414 @Title Access to grib_get_double_array()
33415 
33416 @Prototype int cdiGribIterator_getDoubleArray(CdiGribIterator *me, const char *key, double *result, size_t *size)
33417 @Parameter
33418     @item me The iterator to operate on.
33419     @item ... The arguments to the underlying GRIB-API function.
33420 
33421 @Result An error code.
33422 
33423 @Description
33424     Callthrough to grib_get_double_array().
33425 */
cdiGribIterator_getDoubleArray(CdiGribIterator * me,const char * key,double * result,size_t * size)33426 int cdiGribIterator_getDoubleArray(CdiGribIterator *me, const char *key, double *result, size_t *size)
33427 {
33428 #ifdef HAVE_LIBGRIB_API
33429   return grib_get_double_array(me->gribHandle, key, result, size);
33430 #else
33431   (void)me;
33432   (void)key;
33433   (void)result;
33434   (void)size;
33435   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33436   return -4;
33437 #endif
33438 }
33439 
33440 /*
33441 @Function cdiGribIterator_inqDoubleValue
33442 @Title Get the value of a GRIB-API key as a double
33443 
33444 @Prototype double cdiGribIterator_inqDoubleValue(CdiGribIterator *me, const char *key)
33445 @Parameter
33446     @item me The iterator to operate on.
33447     @item key The GRIB-API key to retrieve.
33448 
33449 @Result The value of the key.
33450 
33451 @Description
33452     Use this to fetch a grib value if you are certain that the given key must be present.
33453     This will abort the process if the key cannot be retrieved.
33454 */
cdiGribIterator_inqDoubleValue(CdiGribIterator * me,const char * key)33455 double cdiGribIterator_inqDoubleValue(CdiGribIterator *me, const char *key)
33456 {
33457 #ifdef HAVE_LIBGRIB_API
33458   return gribGetDouble(me->gribHandle, key);
33459 #else
33460   (void)me;
33461   (void)key;
33462   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33463   return -4;
33464 #endif
33465 }
33466 
33467 /*
33468 @Function cdiGribIterator_inqDoubleDefaultValue
33469 @Title Get the value of a GRIB-API key as a double
33470 
33471 @Prototype double cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator *me, const char *key, double defaultValue)
33472 @Parameter
33473     @item me The iterator to operate on.
33474     @item key The GRIB-API key to retrieve.
33475     @item defaultValue The value to return if the key is not present.
33476 
33477 @Result The value of the key or the given default value.
33478 
33479 @Description
33480     Use this if you can handle failure to fetch the key by supplying a default value.
33481     This function cannot fail.
33482 */
cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator * me,const char * key,double defaultValue)33483 double cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator *me, const char *key, double defaultValue)
33484 {
33485 #ifdef HAVE_LIBGRIB_API
33486   return gribGetDoubleDefault(me->gribHandle, key, defaultValue);
33487 #else
33488   (void)me;
33489   (void)key;
33490   (void)defaultValue;
33491   xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
33492   return -4;
33493 #endif
33494 }
33495 
33496 /*
33497  * Local Variables:
33498  * c-file-style: "Java"
33499  * c-basic-offset: 2
33500  * indent-tabs-mode: nil
33501  * show-trailing-whitespace: t
33502  * require-trailing-newline: t
33503  * End:
33504  */
33505 #ifndef MODEL_H
33506 #define MODEL_H
33507 
33508 int
33509 modelUnpack(void *buf, int size, int *position,
33510             int originNamespace, void *context, int force_id);
33511 
33512 void modelDefaultEntries(void);
33513 
33514 #endif
33515 /*
33516  * Local Variables:
33517  * c-file-style: "Java"
33518  * c-basic-offset: 2
33519  * indent-tabs-mode: nil
33520  * show-trailing-whitespace: t
33521  * require-trailing-newline: t
33522  * End:
33523  */
33524 #include <limits.h>
33525 
33526 
33527 #undef  CDI_UNDEFID
33528 #define CDI_UNDEFID -1
33529 
33530 typedef struct
33531 {
33532   int      self;
33533   int      used;
33534   int      instID;
33535   int      modelgribID;
33536   char    *name;
33537 }
33538 model_t;
33539 
33540 
33541 static int  MODEL_Debug = 0;   /* If set to 1, debugging */
33542 
33543 static void modelInit(void);
33544 
33545 
33546 static int modelCompareP(void *modelptr1, void *modelptr2);
33547 static void   modelDestroyP ( void * modelptr );
33548 static void   modelPrintP   ( void * modelptr, FILE * fp );
33549 static int    modelGetSizeP ( void * modelptr, void *context);
33550 static void   modelPackP    ( void * modelptr, void * buff, int size,
33551                               int *position, void *context);
33552 static int    modelTxCode   ( void );
33553 
33554 static const resOps modelOps = {
33555   modelCompareP,
33556   modelDestroyP,
33557   modelPrintP,
33558   modelGetSizeP,
33559   modelPackP,
33560   modelTxCode
33561 };
33562 
33563 static
modelDefaultValue(model_t * modelptr)33564 void modelDefaultValue ( model_t *modelptr )
33565 {
33566   modelptr->self        = CDI_UNDEFID;
33567   modelptr->used        = 0;
33568   modelptr->instID      = CDI_UNDEFID;
33569   modelptr->modelgribID = CDI_UNDEFID;
33570   modelptr->name        = NULL;
33571 }
33572 
33573 static model_t *
modelNewEntry(cdiResH resH,int instID,int modelgribID,const char * name)33574 modelNewEntry(cdiResH resH, int instID, int modelgribID, const char *name)
33575 {
33576   model_t *modelptr = (model_t *) Malloc(sizeof(model_t));
33577   modelDefaultValue ( modelptr );
33578   if (resH == CDI_UNDEFID)
33579     modelptr->self = reshPut(modelptr, &modelOps);
33580   else
33581     {
33582       modelptr->self = resH;
33583       reshReplace(resH, modelptr, &modelOps);
33584     }
33585   modelptr->used = 1;
33586   modelptr->instID = instID;
33587   modelptr->modelgribID = modelgribID;
33588   if ( name && *name ) modelptr->name = strdupx(name);
33589 
33590   return (modelptr);
33591 }
33592 
modelDefaultEntries(void)33593 void modelDefaultEntries ( void )
33594 {
33595   int instID;
33596   enum { nDefModels = 10 };
33597   cdiResH resH[nDefModels];
33598 
33599   instID  = institutInq(  0,   0, "ECMWF", NULL);
33600   /* (void)    modelDef(instID, 131, "ERA15"); */
33601   /* (void)    modelDef(instID, 199, "ERA40"); */
33602 
33603   instID  = institutInq( 98, 232, "MPIMET", NULL);
33604   resH[0] = modelDef(instID,  64, "ECHAM5.4");
33605   resH[1] = modelDef(instID,  63, "ECHAM5.3");
33606   resH[2] = modelDef(instID,  62, "ECHAM5.2");
33607   resH[3] = modelDef(instID,  61, "ECHAM5.1");
33608 
33609   instID  = institutInq( 98, 255, "MPIMET", NULL);
33610   resH[4] = modelDef(instID,  60, "ECHAM5.0");
33611   resH[5] = modelDef(instID,  50, "ECHAM4");
33612   resH[6] = modelDef(instID, 110, "MPIOM1");
33613 
33614   instID  = institutInq(  0,   0, "DWD", NULL);
33615   resH[7] = modelDef(instID, 149, "GME");
33616 
33617   instID  = institutInq(  0,   0, "MCH", NULL);
33618   //(void)  = modelDef(instID, 137, "COSMO");
33619   resH[8] = modelDef(instID, 255, "COSMO");
33620 
33621   instID  = institutInq(  0,   1, "NCEP", NULL);
33622   resH[9] = modelDef(instID,  80, "T62L28MRF");
33623 
33624   /* pre-defined models are not synchronized */
33625   for ( int i = 0; i < nDefModels ; i++ )
33626     reshSetStatus(resH[i], &modelOps, RESH_IN_USE);
33627 }
33628 
33629 static
modelInit(void)33630 void modelInit(void)
33631 {
33632   static bool modelInitialized = false;
33633 
33634   if (modelInitialized) return;
33635 
33636   modelInitialized = true;
33637   char *env = getenv("MODEL_DEBUG");
33638   if ( env ) MODEL_Debug = atoi(env);
33639 }
33640 
33641 struct modelLoc
33642 {
33643   const char *name;
33644   int instID, modelgribID, resID;
33645 };
33646 
33647 static enum cdiApplyRet
findModelByID(int resID,void * res,void * data)33648 findModelByID(int resID, void *res, void *data)
33649 {
33650   model_t *modelptr = (model_t*) res;
33651   struct modelLoc *ret = (struct modelLoc*) data;
33652   int instID = ret->instID, modelgribID = ret->modelgribID;
33653   if (modelptr->used
33654       && modelptr->instID == instID
33655       && modelptr->modelgribID == modelgribID)
33656     {
33657       ret->resID = resID;
33658       return CDI_APPLY_STOP;
33659     }
33660   else
33661     return CDI_APPLY_GO_ON;
33662 }
33663 
33664 static enum cdiApplyRet
findModelByName(int resID,void * res,void * data)33665 findModelByName(int resID, void *res, void *data)
33666 {
33667   model_t *modelptr = (model_t*) res;
33668   struct modelLoc *ret = (struct modelLoc*) data;
33669   int instID = ret->instID, modelgribID = ret->modelgribID;
33670   const char *name = ret->name;
33671   if (modelptr->used
33672       && (instID == -1 || modelptr->instID == instID)
33673       && (modelgribID == 0 || modelptr->modelgribID == modelgribID)
33674       && modelptr->name)
33675     {
33676       const char *p = name, *q = modelptr->name;
33677       while (*p != '\0' && *p == *q)
33678         ++p, ++q;
33679       if (*p == '\0' || *q == '\0')
33680         {
33681           ret->resID = resID;
33682           return CDI_APPLY_STOP;
33683         }
33684     }
33685   return CDI_APPLY_GO_ON;
33686 }
33687 
modelInq(int instID,int modelgribID,const char * name)33688 int modelInq(int instID, int modelgribID, const char *name)
33689 {
33690   modelInit ();
33691 
33692   struct modelLoc searchState = { .name = name, .instID = instID,
33693                                   .modelgribID = modelgribID,
33694                                   .resID = CDI_UNDEFID };
33695   if (name && *name)
33696     cdiResHFilterApply(&modelOps, findModelByName, &searchState);
33697   else
33698     cdiResHFilterApply(&modelOps, findModelByID, &searchState);
33699   return searchState.resID;
33700 }
33701 
33702 
modelDef(int instID,int modelgribID,const char * name)33703 int modelDef(int instID, int modelgribID, const char *name)
33704 {
33705   model_t *modelptr;
33706 
33707   modelInit ();
33708 
33709   modelptr = modelNewEntry(CDI_UNDEFID, instID, modelgribID, name);
33710 
33711   return modelptr->self;
33712 }
33713 
33714 
modelInqInstitut(int modelID)33715 int modelInqInstitut(int modelID)
33716 {
33717   model_t *modelptr = NULL;
33718 
33719   modelInit ();
33720 
33721   if ( modelID != CDI_UNDEFID )
33722     modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
33723 
33724   return modelptr ? modelptr->instID : CDI_UNDEFID;
33725 }
33726 
33727 
modelInqGribID(int modelID)33728 int modelInqGribID(int modelID)
33729 {
33730   model_t *modelptr = NULL;
33731 
33732   modelInit ();
33733 
33734   if ( modelID != CDI_UNDEFID )
33735     modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
33736 
33737   return modelptr ? modelptr->modelgribID : CDI_UNDEFID;
33738 }
33739 
33740 
modelInqNamePtr(int modelID)33741 const char *modelInqNamePtr(int modelID)
33742 {
33743   model_t *modelptr = NULL;
33744 
33745   modelInit ();
33746 
33747   if ( modelID != CDI_UNDEFID )
33748     modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
33749 
33750   return modelptr ? modelptr->name : NULL;
33751 }
33752 
33753 
33754 static int
modelCompareP(void * modelptr1,void * modelptr2)33755 modelCompareP(void *modelptr1, void *modelptr2)
33756 {
33757   model_t *model1 = (model_t *)modelptr1, *model2 = (model_t *)modelptr2;
33758   int diff = (namespaceResHDecode(model1->instID).idx
33759               != namespaceResHDecode(model2->instID).idx)
33760     | (model1->modelgribID != model2->modelgribID)
33761     | (strcmp(model1->name, model2->name) != 0);
33762   return diff;
33763 }
33764 
33765 
modelDestroyP(void * modelptr)33766 void modelDestroyP ( void * modelptr )
33767 {
33768   model_t *mp = (model_t*) modelptr;
33769   if (mp->name)
33770     Free(mp->name);
33771   Free(mp);
33772 }
33773 
33774 
modelPrintP(void * modelptr,FILE * fp)33775 void modelPrintP   ( void * modelptr, FILE * fp )
33776 {
33777   model_t *mp = (model_t*) modelptr;
33778 
33779   if ( !mp ) return;
33780 
33781   fprintf ( fp, "#\n");
33782   fprintf ( fp, "# modelID %d\n", mp->self);
33783   fprintf ( fp, "#\n");
33784   fprintf ( fp, "self          = %d\n", mp->self );
33785   fprintf ( fp, "used          = %d\n", mp->used );
33786   fprintf ( fp, "instID        = %d\n", mp->instID );
33787   fprintf ( fp, "modelgribID   = %d\n", mp->modelgribID );
33788   fprintf ( fp, "name          = %s\n", mp->name ? mp->name : "NN" );
33789 }
33790 
33791 
33792 static int
modelTxCode(void)33793 modelTxCode ( void )
33794 {
33795   return MODEL;
33796 }
33797 
33798 enum {
33799   model_nints = 4,
33800 };
33801 
33802 
modelGetSizeP(void * modelptr,void * context)33803 static int modelGetSizeP(void * modelptr, void *context)
33804 {
33805   model_t *p = (model_t*)modelptr;
33806   size_t txsize = (size_t)serializeGetSize(model_nints, CDI_DATATYPE_INT, context)
33807     + (size_t)serializeGetSize(p->name?(int)strlen(p->name) + 1:0, CDI_DATATYPE_TXT, context);
33808   xassert(txsize <= INT_MAX);
33809   return (int)txsize;
33810 }
33811 
33812 
modelPackP(void * modelptr,void * buf,int size,int * position,void * context)33813 static void modelPackP(void * modelptr, void * buf, int size, int *position, void *context)
33814 {
33815   model_t *p = (model_t*) modelptr;
33816   int tempbuf[model_nints];
33817   tempbuf[0] = p->self;
33818   tempbuf[1] = p->instID;
33819   tempbuf[2] = p->modelgribID;
33820   tempbuf[3] = p->name ? (int)strlen(p->name) + 1 : 0;
33821   serializePack(tempbuf, model_nints, CDI_DATATYPE_INT, buf, size, position, context);
33822   if (p->name)
33823     serializePack(p->name, tempbuf[3], CDI_DATATYPE_TXT, buf, size, position, context);
33824 }
33825 
33826 int
modelUnpack(void * buf,int size,int * position,int originNamespace,void * context,int force_id)33827 modelUnpack(void *buf, int size, int *position, int originNamespace, void *context,
33828             int force_id)
33829 {
33830   int tempbuf[model_nints];
33831   char *name;
33832   serializeUnpack(buf, size, position, tempbuf, model_nints, CDI_DATATYPE_INT, context);
33833   if (tempbuf[3] != 0)
33834     {
33835       name = (char *) Malloc((size_t)tempbuf[3]);
33836       serializeUnpack(buf, size, position,
33837                       name, tempbuf[3], CDI_DATATYPE_TXT, context);
33838     }
33839   else
33840     {
33841       name = (char*)"";
33842     }
33843   int targetID = namespaceAdaptKey(tempbuf[0], originNamespace);
33844   model_t *mp = modelNewEntry(force_id?targetID:CDI_UNDEFID,
33845                               namespaceAdaptKey(tempbuf[1], originNamespace),
33846                               tempbuf[2], name);
33847   if (tempbuf[3] != 0)
33848     Free(name);
33849   xassert(!force_id
33850           || (mp->self == namespaceAdaptKey(tempbuf[0], originNamespace)));
33851   reshSetStatus(mp->self, &modelOps,
33852                 reshGetStatus(mp->self, &modelOps) & ~RESH_SYNC_BIT);
33853   return mp->self;
33854 }
33855 
33856 /*
33857  * Local Variables:
33858  * c-file-style: "Java"
33859  * c-basic-offset: 2
33860  * indent-tabs-mode: nil
33861  * show-trailing-whitespace: t
33862  * require-trailing-newline: t
33863  * End:
33864  */
33865 #ifdef HAVE_CONFIG_H
33866 #endif
33867 
33868 #ifndef _XOPEN_SOURCE
33869 #define _XOPEN_SOURCE 600 /* PTHREAD_MUTEX_RECURSIVE */
33870 #endif
33871 
33872 #include <limits.h>
33873 #include <stdio.h>
33874 
33875 
33876 static unsigned nNamespaces = 1;
33877 static int activeNamespace = 0;
33878 
33879 #ifdef HAVE_LIBNETCDF
33880 #define CDI_NETCDF_SWITCHES                     \
33881   { .func = (void (*)()) nc__create },          \
33882   { .func = (void (*)()) cdf_def_var_serial },  \
33883   { .func = (void (*)()) cdfDefTimestep },      \
33884   { .func = (void (*)()) cdfDefCoordinateVars }
33885 
33886 #else
33887 #define CDI_NETCDF_SWITCHES
33888 #endif
33889 
33890 #define defaultSwitches {                                   \
33891     { .func = (void (*)()) cdiAbortC_serial },              \
33892     { .func = (void (*)()) cdiWarning },                    \
33893     { .func = (void (*)()) serializeGetSizeInCore },        \
33894     { .func = (void (*)()) serializePackInCore },           \
33895     { .func = (void (*)()) serializeUnpackInCore },         \
33896     { .func = (void (*)()) fileOpen_serial },               \
33897     { .func = (void (*)()) fileWrite },                     \
33898     { .func = (void (*)()) fileClose_serial },              \
33899     { .func = (void (*)()) cdiStreamOpenDefaultDelegate },  \
33900     { .func = (void (*)()) cdiStreamDefVlist_ },            \
33901     { .func = (void (*)()) cdiStreamSetupVlist_ },          \
33902     { .func = (void (*)()) cdiStreamWriteVar_ },            \
33903     { .func = (void (*)()) cdiStreamWriteVarChunk_ },       \
33904     { .func = (void (*)()) 0 },                             \
33905     { .func = (void (*)()) 0 },                             \
33906     { .func = (void (*)()) cdiStreamCloseDefaultDelegate }, \
33907     { .func = (void (*)()) cdiStreamDefTimestep_ }, \
33908     { .func = (void (*)()) cdiStreamSync_ },                \
33909     CDI_NETCDF_SWITCHES                        \
33910     }
33911 
33912 #if defined (SX) || defined (__cplusplus)
33913 static const union namespaceSwitchValue
33914   defaultSwitches_[NUM_NAMESPACE_SWITCH] = defaultSwitches;
33915 #endif
33916 
33917 enum namespaceStatus {
33918   NAMESPACE_STATUS_INUSE,
33919   NAMESPACE_STATUS_UNUSED,
33920 };
33921 
33922 static struct Namespace
33923 {
33924   enum namespaceStatus resStage;
33925   union namespaceSwitchValue switches[NUM_NAMESPACE_SWITCH];
33926 } initialNamespace = {
33927   .resStage = NAMESPACE_STATUS_INUSE,
33928   .switches = defaultSwitches
33929 };
33930 
33931 static struct Namespace *namespaces = &initialNamespace;
33932 
33933 static unsigned namespacesSize = 1;
33934 
33935 #if  defined  (HAVE_LIBPTHREAD)
33936 #  include <pthread.h>
33937 
33938 static pthread_once_t  namespaceOnce = PTHREAD_ONCE_INIT;
33939 static pthread_mutex_t namespaceMutex;
33940 
33941 static void
namespaceInitialize(void)33942 namespaceInitialize(void)
33943 {
33944 #if defined(PTHREAD_MUTEXATTR)
33945   pthread_mutexattr_t ma;
33946   pthread_mutexattr_init(&ma);
33947   pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
33948   pthread_mutex_init(&namespaceMutex, &ma);
33949   pthread_mutexattr_destroy(&ma);
33950 #endif
33951 }
33952 
33953 #  define NAMESPACE_LOCK()         pthread_mutex_lock(&namespaceMutex)
33954 #  define NAMESPACE_UNLOCK()       pthread_mutex_unlock(&namespaceMutex)
33955 #  define NAMESPACE_INIT()         pthread_once(&namespaceOnce, \
33956                                                 namespaceInitialize)
33957 
33958 
33959 #else
33960 
33961 #  define NAMESPACE_INIT() do { } while (0)
33962 #  define NAMESPACE_LOCK()
33963 #  define NAMESPACE_UNLOCK()
33964 
33965 #endif
33966 
33967 
33968 enum {
33969   intbits = sizeof(int) * CHAR_BIT,
33970   nspbits = 4,
33971   idxbits = intbits - nspbits,
33972   nspmask = (int)((( (unsigned)1 << nspbits ) - 1) << idxbits),
33973   idxmask = ( 1 << idxbits ) - 1,
33974 };
33975 
33976 enum {
33977   NUM_NAMESPACES = 1 << nspbits,
33978   NUM_IDX = 1 << idxbits,
33979 };
33980 
33981 
namespaceIdxEncode(namespaceTuple_t tin)33982 int namespaceIdxEncode ( namespaceTuple_t tin )
33983 {
33984   xassert ( tin.nsp < NUM_NAMESPACES && tin.idx < NUM_IDX);
33985   return ( tin.nsp << idxbits ) + tin.idx;
33986 }
33987 
namespaceIdxEncode2(int nsp,int idx)33988 int namespaceIdxEncode2 ( int nsp, int idx )
33989 {
33990   xassert(nsp < NUM_NAMESPACES && idx < NUM_IDX);
33991   return ( nsp << idxbits ) + idx;
33992 }
33993 
33994 
namespaceResHDecode(int resH)33995 namespaceTuple_t namespaceResHDecode ( int resH )
33996 {
33997   namespaceTuple_t tin;
33998 
33999   tin.idx = resH & idxmask;
34000   tin.nsp = (int)(((unsigned)( resH & nspmask )) >> idxbits);
34001 
34002   return tin;
34003 }
34004 
34005 int
namespaceNew()34006 namespaceNew()
34007 {
34008   int newNamespaceID = -1;
34009   NAMESPACE_INIT();
34010   NAMESPACE_LOCK();
34011   if (namespacesSize > nNamespaces)
34012     {
34013       /* namespace is already available and only needs reinitialization */
34014       for (unsigned i = 0; i < namespacesSize; ++i)
34015         if (namespaces[i].resStage == NAMESPACE_STATUS_UNUSED)
34016           {
34017             newNamespaceID = (int)i;
34018             break;
34019           }
34020     }
34021   else if (namespacesSize == 1)
34022     {
34023       /* make room for additional namespace */
34024       struct Namespace *newNameSpaces
34025         = (struct Namespace *) Malloc(((size_t)namespacesSize + 1) * sizeof (namespaces[0]));
34026       memcpy(newNameSpaces, namespaces, sizeof (namespaces[0]));
34027       namespaces = newNameSpaces;
34028       ++namespacesSize;
34029       newNamespaceID = 1;
34030     }
34031   else if (namespacesSize < NUM_NAMESPACES)
34032     {
34033       /* make room for additional namespace */
34034       newNamespaceID = (int)namespacesSize;
34035       namespaces
34036         = (struct Namespace *) Realloc(namespaces, ((size_t)namespacesSize + 1) * sizeof (namespaces[0]));
34037       ++namespacesSize;
34038     }
34039   else /* implicit: namespacesSize >= NUM_NAMESPACES */
34040     {
34041       NAMESPACE_UNLOCK();
34042       return -1;
34043     }
34044   xassert(newNamespaceID >= 0 && newNamespaceID < NUM_NAMESPACES);
34045   ++nNamespaces;
34046   namespaces[newNamespaceID].resStage = NAMESPACE_STATUS_INUSE;
34047 #if defined (SX) || defined (__cplusplus)
34048   memcpy(namespaces[newNamespaceID].switches,
34049          defaultSwitches_,
34050          sizeof (namespaces[newNamespaceID].switches));
34051 #else
34052     memcpy(namespaces[newNamespaceID].switches,
34053            (union namespaceSwitchValue[NUM_NAMESPACE_SWITCH])defaultSwitches,
34054            sizeof (namespaces[newNamespaceID].switches));
34055 #endif
34056   reshListCreate(newNamespaceID);
34057   NAMESPACE_UNLOCK();
34058   return newNamespaceID;
34059 }
34060 
34061 void
namespaceDelete(int namespaceID)34062 namespaceDelete(int namespaceID)
34063 {
34064   NAMESPACE_INIT();
34065   NAMESPACE_LOCK();
34066   xassert(namespaceID >= 0 && (unsigned)namespaceID < namespacesSize
34067           && nNamespaces);
34068   reshListDestruct(namespaceID);
34069   namespaces[namespaceID].resStage = NAMESPACE_STATUS_UNUSED;
34070   --nNamespaces;
34071   NAMESPACE_UNLOCK();
34072 }
34073 
namespaceGetNumber()34074 int namespaceGetNumber ()
34075 {
34076   return (int)nNamespaces;
34077 }
34078 
34079 
namespaceSetActive(int nId)34080 void namespaceSetActive ( int nId )
34081 {
34082   xassert((unsigned)nId < namespacesSize
34083           && namespaces[nId].resStage != NAMESPACE_STATUS_UNUSED);
34084   activeNamespace = nId;
34085 }
34086 
34087 
namespaceGetActive()34088 int namespaceGetActive ()
34089 {
34090   return activeNamespace;
34091 }
34092 
namespaceAdaptKey(int originResH,int originNamespace)34093 int namespaceAdaptKey ( int originResH, int originNamespace )
34094 {
34095   namespaceTuple_t tin;
34096   int nsp;
34097 
34098   if ( originResH == CDI_UNDEFID ) return CDI_UNDEFID;
34099 
34100   tin.idx = originResH & idxmask;
34101   tin.nsp = (int)(((unsigned)( originResH & nspmask )) >> idxbits);
34102 
34103   xassert ( tin.nsp == originNamespace );
34104 
34105   nsp = namespaceGetActive ();
34106 
34107   return namespaceIdxEncode2 ( nsp, tin.idx );
34108 }
34109 
34110 
namespaceAdaptKey2(int originResH)34111 int namespaceAdaptKey2 ( int originResH )
34112 {
34113   namespaceTuple_t tin;
34114   int nsp;
34115 
34116   if ( originResH == CDI_UNDEFID ) return CDI_UNDEFID;
34117 
34118   tin.idx = originResH & idxmask;
34119   tin.nsp = (int)(((unsigned)( originResH & nspmask )) >> idxbits);
34120 
34121   nsp = namespaceGetActive ();
34122 
34123   return namespaceIdxEncode2 ( nsp, tin.idx );
34124 }
34125 
namespaceSwitchSet(enum namespaceSwitch sw,union namespaceSwitchValue value)34126 void namespaceSwitchSet(enum namespaceSwitch sw, union namespaceSwitchValue value)
34127 {
34128   xassert(sw > NSSWITCH_NO_SUCH_SWITCH && sw < NUM_NAMESPACE_SWITCH);
34129   int nsp = namespaceGetActive();
34130   namespaces[nsp].switches[sw] = value;
34131 }
34132 
namespaceSwitchGet(enum namespaceSwitch sw)34133 union namespaceSwitchValue namespaceSwitchGet(enum namespaceSwitch sw)
34134 {
34135   xassert(sw > NSSWITCH_NO_SUCH_SWITCH && sw < NUM_NAMESPACE_SWITCH);
34136   int nsp = namespaceGetActive();
34137   return namespaces[nsp].switches[sw];
34138 }
34139 
cdiReset(void)34140 void cdiReset(void)
34141 {
34142   NAMESPACE_INIT();
34143   NAMESPACE_LOCK();
34144   for (unsigned namespaceID = 0; namespaceID < namespacesSize; ++namespaceID)
34145     if (namespaces[namespaceID].resStage != NAMESPACE_STATUS_UNUSED)
34146       namespaceDelete((int)namespaceID);
34147   if (namespaces != &initialNamespace)
34148     {
34149       Free(namespaces);
34150       namespaces = &initialNamespace;
34151       namespaces[0].resStage = NAMESPACE_STATUS_UNUSED;
34152     }
34153   namespacesSize = 1;
34154   nNamespaces = 0;
34155   NAMESPACE_UNLOCK();
34156 }
34157 
34158 /*
34159  * Local Variables:
34160  * c-file-style: "Java"
34161  * c-basic-offset: 2
34162  * indent-tabs-mode: nil
34163  * show-trailing-whitespace: t
34164  * require-trailing-newline: t
34165  * End:
34166  */
34167 
34168 
cdiRefObject_construct(CdiReferencedObject * me)34169 void cdiRefObject_construct(CdiReferencedObject* me)
34170 {
34171   me->destructor = cdiRefObject_destruct;
34172   me->refCount = 1;
34173 }
34174 
cdiRefObject_retain(CdiReferencedObject * me)34175 void cdiRefObject_retain(CdiReferencedObject* me)
34176 {
34177   size_t oldCount = me->refCount++;
34178   xassert(oldCount && "A reference counted object was used after it was destructed.");
34179 }
34180 
cdiRefObject_release(CdiReferencedObject * me)34181 void cdiRefObject_release(CdiReferencedObject* me)
34182 {
34183   size_t oldCount = me->refCount--;
34184   xassert(oldCount && "A reference counted object was released too often.");
34185   if(oldCount == 1)
34186     {
34187       me->destructor(me);
34188       Free(me);
34189     }
34190 }
34191 
cdiRefObject_destruct(CdiReferencedObject * me)34192 void cdiRefObject_destruct(CdiReferencedObject* me)
34193 {
34194   (void)me;
34195   /* Empty for now, but that's no reason not to call it! */
34196 }
34197 
34198 /*
34199  * Local Variables:
34200  * c-file-style: "Java"
34201  * c-basic-offset: 2
34202  * indent-tabs-mode: nil
34203  * show-trailing-whitespace: t
34204  * require-trailing-newline: t
34205  * End:
34206  */
34207 #ifdef HAVE_CONFIG_H
34208 #endif
34209 
34210 #ifndef _XOPEN_SOURCE
34211 #define _XOPEN_SOURCE 600 /* PTHREAD_MUTEX_RECURSIVE */
34212 #endif
34213 
34214 #include <stdlib.h>
34215 #include <stdio.h>
34216 #include <assert.h>
34217 
34218 #if defined (HAVE_EXECINFO_H)
34219 #include <execinfo.h>
34220 #endif
34221 
34222 static
show_stackframe()34223 void show_stackframe()
34224 {
34225 #if defined HAVE_EXECINFO_H && defined backtrace_size_t && defined HAVE_BACKTRACE
34226   void *trace[16];
34227   backtrace_size_t trace_size = backtrace(trace, 16);
34228   char **messages = backtrace_symbols(trace, trace_size);
34229 
34230   fprintf(stderr, "[bt] Execution path:\n");
34231   if ( messages ) {
34232     for ( backtrace_size_t i = 0; i < trace_size; ++i )
34233       fprintf(stderr, "[bt] %s\n", messages[i]);
34234     free(messages);
34235   }
34236 #endif
34237 }
34238 
34239 
34240 enum { MIN_LIST_SIZE = 128 };
34241 
34242 static void listInitialize(void);
34243 
34244 typedef struct listElem {
34245   union
34246   {
34247     /* free-list management data */
34248     struct
34249     {
34250       int next, prev;
34251     } free;
34252     /* holding an actual value */
34253     struct
34254     {
34255       const resOps *ops;
34256       void         *val;//ptr
34257     } v;
34258   } res;
34259   int           status;
34260 } listElem_t;
34261 
34262 struct resHList_t
34263 {
34264   int size, freeHead, hasDefaultRes;
34265   listElem_t *resources;
34266 };
34267 
34268 static struct resHList_t *resHList;
34269 
34270 static int resHListSize = 0;
34271 
34272 #if  defined  (HAVE_LIBPTHREAD)
34273 #  include <pthread.h>
34274 
34275 static pthread_once_t  listInitThread = PTHREAD_ONCE_INIT;
34276 static pthread_mutex_t listMutex;
34277 
34278 #  define LIST_LOCK()         pthread_mutex_lock(&listMutex)
34279 #  define LIST_UNLOCK()       pthread_mutex_unlock(&listMutex)
34280 #  define LIST_INIT(init0)         do {                         \
34281     pthread_once(&listInitThread, listInitialize);              \
34282     pthread_mutex_lock(&listMutex);                             \
34283     if ((init0) && (!resHList || !resHList[0].resources))       \
34284       reshListCreate(0);                                        \
34285     pthread_mutex_unlock(&listMutex);                           \
34286   } while (0)
34287 
34288 
34289 
34290 #else
34291 
34292 static int listInit = 0;
34293 
34294 #  define LIST_LOCK()
34295 #  define LIST_UNLOCK()
34296 #  define LIST_INIT(init0)        do {                          \
34297   if ( !listInit )                                              \
34298     {                                                           \
34299       listInitialize();                                         \
34300       if ((init0) && (!resHList || !resHList[0].resources))     \
34301         reshListCreate(0);                                      \
34302       listInit = 1;                                             \
34303     }                                                           \
34304   } while(0)
34305 
34306 #endif
34307 
34308 /**************************************************************/
34309 
34310 static void
listInitResources(int nsp)34311 listInitResources(int nsp)
34312 {
34313   xassert(nsp < resHListSize && nsp >= 0);
34314   int size = resHList[nsp].size = MIN_LIST_SIZE;
34315   xassert(resHList[nsp].resources == NULL);
34316   resHList[nsp].resources = (listElem_t*) Calloc(MIN_LIST_SIZE, sizeof(listElem_t));
34317   listElem_t *p = resHList[nsp].resources;
34318 
34319   for (int i = 0; i < size; i++ )
34320     {
34321       p[i].res.free.next = i + 1;
34322       p[i].res.free.prev = i - 1;
34323       p[i].status = RESH_UNUSED;
34324     }
34325 
34326   p[size-1].res.free.next = -1;
34327   resHList[nsp].freeHead = 0;
34328   int oldNsp = namespaceGetActive();
34329   namespaceSetActive(nsp);
34330   instituteDefaultEntries();
34331   modelDefaultEntries();
34332   namespaceSetActive(oldNsp);
34333 }
34334 
34335 static inline void
reshListClearEntry(int i)34336 reshListClearEntry(int i)
34337 {
34338   resHList[i].size = 0;
34339   resHList[i].resources = NULL;
34340   resHList[i].freeHead = -1;
34341 }
34342 
34343 void
reshListCreate(int namespaceID)34344 reshListCreate(int namespaceID)
34345 {
34346   LIST_INIT(namespaceID != 0);
34347   LIST_LOCK();
34348   if (resHListSize <= namespaceID)
34349     {
34350       resHList = (struct resHList_t *) Realloc(resHList, (size_t)(namespaceID + 1) * sizeof (resHList[0]));
34351       for (int i = resHListSize; i <= namespaceID; ++i)
34352         reshListClearEntry(i);
34353       resHListSize = namespaceID + 1;
34354     }
34355   listInitResources(namespaceID);
34356   LIST_UNLOCK();
34357 }
34358 
34359 
34360 /**************************************************************/
34361 
34362 void
reshListDestruct(int namespaceID)34363 reshListDestruct(int namespaceID)
34364 {
34365   LIST_LOCK();
34366   xassert(resHList && namespaceID >= 0 && namespaceID < resHListSize);
34367   int callerNamespaceID = namespaceGetActive();
34368   namespaceSetActive(namespaceID);
34369   if (resHList[namespaceID].resources)
34370     {
34371       for ( int j = 0; j < resHList[namespaceID].size; j++ )
34372         {
34373           listElem_t *listElem = resHList[namespaceID].resources + j;
34374           if (listElem->status & RESH_IN_USE_BIT)
34375             listElem->res.v.ops->valDestroy(listElem->res.v.val);
34376         }
34377       Free(resHList[namespaceID].resources);
34378       resHList[namespaceID].resources = NULL;
34379       reshListClearEntry(namespaceID);
34380     }
34381   if (resHList[callerNamespaceID].resources)
34382     namespaceSetActive(callerNamespaceID);
34383   LIST_UNLOCK();
34384 }
34385 
34386 
listDestroy(void)34387 static void listDestroy ( void )
34388 {
34389   LIST_LOCK();
34390   for (int i = resHListSize; i > 0; --i)
34391     if (resHList[i-1].resources)
34392       namespaceDelete(i-1);
34393   resHListSize = 0;
34394   Free(resHList);
34395   resHList = NULL;
34396   cdiReset();
34397   LIST_UNLOCK();
34398 }
34399 
34400 /**************************************************************/
34401 
34402 static
listInitialize(void)34403 void listInitialize ( void )
34404 {
34405 #if  defined  (HAVE_LIBPTHREAD)
34406 #if defined(PTHREAD_MUTEXATTR)
34407   pthread_mutexattr_t ma;
34408   pthread_mutexattr_init(&ma);
34409   pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
34410   /* initialize global API mutex lock */
34411   pthread_mutex_init ( &listMutex, &ma);
34412   pthread_mutexattr_destroy(&ma);
34413 #endif
34414 #endif
34415   /* file is special and has its own table, which needs to be
34416    * created, before we register the listDestroy exit handler */
34417   {
34418     int null_id;
34419     null_id = fileOpen_serial("/dev/null", "r");
34420     if (null_id != -1)
34421       fileClose_serial(null_id);
34422   }
34423   atexit ( listDestroy );
34424 }
34425 
34426 /**************************************************************/
34427 
34428 static
listSizeExtend()34429 void listSizeExtend()
34430 {
34431   int nsp = namespaceGetActive ();
34432   int oldSize = resHList[nsp].size;
34433   size_t newListSize = (size_t)oldSize + MIN_LIST_SIZE;
34434 
34435   resHList[nsp].resources = (listElem_t*) Realloc(resHList[nsp].resources,
34436                                                    newListSize * sizeof(listElem_t));
34437 
34438   listElem_t *r = resHList[nsp].resources;
34439   for (size_t i = (size_t)oldSize; i < newListSize; ++i)
34440     {
34441       r[i].res.free.next = (int)i + 1;
34442       r[i].res.free.prev = (int)i - 1;
34443       r[i].status = RESH_UNUSED;
34444     }
34445 
34446   if (resHList[nsp].freeHead != -1)
34447     r[resHList[nsp].freeHead].res.free.prev = (int)newListSize - 1;
34448   r[newListSize-1].res.free.next = resHList[nsp].freeHead;
34449   r[oldSize].res.free.prev = -1;
34450   resHList[nsp].freeHead = oldSize;
34451   resHList[nsp].size = (int)newListSize;
34452 }
34453 
34454 /**************************************************************/
34455 
34456 static void
reshPut_(int nsp,int entry,void * p,const resOps * ops)34457 reshPut_(int nsp, int entry, void *p, const resOps *ops)
34458 {
34459   listElem_t *newListElem = resHList[nsp].resources + entry;
34460   int next = newListElem->res.free.next,
34461     prev = newListElem->res.free.prev;
34462   if (next != -1)
34463     resHList[nsp].resources[next].res.free.prev = prev;
34464   if (prev != -1)
34465     resHList[nsp].resources[prev].res.free.next = next;
34466   else
34467     resHList[nsp].freeHead = next;
34468   newListElem->res.v.val = p;
34469   newListElem->res.v.ops = ops;
34470   newListElem->status = RESH_DESYNC_IN_USE;
34471 }
34472 
reshPut(void * p,const resOps * ops)34473 int reshPut ( void *p, const resOps *ops )
34474 {
34475   xassert ( p && ops );
34476 
34477   LIST_INIT(1);
34478 
34479   LIST_LOCK();
34480 
34481   int nsp = namespaceGetActive ();
34482 
34483   if ( resHList[nsp].freeHead == -1) listSizeExtend();
34484   int entry = resHList[nsp].freeHead;
34485   cdiResH resH = namespaceIdxEncode2(nsp, entry);
34486   reshPut_(nsp, entry, p, ops);
34487 
34488   LIST_UNLOCK();
34489 
34490   return resH;
34491 }
34492 
34493 /**************************************************************/
34494 
34495 static void
reshRemove_(int nsp,int idx)34496 reshRemove_(int nsp, int idx)
34497 {
34498   int curFree = resHList[nsp].freeHead;
34499   listElem_t *r = resHList[nsp].resources;
34500   r[idx].res.free.next = curFree;
34501   r[idx].res.free.prev = -1;
34502   if (curFree != -1)
34503     r[curFree].res.free.prev = idx;
34504   r[idx].status = RESH_DESYNC_DELETED;
34505   resHList[nsp].freeHead = idx;
34506 }
34507 
reshDestroy(cdiResH resH)34508 void reshDestroy(cdiResH resH)
34509 {
34510   int nsp;
34511   namespaceTuple_t nspT;
34512 
34513   LIST_LOCK();
34514 
34515   nsp = namespaceGetActive ();
34516 
34517   nspT = namespaceResHDecode ( resH );
34518 
34519   xassert ( nspT.nsp == nsp
34520             && nspT.idx >= 0
34521             && nspT.idx < resHList[nsp].size
34522             && resHList[nsp].resources[nspT.idx].res.v.ops);
34523 
34524   if (resHList[nsp].resources[nspT.idx].status & RESH_IN_USE_BIT)
34525     reshRemove_(nsp, nspT.idx);
34526 
34527   LIST_UNLOCK();
34528 }
34529 
reshRemove(cdiResH resH,const resOps * ops)34530 void reshRemove ( cdiResH resH, const resOps * ops )
34531 {
34532   int nsp;
34533   namespaceTuple_t nspT;
34534 
34535   LIST_LOCK();
34536 
34537   nsp = namespaceGetActive ();
34538 
34539   nspT = namespaceResHDecode ( resH );
34540 
34541   xassert ( nspT.nsp == nsp
34542             && nspT.idx >= 0
34543             && nspT.idx < resHList[nsp].size
34544             && (resHList[nsp].resources[nspT.idx].status & RESH_IN_USE_BIT)
34545             && resHList[nsp].resources[nspT.idx].res.v.ops
34546             && resHList[nsp].resources[nspT.idx].res.v.ops == ops );
34547 
34548   reshRemove_(nsp, nspT.idx);
34549 
34550   LIST_UNLOCK();
34551 }
34552 
34553 /**************************************************************/
34554 
reshReplace(cdiResH resH,void * p,const resOps * ops)34555 void reshReplace(cdiResH resH, void *p, const resOps *ops)
34556 {
34557   xassert(p && ops);
34558   LIST_INIT(1);
34559   LIST_LOCK();
34560   int nsp = namespaceGetActive();
34561   namespaceTuple_t nspT = namespaceResHDecode(resH);
34562   while (resHList[nsp].size <= nspT.idx)
34563     listSizeExtend();
34564   listElem_t *q = resHList[nsp].resources + nspT.idx;
34565   if (q->status & RESH_IN_USE_BIT)
34566     {
34567       q->res.v.ops->valDestroy(q->res.v.val);
34568       reshRemove_(nsp, nspT.idx);
34569     }
34570   reshPut_(nsp, nspT.idx, p, ops);
34571   LIST_UNLOCK();
34572 }
34573 
34574 
34575 static listElem_t *
reshGetElem(const char * caller,const char * expressionString,cdiResH resH,const resOps * ops)34576 reshGetElem(const char *caller, const char* expressionString, cdiResH resH, const resOps *ops)
34577 {
34578   listElem_t *listElem;
34579   xassert ( ops );
34580 
34581   LIST_INIT(1);
34582 
34583   LIST_LOCK();
34584 
34585   int nsp = namespaceGetActive ();
34586 
34587   namespaceTuple_t nspT = namespaceResHDecode ( resH );
34588   assert(nspT.idx >= 0);
34589 
34590   if (nspT.nsp == nsp &&
34591       nspT.idx < resHList[nsp].size)
34592     {
34593       listElem = resHList[nsp].resources + nspT.idx;
34594       LIST_UNLOCK();
34595     }
34596   else
34597     {
34598       LIST_UNLOCK();
34599       show_stackframe();
34600 
34601       if ( resH == CDI_UNDEFID )
34602         {
34603           xabortC(caller, "Error while trying to resolve the ID \"%s\" in `%s()`: the value is CDI_UNDEFID (= %d).\n\tThis is most likely the result of a failed earlier call. Please check the IDs returned by CDI.", expressionString, caller, resH);
34604         }
34605       else
34606         {
34607           xabortC(caller, "Error while trying to resolve the ID \"%s\" in `%s()`: the value is garbage (= %d, which resolves to namespace = %d, index = %d).\n\tThis is either the result of using an uninitialized variable,\n\tof using a value as an ID that is not an ID,\n\tor of using an ID after it has been invalidated.", expressionString, caller, resH, nspT.nsp, nspT.idx);
34608         }
34609     }
34610 
34611   if ( !(listElem && listElem->res.v.ops == ops) )
34612     {
34613       show_stackframe();
34614 
34615       xabortC(caller, "Error while trying to resolve the ID \"%s\" in `%s()`: list element not found. The failed ID is %d", expressionString, caller, (int)resH);
34616     }
34617 
34618   return listElem;
34619 }
34620 
reshGetValue(const char * caller,const char * expressionString,cdiResH resH,const resOps * ops)34621 void *reshGetValue(const char * caller, const char* expressionString, cdiResH resH, const resOps * ops)
34622 {
34623   return reshGetElem(caller, expressionString, resH, ops)->res.v.val;
34624 }
34625 
34626 /**************************************************************/
34627 
reshGetResHListOfType(unsigned numIDs,int resHs[],const resOps * ops)34628 void reshGetResHListOfType(unsigned numIDs, int resHs[], const resOps *ops)
34629 {
34630   xassert ( resHs && ops );
34631 
34632   LIST_INIT(1);
34633 
34634   LIST_LOCK();
34635 
34636   int nsp = namespaceGetActive();
34637   unsigned j = 0;
34638   for (int i = 0; i < resHList[nsp].size && j < numIDs; i++ )
34639     if ((resHList[nsp].resources[i].status & RESH_IN_USE_BIT)
34640         && resHList[nsp].resources[i].res.v.ops == ops)
34641       resHs[j++] = namespaceIdxEncode2(nsp, i);
34642 
34643   LIST_UNLOCK();
34644 }
34645 
34646 enum cdiApplyRet
cdiResHApply(enum cdiApplyRet (* func)(int id,void * res,const resOps * p,void * data),void * data)34647 cdiResHApply(enum cdiApplyRet (*func)(int id, void *res, const resOps *p,
34648                                       void *data), void *data)
34649 {
34650   xassert(func);
34651 
34652   LIST_INIT(1);
34653 
34654   LIST_LOCK();
34655 
34656   int nsp = namespaceGetActive ();
34657   enum cdiApplyRet ret = CDI_APPLY_GO_ON;
34658   for (int i = 0; i < resHList[nsp].size && ret > 0; ++i)
34659     if (resHList[nsp].resources[i].status & RESH_IN_USE_BIT)
34660       ret = func(namespaceIdxEncode2(nsp, i),
34661                  resHList[nsp].resources[i].res.v.val,
34662                  resHList[nsp].resources[i].res.v.ops, data);
34663   LIST_UNLOCK();
34664   return ret;
34665 }
34666 
34667 
34668 enum cdiApplyRet
cdiResHFilterApply(const resOps * p,enum cdiApplyRet (* func)(int id,void * res,void * data),void * data)34669 cdiResHFilterApply(const resOps *p,
34670                    enum cdiApplyRet (*func)(int id, void *res, void *data),
34671                    void *data)
34672 {
34673   xassert(p && func);
34674 
34675   LIST_INIT(1);
34676 
34677   LIST_LOCK();
34678 
34679   int nsp = namespaceGetActive ();
34680   enum cdiApplyRet ret = CDI_APPLY_GO_ON;
34681   listElem_t *r = resHList[nsp].resources;
34682   for (int i = 0; i < resHList[nsp].size && ret > 0; ++i)
34683     if ((r[i].status & RESH_IN_USE_BIT) && r[i].res.v.ops == p)
34684       ret = func(namespaceIdxEncode2(nsp, i), r[i].res.v.val,
34685                  data);
34686   LIST_UNLOCK();
34687   return ret;
34688 }
34689 
34690 
34691 
34692 
34693 /**************************************************************/
34694 
reshCountType(const resOps * ops)34695 unsigned reshCountType(const resOps *ops)
34696 {
34697   unsigned countType = 0;
34698 
34699   xassert(ops);
34700 
34701   LIST_INIT(1);
34702 
34703   LIST_LOCK();
34704 
34705   int nsp = namespaceGetActive ();
34706 
34707   listElem_t *r = resHList[nsp].resources;
34708   size_t len = (size_t)resHList[nsp].size;
34709   for (size_t i = 0; i < len; i++ )
34710     countType += ((r[i].status & RESH_IN_USE_BIT) && r[i].res.v.ops == ops);
34711 
34712   LIST_UNLOCK();
34713 
34714   return countType;
34715 }
34716 
34717 /**************************************************************/
34718 
34719 int
reshResourceGetPackSize_intern(int resH,const resOps * ops,void * context,const char * caller,const char * expressionString)34720 reshResourceGetPackSize_intern(int resH, const resOps *ops, void *context, const char* caller, const char* expressionString)
34721 {
34722   listElem_t *curr = reshGetElem(caller, expressionString, resH, ops);
34723   return curr->res.v.ops->valGetPackSize(curr->res.v.val, context);
34724 }
34725 
34726 void
reshPackResource_intern(int resH,const resOps * ops,void * buf,int buf_size,int * position,void * context,const char * caller,const char * expressionString)34727 reshPackResource_intern(int resH, const resOps *ops, void *buf, int buf_size, int *position, void *context,
34728                         const char* caller, const char* expressionString)
34729 {
34730   listElem_t *curr = reshGetElem(caller, expressionString, resH, ops);
34731   curr->res.v.ops->valPack(curr->res.v.val, buf, buf_size, position, context);
34732 }
34733 
34734 enum {
34735   resHPackHeaderNInt = 2,
34736   resHDeleteNInt = 2,
34737 };
34738 
getPackBufferSize(void * context)34739 static int getPackBufferSize(void *context)
34740 {
34741   int intpacksize, packBufferSize = 0;
34742 
34743   int nsp = namespaceGetActive ();
34744 
34745   /* pack start marker, namespace and sererator marker */
34746   packBufferSize += resHPackHeaderNInt * (intpacksize = serializeGetSize(1, CDI_DATATYPE_INT, context));
34747 
34748   /* pack resources, type marker and seperator marker */
34749   listElem_t *r = resHList[nsp].resources;
34750   for ( int i = 0; i < resHList[nsp].size; i++)
34751     if (r[i].status & RESH_SYNC_BIT)
34752       {
34753         if (r[i].status == RESH_DESYNC_DELETED)
34754           {
34755             packBufferSize += resHDeleteNInt * intpacksize;
34756           }
34757         else if (r[i].status == RESH_DESYNC_IN_USE)
34758           {
34759             xassert ( r[i].res.v.ops );
34760             /* packed resource plus 1 int for type */
34761             packBufferSize +=
34762               r[i].res.v.ops->valGetPackSize(r[i].res.v.val, context)
34763               + intpacksize;
34764           }
34765       }
34766   /* end marker */
34767   packBufferSize += intpacksize;
34768 
34769   return packBufferSize;
34770 }
34771 
34772 /**************************************************************/
34773 
reshPackBufferDestroy(char ** buffer)34774 void reshPackBufferDestroy ( char ** buffer )
34775 {
34776   if ( buffer ) free ( *buffer );
34777 }
34778 
34779 /**************************************************************/
34780 
reshGetTxCode(cdiResH resH)34781 int reshGetTxCode(cdiResH resH)
34782 {
34783   int type = 0;
34784 
34785   LIST_LOCK();
34786 
34787   int nsp = namespaceGetActive ();
34788 
34789   namespaceTuple_t nspT = namespaceResHDecode ( resH );
34790   assert(nspT.idx >= 0);
34791 
34792   if (nspT.nsp == nsp &&
34793       nspT.idx < resHList[nsp].size)
34794     {
34795       listElem_t *listElem = resHList[nsp].resources + nspT.idx;
34796       xassert ( listElem->res.v.ops );
34797       type = listElem->res.v.ops->valTxCode();
34798     }
34799 
34800   LIST_UNLOCK();
34801 
34802   return type;
34803 }
34804 
34805 /**************************************************************/
34806 
reshPackBufferCreate(char ** packBuffer,int * packBufferSize,void * context)34807 int reshPackBufferCreate(char **packBuffer, int *packBufferSize, void *context)
34808 {
34809   int packBufferPos = 0;
34810   int end = END;
34811 
34812   xassert ( packBuffer );
34813 
34814   LIST_LOCK();
34815 
34816   int nsp = namespaceGetActive ();
34817 
34818   int pBSize = *packBufferSize = getPackBufferSize(context);
34819   char *pB = *packBuffer = (char *) Malloc((size_t)pBSize);
34820 
34821   {
34822     int header[resHPackHeaderNInt] = { START, nsp };
34823     serializePack(header, resHPackHeaderNInt,  CDI_DATATYPE_INT, pB, pBSize, &packBufferPos, context);
34824   }
34825 
34826   listElem_t *r = resHList[nsp].resources;
34827   for ( int i = 0; i < resHList[nsp].size; i++ )
34828     if (r[i].status & RESH_SYNC_BIT)
34829       {
34830         if (r[i].status == RESH_DESYNC_DELETED)
34831           {
34832             int temp[resHDeleteNInt]
34833               = { RESH_DELETE, namespaceIdxEncode2(nsp, i) };
34834             serializePack(temp, resHDeleteNInt, CDI_DATATYPE_INT,
34835                           pB, pBSize, &packBufferPos, context);
34836           }
34837         else
34838           {
34839             listElem_t * curr = r + i;
34840             xassert ( curr->res.v.ops );
34841             int type = curr->res.v.ops->valTxCode();
34842             if ( ! type ) continue;
34843             serializePack(&type, 1, CDI_DATATYPE_INT, pB,
34844                           pBSize, &packBufferPos, context);
34845             curr->res.v.ops->valPack(curr->res.v.val,
34846                                      pB, pBSize, &packBufferPos, context);
34847           }
34848         r[i].status &= ~RESH_SYNC_BIT;
34849       }
34850 
34851   LIST_UNLOCK();
34852 
34853   serializePack(&end, 1,  CDI_DATATYPE_INT, pB, pBSize, &packBufferPos, context);
34854 
34855   return packBufferPos;
34856 }
34857 
34858 /**************************************************************/
34859 
34860 /* for thread safety this feature would have to be integrated in reshPut */
34861 
reshSetStatus(cdiResH resH,const resOps * ops,int status)34862 void reshSetStatus ( cdiResH resH, const resOps * ops, int status )
34863 {
34864   int nsp;
34865   namespaceTuple_t nspT;
34866   listElem_t * listElem;
34867 
34868   xassert((ops != NULL) ^ !(status & RESH_IN_USE_BIT));
34869 
34870   LIST_INIT(1);
34871 
34872   LIST_LOCK();
34873 
34874   nsp = namespaceGetActive ();
34875 
34876   nspT = namespaceResHDecode ( resH );
34877 
34878   xassert ( nspT.nsp == nsp &&
34879             nspT.idx >= 0 &&
34880             nspT.idx < resHList[nsp].size );
34881 
34882   xassert ( resHList[nsp].resources );
34883   listElem = resHList[nsp].resources + nspT.idx;
34884 
34885   xassert((!ops || (listElem->res.v.ops == ops))
34886           && (listElem->status & RESH_IN_USE_BIT) == (status & RESH_IN_USE_BIT));
34887 
34888   listElem->status = status;
34889 
34890   LIST_UNLOCK();
34891 }
34892 
34893 /**************************************************************/
34894 
reshGetStatus(cdiResH resH,const resOps * ops)34895 int reshGetStatus ( cdiResH resH, const resOps * ops )
34896 {
34897   LIST_INIT(1);
34898 
34899   LIST_LOCK();
34900 
34901   int nsp = namespaceGetActive ();
34902 
34903   namespaceTuple_t nspT = namespaceResHDecode ( resH );
34904 
34905   xassert ( nspT.nsp == nsp &&
34906             nspT.idx >= 0 );
34907 
34908   int status = RESH_UNUSED;
34909   if (nspT.idx < resHList[nsp].size)
34910     {
34911       listElem_t *listElem = resHList[nsp].resources + nspT.idx;
34912       const resOps *elemOps = listElem->res.v.ops;
34913       xassert(listElem && (!(listElem->status & RESH_IN_USE_BIT) || elemOps == ops));
34914       status = listElem->status;
34915     }
34916 
34917   LIST_UNLOCK();
34918 
34919   return status;
34920 }
34921 
34922 /**************************************************************/
34923 
reshLock()34924 void reshLock ()
34925 {
34926   LIST_LOCK();
34927 }
34928 
34929 /**************************************************************/
34930 
reshUnlock()34931 void reshUnlock ()
34932 {
34933   LIST_UNLOCK();
34934 }
34935 
34936 /**************************************************************/
34937 
reshListCompare(int nsp0,int nsp1)34938 int reshListCompare ( int nsp0, int nsp1 )
34939 {
34940   LIST_INIT(1);
34941   LIST_LOCK();
34942 
34943   xassert(resHListSize > nsp0 && resHListSize > nsp1 &&
34944           nsp0 >= 0 && nsp1 >= 0);
34945 
34946   int valCompare = 0;
34947   int i, listSizeMin = (resHList[nsp0].size <= resHList[nsp1].size)
34948     ? resHList[nsp0].size : resHList[nsp1].size;
34949   listElem_t *resources0 = resHList[nsp0].resources,
34950     *resources1 = resHList[nsp1].resources;
34951   for (i = 0; i < listSizeMin; i++)
34952     {
34953       int occupied0 = (resources0[i].status & RESH_IN_USE_BIT) != 0,
34954         occupied1 = (resources1[i].status & RESH_IN_USE_BIT) != 0;
34955       /* occupation mismatch ? */
34956       int diff = occupied0 ^ occupied1;
34957       valCompare |= (diff << cdiResHListOccupationMismatch);
34958       if (!diff && occupied0)
34959         {
34960           /* both occupied, do resource types match? */
34961           diff = (resources0[i].res.v.ops != resources1[i].res.v.ops
34962                   || resources0[i].res.v.ops == NULL);
34963           valCompare |= (diff << cdiResHListResourceTypeMismatch);
34964           if (!diff)
34965             {
34966               /* types match, does content match also? */
34967               diff
34968                 = resources0[i].res.v.ops->valCompare(resources0[i].res.v.val,
34969                                                       resources1[i].res.v.val);
34970               valCompare |= (diff << cdiResHListResourceContentMismatch);
34971             }
34972         }
34973     }
34974   /* find resources in nsp 0 beyond end of nsp 1 */
34975   for (int j = listSizeMin; j < resHList[nsp0].size; ++j)
34976     valCompare |= (((resources0[j].status & RESH_IN_USE_BIT) != 0)
34977                    << cdiResHListOccupationMismatch);
34978   /* find resources in nsp 1 beyond end of nsp 0 */
34979   for (; i < resHList[nsp1].size; ++i)
34980     valCompare |= (((resources1[i].status & RESH_IN_USE_BIT) != 0)
34981                    << cdiResHListOccupationMismatch);
34982 
34983   LIST_UNLOCK();
34984 
34985   return valCompare;
34986 }
34987 
34988 /**************************************************************/
34989 
reshListPrint(FILE * fp)34990 void reshListPrint(FILE *fp)
34991 {
34992   int i, j, temp;
34993   listElem_t * curr;
34994 
34995   LIST_INIT(1);
34996 
34997 
34998   temp = namespaceGetActive ();
34999 
35000   fprintf ( fp, "\n\n##########################################\n#\n#  print " \
35001             "global resource list \n#\n" );
35002 
35003   for ( i = 0; i < namespaceGetNumber (); i++ )
35004     {
35005       namespaceSetActive ( i );
35006 
35007       fprintf ( fp, "\n" );
35008       fprintf ( fp, "##################################\n" );
35009       fprintf ( fp, "#\n" );
35010       fprintf ( fp, "# namespace=%d\n", i );
35011       fprintf ( fp, "#\n" );
35012       fprintf ( fp, "##################################\n\n" );
35013 
35014       fprintf ( fp, "resHList[%d].size=%d\n", i, resHList[i].size );
35015 
35016       for ( j = 0; j < resHList[i].size; j++ )
35017         {
35018           curr = resHList[i].resources + j;
35019           if (!(curr->status & RESH_IN_USE_BIT))
35020             {
35021               curr->res.v.ops->valPrint(curr->res.v.val, fp);
35022               fprintf ( fp, "\n" );
35023             }
35024         }
35025     }
35026   fprintf ( fp, "#\n#  end global resource list" \
35027             "\n#\n##########################################\n\n" );
35028 
35029   namespaceSetActive ( temp );
35030 }
35031 
35032 
35033 /*
35034  * Local Variables:
35035  * c-file-style: "Java"
35036  * c-basic-offset: 2
35037  * indent-tabs-mode: nil
35038  * show-trailing-whitespace: t
35039  * require-trailing-newline: t
35040  * End:
35041  */
35042 #include <inttypes.h>
35043 #include <limits.h>
35044 #include <string.h>
35045 
35046 
35047 int
serializeGetSize(int count,int datatype,void * context)35048 serializeGetSize(int count, int datatype, void *context)
35049 {
35050   int (*serialize_get_size_p)(int count, int datatype, void *context)
35051     = (int (*)(int, int, void *))
35052     namespaceSwitchGet(NSSWITCH_SERIALIZE_GET_SIZE).func;
35053   return serialize_get_size_p(count, datatype, context);
35054 }
35055 
serializePack(const void * data,int count,int datatype,void * buf,int buf_size,int * position,void * context)35056 void serializePack(const void *data, int count, int datatype,
35057                    void *buf, int buf_size, int *position, void *context)
35058 {
35059   void (*serialize_pack_p)(const void *data, int count, int datatype,
35060                            void *buf, int buf_size, int *position, void *context)
35061     = (void (*)(const void *, int, int, void *, int, int *, void *))
35062     namespaceSwitchGet(NSSWITCH_SERIALIZE_PACK).func;
35063   serialize_pack_p(data, count, datatype, buf, buf_size, position, context);
35064 }
35065 
serializeUnpack(const void * buf,int buf_size,int * position,void * data,int count,int datatype,void * context)35066 void serializeUnpack(const void *buf, int buf_size, int *position,
35067                      void *data, int count, int datatype, void *context)
35068 {
35069   void (*serialize_unpack_p)(const void *buf, int buf_size, int *position,
35070                              void *data, int count, int datatype, void *context)
35071     = (void (*)(const void *, int, int *, void *, int, int, void *))
35072     namespaceSwitchGet(NSSWITCH_SERIALIZE_UNPACK).func;
35073   serialize_unpack_p(buf, buf_size, position, data, count, datatype, context);
35074 }
35075 
35076 
35077 
35078 int
serializeGetSizeInCore(int count,int datatype,void * context)35079 serializeGetSizeInCore(int count, int datatype, void *context)
35080 {
35081   int elemSize;
35082   (void)context;
35083   switch (datatype)
35084   {
35085   case CDI_DATATYPE_INT8:
35086     elemSize = sizeof (int8_t);
35087     break;
35088   case CDI_DATATYPE_INT16:
35089     elemSize = sizeof (int16_t);
35090     break;
35091   case CDI_DATATYPE_UINT32:
35092     elemSize = sizeof (uint32_t);
35093     break;
35094   case CDI_DATATYPE_INT:
35095     elemSize = sizeof (int);
35096     break;
35097   case CDI_DATATYPE_UINT:
35098     elemSize = sizeof (unsigned);
35099     break;
35100   case CDI_DATATYPE_FLT:
35101   case CDI_DATATYPE_FLT64:
35102     elemSize = sizeof (double);
35103     break;
35104   case CDI_DATATYPE_TXT:
35105   case CDI_DATATYPE_UCHAR:
35106     elemSize = 1;
35107     break;
35108   case CDI_DATATYPE_LONG:
35109     elemSize = sizeof (long);
35110     break;
35111   default:
35112     xabort("Unexpected datatype");
35113   }
35114   return count * elemSize;
35115 }
35116 
serializePackInCore(const void * data,int count,int datatype,void * buf,int buf_size,int * position,void * context)35117 void serializePackInCore(const void *data, int count, int datatype,
35118                          void *buf, int buf_size, int *position, void *context)
35119 {
35120   int size = serializeGetSize(count, datatype, context);
35121   int pos = *position;
35122   xassert(INT_MAX - pos >= size && buf_size - pos >= size);
35123   memcpy((unsigned char *)buf + pos, data, (size_t)size);
35124   pos += size;
35125   *position = pos;
35126 }
35127 
serializeUnpackInCore(const void * buf,int buf_size,int * position,void * data,int count,int datatype,void * context)35128 void serializeUnpackInCore(const void *buf, int buf_size, int *position,
35129                            void *data, int count, int datatype, void *context)
35130 {
35131   int size = serializeGetSize(count, datatype, context);
35132   int pos = *position;
35133   xassert(INT_MAX - pos >= size && buf_size - pos >= size);
35134   memcpy(data, (unsigned char *)buf + pos, (size_t)size);
35135   pos += size;
35136   *position = pos;
35137 }
35138 
35139 /*
35140  * Local Variables:
35141  * c-file-style: "Java"
35142  * c-basic-offset: 2
35143  * indent-tabs-mode: nil
35144  * show-trailing-whitespace: t
35145  * require-trailing-newline: t
35146  * End:
35147  */
35148 #include <stdio.h>
35149 #include <stdlib.h>
35150 #include <stdarg.h>
35151 #include <string.h>
35152 #include <ctype.h>
35153 
35154 
35155 
35156 enum {
35157   SRV_HEADER_LEN = 8,
35158 };
35159 
35160 
35161 static int initSrvLib      = 0;
35162 static int srvDefaultHprec = 0;
35163 static int srvDefaultDprec = 0;
35164 
35165 
35166 /*
35167  * A version string.
35168  */
35169 #undef  LIBVERSION
35170 #define LIBVERSION      1.4.1
35171 #define XSTRING(x)	#x
35172 #define STRING(x)	XSTRING(x)
35173 static const char srv_libvers[] = STRING(LIBVERSION);
35174 
srvLibraryVersion(void)35175 const char *srvLibraryVersion(void)
35176 {
35177   return srv_libvers;
35178 }
35179 
35180 
35181 static int SRV_Debug = 0;    /* If set to 1, debugging */
35182 
35183 
srvDebug(int debug)35184 void srvDebug(int debug)
35185 {
35186   SRV_Debug = debug;
35187   if (SRV_Debug) Message("debug level %d", debug);
35188 }
35189 
35190 static
srvLibInit()35191 void srvLibInit()
35192 {
35193   const char *envName = "SRV_PRECISION";
35194 
35195   char *envString = getenv(envName);
35196   if ( envString )
35197     {
35198       int nrun = (strlen(envString) == 2) ? 1 : 2;
35199 
35200       int pos = 0;
35201       while ( nrun-- )
35202 	{
35203 	  switch ( tolower((int) envString[pos]) )
35204 	    {
35205 	    case 'i':
35206 	      {
35207 		switch ( (int) envString[pos+1] )
35208 		  {
35209 		  case '4': srvDefaultHprec = EXSE_SINGLE_PRECISION; break;
35210 		  case '8': srvDefaultHprec = EXSE_DOUBLE_PRECISION; break;
35211 		  default:
35212 		    Message("Invalid digit in %s: %s", envName, envString);
35213 		  }
35214 		break;
35215 	      }
35216 	    case 'r':
35217 	      {
35218 		switch ( (int) envString[pos+1] )
35219 		  {
35220 		  case '4': srvDefaultDprec = EXSE_SINGLE_PRECISION; break;
35221 		  case '8': srvDefaultDprec = EXSE_DOUBLE_PRECISION; break;
35222 		  default:
35223 		    Message("Invalid digit in %s: %s", envName, envString);
35224 		  }
35225 		break;
35226 	      }
35227 	    default:
35228               {
35229                 Message("Invalid character in %s: %s", envName, envString);
35230                 break;
35231               }
35232             }
35233 	  pos += 2;
35234 	}
35235     }
35236 
35237   initSrvLib = 1;
35238 }
35239 
35240 static
srvInit(srvrec_t * srvp)35241 void srvInit(srvrec_t *srvp)
35242 {
35243   srvp->checked    = 0;
35244   srvp->byteswap   = 0;
35245   srvp->hprec      = 0;
35246   srvp->dprec      = 0;
35247   srvp->datasize   = 0;
35248   srvp->buffersize = 0;
35249   srvp->buffer     = NULL;
35250 }
35251 
35252 
srvNew(void)35253 void *srvNew(void)
35254 {
35255   if ( ! initSrvLib ) srvLibInit();
35256 
35257   srvrec_t *srvp = (srvrec_t *) Malloc(sizeof(srvrec_t));
35258 
35259   srvInit(srvp);
35260 
35261   return (void*)srvp;
35262 }
35263 
35264 
srvDelete(void * srv)35265 void srvDelete(void *srv)
35266 {
35267   srvrec_t *srvp = (srvrec_t *) srv;
35268 
35269   if ( srvp )
35270     {
35271       if ( srvp->buffer ) Free(srvp->buffer);
35272       Free(srvp);
35273     }
35274 }
35275 
35276 
srvCheckFiletype(int fileID,int * swap)35277 int srvCheckFiletype(int fileID, int *swap)
35278 {
35279   size_t data = 0;
35280   size_t dimx = 0, dimy = 0;
35281   size_t fact = 0;
35282   unsigned char buffer[72], *pbuf;
35283 
35284   if ( fileRead(fileID, buffer, 4) != 4 ) return 0;
35285 
35286   size_t blocklen  = (size_t) get_UINT32(buffer);
35287   size_t sblocklen = (size_t) get_SUINT32(buffer);
35288 
35289   if ( SRV_Debug )
35290     Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
35291 
35292   if ( blocklen == 32 )
35293     {
35294      *swap = 0;
35295       fact = blocklen>>3;
35296       if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return 0;
35297       pbuf = buffer+4*fact;      dimx = (size_t) get_UINT32(pbuf);
35298       pbuf = buffer+5*fact;      dimy = (size_t) get_UINT32(pbuf);
35299       pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
35300     }
35301   else if ( blocklen == 64 )
35302     {
35303      *swap = 0;
35304       fact = blocklen>>3;
35305       if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return 0;
35306       pbuf = buffer+4*fact;      dimx = (size_t) get_UINT64(pbuf);
35307       pbuf = buffer+5*fact;      dimy = (size_t) get_UINT64(pbuf);
35308       pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
35309     }
35310   else if ( sblocklen == 32 )
35311     {
35312      *swap = 1;
35313       fact = sblocklen>>3;
35314       if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return 0;
35315       pbuf = buffer+4*fact;       dimx = (size_t) get_SUINT32(pbuf);
35316       pbuf = buffer+5*fact;       dimy = (size_t) get_SUINT32(pbuf);
35317       pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
35318     }
35319   else if ( sblocklen == 64 )
35320     {
35321      *swap = 1;
35322       fact = sblocklen>>3;
35323       if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return 0;
35324       pbuf = buffer+4*fact;       dimx = (size_t) get_SUINT64(pbuf);
35325       pbuf = buffer+5*fact;       dimy = (size_t) get_SUINT64(pbuf);
35326       pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
35327     }
35328 
35329   fileRewind(fileID);
35330 
35331   if ( SRV_Debug )
35332     {
35333       Message("swap = %d fact = %d", *swap, fact);
35334       Message("dimx = %lu dimy = %lu data = %lu", dimx, dimy, data);
35335     }
35336 
35337   int found = data && (dimx*dimy*fact == data || dimx*dimy*8 == data);
35338   return found;
35339 }
35340 
35341 
srvInqHeader(void * srv,int * header)35342 int srvInqHeader(void *srv, int *header)
35343 {
35344   srvrec_t *srvp = (srvrec_t *) srv;
35345 
35346   for (size_t i = 0; i < SRV_HEADER_LEN; i++) header[i] = srvp->header[i];
35347 
35348   if (SRV_Debug) Message("datasize = %lu", srvp->datasize);
35349 
35350   return 0;
35351 }
35352 
35353 
srvDefHeader(void * srv,const int * header)35354 int srvDefHeader(void *srv, const int *header)
35355 {
35356   srvrec_t *srvp = (srvrec_t *) srv;
35357 
35358   for (size_t i = 0; i < SRV_HEADER_LEN; i++) srvp->header[i] = header[i];
35359 
35360   srvp->datasize = (size_t)(header[4] * header[5]);
35361 
35362   if (SRV_Debug) Message("datasize = %lu", srvp->datasize);
35363 
35364   return 0;
35365 }
35366 
35367 static
srvInqData(srvrec_t * srvp,int prec,void * data)35368 int srvInqData(srvrec_t *srvp, int prec, void *data)
35369 {
35370   int ierr = 0;
35371   int byteswap = srvp->byteswap;
35372   size_t datasize = srvp->datasize;
35373   void *buffer = srvp->buffer;
35374   int dprec = srvp->dprec;
35375 
35376   switch ( dprec )
35377     {
35378     case EXSE_SINGLE_PRECISION:
35379       {
35380 	if ( sizeof(FLT32) == 4 )
35381 	  {
35382 	    if ( byteswap ) swap4byte(buffer, datasize);
35383 
35384 	    if ( dprec == prec )
35385 	      memcpy(data, buffer, datasize*sizeof(FLT32));
35386 	    else
35387 	      for (size_t i = 0; i < datasize; i++)
35388 		((double *) data)[i] = (double) ((float *) buffer)[i];
35389 	  }
35390 	else
35391 	  {
35392 	    Error("not implemented for %d byte float", sizeof(FLT32));
35393 	  }
35394 	break;
35395       }
35396     case EXSE_DOUBLE_PRECISION:
35397 	if ( sizeof(FLT64) == 8 )
35398 	  {
35399 	    if ( byteswap ) swap8byte(buffer, datasize);
35400 
35401 	    if ( dprec == prec )
35402 	      memcpy(data, buffer, datasize*sizeof(FLT64));
35403 	    else
35404 	      for (size_t i = 0; i < datasize; i++)
35405 		((float *) data)[i] = (float) ((double *) buffer)[i];
35406 	  }
35407 	else
35408 	  {
35409 	    Error("not implemented for %d byte float", sizeof(FLT64));
35410 	  }
35411 	break;
35412     default:
35413       {
35414 	Error("unexpected data precision %d", dprec);
35415         break;
35416       }
35417     }
35418 
35419   return ierr;
35420 }
35421 
35422 
srvInqDataSP(void * srv,float * data)35423 int srvInqDataSP(void *srv, float *data)
35424 {
35425   return srvInqData((srvrec_t *)srv, EXSE_SINGLE_PRECISION, (void *) data);
35426 }
35427 
35428 
srvInqDataDP(void * srv,double * data)35429 int srvInqDataDP(void *srv, double *data)
35430 {
35431   return srvInqData((srvrec_t *)srv, EXSE_DOUBLE_PRECISION, (void *) data);
35432 }
35433 
35434 
35435 static int
srvDefData(void * srv,int prec,const void * data)35436 srvDefData(void *srv, int prec, const void *data)
35437 {
35438   srvrec_t *srvp = (srvrec_t *) srv;
35439 
35440   int dprec = srvDefaultDprec ? srvDefaultDprec : srvp->dprec;
35441   srvp->dprec = dprec ? dprec : prec;
35442 
35443   int hprec = srvDefaultHprec ? srvDefaultHprec : srvp->hprec;
35444   srvp->hprec = hprec ? hprec : dprec;
35445 
35446   int *header = srvp->header;
35447 
35448   size_t datasize = (size_t)(header[4] * header[5]);
35449   size_t blocklen = datasize * (size_t)dprec;
35450 
35451   srvp->datasize = datasize;
35452 
35453   void *buffer = srvp->buffer;
35454   size_t buffersize = srvp->buffersize;
35455   if ( buffersize != blocklen )
35456     {
35457       buffersize = blocklen;
35458       buffer = Realloc(buffer, buffersize);
35459       srvp->buffer = buffer;
35460       srvp->buffersize = buffersize;
35461     }
35462 
35463   switch ( dprec )
35464     {
35465     case EXSE_SINGLE_PRECISION:
35466       {
35467 	if ( dprec == prec )
35468 	  memcpy(buffer, data, datasize*sizeof(FLT32));
35469 	else
35470 	  for (size_t i = 0; i < datasize; i++)
35471 	    ((float *) buffer)[i] = (float) ((double *) data)[i];
35472 
35473 	break;
35474       }
35475     case EXSE_DOUBLE_PRECISION:
35476       {
35477 	if ( dprec == prec )
35478 	  memcpy(buffer, data, datasize*sizeof(FLT64));
35479 	else
35480 	  for (size_t i = 0; i < datasize; i++)
35481 	    ((double *) buffer)[i] = (double) ((float *) data)[i];
35482 
35483 	break;
35484       }
35485     default:
35486       {
35487 	Error("unexpected data precision %d", dprec);
35488         break;
35489       }
35490     }
35491 
35492   return 0;
35493 }
35494 
35495 
srvDefDataSP(void * srv,const float * data)35496 int srvDefDataSP(void *srv, const float *data)
35497 {
35498   return srvDefData(srv, EXSE_SINGLE_PRECISION, (void *) data);
35499 }
35500 
35501 
srvDefDataDP(void * srv,const double * data)35502 int srvDefDataDP(void *srv, const double *data)
35503 {
35504   return srvDefData(srv, EXSE_DOUBLE_PRECISION, (void *) data);
35505 }
35506 
35507 
srvRead(int fileID,void * srv)35508 int srvRead(int fileID, void *srv)
35509 {
35510   srvrec_t *srvp = (srvrec_t *) srv;
35511   union {
35512     INT32 i32[SRV_HEADER_LEN];
35513     INT64 i64[SRV_HEADER_LEN];
35514   } tempheader;
35515 
35516   if ( ! srvp->checked )
35517     {
35518       int status = srvCheckFiletype(fileID, &srvp->byteswap);
35519       if ( status == 0 ) Error("Not a SERVICE file!");
35520       srvp->checked = 1;
35521     }
35522 
35523   int byteswap = srvp->byteswap;
35524 
35525   /* read header record */
35526   size_t blocklen = binReadF77Block(fileID, byteswap);
35527 
35528   if ( fileEOF(fileID) ) return -1;
35529 
35530   if ( SRV_Debug ) Message("blocklen = %lu", blocklen);
35531 
35532   size_t hprec = blocklen / SRV_HEADER_LEN;
35533 
35534   srvp->hprec = (int)hprec;
35535 
35536   switch ( hprec )
35537     {
35538     case EXSE_SINGLE_PRECISION:
35539       {
35540 	binReadInt32(fileID, byteswap, SRV_HEADER_LEN, tempheader.i32);
35541 
35542 	for (size_t i = 0; i < SRV_HEADER_LEN; i++)
35543           srvp->header[i] = (int)tempheader.i32[i];
35544 
35545 	break;
35546       }
35547     case EXSE_DOUBLE_PRECISION:
35548       {
35549 	binReadInt64(fileID, byteswap, SRV_HEADER_LEN, tempheader.i64);
35550 
35551 	for (size_t i = 0; i < SRV_HEADER_LEN; i++)
35552           srvp->header[i] = (int)tempheader.i64[i];
35553 
35554 	break;
35555       }
35556     default:
35557       {
35558 	Error("Unexpected header precision %d", hprec);
35559         break;
35560       }
35561     }
35562 
35563   size_t blocklen2 = binReadF77Block(fileID, byteswap);
35564 
35565   if ( blocklen2 != blocklen )
35566     {
35567       Warning("Header blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
35568       if ( blocklen2 != 0 ) return -1;
35569     }
35570 
35571   srvp->datasize = (size_t)(srvp->header[4] * srvp->header[5]);
35572 
35573   if ( SRV_Debug ) Message("datasize = %lu", srvp->datasize);
35574 
35575   blocklen = binReadF77Block(fileID, byteswap);
35576 
35577   void *buffer = srvp->buffer;
35578   size_t buffersize = srvp->buffersize;
35579 
35580   if ( buffersize < blocklen )
35581     {
35582       buffersize = blocklen;
35583       buffer = Realloc(buffer, buffersize);
35584       srvp->buffer = buffer;
35585       srvp->buffersize = buffersize;
35586     }
35587 
35588   size_t datasize = srvp->datasize;
35589 
35590   size_t dprec = blocklen / datasize;
35591 
35592   srvp->dprec = (int)dprec;
35593 
35594   if ( dprec != EXSE_SINGLE_PRECISION && dprec != EXSE_DOUBLE_PRECISION )
35595     {
35596       Warning("Unexpected data precision %d", dprec);
35597       return -1;
35598     }
35599 
35600   fileRead(fileID, buffer, blocklen);
35601 
35602   blocklen2 = binReadF77Block(fileID, byteswap);
35603 
35604   if ( blocklen2 != blocklen )
35605     {
35606       Warning("Data blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
35607       if ( blocklen2 != 0 ) return -1;
35608     }
35609 
35610   return 0;
35611 }
35612 
35613 
srvWrite(int fileID,void * srv)35614 void srvWrite(int fileID, void *srv)
35615 {
35616   srvrec_t *srvp = (srvrec_t *) srv;
35617   union
35618   {
35619     INT32 i32[SRV_HEADER_LEN];
35620     INT64 i64[SRV_HEADER_LEN];
35621   } tempheader;
35622   int byteswap = srvp->byteswap;
35623   int dprec  = srvp->dprec;
35624   int hprec  = srvp->hprec;
35625   int *restrict header = srvp->header;
35626 
35627   /* write header record */
35628   size_t blocklen = SRV_HEADER_LEN * (size_t)hprec;
35629 
35630   binWriteF77Block(fileID, byteswap, blocklen);
35631 
35632   switch ( hprec )
35633     {
35634     case EXSE_SINGLE_PRECISION:
35635       {
35636 	for (size_t i = 0; i < SRV_HEADER_LEN; i++)
35637           tempheader.i32[i] = (INT32) header[i];
35638 
35639 	binWriteInt32(fileID, byteswap, SRV_HEADER_LEN, tempheader.i32);
35640 
35641 	break;
35642       }
35643     case EXSE_DOUBLE_PRECISION:
35644       {
35645 	for (size_t i = 0; i < SRV_HEADER_LEN; i++)
35646           tempheader.i64[i] = (INT64) header[i];
35647 
35648 	binWriteInt64(fileID, byteswap, SRV_HEADER_LEN, tempheader.i64);
35649 
35650 	break;
35651       }
35652     default:
35653       {
35654 	Error("unexpected header precision %d", hprec);
35655         break;
35656       }
35657     }
35658 
35659   binWriteF77Block(fileID, byteswap, blocklen);
35660 
35661   size_t datasize = (size_t)(header[4] * header[5]);
35662   blocklen = datasize * (size_t)dprec;
35663 
35664   binWriteF77Block(fileID, byteswap, blocklen);
35665 
35666   srvp->datasize = datasize;
35667 
35668   void *buffer = srvp->buffer;
35669 
35670   switch ( dprec )
35671     {
35672     case EXSE_SINGLE_PRECISION:
35673       {
35674 	binWriteFlt32(fileID, byteswap, datasize, (FLT32 *) buffer);
35675 	break;
35676       }
35677     case EXSE_DOUBLE_PRECISION:
35678       {
35679 	binWriteFlt64(fileID, byteswap, datasize, (FLT64 *) buffer);
35680 	break;
35681       }
35682     default:
35683       {
35684 	Error("unexpected data precision %d", dprec);
35685         break;
35686       }
35687     }
35688 
35689   binWriteF77Block(fileID, byteswap, blocklen);
35690 }
35691 /*
35692  * Local Variables:
35693  * c-file-style: "Java"
35694  * c-basic-offset: 2
35695  * indent-tabs-mode: nil
35696  * show-trailing-whitespace: t
35697  * require-trailing-newline: t
35698  * End:
35699  */
35700 #ifndef STREAM_SCAN_H
35701 #define STREAM_SCAN_H
35702 
35703 
35704 void streamScanResizeRecords1(stream_t *streamptr);
35705 int streamScanInitRecords2(stream_t *streamptr);
35706 int streamScanInitRecords(stream_t *streamptr, int tsID);
35707 void streamScanTimeConstAdjust(stream_t *streamptr, const taxis_t *taxis);
35708 void streamScanTsFixNtsteps(stream_t *streamptr, off_t recpos);
35709 
35710 #endif  /* STREAM_SCAN_H */
35711 
35712 
streamScanResizeRecords1(stream_t * streamptr)35713 void streamScanResizeRecords1(stream_t *streamptr)
35714 {
35715   const int nrecords = streamptr->tsteps[0].nallrecs;
35716   if (nrecords < streamptr->tsteps[0].recordSize)
35717     {
35718       streamptr->tsteps[0].recordSize = nrecords;
35719       streamptr->tsteps[0].records =
35720         (record_t *) Realloc(streamptr->tsteps[0].records, (size_t)nrecords*sizeof(record_t));
35721     }
35722 
35723   streamptr->tsteps[0].recIDs = (int *) Malloc((size_t)nrecords*sizeof(int));
35724   streamptr->tsteps[0].nrecs = nrecords;
35725   for (int recID = 0; recID < nrecords; ++recID)
35726     streamptr->tsteps[0].recIDs[recID] = recID;
35727 }
35728 
35729 
streamScanInitRecords2(stream_t * streamptr)35730 int streamScanInitRecords2(stream_t *streamptr)
35731 {
35732   const int nrecords = streamptr->tsteps[1].nallrecs;
35733   streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords*sizeof(int));
35734   streamptr->tsteps[1].nrecs = 0;
35735 
35736   for (int recID = 0; recID < nrecords; ++recID)
35737     streamptr->tsteps[1].recIDs[recID] = -1;
35738 
35739   for (int recID = 0; recID < nrecords; ++recID)
35740     {
35741       streamptr->tsteps[1].records[recID].position = streamptr->tsteps[0].records[recID].position;
35742       streamptr->tsteps[1].records[recID].size     = streamptr->tsteps[0].records[recID].size;
35743     }
35744 
35745   return nrecords;
35746 }
35747 
35748 
streamScanInitRecords(stream_t * streamptr,int tsID)35749 int streamScanInitRecords(stream_t *streamptr, int tsID)
35750 {
35751   const int nrecs = streamptr->tsteps[1].nrecs;
35752 
35753   streamptr->tsteps[tsID].nrecs = nrecs;
35754   streamptr->tsteps[tsID].recIDs = (int *) Malloc((size_t)nrecs*sizeof(int));
35755 
35756   for (int recID = 0; recID < nrecs; ++recID)
35757     streamptr->tsteps[tsID].recIDs[recID] = streamptr->tsteps[1].recIDs[recID];
35758 
35759   return nrecs;
35760 }
35761 
35762 
streamScanTimeConstAdjust(stream_t * streamptr,const taxis_t * taxis)35763 void streamScanTimeConstAdjust(stream_t *streamptr, const taxis_t *taxis)
35764 {
35765   const int vlistID = streamptr->vlistID;
35766   if (streamptr->ntsteps == 1)
35767     {
35768       if (taxis->vdate == 0 && taxis->vtime == 0)
35769 	{
35770 	  streamptr->ntsteps = 0;
35771 	  for (int varID = 0; varID < streamptr->nvars; ++varID)
35772             vlistDefVarTimetype(vlistID, varID, TIME_CONSTANT);
35773 	}
35774     }
35775 }
35776 
35777 
streamScanTsFixNtsteps(stream_t * streamptr,off_t recpos)35778 void streamScanTsFixNtsteps(stream_t *streamptr, off_t recpos)
35779 {
35780   if (streamptr->ntsteps == -1)
35781     {
35782       const int tsID = tstepsNewEntry(streamptr);
35783       if (tsID != streamptr->rtsteps)
35784 	Error("Internal error. tsID = %d", tsID);
35785 
35786       streamptr->tsteps[tsID-1].next = true;
35787       streamptr->tsteps[tsID].position = recpos;
35788     }
35789 }
35790 #ifndef STREAM_CGRIBEX_H
35791 #define STREAM_CGRIBEX_H
35792 
35793 void *cgribexNew();
35794 void cgribexDelete(void *cgribexp);
35795 
35796 int cgribexScanTimestep1(stream_t *streamptr);
35797 int cgribexScanTimestep2(stream_t *streamptr);
35798 int cgribexScanTimestep(stream_t *streamptr);
35799 
35800 int cgribexDecode(int memtype, void *cgribexp, void *gribbuffer, size_t gribsize, void *data, size_t datasize,
35801 		  int unreduced, size_t *nmiss, double missval);
35802 
35803 size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
35804 		     int vdate, int vtime, int tsteptype, int numavg,
35805 		     size_t datasize, const void *data, size_t nmiss, void *gribbuffer, size_t gribbuffersize);
35806 
35807 void *cgribex_handle_new_from_meassage(void *gribbuffer, size_t recsize);
35808 void cgribex_handle_delete(void *gh);
35809 
35810 void cgribexChangeParameterIdentification(void *gh, int code, int ltype, int lev);
35811 
35812 #endif  /* STREAM_CGRIBEX_H */
35813 /*
35814  * Local Variables:
35815  * c-file-style: "Java"
35816  * c-basic-offset: 2
35817  * indent-tabs-mode: nil
35818  * show-trailing-whitespace: t
35819  * require-trailing-newline: t
35820  * End:
35821  */
35822 #ifndef _STREAM_SRV_H
35823 #define _STREAM_SRV_H
35824 
35825 #ifndef _SERVICE_H
35826 #endif
35827 
35828 int    srvInqContents(stream_t *streamptr);
35829 int    srvInqTimestep(stream_t *streamptr, int tsID);
35830 
35831 int    srvInqRecord(stream_t *streamptr, int *varID, int *levelID);
35832 void   srvDefRecord(stream_t *streamptr);
35833 void   srvCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
35834 void   srvReadRecord(stream_t *streamptr, double *data, size_t *nmiss);
35835 void   srvWriteRecord(stream_t *streamptr, const double *data);
35836 
35837 void   srvReadVarDP (stream_t *streamptr, int varID,       double *data, size_t *nmiss);
35838 void   srvWriteVarDP(stream_t *streamptr, int varID, const double *data);
35839 
35840 void   srvReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, size_t *nmiss);
35841 void   srvWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
35842 
35843 #endif  /* _STREAM_SRV_H */
35844 /*
35845  * Local Variables:
35846  * c-file-style: "Java"
35847  * c-basic-offset: 2
35848  * indent-tabs-mode: nil
35849  * show-trailing-whitespace: t
35850  * require-trailing-newline: t
35851  * End:
35852  */
35853 #ifndef _STREAM_EXT_H
35854 #define _STREAM_EXT_H
35855 
35856 #ifndef _EXTRA_H
35857 #endif
35858 
35859 int    extInqContents(stream_t *streamptr);
35860 int    extInqTimestep(stream_t *streamptr, int tsID);
35861 
35862 int    extInqRecord(stream_t *streamptr, int *varID, int *levelID);
35863 void   extDefRecord(stream_t *streamptr);
35864 void   extCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
35865 void   extReadRecord(stream_t *streamptr, double *data, size_t *nmiss);
35866 void   extWriteRecord(stream_t *streamptr, const double *data);
35867 
35868 void   extReadVarDP (stream_t *streamptr, int varID,       double *data, size_t *nmiss);
35869 void   extWriteVarDP(stream_t *streamptr, int varID, const double *data);
35870 
35871 void   extReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, size_t *nmiss);
35872 void   extWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
35873 
35874 #endif  /* _STREAM_EXT_H */
35875 /*
35876  * Local Variables:
35877  * c-file-style: "Java"
35878  * c-basic-offset: 2
35879  * indent-tabs-mode: nil
35880  * show-trailing-whitespace: t
35881  * require-trailing-newline: t
35882  * End:
35883  */
35884 #ifndef _STREAM_IEG_H
35885 #define _STREAM_IEG_H
35886 
35887 #ifndef _IEG_H
35888 #endif
35889 
35890 int    iegInqContents(stream_t *streamptr);
35891 int    iegInqTimestep(stream_t *streamptr, int tsID);
35892 
35893 int    iegInqRecord(stream_t *streamptr, int *varID, int *levelID);
35894 void   iegDefRecord(stream_t *streamptr);
35895 void   iegCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
35896 void   iegReadRecord(stream_t *streamptr, double *data, size_t *nmiss);
35897 void   iegWriteRecord(stream_t *streamptr, const double *data);
35898 
35899 void   iegReadVarDP (stream_t *streamptr, int varID,       double *data, size_t *nmiss);
35900 void   iegWriteVarDP(stream_t *streamptr, int varID, const double *data);
35901 
35902 void   iegReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, size_t *nmiss);
35903 void   iegWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
35904 
35905 #endif  /* _STREAM_IEG_H */
35906 /*
35907  * Local Variables:
35908  * c-file-style: "Java"
35909  * c-basic-offset: 2
35910  * indent-tabs-mode: nil
35911  * show-trailing-whitespace: t
35912  * require-trailing-newline: t
35913  * End:
35914  */
35915 #ifdef  HAVE_CONFIG_H
35916 #endif
35917 
35918 #ifndef _XOPEN_SOURCE
35919 #define _XOPEN_SOURCE 600
35920 #endif
35921 
35922 #include <sys/stat.h> // struct stat
35923 #include <ctype.h>
35924 
35925 
35926 
35927 static stream_t *stream_new_entry(int resH);
35928 static void stream_delete_entry(stream_t *streamptr);
35929 static int streamCompareP(void * streamptr1, void * streamptr2);
35930 static void streamDestroyP(void * streamptr);
35931 static void streamPrintP(void * streamptr, FILE * fp);
35932 static int streamGetPackSize(void * streamptr, void *context);
35933 static void streamPack(void * streamptr, void * buff, int size, int * position, void *context);
35934 static int streamTxCode(void);
35935 
35936 const resOps streamOps = {
35937   streamCompareP,
35938   streamDestroyP,
35939   streamPrintP,
35940   streamGetPackSize,
35941   streamPack,
35942   streamTxCode
35943 };
35944 
35945 
35946 
35947 static
getByteorder(int byteswap)35948 int getByteorder(int byteswap)
35949 {
35950   int byteorder = -1;
35951 
35952   switch (HOST_ENDIANNESS)
35953     {
35954     case CDI_BIGENDIAN:
35955       byteorder = byteswap ? CDI_LITTLEENDIAN : CDI_BIGENDIAN;
35956       break;
35957     case CDI_LITTLEENDIAN:
35958       byteorder = byteswap ? CDI_BIGENDIAN : CDI_LITTLEENDIAN;
35959       break;
35960     /* FIXME: does not currently adjust for PDP endianness */
35961     case CDI_PDPENDIAN:
35962     default:
35963       Error("unhandled endianness");
35964     }
35965   return byteorder;
35966 }
35967 
35968 // used also in CDO
cdiGetFiletype(const char * filename,int * byteorder)35969 int cdiGetFiletype(const char *filename, int *byteorder)
35970 {
35971   int filetype = CDI_EUFTYPE;
35972   int swap = 0;
35973   int version;
35974   long recpos;
35975 
35976   int fileID = fileOpen(filename, "r");
35977 
35978   if ( fileID == CDI_UNDEFID )
35979     {
35980       if ( strncmp(filename, "http:", 5) == 0 || strncmp(filename, "https:", 6) == 0 )
35981 	return CDI_FILETYPE_NC;
35982       else
35983 	return CDI_ESYSTEM;
35984     }
35985   else if ( fileID == -2 ) return CDI_ETMOF;
35986 
35987   char buffer[8];
35988   if ( fileRead(fileID, buffer, 8) != 8 )
35989     {
35990       struct stat buf;
35991       if ( stat(filename, &buf) == 0 )
35992         {
35993           if ( buf.st_size == 0 ) return CDI_EISEMPTY;
35994           if ( buf.st_mode&S_IFDIR ) return CDI_EISDIR;
35995         }
35996 
35997       return CDI_EUFTYPE;
35998     }
35999 
36000   fileRewind(fileID);
36001 
36002   if ( memcmp(buffer, "GRIB", 4) == 0 )
36003     {
36004       version = buffer[7];
36005       if ( version <= 1 )
36006 	{
36007 	  filetype = CDI_FILETYPE_GRB;
36008 	  if ( CDI_Debug ) Message("found GRIB file = %s, version %d", filename, version);
36009 	}
36010       else if ( version == 2 )
36011 	{
36012 	  filetype = CDI_FILETYPE_GRB2;
36013 	  if ( CDI_Debug ) Message("found GRIB2 file = %s", filename);
36014 	}
36015     }
36016   else if ( memcmp(buffer, "CDF\001", 4) == 0 )
36017     {
36018       filetype = CDI_FILETYPE_NC;
36019       if ( CDI_Debug ) Message("found CDF1 file = %s", filename);
36020     }
36021   else if ( memcmp(buffer, "CDF\002", 4) == 0 )
36022     {
36023       filetype = CDI_FILETYPE_NC2;
36024       if ( CDI_Debug ) Message("found CDF2 file = %s", filename);
36025     }
36026   else if ( memcmp(buffer, "CDF\005", 4) == 0 )
36027     {
36028       filetype = CDI_FILETYPE_NC5;
36029       if ( CDI_Debug ) Message("found CDF5 file = %s", filename);
36030     }
36031   else if ( memcmp(buffer+1, "HDF", 3) == 0 )
36032     {
36033       filetype = CDI_FILETYPE_NC4;
36034       if ( CDI_Debug ) Message("found HDF file = %s", filename);
36035     }
36036 #ifdef  HAVE_LIBSERVICE
36037   else if ( srvCheckFiletype(fileID, &swap) )
36038     {
36039       filetype = CDI_FILETYPE_SRV;
36040       if ( CDI_Debug ) Message("found SRV file = %s", filename);
36041     }
36042 #endif
36043 #ifdef  HAVE_LIBEXTRA
36044   else if ( extCheckFiletype(fileID, &swap) )
36045     {
36046       filetype = CDI_FILETYPE_EXT;
36047       if ( CDI_Debug ) Message("found EXT file = %s", filename);
36048     }
36049 #endif
36050 #ifdef  HAVE_LIBIEG
36051   else if ( iegCheckFiletype(fileID, &swap) )
36052     {
36053       filetype = CDI_FILETYPE_IEG;
36054       if ( CDI_Debug ) Message("found IEG file = %s", filename);
36055     }
36056 #endif
36057 #ifdef HAVE_LIBGRIB
36058   else if ( gribCheckSeek(fileID, &recpos, &version) == 0 )
36059     {
36060       if ( version <= 1 )
36061 	{
36062 	  filetype = CDI_FILETYPE_GRB;
36063 	  if ( CDI_Debug ) Message("found seeked GRIB file = %s", filename);
36064 	}
36065       else if ( version == 2 )
36066 	{
36067 	  filetype = CDI_FILETYPE_GRB2;
36068 	  if ( CDI_Debug ) Message("found seeked GRIB2 file = %s", filename);
36069 	}
36070     }
36071 #endif
36072 
36073   fileClose(fileID);
36074 
36075   *byteorder = getByteorder(swap);
36076 
36077   return filetype;
36078 }
36079 
36080 /*
36081 @Function  streamInqFiletype
36082 @Title     Get the filetype
36083 
36084 @Prototype int streamInqFiletype(int streamID)
36085 @Parameter
36086     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
36087 
36088 @Description
36089 The function @func{streamInqFiletype} returns the filetype of a stream.
36090 
36091 @Result
36092 @func{streamInqFiletype} returns the type of the file format,
36093 one of the set of predefined CDI file format types.
36094 The valid CDI file format types are @func{CDI_FILETYPE_GRB}, @func{CDI_FILETYPE_GRB2}, @func{CDI_FILETYPE_NC}, @func{CDI_FILETYPE_NC2},
36095 @func{CDI_FILETYPE_NC4}, @func{CDI_FILETYPE_NC4C}, @func{CDI_FILETYPE_NC5}, @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} and @func{CDI_FILETYPE_IEG}.
36096 
36097 @EndFunction
36098 */
streamInqFiletype(int streamID)36099 int streamInqFiletype(int streamID)
36100 {
36101   stream_t *streamptr = stream_to_pointer(streamID);
36102   return streamptr->filetype;
36103 }
36104 
36105 
getByteswap(int byteorder)36106 int getByteswap(int byteorder)
36107 {
36108   int byteswap = -1;
36109 
36110   switch (byteorder)
36111     {
36112     case CDI_BIGENDIAN:
36113     case CDI_LITTLEENDIAN:
36114     case CDI_PDPENDIAN:
36115       byteswap = (HOST_ENDIANNESS != byteorder);
36116       break;
36117     case -1:
36118       break;
36119     default:
36120       Error("unexpected byteorder %d query!", byteorder);
36121     }
36122 
36123   return byteswap;
36124 }
36125 
36126 
streamDefNumWorker(int streamID,int numWorker)36127 void streamDefNumWorker(int streamID, int numWorker)
36128 {
36129   if (numWorker > 0)
36130     {
36131       stream_t *streamptr = stream_to_pointer(streamID);
36132       streamptr->numWorker = numWorker;
36133     }
36134 }
36135 
36136 
36137 /*
36138 @Function  streamDefByteorder
36139 @Title     Define the byte order
36140 
36141 @Prototype void streamDefByteorder(int streamID, int byteorder)
36142 @Parameter
36143     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
36144     @Item  byteorder The byte order of a dataset, one of the CDI constants @func{CDI_BIGENDIAN} and
36145                      @func{CDI_LITTLEENDIAN}.
36146 
36147 @Description
36148 The function @func{streamDefByteorder} defines the byte order of a binary dataset
36149 with the file format type @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} or @func{CDI_FILETYPE_IEG}.
36150 
36151 @EndFunction
36152 */
streamDefByteorder(int streamID,int byteorder)36153 void streamDefByteorder(int streamID, int byteorder)
36154 {
36155   stream_t *streamptr = stream_to_pointer(streamID);
36156   streamptr->byteorder = byteorder;
36157   int filetype = streamptr->filetype;
36158 
36159   switch (filetype)
36160     {
36161 #ifdef  HAVE_LIBSERVICE
36162     case CDI_FILETYPE_SRV:
36163       {
36164 	srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
36165 	srvp->byteswap = getByteswap(byteorder);
36166 
36167 	break;
36168       }
36169 #endif
36170 #ifdef  HAVE_LIBEXTRA
36171     case CDI_FILETYPE_EXT:
36172       {
36173 	extrec_t *extp = (extrec_t*) streamptr->record->exsep;
36174 	extp->byteswap = getByteswap(byteorder);
36175 
36176 	break;
36177       }
36178 #endif
36179 #ifdef  HAVE_LIBIEG
36180     case CDI_FILETYPE_IEG:
36181       {
36182 	iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
36183 	iegp->byteswap = getByteswap(byteorder);
36184 
36185 	break;
36186       }
36187 #endif
36188     }
36189 
36190   reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
36191 }
36192 
36193 /*
36194 @Function  streamInqByteorder
36195 @Title     Get the byte order
36196 
36197 @Prototype int streamInqByteorder(int streamID)
36198 @Parameter
36199     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
36200 
36201 @Description
36202 The function @func{streamInqByteorder} returns the byte order of a binary dataset
36203 with the file format type @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} or @func{CDI_FILETYPE_IEG}.
36204 
36205 @Result
36206 @func{streamInqByteorder} returns the type of the byte order.
36207 The valid CDI byte order types are @func{CDI_BIGENDIAN} and @func{CDI_LITTLEENDIAN}
36208 
36209 @EndFunction
36210 */
streamInqByteorder(int streamID)36211 int streamInqByteorder(int streamID)
36212 {
36213   stream_t *streamptr = stream_to_pointer(streamID);
36214   return streamptr->byteorder;
36215 }
36216 
36217 
streamFilesuffix(int filetype)36218 const char *streamFilesuffix(int filetype)
36219 {
36220   static const char *noSuffix  = "";
36221   static const char *ncSuffix  = ".nc";
36222   static const char *grbSuffix = ".grb";
36223   static const char *srvSuffix = ".srv";
36224   static const char *extSuffix = ".ext";
36225   static const char *iegSuffix = ".ieg";
36226 
36227   switch (cdiBaseFiletype(filetype))
36228     {
36229     case CDI_FILETYPE_GRB:
36230     case CDI_FILETYPE_GRB2:    return grbSuffix;
36231     case CDI_FILETYPE_SRV:     return srvSuffix;
36232     case CDI_FILETYPE_EXT:     return extSuffix;
36233     case CDI_FILETYPE_IEG:     return iegSuffix;
36234     case CDI_FILETYPE_NETCDF:  return ncSuffix;
36235     default:                   return noSuffix;
36236     }
36237 }
36238 
36239 
streamFilename(int streamID)36240 const char *streamFilename(int streamID)
36241 {
36242   stream_t *streamptr = stream_to_pointer(streamID);
36243   return streamptr->filename;
36244 }
36245 
36246 static
cdiInqTimeSize(int streamID)36247 long cdiInqTimeSize(int streamID)
36248 {
36249   int tsID = 0, nrecs;
36250   stream_t *streamptr = stream_to_pointer(streamID);
36251   long ntsteps = streamptr->ntsteps;
36252 
36253   if ( ntsteps == (long)CDI_UNDEFID )
36254     while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
36255       ntsteps = streamptr->ntsteps;
36256 
36257   return ntsteps;
36258 }
36259 
36260 static
cdiInqContents(stream_t * streamptr)36261 int cdiInqContents(stream_t *streamptr)
36262 {
36263   int status = 0;
36264   int filetype = streamptr->filetype;
36265 
36266   switch (cdiBaseFiletype(filetype))
36267     {
36268 #ifdef  HAVE_LIBGRIB
36269     case CDI_FILETYPE_GRB:
36270     case CDI_FILETYPE_GRB2:
36271       {
36272         status = grbInqContents(streamptr);
36273 	break;
36274       }
36275 #endif
36276 #ifdef  HAVE_LIBSERVICE
36277     case CDI_FILETYPE_SRV:
36278       {
36279         status = srvInqContents(streamptr);
36280 	break;
36281       }
36282 #endif
36283 #ifdef  HAVE_LIBEXTRA
36284     case CDI_FILETYPE_EXT:
36285       {
36286         status = extInqContents(streamptr);
36287 	break;
36288       }
36289 #endif
36290 #ifdef  HAVE_LIBIEG
36291     case CDI_FILETYPE_IEG:
36292       {
36293         status = iegInqContents(streamptr);
36294 	break;
36295       }
36296 #endif
36297 #ifdef  HAVE_LIBNETCDF
36298     case CDI_FILETYPE_NETCDF:
36299       {
36300         status = cdfInqContents(streamptr);
36301 	break;
36302       }
36303 #endif
36304     default:
36305       {
36306 	if ( CDI_Debug )
36307 	  Message("%s support not compiled in!", strfiletype(filetype));
36308 
36309 	status = CDI_ELIBNAVAIL;
36310         break;
36311       }
36312     }
36313 
36314   if ( status == 0 )
36315     {
36316       int taxisID = vlistInqTaxis(streamptr->vlistID);
36317       if ( taxisID != CDI_UNDEFID )
36318         {
36319           taxis_t *taxisptr1 = &streamptr->tsteps[0].taxis;
36320           taxis_t *taxisptr2 = taxisPtr(taxisID);
36321           ptaxisCopy(taxisptr2, taxisptr1);
36322         }
36323     }
36324 
36325   return status;
36326 }
36327 
36328 
cdiStreamOpenDefaultDelegate(const char * filename,char filemode,int filetype,stream_t * streamptr,int recordBufIsToBeCreated)36329 int cdiStreamOpenDefaultDelegate(const char *filename, char filemode, int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
36330 {
36331   int fileID;
36332   char temp[2] = { filemode, 0 };
36333 
36334   switch (filetype)
36335     {
36336 #if defined(HAVE_LIBGRIB) && (defined(HAVE_LIBCGRIBEX) || defined(HAVE_LIBGRIB_API))
36337     case CDI_FILETYPE_GRB:
36338       {
36339         fileID = gribOpen(filename, temp);
36340         if ( fileID < 0 ) return CDI_ESYSTEM;
36341         if (recordBufIsToBeCreated)
36342           {
36343             streamptr->record = (Record *) Malloc(sizeof(Record));
36344             streamptr->record->buffer = NULL;
36345 #ifdef  HAVE_LIBCGRIBEX
36346             streamptr->record->cgribexp = cgribexNew();
36347 #else
36348             streamptr->record->cgribexp = NULL;
36349 #endif
36350           }
36351         break;
36352       }
36353 #ifdef  HAVE_LIBGRIB_API
36354     case CDI_FILETYPE_GRB2:
36355       {
36356         fileID = gribOpen(filename, temp);
36357         if ( fileID < 0 ) return CDI_ESYSTEM;
36358         if (recordBufIsToBeCreated)
36359           {
36360             streamptr->record = (Record *) Malloc(sizeof(Record));
36361             streamptr->record->buffer = NULL;
36362           }
36363         break;
36364       }
36365 #endif
36366 #endif
36367 #ifdef  HAVE_LIBSERVICE
36368     case CDI_FILETYPE_SRV:
36369       {
36370         fileID = fileOpen(filename, temp);
36371         if ( fileID < 0 ) return CDI_ESYSTEM;
36372         if (recordBufIsToBeCreated)
36373           {
36374             streamptr->record = (Record *) Malloc(sizeof(Record));
36375             streamptr->record->buffer = NULL;
36376             streamptr->record->exsep = srvNew();
36377           }
36378         break;
36379       }
36380 #endif
36381 #ifdef  HAVE_LIBEXTRA
36382     case CDI_FILETYPE_EXT:
36383       {
36384         fileID = fileOpen(filename, temp);
36385         if ( fileID < 0 ) return CDI_ESYSTEM;
36386         if (recordBufIsToBeCreated)
36387           {
36388             streamptr->record = (Record *) Malloc(sizeof(Record));
36389             streamptr->record->buffer = NULL;
36390             streamptr->record->exsep = extNew();
36391           }
36392         break;
36393       }
36394 #endif
36395 #ifdef  HAVE_LIBIEG
36396     case CDI_FILETYPE_IEG:
36397       {
36398         fileID = fileOpen(filename, temp);
36399         if ( fileID < 0 ) return CDI_ESYSTEM;
36400         if (recordBufIsToBeCreated)
36401           {
36402             streamptr->record = (Record *) Malloc(sizeof(Record));
36403             streamptr->record->buffer = NULL;
36404             streamptr->record->exsep = iegNew();
36405           }
36406         break;
36407       }
36408 #endif
36409 #ifdef  HAVE_LIBNETCDF
36410     case CDI_FILETYPE_NC:
36411     case CDI_FILETYPE_NC2:
36412     case CDI_FILETYPE_NC5:
36413       {
36414         fileID = cdfOpen(filename, temp, filetype);
36415         break;
36416       }
36417     case CDI_FILETYPE_NC4:
36418     case CDI_FILETYPE_NC4C:
36419       {
36420         fileID = cdf4Open(filename, temp, &filetype);
36421         break;
36422       }
36423 #endif
36424     default:
36425       {
36426         if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
36427         return CDI_ELIBNAVAIL;
36428       }
36429     }
36430 
36431   streamptr->filetype = filetype;
36432 
36433   return fileID;
36434 }
36435 
36436 
streamOpenID(const char * filename,char filemode,int filetype,int resH)36437 int streamOpenID(const char *filename, char filemode, int filetype, int resH)
36438 {
36439   if ( CDI_Debug )
36440     Message("Open %s mode %c file %s", strfiletype(filetype), filemode, filename?filename:"(NUL)");
36441 
36442   if ( ! filename || filetype < 0 ) return CDI_EINVAL;
36443 
36444   stream_t *streamptr = stream_new_entry(resH);
36445   int streamID = CDI_ESYSTEM;
36446 
36447   int (*streamOpenDelegate)(const char *filename, char filemode,
36448                             int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
36449     = (int (*)(const char *, char, int, stream_t *, int))
36450     namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
36451 
36452   int fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
36453   if ( fileID < 0 )
36454     {
36455       streamID = fileID;
36456     }
36457   else
36458     {
36459       streamID = streamptr->self;
36460       if ( streamID < 0 ) return CDI_ELIMIT;
36461 
36462       streamptr->filemode = filemode;
36463       streamptr->filename = strdupx(filename);
36464       streamptr->fileID   = fileID;
36465 
36466       if ( filemode == 'r' )
36467         {
36468           int vlistID = vlistCreate();
36469           if ( vlistID < 0 ) return CDI_ELIMIT;
36470 
36471           cdiVlistMakeInternal(vlistID);
36472           streamptr->vlistID = vlistID;
36473           /* cdiReadByteorder(streamID); */
36474           int status = cdiInqContents(streamptr);
36475           if ( status < 0 )
36476             {
36477               streamID = status;
36478             }
36479           else
36480             {
36481               vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
36482               vlistptr->ntsteps = streamptr->ntsteps;
36483               cdiVlistMakeImmutable(vlistID);
36484             }
36485         }
36486     }
36487 
36488   if ( streamID < 0 )
36489     {
36490       Free(streamptr->record);
36491       stream_delete_entry(streamptr);
36492     }
36493 
36494   return streamID;
36495 }
36496 
36497 static
streamOpen(const char * filename,const char * filemode,int filetype)36498 int streamOpen(const char *filename, const char *filemode, int filetype)
36499 {
36500   if ( !filemode || strlen(filemode) != 1 ) return CDI_EINVAL;
36501   return streamOpenID(filename, (char)tolower(filemode[0]), filetype, CDI_UNDEFID);
36502 }
36503 
36504 static
streamOpenA(const char * filename,const char * filemode,int filetype)36505 int streamOpenA(const char *filename, const char *filemode, int filetype)
36506 {
36507   if ( CDI_Debug )
36508     Message("Open %s file (mode=%c); filename: %s", strfiletype(filetype), (int) *filemode, filename);
36509   if ( CDI_Debug ) printf("streamOpenA: %s\n", filename); // seg fault without this line on thunder/squall with "cdo cat x y"
36510 
36511   if ( ! filename || ! filemode || filetype < 0 ) return CDI_EINVAL;
36512 
36513   stream_t *streamptr = stream_new_entry(CDI_UNDEFID);
36514   int fileID = CDI_UNDEFID;
36515 
36516   {
36517     int (*streamOpenDelegate)(const char *filename, char filemode,
36518                               int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
36519       = (int (*)(const char *, char, int, stream_t *, int))
36520       namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
36521 
36522     fileID = streamOpenDelegate(filename, 'r', filetype, streamptr, 1);
36523   }
36524 
36525   if ( fileID == CDI_UNDEFID || fileID == CDI_ELIBNAVAIL || fileID == CDI_ESYSTEM ) return fileID;
36526 
36527   int streamID = streamptr->self;
36528 
36529   streamptr->filemode = tolower(*filemode);
36530   streamptr->filename = strdupx(filename);
36531   streamptr->fileID   = fileID;
36532 
36533   streamptr->vlistID = vlistCreate();
36534   cdiVlistMakeInternal(streamptr->vlistID);
36535   /* cdiReadByteorder(streamID); */
36536   int status = cdiInqContents(streamptr);
36537   if ( status < 0 ) return status;
36538   vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
36539   vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
36540 
36541   // Needed for NetCDF4
36542   for ( int varID = 0; varID < vlistptr->nvars; ++varID )
36543     streamptr->vars[varID].defmiss = true;
36544 
36545   if ( !strcmp(filemode, "r") ) cdiVlistMakeImmutable(streamptr->vlistID);
36546 
36547   {
36548     void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
36549       = (void (*)(stream_t *, int))
36550       namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
36551 
36552     streamCloseDelegate(streamptr, 0);
36553   }
36554 
36555   switch (filetype)
36556     {
36557 #if defined(HAVE_LIBGRIB) && (defined(HAVE_LIBCGRIBEX) || defined(HAVE_LIBGRIB_API))
36558     case CDI_FILETYPE_GRB:
36559 #ifdef  HAVE_LIBGRIB_API
36560     case CDI_FILETYPE_GRB2:
36561 #endif
36562       {
36563         fileID = gribOpen(filename, filemode);
36564         if ( fileID != CDI_UNDEFID ) gribContainersNew(streamptr);
36565 	break;
36566       }
36567 #endif
36568 #ifdef  HAVE_LIBSERVICE
36569     case CDI_FILETYPE_SRV:
36570       {
36571         fileID = fileOpen(filename, filemode);
36572 	break;
36573       }
36574 #endif
36575 #ifdef  HAVE_LIBEXTRA
36576     case CDI_FILETYPE_EXT:
36577       {
36578         fileID = fileOpen(filename, filemode);
36579 	break;
36580       }
36581 #endif
36582 #ifdef  HAVE_LIBIEG
36583     case CDI_FILETYPE_IEG:
36584       {
36585         fileID = fileOpen(filename, filemode);
36586 	break;
36587       }
36588 #endif
36589 #ifdef  HAVE_LIBNETCDF
36590     case CDI_FILETYPE_NC:
36591     case CDI_FILETYPE_NC2:
36592     case CDI_FILETYPE_NC5:
36593       {
36594 	fileID = cdfOpen(filename, filemode, filetype);
36595 	streamptr->ncmode = 2;
36596 	break;
36597       }
36598     case CDI_FILETYPE_NC4:
36599     case CDI_FILETYPE_NC4C:
36600       {
36601 	fileID = cdf4Open(filename, filemode, &filetype);
36602 	streamptr->ncmode = 2;
36603 	break;
36604       }
36605 #endif
36606     default:
36607       {
36608 	if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
36609 	return CDI_ELIBNAVAIL;
36610       }
36611     }
36612 
36613   if ( fileID == CDI_UNDEFID )
36614     streamID = CDI_UNDEFID;
36615   else
36616     streamptr->fileID = fileID;
36617 
36618   return streamID;
36619 }
36620 
36621 /*
36622 @Function  streamOpenRead
36623 @Title     Open a dataset for reading
36624 
36625 @Prototype int streamOpenRead(const char *path)
36626 @Parameter
36627     @Item  path  The name of the dataset to be read.
36628 
36629 @Description
36630 The function @func{streamOpenRead} opens an existing dataset for reading.
36631 
36632 @Result
36633 Upon successful completion @func{streamOpenRead} returns an identifier to the
36634 open stream. Otherwise, a negative number with the error status is returned.
36635 
36636 @Errors
36637 @List
36638    @Item  CDI_ESYSTEM     Operating system error.
36639    @Item  CDI_EINVAL      Invalid argument.
36640    @Item  CDI_EUFILETYPE  Unsupported file type.
36641    @Item  CDI_ELIBNAVAIL  Library support not compiled in.
36642 @EndList
36643 
36644 @Example
36645 Here is an example using @func{streamOpenRead} to open an existing NetCDF
36646 file named @func{foo.nc} for reading:
36647 
36648 @Source
36649    ...
36650 int streamID;
36651    ...
36652 streamID = streamOpenRead("foo.nc");
36653 if ( streamID < 0 ) handle_error(streamID);
36654    ...
36655 @EndSource
36656 @EndFunction
36657 */
streamOpenRead(const char * filename)36658 int streamOpenRead(const char *filename)
36659 {
36660   cdiInitialize();
36661 
36662   int byteorder = 0;
36663   int filetype = cdiGetFiletype(filename, &byteorder);
36664 
36665   if ( filetype < 0 ) return filetype;
36666 
36667   int streamID = streamOpen(filename, "r", filetype);
36668 
36669   if ( streamID >= 0 )
36670     {
36671       stream_t *streamptr = stream_to_pointer(streamID);
36672       streamptr->byteorder = byteorder;
36673     }
36674 
36675   return streamID;
36676 }
36677 
36678 
streamOpenAppend(const char * filename)36679 int streamOpenAppend(const char *filename)
36680 {
36681   cdiInitialize();
36682 
36683   int byteorder = 0;
36684   int filetype = cdiGetFiletype(filename, &byteorder);
36685 
36686   if ( filetype < 0 ) return filetype;
36687 
36688   int streamID = streamOpenA(filename, "a", filetype);
36689 
36690   if ( streamID >= 0 )
36691     {
36692       stream_t *streamptr = stream_to_pointer(streamID);
36693       streamptr->byteorder = byteorder;
36694     }
36695 
36696   return streamID;
36697 }
36698 
36699 /*
36700 @Function  streamOpenWrite
36701 @Title     Create a new dataset
36702 
36703 @Prototype int streamOpenWrite(const char *path, int filetype)
36704 @Parameter
36705     @Item  path      The name of the new dataset.
36706     @Item  filetype  The type of the file format, one of the set of predefined CDI file format types.
36707                      The valid CDI file format types are @func{CDI_FILETYPE_GRB}, @func{CDI_FILETYPE_GRB2}, @func{CDI_FILETYPE_NC},
36708                      @func{CDI_FILETYPE_NC2}, @func{CDI_FILETYPE_NC4}, @func{CDI_FILETYPE_NC4C}, @func{CDI_FILETYPE_NC5}, @func{CDI_FILETYPE_SRV},
36709                      @func{CDI_FILETYPE_EXT} and @func{CDI_FILETYPE_IEG}.
36710 
36711 @Description
36712 The function @func{streamOpenWrite} creates a new datset.
36713 @Result
36714 Upon successful completion @func{streamOpenWrite} returns an identifier to the
36715 open stream. Otherwise, a negative number with the error status is returned.
36716 
36717 @Errors
36718 @List
36719    @Item  CDI_ESYSTEM     Operating system error.
36720    @Item  CDI_EINVAL      Invalid argument.
36721    @Item  CDI_EUFILETYPE  Unsupported file type.
36722    @Item  CDI_ELIBNAVAIL  Library support not compiled in.
36723 @EndList
36724 
36725 @Example
36726 Here is an example using @func{streamOpenWrite} to create a new NetCDF file named @func{foo.nc} for writing:
36727 
36728 @Source
36729    ...
36730 int streamID;
36731    ...
36732 streamID = streamOpenWrite("foo.nc", CDI_FILETYPE_NC);
36733 if ( streamID < 0 ) handle_error(streamID);
36734    ...
36735 @EndSource
36736 @EndFunction
36737 */
streamOpenWrite(const char * filename,int filetype)36738 int streamOpenWrite(const char *filename, int filetype)
36739 {
36740   cdiInitialize();
36741 
36742   return streamOpen(filename, "w", filetype);
36743 }
36744 
36745 static
streamDefaultValue(stream_t * streamptr)36746 void streamDefaultValue ( stream_t * streamptr )
36747 {
36748   streamptr->self              = CDI_UNDEFID;
36749   streamptr->accesstype        = CDI_UNDEFID;
36750   streamptr->accessmode        = 0;
36751   streamptr->filetype          = CDI_FILETYPE_UNDEF;
36752   streamptr->byteorder         = CDI_UNDEFID;
36753   streamptr->fileID            = 0;
36754   streamptr->filemode          = 0;
36755   streamptr->numvals           = 0;
36756   streamptr->filename          = NULL;
36757   streamptr->record            = NULL;
36758   streamptr->varsAllocated     = 0;
36759   streamptr->nrecs             = 0;
36760   streamptr->nvars             = 0;
36761   streamptr->vars              = NULL;
36762   streamptr->ncmode            = 0;
36763   streamptr->curTsID           = CDI_UNDEFID;
36764   streamptr->rtsteps           = 0;
36765   streamptr->ntsteps           = CDI_UNDEFID;
36766   streamptr->tsteps            = NULL;
36767   streamptr->tstepsTableSize   = 0;
36768   streamptr->tstepsNextID      = 0;
36769   streamptr->vlistID           = CDI_UNDEFID;
36770   streamptr->globalatts        = 0;
36771   streamptr->localatts         = 0;
36772   streamptr->unreduced         = cdiDataUnreduced;
36773   streamptr->sortname          = cdiSortName > 0;
36774   streamptr->sortparam         = cdiSortParam > 0;
36775   streamptr->have_missval      = cdiHaveMissval;
36776   streamptr->comptype          = CDI_COMPRESS_NONE;
36777   streamptr->complevel         = 0;
36778 
36779   basetimeInit(&streamptr->basetime);
36780 
36781 #ifdef HAVE_LIBNETCDF
36782   streamptr->nc_complex_float_id  = CDI_UNDEFID;
36783   streamptr->nc_complex_double_id = CDI_UNDEFID;
36784 
36785   for ( int i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->zaxisID[i]  = CDI_UNDEFID;
36786   for ( int i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->nczvarID[i] = CDI_UNDEFID;
36787 
36788   for ( int i = 0; i < MAX_GRIDS_PS; i++ )
36789     {
36790       streamptr->ncgrid[i].gridID = CDI_UNDEFID;
36791       for (size_t j = 0; j < CDF_SIZE_ncIDs; ++j)
36792         streamptr->ncgrid[i].ncIDs[j] = CDI_UNDEFID;
36793     }
36794 
36795   streamptr->vct.ilev          = 0;
36796   streamptr->vct.mlev          = 0;
36797   streamptr->vct.ilevID        = CDI_UNDEFID;
36798   streamptr->vct.mlevID        = CDI_UNDEFID;
36799 #endif
36800 
36801   streamptr->gribContainers    = NULL;
36802 
36803   streamptr->numWorker         = 0;
36804   streamptr->nextRecID         = 0;
36805   streamptr->cachedTsID        = -1;
36806   streamptr->jobs              = NULL;
36807   streamptr->jobManager        = NULL;
36808 }
36809 
36810 static
stream_new_entry(int resH)36811 stream_t *stream_new_entry(int resH)
36812 {
36813   cdiInitialize(); /* ***************** make MT version !!! */
36814 
36815   stream_t *streamptr = (stream_t *) Malloc(sizeof(stream_t));
36816   streamDefaultValue ( streamptr );
36817 
36818   if (resH == CDI_UNDEFID)
36819     streamptr->self = reshPut(streamptr, &streamOps);
36820   else
36821     {
36822       streamptr->self = resH;
36823       reshReplace(resH, streamptr, &streamOps);
36824     }
36825 
36826   return streamptr;
36827 }
36828 
36829 
cdiStreamCloseDefaultDelegate(stream_t * streamptr,int recordBufIsToBeDeleted)36830 void cdiStreamCloseDefaultDelegate(stream_t *streamptr, int recordBufIsToBeDeleted)
36831 {
36832   int fileID   = streamptr->fileID;
36833   int filetype = streamptr->filetype;
36834   if ( fileID == CDI_UNDEFID )
36835     Warning("File %s not open!", streamptr->filename);
36836   else
36837     switch (cdiBaseFiletype(filetype))
36838       {
36839 #if defined(HAVE_LIBGRIB) && (defined(HAVE_LIBCGRIBEX) || defined(HAVE_LIBGRIB_API))
36840       case CDI_FILETYPE_GRB:
36841         {
36842           gribClose(fileID);
36843           if (recordBufIsToBeDeleted) gribContainersDelete(streamptr);
36844 #ifdef  HAVE_LIBCGRIBEX
36845           if (recordBufIsToBeDeleted) cgribexDelete(streamptr->record->cgribexp);
36846 #endif
36847           break;
36848         }
36849       case CDI_FILETYPE_GRB2:
36850         {
36851           gribClose(fileID);
36852           if (recordBufIsToBeDeleted) gribContainersDelete(streamptr);
36853           break;
36854         }
36855 #endif
36856 #ifdef  HAVE_LIBSERVICE
36857       case CDI_FILETYPE_SRV:
36858         {
36859           fileClose(fileID);
36860           if (recordBufIsToBeDeleted) srvDelete(streamptr->record->exsep);
36861           break;
36862         }
36863 #endif
36864 #ifdef  HAVE_LIBEXTRA
36865       case CDI_FILETYPE_EXT:
36866         {
36867           fileClose(fileID);
36868           if (recordBufIsToBeDeleted) extDelete(streamptr->record->exsep);
36869           break;
36870         }
36871 #endif
36872 #ifdef  HAVE_LIBIEG
36873       case CDI_FILETYPE_IEG:
36874         {
36875           fileClose(fileID);
36876           if (recordBufIsToBeDeleted) iegDelete(streamptr->record->exsep);
36877           break;
36878         }
36879 #endif
36880 #ifdef  HAVE_LIBNETCDF
36881       case CDI_FILETYPE_NETCDF:
36882         {
36883           cdfClose(fileID);
36884           if (streamptr->ntsteps == 0)
36885             {
36886               if ( streamptr->tsteps[0].records )
36887                 {
36888                   Free(streamptr->tsteps[0].records);
36889                   streamptr->tsteps[0].records = NULL;
36890                 }
36891               if ( streamptr->tsteps[0].recIDs )
36892                 {
36893                   Free(streamptr->tsteps[0].recIDs);
36894                   streamptr->tsteps[0].recIDs = NULL;
36895                 }
36896             }
36897           break;
36898         }
36899 #endif
36900       default:
36901         {
36902           Error("%s support not compiled in (fileID = %d)!", strfiletype(filetype), fileID);
36903           break;
36904         }
36905       }
36906 }
36907 
36908 
36909 static
deallocate_sleveltable_t(sleveltable_t * entry)36910 void deallocate_sleveltable_t(sleveltable_t *entry)
36911 {
36912   if (entry->recordID) Free(entry->recordID);
36913   if (entry->lindex)   Free(entry->lindex);
36914   entry->recordID = NULL;
36915   entry->lindex   = NULL;
36916 }
36917 
36918 
36919 /*
36920 @Function  streamClose
36921 @Title     Close an open dataset
36922 
36923 @Prototype  void streamClose(int streamID)
36924 @Parameter
36925     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
36926 
36927 @Description
36928 The function @func{streamClose} closes an open dataset.
36929 
36930 @EndFunction
36931 */
streamClose(int streamID)36932 void streamClose(int streamID)
36933 {
36934   stream_t *streamptr = stream_to_pointer(streamID);
36935 
36936   if ( CDI_Debug )
36937     Message("streamID = %d filename = %s", streamID, streamptr->filename);
36938 
36939   const int vlistID  = streamptr->vlistID;
36940 
36941   void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
36942     = (void (*)(stream_t *, int))
36943     namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
36944 
36945   if ( streamptr->filetype != -1 ) streamCloseDelegate(streamptr, 1);
36946 
36947   if ( streamptr->record )
36948     {
36949       if ( streamptr->record->buffer )
36950         Free(streamptr->record->buffer);
36951 
36952       Free(streamptr->record);
36953     }
36954 
36955   streamptr->filetype = 0;
36956   if ( streamptr->filename ) Free(streamptr->filename);
36957 
36958   for ( int index = 0; index < streamptr->nvars; index++ )
36959     {
36960       sleveltable_t *pslev = streamptr->vars[index].recordTable;
36961       const unsigned nsub = streamptr->vars[index].subtypeSize >= 0
36962         ? (unsigned)streamptr->vars[index].subtypeSize : 0U;
36963       for (size_t isub=0; isub < nsub; isub++)
36964         {
36965           deallocate_sleveltable_t(pslev + isub);
36966         }
36967       if (pslev) Free(pslev);
36968     }
36969   Free(streamptr->vars);
36970   streamptr->vars = NULL;
36971 
36972   for ( int index = 0; index < streamptr->ntsteps; ++index )
36973     {
36974       if ( streamptr->tsteps[index].records ) Free(streamptr->tsteps[index].records);
36975       if ( streamptr->tsteps[index].recIDs  ) Free(streamptr->tsteps[index].recIDs);
36976       taxisDestroyKernel(&streamptr->tsteps[index].taxis);
36977     }
36978 
36979   if ( streamptr->tsteps ) Free(streamptr->tsteps);
36980 
36981   if ( streamptr->basetime.timevar_cache ) Free(streamptr->basetime.timevar_cache);
36982 
36983   if ( vlistID != -1 )
36984     {
36985       if ( streamptr->filemode != 'w' && vlistInqTaxis(vlistID) != -1 )
36986         taxisDestroy(vlistInqTaxis(vlistID));
36987 
36988       cdiVlistDestroy_(vlistID);
36989     }
36990 
36991   if (streamptr->jobs) free(streamptr->jobs);
36992   if (streamptr->jobManager) AsyncWorker_finalize(streamptr->jobManager);
36993 
36994   stream_delete_entry(streamptr);
36995 }
36996 
36997 static
stream_delete_entry(stream_t * streamptr)36998 void stream_delete_entry(stream_t *streamptr)
36999 {
37000   xassert ( streamptr );
37001 
37002   int idx = streamptr->self;
37003   Free(streamptr);
37004   reshRemove ( idx, &streamOps );
37005 
37006   if ( CDI_Debug )
37007     Message("Removed idx %d from stream list", idx);
37008 }
37009 
37010 
cdiStreamSync_(stream_t * streamptr)37011 void cdiStreamSync_(stream_t *streamptr)
37012 {
37013   int fileID   = streamptr->fileID;
37014   int filetype = streamptr->filetype;
37015   int vlistID  = streamptr->vlistID;
37016   int nvars    = vlistNvars(vlistID);
37017 
37018   if      ( fileID == CDI_UNDEFID )  Warning("File %s not open!", streamptr->filename);
37019   else if ( vlistID == CDI_UNDEFID ) Warning("Vlist undefined for file %s!", streamptr->filename);
37020   else if ( nvars == 0 )             Warning("No variables defined!");
37021   else
37022     {
37023       if ( streamptr->filemode == 'w' || streamptr->filemode == 'a' )
37024 	{
37025 	  switch (cdiBaseFiletype(filetype))
37026 	    {
37027 #ifdef  HAVE_LIBNETCDF
37028 	    case CDI_FILETYPE_NETCDF:
37029 	      {
37030 		void cdf_sync(int ncid);
37031 		if ( streamptr->ncmode == 2 ) cdf_sync(fileID);
37032 		break;
37033 	      }
37034 #endif
37035 	    default:
37036 	      {
37037 		fileFlush(fileID);
37038 		break;
37039 	      }
37040 	    }
37041 	}
37042     }
37043 }
37044 
37045 /*
37046 @Function  streamSync
37047 @Title     Synchronize an Open Dataset to Disk
37048 
37049 @Prototype  void streamSync(int streamID)
37050 @Parameter
37051     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
37052 
37053 @Description
37054 The function @func{streamSync} offers a way to synchronize the disk copy of a dataset with in-memory buffers.
37055 
37056 @EndFunction
37057 */
streamSync(int streamID)37058 void streamSync(int streamID)
37059 {
37060   stream_t *streamptr = stream_to_pointer(streamID);
37061 
37062   void (*myStreamSync_)(stream_t *streamptr)
37063     = (void (*)(stream_t *))namespaceSwitchGet(NSSWITCH_STREAM_SYNC).func;
37064   myStreamSync_(streamptr);
37065 }
37066 
37067 
cdiStreamDefTimestep_(stream_t * streamptr,int tsID)37068 int cdiStreamDefTimestep_(stream_t *streamptr, int tsID)
37069 {
37070   stream_check_ptr(__func__, streamptr);
37071 
37072   if ( CDI_Debug ) Message("streamID = %d  tsID = %d", streamptr->self, tsID);
37073 
37074   int vlistID = streamptr->vlistID;
37075   int time_is_varying = vlistHasTime(vlistID);
37076   int taxisID = vlistInqTaxis(vlistID) ;
37077 
37078   /* moved to cdiStreamSetupVlist
37079   int taxisID = time_is_varying ? vlistInqTaxis(vlistID) : CDI_UNDEFID;
37080   if ( time_is_varying )
37081     {
37082       if ( taxisID == CDI_UNDEFID )
37083         {
37084           Warning("taxisID undefined for fileID = %d! Using absolute time axis.", streamptr->self);
37085           taxisID = taxisCreate(TAXIS_ABSOLUTE);
37086           vlistDefTaxis(vlistID, taxisID);
37087         }
37088     }
37089   */
37090   if ( tsID > 0 )
37091     {
37092       int newtsID = tstepsNewEntry(streamptr);
37093       if ( tsID != newtsID )
37094         Error("Internal problem: tsID = %d newtsID = %d", tsID, newtsID);
37095     }
37096 
37097   if ( time_is_varying )
37098     ptaxisCopy(&streamptr->tsteps[tsID].taxis, taxisPtr(taxisID));
37099 
37100   streamptr->curTsID = tsID;
37101   streamptr->ntsteps = tsID + 1;
37102 
37103 #ifdef HAVE_LIBNETCDF
37104   if (cdiBaseFiletype(streamptr->filetype) == CDI_FILETYPE_NETCDF  && time_is_varying)
37105     {
37106       void (*myCdfDefTimestep)(stream_t *streamptr, int tsID)
37107         = (void (*)(stream_t *, int))
37108         namespaceSwitchGet(NSSWITCH_CDF_DEF_TIMESTEP).func;
37109       myCdfDefTimestep(streamptr, tsID);
37110     }
37111 #endif
37112 
37113   cdi_create_records(streamptr, tsID);
37114 
37115   return (int)streamptr->ntsteps;
37116 }
37117 
37118 /*
37119 @Function  streamDefTimestep
37120 @Title     Define a timestep
37121 
37122 @Prototype int streamDefTimestep(int streamID, int tsID)
37123 @Parameter
37124     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
37125     @Item  tsID      Timestep identifier.
37126 
37127 @Description
37128 The function @func{streamDefTimestep} defines a timestep of a stream by the identifier tsID.
37129 The identifier tsID is the timestep index starting at 0 for the first timestep.
37130 Before calling this function the functions @func{taxisDefVdate} and @func{taxisDefVtime} should be used
37131 to define the timestamp for this timestep. All calls to write the data refer to this timestep.
37132 
37133 @Result
37134 @func{streamDefTimestep} returns the number of expected records of the timestep.
37135 
37136 @EndFunction
37137 */
streamDefTimestep(int streamID,int tsID)37138 int streamDefTimestep(int streamID, int tsID)
37139 {
37140   stream_t *streamptr = stream_to_pointer(streamID);
37141   int (*myStreamDefTimestep_)(stream_t *streamptr, int tsID)
37142     = (int (*)(stream_t *, int))
37143     namespaceSwitchGet(NSSWITCH_STREAM_DEF_TIMESTEP_).func;
37144   return myStreamDefTimestep_(streamptr, tsID);
37145 }
37146 
37147 
streamInqCurTimestepID(int streamID)37148 int streamInqCurTimestepID(int streamID)
37149 {
37150   stream_t *streamptr = stream_to_pointer(streamID);
37151   return streamptr->curTsID;
37152 }
37153 
37154 /*
37155 @Function  streamInqTimestep
37156 @Title     Get timestep information
37157 
37158 @Prototype int streamInqTimestep(int streamID, int tsID)
37159 @Parameter
37160     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
37161     @Item  tsID      Timestep identifier.
37162 
37163 @Description
37164 The function @func{streamInqTimestep} sets the next timestep to the identifier tsID.
37165 The identifier tsID is the timestep index starting at 0 for the first timestep.
37166 After a call to this function the functions @func{taxisInqVdate} and @func{taxisInqVtime} can be used
37167 to read the timestamp for this timestep. All calls to read the data refer to this timestep.
37168 
37169 @Result
37170 @func{streamInqTimestep} returns the number of records of the timestep or 0, if the end of the file is reached.
37171 
37172 @EndFunction
37173 */
streamInqTimestep(int streamID,int tsID)37174 int streamInqTimestep(int streamID, int tsID)
37175 {
37176   int nrecs = 0;
37177   int taxisID;
37178   stream_t *streamptr = stream_to_pointer(streamID);
37179   int vlistID = streamptr->vlistID;
37180 
37181   if (tsID < streamptr->ntsteps) streamptr->tsteps[tsID].curRecID = CDI_UNDEFID; // fix for netCDF
37182   if (tsID < streamptr->rtsteps)
37183     {
37184       streamptr->curTsID = tsID;
37185       nrecs = streamptr->tsteps[tsID].nrecs;
37186       streamptr->tsteps[tsID].curRecID = CDI_UNDEFID;
37187       taxisID = vlistInqTaxis(vlistID);
37188       if ( taxisID == -1 )
37189 	Error("Timestep undefined for fileID = %d", streamID);
37190       ptaxisCopy(taxisPtr(taxisID), &streamptr->tsteps[tsID].taxis);
37191 
37192       return nrecs;
37193     }
37194 
37195   if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID ) return 0;
37196 
37197   int filetype = streamptr->filetype;
37198 
37199   if ( CDI_Debug )
37200     Message("streamID = %d  tsID = %d  filetype = %d", streamID, tsID, filetype);
37201 
37202   switch (cdiBaseFiletype(filetype))
37203     {
37204 #ifdef  HAVE_LIBGRIB
37205     case CDI_FILETYPE_GRB:
37206     case CDI_FILETYPE_GRB2:
37207       {
37208         nrecs = grbInqTimestep(streamptr, tsID);
37209 	break;
37210       }
37211 #endif
37212 #ifdef  HAVE_LIBSERVICE
37213     case CDI_FILETYPE_SRV:
37214       {
37215         nrecs = srvInqTimestep(streamptr, tsID);
37216 	break;
37217       }
37218 #endif
37219 #ifdef  HAVE_LIBEXTRA
37220     case CDI_FILETYPE_EXT:
37221       {
37222         nrecs = extInqTimestep(streamptr, tsID);
37223 	break;
37224       }
37225 #endif
37226 #ifdef  HAVE_LIBIEG
37227     case CDI_FILETYPE_IEG:
37228       {
37229         nrecs = iegInqTimestep(streamptr, tsID);
37230 	break;
37231       }
37232 #endif
37233 #ifdef  HAVE_LIBNETCDF
37234     case CDI_FILETYPE_NETCDF:
37235       {
37236         nrecs = cdfInqTimestep(streamptr, tsID);
37237 	break;
37238       }
37239 #endif
37240     default:
37241       {
37242 	Error("%s support not compiled in!", strfiletype(filetype));
37243 	break;
37244       }
37245     }
37246 
37247   taxisID = vlistInqTaxis(vlistID);
37248   if ( taxisID == -1 )
37249     Error("Timestep undefined for fileID = %d", streamID);
37250 
37251   ptaxisCopy(taxisPtr(taxisID), &streamptr->tsteps[tsID].taxis);
37252 
37253   return nrecs;
37254 }
37255 
37256 #if 0
37257 void streamWriteContents(int streamID, char *cname)
37258 {
37259   stream_t *streamptr = stream_to_pointer(streamID);
37260 
37261   int vlistID = streamptr->vlistID;
37262 
37263   FILE *cnp = fopen(cname, "w");
37264 
37265   if ( cnp == NULL ) SysError(cname);
37266 
37267   fprintf(cnp, "#CDI library version %s\n"
37268           "#\n", cdiLibraryVersion());
37269 
37270   int filetype = streamptr->filetype;
37271   fprintf(cnp, "filename: %s\n"
37272           "filetype: %s\n", streamptr->filename, strfiletype(filetype));
37273 
37274   fputs("#\n#grids:\n", cnp);
37275 
37276   int ngrids = vlistNgrids(vlistID);
37277   for ( int i = 0; i < ngrids; i++ )
37278     {
37279       int gridID   = vlistGrid(vlistID, i);
37280       int gridtype = gridInqType(gridID);
37281       size_t xsize    = gridInqXsize(gridID);
37282       size_t ysize    = gridInqYsize(gridID);
37283       fprintf(cnp, "%4d:%4d:%4zu:%4zu\n", i+1, gridtype, xsize, ysize);
37284     }
37285 
37286   fputs("#\nvarID:code:gridID:zaxisID:tsteptype:datatype\n", cnp);
37287 
37288   int nvars = vlistNvars(vlistID);
37289   for ( int varID = 0; varID < nvars; varID++ )
37290     {
37291       int code      = vlistInqVarCode(vlistID, varID);
37292       int gridID    = vlistInqVarGrid(vlistID, varID);
37293       int zaxisID   = vlistInqVarZaxis(vlistID, varID);
37294       int tsteptype = vlistInqVarTsteptype(vlistID, varID);
37295       int datatype  = vlistInqVarDatatype(vlistID, varID);
37296       fprintf(cnp, "%4d:%4d:%4d:%4d:%4d:%4d:\n",
37297 	      varID+1, code, gridID, zaxisID, tsteptype, datatype);
37298     }
37299 
37300   fputs("#\ntsID:nrecs:date:time\n", cnp);
37301 
37302   int tsID = 0;
37303   while (1)
37304     {
37305       int nrecs      = streamptr->tsteps[tsID].nallrecs;
37306       int date       = streamptr->tsteps[tsID].taxis.vdate;
37307       int time       = streamptr->tsteps[tsID].taxis.vtime;
37308       off_t position = streamptr->tsteps[tsID].position;
37309 
37310       fprintf(cnp, "%4d:%4d:%4d:%4d:%ld\n",
37311 	      tsID, nrecs, date, time, (long) position);
37312 
37313       if ( streamptr->tsteps[tsID].next )
37314 	tsID++;
37315       else
37316 	break;
37317     }
37318 
37319   fputs("#\ntsID:recID:varID:levID:size:pos\n", cnp);
37320 
37321   tsID = 0;
37322   while (1)
37323     {
37324       int nrecs = streamptr->tsteps[tsID].nallrecs;
37325       for ( int recID = 0; recID < nrecs; recID++ )
37326 	{
37327 	  int varID   = streamptr->tsteps[tsID].records[recID].varID;
37328 	  int levelID = streamptr->tsteps[tsID].records[recID].levelID;
37329 	  off_t recpos = streamptr->tsteps[tsID].records[recID].position;
37330 	  long recsize = (long)streamptr->tsteps[tsID].records[recID].size;
37331 	  fprintf(cnp, "%4d:%4d:%4d:%4d:%4ld:%ld\n",
37332 		  tsID, recID, varID, levelID, recsize, (long) recpos);
37333 	}
37334 
37335       if ( streamptr->tsteps[tsID].next )
37336 	tsID++;
37337       else
37338 	break;
37339     }
37340 
37341   fclose(cnp);
37342 }
37343 #endif
37344 
37345 // This function is used in CDO!
streamNvals(int streamID)37346 size_t streamNvals(int streamID)
37347 {
37348   stream_t *streamptr = stream_to_pointer(streamID);
37349   return streamptr->numvals;
37350 }
37351 
37352 /*
37353 @Function  streamDefVlist
37354 @Title     Define the variable list
37355 
37356 @Prototype void streamDefVlist(int streamID, int vlistID)
37357 @Parameter
37358     @Item  streamID Stream ID, from a previous call to @fref{streamOpenWrite}.
37359     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
37360 
37361 @Description
37362 The function @func{streamDefVlist} defines the variable list of a stream.
37363 
37364 To safeguard against errors by modifying the wrong vlist object,
37365 this function makes the passed vlist object immutable.
37366 All further vlist changes have to use the vlist object returned by streamInqVlist().
37367 
37368 @EndFunction
37369 */
streamDefVlist(int streamID,int vlistID)37370 void streamDefVlist(int streamID, int vlistID)
37371 {
37372   void (*myStreamDefVlist)(int streamID, int vlistID)
37373     = (void (*)(int, int))namespaceSwitchGet(NSSWITCH_STREAM_DEF_VLIST_).func;
37374   myStreamDefVlist(streamID, vlistID);
37375 }
37376 
37377 /* the single image implementation of streamDefVlist */
cdiStreamDefVlist_(int streamID,int vlistID)37378 void cdiStreamDefVlist_(int streamID, int vlistID)
37379 {
37380   stream_t *streamptr = stream_to_pointer(streamID);
37381 
37382   if ( streamptr->vlistID == CDI_UNDEFID )
37383     {
37384       int vlistCopy = vlistDuplicate(vlistID);
37385       cdiVlistMakeInternal(vlistCopy);
37386       cdiVlistMakeImmutable(vlistID);
37387       cdiStreamSetupVlist(streamptr, vlistCopy);
37388     }
37389   else
37390     Warning("vlist already defined for %s!", streamptr->filename);
37391 }
37392 
37393 /*
37394 @Function  streamInqVlist
37395 @Title     Get the variable list
37396 
37397 @Prototype int streamInqVlist(int streamID)
37398 @Parameter
37399     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
37400 
37401 @Description
37402 The function @func{streamInqVlist} returns the variable list of a stream.
37403 
37404 @Result
37405 @func{streamInqVlist} returns an identifier to the variable list.
37406 
37407 @EndFunction
37408 */
streamInqVlist(int streamID)37409 int streamInqVlist(int streamID)
37410 {
37411   stream_t *streamptr = stream_to_pointer(streamID);
37412   return streamptr->vlistID;
37413 }
37414 
37415 
streamDefCompType(int streamID,int comptype)37416 void streamDefCompType(int streamID, int comptype)
37417 {
37418   stream_t *streamptr = stream_to_pointer(streamID);
37419   if ( streamptr->comptype != comptype )
37420     {
37421       streamptr->comptype = comptype;
37422       reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
37423     }
37424 }
37425 
37426 
streamDefCompLevel(int streamID,int complevel)37427 void streamDefCompLevel(int streamID, int complevel)
37428 {
37429   stream_t *streamptr = stream_to_pointer(streamID);
37430   if ( streamptr->complevel != complevel )
37431     {
37432       streamptr->complevel = complevel;
37433       reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
37434     }
37435 }
37436 
37437 
streamInqCompType(int streamID)37438 int streamInqCompType(int streamID)
37439 {
37440   stream_t *streamptr = stream_to_pointer(streamID);
37441   return streamptr->comptype;
37442 }
37443 
37444 
streamInqCompLevel(int streamID)37445 int streamInqCompLevel(int streamID)
37446 {
37447   stream_t *streamptr = stream_to_pointer(streamID);
37448   return streamptr->complevel;
37449 }
37450 
streamInqFileID(int streamID)37451 int streamInqFileID(int streamID)
37452 {
37453   stream_t *streamptr = ( stream_t *) reshGetVal ( streamID, &streamOps );
37454   return streamptr->fileID;
37455 }
37456 
37457 
cdiDefAccesstype(int streamID,int type)37458 void cdiDefAccesstype(int streamID, int type)
37459 {
37460   stream_t *streamptr = (stream_t *)reshGetVal(streamID, &streamOps);
37461 
37462   if ( streamptr->accesstype == CDI_UNDEFID )
37463     {
37464       streamptr->accesstype = type;
37465     }
37466   else if ( streamptr->accesstype != type )
37467     Error("Changing access type from %s not allowed!",
37468           streamptr->accesstype == TYPE_REC ? "REC to VAR" : "VAR to REC");
37469 }
37470 
37471 
cdiInqAccesstype(int streamID)37472 int cdiInqAccesstype(int streamID)
37473 {
37474   stream_t *streamptr = (stream_t *) reshGetVal ( streamID, &streamOps );
37475   return streamptr->accesstype;
37476 }
37477 
37478 static
streamTxCode(void)37479 int streamTxCode(void)
37480 {
37481   return STREAM;
37482 }
37483 
cdiStreamSetupVlist(stream_t * streamptr,int vlistID)37484 void cdiStreamSetupVlist(stream_t *streamptr, int vlistID)
37485 {
37486   void (*myStreamSetupVlist)(stream_t *streamptr, int vlistID)
37487     = (void (*)(stream_t *, int)) namespaceSwitchGet(NSSWITCH_STREAM_SETUP_VLIST).func;
37488   myStreamSetupVlist(streamptr, vlistID);
37489 }
37490 
37491 
cdiStreamSetupVlist_(stream_t * streamptr,int vlistID)37492 void cdiStreamSetupVlist_(stream_t *streamptr, int vlistID)
37493 {
37494   streamptr->vlistID = vlistID;
37495   int nvars = vlistNvars(vlistID);
37496   for ( int varID = 0; varID < nvars; varID++ )
37497     {
37498       int gridID    = vlistInqVarGrid(vlistID, varID);
37499       int zaxisID   = vlistInqVarZaxis(vlistID, varID);
37500       int tilesetID = vlistInqVarSubtype(vlistID, varID);
37501       stream_new_var(streamptr, gridID, zaxisID, tilesetID);
37502       if ( streamptr->have_missval )
37503         vlistDefVarMissval(vlistID, varID, vlistInqVarMissval(vlistID, varID));
37504     }
37505 
37506   if (streamptr->filemode == 'w')
37507     {
37508       tstepsNewEntry(streamptr); // timestep 0
37509       int vlistIDw = streamptr->vlistID;
37510       int time_is_varying = vlistHasTime(vlistIDw);
37511       if ( time_is_varying )
37512         {
37513           int taxisID = vlistInqTaxis(vlistIDw);
37514           if ( taxisID == CDI_UNDEFID )
37515             {
37516               Warning("taxisID undefined for fileID = %d! Using absolute time axis.", streamptr->self);
37517               taxisID = taxisCreate(TAXIS_ABSOLUTE);
37518               vlistDefTaxis(vlistIDw, taxisID);
37519             }
37520 
37521 #ifdef HAVE_LIBNETCDF
37522           if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
37523             if (cdiBaseFiletype(streamptr->filetype) == CDI_FILETYPE_NETCDF)
37524               {
37525                 taxis_t *taxisptr = taxisPtr(taxisID);
37526                 if ( taxisptr->rdate == -1 )
37527                   {
37528                     int vdate = taxisInqVdate(taxisID);
37529                     if ( vdate == 0 ) vdate = 10101;
37530                     taxisDefRdate(taxisID, vdate);
37531                   }
37532               }
37533 #endif
37534           ptaxisCopy(&streamptr->tsteps[0].taxis, taxisPtr(taxisID));
37535         }
37536 
37537       switch (cdiBaseFiletype(streamptr->filetype))
37538         {
37539 #ifdef HAVE_LIBNETCDF
37540         case CDI_FILETYPE_NETCDF:
37541           {
37542             /* calls cdfDefCoordinateVars in serial mode but
37543              * cdiPioClientStreamNOP (i.e. nothing) on client ranks
37544              * and cdiPioServerCdfDefVars on server ranks in parallel mode*/
37545             void (*myCdfDefVars)(stream_t *streamptr)
37546               = (void (*)(stream_t *)) namespaceSwitchGet(NSSWITCH_CDF_STREAM_SETUP).func;
37547             myCdfDefVars(streamptr);
37548           }
37549           break;
37550 #endif
37551 #ifdef HAVE_LIBGRIB
37552         case CDI_FILETYPE_GRB:
37553         case CDI_FILETYPE_GRB2:
37554           gribContainersNew(streamptr);
37555           break;
37556 #endif
37557         default:
37558           ;
37559         }
37560     }
37561 }
37562 
37563 
cdiStreamGetIndexList(unsigned numIDs,int * IDs)37564 void cdiStreamGetIndexList(unsigned numIDs, int *IDs)
37565 {
37566   reshGetResHListOfType(numIDs, IDs, &streamOps);
37567 }
37568 
streamInqNvars(int streamID)37569 int streamInqNvars ( int streamID )
37570 {
37571   stream_t *streamptr = (stream_t *)reshGetVal(streamID, &streamOps);
37572   return streamptr->nvars;
37573 }
37574 
37575 
streamCompareP(void * streamptr1,void * streamptr2)37576 static int streamCompareP(void * streamptr1, void * streamptr2)
37577 {
37578   stream_t * s1 = ( stream_t * ) streamptr1;
37579   stream_t * s2 = ( stream_t * ) streamptr2;
37580   enum {
37581     differ = -1,
37582     equal  = 0,
37583   };
37584 
37585   xassert ( s1 );
37586   xassert ( s2 );
37587 
37588   if ( s1->filetype  != s2->filetype  ) return differ;
37589   if ( s1->byteorder != s2->byteorder ) return differ;
37590   if ( s1->comptype  != s2->comptype  ) return differ;
37591   if ( s1->complevel != s2->complevel ) return differ;
37592 
37593   if ( s1->filename )
37594     {
37595       if (strcmp(s1->filename, s2->filename))
37596 	return differ;
37597     }
37598   else if ( s2->filename )
37599     return differ;
37600 
37601   return equal;
37602 }
37603 
37604 
streamDestroyP(void * streamptr)37605 void streamDestroyP ( void * streamptr )
37606 {
37607   stream_t *sp = ( stream_t * ) streamptr;
37608 
37609   xassert ( sp );
37610 
37611   int id = sp->self;
37612   streamClose ( id );
37613 }
37614 
37615 
streamPrintP(void * streamptr,FILE * fp)37616 void streamPrintP(void *streamptr, FILE *fp)
37617 {
37618   stream_t *sp = (stream_t *) streamptr;
37619 
37620   if ( !sp ) return;
37621 
37622   fprintf(fp, "#\n"
37623           "# streamID %d\n"
37624           "#\n"
37625           "self          = %d\n"
37626           "accesstype    = %d\n"
37627           "accessmode    = %d\n"
37628           "filetype      = %d\n"
37629           "byteorder     = %d\n"
37630           "fileID        = %d\n"
37631           "filemode      = %d\n"
37632           "filename      = %s\n"
37633           "nrecs         = %d\n"
37634           "nvars         = %d\n"
37635           "varsAllocated = %d\n"
37636           "curTsID       = %d\n"
37637           "rtsteps       = %d\n"
37638           "ntsteps       = %ld\n"
37639           "tstepsTableSize= %d\n"
37640           "tstepsNextID  = %d\n"
37641           "ncmode        = %d\n"
37642           "vlistID       = %d\n"
37643           "globalatts    = %d\n"
37644           "localatts     = %d\n"
37645           "unreduced     = %d\n"
37646           "sortname      = %d\n"
37647           "have_missval  = %d\n"
37648           "ztype         = %d\n"
37649           "zlevel        = %d\n",
37650           sp->self, sp->self, sp->accesstype, sp->accessmode,
37651           sp->filetype, sp->byteorder, sp->fileID, sp->filemode,
37652           sp->filename, sp->nrecs, sp->nvars, sp->varsAllocated,
37653           sp->curTsID, sp->rtsteps, sp->ntsteps, sp->tstepsTableSize,
37654           sp->tstepsNextID, sp->ncmode, sp->vlistID,
37655           sp->globalatts, sp->localatts, sp->unreduced, sp->sortname,
37656           sp->have_missval, sp->comptype, sp->complevel);
37657 }
37658 
37659 enum {
37660   streamNint = 10,
37661 };
37662 
37663 static int
streamGetPackSize(void * voidP,void * context)37664 streamGetPackSize(void * voidP, void *context)
37665 {
37666   stream_t * streamP = ( stream_t * ) voidP;
37667   int packBufferSize
37668     = serializeGetSize(streamNint, CDI_DATATYPE_INT, context)
37669     + serializeGetSize(2, CDI_DATATYPE_UINT32, context)
37670     + serializeGetSize((int)strlen(streamP->filename) + 1,
37671                        CDI_DATATYPE_TXT, context)
37672     + serializeGetSize(1, CDI_DATATYPE_FLT64, context);
37673   return packBufferSize;
37674 }
37675 
37676 
37677 static void
streamPack(void * streamptr,void * packBuffer,int packBufferSize,int * packBufferPos,void * context)37678 streamPack(void * streamptr, void * packBuffer, int packBufferSize,
37679            int * packBufferPos, void *context)
37680 {
37681   stream_t * streamP = ( stream_t * ) streamptr;
37682   int intBuffer[streamNint];
37683 
37684   intBuffer[0] = streamP->self;
37685   intBuffer[1] = streamP->filetype;
37686   intBuffer[2] = (int)strlen(streamP->filename) + 1;
37687   intBuffer[3] = streamP->vlistID;
37688   intBuffer[4] = streamP->byteorder;
37689   intBuffer[5] = streamP->comptype;
37690   intBuffer[6] = streamP->complevel;
37691   intBuffer[7] = streamP->unreduced;
37692   intBuffer[8] = streamP->sortname;
37693   intBuffer[9] = streamP->have_missval;
37694 
37695   serializePack(intBuffer, streamNint, CDI_DATATYPE_INT, packBuffer, packBufferSize, packBufferPos, context);
37696   uint32_t d = cdiCheckSum(CDI_DATATYPE_INT, streamNint, intBuffer);
37697   serializePack(&d, 1, CDI_DATATYPE_UINT32, packBuffer, packBufferSize, packBufferPos, context);
37698 
37699   serializePack(&CDI_Default_Missval, 1, CDI_DATATYPE_FLT64, packBuffer, packBufferSize, packBufferPos, context);
37700   serializePack(streamP->filename, intBuffer[2], CDI_DATATYPE_TXT, packBuffer, packBufferSize, packBufferPos, context);
37701   d = cdiCheckSum(CDI_DATATYPE_TXT, intBuffer[2], streamP->filename);
37702   serializePack(&d, 1, CDI_DATATYPE_UINT32, packBuffer, packBufferSize, packBufferPos, context);
37703 }
37704 
37705 struct streamAssoc
streamUnpack(char * unpackBuffer,int unpackBufferSize,int * unpackBufferPos,int originNamespace,void * context)37706 streamUnpack(char * unpackBuffer, int unpackBufferSize,
37707              int * unpackBufferPos, int originNamespace, void *context)
37708 {
37709   int intBuffer[streamNint];
37710   uint32_t d;
37711   char filename[CDI_MAX_NAME];
37712 
37713   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
37714                   intBuffer, streamNint, CDI_DATATYPE_INT, context);
37715   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
37716                   &d, 1, CDI_DATATYPE_UINT32, context);
37717   xassert(cdiCheckSum(CDI_DATATYPE_INT, streamNint, intBuffer) == d);
37718 
37719   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
37720                   &CDI_Default_Missval, 1, CDI_DATATYPE_FLT64, context);
37721   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
37722                   &filename, intBuffer[2], CDI_DATATYPE_TXT, context);
37723   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
37724                   &d, 1, CDI_DATATYPE_UINT32, context);
37725   xassert(d == cdiCheckSum(CDI_DATATYPE_TXT, intBuffer[2], filename));
37726   int targetStreamID = namespaceAdaptKey(intBuffer[0], originNamespace),
37727     streamID = streamOpenID(filename, 'w', intBuffer[1], targetStreamID);
37728   xassert(streamID >= 0 && targetStreamID == streamID);
37729   streamDefByteorder(streamID, intBuffer[4]);
37730   streamDefCompType(streamID, intBuffer[5]);
37731   streamDefCompLevel(streamID, intBuffer[6]);
37732   stream_t *streamptr = stream_to_pointer(streamID);
37733   streamptr->unreduced = intBuffer[7];
37734   streamptr->sortname = intBuffer[8];
37735   streamptr->have_missval = intBuffer[9];
37736   struct streamAssoc retval = { streamID, intBuffer[3] };
37737   return retval;
37738 }
37739 
37740 /*
37741  * Local Variables:
37742  * c-file-style: "Java"
37743  * c-basic-offset: 2
37744  * indent-tabs-mode: nil
37745  * show-trailing-whitespace: t
37746  * require-trailing-newline: t
37747  * End:
37748  */
37749 #ifdef HAVE_CONFIG_H
37750 #endif
37751 
37752 
37753 
37754 /* the single image implementation */
cdiStreamWriteVar_(int streamID,int varID,int memtype,const void * data,size_t nmiss)37755 int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, size_t nmiss)
37756 {
37757   // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
37758   // A value > 0 is returned in this case, otherwise it returns zero.
37759   int status = 0;
37760 
37761   if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
37762 
37763   check_parg(data);
37764 
37765   stream_t *streamptr = stream_to_pointer(streamID);
37766   if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
37767     Error("Writing of non-trivial subtypes not yet implemented!");
37768 
37769   // check taxis
37770   if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
37771 
37772   int filetype = streamptr->filetype;
37773 
37774   switch (cdiBaseFiletype(filetype))
37775     {
37776 #ifdef HAVE_LIBGRIB
37777     case CDI_FILETYPE_GRB:
37778     case CDI_FILETYPE_GRB2:
37779       {
37780         grb_write_var(streamptr, varID, memtype, data, nmiss);
37781 	break;
37782       }
37783 #endif
37784 #ifdef HAVE_LIBSERVICE
37785     case CDI_FILETYPE_SRV:
37786       {
37787         if ( memtype == MEMTYPE_FLOAT ) return 1;
37788         srvWriteVarDP(streamptr, varID, (double *)data);
37789 	break;
37790       }
37791 #endif
37792 #ifdef HAVE_LIBEXTRA
37793     case CDI_FILETYPE_EXT:
37794       {
37795         if ( memtype == MEMTYPE_FLOAT ) return 1;
37796         extWriteVarDP(streamptr, varID, (double *)data);
37797 	break;
37798       }
37799 #endif
37800 #ifdef HAVE_LIBIEG
37801     case CDI_FILETYPE_IEG:
37802       {
37803         if ( memtype == MEMTYPE_FLOAT ) return 1;
37804         iegWriteVarDP(streamptr, varID, (double *)data);
37805 	break;
37806       }
37807 #endif
37808 #ifdef HAVE_LIBNETCDF
37809     case CDI_FILETYPE_NETCDF:
37810       {
37811         cdf_write_var(streamptr, varID, memtype, data, nmiss);
37812 	break;
37813       }
37814 #endif
37815     default:
37816       {
37817 	Error("%s support not compiled in!", strfiletype(filetype));
37818 	break;
37819       }
37820     }
37821 
37822   return status;
37823 }
37824 
37825 /*
37826 @Function  streamWriteVar
37827 @Title     Write a variable
37828 
37829 @Prototype void streamWriteVar(int streamID, int varID, const double *data, size_t nmiss)
37830 @Parameter
37831     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
37832     @Item  varID     Variable identifier.
37833     @Item  data      Pointer to a block of double precision floating point data values to be written.
37834     @Item  nmiss     Number of missing values.
37835 
37836 @Description
37837 The function streamWriteVar writes the values of one time step of a variable to an open dataset.
37838 The values are converted to the external data type of the variable, if necessary.
37839 @EndFunction
37840 */
streamWriteVar(int streamID,int varID,const double * data,size_t nmiss)37841 void streamWriteVar(int streamID, int varID, const double *data, size_t nmiss)
37842 {
37843   void (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype, const void *data, size_t nmiss)
37844     = (void (*)(int, int, int, const void *, size_t))
37845     namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
37846 
37847   myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
37848 }
37849 
37850 /*
37851 @Function  streamWriteVarF
37852 @Title     Write a variable
37853 
37854 @Prototype void streamWriteVarF(int streamID, int varID, const float *data, size_t nmiss)
37855 @Parameter
37856     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
37857     @Item  varID     Variable identifier.
37858     @Item  data      Pointer to a block of single precision floating point data values to be written.
37859     @Item  nmiss     Number of missing values.
37860 
37861 @Description
37862 The function streamWriteVarF writes the values of one time step of a variable to an open dataset.
37863 The values are converted to the external data type of the variable, if necessary.
37864 @EndFunction
37865 */
streamWriteVarF(int streamID,int varID,const float * data,size_t nmiss)37866 void streamWriteVarF(int streamID, int varID, const float *data, size_t nmiss)
37867 {
37868   int (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype, const void *data, size_t nmiss)
37869     = (int (*)(int, int, int, const void *, size_t))
37870     namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
37871 
37872   if ( myCdiStreamWriteVar_(streamID, varID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
37873     {
37874       // In case the file format does not support single precision writing,
37875       // we fall back to double precision writing, converting the data
37876       // on the fly.
37877       int vlistID = streamInqVlist(streamID);
37878       size_t elementCount = gridInqSize(vlistInqVarGrid(vlistID, varID));
37879       elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
37880       double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
37881       for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
37882       myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) conversionBuffer, nmiss);
37883       Free(conversionBuffer);
37884     }
37885 }
37886 
37887 static
cdiStreamWriteVarSlice(int streamID,int varID,int levelID,int memtype,const void * data,size_t nmiss)37888 int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, const void *data, size_t nmiss)
37889 {
37890   // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
37891   // A value > 0 is returned in this case, otherwise it returns zero.
37892   int status = 0;
37893 
37894   if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
37895 
37896   check_parg(data);
37897 
37898   stream_t *streamptr = stream_to_pointer(streamID);
37899   if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
37900     Error("Writing of non-trivial subtypes not yet implemented!");
37901 
37902   // check taxis
37903   if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
37904 
37905   int filetype = streamptr->filetype;
37906 
37907   switch (cdiBaseFiletype(filetype))
37908     {
37909 #ifdef HAVE_LIBGRIB
37910     case CDI_FILETYPE_GRB:
37911     case CDI_FILETYPE_GRB2:
37912       {
37913         grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
37914 	break;
37915       }
37916 #endif
37917 #ifdef HAVE_LIBSERVICE
37918     case CDI_FILETYPE_SRV:
37919       {
37920         if ( memtype == MEMTYPE_FLOAT ) return 1;
37921         srvWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
37922 	break;
37923       }
37924 #endif
37925 #ifdef HAVE_LIBEXTRA
37926     case CDI_FILETYPE_EXT:
37927       {
37928         if ( memtype == MEMTYPE_FLOAT ) return 1;
37929         extWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
37930 	break;
37931       }
37932 #endif
37933 #ifdef HAVE_LIBIEG
37934     case CDI_FILETYPE_IEG:
37935       {
37936         if ( memtype == MEMTYPE_FLOAT ) return 1;
37937         iegWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
37938 	break;
37939       }
37940 #endif
37941 #ifdef HAVE_LIBNETCDF
37942     case CDI_FILETYPE_NETCDF:
37943       cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
37944       break;
37945 #endif
37946     default:
37947       {
37948 	Error("%s support not compiled in!", strfiletype(filetype));
37949 	break;
37950       }
37951     }
37952 
37953   return status;
37954 }
37955 
37956 /*
37957 @Function  streamWriteVarSlice
37958 @Title     Write a horizontal slice of a variable
37959 
37960 @Prototype void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, size_t nmiss)
37961 @Parameter
37962     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
37963     @Item  varID     Variable identifier.
37964     @Item  levelID   Level identifier.
37965     @Item  data      Pointer to a block of double precision floating point data values to be written.
37966     @Item  nmiss     Number of missing values.
37967 
37968 @Description
37969 The function streamWriteVarSlice writes the values of a horizontal slice of a variable to an open dataset.
37970 The values are converted to the external data type of the variable, if necessary.
37971 @EndFunction
37972 */
streamWriteVarSlice(int streamID,int varID,int levelID,const double * data,size_t nmiss)37973 void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, size_t nmiss)
37974 {
37975   cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
37976 }
37977 
37978 /*
37979 @Function  streamWriteVarSliceF
37980 @Title     Write a horizontal slice of a variable
37981 
37982 @Prototype void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, size_t nmiss)
37983 @Parameter
37984     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
37985     @Item  varID     Variable identifier.
37986     @Item  levelID   Level identifier.
37987     @Item  data      Pointer to a block of single precision floating point data values to be written.
37988     @Item  nmiss     Number of missing values.
37989 
37990 @Description
37991 The function streamWriteVarSliceF writes the values of a horizontal slice of a variable to an open dataset.
37992 The values are converted to the external data type of the variable, if necessary.
37993 @EndFunction
37994 */
streamWriteVarSliceF(int streamID,int varID,int levelID,const float * data,size_t nmiss)37995 void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, size_t nmiss)
37996 {
37997   if ( cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
37998     {
37999       // In case the file format does not support single precision writing,
38000       // we fall back to double precision writing, converting the data on the fly.
38001       size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
38002       double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
38003       for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
38004       streamWriteVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
38005       Free(conversionBuffer);
38006     }
38007 }
38008 
38009 
streamWriteVarChunk(int streamID,int varID,const int rect[][2],const double * data,size_t nmiss)38010 void streamWriteVarChunk(int streamID, int varID,
38011                          const int rect[][2], const double *data, size_t nmiss)
38012 {
38013   void (*myCdiStreamWriteVarChunk_)(int streamID, int varID, int memtype,
38014                                     const int rect[][2], const void *data, size_t nmiss)
38015     = (void (*)(int, int, int, const int [][2], const void *, size_t))
38016     namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_CHUNK_).func;
38017   myCdiStreamWriteVarChunk_(streamID, varID, MEMTYPE_DOUBLE, rect, data, nmiss);
38018 }
38019 
38020 /* single image implementation */
cdiStreamWriteVarChunk_(int streamID,int varID,int memtype,const int rect[][2],const void * data,size_t nmiss)38021 void cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
38022                              const int rect[][2], const void *data, size_t nmiss)
38023 {
38024   if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
38025 
38026   stream_t *streamptr = stream_to_pointer(streamID);
38027 
38028   // streamDefineTaxis(streamID);
38029 
38030   int filetype = streamptr->filetype;
38031 
38032   switch (cdiBaseFiletype(filetype))
38033     {
38034 #if defined (HAVE_LIBGRIB)
38035     case CDI_FILETYPE_GRB:
38036     case CDI_FILETYPE_GRB2:
38037 #endif
38038 #if defined (HAVE_LIBSERVICE)
38039     case CDI_FILETYPE_SRV:
38040 #endif
38041 #if defined (HAVE_LIBEXTRA)
38042     case CDI_FILETYPE_EXT:
38043 #endif
38044 #if defined (HAVE_LIBIEG)
38045     case CDI_FILETYPE_IEG:
38046 #endif
38047 #if  defined (HAVE_LIBGRIB) || defined (HAVE_LIBSERVICE)      \
38048   || defined (HAVE_LIBEXTRA) || defined (HAVE_LIBIEG)
38049       xabort("streamWriteVarChunk not implemented for filetype %s!", strfiletype(filetype));
38050       break;
38051 #endif
38052 #ifdef HAVE_LIBNETCDF
38053     case CDI_FILETYPE_NETCDF:
38054       cdf_write_var_chunk(streamptr, varID, memtype, rect, data, nmiss);
38055       break;
38056 #endif
38057     default:
38058       Error("%s support not compiled in!", strfiletype(filetype));
38059       break;
38060     }
38061 }
38062 
38063 static
stream_write_record(int streamID,int memtype,const void * data,size_t nmiss)38064 int stream_write_record(int streamID, int memtype, const void *data, size_t nmiss)
38065 {
38066   // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
38067   // A value > 0 is returned in this case, otherwise it returns zero.
38068   int status = 0;
38069 
38070   check_parg(data);
38071 
38072   stream_t *streamptr = stream_to_pointer(streamID);
38073 
38074   switch (cdiBaseFiletype(streamptr->filetype))
38075     {
38076 #ifdef HAVE_LIBGRIB
38077     case CDI_FILETYPE_GRB:
38078     case CDI_FILETYPE_GRB2:
38079       grb_write_record(streamptr, memtype, data, nmiss);
38080       break;
38081 #endif
38082 #ifdef HAVE_LIBSERVICE
38083     case CDI_FILETYPE_SRV:
38084       if ( memtype == MEMTYPE_FLOAT ) return 1;
38085       srvWriteRecord(streamptr, (const double *)data);
38086       break;
38087 #endif
38088 #ifdef HAVE_LIBEXTRA
38089     case CDI_FILETYPE_EXT:
38090       if ( memtype == MEMTYPE_FLOAT ) return 1;
38091       extWriteRecord(streamptr, (const double *)data);
38092       break;
38093 #endif
38094 #ifdef HAVE_LIBIEG
38095     case CDI_FILETYPE_IEG:
38096       if ( memtype == MEMTYPE_FLOAT ) return 1;
38097       iegWriteRecord(streamptr, (const double *)data);
38098       break;
38099 #endif
38100 #ifdef HAVE_LIBNETCDF
38101     case CDI_FILETYPE_NETCDF:
38102       {
38103 	cdf_write_record(streamptr, memtype, data, nmiss);
38104 	break;
38105       }
38106 #endif
38107     default:
38108       {
38109 	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
38110 	break;
38111       }
38112     }
38113 
38114   return status;
38115 }
38116 
38117 /*
38118 @Function  streamWriteRecord
38119 @Title     Write a horizontal slice of a variable
38120 
38121 @Prototype void streamWriteRecord(int streamID, const double *data, size_t nmiss)
38122 @Parameter
38123     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
38124     @Item  data      Pointer to a block of double precision floating point data values to be written.
38125     @Item  nmiss     Number of missing values.
38126 
38127 @Description
38128 The function streamWriteRecord writes the values of a horizontal slice (record) of a variable to an open dataset.
38129 The values are converted to the external data type of the variable, if necessary.
38130 @EndFunction
38131 */
streamWriteRecord(int streamID,const double * data,size_t nmiss)38132 void streamWriteRecord(int streamID, const double *data, size_t nmiss)
38133 {
38134   stream_write_record(streamID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
38135 }
38136 
38137 
streamWriteRecordF(int streamID,const float * data,size_t nmiss)38138 void streamWriteRecordF(int streamID, const float *data, size_t nmiss)
38139 {
38140   if ( stream_write_record(streamID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
38141     {
38142       // In case the file format does not support single precision writing,
38143       // we fall back to double precision writing, converting the data on the fly.
38144       stream_t *streamptr = stream_to_pointer(streamID);
38145       int varID = streamptr->record->varID;
38146       size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
38147       double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
38148       for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
38149       streamWriteRecord(streamID, conversionBuffer, nmiss);
38150       Free(conversionBuffer);
38151     }
38152 }
38153 
38154 #ifdef HAVE_CONFIG_H
38155 #endif
38156 
38157 
38158 
38159 /* the single image implementation */
38160 static
cdiStreamReadVar(int streamID,int varID,int memtype,void * data,size_t * nmiss)38161 int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, size_t *nmiss)
38162 {
38163   // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
38164   // A value > 0 is returned in this case, otherwise it returns zero.
38165   int status = 0;
38166 
38167   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
38168 
38169   check_parg(data);
38170   check_parg(nmiss);
38171 
38172   stream_t *streamptr = stream_to_pointer(streamID);
38173   int filetype = streamptr->filetype;
38174 
38175   *nmiss = 0;
38176 
38177   switch (cdiBaseFiletype(filetype))
38178     {
38179 #ifdef HAVE_LIBGRIB
38180     case CDI_FILETYPE_GRB:
38181     case CDI_FILETYPE_GRB2:
38182       {
38183         grb_read_var(streamptr, varID, memtype, data, nmiss);
38184 	break;
38185       }
38186 #endif
38187 #ifdef HAVE_LIBSERVICE
38188     case CDI_FILETYPE_SRV:
38189       {
38190         if ( memtype == MEMTYPE_FLOAT ) return 1;
38191         srvReadVarDP(streamptr, varID, (double *)data, nmiss);
38192 	break;
38193       }
38194 #endif
38195 #ifdef HAVE_LIBEXTRA
38196     case CDI_FILETYPE_EXT:
38197       {
38198         if ( memtype == MEMTYPE_FLOAT ) return 1;
38199         extReadVarDP(streamptr, varID, (double *)data, nmiss);
38200 	break;
38201       }
38202 #endif
38203 #ifdef HAVE_LIBIEG
38204     case CDI_FILETYPE_IEG:
38205       {
38206         if ( memtype == MEMTYPE_FLOAT ) return 1;
38207         iegReadVarDP(streamptr, varID, (double *)data, nmiss);
38208 	break;
38209       }
38210 #endif
38211 #ifdef HAVE_LIBNETCDF
38212     case CDI_FILETYPE_NETCDF:
38213       {
38214         cdf_read_var(streamptr, varID, memtype, data, nmiss);
38215 	break;
38216       }
38217 #endif
38218     default:
38219       {
38220 	Error("%s support not compiled in!", strfiletype(filetype));
38221 	break;
38222       }
38223     }
38224 
38225   return status;
38226 }
38227 
38228 /*
38229 @Function  streamReadVar
38230 @Title     Read a variable
38231 
38232 @Prototype void streamReadVar(int streamID, int varID, double *data, size_t *nmiss)
38233 @Parameter
38234     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
38235     @Item  varID     Variable identifier.
38236     @Item  data      Pointer to the location into which the data values are read.
38237                      The caller must allocate space for the returned values.
38238     @Item  nmiss     Number of missing values.
38239 
38240 @Description
38241 The function streamReadVar reads all the values of one time step of a variable
38242 from an open dataset.
38243 @EndFunction
38244 */
streamReadVar(int streamID,int varID,double * data,size_t * nmiss)38245 void streamReadVar(int streamID, int varID, double *data, size_t *nmiss)
38246 {
38247   cdiStreamReadVar(streamID, varID, MEMTYPE_DOUBLE, data, nmiss);
38248 }
38249 
38250 /*
38251 @Function  streamReadVarF
38252 @Title     Read a variable
38253 
38254 @Prototype void streamReadVar(int streamID, int varID, float *data, size_t *nmiss)
38255 @Parameter
38256     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
38257     @Item  varID     Variable identifier.
38258     @Item  data      Pointer to the location into which the data values are read.
38259                      The caller must allocate space for the returned values.
38260     @Item  nmiss     Number of missing values.
38261 
38262 @Description
38263 The function streamReadVar reads all the values of one time step of a variable
38264 from an open dataset.
38265 @EndFunction
38266 */
streamReadVarF(int streamID,int varID,float * data,size_t * nmiss)38267 void streamReadVarF(int streamID, int varID, float *data, size_t *nmiss)
38268 {
38269   if ( cdiStreamReadVar(streamID, varID, MEMTYPE_FLOAT, data, nmiss) )
38270     {
38271       // In case the file format does not support single precision reading,
38272       // we fall back to double precision reading, converting the data on the fly.
38273       size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
38274       elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(streamInqVlist(streamID), varID));
38275       double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
38276       streamReadVar(streamID, varID, conversionBuffer, nmiss);
38277       for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
38278       Free(conversionBuffer);
38279     }
38280 }
38281 
38282 
38283 static
cdiStreamReadVarSlice(int streamID,int varID,int levelID,int memtype,void * data,size_t * nmiss)38284 int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, void *data, size_t *nmiss)
38285 {
38286   // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
38287   // A value > 0 is returned in this case, otherwise it returns zero.
38288   int status = 0;
38289 
38290   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
38291 
38292   check_parg(data);
38293   check_parg(nmiss);
38294 
38295   stream_t *streamptr = stream_to_pointer(streamID);
38296   int filetype = streamptr->filetype;
38297 
38298   *nmiss = 0;
38299 
38300   switch (cdiBaseFiletype(filetype))
38301     {
38302 #ifdef HAVE_LIBGRIB
38303     case CDI_FILETYPE_GRB:
38304     case CDI_FILETYPE_GRB2:
38305       {
38306         grb_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
38307 	break;
38308       }
38309 #endif
38310 #ifdef HAVE_LIBSERVICE
38311     case CDI_FILETYPE_SRV:
38312       {
38313         if ( memtype == MEMTYPE_FLOAT ) return 1;
38314         srvReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
38315 	break;
38316       }
38317 #endif
38318 #ifdef HAVE_LIBEXTRA
38319     case CDI_FILETYPE_EXT:
38320       {
38321         if ( memtype == MEMTYPE_FLOAT ) return 1;
38322         extReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
38323 	break;
38324       }
38325 #endif
38326 #ifdef HAVE_LIBIEG
38327     case CDI_FILETYPE_IEG:
38328       {
38329         if ( memtype == MEMTYPE_FLOAT ) return 1;
38330         iegReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
38331 	break;
38332       }
38333 #endif
38334 #ifdef HAVE_LIBNETCDF
38335     case CDI_FILETYPE_NETCDF:
38336       {
38337         cdf_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
38338         break;
38339       }
38340 #endif
38341     default:
38342       {
38343 	Error("%s support not compiled in!", strfiletype(filetype));
38344         status = 2;
38345 	break;
38346       }
38347     }
38348 
38349   return status;
38350 }
38351 
38352 /*
38353 @Function  streamReadVarSlice
38354 @Title     Read a horizontal slice of a variable
38355 
38356 @Prototype void streamReadVarSlice(int streamID, int varID, int levelID, double *data, size_t *nmiss)
38357 @Parameter
38358     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
38359     @Item  varID     Variable identifier.
38360     @Item  levelID   Level identifier.
38361     @Item  data      Pointer to the location into which the data values are read.
38362                      The caller must allocate space for the returned values.
38363     @Item  nmiss     Number of missing values.
38364 
38365 @Description
38366 The function streamReadVarSlice reads all the values of a horizontal slice of a variable
38367 from an open dataset.
38368 @EndFunction
38369 */
streamReadVarSlice(int streamID,int varID,int levelID,double * data,size_t * nmiss)38370 void streamReadVarSlice(int streamID, int varID, int levelID, double *data, size_t *nmiss)
38371 {
38372   if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, data, nmiss) )
38373     {
38374       Warning("Unexpected error returned from cdiStreamReadVarSlice()!");
38375       size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
38376       memset(data, 0, elementCount * sizeof(*data));
38377     }
38378 }
38379 
38380 /*
38381 @Function  streamReadVarSliceF
38382 @Title     Read a horizontal slice of a variable
38383 
38384 @Prototype void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, size_t *nmiss)
38385 @Parameter
38386     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
38387     @Item  varID     Variable identifier.
38388     @Item  levelID   Level identifier.
38389     @Item  data      Pointer to the location into which the data values are read.
38390                      The caller must allocate space for the returned values.
38391     @Item  nmiss     Number of missing values.
38392 
38393 @Description
38394 The function streamReadVarSliceF reads all the values of a horizontal slice of a variable
38395 from an open dataset.
38396 @EndFunction
38397 */
streamReadVarSliceF(int streamID,int varID,int levelID,float * data,size_t * nmiss)38398 void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, size_t *nmiss)
38399 {
38400   if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, data, nmiss) )
38401     {
38402       // In case the file format does not support single precision reading,
38403       // we fall back to double precision reading, converting the data on the fly.
38404       size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
38405       double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
38406       streamReadVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
38407       for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
38408       Free(conversionBuffer);
38409     }
38410 }
38411 
38412 static
stream_read_record(int streamID,int memtype,void * data,size_t * nmiss)38413 int stream_read_record(int streamID, int memtype, void *data, size_t *nmiss)
38414 {
38415   // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
38416   // A value > 0 is returned in this case, otherwise it returns zero.
38417   int status = 0;
38418 
38419   check_parg(data);
38420   check_parg(nmiss);
38421 
38422   stream_t *streamptr = stream_to_pointer(streamID);
38423 
38424   *nmiss = 0;
38425 
38426   switch (cdiBaseFiletype(streamptr->filetype))
38427     {
38428 #ifdef HAVE_LIBGRIB
38429     case CDI_FILETYPE_GRB:
38430     case CDI_FILETYPE_GRB2:
38431       grb_read_record(streamptr, memtype, data, nmiss);
38432       break;
38433 #endif
38434 #ifdef HAVE_LIBSERVICE
38435     case CDI_FILETYPE_SRV:
38436       if ( memtype == MEMTYPE_FLOAT ) return 1;
38437       srvReadRecord(streamptr, (double *)data, nmiss);
38438       break;
38439 #endif
38440 #ifdef HAVE_LIBEXTRA
38441     case CDI_FILETYPE_EXT:
38442       if ( memtype == MEMTYPE_FLOAT ) return 1;
38443       extReadRecord(streamptr, (double *)data, nmiss);
38444       break;
38445 #endif
38446 #ifdef HAVE_LIBIEG
38447     case CDI_FILETYPE_IEG:
38448       if ( memtype == MEMTYPE_FLOAT ) return 1;
38449       iegReadRecord(streamptr, (double *)data, nmiss);
38450       break;
38451 #endif
38452 #ifdef HAVE_LIBNETCDF
38453     case CDI_FILETYPE_NETCDF:
38454       cdf_read_record(streamptr, memtype, data, nmiss);
38455       break;
38456 #endif
38457     default:
38458       {
38459 	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
38460 	break;
38461       }
38462     }
38463 
38464   return status;
38465 }
38466 
38467 
streamReadRecord(int streamID,double * data,size_t * nmiss)38468 void streamReadRecord(int streamID, double *data, size_t *nmiss)
38469 {
38470   stream_read_record(streamID, MEMTYPE_DOUBLE, (void *) data, nmiss);
38471 }
38472 
38473 
streamReadRecordF(int streamID,float * data,size_t * nmiss)38474 void streamReadRecordF(int streamID, float *data, size_t *nmiss)
38475 {
38476   if ( stream_read_record(streamID, MEMTYPE_FLOAT, (void *) data, nmiss) )
38477     {
38478       // In case the file format does not support single precision reading,
38479       // we fall back to double precision reading, converting the data on the fly.
38480       stream_t *streamptr = stream_to_pointer(streamID);
38481       int tsID   = streamptr->curTsID;
38482       int vrecID = streamptr->tsteps[tsID].curRecID;
38483       int recID  = streamptr->tsteps[tsID].recIDs[vrecID];
38484       int varID  = streamptr->tsteps[tsID].records[recID].varID;
38485       int nwpv = vlistInqVarNumber(streamInqVlist(streamID), varID);
38486       size_t elementCount = nwpv*gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
38487       double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
38488       streamReadRecord(streamID, conversionBuffer, nmiss);
38489       for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
38490       Free(conversionBuffer);
38491     }
38492 }
38493 #ifndef  VARSCAN_H
38494 #define  VARSCAN_H
38495 
38496 #ifndef  GRID_H
38497 #endif
38498 
38499 
38500 void varAddRecord(int recID, int param, int gridID, int zaxistype, int lbounds,
38501 		  int level1, int level2, int level_sf, int level_unit, int prec,
38502 		  int *pvarID, int *plevelID, int tsteptype, int ltype1, int ltype2,
38503 		  const char *name, const VarScanKeys *scanKeys, const var_tile_t *tiles, int *tile_index);
38504 
38505 void varDefVCT(size_t vctsize, double *vctptr);
38506 void varDefZAxisReference(int nlev, int nvgrid, unsigned char uuid[CDI_UUID_SIZE]);
38507 
38508 int  varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, const char **cvals, size_t clength, bool lbounds,
38509 		 const double *levels1, const double *levels2, int vctsize, const double *vct, char *name,
38510 		 const char *longname, const char *units, int prec, int mode, int ltype1, int ltype2);
38511 
38512 void varDefMissval(int varID, double missval);
38513 void varDefCompType(int varID, int comptype);
38514 void varDefCompLevel(int varID, int complevel);
38515 void varDefInst(int varID, int instID);
38516 int  varInqInst(int varID);
38517 void varDefModel(int varID, int modelID);
38518 int  varInqModel(int varID);
38519 void varDefTable(int varID, int tableID);
38520 int  varInqTable(int varID);
38521 
38522 void varDefKeyInt(int varID, int key, int value);
38523 void varDefKeyBytes(int varID, int key, const unsigned char *bytes, int length);
38524 void varDefKeyString(int varID, int key, const char *string);
38525 
38526 void varDefOptGribInt(int varID, int tile_index, long lval, const char *keyword);
38527 void varDefOptGribDbl(int varID, int tile_index, double dval, const char *keyword);
38528 int varOptGribNentries(int varID);
38529 
38530 bool zaxisCompare(int zaxisID, int zaxistype, int nlevels, bool lbounds, const double *levels, const char *longname, const char *units, int ltype1, int ltype2);
38531 
38532 #endif
38533 /*
38534  * Local Variables:
38535  * c-file-style: "Java"
38536  * c-basic-offset: 2
38537  * indent-tabs-mode: nil
38538  * show-trailing-whitespace: t
38539  * require-trailing-newline: t
38540  * End:
38541  */
38542 #ifdef HAVE_CONFIG_H
38543 #endif
38544 
38545 #ifdef HAVE_LIBNETCDF
38546 
38547 #include <ctype.h>
38548 #include <limits.h>
38549 
38550 
38551 
38552 #define  X_AXIS  1
38553 #define  Y_AXIS  2
38554 #define  Z_AXIS  3
38555 #define  T_AXIS  4
38556 
38557 #define  POSITIVE_UP    1
38558 #define  POSITIVE_DOWN  2
38559 
38560 typedef struct {
38561   int     dimid;
38562   int     ncvarid;
38563   int     dimtype;
38564   size_t  len;
38565   char    name[CDI_MAX_NAME];
38566 }
38567 ncdim_t;
38568 
38569 #define  MAX_COORDVARS  4
38570 #define  MAX_AUXVARS    4
38571 
38572 typedef struct {
38573   int      ncid;
38574   int      isvar;
38575   bool     ignore;
38576   bool     isx;
38577   bool     isy;
38578   bool     isc;
38579   bool     islon;
38580   bool     islat;
38581   bool     islev;
38582   bool     istime;
38583   bool     warn;
38584   bool     calendar;
38585   bool     climatology;
38586   bool     lformulaterms;
38587   int      param;
38588   int      code;
38589   int      tabnum;
38590   int      bounds;
38591   int      gridID;
38592   int      zaxisID;
38593   int      timetype;
38594   int      gridtype;
38595   int      zaxistype;
38596   int      xdim;
38597   int      ydim;
38598   int      zdim;
38599   int      xvarid;
38600   int      yvarid;
38601   int      rpvarid;
38602   int      zvarid;
38603   int      cvarids[MAX_COORDVARS];
38604   int      tvarid;
38605   int      psvarid;
38606   int      p0varid;
38607   int      ncoordvars;
38608   int      coordvarids[MAX_COORDVARS];
38609   int      nauxvars;
38610   int      auxvarids[MAX_AUXVARS];
38611   int      cellarea;
38612   int      tableID;
38613   int      truncation;
38614   int      position;
38615   int      numLPE;
38616   bool     defmissval;
38617   bool     deffillval;
38618   int      xtype;
38619   int      gmapid;
38620   int      positive;
38621   int      ndims;
38622   int      dimids[8];
38623   int      dimtype[8];
38624   size_t   chunks[8];
38625   int      chunked;
38626   int      chunktype;
38627   int      natts;
38628   bool     ldeflate;
38629   bool     lszip;
38630   bool     lunsigned;
38631   bool     lvalidrange;
38632   int     *atts;
38633   size_t   vctsize;
38634   double  *vct;
38635   double   missval;
38636   double   fillval;
38637   double   addoffset;
38638   double   scalefactor;
38639   double   validrange[2];
38640   char     name[CDI_MAX_NAME];
38641   char     longname[CDI_MAX_NAME];
38642   char     stdname[CDI_MAX_NAME];
38643   char     units[CDI_MAX_NAME];
38644   char     extra[CDI_MAX_NAME];
38645   int      typeOfEnsembleForecast;
38646   int      numberOfForecastsInEnsemble;
38647   int      perturbationNumber;
38648 }
38649 ncvar_t;
38650 
38651 
38652 static
scanTimeString(const char * ptu,int64_t * rdate,int * rtime)38653 void scanTimeString(const char *ptu, int64_t *rdate, int *rtime)
38654 {
38655   int year = 1, month = 1, day = 1;
38656   int hour = 0, minute = 0, second = 0;
38657   int v1 = 1, v2 = 1, v3 = 1;
38658   char ch = ' ';
38659 
38660   if ( *ptu ) sscanf(ptu, "%d-%d-%d%c%d:%d:%d", &v1, &v2, &v3, &ch, &hour, &minute, &second);
38661 
38662   if ( v3 > 999 && v1 < 32 )
38663     { year = v3; month = v2; day = v1; }
38664   else
38665     { year = v1; month = v2; day = v3; }
38666 
38667   *rdate = cdiEncodeDate(year, month, day);
38668   *rtime = cdiEncodeTime(hour, minute, second);
38669 }
38670 
38671 static
scanTimeUnit(const char * unitstr)38672 int scanTimeUnit(const char *unitstr)
38673 {
38674   const size_t len = strlen(unitstr);
38675   const int timeunit = get_timeunit(len, unitstr);
38676   if ( timeunit == -1 ) Message("Unsupported TIMEUNIT: %s!", unitstr);
38677   return timeunit;
38678 }
38679 
38680 static
setForecastTime(const char * timestr,taxis_t * taxis)38681 void setForecastTime(const char *timestr, taxis_t *taxis)
38682 {
38683   const size_t len = strlen(timestr);
38684   if ( len != 0 )
38685     scanTimeString(timestr, &taxis->fdate, &taxis->ftime);
38686   else
38687     taxis->fdate = taxis->ftime = 0;
38688 }
38689 
38690 static
setBaseTime(const char * timeunits,taxis_t * taxis)38691 int setBaseTime(const char *timeunits, taxis_t *taxis)
38692 {
38693   int taxistype = TAXIS_ABSOLUTE;
38694 
38695   size_t len = strlen(timeunits);
38696   while ( isspace(*timeunits) && len ) { timeunits++; len--; }
38697 
38698   char *tu = (char *)Malloc((len+1) * sizeof(char));
38699 
38700   for ( size_t i = 0; i < len; i++ ) tu[i] = (char)tolower((int)timeunits[i]);
38701   tu[len] = 0;
38702 
38703   int timeunit = get_timeunit(len, tu);
38704   if ( timeunit == -1 )
38705     {
38706       Message("Unsupported TIMEUNIT: %s!", timeunits);
38707       return 1;
38708     }
38709 
38710   size_t pos = 0;
38711   while ( pos < len && !isspace(tu[pos]) ) ++pos;
38712   if ( tu[pos] )
38713     {
38714       while ( isspace(tu[pos]) ) ++pos;
38715 
38716       if ( strStartsWith(tu+pos, "since") ) taxistype = TAXIS_RELATIVE;
38717 
38718       while ( pos < len && !isspace(tu[pos]) ) ++pos;
38719       if ( tu[pos] )
38720         {
38721           while ( isspace(tu[pos]) ) ++pos;
38722 
38723           if ( taxistype == TAXIS_ABSOLUTE )
38724             {
38725               if ( timeunit == TUNIT_DAY )
38726                 {
38727                   if ( !strStartsWith(tu+pos, "%y%m%d.%f") )
38728                     {
38729                       Warning("Unsupported format %s for TIMEUNIT day!", tu+pos);
38730                       timeunit = -1;
38731                     }
38732                 }
38733               else if ( timeunit == TUNIT_MONTH )
38734                 {
38735                   if ( !strStartsWith(tu+pos, "%y%m.%f") )
38736                     {
38737                       Warning("Unsupported format %s for TIMEUNIT month!", tu+pos);
38738                       timeunit = -1;
38739                     }
38740                 }
38741               else if ( timeunit == TUNIT_YEAR )
38742                 {
38743                   if ( !strStartsWith(tu+pos, "%y.%f") )
38744                     {
38745                       Warning("Unsupported format %s for TIMEUNIT year!", tu+pos);
38746                       timeunit = -1;
38747                     }
38748                 }
38749               else
38750                 {
38751                   Warning("Unsupported format for time units: %s!", tu);
38752                 }
38753             }
38754           else if ( taxistype == TAXIS_RELATIVE )
38755             {
38756               int64_t rdate = -1;
38757               int rtime = -1;
38758               scanTimeString(tu+pos, &rdate, &rtime);
38759               taxis->rdate = rdate;
38760               taxis->rtime = rtime;
38761 
38762               if ( CDI_Debug ) Message("rdate = %lld  rtime = %d", rdate, rtime);
38763             }
38764         }
38765     }
38766 
38767   taxis->type = taxistype;
38768   taxis->unit = timeunit;
38769 
38770   Free(tu);
38771 
38772   if ( CDI_Debug ) Message("taxistype = %d  unit = %d", taxistype, timeunit);
38773 
38774   return 0;
38775 }
38776 
38777 static
xtypeIsText(int xtype)38778 bool xtypeIsText(int xtype)
38779 {
38780   const bool isText = (xtype == NC_CHAR)
38781 #ifdef HAVE_NETCDF4
38782     || (xtype == NC_STRING)
38783 #endif
38784     ;
38785   return isText;
38786 }
38787 
38788 static
xtypeIsFloat(nc_type xtype)38789 bool xtypeIsFloat(nc_type xtype)
38790 {
38791   const bool isFloat = xtype == NC_FLOAT || xtype == NC_DOUBLE;
38792   return isFloat;
38793 }
38794 
38795 static
xtypeIsInt(nc_type xtype)38796 bool xtypeIsInt(nc_type xtype)
38797 {
38798   const bool isInt = xtype == NC_SHORT || xtype == NC_INT || xtype == NC_BYTE
38799 #ifdef HAVE_NETCDF4
38800     || xtype == NC_USHORT || xtype == NC_UINT || xtype == NC_UBYTE
38801 #endif
38802     ;
38803 
38804   return isInt;
38805 }
38806 
38807 static
cdfInqDatatype(stream_t * streamptr,int xtype,bool lunsigned)38808 int cdfInqDatatype(stream_t *streamptr, int xtype, bool lunsigned)
38809 {
38810   int datatype = -1;
38811 
38812 #ifdef HAVE_NETCDF4
38813   if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
38814 #endif
38815 
38816   if      ( xtype == NC_BYTE   )  datatype = CDI_DATATYPE_INT8;
38817   else if ( xtype == NC_CHAR   )  datatype = CDI_DATATYPE_UINT8;
38818   else if ( xtype == NC_SHORT  )  datatype = CDI_DATATYPE_INT16;
38819   else if ( xtype == NC_INT    )  datatype = CDI_DATATYPE_INT32;
38820   else if ( xtype == NC_FLOAT  )  datatype = CDI_DATATYPE_FLT32;
38821   else if ( xtype == NC_DOUBLE )  datatype = CDI_DATATYPE_FLT64;
38822 #ifdef HAVE_NETCDF4
38823   else if ( xtype == NC_UBYTE  )  datatype = CDI_DATATYPE_UINT8;
38824   else if ( xtype == NC_LONG   )  datatype = CDI_DATATYPE_INT32;
38825   else if ( xtype == NC_USHORT )  datatype = CDI_DATATYPE_UINT16;
38826   else if ( xtype == NC_UINT   )  datatype = CDI_DATATYPE_UINT32;
38827   else if ( xtype == NC_INT64  )  datatype = CDI_DATATYPE_FLT64;
38828   else if ( xtype == NC_UINT64 )  datatype = CDI_DATATYPE_FLT64;
38829   else
38830     {
38831       if (xtype != streamptr->nc_complex_float_id && xtype != streamptr->nc_complex_double_id)
38832         {
38833           int isUserDefinedType = false;
38834 #ifdef NC_FIRSTUSERTYPEID
38835           isUserDefinedType = xtype >= NC_FIRSTUSERTYPEID;
38836 #endif
38837           if (isUserDefinedType)
38838             {
38839               int fileID = streamptr->fileID;
38840               size_t nfields = 0, compoundsize = 0;
38841               int status = nc_inq_compound(fileID, xtype, NULL, &compoundsize, &nfields);
38842               if (status == NC_NOERR && nfields == 2 && (compoundsize == 8 || compoundsize == 16))
38843                 {
38844                   nc_type field_type1 = -1, field_type2 = -1;
38845                   int field_dims1 = 0, field_dims2 = 0;
38846                   nc_inq_compound_field(fileID, xtype, 0, NULL, NULL, &field_type1, &field_dims1, NULL);
38847                   nc_inq_compound_field(fileID, xtype, 1, NULL, NULL, &field_type2, &field_dims2, NULL);
38848                   if (field_type1 == field_type2 && field_dims1 == 0 && field_dims2 == 0)
38849                     {
38850                       if      (field_type1 == NC_FLOAT)  streamptr->nc_complex_float_id = xtype;
38851                       else if (field_type1 == NC_DOUBLE) streamptr->nc_complex_double_id = xtype;
38852                     }
38853                 }
38854             }
38855         }
38856       if      ( xtype == streamptr->nc_complex_float_id  )  datatype = CDI_DATATYPE_CPX32;
38857       else if ( xtype == streamptr->nc_complex_double_id )  datatype = CDI_DATATYPE_CPX64;
38858     }
38859 #endif
38860 
38861   return datatype;
38862 }
38863 
38864 static
cdfGetAttInt(int fileID,int ncvarid,const char * attname,size_t attlen,int * attint)38865 void cdfGetAttInt(int fileID, int ncvarid, const char *attname, size_t attlen, int *attint)
38866 {
38867   *attint = 0;
38868 
38869   nc_type atttype;
38870   size_t nc_attlen;
38871   cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
38872   cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
38873 
38874   if ( xtypeIsFloat(atttype) || xtypeIsInt(atttype) )
38875     {
38876       const bool lalloc = nc_attlen > attlen;
38877       int *pintatt = lalloc ? (int *)(Malloc(nc_attlen*sizeof(int))) : attint;
38878       cdf_get_att_int(fileID, ncvarid, attname, pintatt);
38879       if ( lalloc )
38880         {
38881           memcpy(attint, pintatt, attlen*sizeof(int));
38882           Free(pintatt);
38883         }
38884     }
38885 }
38886 
38887 static
cdfGetAttDouble(int fileID,int ncvarid,char * attname,size_t attlen,double * attdouble)38888 void cdfGetAttDouble(int fileID, int ncvarid, char *attname, size_t attlen, double *attdouble)
38889 {
38890   *attdouble = 0;
38891 
38892   nc_type atttype;
38893   size_t nc_attlen;
38894   cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
38895   cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
38896 
38897   if ( xtypeIsFloat(atttype) || xtypeIsInt(atttype) )
38898     {
38899       const bool lalloc = nc_attlen > attlen;
38900       double *pdoubleatt = lalloc ? (double*)Malloc(nc_attlen*sizeof(double)) : attdouble;
38901       cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);
38902       if ( lalloc )
38903         {
38904           memcpy(attdouble, pdoubleatt, attlen*sizeof(double));
38905           Free(pdoubleatt);
38906         }
38907     }
38908 }
38909 
38910 static
cdfCheckAttText(int fileID,int ncvarid,const char * attname)38911 bool cdfCheckAttText(int fileID, int ncvarid, const char *attname)
38912 {
38913   bool status = false;
38914   nc_type atttype;
38915 
38916   const int status_nc = nc_inq_atttype(fileID, ncvarid, attname, &atttype);
38917   if ( status_nc == NC_NOERR && (atttype == NC_CHAR
38918 #ifdef HAVE_NETCDF4
38919            || atttype == NC_STRING
38920 #endif
38921            ) )
38922     {
38923       status = true;
38924     }
38925 
38926   return status;
38927 }
38928 
38929 static
cdfGetAttText(int fileID,int ncvarid,const char * attname,size_t attlen,char * atttext)38930 void cdfGetAttText(int fileID, int ncvarid, const char *attname, size_t attlen, char *atttext)
38931 {
38932   atttext[0] = 0;
38933 
38934   nc_type atttype;
38935   size_t nc_attlen;
38936   cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
38937   cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
38938 
38939   if ( atttype == NC_CHAR )
38940     {
38941       char attbuf[65636];
38942       if ( nc_attlen < sizeof(attbuf) )
38943         {
38944           cdf_get_att_text(fileID, ncvarid, attname, attbuf);
38945 
38946           if ( nc_attlen > (attlen-1) ) nc_attlen = (attlen-1);
38947 
38948           attbuf[nc_attlen++] = 0;
38949           memcpy(atttext, attbuf, nc_attlen);
38950         }
38951     }
38952 #ifdef HAVE_NETCDF4
38953   else if ( atttype == NC_STRING )
38954     {
38955       if ( nc_attlen == 1 )
38956         {
38957           char *attbuf = NULL;
38958           cdf_get_att_string(fileID, ncvarid, attname, &attbuf);
38959 
38960           size_t ssize = strlen(attbuf) + 1;
38961           if ( ssize > attlen ) ssize = attlen;
38962           memcpy(atttext, attbuf, ssize);
38963           atttext[ssize - 1] = 0;
38964           Free(attbuf);
38965         }
38966     }
38967 #endif
38968 }
38969 
38970 
cdf_scale_add(size_t size,double * data,double addoffset,double scalefactor)38971 void cdf_scale_add(size_t size, double *data, double addoffset, double scalefactor)
38972 {
38973   const bool laddoffset   = IS_NOT_EQUAL(addoffset, 0);
38974   const bool lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
38975 
38976   if ( laddoffset && lscalefactor )
38977     {
38978       for (size_t i = 0; i < size; ++i) data[i] = data[i] * scalefactor + addoffset;
38979     }
38980   else if (lscalefactor)
38981     {
38982       for (size_t i = 0; i < size; ++i) data[i] *= scalefactor;
38983     }
38984   else if (laddoffset)
38985     {
38986       for (size_t i = 0; i < size; ++i) data[i] += addoffset;
38987     }
38988 }
38989 
38990 static
cdfCreateRecords(stream_t * streamptr,int tsID)38991 void cdfCreateRecords(stream_t *streamptr, int tsID)
38992 {
38993   if ( tsID < 0 || (tsID >= streamptr->ntsteps && tsID > 0) ) return;
38994 
38995   if ( streamptr->tsteps[tsID].nallrecs > 0 ) return;
38996 
38997   int vlistID  = streamptr->vlistID;
38998 
38999   tsteps_t* sourceTstep = streamptr->tsteps;
39000   tsteps_t* destTstep = sourceTstep + tsID;
39001 
39002   const int nvars = vlistNvars(vlistID);
39003   const int nrecs = vlistNrecs(vlistID);
39004   if ( nrecs <= 0 ) return;
39005 
39006   if ( tsID == 0 )
39007     {
39008       const int nvrecs = nrecs; /* use all records at first timestep */
39009 
39010       streamptr->nrecs += nrecs;
39011 
39012       destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
39013       destTstep->nrecs      = nrecs;
39014       destTstep->nallrecs   = nrecs;
39015       destTstep->recordSize = nrecs;
39016       destTstep->curRecID   = CDI_UNDEFID;
39017       destTstep->recIDs     = (int *) Malloc((size_t)nvrecs*sizeof (int));;
39018       for ( int recID = 0; recID < nvrecs; recID++ ) destTstep->recIDs[recID] = recID;
39019 
39020       record_t *records = destTstep->records;
39021 
39022       for ( int varID = 0, recID = 0; varID < nvars; varID++ )
39023         {
39024           const int zaxisID = vlistInqVarZaxis(vlistID, varID);
39025           const int nlev    = zaxisInqSize(zaxisID);
39026           for ( int levelID = 0; levelID < nlev; levelID++ )
39027             {
39028               recordInitEntry(&records[recID]);
39029               records[recID].varID   = (short)varID;
39030               records[recID].levelID = (short)levelID;
39031               recID++;
39032             }
39033         }
39034     }
39035   else if ( tsID == 1 )
39036     {
39037       int nvrecs = 0;
39038       for ( int varID = 0; varID < nvars; varID++ )
39039         {
39040           if ( vlistInqVarTimetype(vlistID, varID) != TIME_CONSTANT )
39041             {
39042               int zaxisID = vlistInqVarZaxis(vlistID, varID);
39043               nvrecs += zaxisInqSize(zaxisID);
39044             }
39045         }
39046 
39047       streamptr->nrecs += nvrecs;
39048 
39049       destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
39050       destTstep->nrecs      = nvrecs;
39051       destTstep->nallrecs   = nrecs;
39052       destTstep->recordSize = nrecs;
39053       destTstep->curRecID   = CDI_UNDEFID;
39054 
39055       memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
39056 
39057       if ( nvrecs )
39058         {
39059           destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
39060           for ( int recID = 0, vrecID = 0; recID < nrecs; recID++ )
39061             {
39062               int varID = destTstep->records[recID].varID;
39063               if ( vlistInqVarTimetype(vlistID, varID) != TIME_CONSTANT )
39064                 {
39065                   destTstep->recIDs[vrecID++] = recID;
39066                 }
39067             }
39068         }
39069     }
39070   else
39071     {
39072       if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
39073 
39074       const int nvrecs = streamptr->tsteps[1].nrecs;
39075 
39076       streamptr->nrecs += nvrecs;
39077 
39078       destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
39079       destTstep->nrecs      = nvrecs;
39080       destTstep->nallrecs   = nrecs;
39081       destTstep->recordSize = nrecs;
39082       destTstep->curRecID   = CDI_UNDEFID;
39083 
39084       memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
39085 
39086       destTstep->recIDs     = (int *) Malloc((size_t)nvrecs * sizeof(int));
39087 
39088       memcpy(destTstep->recIDs, streamptr->tsteps[1].recIDs, (size_t)nvrecs*sizeof(int));
39089     }
39090 }
39091 
39092 static
cdf_time_dimid(int fileID,int ndims,int nvars,ncdim_t * ncdims)39093 int cdf_time_dimid(int fileID, int ndims, int nvars, ncdim_t *ncdims)
39094 {
39095   char dimname[CDI_MAX_NAME];
39096 
39097   for ( int dimid = 0; dimid < ndims; ++dimid )
39098     {
39099       dimname[0] = 0;
39100       cdf_inq_dimname(fileID, ncdims[dimid].dimid, dimname);
39101       if ( strIsEqual(dimname, "time") || strIsEqual(dimname, "Time") ) return dimid;
39102     }
39103 
39104   for ( int varid = 0; varid < nvars; ++varid )
39105     {
39106       nc_type xtype;
39107       int nvdims, nvatts, dimids[9];
39108       cdf_inq_var(fileID, varid, NULL, &xtype, &nvdims, dimids, &nvatts);
39109       for ( int i = 0; i < nvdims; ++i )
39110         for ( int dimid = 0; dimid < ndims; ++dimid )
39111           if ( ncdims[dimid].dimid == dimids[i] )
39112             {
39113               dimids[i] = dimid;
39114               break;
39115             }
39116 
39117       if ( nvdims == 1 )
39118         {
39119           char sbuf[CDI_MAX_NAME];
39120           for ( int iatt = 0; iatt < nvatts; ++iatt )
39121             {
39122               sbuf[0] = 0;
39123               cdf_inq_attname(fileID, varid, iatt, sbuf);
39124               if ( strncmp(sbuf, "units", 5) == 0 )
39125                 {
39126                   cdfGetAttText(fileID, varid, "units", sizeof(sbuf), sbuf);
39127                   strToLower(sbuf);
39128 
39129                   if ( is_time_units(sbuf) ) return dimids[0];
39130                 }
39131             }
39132         }
39133     }
39134 
39135   return CDI_UNDEFID;
39136 }
39137 
39138 static
init_ncdims(long ndims,ncdim_t * ncdims)39139 void init_ncdims(long ndims, ncdim_t *ncdims)
39140 {
39141   for ( long ncdimid = 0; ncdimid < ndims; ncdimid++ )
39142     {
39143       ncdims[ncdimid].dimid        = CDI_UNDEFID;
39144       ncdims[ncdimid].ncvarid      = CDI_UNDEFID;
39145       ncdims[ncdimid].dimtype      = CDI_UNDEFID;
39146       ncdims[ncdimid].len          = 0;
39147       ncdims[ncdimid].name[0]      = 0;
39148     }
39149 }
39150 
39151 static
init_ncvars(long nvars,ncvar_t * ncvars)39152 void init_ncvars(long nvars, ncvar_t *ncvars)
39153 {
39154   for ( long ncvarid = 0; ncvarid < nvars; ++ncvarid )
39155     {
39156       ncvars[ncvarid].ncid            = CDI_UNDEFID;
39157       ncvars[ncvarid].isvar           = CDI_UNDEFID;
39158       ncvars[ncvarid].ignore          = false;
39159       ncvars[ncvarid].isx             = false;
39160       ncvars[ncvarid].isy             = false;
39161       ncvars[ncvarid].isc             = false;
39162       ncvars[ncvarid].islon           = false;
39163       ncvars[ncvarid].islat           = false;
39164       ncvars[ncvarid].islev           = false;
39165       ncvars[ncvarid].istime          = false;
39166       ncvars[ncvarid].warn            = false;
39167       ncvars[ncvarid].calendar        = false;
39168       ncvars[ncvarid].climatology     = false;
39169       ncvars[ncvarid].lformulaterms   = false;
39170       ncvars[ncvarid].timetype        = TIME_CONSTANT;
39171       ncvars[ncvarid].param           = CDI_UNDEFID;
39172       ncvars[ncvarid].code            = CDI_UNDEFID;
39173       ncvars[ncvarid].tabnum          = 0;
39174       ncvars[ncvarid].bounds          = CDI_UNDEFID;
39175       ncvars[ncvarid].gridID          = CDI_UNDEFID;
39176       ncvars[ncvarid].zaxisID         = CDI_UNDEFID;
39177       ncvars[ncvarid].gridtype        = CDI_UNDEFID;
39178       ncvars[ncvarid].zaxistype       = CDI_UNDEFID;
39179       ncvars[ncvarid].xdim            = CDI_UNDEFID;
39180       ncvars[ncvarid].ydim            = CDI_UNDEFID;
39181       ncvars[ncvarid].zdim            = CDI_UNDEFID;
39182       ncvars[ncvarid].xvarid          = CDI_UNDEFID;
39183       ncvars[ncvarid].yvarid          = CDI_UNDEFID;
39184       ncvars[ncvarid].rpvarid         = CDI_UNDEFID;
39185       ncvars[ncvarid].zvarid          = CDI_UNDEFID;
39186       ncvars[ncvarid].tvarid          = CDI_UNDEFID;
39187       ncvars[ncvarid].psvarid         = CDI_UNDEFID;
39188       ncvars[ncvarid].p0varid         = CDI_UNDEFID;
39189       ncvars[ncvarid].ncoordvars      = 0;
39190       for ( int i = 0; i < MAX_COORDVARS; ++i )
39191         {
39192           ncvars[ncvarid].coordvarids[i]  = CDI_UNDEFID;
39193           ncvars[ncvarid].cvarids[i]      = CDI_UNDEFID;
39194         }
39195       ncvars[ncvarid].nauxvars      = 0;
39196       for ( int i = 0; i < MAX_AUXVARS; ++i )
39197         ncvars[ncvarid].auxvarids[i]  = CDI_UNDEFID;
39198       ncvars[ncvarid].cellarea        = CDI_UNDEFID;
39199       ncvars[ncvarid].tableID         = CDI_UNDEFID;
39200       ncvars[ncvarid].xtype           = 0;
39201       ncvars[ncvarid].ndims           = 0;
39202       ncvars[ncvarid].gmapid          = CDI_UNDEFID;
39203       ncvars[ncvarid].vctsize         = 0;
39204       ncvars[ncvarid].vct             = NULL;
39205       ncvars[ncvarid].truncation      = 0;
39206       ncvars[ncvarid].position        = 0;
39207       ncvars[ncvarid].numLPE          = 0;
39208       ncvars[ncvarid].positive        = 0;
39209       ncvars[ncvarid].chunked         = 0;
39210       ncvars[ncvarid].chunktype       = CDI_UNDEFID;
39211       ncvars[ncvarid].defmissval      = false;
39212       ncvars[ncvarid].deffillval      = false;
39213       ncvars[ncvarid].missval         = 0;
39214       ncvars[ncvarid].fillval         = 0;
39215       ncvars[ncvarid].addoffset       = 0;
39216       ncvars[ncvarid].scalefactor     = 1;
39217       ncvars[ncvarid].natts           = 0;
39218       ncvars[ncvarid].atts            = NULL;
39219       ncvars[ncvarid].ldeflate        = false;
39220       ncvars[ncvarid].lszip           = false;
39221       ncvars[ncvarid].lunsigned       = false;
39222       ncvars[ncvarid].lvalidrange     = false;
39223       ncvars[ncvarid].validrange[0]   = VALIDMISS;
39224       ncvars[ncvarid].validrange[1]   = VALIDMISS;
39225       ncvars[ncvarid].typeOfEnsembleForecast      = -1;
39226       ncvars[ncvarid].numberOfForecastsInEnsemble = -1;
39227       ncvars[ncvarid].perturbationNumber          = -1;
39228       memset(ncvars[ncvarid].name, 0, CDI_MAX_NAME);
39229       memset(ncvars[ncvarid].longname, 0, CDI_MAX_NAME);
39230       memset(ncvars[ncvarid].stdname, 0, CDI_MAX_NAME);
39231       memset(ncvars[ncvarid].units, 0, CDI_MAX_NAME);
39232       memset(ncvars[ncvarid].extra, 0, CDI_MAX_NAME);
39233     }
39234 }
39235 
39236 static
cdf_set_var(ncvar_t * ncvars,int ncvarid,short isvar)39237 void cdf_set_var(ncvar_t *ncvars, int ncvarid, short isvar)
39238 {
39239   if ( ncvars[ncvarid].isvar != CDI_UNDEFID &&
39240        ncvars[ncvarid].isvar != isvar   &&
39241        ncvars[ncvarid].warn  == false )
39242     {
39243       if ( ! ncvars[ncvarid].ignore )
39244         Warning("Inconsistent variable definition for %s!", ncvars[ncvarid].name);
39245 
39246       ncvars[ncvarid].warn = true;
39247       isvar = FALSE;
39248     }
39249 
39250   ncvars[ncvarid].isvar = isvar;
39251 }
39252 
39253 static
cdf_set_dim(ncvar_t * ncvars,int ncvarid,int dimid,int dimtype)39254 void cdf_set_dim(ncvar_t *ncvars, int ncvarid, int dimid, int dimtype)
39255 {
39256   if ( ncvars[ncvarid].dimtype[dimid] != CDI_UNDEFID &&
39257        ncvars[ncvarid].dimtype[dimid] != dimtype )
39258     {
39259       Warning("Inconsistent dimension definition for %s! dimid = %d;  type = %d;  newtype = %d",
39260               ncvars[ncvarid].name, dimid, ncvars[ncvarid].dimtype[dimid], dimtype);
39261     }
39262 
39263   ncvars[ncvarid].dimtype[dimid] = dimtype;
39264 }
39265 
39266 static
scan_hybrid_formulaterms(int ncid,int ncfvarid,int * avarid,int * bvarid,int * psvarid,int * p0varid)39267 void scan_hybrid_formulaterms(int ncid, int ncfvarid, int *avarid, int *bvarid, int *psvarid, int *p0varid)
39268 {
39269   *avarid  = -1;
39270   *bvarid  = -1;
39271   *psvarid = -1;
39272   *p0varid = -1;
39273 
39274   char attstring[1024];
39275   cdfGetAttText(ncid, ncfvarid, "formula_terms", sizeof(attstring), attstring);
39276   char *pstring = attstring;
39277 
39278   bool lstop = false;
39279   for ( int i = 0; i < 4; i++ )
39280     {
39281       while ( isspace((int) *pstring) ) pstring++;
39282       if ( *pstring == 0 ) break;
39283       char *tagname = pstring;
39284       while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
39285       if ( *pstring == 0 ) lstop = true;
39286       *pstring++ = 0;
39287 
39288       while ( isspace((int) *pstring) ) pstring++;
39289       if ( *pstring == 0 ) break;
39290       char *varname = pstring;
39291       while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
39292       if ( *pstring == 0 ) lstop = true;
39293       *pstring++ = 0;
39294 
39295       int dimvarid;
39296       int status_nc = nc_inq_varid(ncid, varname, &dimvarid);
39297       if ( status_nc == NC_NOERR )
39298         {
39299           if      ( strIsEqual(tagname, "ap:") ) *avarid  = dimvarid;
39300           else if ( strIsEqual(tagname, "a:")  ) *avarid  = dimvarid;
39301           else if ( strIsEqual(tagname, "b:")  ) *bvarid  = dimvarid;
39302           else if ( strIsEqual(tagname, "ps:") ) *psvarid = dimvarid;
39303           else if ( strIsEqual(tagname, "p0:") ) *p0varid = dimvarid;
39304         }
39305       else if ( !strIsEqual(tagname, "ps:") )
39306         {
39307           Warning("%s - %s", nc_strerror(status_nc), varname);
39308         }
39309 
39310       if ( lstop ) break;
39311     }
39312 }
39313 
39314 static
readVCT(int ncid,int ndims2,size_t dimlen,size_t dimlen2,int avarid2,int bvarid2,double * vct)39315 void readVCT(int ncid, int ndims2, size_t dimlen, size_t dimlen2, int avarid2, int bvarid2, double *vct)
39316 {
39317   double *abuf = (double*) Malloc(dimlen*2*sizeof(double));
39318   double *bbuf = (double*) Malloc(dimlen*2*sizeof(double));
39319   cdf_get_var_double(ncid, avarid2, abuf);
39320   cdf_get_var_double(ncid, bvarid2, bbuf);
39321 
39322   if ( ndims2 == 2 )
39323     {
39324       for ( size_t i = 0; i < dimlen; ++i )
39325         {
39326           vct[i] = abuf[i*2];
39327           vct[i+dimlen+1] = bbuf[i*2];
39328         }
39329       vct[dimlen]     = abuf[dimlen*2-1];
39330       vct[dimlen*2+1] = bbuf[dimlen*2-1];
39331     }
39332   else
39333     {
39334       for ( size_t i = 0; i < dimlen2; ++i )
39335         {
39336           vct[i] = abuf[i];
39337           vct[i+dimlen+1] = bbuf[i];
39338         }
39339     }
39340 
39341   Free(abuf);
39342   Free(bbuf);
39343 }
39344 
39345 static
isHybridSigmaPressureCoordinate(int ncid,int ncvarid,ncvar_t * ncvars,const ncdim_t * ncdims)39346 bool isHybridSigmaPressureCoordinate(int ncid, int ncvarid, ncvar_t *ncvars, const ncdim_t *ncdims)
39347 {
39348   bool status = false;
39349   ncvar_t *ncvar = &ncvars[ncvarid];
39350 
39351   if ( strIsEqual(ncvar->stdname, "atmosphere_hybrid_sigma_pressure_coordinate") )
39352     {
39353       CDI_Convention = CDI_CONVENTION_CF;
39354 
39355       status = true;
39356       ncvar->zaxistype = ZAXIS_HYBRID;
39357       //int ndims = ncvar->ndims;
39358       int dimid = ncvar->dimids[0];
39359       size_t dimlen = ncdims[dimid].len;
39360       int avarid1 = -1, bvarid1 = -1, psvarid1 = -1, p0varid1 = -1;
39361       int ncfvarid = ncvarid;
39362       if ( ncvars[ncfvarid].lformulaterms )
39363         scan_hybrid_formulaterms(ncid, ncfvarid, &avarid1, &bvarid1, &psvarid1, &p0varid1);
39364       // printf("avarid1, bvarid1, psvarid1, p0varid1 %d %d %d %d\n", avarid1, bvarid1, psvarid1, p0varid1);
39365       if ( avarid1  != -1 ) ncvars[avarid1].isvar = FALSE;
39366       if ( bvarid1  != -1 ) ncvars[bvarid1].isvar = FALSE;
39367       if ( psvarid1 != -1 ) ncvar->psvarid = psvarid1;
39368       if ( p0varid1 != -1 ) ncvar->p0varid = p0varid1;
39369 
39370       if ( ncvar->bounds != CDI_UNDEFID && ncvars[ncvar->bounds].lformulaterms )
39371         {
39372           ncfvarid = ncvar->bounds;
39373           int avarid2 = -1, bvarid2 = -1, psvarid2 = -1, p0varid2 = -1;
39374           if ( ncvars[ncfvarid].lformulaterms )
39375             scan_hybrid_formulaterms(ncid, ncfvarid, &avarid2, &bvarid2, &psvarid2, &p0varid2);
39376           // printf("avarid2, bvarid2, psvarid2, p0varid2 %d %d %d %d\n", avarid2, bvarid2, psvarid2, p0varid2);
39377           if ( avarid2 != -1 && bvarid2 != -1 )
39378             {
39379               ncvars[avarid2].isvar = FALSE;
39380               ncvars[bvarid2].isvar = FALSE;
39381 
39382               const int ndims2 = ncvars[avarid2].ndims;
39383               const int dimid2 = ncvars[avarid2].dimids[0];
39384               const size_t dimlen2 = ncdims[dimid2].len;
39385 
39386               if ( (ndims2 == 2 && dimid == ncvars[avarid2].dimids[0] ) ||
39387                    (ndims2 == 1 && dimlen == dimlen2-1 ) )
39388                 {
39389                   double px = 1;
39390                   if ( p0varid1 != -1 && p0varid1 == p0varid2 )
39391                     cdf_get_var_double(ncid, p0varid2, &px);
39392 
39393                   const size_t vctsize = (dimlen+1)*2;
39394                   double *vct = (double *) Malloc(vctsize*sizeof(double));
39395 
39396                   readVCT(ncid, ndims2, dimlen, dimlen2, avarid2, bvarid2, vct);
39397 
39398                   if ( p0varid1 != -1 && IS_NOT_EQUAL(px, 1) )
39399                     for ( size_t i = 0; i < dimlen+1; ++i ) vct[i] *= px;
39400 
39401                   ncvar->vct = vct;
39402                   ncvar->vctsize = vctsize;
39403                 }
39404             }
39405         }
39406     }
39407 
39408   return status;
39409 }
39410 
39411 static
cdf_set_cdi_attr(int ncid,int ncvarid,int attnum,int cdiID,int varID)39412 void cdf_set_cdi_attr(int ncid, int ncvarid, int attnum, int cdiID, int varID)
39413 {
39414   nc_type atttype;
39415   size_t attlen;
39416   char attname[CDI_MAX_NAME];
39417 
39418   cdf_inq_attname(ncid, ncvarid, attnum, attname);
39419   cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
39420   cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
39421   if ( xtypeIsInt(atttype) )
39422     {
39423       int attint;
39424       int *pattint = attlen > 1 ? (int*) malloc(attlen*sizeof(int)) : &attint;
39425       cdfGetAttInt(ncid, ncvarid, attname, attlen, pattint);
39426       int datatype = (atttype == NC_SHORT)  ? CDI_DATATYPE_INT16 :
39427                      (atttype == NC_BYTE)   ? CDI_DATATYPE_INT8 :
39428 #ifdef HAVE_NETCDF4
39429                      (atttype == NC_UBYTE)  ? CDI_DATATYPE_UINT8 :
39430                      (atttype == NC_USHORT) ? CDI_DATATYPE_UINT16 :
39431                      (atttype == NC_UINT)   ? CDI_DATATYPE_UINT32 :
39432 #endif
39433                      CDI_DATATYPE_INT32;
39434       cdiDefAttInt(cdiID, varID, attname, datatype, (int)attlen, pattint);
39435       if (attlen > 1) free(pattint);
39436     }
39437   else if ( xtypeIsFloat(atttype) )
39438     {
39439       double attflt;
39440       double *pattflt = attlen > 1 ? (double*) malloc(attlen*sizeof(double)) : &attflt;
39441       cdfGetAttDouble(ncid, ncvarid, attname, attlen, pattflt);
39442       const int datatype = (atttype == NC_FLOAT) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64;
39443       cdiDefAttFlt(cdiID, varID, attname, datatype, (int)attlen, pattflt);
39444       if (attlen > 1) free(pattflt);
39445     }
39446   else if ( xtypeIsText(atttype) )
39447     {
39448       char attstring[8192];
39449       cdfGetAttText(ncid, ncvarid, attname, sizeof(attstring), attstring);
39450       cdiDefAttTxt(cdiID, varID, attname, strlen(attstring), attstring);
39451     }
39452 }
39453 
39454 static
cdf_print_vars(const ncvar_t * ncvars,int nvars,const char * oname)39455 void cdf_print_vars(const ncvar_t *ncvars, int nvars, const char *oname)
39456 {
39457   char axis[7];
39458   static const char iaxis[] = {'t', 'z', 'y', 'x'};
39459 
39460   fprintf(stderr, "%s:\n", oname);
39461 
39462   for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
39463     {
39464       int ndim = 0;
39465       if ( ncvars[ncvarid].isvar )
39466         {
39467           axis[ndim++] = 'v';
39468           axis[ndim++] = ':';
39469           for ( int i = 0; i < ncvars[ncvarid].ndims; i++ )
39470             {/*
39471               if      ( ncvars[ncvarid].tvarid != -1 ) axis[ndim++] = iaxis[0];
39472               else if ( ncvars[ncvarid].zvarid != -1 ) axis[ndim++] = iaxis[1];
39473               else if ( ncvars[ncvarid].yvarid != -1 ) axis[ndim++] = iaxis[2];
39474               else if ( ncvars[ncvarid].xvarid != -1 ) axis[ndim++] = iaxis[3];
39475               else
39476              */
39477               if      ( ncvars[ncvarid].dimtype[i] == T_AXIS ) axis[ndim++] = iaxis[0];
39478               else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) axis[ndim++] = iaxis[1];
39479               else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) axis[ndim++] = iaxis[2];
39480               else if ( ncvars[ncvarid].dimtype[i] == X_AXIS ) axis[ndim++] = iaxis[3];
39481               else                                             axis[ndim++] = '?';
39482             }
39483         }
39484       else
39485         {
39486           axis[ndim++] = 'c';
39487           axis[ndim++] = ':';
39488           if      ( ncvars[ncvarid].istime ) axis[ndim++] = iaxis[0];
39489           else if ( ncvars[ncvarid].islev  ) axis[ndim++] = iaxis[1];
39490           else if ( ncvars[ncvarid].islat  ) axis[ndim++] = iaxis[2];
39491           else if ( ncvars[ncvarid].isy    ) axis[ndim++] = iaxis[2];
39492           else if ( ncvars[ncvarid].islon  ) axis[ndim++] = iaxis[3];
39493           else if ( ncvars[ncvarid].isx    ) axis[ndim++] = iaxis[3];
39494           else                               axis[ndim++] = '?';
39495         }
39496 
39497       axis[ndim++] = 0;
39498 
39499       fprintf(stderr, "%3d %3d  %-6s %s\n", ncvarid, ndim-3, axis, ncvars[ncvarid].name);
39500     }
39501 }
39502 
39503 static
cdfScanAttrAxis(ncvar_t * ncvars,ncdim_t * ncdims,int ncvarid,const char * attstring,int nvdims,const int * dimidsp)39504 void cdfScanAttrAxis(ncvar_t *ncvars, ncdim_t *ncdims, int ncvarid, const char *attstring, int nvdims, const int *dimidsp)
39505 {
39506   int attlen = (int) strlen(attstring);
39507 
39508   if (nvdims == 0 && attlen == 1)
39509     {
39510       if (attstring[0] == 'z')
39511         {
39512           cdf_set_var(ncvars, ncvarid, FALSE);
39513           ncvars[ncvarid].islev = true;
39514           return;
39515         }
39516     }
39517 
39518   if (attlen != nvdims) return;
39519 
39520   for (int i = 0; i < attlen; ++i)
39521     {
39522       if (attstring[i] != '-' && attstring[i] != 't' && attstring[i] != 'z' && attstring[i] != 'y' && attstring[i] != 'x')
39523         {
39524           return;
39525         }
39526     }
39527 
39528   while (attlen--)
39529     {
39530       const int attchr = attstring[attlen];
39531       if (attchr == 't')
39532         {
39533           if (attlen != 0) Warning("axis attribute 't' not on first position!");
39534           cdf_set_dim(ncvars, ncvarid, attlen, T_AXIS);
39535         }
39536       else if (attchr == 'z')
39537         {
39538           ncvars[ncvarid].zdim = dimidsp[attlen];
39539           cdf_set_dim(ncvars, ncvarid, attlen, Z_AXIS);
39540 
39541           if (ncvars[ncvarid].ndims == 1)
39542             {
39543               cdf_set_var(ncvars, ncvarid, FALSE);
39544               ncdims[ncvars[ncvarid].dimids[0]].dimtype = Z_AXIS;
39545             }
39546         }
39547       else if (attchr == 'y')
39548         {
39549           ncvars[ncvarid].ydim = dimidsp[attlen];
39550           cdf_set_dim(ncvars, ncvarid, attlen, Y_AXIS);
39551 
39552           if ( ncvars[ncvarid].ndims == 1 )
39553             {
39554               cdf_set_var(ncvars, ncvarid, FALSE);
39555               ncdims[ncvars[ncvarid].dimids[0]].dimtype = Y_AXIS;
39556             }
39557         }
39558       else if (attchr == 'x')
39559         {
39560           ncvars[ncvarid].xdim = dimidsp[attlen];
39561           cdf_set_dim(ncvars, ncvarid, attlen, X_AXIS);
39562 
39563           if (ncvars[ncvarid].ndims == 1)
39564             {
39565               cdf_set_var(ncvars, ncvarid, FALSE);
39566               ncdims[ncvars[ncvarid].dimids[0]].dimtype = X_AXIS;
39567             }
39568         }
39569     }
39570 }
39571 
39572 static
cdf_get_cell_varid(char * attstring,int ncid)39573 int cdf_get_cell_varid(char *attstring, int ncid)
39574 {
39575   int nc_cell_id = CDI_UNDEFID;
39576 
39577   char *pstring = attstring;
39578   while ( isspace((int) *pstring) ) pstring++;
39579   char *cell_measures = pstring;
39580   while ( isalnum((int) *pstring) ) pstring++;
39581   *pstring++ = 0;
39582   while ( isspace((int) *pstring) ) pstring++;
39583   char *cell_var = pstring;
39584   while ( ! isspace((int) *pstring) && *pstring != 0 ) pstring++;
39585   *pstring++ = 0;
39586   /*
39587     printf("cell_measures >%s<\n", cell_measures);
39588     printf("cell_var >%s<\n", cell_var);
39589   */
39590   if ( strStartsWith(cell_measures, "area") )
39591     {
39592       int nc_var_id;
39593       int status = nc_inq_varid(ncid, cell_var, &nc_var_id);
39594       if ( status == NC_NOERR )
39595         nc_cell_id = nc_var_id;
39596       /*
39597       else
39598         Warning("%s - %s", nc_strerror(status), cell_var);
39599       */
39600     }
39601 
39602   return nc_cell_id;
39603 }
39604 
39605 static
cdfScanVarAttr(int nvars,ncvar_t * ncvars,int ndims,ncdim_t * ncdims,int timedimid,int modelID,int format)39606 void cdfScanVarAttr(int nvars, ncvar_t *ncvars, int ndims, ncdim_t *ncdims, int timedimid, int modelID, int format)
39607 {
39608   int ncdimid;
39609   int nvdims, nvatts;
39610   int iatt;
39611   nc_type xtype, atttype;
39612   size_t attlen;
39613   char name[CDI_MAX_NAME];
39614   char attname[CDI_MAX_NAME];
39615   char attstring[8192];
39616 
39617   int nchecked_vars = 0;
39618   enum { max_check_vars = 9 };
39619   char *checked_vars[max_check_vars];
39620   for ( int i = 0; i < max_check_vars; ++i ) checked_vars[i] = NULL;
39621 
39622   for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
39623     {
39624       const int ncid = ncvars[ncvarid].ncid;
39625       int *dimidsp = ncvars[ncvarid].dimids;
39626 
39627       cdf_inq_var(ncid, ncvarid, name, &xtype, &nvdims, dimidsp, &nvatts);
39628       for ( int i = 0; i < nvdims; ++i )
39629         for ( int dimid = 0; dimid < ndims; ++dimid )
39630           if ( ncdims[dimid].dimid == dimidsp[i] )
39631             {
39632               dimidsp[i] = dimid;
39633               break;
39634             }
39635       strcpy(ncvars[ncvarid].name, name);
39636 
39637       for ( ncdimid = 0; ncdimid < nvdims; ncdimid++ )
39638         ncvars[ncvarid].dimtype[ncdimid] = -1;
39639 
39640       ncvars[ncvarid].xtype = xtype;
39641       ncvars[ncvarid].ndims = nvdims;
39642 
39643 #ifdef HAVE_NETCDF4
39644       if ( format == NC_FORMAT_NETCDF4_CLASSIC || format == NC_FORMAT_NETCDF4 )
39645         {
39646           int shuffle = 0, deflate = 0, deflate_level = 0;
39647           nc_inq_var_deflate(ncid, ncvarid, &shuffle, &deflate, &deflate_level);
39648           if (deflate > 0) ncvars[ncvarid].ldeflate = true;
39649 
39650 #ifdef HAVE_NC_DEF_VAR_SZIP
39651           int options_mask = 0, pixels_per_block = 0;
39652           nc_inq_var_szip(ncid, ncvarid, &options_mask, &pixels_per_block);
39653           if (options_mask && pixels_per_block) ncvars[ncvarid].lszip = true;
39654 #endif
39655           /*
39656           size_t cache_size, nelems;
39657           float preemption;
39658           nc_get_chunk_cache(&cache_size, &nelems, &preemption);
39659           printf("cache_size %lu nelems %lu preemption %g\n", cache_size, nelems, preemption);
39660           nc_get_var_chunk_cache(ncid, ncvarid, &cache_size, &nelems, &preemption);
39661           printf("varid %d cache_size %lu nelems %lu preemption %g\n", ncvarid, cache_size, nelems, preemption);
39662           */
39663           size_t chunks[nvdims];
39664           int storage_in;
39665           if ( nc_inq_var_chunking(ncid, ncvarid, &storage_in, chunks) == NC_NOERR )
39666             {
39667               if ( storage_in == NC_CHUNKED )
39668                 {
39669                   ncvars[ncvarid].chunked = 1;
39670                   for ( int i = 0; i < nvdims; ++i ) ncvars[ncvarid].chunks[i] = chunks[i];
39671                   if ( CDI_Debug )
39672                     {
39673                       fprintf(stderr, "%s: chunking %d %d %d  chunks ", name, storage_in, NC_CONTIGUOUS, NC_CHUNKED);
39674                       for ( int i = 0; i < nvdims; ++i ) fprintf(stderr, "%zu ", chunks[i]);
39675                       fprintf(stderr, "\n");
39676                     }
39677                   {
39678                     char *buf = ncvars[ncvarid].extra;
39679                     size_t pos = strlen(buf);
39680                     static const char prefix[] = "chunks=";
39681                     memcpy(buf + pos, prefix, sizeof (prefix));
39682                     pos += sizeof (prefix) - 1;
39683                     for ( int i = nvdims-1; i >= 0; --i )
39684                       {
39685                         pos += (size_t)(sprintf(buf + pos, "%zu%s", chunks[i], i > 0 ? "x" : ""));
39686                       }
39687                     buf[pos] = ' '; buf[pos + 1] = 0;
39688                   }
39689                 }
39690             }
39691         }
39692 #endif
39693 
39694       if ( nvdims > 0 )
39695         {
39696           if ( timedimid == dimidsp[0] )
39697             {
39698               ncvars[ncvarid].timetype = TIME_VARYING;
39699               cdf_set_dim(ncvars, ncvarid, 0, T_AXIS);
39700             }
39701           else
39702             {
39703               for ( ncdimid = 1; ncdimid < nvdims; ncdimid++ )
39704                 {
39705                   if ( timedimid == dimidsp[ncdimid] )
39706                     {
39707                       Warning("Time must be the first dimension! Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
39708                       ncvars[ncvarid].isvar = FALSE;
39709                     }
39710                 }
39711             }
39712         }
39713 
39714       if (ncvars[ncvarid].natts == 0 && nvatts > 0)
39715         ncvars[ncvarid].atts = (int*) Malloc((size_t)nvatts*sizeof(int));
39716 
39717       for ( iatt = 0; iatt < nvatts; iatt++ )
39718         {
39719           int nc_cell_id = CDI_UNDEFID;
39720 
39721           cdf_inq_attname(ncid, ncvarid, iatt, attname);
39722           cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
39723           cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
39724 
39725           size_t attstringsize = sizeof(attstring);
39726           const bool isText = xtypeIsText(atttype);
39727           const bool isNumber = xtypeIsFloat(atttype) || xtypeIsInt(atttype);
39728           if (isText)
39729             {
39730               cdfGetAttText(ncid, ncvarid, attname, sizeof(attstring), attstring);
39731               attstringsize = strlen(attstring) + 1;
39732               if ( attstringsize > CDI_MAX_NAME ) attstringsize = CDI_MAX_NAME;
39733             }
39734 
39735           if ( isText && strIsEqual(attname, "long_name") )
39736             {
39737               memcpy(ncvars[ncvarid].longname, attstring, attstringsize);
39738             }
39739           else if ( isText && strIsEqual(attname, "standard_name") )
39740             {
39741               memcpy(ncvars[ncvarid].stdname, attstring, attstringsize);
39742             }
39743           else if ( isText && strIsEqual(attname, "units") )
39744             {
39745               memcpy(ncvars[ncvarid].units, attstring, attstringsize);
39746             }
39747           else if ( isText && strIsEqual(attname, "calendar") )
39748             {
39749               ncvars[ncvarid].calendar = true;
39750             }
39751           else if ( isText && strIsEqual(attname, "param") )
39752             {
39753 	      int pnum = 0, pcat = 255, pdis = 255;
39754 	      sscanf(attstring, "%d.%d.%d", &pnum, &pcat, &pdis);
39755 	      ncvars[ncvarid].param = cdiEncodeParam(pnum, pcat, pdis);
39756               cdf_set_var(ncvars, ncvarid, TRUE);
39757             }
39758           else if ( isNumber && strIsEqual(attname, "code") )
39759             {
39760               cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].code);
39761               cdf_set_var(ncvars, ncvarid, TRUE);
39762             }
39763           else if ( isNumber && strIsEqual(attname, "table") )
39764             {
39765               int tablenum;
39766               cdfGetAttInt(ncid, ncvarid, attname, 1, &tablenum);
39767               if ( tablenum > 0 )
39768                 {
39769                   ncvars[ncvarid].tabnum = tablenum;
39770                   ncvars[ncvarid].tableID = tableInq(modelID, tablenum, NULL);
39771                   if ( ncvars[ncvarid].tableID == CDI_UNDEFID )
39772                     ncvars[ncvarid].tableID = tableDef(modelID, tablenum, NULL);
39773                 }
39774               cdf_set_var(ncvars, ncvarid, TRUE);
39775             }
39776           else if ( isText && strIsEqual(attname, "trunc_type") )
39777             {
39778               if ( strIsEqual(attstring, "Triangular") )
39779                 ncvars[ncvarid].gridtype = GRID_SPECTRAL;
39780             }
39781           else if ( isText && (strIsEqual(attname, "grid_type") || strIsEqual(attname, "CDI_grid_type")) )
39782             {
39783               strToLower(attstring);
39784               cdf_set_gridtype(attstring, &ncvars[ncvarid].gridtype);
39785               cdf_set_var(ncvars, ncvarid, TRUE);
39786             }
39787           else if ( isText && strIsEqual(attname, "CDI_grid_latitudes") )
39788             {
39789               int nc_yvar_id;
39790               int status = nc_inq_varid(ncid, attstring, &nc_yvar_id);
39791               if ( status == NC_NOERR )
39792                 {
39793                   ncvars[ncvarid].yvarid = nc_yvar_id;
39794                   cdf_set_var(ncvars, ncvars[ncvarid].yvarid, FALSE);
39795                 }
39796               else
39797                 Warning("%s - %s", nc_strerror(status), attstring);
39798 
39799               cdf_set_var(ncvars, ncvarid, TRUE);
39800             }
39801           else if ( isText && strIsEqual(attname, "CDI_grid_reduced_points") )
39802             {
39803               int nc_rpvar_id;
39804               int status = nc_inq_varid(ncid, attstring, &nc_rpvar_id);
39805               if ( status == NC_NOERR )
39806                 {
39807                   ncvars[ncvarid].rpvarid = nc_rpvar_id;
39808                   cdf_set_var(ncvars, ncvars[ncvarid].rpvarid, FALSE);
39809                 }
39810               else
39811                 Warning("%s - %s", nc_strerror(status), attstring);
39812 
39813               cdf_set_var(ncvars, ncvarid, TRUE);
39814             }
39815           else if ( isNumber && strIsEqual(attname, "CDI_grid_num_LPE") )
39816             {
39817               cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].numLPE);
39818             }
39819           else if ( isText && strIsEqual(attname, "level_type") )
39820             {
39821               strToLower(attstring);
39822               cdf_set_zaxistype(attstring, &ncvars[ncvarid].zaxistype);
39823               cdf_set_var(ncvars, ncvarid, TRUE);
39824             }
39825           else if ( isNumber && strIsEqual(attname, "trunc_count") )
39826             {
39827               cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
39828             }
39829           else if ( isNumber && strIsEqual(attname, "truncation") )
39830             {
39831               cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
39832             }
39833           else if ( isNumber && strIsEqual(attname, "number_of_grid_in_reference") )
39834             {
39835               cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].position);
39836             }
39837           else if ( isNumber && strIsEqual(attname, "add_offset") )
39838             {
39839 	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].addoffset);
39840 	      /*
39841 		if ( atttype != NC_BYTE && atttype != NC_SHORT && atttype != NC_INT )
39842 		if ( ncvars[ncvarid].addoffset != 0 )
39843 		Warning("attribute add_offset not supported for atttype %d", atttype);
39844 	      */
39845 	      /* (also used for lon/lat) cdf_set_var(ncvars, ncvarid, TRUE); */
39846             }
39847           else if ( isNumber && strIsEqual(attname, "scale_factor") )
39848             {
39849 	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].scalefactor);
39850 	      /*
39851 		if ( atttype != NC_BYTE && atttype != NC_SHORT && atttype != NC_INT )
39852 		if ( ncvars[ncvarid].scalefactor != 1 )
39853 		Warning("attribute scale_factor not supported for atttype %d", atttype);
39854 	      */
39855 	      /* (also used for lon/lat) cdf_set_var(ncvars, ncvarid, TRUE); */
39856             }
39857           else if ( isText && strIsEqual(attname, "climatology") )
39858             {
39859               int ncboundsid;
39860               int status = nc_inq_varid(ncid, attstring, &ncboundsid);
39861               if ( status == NC_NOERR )
39862                 {
39863                   ncvars[ncvarid].climatology = true;
39864                   ncvars[ncvarid].bounds = ncboundsid;
39865                   cdf_set_var(ncvars, ncvars[ncvarid].bounds, FALSE);
39866                   cdf_set_var(ncvars, ncvarid, FALSE);
39867                 }
39868               else
39869                 Warning("%s - %s", nc_strerror(status), attstring);
39870             }
39871           else if ( isText && strIsEqual(attname, "bounds") )
39872             {
39873               int ncboundsid;
39874               int status = nc_inq_varid(ncid, attstring, &ncboundsid);
39875               if ( status == NC_NOERR )
39876                 {
39877                   ncvars[ncvarid].bounds = ncboundsid;
39878                   cdf_set_var(ncvars, ncvars[ncvarid].bounds, FALSE);
39879                   cdf_set_var(ncvars, ncvarid, FALSE);
39880                 }
39881               else
39882                 Warning("%s - %s", nc_strerror(status), attstring);
39883             }
39884           else if ( isText &&  strIsEqual(attname, "formula_terms") )
39885             {
39886               ncvars[ncvarid].lformulaterms = true;
39887             }
39888           else if ( isText && strIsEqual(attname, "cell_measures") && (nc_cell_id=cdf_get_cell_varid(attstring, ncid)) != CDI_UNDEFID )
39889             {
39890               ncvars[ncvarid].cellarea = nc_cell_id;
39891               ncvars[nc_cell_id].isvar = FALSE;
39892               cdf_set_var(ncvars, ncvarid, TRUE);
39893             }
39894           else if ( isText && (strIsEqual(attname, "associate") || strIsEqual(attname, "coordinates")) )
39895             {
39896               bool lstop = false;
39897               char *pstring = attstring;
39898 
39899               for ( int i = 0; i < MAX_COORDVARS; i++ )
39900                 {
39901                   while ( isspace((int) *pstring) ) pstring++;
39902                   if ( *pstring == 0 ) break;
39903                   char *varname = pstring;
39904                   while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
39905                   if ( *pstring == 0 ) lstop = true;
39906                   if ( *(pstring-1) == ',' ) *(pstring-1) = 0;
39907                   *pstring++ = 0;
39908 
39909                   int dimvarid;
39910                   int status = nc_inq_varid(ncid, varname, &dimvarid);
39911                   if ( status == NC_NOERR )
39912                     {
39913                       cdf_set_var(ncvars, dimvarid, FALSE);
39914                       if ( !CDI_Ignore_Att_Coordinates )
39915                         {
39916                           ncvars[ncvarid].coordvarids[i] = dimvarid;
39917                           ncvars[ncvarid].ncoordvars++;
39918                         }
39919                     }
39920                   else
39921                     {
39922                       if ( !CDI_Ignore_Att_Coordinates ) ncvars[ncvarid].ncoordvars++;
39923 
39924                       int k;
39925                       for ( k = 0; k < nchecked_vars; ++k )
39926                         if ( strIsEqual(checked_vars[k], varname) ) break;
39927 
39928                       if ( k == nchecked_vars )
39929                         {
39930                           if ( nchecked_vars < max_check_vars ) checked_vars[nchecked_vars++] = strdup(varname);
39931                           Warning("%s - >%s<", nc_strerror(status), varname);
39932                         }
39933                     }
39934 
39935                   if ( lstop ) break;
39936                 }
39937 
39938               cdf_set_var(ncvars, ncvarid, TRUE);
39939             }
39940           else if ( isText && strIsEqual(attname, "auxiliary_variable") )
39941             {
39942               bool lstop = false;
39943               char *pstring = attstring;
39944 
39945               for ( int i = 0; i < MAX_AUXVARS; i++ )
39946                 {
39947                   while ( isspace((int) *pstring) ) pstring++;
39948                   if ( *pstring == 0 ) break;
39949                   char *varname = pstring;
39950                   while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
39951                   if ( *pstring == 0 ) lstop = true;
39952                   *pstring++ = 0;
39953 
39954                   int dimvarid;
39955                   int status = nc_inq_varid(ncid, varname, &dimvarid);
39956                   if ( status == NC_NOERR )
39957                     {
39958                       cdf_set_var(ncvars, dimvarid, FALSE);
39959                       //  if ( !CDI_Ignore_Att_Coordinates )
39960                         {
39961                           ncvars[ncvarid].auxvarids[i] = dimvarid;
39962                           ncvars[ncvarid].nauxvars++;
39963                         }
39964                     }
39965                   else
39966                     Warning("%s - %s", nc_strerror(status), varname);
39967 
39968                   if ( lstop ) break;
39969                 }
39970 
39971               cdf_set_var(ncvars, ncvarid, TRUE);
39972             }
39973           else if ( isText && strIsEqual(attname, "grid_mapping") )
39974             {
39975               int nc_gmap_id;
39976               int status = nc_inq_varid(ncid, attstring, &nc_gmap_id);
39977               if ( status == NC_NOERR )
39978                 {
39979                   ncvars[ncvarid].gmapid = nc_gmap_id;
39980                   cdf_set_var(ncvars, ncvars[ncvarid].gmapid, FALSE);
39981                 }
39982               else
39983                 Warning("%s - %s", nc_strerror(status), attstring);
39984 
39985               cdf_set_var(ncvars, ncvarid, TRUE);
39986             }
39987           else if ( isText && strIsEqual(attname, "positive") )
39988             {
39989               strToLower(attstring);
39990 
39991               if      ( strIsEqual(attstring, "down") ) ncvars[ncvarid].positive = POSITIVE_DOWN;
39992               else if ( strIsEqual(attstring, "up")   ) ncvars[ncvarid].positive = POSITIVE_UP;
39993 
39994               if ( ncvars[ncvarid].ndims == 1 )
39995                 {
39996                   cdf_set_var(ncvars, ncvarid, FALSE);
39997                   cdf_set_dim(ncvars, ncvarid, 0, Z_AXIS);
39998                   ncdims[ncvars[ncvarid].dimids[0]].dimtype = Z_AXIS;
39999                 }
40000               else if ( ncvars[ncvarid].ndims == 0 )
40001                 {
40002                   cdf_set_var(ncvars, ncvarid, FALSE);
40003                   ncvars[ncvarid].islev = true;
40004                 }
40005               else
40006                 {
40007                   ncvars[ncvarid].atts[ncvars[ncvarid].natts++] = iatt;
40008                 }
40009             }
40010           else if ( isNumber && strIsEqual(attname, "_FillValue") )
40011             {
40012 	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].fillval);
40013 	      ncvars[ncvarid].deffillval = true;
40014 	      /* cdf_set_var(ncvars, ncvarid, TRUE); */
40015             }
40016           else if ( isNumber && strIsEqual(attname, "missing_value") )
40017             {
40018 	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].missval);
40019 	      ncvars[ncvarid].defmissval = true;
40020 	      /* cdf_set_var(ncvars, ncvarid, TRUE); */
40021             }
40022           else if ( isNumber && strIsEqual(attname, "valid_range") && attlen == 2 )
40023             {
40024               if ( ncvars[ncvarid].lvalidrange == false )
40025                 {
40026                   bool lignore = xtypeIsFloat(atttype) != xtypeIsFloat(xtype);
40027                   if ( !CDI_Ignore_Valid_Range && lignore == false )
40028                     {
40029                       cdfGetAttDouble(ncid, ncvarid, attname, 2, ncvars[ncvarid].validrange);
40030                       ncvars[ncvarid].lvalidrange = (ncvars[ncvarid].validrange[0] <= ncvars[ncvarid].validrange[1]);
40031                       if ( ((int)ncvars[ncvarid].validrange[0]) == 0 && ((int)ncvars[ncvarid].validrange[1]) == 255 )
40032                         ncvars[ncvarid].lunsigned = true;
40033                       /* cdf_set_var(ncvars, ncvarid, TRUE); */
40034                     }
40035                   else if ( lignore )
40036                     {
40037                       Warning("Inconsistent data type for attribute %s:valid_range, ignored!", name);
40038                     }
40039                 }
40040             }
40041           else if ( isNumber && strIsEqual(attname, "valid_min") && attlen == 1 )
40042             {
40043               bool lignore = xtypeIsFloat(atttype) != xtypeIsFloat(xtype);
40044               if ( !CDI_Ignore_Valid_Range && lignore == false )
40045                 {
40046                   cdfGetAttDouble(ncid, ncvarid, attname, 1, &(ncvars[ncvarid].validrange)[0]);
40047                   ncvars[ncvarid].lvalidrange = true;
40048                 }
40049               else if ( lignore )
40050                 {
40051                   Warning("Inconsistent data type for attribute %s:valid_min, ignored!", name);
40052                 }
40053             }
40054           else if ( isNumber && strIsEqual(attname, "valid_max") && attlen == 1 )
40055             {
40056               bool lignore = xtypeIsFloat(atttype) != xtypeIsFloat(xtype);
40057               if ( !CDI_Ignore_Valid_Range && lignore == false )
40058                 {
40059                   cdfGetAttDouble(ncid, ncvarid, attname, 1, &(ncvars[ncvarid].validrange)[1]);
40060                   ncvars[ncvarid].lvalidrange = true;
40061                 }
40062               else if ( lignore )
40063                 {
40064                   Warning("Inconsistent data type for attribute %s:valid_max, ignored!", name);
40065                 }
40066             }
40067           else if ( isText && strIsEqual(attname, "_Unsigned") )
40068             {
40069               strToLower(attstring);
40070               if ( strIsEqual(attstring, "true") )
40071                 {
40072                   ncvars[ncvarid].lunsigned = true;
40073                   /*
40074                   ncvars[ncvarid].lvalidrange = true;
40075                   ncvars[ncvarid].validrange[0] = 0;
40076                   ncvars[ncvarid].validrange[1] = 255;
40077                   */
40078                 }
40079 	      /* cdf_set_var(ncvars, ncvarid, TRUE); */
40080             }
40081           else if ( isText && strIsEqual(attname, "cdi") )
40082             {
40083 	      strToLower(attstring);
40084 
40085 	      if ( strIsEqual(attstring, "ignore") )
40086 		{
40087 		  ncvars[ncvarid].ignore = true;
40088 		  cdf_set_var(ncvars, ncvarid, FALSE);
40089 		}
40090             }
40091 	  else if ( isNumber &&
40092                     (strIsEqual(attname, "realization")       ||
40093                      strIsEqual(attname, "ensemble_members")  ||
40094                      strIsEqual(attname, "forecast_init_type")) )
40095 	    {
40096 	      int temp;
40097 	      cdfGetAttInt(ncid, ncvarid, attname, 1, &temp);
40098 
40099 	      if      ( strIsEqual(attname, "realization") )  ncvars[ncvarid].perturbationNumber = temp;
40100 	      else if ( strIsEqual(attname, "ensemble_members") ) ncvars[ncvarid].numberOfForecastsInEnsemble = temp;
40101 	      else if ( strIsEqual(attname, "forecast_init_type") ) ncvars[ncvarid].typeOfEnsembleForecast = temp;
40102 
40103 	      cdf_set_var(ncvars, ncvarid, TRUE);
40104 	    }
40105 	  else
40106 	    {
40107 	      ncvars[ncvarid].atts[ncvars[ncvarid].natts++] = iatt;
40108 	    }
40109 	}
40110     }
40111 
40112   for ( int i = 0; i < max_check_vars; ++i ) if ( checked_vars[i] ) Free(checked_vars[i]);
40113 }
40114 
40115 static
cdfVerifyVarAttr(int nvars,ncvar_t * ncvars,ncdim_t * ncdims)40116 void cdfVerifyVarAttr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims)
40117 {
40118   nc_type atttype;
40119   size_t attlen;
40120   char attname[CDI_MAX_NAME];
40121   char attstring[8192];
40122 
40123   for (int ncvarid = 0; ncvarid < nvars; ncvarid++)
40124     {
40125       const int ncid = ncvars[ncvarid].ncid;
40126       const int *dimidsp = ncvars[ncvarid].dimids;
40127       const int nvdims = ncvars[ncvarid].ndims;
40128       const int nvatts = ncvars[ncvarid].natts;
40129 
40130       for (int i = 0; i < nvatts; i++)
40131         {
40132           const int attnum = ncvars[ncvarid].atts[i];
40133           cdf_inq_attname(ncid, ncvarid, attnum, attname);
40134           cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
40135           cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
40136 
40137           size_t attstringsize = sizeof(attstring);
40138           const bool isText = xtypeIsText(atttype);
40139           // const bool isNumber = xtypeIsFloat(atttype) || xtypeIsInt(atttype);
40140 
40141           if (isText)
40142             {
40143               cdfGetAttText(ncid, ncvarid, attname, sizeof(attstring), attstring);
40144               attstringsize = strlen(attstring) + 1;
40145               if (attstringsize > CDI_MAX_NAME) attstringsize = CDI_MAX_NAME;
40146 
40147               if (strIsEqual(attname, "axis"))
40148                 {
40149                   cdfScanAttrAxis(ncvars, ncdims, ncvarid, strToLower(attstring), nvdims, dimidsp);
40150                 }
40151               /*
40152               else if (strIsEqual(attname, "standard_name"))
40153                 {
40154                   memcpy(ncvars[ncvarid].stdname, attstring, attstringsize);
40155                 }
40156               */
40157             }
40158         }
40159     }
40160 }
40161 
40162 
40163 static
cdf_set_dimtype(int nvars,ncvar_t * ncvars,ncdim_t * ncdims)40164 void cdf_set_dimtype(int nvars, ncvar_t *ncvars, ncdim_t *ncdims)
40165 {
40166   for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
40167     {
40168       if ( ncvars[ncvarid].isvar == TRUE )
40169 	{
40170 	  int ndims = ncvars[ncvarid].ndims;
40171 	  for ( int i = 0; i < ndims; i++ )
40172 	    {
40173 	      int ncdimid = ncvars[ncvarid].dimids[i];
40174               int dimtype = ncdims[ncdimid].dimtype;
40175 	      if ( dimtype >= X_AXIS && dimtype <= T_AXIS )
40176                 cdf_set_dim(ncvars, ncvarid, i, dimtype);
40177 	    }
40178 
40179 	  if ( CDI_Debug )
40180 	    {
40181 	      Message("var %d %s", ncvarid, ncvars[ncvarid].name);
40182 	      for ( int i = 0; i < ndims; i++ )
40183 		printf("  dim%d type=%d  ", i, ncvars[ncvarid].dimtype[i]);
40184 	      printf("\n");
40185 	    }
40186           }
40187       }
40188 
40189   for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
40190     {
40191       if ( ncvars[ncvarid].isvar == TRUE )
40192 	{
40193 	  bool lxdim = false, lydim = false, lzdim = false/* , ltdim = false */;
40194           int lcdim = 0;
40195 	  int ndims = ncvars[ncvarid].ndims;
40196 	  for ( int i = 0; i < ndims; i++ )
40197 	    {
40198               int dimtype = ncvars[ncvarid].dimtype[i];
40199               lxdim = lxdim | (dimtype == X_AXIS);
40200 	      lydim = lydim | (dimtype == Y_AXIS);
40201 	      lzdim = lzdim | (dimtype == Z_AXIS);
40202               if ( ncvars[ncvarid].cvarids[i] != CDI_UNDEFID ) lcdim++;
40203 	      /* else if ( ncvars[ncvarid].dimtype[i] == T_AXIS ) ltdim = true; */
40204 	    }
40205 
40206           int allcdims = lcdim;
40207 
40208           if ( !lxdim && ncvars[ncvarid].xvarid != CDI_UNDEFID )
40209             {
40210               if ( ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = true;
40211             }
40212 
40213           if ( !lydim && ncvars[ncvarid].yvarid != CDI_UNDEFID )
40214             {
40215               if ( ncvars[ncvars[ncvarid].yvarid].ndims == 0 ) lydim = true;
40216             }
40217 
40218           if ( lxdim && (lydim || ncvars[ncvarid].gridtype == GRID_UNSTRUCTURED) )
40219             for ( int i = ndims-1; i >= 0; i-- )
40220               {
40221                 if ( ncvars[ncvarid].dimtype[i] == -1 )
40222                   {
40223                     if ( !lzdim )
40224                       {
40225                         if ( lcdim )
40226                           {
40227                             int cdimvar = ncvars[ncvarid].cvarids[allcdims-lcdim];
40228                             ncvars[ncvarid].zvarid = cdimvar;
40229                             lcdim--;
40230 		            ncvars[cdimvar].zaxistype = ZAXIS_CHAR;
40231                           }
40232                         cdf_set_dim(ncvars, ncvarid, i, Z_AXIS);
40233                         lzdim = true;
40234                         int ncdimid = ncvars[ncvarid].dimids[i];
40235                         if ( ncdims[ncdimid].dimtype == CDI_UNDEFID )
40236                           ncdims[ncdimid].dimtype = Z_AXIS;
40237                       }
40238                   }
40239               }
40240 	}
40241     }
40242 
40243   for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
40244     {
40245       int ndims = ncvars[ncvarid].ndims;
40246       for ( int i = 0; i < ndims; i++ )
40247         {
40248           if ( ncvars[ncvarid].dimtype[i] == CDI_UNDEFID )
40249             {
40250               int ncdimid = ncvars[ncvarid].dimids[i];
40251               if ( ncdims[ncdimid].dimtype == Z_AXIS )
40252                 {
40253                   ncvars[ncvarid].islev = true;
40254                   cdf_set_dim(ncvars, ncvarid, i, Z_AXIS);
40255                 }
40256             }
40257         }
40258     }
40259 
40260   for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
40261     {
40262       if ( ncvars[ncvarid].isvar == TRUE )
40263 	{
40264 	  bool lxdim = false, lydim = false, lzdim = false/* , ltdim = false */;
40265           int lcdim = 0;
40266 	  int ndims = ncvars[ncvarid].ndims;
40267 	  for ( int i = 0; i < ndims; i++ )
40268 	    {
40269 	      if      ( ncvars[ncvarid].dimtype[i] == X_AXIS ) lxdim = true;
40270 	      else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) lydim = true;
40271 	      else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) lzdim = true;
40272               else if ( ncvars[ncvarid].cvarids[i] != CDI_UNDEFID ) lcdim++;
40273 	      /* else if ( ncvars[ncvarid].dimtype[i] == T_AXIS ) ltdim = true; */
40274 	    }
40275 
40276           int allcdims = lcdim;
40277 
40278           if ( !lxdim && ncvars[ncvarid].xvarid != CDI_UNDEFID )
40279             {
40280               if ( ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = true;
40281             }
40282 
40283           if ( !lydim && ncvars[ncvarid].yvarid != CDI_UNDEFID )
40284             {
40285               if ( ncvars[ncvars[ncvarid].yvarid].ndims == 0 ) lydim = true;
40286             }
40287 
40288           //   if ( ndims > 1 )
40289             for ( int i = ndims-1; i >= 0; i-- )
40290               {
40291                 if ( ncvars[ncvarid].dimtype[i] == -1 )
40292                   {
40293                     if ( !lxdim )
40294                       {
40295                         if ( lcdim && ncvars[ncvarid].xvarid == CDI_UNDEFID )
40296                           {
40297                             int cdimvar = ncvars[ncvarid].cvarids[allcdims-lcdim];
40298                             ncvars[ncvarid].xvarid = cdimvar;
40299                             lcdim--;
40300                           }
40301                         cdf_set_dim(ncvars, ncvarid, i, X_AXIS);
40302                         lxdim = true;
40303                       }
40304                     else if ( !lydim && ncvars[ncvarid].gridtype != GRID_UNSTRUCTURED )
40305                       {
40306                         if ( lcdim && ncvars[ncvarid].yvarid == CDI_UNDEFID )
40307                           {
40308                             int cdimvar = ncvars[ncvarid].cvarids[allcdims-lcdim];
40309                             ncvars[ncvarid].yvarid = cdimvar;
40310                             lcdim--;
40311                           }
40312                         cdf_set_dim(ncvars, ncvarid, i, Y_AXIS);
40313                         lydim = true;
40314                       }
40315                     else if ( !lzdim )
40316                       {
40317                         if ( lcdim > 0 )
40318                           {
40319                             int cdimvar = ncvars[ncvarid].cvarids[allcdims-lcdim];
40320                             ncvars[ncvarid].zvarid = cdimvar;
40321                             lcdim--;
40322 		            ncvars[cdimvar].zaxistype = ZAXIS_CHAR;
40323                           }
40324                         cdf_set_dim(ncvars, ncvarid, i, Z_AXIS);
40325                         lzdim = true;
40326                       }
40327                   }
40328               }
40329 	}
40330     }
40331 }
40332 
40333 /* verify coordinate vars - first scan (dimname == varname) */
40334 static
verify_coordinate_vars_1(int ncid,int ndims,ncdim_t * ncdims,ncvar_t * ncvars,int timedimid,bool * lhybrid_cf)40335 void verify_coordinate_vars_1(int ncid, int ndims, ncdim_t *ncdims, ncvar_t *ncvars, int timedimid, bool *lhybrid_cf)
40336 {
40337   for ( int ncdimid = 0; ncdimid < ndims; ncdimid++ )
40338     {
40339       int ncvarid = ncdims[ncdimid].ncvarid;
40340       if ( ncvarid != -1 )
40341 	{
40342 	  if ( ncvars[ncvarid].dimids[0] == timedimid )
40343 	    {
40344               ncvars[ncvarid].istime = true;
40345 	      ncdims[ncdimid].dimtype = T_AXIS;
40346 	      continue;
40347 	    }
40348 
40349           if ( isHybridSigmaPressureCoordinate(ncid, ncvarid, ncvars, ncdims) )
40350             {
40351               *lhybrid_cf = true;
40352               continue;
40353             }
40354 
40355 	  if ( ncvars[ncvarid].units[0] != 0 )
40356 	    {
40357 	      if ( is_lon_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
40358 		{
40359 		  ncvars[ncvarid].islon = true;
40360 		  cdf_set_var(ncvars, ncvarid, FALSE);
40361 		  cdf_set_dim(ncvars, ncvarid, 0, X_AXIS);
40362 		  ncdims[ncdimid].dimtype = X_AXIS;
40363 		}
40364 	      else if ( is_lat_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
40365 		{
40366 		  ncvars[ncvarid].islat = true;
40367 		  cdf_set_var(ncvars, ncvarid, FALSE);
40368 		  cdf_set_dim(ncvars, ncvarid, 0, Y_AXIS);
40369 		  ncdims[ncdimid].dimtype = Y_AXIS;
40370 		}
40371 	      else if ( is_x_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
40372 		{
40373 		  ncvars[ncvarid].isx = true;
40374 		  cdf_set_var(ncvars, ncvarid, FALSE);
40375 		  cdf_set_dim(ncvars, ncvarid, 0, X_AXIS);
40376 		  ncdims[ncdimid].dimtype = X_AXIS;
40377 		}
40378 	      else if ( is_y_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
40379 		{
40380 		  ncvars[ncvarid].isy = true;
40381 		  cdf_set_var(ncvars, ncvarid, FALSE);
40382 		  cdf_set_dim(ncvars, ncvarid, 0, Y_AXIS);
40383 		  ncdims[ncdimid].dimtype = Y_AXIS;
40384 		}
40385 	      else if ( is_pressure_units(ncvars[ncvarid].units) )
40386 		{
40387 		  ncvars[ncvarid].zaxistype = ZAXIS_PRESSURE;
40388 		}
40389 	      else if ( strcmp(ncvars[ncvarid].units, "level") == 0 || strcmp(ncvars[ncvarid].units, "1") == 0 )
40390 		{
40391 		  if      ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer midpoints") == 0 )
40392 		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
40393 		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at midpoints", 25) == 0 )
40394 		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
40395 		  else if ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer interfaces") == 0 )
40396 		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
40397 		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at interfaces", 26) == 0 )
40398 		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
40399 		  else if ( strcmp(ncvars[ncvarid].units, "level") == 0 )
40400 		    ncvars[ncvarid].zaxistype = ZAXIS_GENERIC;
40401 		}
40402 	      else if ( is_DBL_axis(ncvars[ncvarid].longname) )
40403                 {
40404                   ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_LAND;
40405 		}
40406 	      else if ( is_height_units(ncvars[ncvarid].units) )
40407 		{
40408 		  if ( is_depth_axis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
40409 		    ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_SEA;
40410 		  else if ( is_height_axis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
40411 		    ncvars[ncvarid].zaxistype = ZAXIS_HEIGHT;
40412 		  else if ( is_altitude_axis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
40413 		    ncvars[ncvarid].zaxistype = ZAXIS_ALTITUDE;
40414 		}
40415 	    }
40416           else
40417             {
40418               if ( (strcmp(ncvars[ncvarid].longname, "generalized_height") == 0 ||
40419                     strcmp(ncvars[ncvarid].longname, "generalized height") == 0) &&
40420                    strcmp(ncvars[ncvarid].stdname, "height") == 0 )
40421                   ncvars[ncvarid].zaxistype = ZAXIS_REFERENCE;
40422               else if ( strIsEqual(ncvars[ncvarid].stdname, "air_pressure") )
40423 		  ncvars[ncvarid].zaxistype = ZAXIS_PRESSURE;
40424             }
40425 
40426 	  if ( !ncvars[ncvarid].islon && ncvars[ncvarid].longname[0] != 0 &&
40427                !ncvars[ncvarid].islat && ncvars[ncvarid].longname[1] != 0 )
40428 	    {
40429 	      if ( strStartsWith(ncvars[ncvarid].longname+1, "ongitude") )
40430 		{
40431 		  ncvars[ncvarid].islon = true;
40432 		  cdf_set_var(ncvars, ncvarid, FALSE);
40433 		  cdf_set_dim(ncvars, ncvarid, 0, X_AXIS);
40434 		  ncdims[ncdimid].dimtype = X_AXIS;
40435 		  continue;
40436 		}
40437 	      else if ( strStartsWith(ncvars[ncvarid].longname+1, "atitude") )
40438 		{
40439 		  ncvars[ncvarid].islat = true;
40440 		  cdf_set_var(ncvars, ncvarid, FALSE);
40441 		  cdf_set_dim(ncvars, ncvarid, 0, Y_AXIS);
40442 		  ncdims[ncdimid].dimtype = Y_AXIS;
40443 		  continue;
40444 		}
40445 	    }
40446 
40447 	  if ( ncvars[ncvarid].zaxistype != CDI_UNDEFID )
40448 	    {
40449               ncvars[ncvarid].islev = true;
40450 	      cdf_set_var(ncvars, ncvarid, FALSE);
40451 	      cdf_set_dim(ncvars, ncvarid, 0, Z_AXIS);
40452 	      ncdims[ncdimid].dimtype = Z_AXIS;
40453 	    }
40454 	}
40455     }
40456 }
40457 
40458 /* verify coordinate vars - second scan (all other variables) */
40459 static
verify_coordinate_vars_2(stream_t * streamptr,int nvars,ncvar_t * ncvars)40460 void verify_coordinate_vars_2(stream_t *streamptr, int nvars, ncvar_t *ncvars)
40461 {
40462   for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
40463     {
40464       if ( ncvars[ncvarid].isvar == 0 )
40465 	{
40466 	  if ( ncvars[ncvarid].units[0] != 0 )
40467 	    {
40468 	      if ( is_lon_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
40469 		{
40470 		  ncvars[ncvarid].islon = true;
40471 		  continue;
40472 		}
40473 	      else if ( is_lat_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
40474 		{
40475 		  ncvars[ncvarid].islat = true;
40476 		  continue;
40477 		}
40478 	      else if ( is_x_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
40479 		{
40480 		  ncvars[ncvarid].isx = true;
40481 		  continue;
40482 		}
40483 	      else if ( is_y_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
40484 		{
40485 		  ncvars[ncvarid].isy = true;
40486 		  continue;
40487 		}
40488 	      else if ( ncvars[ncvarid].zaxistype == CDI_UNDEFID &&
40489                         (strcmp(ncvars[ncvarid].units, "level") == 0 || strcmp(ncvars[ncvarid].units, "1") == 0) )
40490 		{
40491 		  if      ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer midpoints") == 0 )
40492 		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
40493 		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at midpoints", 25) == 0 )
40494 		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
40495 		  else if ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer interfaces") == 0 )
40496 		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
40497 		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at interfaces", 26) == 0 )
40498 		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
40499 		  else if ( strcmp(ncvars[ncvarid].units, "level") == 0 )
40500 		    ncvars[ncvarid].zaxistype = ZAXIS_GENERIC;
40501 		  continue;
40502 		}
40503 	      else if ( ncvars[ncvarid].zaxistype == CDI_UNDEFID && is_pressure_units(ncvars[ncvarid].units) )
40504 		{
40505 		  ncvars[ncvarid].zaxistype = ZAXIS_PRESSURE;
40506 		  continue;
40507 		}
40508 	      else if ( is_DBL_axis(ncvars[ncvarid].longname) )
40509 		{
40510                   ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_LAND;
40511 		  continue;
40512 		}
40513 	      else if ( is_height_units(ncvars[ncvarid].units) )
40514 		{
40515 		  if ( is_depth_axis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
40516 		    ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_SEA;
40517 		  else if ( is_height_axis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
40518 		    ncvars[ncvarid].zaxistype = ZAXIS_HEIGHT;
40519 		  continue;
40520 		}
40521             }
40522           else if ( strcmp(ncvars[ncvarid].stdname, "region") == 0  ||
40523                     strcmp(ncvars[ncvarid].stdname, "area_type") == 0 ||
40524                     cdfInqDatatype(streamptr, ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned) == CDI_DATATYPE_UINT8 )
40525             {
40526               ncvars[ncvarid].isc = true;
40527             }
40528           else if ( strIsEqual(ncvars[ncvarid].stdname, "air_pressure") )
40529 	    ncvars[ncvarid].zaxistype = ZAXIS_PRESSURE;
40530 
40531 	  /* not needed anymore for rotated grids */
40532 	  if ( !ncvars[ncvarid].islon && ncvars[ncvarid].longname[0] != 0 &&
40533                !ncvars[ncvarid].islat && ncvars[ncvarid].longname[1] != 0 )
40534 	    {
40535 	      if ( strStartsWith(ncvars[ncvarid].longname+1, "ongitude") )
40536 		{
40537 		  ncvars[ncvarid].islon = true;
40538 		  continue;
40539 		}
40540 	      else if ( strStartsWith(ncvars[ncvarid].longname+1, "atitude") )
40541 		{
40542 		  ncvars[ncvarid].islat = true;
40543 		  continue;
40544 		}
40545 	    }
40546 	}
40547     }
40548 }
40549 
40550 static
grid_set_chunktype(grid_t * grid,ncvar_t * ncvar)40551 void grid_set_chunktype(grid_t *grid, ncvar_t *ncvar)
40552 {
40553   if ( ncvar->chunked )
40554     {
40555       int ndims = ncvar->ndims;
40556 
40557       if ( grid->type == GRID_UNSTRUCTURED )
40558         {
40559           ncvar->chunktype = ncvar->chunks[ndims-1] == grid->size
40560             ? CDI_CHUNK_GRID : CDI_CHUNK_AUTO;
40561         }
40562       else
40563         {
40564           if ( grid->x.size > 1 && grid->y.size > 1 && ndims > 1 &&
40565                grid->x.size == ncvar->chunks[ndims-1] &&
40566                grid->y.size == ncvar->chunks[ndims-2] )
40567             ncvar->chunktype = CDI_CHUNK_GRID;
40568           else if ( grid->x.size > 1 && grid->x.size == ncvar->chunks[ndims-1] )
40569             ncvar->chunktype = CDI_CHUNK_LINES;
40570           else
40571             ncvar->chunktype = CDI_CHUNK_AUTO;
40572         }
40573     }
40574 }
40575 
40576 /* define all input grids */
40577 static
cdf_load_vals(size_t size,int ndims,int varid,ncvar_t * ncvar,double ** gridvals,struct xyValGet * valsGet,int ntdims,size_t * start,size_t * count)40578 void cdf_load_vals(size_t size, int ndims, int varid, ncvar_t *ncvar, double **gridvals, struct xyValGet *valsGet,
40579                    int ntdims, size_t *start, size_t *count)
40580 {
40581   if ( CDI_Netcdf_Lazy_Grid_Load )
40582     {
40583       *valsGet = (struct xyValGet){
40584         .scalefactor = ncvar->scalefactor,
40585         .addoffset = ncvar->addoffset,
40586         .start = { start[0], start[1], start[2] },
40587         .count = { count[0], count[1], count[2] },
40588         .size = size,
40589         .datasetNCId = ncvar->ncid,
40590         .varNCId = varid,
40591         .ndims = (short)ndims,
40592       };
40593       *gridvals = cdfPendingLoad;
40594     }
40595   else
40596     {
40597       *gridvals = (double*) Malloc(size*sizeof(double));
40598       if ( ntdims == 1 )
40599         cdf_get_vara_double(ncvar->ncid, varid, start, count, *gridvals);
40600       else
40601         cdf_get_var_double(ncvar->ncid, varid, *gridvals);
40602       cdf_scale_add(size, *gridvals, ncvar->addoffset, ncvar->scalefactor);
40603     }
40604 }
40605 
40606 #ifndef USE_MPI
40607 static
cdf_load_cvals(size_t size,int varid,ncvar_t * ncvar,char *** gridvals,size_t dimlength)40608 void cdf_load_cvals(size_t size, int varid, ncvar_t *ncvar, char ***gridvals, size_t dimlength)
40609 {
40610   size_t startc[] = {0, 0};
40611   size_t countc[] = {1, size/dimlength};
40612   *gridvals = (char **) Malloc(dimlength * sizeof(char *));
40613   for ( size_t i = 0; i < dimlength; i++ )
40614     {
40615       (*gridvals)[i] = (char*) Malloc((size/dimlength) * sizeof(char));
40616       cdf_get_vara_text(ncvar->ncid, varid, startc, countc, (*gridvals)[i]);
40617       startc[0] = i+1;
40618     }
40619 }
40620 #endif
40621 
40622 static
cdf_load_bounds(size_t size,ncvar_t * ncvar,double ** gridbounds,struct cdfLazyGridIds * cellBoundsGet)40623 void cdf_load_bounds(size_t size, ncvar_t *ncvar, double **gridbounds, struct cdfLazyGridIds *cellBoundsGet)
40624 {
40625   if ( CDI_Netcdf_Lazy_Grid_Load )
40626     {
40627       cellBoundsGet->datasetNCId = ncvar->ncid;
40628       cellBoundsGet->varNCId  = ncvar->bounds;
40629       *gridbounds = cdfPendingLoad;
40630     }
40631   else
40632     {
40633       *gridbounds = (double*) Malloc(size*sizeof(double));
40634       cdf_get_var_double(ncvar->ncid, ncvar->bounds, *gridbounds);
40635     }
40636 }
40637 
40638 static
cdf_load_cellarea(size_t size,ncvar_t * ncvar,double ** gridarea,struct cdfLazyGridIds * cellAreaGet)40639 void cdf_load_cellarea(size_t size, ncvar_t *ncvar, double **gridarea, struct cdfLazyGridIds *cellAreaGet)
40640 {
40641   if ( CDI_Netcdf_Lazy_Grid_Load )
40642     {
40643       cellAreaGet->datasetNCId = ncvar->ncid;
40644       cellAreaGet->varNCId = ncvar->cellarea;
40645       *gridarea = cdfPendingLoad;
40646     }
40647   else
40648     {
40649       *gridarea = (double*) Malloc(size*sizeof(double));
40650       cdf_get_var_double(ncvar->ncid, ncvar->cellarea, *gridarea);
40651     }
40652 }
40653 
40654 static
cdf_copy_grid_axis_attr(ncvar_t * ncvar,struct gridaxis_t * gridaxis)40655 void cdf_copy_grid_axis_attr(ncvar_t *ncvar, struct gridaxis_t *gridaxis)
40656 {
40657   cdiDefVarKeyBytes(&gridaxis->keys, CDI_KEY_NAME, (const unsigned char*)ncvar->name, (int)strlen(ncvar->name)+1);
40658   if (ncvar->longname[0])
40659     cdiDefVarKeyBytes(&gridaxis->keys, CDI_KEY_LONGNAME, (const unsigned char*)ncvar->longname, (int)strlen(ncvar->longname)+1);
40660   if (ncvar->units[0])
40661     cdiDefVarKeyBytes(&gridaxis->keys, CDI_KEY_UNITS, (const unsigned char*)ncvar->units, (int)strlen(ncvar->units)+1);
40662 #ifndef USE_MPI
40663   if ( gridaxis->cvals )
40664     if (ncvar->stdname[0])
40665       cdiDefVarKeyBytes(&gridaxis->keys, CDI_KEY_STDNAME, (const unsigned  char*)ncvar->stdname, (int)strlen(ncvar->stdname)+1);
40666 #endif
40667 }
40668 
40669 static
cdf_get_xydimid(int ndims,int * dimids,int * dimtype,int * xdimid,int * ydimid)40670 int cdf_get_xydimid(int ndims, int *dimids, int *dimtype, int *xdimid, int *ydimid)
40671 {
40672   int nxdims = 0, nydims = 0;
40673   int xdimids[2] = {-1,-1}, ydimids[2] = {-1,-1};
40674 
40675   for ( int i = 0; i < ndims; i++ )
40676     {
40677       if ( dimtype[i] == X_AXIS && nxdims < 2 )
40678         {
40679           xdimids[nxdims] = dimids[i];
40680           nxdims++;
40681         }
40682       else if ( dimtype[i] == Y_AXIS && nydims < 2 )
40683         {
40684           ydimids[nydims] = dimids[i];
40685           nydims++;
40686         }
40687     }
40688 
40689   if ( nxdims == 2 )
40690     {
40691       *xdimid = xdimids[1];
40692       *ydimid = xdimids[0];
40693     }
40694   else if ( nydims == 2 )
40695     {
40696       *xdimid = ydimids[1];
40697       *ydimid = ydimids[0];
40698     }
40699   else
40700     {
40701       *xdimid = xdimids[0];
40702       *ydimid = ydimids[0];
40703     }
40704 
40705   return nydims;
40706 }
40707 
40708 static
cdf_check_gridtype(int * gridtype,bool islon,bool islat,size_t xsize,size_t ysize,grid_t * grid)40709 void cdf_check_gridtype(int *gridtype, bool islon, bool islat, size_t xsize, size_t ysize, grid_t *grid)
40710 {
40711   if ( islat && (islon || xsize == 0) )
40712     {
40713       double yinc = 0;
40714       if ( islon && ysize > 1 )
40715         {
40716           yinc = fabs(grid->y.vals[0] - grid->y.vals[1]);
40717           for ( size_t i = 2; i < ysize; i++ )
40718             if ( (fabs(grid->y.vals[i-1] - grid->y.vals[i]) - yinc) > (yinc/1000) )
40719               {
40720                 yinc = 0;
40721                 break;
40722               }
40723         }
40724       if ( ysize < 10000 && isGaussGrid(ysize, yinc, grid->y.vals) )
40725         {
40726           *gridtype = GRID_GAUSSIAN;
40727           grid->np = (int)(ysize/2);
40728         }
40729       else
40730         *gridtype = GRID_LONLAT;
40731     }
40732   else if ( islon && !islat && ysize == 0 )
40733     {
40734       *gridtype = GRID_LONLAT;
40735     }
40736   else
40737     *gridtype = GRID_GENERIC;
40738 }
40739 
40740 static
cdf_read_xcoord(stream_t * streamptr,struct cdfLazyGrid * restrict lazyGrid,ncdim_t * ncdims,ncvar_t * ncvar,int xvarid,ncvar_t * axisvar,size_t * xsize,size_t ysize,int ntdims,size_t * start,size_t * count,bool * islon)40741 bool cdf_read_xcoord(stream_t *streamptr, struct cdfLazyGrid *restrict lazyGrid, ncdim_t *ncdims, ncvar_t *ncvar, int xvarid, ncvar_t *axisvar,
40742                      size_t *xsize, size_t ysize, int ntdims, size_t *start, size_t *count, bool *islon)
40743 {
40744   grid_t *grid = &lazyGrid->base;
40745   bool skipvar = true;
40746   *islon = axisvar->islon;
40747   int ndims = axisvar->ndims;
40748   size_t size = 0;
40749   const int datatype = cdfInqDatatype(streamptr, axisvar->xtype, axisvar->lunsigned);
40750 
40751   if ( (ndims - ntdims) == 2 )
40752     {
40753       /* Check size of 2 dimensional coordinate variables */
40754       int dimid = axisvar->dimids[ndims-2];
40755       const size_t dimsize1 = ncdims[dimid].len;
40756       dimid = axisvar->dimids[ndims-1];
40757       const size_t dimsize2 = ncdims[dimid].len;
40758 
40759       if ( datatype == CDI_DATATYPE_UINT8 )
40760         {
40761           ncvar->gridtype = GRID_CHARXY;
40762           size = dimsize1*dimsize2;
40763           skipvar = dimsize1 != *xsize;
40764         }
40765       else
40766         {
40767           ncvar->gridtype = GRID_CURVILINEAR;
40768           size = (*xsize)*ysize;
40769           skipvar = dimsize1*dimsize2 != size;
40770         }
40771     }
40772   else if ( (ndims - ntdims) == 1 )
40773     {
40774       size = *xsize;
40775       /* Check size of 1 dimensional coordinate variables */
40776       const int dimid = axisvar->dimids[ndims-1];
40777       const size_t dimsize = ncdims[dimid].len;
40778       skipvar = dimsize != size;
40779     }
40780   else if ( ndims == 0 && *xsize == 0 )
40781     {
40782       size = *xsize = 1;
40783       skipvar = false;
40784     }
40785 
40786   if ( skipvar )
40787     {
40788       Warning("Unsupported array structure, skipped variable %s!", ncvar->name);
40789       ncvar->isvar = -1;
40790       return true;
40791     }
40792 
40793   if ( datatype != -1 )  grid->datatype = datatype;
40794 
40795   if ( datatype == CDI_DATATYPE_UINT8 && !CDI_Netcdf_Lazy_Grid_Load )
40796     {
40797 #ifndef USE_MPI
40798       cdf_load_cvals(size, xvarid, axisvar, &grid->x.cvals, *xsize);
40799       grid->x.clength = size / (*xsize) ;
40800 #endif
40801     }
40802   else
40803     cdf_load_vals(size, ndims, xvarid, axisvar, &grid->x.vals, &lazyGrid->xValsGet, ntdims, start, count);
40804 
40805   cdf_copy_grid_axis_attr(axisvar, &grid->x);
40806 
40807   return false;
40808 }
40809 
40810 static
cdf_read_ycoord(stream_t * streamptr,struct cdfLazyGrid * restrict lazyGrid,ncdim_t * ncdims,ncvar_t * ncvar,int yvarid,ncvar_t * axisvar,size_t xsize,size_t * ysize,int ntdims,size_t * start,size_t * count,bool * islat)40811 bool cdf_read_ycoord(stream_t *streamptr, struct cdfLazyGrid *restrict lazyGrid, ncdim_t *ncdims, ncvar_t *ncvar, int yvarid, ncvar_t *axisvar,
40812                      size_t xsize, size_t *ysize, int ntdims, size_t *start, size_t *count, bool *islat)
40813 {
40814   grid_t *grid = &lazyGrid->base;
40815   bool skipvar = true;
40816   *islat = axisvar->islat;
40817   int ndims = axisvar->ndims;
40818   size_t size = 0;
40819   const int datatype = cdfInqDatatype(streamptr, axisvar->xtype, axisvar->lunsigned);
40820 
40821   if ( (ndims - ntdims) == 2 )
40822     {
40823       /* Check size of 2 dimensional coordinate variables */
40824       int dimid = axisvar->dimids[ndims-2];
40825       const size_t dimsize1 = ncdims[dimid].len;
40826       dimid = axisvar->dimids[ndims-1];
40827       const size_t dimsize2 = ncdims[dimid].len;
40828 
40829       if ( datatype == CDI_DATATYPE_UINT8 )
40830         {
40831           ncvar->gridtype = GRID_CHARXY;
40832           size = dimsize1*dimsize2;
40833           skipvar = dimsize1 != *ysize;
40834         }
40835       else
40836         {
40837           ncvar->gridtype = GRID_CURVILINEAR;
40838           size = xsize*(*ysize);
40839           skipvar = dimsize1*dimsize2 != size;
40840         }
40841     }
40842   else if ( (ndims - ntdims) == 1 )
40843     {
40844       if ( *ysize == 0 ) size = xsize;
40845       else               size = *ysize;
40846 
40847       const int dimid = axisvar->dimids[ndims-1];
40848       const size_t dimsize = ncdims[dimid].len;
40849       skipvar = dimsize != size;
40850     }
40851   else if ( ndims == 0 && *ysize == 0 )
40852     {
40853       size = *ysize = 1;
40854       skipvar = false;
40855     }
40856 
40857   if ( skipvar )
40858     {
40859       Warning("Unsupported array structure, skipped variable %s!", ncvar->name);
40860       ncvar->isvar = -1;
40861       return true;
40862     }
40863 
40864   if ( datatype != -1 )  grid->datatype = datatype;
40865 
40866   if ( datatype == CDI_DATATYPE_UINT8 && !CDI_Netcdf_Lazy_Grid_Load )
40867     {
40868 #ifndef USE_MPI
40869       cdf_load_cvals(size, yvarid, axisvar, &grid->y.cvals, *ysize);
40870       grid->y.clength = size / (*ysize) ;
40871 #endif
40872     }
40873   else
40874     cdf_load_vals(size, ndims, yvarid, axisvar, &grid->y.vals, &lazyGrid->yValsGet, ntdims, start, count);
40875 
40876   cdf_copy_grid_axis_attr(axisvar, &grid->y);
40877 
40878   return false;
40879 }
40880 
40881 static
cdf_read_coordinates(stream_t * streamptr,struct cdfLazyGrid * restrict lazyGrid,ncvar_t * ncvar,ncvar_t * ncvars,ncdim_t * ncdims,int timedimid,int xvarid,int yvarid,size_t xsize,size_t ysize,int * vdimid)40882 bool cdf_read_coordinates(stream_t *streamptr, struct cdfLazyGrid *restrict lazyGrid, ncvar_t *ncvar, ncvar_t *ncvars, ncdim_t *ncdims,
40883                           int timedimid, int xvarid, int yvarid, size_t xsize, size_t ysize, int *vdimid)
40884 {
40885   grid_t *grid = &lazyGrid->base;
40886   size_t size = 0;
40887 
40888   grid->datatype = CDI_DATATYPE_FLT64;
40889 
40890   if ( ncvar->gridtype == GRID_TRAJECTORY )
40891     {
40892       if ( ncvar->xvarid == CDI_UNDEFID ) Error("Longitude coordinate undefined for %s!", ncvar->name);
40893       if ( ncvar->yvarid == CDI_UNDEFID ) Error("Latitude coordinate undefined for %s!", ncvar->name);
40894     }
40895   else
40896     {
40897       size_t start[3], count[3];
40898       int ntdims = 0;
40899 
40900       if ( xvarid != CDI_UNDEFID && yvarid != CDI_UNDEFID )
40901         {
40902           const int ndims = ncvars[xvarid].ndims;
40903           if ( ndims != ncvars[yvarid].ndims && !ncvars[xvarid].isc && !ncvars[yvarid].isc )
40904             {
40905               Warning("Inconsistent grid structure for variable %s!", ncvar->name);
40906               ncvar->xvarid = xvarid = CDI_UNDEFID;
40907               ncvar->yvarid = yvarid = CDI_UNDEFID;
40908             }
40909           if ( ndims > 1 )
40910             {
40911               if ( ndims <= 3 )
40912                 {
40913                   if ( ncvars[xvarid].dimids[0] == timedimid && ncvars[yvarid].dimids[0] == timedimid )
40914                     {
40915                       static bool ltwarn = true;
40916                       size_t ntsteps = 0;
40917                       cdf_inq_dimlen(ncvar->ncid, ncdims[timedimid].dimid, &ntsteps);
40918                       if ( ltwarn && ntsteps > 1 ) Warning("Time varying grids unsupported, using grid at time step 1!");
40919                       ltwarn = false;
40920                       ntdims = 1;
40921                       start[0] = start[1] = start[2] = 0;
40922                       count[0] = 1; count[1] = ysize; count[ndims-1] = xsize;
40923                     }
40924                 }
40925               else
40926                 {
40927                   Warning("Unsupported grid structure for variable %s (grid dims > 2)!", ncvar->name);
40928                   ncvar->xvarid = xvarid = CDI_UNDEFID;
40929                   ncvar->yvarid = yvarid = CDI_UNDEFID;
40930                 }
40931             }
40932         }
40933 
40934       if ( xvarid != CDI_UNDEFID )
40935         {
40936           if ( (ncvars[xvarid].ndims - ntdims) > 2 )
40937             {
40938               Warning("Coordinate variable %s has to many dimensions (%d), skipped!", ncvars[xvarid].name, ncvars[xvarid].ndims);
40939               //ncvar->xvarid = CDI_UNDEFID;
40940               xvarid = CDI_UNDEFID;
40941             }
40942         }
40943 
40944       if ( yvarid != CDI_UNDEFID )
40945         {
40946           if ( (ncvars[yvarid].ndims - ntdims) > 2 )
40947             {
40948               Warning("Coordinate variable %s has to many dimensions (%d), skipped!", ncvars[yvarid].name, ncvars[yvarid].ndims);
40949               //ncvar->yvarid = CDI_UNDEFID;
40950               yvarid = CDI_UNDEFID;
40951             }
40952         }
40953 
40954       bool islon = false, islat = false;
40955 
40956       if ( xvarid != CDI_UNDEFID )
40957         if ( cdf_read_xcoord(streamptr, lazyGrid, ncdims, ncvar, xvarid, &ncvars[xvarid],
40958                              &xsize, ysize, ntdims, start, count, &islon) )
40959           return true;
40960 
40961       if ( yvarid != CDI_UNDEFID )
40962         if ( cdf_read_ycoord(streamptr, lazyGrid, ncdims, ncvar, yvarid, &ncvars[yvarid],
40963                              xsize, &ysize, ntdims, start, count, &islat) )
40964           return true;
40965 
40966       if      ( ncvar->gridtype == GRID_UNSTRUCTURED ) size = xsize;
40967       else if ( ncvar->gridtype == GRID_GAUSSIAN_REDUCED ) size = xsize;
40968       else if ( ysize == 0 ) size = xsize;
40969       else if ( xsize == 0 ) size = ysize;
40970       else                   size = xsize*ysize;
40971 
40972       if ( ncvar->gridtype == CDI_UNDEFID || ncvar->gridtype == GRID_GENERIC )
40973         cdf_check_gridtype(&ncvar->gridtype, islon, islat, xsize, ysize, grid);
40974     }
40975 
40976   int gridtype = grid->type;
40977   if ( gridtype != GRID_PROJECTION ) gridtype = ncvar->gridtype;
40978   else if ( gridtype == GRID_PROJECTION && ncvar->gridtype == GRID_LONLAT )
40979     {
40980       const int gmapvarid = ncvar->gmapid;
40981       if ( gmapvarid != CDI_UNDEFID && cdfCheckAttText(ncvar->ncid, gmapvarid, "grid_mapping_name") )
40982         {
40983           char attstring[CDI_MAX_NAME];
40984           cdfGetAttText(ncvar->ncid, gmapvarid, "grid_mapping_name", CDI_MAX_NAME, attstring);
40985           if ( strIsEqual(attstring, "latitude_longitude") ) gridtype = ncvar->gridtype;
40986         }
40987     }
40988 
40989   switch (gridtype)
40990     {
40991     case GRID_GENERIC:
40992     case GRID_LONLAT:
40993     case GRID_GAUSSIAN:
40994     case GRID_UNSTRUCTURED:
40995     case GRID_CURVILINEAR:
40996     case GRID_PROJECTION:
40997       {
40998         grid->size  = size;
40999         grid->x.size = xsize;
41000         grid->y.size = ysize;
41001         if ( xvarid != CDI_UNDEFID && CDI_Read_Cell_Corners )
41002           {
41003             grid->x.flag = 1;
41004             int bvarid = ncvars[xvarid].bounds;
41005             if ( bvarid != CDI_UNDEFID )
41006               {
41007                 int nbdims = ncvars[bvarid].ndims;
41008                 if ( nbdims == 2 || nbdims == 3 )
41009                   {
41010                     *vdimid = ncvars[bvarid].dimids[nbdims-1];
41011                     grid->nvertex = (int)ncdims[*vdimid].len;
41012                     cdf_load_bounds(size*(size_t)grid->nvertex, &ncvars[xvarid], &grid->x.bounds, &lazyGrid->xBoundsGet);
41013                   }
41014               }
41015           }
41016         if ( yvarid != CDI_UNDEFID && CDI_Read_Cell_Corners )
41017           {
41018             grid->y.flag = 1;
41019             int bvarid = ncvars[yvarid].bounds;
41020             if ( bvarid != CDI_UNDEFID )
41021               {
41022                 int nbdims = ncvars[bvarid].ndims;
41023                 if ( nbdims == 2 || nbdims == 3 )
41024                   {
41025                     if ( *vdimid == CDI_UNDEFID )
41026                       {
41027                         *vdimid = ncvars[bvarid].dimids[nbdims-1];
41028                         grid->nvertex = (int)ncdims[*vdimid].len;
41029                       }
41030                     cdf_load_bounds(size*(size_t)grid->nvertex, &ncvars[yvarid], &grid->y.bounds, &lazyGrid->yBoundsGet);
41031                   }
41032               }
41033           }
41034 
41035         if ( ncvar->cellarea != CDI_UNDEFID )
41036           cdf_load_cellarea(size, ncvar, &grid->area, &lazyGrid->cellAreaGet);
41037 
41038         if (gridtype == GRID_GAUSSIAN)
41039           {
41040             if (ncvar->numLPE > 0) grid->np = ncvar->numLPE;
41041           }
41042 
41043         break;
41044       }
41045     case GRID_GAUSSIAN_REDUCED:
41046       {
41047         if (ncvar->numLPE > 0 && ncvar->rpvarid != CDI_UNDEFID)
41048           {
41049             if (ncvars[ncvar->rpvarid].ndims == 1)
41050               {
41051                 grid->size = size;
41052                 int dimid = ncvars[ncvar->rpvarid].dimids[0];
41053                 size_t len = ncdims[dimid].len;
41054                 grid->y.size = len;
41055                 grid->reducedPointsSize = len;
41056                 grid->reducedPoints = (int*) Malloc(len*sizeof(int));
41057                 cdf_get_var_int(ncvar->ncid, ncvar->rpvarid, grid->reducedPoints);
41058                 grid->np = ncvar->numLPE;
41059 
41060                 int bvarid = ncvars[yvarid].bounds;
41061                 if ( bvarid != CDI_UNDEFID )
41062                   {
41063                     int nbdims = ncvars[bvarid].ndims;
41064                     if ( nbdims == 2 || nbdims == 3 )
41065                       {
41066                         if ( *vdimid == CDI_UNDEFID )
41067                           {
41068                             *vdimid = ncvars[bvarid].dimids[nbdims-1];
41069                             grid->nvertex = (int)ncdims[*vdimid].len;
41070                           }
41071                         cdf_load_bounds(size*(size_t)grid->nvertex, &ncvars[yvarid], &grid->y.bounds, &lazyGrid->yBoundsGet);
41072                       }
41073                   }
41074               }
41075           }
41076         break;
41077       }
41078     case GRID_SPECTRAL:
41079       {
41080         grid->size = size;
41081         grid->lcomplex = 1;
41082         grid->trunc = ncvar->truncation;
41083         break;
41084       }
41085     case GRID_FOURIER:
41086       {
41087         grid->size = size;
41088         grid->trunc = ncvar->truncation;
41089         break;
41090       }
41091     case GRID_TRAJECTORY:
41092       {
41093         grid->size = 1;
41094         break;
41095       }
41096     case GRID_CHARXY:
41097       {
41098         grid->size = size;
41099         grid->x.size = xsize;
41100         grid->y.size = ysize;
41101         break;
41102       }
41103     }
41104 
41105   // if ( grid->type != GRID_PROJECTION && grid->type != ncvar->gridtype )
41106   if ( grid->type != gridtype )
41107     {
41108       // int gridtype = ncvar->gridtype;
41109       grid->type = gridtype;
41110       cdiGridTypeInit(grid, gridtype, grid->size);
41111     }
41112 
41113   if ( grid->size == 0 )
41114     {
41115       const int ndims = ncvar->ndims;
41116       int *dimtype = ncvar->dimtype;
41117       if ( ndims == 0 ||
41118            (ndims == 1 && dimtype[0] == T_AXIS) ||
41119            (ndims == 1 && dimtype[0] == Z_AXIS) ||
41120            (ndims == 2 && dimtype[0] == T_AXIS && dimtype[1] == Z_AXIS) )
41121         {
41122           grid->type  = GRID_GENERIC;
41123           grid->size  = 1;
41124           grid->x.size = 0;
41125           grid->y.size = 0;
41126         }
41127       else
41128         {
41129           Warning("Unsupported grid, skipped variable %s!", ncvar->name);
41130           ncvar->isvar = -1;
41131           return true;
41132         }
41133     }
41134 
41135   return false;
41136 }
41137 
41138 static
cdf_set_unstructured_par(ncvar_t * ncvar,grid_t * grid,int * xdimid,int * ydimid,int number_of_grid_used,unsigned char * uuidOfHGrid)41139 bool cdf_set_unstructured_par(ncvar_t *ncvar, grid_t *grid, int *xdimid, int *ydimid, int number_of_grid_used, unsigned char *uuidOfHGrid)
41140 {
41141   int ndims = ncvar->ndims;
41142   int *dimtype = ncvar->dimtype;
41143 
41144   int zdimid = CDI_UNDEFID;
41145   int xdimidx = CDI_UNDEFID, ydimidx = CDI_UNDEFID;
41146 
41147   for ( int i = 0; i < ndims; i++ )
41148     {
41149       if      ( dimtype[i] == X_AXIS ) xdimidx = i;
41150       else if ( dimtype[i] == Y_AXIS ) ydimidx = i;
41151       else if ( dimtype[i] == Z_AXIS ) zdimid = ncvar->dimids[i];
41152     }
41153 
41154   if ( *xdimid != CDI_UNDEFID && *ydimid != CDI_UNDEFID && zdimid == CDI_UNDEFID )
41155     {
41156       if ( grid->x.size > grid->y.size && grid->y.size < 1000 )
41157         {
41158           dimtype[ydimidx] = Z_AXIS;
41159           *ydimid = CDI_UNDEFID;
41160           grid->size  = grid->x.size;
41161           grid->y.size = 0;
41162         }
41163       else if ( grid->y.size > grid->x.size && grid->x.size < 1000 )
41164         {
41165           dimtype[xdimidx] = Z_AXIS;
41166           *xdimid = *ydimid;
41167           *ydimid = CDI_UNDEFID;
41168           grid->size  = grid->y.size;
41169           grid->x.size = grid->y.size;
41170           grid->y.size = 0;
41171         }
41172     }
41173 
41174   if ( grid->size != grid->x.size )
41175     {
41176       Warning("Unsupported array structure, skipped variable %s!", ncvar->name);
41177       ncvar->isvar = -1;
41178       return true;
41179     }
41180 
41181   if ( number_of_grid_used != CDI_UNDEFID ) cdiDefVarKeyInt(&grid->keys, CDI_KEY_NUMBEROFGRIDUSED, number_of_grid_used);
41182   if ( ncvar->position > 0 ) cdiDefVarKeyInt(&grid->keys, CDI_KEY_NUMBEROFGRIDINREFERENCE, ncvar->position);
41183   if ( uuidOfHGrid[0] != 0 ) cdiDefVarKeyBytes(&grid->keys, CDI_KEY_UUID, uuidOfHGrid, CDI_UUID_SIZE);
41184 
41185   return false;
41186 }
41187 
41188 static
cdf_read_mapping_atts(int ncid,int gmapvarid,int projID,const char * varname)41189 void cdf_read_mapping_atts(int ncid, int gmapvarid, int projID, const char *varname)
41190 {
41191   if ( cdfCheckAttText(ncid, gmapvarid, "grid_mapping_name") )
41192     {
41193       char attstring[CDI_MAX_NAME];
41194       cdfGetAttText(ncid, gmapvarid, "grid_mapping_name", CDI_MAX_NAME, attstring);
41195       cdiDefKeyString(projID, CDI_GLOBAL, CDI_KEY_GRIDMAP_NAME, attstring);
41196     }
41197   else
41198     {
41199       Warning("Text attribute %s:grid_mapping_name missing!", varname);
41200     }
41201 
41202   int nvatts;
41203   cdf_inq_varnatts(ncid, gmapvarid, &nvatts);
41204   for ( int attnum = 0; attnum < nvatts; ++attnum )
41205     cdf_set_cdi_attr(ncid, gmapvarid, attnum, projID, CDI_GLOBAL);
41206 }
41207 
41208 static
cdf_set_grid_to_similar_vars(ncvar_t * ncvar1,ncvar_t * ncvar2,int gridtype,int xdimid,int ydimid)41209 void cdf_set_grid_to_similar_vars(ncvar_t *ncvar1, ncvar_t *ncvar2, int gridtype, int xdimid, int ydimid)
41210 {
41211   if ( ncvar2->isvar == TRUE && ncvar2->gridID == CDI_UNDEFID )
41212     {
41213       int xdimid2 = CDI_UNDEFID, ydimid2 = CDI_UNDEFID, zdimid2 = CDI_UNDEFID;
41214       int xdimidx = CDI_UNDEFID, ydimidx = CDI_UNDEFID;
41215       int ndims2 = ncvar2->ndims;
41216 
41217       int *dimtype2 = ncvar2->dimtype;
41218       int *dimids2 = ncvar2->dimids;
41219       for ( int i = 0; i < ndims2; i++ )
41220         {
41221           if      ( dimtype2[i] == X_AXIS ) { xdimid2 = dimids2[i]; xdimidx = i; }
41222           else if ( dimtype2[i] == Y_AXIS ) { ydimid2 = dimids2[i]; ydimidx = i; }
41223           else if ( dimtype2[i] == Z_AXIS ) { zdimid2 = dimids2[i]; }
41224         }
41225 
41226       if ( ncvar2->gridtype == CDI_UNDEFID && gridtype == GRID_UNSTRUCTURED )
41227         {
41228           if ( xdimid == xdimid2 && ydimid2 != CDI_UNDEFID && zdimid2 == CDI_UNDEFID )
41229             {
41230               ncvar2->dimtype[ydimidx] = Z_AXIS;
41231               ydimid2 = CDI_UNDEFID;
41232             }
41233 
41234           if ( xdimid == ydimid2 && xdimid2 != CDI_UNDEFID && zdimid2 == CDI_UNDEFID )
41235             {
41236               ncvar2->dimtype[xdimidx] = Z_AXIS;
41237               xdimid2 = ydimid2;
41238               ydimid2 = CDI_UNDEFID;
41239             }
41240         }
41241 
41242       if ( xdimid == xdimid2 && (ydimid == ydimid2 || (xdimid == ydimid && ydimid2 == CDI_UNDEFID)) )
41243         {
41244           bool same_grid = ncvar1->xvarid == ncvar2->xvarid
41245                         && ncvar1->yvarid == ncvar2->yvarid
41246                         && ncvar1->position == ncvar2->position;
41247           /*
41248             if ( xvarid != -1 && ncvar2->xvarid != CDI_UNDEFID &&
41249             xvarid != ncvar2->xvarid ) same_grid = false;
41250 
41251             if ( yvarid != -1 && ncvar2->yvarid != CDI_UNDEFID &&
41252             yvarid != ncvar2->yvarid ) same_grid = false;
41253           */
41254 
41255           if ( same_grid )
41256             {
41257               if ( CDI_Debug ) Message("Same gridID %d %s", ncvar1->gridID, ncvar2->name);
41258               ncvar2->gridID = ncvar1->gridID;
41259               ncvar2->chunktype = ncvar1->chunktype;
41260             }
41261         }
41262     }
41263 }
41264 
41265 static
cdf_define_all_grids(stream_t * streamptr,ncgrid_t * ncgrid,int vlistID,ncdim_t * ncdims,int nvars,ncvar_t * ncvars,int timedimid,unsigned char * uuidOfHGrid,char * gridfile,int number_of_grid_used)41266 int cdf_define_all_grids(stream_t *streamptr, ncgrid_t *ncgrid, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars,
41267                          int timedimid, unsigned char *uuidOfHGrid, char *gridfile, int number_of_grid_used)
41268 {
41269   for ( int ncvarid = 0; ncvarid < nvars; ++ncvarid )
41270     {
41271       ncvar_t *ncvar = &ncvars[ncvarid];
41272       if ( ncvar->isvar && ncvar->gridID == CDI_UNDEFID )
41273 	{
41274           int ndims = ncvar->ndims;
41275           int *dimtype = ncvar->dimtype;
41276           int vdimid = CDI_UNDEFID;
41277           struct addIfNewRes projAdded = { .Id = CDI_UNDEFID, .isNew = 0 },
41278                              gridAdded = { .Id = CDI_UNDEFID, .isNew = 0 };
41279 	  int xdimid = CDI_UNDEFID, ydimid = CDI_UNDEFID;
41280           int nydims = cdf_get_xydimid(ndims, ncvar->dimids, dimtype, &xdimid, &ydimid);
41281 
41282           int xaxisid = (xdimid != CDI_UNDEFID) ? ncdims[xdimid].ncvarid : CDI_UNDEFID;
41283           int yaxisid = (ydimid != CDI_UNDEFID) ? ncdims[ydimid].ncvarid : CDI_UNDEFID;
41284           int xvarid = (ncvar->xvarid != CDI_UNDEFID) ? ncvar->xvarid : xaxisid;
41285           int yvarid = (ncvar->yvarid != CDI_UNDEFID) ? ncvar->yvarid : yaxisid;
41286 
41287 	  size_t xsize = (xdimid != CDI_UNDEFID) ? ncdims[xdimid].len : 0;
41288 	  size_t ysize = (ydimid != CDI_UNDEFID) ? ncdims[ydimid].len : 0;
41289 
41290 	  if ( ydimid == CDI_UNDEFID && yvarid != CDI_UNDEFID )
41291 	    {
41292 	      if ( ncvars[yvarid].ndims == 1 )
41293 		{
41294 		  ydimid = ncvars[yvarid].dimids[0];
41295 		  ysize  = ncdims[ydimid].len;
41296 		}
41297 	    }
41298 
41299           const int gmapvarid = ncvar->gmapid;
41300           bool lproj = gmapvarid != CDI_UNDEFID;
41301 
41302           if ( !lproj && xaxisid != CDI_UNDEFID && xaxisid != xvarid && yaxisid != CDI_UNDEFID && yaxisid != yvarid )
41303             {
41304               lproj = true;
41305             }
41306 
41307           const bool lgrid = !(lproj && ncvar->xvarid == CDI_UNDEFID);
41308 
41309           const bool lunstructured = xdimid != CDI_UNDEFID && xdimid == ydimid && nydims == 0;
41310 	  if ( (ncvar->gridtype == CDI_UNDEFID || ncvar->gridtype == GRID_GENERIC) && lunstructured )
41311             ncvar->gridtype = GRID_UNSTRUCTURED;
41312 
41313           struct cdfLazyGrid *restrict lazyGrid = NULL, *restrict lazyProj = NULL;
41314 
41315           {
41316             const int gridtype = !lgrid ? GRID_PROJECTION : ncvar->gridtype;
41317             if ( CDI_Netcdf_Lazy_Grid_Load )
41318               {
41319                 cdfLazyGridRenew(&lazyGrid, gridtype);
41320                 if ( lgrid && lproj ) cdfLazyGridRenew(&lazyProj, GRID_PROJECTION);
41321               }
41322             else
41323               {
41324                 cdfBaseGridRenew(&lazyGrid, gridtype);
41325                 if ( lgrid && lproj ) cdfBaseGridRenew(&lazyProj, GRID_PROJECTION);
41326               }
41327           }
41328           grid_t *grid = &lazyGrid->base;
41329           grid_t *proj = ( lgrid && lproj ) ? &lazyProj->base : NULL;
41330 
41331           xaxisid = (xdimid != CDI_UNDEFID) ? ncdims[xdimid].ncvarid : CDI_UNDEFID;
41332           yaxisid = (ydimid != CDI_UNDEFID) ? ncdims[ydimid].ncvarid : CDI_UNDEFID;
41333 
41334           if ( cdf_read_coordinates(streamptr, lazyGrid, ncvar, ncvars, ncdims,
41335                                     timedimid, xvarid, yvarid, xsize, ysize, &vdimid) )
41336             continue;
41337 
41338 	  if ( number_of_grid_used != CDI_UNDEFID &&
41339                (grid->type == CDI_UNDEFID || grid->type == GRID_GENERIC) &&
41340                xdimid != CDI_UNDEFID && xsize > 999 )
41341             grid->type = GRID_UNSTRUCTURED;
41342 
41343           if ( grid->type == GRID_UNSTRUCTURED )
41344             if ( cdf_set_unstructured_par(ncvar, grid, &xdimid, &ydimid, number_of_grid_used, uuidOfHGrid) )
41345               continue;
41346 
41347           if ( lproj && lgrid )
41348             {
41349               int dimid;
41350               cdf_read_coordinates(streamptr, lazyProj, ncvar, ncvars, ncdims, timedimid,
41351                                    xaxisid, yaxisid, xsize, ysize, &dimid);
41352 	    }
41353 
41354 	  if ( CDI_Debug )
41355 	    {
41356 	      Message("grid: type = %d, size = %zu, nx = %zu, ny = %zu",
41357 		      grid->type, grid->size, grid->x.size, grid->y.size);
41358               if ( proj )
41359                 Message("proj: type = %d, size = %zu, nx = %zu, ny = %zu",
41360                         proj->type, proj->size, proj->x.size, proj->y.size);
41361 	    }
41362 
41363 
41364           if ( lgrid && lproj )
41365             {
41366               projAdded = cdiVlistAddGridIfNew(vlistID, proj, 2);
41367               grid->proj = projAdded.Id;
41368             }
41369 
41370           gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 1);
41371           ncvar->gridID = gridAdded.Id;
41372 
41373           const int gridID = ncvar->gridID;
41374 
41375           if ( lproj && gmapvarid != CDI_UNDEFID )
41376             {
41377               const int projID = lgrid ? grid->proj : gridID;
41378               const int ncid = ncvars[gmapvarid].ncid;
41379               const int gmapvartype = ncvars[gmapvarid].xtype;
41380               cdiDefKeyInt(projID, CDI_GLOBAL, CDI_KEY_GRIDMAP_VARTYPE, gmapvartype);
41381               const char *gmapvarname = ncvars[gmapvarid].name;
41382               cdf_read_mapping_atts(ncid, gmapvarid, projID, gmapvarname);
41383               cdiDefKeyString(projID, CDI_GLOBAL, CDI_KEY_GRIDMAP_VARNAME, gmapvarname);
41384               gridVerifyProj(projID);
41385             }
41386 
41387           if ( grid->type == GRID_UNSTRUCTURED && gridfile[0] != 0 )
41388             gridDefReference(gridID, gridfile);
41389 
41390           if ( ncvar->chunked ) grid_set_chunktype(grid, ncvar);
41391 
41392 	  const int gridindex = vlistGridIndex(vlistID, gridID);
41393           ncgrid[gridindex].gridID = gridID;
41394           if (xdimid != CDI_UNDEFID) ncgrid[gridindex].ncIDs[CDF_DIMID_X] = ncdims[xdimid].dimid;
41395           if (ydimid != CDI_UNDEFID) ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = ncdims[ydimid].dimid;
41396 
41397           if (grid->type == GRID_TRAJECTORY)
41398             {
41399               ncgrid[gridindex].ncIDs[CDF_VARID_X] = xvarid;
41400               ncgrid[gridindex].ncIDs[CDF_VARID_Y] = yvarid;
41401             }
41402 
41403           if ( xdimid == CDI_UNDEFID && ydimid == CDI_UNDEFID && grid->size == 1 )
41404             gridDefHasDims(gridID, FALSE);
41405 
41406           if ( xdimid != CDI_UNDEFID ) cdiDefKeyString(gridID, CDI_XAXIS, CDI_KEY_DIMNAME, ncdims[xdimid].name);
41407           if ( ydimid != CDI_UNDEFID ) cdiDefKeyString(gridID, CDI_YAXIS, CDI_KEY_DIMNAME, ncdims[ydimid].name);
41408           if ( vdimid != CDI_UNDEFID ) cdiDefKeyString(gridID, CDI_GLOBAL, CDI_KEY_VDIMNAME, ncdims[vdimid].name);
41409 
41410 	  if ( CDI_Debug ) Message("gridID %d %d %s", gridID, ncvarid, ncvar->name);
41411 
41412 	  for ( int ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
41413             cdf_set_grid_to_similar_vars(ncvar, &ncvars[ncvarid2], grid->type, xdimid, ydimid);
41414 
41415           if ( gridAdded.isNew ) lazyGrid = NULL;
41416           if ( projAdded.isNew ) lazyProj = NULL;
41417 
41418           if ( lazyGrid )
41419             {
41420               if ( CDI_Netcdf_Lazy_Grid_Load ) cdfLazyGridDestroy(lazyGrid);
41421               if ( grid ) { grid_free(grid); Free(grid); }
41422             }
41423 
41424           if ( lazyProj )
41425             {
41426               if ( CDI_Netcdf_Lazy_Grid_Load ) cdfLazyGridDestroy(lazyProj);
41427               if ( proj ) { grid_free(proj); Free(proj); }
41428             }
41429 	}
41430     }
41431 
41432   return 0;
41433 }
41434 
41435 /* define all input zaxes */
41436 static
cdf_define_all_zaxes(stream_t * streamptr,int vlistID,ncdim_t * ncdims,int nvars,ncvar_t * ncvars,size_t vctsize_echam,double * vct_echam,unsigned char * uuidOfVGrid)41437 int cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars,
41438                          size_t vctsize_echam, double *vct_echam, unsigned char *uuidOfVGrid)
41439 {
41440   char *pname, *plongname, *punits, *pstdname;
41441   size_t vctsize = vctsize_echam;
41442   double *vct = vct_echam;
41443 
41444   for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
41445     {
41446       ncvar_t *ncvar = &ncvars[ncvarid];
41447       if ( ncvar->isvar == TRUE && ncvar->zaxisID == CDI_UNDEFID )
41448 	{
41449           bool is_scalar = false;
41450 	  bool with_bounds = false;
41451 	  int zdimid = CDI_UNDEFID;
41452 	  int zvarid = CDI_UNDEFID;
41453 	  size_t zsize = 1;
41454           int psvarid = -1;
41455           int p0varid = -1;
41456 
41457           int positive = 0;
41458           int ndims = ncvar->ndims;
41459 
41460           if ( ncvar->zvarid != -1 && ncvars[ncvar->zvarid].ndims == 0 )
41461             {
41462               zvarid = ncvar->zvarid;
41463               is_scalar = true;
41464             }
41465           else
41466             {
41467               for ( int i = 0; i < ndims; i++ )
41468                 {
41469                   if ( ncvar->dimtype[i] == Z_AXIS )
41470                     zdimid = ncvar->dimids[i];
41471                 }
41472 
41473               if ( zdimid != CDI_UNDEFID )
41474                 {
41475                   // zvarid = ncdims[zdimid].ncvarid;
41476                   zvarid = (ncvar->zvarid != CDI_UNDEFID) ? ncvar->zvarid : ncdims[zdimid].ncvarid;
41477                   zsize  = ncdims[zdimid].len;
41478                 }
41479             }
41480 
41481 	  if ( CDI_Debug ) Message("nlevs = %zu", zsize);
41482 
41483 	  double *zvar = NULL;
41484           char **zcvals = NULL;
41485           size_t zclength = 0;
41486 
41487 	  int zaxisType = CDI_UNDEFID;
41488 	  if ( zvarid != CDI_UNDEFID ) zaxisType = ncvars[zvarid].zaxistype;
41489 	  if ( zaxisType == CDI_UNDEFID ) zaxisType = ZAXIS_GENERIC;
41490 
41491           int zdatatype = CDI_DATATYPE_FLT64;
41492 	  double *restrict lbounds = NULL;
41493 	  double *restrict ubounds = NULL;
41494 
41495 	  if ( zvarid != CDI_UNDEFID )
41496 	    {
41497 	      positive  = ncvars[zvarid].positive;
41498 	      pname     = ncvars[zvarid].name;
41499 	      plongname = ncvars[zvarid].longname;
41500 	      punits    = ncvars[zvarid].units;
41501 	      pstdname  = ncvars[zvarid].stdname;
41502 	      if ( ncvars[zvarid].xtype == NC_FLOAT ) zdatatype = CDI_DATATYPE_FLT32;
41503 	      /* don't change the name !!! */
41504 	      /*
41505 	      if ( (len = strlen(pname)) > 2 )
41506 		if ( pname[len-2] == '_' && isdigit((int) pname[len-1]) )
41507 		  pname[len-2] = 0;
41508 	      */
41509 #ifndef USE_MPI
41510               if ( zaxisType == ZAXIS_CHAR )
41511                 {
41512                   if ( ncvars[zvarid].ndims == 2 )
41513                     {
41514                       zdatatype = CDI_DATATYPE_UINT8;
41515                       zclength = ncdims[ncvars[zvarid].dimids[1]].len;
41516                       cdf_load_cvals(zsize*zclength, zvarid, ncvar, &zcvals, zsize);
41517                     }
41518                 }
41519 #endif
41520 
41521               if ( zaxisType == ZAXIS_HYBRID && ncvars[zvarid].vct )
41522                 {
41523                   vct = ncvars[zvarid].vct;
41524                   vctsize = ncvars[zvarid].vctsize;
41525 
41526                   if ( ncvars[zvarid].psvarid != -1 ) psvarid = ncvars[zvarid].psvarid;
41527                   if ( ncvars[zvarid].p0varid != -1 ) p0varid = ncvars[zvarid].p0varid;
41528                 }
41529 
41530               if ( zaxisType != ZAXIS_CHAR )
41531                 {
41532                   zvar = (double*) Malloc(zsize*sizeof(double));
41533                   cdf_get_var_double(ncvars[zvarid].ncid, zvarid, zvar);
41534                 }
41535 
41536 	      if ( ncvars[zvarid].bounds != CDI_UNDEFID )
41537 		{
41538 		  const int nbdims = ncvars[ncvars[zvarid].bounds].ndims;
41539 		  if ( nbdims == 2 || is_scalar )
41540 		    {
41541 		      const size_t nlevel  = is_scalar ? 1 : ncdims[ncvars[ncvars[zvarid].bounds].dimids[0]].len;
41542 		      const int nvertex = (int)ncdims[ncvars[ncvars[zvarid].bounds].dimids[1-is_scalar]].len;
41543 		      if ( nlevel == zsize && nvertex == 2 )
41544 			{
41545 			  with_bounds = true;
41546 			  lbounds = (double *) Malloc(4 * nlevel*sizeof(double));
41547 			  ubounds = lbounds + nlevel;
41548 			  double *restrict zbounds = lbounds + 2 * nlevel;
41549 			  cdf_get_var_double(ncvars[zvarid].ncid, ncvars[zvarid].bounds, zbounds);
41550 			  for ( size_t i = 0; i < nlevel; ++i )
41551 			    {
41552 			      lbounds[i] = zbounds[i*2];
41553 			      ubounds[i] = zbounds[i*2+1];
41554 			    }
41555 			}
41556 		    }
41557 		}
41558 	    }
41559 	  else
41560 	    {
41561               pname     = (zdimid != CDI_UNDEFID) ? ncdims[zdimid].name : NULL;
41562 	      plongname = NULL;
41563 	      punits    = NULL;
41564 	      pstdname   = NULL;
41565 
41566 	      if ( zsize == 1 && zdimid == CDI_UNDEFID )
41567 		{
41568                   zaxisType = (ncvar->zaxistype != CDI_UNDEFID) ? ncvar->zaxistype : ZAXIS_SURFACE;
41569                   // if ( pname )
41570                     {
41571                       zvar = (double*) Malloc(sizeof(double));
41572                       zvar[0] = 0;
41573                     }
41574                 }
41575 	    }
41576 
41577           if ( zsize > INT_MAX )
41578             {
41579               Warning("Size limit exceeded for z-axis dimension (limit=%d)!", INT_MAX);
41580               return CDI_EDIMSIZE;
41581             }
41582 
41583       	  ncvar->zaxisID = varDefZaxis(vlistID, zaxisType, (int) zsize, zvar, (const char **)zcvals, zclength, with_bounds, lbounds, ubounds,
41584                                        (int)vctsize, vct, pname, plongname, punits, zdatatype, 1, 0, -1);
41585 
41586           const int zaxisID = ncvar->zaxisID;
41587 
41588           if ( CDI_CMOR_Mode && zsize == 1 && zaxisType != ZAXIS_HYBRID ) zaxisDefScalar(zaxisID);
41589 
41590           if (pstdname && *pstdname)
41591             cdiDefKeyBytes(zaxisID, CDI_GLOBAL, CDI_KEY_STDNAME, (const unsigned  char*)pstdname, (int)strlen(pstdname)+1);
41592 
41593           if ( uuidOfVGrid[0] != 0 )
41594             cdiDefKeyBytes(zaxisID, CDI_GLOBAL, CDI_KEY_UUID, uuidOfVGrid, CDI_UUID_SIZE);
41595 
41596           if ( zaxisType == ZAXIS_HYBRID )
41597             {
41598               if ( psvarid != -1 )
41599                 cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_PSNAME, ncvars[psvarid].name);
41600               if ( p0varid != -1 )
41601                 {
41602                   double px = 1;
41603                   cdf_get_var_double(ncvars[p0varid].ncid, p0varid, &px);
41604                   cdiDefKeyFloat(zaxisID, CDI_GLOBAL, CDI_KEY_P0VALUE, px);
41605                   cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_P0NAME, ncvars[p0varid].name);
41606                 }
41607             }
41608 
41609           if ( positive > 0 ) zaxisDefPositive(zaxisID, positive);
41610           if ( is_scalar ) zaxisDefScalar(zaxisID);
41611 
41612           if ( zdimid != CDI_UNDEFID )
41613             cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_DIMNAME, ncdims[zdimid].name);
41614 
41615 	  if ( zvar ) Free(zvar);
41616 	  if ( zcvals )
41617             {
41618               for ( size_t i = 0; i < zsize; i++ ) Free(zcvals[i]);
41619               Free(zcvals);
41620             }
41621 	  if ( lbounds ) Free(lbounds);
41622 
41623           if ( zvarid != CDI_UNDEFID )
41624             {
41625               const int ncid = ncvars[zvarid].ncid;
41626               const int nvatts = ncvars[zvarid].natts;
41627               for ( int iatt = 0; iatt < nvatts; ++iatt )
41628                 {
41629                   const int attnum = ncvars[zvarid].atts[iatt];
41630                   cdf_set_cdi_attr(ncid, zvarid, attnum, zaxisID, CDI_GLOBAL);
41631                 }
41632             }
41633 
41634           const int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
41635 	  streamptr->zaxisID[zaxisindex] = zdimid >= 0 ? ncdims[zdimid].dimid : zdimid;
41636 
41637 	  if ( CDI_Debug )
41638 	    Message("zaxisID %d %d %s", zaxisID, ncvarid, ncvar->name);
41639 
41640 	  for ( int ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
41641 	    if ( ncvars[ncvarid2].isvar == TRUE && ncvars[ncvarid2].zaxisID == CDI_UNDEFID /*&& ncvars[ncvarid2].zaxistype == CDI_UNDEFID*/ )
41642 	      {
41643                 int zvarid2 = CDI_UNDEFID;
41644                 if ( ncvars[ncvarid2].zvarid != CDI_UNDEFID && ncvars[ncvars[ncvarid2].zvarid].ndims == 0 )
41645                   zvarid2 = ncvars[ncvarid2].zvarid;
41646 
41647 		int zdimid2 = CDI_UNDEFID;
41648 		ndims = ncvars[ncvarid2].ndims;
41649 		for ( int i = 0; i < ndims; i++ )
41650 		  {
41651 		    if ( ncvars[ncvarid2].dimtype[i] == Z_AXIS )
41652 		      zdimid2 = ncvars[ncvarid2].dimids[i];
41653 		  }
41654 
41655 		if ( zdimid == zdimid2 /* && zvarid == zvarid2 */)
41656 		  {
41657                     if ( (zdimid != CDI_UNDEFID && ncvars[ncvarid2].zaxistype == CDI_UNDEFID) ||
41658                          (zdimid == CDI_UNDEFID && zvarid != CDI_UNDEFID && zvarid == zvarid2) ||
41659                          (zdimid == CDI_UNDEFID && zaxisType == ncvars[ncvarid2].zaxistype) ||
41660                          (zdimid == CDI_UNDEFID && zvarid2 == CDI_UNDEFID && ncvars[ncvarid2].zaxistype == CDI_UNDEFID) )
41661                       {
41662                         if ( CDI_Debug )
41663                           Message("zaxisID %d %d %s", zaxisID, ncvarid2, ncvars[ncvarid2].name);
41664                         ncvars[ncvarid2].zaxisID = zaxisID;
41665                       }
41666                   }
41667 	      }
41668 	}
41669     }
41670 
41671   return 0;
41672 }
41673 
41674 
41675 struct cdf_varinfo
41676 {
41677   int        varid;
41678   const char *name;
41679 };
41680 
41681 static
cdf_cmp_varname(const void * s1,const void * s2)41682 int cdf_cmp_varname(const void *s1, const void *s2)
41683 {
41684   const struct cdf_varinfo *x = (const struct cdf_varinfo *)s1,
41685                            *y = (const struct cdf_varinfo *)s2;
41686   return strcmp(x->name, y->name);
41687 }
41688 
41689 static
cdf_sort_varnames(int * varids,const int nvars,const ncvar_t * ncvars)41690 void cdf_sort_varnames(int *varids, const int nvars, const ncvar_t *ncvars)
41691 {
41692   struct cdf_varinfo *varInfo
41693     = (struct cdf_varinfo *) Malloc((size_t)nvars * sizeof(struct cdf_varinfo));
41694 
41695   for ( int varID = 0; varID < nvars; varID++ )
41696     {
41697       const int ncvarid = varids[varID];
41698       varInfo[varID].varid = ncvarid;
41699       varInfo[varID].name = ncvars[ncvarid].name;
41700     }
41701   qsort(varInfo, (size_t)nvars, sizeof(varInfo[0]), cdf_cmp_varname);
41702   for ( int varID = 0; varID < nvars; varID++ )
41703     {
41704       varids[varID] = varInfo[varID].varid;
41705     }
41706   Free(varInfo);
41707   if ( CDI_Debug )
41708     for ( int i = 0; i < nvars; i++ ) Message("sorted varids[%d] = %d", i, varids[i]);
41709 }
41710 
41711 static
cdf_define_code_and_param(int vlistID,int varID)41712 void cdf_define_code_and_param(int vlistID, int varID)
41713 {
41714   if ( vlistInqVarCode(vlistID, varID) == -varID-1 )
41715     {
41716       char name[CDI_MAX_NAME]; name[0] = 0;
41717       vlistInqVarName(vlistID, varID, name);
41718       const size_t len = strlen(name);
41719       if ( len > 3 && isdigit((int) name[3]) )
41720         {
41721           if ( strStartsWith(name, "var") )
41722             {
41723               vlistDefVarCode(vlistID, varID, atoi(name+3));
41724             }
41725         }
41726       else if ( len > 4 && isdigit((int) name[4]) )
41727         {
41728           if ( strStartsWith(name, "code") )
41729             {
41730               vlistDefVarCode(vlistID, varID, atoi(name+4));
41731             }
41732         }
41733       else if ( len > 5 && isdigit((int) name[5]) )
41734         {
41735           if ( strStartsWith(name, "param") )
41736             {
41737               int pnum = -1, pcat = 255, pdis = 255;
41738               sscanf(name+5, "%d.%d.%d", &pnum, &pcat, &pdis);
41739               vlistDefVarParam(vlistID, varID, cdiEncodeParam(pnum, pcat, pdis));
41740             }
41741         }
41742     }
41743 }
41744 
41745 static
cdf_define_institut_and_model_id(int vlistID,int varID)41746 void cdf_define_institut_and_model_id(int vlistID, int varID)
41747 {
41748   int varInstID  = vlistInqVarInstitut(vlistID, varID);
41749   int varModelID = vlistInqVarModel(vlistID, varID);
41750   int varTableID = vlistInqVarTable(vlistID, varID);
41751   const int code = vlistInqVarCode(vlistID, varID);
41752   if ( CDI_Default_TableID != CDI_UNDEFID )
41753     {
41754       char name[CDI_MAX_NAME]; name[0] = 0;
41755       char longname[CDI_MAX_NAME]; longname[0] = 0;
41756       char units[CDI_MAX_NAME]; units[0] = 0;
41757       tableInqEntry(CDI_Default_TableID, code, -1, name, longname, units);
41758       if ( name[0] )
41759         {
41760           cdiDeleteKey(vlistID, varID, CDI_KEY_NAME);
41761           cdiDeleteKey(vlistID, varID, CDI_KEY_LONGNAME);
41762           cdiDeleteKey(vlistID, varID, CDI_KEY_UNITS);
41763 
41764           if ( varTableID != CDI_UNDEFID )
41765             {
41766               cdiDefKeyString(vlistID, varID, CDI_KEY_NAME, name);
41767               if ( longname[0] ) cdiDefKeyString(vlistID, varID, CDI_KEY_LONGNAME, longname);
41768               if ( units[0] ) cdiDefKeyString(vlistID, varID, CDI_KEY_UNITS, units);
41769             }
41770           else
41771             {
41772               varTableID = CDI_Default_TableID;
41773             }
41774         }
41775 
41776       if ( CDI_Default_ModelID != CDI_UNDEFID ) varModelID = CDI_Default_ModelID;
41777       if ( CDI_Default_InstID  != CDI_UNDEFID ) varInstID  = CDI_Default_InstID;
41778     }
41779   if ( varInstID  != CDI_UNDEFID ) vlistDefVarInstitut(vlistID, varID, varInstID);
41780   if ( varModelID != CDI_UNDEFID ) vlistDefVarModel(vlistID, varID, varModelID);
41781   if ( varTableID != CDI_UNDEFID ) vlistDefVarTable(vlistID, varID, varTableID);
41782 }
41783 
41784 // define all input data variables
41785 static
cdf_define_all_vars(stream_t * streamptr,int vlistID,int instID,int modelID,int nvars,int num_ncvars,ncvar_t * ncvars,ncdim_t * ncdims)41786 void cdf_define_all_vars(stream_t *streamptr, int vlistID, int instID, int modelID, int nvars, int num_ncvars, ncvar_t *ncvars, ncdim_t *ncdims)
41787 {
41788   int *varids = (int *) Malloc((size_t)nvars * sizeof (int));
41789   int n = 0;
41790   for ( int ncvarid = 0; ncvarid < num_ncvars; ncvarid++ )
41791     if ( ncvars[ncvarid].isvar == TRUE ) varids[n++] = ncvarid;
41792 
41793   if ( CDI_Debug )
41794     for ( int i = 0; i < nvars; i++ ) Message("varids[%d] = %d", i, varids[i]);
41795 
41796   if ( streamptr->sortname ) cdf_sort_varnames(varids, nvars, ncvars);
41797 
41798   for ( int varID1 = 0; varID1 < nvars; varID1++ )
41799     {
41800       const int ncvarid = varids[varID1];
41801       const int gridID  = ncvars[ncvarid].gridID;
41802       const int zaxisID = ncvars[ncvarid].zaxisID;
41803 
41804       stream_new_var(streamptr, gridID, zaxisID, CDI_UNDEFID);
41805       const int varID = vlistDefVar(vlistID, gridID, zaxisID, ncvars[ncvarid].timetype);
41806 
41807 #ifdef HAVE_NETCDF4
41808       if (ncvars[ncvarid].ldeflate) vlistDefVarCompType(vlistID, varID, CDI_COMPRESS_ZIP);
41809       if (ncvars[ncvarid].lszip) vlistDefVarCompType(vlistID, varID, CDI_COMPRESS_SZIP);
41810 
41811       if ( ncvars[ncvarid].chunked && ncvars[ncvarid].chunktype != CDI_UNDEFID )
41812         vlistDefVarChunkType(vlistID, varID, ncvars[ncvarid].chunktype);
41813 #endif
41814 
41815       streamptr->vars[varID1].defmiss = false;
41816       streamptr->vars[varID1].ncvarid = ncvarid;
41817 
41818       cdiDefKeyString(vlistID, varID, CDI_KEY_NAME, ncvars[ncvarid].name);
41819       if ( ncvars[ncvarid].param != CDI_UNDEFID ) vlistDefVarParam(vlistID, varID, ncvars[ncvarid].param);
41820       if ( ncvars[ncvarid].code != CDI_UNDEFID )  vlistDefVarCode(vlistID, varID, ncvars[ncvarid].code);
41821       if ( ncvars[ncvarid].code != CDI_UNDEFID )
41822 	{
41823 	  int param = cdiEncodeParam(ncvars[ncvarid].code, ncvars[ncvarid].tabnum, 255);
41824 	  vlistDefVarParam(vlistID, varID, param);
41825 	}
41826       if ( ncvars[ncvarid].longname[0] )  cdiDefKeyString(vlistID, varID, CDI_KEY_LONGNAME, ncvars[ncvarid].longname);
41827       if ( ncvars[ncvarid].stdname[0] )   cdiDefKeyString(vlistID, varID, CDI_KEY_STDNAME, ncvars[ncvarid].stdname);
41828       if ( ncvars[ncvarid].units[0] )     cdiDefKeyString(vlistID, varID, CDI_KEY_UNITS, ncvars[ncvarid].units);
41829 
41830       if ( ncvars[ncvarid].lvalidrange )
41831         vlistDefVarValidrange(vlistID, varID, ncvars[ncvarid].validrange);
41832 
41833       if ( IS_NOT_EQUAL(ncvars[ncvarid].addoffset, 0) )
41834 	vlistDefVarAddoffset(vlistID, varID, ncvars[ncvarid].addoffset);
41835       if ( IS_NOT_EQUAL(ncvars[ncvarid].scalefactor, 1) )
41836 	vlistDefVarScalefactor(vlistID, varID, ncvars[ncvarid].scalefactor);
41837 
41838       vlistDefVarDatatype(vlistID, varID, cdfInqDatatype(streamptr, ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned));
41839 
41840       vlistDefVarInstitut(vlistID, varID, instID);
41841       vlistDefVarModel(vlistID, varID, modelID);
41842       if ( ncvars[ncvarid].tableID != CDI_UNDEFID )
41843 	vlistDefVarTable(vlistID, varID, ncvars[ncvarid].tableID);
41844 
41845       if ( ncvars[ncvarid].deffillval == false && ncvars[ncvarid].defmissval )
41846         {
41847           ncvars[ncvarid].deffillval = true;
41848           ncvars[ncvarid].fillval    = ncvars[ncvarid].missval;
41849         }
41850 
41851       if ( ncvars[ncvarid].deffillval )
41852         vlistDefVarMissval(vlistID, varID, ncvars[ncvarid].fillval);
41853 
41854       if ( CDI_Debug )
41855 	Message("varID = %d  gridID = %d  zaxisID = %d", varID,
41856 		vlistInqVarGrid(vlistID, varID), vlistInqVarZaxis(vlistID, varID));
41857 
41858       const int gridindex = vlistGridIndex(vlistID, gridID);
41859       const int xdimid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
41860       const int ydimid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
41861 
41862       const int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
41863       const int zdimid = streamptr->zaxisID[zaxisindex];
41864 
41865       const int ndims = ncvars[ncvarid].ndims;
41866       int iodim = 0;
41867       int ixyz = 0;
41868       static const int ipow10[4] = {1, 10, 100, 1000};
41869 
41870       if ( ncvars[ncvarid].timetype != TIME_CONSTANT ) iodim++;
41871 
41872       const int *dimids = ncvars[ncvarid].dimids;
41873 
41874       if ( gridInqType(gridID) == GRID_UNSTRUCTURED && ndims-iodim <= 2 && (ydimid == xdimid || ydimid == CDI_UNDEFID) )
41875         {
41876           ixyz = (xdimid == ncdims[dimids[ndims-1]].dimid) ? 321 : 213;
41877         }
41878       else
41879         {
41880           for ( int idim = iodim; idim < ndims; idim++ )
41881             {
41882               const int dimid = ncdims[dimids[idim]].dimid;
41883               if      ( xdimid == dimid ) ixyz += 1*ipow10[ndims-idim-1];
41884               else if ( ydimid == dimid ) ixyz += 2*ipow10[ndims-idim-1];
41885               else if ( zdimid == dimid ) ixyz += 3*ipow10[ndims-idim-1];
41886             }
41887         }
41888 
41889       vlistDefVarXYZ(vlistID, varID, ixyz);
41890       /*
41891       printf("ixyz %d\n", ixyz);
41892       printf("ndims %d\n", ncvars[ncvarid].ndims);
41893       for ( int i = 0; i < ncvars[ncvarid].ndims; ++i )
41894         printf("dimids: %d %d\n", i, dimids[i]);
41895       printf("xdimid, ydimid %d %d\n", xdimid, ydimid);
41896       */
41897       if ( ncvars[ncvarid].numberOfForecastsInEnsemble != -1 )
41898         {
41899           cdiDefKeyInt(vlistID, varID, CDI_KEY_TYPEOFENSEMBLEFORECAST, ncvars[ncvarid].typeOfEnsembleForecast);
41900           cdiDefKeyInt(vlistID, varID, CDI_KEY_NUMBEROFFORECASTSINENSEMBLE, ncvars[ncvarid].numberOfForecastsInEnsemble);
41901           cdiDefKeyInt(vlistID, varID, CDI_KEY_PERTURBATIONNUMBER, ncvars[ncvarid].perturbationNumber);
41902         }
41903 
41904       if ( ncvars[ncvarid].extra[0] != 0 )
41905         {
41906           vlistDefVarExtra(vlistID, varID, ncvars[ncvarid].extra);
41907         }
41908     }
41909 
41910   for ( int varID = 0; varID < nvars; varID++ )
41911     {
41912       const int ncvarid = varids[varID];
41913       const int ncid = ncvars[ncvarid].ncid;
41914 
41915       const int nvatts = ncvars[ncvarid].natts;
41916       for ( int iatt = 0; iatt < nvatts; ++iatt )
41917         {
41918           const int attnum = ncvars[ncvarid].atts[iatt];
41919           cdf_set_cdi_attr(ncid, ncvarid, attnum, vlistID, varID);
41920         }
41921 
41922       if ( ncvars[ncvarid].atts )
41923         {
41924           Free(ncvars[ncvarid].atts);
41925           ncvars[ncvarid].atts = NULL;
41926         }
41927 
41928       if ( ncvars[ncvarid].vct )
41929         {
41930           Free(ncvars[ncvarid].vct);
41931           ncvars[ncvarid].vct = NULL;
41932         }
41933     }
41934 
41935   /* release mem of not freed attributes */
41936   for ( int ncvarid = 0; ncvarid < num_ncvars; ncvarid++ )
41937     if ( ncvars[ncvarid].atts ) Free(ncvars[ncvarid].atts);
41938 
41939   if ( varids ) Free(varids);
41940 
41941   for ( int varID = 0; varID < nvars; varID++ ) cdf_define_code_and_param(vlistID, varID);
41942 
41943   for ( int varID = 0; varID < nvars; varID++ ) cdf_define_institut_and_model_id(vlistID, varID);
41944 }
41945 
41946 static
cdf_copy_attint(int fileID,int vlistID,nc_type xtype,size_t attlen,char * attname)41947 void cdf_copy_attint(int fileID, int vlistID, nc_type xtype, size_t attlen, char *attname)
41948 {
41949   int attint[8];
41950   int *pattint = (attlen > 8) ? (int*) malloc(attlen*sizeof(int)) : attint;
41951   cdfGetAttInt(fileID, NC_GLOBAL, attname, attlen, pattint);
41952   const int datatype = (xtype == NC_SHORT) ? CDI_DATATYPE_INT16 : CDI_DATATYPE_INT32;
41953   cdiDefAttInt(vlistID, CDI_GLOBAL, attname, datatype, (int)attlen, pattint);
41954   if (attlen > 8) free(pattint);
41955 }
41956 
41957 static
cdf_copy_attflt(int fileID,int vlistID,nc_type xtype,size_t attlen,char * attname)41958 void cdf_copy_attflt(int fileID, int vlistID, nc_type xtype, size_t attlen, char *attname)
41959 {
41960   double attflt[8];
41961   double *pattflt = (attlen > 8) ? (double*) malloc(attlen*sizeof(double)) : attflt;
41962   cdfGetAttDouble(fileID, NC_GLOBAL, attname, attlen, pattflt);
41963   const int datatype = (xtype == NC_FLOAT) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64;
41964   cdiDefAttFlt(vlistID, CDI_GLOBAL, attname, datatype, (int)attlen, pattflt);
41965   if (attlen > 8) free(pattflt);
41966 }
41967 
41968 static
cdf_scan_global_attr(int fileID,int vlistID,int ngatts,int * instID,int * modelID,bool * ucla_les,unsigned char * uuidOfHGrid,unsigned char * uuidOfVGrid,char * gridfile,int * number_of_grid_used)41969 void cdf_scan_global_attr(int fileID, int vlistID, int ngatts, int *instID, int *modelID, bool *ucla_les, unsigned char *uuidOfHGrid, unsigned char *uuidOfVGrid, char *gridfile, int *number_of_grid_used)
41970 {
41971   nc_type xtype;
41972   size_t attlen;
41973   char attname[CDI_MAX_NAME];
41974   char attstring[65636];
41975 
41976   for ( int iatt = 0; iatt < ngatts; iatt++ )
41977     {
41978       cdf_inq_attname(fileID, NC_GLOBAL, iatt, attname);
41979       cdf_inq_atttype(fileID, NC_GLOBAL, attname, &xtype);
41980       cdf_inq_attlen(fileID, NC_GLOBAL, attname, &attlen);
41981 
41982       if ( xtypeIsText(xtype) )
41983 	{
41984 	  cdfGetAttText(fileID, NC_GLOBAL, attname, sizeof(attstring), attstring);
41985 
41986           size_t attstrlen = strlen(attstring);
41987 
41988 	  if ( attlen > 0 && attstring[0] != 0 )
41989 	    {
41990 	      if ( strIsEqual(attname, "institution") )
41991 		{
41992 		  *instID = institutInq(0, 0, NULL, attstring);
41993 		  if ( *instID == CDI_UNDEFID )
41994 		    *instID = institutDef(0, 0, NULL, attstring);
41995 		}
41996 	      else if ( strIsEqual(attname, "source") )
41997 		{
41998 		  *modelID = modelInq(-1, 0, attstring);
41999 		  if ( *modelID == CDI_UNDEFID )
42000 		    *modelID = modelDef(-1, 0, attstring);
42001 		}
42002 	      else if ( strIsEqual(attname, "Source") )
42003 		{
42004 		  if ( strncmp(attstring, "UCLA-LES", 8) == 0 )
42005 		    *ucla_les = true;
42006 		}
42007 	      /*
42008 	      else if ( strIsEqual(attname, "Conventions") )
42009 		{
42010 		}
42011 	      */
42012 	      else if ( strIsEqual(attname, "_NCProperties") )
42013 		{
42014 		}
42015 	      else if ( strIsEqual(attname, "CDI") )
42016 		{
42017 		}
42018 	      else if ( strIsEqual(attname, "CDO") )
42019 		{
42020 		}
42021               /*
42022 	      else if ( strIsEqual(attname, "forecast_reference_time") )
42023 		{
42024                   memcpy(fcreftime, attstring, attstrlen+1);
42025 		}
42026               */
42027 	      else if ( strIsEqual(attname, "grid_file_uri") )
42028 		{
42029                   memcpy(gridfile, attstring, attstrlen+1);
42030 		}
42031 	      else if ( strIsEqual(attname, "uuidOfHGrid") && attstrlen == 36 )
42032 		{
42033                   attstring[36] = 0;
42034                   cdiStr2UUID(attstring, uuidOfHGrid);
42035                   //   printf("uuid: %d %s\n", attlen, attstring);
42036 		}
42037 	      else if ( strIsEqual(attname, "uuidOfVGrid") && attstrlen == 36 )
42038 		{
42039                   attstring[36] = 0;
42040                   cdiStr2UUID(attstring, uuidOfVGrid);
42041 		}
42042 	      else
42043 		{
42044                   if ( strIsEqual(attname, "ICON_grid_file_uri") && gridfile[0] == 0 )
42045                     memcpy(gridfile, attstring, attstrlen+1);
42046 
42047 		  cdiDefAttTxt(vlistID, CDI_GLOBAL, attname, (int)attstrlen, attstring);
42048 		}
42049 	    }
42050 	}
42051       else if ( xtype == NC_SHORT || xtype == NC_INT )
42052 	{
42053 	  if ( strIsEqual(attname, "number_of_grid_used") )
42054 	    {
42055 	      (*number_of_grid_used) = CDI_UNDEFID;
42056 	      cdfGetAttInt(fileID, NC_GLOBAL, attname, 1, number_of_grid_used);
42057 	    }
42058  	  else
42059             {
42060               cdf_copy_attint(fileID, vlistID, xtype, attlen, attname);
42061             }
42062         }
42063       else if ( xtype == NC_FLOAT || xtype == NC_DOUBLE )
42064 	{
42065           cdf_copy_attflt(fileID, vlistID, xtype, attlen, attname);
42066 	}
42067     }
42068 }
42069 
42070 static
find_leadtime(int nvars,ncvar_t * ncvars,int timedimid)42071 int find_leadtime(int nvars, ncvar_t *ncvars, int timedimid)
42072 {
42073   int leadtime_id = CDI_UNDEFID;
42074 
42075   for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
42076     {
42077       ncvar_t *ncvar = &ncvars[ncvarid];
42078       if ( ncvar->ndims == 1 && timedimid == ncvar->dimids[0])
42079         if ( ncvar->stdname[0] && strIsEqual(ncvar->stdname, "forecast_period") )
42080           {
42081             leadtime_id = ncvarid;
42082             break;
42083           }
42084     }
42085 
42086   return leadtime_id;
42087 }
42088 
42089 static
find_time_vars(int nvars,ncvar_t * ncvars,ncdim_t * ncdims,int timedimid,stream_t * streamptr,bool * time_has_units,bool * time_has_bounds,bool * time_climatology)42090 void find_time_vars(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimid, stream_t *streamptr,
42091                     bool *time_has_units, bool *time_has_bounds, bool *time_climatology)
42092 {
42093   int ncvarid;
42094 
42095   if ( timedimid == CDI_UNDEFID )
42096     {
42097       char timeunits[CDI_MAX_NAME];
42098 
42099       for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
42100         {
42101           ncvar_t *ncvar = &ncvars[ncvarid];
42102           if ( ncvar->ndims == 0 && strIsEqual(ncvar->name, "time") )
42103             {
42104               if ( ncvars[ncvarid].units[0] )
42105                 {
42106                   strcpy(timeunits, ncvar->units);
42107                   strToLower(timeunits);
42108 
42109                   if ( is_time_units(timeunits) )
42110                     {
42111                       streamptr->basetime.ncvarid = ncvarid;
42112                       break;
42113                     }
42114                 }
42115             }
42116         }
42117     }
42118   else
42119     {
42120       bool ltimevar = false;
42121 
42122       if ( ncdims[timedimid].ncvarid != CDI_UNDEFID )
42123         {
42124           streamptr->basetime.ncvarid = ncdims[timedimid].ncvarid;
42125           ltimevar = true;
42126         }
42127 
42128       for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
42129         {
42130           ncvar_t *ncvar = &ncvars[ncvarid];
42131           if ( ncvarid != streamptr->basetime.ncvarid &&
42132                ncvar->ndims == 1 &&
42133                timedimid == ncvar->dimids[0] &&
42134                !xtypeIsText(ncvar->xtype) &&
42135                is_timeaxis_units(ncvar->units) )
42136             {
42137               ncvar->isvar = FALSE;
42138 
42139               if ( !ltimevar )
42140                 {
42141                   streamptr->basetime.ncvarid = ncvarid;
42142                   ltimevar = true;
42143                   if ( CDI_Debug ) fprintf(stderr, "timevar %s\n", ncvar->name);
42144                 }
42145               else
42146                 {
42147                   Warning("Found more than one time variable, skipped variable %s!", ncvar->name);
42148                 }
42149             }
42150         }
42151 
42152       if ( ltimevar == false ) // search for WRF time description
42153         {
42154           for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
42155             {
42156               ncvar_t *ncvar = &ncvars[ncvarid];
42157               if ( ncvarid != streamptr->basetime.ncvarid &&
42158                    ncvar->ndims == 2 &&
42159                    timedimid == ncvar->dimids[0] &&
42160                    xtypeIsText(ncvar->xtype) &&
42161                    (ncdims[ncvar->dimids[1]].len == 19 || ncdims[ncvar->dimids[1]].len == 64))
42162                 {
42163                   ncvar->istime = true;
42164                   streamptr->basetime.ncvarid = ncvarid;
42165                   streamptr->basetime.lwrf    = true;
42166                   break;
42167                 }
42168             }
42169         }
42170 
42171       // time varID
42172       ncvarid = streamptr->basetime.ncvarid;
42173 
42174       if ( ncvarid == CDI_UNDEFID ) Warning("Time variable >%s< not found!", ncdims[timedimid].name);
42175     }
42176 
42177   // time varID
42178   ncvarid = streamptr->basetime.ncvarid;
42179 
42180   if ( ncvarid != CDI_UNDEFID && streamptr->basetime.lwrf == false )
42181     {
42182       ncvar_t *ncvar = &ncvars[ncvarid];
42183       if ( ncvar->units[0] != 0 ) *time_has_units = true;
42184 
42185       if ( ncvar->bounds != CDI_UNDEFID )
42186         {
42187           int nbdims = ncvars[ncvar->bounds].ndims;
42188           if ( nbdims == 2 )
42189             {
42190               int len = (int) ncdims[ncvars[ncvar->bounds].dimids[nbdims-1]].len;
42191               if ( len == 2 && timedimid == ncvars[ncvar->bounds].dimids[0] )
42192                 {
42193                   *time_has_bounds = true;
42194                   streamptr->basetime.ncvarboundsid = ncvar->bounds;
42195                   if ( ncvar->climatology ) *time_climatology = true;
42196                 }
42197             }
42198         }
42199     }
42200 }
42201 
42202 static
read_vct_echam(int fileID,int nvars,ncvar_t * ncvars,ncdim_t * ncdims,double ** vct,size_t * pvctsize)42203 void read_vct_echam(int fileID, int nvars, ncvar_t *ncvars, ncdim_t *ncdims, double **vct, size_t *pvctsize)
42204 {
42205   /* find ECHAM VCT */
42206   int nvcth_id = CDI_UNDEFID, vcta_id = CDI_UNDEFID, vctb_id = CDI_UNDEFID;
42207 
42208   for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
42209     {
42210       if ( ncvars[ncvarid].ndims == 1 )
42211         {
42212           size_t len = strlen(ncvars[ncvarid].name);
42213           if ( len == 4 && ncvars[ncvarid].name[0] == 'h' && ncvars[ncvarid].name[1] == 'y' )
42214             {
42215               if ( ncvars[ncvarid].name[2] == 'a' && ncvars[ncvarid].name[3] == 'i' ) // hyai
42216                 {
42217                   vcta_id = ncvarid;
42218                   nvcth_id = ncvars[ncvarid].dimids[0];
42219                   ncvars[ncvarid].isvar = FALSE;
42220                 }
42221               else if ( ncvars[ncvarid].name[2] == 'b' && ncvars[ncvarid].name[3] == 'i' ) //hybi
42222                 {
42223                   vctb_id = ncvarid;
42224                   nvcth_id = ncvars[ncvarid].dimids[0];
42225                   ncvars[ncvarid].isvar = FALSE;
42226                 }
42227               else if ( (ncvars[ncvarid].name[2] == 'a' || ncvars[ncvarid].name[2] == 'b') && ncvars[ncvarid].name[3] == 'm' )
42228                 {
42229                   ncvars[ncvarid].isvar = FALSE; // hyam or hybm
42230                 }
42231             }
42232 	}
42233     }
42234 
42235   /* read VCT */
42236   if ( nvcth_id != CDI_UNDEFID && vcta_id != CDI_UNDEFID && vctb_id != CDI_UNDEFID )
42237     {
42238       size_t vctsize = ncdims[nvcth_id].len;
42239       vctsize *= 2;
42240       *vct = (double *) Malloc(vctsize*sizeof(double));
42241       cdf_get_var_double(fileID, vcta_id, *vct);
42242       cdf_get_var_double(fileID, vctb_id, *vct+vctsize/2);
42243       *pvctsize = vctsize;
42244     }
42245 }
42246 
42247 static
cdf_set_ucla_dimtype(int ndims,ncdim_t * ncdims,ncvar_t * ncvars)42248 void cdf_set_ucla_dimtype(int ndims, ncdim_t *ncdims, ncvar_t *ncvars)
42249 {
42250   for ( int ncdimid = 0; ncdimid < ndims; ncdimid++ )
42251     {
42252       int ncvarid = ncdims[ncdimid].ncvarid;
42253       if ( ncvarid != -1 )
42254         {
42255           if ( ncdims[ncdimid].dimtype == CDI_UNDEFID && ncvars[ncvarid].units[0] == 'm' )
42256             {
42257               if      ( ncvars[ncvarid].name[0] == 'x' ) ncdims[ncdimid].dimtype = X_AXIS;
42258               else if ( ncvars[ncvarid].name[0] == 'y' ) ncdims[ncdimid].dimtype = Y_AXIS;
42259               else if ( ncvars[ncvarid].name[0] == 'z' ) ncdims[ncdimid].dimtype = Z_AXIS;
42260             }
42261         }
42262     }
42263 }
42264 
42265 static
cdfCheckVars(stream_t * streamptr,int nvars,ncvar_t * ncvars,size_t ntsteps,int timedimid)42266 int cdfCheckVars(stream_t *streamptr, int nvars, ncvar_t *ncvars, size_t ntsteps, int timedimid)
42267 {
42268   for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
42269     {
42270       if (ncvars[ncvarid].istime && ncvars[ncvarid].ndims == 2)
42271         {
42272           ncvars[ncvarid].isvar = 0;
42273           continue;
42274         }
42275 
42276       if ( timedimid != CDI_UNDEFID )
42277 	if ( ncvars[ncvarid].isvar == -1 &&
42278 	     ncvars[ncvarid].ndims > 1   &&
42279 	     timedimid == ncvars[ncvarid].dimids[0] )
42280 	  cdf_set_var(ncvars, ncvarid, TRUE);
42281 
42282       if ( ncvars[ncvarid].isvar == -1 )
42283         {
42284           if ( ncvars[ncvarid].ndims == 0 )
42285             cdf_set_var(ncvars, ncvarid, nvars == 1 ? TRUE : FALSE);
42286           else if ( ncvars[ncvarid].ndims > 0 )
42287             cdf_set_var(ncvars, ncvarid, TRUE);
42288           else
42289             {
42290               ncvars[ncvarid].isvar = 0;
42291               Warning("Variable %s has an unknown type, skipped!", ncvars[ncvarid].name);
42292             }
42293         }
42294 
42295       if ( ncvars[ncvarid].isvar == 0 ) continue;
42296 
42297       if ( ncvars[ncvarid].ndims > 4 )
42298 	{
42299 	  ncvars[ncvarid].isvar = 0;
42300 	  Warning("%d dimensional variables are not supported, skipped variable %s!",
42301                   ncvars[ncvarid].ndims, ncvars[ncvarid].name);
42302 	  continue;
42303 	}
42304 
42305       if ( ncvars[ncvarid].ndims == 4 && timedimid == CDI_UNDEFID )
42306 	{
42307 	  ncvars[ncvarid].isvar = 0;
42308 	  Warning("%d dimensional variables without time dimension are not supported, skipped variable %s!",
42309                   ncvars[ncvarid].ndims, ncvars[ncvarid].name);
42310 	  continue;
42311 	}
42312 
42313       if ( xtypeIsText(ncvars[ncvarid].xtype) )
42314 	{
42315 	  ncvars[ncvarid].isvar = 0;
42316 	  Warning("Unsupported data type (char/string), skipped variable %s!", ncvars[ncvarid].name);
42317 	  continue;
42318 	}
42319 
42320       if ( cdfInqDatatype(streamptr, ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned) == -1 )
42321 	{
42322 	  ncvars[ncvarid].isvar = 0;
42323 	  Warning("Unsupported data type, skipped variable %s!", ncvars[ncvarid].name);
42324 	  continue;
42325 	}
42326 
42327       if ( timedimid != CDI_UNDEFID && ntsteps == 0 && ncvars[ncvarid].ndims > 0 )
42328 	{
42329 	  if ( timedimid == ncvars[ncvarid].dimids[0] )
42330 	    {
42331 	      ncvars[ncvarid].isvar = 0;
42332 	      Warning("Number of time steps undefined, skipped variable %s!", ncvars[ncvarid].name);
42333 	      continue;
42334 	    }
42335 	}
42336     }
42337 
42338   return timedimid;
42339 }
42340 
42341 static
cdfVerifyVars(int nvars,ncvar_t * ncvars,ncdim_t * ncdims)42342 void cdfVerifyVars(int nvars, ncvar_t *ncvars, ncdim_t *ncdims)
42343 {
42344   for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
42345     {
42346       if (ncvars[ncvarid].isvar == 1 && ncvars[ncvarid].ndims > 0 )
42347         {
42348           int ndims = 0;
42349           for (int i = 0; i < ncvars[ncvarid].ndims; ++i)
42350             {
42351               if      (ncvars[ncvarid].dimtype[i] == T_AXIS) ndims++;
42352               else if (ncvars[ncvarid].dimtype[i] == Z_AXIS) ndims++;
42353               else if (ncvars[ncvarid].dimtype[i] == Y_AXIS) ndims++;
42354               else if (ncvars[ncvarid].dimtype[i] == X_AXIS) ndims++;
42355             }
42356 
42357           if ( ncvars[ncvarid].ndims != ndims )
42358             {
42359               ncvars[ncvarid].isvar = 0;
42360               Warning("Inconsistent number of dimensions, skipped variable %s!", ncvars[ncvarid].name);
42361             }
42362 
42363           int zdimid = -1;
42364           for (int i = 0; i < ncvars[ncvarid].ndims; ++i)
42365             {
42366               if (ncvars[ncvarid].dimtype[i] == Z_AXIS) zdimid = ncvars[ncvarid].dimids[i];
42367             }
42368 
42369           int zaxisID = ncvars[ncvarid].zaxisID;
42370           if (zaxisInqScalar(zaxisID) && zdimid != -1)
42371             {
42372               ncvars[ncvarid].isvar = 0;
42373               Warning("Unsupported dimension >%s<, skipped variable %s!", ncdims[zdimid].name, ncvars[ncvarid].name);
42374             }
42375         }
42376     }
42377 }
42378 
42379 
cdfInqContents(stream_t * streamptr)42380 int cdfInqContents(stream_t *streamptr)
42381 {
42382   int ndims, nvars, ngatts, unlimdimid;
42383   int ncvarid;
42384   bool time_has_units = false;
42385   bool time_has_bounds = false;
42386   bool time_climatology = false;
42387   int leadtime_id = CDI_UNDEFID;
42388   int instID  = CDI_UNDEFID;
42389   int modelID = CDI_UNDEFID;
42390   int calendar = CDI_UNDEFID;
42391   int format = 0;
42392   bool ucla_les = false;
42393   char gridfile[8912];
42394   char fcreftime[CDI_MAX_NAME];
42395   int number_of_grid_used = CDI_UNDEFID;
42396 
42397   unsigned char uuidOfHGrid[CDI_UUID_SIZE];
42398   unsigned char uuidOfVGrid[CDI_UUID_SIZE];
42399   memset(uuidOfHGrid, 0, CDI_UUID_SIZE);
42400   memset(uuidOfVGrid, 0, CDI_UUID_SIZE);
42401   gridfile[0] = 0;
42402   fcreftime[0] = 0;
42403 
42404   int vlistID = streamptr->vlistID;
42405   int fileID  = streamptr->fileID;
42406 
42407   if ( CDI_Debug ) Message("streamID = %d, fileID = %d", streamptr->self, fileID);
42408 
42409 #ifdef HAVE_NETCDF4
42410   nc_inq_format(fileID, &format);
42411 #endif
42412 
42413   cdf_inq(fileID, &ndims , &nvars, &ngatts, &unlimdimid);
42414 
42415   if ( CDI_Debug )
42416     Message("root: ndims %d, nvars %d, ngatts %d", ndims, nvars, ngatts);
42417   /*
42418   if ( ndims == 0 )
42419     {
42420       Warning("No dimensions found!");
42421       return CDI_EUFSTRUCT;
42422     }
42423   */
42424   // alloc ncdims
42425   ncdim_t *ncdims = ndims ? (ncdim_t *) Malloc((size_t)ndims * sizeof(ncdim_t)) : NULL;
42426   init_ncdims(ndims, ncdims);
42427 
42428   int ncdimid = 0;
42429   size_t dimlen;
42430   for ( int dimid = 0; dimid < NC_MAX_DIMS; ++dimid )
42431     {
42432       int status = nc_inq_dimlen(fileID, dimid, &dimlen);
42433       if ( status == NC_NOERR )
42434         {
42435           ncdims[ncdimid++].dimid = dimid;
42436           if ( ncdimid == ndims ) break;
42437         }
42438     }
42439 
42440 #ifdef  HAVE_NETCDF4
42441   if ( format == NC_FORMAT_NETCDF4 )
42442     {
42443       int numgrps = 0;
42444       int ncids[NC_MAX_VARS];
42445       char gname[CDI_MAX_NAME];
42446       int gndims, gnvars, gngatts, gunlimdimid;
42447       nc_inq_grps(fileID, &numgrps, ncids);
42448       for ( int i = 0; i < numgrps; ++i )
42449         {
42450           int ncid = ncids[i];
42451           nc_inq_grpname(ncid, gname);
42452           cdf_inq(ncid, &gndims , &gnvars, &gngatts, &gunlimdimid);
42453 
42454           if ( CDI_Debug )
42455             Message("%s: ndims %d, nvars %d, ngatts %d", gname, gndims, gnvars, gngatts);
42456 
42457           if ( gndims == 0 )
42458             {
42459             }
42460         }
42461       if ( numgrps ) Warning("NetCDF4 groups not supported! Found %d root group%s.", numgrps, numgrps>1?"s":"");
42462     }
42463 #endif
42464 
42465   if ( nvars == 0 )
42466     {
42467       Warning("No arrays found!");
42468       return CDI_EUFSTRUCT;
42469     }
42470 
42471   // alloc ncvars
42472   ncvar_t *ncvars = (ncvar_t *) Malloc((size_t)nvars * sizeof (ncvar_t));
42473   init_ncvars(nvars, ncvars);
42474 
42475   for ( ncvarid = 0; ncvarid < nvars; ++ncvarid ) ncvars[ncvarid].ncid = fileID;
42476 
42477 
42478   // scan global attributes
42479   cdf_scan_global_attr(fileID, vlistID, ngatts, &instID, &modelID, &ucla_les,
42480                        uuidOfHGrid, uuidOfVGrid, gridfile, &number_of_grid_used);
42481 
42482   // find time dim
42483   int timedimid = (unlimdimid >= 0) ? unlimdimid : cdf_time_dimid(fileID, ndims, nvars, ncdims);
42484 
42485   streamptr->basetime.ncdimid = timedimid;
42486 
42487   size_t ntsteps = 0;
42488   if ( timedimid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, ncdims[timedimid].dimid, &ntsteps);
42489   if ( ntsteps > INT_MAX )
42490     {
42491       Warning("Size limit exceeded for time dimension (limit=%d)!", INT_MAX);
42492       return CDI_EDIMSIZE;
42493     }
42494 
42495   if ( CDI_Debug ) Message("Number of timesteps = %zu", ntsteps);
42496   if ( CDI_Debug ) Message("Time dimid = %d", streamptr->basetime.ncdimid);
42497 
42498   // read ncdims
42499   for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
42500     {
42501       cdf_inq_dimlen(fileID, ncdims[ncdimid].dimid, &ncdims[ncdimid].len);
42502       cdf_inq_dimname(fileID, ncdims[ncdimid].dimid, ncdims[ncdimid].name);
42503       if ( timedimid == ncdimid )
42504         ncdims[ncdimid].dimtype = T_AXIS;
42505     }
42506 
42507   if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "cdfScanVarAttr");
42508 
42509   // scan attributes of all variables
42510   cdfScanVarAttr(nvars, ncvars, ndims, ncdims, timedimid, modelID, format);
42511 
42512   cdfVerifyVarAttr(nvars, ncvars, ncdims);
42513 
42514 
42515   if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "find coordinate vars");
42516 
42517   // find coordinate vars
42518   for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
42519     {
42520       for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
42521 	{
42522 	  if ( ncvars[ncvarid].ndims == 1 )
42523 	    {
42524 	      if ( timedimid != CDI_UNDEFID && timedimid == ncvars[ncvarid].dimids[0] )
42525 		{
42526 		  if ( ncvars[ncvarid].isvar != FALSE ) cdf_set_var(ncvars, ncvarid, TRUE);
42527 		}
42528 	      else
42529 		{
42530                   //  if ( ncvars[ncvarid].isvar != TRUE ) cdf_set_var(ncvars, ncvarid, FALSE);
42531 		}
42532 	      // if ( ncvars[ncvarid].isvar != TRUE ) cdf_set_var(ncvars, ncvarid, FALSE);
42533 
42534 	      if ( ncdimid == ncvars[ncvarid].dimids[0] && ncdims[ncdimid].ncvarid == CDI_UNDEFID )
42535 		if ( strIsEqual(ncvars[ncvarid].name, ncdims[ncdimid].name) )
42536 		  {
42537 		    ncdims[ncdimid].ncvarid = ncvarid;
42538 		    ncvars[ncvarid].isvar = FALSE;
42539 		  }
42540 	    }
42541 	}
42542     }
42543 
42544   // find time vars
42545   find_time_vars(nvars, ncvars, ncdims, timedimid, streamptr, &time_has_units, &time_has_bounds, &time_climatology);
42546 
42547   leadtime_id = find_leadtime(nvars, ncvars, timedimid);
42548   if ( leadtime_id != CDI_UNDEFID ) ncvars[leadtime_id].isvar = FALSE;
42549 
42550   // check ncvars
42551   timedimid = cdfCheckVars(streamptr, nvars, ncvars, ntsteps, timedimid);
42552 
42553   // verify coordinate vars - first scan (dimname == varname)
42554   bool lhybrid_cf = false;
42555   verify_coordinate_vars_1(fileID, ndims, ncdims, ncvars, timedimid, &lhybrid_cf);
42556 
42557   // verify coordinate vars - second scan (all other variables)
42558   verify_coordinate_vars_2(streamptr, nvars, ncvars);
42559 
42560   if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "verify_coordinate_vars");
42561 
42562   if ( ucla_les ) cdf_set_ucla_dimtype(ndims, ncdims, ncvars);
42563 
42564   /*
42565   for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
42566     {
42567       ncvarid = ncdims[ncdimid].ncvarid;
42568       if ( ncvarid != -1 )
42569 	{
42570 	  printf("coord var %d %s %s\n", ncvarid, ncvars[ncvarid].name, ncvars[ncvarid].units);
42571 	  if ( ncdims[ncdimid].dimtype == X_AXIS )
42572 	    printf("coord var %d %s is x dim\n", ncvarid, ncvars[ncvarid].name);
42573 	  if ( ncdims[ncdimid].dimtype == Y_AXIS )
42574 	    printf("coord var %d %s is y dim\n", ncvarid, ncvars[ncvarid].name);
42575 	  if ( ncdims[ncdimid].dimtype == Z_AXIS )
42576 	    printf("coord var %d %s is z dim\n", ncvarid, ncvars[ncvarid].name);
42577 	  if ( ncdims[ncdimid].dimtype == T_AXIS )
42578 	    printf("coord var %d %s is t dim\n", ncvarid, ncvars[ncvarid].name);
42579 
42580 	  if ( ncvars[ncvarid].islon )
42581 	    printf("coord var %d %s is lon\n", ncvarid, ncvars[ncvarid].name);
42582 	  if ( ncvars[ncvarid].islat )
42583 	    printf("coord var %d %s is lat\n", ncvarid, ncvars[ncvarid].name);
42584 	  if ( ncvars[ncvarid].islev )
42585 	    printf("coord var %d %s is lev\n", ncvarid, ncvars[ncvarid].name);
42586 	}
42587     }
42588   */
42589 
42590   // Set coordinate varids (att: associate)
42591   for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
42592     {
42593       ncvar_t *ncvar = &ncvars[ncvarid];
42594       if ( ncvar->isvar == TRUE && ncvar->ncoordvars )
42595 	{
42596 	  for ( int i = 0; i < ncvar->ncoordvars; i++ )
42597 	    {
42598               const int cvarid = ncvar->coordvarids[i];
42599               if ( ncvar->coordvarids[i] != CDI_UNDEFID )
42600                 {
42601                   if      (ncvars[cvarid].islon || ncvars[cvarid].isx)   ncvar->xvarid = cvarid;
42602                   else if (ncvars[cvarid].islat || ncvars[cvarid].isy)   ncvar->yvarid = cvarid;
42603                   else if (ncvars[cvarid].islev)  ncvar->zvarid = cvarid;
42604                   else if (ncvars[cvarid].istime) ncvar->tvarid = cvarid;
42605                   else if (ncvars[cvarid].isc)    ncvar->cvarids[i] = cvarid;
42606                   else if (ncvars[cvarid].warn == false)
42607                     {
42608                       Warning("Coordinates variable %s can't be assigned!", ncvars[cvarid].name);
42609                       ncvars[ncvarid].warn = true;
42610                     }
42611                 }
42612             }
42613 	}
42614     }
42615 
42616   // set dim type
42617   cdf_set_dimtype(nvars, ncvars, ncdims);
42618 
42619   // read ECHAM VCT if present
42620   size_t vctsize = 0;
42621   double *vct = NULL;
42622   if ( !lhybrid_cf ) read_vct_echam(fileID, nvars, ncvars, ncdims, &vct, &vctsize);
42623 
42624 
42625   if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "cdf_define_all_grids");
42626 
42627   // define all grids
42628   int status;
42629   status = cdf_define_all_grids(streamptr, streamptr->ncgrid, vlistID, ncdims, nvars, ncvars, timedimid, uuidOfHGrid, gridfile, number_of_grid_used);
42630   if ( status < 0 ) return status;
42631 
42632   // define all zaxes
42633   status = cdf_define_all_zaxes(streamptr, vlistID, ncdims, nvars, ncvars, vctsize, vct, uuidOfVGrid);
42634   if ( vct ) Free(vct);
42635   if ( status < 0 ) return status;
42636 
42637   // verify vars
42638   cdfVerifyVars(nvars, ncvars, ncdims);
42639 
42640   // select vars
42641   int nvars_data = 0;
42642   for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
42643     if ( ncvars[ncvarid].isvar == TRUE ) nvars_data++;
42644 
42645   if ( CDI_Debug ) Message("time varid = %d", streamptr->basetime.ncvarid);
42646   if ( CDI_Debug ) Message("ntsteps = %zu", ntsteps);
42647   if ( CDI_Debug ) Message("nvars_data = %d", nvars_data);
42648 
42649   if ( nvars_data == 0 )
42650     {
42651       streamptr->ntsteps = 0;
42652       Warning("No data arrays found!");
42653       return CDI_EUFSTRUCT;
42654     }
42655 
42656   if ( ntsteps == 0 && streamptr->basetime.ncdimid == CDI_UNDEFID && streamptr->basetime.ncvarid != CDI_UNDEFID )
42657     ntsteps = 1;
42658 
42659   streamptr->ntsteps = (long)ntsteps;
42660 
42661   // define all data variables
42662   cdf_define_all_vars(streamptr, vlistID, instID, modelID, nvars_data, nvars, ncvars, ncdims);
42663 
42664 
42665   cdiCreateTimesteps(streamptr);
42666 
42667   // time varID
42668   int nctimevarid = streamptr->basetime.ncvarid;
42669 
42670   if (nctimevarid != CDI_UNDEFID && (!time_has_units || streamptr->basetime.lwrf)) ncvars[nctimevarid].units[0] = 0;
42671   if (nctimevarid != CDI_UNDEFID && time_has_units) streamptr->basetime.lunits = true;
42672 
42673   if ( time_has_units )
42674     {
42675       taxis_t *taxis = &streamptr->tsteps[0].taxis;
42676 
42677       if ( setBaseTime(ncvars[nctimevarid].units, taxis) == 1 )
42678         {
42679           nctimevarid = CDI_UNDEFID;
42680           streamptr->basetime.ncvarid = CDI_UNDEFID;
42681           streamptr->basetime.lunits = false;
42682         }
42683 
42684       if ( leadtime_id != CDI_UNDEFID && taxis->type == TAXIS_RELATIVE )
42685         {
42686           streamptr->basetime.leadtimeid = leadtime_id;
42687           taxis->type = TAXIS_FORECAST;
42688 
42689           int timeunit = -1;
42690           if ( ncvars[leadtime_id].units[0] != 0 ) timeunit = scanTimeUnit(ncvars[leadtime_id].units);
42691           if ( timeunit == -1 ) timeunit = taxis->unit;
42692           taxis->fc_unit = timeunit;
42693 
42694           setForecastTime(fcreftime, taxis);
42695         }
42696     }
42697 
42698   if ( time_has_bounds )
42699     {
42700       streamptr->tsteps[0].taxis.has_bounds = true;
42701       if ( time_climatology ) streamptr->tsteps[0].taxis.climatology = true;
42702     }
42703 
42704   if ( nctimevarid != CDI_UNDEFID )
42705     {
42706       taxis_t *taxis = &streamptr->tsteps[0].taxis;
42707       ptaxisDefName(taxis, ncvars[nctimevarid].name);
42708 
42709       if ( ncvars[nctimevarid].longname[0] )
42710         ptaxisDefLongname(taxis, ncvars[nctimevarid].longname);
42711 
42712       if ( ncvars[nctimevarid].units[0] )
42713         ptaxisDefUnits(taxis, ncvars[nctimevarid].units);
42714 
42715       int xtype = ncvars[nctimevarid].xtype;
42716       int datatype = (xtype == NC_INT) ? CDI_DATATYPE_INT32 : ((xtype == NC_FLOAT) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64);
42717       ptaxisDefDatatype(taxis, datatype);
42718     }
42719 
42720   if ( nctimevarid != CDI_UNDEFID )
42721     if ( ncvars[nctimevarid].calendar == true )
42722       {
42723         char attstring[1024];
42724 	cdfGetAttText(fileID, nctimevarid, "calendar", sizeof(attstring), attstring);
42725 	strToLower(attstring);
42726         cdf_set_calendar(attstring, &calendar);
42727       }
42728 
42729   int taxisID;
42730   if ( streamptr->tsteps[0].taxis.type == TAXIS_FORECAST )
42731     {
42732       taxisID = taxisCreate(TAXIS_FORECAST);
42733     }
42734   else if ( streamptr->tsteps[0].taxis.type == TAXIS_RELATIVE )
42735     {
42736       taxisID = taxisCreate(TAXIS_RELATIVE);
42737     }
42738   else
42739     {
42740       taxisID = taxisCreate(TAXIS_ABSOLUTE);
42741       if ( !time_has_units )
42742 	{
42743 	  taxisDefTunit(taxisID, TUNIT_DAY);
42744 	  streamptr->tsteps[0].taxis.unit = TUNIT_DAY;
42745 	}
42746     }
42747 
42748 
42749   if ( calendar == CDI_UNDEFID && streamptr->tsteps[0].taxis.type != TAXIS_ABSOLUTE )
42750     {
42751       calendar = CALENDAR_STANDARD;
42752     }
42753 
42754 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
42755 #pragma GCC diagnostic push
42756 #pragma GCC diagnostic warning "-Wstrict-overflow"
42757 #endif
42758   if ( calendar != CDI_UNDEFID )
42759     {
42760       taxis_t *taxis = &streamptr->tsteps[0].taxis;
42761       taxis->calendar = calendar;
42762       taxisDefCalendar(taxisID, calendar);
42763     }
42764 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
42765 #pragma GCC diagnostic pop
42766 #endif
42767 
42768   vlistDefTaxis(vlistID, taxisID);
42769 
42770   streamptr->curTsID = 0;
42771   streamptr->rtsteps = 1;
42772 
42773   (void) cdfInqTimestep(streamptr, 0);
42774 
42775   cdfCreateRecords(streamptr, 0);
42776 
42777   // free ncdims
42778   if ( ncdims ) Free(ncdims);
42779 
42780   // free ncvars
42781   if ( ncvars ) Free(ncvars);
42782 
42783   return 0;
42784 }
42785 
42786 static
wrf_read_timestep(int fileID,int nctimevarid,int tsID,taxis_t * taxis)42787 void wrf_read_timestep(int fileID, int nctimevarid, int tsID, taxis_t *taxis)
42788 {
42789   size_t start[2], count[2];
42790   char stvalue[128];
42791   start[0] = (size_t) tsID; start[1] = 0;
42792   count[0] = 1; count[1] = 19;
42793   stvalue[0] = 0;
42794   cdf_get_vara_text(fileID, nctimevarid, start, count, stvalue);
42795   stvalue[19] = 0;
42796   {
42797     int year = 1, month = 1, day = 1 , hour = 0, minute = 0, second = 0;
42798     if ( strlen(stvalue) == 19 )
42799       sscanf(stvalue, "%d-%d-%d_%d:%d:%d", &year, &month, &day, &hour, &minute, &second);
42800     taxis->vdate = cdiEncodeDate(year, month, day);
42801     taxis->vtime = cdiEncodeTime(hour, minute, second);
42802     taxis->type = TAXIS_ABSOLUTE;
42803   }
42804 }
42805 
42806 static
get_timevalue(int fileID,int nctimevarid,int tsID,timecache_t * tcache)42807 double get_timevalue(int fileID, int nctimevarid, int tsID, timecache_t *tcache)
42808 {
42809   double timevalue = 0;
42810 
42811   if ( tcache )
42812     {
42813       if ( tcache->size == 0 || (tsID < (int)tcache->startid || tsID > (int)(tcache->startid+tcache->size-1)) )
42814         {
42815           size_t maxvals = MAX_TIMECACHE_SIZE;
42816           if (maxvals > tcache->maxvals) maxvals = tcache->maxvals;
42817           tcache->startid = tsID;
42818           //tcache->startid = (tsID/MAX_TIMECACHE_SIZE)*MAX_TIMECACHE_SIZE;
42819           //if ( (tcache->startid + maxvals) > tcache->maxvals ) maxvals = (tcache->maxvals)%MAX_TIMECACHE_SIZE;
42820           tcache->size = maxvals;
42821           //fprintf(stderr, "fill time cache: %d %d %d %d %d\n", tcache->maxvals, tsID, tcache->startid, tcache->startid+maxvals-1, maxvals);
42822           cdf_get_vara_double(fileID, nctimevarid, &tcache->startid, &maxvals, tcache->cache);
42823         }
42824 
42825       //timevalue = tcache->cache[tsID%MAX_TIMECACHE_SIZE];
42826       timevalue = tcache->cache[tsID];
42827     }
42828   else
42829     {
42830       size_t index = (size_t) tsID;
42831       cdf_get_var1_double(fileID, nctimevarid, &index, &timevalue);
42832     }
42833 
42834   if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
42835 
42836   return timevalue;
42837 }
42838 
42839 
cdfInqTimestep(stream_t * streamptr,int tsID)42840 int cdfInqTimestep(stream_t * streamptr, int tsID)
42841 {
42842   if ( CDI_Debug ) Message("streamID = %d  tsID = %d", streamptr->self, tsID);
42843 
42844   if ( tsID < 0 ) Error("unexpected tsID = %d", tsID);
42845 
42846   if ( tsID < streamptr->ntsteps && streamptr->ntsteps > 0 )
42847     {
42848       cdfCreateRecords(streamptr, tsID);
42849 
42850       taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
42851       if ( tsID > 0 )
42852 	ptaxisCopy(taxis, &streamptr->tsteps[0].taxis);
42853 
42854       double timevalue = tsID;
42855 
42856       int nctimevarid = streamptr->basetime.ncvarid;
42857       if (nctimevarid != CDI_UNDEFID && streamptr->basetime.lunits)
42858 	{
42859 	  int fileID = streamptr->fileID;
42860 	  size_t index = (size_t)tsID;
42861 
42862 	  if ( streamptr->basetime.lwrf )
42863 	    {
42864               wrf_read_timestep(fileID, nctimevarid, tsID, taxis);
42865 	    }
42866 	  else
42867 	    {
42868 #ifdef USE_TIMECACHE
42869               if ( streamptr->basetime.timevar_cache == NULL )
42870                 {
42871                   streamptr->basetime.timevar_cache = (timecache_t *) Malloc(sizeof(timecache_t));
42872                   streamptr->basetime.timevar_cache->size = 0;
42873                   streamptr->basetime.timevar_cache->maxvals = streamptr->ntsteps;
42874                 }
42875 #endif
42876               timevalue = get_timevalue(fileID, nctimevarid, tsID, streamptr->basetime.timevar_cache);
42877 	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate, &taxis->vtime);
42878 	    }
42879 
42880 	  int nctimeboundsid = streamptr->basetime.ncvarboundsid;
42881 	  if ( nctimeboundsid != CDI_UNDEFID )
42882 	    {
42883 	      size_t start[2], count[2];
42884               start[0] = index; count[0] = 1; start[1] = 0; count[1] = 1;
42885 	      cdf_get_vara_double(fileID, nctimeboundsid, start, count, &timevalue);
42886               if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
42887 
42888 	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_lb, &taxis->vtime_lb);
42889 
42890               start[0] = index; count[0] = 1; start[1] = 1; count[1] = 1;
42891 	      cdf_get_vara_double(fileID, nctimeboundsid, start, count, &timevalue);
42892               if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
42893 
42894 	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_ub, &taxis->vtime_ub);
42895 	    }
42896 
42897           int leadtimeid = streamptr->basetime.leadtimeid;
42898           if ( leadtimeid != CDI_UNDEFID )
42899             {
42900               timevalue = get_timevalue(fileID, leadtimeid, tsID, NULL);
42901               cdiSetForecastPeriod(timevalue, taxis);
42902             }
42903 	}
42904     }
42905 
42906   streamptr->curTsID = tsID;
42907   long nrecs = streamptr->tsteps[tsID].nrecs;
42908 
42909   return (int) nrecs;
42910 }
42911 
42912 #endif
42913 /*
42914  * Local Variables:
42915  * c-file-style: "Java"
42916  * c-basic-offset: 2
42917  * indent-tabs-mode: nil
42918  * show-trailing-whitespace: t
42919  * require-trailing-newline: t
42920  * End:
42921  */
42922 #ifdef HAVE_CONFIG_H
42923 #endif
42924 
42925 #ifdef HAVE_LIBNETCDF
42926 
42927 
42928 
42929 #define  POSITIVE_UP    1
42930 #define  POSITIVE_DOWN  2
42931 
42932 
42933 static const char bndsName[] = "bnds";
42934 
42935 
cdfCopyRecord(stream_t * streamptr2,stream_t * streamptr1)42936 void cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
42937 {
42938   int vlistID1 = streamptr1->vlistID;
42939   int tsID     = streamptr1->curTsID;
42940   int vrecID   = streamptr1->tsteps[tsID].curRecID;
42941   int recID    = streamptr1->tsteps[tsID].recIDs[vrecID];
42942   int ivarID   = streamptr1->tsteps[tsID].records[recID].varID;
42943   int gridID   = vlistInqVarGrid(vlistID1, ivarID);
42944   size_t datasize = gridInqSize(gridID);
42945   int datatype = vlistInqVarDatatype(vlistID1, ivarID);
42946   int memtype  = datatype != CDI_DATATYPE_FLT32 ? MEMTYPE_DOUBLE : MEMTYPE_FLOAT;
42947 
42948   void *data = Malloc(datasize * (memtype == MEMTYPE_DOUBLE ? sizeof(double) : sizeof(float)));
42949 
42950   size_t nmiss;
42951   cdf_read_record(streamptr1, memtype, data, &nmiss);
42952   cdf_write_record(streamptr2, memtype, data, nmiss);
42953 
42954   Free(data);
42955 }
42956 
42957 
cdfDefRecord(stream_t * streamptr)42958 void cdfDefRecord(stream_t *streamptr)
42959 {
42960   (void)streamptr;
42961 }
42962 
42963 static
cdfDefTimeValue(stream_t * streamptr,int tsID)42964 void cdfDefTimeValue(stream_t *streamptr, int tsID)
42965 {
42966   const int fileID = streamptr->fileID;
42967 
42968   if ( CDI_Debug ) Message("streamID = %d, fileID = %d", streamptr->self, fileID);
42969 
42970   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
42971 
42972   if ( streamptr->ncmode == 1 )
42973     {
42974       cdf_enddef(fileID);
42975       streamptr->ncmode = 2;
42976     }
42977 
42978   double timevalue = cdiEncodeTimeval(taxis->vdate, taxis->vtime, &streamptr->tsteps[0].taxis);
42979   if ( CDI_Debug ) Message("tsID = %d  timevalue = %f", tsID, timevalue);
42980 
42981   int ncvarid = streamptr->basetime.ncvarid;
42982   size_t index = (size_t)tsID;
42983   cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
42984 
42985   if ( taxis->has_bounds )
42986     {
42987       ncvarid = streamptr->basetime.ncvarboundsid;
42988       if ( ncvarid == CDI_UNDEFID ) Error("Call to taxisWithBounds() missing!");
42989 
42990       timevalue = cdiEncodeTimeval(taxis->vdate_lb, taxis->vtime_lb, &streamptr->tsteps[0].taxis);
42991       size_t start[2], count[2];
42992       start[0] = (size_t)tsID; count[0] = 1; start[1] = 0; count[1] = 1;
42993       cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);
42994 
42995       timevalue = cdiEncodeTimeval(taxis->vdate_ub, taxis->vtime_ub, &streamptr->tsteps[0].taxis);
42996       start[0] = (size_t)tsID; count[0] = 1; start[1] = 1; count[1] = 1;
42997       cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);
42998     }
42999 
43000   ncvarid = streamptr->basetime.leadtimeid;
43001   if ( taxis->type == TAXIS_FORECAST && ncvarid != CDI_UNDEFID )
43002     {
43003       timevalue = taxis->fc_period;
43004       cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
43005     }
43006 }
43007 
cdfDefTimestep(stream_t * streamptr,int tsID)43008 void cdfDefTimestep(stream_t *streamptr, int tsID)
43009 {
43010   cdfDefTimeValue(streamptr, tsID);
43011 }
43012 
43013 static
cdfDefComplex(stream_t * streamptr,int gridID,int gridindex)43014 void cdfDefComplex(stream_t *streamptr, int gridID, int gridindex)
43015 {
43016   int dimID;
43017   ncgrid_t *ncgrid = streamptr->ncgrid;
43018 
43019   for ( int index = 0; index < gridindex; ++index )
43020     {
43021       if ( ncgrid[index].ncIDs[CDF_DIMID_X] != CDI_UNDEFID )
43022         {
43023           const int gridID0 = ncgrid[index].gridID;
43024           const int gridtype0 = gridInqType(gridID0);
43025           if ( gridtype0 == GRID_SPECTRAL || gridtype0 == GRID_FOURIER )
43026             {
43027               dimID = ncgrid[index].ncIDs[CDF_DIMID_X];
43028               goto dimIDEstablished;
43029             }
43030         }
43031     }
43032 
43033   {
43034     static const char axisname[] = "nc2";
43035     const size_t dimlen = 2;
43036     const int fileID  = streamptr->fileID;
43037 
43038     if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
43039     cdf_def_dim(fileID, axisname, dimlen, &dimID);
43040     cdf_enddef(fileID);
43041     streamptr->ncmode = 2;
43042   }
43043   dimIDEstablished:
43044   ncgrid[gridindex].gridID = gridID;
43045   ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
43046 }
43047 
43048 struct idSearch
43049 {
43050   int numNonMatching, foundID;
43051   size_t foundIdx;
43052 };
43053 
43054 static inline struct idSearch
cdfSearchIDBySize(size_t startIdx,size_t numIDs,const ncgrid_t ncgrid[],int ncIDType,int searchType,int searchSize,int (* typeInq)(int id),size_t (* sizeInq)(int id))43055 cdfSearchIDBySize(size_t startIdx, size_t numIDs, const ncgrid_t ncgrid[/*numIDs*/],
43056                   int ncIDType, int searchType, int searchSize,
43057                   int (*typeInq)(int id), size_t (*sizeInq)(int id))
43058 {
43059   int numNonMatching = 0,
43060     foundID = CDI_UNDEFID;
43061   size_t foundIdx = SIZE_MAX;
43062   for ( size_t index = startIdx; index < numIDs; index++ )
43063     {
43064       if ( ncgrid[index].ncIDs[ncIDType] != CDI_UNDEFID )
43065         {
43066           int id0 = ncgrid[index].gridID,
43067             id0Type = typeInq(id0);
43068           if ( id0Type == searchType )
43069             {
43070               int size0 = sizeInq(id0);
43071               if ( searchSize == size0 )
43072                 {
43073                   foundID = ncgrid[index].ncIDs[ncIDType];
43074                   foundIdx = index;
43075                   break;
43076                 }
43077               numNonMatching++;
43078             }
43079         }
43080     }
43081   return (struct idSearch){ .numNonMatching = numNonMatching,
43082       .foundID = foundID, .foundIdx = foundIdx };
43083 }
43084 
43085 static size_t
cdfGridInqHalfSize(int gridID)43086 cdfGridInqHalfSize(int gridID)
43087 {
43088   return gridInqSize(gridID)/2;
43089 }
43090 
43091 static void
cdfDefSPorFC(stream_t * streamptr,int gridID,int gridindex,char * restrict axisname,int gridRefType)43092 cdfDefSPorFC(stream_t *streamptr, int gridID, int gridindex, char *restrict axisname, int gridRefType)
43093 {
43094   ncgrid_t *ncgrid = streamptr->ncgrid;
43095 
43096   const size_t dimlen = gridInqSize(gridID)/2;
43097 
43098   struct idSearch search
43099     = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_Y,
43100                         gridRefType, (int)dimlen, gridInqType, cdfGridInqHalfSize);
43101   int dimID = search.foundID;
43102   const int iz = search.numNonMatching;
43103 
43104   if ( dimID == CDI_UNDEFID )
43105     {
43106       int fileID  = streamptr->fileID;
43107       if ( iz == 0 ) axisname[3] = '\0';
43108       else           sprintf(&axisname[3], "%1d", iz+1);
43109 
43110       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
43111 
43112       cdf_def_dim(fileID, axisname, dimlen, &dimID);
43113 
43114       cdf_enddef(fileID);
43115       streamptr->ncmode = 2;
43116     }
43117 
43118   ncgrid[gridindex].gridID = gridID;
43119   ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = dimID;
43120 }
43121 
43122 static
cdfDefSP(stream_t * streamptr,int gridID,int gridindex)43123 void cdfDefSP(stream_t *streamptr, int gridID, int gridindex)
43124 {
43125   // char longname[] = "Spherical harmonic coefficient";
43126   char axisname[5] = "nspX";
43127   cdfDefSPorFC(streamptr, gridID, gridindex, axisname, GRID_SPECTRAL);
43128 }
43129 
43130 
43131 static
cdfDefFC(stream_t * streamptr,int gridID,int gridindex)43132 void cdfDefFC(stream_t *streamptr, int gridID, int gridindex)
43133 {
43134   char axisname[5] = "nfcX";
43135   cdfDefSPorFC(streamptr, gridID, gridindex, axisname, GRID_FOURIER);
43136 }
43137 
43138 static const struct cdfDefGridAxisInqs {
43139   size_t (*axisSize)(int gridID);
43140   double (*axisVal)(int gridID, size_t index);
43141   const double *(*axisValsPtr)(int gridID);
43142   const double *(*axisBoundsPtr)(int gridID);
43143 } gridInqsX = {
43144   .axisSize = gridInqXsize,
43145   .axisVal = gridInqXval,
43146   .axisValsPtr = gridInqXvalsPtr,
43147   .axisBoundsPtr = gridInqXboundsPtr,
43148 }, gridInqsY = {
43149   .axisSize = gridInqYsize,
43150   .axisVal = gridInqYval,
43151   .axisValsPtr = gridInqYvalsPtr,
43152   .axisBoundsPtr = gridInqYboundsPtr,
43153 };
43154 
43155 static
cdfPutGridStdAtts(int fileID,int ncvarid,int gridID,int dimtype)43156 void cdfPutGridStdAtts(int fileID, int ncvarid, int gridID, int dimtype)
43157 {
43158   size_t len;
43159 
43160   int axisKey = (dimtype == 'Z') ? CDI_GLOBAL : ((dimtype == 'X') ? CDI_XAXIS : CDI_YAXIS);
43161 
43162   char stdname[CDI_MAX_NAME];
43163   int length = CDI_MAX_NAME;
43164   cdiInqKeyString(gridID, axisKey, CDI_KEY_STDNAME, stdname, &length);
43165   if ( stdname[0] && (len = strlen(stdname)) )
43166     cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
43167 
43168   char longname[CDI_MAX_NAME];
43169   length = CDI_MAX_NAME;
43170   cdiInqKeyString(gridID, axisKey, CDI_KEY_LONGNAME, longname, &length);
43171   if ( longname[0] && (len = strlen(longname)) )
43172     cdf_put_att_text(fileID, ncvarid, "long_name", len, longname);
43173 
43174   char units[CDI_MAX_NAME];
43175   length = CDI_MAX_NAME;
43176   axisKey = (dimtype == 'Z') ? CDI_GLOBAL : ((dimtype == 'X') ? CDI_XAXIS : CDI_YAXIS);
43177   cdiInqKeyString(gridID, axisKey, CDI_KEY_UNITS, units, &length);
43178   if ( units[0] && (len = strlen(units)) )
43179     cdf_put_att_text(fileID, ncvarid, "units", len, units);
43180 }
43181 
43182 static void
cdfDefTrajLatLon(stream_t * streamptr,int gridID,int gridindex,const struct cdfDefGridAxisInqs * inqs,int dimtype)43183 cdfDefTrajLatLon(stream_t *streamptr, int gridID, int gridindex,
43184                  const struct cdfDefGridAxisInqs *inqs, int dimtype)
43185 {
43186   const nc_type xtype = (gridInqDatatype(gridID) == CDI_DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE;
43187   ncgrid_t *ncgrid = streamptr->ncgrid;
43188 
43189   const size_t dimlen = inqs->axisSize(gridID);
43190   if ( dimlen != 1 )
43191     Error("%c size isn't 1 for %s grid!", dimtype, gridNamePtr(gridInqType(gridID)));
43192 
43193   int ncvarid = ncgrid[gridindex].ncIDs[dimtype == 'X' ? CDF_DIMID_X : CDF_DIMID_Y];
43194 
43195   if ( ncvarid == CDI_UNDEFID )
43196     {
43197       int dimNcID = streamptr->basetime.ncvarid;
43198       const int fileID  = streamptr->fileID;
43199       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
43200 
43201       char axisname[CDI_MAX_NAME];
43202       const int axistype = (dimtype == 'X') ? CDI_XAXIS : CDI_YAXIS;
43203       int length = CDI_MAX_NAME;
43204       cdiInqKeyString(gridID, axistype, CDI_KEY_NAME, axisname, &length);
43205       cdf_def_var(fileID, axisname, xtype, 1, &dimNcID, &ncvarid);
43206       cdfPutGridStdAtts(fileID, ncvarid, gridID, dimtype);
43207       cdf_enddef(fileID);
43208       streamptr->ncmode = 2;
43209     }
43210 
43211   ncgrid[gridindex].gridID = gridID;
43212   /* var ID for trajectory !!! */
43213   ncgrid[gridindex].ncIDs[dimtype == 'X' ? CDF_DIMID_X : CDF_DIMID_Y] = ncvarid;
43214 }
43215 
43216 static
cdfDefTrajLon(stream_t * streamptr,int gridID,int gridindex)43217 void cdfDefTrajLon(stream_t *streamptr, int gridID, int gridindex)
43218 {
43219   cdfDefTrajLatLon(streamptr, gridID, gridindex, &gridInqsX, 'X');
43220 }
43221 
43222 
43223 static
cdfDefTrajLat(stream_t * streamptr,int gridID,int gridindex)43224 void cdfDefTrajLat(stream_t *streamptr, int gridID, int gridindex)
43225 {
43226   cdfDefTrajLatLon(streamptr, gridID, gridindex, &gridInqsY, 'Y');
43227 }
43228 
43229 static
checkDimName(int fileID,size_t dimlen,char * dimname)43230 int checkDimName(int fileID, size_t dimlen, char *dimname)
43231 {
43232   /* check whether the dimenion name is already defined with the same length */
43233   unsigned iz = 0;
43234   int dimid = CDI_UNDEFID;
43235   char name[CDI_MAX_NAME];
43236 
43237   const size_t len = strlen(dimname);
43238   memcpy(name, dimname, len + 1);
43239 
43240   do
43241     {
43242       if ( iz ) sprintf(name + len, "_%u", iz+1);
43243 
43244       int dimid0;
43245       const int status = nc_inq_dimid(fileID, name, &dimid0);
43246       if ( status != NC_NOERR ) break;
43247       size_t dimlen0;
43248       cdf_inq_dimlen(fileID, dimid0, &dimlen0);
43249       if ( dimlen0 == dimlen )
43250         {
43251           dimid = dimid0;
43252           break;
43253         }
43254       iz++;
43255     }
43256   while ( iz <= 99 );
43257 
43258 
43259   if ( iz ) sprintf(dimname + len, "_%u", iz+1);
43260 
43261   return dimid;
43262 }
43263 
43264 static
checkGridName(char * axisname,int fileID)43265 void checkGridName(char *axisname, int fileID)
43266 {
43267   int ncdimid;
43268   char axisname2[CDI_MAX_NAME];
43269 
43270   /* check that the name is not already defined */
43271   unsigned iz = 0;
43272 
43273   const size_t axisnameLen = strlen(axisname);
43274   memcpy(axisname2, axisname, axisnameLen + 1);
43275 
43276   do
43277     {
43278       if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
43279 
43280       if ( nc_inq_varid(fileID, axisname2, &ncdimid) != NC_NOERR ) break;
43281 
43282       ++iz;
43283     }
43284   while ( iz <= 99 );
43285 
43286   if ( iz ) sprintf(axisname + axisnameLen, "_%u", iz+1);
43287 }
43288 
43289 static
checkZaxisName(char * axisname,int fileID,int vlistID,int zaxisID,int nzaxis)43290 int checkZaxisName(char *axisname, int fileID, int vlistID, int zaxisID, int nzaxis)
43291 {
43292   char axisname2[CDI_MAX_NAME];
43293 
43294   /* check that the name is not already defined */
43295   unsigned iz = 0;
43296 
43297   const size_t axisnameLen = strlen(axisname);
43298   memcpy(axisname2, axisname, axisnameLen + 1);
43299   do
43300     {
43301       if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
43302 
43303       int ncdimid;
43304       const int status = nc_inq_varid(fileID, axisname2, &ncdimid);
43305       if ( status != NC_NOERR )
43306         {
43307           if ( iz )
43308             {
43309               /* check that the name does not exist for other zaxes */
43310               for ( int index = 0; index < nzaxis; index++ )
43311                 {
43312                   const int zaxisID0 = vlistZaxis(vlistID, index);
43313                   if ( zaxisID != zaxisID0 )
43314                     {
43315                       const char *axisname0 = zaxisInqNamePtr(zaxisID0);
43316                       if ( strcmp(axisname0, axisname2) == 0 ) goto nextSuffix;
43317                     }
43318                 }
43319             }
43320           break;
43321         }
43322       nextSuffix:
43323       ++iz;
43324     }
43325   while (iz <= 99);
43326 
43327 
43328   if ( iz ) sprintf(axisname + axisnameLen, "_%u", iz+1);
43329 
43330   return (int)iz;
43331 }
43332 
43333 static void
cdfDefAxisCommon(stream_t * streamptr,int gridID,int gridindex,int ndims,bool addVarToGrid,const struct cdfDefGridAxisInqs * gridAxisInq,int axisKey,char axisLetter,void (* finishCyclicBounds)(double * pbounds,size_t dimlen,const double * pvals))43334 cdfDefAxisCommon(stream_t *streamptr, int gridID, int gridindex, int ndims, bool addVarToGrid,
43335                  const struct cdfDefGridAxisInqs *gridAxisInq, int axisKey, char axisLetter,
43336                  void (*finishCyclicBounds)(double *pbounds, size_t dimlen, const double *pvals))
43337 {
43338   int dimID = CDI_UNDEFID;
43339   const int fileID  = streamptr->fileID;
43340   const size_t dimlen = gridAxisInq->axisSize(gridID);
43341   const nc_type xtype = (nc_type)cdfDefDatatype(gridInqDatatype(gridID), streamptr);
43342 
43343   ncgrid_t *ncgrid = streamptr->ncgrid;
43344 
43345   const double *pvals = gridAxisInq->axisValsPtr(gridID);
43346   char dimname[CDI_MAX_NAME+3]; dimname[0] = 0;
43347   int length = sizeof(dimname);
43348   if ( ndims && pvals == NULL ) cdiInqKeyString(gridID, axisKey, CDI_KEY_DIMNAME, dimname, &length);
43349 
43350   for ( int index = 0; index < gridindex; ++index )
43351     {
43352       const int gridID0 = ncgrid[index].gridID;
43353       assert(gridID0 != CDI_UNDEFID);
43354       const int gridtype0 = gridInqType(gridID0);
43355       if ( gridtype0 == GRID_GAUSSIAN    ||
43356            gridtype0 == GRID_LONLAT      ||
43357            gridtype0 == GRID_PROJECTION  ||
43358            gridtype0 == GRID_GENERIC )
43359         {
43360           const size_t dimlen0 = gridAxisInq->axisSize(gridID0);
43361           char dimname0[CDI_MAX_NAME]; dimname0[0] = 0;
43362           length = sizeof(dimname0);
43363           if ( dimname[0] ) cdiInqKeyString(gridID0, axisKey, CDI_KEY_DIMNAME, dimname0, &length);
43364           const bool lname = dimname0[0] ? strcmp(dimname, dimname0) == 0 : true;
43365           if ( dimlen == dimlen0 && lname )
43366             {
43367               double (*inqVal)(int gridID, size_t index) = gridAxisInq->axisVal;
43368               if ( IS_EQUAL(inqVal(gridID0, 0), inqVal(gridID, 0)) &&
43369                    IS_EQUAL(inqVal(gridID0, dimlen-1), inqVal(gridID, dimlen-1)) )
43370                 {
43371                   dimID = ncgrid[index].ncIDs[axisLetter == 'X' ? CDF_DIMID_X : CDF_DIMID_Y];
43372                   break;
43373                 }
43374             }
43375         }
43376     }
43377 
43378   if ( dimID == CDI_UNDEFID )
43379     {
43380       int ncvarid = CDI_UNDEFID, ncbvarid = CDI_UNDEFID;
43381       char axisname[CDI_MAX_NAME];
43382       length = CDI_MAX_NAME;
43383       cdiInqKeyString(gridID, axisKey, CDI_KEY_NAME, axisname, &length);
43384       if ( axisname[0] == 0 ) Error("axis name undefined!");
43385 
43386       checkGridName(axisname, fileID);
43387       const size_t axisnameLen = strlen(axisname);
43388 
43389       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
43390 
43391       if ( ndims )
43392         {
43393           if ( dimname[0] == 0 ) strcpy(dimname, axisname);
43394           dimID = checkDimName(fileID, dimlen, dimname);
43395 
43396           if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
43397         }
43398 
43399       bool gen_bounds = false;
43400       const bool grid_is_cyclic = gridIsCircular(gridID) > 0;
43401       double *pbounds = NULL;
43402       if ( pvals )
43403         {
43404           cdf_def_var(fileID, axisname, xtype, ndims, &dimID, &ncvarid);
43405 
43406           cdfPutGridStdAtts(fileID, ncvarid, gridID, axisLetter);
43407           {
43408             char axisStr[2] = { axisLetter, '\0' };
43409             cdf_put_att_text(fileID, ncvarid, "axis", 1, axisStr);
43410           }
43411 
43412           size_t nvertex = gridInqNvertex(gridID);
43413           pbounds = (double *)gridAxisInq->axisBoundsPtr(gridID);
43414 
43415           if ( CDI_CMOR_Mode && grid_is_cyclic && !pbounds )
43416             {
43417               gen_bounds = true;
43418               nvertex = 2;
43419               pbounds = (double*) Malloc(2*dimlen*sizeof(double));
43420               for ( size_t i = 0; i < dimlen-1; ++i )
43421                 {
43422                   pbounds[i*2+1]   = (pvals[i] + pvals[i+1])/2;
43423                   pbounds[(i+1)*2] = (pvals[i] + pvals[i+1])/2;
43424                 }
43425               finishCyclicBounds(pbounds, dimlen, pvals);
43426             }
43427 
43428           int nvdimID = CDI_UNDEFID;
43429           if ( pbounds )
43430             {
43431               if ( nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR )
43432                 cdf_def_dim(fileID, bndsName, nvertex, &nvdimID);
43433             }
43434           if ( pbounds && nvdimID != CDI_UNDEFID )
43435             {
43436               char boundsname[CDI_MAX_NAME];
43437               memcpy(boundsname, axisname, axisnameLen);
43438               boundsname[axisnameLen] = '_';
43439               memcpy(boundsname + axisnameLen + 1, bndsName, sizeof(bndsName));
43440               int dimIDs[2] = { dimID, nvdimID };
43441               cdf_def_var(fileID, boundsname, xtype, 2, dimIDs, &ncbvarid);
43442               cdf_put_att_text(fileID, ncvarid, "bounds", axisnameLen + sizeof(bndsName), boundsname);
43443             }
43444         }
43445 
43446       cdf_enddef(fileID);
43447       streamptr->ncmode = 2;
43448 
43449       if ( ncvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncvarid, pvals);
43450       if ( ncbvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbvarid, pbounds);
43451       if ( gen_bounds ) Free(pbounds);
43452 
43453       if (ndims == 0 || addVarToGrid)
43454         ncgrid[gridindex].ncIDs[axisLetter == 'X' ? CDF_VARID_X : CDF_VARID_Y] = ncvarid;
43455     }
43456 
43457   ncgrid[gridindex].gridID = gridID;
43458   ncgrid[gridindex].ncIDs[axisLetter == 'X' ? CDF_DIMID_X : CDF_DIMID_Y] = dimID;
43459 }
43460 
43461 static
finishCyclicXBounds(double * pbounds,size_t dimlen,const double * pvals)43462 void finishCyclicXBounds(double *pbounds, size_t dimlen, const double *pvals)
43463 {
43464   pbounds[0] = (pvals[0] + pvals[dimlen-1]-360)*0.5;
43465   pbounds[2*dimlen-1] = (pvals[dimlen-1] + pvals[0]+360)*0.5;
43466 }
43467 
43468 static
finishCyclicYBounds(double * pbounds,size_t dimlen,const double * pvals)43469 void finishCyclicYBounds(double *pbounds, size_t dimlen, const double *pvals)
43470 {
43471   pbounds[0] = copysign(90.0, pvals[0]);
43472   pbounds[2*dimlen-1] = copysign(90.0, pvals[dimlen-1]);
43473 }
43474 
43475 static
cdfDefXaxis(stream_t * streamptr,int gridID,int gridindex,int ndims,bool addVarToGrid)43476 void cdfDefXaxis(stream_t *streamptr, int gridID, int gridindex, int ndims, bool addVarToGrid)
43477 {
43478   cdfDefAxisCommon(streamptr, gridID, gridindex, ndims, addVarToGrid, &gridInqsX, CDI_XAXIS, 'X', finishCyclicXBounds);
43479 }
43480 
43481 static
cdfDefYaxis(stream_t * streamptr,int gridID,int gridindex,int ndims,bool addVarToGrid)43482 void cdfDefYaxis(stream_t *streamptr, int gridID, int gridindex, int ndims, bool addVarToGrid)
43483 {
43484   cdfDefAxisCommon(streamptr, gridID, gridindex, ndims, addVarToGrid, &gridInqsY, CDI_YAXIS, 'Y', finishCyclicYBounds);
43485 }
43486 
43487 static
cdfGridCompress(int fileID,int ncvarid,size_t gridsize,int filetype,int comptype)43488 void cdfGridCompress(int fileID, int ncvarid, size_t gridsize, int filetype, int comptype)
43489 {
43490 #ifdef HAVE_NETCDF4
43491   if ( gridsize > 1 && comptype == CDI_COMPRESS_ZIP && (filetype == CDI_FILETYPE_NC4 || filetype == CDI_FILETYPE_NC4C) )
43492     {
43493       cdf_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
43494       cdfDefVarDeflate(fileID, ncvarid, 1);
43495     }
43496 #endif
43497 }
43498 
43499 static
cdfDefGridReference(stream_t * streamptr,int gridID)43500 void cdfDefGridReference(stream_t *streamptr, int gridID)
43501 {
43502   const int fileID = streamptr->fileID;
43503 
43504   int number = 0;
43505   cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDUSED, &number);
43506   if ( number > 0 ) cdf_put_att_int(fileID, NC_GLOBAL, "number_of_grid_used", NC_INT, 1, &number);
43507 
43508   grid_t *gridptr = grid_to_pointer(gridID);
43509   const char *gridfile = cdiInqVarKeyStringPtr(&gridptr->keys, CDI_KEY_REFERENCEURI);
43510   if ( gridfile && gridfile[0] != 0 )
43511     cdf_put_att_text(fileID, NC_GLOBAL, "grid_file_uri", strlen(gridfile), gridfile);
43512 }
43513 
43514 static
cdfDefGridUUID(stream_t * streamptr,int gridID)43515 void cdfDefGridUUID(stream_t *streamptr, int gridID)
43516 {
43517   unsigned char uuidOfHGrid[CDI_UUID_SIZE];
43518   size_t len = CDI_UUID_SIZE;
43519   memset(uuidOfHGrid, 0, len);
43520   int length = CDI_UUID_SIZE;
43521   cdiInqKeyBytes(gridID, CDI_GLOBAL, CDI_KEY_UUID, uuidOfHGrid, &length);
43522   if ( !cdiUUIDIsNull(uuidOfHGrid) )
43523     {
43524       char uuidOfHGridStr[37];
43525       cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
43526       if ( uuidOfHGridStr[0] != 0 && strlen(uuidOfHGridStr) == 36 )
43527         {
43528           int fileID  = streamptr->fileID;
43529           //if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
43530           cdf_put_att_text(fileID, NC_GLOBAL, "uuidOfHGrid", 36, uuidOfHGridStr);
43531           //if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
43532         }
43533     }
43534 }
43535 
43536 struct cdfDefIrregularGridCommonIDs
43537 {
43538   int xdimID, ydimID, ncxvarid, ncyvarid, ncavarid;
43539 };
43540 
43541 static struct cdfDefIrregularGridCommonIDs
cdfDefIrregularGridCommon(stream_t * streamptr,int gridID,size_t xdimlen,size_t ydimlen,int ndims,const char * xdimname_default,size_t nvertex,const char * vdimname_default,bool setVdimname)43542 cdfDefIrregularGridCommon(stream_t *streamptr, int gridID,
43543                           size_t xdimlen, size_t ydimlen,
43544                           int ndims, const char *xdimname_default,
43545                           size_t nvertex, const char *vdimname_default,
43546                           bool setVdimname)
43547 {
43548   nc_type xtype = (nc_type)cdfDefDatatype(gridInqDatatype(gridID), streamptr);
43549   int xdimID = CDI_UNDEFID;
43550   int ydimID = CDI_UNDEFID;
43551   int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID;
43552   int ncbxvarid = CDI_UNDEFID, ncbyvarid = CDI_UNDEFID;
43553   int fileID  = streamptr->fileID;
43554   if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
43555 
43556   {
43557     char xdimname[CDI_MAX_NAME+3];
43558     int length = sizeof(xdimname);
43559     cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_DIMNAME, xdimname, &length);
43560     if ( xdimname[0] == 0 ) strcpy(xdimname, xdimname_default);
43561     xdimID = checkDimName(fileID, xdimlen, xdimname);
43562     if ( xdimID == CDI_UNDEFID ) cdf_def_dim(fileID, xdimname, xdimlen, &xdimID);
43563   }
43564 
43565   if ( ndims == 3 )
43566     {
43567       char ydimname[CDI_MAX_NAME+3];
43568       int length = sizeof(ydimname);
43569       cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_DIMNAME, ydimname, &length);
43570       if ( ydimname[0] == 0 ) { ydimname[0] = 'y'; ydimname[1] = 0; }
43571       ydimID = checkDimName(fileID, ydimlen, ydimname);
43572       if ( ydimID == CDI_UNDEFID ) cdf_def_dim(fileID, ydimname, ydimlen, &ydimID);
43573     }
43574 
43575   int nvdimID = CDI_UNDEFID;
43576   int dimIDs[3];
43577   dimIDs[ndims-1] = CDI_UNDEFID;
43578   if ( setVdimname )
43579     {
43580       char vdimname[CDI_MAX_NAME+3];
43581       int length = CDI_MAX_NAME;
43582       cdiInqKeyString(gridID, CDI_GLOBAL, CDI_KEY_VDIMNAME, vdimname, &length);
43583       if ( vdimname[0] == 0 ) strcpy(vdimname, vdimname_default);
43584       nvdimID = dimIDs[ndims-1] = checkDimName(fileID, nvertex, vdimname);
43585       if ( nvdimID == CDI_UNDEFID )
43586         {
43587           cdf_def_dim(fileID, vdimname, nvertex, dimIDs+ndims-1);
43588           nvdimID = dimIDs[ndims-1];
43589         }
43590     }
43591 
43592   if ( ndims == 3 )
43593     {
43594       dimIDs[0] = ydimID;
43595       dimIDs[1] = xdimID;
43596     }
43597   else /* ndims == 2 */
43598     {
43599       dimIDs[0] = xdimID;
43600       cdfDefGridReference(streamptr, gridID);
43601       cdfDefGridUUID(streamptr, gridID);
43602     }
43603 
43604   const double *xvalsPtr = gridInqXvalsPtr(gridID),
43605     *xboundsPtr = NULL;
43606   if ( xvalsPtr )
43607     {
43608       char xaxisname[CDI_MAX_NAME];
43609       int length = CDI_MAX_NAME;
43610       cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_NAME, xaxisname, &length);
43611       checkGridName(xaxisname, fileID);
43612       cdf_def_var(fileID, xaxisname, xtype, ndims-1, dimIDs, &ncxvarid);
43613       cdfGridCompress(fileID, ncxvarid, xdimlen*ydimlen, streamptr->filetype, streamptr->comptype);
43614 
43615       cdfPutGridStdAtts(fileID, ncxvarid, gridID, 'X');
43616 
43617       /* attribute for Panoply */
43618       if ( ndims == 3 )
43619         cdf_put_att_text(fileID, ncxvarid, "_CoordinateAxisType", 3, "Lon");
43620 
43621       if ( (xboundsPtr = gridInqXboundsPtr(gridID)) && nvdimID != CDI_UNDEFID )
43622         {
43623           const size_t xaxisnameLen = strlen(xaxisname);
43624           xaxisname[xaxisnameLen] = '_';
43625           memcpy(xaxisname + xaxisnameLen + 1, bndsName, sizeof (bndsName));
43626           cdf_def_var(fileID, xaxisname, xtype, ndims, dimIDs, &ncbxvarid);
43627           cdfGridCompress(fileID, ncbxvarid, xdimlen*ydimlen, streamptr->filetype, streamptr->comptype);
43628 
43629           cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname);
43630         }
43631     }
43632 
43633   const double *yvalsPtr = gridInqYvalsPtr(gridID),
43634     *yboundsPtr = NULL;
43635   if ( yvalsPtr )
43636     {
43637       char yaxisname[CDI_MAX_NAME];
43638       gridInqYname(gridID, yaxisname);
43639       checkGridName(yaxisname, fileID);
43640 
43641       cdf_def_var(fileID, yaxisname, xtype, ndims - 1, dimIDs, &ncyvarid);
43642       cdfGridCompress(fileID, ncyvarid, xdimlen*ydimlen, streamptr->filetype, streamptr->comptype);
43643 
43644       cdfPutGridStdAtts(fileID, ncyvarid, gridID, 'Y');
43645 
43646       /* attribute for Panoply */
43647       if ( ndims == 3 )
43648         cdf_put_att_text(fileID, ncyvarid, "_CoordinateAxisType", 3, "Lat");
43649 
43650       if ( (yboundsPtr = gridInqYboundsPtr(gridID)) && nvdimID != CDI_UNDEFID )
43651         {
43652           const size_t yaxisnameLen = strlen(yaxisname);
43653           yaxisname[yaxisnameLen] = '_';
43654           memcpy(yaxisname + yaxisnameLen + 1, bndsName, sizeof (bndsName));
43655           cdf_def_var(fileID, yaxisname, xtype, ndims, dimIDs, &ncbyvarid);
43656           cdfGridCompress(fileID, ncbyvarid, xdimlen*ydimlen, streamptr->filetype, streamptr->comptype);
43657 
43658           cdf_put_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname);
43659         }
43660     }
43661 
43662   const double *areaPtr = gridInqAreaPtr(gridID);
43663   if ( areaPtr )
43664     {
43665       static const char yaxisname_[] = "cell_area";
43666       static const char units[] = "m2";
43667       static const char longname[] = "area of grid cell";
43668       static const char stdname[] = "cell_area";
43669 
43670       cdf_def_var(fileID, yaxisname_, xtype, ndims-1, dimIDs, &ncavarid);
43671 
43672       cdf_put_att_text(fileID, ncavarid, "standard_name", sizeof (stdname) - 1, stdname);
43673       cdf_put_att_text(fileID, ncavarid, "long_name", sizeof (longname) - 1, longname);
43674       cdf_put_att_text(fileID, ncavarid, "units", sizeof (units) - 1, units);
43675     }
43676 
43677   cdf_enddef(fileID);
43678   streamptr->ncmode = 2;
43679 
43680   if ( ncxvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncxvarid,  xvalsPtr);
43681   if ( ncbxvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbxvarid, xboundsPtr);
43682   if ( ncyvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncyvarid,  yvalsPtr);
43683   if ( ncbyvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbyvarid, yboundsPtr);
43684   if ( ncavarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncavarid,  areaPtr);
43685 
43686   return (struct cdfDefIrregularGridCommonIDs) {
43687     .xdimID=xdimID, .ydimID = ydimID,
43688     .ncxvarid=ncxvarid, .ncyvarid=ncyvarid, .ncavarid=ncavarid
43689   };
43690 }
43691 
43692 static
cdfDefCurvilinear(stream_t * streamptr,int gridID,int gridindex)43693 void cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridindex)
43694 {
43695   ncgrid_t *ncgrid = streamptr->ncgrid;
43696 
43697   const size_t dimlen = gridInqSize(gridID);
43698   const size_t xdimlen = gridInqXsize(gridID);
43699   const size_t ydimlen = gridInqYsize(gridID);
43700 
43701   int xdimID = CDI_UNDEFID, ydimID = CDI_UNDEFID;
43702   int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID;
43703 
43704   size_t ofs = 0;
43705   do {
43706     struct idSearch search
43707       = cdfSearchIDBySize(ofs, (size_t)gridindex, ncgrid, CDF_DIMID_X,
43708                           GRID_CURVILINEAR, (int)dimlen, gridInqType, gridInqSize);
43709     const size_t index = search.foundIdx;
43710     if ( index != SIZE_MAX )
43711       {
43712         const int gridID0 = ncgrid[index].gridID;
43713         if (    IS_EQUAL(gridInqXval(gridID0, 0), gridInqXval(gridID, 0))
43714                 && IS_EQUAL(gridInqXval(gridID0, dimlen-1),
43715                             gridInqXval(gridID, dimlen-1))
43716                 && IS_EQUAL(gridInqYval(gridID0, 0), gridInqYval(gridID, 0))
43717                 && IS_EQUAL(gridInqYval(gridID0, dimlen-1),
43718                             gridInqYval(gridID, dimlen-1)) )
43719           {
43720             xdimID = ncgrid[index].ncIDs[CDF_DIMID_X];
43721             ydimID = ncgrid[index].ncIDs[CDF_DIMID_Y];
43722             ncxvarid = ncgrid[index].ncIDs[CDF_VARID_X];
43723             ncyvarid = ncgrid[index].ncIDs[CDF_VARID_Y];
43724             break;
43725           }
43726         ofs = search.foundIdx;
43727         if ( ofs < (size_t)gridindex )
43728           continue;
43729       }
43730   } while (false);
43731 
43732   if ( xdimID == CDI_UNDEFID || ydimID == CDI_UNDEFID )
43733     {
43734       struct cdfDefIrregularGridCommonIDs createdIDs
43735         = cdfDefIrregularGridCommon(streamptr, gridID,
43736                                     xdimlen, ydimlen, 3, "x", 4, "nv4",
43737                                     gridInqXboundsPtr(gridID)
43738                                     || gridInqYboundsPtr(gridID));
43739       xdimID = createdIDs.xdimID;
43740       ydimID = createdIDs.ydimID;
43741       ncxvarid = createdIDs.ncxvarid;
43742       ncyvarid = createdIDs.ncyvarid;
43743       ncavarid = createdIDs.ncavarid;
43744     }
43745 
43746   ncgrid[gridindex].gridID = gridID;
43747   ncgrid[gridindex].ncIDs[CDF_DIMID_X] = xdimID;
43748   ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = ydimID;
43749   ncgrid[gridindex].ncIDs[CDF_VARID_X] = ncxvarid;
43750   ncgrid[gridindex].ncIDs[CDF_VARID_Y] = ncyvarid;
43751   ncgrid[gridindex].ncIDs[CDF_VARID_A] = ncavarid;
43752 }
43753 
43754 
43755 static
cdfDefUnstructured(stream_t * streamptr,int gridID,int gridindex)43756 void cdfDefUnstructured(stream_t *streamptr, int gridID, int gridindex)
43757 {
43758   ncgrid_t *ncgrid = streamptr->ncgrid;
43759 
43760   const size_t dimlen = gridInqSize(gridID);
43761 
43762   int dimID = CDI_UNDEFID;
43763   int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID;
43764 
43765   size_t ofs = 0;
43766   do {
43767     struct idSearch search
43768       = cdfSearchIDBySize(ofs, (size_t)gridindex, ncgrid, CDF_DIMID_X,
43769                           GRID_UNSTRUCTURED, (int)dimlen, gridInqType, gridInqSize);
43770     const size_t index = search.foundIdx;
43771     if ( index != SIZE_MAX )
43772       {
43773         const int gridID0 = ncgrid[index].gridID;
43774         if ( gridInqNvertex(gridID0) == gridInqNvertex(gridID) &&
43775              IS_EQUAL(gridInqXval(gridID0, 0), gridInqXval(gridID, 0)) &&
43776              IS_EQUAL(gridInqXval(gridID0, dimlen-1),
43777                       gridInqXval(gridID, dimlen-1)) &&
43778              IS_EQUAL(gridInqYval(gridID0, 0), gridInqYval(gridID, 0)) &&
43779              IS_EQUAL(gridInqYval(gridID0, dimlen-1),
43780                       gridInqYval(gridID, dimlen-1)) )
43781           {
43782             dimID = ncgrid[index].ncIDs[CDF_DIMID_X];
43783             ncxvarid = ncgrid[index].ncIDs[CDF_VARID_X];
43784             ncyvarid = ncgrid[index].ncIDs[CDF_VARID_Y];
43785             ncavarid = ncgrid[index].ncIDs[CDF_VARID_A];
43786             break;
43787           }
43788         ofs = search.foundIdx;
43789         if ( ofs < (size_t)gridindex )
43790           continue;
43791       }
43792   } while (false);
43793 
43794   if ( dimID == CDI_UNDEFID )
43795     {
43796       const size_t nvertex = (size_t)gridInqNvertex(gridID);
43797       struct cdfDefIrregularGridCommonIDs createdIDs
43798         = cdfDefIrregularGridCommon(streamptr, gridID,
43799                                     dimlen, 1, 2, "ncells",
43800                                     nvertex, "vertices", nvertex > 0);
43801       dimID = createdIDs.xdimID;
43802       ncxvarid = createdIDs.ncxvarid;
43803       ncyvarid = createdIDs.ncyvarid;
43804       ncavarid = createdIDs.ncavarid;
43805     }
43806 
43807   ncgrid[gridindex].gridID = gridID;
43808   ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
43809   ncgrid[gridindex].ncIDs[CDF_VARID_X] = ncxvarid;
43810   ncgrid[gridindex].ncIDs[CDF_VARID_Y] = ncyvarid;
43811   ncgrid[gridindex].ncIDs[CDF_VARID_A] = ncavarid;
43812 }
43813 
43814 struct attTxtTab2
43815 {
43816   const char *attName, *attVal;
43817   size_t valLen;
43818 };
43819 
43820 static
cdf_def_vct_echam(stream_t * streamptr,int zaxisID)43821 void cdf_def_vct_echam(stream_t *streamptr, int zaxisID)
43822 {
43823   const int type = zaxisInqType(zaxisID);
43824   if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
43825     {
43826       const int ilev = zaxisInqVctSize(zaxisID)/2;
43827       if ( ilev == 0 ) return;
43828 
43829       const int mlev = ilev - 1;
43830 
43831       if ( streamptr->vct.ilev > 0 )
43832         {
43833           if ( streamptr->vct.ilev != ilev )
43834             Error("More than one VCT for each file unsupported!");
43835           return;
43836         }
43837 
43838       const int fileID = streamptr->fileID;
43839 
43840       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
43841 
43842       int ncdimid = -1, ncdimid2 = -1;
43843       int hyaiid, hybiid, hyamid = -1, hybmid = -1;
43844 
43845       cdf_def_dim(fileID, "nhyi", (size_t)ilev, &ncdimid2);
43846       cdf_def_var(fileID, "hyai", NC_DOUBLE, 1, &ncdimid2, &hyaiid);
43847       cdf_def_var(fileID, "hybi", NC_DOUBLE, 1, &ncdimid2, &hybiid);
43848       if ( mlev > 0 )
43849         {
43850           cdf_def_dim(fileID, "nhym", (size_t)mlev, &ncdimid);
43851           cdf_def_var(fileID, "hyam", NC_DOUBLE, 1, &ncdimid,  &hyamid);
43852           cdf_def_var(fileID, "hybm", NC_DOUBLE, 1, &ncdimid,  &hybmid);
43853         }
43854 
43855       streamptr->vct.ilev   = ilev;
43856       streamptr->vct.mlev   = mlev;
43857       streamptr->vct.mlevID = ncdimid;
43858       streamptr->vct.ilevID = ncdimid2;
43859 
43860       {
43861         static const char lname_n[] = "long_name",
43862           units_n[] = "units",
43863           lname_v_ai[] = "hybrid A coefficient at layer interfaces",
43864           units_v_ai[] = "Pa",
43865           lname_v_bi[] = "hybrid B coefficient at layer interfaces",
43866           units_v_bi[] = "1";
43867         static const struct attTxtTab2 tab[]
43868           = {
43869           { lname_n, lname_v_ai, sizeof (lname_v_ai) - 1 },
43870           { units_n, units_v_ai, sizeof (units_v_ai) - 1 },
43871           { lname_n, lname_v_bi, sizeof (lname_v_bi) - 1 },
43872           { units_n, units_v_bi, sizeof (units_v_bi) - 1 },
43873         };
43874         enum { tabLen = sizeof (tab) / sizeof (tab[0]) };
43875         const int ids[tabLen] = { hyaiid, hyaiid, hybiid, hybiid };
43876         for ( size_t i = 0; i < tabLen; ++i )
43877           cdf_put_att_text(fileID, ids[i], tab[i].attName, tab[i].valLen, tab[i].attVal);
43878       }
43879 
43880       {
43881         static const char lname_n[] = "long_name",
43882           units_n[] = "units",
43883           lname_v_am[] = "hybrid A coefficient at layer midpoints",
43884           units_v_am[] = "Pa",
43885           lname_v_bm[] = "hybrid B coefficient at layer midpoints",
43886           units_v_bm[] = "1";
43887         static const struct attTxtTab2 tab[]
43888           = {
43889           { lname_n, lname_v_am, sizeof (lname_v_am) - 1 },
43890           { units_n, units_v_am, sizeof (units_v_am) - 1 },
43891           { lname_n, lname_v_bm, sizeof (lname_v_bm) - 1 },
43892           { units_n, units_v_bm, sizeof (units_v_bm) - 1 },
43893         };
43894         enum { tabLen = sizeof (tab) / sizeof (tab[0]) };
43895         const int ids[tabLen] = { hyamid, hyamid, hybmid, hybmid };
43896         for ( size_t i = 0; i < tabLen; ++i )
43897           cdf_put_att_text(fileID, ids[i], tab[i].attName, tab[i].valLen, tab[i].attVal);
43898       }
43899 
43900       cdf_enddef(fileID);
43901       streamptr->ncmode = 2;
43902 
43903       const double *vctptr = zaxisInqVctPtr(zaxisID);
43904 
43905       cdf_put_var_double(fileID, hyaiid, vctptr);
43906       cdf_put_var_double(fileID, hybiid, vctptr+ilev);
43907 
43908       size_t start;
43909       size_t count = 1;
43910       double mval;
43911       for ( int i = 0; i < mlev; i++ )
43912         {
43913           start = (size_t)i;
43914           mval = (vctptr[i] + vctptr[i+1]) * 0.5;
43915           cdf_put_vara_double(fileID, hyamid, &start, &count, &mval);
43916           mval = (vctptr[ilev+i] + vctptr[ilev+i+1]) * 0.5;
43917           cdf_put_vara_double(fileID, hybmid, &start, &count, &mval);
43918         }
43919     }
43920 }
43921 
43922 static
cdf_def_vct_cf(stream_t * streamptr,int zaxisID,int nclevID,int ncbndsID,int p0status,double p0value)43923 void cdf_def_vct_cf(stream_t *streamptr, int zaxisID, int nclevID, int ncbndsID, int p0status, double p0value)
43924 {
43925   const int type = zaxisInqType(zaxisID);
43926   if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
43927     {
43928       const int ilev = zaxisInqVctSize(zaxisID)/2;
43929       if ( ilev == 0 ) return;
43930 
43931       const int mlev = ilev - 1;
43932       int hyaiid = 0, hybiid = 0, hyamid, hybmid;
43933 
43934       if ( streamptr->vct.ilev > 0 )
43935         {
43936           if ( streamptr->vct.ilev != ilev )
43937             Error("more than one VCT for each file unsupported!");
43938           return;
43939         }
43940 
43941       const int fileID = streamptr->fileID;
43942 
43943       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
43944 
43945       int dimIDs[2];
43946       dimIDs[0] = nclevID;
43947       dimIDs[1] = ncbndsID;
43948 
43949       streamptr->vct.mlev   = mlev;
43950       streamptr->vct.ilev   = ilev;
43951       streamptr->vct.mlevID = nclevID;
43952       streamptr->vct.ilevID = nclevID;
43953 
43954       if ( p0status == 0 )
43955         cdf_def_var(fileID, "a", NC_DOUBLE, 1, dimIDs,  &hyamid);
43956       else
43957         cdf_def_var(fileID, "ap", NC_DOUBLE, 1, dimIDs,  &hyamid);
43958       cdf_def_var(fileID, "b",  NC_DOUBLE, 1, dimIDs,  &hybmid);
43959 
43960       {
43961         static const char lname[] = "vertical coordinate formula term: ap(k)";
43962         cdf_put_att_text(fileID, hyamid, "long_name", sizeof (lname) - 1, lname);
43963 
43964         static const char units[] = "Pa";
43965         cdf_put_att_text(fileID, hyamid, "units", sizeof (units) - 1, units);
43966       }
43967       {
43968         static const char lname[] = "vertical coordinate formula term: b(k)";
43969         cdf_put_att_text(fileID, hybmid, "long_name", sizeof (lname) - 1, lname);
43970 
43971         static const char units[] = "1";
43972         cdf_put_att_text(fileID, hybmid, "units", sizeof (units) - 1, units);
43973       }
43974 
43975       if ( ncbndsID != -1 )
43976         {
43977           if ( p0status == 0 )
43978             cdf_def_var(fileID, "a_bnds", NC_DOUBLE, 2, dimIDs, &hyaiid);
43979           else
43980             cdf_def_var(fileID, "ap_bnds", NC_DOUBLE, 2, dimIDs, &hyaiid);
43981           cdf_def_var(fileID, "b_bnds",  NC_DOUBLE, 2, dimIDs, &hybiid);
43982 
43983           {
43984             static const char lname[] = "vertical coordinate formula term: ap(k+1/2)";
43985             cdf_put_att_text(fileID, hyaiid, "long_name", sizeof (lname) - 1, lname);
43986 
43987             static const char units[] = "Pa";
43988             cdf_put_att_text(fileID, hyaiid, "units", sizeof (units) - 1, units);
43989           }
43990           {
43991             static const char lname[] = "vertical coordinate formula term: b(k+1/2)";
43992             cdf_put_att_text(fileID, hybiid, "long_name", sizeof (lname) - 1, lname);
43993 
43994             static const char units[] = "1";
43995             cdf_put_att_text(fileID, hybiid, "units", sizeof (units) - 1, units);
43996           }
43997         }
43998 
43999       cdf_enddef(fileID);
44000       streamptr->ncmode = 2;
44001 
44002       const int vctsize = zaxisInqVctSize(zaxisID);
44003       double *vct = (double*) malloc(vctsize*sizeof(double));;
44004       zaxisInqVct(zaxisID, vct);
44005 
44006       if ( p0status == 0 && IS_NOT_EQUAL(p0value,0) )
44007         for ( int i = 0; i < vctsize/2; ++i ) vct[i] /= p0value;
44008 
44009       double *tarray = (double*) malloc(ilev*2*sizeof(double));
44010 
44011       if ( ncbndsID != -1 )
44012         {
44013           for ( int i = 0; i < mlev; ++i )
44014             {
44015               tarray[2*i  ] = vct[i];
44016               tarray[2*i+1] = vct[i+1];
44017             }
44018           cdf_put_var_double(fileID, hyaiid, tarray);
44019 
44020           for ( int i = 0; i < mlev; ++i )
44021             {
44022               tarray[2*i  ] = vct[ilev+i];
44023               tarray[2*i+1] = vct[ilev+i+1];
44024             }
44025           cdf_put_var_double(fileID, hybiid, tarray);
44026         }
44027 
44028       for ( int i = 0; i < mlev; ++i )
44029         tarray[i] = (vct[i] + vct[i+1]) * 0.5;
44030       cdf_put_var_double(fileID, hyamid, tarray);
44031 
44032       for ( int i = 0; i < mlev; ++i )
44033         tarray[i] = (vct[ilev+i] + vct[ilev+i+1]) * 0.5;
44034       cdf_put_var_double(fileID, hybmid, tarray);
44035 
44036       free(tarray);
44037       free(vct);
44038     }
44039 }
44040 
44041 struct attTxtTab { const char *txt; size_t txtLen; };
44042 
44043 static
cdf_def_zaxis_hybrid_echam(stream_t * streamptr,int type,int * ncvaridp,int zaxisID,int zaxisindex,int xtype,size_t dimlen,int * dimID,char * axisname)44044 void cdf_def_zaxis_hybrid_echam(stream_t *streamptr, int type, int *ncvaridp, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname)
44045 {
44046   const int fileID = streamptr->fileID;
44047 
44048   if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
44049 
44050   cdf_def_dim(fileID, axisname, dimlen, dimID);
44051   cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID,  ncvaridp);
44052   const int ncvarid = *ncvaridp;
44053 
44054   {
44055     static const char sname[] = "hybrid_sigma_pressure";
44056     cdf_put_att_text(fileID, ncvarid, "standard_name", sizeof (sname) - 1, sname);
44057   }
44058   {
44059     static const char *attName[] = {
44060       "long_name",
44061       "formula",
44062       "formula_terms"
44063     };
44064     enum { nAtt = sizeof (attName) / sizeof (attName[0]) };
44065     static const char lname_m[] = "hybrid level at layer midpoints",
44066       formula_m[] = "hyam hybm (mlev=hyam+hybm*aps)",
44067       fterms_m[] = "ap: hyam b: hybm ps: aps",
44068       lname_i[] = "hybrid level at layer interfaces",
44069       formula_i[] = "hyai hybi (ilev=hyai+hybi*aps)",
44070       fterms_i[] = "ap: hyai b: hybi ps: aps";
44071     static const struct attTxtTab tab[2][nAtt] = {
44072       {
44073         { lname_i, sizeof (lname_i) - 1 },
44074         { formula_i, sizeof (formula_i) - 1 },
44075         { fterms_i, sizeof (fterms_i) - 1 }
44076       },
44077       {
44078         { lname_m, sizeof (lname_m) - 1 },
44079         { formula_m, sizeof (formula_m) - 1 },
44080         { fterms_m, sizeof (fterms_m) - 1 }
44081       }
44082     };
44083 
44084     const size_t tabSelect = type == ZAXIS_HYBRID;
44085     for (size_t i = 0; i < nAtt; ++i)
44086       cdf_put_att_text(fileID, ncvarid, attName[i],
44087                        tab[tabSelect][i].txtLen, tab[tabSelect][i].txt);
44088   }
44089 
44090   {
44091     static const char units[] = "level";
44092     cdf_put_att_text(fileID, ncvarid, "units", sizeof (units) - 1, units);
44093   }
44094   {
44095     static const char direction[] = "down";
44096     cdf_put_att_text(fileID, ncvarid, "positive", sizeof (direction) - 1, direction);
44097   }
44098 
44099   cdf_enddef(fileID);
44100   streamptr->ncmode = 2;
44101 
44102   cdf_put_var_double(fileID, ncvarid, zaxisInqLevelsPtr(zaxisID));
44103 
44104   cdf_def_vct_echam(streamptr, zaxisID);
44105 
44106   if ( *dimID == CDI_UNDEFID )
44107     streamptr->zaxisID[zaxisindex] = type == ZAXIS_HYBRID
44108       ? streamptr->vct.mlevID : streamptr->vct.ilevID;
44109 }
44110 
44111 static
cdf_def_zaxis_hybrid_cf(stream_t * streamptr,int type,int * ncvaridp,int zaxisID,int zaxisindex,int xtype,size_t dimlen,int * dimID,char * axisname)44112 void cdf_def_zaxis_hybrid_cf(stream_t *streamptr, int type, int *ncvaridp, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname)
44113 {
44114   const int fileID = streamptr->fileID;
44115   if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
44116 
44117   char psname[CDI_MAX_NAME];
44118   int length = CDI_MAX_NAME;
44119   cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_PSNAME, psname, &length);
44120   if ( psname[0] == 0 ) strcpy(psname, "ps");
44121 
44122   char p0name[CDI_MAX_NAME]; p0name[0] = 0;
44123   double p0value = 1;
44124   int p0varid = CDI_UNDEFID;
44125   const int p0status = cdiInqKeyFloat(zaxisID, CDI_GLOBAL, CDI_KEY_P0VALUE, &p0value);
44126   if ( p0status == CDI_NOERR )
44127     {
44128       length = CDI_MAX_NAME;
44129       cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_P0NAME, p0name, &length);
44130       if ( p0name[0] == 0 ) strcpy(p0name, "p0");
44131       cdf_def_var(fileID, p0name, NC_DOUBLE, 0, 0,  &p0varid);
44132       static const char longname[] = "reference pressure";
44133       cdf_put_att_text(fileID, p0varid, "long_name", strlen(longname), longname);
44134       static const char units[] = "Pa";
44135       cdf_put_att_text(fileID, p0varid, "units", strlen(units), units);
44136     }
44137 
44138   char zname[CDI_MAX_NAME];
44139   char zlongname[CDI_MAX_NAME];
44140   char zunits[CDI_MAX_NAME];
44141   length = CDI_MAX_NAME;
44142   cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_NAME, zname, &length);
44143   if ( zname[0] ) strcpy(axisname, zname);
44144   zlongname[0] = 0;
44145   if ( zlongname[0] == 0 ) strcpy(zlongname, "hybrid sigma pressure coordinate");
44146   length = CDI_MAX_NAME;
44147   cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, zunits, &length);
44148   if ( zunits[0] == 0 ) strcpy(zunits, "1");
44149 
44150   cdf_def_dim(fileID, axisname, dimlen, dimID);
44151   cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID, ncvaridp);
44152   int ncvarid = *ncvaridp;
44153 
44154   {
44155     static const char sname[] = "standard_name",
44156       sname_v[] = "atmosphere_hybrid_sigma_pressure_coordinate",
44157       axis[] = "axis",
44158       axis_v[] = "Z",
44159       direction[] = "positive",
44160       direction_v[] = "down";
44161     struct attTxtTab2 tab[] = {
44162       { sname, sname_v, sizeof (sname_v) - 1 },
44163       { axis, axis_v, sizeof (axis_v) - 1 },
44164       { direction, direction_v, sizeof (direction_v) - 1 },
44165     };
44166     enum { nAtt = sizeof (tab) / sizeof (tab[0]) };
44167     for ( size_t i = 0; i < nAtt; ++i )
44168       cdf_put_att_text(fileID, ncvarid, tab[i].attName, tab[i].valLen, tab[i].attVal);
44169 
44170     cdf_put_att_text(fileID, ncvarid, "long_name", strlen(zlongname), zlongname);
44171     cdf_put_att_text(fileID, ncvarid, "units", strlen(zunits), zunits);
44172   }
44173 
44174   size_t len = 0;
44175   char txt[CDI_MAX_NAME];
44176   if ( p0status == 0 )
44177     len = (size_t)(sprintf(txt, "%s%s %s%s", "a: a b: b p0: ", p0name, "ps: ", psname));
44178   else
44179     len = (size_t)(sprintf(txt, "%s%s", "ap: ap b: b ps: ", psname));
44180   cdf_put_att_text(fileID, ncvarid, "formula_terms", len, txt);
44181 
44182   int ncbvarid = CDI_UNDEFID;
44183   int nvdimID = CDI_UNDEFID;
44184 
44185   double *buffer = (double *) malloc(4*dimlen*sizeof(double));
44186   double *levels = buffer;
44187   double *lbounds = buffer + 2*dimlen;
44188   double *ubounds = buffer + 3*dimlen;
44189 
44190   if ( zaxisInqLevels(zaxisID, NULL) )
44191     zaxisInqLevels(zaxisID, levels);
44192   else
44193     for ( size_t i = 0; i < dimlen; ++i ) levels[i] = i+1;
44194 
44195   if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
44196     {
44197       zaxisInqLbounds(zaxisID, lbounds);
44198       zaxisInqUbounds(zaxisID, ubounds);
44199     }
44200   else
44201     {
44202       for ( size_t i = 0; i < dimlen; ++i ) lbounds[i] = levels[i];
44203       for ( size_t i = 0; i < dimlen-1; ++i ) ubounds[i] = levels[i+1];
44204       ubounds[dimlen-1] = levels[dimlen-1] + 1;
44205     }
44206 
44207   //if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
44208     {
44209       const size_t nvertex = 2;
44210       if ( dimlen > 1 && nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR )
44211         cdf_def_dim(fileID, bndsName, nvertex, &nvdimID);
44212 
44213       if ( nvdimID != CDI_UNDEFID )
44214         {
44215           size_t axisnameLen = strlen(axisname);
44216           axisname[axisnameLen] = '_';
44217           memcpy(axisname + axisnameLen + 1, bndsName, sizeof (bndsName));
44218           axisnameLen += sizeof (bndsName);
44219           int dimIDs[2] = { *dimID, nvdimID };
44220           cdf_def_var(fileID, axisname, (nc_type) xtype, 2, dimIDs, &ncbvarid);
44221           cdf_put_att_text(fileID, ncvarid, "bounds", axisnameLen, axisname);
44222           {
44223             static const char sname[] = "standard_name",
44224               sname_v[] = "atmosphere_hybrid_sigma_pressure_coordinate";
44225             struct attTxtTab2 tab[] = {
44226               { sname, sname_v, sizeof (sname_v) - 1 },
44227             };
44228             enum { nAtt = sizeof (tab) / sizeof (tab[0]) };
44229             for ( size_t i = 0; i < nAtt; ++i )
44230               cdf_put_att_text(fileID, ncbvarid, tab[i].attName, tab[i].valLen, tab[i].attVal);
44231             cdf_put_att_text(fileID, ncbvarid, "units", strlen(zunits), zunits);
44232           }
44233 
44234           if ( p0status == 0 )
44235             len = (size_t)(sprintf(txt, "%s%s %s%s", "a: a_bnds b: b_bnds p0: ", p0name, "ps: ", psname));
44236           else
44237             len = (size_t)(sprintf(txt, "%s%s", "ap: ap_bnds b: b_bnds ps: ", psname));
44238           cdf_put_att_text(fileID, ncbvarid, "formula_terms", len, txt);
44239         }
44240     }
44241 
44242   cdf_enddef(fileID);
44243   streamptr->ncmode = 2;
44244 
44245   cdf_put_var_double(fileID, ncvarid, levels);
44246 
44247   if ( p0varid != CDI_UNDEFID ) cdf_put_var_double(fileID, p0varid, &p0value);
44248 
44249   if ( ncbvarid != CDI_UNDEFID )
44250     {
44251       double *zbounds = buffer;
44252       for ( size_t i = 0; i < dimlen; ++i )
44253         {
44254           zbounds[2*i  ] = lbounds[i];
44255           zbounds[2*i+1] = ubounds[i];
44256         }
44257       cdf_put_var_double(fileID, ncbvarid, zbounds);
44258     }
44259 
44260   cdf_def_vct_cf(streamptr, zaxisID, *dimID, nvdimID, p0status, p0value);
44261 
44262   if ( *dimID == CDI_UNDEFID )
44263     streamptr->zaxisID[zaxisindex] = type == ZAXIS_HYBRID
44264       ? streamptr->vct.mlevID : streamptr->vct.ilevID;
44265 
44266   free(buffer);
44267 }
44268 
44269 static
cdf_def_zaxis_hybrid(stream_t * streamptr,int type,int * ncvarid,int zaxisID,int zaxisindex,int xtype,size_t dimlen,int * dimID,char * axisname)44270 void cdf_def_zaxis_hybrid(stream_t *streamptr, int type, int *ncvarid, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname)
44271 {
44272   void (*def_zaxis_hybrid_delegate)(stream_t *streamptr, int type, int *ncvarid, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname)
44273     = ( (!CDI_CMOR_Mode && CDI_Convention == CDI_CONVENTION_ECHAM)
44274         || type == ZAXIS_HYBRID_HALF )
44275     ? cdf_def_zaxis_hybrid_echam : cdf_def_zaxis_hybrid_cf;
44276   def_zaxis_hybrid_delegate(streamptr, type, ncvarid, zaxisID, zaxisindex, xtype, dimlen, dimID, axisname);
44277 }
44278 
44279 static
cdfDefZaxisUUID(stream_t * streamptr,int zaxisID)44280 void cdfDefZaxisUUID(stream_t *streamptr, int zaxisID)
44281 {
44282   unsigned char uuidOfVGrid[CDI_UUID_SIZE];
44283   int length = CDI_UUID_SIZE;
44284   memset(uuidOfVGrid, 0, length);
44285   cdiInqKeyBytes(zaxisID, CDI_GLOBAL, CDI_KEY_UUID, uuidOfVGrid, &length);
44286   if ( uuidOfVGrid[0] != 0 )
44287     {
44288       char uuidOfVGridStr[37];
44289       cdiUUID2Str(uuidOfVGrid, uuidOfVGridStr);
44290       if ( uuidOfVGridStr[0] != 0 && strlen(uuidOfVGridStr) == 36 )
44291         {
44292           const int fileID  = streamptr->fileID;
44293           if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
44294           cdf_put_att_text(fileID, NC_GLOBAL, "uuidOfVGrid", 36, uuidOfVGridStr);
44295           if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
44296         }
44297     }
44298 }
44299 
44300 #ifndef USE_MPI
44301 static
cdfDefZaxisChar(stream_t * streamptr,int zaxisID,char * axisname,int * dimID,size_t dimlen,int zaxisindex)44302 void cdfDefZaxisChar(stream_t *streamptr, int zaxisID, char *axisname, int *dimID, size_t dimlen, int zaxisindex)
44303 {
44304   const int fileID  = streamptr->fileID;
44305   int ncvarID = CDI_UNDEFID;
44306   if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
44307 
44308   /* Check StrlenID */
44309   char strlen[8] = "strlen\0";
44310   const size_t clen = (size_t) zaxisInqCLen(zaxisID);
44311   if ( clen == 0 )
44312     Error("Maximal string length value is 0.\nA given character axis requires a dimension to save the maximal string length.");
44313   int strlenID = CDI_UNDEFID;
44314   strlenID = checkDimName(fileID, clen, strlen);
44315 
44316   if ( strlenID == CDI_UNDEFID ) cdf_def_dim(fileID, strlen, clen, &strlenID);
44317 
44318   /* Check 'areatype'dimID */
44319   char dimname[CDI_MAX_NAME+3];
44320   int length = sizeof(dimname);
44321   cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_DIMNAME, dimname, &length);
44322   *dimID = checkDimName(fileID, dimlen, dimname);
44323   if (dimlen <= 0)
44324     Error("No strings delivered for a character axis.");
44325   if ( dimname[0] == 0 ) { memcpy(dimname, "area_type", 10); dimname[10] = 0; }
44326 
44327   if ( *dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, dimID);
44328 
44329   int dimIDs[2];
44330   dimIDs[0] = *dimID;
44331   dimIDs[1] = strlenID;
44332 
44333   /* Get Stringvalues */
44334   char **cvals = zaxisInqCValsPtr(zaxisID);
44335 
44336   if ( cvals )
44337     {
44338       /* Define variable and its attributes */
44339       cdf_def_var(fileID, axisname, NC_CHAR, 2, dimIDs, &ncvarID);
44340 
44341       cdfPutGridStdAtts(fileID, ncvarID, zaxisID, 'Z');
44342       cdf_put_att_text(fileID, ncvarID, "axis", 1, "Z");
44343       cdfDefineAttributes(zaxisID, CDI_GLOBAL, fileID, ncvarID);
44344 
44345       streamptr->nczvarID[zaxisindex] = ncvarID;
44346       cdf_enddef(fileID);
44347 
44348       /* Write Stringvalues */
44349       size_t start[2], count[2];
44350       start[1] = 0;
44351       count[0] = 1;
44352       count[1] = clen;
44353       for ( size_t i = 0; i < dimlen; i++ )
44354         {
44355           start[0] = i;
44356           nc_put_vara_text(fileID, ncvarID, start, count, cvals[i]);
44357         }
44358     }
44359 
44360   streamptr->ncmode = 2;
44361 }
44362 #endif
44363 
44364 static
cdfDefZaxis(stream_t * streamptr,int zaxisID)44365 void cdfDefZaxis(stream_t *streamptr, int zaxisID)
44366 {
44367   /*  char zaxisname0[CDI_MAX_NAME]; */
44368   int dimID = CDI_UNDEFID;
44369   int ncvarid = CDI_UNDEFID, ncbvarid = CDI_UNDEFID;
44370   const int xtype = zaxisInqDatatype(zaxisID) == CDI_DATATYPE_FLT32 ? NC_FLOAT : NC_DOUBLE;
44371 
44372   const int vlistID = streamptr->vlistID;
44373   const int fileID  = streamptr->fileID;
44374 
44375   const int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
44376 
44377   const int nzaxis = vlistNzaxis(vlistID);
44378 
44379   const size_t dimlen = (size_t)zaxisInqSize(zaxisID);
44380   const int type = zaxisInqType(zaxisID);
44381 
44382   int ndims = 1;
44383 
44384   if ( dimlen == 1 )
44385     {
44386       bool is_scalar = zaxisInqScalar(zaxisID) > 0;
44387       if ( !is_scalar && CDI_CMOR_Mode )
44388         {
44389           is_scalar = true;
44390           zaxisDefScalar(zaxisID);
44391         }
44392 
44393       if ( is_scalar ) ndims = 0;
44394       if ( CDI_Reduce_Dim ) return;
44395 
44396       switch (type)
44397         {
44398         case ZAXIS_SURFACE:
44399         case ZAXIS_CLOUD_BASE:
44400         case ZAXIS_CLOUD_TOP:
44401         case ZAXIS_ISOTHERM_ZERO:
44402         case ZAXIS_TROPOPAUSE:
44403         case ZAXIS_TOA:
44404         case ZAXIS_SEA_BOTTOM:
44405         case ZAXIS_ATMOSPHERE:
44406         case ZAXIS_MEANSEA:
44407         case ZAXIS_LAKE_BOTTOM:
44408         case ZAXIS_SEDIMENT_BOTTOM:
44409         case ZAXIS_SEDIMENT_BOTTOM_TA:
44410         case ZAXIS_SEDIMENT_BOTTOM_TW:
44411         case ZAXIS_MIX_LAYER:
44412           return;
44413         }
44414     }
44415 
44416   char axisname[CDI_MAX_NAME];
44417   int length = CDI_MAX_NAME;
44418   cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_NAME, axisname, &length);
44419 
44420   if ( dimID == CDI_UNDEFID )
44421     {
44422       checkZaxisName(axisname, fileID, vlistID, zaxisID, nzaxis);
44423 
44424       char dimname[CDI_MAX_NAME+3]; dimname[0] = 0;
44425       if ( dimname[0] == 0 ) strcpy(dimname, axisname);
44426 
44427       if ( type == ZAXIS_REFERENCE ) cdfDefZaxisUUID(streamptr, zaxisID);
44428 
44429       if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
44430         {
44431           cdf_def_zaxis_hybrid(streamptr, type, &ncvarid, zaxisID, zaxisindex, xtype, dimlen, &dimID, axisname);
44432 
44433           int natts;
44434           cdiInqNatts(zaxisID, CDI_GLOBAL, &natts);
44435           if ( natts > 0 && streamptr->ncmode == 2 ) cdf_redef(fileID);
44436           cdfDefineAttributes(zaxisID, CDI_GLOBAL, fileID, ncvarid);
44437           if ( natts > 0 && streamptr->ncmode == 2 ) cdf_enddef(fileID);
44438         }
44439 #ifndef USE_MPI
44440       else if ( type == ZAXIS_CHAR )
44441         cdfDefZaxisChar(streamptr, zaxisID, axisname, &dimID, dimlen, zaxisindex);
44442 #endif
44443       else
44444         {
44445           dimID = checkDimName(fileID, dimlen, dimname);
44446 
44447           if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
44448 
44449           if ( ndims && dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
44450 
44451           if ( zaxisInqLevels(zaxisID, NULL) )
44452             {
44453               cdf_def_var(fileID, axisname, (nc_type) xtype, ndims, &dimID, &ncvarid);
44454 
44455               cdfPutGridStdAtts(fileID, ncvarid, zaxisID, 'Z');
44456 
44457               {
44458                 const int positive = zaxisInqPositive(zaxisID);
44459                 static const char positive_up[] = "up",
44460                                   positive_down[] = "down";
44461                 static const struct attTxtTab tab[2] = {
44462                   { positive_up, sizeof (positive_up) - 1 },
44463                   { positive_down, sizeof (positive_down) - 1 },
44464                 };
44465                 if ( positive == POSITIVE_UP || positive == POSITIVE_DOWN )
44466                   {
44467                     const size_t select = positive == POSITIVE_DOWN;
44468                     cdf_put_att_text(fileID, ncvarid, "positive", tab[select].txtLen, tab[select].txt);
44469                   }
44470               }
44471               cdf_put_att_text(fileID, ncvarid, "axis", 1, "Z");
44472 
44473               if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
44474                 {
44475                   int nvdimID = CDI_UNDEFID;
44476                   const size_t nvertex = 2;
44477                   if ( nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR )
44478                     cdf_def_dim(fileID, bndsName, nvertex, &nvdimID);
44479 
44480                   if ( nvdimID != CDI_UNDEFID )
44481                     {
44482                       const size_t axisnameLen = strlen(axisname);
44483                       axisname[axisnameLen] = '_';
44484                       memcpy(axisname + axisnameLen + 1, bndsName, sizeof (bndsName));
44485                       int dimIDs[2];
44486                       dimIDs[0] = dimID;
44487                       dimIDs[ndims] = nvdimID;
44488                       cdf_def_var(fileID, axisname, (nc_type) xtype, ndims+1, dimIDs, &ncbvarid);
44489                       cdf_put_att_text(fileID, ncvarid, "bounds", strlen(axisname), axisname);
44490                     }
44491                 }
44492 
44493               cdfDefineAttributes(zaxisID, CDI_GLOBAL, fileID, ncvarid);
44494             }
44495 
44496           cdf_enddef(fileID);
44497           streamptr->ncmode = 2;
44498 
44499           if ( zaxisInqLevels(zaxisID, NULL) )
44500             {
44501               cdf_put_var_double(fileID, ncvarid, zaxisInqLevelsPtr(zaxisID));
44502 
44503               if ( ncbvarid != CDI_UNDEFID )
44504                 {
44505                   double *buffer = (double *) malloc(4*dimlen*sizeof(double));
44506                   double *zbounds = buffer;
44507                   double *lbounds = buffer + 2*dimlen;
44508                   double *ubounds = buffer + 3*dimlen;
44509                   zaxisInqLbounds(zaxisID, lbounds);
44510                   zaxisInqUbounds(zaxisID, ubounds);
44511                   for ( size_t i = 0; i < dimlen; ++i )
44512                     {
44513                       zbounds[2*i  ] = lbounds[i];
44514                       zbounds[2*i+1] = ubounds[i];
44515                     }
44516 
44517                   cdf_put_var_double(fileID, ncbvarid, zbounds);
44518 
44519                   free(buffer);
44520                 }
44521 
44522               if ( ndims == 0 ) streamptr->nczvarID[zaxisindex] = ncvarid;
44523             }
44524         }
44525     }
44526 
44527   if ( dimID != CDI_UNDEFID )
44528     streamptr->zaxisID[zaxisindex] = dimID;
44529 }
44530 
44531 static
cdf_def_mapping(stream_t * streamptr,int gridID)44532 void cdf_def_mapping(stream_t *streamptr, int gridID)
44533 {
44534   char gmapname[CDI_MAX_NAME];
44535   int length = CDI_MAX_NAME;
44536   cdiInqKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_NAME, gmapname, &length);
44537   if ( gmapname[0] )
44538     {
44539       nc_type gmapvartype = NC_INT;
44540       int datatype = -1;
44541       int status = cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_VARTYPE, &datatype);
44542       if (status == CDI_NOERR) gmapvartype = (nc_type) datatype;
44543       char gmapvarname[CDI_MAX_NAME];
44544       length = CDI_MAX_NAME;
44545       cdiInqKeyString(gridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_VARNAME, gmapvarname, &length);
44546 
44547       const int fileID = streamptr->fileID;
44548       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
44549 
44550       int ncvarid;
44551       const int ncerrcode = nc_def_var(fileID, gmapvarname, (nc_type) gmapvartype, 0, NULL, &ncvarid);
44552       if ( ncerrcode == NC_NOERR )
44553         cdfDefineAttributes(gridID, CDI_GLOBAL, fileID, ncvarid);
44554 
44555       cdf_enddef(fileID);
44556 
44557       if ( ncerrcode == NC_NOERR && gmapvartype != NC_CHAR )
44558         {
44559           int dummy = 1;
44560           cdf_put_var_int(fileID, ncvarid, &dummy);
44561         }
44562     }
44563 }
44564 
44565 static
cdfDefCharacter(stream_t * streamptr,int gridID,int gridindex,int xory,int strlen)44566 void cdfDefCharacter(stream_t *streamptr, int gridID, int gridindex, int xory, int strlen)
44567 {
44568   if ( streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] != CDI_UNDEFID ) return;
44569 
44570   const size_t dimlen = ( xory == 0 ) ? gridInqXsize(gridID) : gridInqYsize(gridID);
44571   int dimID, strlenID;
44572   ncgrid_t *ncgrid = streamptr->ncgrid;
44573 
44574   // Check for all grids up to gridindex whether it already is defined
44575 
44576   for ( int index = 0; index < gridindex; index++ )
44577     {
44578       const int gridID0 = ncgrid[index].gridID;
44579       const int gridtype0 = gridInqType(gridID0);
44580       if ( gridtype0 == GRID_CHARXY )
44581         {
44582           if ( gridInqXIsc(gridID0) == strlen && gridInqXsize(gridID0) == dimlen )
44583             return;
44584           else if ( gridInqYIsc(gridID0) == strlen && gridInqYsize(gridID0) == dimlen )
44585             return;
44586         }
44587     }
44588 
44589   const int fileID  = streamptr->fileID;
44590 
44591   if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
44592 
44593   // Define Dims
44594 
44595   char dimname[CDI_MAX_NAME+3];
44596   int length = sizeof(dimname);
44597   cdiInqKeyString(gridID, (xory == 0) ? CDI_XAXIS : CDI_YAXIS, CDI_KEY_DIMNAME, dimname, &length);
44598   if ( dimname[0] == 0 ) { memcpy(dimname, "region", 7); dimname[6] = 0; }
44599   dimID = checkDimName(fileID, dimlen, dimname);
44600   if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
44601 
44602   // Define strlength dim
44603 
44604   strcpy(dimname, "strlen");
44605   strlenID = checkDimName(fileID, strlen, dimname);
44606   if ( strlenID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, strlen, &strlenID);
44607 
44608   // Define Variable
44609 
44610   int dimIDs[2];
44611   dimIDs[0] = dimID;
44612   dimIDs[1] = strlenID;
44613 
44614   char axisname[CDI_MAX_NAME];
44615   char **cvals = (char **) Malloc(dimlen * sizeof(char *));
44616   for ( size_t i = 0; i < dimlen; i++ )
44617     cvals[i] = (char*) Malloc(strlen * sizeof(char));
44618   int ncaxisid;
44619   if ( xory == 0 )
44620     {
44621       length = CDI_MAX_NAME;
44622       cdiInqKeyString(gridID, CDI_XAXIS, CDI_KEY_NAME, axisname, &length);
44623       gridInqXCvals(gridID, cvals);
44624     }
44625   else
44626     {
44627       length = CDI_MAX_NAME;
44628       cdiInqKeyString(gridID, CDI_YAXIS, CDI_KEY_NAME, axisname, &length);
44629       gridInqXCvals(gridID, cvals);
44630     }
44631   int status = nc_inq_varid(fileID, axisname, &ncaxisid);
44632   if ( status != NC_NOERR )
44633     {
44634       cdf_def_var(fileID, axisname, NC_CHAR, 2, dimIDs, &ncaxisid);
44635       if ( xory == 0 )
44636         cdfPutGridStdAtts(fileID, ncaxisid, gridID, 'X');
44637       else
44638         cdfPutGridStdAtts(fileID, ncaxisid, gridID, 'Y');
44639     }
44640   else
44641     return;
44642   cdf_enddef(fileID);
44643 
44644   // Write Var
44645 
44646   size_t start[2], count[2];
44647   start[1] = 0;
44648   count[0] = 1;
44649   count[1] = strlen;
44650   for (size_t i = 0; i < dimlen; i++)
44651     {
44652       start[0] = i;
44653       status = nc_put_vara_text(fileID, ncaxisid, start, count, cvals[i]);
44654     }
44655 
44656   ncgrid[gridindex].gridID = gridID;
44657   if ( xory == 0 )
44658     {
44659       ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
44660       ncgrid[gridindex].ncIDs[CDF_VARID_X] = ncaxisid;
44661     }
44662   else
44663     {
44664       ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = dimID;
44665       ncgrid[gridindex].ncIDs[CDF_VARID_Y] = ncaxisid;
44666     }
44667   streamptr->ncmode = 2;
44668 }
44669 
44670 static
cdfDefRgrid(stream_t * streamptr,int gridID,int gridindex)44671 void cdfDefRgrid(stream_t *streamptr, int gridID, int gridindex)
44672 {
44673   ncgrid_t *ncgrid = streamptr->ncgrid;
44674 
44675   ncgrid[gridindex].gridID = gridID;
44676 
44677   {
44678     const size_t dimlen = gridInqSize(gridID);
44679 
44680     struct idSearch search = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_X,
44681                                                GRID_GAUSSIAN_REDUCED, (int)dimlen, gridInqType, gridInqSize);
44682     const int iz = search.numNonMatching;
44683     int dimID = search.foundID;
44684 
44685     if ( dimID == CDI_UNDEFID )
44686       {
44687         const int fileID  = streamptr->fileID;
44688 
44689         char axisname[16] = "rgridX";
44690         if ( iz == 0 ) axisname[5] = '\0';
44691         else           sprintf(&axisname[5], "%1d", iz+1);
44692 
44693         if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
44694 
44695         cdf_def_dim(fileID, axisname, dimlen, &dimID);
44696 
44697         cdf_enddef(fileID);
44698         streamptr->ncmode = 2;
44699       }
44700 
44701     ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
44702   }
44703 
44704   {
44705     const size_t dimlen = gridInqYsize(gridID);
44706 
44707     struct idSearch search = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_RP,
44708                                                GRID_GAUSSIAN_REDUCED, (int)dimlen, gridInqType, gridInqSize);
44709     const int iz = search.numNonMatching;
44710     int dimID = search.foundID;
44711 
44712     if ( dimID == CDI_UNDEFID )
44713       {
44714         const int fileID  = streamptr->fileID;
44715 
44716         char axisname[32] = "reduced_pointsX";
44717         if ( iz == 0 ) axisname[14] = '\0';
44718         else           sprintf(&axisname[5], "%1d", iz+1);
44719 
44720         if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
44721 
44722         cdf_def_dim(fileID, axisname, dimlen, &dimID);
44723 
44724         int ncvarid = CDI_UNDEFID;
44725 
44726         int ndims = 1;
44727         const nc_type xtype = NC_INT;
44728         cdf_def_var(fileID, axisname, xtype, ndims, &dimID, &ncvarid);
44729 
44730         cdf_enddef(fileID);
44731         streamptr->ncmode = 2;
44732 
44733         int *reducedPoints = (int*) Malloc(dimlen*sizeof(int));
44734         gridInqReducedPoints(gridID, reducedPoints);
44735         cdf_put_var_int(fileID, ncvarid, reducedPoints);
44736         Free(reducedPoints);
44737 
44738         ncgrid[gridindex].ncIDs[CDF_VARID_RP] = ncvarid;
44739       }
44740 
44741     ncgrid[gridindex].ncIDs[CDF_DIMID_RP] = dimID;
44742   }
44743 }
44744 
44745 static
cdfDefGdim(stream_t * streamptr,int gridID,int gridindex)44746 void cdfDefGdim(stream_t *streamptr, int gridID, int gridindex)
44747 {
44748   ncgrid_t *ncgrid = streamptr->ncgrid;
44749   int dimID = CDI_UNDEFID;
44750 
44751   const size_t dimlen = gridInqSize(gridID);
44752 
44753   if ( gridInqYsize(gridID) == 0 )
44754     {
44755       struct idSearch search
44756         = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_X,
44757                             GRID_GENERIC, (int)dimlen, gridInqType, gridInqSize);
44758       dimID = search.foundID;
44759     }
44760 
44761   if ( gridInqXsize(gridID) == 0 )
44762     {
44763       struct idSearch search
44764         = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_Y,
44765                             GRID_GENERIC, (int)dimlen, gridInqType, gridInqSize);
44766       dimID = search.foundID;
44767     }
44768 
44769   if ( dimID == CDI_UNDEFID )
44770     {
44771       int fileID  = streamptr->fileID;
44772       char dimname[CDI_MAX_NAME];
44773       strcpy(dimname, "gsize");
44774 
44775       dimID = checkDimName(fileID, dimlen, dimname);
44776 
44777       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
44778 
44779       if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
44780 
44781       cdf_enddef(fileID);
44782       streamptr->ncmode = 2;
44783     }
44784 
44785   ncgrid[gridindex].gridID = gridID;
44786   ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
44787 }
44788 
44789 static
cdfDefGrid(stream_t * streamptr,int gridID,int gridindex)44790 void cdfDefGrid(stream_t *streamptr, int gridID, int gridindex)
44791 {
44792   if ( streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] != CDI_UNDEFID ) return;
44793 
44794   const int gridtype = gridInqType(gridID);
44795   const size_t size = gridInqSize(gridID);
44796 
44797   if ( CDI_Debug )
44798     Message("gridtype = %d  size = %zu", gridtype, size);
44799 
44800   if ( CDI_Reduce_Dim && size == 1 ) // no grid information
44801     {
44802       streamptr->ncgrid[gridindex].gridID = gridID;
44803       return;
44804     }
44805 
44806   if ( gridtype == GRID_GAUSSIAN    ||
44807        gridtype == GRID_LONLAT      ||
44808        gridtype == GRID_PROJECTION  ||
44809        gridtype == GRID_GENERIC )
44810     {
44811       if ( gridtype == GRID_GENERIC )
44812         {
44813           if ( size == 1 && gridInqXsize(gridID) == 0 && gridInqYsize(gridID) == 0 )
44814             {
44815               // no grid information
44816               streamptr->ncgrid[gridindex].gridID = gridID;
44817             }
44818           else
44819             {
44820               bool lx = false, ly = false;
44821               if ( gridInqXsize(gridID) /*&& gridInqXvals(gridID, NULL) */ )
44822                 {
44823                   cdfDefXaxis(streamptr, gridID, gridindex, 1, false);
44824                   lx = true;
44825                 }
44826 
44827               if ( gridInqYsize(gridID) /*&& gridInqYvals(gridID, NULL) */ )
44828                 {
44829                   cdfDefYaxis(streamptr, gridID, gridindex, 1, false);
44830                   ly = true;
44831                 }
44832 
44833               if ( !lx && !ly ) cdfDefGdim(streamptr, gridID, gridindex);
44834             }
44835         }
44836       else
44837         {
44838           const int ndims = !(gridtype == GRID_LONLAT && size == 1 && !gridInqHasDims(gridID));
44839 
44840           if ( gridInqXsize(gridID) ) cdfDefXaxis(streamptr, gridID, gridindex, ndims, false);
44841           if ( gridInqYsize(gridID) ) cdfDefYaxis(streamptr, gridID, gridindex, ndims, false);
44842 
44843           cdf_def_mapping(streamptr, gridID);
44844         }
44845     }
44846   else if ( gridtype == GRID_CURVILINEAR )
44847     {
44848       cdfDefCurvilinear(streamptr, gridID, gridindex);
44849     }
44850   else if ( gridtype == GRID_UNSTRUCTURED )
44851     {
44852       cdfDefUnstructured(streamptr, gridID, gridindex);
44853     }
44854   else if ( gridtype == GRID_GAUSSIAN_REDUCED )
44855     {
44856       cdfDefRgrid(streamptr, gridID, gridindex);
44857       if ( gridInqYsize(gridID) ) cdfDefYaxis(streamptr, gridID, gridindex, 1, true);
44858     }
44859   else if ( gridtype == GRID_SPECTRAL )
44860     {
44861       cdfDefComplex(streamptr, gridID, gridindex);
44862       cdfDefSP(streamptr, gridID, gridindex);
44863     }
44864   else if ( gridtype == GRID_FOURIER )
44865     {
44866       cdfDefComplex(streamptr, gridID, gridindex);
44867       cdfDefFC(streamptr, gridID, gridindex);
44868     }
44869   else if ( gridtype == GRID_TRAJECTORY )
44870     {
44871       cdfDefTrajLon(streamptr, gridID, gridindex);
44872       cdfDefTrajLat(streamptr, gridID, gridindex);
44873     }
44874   else if ( gridtype == GRID_CHARXY )
44875     {
44876       int strlen = 0;
44877       if ( (strlen = gridInqXIsc(gridID)) )
44878         cdfDefCharacter(streamptr, gridID, gridindex, 0, strlen);
44879       else
44880         if ( gridInqXsize(gridID) ) cdfDefXaxis(streamptr, gridID, gridindex, 1, false);
44881       if ( (strlen = gridInqYIsc(gridID)) )
44882         cdfDefCharacter(streamptr, gridID, gridindex, 1, strlen);
44883       else
44884         if ( gridInqYsize(gridID) ) cdfDefYaxis(streamptr, gridID, gridindex, 1, false);
44885     }
44886   else
44887     {
44888       Error("Unsupported grid type: %s", gridNamePtr(gridtype));
44889     }
44890 }
44891 
44892 
cdfDefCoordinateVars(stream_t * streamptr)44893 void cdfDefCoordinateVars(stream_t *streamptr)
44894 {
44895   const int vlistID = streamptr->vlistID;
44896   if ( vlistID == CDI_UNDEFID ) Error("Internal problem! vlist undefined for streamptr %p", streamptr);
44897 
44898   if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
44899 
44900   const int ngrids = vlistNgrids(vlistID);
44901   if ( 2*ngrids > MAX_GRIDS_PS ) Error("Internal problem! Too many grids per stream (max=%d)\n", MAX_GRIDS_PS);
44902   for ( int index = 0; index < 2*ngrids; ++index )
44903     {
44904       streamptr->ncgrid[index].gridID = CDI_UNDEFID;
44905       for (size_t i = 0; i < CDF_SIZE_ncIDs; ++i)
44906         streamptr->ncgrid[index].ncIDs[i] = CDI_UNDEFID;
44907     }
44908 
44909   for ( int index = 0; index < ngrids; ++index )
44910     {
44911       const int gridID = vlistGrid(vlistID, index);
44912       cdfDefGrid(streamptr, gridID, index);
44913     }
44914   {
44915     int index = ngrids-1;
44916     for ( int i = 0; i < ngrids; ++i )
44917       {
44918         int gridID = vlistGrid(vlistID, i);
44919         int projID = gridInqProj(gridID);
44920         if ( projID != CDI_UNDEFID ) cdfDefGrid(streamptr, projID, ++index);
44921       }
44922   }
44923   const int nzaxis = vlistNzaxis(vlistID);
44924   for ( int index = 0; index < nzaxis; ++index )
44925     {
44926       const int zaxisID = vlistZaxis(vlistID, index);
44927       if ( streamptr->zaxisID[index] == CDI_UNDEFID ) cdfDefZaxis(streamptr, zaxisID);
44928     }
44929 
44930   if ( streamptr->ncmode != 2 )
44931     {
44932       cdf_enddef(streamptr->fileID);
44933       streamptr->ncmode = 2;
44934     }
44935 }
44936 
44937 #endif
44938 
44939 /*
44940  * Local Variables:
44941  * c-file-style: "Java"
44942  * c-basic-offset: 2
44943  * indent-tabs-mode: nil
44944  * show-trailing-whitespace: t
44945  * require-trailing-newline: t
44946  * End:
44947  */
44948 #ifdef HAVE_CONFIG_H
44949 #endif
44950 
44951 #ifdef HAVE_LIBNETCDF
44952 
44953 #include <stdio.h>
44954 #include <string.h>
44955 
44956 
44957 
44958 static
cdfDefTimeBounds(int fileID,int nctimevarid,int nctimedimid,const char * taxis_name,taxis_t * taxis)44959 int cdfDefTimeBounds(int fileID, int nctimevarid, int nctimedimid, const char *taxis_name, taxis_t* taxis)
44960 {
44961   int dims[2];
44962 
44963   dims[0] = nctimedimid;
44964 
44965   /* fprintf(stderr, "time has bounds\n"); */
44966   static const char bndsName[] = "bnds";
44967   if ( nc_inq_dimid(fileID, bndsName, &dims[1]) != NC_NOERR )
44968     cdf_def_dim(fileID, bndsName, 2, &dims[1]);
44969 
44970   const char *bndsAttName, *bndsAttVal;
44971   size_t bndsAttValLen;
44972   char tmpstr[CDI_MAX_NAME];
44973   if ( taxis->climatology )
44974     {
44975       static const char climatology_bndsName[] = "climatology_bnds",
44976         climatology_bndsAttName[] = "climatology";
44977       bndsAttName = climatology_bndsAttName;
44978       bndsAttValLen = sizeof (climatology_bndsName) - 1;
44979       bndsAttVal = climatology_bndsName;
44980     }
44981   else
44982     {
44983       size_t taxisnameLen = strlen(taxis_name);
44984       memcpy(tmpstr, taxis_name, taxisnameLen);
44985       tmpstr[taxisnameLen] = '_';
44986       memcpy(tmpstr + taxisnameLen + 1, bndsName, sizeof (bndsName));
44987       size_t tmpstrLen = taxisnameLen + sizeof (bndsName);
44988       static const char generic_bndsAttName[] = "bounds";
44989       bndsAttName = generic_bndsAttName;
44990       bndsAttValLen = tmpstrLen;
44991       bndsAttVal = tmpstr;
44992     }
44993 
44994   int time_bndsid = -1;
44995   cdf_def_var(fileID, bndsAttVal, NC_DOUBLE, 2, dims, &time_bndsid);
44996   cdf_put_att_text(fileID, nctimevarid, bndsAttName, bndsAttValLen, bndsAttVal);
44997 
44998   return time_bndsid;
44999 }
45000 
45001 static
cdfDefTimeUnits(char * unitstr,taxis_t * taxis)45002 void cdfDefTimeUnits(char *unitstr, taxis_t *taxis)
45003 {
45004   if ( taxis->units && taxis->units[0] )
45005     {
45006       strcpy(unitstr, taxis->units);
45007     }
45008   else
45009     {
45010       unitstr[0] = 0;
45011 
45012       if ( taxis->type == TAXIS_ABSOLUTE )
45013         {
45014           static const char *const unitstrfmt[3]
45015             = { "year as %Y.%f",
45016                 "month as %Y%m.%f",
45017                 "day as %Y%m%d.%f" };
45018           size_t fmtidx = (taxis->unit == TUNIT_YEAR ? 0
45019                            : (taxis->unit == TUNIT_MONTH ? 1
45020                               : 2));
45021           strcpy(unitstr, unitstrfmt[fmtidx]);
45022         }
45023       else
45024         {
45025           int year, month, day, hour, minute, second;
45026           cdiDecodeDate(taxis->rdate, &year, &month, &day);
45027           cdiDecodeTime(taxis->rtime, &hour, &minute, &second);
45028 
45029           int timeunit = (taxis->unit != -1) ? taxis->unit : TUNIT_HOUR;
45030           if      ( timeunit == TUNIT_QUARTER   ) timeunit = TUNIT_MINUTE;
45031           else if ( timeunit == TUNIT_30MINUTES ) timeunit = TUNIT_MINUTE;
45032           else if (    timeunit == TUNIT_3HOURS
45033                     || timeunit == TUNIT_6HOURS
45034                     || timeunit == TUNIT_12HOURS ) timeunit = TUNIT_HOUR;
45035 
45036           sprintf(unitstr, "%s since %d-%d-%d %02d:%02d:%02d",
45037                   tunitNamePtr(timeunit), year, month, day, hour, minute, second);
45038         }
45039     }
45040 }
45041 
45042 static
cdfDefForecastTimeUnits(char * unitstr,int timeunit)45043 void cdfDefForecastTimeUnits(char *unitstr, int timeunit)
45044 {
45045   unitstr[0] = 0;
45046 
45047   if ( timeunit == -1 ) timeunit = TUNIT_HOUR;
45048   else if ( timeunit == TUNIT_QUARTER   ) timeunit = TUNIT_MINUTE;
45049   else if ( timeunit == TUNIT_30MINUTES ) timeunit = TUNIT_MINUTE;
45050   else if (    timeunit == TUNIT_3HOURS
45051             || timeunit == TUNIT_6HOURS
45052             || timeunit == TUNIT_12HOURS ) timeunit = TUNIT_HOUR;
45053 
45054   strcpy(unitstr, tunitNamePtr(timeunit));
45055 }
45056 
45057 static
cdfDefCalendar(int fileID,int ncvarid,int calendar)45058 void cdfDefCalendar(int fileID, int ncvarid, int calendar)
45059 {
45060   static const struct { int calCode; const char *calStr; } calTab[] = {
45061     { CALENDAR_STANDARD, "standard" },
45062     { CALENDAR_GREGORIAN, "gregorian" },
45063     { CALENDAR_PROLEPTIC, "proleptic_gregorian" },
45064     { CALENDAR_NONE, "none" },
45065     { CALENDAR_360DAYS, "360_day" },
45066     { CALENDAR_365DAYS, "365_day" },
45067     { CALENDAR_366DAYS, "366_day" },
45068   };
45069   enum { calTabSize = sizeof calTab / sizeof calTab[0] };
45070 
45071   for ( size_t i = 0; i < calTabSize; ++i )
45072     if ( calTab[i].calCode == calendar )
45073       {
45074         const char *calstr = calTab[i].calStr;
45075         size_t len = strlen(calstr);
45076         cdf_put_att_text(fileID, ncvarid, "calendar", len, calstr);
45077         break;
45078       }
45079 }
45080 
45081 
cdfDefTime(stream_t * streamptr)45082 void cdfDefTime(stream_t* streamptr)
45083 {
45084   static const char default_name[] = "time";
45085 
45086   if ( streamptr->basetime.ncvarid != CDI_UNDEFID ) return;
45087 
45088   const int fileID = streamptr->fileID;
45089 
45090   if ( streamptr->ncmode == 0 ) streamptr->ncmode = 1;
45091   if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
45092 
45093   taxis_t *taxis = &streamptr->tsteps[0].taxis;
45094 
45095   const char *taxis_name = (taxis->name && taxis->name[0]) ? taxis->name : default_name ;
45096   int time_dimid;
45097   cdf_def_dim(fileID, taxis_name, NC_UNLIMITED, &time_dimid);
45098   streamptr->basetime.ncdimid = time_dimid;
45099 
45100   const int datatype = taxis->datatype;
45101   const nc_type xtype = (datatype == CDI_DATATYPE_INT32) ? NC_INT : ((datatype == CDI_DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE);
45102 
45103   int time_varid;
45104   cdf_def_var(fileID, taxis_name, xtype, 1, &time_dimid, &time_varid);
45105   streamptr->basetime.ncvarid = time_varid;
45106 
45107 #ifdef  HAVE_NETCDF4
45108   if ( streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C )
45109     {
45110       const size_t chunk = 512;
45111       cdf_def_var_chunking(fileID, time_varid, NC_CHUNKED, &chunk);
45112     }
45113 #endif
45114 
45115   static const char timeStr[] = "time";
45116   cdf_put_att_text(fileID, time_varid, "standard_name", sizeof(timeStr) - 1, timeStr);
45117 
45118   if ( taxis->longname && taxis->longname[0] )
45119     cdf_put_att_text(fileID, time_varid, "long_name", strlen(taxis->longname), taxis->longname);
45120 
45121   if ( taxis->has_bounds )
45122     {
45123       int time_bndsid = cdfDefTimeBounds(fileID, time_varid, time_dimid, taxis_name, taxis);
45124       streamptr->basetime.ncvarboundsid = time_bndsid;
45125     }
45126 
45127   char unitstr[CDI_MAX_NAME];
45128   cdfDefTimeUnits(unitstr, taxis);
45129   size_t len = strlen(unitstr);
45130   if (len) cdf_put_att_text(fileID, time_varid, "units", len, unitstr);
45131 
45132   if ( taxis->calendar != -1 )
45133     {
45134       cdfDefCalendar(fileID, time_varid, taxis->calendar);
45135     }
45136 
45137   if ( taxis->type == TAXIS_FORECAST )
45138     {
45139       int leadtimeid;
45140       cdf_def_var(fileID, "leadtime", xtype, 1, &time_dimid, &leadtimeid);
45141       streamptr->basetime.leadtimeid = leadtimeid;
45142 
45143       static const char stdname[] = "forecast_period";
45144       cdf_put_att_text(fileID, leadtimeid, "standard_name", sizeof(stdname) - 1, stdname);
45145 
45146       static const char lname[] = "Time elapsed since the start of the forecast";
45147       cdf_put_att_text(fileID, leadtimeid, "long_name", sizeof(lname) - 1, lname);
45148 
45149       cdfDefForecastTimeUnits(unitstr, taxis->fc_unit);
45150       len = strlen(unitstr);
45151       if ( len ) cdf_put_att_text(fileID, leadtimeid, "units", len, unitstr);
45152     }
45153 
45154   cdf_put_att_text(fileID, time_varid, "axis", 1, "T");
45155 
45156   if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
45157 }
45158 
45159 #endif
45160 /*
45161  * Local Variables:
45162  * c-file-style: "Java"
45163  * c-basic-offset: 2
45164  * indent-tabs-mode: nil
45165  * show-trailing-whitespace: t
45166  * require-trailing-newline: t
45167  * End:
45168  */
45169 #ifndef CDI_DATETIME_H
45170 #define CDI_DATETIME_H
45171 
45172 typedef struct
45173 {
45174   long date;
45175   long time;
45176 }
45177 DateTime;
45178 
45179 static inline int
datetimeDiffer(DateTime dt1,DateTime dt2)45180 datetimeDiffer(DateTime dt1, DateTime dt2)
45181 {
45182   return (2 * ((dt1.date > dt2.date) - (dt1.date < dt2.date))
45183           + (dt1.time > dt2.time) - (dt1.time < dt2.time)) != 0;
45184 }
45185 
45186 
45187 #endif
45188 /*
45189  * Local Variables:
45190  * c-file-style: "Java"
45191  * c-basic-offset: 2
45192  * indent-tabs-mode: nil
45193  * show-trailing-whitespace: t
45194  * require-trailing-newline: t
45195  * End:
45196  */
45197 #if HAVE_CONFIG_H
45198 #endif
45199 
45200 #include <limits.h>
45201 #include <stdio.h>
45202 
45203 
45204 #ifdef HAVE_LIBCGRIBEX
45205 
45206 
45207 
45208 typedef struct {
45209   int       sec0[2];
45210   int       sec1[1024];
45211   size_t    sec2len;
45212   int      *sec2;
45213   int       sec3[2];
45214   int       sec4[512];
45215   double   fsec2[512];
45216   double   fsec3[2];
45217 }
45218 cgribexrec_t;
45219 
45220 
45221 typedef struct {
45222   int param;
45223   int level1;
45224   int level2;
45225   int ltype;
45226   int tsteptype;
45227 } compvar_t;
45228 
45229 
45230 typedef struct
45231 {
45232   void *gribbuffer;
45233   size_t gribbuffersize;
45234   unsigned char *pds;
45235   unsigned char *gds;
45236   unsigned char *bms;
45237   unsigned char *bds;
45238 } cgribex_handle;
45239 
45240 
45241 
45242 static
cgribexInit(cgribexrec_t * cgribexp)45243 void cgribexInit(cgribexrec_t *cgribexp)
45244 {
45245   cgribexp->sec2len = 4096;
45246   cgribexp->sec2 = (int *) Malloc(cgribexp->sec2len*sizeof(int));
45247 }
45248 
45249 
cgribexNew()45250 void *cgribexNew()
45251 {
45252   cgribexrec_t *cgribexp = (cgribexrec_t *) Malloc(sizeof(cgribexrec_t));
45253   cgribexInit(cgribexp);
45254   return (void*)cgribexp;
45255 }
45256 
45257 
cgribexDelete(void * cgribex)45258 void cgribexDelete(void *cgribex)
45259 {
45260   cgribexrec_t *cgribexp = (cgribexrec_t *) cgribex;
45261   if (cgribexp)
45262     {
45263       if (cgribexp->sec2) Free(cgribexp->sec2);
45264       Free(cgribexp);
45265     }
45266 }
45267 
45268 
45269 int grib1Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **pdsp,
45270 		  unsigned char **gdsp, unsigned char **bmsp, unsigned char **bdsp, long *gribrecsize);
45271 
45272 static
cgribexSection2Length(void * gribbuffer,size_t gribbuffersize)45273 size_t cgribexSection2Length(void *gribbuffer, size_t gribbuffersize)
45274 {
45275   long sec2len = 0;
45276 
45277   if ( gribbuffersize && gribbuffer )
45278     {
45279       unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
45280       long gribrecsize;
45281       int status = grib1Sections((unsigned char *)gribbuffer, (long)gribbuffersize, &pds, &gds, &bms, &bds, &gribrecsize);
45282       if (status >= 0 && gds != NULL) sec2len = (unsigned) ((gds[0] << 16) + (gds[1] << 8)  + (gds[3]));
45283     }
45284 
45285   return sec2len;
45286 }
45287 
45288 
cgribex_handle_new_from_meassage(void * gribbuffer,size_t gribbuffersize)45289 void *cgribex_handle_new_from_meassage(void *gribbuffer, size_t gribbuffersize)
45290 {
45291   cgribex_handle *gh = (cgribex_handle*) Malloc(sizeof(cgribex_handle));
45292   gh->gribbuffer = NULL;
45293   gh->gribbuffersize = 0;
45294   gh->pds = NULL;
45295 
45296   if (gribbuffersize && gribbuffer)
45297     {
45298       unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
45299       long gribrecsize;
45300       int status = grib1Sections((unsigned char *)gribbuffer, (long)gribbuffersize, &pds, &gds, &bms, &bds, &gribrecsize);
45301       if (status >= 0)
45302         {
45303           gh->gribbuffer = gribbuffer;
45304           gh->gribbuffersize = gribbuffersize;
45305           gh->pds = pds;
45306           gh->gds = gds;
45307           gh->bms = bms;
45308           gh->bds = bds;
45309         }
45310     }
45311 
45312   return (void*)gh;
45313 }
45314 
45315 
cgribex_handle_delete(void * gh)45316 void cgribex_handle_delete(void *gh)
45317 {
45318   if (gh) Free(gh);
45319 }
45320 
45321 static
cgribexGetGridType(int * isec2)45322 int cgribexGetGridType(int *isec2)
45323 {
45324   int gridtype = GRID_GENERIC;
45325 
45326   // clang-format off
45327   switch (ISEC2_GridType)
45328     {
45329     case  GRIB1_GTYPE_LATLON:     { gridtype = GRID_LONLAT;     break; }
45330     case  GRIB1_GTYPE_LATLON_ROT: { gridtype = GRID_PROJECTION; break; }
45331     case  GRIB1_GTYPE_LCC:        { gridtype = CDI_PROJ_LCC;    break; }
45332     case  GRIB1_GTYPE_GAUSSIAN:   { gridtype = ISEC2_Reduced ? GRID_GAUSSIAN_REDUCED : GRID_GAUSSIAN; break; }
45333     case  GRIB1_GTYPE_SPECTRAL:   { gridtype = GRID_SPECTRAL;   break; }
45334     case  GRIB1_GTYPE_GME:        { gridtype = GRID_GME;        break; }
45335     }
45336   // clang-format on
45337 
45338   return gridtype;
45339 }
45340 
45341 static
cgribexGetIsRotated(int * isec2)45342 bool cgribexGetIsRotated(int *isec2)
45343 {
45344   return (ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT);
45345 }
45346 
45347 static
cgribexGetZaxisHasBounds(int grb_ltype)45348 bool cgribexGetZaxisHasBounds(int grb_ltype)
45349 {
45350   // clang-format off
45351   switch (grb_ltype)
45352     {
45353     case GRIB1_LTYPE_SIGMA_LAYER:
45354     case GRIB1_LTYPE_HYBRID_LAYER:
45355     case GRIB1_LTYPE_LANDDEPTH_LAYER: return true;
45356     }
45357   // clang-format on
45358 
45359   return false;
45360 }
45361 
45362 static
cgribexGetTimeUnit(int * isec1)45363 int cgribexGetTimeUnit(int *isec1)
45364 {
45365   int timeunit = TUNIT_HOUR;
45366   static bool lprint = true;
45367 
45368   // clang-format off
45369   switch ( ISEC1_TimeUnit )
45370     {
45371     case ISEC1_TABLE4_MINUTE:    timeunit = TUNIT_MINUTE;    break;
45372     case ISEC1_TABLE4_QUARTER:   timeunit = TUNIT_QUARTER;   break;
45373     case ISEC1_TABLE4_30MINUTES: timeunit = TUNIT_30MINUTES; break;
45374     case ISEC1_TABLE4_HOUR:      timeunit = TUNIT_HOUR;      break;
45375     case ISEC1_TABLE4_3HOURS:    timeunit = TUNIT_3HOURS;    break;
45376     case ISEC1_TABLE4_6HOURS:    timeunit = TUNIT_6HOURS;    break;
45377     case ISEC1_TABLE4_12HOURS:   timeunit = TUNIT_12HOURS;   break;
45378     case ISEC1_TABLE4_DAY:       timeunit = TUNIT_DAY;       break;
45379     default:
45380       if ( lprint )
45381 	{
45382 	  Message("GRIB time unit %d unsupported!", ISEC1_TimeUnit);
45383 	  lprint = false;
45384 	}
45385       break;
45386     }
45387   // clang-format on
45388 
45389   return timeunit;
45390 }
45391 
45392 static
cgribexTimeIsFC(int * isec1)45393 bool cgribexTimeIsFC(int *isec1)
45394 {
45395   bool isFC = (ISEC1_TimeRange == 10 && ISEC1_TimePeriod1 == 0 && ISEC1_TimePeriod2 == 0) ? false : true;
45396   return isFC;
45397 }
45398 
45399 static
cgribexGetTsteptype(int timerange)45400 int cgribexGetTsteptype(int timerange)
45401 {
45402   static bool lprint = true;
45403 
45404   // clang-format off
45405   int tsteptype = TSTEP_INSTANT;
45406   switch ( timerange )
45407     {
45408     case  0:  tsteptype = TSTEP_INSTANT;  break;
45409     case  1:  tsteptype = TSTEP_INSTANT2; break;
45410     case  2:  tsteptype = TSTEP_RANGE;    break;
45411     case  3:  tsteptype = TSTEP_AVG;      break;
45412     case  4:  tsteptype = TSTEP_ACCUM;    break;
45413     case  5:  tsteptype = TSTEP_DIFF;     break;
45414     case 10:  tsteptype = TSTEP_INSTANT3; break;
45415     default:
45416       if ( lprint )
45417 	{
45418 	  Message("Time range indicator %d unsupported, set to 0!", timerange);
45419 	  lprint = false;
45420 	}
45421       break;
45422     }
45423   // clang-format on
45424 
45425   return tsteptype;
45426 }
45427 
45428 static
cgribexGetGrid(stream_t * streamptr,int * isec2,int * isec4,grid_t * grid,int iret)45429 bool cgribexGetGrid(stream_t *streamptr, int *isec2, int *isec4, grid_t *grid, int iret)
45430 {
45431   bool uvRelativeToGrid = false;
45432   bool compyinc = true;
45433   int gridtype = cgribexGetGridType(isec2);
45434   int projtype = (gridtype == GRID_PROJECTION && cgribexGetIsRotated(isec2)) ? CDI_PROJ_RLL : CDI_UNDEFID;
45435   if ( gridtype == CDI_PROJ_LCC )
45436     {
45437       projtype = gridtype;
45438       gridtype = GRID_PROJECTION;
45439     }
45440 
45441   if ( streamptr->unreduced && gridtype == GRID_GAUSSIAN_REDUCED && iret != -801 )
45442     {
45443       int nlon = 0;
45444       for ( int ilat = 0; ilat < ISEC2_NumLat; ++ilat )
45445         if ( ISEC2_ReducedPoints(ilat) > nlon ) nlon = ISEC2_ReducedPoints(ilat);
45446       gridtype = GRID_GAUSSIAN;
45447       ISEC2_NumLon = nlon;
45448       ISEC4_NumValues = nlon*ISEC2_NumLat;
45449       compyinc = false;
45450     }
45451 
45452   grid_init(grid);
45453   cdiGridTypeInit(grid, gridtype, 0);
45454 
45455   if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || projtype == CDI_PROJ_RLL )
45456     {
45457       const bool ijDirectionIncrementGiven = gribbyte_get_bit(ISEC2_ResFlag, 1);
45458       uvRelativeToGrid = gribbyte_get_bit(ISEC2_ResFlag, 5);
45459 
45460       const size_t nvalues = (size_t) ISEC4_NumValues;
45461       const size_t nlon = (size_t) ISEC2_NumLon;
45462       const size_t nlat = (size_t) ISEC2_NumLat;
45463       if ( nvalues != nlon*nlat )
45464         Error("numberOfPoints (%zu) and gridSize (%zu) differ!", nvalues, nlon*nlat);
45465 
45466       grid->size   = nvalues;
45467       grid->x.size = nlon;
45468       grid->y.size = nlat;
45469 
45470       if ( gridtype == GRID_GAUSSIAN ) grid->np = ISEC2_NumPar;
45471       grid->x.inc  = 0;
45472       grid->y.inc  = 0;
45473       grid->x.flag = 0;
45474       /* if ( ISEC2_FirstLon != 0 || ISEC2_LastLon != 0 ) */
45475       {
45476         if ( grid->x.size > 1 )
45477           {
45478             bool recompinc = true;
45479 
45480             if ( ISEC2_LastLon < ISEC2_FirstLon )
45481               {
45482                 if ( ISEC2_FirstLon >= 180000 )
45483                   ISEC2_FirstLon -= 360000;
45484                 else
45485                   ISEC2_LastLon += 360000;
45486               }
45487 
45488             if ( ijDirectionIncrementGiven && ISEC2_LonIncr > 0 )
45489               {
45490                 if ( labs(ISEC2_LastLon - (ISEC2_FirstLon+ISEC2_LonIncr*((long)grid->x.size-1))) <= 2 )
45491                   {
45492                     recompinc = false;
45493                     grid->x.inc = ISEC2_LonIncr * 0.001;
45494                   }
45495               }
45496 
45497             /* recompute xinc if necessary */
45498             if ( recompinc ) grid->x.inc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->x.size-1);
45499 
45500             /* correct xinc if necessary */
45501             if ( ISEC2_FirstLon == 0 && ISEC2_LastLon > 354000 && ISEC2_LastLon < 360000 )
45502               {
45503                 double xinc = 360. / grid->x.size;
45504                 if ( fabs(grid->x.inc-xinc) > 0.0 )
45505                   {
45506                     grid->x.inc = xinc;
45507                     if ( CDI_Debug ) Message("set xinc to %g", grid->x.inc);
45508                   }
45509               }
45510           }
45511         grid->x.first = ISEC2_FirstLon * 0.001;
45512         grid->x.last  = ISEC2_LastLon  * 0.001;
45513         grid->x.flag  = 2;
45514       }
45515       grid->y.flag = 0;
45516       /* if ( ISEC2_FirstLat != 0 || ISEC2_LastLat != 0 ) */
45517       {
45518         if ( grid->y.size > 1 && compyinc )
45519           {
45520             bool recompinc = true;
45521             if ( ijDirectionIncrementGiven && ISEC2_LatIncr > 0 )
45522               {
45523                 if ( labs(ISEC2_LastLat - (ISEC2_FirstLat+ISEC2_LatIncr*((long)grid->y.size-1))) <= 2 )
45524                   {
45525                     recompinc = false;
45526                     grid->y.inc = ISEC2_LatIncr * 0.001;
45527                   }
45528               }
45529 
45530             /* recompute yinc if necessary */
45531             if ( recompinc ) grid->y.inc = (ISEC2_LastLat - ISEC2_FirstLat) * 0.001 / (grid->y.size - 1);
45532           }
45533         grid->y.first = ISEC2_FirstLat * 0.001;
45534         grid->y.last  = ISEC2_LastLat  * 0.001;
45535         grid->y.flag  = 2;
45536       }
45537     }
45538   else if ( gridtype == GRID_GAUSSIAN_REDUCED )
45539     {
45540       const bool ijDirectionIncrementGiven = gribbyte_get_bit(ISEC2_ResFlag, 1);
45541       uvRelativeToGrid = gribbyte_get_bit(ISEC2_ResFlag, 5);
45542       grid->np      = ISEC2_NumPar;
45543       grid->size    = (size_t)ISEC4_NumValues;
45544       grid->reducedPoints  = ISEC2_ReducedPointsPtr;
45545       grid->reducedPointsSize = (size_t)ISEC2_NumLat;
45546       grid->y.size  = (size_t)ISEC2_NumLat;
45547       grid->x.inc   = 0;
45548       grid->y.inc   = 0;
45549       grid->x.flag  = 0;
45550       /* if ( ISEC2_FirstLon != 0 || ISEC2_LastLon != 0 ) */
45551       {
45552         if ( grid->x.size > 1 )
45553           {
45554             if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
45555 
45556             if ( ijDirectionIncrementGiven && ISEC2_LonIncr > 0 )
45557               grid->x.inc = ISEC2_LonIncr * 0.001;
45558             else
45559               grid->x.inc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->x.size - 1);
45560           }
45561         grid->x.first = ISEC2_FirstLon * 0.001;
45562         grid->x.last  = ISEC2_LastLon  * 0.001;
45563         grid->x.flag  = 2;
45564       }
45565       grid->y.flag = 0;
45566       /* if ( ISEC2_FirstLat != 0 || ISEC2_LastLat != 0 ) */
45567       {
45568         if ( grid->y.size > 1 )
45569           {
45570             if ( ijDirectionIncrementGiven && ISEC2_LatIncr > 0 )
45571               grid->y.inc = ISEC2_LatIncr * 0.001;
45572             else
45573               grid->y.inc = (ISEC2_LastLat - ISEC2_FirstLat) * 0.001 / (grid->y.size - 1);
45574           }
45575         grid->y.first = ISEC2_FirstLat * 0.001;
45576         grid->y.last  = ISEC2_LastLat  * 0.001;
45577         grid->y.flag  = 2;
45578       }
45579     }
45580   else if ( projtype == CDI_PROJ_LCC )
45581     {
45582       uvRelativeToGrid = gribbyte_get_bit(ISEC2_ResFlag, 5);
45583 
45584       const size_t nvalues = (size_t) ISEC4_NumValues;
45585       const size_t nlon = (size_t) ISEC2_NumLon;
45586       const size_t nlat = (size_t) ISEC2_NumLat;
45587       if ( nvalues != nlon*nlat )
45588         Error("numberOfPoints (%zu) and gridSize (%zu) differ!", nvalues, nlon*nlat);
45589 
45590       grid->size   = nvalues;
45591       grid->x.size = nlon;
45592       grid->y.size = nlat;
45593 
45594       grid->x.first = 0;
45595       grid->x.last  = 0;
45596       grid->x.inc   = ISEC2_Lambert_dx;
45597       grid->y.first = 0;
45598       grid->y.last  = 0;
45599       grid->y.inc   = ISEC2_Lambert_dy;
45600       grid->x.flag  = 2;
45601       grid->y.flag  = 2;
45602     }
45603   else if ( gridtype == GRID_SPECTRAL )
45604     {
45605       grid->size  = (size_t) ISEC4_NumValues;
45606       grid->trunc = ISEC2_PentaJ;
45607       grid->lcomplex = (ISEC2_RepMode == 2) ? 1 : 0;
45608    }
45609   else if ( gridtype == GRID_GME )
45610     {
45611       grid->size  = (size_t) ISEC4_NumValues;
45612       grid->gme.nd  = ISEC2_GME_ND;
45613       grid->gme.ni  = ISEC2_GME_NI;
45614       grid->gme.ni2 = ISEC2_GME_NI2;
45615       grid->gme.ni3 = ISEC2_GME_NI3;
45616     }
45617   else if ( gridtype == GRID_GENERIC )
45618     {
45619       grid->size  = (size_t) ISEC4_NumValues;
45620       grid->x.size = 0;
45621       grid->y.size = 0;
45622     }
45623   else
45624     {
45625       Error("Unsupported grid type: %s", gridNamePtr(gridtype));
45626     }
45627 
45628   grid->type = gridtype;
45629   grid->projtype = projtype;
45630 
45631   return uvRelativeToGrid;
45632 }
45633 
45634 static
cgribexGetLevel(int * isec1,int * leveltype,int * level1,int * level2)45635 void cgribexGetLevel(int *isec1, int *leveltype, int *level1, int *level2)
45636 {
45637   *leveltype = ISEC1_LevelType;
45638   *level1 = ISEC1_Level1;
45639   *level2 = ISEC1_Level2;
45640   if ( *leveltype == GRIB1_LTYPE_ISOBARIC ) *level1 *= 100;
45641   else if ( *leveltype == GRIB1_LTYPE_99 || *leveltype == GRIB1_LTYPE_ISOBARIC_PA ) *leveltype = GRIB1_LTYPE_ISOBARIC;
45642 }
45643 
45644 static
cgribexAddRecord(stream_t * streamptr,cgribexrec_t * cgribexp,int param,size_t recsize,off_t position,int comptype,int lmv,int iret)45645 void cgribexAddRecord(stream_t *streamptr, cgribexrec_t *cgribexp, int param, size_t recsize,
45646                       off_t position, int comptype, int lmv, int iret)
45647 {
45648   int *isec1 = cgribexp->sec1;
45649   int *isec2 = cgribexp->sec2;
45650   int *isec4 = cgribexp->sec4;
45651   double *fsec2 = cgribexp->fsec2;
45652   double *fsec3 = cgribexp->fsec3;
45653 
45654   int datatype = (ISEC4_NumBits > 0 && ISEC4_NumBits <= 32) ? ISEC4_NumBits : CDI_DATATYPE_PACK;
45655   if ( datatype > 32 ) datatype = CDI_DATATYPE_PACK32;
45656   if ( datatype <  0 ) datatype = CDI_DATATYPE_PACK;
45657 
45658   const int vlistID = streamptr->vlistID;
45659   const int tsID    = streamptr->curTsID;
45660   const int recID   = recordNewEntry(streamptr, tsID);
45661   record_t *record = &streamptr->tsteps[tsID].records[recID];
45662 
45663   const int tsteptype = cgribexGetTsteptype(ISEC1_TimeRange);
45664 
45665   int leveltype, level1, level2;
45666   cgribexGetLevel(isec1, &leveltype, &level1, &level2);
45667 
45668   /* fprintf(stderr, "param %d %d %d %d\n", param, level1, level2, leveltype); */
45669 
45670   record->size      = recsize;
45671   record->position  = position;
45672   record->param     = param;
45673   record->ilevel    = level1;
45674   record->ilevel2   = level2;
45675   record->ltype     = leveltype;
45676   record->tsteptype = (short)tsteptype;
45677 
45678   grid_t *gridptr = (grid_t*) Malloc(sizeof(*gridptr));
45679   const bool uvRelativeToGrid = cgribexGetGrid(streamptr, isec2, isec4, gridptr, iret);
45680 
45681   struct addIfNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, gridptr, 0);
45682   int gridID = gridAdded.Id;
45683   if ( gridAdded.isNew )
45684     {
45685       if ( gridptr->reducedPointsSize )
45686         {
45687           const size_t reducedPointsSize = (size_t) gridptr->reducedPointsSize;
45688           int *reducedPoints = gridptr->reducedPoints;
45689           gridptr->reducedPoints = (int*) Malloc(reducedPointsSize * sizeof(int));
45690           memcpy(gridptr->reducedPoints, reducedPoints, reducedPointsSize * sizeof(int));
45691         }
45692       else if ( gridptr->projtype == CDI_PROJ_RLL )
45693         {
45694           const double xpole =   ISEC2_LonSP*0.001 - 180;
45695           const double ypole = - ISEC2_LatSP*0.001;
45696           const double angle = - FSEC2_RotAngle;
45697           gridDefParamRLL(gridID, xpole, ypole, angle);
45698         }
45699       else if ( gridptr->projtype == CDI_PROJ_LCC )
45700         {
45701           const bool earthIsOblate = gribbyte_get_bit(ISEC2_ResFlag, 2);
45702           const double a = earthIsOblate ? 6378160. : 6367470.;
45703           const double rf = earthIsOblate ? 297.0 : 0;
45704           const double xval_0 = ISEC2_FirstLon * 0.001;
45705           const double yval_0 = ISEC2_FirstLat * 0.001;
45706           const double lon_0  = ISEC2_Lambert_Lov * 0.001;
45707           double lat_1  = ISEC2_Lambert_LatS1 * 0.001;
45708           double lat_2  = ISEC2_Lambert_LatS2 * 0.001;
45709           const bool lsouth = gribbyte_get_bit(ISEC2_Lambert_ProjFlag, 1);
45710           if ( lsouth ) { lat_1 = -lat_1; lat_2 = -lat_2; }
45711 
45712           const double lat_0 = lat_2;
45713           double x_0 = CDI_Grid_Missval;
45714           double y_0 = CDI_Grid_Missval;
45715 
45716           if ( proj_lonlat_to_lcc_func )
45717             {
45718               x_0 = xval_0; y_0 = yval_0;
45719               proj_lonlat_to_lcc_func(CDI_Grid_Missval, lon_0, lat_0, lat_1, lat_2, a, rf, (size_t)1, &x_0, &y_0);
45720               if ( IS_NOT_EQUAL(x_0, CDI_Grid_Missval) && IS_NOT_EQUAL(y_0, CDI_Grid_Missval) )
45721                 { x_0 = -x_0; y_0 = -y_0; }
45722             }
45723           gridDefParamLCC(gridID, CDI_Grid_Missval, lon_0, lat_0, lat_1, lat_2, a, rf, xval_0, yval_0, x_0, y_0);
45724         }
45725     }
45726   else
45727     Free(gridptr);
45728 
45729   const int zaxistype = grib1ltypeToZaxisType(leveltype);
45730   if ( zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF )
45731     {
45732       const size_t vctsize = (size_t)ISEC2_NumVCP;
45733       double *vctptr = &fsec2[10];
45734       varDefVCT(vctsize, vctptr);
45735     }
45736 
45737   const bool lbounds = cgribexGetZaxisHasBounds(leveltype);
45738 
45739   int varID = 0, levelID = 0;
45740   varAddRecord(recID, param, gridID, zaxistype, lbounds, level1, level2, 0, 0,
45741 	       datatype, &varID, &levelID, tsteptype, leveltype, -1,
45742                NULL, NULL, NULL, NULL);
45743 
45744   record->varID = (short)varID;
45745   record->levelID = (short)levelID;
45746 
45747   varDefCompType(varID, comptype);
45748 
45749   if ( uvRelativeToGrid ) varDefKeyInt(varID, CDI_KEY_UVRELATIVETOGRID, 1);
45750 
45751   if ( ISEC1_LocalFLag )
45752     {
45753       if      ( ISEC1_CenterID == 78  && isec1[36] == 253 ) // DWD local extension
45754         {
45755           varDefKeyInt(varID, CDI_KEY_TYPEOFENSEMBLEFORECAST, isec1[52]);
45756           varDefKeyInt(varID, CDI_KEY_NUMBEROFFORECASTSINENSEMBLE, isec1[53]);
45757           varDefKeyInt(varID, CDI_KEY_PERTURBATIONNUMBER, isec1[54]);
45758         }
45759       else if ( ISEC1_CenterID == 252 && isec1[36] ==   1 ) // MPIM local extension
45760         {
45761           varDefKeyInt(varID, CDI_KEY_TYPEOFENSEMBLEFORECAST, isec1[37]);
45762           varDefKeyInt(varID, CDI_KEY_NUMBEROFFORECASTSINENSEMBLE, isec1[39]);
45763           varDefKeyInt(varID, CDI_KEY_PERTURBATIONNUMBER, isec1[38]);
45764         }
45765     }
45766 
45767   if ( lmv ) varDefMissval(varID, FSEC3_MissVal);
45768 
45769   if ( varInqInst(varID) == CDI_UNDEFID )
45770     {
45771       const int center = ISEC1_CenterID;
45772       const int subcenter = ISEC1_SubCenterID;
45773       int instID = institutInq(center, subcenter, NULL, NULL);
45774       if ( instID == CDI_UNDEFID )
45775 	instID = institutDef(center, subcenter, NULL, NULL);
45776       varDefInst(varID, instID);
45777     }
45778 
45779   if ( varInqModel(varID) == CDI_UNDEFID )
45780     {
45781       int modelID = modelInq(varInqInst(varID), ISEC1_ModelID, NULL);
45782       if ( modelID == CDI_UNDEFID )
45783 	modelID = modelDef(varInqInst(varID), ISEC1_ModelID, NULL);
45784       varDefModel(varID, modelID);
45785     }
45786 
45787   if ( varInqTable(varID) == CDI_UNDEFID )
45788     {
45789       int tableID = tableInq(varInqModel(varID), ISEC1_CodeTable, NULL);
45790       if ( tableID == CDI_UNDEFID )
45791 	tableID = tableDef(varInqModel(varID), ISEC1_CodeTable, NULL);
45792       varDefTable(varID, tableID);
45793     }
45794 
45795   streamptr->tsteps[tsID].nallrecs++;
45796   streamptr->nrecs++;
45797 }
45798 
45799 static
MCH_get_undef(int * isec1,double * undef_pds,double * undef_eps)45800 void MCH_get_undef(int *isec1, double *undef_pds, double *undef_eps)
45801 {
45802   /* 2010-01-13: Oliver Fuhrer */
45803   if ( ISEC1_CenterID == 215 )
45804     {
45805       if (isec1[34] != 0 && isec1[34] != 255)
45806         {
45807           if (isec1[34] & 2)
45808             {
45809               *undef_pds = ((isec1[34] & 1) ? -0.99 : +0.99) * pow(10.0,-isec1[35]);
45810               *undef_eps = pow(10.0,-isec1[35]-1);
45811             }
45812           else
45813             {
45814               *undef_pds = ((isec1[34] & 1) ? -0.99 : +0.99) * pow(10.0,+isec1[35]);
45815               *undef_eps = pow(10.0,isec1[35]-1);
45816             }
45817         }
45818     }
45819 }
45820 
45821 static
cgribexDecodeHeader(cgribexrec_t * cgribexp,int * gribbuffer,int recsize,int * lmv,int * iret)45822 void cgribexDecodeHeader(cgribexrec_t *cgribexp, int *gribbuffer, int recsize, int *lmv, int *iret)
45823 {
45824   int *isec0 = cgribexp->sec0;
45825   int *isec1 = cgribexp->sec1;
45826   int *isec2 = cgribexp->sec2;
45827   int *isec3 = cgribexp->sec3;
45828   int *isec4 = cgribexp->sec4;
45829   double *fsec2 = cgribexp->fsec2;
45830   double *fsec3 = cgribexp->fsec3;
45831 
45832   int ipunp = 0, iword = 0;
45833 
45834   memset(isec1, 0, 256*sizeof(int));
45835   memset(isec2, 0, 32*sizeof(int));
45836 
45837   double *fsec4 = NULL;
45838   gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, fsec4,
45839 	   ipunp, (int *) gribbuffer, recsize, &iword, "J", iret);
45840 
45841   if ( !(ISEC1_Sec2Or3Flag & 128) ) isec2[0] = -1; // default generic grid
45842 
45843   *lmv = 0;
45844 
45845   if ( ISEC1_CenterID == 215 && (isec1[34] != 0 && isec1[34] != 255) )
45846     {
45847       double undef_pds, undef_eps;
45848       MCH_get_undef(isec1, &undef_pds, &undef_eps);
45849       FSEC3_MissVal = undef_pds;
45850       *lmv = 1;
45851     }
45852 }
45853 
45854 static
cgribexVarSet(int param,int level1,int level2,int leveltype,int trange)45855 compvar_t cgribexVarSet(int param, int level1, int level2, int leveltype, int trange)
45856 {
45857   int tsteptype = cgribexGetTsteptype(trange);
45858 
45859   compvar_t compVar;
45860   compVar.param     = param;
45861   compVar.level1    = level1;
45862   compVar.level2    = level2;
45863   compVar.ltype     = leveltype;
45864   compVar.tsteptype = tsteptype;
45865 
45866   return compVar;
45867 }
45868 
45869 static inline
cgribexVarCompare(compvar_t compVar,record_t record,int flag)45870 int cgribexVarCompare(compvar_t compVar, record_t record, int flag)
45871 {
45872   bool vinst = compVar.tsteptype == TSTEP_INSTANT || compVar.tsteptype == TSTEP_INSTANT2 || compVar.tsteptype == TSTEP_INSTANT3;
45873   bool rinst = record.tsteptype == TSTEP_INSTANT || record.tsteptype == TSTEP_INSTANT2 || record.tsteptype == TSTEP_INSTANT3;
45874   int tstepDiff = (!((flag == 0) & (vinst && rinst)))
45875                 & (compVar.tsteptype != record.tsteptype);
45876   int rstatus = (compVar.param != record.param)
45877     |           (compVar.level1 != record.ilevel)
45878     |           (compVar.level2 != record.ilevel2)
45879     |           (compVar.ltype != record.ltype)
45880     |           tstepDiff;
45881   return rstatus;
45882 }
45883 
45884 #define gribWarning(text, nrecs, timestep, paramstr, level1, level2) \
45885             Warning("Record %2d (id=%s lev1=%d lev2=%d) timestep %d: %s", nrecs, paramstr, level1, level2, timestep, text)
45886 
45887 
45888 static
cgribexSkipRecords(const int fileID)45889 void cgribexSkipRecords(const int fileID)
45890 {
45891   int nskip = CDI_Skip_Records;
45892   while (nskip-- > 0)
45893     {
45894       const size_t recsize = gribGetSize(fileID);
45895       if (recsize == 0) Error("Skipping of %d records failed!", CDI_Skip_Records);
45896 
45897       const off_t recpos = fileGetPos(fileID);
45898       fileSetPos(fileID, recpos, SEEK_CUR);
45899     }
45900 }
45901 
cgribexScanTimestep1(stream_t * streamptr)45902 int cgribexScanTimestep1(stream_t *streamptr)
45903 {
45904   int lmv = 0, iret = 0;
45905   off_t recpos = 0;
45906   void *gribbuffer = NULL;
45907   size_t buffersize = 0;
45908   int leveltype = 0, level1 = 0, level2 = 0;
45909   DateTime datetime0 = { .date = 10101, .time = 0 };
45910   unsigned recID;
45911   int nrecs_scanned = 0;
45912   bool warn_time = true;
45913   bool warn_numavg = true;
45914   bool fcast = false;
45915   char paramstr[32];
45916 
45917   streamptr->curTsID = 0;
45918 
45919   cgribexrec_t *cgribexp = (cgribexrec_t *) streamptr->record->cgribexp;
45920 
45921   const int tsID = tstepsNewEntry(streamptr);
45922   if (tsID != 0) Error("Internal problem! tstepsNewEntry returns %d", tsID);
45923 
45924   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
45925 
45926   const int fileID = streamptr->fileID;
45927 
45928   if (CDI_Skip_Records) cgribexSkipRecords(fileID);
45929 
45930   unsigned nrecs = 0;
45931   while (true)
45932     {
45933       const size_t recsize = gribGetSize(fileID);
45934       recpos = fileGetPos(fileID);
45935 
45936       if ( recsize == 0 )
45937 	{
45938 	  if ( nrecs == 0 ) Error("No GRIB records found!");
45939 	  streamptr->ntsteps = 1;
45940 	  break;
45941 	}
45942 
45943       ensureBufferSize(recsize, &buffersize, &gribbuffer);
45944 
45945       size_t readsize = recsize;
45946       // Search for next 'GRIB', read the following record, and position file offset after it.
45947       if (gribRead(fileID, gribbuffer, &readsize)) break;
45948 
45949       const int comptype = grbDecompress(recsize, &buffersize, &gribbuffer);
45950 
45951       const size_t sec2len = cgribexSection2Length(gribbuffer, buffersize);
45952       if (sec2len > cgribexp->sec2len)
45953         {
45954           cgribexp->sec2len = sec2len;
45955           cgribexp->sec2 = (int *) Realloc(cgribexp->sec2, sec2len*sizeof(int));
45956         }
45957 
45958       int *isec1 = cgribexp->sec1;
45959 
45960       nrecs_scanned++;
45961       cgribexDecodeHeader(cgribexp, (int *) gribbuffer, (int)recsize, &lmv, &iret);
45962 
45963       const int param = cdiEncodeParam(ISEC1_Parameter, ISEC1_CodeTable, 255);
45964       cdiParamToString(param, paramstr, sizeof(paramstr));
45965 
45966       cgribexGetLevel(isec1, &leveltype, &level1, &level2);
45967 
45968       int vdate, sdate;
45969       int vtime, stime;
45970       gribDateTimeX(isec1, &vdate, &vtime, &sdate, &stime);
45971       DateTime datetime = { .date = vdate, .time = vtime };
45972 
45973       if ( nrecs == 0 )
45974 	{
45975           datetime0 = datetime;
45976 	  fcast = cgribexTimeIsFC(isec1);
45977 	  taxis->unit = cgribexGetTimeUnit(isec1);
45978 	  taxis->rdate = gribRefDate(isec1);
45979 	  taxis->rtime = gribRefTime(isec1);
45980           taxis->sdate = sdate;
45981           taxis->stime = stime;
45982           taxis->vdate = vdate;
45983           taxis->vtime = vtime;
45984 	}
45985       else
45986 	{
45987 	  compvar_t compVar = cgribexVarSet(param, level1, level2, leveltype, ISEC1_TimeRange);
45988           record_t *records = streamptr->tsteps[tsID].records;
45989 	  for ( recID = 0; recID < nrecs; recID++ )
45990 	    {
45991 	      if ( cgribexVarCompare(compVar, records[recID], 0) == 0 ) break;
45992 	    }
45993 
45994 	  if ( CDI_Inventory_Mode == 1 )
45995 	    {
45996 	      if ( recID < nrecs ) break;
45997 	      if ( warn_time )
45998 		if ( datetimeDiffer(datetime, datetime0) )
45999 		  {
46000                     gribWarning("Inconsistent verification time!", nrecs_scanned, tsID+1, paramstr, level1, level2);
46001 		    warn_time = false;
46002 		  }
46003 	    }
46004 	  else
46005 	    {
46006 	      if ( datetimeDiffer(datetime, datetime0) ) break;
46007 
46008 	      if ( recID < nrecs )
46009 		{
46010 		  gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, paramstr, level1, level2);
46011 		  continue;
46012 		}
46013 	    }
46014 	}
46015 
46016       if ( ISEC1_AvgNum )
46017 	{
46018 	  if (  taxis->numavg && warn_numavg && (taxis->numavg != ISEC1_AvgNum) )
46019 	    {
46020 	      Warning("Changing numavg from %d to %d not supported!", taxis->numavg, ISEC1_AvgNum);
46021 	      warn_numavg = false;
46022 	    }
46023 	  else
46024 	    {
46025 	      taxis->numavg = ISEC1_AvgNum;
46026 	    }
46027 	}
46028 
46029       nrecs++;
46030 
46031       if ( CDI_Debug )
46032 	Message("Read record %2d (id=%s lev1=%d lev2=%d) %8d %6d", nrecs_scanned, paramstr, level1, level2, vdate, vtime);
46033 
46034       cgribexAddRecord(streamptr, cgribexp, param, recsize, recpos, comptype, lmv, iret);
46035     }
46036 
46037   streamptr->rtsteps = 1;
46038 
46039   if ( nrecs == 0 ) return CDI_EUFSTRUCT;
46040 
46041   cdi_generate_vars(streamptr);
46042 
46043   taxis->type = fcast ? TAXIS_RELATIVE : TAXIS_ABSOLUTE;
46044   const int taxisID = taxisCreate(taxis->type);
46045 
46046   const int vlistID = streamptr->vlistID;
46047   vlistDefTaxis(vlistID, taxisID);
46048 
46049   streamScanResizeRecords1(streamptr);
46050 
46051   streamptr->record->buffer     = gribbuffer;
46052   streamptr->record->buffersize = buffersize;
46053 
46054   streamScanTsFixNtsteps(streamptr, recpos);
46055   streamScanTimeConstAdjust(streamptr, taxis);
46056 
46057   return 0;
46058 }
46059 
46060 
cgribexScanTimestep2(stream_t * streamptr)46061 int cgribexScanTimestep2(stream_t * streamptr)
46062 {
46063   int lmv = 0, iret = 0;
46064   off_t recpos = 0;
46065   int leveltype = 0, level1 = 0, level2 = 0;
46066   DateTime datetime0 = { LONG_MIN, LONG_MIN };
46067   int recID = 0;
46068   bool warn_numavg = true;
46069   char paramstr[32];
46070 
46071   streamptr->curTsID = 1;
46072 
46073   cgribexrec_t *cgribexp = (cgribexrec_t *) streamptr->record->cgribexp;
46074   int *isec1 = cgribexp->sec1;
46075   int *isec2 = cgribexp->sec2;
46076 
46077   const int fileID  = streamptr->fileID;
46078   const int vlistID = streamptr->vlistID;
46079 
46080   void *gribbuffer = streamptr->record->buffer;
46081   size_t buffersize = streamptr->record->buffersize;
46082 
46083   int tsID = streamptr->rtsteps;
46084   if ( tsID != 1 ) Error("Internal problem! unexpected timestep %d", tsID+1);
46085 
46086   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
46087 
46088   fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
46089 
46090   cdi_create_records(streamptr, tsID);
46091   record_t *records = streamptr->tsteps[tsID].records;
46092 
46093   const int nrecords = streamScanInitRecords2(streamptr);
46094 
46095   int nrecs_scanned = nrecords;
46096   int rindex = 0;
46097   while (true)
46098     {
46099       if ( rindex > nrecords ) break;
46100 
46101       const size_t recsize = gribGetSize(fileID);
46102       recpos = fileGetPos(fileID);
46103       if ( recsize == 0 )
46104 	{
46105 	  streamptr->ntsteps = 2;
46106 	  break;
46107 	}
46108 
46109       ensureBufferSize(recsize, &buffersize, &gribbuffer);
46110 
46111       size_t readsize = recsize;
46112       if (gribRead(fileID, gribbuffer, &readsize)) break;
46113 
46114       grbDecompress(recsize, &buffersize, &gribbuffer);
46115 
46116       nrecs_scanned++;
46117       cgribexDecodeHeader(cgribexp, (int *) gribbuffer, (int)recsize, &lmv, &iret);
46118 
46119       const int param = cdiEncodeParam(ISEC1_Parameter, ISEC1_CodeTable, 255);
46120       cdiParamToString(param, paramstr, sizeof(paramstr));
46121 
46122       cgribexGetLevel(isec1, &leveltype, &level1, &level2);
46123 
46124       int vdate, sdate;
46125       int vtime, stime;
46126       gribDateTimeX(isec1, &vdate, &vtime, &sdate, &stime);
46127       DateTime datetime = { .date = vdate, .time = vtime };
46128 
46129       if ( rindex == 0 )
46130 	{
46131           datetime0 = datetime;
46132           const int taxisID = vlistInqTaxis(vlistID);
46133 	  if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
46134 	    {
46135 	      taxis->type  = TAXIS_RELATIVE;
46136 	      taxis->rdate = gribRefDate(isec1);
46137 	      taxis->rtime = gribRefTime(isec1);
46138 	    }
46139 	  else
46140 	    {
46141 	      taxis->type  = TAXIS_ABSOLUTE;
46142 	    }
46143 	  taxis->unit  = cgribexGetTimeUnit(isec1);
46144 	  taxis->vdate = vdate;
46145 	  taxis->vtime = vtime;
46146           taxis->sdate = sdate;
46147           taxis->stime = stime;
46148 	}
46149 
46150       const int tsteptype = cgribexGetTsteptype(ISEC1_TimeRange);
46151 
46152       if ( ISEC1_AvgNum )
46153 	{
46154 	  if ( taxis->numavg && warn_numavg && (taxis->numavg != ISEC1_AvgNum) )
46155             warn_numavg = false;
46156 	  else
46157             taxis->numavg = ISEC1_AvgNum;
46158 	}
46159 
46160       compvar_t compVar = cgribexVarSet(param, level1, level2, leveltype, ISEC1_TimeRange);
46161 
46162       for ( recID = 0; recID < nrecords; recID++ )
46163 	{
46164 	  if ( cgribexVarCompare(compVar, records[recID], 0) == 0 ) break;
46165 	}
46166 
46167       if ( recID == nrecords )
46168 	{
46169 	  gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, paramstr, level1, level2);
46170 	  return CDI_EUFSTRUCT;
46171 	}
46172 
46173       if ( CDI_Inventory_Mode == 1 )
46174 	{
46175 	  if ( records[recID].used )
46176 	    {
46177 	      break;
46178 	    }
46179 	  else
46180 	    {
46181 	      records[recID].used = true;
46182 	      streamptr->tsteps[tsID].recIDs[rindex] = recID;
46183 	    }
46184 	}
46185       else
46186 	{
46187 	  if ( records[recID].used )
46188 	    {
46189 	      if ( datetimeDiffer(datetime, datetime0) ) break;
46190 
46191               gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, paramstr, level1, level2);
46192 	      continue;
46193 	    }
46194 	  else
46195 	    {
46196 	      records[recID].used = true;
46197 	      streamptr->tsteps[tsID].recIDs[rindex] = recID;
46198 	    }
46199 	}
46200 
46201       if ( CDI_Debug )
46202 	Message("Read record %2d (id=%s lev1=%d lev2=%d) %8d %6d", nrecs_scanned, paramstr, level1, level2, vdate, vtime);
46203 
46204       if ( cgribexVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) != 0 )
46205 	{
46206 	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
46207                   tsID, recID, records[recID].param, param, records[recID].ilevel, level1);
46208 	  return CDI_EUFSTRUCT;
46209 	}
46210 
46211       records[recID].position = recpos;
46212       records[recID].size = recsize;
46213 
46214       const int varID = records[recID].varID;
46215       const int gridID = vlistInqVarGrid(vlistID, varID);
46216       if ( gridInqSize(gridID) == 1 && gridInqType(gridID) == GRID_LONLAT )
46217 	{
46218 	  if ( IS_NOT_EQUAL(gridInqXval(gridID, 0), ISEC2_FirstLon*0.001) ||
46219 	       IS_NOT_EQUAL(gridInqYval(gridID, 0), ISEC2_FirstLat*0.001) )
46220 	    gridChangeType(gridID, GRID_TRAJECTORY);
46221 	}
46222 
46223       if ( tsteptype != TSTEP_INSTANT2 && tsteptype != vlistInqVarTsteptype(vlistID, varID) )
46224 	vlistDefVarTsteptype(vlistID, varID, tsteptype);
46225 
46226       rindex++;
46227     }
46228 
46229   int nrecs = 0;
46230   for ( recID = 0; recID < nrecords; recID++ )
46231     {
46232       if ( ! records[recID].used )
46233 	{
46234           vlistDefVarTimetype(vlistID, records[recID].varID, TIME_CONSTANT);
46235 	}
46236       else
46237 	{
46238 	  nrecs++;
46239 	}
46240     }
46241   streamptr->tsteps[tsID].nrecs = nrecs;
46242 
46243   streamptr->rtsteps = 2;
46244 
46245   streamScanTsFixNtsteps(streamptr, recpos);
46246 
46247   streamptr->record->buffer     = gribbuffer;
46248   streamptr->record->buffersize = buffersize;
46249 
46250   return 0;
46251 }
46252 
46253 
cgribexScanTimestep(stream_t * streamptr)46254 int cgribexScanTimestep(stream_t * streamptr)
46255 {
46256   int lmv = 0, iret = 0;
46257   off_t recpos = 0;
46258   int leveltype = 0, level1 = 0, level2 = 0;
46259   DateTime datetime0 = { LONG_MIN, LONG_MIN };
46260   int vrecID, recID = 0;
46261   bool warn_numavg = true;
46262   int nrecs = 0;
46263   char paramstr[32];
46264 
46265   cgribexrec_t *cgribexp = (cgribexrec_t *) streamptr->record->cgribexp;
46266   int *isec1 = cgribexp->sec1;
46267 
46268   int tsID  = streamptr->rtsteps;
46269   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
46270 
46271   if ( streamptr->tsteps[tsID].recordSize == 0 )
46272     {
46273       void *gribbuffer = streamptr->record->buffer;
46274       size_t buffersize = streamptr->record->buffersize;
46275 
46276       cdi_create_records(streamptr, tsID);
46277       record_t *records = streamptr->tsteps[tsID].records;
46278 
46279       nrecs = streamScanInitRecords(streamptr, tsID);
46280 
46281       const int fileID = streamptr->fileID;
46282 
46283       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
46284 
46285       int nrecs_scanned = streamptr->tsteps[0].nallrecs + streamptr->tsteps[1].nrecs*(tsID-1);
46286       int rindex = 0;
46287       while ( true )
46288 	{
46289 	  if ( rindex > nrecs ) break;
46290 
46291 	  const size_t recsize = gribGetSize(fileID);
46292 	  recpos = fileGetPos(fileID);
46293 	  if ( recsize == 0 )
46294 	    {
46295 	      streamptr->ntsteps = streamptr->rtsteps + 1;
46296 	      break;
46297 	    }
46298 
46299           if ( rindex >= nrecs ) break;
46300 
46301           ensureBufferSize(recsize, &buffersize, &gribbuffer);
46302 
46303 	  size_t readsize = recsize;
46304 	  if (gribRead(fileID, gribbuffer, &readsize))
46305 	    {
46306 	      Warning("Inconsistent timestep %d (GRIB record %d/%d)!", tsID+1, rindex+1,
46307                       streamptr->tsteps[tsID].recordSize);
46308 	      break;
46309 	    }
46310 
46311           grbDecompress(recsize, &buffersize, &gribbuffer);
46312 
46313           nrecs_scanned++;
46314 	  cgribexDecodeHeader(cgribexp, (int *) gribbuffer, (int)recsize, &lmv, &iret);
46315 
46316 	  const int param = cdiEncodeParam(ISEC1_Parameter, ISEC1_CodeTable, 255);
46317           cdiParamToString(param, paramstr, sizeof(paramstr));
46318 
46319           cgribexGetLevel(isec1, &leveltype, &level1, &level2);
46320 
46321           int vdate, sdate;
46322           int vtime, stime;
46323 	  gribDateTimeX(isec1, &vdate, &vtime, &sdate, &stime);
46324           DateTime datetime = { .date = vdate, .time = vtime };
46325 
46326 	  if ( rindex == nrecs ) break;
46327 
46328 	  if ( rindex == 0 )
46329 	    {
46330               datetime0 = datetime;
46331               const int vlistID = streamptr->vlistID;
46332 	      const int taxisID = vlistInqTaxis(vlistID);
46333 	      if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
46334 		{
46335 		  taxis->type  = TAXIS_RELATIVE;
46336 		  taxis->rdate = gribRefDate(isec1);
46337 		  taxis->rtime = gribRefTime(isec1);
46338 		}
46339 	      else
46340 		{
46341 		  taxis->type  = TAXIS_ABSOLUTE;
46342 		}
46343 	      taxis->unit  = cgribexGetTimeUnit(isec1);
46344 	      taxis->vdate = vdate;
46345 	      taxis->vtime = vtime;
46346               taxis->sdate = sdate;
46347               taxis->stime = stime;
46348 	    }
46349 
46350 	  if ( ISEC1_AvgNum )
46351 	    {
46352 	      if (  taxis->numavg && warn_numavg && (taxis->numavg != ISEC1_AvgNum) )
46353                 warn_numavg = false;
46354 	      else
46355                 taxis->numavg = ISEC1_AvgNum;
46356 	    }
46357 
46358 	  datetime.date = vdate;
46359 	  datetime.time = vtime;
46360 
46361 	  compvar_t compVar = cgribexVarSet(param, level1, level2, leveltype, ISEC1_TimeRange);
46362 
46363 	  for ( vrecID = 0; vrecID < nrecs; vrecID++ )
46364 	    {
46365 	      recID = streamptr->tsteps[1].recIDs[vrecID];
46366 	      if ( cgribexVarCompare(compVar, records[recID], 0) == 0 ) break;
46367 	    }
46368 
46369 	  if ( vrecID == nrecs )
46370 	    {
46371 	      gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, paramstr, level1, level2);
46372 
46373 	      if ( CDI_Inventory_Mode == 1 )
46374 		return CDI_EUFSTRUCT;
46375 	      else
46376 		continue;
46377 	    }
46378 
46379 	  if ( CDI_Inventory_Mode == 1 )
46380 	    {
46381 	      records[recID].used = true;
46382 	      streamptr->tsteps[tsID].recIDs[rindex] = recID;
46383 	    }
46384 	  else
46385 	    {
46386 	      if ( records[recID].used )
46387 		{
46388 		  char paramstr_[32];
46389 		  cdiParamToString(param, paramstr_, sizeof(paramstr_));
46390 
46391 		  if ( datetimeDiffer(datetime, datetime0) ) break;
46392 
46393 		  if ( CDI_Debug )
46394                     gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, paramstr_, level1, level2);
46395 
46396 		  continue;
46397 		}
46398 	      else
46399 		{
46400 		  records[recID].used = true;
46401 		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
46402 		}
46403 	    }
46404 
46405 	  if ( CDI_Debug )
46406             Message("Read record %2d (id=%s lev1=%d lev2=%d) %8d %6d", nrecs_scanned, paramstr, level1, level2, vdate, vtime);
46407 
46408 	  if ( cgribexVarCompare(compVar, records[recID], 0) != 0 )
46409 	    {
46410 	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
46411                       tsID, recID, records[recID].param, param, records[recID].ilevel, level1);
46412 	      Error("Invalid, unsupported or inconsistent record structure");
46413 	    }
46414 
46415 	  records[recID].position = recpos;
46416 	  records[recID].size = recsize;
46417 
46418 	  rindex++;
46419 	}
46420 
46421       for ( vrecID = 0; vrecID < nrecs; vrecID++ )
46422 	{
46423 	  recID = streamptr->tsteps[tsID].recIDs[vrecID];
46424 	  if ( ! records[recID].used ) break;
46425 	}
46426 
46427       if ( vrecID < nrecs )
46428 	{
46429 	  cdiParamToString(records[recID].param, paramstr, sizeof(paramstr));
46430 	  gribWarning("Paramameter not found!", nrecs_scanned, tsID+1, paramstr,
46431                       records[recID].ilevel, records[recID].ilevel2);
46432 	  return CDI_EUFSTRUCT;
46433 	}
46434 
46435       streamptr->rtsteps++;
46436 
46437       if ( streamptr->ntsteps != streamptr->rtsteps )
46438 	{
46439 	  tsID = tstepsNewEntry(streamptr);
46440 	  if ( tsID != streamptr->rtsteps )
46441 	    Error("Internal error. tsID = %d", tsID);
46442 
46443 	  streamptr->tsteps[tsID-1].next   = true;
46444 	  streamptr->tsteps[tsID].position = recpos;
46445 	}
46446 
46447       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
46448       streamptr->tsteps[tsID].position = recpos;
46449 
46450       streamptr->record->buffer     = gribbuffer;
46451       streamptr->record->buffersize = buffersize;
46452     }
46453 
46454   if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
46455     {
46456       Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
46457       streamptr->ntsteps = tsID;
46458     }
46459 
46460   return streamptr->ntsteps;
46461 }
46462 
46463 #ifdef gribWarning
46464 #undef gribWarning
46465 #endif
46466 
cgribexDecode(int memtype,void * cgribex,void * gribbuffer,size_t gribsize,void * data,size_t datasize,int unreduced,size_t * nmiss,double missval)46467 int cgribexDecode(int memtype, void *cgribex, void *gribbuffer, size_t gribsize, void *data, size_t datasize,
46468 		  int unreduced, size_t *nmiss, double missval)
46469 {
46470   int status = 0;
46471 
46472   bool lalloc = cgribex == NULL;
46473   cgribexrec_t *cgribexp = (cgribexrec_t *) (lalloc ? cgribexNew() : cgribex);
46474 
46475   int *isec0 = cgribexp->sec0;
46476   int *isec1 = cgribexp->sec1;
46477   int *isec2 = cgribexp->sec2;
46478   int *isec3 = cgribexp->sec3;
46479   int *isec4 = cgribexp->sec4;
46480   double *fsec2 = cgribexp->fsec2;
46481   double *fsec3 = cgribexp->fsec3;
46482   float fsec2f[sizeof(cgribexp->fsec2)/sizeof(double)];
46483   float fsec3f[sizeof(cgribexp->fsec3)/sizeof(double)];
46484 
46485   char hoper[2];
46486   strcpy(hoper, unreduced ? "R" : "D");
46487 
46488   FSEC3_MissVal = missval;
46489 
46490   int iret = 0, iword = 0;
46491   if ( memtype == MEMTYPE_FLOAT )
46492     gribExSP(isec0, isec1, isec2, fsec2f, isec3, fsec3f, isec4, (float*) data,
46493              (int) datasize, (int*) gribbuffer, (int)gribsize, &iword, hoper, &iret);
46494   else
46495     gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, (double*) data,
46496              (int) datasize, (int*) gribbuffer, (int)gribsize, &iword, hoper, &iret);
46497 
46498   *nmiss = (ISEC1_Sec2Or3Flag & 64) ? ISEC4_NumValues - ISEC4_NumNonMissValues : 0;
46499 
46500   if ( ISEC1_CenterID == 215 && (isec1[34] != 0 && isec1[34] != 255) )
46501     {
46502       double undef_pds, undef_eps;
46503       MCH_get_undef(isec1, &undef_pds, &undef_eps);
46504 
46505       *nmiss = 0;
46506       if ( memtype == MEMTYPE_FLOAT )
46507         {
46508           float *restrict dataf = (float*) data;
46509           for ( size_t i = 0; i < datasize; i++ )
46510             if ( (fabs(dataf[i]-undef_pds) < undef_eps) || IS_EQUAL(dataf[i], FSEC3_MissVal) )
46511               {
46512                 dataf[i] = (float)missval;
46513                 (*nmiss)++;
46514               }
46515         }
46516       else
46517         {
46518           double *restrict datad = (double*) data;
46519           for ( size_t i = 0; i < datasize; i++ )
46520             if ( (fabs(datad[i]-undef_pds) < undef_eps) || IS_EQUAL(datad[i], FSEC3_MissVal) )
46521               {
46522                 datad[i] = missval;
46523                 (*nmiss)++;
46524               }
46525         }
46526     }
46527 
46528   if (lalloc) cgribexDelete(cgribexp);
46529 
46530   return status;
46531 }
46532 
46533 
46534 static
cgribexDefInstitut(int * isec1,int vlistID,int varID)46535 void cgribexDefInstitut(int *isec1, int vlistID, int varID)
46536 {
46537   int instID = (vlistInqInstitut(vlistID) != CDI_UNDEFID) ? vlistInqInstitut(vlistID) : vlistInqVarInstitut(vlistID, varID);
46538   if ( instID != CDI_UNDEFID )
46539     {
46540       ISEC1_CenterID    = institutInqCenter(instID);
46541       ISEC1_SubCenterID = institutInqSubcenter(instID);
46542     }
46543 }
46544 
46545 static
cgribexDefModel(int * isec1,int vlistID,int varID)46546 void cgribexDefModel(int *isec1, int vlistID, int varID)
46547 {
46548   int modelID = (vlistInqModel(vlistID) != CDI_UNDEFID) ? vlistInqModel(vlistID) : vlistInqVarModel(vlistID, varID);
46549   if ( modelID != CDI_UNDEFID )
46550     ISEC1_ModelID = modelInqGribID(modelID);
46551 }
46552 
46553 static
cgribexDefParam(int * isec1,int param)46554 void cgribexDefParam(int *isec1, int param)
46555 {
46556   int pdis, pcat, pnum;
46557   cdiDecodeParam(param, &pnum, &pcat, &pdis);
46558   if ( pnum < 0 ) pnum = -pnum;
46559 
46560   static bool lwarn_pdis = true;
46561   if ( pdis != 255 && lwarn_pdis )
46562     {
46563       char paramstr[32];
46564       cdiParamToString(param, paramstr, sizeof(paramstr));
46565       Warning("Can't convert GRIB2 parameter ID (%s) to GRIB1, set to %d.%d!", paramstr, pnum, pcat);
46566       lwarn_pdis = false;
46567     }
46568 
46569   static bool lwarn_pnum = true;
46570   if ( pnum > 255 && lwarn_pnum )
46571     {
46572       Warning("Parameter number %d out of range (1-255), set to %d!", pnum, pnum%256);
46573       lwarn_pnum = false;
46574       pnum = pnum%256;
46575     }
46576 
46577   ISEC1_CodeTable = pcat;
46578   ISEC1_Parameter = pnum;
46579 }
46580 
46581 static
cgribexDefTimerange(int tsteptype,int factor,int calendar,int rdate,int rtime,int vdate,int vtime,int sdate,int stime,int * pip1,int * pip2)46582 int cgribexDefTimerange(int tsteptype, int factor, int calendar, int rdate, int rtime,
46583 			int vdate, int vtime, int sdate, int stime, int *pip1, int *pip2)
46584 {
46585   int year, month, day, hour, minute, second;
46586   int64_t julday1, julday2, days;
46587   int secofday1, secofday2, secs;
46588 
46589   cdiDecodeDate(rdate, &year, &month, &day);
46590   cdiDecodeTime(rtime, &hour, &minute, &second);
46591   encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday1, &secofday1);
46592 
46593   cdiDecodeDate(vdate, &year, &month, &day);
46594   cdiDecodeTime(vtime, &hour, &minute, &second);
46595   encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday2, &secofday2);
46596 
46597   (void) julday_sub(julday1, secofday1, julday2, secofday2, &days, &secs);
46598 
46599   int timerange = -1;
46600   int ip1 = 0, ip2 = 0;
46601   if ( !(int)(fmod(days*86400.0 + secs, factor)) )
46602     {
46603       const int ip = (int) ((days*86400.0 + secs)/factor);
46604       if ( (ip > 255) && (tsteptype == TSTEP_INSTANT) ) tsteptype = TSTEP_INSTANT3;
46605 
46606       int ipx = 0;
46607       if (sdate != 0 && (tsteptype == TSTEP_RANGE || tsteptype == TSTEP_AVG || tsteptype == TSTEP_ACCUM || tsteptype == TSTEP_DIFF))
46608         {
46609           cdiDecodeDate(sdate, &year, &month, &day);
46610           cdiDecodeTime(stime, &hour, &minute, &second);
46611           encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday2, &secofday2);
46612 
46613           (void) julday_sub(julday1, secofday1, julday2, secofday2, &days, &secs);
46614 
46615           ipx = (int) ((days*86400.0 + secs)/factor);
46616         }
46617 
46618       // clang-format off
46619       switch ( tsteptype )
46620 	{
46621 	case TSTEP_INSTANT:  timerange =  0; ip1 = ip;  ip2 = 0;  break;
46622 	case TSTEP_INSTANT2: timerange =  1; ip1 = 0;   ip2 = 0;  break;
46623 	case TSTEP_RANGE:    timerange =  2; ip1 = 0;   ip2 = ip; break;
46624 	case TSTEP_AVG:      timerange =  3; ip1 = 0;   ip2 = ip; break;
46625 	case TSTEP_ACCUM:    timerange =  4; ip1 = ipx; ip2 = ip; break;
46626 	case TSTEP_DIFF:     timerange =  5; ip1 = 0;   ip2 = ip; break;
46627 	case TSTEP_INSTANT3:
46628 	default:             timerange = 10; ip1 = ip/256; ip2 = ip%256; break;
46629 	}
46630       // clang-format on
46631     }
46632 
46633   *pip1 = ip1;
46634   *pip2 = ip2;
46635 
46636   return timerange;
46637 }
46638 
46639 static
cgribexDefDateTime(int * isec1,int timeunit,int date,int time)46640 int cgribexDefDateTime(int *isec1, int timeunit, int date, int time)
46641 {
46642   int year, month, day, hour, minute, second;
46643   cdiDecodeDate(date, &year, &month, &day);
46644   cdiDecodeTime(time, &hour, &minute, &second);
46645 
46646   int century =  year / 100;
46647 
46648   ISEC1_Year = year - century*100;
46649 
46650   if ( year < 0 )
46651     {
46652       century = -century;
46653       ISEC1_Year = -ISEC1_Year;
46654     }
46655 
46656   if ( ISEC1_Year == 0 )
46657     {
46658       century -= 1;
46659       ISEC1_Year = 100;
46660     }
46661 
46662   century += 1;
46663   if ( year < 0 ) century = -century;
46664 
46665   ISEC1_Month  = month;
46666   ISEC1_Day    = day;
46667   ISEC1_Hour   = hour;
46668   ISEC1_Minute = minute;
46669 
46670   ISEC1_Century = century;
46671 
46672   int factor = 1;
46673   // clang-format off
46674   switch (timeunit)
46675     {
46676     case TUNIT_MINUTE:    factor =    60; ISEC1_TimeUnit = ISEC1_TABLE4_MINUTE;    break;
46677     case TUNIT_QUARTER:   factor =   900; ISEC1_TimeUnit = ISEC1_TABLE4_QUARTER;   break;
46678     case TUNIT_30MINUTES: factor =  1800; ISEC1_TimeUnit = ISEC1_TABLE4_30MINUTES; break;
46679     case TUNIT_HOUR:      factor =  3600; ISEC1_TimeUnit = ISEC1_TABLE4_HOUR;      break;
46680     case TUNIT_3HOURS:    factor = 10800; ISEC1_TimeUnit = ISEC1_TABLE4_3HOURS;    break;
46681     case TUNIT_6HOURS:    factor = 21600; ISEC1_TimeUnit = ISEC1_TABLE4_6HOURS;    break;
46682     case TUNIT_12HOURS:   factor = 43200; ISEC1_TimeUnit = ISEC1_TABLE4_12HOURS;   break;
46683     case TUNIT_DAY:       factor = 86400; ISEC1_TimeUnit = ISEC1_TABLE4_DAY;       break;
46684     default:              factor =  3600; ISEC1_TimeUnit = ISEC1_TABLE4_HOUR;      break;
46685     }
46686   // clang-format on
46687 
46688   return factor;
46689 }
46690 
46691 static
cgribexDefTime(int * isec1,int vdate,int vtime,int tsteptype,int numavg,int taxisID)46692 void cgribexDefTime(int *isec1, int vdate, int vtime, int tsteptype, int numavg, int taxisID)
46693 {
46694   int timetype = TAXIS_ABSOLUTE;
46695   int timeunit = TUNIT_HOUR;
46696 
46697   if ( taxisID != -1 )
46698     {
46699       timetype = taxisInqType(taxisID);
46700       timeunit = taxisInqTunit(taxisID);
46701     }
46702 
46703   if ( timetype == TAXIS_RELATIVE )
46704     {
46705       const int calendar = taxisInqCalendar(taxisID);
46706 
46707       int rdate = taxisInqRdate(taxisID);
46708       int rtime = taxisInqRtime(taxisID);
46709       if (vdate < rdate || (vdate == rdate && vtime < rtime))
46710         {
46711           rdate = vdate;
46712           rtime = vtime;
46713         }
46714 
46715       int sdate = taxisInqSdate(taxisID);
46716       int stime = taxisInqStime(taxisID);
46717 
46718       int factor = cgribexDefDateTime(isec1, timeunit, rdate, rtime);
46719       int ip1 = 0, ip2 = 0;
46720       int timerange = cgribexDefTimerange(tsteptype, factor, calendar, rdate, rtime, vdate, vtime, sdate, stime, &ip1, &ip2);
46721 
46722       if ( ip2 > 0xFF && timeunit < TUNIT_YEAR )
46723         {
46724           timeunit++;
46725           factor = cgribexDefDateTime(isec1, timeunit, rdate, rtime);
46726           timerange = cgribexDefTimerange(tsteptype, factor, calendar, rdate, rtime, vdate, vtime, sdate, stime, &ip1, &ip2);
46727         }
46728 
46729       if ( timerange == -1 || timerange == 1 || timerange == 3 ) timetype = TAXIS_ABSOLUTE;
46730       /*
46731       else if ( timerange == 10 )
46732 	{
46733 	  if ( ip1 < 0 || ip1 > 0xFFFF ) timetype = TAXIS_ABSOLUTE;
46734 	  if ( ip2 < 0 || ip2 > 0xFFFF ) timetype = TAXIS_ABSOLUTE;
46735 	}
46736       */
46737       else
46738 	{
46739 	  if ( ip1 < 0 || ip1 > 0xFF   ) timetype = TAXIS_ABSOLUTE;
46740 	  if ( ip2 < 0 || ip2 > 0xFF   ) timetype = TAXIS_ABSOLUTE;
46741 	}
46742       /*
46743       static bool lwarn = true;
46744       if ( lwarn && timetype == TAXIS_ABSOLUTE )
46745         {
46746           lwarn = false;
46747           Warning("Can't store forecast time %ld %d relative to %ld %d, converted to absolute time!", (long)vdate, vtime, (long)rdate, rtime);
46748         }
46749       */
46750       ISEC1_TimeRange   = timerange;
46751       ISEC1_TimePeriod1 = ip1;
46752       ISEC1_TimePeriod2 = ip2;
46753     }
46754 
46755   if ( timetype == TAXIS_ABSOLUTE )
46756     {
46757       (void) cgribexDefDateTime(isec1, timeunit, vdate, vtime);
46758 
46759       /*
46760       if ( numavg > 0 )
46761 	ISEC1_TimeRange = 0;
46762       else
46763       */
46764       if ( ISEC1_TimeRange != 3 ) ISEC1_TimeRange = 10;
46765 
46766       ISEC1_TimePeriod1 = 0;
46767       ISEC1_TimePeriod2 = 0;
46768     }
46769 
46770   ISEC1_AvgNum         = numavg;
46771   ISEC1_AvgMiss        = 0;
46772   ISEC1_DecScaleFactor = 0;
46773 }
46774 
46775 static
cgribexDefGridRegular(int * isec2,double * fsec2,int gridID,int gridtype,bool gridIsRotated,bool gridIsCurvilinear,int uvRelativeToGrid)46776 void cgribexDefGridRegular(int *isec2, double *fsec2, int gridID, int gridtype, bool gridIsRotated, bool gridIsCurvilinear, int uvRelativeToGrid)
46777 {
46778   if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
46779     ISEC2_GridType = GRIB1_GTYPE_GAUSSIAN;
46780   else if ( gridtype == GRID_LONLAT && gridIsRotated )
46781     ISEC2_GridType = GRIB1_GTYPE_LATLON_ROT;
46782   else
46783     ISEC2_GridType = GRIB1_GTYPE_LATLON;
46784 
46785   double xfirst = 0, xlast = 0, xinc = 0;
46786   double yfirst = 0, ylast = 0, yinc = 0;
46787 
46788   int nlon = (int)gridInqXsize(gridID);
46789   int nlat = (int)gridInqYsize(gridID);
46790 
46791   if ( gridtype == GRID_GAUSSIAN_REDUCED )
46792     {
46793       ISEC2_Reduced = true;
46794       nlon = 0;
46795       gridInqReducedPoints(gridID, ISEC2_ReducedPointsPtr);
46796     }
46797   else
46798     {
46799       if ( nlon == 0 ) nlon = 1;
46800       else
46801         {
46802           xfirst = gridInqXval(gridID, 0);
46803           xlast  = gridInqXval(gridID, (gridIsCurvilinear ? nlon*nlat : nlon) - 1);
46804           xinc   = fabs(gridInqXinc(gridID));
46805         }
46806     }
46807 
46808   if ( nlat == 0 ) nlat = 1;
46809   else
46810     {
46811       yfirst = gridInqYval(gridID, 0);
46812       ylast  = gridInqYval(gridID, (gridIsCurvilinear ? nlon*nlat : nlat) - 1);
46813       yinc   = fabs(gridInqYinc(gridID));
46814     }
46815 
46816   ISEC2_NumLon   = nlon;
46817   ISEC2_NumLat   = nlat;
46818   ISEC2_FirstLat = (int)lround(yfirst*1000);
46819   ISEC2_LastLat  = (int)lround(ylast*1000);
46820   if ( gridtype == GRID_GAUSSIAN_REDUCED )
46821     {
46822       ISEC2_FirstLon = 0;
46823       ISEC2_LastLon  = (int)lround(1000*(360.-360./(nlat*2)));
46824       //ISEC2_LonIncr  = (int)lround(1000*360./(nlat*2)); // gribapi gridType detector doesn't like lonIncr
46825     }
46826   else
46827     {
46828       ISEC2_FirstLon = (int)lround(xfirst*1000);
46829       ISEC2_LastLon  = (int)lround(xlast*1000);
46830       ISEC2_LonIncr  = (int)lround(xinc*1000);
46831     }
46832 
46833   if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
46834     {
46835       int np = gridInqNP(gridID);
46836       if ( np == 0 ) np = nlat/2;
46837       ISEC2_NumPar = np;
46838     }
46839   else
46840     {
46841       ISEC2_LatIncr = (int)lround(yinc*1000);
46842     }
46843 
46844   if ( ISEC2_NumLon > 1 && ISEC2_NumLat == 1 )
46845     if ( ISEC2_LonIncr != 0 && ISEC2_LatIncr == 0 ) ISEC2_LatIncr = ISEC2_LonIncr;
46846 
46847   if ( ISEC2_NumLon == 1 && ISEC2_NumLat > 1 )
46848     if ( ISEC2_LonIncr == 0 && ISEC2_LatIncr != 0 ) ISEC2_LonIncr = ISEC2_LatIncr;
46849 
46850   ISEC2_ResFlag = 0;
46851   if ( ISEC2_LatIncr && ISEC2_LonIncr ) gribbyte_set_bit(&ISEC2_ResFlag, 1);
46852   if ( uvRelativeToGrid > 0 ) gribbyte_set_bit(&ISEC2_ResFlag, 5);
46853 
46854   if ( gridIsRotated )
46855     {
46856       double xpole = 0, ypole = 0, angle = 0;
46857       gridInqParamRLL(gridID, &xpole, &ypole, &angle);
46858 
46859       ISEC2_LatSP = - (int)lround(ypole * 1000);
46860       ISEC2_LonSP =   (int)lround((xpole + 180) * 1000);
46861       if ( fabs(angle) > 0 ) angle = -angle;
46862       FSEC2_RotAngle = angle;
46863     }
46864 
46865   ISEC2_ScanFlag = 0;
46866   if ( ISEC2_LastLon < ISEC2_FirstLon ) gribbyte_set_bit(&ISEC2_ScanFlag, 1); // East -> West
46867   if ( ISEC2_LastLat > ISEC2_FirstLat ) gribbyte_set_bit(&ISEC2_ScanFlag, 2); // South -> North
46868 }
46869 
46870 static
cgribexDefGridLambert(int * isec2,int gridID,int uvRelativeToGrid)46871 void cgribexDefGridLambert(int *isec2, int gridID, int uvRelativeToGrid)
46872 {
46873   const int xsize = (int)gridInqXsize(gridID);
46874   const int ysize = (int)gridInqYsize(gridID);
46875 
46876   double lon_0, lat_0, lat_1, lat_2, a, rf, xval_0, yval_0, x_0, y_0;
46877   gridInqParamLCC(gridID, CDI_Grid_Missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0);
46878   gridVerifyGribParamLCC(CDI_Grid_Missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0);
46879   bool lsouth = (lat_1 < 0);
46880   if ( lsouth ) { lat_1 = -lat_2; lat_2 = -lat_2; }
46881 
46882   const double xinc = gridInqXinc(gridID);
46883   const double yinc = gridInqYinc(gridID);
46884 
46885   ISEC2_GridType = GRIB1_GTYPE_LCC;
46886   ISEC2_NumLon   = xsize;
46887   ISEC2_NumLat   = ysize;
46888   ISEC2_FirstLon       = (int)lround(xval_0 * 1000);
46889   ISEC2_FirstLat       = (int)lround(yval_0 * 1000);
46890   ISEC2_Lambert_Lov    = (int)lround(lon_0 * 1000);
46891   ISEC2_Lambert_LatS1  = (int)lround(lat_1 * 1000);
46892   ISEC2_Lambert_LatS2  = (int)lround(lat_2 * 1000);
46893   ISEC2_Lambert_dx     = (int)lround(xinc);
46894   ISEC2_Lambert_dy     = (int)lround(yinc);
46895   ISEC2_Lambert_LatSP  = 0;
46896   ISEC2_Lambert_LonSP  = 0;
46897   ISEC2_Lambert_ProjFlag = 0;
46898   if ( lsouth ) gribbyte_set_bit(&ISEC2_Lambert_ProjFlag, 1);
46899 
46900   const bool earthIsOblate = (IS_EQUAL(a, 6378160.) && IS_EQUAL(rf, 297.));
46901   ISEC2_ResFlag = 0;
46902   if ( ISEC2_Lambert_dx && ISEC2_Lambert_dy ) gribbyte_set_bit(&ISEC2_ResFlag, 1);
46903   if ( earthIsOblate ) gribbyte_set_bit(&ISEC2_ResFlag, 2);
46904   if ( uvRelativeToGrid > 0 ) gribbyte_set_bit(&ISEC2_ResFlag, 5);
46905 
46906   ISEC2_ScanFlag = 0;
46907   gribbyte_set_bit(&ISEC2_ScanFlag, 2); // South -> North
46908 }
46909 
46910 static
cgribexDefGridSpectal(int * isec2,int * isec4,int gridID)46911 void cgribexDefGridSpectal(int *isec2, int *isec4, int gridID)
46912 {
46913   ISEC2_GridType = GRIB1_GTYPE_SPECTRAL;
46914   ISEC2_PentaJ   = gridInqTrunc(gridID);
46915   ISEC2_PentaK   = ISEC2_PentaJ;
46916   ISEC2_PentaM   = ISEC2_PentaJ;
46917   ISEC2_RepType  = 1;
46918   isec4[2]       = 128;
46919   if ( gridInqComplexPacking(gridID) && ISEC2_PentaJ >= 21 )
46920     {
46921       ISEC2_RepMode  = 2;
46922       isec4[3]       = 64;
46923       isec4[16]      = 0;
46924       isec4[17]      = 20;
46925       isec4[18]      = 20;
46926       isec4[19]      = 20;
46927     }
46928   else
46929     {
46930       ISEC2_RepMode  = 1;
46931       isec4[3]       = 0;
46932     }
46933 }
46934 
46935 static
cgribexDefGridGME(int * isec2,int gridID)46936 void cgribexDefGridGME(int *isec2, int gridID)
46937 {
46938   ISEC2_GridType   = GRIB1_GTYPE_GME;
46939   int nd = 0, ni = 0, ni2 = 0, ni3 = 0;
46940   gridInqParamGME(gridID, &nd, &ni, &ni2, &ni3);
46941   ISEC2_GME_ND     = nd;
46942   ISEC2_GME_NI     = ni;
46943   ISEC2_GME_NI2    = ni2;
46944   ISEC2_GME_NI3    = ni3;
46945   ISEC2_GME_AFlag  = 0;
46946   ISEC2_GME_LatPP  = 90000;
46947   ISEC2_GME_LonPP  = 0;
46948   ISEC2_GME_LonMPL = 0;
46949   ISEC2_GME_BFlag  = 0;
46950 }
46951 
46952 static
cgribexDefGrid(int * isec1,int * isec2,double * fsec2,int * isec4,int gridID,int uvRelativeToGrid)46953 void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridID, int uvRelativeToGrid)
46954 {
46955   memset(isec2, 0, 16*sizeof(int));
46956   ISEC1_Sec2Or3Flag = 128;
46957   ISEC1_GridDefinition = 255;
46958   ISEC2_Reduced  = false;
46959   ISEC2_ScanFlag = 0;
46960 
46961   int gridsize = (int) gridInqSize(gridID);
46962   bool gridIsRotated = false;
46963   bool gridIsCurvilinear = false;
46964   int gridtype = grbGetGridtype(&gridID, gridsize, &gridIsRotated, &gridIsCurvilinear);
46965 
46966   switch (gridtype)
46967     {
46968     case GRID_LONLAT:
46969     case GRID_GAUSSIAN:
46970     case GRID_GAUSSIAN_REDUCED:
46971     case GRID_TRAJECTORY:
46972       {
46973         cgribexDefGridRegular(isec2, fsec2, gridID, gridtype, gridIsRotated, gridIsCurvilinear, uvRelativeToGrid);
46974 	break;
46975       }
46976     case CDI_PROJ_LCC:
46977       {
46978         cgribexDefGridLambert(isec2, gridID, uvRelativeToGrid);
46979 	break;
46980       }
46981     case GRID_SPECTRAL:
46982       {
46983         cgribexDefGridSpectal(isec2, isec4, gridID);
46984 	break;
46985       }
46986     case GRID_GME:
46987       {
46988         cgribexDefGridGME(isec2, gridID);
46989 	break;
46990       }
46991     case GRID_GENERIC:
46992       {
46993         ISEC1_Sec2Or3Flag = 0;
46994 	break;
46995       }
46996     default:
46997       {
46998         static bool lwarn = true;
46999         ISEC1_Sec2Or3Flag = 0;
47000         if (lwarn)
47001           Warning("CGRIBEX library doesn't support %s grids, grid information will be lost!", gridNamePtr(gridtype));
47002         lwarn = false;
47003 	break;
47004       }
47005     }
47006 }
47007 
47008 static
isec1DefLevel(int * isec1,int leveltype,int level1,int level2)47009 void isec1DefLevel(int *isec1, int leveltype, int level1, int level2)
47010 {
47011   ISEC1_LevelType = leveltype;
47012   ISEC1_Level1    = level1;
47013   ISEC1_Level2    = level2;
47014 }
47015 
47016 static
cgribexDefLevel(int * isec1,int * isec2,double * fsec2,int zaxisID,int levelID)47017 void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int levelID)
47018 {
47019   char units[CDI_MAX_NAME];
47020 
47021   int zaxistype = zaxisInqType(zaxisID);
47022   int ltype = 0;
47023   cdiInqKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE, &ltype);
47024 
47025   if ( zaxistype == ZAXIS_GENERIC && ltype == 0 )
47026     {
47027       Message("Changed zaxis type from %s to %s", zaxisNamePtr(zaxistype), zaxisNamePtr(ZAXIS_PRESSURE));
47028       zaxistype = ZAXIS_PRESSURE;
47029       zaxisChangeType(zaxisID, zaxistype);
47030       cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, "Pa");
47031     }
47032 
47033   ISEC2_NumVCP = 0;
47034 
47035   int grib_ltype = zaxisTypeToGrib1ltype(zaxistype);
47036 
47037   switch (zaxistype)
47038     {
47039     case ZAXIS_SURFACE:
47040     case ZAXIS_MEANSEA:
47041     case ZAXIS_ALTITUDE:
47042     case ZAXIS_DEPTH_BELOW_SEA:
47043     case ZAXIS_ISENTROPIC:
47044       {
47045         isec1DefLevel(isec1, grib_ltype, (int)(zaxisInqLevel(zaxisID, levelID)), 0);
47046 	break;
47047       }
47048     case ZAXIS_CLOUD_BASE:
47049     case ZAXIS_CLOUD_TOP:
47050     case ZAXIS_ISOTHERM_ZERO:
47051     case ZAXIS_TROPOPAUSE:
47052     case ZAXIS_TOA:
47053     case ZAXIS_SEA_BOTTOM:
47054     case ZAXIS_ATMOSPHERE:
47055       {
47056         isec1DefLevel(isec1, grib_ltype, 0, 0);
47057 	break;
47058       }
47059     case ZAXIS_HYBRID:
47060     case ZAXIS_HYBRID_HALF:
47061       {
47062 	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
47063           isec1DefLevel(isec1, GRIB1_LTYPE_HYBRID_LAYER, (int)(zaxisInqLbound(zaxisID, levelID)),
47064                         (int)(zaxisInqUbound(zaxisID, levelID)));
47065 	else
47066           isec1DefLevel(isec1, GRIB1_LTYPE_HYBRID, (int)(zaxisInqLevel(zaxisID, levelID)), 0);
47067 
47068 	int vctsize = zaxisInqVctSize(zaxisID);
47069 	if ( vctsize > 255 )
47070 	  {
47071             static bool lwarning_vct = true;
47072 	    ISEC2_NumVCP = 0;
47073 	    if ( lwarning_vct )
47074 	      {
47075 		Warning("VCT size of %d is too large (maximum is 255). Set to 0!", vctsize);
47076 		lwarning_vct = false;
47077 	      }
47078 	  }
47079 	else
47080 	  {
47081 	    ISEC2_NumVCP = vctsize;
47082 	    zaxisInqVct(zaxisID, &fsec2[10]);
47083 	  }
47084 	break;
47085       }
47086     case ZAXIS_PRESSURE:
47087       {
47088 	double level = zaxisInqLevel(zaxisID, levelID);
47089 	if ( level < 0 ) Warning("Pressure level of %f Pa is below zero!", level);
47090 
47091         int length = CDI_MAX_NAME;
47092         cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, units, &length);
47093 	if ( units[0] && (units[0] != 'P') | (units[1] != 'a') ) level *= 100;
47094 
47095 	double dum;
47096 	if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
47097           grib_ltype = GRIB1_LTYPE_ISOBARIC_PA;
47098 	else
47099           level = level/100;
47100 
47101         isec1DefLevel(isec1, grib_ltype, (int) level, 0);
47102 	break;
47103       }
47104     case ZAXIS_HEIGHT:
47105       {
47106 	double level = zaxisInqLevel(zaxisID, levelID);
47107 
47108         int length = CDI_MAX_NAME;
47109         cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, units, &length);
47110         if ( units[1] == 'm' && !units[2] )
47111           {
47112             // clang-format off
47113             if      ( units[0] == 'c' ) level *= 0.01;
47114             else if ( units[0] == 'd' ) level *= 0.1;
47115             else if ( units[0] == 'k' ) level *= 1000;
47116             // clang-format on
47117           }
47118 
47119         isec1DefLevel(isec1, grib_ltype, (int) level, 0);
47120 	break;
47121       }
47122     case ZAXIS_SIGMA:
47123       {
47124 	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
47125           isec1DefLevel(isec1, GRIB1_LTYPE_SIGMA_LAYER, (int)(zaxisInqLbound(zaxisID, levelID)),
47126                         (int)(zaxisInqUbound(zaxisID, levelID)));
47127 	else
47128           isec1DefLevel(isec1, GRIB1_LTYPE_SIGMA, (int)(zaxisInqLevel(zaxisID, levelID)), 0);
47129 
47130 	break;
47131       }
47132     case ZAXIS_DEPTH_BELOW_LAND:
47133       {
47134         int length = CDI_MAX_NAME;
47135         cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, units, &length);
47136 
47137 	double factor = 100; // default: meter
47138         // clang-format off
47139         if      ( units[0] == 'm' && units[1] == 'm' ) factor =   0.1;
47140         else if ( units[0] == 'c' && units[1] == 'm' ) factor =   1;
47141         else if ( units[0] == 'd' && units[1] == 'm' ) factor =  10;
47142         // clang-format on
47143 
47144 	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
47145           isec1DefLevel(isec1, GRIB1_LTYPE_LANDDEPTH_LAYER, (int) (factor*zaxisInqLbound(zaxisID, levelID)),
47146                         (int) (factor*zaxisInqUbound(zaxisID, levelID)));
47147 	else
47148           isec1DefLevel(isec1, GRIB1_LTYPE_LANDDEPTH, (int) (factor*zaxisInqLevel(zaxisID, levelID)), 0);
47149 
47150 	break;
47151       }
47152     case ZAXIS_GENERIC:
47153       {
47154         isec1DefLevel(isec1, ltype, (int)(zaxisInqLevel(zaxisID, levelID)), 0);
47155 	break;
47156       }
47157     default:
47158       {
47159 	Error("Unsupported zaxis type: %s", zaxisNamePtr(zaxistype));
47160 	break;
47161       }
47162     }
47163 }
47164 
47165 static
cgribexDefaultSec0(int * isec0)47166 void cgribexDefaultSec0(int *isec0)
47167 {
47168   ISEC0_GRIB_Len     = 0;
47169   ISEC0_GRIB_Version = 0;
47170 }
47171 
47172 static
cgribexDefaultSec1(int * isec1)47173 void cgribexDefaultSec1(int *isec1)
47174 {
47175   ISEC1_CenterID    = 0;
47176   ISEC1_SubCenterID = 0;
47177   ISEC1_LocalFLag   = 0;
47178 }
47179 
47180 static
cgribexDefaultSec4(int * isec4)47181 void cgribexDefaultSec4(int *isec4)
47182 {
47183   for ( int i = 2; i <= 10; ++i ) isec4[i] = 0;
47184 }
47185 
47186 static
cgribexDefEnsembleVar(int * isec1,int vlistID,int varID)47187 void cgribexDefEnsembleVar(int *isec1, int vlistID, int varID)
47188 {
47189   // For Ensemble info
47190 
47191   //Put1Byte(isec1[36]);        // MPIM local GRIB use definition identifier (extension identifier)
47192   //Put1Byte(isec1[37]);        // type of ensemble forecast
47193   //Put2Byte(isec1[38]);        // individual ensemble member
47194   //Put2Byte(isec1[39]);        // number of forecasts in ensemble
47195 
47196   int perturbationNumber, numberOfForecastsInEnsemble, typeOfEnsembleForecast;
47197   const int r1 = cdiInqKeyInt(vlistID, varID, CDI_KEY_PERTURBATIONNUMBER, &perturbationNumber);
47198   const int r2 = cdiInqKeyInt(vlistID, varID, CDI_KEY_NUMBEROFFORECASTSINENSEMBLE, &numberOfForecastsInEnsemble);
47199   const int r3 = cdiInqKeyInt(vlistID, varID, CDI_KEY_TYPEOFENSEMBLEFORECAST, &typeOfEnsembleForecast);
47200 
47201   if ( r1 == 0 && r2 == 0 && r3 == 0 )
47202     {
47203       if ( ISEC1_CenterID == 252 )
47204         {
47205           ISEC1_LocalFLag = 1;
47206           isec1[36] = 1;
47207           isec1[37] = typeOfEnsembleForecast;
47208           isec1[38] = perturbationNumber;
47209           isec1[39] = numberOfForecastsInEnsemble;
47210         }
47211     }
47212 }
47213 
47214 
cgribexEncode(int memtype,int varID,int levelID,int vlistID,int gridID,int zaxisID,int vdate,int vtime,int tsteptype,int numavg,size_t datasize,const void * data,size_t nmiss,void * gribbuffer,size_t gribbuffersize)47215 size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
47216 		     int vdate, int vtime, int tsteptype, int numavg,
47217 		     size_t datasize, const void *data, size_t nmiss, void *gribbuffer, size_t gribbuffersize)
47218 {
47219   cgribexrec_t *cgribexp = (cgribexrec_t *)cgribexNew();
47220 
47221   const size_t sec2len = 1024 + 2*gridInqYsize(gridID); // Gaussian reduced grid
47222   if (sec2len > cgribexp->sec2len)
47223     {
47224       cgribexp->sec2len = sec2len;
47225       cgribexp->sec2 = (int *) Realloc(cgribexp->sec2, sec2len*sizeof(int));
47226     }
47227 
47228   int *isec0 = cgribexp->sec0;
47229   int *isec1 = cgribexp->sec1;
47230   int *isec2 = cgribexp->sec2;
47231   int *isec3 = cgribexp->sec3;
47232   int *isec4 = cgribexp->sec4;
47233   double *fsec2 = cgribexp->fsec2;
47234   double *fsec3 = cgribexp->fsec3;
47235   float fsec2f[sizeof(cgribexp->fsec2)/sizeof(double)];
47236   float fsec3f[sizeof(cgribexp->fsec3)/sizeof(double)];
47237 
47238   memset(isec1, 0, 256*sizeof(int));
47239   fsec2[0] = 0; fsec2[1] = 0;
47240   fsec2f[0] = 0; fsec2f[1] = 0;
47241 
47242   const int gribsize = (int)(gribbuffersize / sizeof(int));
47243   const int param    = vlistInqVarParam(vlistID, varID);
47244 
47245   cgribexDefaultSec0(isec0);
47246   cgribexDefaultSec1(isec1);
47247   cgribexDefaultSec4(isec4);
47248 
47249   cgribexDefInstitut(isec1, vlistID, varID);
47250   cgribexDefModel(isec1, vlistID, varID);
47251 
47252   const int datatype = vlistInqVarDatatype(vlistID, varID);
47253 
47254   int uvRelativeToGrid = -1;
47255   cdiInqKeyInt(vlistID, varID, CDI_KEY_UVRELATIVETOGRID, &uvRelativeToGrid);
47256 
47257   cgribexDefParam(isec1, param);
47258   cgribexDefTime(isec1, vdate, vtime, tsteptype, numavg, vlistInqTaxis(vlistID));
47259   cgribexDefGrid(isec1, isec2, fsec2, isec4, gridID, uvRelativeToGrid);
47260   cgribexDefLevel(isec1, isec2, fsec2, zaxisID, levelID);
47261 
47262   cgribexDefEnsembleVar(isec1, vlistID, varID);
47263 
47264   cdi_check_gridsize_int_limit("GRIB1", datasize);
47265 
47266   ISEC4_NumValues = (int) datasize;
47267   ISEC4_NumBits   = grbBitsPerValue(datatype);
47268 
47269   if ( nmiss > 0 )
47270     {
47271       FSEC3_MissVal = vlistInqVarMissval(vlistID, varID);
47272       ISEC1_Sec2Or3Flag |= 64;
47273     }
47274 
47275   if ( isec4[2] == 128 && isec4[3] == 64 )
47276     {
47277       if ( memtype == MEMTYPE_FLOAT )
47278         isec4[16] = (int) (1000*calculate_pfactor_float((const float*) data, ISEC2_PentaJ, isec4[17]));
47279       else
47280         isec4[16] = (int) (1000*calculate_pfactor_double((const double*) data, ISEC2_PentaJ, isec4[17]));
47281       if ( isec4[16] < -10000 ) isec4[16] = -10000;
47282       if ( isec4[16] >  10000 ) isec4[16] =  10000;
47283     }
47284   //printf("isec4[16] %d\n", isec4[16]);
47285 
47286   if ( memtype == MEMTYPE_FLOAT )
47287     {
47288       int numVCP = (ISEC2_NumVCP > 0) ? ISEC2_NumVCP : 0;
47289       for ( int i = 0; i < numVCP; ++i ) fsec2f[10+i] = (float)fsec2[10+i];
47290       fsec3f[ 1] = (float)fsec3[ 1];
47291     }
47292 
47293   int iret = 0, iword = 0;
47294   if ( memtype == MEMTYPE_FLOAT )
47295     gribExSP(isec0, isec1, isec2, fsec2f, isec3, fsec3f, isec4, (float*) data,
47296              (int) datasize, (int*) gribbuffer, gribsize, &iword, "C", &iret);
47297   else
47298     gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, (double*) data,
47299              (int) datasize, (int*) gribbuffer, gribsize, &iword, "C", &iret);
47300 
47301   cgribexDelete(cgribexp);
47302 
47303   if ( iret ) Error("Problem during GRIB encode (errno = %d)!", iret);
47304 
47305   const size_t nbytes = (size_t)iword * sizeof(int);
47306   return nbytes;
47307 }
47308 
47309 
cgribexChangeParameterIdentification(void * gh,int code,int ltype,int lev)47310 void cgribexChangeParameterIdentification(void *gh, int code, int ltype, int lev)
47311 {
47312   if ( !gh ) return;
47313 
47314   unsigned char *pds = ((cgribex_handle*)gh)->pds;
47315   if ( !pds ) return;
47316 
47317   pds[8]  = (unsigned char) code;
47318   pds[9]  = (unsigned char) ltype;
47319   pds[10] = (unsigned char) lev;
47320 }
47321 
47322 #endif
47323 /*
47324  * Local Variables:
47325  * c-file-style: "Java"
47326  * c-basic-offset: 2
47327  * indent-tabs-mode: nil
47328  * show-trailing-whitespace: t
47329  * require-trailing-newline: t
47330  * End:
47331  */
47332 #ifdef HAVE_CONFIG_H
47333 #endif
47334 
47335 
47336 
47337 
47338 #ifdef HAVE_LIBEXTRA
47339 
47340 static
extInqDatatype(int prec,int number)47341 int extInqDatatype(int prec, int number)
47342 {
47343   int datatype;
47344 
47345   if ( number == 2 )
47346     datatype = (prec == EXSE_DOUBLE_PRECISION) ? CDI_DATATYPE_CPX64 : CDI_DATATYPE_CPX32;
47347   else
47348     datatype = (prec == EXSE_DOUBLE_PRECISION) ? CDI_DATATYPE_FLT64 : CDI_DATATYPE_FLT32;
47349 
47350   return datatype;
47351 }
47352 
47353 static
extDefDatatype(int datatype,int * prec,int * number)47354 void extDefDatatype(int datatype, int *prec, int *number)
47355 {
47356 
47357   if ( datatype != CDI_DATATYPE_FLT32 && datatype != CDI_DATATYPE_FLT64 &&
47358        datatype != CDI_DATATYPE_CPX32 && datatype != CDI_DATATYPE_CPX64 )
47359     datatype = CDI_DATATYPE_FLT32;
47360 
47361   *number = (datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64) ? 2 : 1;
47362 
47363   *prec = (datatype == CDI_DATATYPE_FLT64 || datatype == CDI_DATATYPE_CPX64) ? EXSE_DOUBLE_PRECISION : EXSE_SINGLE_PRECISION;
47364 }
47365 
47366 /* not used
47367 int extInqRecord(stream_t *streamptr, int *varID, int *levelID)
47368 {
47369   int status;
47370   int fileID;
47371   int icode, ilevel;
47372   int zaxisID = -1;
47373   int header[4];
47374   int vlistID;
47375   void *extp = streamptr->record->exsep;
47376 
47377   vlistID = streamptr->vlistID;
47378   fileID  = streamptr->fileID;
47379 
47380   *varID   = -1;
47381   *levelID = -1;
47382 
47383   status = extRead(fileID, extp);
47384   if ( status != 0 ) return 0;
47385 
47386   extInqHeader(extp, header);
47387 
47388   icode  = header[1];
47389   ilevel = header[2];
47390 
47391   *varID = vlistInqVarID(vlistID, icode);
47392 
47393   if ( *varID == CDI_UNDEFID ) Error("Code %d undefined", icode);
47394 
47395   zaxisID = vlistInqVarZaxis(vlistID, *varID);
47396 
47397   *levelID = zaxisInqLevelID(zaxisID, (double) ilevel);
47398 
47399   return 1;
47400 }
47401 */
47402 
extReadRecord(stream_t * streamptr,double * data,size_t * nmiss)47403 void extReadRecord(stream_t *streamptr, double *data, size_t *nmiss)
47404 {
47405   int vlistID = streamptr->vlistID;
47406   int fileID  = streamptr->fileID;
47407   int tsID    = streamptr->curTsID;
47408   int vrecID  = streamptr->tsteps[tsID].curRecID;
47409   int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
47410   int varID   = streamptr->tsteps[tsID].records[recID].varID;
47411   off_t recpos = streamptr->tsteps[tsID].records[recID].position;
47412 
47413   fileSetPos(fileID, recpos, SEEK_SET);
47414 
47415   void *extp = streamptr->record->exsep;
47416   int status = extRead(fileID, extp);
47417   if ( status != 0 ) Error("Failed to read EXTRA record");
47418 
47419   int header[4];
47420   extInqHeader(extp, header);
47421   extInqDataDP(extp, data);
47422 
47423   double missval = vlistInqVarMissval(vlistID, varID);
47424   int gridID  = vlistInqVarGrid(vlistID, varID);
47425   size_t size = gridInqSize(gridID);
47426 
47427   streamptr->numvals += size;
47428 
47429   *nmiss = 0;
47430   if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
47431     {
47432       for ( size_t i = 0; i < size; i++ )
47433 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
47434 	  {
47435 	    data[i] = missval;
47436 	    (*nmiss)++;
47437 	  }
47438     }
47439   else
47440     {
47441       for ( size_t i = 0; i < 2*size; i+=2 )
47442 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
47443 	  {
47444 	    data[i] = missval;
47445 	    (*nmiss)++;
47446 	  }
47447     }
47448 }
47449 
47450 
extCopyRecord(stream_t * streamptr2,stream_t * streamptr1)47451 void extCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
47452 {
47453   streamFCopyRecord(streamptr2, streamptr1, "EXTRA");
47454 }
47455 
47456 
extDefRecord(stream_t * streamptr)47457 void extDefRecord(stream_t *streamptr)
47458 {
47459   Record *record = streamptr->record;
47460 
47461   int pdis, pcat, pnum;
47462   cdiDecodeParam(record->param, &pnum, &pcat, &pdis);
47463 
47464   int header[4];
47465   header[0] = record->date;
47466   header[1] = pnum;
47467   header[2] = record->level;
47468   int gridID = record->gridID;
47469   cdi_check_gridsize_int_limit("EXTRA", gridInqSize(gridID));
47470   header[3] = (int) gridInqSize(gridID);
47471 
47472   extrec_t *extp = (extrec_t*) record->exsep;
47473   extDefDatatype(record->prec, &extp->prec, &extp->number);
47474   extDefHeader(extp, header);
47475 }
47476 
47477 
extWriteRecord(stream_t * streamptr,const double * data)47478 void extWriteRecord(stream_t *streamptr, const double *data)
47479 {
47480   void *extp = streamptr->record->exsep;
47481   extDefDataDP(extp, data);
47482   extWrite(streamptr->fileID, extp);
47483 }
47484 
47485 static
extAddRecord(stream_t * streamptr,int param,int level,size_t xysize,size_t recsize,off_t position,int prec,int number)47486 void extAddRecord(stream_t *streamptr, int param, int level, size_t xysize,
47487 		  size_t recsize, off_t position, int prec, int number)
47488 {
47489   const int vlistID = streamptr->vlistID;
47490   const int tsID    = streamptr->curTsID;
47491   const int recID   = recordNewEntry(streamptr, tsID);
47492   record_t *record = &streamptr->tsteps[tsID].records[recID];
47493 
47494   record->size     = recsize;
47495   record->position = position;
47496   record->param    = param;
47497   record->ilevel   = level;
47498 
47499   grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
47500   grid_init(grid);
47501   cdiGridTypeInit(grid, GRID_GENERIC, xysize);
47502   grid->x.size = xysize;
47503   grid->y.size = 0;
47504   struct addIfNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
47505   const int gridID = gridAdded.Id;
47506   if (!gridAdded.isNew) Free(grid);
47507 
47508   const int leveltype = ZAXIS_GENERIC;
47509   const int datatype = extInqDatatype(prec, number);
47510 
47511   int varID, levelID = 0;
47512   varAddRecord(recID, param, gridID, leveltype, 0, level, 0, 0, 0,
47513                datatype, &varID, &levelID, TSTEP_INSTANT, 0, -1,
47514                NULL, NULL, NULL, NULL);
47515 
47516   record->varID   = (short)varID;
47517   record->levelID = (short)levelID;
47518 
47519   streamptr->tsteps[tsID].nallrecs++;
47520   streamptr->nrecs++;
47521 
47522   if ( CDI_Debug )
47523     Message("varID = %d gridID = %d levelID = %d", varID, gridID, levelID);
47524 }
47525 
47526 static
extScanTimestep1(stream_t * streamptr)47527 void extScanTimestep1(stream_t *streamptr)
47528 {
47529   int header[4];
47530   DateTime datetime0 = { LONG_MIN, LONG_MIN };
47531   off_t recpos = 0;
47532   extrec_t *extp = (extrec_t*) streamptr->record->exsep;
47533 
47534   streamptr->curTsID = 0;
47535 
47536   int tsID  = tstepsNewEntry(streamptr);
47537   if ( tsID != 0 ) Error("Internal problem! tstepsNewEntry returns %d", tsID);
47538   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
47539 
47540   const int fileID = streamptr->fileID;
47541 
47542   int nrecs = 0;
47543   while ( true )
47544     {
47545       recpos = fileGetPos(fileID);
47546       if ( extRead(fileID, extp) != 0 )
47547 	{
47548 	  streamptr->ntsteps = 1;
47549 	  break;
47550 	}
47551 
47552       const size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
47553 
47554       extInqHeader(extp, header);
47555 
47556       const int vdate   = header[0];
47557       const int vtime   = 0;
47558       const int rcode   = header[1];
47559       const int rlevel  = header[2];
47560       const int rxysize = header[3];
47561       const int param   = cdiEncodeParam(rcode, 255, 255);
47562       DateTime datetime = { .date = vdate, .time = vtime};
47563 
47564       if ( nrecs == 0 )
47565 	{
47566 	  datetime0 = datetime;
47567           taxis->vdate = vdate;
47568           taxis->vtime = vtime;
47569 	}
47570       else
47571 	{
47572           record_t *records = streamptr->tsteps[tsID].records;
47573 	  for ( int recID = 0; recID < nrecs; recID++ )
47574             if ( param == records[recID].param && rlevel == records[recID].ilevel )
47575               goto tstepScanLoopFinished;
47576 
47577 	  if ( datetimeDiffer(datetime, datetime0) )
47578 	    Warning("Inconsistent verification time for code %d level %d", rcode, rlevel);
47579 	}
47580 
47581       nrecs++;
47582 
47583       if ( CDI_Debug )
47584 	Message("%4d%8d%4d%8d%8d%6d", nrecs, (int)recpos, rcode, rlevel, vdate, vtime);
47585 
47586       extAddRecord(streamptr, param, rlevel, rxysize, recsize, recpos, extp->prec, extp->number);
47587     }
47588 
47589   tstepScanLoopFinished:
47590   streamptr->rtsteps = 1;
47591 
47592   cdi_generate_vars(streamptr);
47593 
47594   const int taxisID = taxisCreate(TAXIS_ABSOLUTE);
47595   taxis->type  = TAXIS_ABSOLUTE;
47596   taxis->rdate = taxis->vdate;
47597   taxis->rtime = taxis->vtime;
47598 
47599   const int vlistID = streamptr->vlistID;
47600   vlistDefTaxis(vlistID, taxisID);
47601 
47602   vlist_check_contents(vlistID);
47603 
47604   streamScanResizeRecords1(streamptr);
47605 
47606   streamScanTsFixNtsteps(streamptr, recpos);
47607   streamScanTimeConstAdjust(streamptr, taxis);
47608 }
47609 
47610 static
extScanTimestep2(stream_t * streamptr)47611 int extScanTimestep2(stream_t *streamptr)
47612 {
47613   int header[4];
47614   off_t recpos = 0;
47615   void *extp = streamptr->record->exsep;
47616 
47617   streamptr->curTsID = 1;
47618 
47619   const int fileID  = streamptr->fileID;
47620   const int vlistID = streamptr->vlistID;
47621 
47622   int tsID = streamptr->rtsteps;
47623   if ( tsID != 1 ) Error("Internal problem! unexpected timestep %d", tsID+1);
47624 
47625   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
47626 
47627   fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
47628 
47629   cdi_create_records(streamptr, tsID);
47630   record_t *records = streamptr->tsteps[tsID].records;
47631 
47632   const int nrecords = streamScanInitRecords2(streamptr);
47633 
47634   for ( int rindex = 0; rindex <= nrecords; rindex++ )
47635     {
47636       recpos = fileGetPos(fileID);
47637       if ( extRead(fileID, extp) != 0 )
47638 	{
47639 	  streamptr->ntsteps = 2;
47640 	  break;
47641 	}
47642 
47643       const size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
47644 
47645       extInqHeader(extp, header);
47646 
47647       const int vdate  = header[0];
47648       const int vtime  = 0;
47649       const int rcode  = header[1];
47650       const int rlevel = header[2];
47651       const int param  = cdiEncodeParam(rcode, 255, 255);
47652 
47653       if ( rindex == 0 )
47654 	{
47655 	  taxis->type  = TAXIS_ABSOLUTE;
47656 	  taxis->vdate = vdate;
47657 	  taxis->vtime = vtime;
47658 	}
47659 
47660       bool nextstep = false;
47661       int recID;
47662       for ( recID = 0; recID < nrecords; recID++ )
47663 	{
47664 	  if ( param == records[recID].param && rlevel == records[recID].ilevel )
47665 	    {
47666 	      if ( records[recID].used )
47667 		{
47668 		  nextstep = true;
47669 		}
47670 	      else
47671 		{
47672 		  records[recID].used = true;
47673 		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
47674 		}
47675 	      break;
47676 	    }
47677 	}
47678       if ( recID == nrecords )
47679 	{
47680 	  Warning("Code %d level %d not found at timestep %d", rcode, rlevel, tsID+1);
47681 	  return CDI_EUFSTRUCT;
47682 	}
47683 
47684       if ( nextstep ) break;
47685 
47686       if ( CDI_Debug )
47687 	Message("%4d%8d%4d%8d%8d%6d", rindex+1, (int)recpos, rcode, rlevel, vdate, vtime);
47688 
47689       if ( param != records[recID].param || rlevel != records[recID].ilevel )
47690 	{
47691 	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
47692 		  tsID, recID, records[recID].param, param, records[recID].ilevel, rlevel);
47693 	  return CDI_EUFSTRUCT;
47694 	}
47695 
47696       records[recID].position = recpos;
47697       records[recID].size = recsize;
47698     }
47699 
47700   int nrecs = 0;
47701   for ( int recID = 0; recID < nrecords; recID++ )
47702     {
47703       if ( ! records[recID].used )
47704 	{
47705           vlistDefVarTimetype(vlistID, records[recID].varID, TIME_CONSTANT);
47706 	}
47707       else
47708 	{
47709 	  nrecs++;
47710 	}
47711     }
47712   streamptr->tsteps[tsID].nrecs = nrecs;
47713 
47714   streamptr->rtsteps = 2;
47715 
47716   streamScanTsFixNtsteps(streamptr, recpos);
47717 
47718   return 0;
47719 }
47720 
47721 
extInqContents(stream_t * streamptr)47722 int extInqContents(stream_t *streamptr)
47723 {
47724   streamptr->curTsID = 0;
47725 
47726   extScanTimestep1(streamptr);
47727 
47728   const int status = (streamptr->ntsteps == -1) ? extScanTimestep2(streamptr) : 0;
47729 
47730   fileSetPos(streamptr->fileID, 0, SEEK_SET);
47731 
47732   return status;
47733 }
47734 
47735 static
extScanTimestep(stream_t * streamptr)47736 long extScanTimestep(stream_t *streamptr)
47737 {
47738   int header[4];
47739   off_t recpos = 0;
47740   int nrecs = 0;
47741   void *extp = streamptr->record->exsep;
47742 
47743   int tsID = streamptr->rtsteps;
47744   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
47745 
47746   if ( streamptr->tsteps[tsID].recordSize == 0 )
47747     {
47748       cdi_create_records(streamptr, tsID);
47749       record_t *records = streamptr->tsteps[tsID].records;
47750 
47751       nrecs = streamScanInitRecords(streamptr, tsID);
47752 
47753       const int fileID = streamptr->fileID;
47754 
47755       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
47756 
47757       for ( int rindex = 0; rindex <= nrecs; rindex++ )
47758 	{
47759 	  recpos = fileGetPos(fileID);
47760 	  if ( extRead(fileID, extp) != 0 )
47761 	    {
47762 	      streamptr->ntsteps = streamptr->rtsteps + 1;
47763 	      break;
47764 	    }
47765 
47766 	  const size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
47767 
47768 	  extInqHeader(extp, header);
47769 
47770 	  const int vdate  = header[0];
47771 	  const int vtime  = 0;
47772 	  const int rcode  = header[1];
47773 	  const int rlevel = header[2];
47774 	  const int param  = cdiEncodeParam(rcode, 255, 255);
47775 
47776 	  // if ( rindex == nrecs ) break; gcc-4.5 internal compiler error
47777 	  if ( rindex == nrecs ) continue;
47778 	  const int recID = streamptr->tsteps[tsID].recIDs[rindex];
47779 
47780 	  if ( rindex == 0 )
47781 	    {
47782 	      taxis->type  = TAXIS_ABSOLUTE;
47783 	      taxis->vdate = vdate;
47784 	      taxis->vtime = vtime;
47785 	    }
47786 
47787           if ( param != records[recID].param || rlevel != records[recID].ilevel )
47788 	    {
47789 	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
47790 		      tsID, recID, records[recID].param, param, records[recID].ilevel, rlevel);
47791 	      Error("Invalid, unsupported or inconsistent record structure!");
47792 	    }
47793 
47794 	  records[recID].position = recpos;
47795 	  records[recID].size = recsize;
47796 
47797 	  if ( CDI_Debug )
47798 	    Message("%4d%8d%4d%8d%8d%6d", rindex, (int)recpos, rcode, rlevel, vdate, vtime);
47799 	}
47800 
47801       streamptr->rtsteps++;
47802 
47803       if ( streamptr->ntsteps != streamptr->rtsteps )
47804 	{
47805 	  tsID = tstepsNewEntry(streamptr);
47806 	  if ( tsID != streamptr->rtsteps )
47807 	    Error("Internal error. tsID = %d", tsID);
47808 
47809 	  streamptr->tsteps[tsID-1].next   = true;
47810 	  streamptr->tsteps[tsID].position = recpos;
47811 	}
47812 
47813       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
47814       streamptr->tsteps[tsID].position = recpos;
47815     }
47816 
47817   if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
47818     {
47819       Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
47820       streamptr->ntsteps = tsID;
47821     }
47822 
47823   return streamptr->ntsteps;
47824 }
47825 
47826 
extInqTimestep(stream_t * streamptr,int tsID)47827 int extInqTimestep(stream_t *streamptr, int tsID)
47828 {
47829   if ( tsID == 0 && streamptr->rtsteps == 0 )
47830     Error("Call to cdiInqContents missing!");
47831 
47832   if ( CDI_Debug )
47833     Message("tsID = %d rtsteps = %d", tsID, streamptr->rtsteps);
47834 
47835   long ntsteps = CDI_UNDEFID;
47836   while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == CDI_UNDEFID )
47837     ntsteps = extScanTimestep(streamptr);
47838 
47839   int nrecs = 0;
47840   if ( !(tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID) )
47841     {
47842       streamptr->curTsID = tsID;
47843       nrecs = streamptr->tsteps[tsID].nrecs;
47844     }
47845 
47846   return nrecs;
47847 }
47848 
47849 
extReadVarSliceDP(stream_t * streamptr,int varID,int levID,double * data,size_t * nmiss)47850 void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, size_t *nmiss)
47851 {
47852   if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
47853 
47854   void *extp = streamptr->record->exsep;
47855 
47856   int vlistID  = streamptr->vlistID;
47857   int fileID   = streamptr->fileID;
47858   /* NOTE: tiles are not supported here! */
47859   double missval = vlistInqVarMissval(vlistID, varID);
47860   size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
47861   int tsid = streamptr->curTsID;
47862 
47863   off_t currentfilepos = fileGetPos(fileID);
47864 
47865   /* NOTE: tiles are not supported here! */
47866   int recID = streamptr->vars[varID].recordTable[0].recordID[levID];
47867   off_t recpos = streamptr->tsteps[tsid].records[recID].position;
47868   fileSetPos(fileID, recpos, SEEK_SET);
47869   extRead(fileID, extp);
47870   int header[4];
47871   extInqHeader(extp, header);
47872   extInqDataDP(extp, data);
47873 
47874   fileSetPos(fileID, currentfilepos, SEEK_SET);
47875 
47876   *nmiss = 0;
47877   if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
47878     {
47879       for ( size_t i = 0; i < gridsize; i++ )
47880 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
47881 	  {
47882 	    data[i] = missval;
47883 	    (*nmiss)++;
47884 	  }
47885     }
47886   else
47887     {
47888       for ( size_t i = 0; i < 2*gridsize; i+=2 )
47889 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
47890 	  {
47891 	    data[i] = missval;
47892 	    (*nmiss)++;
47893 	  }
47894     }
47895 }
47896 
47897 
extReadVarDP(stream_t * streamptr,int varID,double * data,size_t * nmiss)47898 void extReadVarDP(stream_t *streamptr, int varID, double *data, size_t *nmiss)
47899 {
47900   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
47901 
47902   int vlistID = streamptr->vlistID;
47903   size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
47904   size_t nlevs    = (size_t) streamptr->vars[varID].recordTable[0].nlevs;
47905 
47906   for ( size_t levID = 0; levID < nlevs; levID++)
47907     extReadVarSliceDP(streamptr, varID, (int)levID, &data[levID*gridsize], nmiss);
47908 }
47909 
47910 
extWriteVarSliceDP(stream_t * streamptr,int varID,int levID,const double * data)47911 void extWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
47912 {
47913   if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
47914 
47915   int vlistID  = streamptr->vlistID;
47916   int fileID   = streamptr->fileID;
47917   int tsID     = streamptr->curTsID;
47918 
47919   int pdis, pcat, pnum;
47920   cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
47921 
47922   int header[4];
47923   header[0] = streamptr->tsteps[tsID].taxis.vdate;
47924   header[1] = pnum;
47925   header[2] = (int)(zaxisInqLevel(vlistInqVarZaxis(vlistID, varID), levID));
47926   int gridID = vlistInqVarGrid(vlistID, varID);
47927   cdi_check_gridsize_int_limit("EXTRA", gridInqSize(gridID));
47928   header[3] = (int) gridInqSize(gridID);
47929 
47930   extrec_t *extp = (extrec_t*) streamptr->record->exsep;
47931   extDefDatatype(vlistInqVarDatatype(vlistID, varID), &extp->prec, &extp->number);
47932   extDefHeader(extp, header);
47933 
47934   extDefDataDP(extp, data);
47935   extWrite(fileID, extp);
47936 }
47937 
47938 
extWriteVarDP(stream_t * streamptr,int varID,const double * data)47939 void extWriteVarDP(stream_t *streamptr, int varID, const double *data)
47940 {
47941   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
47942 
47943   int vlistID = streamptr->vlistID;
47944   size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
47945   size_t nlevs    = (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
47946 
47947   for ( size_t levID = 0;  levID < nlevs; levID++ )
47948     extWriteVarSliceDP(streamptr, varID, (int)levID, &data[levID*gridsize]);
47949 }
47950 
47951 #endif /* HAVE_LIBEXTRA */
47952 
47953 /*
47954  * Local Variables:
47955  * c-file-style: "Java"
47956  * c-basic-offset: 2
47957  * indent-tabs-mode: nil
47958  * show-trailing-whitespace: t
47959  * require-trailing-newline: t
47960  * End:
47961  */
47962 #ifndef STREAM_GRIBAPI_H
47963 #define STREAM_GRIBAPI_H
47964 
47965 #ifdef HAVE_LIBGRIB_API
47966 
47967 
47968 int gribapiScanTimestep1(stream_t * streamptr);
47969 int gribapiScanTimestep2(stream_t * streamptr);
47970 int gribapiScanTimestep(stream_t * streamptr);
47971 
47972 int gribapiDecode(void *gribbuffer, size_t gribsize, double *data, size_t datasize,
47973 		  int unreduced, size_t *nmiss, double missval);
47974 
47975 size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID,
47976 		     int64_t vdate, int vtime, int tsteptype, int numavg,
47977 		     size_t datasize, const double *data, size_t nmiss, void **gribbuffer, size_t *gribbuffersize,
47978 		     int ljpeg, void *gribContainer);
47979 
47980 int gribapiGetScanningMode(grib_handle *gh);
47981 void gribapiSetScanningMode(grib_handle *gh, int scanningMode);
47982 
47983 void gribapiChangeParameterIdentification(grib_handle *gh, int code, int ltype, int lev);
47984 
47985 #endif
47986 
47987 #endif  /* STREAM_GRIBAPI_H */
47988 /*
47989  * Local Variables:
47990  * c-file-style: "Java"
47991  * c-basic-offset: 2
47992  * indent-tabs-mode: nil
47993  * show-trailing-whitespace: t
47994  * require-trailing-newline: t
47995  * End:
47996  */
47997 #ifdef HAVE_CONFIG_H
47998 #endif
47999 
48000 
48001 int cdiDebugExt                        =  0;      //  Debug level for the KNMI extensions
48002 #ifdef HIRLAM_EXTENSIONS
48003 // *** RELATED to GRIB only ***
48004 int cdiGribUseTimeRangeIndicator        = 0;       // normaly cdo looks in grib for attribute called "stepType"
48005                                                    // but NWP models such as Harmonie 37h1.2, use "timeRangeIndicator"
48006                                                    // where:  0: for instanteneous fields; 4: for accumulated fields
48007 #endif // HIRLAM_EXTENSIONS
48008 
48009 
ensureBufferSize(size_t requiredSize,size_t * curSize,void ** buffer)48010 void ensureBufferSize(size_t requiredSize, size_t *curSize, void **buffer)
48011 {
48012   if ( *curSize < requiredSize )
48013     {
48014       *curSize = requiredSize;
48015       *buffer = Realloc(*buffer, *curSize);
48016     }
48017 }
48018 
grbDecompress(size_t recsize,size_t * buffersize,void ** gribbuffer)48019 int grbDecompress(size_t recsize, size_t *buffersize, void **gribbuffer)
48020 {
48021   int comptype = CDI_COMPRESS_NONE;
48022 
48023   size_t unzipsize;
48024   if ( gribGetZip(recsize, (unsigned char *)*gribbuffer, &unzipsize) > 0 )
48025     {
48026       comptype = CDI_COMPRESS_SZIP;
48027       unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
48028       ensureBufferSize(unzipsize, buffersize, gribbuffer);
48029     }
48030 
48031   return comptype;
48032 }
48033 
48034 
48035 // Regarding operation to change parameter identification:
48036 // change if cdiGribChangeParameterID.active
48037 struct cdiGribParamChange cdiGribChangeParameterID;
48038 
48039 // Used only for CDO module Selmulti
streamGrbChangeParameterIdentification(int code,int ltype,int lev)48040 void streamGrbChangeParameterIdentification(int code, int ltype, int lev)
48041 {
48042   // NOTE this is a "PROXY" function for gribapiChangeParameterIdentification();
48043   // This just sets the globals. There are probably better solutions to this.
48044   // The parameter change is done by function  gribapiChangeParameterIdentification() in stream_gribapi.c
48045   // Setting this control variable to true will cause calling fnc. gribapiChangeParameterIdentification later.
48046   // After grib attributes have been changed this variable goes to false.
48047   cdiGribChangeParameterID.active = true;
48048   cdiGribChangeParameterID.code = code;
48049   cdiGribChangeParameterID.ltype = ltype;
48050   cdiGribChangeParameterID.lev = lev;
48051 }
48052 
48053 struct cdiGribScanModeChange cdiGribDataScanningMode;
48054 
streamGrbDefDataScanningMode(int scanmode)48055 void streamGrbDefDataScanningMode(int scanmode)
48056 {
48057   cdiGribDataScanningMode.active = true;
48058   cdiGribDataScanningMode.value = scanmode;
48059 }
48060 
48061 
grib1ltypeToZaxisType(int grib_ltype)48062 int grib1ltypeToZaxisType(int grib_ltype)
48063 {
48064   int zaxistype = ZAXIS_GENERIC;
48065   // clang-format off
48066   switch ( grib_ltype )
48067     {
48068     case GRIB1_LTYPE_SURFACE:            zaxistype = ZAXIS_SURFACE;                break;
48069     case GRIB1_LTYPE_CLOUD_BASE:         zaxistype = ZAXIS_CLOUD_BASE;             break;
48070     case GRIB1_LTYPE_CLOUD_TOP:          zaxistype = ZAXIS_CLOUD_TOP;              break;
48071     case GRIB1_LTYPE_ISOTHERM0:          zaxistype = ZAXIS_ISOTHERM_ZERO;          break;
48072     case GRIB1_LTYPE_TROPOPAUSE:         zaxistype = ZAXIS_TROPOPAUSE;             break;
48073     case GRIB1_LTYPE_TOA:                zaxistype = ZAXIS_TOA;                    break;
48074     case GRIB1_LTYPE_SEA_BOTTOM:         zaxistype = ZAXIS_SEA_BOTTOM;             break;
48075     case GRIB1_LTYPE_ATMOSPHERE:         zaxistype = ZAXIS_ATMOSPHERE;             break;
48076     case GRIB1_LTYPE_MEANSEA:            zaxistype = ZAXIS_MEANSEA;                break;
48077     case GRIB1_LTYPE_99:
48078     case GRIB1_LTYPE_ISOBARIC_PA:
48079     case GRIB1_LTYPE_ISOBARIC:           zaxistype = ZAXIS_PRESSURE;               break;
48080     case GRIB1_LTYPE_HEIGHT:             zaxistype = ZAXIS_HEIGHT;                 break;
48081     case GRIB1_LTYPE_ALTITUDE:           zaxistype = ZAXIS_ALTITUDE;	           break;
48082     case GRIB1_LTYPE_SIGMA:
48083     case GRIB1_LTYPE_SIGMA_LAYER:        zaxistype = ZAXIS_SIGMA;	           break;
48084     case GRIB1_LTYPE_HYBRID:
48085     case GRIB1_LTYPE_HYBRID_LAYER:       zaxistype = ZAXIS_HYBRID;	           break;
48086     case GRIB1_LTYPE_LANDDEPTH:
48087     case GRIB1_LTYPE_LANDDEPTH_LAYER:    zaxistype = ZAXIS_DEPTH_BELOW_LAND;       break;
48088     case GRIB1_LTYPE_ISENTROPIC:         zaxistype = ZAXIS_ISENTROPIC;             break;
48089     case GRIB1_LTYPE_SEADEPTH:           zaxistype = ZAXIS_DEPTH_BELOW_SEA;        break;
48090     case GRIB1_LTYPE_LAKE_BOTTOM:        zaxistype = ZAXIS_LAKE_BOTTOM;            break;
48091     case GRIB1_LTYPE_SEDIMENT_BOTTOM:    zaxistype = ZAXIS_SEDIMENT_BOTTOM;        break;
48092     case GRIB1_LTYPE_SEDIMENT_BOTTOM_TA: zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;     break;
48093     case GRIB1_LTYPE_SEDIMENT_BOTTOM_TW: zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;     break;
48094     case GRIB1_LTYPE_MIX_LAYER:          zaxistype = ZAXIS_MIX_LAYER;              break;
48095     }
48096   // clang-format on
48097   return zaxistype;
48098 }
48099 
48100 
grib2ltypeToZaxisType(int grib_ltype)48101 int grib2ltypeToZaxisType(int grib_ltype)
48102 {
48103   int zaxistype = ZAXIS_GENERIC;
48104   // clang-format off
48105   switch ( grib_ltype )
48106     {
48107     case GRIB2_LTYPE_SURFACE:            zaxistype = ZAXIS_SURFACE;                break;
48108     case GRIB2_LTYPE_CLOUD_BASE:         zaxistype = ZAXIS_CLOUD_BASE;             break;
48109     case GRIB2_LTYPE_CLOUD_TOP:          zaxistype = ZAXIS_CLOUD_TOP;              break;
48110     case GRIB2_LTYPE_ISOTHERM0:          zaxistype = ZAXIS_ISOTHERM_ZERO;          break;
48111     case GRIB2_LTYPE_TROPOPAUSE:         zaxistype = ZAXIS_TROPOPAUSE;             break;
48112     case GRIB2_LTYPE_TOA:                zaxistype = ZAXIS_TOA;                    break;
48113     case GRIB2_LTYPE_SEA_BOTTOM:         zaxistype = ZAXIS_SEA_BOTTOM;             break;
48114     case GRIB2_LTYPE_ATMOSPHERE:         zaxistype = ZAXIS_ATMOSPHERE;             break;
48115     case GRIB2_LTYPE_MEANSEA:            zaxistype = ZAXIS_MEANSEA;                break;
48116     case GRIB2_LTYPE_ISOBARIC:           zaxistype = ZAXIS_PRESSURE;               break;
48117     case GRIB2_LTYPE_HEIGHT:             zaxistype = ZAXIS_HEIGHT;                 break;
48118     case GRIB2_LTYPE_ALTITUDE:           zaxistype = ZAXIS_ALTITUDE;               break;
48119     case GRIB2_LTYPE_SIGMA:              zaxistype = ZAXIS_SIGMA;                  break;
48120     case GRIB2_LTYPE_HYBRID:
48121  /* case GRIB2_LTYPE_HYBRID_LAYER: */    zaxistype = ZAXIS_HYBRID;                 break;
48122     case GRIB2_LTYPE_LANDDEPTH:
48123  /* case GRIB2_LTYPE_LANDDEPTH_LAYER: */ zaxistype = ZAXIS_DEPTH_BELOW_LAND;       break;
48124     case GRIB2_LTYPE_ISENTROPIC:         zaxistype = ZAXIS_ISENTROPIC;             break;
48125     case GRIB2_LTYPE_SNOW:               zaxistype = ZAXIS_SNOW;                   break;
48126     case GRIB2_LTYPE_SEADEPTH:           zaxistype = ZAXIS_DEPTH_BELOW_SEA;        break;
48127     case GRIB2_LTYPE_LAKE_BOTTOM:        zaxistype = ZAXIS_LAKE_BOTTOM;            break;
48128     case GRIB2_LTYPE_SEDIMENT_BOTTOM:    zaxistype = ZAXIS_SEDIMENT_BOTTOM;        break;
48129     case GRIB2_LTYPE_SEDIMENT_BOTTOM_TA: zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;     break;
48130     case GRIB2_LTYPE_SEDIMENT_BOTTOM_TW: zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;     break;
48131     case GRIB2_LTYPE_MIX_LAYER:          zaxistype = ZAXIS_MIX_LAYER;              break;
48132     case GRIB2_LTYPE_REFERENCE:          zaxistype = ZAXIS_REFERENCE;              break;
48133     }
48134   // clang-format on
48135   return zaxistype;
48136 }
48137 
48138 
zaxisTypeToGrib1ltype(int zaxistype)48139 int zaxisTypeToGrib1ltype(int zaxistype)
48140 {
48141   int grib_ltype = -1;
48142   // clang-format off
48143   switch (zaxistype)
48144     {
48145     case ZAXIS_SURFACE:               grib_ltype = GRIB1_LTYPE_SURFACE;            break;
48146     case ZAXIS_GENERIC:               grib_ltype = -1;                             break;
48147     case ZAXIS_HYBRID:                grib_ltype = -1;                             break;
48148     case ZAXIS_HYBRID_HALF:           grib_ltype = -1;                             break;
48149     case ZAXIS_PRESSURE:              grib_ltype = GRIB1_LTYPE_ISOBARIC;           break;
48150     case ZAXIS_HEIGHT:                grib_ltype = GRIB1_LTYPE_HEIGHT;             break;
48151     case ZAXIS_DEPTH_BELOW_SEA:       grib_ltype = GRIB1_LTYPE_SEADEPTH;           break;
48152     case ZAXIS_DEPTH_BELOW_LAND:      grib_ltype = GRIB1_LTYPE_LANDDEPTH;          break;
48153     case ZAXIS_ISENTROPIC:            grib_ltype = GRIB1_LTYPE_ISENTROPIC;         break;
48154     case ZAXIS_TRAJECTORY:            grib_ltype = -1;                             break;
48155     case ZAXIS_ALTITUDE:              grib_ltype = GRIB1_LTYPE_ALTITUDE;           break;
48156     case ZAXIS_SIGMA:                 grib_ltype = GRIB1_LTYPE_SIGMA;              break;
48157     case ZAXIS_MEANSEA:               grib_ltype = GRIB1_LTYPE_MEANSEA;            break;
48158     case ZAXIS_TROPOPAUSE:            grib_ltype = GRIB1_LTYPE_TROPOPAUSE;         break;
48159     case ZAXIS_TOA:                   grib_ltype = GRIB1_LTYPE_TOA;                break;
48160     case ZAXIS_SEA_BOTTOM:            grib_ltype = GRIB1_LTYPE_SEA_BOTTOM;         break;
48161     case ZAXIS_ATMOSPHERE:            grib_ltype = GRIB1_LTYPE_ATMOSPHERE;         break;
48162     case ZAXIS_CLOUD_BASE:            grib_ltype = GRIB1_LTYPE_CLOUD_BASE;         break;
48163     case ZAXIS_CLOUD_TOP:             grib_ltype = GRIB1_LTYPE_CLOUD_TOP;          break;
48164     case ZAXIS_ISOTHERM_ZERO:         grib_ltype = GRIB1_LTYPE_ISOTHERM0;          break;
48165     case ZAXIS_SNOW:                  grib_ltype = -1;                             break;
48166     case ZAXIS_LAKE_BOTTOM:           grib_ltype = GRIB1_LTYPE_LAKE_BOTTOM;        break;
48167     case ZAXIS_SEDIMENT_BOTTOM:       grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM;    break;
48168     case ZAXIS_SEDIMENT_BOTTOM_TA:    grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM_TA; break;
48169     case ZAXIS_SEDIMENT_BOTTOM_TW:    grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM_TW; break;
48170     case ZAXIS_MIX_LAYER:             grib_ltype = GRIB1_LTYPE_MIX_LAYER;          break;
48171     case ZAXIS_REFERENCE:             grib_ltype = -1;                             break;
48172     }
48173   // clang-format on
48174   return grib_ltype;
48175 }
48176 
48177 
zaxisTypeToGrib2ltype(int zaxistype)48178 int zaxisTypeToGrib2ltype(int zaxistype)
48179 {
48180   int grib_ltype = -1;
48181   // clang-format off
48182   switch (zaxistype)
48183     {
48184     case ZAXIS_SURFACE:               grib_ltype = GRIB2_LTYPE_SURFACE;            break;
48185     case ZAXIS_GENERIC:               grib_ltype = -1;                             break;
48186     case ZAXIS_HYBRID:                grib_ltype = GRIB2_LTYPE_HYBRID;             break;
48187     case ZAXIS_HYBRID_HALF:           grib_ltype = GRIB2_LTYPE_HYBRID;             break;
48188     case ZAXIS_PRESSURE:              grib_ltype = GRIB2_LTYPE_ISOBARIC;           break;
48189     case ZAXIS_HEIGHT:                grib_ltype = GRIB2_LTYPE_HEIGHT;             break;
48190     case ZAXIS_DEPTH_BELOW_SEA:       grib_ltype = GRIB2_LTYPE_SEADEPTH;           break;
48191     case ZAXIS_DEPTH_BELOW_LAND:      grib_ltype = GRIB2_LTYPE_LANDDEPTH;          break;
48192     case ZAXIS_ISENTROPIC:            grib_ltype = GRIB2_LTYPE_ISENTROPIC;         break;
48193     case ZAXIS_TRAJECTORY:            grib_ltype = -1;                             break;
48194     case ZAXIS_ALTITUDE:              grib_ltype = GRIB2_LTYPE_ALTITUDE;           break;
48195     case ZAXIS_SIGMA:                 grib_ltype = GRIB2_LTYPE_SIGMA;              break;
48196     case ZAXIS_MEANSEA:               grib_ltype = GRIB2_LTYPE_MEANSEA;            break;
48197     case ZAXIS_TROPOPAUSE:            grib_ltype = GRIB2_LTYPE_TROPOPAUSE;         break;
48198     case ZAXIS_TOA:                   grib_ltype = GRIB2_LTYPE_TOA;                break;
48199     case ZAXIS_SEA_BOTTOM:            grib_ltype = GRIB2_LTYPE_SEA_BOTTOM;         break;
48200     case ZAXIS_ATMOSPHERE:            grib_ltype = GRIB2_LTYPE_ATMOSPHERE;         break;
48201     case ZAXIS_CLOUD_BASE:            grib_ltype = GRIB2_LTYPE_CLOUD_BASE;         break;
48202     case ZAXIS_CLOUD_TOP:             grib_ltype = GRIB2_LTYPE_CLOUD_TOP;          break;
48203     case ZAXIS_ISOTHERM_ZERO:         grib_ltype = GRIB2_LTYPE_ISOTHERM0;          break;
48204     case ZAXIS_SNOW:                  grib_ltype = GRIB2_LTYPE_SNOW;               break;
48205     case ZAXIS_LAKE_BOTTOM:           grib_ltype = GRIB2_LTYPE_LAKE_BOTTOM;        break;
48206     case ZAXIS_SEDIMENT_BOTTOM:       grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM;    break;
48207     case ZAXIS_SEDIMENT_BOTTOM_TA:    grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM_TA; break;
48208     case ZAXIS_SEDIMENT_BOTTOM_TW:    grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM_TW; break;
48209     case ZAXIS_MIX_LAYER:             grib_ltype = GRIB2_LTYPE_MIX_LAYER;          break;
48210     case ZAXIS_REFERENCE:             grib_ltype = GRIB2_LTYPE_REFERENCE;          break;
48211     }
48212   // clang-format on
48213   return grib_ltype;
48214 }
48215 
48216 
grbBitsPerValue(int datatype)48217 int grbBitsPerValue(int datatype)
48218 {
48219   int bitsPerValue = 16;
48220 
48221   if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
48222     Error("CDI/GRIB library does not support complex numbers!");
48223 
48224   if ( datatype != CDI_UNDEFID )
48225     {
48226       if ( datatype > 0 && datatype <= 32 )
48227 	bitsPerValue = datatype;
48228       else if ( datatype == CDI_DATATYPE_FLT64 )
48229 	bitsPerValue = 24;
48230       else
48231 	bitsPerValue = 16;
48232     }
48233 
48234   return bitsPerValue;
48235 }
48236 
48237 
48238 /*
48239 int grbInqRecord(stream_t * streamptr, int *varID, int *levelID)
48240 {
48241   int status;
48242 
48243   status = cgribexInqRecord(streamptr, varID, levelID);
48244 
48245   return (status);
48246 }
48247 */
48248 
grbDefRecord(stream_t * streamptr)48249 void grbDefRecord(stream_t * streamptr)
48250 {
48251   UNUSED(streamptr);
48252 }
48253 
48254 static
grbScanTimestep1(stream_t * streamptr)48255 int grbScanTimestep1(stream_t * streamptr)
48256 {
48257   int status = CDI_EUFTYPE;
48258 
48259 #ifdef HAVE_LIBCGRIBEX
48260   int filetype  = streamptr->filetype;
48261 
48262   if ( filetype == CDI_FILETYPE_GRB && !CDI_gribapi_grib1 )
48263     status = cgribexScanTimestep1(streamptr);
48264   else
48265 #endif
48266 #ifdef HAVE_LIBGRIB_API
48267     status = gribapiScanTimestep1(streamptr);
48268 #else
48269     Error("Sufficient GRIB support unavailable!");
48270 #endif
48271 
48272   return status;
48273 }
48274 
48275 static
grbScanTimestep2(stream_t * streamptr)48276 int grbScanTimestep2(stream_t * streamptr)
48277 {
48278   int status = CDI_EUFTYPE;
48279 
48280 #ifdef HAVE_LIBCGRIBEX
48281   int filetype = streamptr->filetype;
48282 
48283   if ( filetype == CDI_FILETYPE_GRB && !CDI_gribapi_grib1 )
48284     status = cgribexScanTimestep2(streamptr);
48285   else
48286 #endif
48287 #ifdef HAVE_LIBGRIB_API
48288     status = gribapiScanTimestep2(streamptr);
48289 #else
48290     Error("Sufficient GRIB support unavailable!");
48291 #endif
48292 
48293   return status;
48294 }
48295 
48296 static
grbScanTimestep(stream_t * streamptr)48297 int grbScanTimestep(stream_t * streamptr)
48298 {
48299   int status = CDI_EUFTYPE;
48300 
48301 #ifdef HAVE_LIBCGRIBEX
48302   int filetype  = streamptr->filetype;
48303 
48304   if ( filetype == CDI_FILETYPE_GRB && !CDI_gribapi_grib1 )
48305     status = cgribexScanTimestep(streamptr);
48306   else
48307 #endif
48308 #ifdef HAVE_LIBGRIB_API
48309     status = gribapiScanTimestep(streamptr);
48310 #else
48311     Error("Sufficient GRIB support unavailable!");
48312 #endif
48313 
48314   return status;
48315 }
48316 
48317 
48318 #ifdef HAVE_LIBGRIB
grbInqContents(stream_t * streamptr)48319 int grbInqContents(stream_t * streamptr)
48320 {
48321   streamptr->curTsID = 0;
48322 
48323   int status = grbScanTimestep1(streamptr);
48324   if ( status == 0 && streamptr->ntsteps == -1 ) status = grbScanTimestep2(streamptr);
48325 
48326   int fileID = streamptr->fileID;
48327   fileSetPos(fileID, 0, SEEK_SET);
48328 
48329   return status;
48330 }
48331 #endif
48332 
grbInqTimestep(stream_t * streamptr,int tsID)48333 int grbInqTimestep(stream_t * streamptr, int tsID)
48334 {
48335   if ( tsID == 0 && streamptr->rtsteps == 0 )
48336     Error("Call to cdiInqContents missing!");
48337 
48338   if ( CDI_Debug )
48339     Message("tsid = %d rtsteps = %d", tsID, streamptr->rtsteps);
48340 
48341   int ntsteps = CDI_UNDEFID;
48342   while ( (tsID + 1) > streamptr->rtsteps && ntsteps == CDI_UNDEFID )
48343     {
48344       ntsteps = grbScanTimestep(streamptr);
48345       if ( ntsteps == CDI_EUFSTRUCT )
48346 	{
48347 	  streamptr->ntsteps = streamptr->rtsteps;
48348 	  break;
48349 	}
48350     }
48351 
48352   int nrecs;
48353 
48354   if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
48355     {
48356       nrecs = 0;
48357     }
48358   else
48359     {
48360       streamptr->curTsID = tsID;
48361       nrecs = streamptr->tsteps[tsID].nrecs;
48362     }
48363 
48364   return nrecs;
48365 }
48366 
48367 // used in CDO!!!
streamInqGRIBinfo(int streamID,int * intnum,float * fltnum,off_t * bignum)48368 void streamInqGRIBinfo(int streamID, int *intnum, float *fltnum, off_t *bignum)
48369 {
48370   stream_t *streamptr = stream_to_pointer(streamID);
48371 
48372   int filetype = streamptr->filetype;
48373 
48374   if ( filetype == CDI_FILETYPE_GRB )
48375     {
48376       int tsID     = streamptr->curTsID;
48377       int vrecID   = streamptr->tsteps[tsID].curRecID;
48378       int recID    = streamptr->tsteps[tsID].recIDs[vrecID];
48379       off_t recpos = streamptr->tsteps[tsID].records[recID].position;
48380       int zip      = streamptr->tsteps[tsID].records[recID].zip;
48381 
48382       void *gribbuffer = streamptr->record->buffer;
48383       size_t gribbuffersize = streamptr->record->buffersize;
48384 
48385       if ( zip > 0 )
48386 	Error("Compressed GRIB records unsupported!");
48387       else
48388         grib_info_for_grads(recpos, (long)gribbuffersize, (unsigned char *) gribbuffer, intnum, fltnum, bignum);
48389     }
48390 }
48391 
48392 
grbGetGridtype(int * gridID,size_t gridsize,bool * gridIsRotated,bool * gridIsCurvilinear)48393 int grbGetGridtype(int *gridID, size_t gridsize, bool *gridIsRotated, bool *gridIsCurvilinear)
48394 {
48395   int gridtype = gridInqType(*gridID);
48396 
48397   if ( gridtype == GRID_GENERIC )
48398     {
48399       int xsize = (int) gridInqXsize(*gridID);
48400       int ysize = (int) gridInqYsize(*gridID);
48401 
48402       if ( (ysize ==  32 || ysize ==  48 || ysize ==  64 ||
48403 	    ysize ==  96 || ysize == 160 || ysize == 192 ||
48404 	    ysize == 240 || ysize == 320 || ysize == 384 ||
48405 	    ysize == 480 || ysize == 768 ) &&
48406 	   (xsize == 2*ysize || xsize == 1) )
48407 	{
48408 	  gridtype = GRID_GAUSSIAN;
48409 	}
48410       else if ( gridsize == 1 )
48411 	{
48412 	  gridtype = GRID_LONLAT;
48413 	}
48414       else if ( gridInqXvals(*gridID, NULL) && gridInqYvals(*gridID, NULL) )
48415 	{
48416 	  gridtype = GRID_LONLAT;
48417 	}
48418     }
48419   else if ( gridtype == GRID_CURVILINEAR )
48420     {
48421       int projID = gridInqProj(*gridID);
48422       if ( projID != CDI_UNDEFID && gridInqType(projID) == GRID_PROJECTION )
48423         {
48424           *gridID = projID;
48425           gridtype = GRID_PROJECTION;
48426         }
48427       else
48428         {
48429           static bool lwarning = true;
48430           if ( lwarning && gridsize > 1 )
48431             {
48432               lwarning = false;
48433               Warning("Curvilinear grid is unsupported in GRIB format! Created wrong Grid Description Section!");
48434             }
48435           *gridIsCurvilinear = true;
48436           gridtype = GRID_LONLAT;
48437         }
48438     }
48439 
48440   if ( gridtype == GRID_PROJECTION )
48441     {
48442       int projtype = gridInqProjType(*gridID);
48443       if ( projtype == CDI_PROJ_RLL )
48444         {
48445           gridtype = GRID_LONLAT;
48446           *gridIsRotated = true;
48447         }
48448       else if ( projtype == CDI_PROJ_LCC )
48449         {
48450           gridtype = CDI_PROJ_LCC;
48451         }
48452       else if ( projtype == CDI_PROJ_STERE )
48453         {
48454           gridtype = CDI_PROJ_STERE;
48455         }
48456     }
48457 
48458   return gridtype;
48459 }
48460 
48461 /*
48462  * Local Variables:
48463  * c-file-style: "Java"
48464  * c-basic-offset: 2
48465  * indent-tabs-mode: nil
48466  * show-trailing-whitespace: t
48467  * require-trailing-newline: t
48468  * End:
48469  */
48470 #ifndef _SUBTYPE_H
48471 #define _SUBTYPE_H
48472 
48473 
48474 enum {
48475   /* subtype attributes wrt. TILES */
48476   SUBTYPE_ATT_TILEINDEX                 = 0,
48477   SUBTYPE_ATT_TOTALNO_OF_TILEATTR_PAIRS = 1,
48478   SUBTYPE_ATT_TILE_CLASSIFICATION       = 2,
48479   SUBTYPE_ATT_NUMBER_OF_TILES           = 3,
48480   SUBTYPE_ATT_NUMBER_OF_ATTR            = 4,
48481   SUBTYPE_ATT_TILEATTRIBUTE             = 5,
48482 /* No. of different constants in the enumeration
48483    "subtype_attributes" */
48484   nSubtypeAttributes
48485 };
48486 
48487 
48488 /* Literal constants corresponding to the different constants of the
48489    enumeration "subtype_attributes". */
48490 extern const char * const cdiSubtypeAttributeName[];
48491 
48492 /* Data type specifying an attribute of a subtype (for example an
48493    attribute of a set of TILES) or an attribute of a subtype entry
48494    (for example an attribute of a single TILE). This data type is part
48495    of a linked list. */
48496 struct subtype_attr_t {
48497   int   key, val;                                /* key/value pair */
48498   struct subtype_attr_t* next;                   /* next element in linked list */
48499 };
48500 
48501 
48502 /* Data type specifying a single entry of a subtype, for example a
48503    single TILE in a set of TILES. */
48504 struct subtype_entry_t {
48505   int                     self;                  /* list entry index (0,...,nentries-1) */
48506   struct subtype_entry_t *next;                  /* next node in linked list */
48507 
48508   /* linked list with attributes for this subtype entry, ordered by its key values*/
48509   struct subtype_attr_t  *atts;
48510 };
48511 
48512 
48513 /* Data type specifying a variable subtype, for example a list of
48514    TILES. This can be interpreted as an additional axis like the
48515    vertical axis. */
48516 typedef struct  {
48517   int                     self;                  /* resource handler ID */
48518   int                     subtype;               /* subtype kind: TILES, ... */
48519   int                     nentries;              /* counter: total no. of entries in list */
48520 
48521   /* currently active subtype, e.g. GRIB2 tile index (for example for
48522      stream/vlist accesses): */
48523   int                     active_subtype_index;
48524   struct subtype_entry_t  globals;               /* global attributes */
48525 
48526   /* list of subtype entries, e.g. the list of tiles, ordered by entry->self. */
48527   struct subtype_entry_t *entries;
48528 } subtype_t;
48529 
48530 
48531 
48532 
48533 /* prototypes: allocation and destruction */
48534 void  subtypeAllocate(subtype_t **subtype_ptr2, int subtype);
48535 int   subtypePush(subtype_t *subtype_ptr);
48536 void  subtypeDestroyPtr(void *ptr);
48537 void  subtypeDuplicate(subtype_t *subtype_ptr, subtype_t **dst);
48538 struct subtype_entry_t* subtypeEntryInsert(subtype_t* head);
48539 
48540 /* prototypes: accessing global attributes */
48541 void  subtypePrint(int subtypeID);
48542 void  subtypePrintPtr(subtype_t* subtype_ptr);
48543 void  subtypeDefGlobalDataP(subtype_t *subtype_ptr, int key, int val);
48544 void  subtypeDefGlobalData(int subtypeID, int key, int val);
48545 int   subtypeGetGlobalData(int subtypeID, int key);
48546 int   subtypeGetGlobalDataP(subtype_t *subtype_ptr, int key);
48547 int   subtypeComparePtr(int s1_ID, subtype_t *s2);
48548 
48549 /* prototypes: accessing subtype entries */
48550 void  subtypeDefEntryDataP(struct subtype_entry_t *subtype_entry_ptr, int key, int val);
48551 
48552 
48553 /* prototypes: tile implementations */
48554 void  tilesetInsertP(subtype_t *s1, subtype_t *s2);
48555 
48556 /* Construct a new subtype for a tile set. If a corresponding subtype
48557  * already exists, then we return this subtype ID instead. */
48558 int vlistDefTileSubtype(int vlistID, subtype_t *tiles);
48559 
48560 /* Insert a trivial one-tile-subtype */
48561 int vlistInsertTrivialTileSubtype(int vlistID);
48562 
48563 
48564 #endif
48565 
48566 /*
48567  * Local Variables:
48568  * c-file-style: "Java"
48569  * c-basic-offset: 2
48570  * indent-tabs-mode: nil
48571  * show-trailing-whitespace: t
48572  * require-trailing-newline: t
48573  * End:
48574  */
48575 #ifdef  HAVE_CONFIG_H
48576 #endif
48577 
48578 #ifdef  HAVE_LIBGRIB_API
48579 
48580 
48581 #include <grib_api.h>
48582 
48583 extern int CDI_Inventory_Mode;
48584 
48585 static const var_tile_t dummy_tiles = { 0, -1, -1, -1, -1, -1 };
48586 
48587 
48588 typedef struct {
48589   int param;
48590   int level1;
48591   int level2;
48592   int ltype;
48593   int tsteptype;
48594   size_t gridsize;
48595   char name[32];
48596   VarScanKeys scanKeys;
48597   var_tile_t tiles;
48598 } compvar2_t;
48599 
48600 
48601 static
gribapiGetZaxisType(long editionNumber,int grib_ltype)48602 int gribapiGetZaxisType(long editionNumber, int grib_ltype)
48603 {
48604   return (editionNumber <= 1) ? grib1ltypeToZaxisType(grib_ltype) : grib2ltypeToZaxisType(grib_ltype);
48605 }
48606 
48607 static
getTimeunits(const long unitsOfTime)48608 int getTimeunits(const long unitsOfTime)
48609 {
48610   switch (unitsOfTime)
48611     {
48612     case 13:  return TUNIT_SECOND;
48613     case  0:  return TUNIT_MINUTE;
48614     case  1:  return TUNIT_HOUR;
48615     case 10:  return TUNIT_3HOURS;
48616     case 11:  return TUNIT_6HOURS;
48617     case 12:  return TUNIT_12HOURS;
48618     case  2:  return TUNIT_DAY;
48619     }
48620 
48621   return TUNIT_HOUR;
48622 }
48623 
48624 static
timeunit_factor(const int tu1,const int tu2)48625 double timeunit_factor(const int tu1, const int tu2)
48626 {
48627   if (tu2 == TUNIT_HOUR)
48628     {
48629       switch (tu1)
48630         {
48631         case TUNIT_SECOND:  return 3600;
48632         case TUNIT_MINUTE:  return 60;
48633         case TUNIT_HOUR:    return 1;
48634         case TUNIT_3HOURS:  return 1./3;
48635         case TUNIT_6HOURS:  return 1./6;
48636         case TUNIT_12HOURS: return 1./12;
48637         case TUNIT_DAY:     return 1./24;
48638         }
48639     }
48640 
48641   return 1;
48642 }
48643 
48644 static
gribapiGetTimeUnits(grib_handle * gh)48645 int gribapiGetTimeUnits(grib_handle *gh)
48646 {
48647   long unitsOfTime = -1;
48648   grib_get_long(gh, "indicatorOfUnitOfTimeRange", &unitsOfTime);
48649 
48650   GRIB_CHECK(my_grib_set_long(gh, "stepUnits", unitsOfTime), 0);
48651 
48652   return getTimeunits(unitsOfTime);
48653 }
48654 
48655 static
gribapiGetSteps(grib_handle * gh,int timeunits,int * startStep,int * endStep)48656 void gribapiGetSteps(grib_handle *gh, int timeunits, int *startStep, int *endStep)
48657 {
48658   long unitsOfTime;
48659   int status = grib_get_long(gh, "stepUnits", &unitsOfTime);
48660   const int timeunits2 = (status == 0) ? getTimeunits(unitsOfTime) : timeunits;
48661   //timeunits2 = gribapiGetTimeUnits(gh);
48662 
48663   long lpar;
48664   status = grib_get_long(gh, "forecastTime", &lpar);
48665   if ( status == 0 ) *startStep = (int) lpar;
48666   else
48667     {
48668       status = grib_get_long(gh, "startStep", &lpar);
48669       if ( status == 0 )
48670         *startStep = (int) (((double)lpar * timeunit_factor(timeunits, timeunits2)) + 0.5);
48671     }
48672 
48673   *endStep = *startStep;
48674   status = grib_get_long(gh, "endStep", &lpar);
48675   if ( status == 0 )
48676     *endStep = (int) (((double)lpar * timeunit_factor(timeunits, timeunits2)) + 0.5);
48677   // printf("%d %d %d %d %d %g\n", *startStep, *endStep, lpar, timeunits, timeunits2, timeunit_factor(timeunits, timeunits2));
48678 }
48679 
48680 static
gribapiGetDataDateTime(grib_handle * gh,int64_t * datadate,int * datatime)48681 void gribapiGetDataDateTime(grib_handle *gh, int64_t *datadate, int *datatime)
48682 {
48683   long date;
48684   GRIB_CHECK(grib_get_long(gh, "dataDate", &date), 0);
48685   *datadate = (int64_t) date;
48686   long hour, minute, second;
48687   GRIB_CHECK(grib_get_long(gh, "hour", &hour), 0);
48688   GRIB_CHECK(grib_get_long(gh, "minute", &minute), 0);
48689   GRIB_CHECK(grib_get_long(gh, "second", &second), 0);
48690   *datatime = cdiEncodeTime((int)hour, (int)minute, (int)second);
48691 }
48692 
48693 static
gribapiSetDataDateTime(grib_handle * gh,int64_t datadate,int datatime)48694 void gribapiSetDataDateTime(grib_handle *gh, int64_t datadate, int datatime)
48695 {
48696   GRIB_CHECK(my_grib_set_long(gh, "dataDate", (long)datadate), 0);
48697   int hour, minute, second;
48698   cdiDecodeTime(datatime, &hour, &minute, &second);
48699   GRIB_CHECK(my_grib_set_long(gh, "hour", hour), 0);
48700   GRIB_CHECK(my_grib_set_long(gh, "minute", minute), 0);
48701   GRIB_CHECK(my_grib_set_long(gh, "second", second), 0);
48702 }
48703 
48704 static
gribapiGetTimeUnitFactor(const int timeUnits)48705 int gribapiGetTimeUnitFactor(const int timeUnits)
48706 {
48707   static bool lprint = true;
48708   switch (timeUnits)
48709     {
48710     case TUNIT_SECOND:  return     1;
48711     case TUNIT_MINUTE:  return    60;
48712     case TUNIT_HOUR:    return  3600;
48713     case TUNIT_3HOURS:  return 10800;
48714     case TUNIT_6HOURS:  return 21600;
48715     case TUNIT_12HOURS: return 43200;
48716     case TUNIT_DAY:     return 86400;
48717     default:
48718       if ( lprint )
48719         {
48720           Warning("Time unit %d unsupported", timeUnits);
48721           lprint = false;
48722         }
48723     }
48724 
48725   return 0;
48726 }
48727 
48728 static
gribapiGetValidityDateTime(grib_handle * gh,int64_t * vdate,int * vtime,int64_t * sDate,int * sTime)48729 void gribapiGetValidityDateTime(grib_handle *gh, int64_t *vdate, int *vtime, int64_t *sDate, int *sTime)
48730 {
48731   *sDate = 0;
48732   *sTime = 0;
48733 
48734   long sigofrtime = 3;
48735   if ( gribEditionNumber(gh) > 1 )
48736     GRIB_CHECK(grib_get_long(gh, "significanceOfReferenceTime", &sigofrtime), 0);
48737   else
48738     GRIB_CHECK(grib_get_long(gh, "timeRangeIndicator", &sigofrtime), 0);
48739 
48740   if ( sigofrtime == 3 ) //XXX: This looks like a bug to me, because timeRangeIndicator == 3 does not seem to have the same meaning as significanceOfReferenceTime == 3. I would recommend replacing this condition with `if(!gribapiTimeIsFC())`.
48741     {
48742       gribapiGetDataDateTime(gh, vdate, vtime);
48743     }
48744   else
48745     {
48746       int64_t rdate;
48747       int rtime;
48748       gribapiGetDataDateTime(gh, &rdate, &rtime);
48749 
48750       const int timeUnits = gribapiGetTimeUnits(gh);
48751       int startStep = 0, endStep = 0;
48752       gribapiGetSteps(gh, timeUnits, &startStep, &endStep);
48753 
48754       {
48755 	int ryear, rmonth, rday, rhour, rminute, rsecond;
48756 	cdiDecodeDate(rdate, &ryear, &rmonth, &rday);
48757 	cdiDecodeTime(rtime, &rhour, &rminute, &rsecond);
48758 
48759         if ( rday > 0 )
48760           {
48761             extern int CGRIBEX_grib_calendar;
48762             int64_t julday;
48763             int secofday;
48764             encode_caldaysec(CGRIBEX_grib_calendar, ryear, rmonth, rday, rhour, rminute, rsecond, &julday, &secofday);
48765 
48766             int64_t time_unit_factor = gribapiGetTimeUnitFactor(timeUnits);
48767 
48768             //if (startStep > 0)
48769               {
48770                 int64_t julday_x = julday;
48771                 int secofday_x = secofday;
48772                 julday_add_seconds(time_unit_factor * startStep, &julday_x, &secofday_x);
48773                 decode_caldaysec(CGRIBEX_grib_calendar, julday_x, secofday_x, &ryear, &rmonth, &rday, &rhour, &rminute, &rsecond);
48774                 *sDate = cdiEncodeDate(ryear, rmonth, rday);
48775                 *sTime = cdiEncodeTime(rhour, rminute, 0);
48776               }
48777 
48778             julday_add_seconds(time_unit_factor * endStep, &julday, &secofday);
48779             decode_caldaysec(CGRIBEX_grib_calendar, julday, secofday, &ryear, &rmonth, &rday, &rhour, &rminute, &rsecond);
48780           }
48781 
48782 	*vdate = cdiEncodeDate(ryear, rmonth, rday);
48783 	*vtime = cdiEncodeTime(rhour, rminute, rsecond);
48784       }
48785     }
48786 }
48787 
48788 static
grib1GetLevel(grib_handle * gh,int * leveltype,int * lbounds,int * level1,int * level2)48789 void grib1GetLevel(grib_handle *gh, int *leveltype, int *lbounds, int *level1, int *level2)
48790 {
48791   *leveltype = 0;
48792   *lbounds   = 0;
48793   *level1    = 0;
48794   *level2    = 0;
48795 
48796   long lpar;
48797   if ( !grib_get_long(gh, "indicatorOfTypeOfLevel", &lpar) )       //1 byte
48798     {
48799       *leveltype = (int) lpar;
48800 
48801       switch (*leveltype)
48802 	{
48803 	case GRIB1_LTYPE_SIGMA_LAYER:
48804 	case GRIB1_LTYPE_HYBRID_LAYER:
48805 	case GRIB1_LTYPE_LANDDEPTH_LAYER:
48806 	  { *lbounds = 1; break; }
48807 	}
48808 
48809       if ( *lbounds )
48810 	{
48811 	  GRIB_CHECK(grib_get_long(gh, "topLevel", &lpar), 0);  //1 byte
48812           if (lpar == GRIB_MISSING_LONG) lpar = 0;
48813 	  *level1 = (int)lpar;
48814 	  GRIB_CHECK(grib_get_long(gh, "bottomLevel", &lpar), 0);       //1 byte
48815           if (lpar == GRIB_MISSING_LONG) lpar = 0;
48816  	  *level2 = (int)lpar;
48817 	}
48818       else
48819 	{
48820           double dlevel;
48821 	  GRIB_CHECK(grib_get_double(gh, "level", &dlevel), 0); //2 byte
48822 	  if ( *leveltype == GRIB1_LTYPE_ISOBARIC ) dlevel *= 100;
48823 	  if ( dlevel < -2.e9 || dlevel > 2.e9 ) dlevel = 0;
48824 	  if ( *leveltype == GRIB1_LTYPE_99 || *leveltype == GRIB1_LTYPE_ISOBARIC_PA ) *leveltype = GRIB1_LTYPE_ISOBARIC;
48825 
48826 	  *level1 = (int) dlevel;
48827 	  *level2 = 0;
48828 	}
48829     }
48830 }
48831 
48832 static
grib2ScaleFactor(const long factor)48833 double grib2ScaleFactor(const long factor)
48834 {
48835   switch(factor)
48836     {
48837       case GRIB_MISSING_LONG: return 1;
48838       case -9: return 1000000000;
48839       case -8: return 100000000;
48840       case -7: return 10000000;
48841       case -6: return 1000000;
48842       case -5: return 100000;
48843       case -4: return 10000;
48844       case -3: return 1000;
48845       case -2: return 100;
48846       case -1: return 10;
48847       case  0: return 1;
48848       case  1: return 0.1;
48849       case  2: return 0.01;
48850       case  3: return 0.001;
48851       case  4: return 0.0001;
48852       case  5: return 0.00001;
48853       case  6: return 0.000001;
48854       case  7: return 0.0000001;
48855       case  8: return 0.00000001;
48856       case  9: return 0.000000001;
48857       default: return 0;
48858     }
48859 }
48860 
48861 static
calcLevel(int level_sf,long factor,long level)48862 int calcLevel(int level_sf, long factor, long level)
48863 {
48864   double result = 0;
48865   if (level != GRIB_MISSING_LONG) result = (double)level*grib2ScaleFactor(factor);
48866   if (level_sf) result *= level_sf;
48867   return (int)result;
48868 }
48869 
48870 static
grib2GetLevel(grib_handle * gh,int * leveltype1,int * leveltype2,int * lbounds,int * level1,int * level2,int * level_sf,int * level_unit)48871 void grib2GetLevel(grib_handle *gh, int *leveltype1, int *leveltype2, int *lbounds, int *level1,
48872                    int *level2, int *level_sf, int *level_unit)
48873 {
48874   *leveltype1 = 0;
48875   *leveltype2 = -1;
48876   *lbounds    = 0;
48877   *level1     = 0;
48878   *level2     = 0;
48879   *level_sf   = 0;
48880   *level_unit = 0;
48881 
48882   long lpar;
48883   int status = grib_get_long(gh, "typeOfFirstFixedSurface", &lpar); //1 byte
48884   if ( status == 0 )
48885     {
48886       *leveltype1 = (int) lpar;
48887 
48888       status = grib_get_long(gh, "typeOfSecondFixedSurface", &lpar); //1 byte
48889       /* FIXME: assert(lpar >= INT_MIN && lpar <= INT_MAX) */
48890       if ( status == 0 ) *leveltype2 = (int)lpar;
48891 
48892       if ( *leveltype1 != 255 && *leveltype2 != 255 && *leveltype2 > 0 ) *lbounds = 1;
48893       switch (*leveltype1)
48894         {
48895           case GRIB2_LTYPE_REFERENCE:
48896             if(*leveltype2 == 1) *lbounds = 0;
48897             break;
48898 
48899           case GRIB2_LTYPE_LANDDEPTH:
48900             *level_sf = 1000;
48901             *level_unit = CDI_UNIT_M;
48902             break;
48903 
48904           case GRIB2_LTYPE_ISOBARIC:
48905             *level_sf = 1000;
48906             *level_unit = CDI_UNIT_PA;
48907             break;
48908 
48909           case GRIB2_LTYPE_SIGMA:
48910             *level_sf = 1000;
48911             *level_unit = 0;
48912             break;
48913         }
48914 
48915       long factor, llevel;
48916       GRIB_CHECK(grib_get_long(gh, "scaleFactorOfFirstFixedSurface", &factor), 0);      //1 byte
48917       GRIB_CHECK(grib_get_long(gh, "scaledValueOfFirstFixedSurface", &llevel), 0);      //4 byte
48918       *level1 = calcLevel(*level_sf, factor, llevel);
48919 
48920       if ( *lbounds )
48921         {
48922           GRIB_CHECK(grib_get_long(gh, "scaleFactorOfSecondFixedSurface", &factor), 0); //1 byte
48923           GRIB_CHECK(grib_get_long(gh, "scaledValueOfSecondFixedSurface", &llevel), 0); //4 byte
48924           *level2 = calcLevel(*level_sf, factor, llevel);
48925         }
48926     }
48927 }
48928 
48929 static
gribGetLevel(grib_handle * gh,int * leveltype1,int * leveltype2,int * lbounds,int * level1,int * level2,int * level_sf,int * level_unit,var_tile_t * tiles)48930 void gribGetLevel(grib_handle *gh, int* leveltype1, int* leveltype2, int* lbounds, int* level1, int* level2, int* level_sf, int* level_unit, var_tile_t* tiles)
48931 {
48932   if ( gribEditionNumber(gh) <= 1 )
48933     {
48934       grib1GetLevel(gh, leveltype1, lbounds, level1, level2);
48935       *leveltype2 = -1;
48936       *level_sf = 0;
48937       *level_unit = 0;
48938     }
48939   else
48940     {
48941       grib2GetLevel(gh, leveltype1, leveltype2, lbounds, level1, level2, level_sf, level_unit);
48942 
48943       /* read in tiles attributes (if there are any) */
48944       tiles->tileindex = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_TILEINDEX], 0);
48945       tiles->totalno_of_tileattr_pairs = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_TOTALNO_OF_TILEATTR_PAIRS], -1);
48946       tiles->tileClassification = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_TILE_CLASSIFICATION], -1);
48947       tiles->numberOfTiles = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_NUMBER_OF_TILES], -1);
48948       tiles->numberOfAttributes = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_NUMBER_OF_ATTR], -1);
48949       tiles->attribute = (int)gribGetLongDefault(gh, cdiSubtypeAttributeName[SUBTYPE_ATT_TILEATTRIBUTE], -1);
48950     }
48951 }
48952 
48953 static
gribapiGetString(grib_handle * gh,const char * key,char * string,size_t length)48954 void gribapiGetString(grib_handle *gh, const char *key, char *string, size_t length)
48955 {
48956   string[0] = 0;
48957 
48958   int ret = grib_get_string(gh, key, string, &length);
48959   if (ret != 0)
48960     {
48961       fprintf(stderr, "grib_get_string(gh, \"%s\", ...) failed!\n", key);
48962       GRIB_CHECK(ret, 0);
48963     }
48964   if      ( length == 8 && memcmp(string, "unknown", length) == 0 ) string[0] = 0;
48965   else if ( length == 2 && memcmp(string, "~", length)       == 0 ) string[0] = 0;
48966 }
48967 
48968 static
gribapiGetEnsembleInfo(grib_handle * gh,long * typeOfEnsembleForecast,long * numberOfForecastsInEnsemble,long * perturbationNumber)48969 int gribapiGetEnsembleInfo(grib_handle *gh, long *typeOfEnsembleForecast, long *numberOfForecastsInEnsemble, long *perturbationNumber)
48970 {
48971   int status = 0;
48972   if (grib_get_long(gh, "typeOfEnsembleForecast", typeOfEnsembleForecast) == 0)
48973     {
48974       GRIB_CHECK(grib_get_long(gh, "numberOfForecastsInEnsemble", numberOfForecastsInEnsemble), 0);
48975       GRIB_CHECK(grib_get_long(gh, "perturbationNumber", perturbationNumber), 0);
48976       if (*perturbationNumber > 0) status = 1;
48977     }
48978 
48979   if (status == 0)
48980     {
48981       *typeOfEnsembleForecast = 0;
48982       *perturbationNumber = 0;
48983       *numberOfForecastsInEnsemble = 0;
48984     }
48985 
48986   return status;
48987 }
48988 
48989 static
gribapiGetScanKeys(grib_handle * gh)48990 VarScanKeys gribapiGetScanKeys(grib_handle *gh)
48991 {
48992   VarScanKeys scanKeys;
48993   varScanKeysInit(&scanKeys);
48994 
48995   long typeOfEnsembleForecast = 0, numberOfForecastsInEnsemble = 0, perturbationNumber = 0;
48996   gribapiGetEnsembleInfo(gh, &typeOfEnsembleForecast, &numberOfForecastsInEnsemble, &perturbationNumber);
48997   scanKeys.perturbationNumber = (short)perturbationNumber;
48998 
48999   long typeOfGeneratingProcess = 0;
49000   if (grib_get_long(gh, "typeOfGeneratingProcess", &typeOfGeneratingProcess) == 0)
49001     scanKeys.typeOfGeneratingProcess = (short)typeOfGeneratingProcess;
49002 
49003   return scanKeys;
49004 }
49005 
49006 static
gribapiGetNameKeys(grib_handle * gh,int varID)49007 void gribapiGetNameKeys(grib_handle *gh, int varID)
49008 {
49009   char string[CDI_MAX_NAME];
49010 
49011   size_t vlen = CDI_MAX_NAME;
49012   gribapiGetString(gh, "name", string, vlen); // longname
49013   if (string[0]) varDefKeyString(varID, CDI_KEY_LONGNAME, string);
49014 
49015   gribapiGetString(gh, "units", string, vlen);
49016   if (string[0]) varDefKeyString(varID, CDI_KEY_UNITS, string);
49017 
49018   string[0] = 0;
49019   const int status = grib_get_string(gh, "cfName", string, &vlen);
49020   if ( status != 0 || vlen <= 1 || strncmp(string, "unknown", 7) == 0 ) string[0] = 0;
49021   if (string[0]) varDefKeyString(varID, CDI_KEY_STDNAME, string);
49022 }
49023 
49024 static
gribapiGetKeys(grib_handle * gh,int varID)49025 void gribapiGetKeys(grib_handle *gh, int varID)
49026 {
49027   long tablesVersion = 0;
49028   if ( grib_get_long(gh, "tablesVersion", &tablesVersion) == 0 )
49029     varDefKeyInt(varID, CDI_KEY_TABLESVERSION, (int) tablesVersion);
49030 
49031   long localTablesVersion = 0;
49032   if ( grib_get_long(gh, "localTablesVersion", &localTablesVersion) == 0 )
49033     varDefKeyInt(varID, CDI_KEY_LOCALTABLESVERSION, (int) localTablesVersion);
49034 
49035   long typeOfGeneratingProcess = 0;
49036   if ( grib_get_long(gh, "typeOfGeneratingProcess", &typeOfGeneratingProcess) == 0 )
49037     varDefKeyInt(varID, CDI_KEY_TYPEOFGENERATINGPROCESS, (int) typeOfGeneratingProcess);
49038 
49039   long productDefinitionTemplate = 0;
49040   if ( grib_get_long(gh, "productDefinitionTemplateNumber", &productDefinitionTemplate) == 0 )
49041     varDefKeyInt(varID, CDI_KEY_PRODUCTDEFINITIONTEMPLATE, (int) productDefinitionTemplate);
49042 
49043   long typeOfProcessedData = 0;
49044   if ( grib_get_long(gh, "typeOfProcessedData", &typeOfProcessedData) == 0 )
49045     varDefKeyInt(varID, CDI_KEY_TYPEOFPROCESSEDDATA, (int) typeOfProcessedData);
49046 
49047   long shapeOfTheEarth = 0;
49048   if ( grib_get_long(gh, "shapeOfTheEarth", &shapeOfTheEarth) == 0 )
49049     varDefKeyInt(varID, CDI_KEY_SHAPEOFTHEEARTH, (int) shapeOfTheEarth);
49050 
49051   long backgroundProcess = 0;
49052   if ( grib_get_long(gh, "backgroundProcess", &backgroundProcess) == 0 )
49053     varDefKeyInt(varID, CDI_KEY_BACKGROUNDPROCESS, (int) backgroundProcess);
49054 
49055   long typeOfTimeIncrement = 0;
49056   if ( grib_get_long(gh, "typeOfTimeIncrement", &typeOfTimeIncrement) == 0 )
49057     varDefKeyInt(varID, CDI_KEY_TYPEOFTIMEINCREMENT, (int) typeOfTimeIncrement);
49058   /*
49059   long constituentType = 0;
49060   if ( grib_get_long(gh, "constituentType", &constituentType) == 0 )
49061     varDefKeyInt(varID, CDI_KEY_CONSTITUENTTYPE, (int) constituentType);
49062   */
49063 
49064   /*
49065     Get the ensemble Info from the grib-2 Tables and update the intermediate datastructure.
49066     Further update to the "vlist" is handled in the same way as for GRIB-1 by "cdi_generate_vars"
49067   */
49068   long typeOfEnsembleForecast = 0, numberOfForecastsInEnsemble = 0, perturbationNumber = 0;
49069   gribapiGetEnsembleInfo(gh, &typeOfEnsembleForecast, &numberOfForecastsInEnsemble, &perturbationNumber);
49070   if ( perturbationNumber > 0 )
49071     {
49072       varDefKeyInt(varID, CDI_KEY_TYPEOFENSEMBLEFORECAST, (int) typeOfEnsembleForecast);
49073       varDefKeyInt(varID, CDI_KEY_NUMBEROFFORECASTSINENSEMBLE, (int) numberOfForecastsInEnsemble);
49074       varDefKeyInt(varID, CDI_KEY_PERTURBATIONNUMBER, (int) perturbationNumber);
49075     }
49076 
49077   long section2Length = 0;
49078   int status = grib_get_long(gh, "section2Length", &section2Length);
49079   if (status == 0 && section2Length > 0)
49080     {
49081       long grib2LocalSectionNumber;
49082       long mpimType, mpimClass, mpimUser;
49083       status = grib_get_long(gh, "grib2LocalSectionNumber", &grib2LocalSectionNumber);
49084       if (status == 0)
49085         {
49086           size_t section2PaddingLength = 0;
49087           status = grib_get_size(gh, "section2Padding", &section2PaddingLength);
49088           if (status == 0 && section2PaddingLength > 0)
49089             {
49090               varDefKeyInt(varID, CDI_KEY_GRIB2LOCALSECTIONNUMBER, (int) grib2LocalSectionNumber);
49091               varDefKeyInt(varID, CDI_KEY_SECTION2PADDINGLENGTH, (int) section2PaddingLength);
49092               unsigned char *section2Padding = (unsigned char*) Malloc(section2PaddingLength);
49093               grib_get_bytes(gh, "section2Padding", section2Padding, &section2PaddingLength);
49094               varDefKeyBytes(varID, CDI_KEY_SECTION2PADDING, section2Padding, (int)section2PaddingLength);
49095               Free(section2Padding);
49096             }
49097           else if ( grib_get_long(gh, "mpimType", &mpimType) == 0 &&
49098                     grib_get_long(gh, "mpimClass", &mpimClass) == 0 &&
49099                     grib_get_long(gh, "mpimUser", &mpimUser) == 0)
49100             {
49101               varDefKeyInt(varID, CDI_KEY_MPIMTYPE, mpimType);
49102               varDefKeyInt(varID, CDI_KEY_MPIMCLASS, mpimClass);
49103               varDefKeyInt(varID, CDI_KEY_MPIMUSER, mpimUser);
49104 
49105               size_t revNumLen = 20;
49106               unsigned char revNumber[revNumLen];
49107               if ( grib_get_bytes(gh, "revNumber", revNumber, &revNumLen) == 0 )
49108                 varDefKeyBytes(varID, CDI_KEY_REVNUMBER, revNumber, (int)revNumLen);
49109 
49110               long revStatus;
49111               grib_get_long(gh, "revStatus", &revStatus);
49112               varDefKeyInt(varID, CDI_KEY_REVSTATUS, revStatus);
49113             }
49114         }
49115     }
49116 }
49117 
49118 static
gribapiDefProjRLL(grib_handle * gh,int gridID)49119 void gribapiDefProjRLL(grib_handle *gh, int gridID)
49120 {
49121   double xpole = 0, ypole = 0, angle = 0;
49122   grib_get_double(gh, "latitudeOfSouthernPoleInDegrees",  &ypole);
49123   grib_get_double(gh, "longitudeOfSouthernPoleInDegrees", &xpole);
49124   grib_get_double(gh, "angleOfRotation", &angle);
49125   xpole -= 180;
49126   if ( fabs(ypole) > 0 ) ypole = -ypole; // change from south to north pole
49127   if ( fabs(angle) > 0 ) angle = -angle;
49128 
49129   gridDefParamRLL(gridID, xpole, ypole, angle);
49130 }
49131 
49132 static
shapeOfTheEarthToRadius(long shapeOfTheEarth)49133 double shapeOfTheEarthToRadius(long shapeOfTheEarth)
49134 {
49135   switch (shapeOfTheEarth)
49136     {
49137     case 0:  return 6367470.;
49138     case 2:  return 6378160.;
49139     case 6:  return 6371229.;
49140     case 8:  return 6371200.;
49141     }
49142   return 6367470.;
49143 }
49144 
49145 static
gribapiDefProjLCC(grib_handle * gh,int gridID)49146 void gribapiDefProjLCC(grib_handle *gh, int gridID)
49147 {
49148   long shapeOfTheEarth;
49149   grib_get_long(gh, "shapeOfTheEarth", &shapeOfTheEarth);
49150   const double a = shapeOfTheEarthToRadius(shapeOfTheEarth);
49151   const double rf = (shapeOfTheEarth == 2) ? 297.0 : 0;
49152   double lon_0, lat_1, lat_2, xval_0, yval_0;
49153   long projflag = 0;
49154   grib_get_double(gh, "longitudeOfFirstGridPointInDegrees", &xval_0);
49155   grib_get_double(gh, "latitudeOfFirstGridPointInDegrees", &yval_0);
49156   grib_get_double(gh, "LoVInDegrees", &lon_0);
49157   grib_get_double(gh, "Latin1InDegrees", &lat_1);
49158   grib_get_double(gh, "Latin2InDegrees", &lat_2);
49159   grib_get_long(gh, "projectionCentreFlag", &projflag);
49160   bool lsouth = gribbyte_get_bit((int)projflag, 1);
49161   if ( lsouth ) { lat_1 = -lat_1; lat_2 = -lat_2; }
49162 
49163   double lat_0 = lat_2;
49164   double x_0 = CDI_Grid_Missval;
49165   double y_0 = CDI_Grid_Missval;
49166 
49167   if ( proj_lonlat_to_lcc_func )
49168     {
49169       x_0 = xval_0; y_0 = yval_0;
49170       proj_lonlat_to_lcc_func(CDI_Grid_Missval, lon_0, lat_0, lat_1, lat_2, a, rf, (size_t)1, &x_0, &y_0);
49171       if ( IS_NOT_EQUAL(x_0, CDI_Grid_Missval) && IS_NOT_EQUAL(y_0, CDI_Grid_Missval) )
49172         { x_0 = -x_0; y_0 = -y_0; }
49173     }
49174 
49175   gridDefParamLCC(gridID, CDI_Grid_Missval, lon_0, lat_0, lat_1, lat_2, a, rf, xval_0, yval_0, x_0, y_0);
49176 }
49177 
49178 
49179 static
gribapiDefProjSTERE(grib_handle * gh,int gridID)49180 void gribapiDefProjSTERE(grib_handle *gh, int gridID)
49181 {
49182   long shapeOfTheEarth;
49183   grib_get_long(gh, "shapeOfTheEarth", &shapeOfTheEarth);
49184   const double a = shapeOfTheEarthToRadius(shapeOfTheEarth);
49185 
49186   double lon_0, lat_ts, xval_0, yval_0;
49187   grib_get_double(gh, "longitudeOfFirstGridPointInDegrees", &xval_0);
49188   grib_get_double(gh, "latitudeOfFirstGridPointInDegrees", &yval_0);
49189   grib_get_double(gh, "LaDInDegrees", &lat_ts);
49190   grib_get_double(gh, "orientationOfTheGridInDegrees", &lon_0);
49191 
49192   long southPoleOnProjectionPlane;
49193   grib_get_long(gh, "southPoleOnProjectionPlane", &southPoleOnProjectionPlane);
49194   double lat_0 = southPoleOnProjectionPlane ? -90 : 90;
49195 
49196   double x_0 = CDI_Grid_Missval;
49197   double y_0 = CDI_Grid_Missval;
49198 
49199   if ( proj_lonlat_to_stere_func )
49200     {
49201       x_0 = xval_0; y_0 = yval_0;
49202       proj_lonlat_to_stere_func(CDI_Grid_Missval, lon_0, lat_ts, lat_0, a, (size_t)1, &x_0, &y_0);
49203       if ( IS_NOT_EQUAL(x_0, CDI_Grid_Missval) && IS_NOT_EQUAL(y_0, CDI_Grid_Missval) )
49204         { x_0 = -x_0; y_0 = -y_0; }
49205     }
49206 
49207   gridDefParamSTERE(gridID, CDI_Grid_Missval, lon_0, lat_ts, lat_0, a, xval_0, yval_0, x_0, y_0);
49208 }
49209 
49210 static
gribapiAddRecord(stream_t * streamptr,int param,grib_handle * gh,size_t recsize,off_t position,int datatype,int comptype,const char * varname,int leveltype1,int leveltype2,int lbounds,int level1,int level2,int level_sf,int level_unit,VarScanKeys * scanKeys,const var_tile_t * tiles,int lread_additional_keys)49211 void gribapiAddRecord(stream_t *streamptr, int param, grib_handle *gh,
49212                       size_t recsize, off_t position, int datatype, int comptype, const char *varname,
49213                       int leveltype1, int leveltype2, int lbounds, int level1, int level2, int level_sf, int level_unit,
49214                       VarScanKeys *scanKeys, const var_tile_t *tiles, int lread_additional_keys)
49215 {
49216   const int vlistID = streamptr->vlistID;
49217   const int tsID    = streamptr->curTsID;
49218   const int recID   = recordNewEntry(streamptr, tsID);
49219   record_t *record = &streamptr->tsteps[tsID].records[recID];
49220 
49221   const int tsteptype = gribapiGetTsteptype(gh);
49222   int numavg = 0;
49223 
49224   // fprintf(stderr, "param %d %d %d %d\n", param, level1, level2, leveltype1);
49225 
49226   record->size      = recsize;
49227   record->position  = position;
49228   record->param     = param;
49229   record->ilevel    = level1;
49230   record->ilevel2   = level2;
49231   record->ltype     = leveltype1;
49232   record->tsteptype = (short)tsteptype;
49233   record->gridsize  = gribapiGetGridsize(gh);
49234   record->scanKeys  = *scanKeys;
49235   record->tiles     = tiles ? *tiles : dummy_tiles;
49236 
49237   strncpy(record->varname, varname, sizeof(record->varname)-1);
49238   record->varname[sizeof(record->varname) - 1] = 0;
49239 
49240   grid_t *grid = (grid_t *)Malloc(sizeof(*grid));
49241   const bool uvRelativeToGrid = gribapiGetGrid(gh, grid);
49242 
49243   struct addIfNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
49244   const int gridID = gridAdded.Id;
49245   if      ( !gridAdded.isNew ) Free(grid);
49246   else if ( grid->projtype == CDI_PROJ_RLL ) gribapiDefProjRLL(gh, gridID);
49247   else if ( grid->projtype == CDI_PROJ_LCC ) gribapiDefProjLCC(gh, gridID);
49248   else if ( grid->projtype == CDI_PROJ_STERE ) gribapiDefProjSTERE(gh, gridID);
49249 
49250   const int zaxistype = gribapiGetZaxisType(gribEditionNumber(gh), leveltype1);
49251 
49252   switch (zaxistype)
49253     {
49254     case ZAXIS_HYBRID:
49255     case ZAXIS_HYBRID_HALF:
49256       {
49257         long lpar;
49258         GRIB_CHECK(grib_get_long(gh, "NV", &lpar), 0);
49259         /* FIXME: assert(lpar >= 0) */
49260         const size_t vctsize = (size_t)lpar;
49261         if ( vctsize > 0 )
49262           {
49263             double *vctptr = (double *) Malloc(vctsize*sizeof(double));
49264             size_t dummy = vctsize;
49265             GRIB_CHECK(grib_get_double_array(gh, "pv", vctptr, &dummy), 0);
49266             varDefVCT(vctsize, vctptr);
49267             Free(vctptr);
49268           }
49269         break;
49270       }
49271     case ZAXIS_REFERENCE:
49272       {
49273         unsigned char uuid[CDI_UUID_SIZE];
49274         long lpar;
49275         GRIB_CHECK(grib_get_long(gh, "NV", &lpar), 0);
49276         if ( lpar != 6 ) fprintf(stderr, "Warning ...\n");
49277         GRIB_CHECK(grib_get_long(gh, "nlev", &lpar), 0);
49278         int nhlev = (int)lpar;
49279         GRIB_CHECK(grib_get_long(gh, "numberOfVGridUsed", &lpar), 0);
49280         int nvgrid = (int)lpar;
49281         size_t len = (size_t)CDI_UUID_SIZE;
49282         memset(uuid, 0, CDI_UUID_SIZE);
49283         GRIB_CHECK(grib_get_bytes(gh, "uuidOfVGrid", uuid, &len), 0);
49284         varDefZAxisReference(nhlev, nvgrid, uuid);
49285         break;
49286       }
49287     }
49288 
49289   // if ( datatype > 32 ) datatype = CDI_DATATYPE_PACK32;
49290   if ( datatype <  0 ) datatype = CDI_DATATYPE_PACK;
49291 
49292   // add the previously read record data to the (intermediate) list of records
49293   int tile_index = 0;
49294   int varID = 0, levelID = 0;
49295   varAddRecord(recID, param, gridID, zaxistype, lbounds, level1, level2, level_sf, level_unit,
49296 	       datatype, &varID, &levelID, tsteptype, leveltype1, leveltype2,
49297 	       varname, scanKeys, tiles, &tile_index);
49298 
49299   record->varID = (short)varID;
49300   record->levelID = (short)levelID;
49301 
49302   varDefCompType(varID, comptype);
49303 
49304   if ( uvRelativeToGrid ) varDefKeyInt(varID, CDI_KEY_UVRELATIVETOGRID, 1);
49305 
49306   if (varname[0]) gribapiGetNameKeys(gh, varID);
49307   gribapiGetKeys(gh, varID);
49308 
49309   if (lread_additional_keys)
49310     {
49311       long   lval;
49312       double dval;
49313       for ( int i = 0; i < cdiNAdditionalGRIBKeys; i++ )
49314         {
49315           // note: if the key is not defined, we do not throw an error!
49316           if ( grib_get_long(gh, cdiAdditionalGRIBKeys[i], &lval) == 0 )
49317             varDefOptGribInt(varID, tile_index, lval, cdiAdditionalGRIBKeys[i]);
49318           if ( grib_get_double(gh, cdiAdditionalGRIBKeys[i], &dval) == 0 )
49319             varDefOptGribDbl(varID, tile_index, dval, cdiAdditionalGRIBKeys[i]);
49320         }
49321     }
49322 
49323   if ( varInqInst(varID) == CDI_UNDEFID )
49324     {
49325       long center, subcenter;
49326       GRIB_CHECK(grib_get_long(gh, "centre", &center), 0);
49327       GRIB_CHECK(grib_get_long(gh, "subCentre", &subcenter), 0);
49328       int instID = institutInq((int)center, (int)subcenter, NULL, NULL);
49329       if ( instID == CDI_UNDEFID )
49330 	instID = institutDef((int)center, (int)subcenter, NULL, NULL);
49331       varDefInst(varID, instID);
49332     }
49333 
49334   if ( varInqModel(varID) == CDI_UNDEFID )
49335     {
49336       long processID;
49337       if ( grib_get_long(gh, "generatingProcessIdentifier", &processID) == 0 )
49338 	{
49339           /* FIXME: assert(processID >= INT_MIN && processID <= INT_MAX) */
49340 	  int modelID = modelInq(varInqInst(varID), (int)processID, NULL);
49341 	  if ( modelID == CDI_UNDEFID )
49342 	    modelID = modelDef(varInqInst(varID), (int)processID, NULL);
49343 	  varDefModel(varID, modelID);
49344 	}
49345     }
49346 
49347   if ( varInqTable(varID) == CDI_UNDEFID )
49348     {
49349       int pdis, pcat, pnum;
49350       cdiDecodeParam(param, &pnum, &pcat, &pdis);
49351 
49352       if ( pdis == 255 )
49353 	{
49354 	  int tabnum = pcat;
49355 	  int tableID = tableInq(varInqModel(varID), tabnum, NULL);
49356 	  if ( tableID == CDI_UNDEFID )
49357 	    tableID = tableDef(varInqModel(varID), tabnum, NULL);
49358 	  varDefTable(varID, tableID);
49359 	}
49360     }
49361 
49362   streamptr->tsteps[tsID].nallrecs++;
49363   streamptr->nrecs++;
49364 
49365   if ( CDI_Debug )
49366     Message("varID = %d  param = %d  zaxistype = %d  gridID = %d  levelID = %d",
49367 	    varID, param, zaxistype, gridID, levelID);
49368 }
49369 
49370 static
gribapiVarSet(int param,int level1,int level2,int leveltype,int tsteptype,size_t gridsize,char * name,VarScanKeys scanKeys,var_tile_t tiles_data)49371 compvar2_t gribapiVarSet(int param, int level1, int level2, int leveltype, int tsteptype,
49372                          size_t gridsize, char *name, VarScanKeys scanKeys, var_tile_t tiles_data)
49373 {
49374   compvar2_t compVar;
49375   memset(&compVar, 0, sizeof(compvar2_t));
49376   const size_t maxlen = sizeof(compVar.name);
49377   size_t len = strlen(name);
49378   if ( len > maxlen ) len = maxlen;
49379 
49380   compVar.param     = param;
49381   compVar.level1    = level1;
49382   compVar.level2    = level2;
49383   compVar.ltype     = leveltype;
49384   compVar.tsteptype = tsteptype;
49385   compVar.gridsize  = gridsize;
49386   //memset(compVar.name, 0, maxlen);
49387   memcpy(compVar.name, name, len);
49388   compVar.scanKeys = scanKeys;
49389   compVar.tiles = tiles_data;
49390 
49391   return compVar;
49392 }
49393 
49394 static
gribapiVarCompare(compvar2_t compVar,record_t record,int flag)49395 int gribapiVarCompare(compvar2_t compVar, record_t record, int flag)
49396 {
49397   compvar2_t compVar0;
49398   memset(&compVar0, 0, sizeof(compvar2_t));
49399   compVar0.param     = record.param;
49400   compVar0.level1    = record.ilevel;
49401   compVar0.level2    = record.ilevel2;
49402   compVar0.ltype     = record.ltype;
49403   compVar0.tsteptype = record.tsteptype;
49404   compVar0.gridsize  = record.gridsize;
49405   memcpy(compVar0.name, record.varname, sizeof(compVar.name));
49406 
49407   if ( flag == 0 )
49408     {
49409       if ( compVar0.tsteptype == TSTEP_INSTANT  && compVar.tsteptype == TSTEP_INSTANT3 ) compVar0.tsteptype = TSTEP_INSTANT3;
49410       if ( compVar0.tsteptype == TSTEP_INSTANT3 && compVar.tsteptype == TSTEP_INSTANT  ) compVar0.tsteptype = TSTEP_INSTANT;
49411     }
49412 
49413   compVar0.scanKeys = record.scanKeys;
49414   compVar0.tiles = record.tiles;
49415 
49416   return memcmp(&compVar0, &compVar, sizeof(compvar2_t));
49417 }
49418 
49419 static
gribapiGetDiskRepresentation(size_t recsize,size_t * buffersize,void ** gribbuffer,int * outDatatype,int * outCompressionType)49420 grib_handle *gribapiGetDiskRepresentation(size_t recsize, size_t *buffersize, void **gribbuffer, int *outDatatype, int *outCompressionType)
49421 {
49422   const int gribversion = (int)((char*)*gribbuffer)[7];
49423 
49424   if ( gribversion <= 1 ) *outCompressionType = grbDecompress(recsize, buffersize, gribbuffer);
49425 
49426   grib_handle *gh = grib_handle_new_from_message(NULL, *gribbuffer, recsize);
49427 
49428   bool lieee = false;
49429 
49430   if ( gribversion > 1 )
49431     {
49432       size_t len = 256;
49433       char typeOfPacking[256];
49434       if ( grib_get_string(gh, "packingType", typeOfPacking, &len) == 0 )
49435         {
49436           // fprintf(stderr, "packingType %zu %s\n", len, typeOfPacking);
49437           if      ( strncmp(typeOfPacking, "grid_jpeg", len) == 0 ) *outCompressionType = CDI_COMPRESS_JPEG;
49438           else if ( strncmp(typeOfPacking, "grid_ccsds", len) == 0 ) *outCompressionType = CDI_COMPRESS_AEC;
49439           else if ( strncmp(typeOfPacking, "grid_ieee", len) == 0 ) lieee = true;
49440         }
49441     }
49442 
49443   if ( lieee )
49444     {
49445       long precision;
49446       const int status = grib_get_long(gh, "precision", &precision);
49447       *outDatatype = (status == 0 && precision == 1) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64;
49448     }
49449   else
49450     {
49451       *outDatatype = CDI_DATATYPE_PACK;
49452       long bitsPerValue;
49453       if ( grib_get_long(gh, "bitsPerValue", &bitsPerValue) == 0 )
49454         {
49455           if ( bitsPerValue > 0 && bitsPerValue <= 32 ) *outDatatype = (int)bitsPerValue;
49456         }
49457     }
49458 
49459   return gh;
49460 }
49461 
49462 typedef enum { CHECKTIME_OK, CHECKTIME_SKIP, CHECKTIME_STOP, CHECKTIME_INCONSISTENT } checkTimeResult;
49463 
checkTime(stream_t * streamptr,compvar2_t compVar,const DateTime * verificationTime,const DateTime * expectedVTime)49464 static checkTimeResult checkTime(stream_t* streamptr, compvar2_t compVar, const DateTime* verificationTime, const DateTime* expectedVTime) {
49465   // First determine whether the current record exists already.
49466   int recID = 0;
49467   for ( ; recID < streamptr->nrecs; recID++ )
49468     {
49469       if ( gribapiVarCompare(compVar, streamptr->tsteps[0].records[recID], 1) == 0 ) break;
49470     }
49471   const bool recordExists = recID < streamptr->nrecs;
49472 
49473   // Then we need to know whether the verification time is consistent.
49474   const bool consistentTime = !memcmp(verificationTime, expectedVTime, sizeof(*verificationTime));
49475 
49476   // Finally, we make a decision.
49477   if ( CDI_Inventory_Mode == 1 )
49478     {
49479       if ( recordExists ) return CHECKTIME_STOP;
49480       if ( !consistentTime ) return CHECKTIME_INCONSISTENT;
49481     }
49482   else
49483     {
49484       if ( !consistentTime ) return CHECKTIME_STOP;
49485       if ( recordExists ) return CHECKTIME_SKIP;
49486     }
49487 
49488   return CHECKTIME_OK;
49489 }
49490 
49491 #define gribWarning(text, nrecs, timestep, varname, param, level1, level2) do \
49492   { \
49493     char paramstr[32]; \
49494     cdiParamToString(param, paramstr, sizeof(paramstr)); \
49495     Warning("Record %2d (name=%s id=%s lev1=%d lev2=%d) timestep %d: %s", nrecs, varname, paramstr, level1, level2, timestep, text); \
49496   } \
49497 while(0)
49498 
gribapiScanTimestep1(stream_t * streamptr)49499 int gribapiScanTimestep1(stream_t * streamptr)
49500 {
49501   off_t recpos = 0;
49502   void *gribbuffer = NULL;
49503   size_t buffersize = 0;
49504   DateTime datetime0 = { .date = 10101, .time = 0 };
49505   int nrecs_scanned = 0;        //Only used for debug output.
49506   bool warn_time = true;
49507   int fcast = 0;
49508   grib_handle *gh = NULL;
49509 
49510   streamptr->curTsID = 0;
49511 
49512   const int tsID  = tstepsNewEntry(streamptr);
49513   if ( tsID != 0 ) Error("Internal problem! tstepsNewEntry returns %d", tsID);
49514 
49515   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
49516 
49517   const int fileID = streamptr->fileID;
49518 
49519   unsigned nrecs = 0;
49520   while ( true )
49521     {
49522       int level1 = 0, level2 = 0;
49523       const size_t recsize = gribGetSize(fileID);
49524       recpos = fileGetPos(fileID);
49525 
49526       if ( recsize == 0 )
49527         {
49528           streamptr->ntsteps = 1;
49529           break;
49530         }
49531 
49532       ensureBufferSize(recsize, &buffersize, &gribbuffer);
49533 
49534       size_t readsize = recsize;
49535       // Search for next 'GRIB', read the following record, and position file offset after it.
49536       if (gribRead(fileID, gribbuffer, &readsize)) break;
49537 
49538       int datatype, comptype = 0;
49539       gh = gribapiGetDiskRepresentation(recsize, &buffersize, &gribbuffer, &datatype, &comptype);
49540 
49541       nrecs_scanned++;
49542       GRIB_CHECK(my_grib_set_double(gh, "missingValue", CDI_Default_Missval), 0);
49543 
49544       const int param = gribapiGetParam(gh);
49545       int leveltype1 = -1, leveltype2 = -1, lbounds, level_sf, level_unit;
49546       var_tile_t tiles = dummy_tiles;
49547       gribGetLevel(gh, &leveltype1, &leveltype2, &lbounds, &level1, &level2, &level_sf, &level_unit, &tiles);
49548 
49549       char varname[256];
49550       gribapiGetString(gh, "shortName", varname, sizeof(varname));
49551 
49552       int64_t vdate, sdate;
49553       int vtime, stime;
49554       gribapiGetValidityDateTime(gh, &vdate, &vtime, &sdate, &stime);
49555       DateTime datetime = { .date = vdate, .time = vtime };
49556 
49557       VarScanKeys scanKeys = gribapiGetScanKeys(gh);
49558 
49559       if ( nrecs == 0 )
49560         {
49561           datetime0 = datetime;
49562           gribapiGetDataDateTime(gh, &(taxis->rdate), &(taxis->rtime));
49563           fcast = gribapiTimeIsFC(gh);
49564           if ( fcast ) taxis->unit = gribapiGetTimeUnits(gh);
49565           taxis->fdate = taxis->rdate;
49566           taxis->ftime = taxis->rtime;
49567           taxis->sdate = sdate;
49568           taxis->stime = stime;
49569           taxis->vdate = vdate;
49570           taxis->vtime = vtime;
49571         }
49572       else
49573         {
49574           const int tsteptype = gribapiGetTsteptype(gh);
49575           const size_t gridsize = gribapiGetGridsize(gh);
49576           checkTimeResult result = checkTime(streamptr,
49577                                              gribapiVarSet(param, level1, level2, leveltype1, tsteptype, gridsize, varname, scanKeys, tiles),
49578                                              &datetime, &datetime0);
49579           if ( result == CHECKTIME_STOP )
49580             {
49581               break;
49582             }
49583           else if ( result == CHECKTIME_SKIP )
49584             {
49585               gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, varname, param, level1, level2);
49586               continue;
49587             }
49588           else if ( result == CHECKTIME_INCONSISTENT && warn_time )
49589             {
49590               gribWarning("Inconsistent verification time!", nrecs_scanned, tsID+1, varname, param, level1, level2);
49591               warn_time = false;
49592             }
49593           assert(result == CHECKTIME_OK || result == CHECKTIME_INCONSISTENT);
49594         }
49595 
49596       nrecs++;
49597 
49598       if ( CDI_Debug )
49599         {
49600           char paramstr[32];
49601           cdiParamToString(param, paramstr, sizeof(paramstr));
49602           Message("%4u %8d name=%s id=%s ltype=%d lev1=%d lev2=%d vdate=%lld vtime=%d",
49603                   nrecs, (int)recpos, varname, paramstr, leveltype1, level1, level2, vdate, vtime);
49604         }
49605 
49606       var_tile_t *ptiles = memcmp(&tiles, &dummy_tiles, sizeof(var_tile_t)) ? &tiles : NULL;
49607       gribapiAddRecord(streamptr, param, gh, recsize, recpos, datatype, comptype, varname,
49608                        leveltype1, leveltype2, lbounds, level1, level2, level_sf, level_unit, &scanKeys, ptiles, 1);
49609 
49610       grib_handle_delete(gh);
49611       gh = NULL;
49612     }
49613 
49614   if ( gh ) grib_handle_delete(gh);
49615 
49616   streamptr->rtsteps = 1;
49617 
49618   if ( nrecs == 0 ) return CDI_EUFSTRUCT;
49619 
49620   cdi_generate_vars(streamptr);
49621 
49622   taxis->type = fcast ? TAXIS_RELATIVE : TAXIS_ABSOLUTE;
49623   int taxisID = taxisCreate(taxis->type);
49624   // printf("1: %d %6d  %d %6d  %d %6d\n", taxis->rdate, taxis->rtime, taxis->sdate, taxis->stime, taxis->vdate, taxis->vtime);
49625 
49626   const int vlistID = streamptr->vlistID;
49627   vlistDefTaxis(vlistID, taxisID);
49628 
49629   streamScanResizeRecords1(streamptr);
49630 
49631   streamptr->record->buffer     = gribbuffer;
49632   streamptr->record->buffersize = buffersize;
49633 
49634   streamScanTsFixNtsteps(streamptr, recpos);
49635   streamScanTimeConstAdjust(streamptr, taxis);
49636 
49637   return 0;
49638 }
49639 
49640 
gribapiScanTimestep2(stream_t * streamptr)49641 int gribapiScanTimestep2(stream_t * streamptr)
49642 {
49643   int rstatus = 0;
49644   off_t recpos = 0;
49645   DateTime datetime0 = { LONG_MIN, LONG_MIN };
49646   // int gridID;
49647   int recID;
49648   grib_handle *gh = NULL;
49649 
49650   streamptr->curTsID = 1;
49651 
49652   const int fileID  = streamptr->fileID;
49653   const int vlistID = streamptr->vlistID;
49654 
49655   void *gribbuffer = streamptr->record->buffer;
49656   size_t buffersize = streamptr->record->buffersize;
49657 
49658   int tsID = streamptr->rtsteps;
49659   if ( tsID != 1 ) Error("Internal problem! unexpected timestep %d", tsID+1);
49660 
49661   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
49662 
49663   fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
49664 
49665   cdi_create_records(streamptr, tsID);
49666   record_t *records = streamptr->tsteps[tsID].records;
49667 
49668   const int nrecords = streamScanInitRecords2(streamptr);
49669 
49670   int nrecs_scanned = nrecords; //Only used for debug output
49671   int rindex = 0;
49672   while ( true )
49673     {
49674       if ( rindex > nrecords ) break;
49675 
49676       const size_t recsize = gribGetSize(fileID);
49677       recpos = fileGetPos(fileID);
49678       if ( recsize == 0 )
49679 	{
49680 	  streamptr->ntsteps = 2;
49681 	  break;
49682 	}
49683 
49684       ensureBufferSize(recsize, &buffersize, &gribbuffer);
49685 
49686       size_t readsize = recsize;
49687       if (gribRead(fileID, gribbuffer, &readsize)) break;
49688 
49689       grbDecompress(recsize, &buffersize, &gribbuffer);
49690 
49691       nrecs_scanned++;
49692       gh = grib_handle_new_from_message(NULL, gribbuffer, recsize);
49693       GRIB_CHECK(my_grib_set_double(gh, "missingValue", CDI_Default_Missval), 0);
49694 
49695       const int param = gribapiGetParam(gh);
49696       int level1 = 0, level2 = 0, leveltype1, leveltype2, lbounds, level_sf, level_unit;
49697       var_tile_t tiles = dummy_tiles;
49698       gribGetLevel(gh, &leveltype1, &leveltype2, &lbounds, &level1, &level2, &level_sf, &level_unit, &tiles);
49699 
49700       char varname[256];
49701       gribapiGetString(gh, "shortName", varname, sizeof(varname));
49702 
49703       int64_t vdate, sdate;
49704       int vtime, stime;
49705       gribapiGetValidityDateTime(gh, &vdate, &vtime, &sdate, &stime);
49706       DateTime datetime = { .date = vdate, .time = vtime };
49707 
49708       if ( rindex == 0 )
49709 	{
49710           datetime0 = datetime;
49711           const int taxisID = vlistInqTaxis(vlistID);
49712 	  if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
49713 	    {
49714 	      taxis->type = TAXIS_RELATIVE;
49715 	      taxis->unit = gribapiGetTimeUnits(gh);
49716               gribapiGetDataDateTime(gh, &(taxis->rdate), &(taxis->rtime));
49717 	    }
49718 	  else
49719 	    {
49720 	      taxis->type = TAXIS_ABSOLUTE;
49721 	    }
49722           taxis->fdate = taxis->rdate;
49723           taxis->ftime = taxis->rtime;
49724 	  taxis->vdate = vdate;
49725 	  taxis->vtime = vtime;
49726 	  taxis->sdate = sdate;
49727 	  taxis->stime = stime;
49728           // printf("2: %d %6d  %d %6d  %d %6d\n", taxis->rdate, taxis->rtime, taxis->sdate, taxis->stime, taxis->vdate, taxis->vtime);
49729 	}
49730 
49731       VarScanKeys scanKeys = gribapiGetScanKeys(gh);
49732 
49733       const int tsteptype = gribapiGetTsteptype(gh);
49734       const size_t gridsize = gribapiGetGridsize(gh);
49735       compvar2_t compVar = gribapiVarSet(param, level1, level2, leveltype1, tsteptype, gridsize, varname, scanKeys, tiles);
49736 
49737       for ( recID = 0; recID < nrecords; recID++ )
49738         if ( gribapiVarCompare(compVar, records[recID], 0) == 0 ) break;
49739 
49740       if ( recID == nrecords )
49741 	{
49742           if ( CDI_Inventory_Mode == 1 )
49743             {
49744               gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, varname, param, level1, level2);
49745               return CDI_EUFSTRUCT;
49746             }
49747           else
49748             {
49749               gribWarning("Parameter not defined at timestep 1, skipped!", nrecs_scanned, tsID+1, varname, param, level1, level2);
49750               continue;
49751             }
49752         }
49753 
49754       if ( records[recID].used )
49755         {
49756           if ( CDI_Inventory_Mode == 1 ) break;
49757           else
49758 	    {
49759 	      if ( datetimeDiffer(datetime, datetime0) ) break;
49760 
49761               gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, varname, param, level1, level2);
49762 	      continue;
49763 	    }
49764 	}
49765 
49766       records[recID].used = true;
49767       streamptr->tsteps[tsID].recIDs[rindex] = recID;
49768 
49769       if ( CDI_Debug )
49770         {
49771           char paramstr[32];
49772           cdiParamToString(param, paramstr, sizeof(paramstr));
49773           Message("%4d %8d name=%s id=%s ltype=%d lev1=%d lev2=%d vdate=%lld vtime=%d",
49774                   nrecs_scanned, (int)recpos, varname, paramstr, leveltype1, level1, level2, vdate, vtime);
49775         }
49776 
49777       if ( gribapiVarCompare(compVar, records[recID], 0) != 0 )
49778 	{
49779 	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
49780 		  tsID, recID, records[recID].param, param, records[recID].ilevel, level1);
49781 	  return CDI_EUFSTRUCT;
49782 	}
49783 
49784       records[recID].position = recpos;
49785       records[recID].size = recsize;
49786 
49787       const int varID = records[recID].varID;
49788 
49789       if ( tsteptype != vlistInqVarTsteptype(vlistID, varID) )
49790 	vlistDefVarTsteptype(vlistID, varID, tsteptype);
49791 
49792       grib_handle_delete(gh);
49793       gh = NULL;
49794 
49795       rindex++;
49796     }
49797 
49798   if ( gh ) grib_handle_delete(gh);
49799 
49800   int nrecs = 0;
49801   for ( recID = 0; recID < nrecords; recID++ )
49802     {
49803       if ( ! records[recID].used )
49804 	{
49805 	  vlistDefVarTimetype(vlistID, records[recID].varID, TIME_CONSTANT);
49806 	}
49807       else
49808 	{
49809 	  nrecs++;
49810 	}
49811     }
49812   streamptr->tsteps[tsID].nrecs = nrecs;
49813 
49814   streamptr->rtsteps = 2;
49815 
49816   streamScanTsFixNtsteps(streamptr, recpos);
49817 
49818   streamptr->record->buffer     = gribbuffer;
49819   streamptr->record->buffersize = buffersize;
49820 
49821   return rstatus;
49822 }
49823 
49824 
gribapiScanTimestep(stream_t * streamptr)49825 int gribapiScanTimestep(stream_t * streamptr)
49826 {
49827   int vrecID, recID = -1;
49828   int nrecs = 0;
49829   int vlistID = streamptr->vlistID;
49830 
49831   int tsID  = streamptr->rtsteps;
49832   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
49833 
49834   if ( streamptr->tsteps[tsID].recordSize == 0 )
49835     {
49836       void *gribbuffer = streamptr->record->buffer;
49837       size_t buffersize = streamptr->record->buffersize;
49838 
49839       cdi_create_records(streamptr, tsID);
49840       record_t *records = streamptr->tsteps[tsID].records;
49841 
49842       nrecs = streamScanInitRecords(streamptr, tsID);
49843 
49844       const int fileID = streamptr->fileID;
49845 
49846       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
49847 
49848       int nrecs_scanned = streamptr->tsteps[0].nallrecs + streamptr->tsteps[1].nrecs*(tsID-1);    //Only used for debug output.
49849       int rindex = 0;
49850       off_t recpos = 0;
49851       DateTime datetime0 = { LONG_MIN, LONG_MIN };
49852       grib_handle *gh = NULL;
49853       char varname[256];
49854       while ( true )
49855 	{
49856 	  if ( rindex > nrecs ) break;
49857 
49858 	  const size_t recsize = gribGetSize(fileID);
49859 	  recpos = fileGetPos(fileID);
49860 	  if ( recsize == 0 )
49861 	    {
49862 	      streamptr->ntsteps = streamptr->rtsteps + 1;
49863 	      break;
49864 	    }
49865 
49866 	  if ( rindex >= nrecs ) break;
49867 
49868           ensureBufferSize(recsize, &buffersize, &gribbuffer);
49869 
49870 	  size_t readsize = recsize;
49871 	  if (gribRead(fileID, gribbuffer, &readsize))
49872 	    {
49873 	      Warning("Inconsistent timestep %d (GRIB record %d/%d)!", tsID+1, rindex+1,
49874 		      streamptr->tsteps[tsID].recordSize);
49875 	      break;
49876 	    }
49877 
49878           grbDecompress(recsize, &buffersize, &gribbuffer);
49879 
49880           nrecs_scanned++;
49881 	  gh = grib_handle_new_from_message(NULL, gribbuffer, recsize);
49882 	  GRIB_CHECK(my_grib_set_double(gh, "missingValue", CDI_Default_Missval), 0);
49883 
49884           const int param = gribapiGetParam(gh);
49885           int level1 = 0, level2 = 0, leveltype1, leveltype2 = -1, lbounds, level_sf, level_unit;
49886           var_tile_t tiles = dummy_tiles;
49887           gribGetLevel(gh, &leveltype1, &leveltype2, &lbounds, &level1, &level2, &level_sf, &level_unit, &tiles);
49888 
49889 	  gribapiGetString(gh, "shortName", varname, sizeof(varname));
49890 
49891           int64_t vdate, sdate;
49892           int vtime, stime;
49893 	  gribapiGetValidityDateTime(gh, &vdate, &vtime, &sdate, &stime);
49894           DateTime datetime = { .date  = vdate, .time  = vtime };
49895 
49896 	  if ( rindex == nrecs ) break;
49897 
49898 	  if ( rindex == 0 )
49899 	    {
49900               datetime0 = datetime;
49901               const int taxisID = vlistInqTaxis(vlistID);
49902 	      if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
49903 		{
49904 		  taxis->type = TAXIS_RELATIVE;
49905 		  taxis->unit = gribapiGetTimeUnits(gh);
49906                   gribapiGetDataDateTime(gh, &(taxis->rdate), &(taxis->rtime));
49907 		}
49908 	      else
49909 		{
49910 		  taxis->type = TAXIS_ABSOLUTE;
49911 		}
49912               taxis->fdate = taxis->rdate;
49913               taxis->ftime = taxis->rtime;
49914 	      taxis->vdate = vdate;
49915 	      taxis->vtime = vtime;
49916 	      taxis->sdate = sdate;
49917 	      taxis->stime = stime;
49918               // printf("n: %d %6d  %d %6d  %d %6d\n", taxis->rdate, taxis->rtime, taxis->sdate, taxis->stime, taxis->vdate, taxis->vtime);
49919 	    }
49920 
49921           VarScanKeys scanKeys = gribapiGetScanKeys(gh);
49922 
49923           const int tsteptype = gribapiGetTsteptype(gh);
49924           const size_t gridsize = gribapiGetGridsize(gh);
49925           compvar2_t compVar = gribapiVarSet(param, level1, level2, leveltype1, tsteptype, gridsize, varname, scanKeys, tiles);
49926 
49927 	  for ( vrecID = 0; vrecID < nrecs; vrecID++ )
49928 	    {
49929 	      recID = streamptr->tsteps[1].recIDs[vrecID];
49930 	      if ( gribapiVarCompare(compVar, records[recID], 0) == 0 ) break;
49931 	    }
49932 
49933 	  if ( vrecID == nrecs )
49934 	    {
49935               if ( CDI_Inventory_Mode == 1 )
49936                 {
49937                   gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, varname, param, level1, level2);
49938                   return CDI_EUFSTRUCT;
49939                 }
49940               else
49941                 {
49942                   gribWarning("Parameter not defined at timestep 1, skipped!", nrecs_scanned, tsID+1, varname, param, level1, level2);
49943                   continue;
49944                 }
49945 	    }
49946 
49947 	  if ( CDI_Inventory_Mode != 1 )
49948 	    {
49949 	      if ( records[recID].used )
49950 		{
49951 		  if ( datetimeDiffer(datetime, datetime0) ) break;
49952 
49953 		  if ( CDI_Debug )
49954                     gribWarning("Parameter already exist, skipped!", nrecs_scanned, tsID+1, varname, param, level1, level2);
49955 
49956 		  continue;
49957 		}
49958 	    }
49959 
49960           records[recID].used = true;
49961           streamptr->tsteps[tsID].recIDs[rindex] = recID;
49962 
49963 	  if ( CDI_Debug )
49964 	    Message("%4d %8d %4d %8d %8lld %6d", rindex+1, (int)recpos, param, level1, vdate, vtime);
49965 
49966 	  if ( gribapiVarCompare(compVar, records[recID], 0) != 0 )
49967 	    {
49968 	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
49969 		      tsID, recID, records[recID].param, param, records[recID].ilevel, level1);
49970 	      Error("Invalid, unsupported or inconsistent record structure");
49971 	    }
49972 
49973 	  records[recID].position = recpos;
49974 	  records[recID].size = recsize;
49975 
49976 	  if ( CDI_Debug )
49977 	    Message("%4d %8d %4d %8d %8lld %6d", rindex, (int)recpos, param, level1, vdate, vtime);
49978 
49979           grib_handle_delete(gh);
49980 	  gh = NULL;
49981 
49982 	  rindex++;
49983 	}
49984 
49985       if ( gh ) grib_handle_delete(gh);
49986 
49987       for ( vrecID = 0; vrecID < nrecs; vrecID++ )
49988 	{
49989 	  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
49990 	  if ( ! records[recID].used ) break;
49991 	}
49992 
49993       if ( vrecID < nrecs )
49994 	{
49995 	  gribWarning("Paramameter not found!", nrecs_scanned, tsID+1, varname, records[recID].param,
49996                       records[recID].ilevel, records[recID].ilevel2);
49997 	  return CDI_EUFSTRUCT;
49998 	}
49999 
50000       streamptr->rtsteps++;
50001 
50002       if ( streamptr->ntsteps != streamptr->rtsteps )
50003 	{
50004 	  tsID = tstepsNewEntry(streamptr);
50005 	  if ( tsID != streamptr->rtsteps )
50006 	    Error("Internal error. tsID = %d", tsID);
50007 
50008 	  streamptr->tsteps[tsID-1].next   = true;
50009 	  streamptr->tsteps[tsID].position = recpos;
50010 	}
50011 
50012       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
50013       streamptr->tsteps[tsID].position = recpos;
50014 
50015       streamptr->record->buffer     = gribbuffer;
50016       streamptr->record->buffersize = buffersize;
50017     }
50018 
50019   if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
50020     {
50021       Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
50022       streamptr->ntsteps = tsID;
50023     }
50024 
50025   return streamptr->ntsteps;
50026 }
50027 
50028 #ifdef gribWarning
50029 #undef gribWarning
50030 #endif
50031 
gribapiDecode(void * gribbuffer,size_t gribsize,double * data,size_t gridsize,int unreduced,size_t * nmiss,double missval)50032 int gribapiDecode(void *gribbuffer, size_t gribsize, double *data, size_t gridsize,
50033 		  int unreduced, size_t *nmiss, double missval)
50034 {
50035   int status = 0;
50036 
50037   if ( unreduced )
50038     {
50039       static bool lwarn = true;
50040       if ( lwarn )
50041 	{
50042 	  lwarn = false;
50043 	  Warning("Conversion of gaussian reduced grids unsupported!");
50044 	}
50045     }
50046 
50047   size_t recsize = (size_t)gribsize;
50048   grib_handle *gh = grib_handle_new_from_message(NULL, gribbuffer, recsize);
50049   GRIB_CHECK(my_grib_set_double(gh, "missingValue", missval), 0);
50050 
50051   // get the size of the values array
50052   size_t datasize;
50053   GRIB_CHECK(grib_get_size(gh, "values", &datasize), 0);
50054   // long numberOfPoints;
50055   // GRIB_CHECK(grib_get_long(gh, "numberOfPoints", &numberOfPoints), 0);
50056   // printf("values_size = %d  numberOfPoints = %ld\n", datasize, numberOfPoints);
50057 
50058   if ( gridsize != datasize )
50059     Error("Internal problem: gridsize(%zu) != datasize(%zu)!", gridsize, datasize);
50060   size_t dummy = datasize;
50061   GRIB_CHECK(grib_get_double_array(gh, "values", data, &dummy), 0);
50062 
50063   long lpar;
50064   GRIB_CHECK(grib_get_long(gh, "gridDefinitionTemplateNumber", &lpar), 0);
50065   int gridtype = (int) lpar;
50066 
50067   *nmiss = 0;
50068   if ( gridtype < 50 || gridtype > 53 )
50069     {
50070       GRIB_CHECK(grib_get_long(gh, "numberOfMissing", &lpar), 0);
50071       *nmiss = (int) lpar;
50072       // printf("gridtype %d, nmiss %d\n", gridtype, nmiss);
50073     }
50074 
50075   grib_handle_delete(gh);
50076 
50077   return status;
50078 }
50079 
50080 
50081 static
gribapiDefInstitut(grib_handle * gh,int vlistID,int varID)50082 void gribapiDefInstitut(grib_handle *gh, int vlistID, int varID)
50083 {
50084   int instID = (vlistInqInstitut(vlistID) != CDI_UNDEFID) ?
50085     vlistInqInstitut(vlistID) : vlistInqVarInstitut(vlistID, varID);
50086 
50087   if ( instID != CDI_UNDEFID )
50088     {
50089       long center    = institutInqCenter(instID);
50090       long subcenter = institutInqSubcenter(instID);
50091 
50092       long center0, subcenter0;
50093       GRIB_CHECK(grib_get_long(gh, "centre", &center0), 0);
50094       GRIB_CHECK(grib_get_long(gh, "subCentre", &subcenter0), 0);
50095 
50096       if ( center != center0 )
50097 	GRIB_CHECK(my_grib_set_long(gh, "centre", center), 0);
50098       if ( subcenter != subcenter0 )
50099 	GRIB_CHECK(my_grib_set_long(gh, "subCentre", subcenter), 0);
50100     }
50101 
50102   int status;
50103   int centre, subCentre;
50104   status = cdiInqKeyInt(vlistID, CDI_GLOBAL, CDI_KEY_CENTRE, &centre);
50105   if ( status == 0 ) grib_set_long(gh, "centre", centre);
50106   status = cdiInqKeyInt(vlistID, CDI_GLOBAL, CDI_KEY_SUBCENTRE, &subCentre);
50107   if ( status == 0 ) grib_set_long(gh, "subCentre", subCentre);
50108 
50109   status = cdiInqKeyInt(vlistID, varID, CDI_KEY_CENTRE, &centre);
50110   if ( status == 0 ) grib_set_long(gh, "centre", centre);
50111   status = cdiInqKeyInt(vlistID, varID, CDI_KEY_SUBCENTRE, &subCentre);
50112   if ( status == 0 ) grib_set_long(gh, "subCentre", subCentre);
50113 }
50114 
50115 static
gribapiDefModel(grib_handle * gh,int vlistID,int varID)50116 void gribapiDefModel(grib_handle *gh, int vlistID, int varID)
50117 {
50118   int modelID = (vlistInqModel(vlistID) != CDI_UNDEFID) ?
50119     vlistInqModel(vlistID) : vlistInqVarModel(vlistID, varID);
50120 
50121   if ( modelID != CDI_UNDEFID )
50122     GRIB_CHECK(my_grib_set_long(gh, "generatingProcessIdentifier", modelInqGribID(modelID)), 0);
50123 }
50124 
50125 static
gribapiDefParam(int editionNumber,grib_handle * gh,int param,const char * name,const char * stdname)50126 void gribapiDefParam(int editionNumber, grib_handle *gh, int param, const char *name, const char *stdname)
50127 {
50128   bool ldefined = false;
50129 
50130   int pdis, pcat, pnum;
50131   cdiDecodeParam(param, &pnum, &pcat, &pdis);
50132 
50133   if ( pnum < 0 )
50134     {
50135       size_t len = strlen(stdname);
50136       if ( len )
50137         {
50138           int status = my_grib_set_string(gh, "cfName", stdname, &len);
50139           if ( status == 0 ) ldefined = true;
50140           else Warning("grib_api: No match for cfName=%s", stdname);
50141         }
50142 
50143       if ( ldefined == false )
50144         {
50145           len = strlen(name);
50146           int status = my_grib_set_string(gh, "shortName", name, &len);
50147           if ( status == 0 ) ldefined = true;
50148           else Warning("grib_api: No match for shortName=%s", name);
50149         }
50150     }
50151 
50152   if ( ldefined == false )
50153     {
50154       if ( pnum < 0 ) pnum = -pnum;
50155 
50156       if ( pnum > 255 )
50157         {
50158           static bool lwarn_pnum = true;
50159           if ( lwarn_pnum )
50160             {
50161               Warning("Parameter number %d out of range (1-255), set to %d!", pnum, pnum%256);
50162               lwarn_pnum = false;
50163             }
50164           pnum = pnum%256;
50165         }
50166 
50167       if ( editionNumber <= 1 )
50168 	{
50169           static bool lwarn_pdis = true;
50170 	  if ( pdis != 255 && lwarn_pdis )
50171 	    {
50172 	      char paramstr[32];
50173 	      cdiParamToString(param, paramstr, sizeof(paramstr));
50174 	      Warning("Can't convert GRIB2 parameter ID (%s) to GRIB1, set to %d.%d!", paramstr, pnum, pcat);
50175               lwarn_pdis = false;
50176 	    }
50177 
50178 	  GRIB_CHECK(my_grib_set_long(gh, "table2Version",        pcat), 0);
50179 	  GRIB_CHECK(my_grib_set_long(gh, "indicatorOfParameter", pnum), 0);
50180 	}
50181       else
50182 	{
50183 	  GRIB_CHECK(my_grib_set_long(gh, "discipline",        pdis), 0);
50184 	  GRIB_CHECK(my_grib_set_long(gh, "parameterCategory", pcat), 0);
50185 	  GRIB_CHECK(my_grib_set_long(gh, "parameterNumber",   pnum), 0);
50186 	}
50187     }
50188 
50189   // printf("param: %d.%d.%d %s\n", pnum, pcat, pdis, name);
50190 }
50191 
50192 static
getTimeunitFactor(const int timeunit)50193 int getTimeunitFactor(const int timeunit)
50194 {
50195   switch (timeunit)
50196     {
50197     case TUNIT_SECOND:  return     1;
50198     case TUNIT_MINUTE:  return    60;
50199     case TUNIT_HOUR:    return  3600;
50200     case TUNIT_3HOURS:  return 10800;
50201     case TUNIT_6HOURS:  return 21600;
50202     case TUNIT_12HOURS: return 43200;
50203     case TUNIT_DAY:     return 86400;
50204     }
50205 
50206   return 3600;
50207 }
50208 
50209 static
grib2ProDefTempHasStatisticalDef(const int proDefTempNum)50210 int grib2ProDefTempHasStatisticalDef(const int proDefTempNum)
50211 {
50212   switch (proDefTempNum)
50213     {
50214       case 8:
50215       case 9:
50216       case 10:
50217       case 11:
50218       case 12:
50219       case 13:
50220       case 14:
50221       case 34:
50222       case 42:
50223       case 43:
50224       case 46:
50225       case 47:
50226       case 61:
50227       case 91:
50228       case 1001:
50229       case 1101:
50230       case 40034:
50231         return 1;
50232     }
50233 
50234   return 0;
50235 }
50236 
50237 static
getUnitsOfTime(const int timeunit)50238 int getUnitsOfTime(const int timeunit)
50239 {
50240   switch (timeunit)
50241     {
50242     case TUNIT_SECOND:  return 13;
50243     case TUNIT_MINUTE:  return  0;
50244     case TUNIT_HOUR:    return  1;
50245     case TUNIT_3HOURS:  return 10;
50246     case TUNIT_6HOURS:  return 11;
50247     case TUNIT_12HOURS: return 12;
50248     case TUNIT_DAY:     return  2;
50249     }
50250 
50251   return 1;
50252 }
50253 
50254 static
gribapiDefStepUnits(int editionNumber,grib_handle * gh,int timeunit,int proDefTempNum,int gcinit)50255 void gribapiDefStepUnits(int editionNumber, grib_handle *gh, int timeunit, int proDefTempNum, int gcinit)
50256 {
50257   if ( !gcinit )
50258     {
50259       long unitsOfTime = getUnitsOfTime(timeunit);
50260 
50261       grib_set_long(gh, "stepUnits", unitsOfTime);
50262       if ( editionNumber == 1 )
50263         {
50264           grib_set_long(gh, "unitOfTimeRange", unitsOfTime);
50265         }
50266       else if ( grib2ProDefTempHasStatisticalDef(proDefTempNum) )
50267         {
50268           grib_set_long(gh, "indicatorOfUnitForTimeRange", unitsOfTime);
50269           grib_set_long(gh, "indicatorOfUnitOfTimeRange", unitsOfTime);
50270         }
50271       else
50272         {
50273 	  // NOTE KNMI:  HIRLAM model files LAMH_D11 are in grib1 and do NOT have key indicatorOfUnitForTimeRange
50274 	  // Watch out for compatibility issues.
50275           grib_set_long(gh, "indicatorOfUnitOfTimeRange", unitsOfTime);
50276         }
50277     }
50278 }
50279 
50280 static
gribapiDefSteptype(int editionNumber,grib_handle * gh,int productDefinitionTemplate,int typeOfGeneratingProcess,int tsteptype,int gcinit)50281 int gribapiDefSteptype(int editionNumber, grib_handle *gh, int productDefinitionTemplate, int typeOfGeneratingProcess, int tsteptype, int gcinit)
50282 {
50283   const char *stepType = "instant";
50284   long proDefTempNum = 0;
50285 
50286   if ( tsteptype >= TSTEP_INSTANT && tsteptype <= TSTEP_SUM )
50287     {
50288       stepType = cdiGribAPI_ts_str_map[tsteptype].sname;
50289       proDefTempNum = cdiGribAPI_ts_str_map[tsteptype].productionTemplate;
50290     }
50291 
50292   if ( typeOfGeneratingProcess == 4 )
50293     {
50294       proDefTempNum = (proDefTempNum == 8) ? 11 : 1;
50295     }
50296 
50297   if ( productDefinitionTemplate != -1 ) proDefTempNum = productDefinitionTemplate;
50298 
50299   if ( !gcinit )
50300     {
50301       if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "productDefinitionTemplateNumber", proDefTempNum), 0);
50302       size_t len = strlen(stepType);
50303       int status = my_grib_set_string(gh, "stepType", stepType, &len);
50304       if (status != 0) GRIB_CHECK(my_grib_set_long(gh, "productDefinitionTemplateNumber", 0), 0);
50305     }
50306 
50307   return (int)proDefTempNum;
50308 }
50309 
50310 static
gribapiDefDateTimeAbs(int editionNumber,grib_handle * gh,int64_t date,int time,int productDefinitionTemplate,int typeOfGeneratingProcess,int tsteptype,int gcinit)50311 void gribapiDefDateTimeAbs(int editionNumber, grib_handle *gh, int64_t date, int time, int productDefinitionTemplate, int typeOfGeneratingProcess, int tsteptype, int gcinit)
50312 {
50313   (void ) gribapiDefSteptype(editionNumber, gh, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
50314 
50315   if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "significanceOfReferenceTime", 0), 0);
50316   if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "stepRange", 0), 0);
50317 
50318   if ( date == 0 ) date = 10101;
50319   gribapiSetDataDateTime(gh, date, time);
50320 }
50321 
50322 static
gribapiDefDateTimeRel(int editionNumber,grib_handle * gh,int64_t fdate,int ftime,int64_t vdate,int vtime,int64_t sdate,int stime,int productDefinitionTemplate,int typeOfGeneratingProcess,int tsteptype,int timeunit,int calendar,int gcinit)50323 int gribapiDefDateTimeRel(int editionNumber, grib_handle *gh, int64_t fdate, int ftime, int64_t vdate, int vtime, int64_t sdate, int stime,
50324                           int productDefinitionTemplate, int typeOfGeneratingProcess, int tsteptype, int timeunit, int calendar, int gcinit)
50325 {
50326   int status = -1;
50327   int year, month, day, hour, minute, second;
50328   int64_t julday1, julday2, days;
50329   int secofday1, secofday2, secs;
50330 
50331   cdiDecodeDate(fdate, &year, &month, &day);
50332   cdiDecodeTime(ftime, &hour, &minute, &second);
50333   encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday1, &secofday1);
50334 
50335   if ( vdate == 0 && vtime == 0 ) { vdate = fdate; vtime = ftime; }
50336 
50337   cdiDecodeDate(vdate, &year, &month, &day);
50338   cdiDecodeTime(vtime, &hour, &minute, &second);
50339   encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday2, &secofday2);
50340 
50341   (void) julday_sub(julday1, secofday1, julday2, secofday2, &days, &secs);
50342 
50343   const int factor = getTimeunitFactor(timeunit);
50344 
50345   if ( !(int)(fmod(days*86400.0 + secs, factor)))
50346     {
50347       const int proDefTempNum = gribapiDefSteptype(editionNumber, gh, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
50348       gribapiDefStepUnits(editionNumber, gh, timeunit, proDefTempNum, gcinit);
50349 
50350       long startStep = 0;
50351       const double endStepF = (days*86400.0 + secs)/factor;
50352       const long maxStep = (editionNumber > 1) ? INT_MAX : 65000;
50353       if (endStepF > maxStep) return status;
50354       long endStep = (long) endStepF;
50355 
50356       if (sdate != 0 && (tsteptype == TSTEP_RANGE || tsteptype == TSTEP_AVG || tsteptype == TSTEP_ACCUM || tsteptype == TSTEP_DIFF))
50357         {
50358           cdiDecodeDate(sdate, &year, &month, &day);
50359           cdiDecodeTime(stime, &hour, &minute, &second);
50360           encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday2, &secofday2);
50361 
50362           (void) julday_sub(julday1, secofday1, julday2, secofday2, &days, &secs);
50363 
50364           startStep = (long) ((days*86400.0 + secs)/factor);
50365         }
50366 
50367       if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "significanceOfReferenceTime", 1), 0);
50368       if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "stepRange", 0), 0);
50369 
50370       if ( fdate == 0 ) fdate = 10101;
50371       gribapiSetDataDateTime(gh, fdate, ftime);
50372 
50373       // printf(">>>>> tsteptype %d  startStep %ld  endStep %ld\n", tsteptype, startStep, endStep);
50374 
50375       // Product Definition Template Number: defined in GRIB_API file 4.0.table point in time products:
50376       if ( (proDefTempNum >= 0 && proDefTempNum <=  7) ||
50377            proDefTempNum == 55 || proDefTempNum == 40055 ) // Tile
50378         startStep = endStep;
50379 
50380       if (endStep < startStep || startStep > 255 || endStep > 255)
50381         {
50382           startStep = 0;
50383           endStep = 0;
50384         }
50385       else
50386         {
50387           status = 0;
50388         }
50389 
50390       if ( editionNumber > 1 ) GRIB_CHECK(my_grib_set_long(gh, "forecastTime", startStep), 0);
50391       //if ( editionNumber == 1 && startStep > 0) GRIB_CHECK(my_grib_set_long(gh, "startStep", startStep), 0);
50392       if ( editionNumber == 1 ) GRIB_CHECK(my_grib_set_long(gh, "startStep", startStep), 0);
50393       GRIB_CHECK(my_grib_set_long(gh, "endStep", endStep), 0);
50394     }
50395 
50396   return status;
50397 }
50398 
50399 static
gribapiDefTime(int editionNumber,int productDefinitionTemplate,int typeOfGeneratingProcess,grib_handle * gh,int64_t vdate,int vtime,int tsteptype,int numavg,int taxisID,int gcinit)50400 void gribapiDefTime(int editionNumber, int productDefinitionTemplate, int typeOfGeneratingProcess, grib_handle *gh,
50401                     int64_t vdate, int vtime, int tsteptype, int numavg, int taxisID, int gcinit)
50402 {
50403   UNUSED(numavg);
50404 
50405   int taxistype = -1;
50406   if ( taxisID != -1 ) taxistype = taxisInqType(taxisID);
50407 
50408   if ( typeOfGeneratingProcess == 196 )
50409     {
50410       vdate = 10101;
50411       vtime = 0;
50412       taxistype = TAXIS_ABSOLUTE;
50413     }
50414   /*
50415   else if ( typeOfGeneratingProcess == 9 )
50416     {
50417     }
50418   */
50419 
50420   if ( taxistype == TAXIS_RELATIVE )
50421     {
50422       const int timeunit = taxisInqTunit(taxisID);
50423       const int calendar = taxisInqCalendar(taxisID);
50424 
50425       int64_t fdate = taxisInqFdate(taxisID);
50426       int ftime = taxisInqFtime(taxisID);
50427       if (fdate == CDI_UNDEFID)
50428         {
50429           fdate = taxisInqRdate(taxisID);
50430           ftime = taxisInqRtime(taxisID);
50431         }
50432       if (vdate < fdate || (vdate == fdate && vtime < ftime))
50433         {
50434           fdate = vdate;
50435           ftime = vtime;
50436         }
50437 
50438       int64_t sdate = taxisInqSdate(taxisID);
50439       int stime = taxisInqStime(taxisID);
50440 
50441       int status = gribapiDefDateTimeRel(editionNumber, gh, fdate, ftime, vdate, vtime, sdate, stime, productDefinitionTemplate,
50442                                          typeOfGeneratingProcess, tsteptype, timeunit, calendar, gcinit);
50443       if ( status != 0 ) taxistype = TAXIS_ABSOLUTE;
50444     }
50445 
50446   if ( taxistype == TAXIS_ABSOLUTE )
50447     {
50448       gribapiDefDateTimeAbs(editionNumber, gh, vdate, vtime, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
50449     }
50450 }
50451 
50452 static
gribapiDefGridRegular(grib_handle * gh,int gridID,int gridtype,bool gridIsRotated,bool gridIsCurvilinear,int uvRelativeToGrid)50453 void gribapiDefGridRegular(grib_handle *gh, int gridID, int gridtype, bool gridIsRotated, bool gridIsCurvilinear, int uvRelativeToGrid)
50454 {
50455   const char *mesg;
50456   size_t len;
50457   if ( gridtype == GRID_GAUSSIAN )
50458     {
50459       static const char mesg_gaussian[] = "regular_gg";
50460       len = sizeof(mesg_gaussian) - 1;
50461       mesg = mesg_gaussian;
50462     }
50463   else if ( gridtype == GRID_GAUSSIAN_REDUCED )
50464     {
50465       static const char mesg_gaussian_reduced[] = "reduced_gg";
50466       len = sizeof(mesg_gaussian_reduced) - 1;
50467       mesg = mesg_gaussian_reduced;
50468     }
50469   else if ( gridIsRotated )
50470     {
50471       static const char mesg_rot_lonlat[] = "rotated_ll";
50472       len = sizeof(mesg_rot_lonlat) - 1;
50473       mesg = mesg_rot_lonlat;
50474     }
50475   else
50476     {
50477       static const char mesg_regular_ll[] = "regular_ll";
50478       len = sizeof(mesg_regular_ll) - 1;
50479       mesg = mesg_regular_ll;
50480     }
50481   GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
50482 
50483   double xfirst = 0, xlast = 0, xinc = 0;
50484   double yfirst = 0, ylast = 0, yinc = 0;
50485 
50486   size_t nlon = gridInqXsize(gridID);
50487   size_t nlat = gridInqYsize(gridID);
50488 
50489   if ( gridtype == GRID_GAUSSIAN_REDUCED )
50490     {
50491       nlon = 0;
50492 
50493       int *reducedPoints = (int *) Malloc(nlat*sizeof(int));
50494       long *pl    = (long *) Malloc(nlat*sizeof(long));
50495       gridInqReducedPoints(gridID, reducedPoints);
50496       for ( size_t i = 0; i < nlat; ++i ) pl[i] = reducedPoints[i];
50497 
50498       GRIB_CHECK(grib_set_long_array(gh, "pl", pl, nlat), 0);
50499 
50500       Free(pl);
50501       Free(reducedPoints);
50502 
50503       xfirst = 0;
50504       xinc   =        360. * 0.5 / (double)nlat;
50505       xlast  = 360. - 360. * 0.5 / (double)nlat;
50506     }
50507   else
50508     {
50509       if ( nlon == 0 ) nlon = 1;
50510       else
50511         {
50512           xfirst = gridInqXval(gridID, 0);
50513           xlast  = gridInqXval(gridID, (gridIsCurvilinear ? nlon*nlat : nlon) - 1);
50514           xinc   = fabs(gridInqXinc(gridID));
50515         }
50516     }
50517 
50518   if ( nlat == 0 ) nlat = 1;
50519   else
50520     {
50521       yfirst = gridInqYval(gridID, 0);
50522       ylast  = gridInqYval(gridID, (gridIsCurvilinear ? nlon*nlat : nlat) - 1);
50523       yinc   = fabs(gridInqYinc(gridID));
50524     }
50525 
50526   double xfirsto = xfirst;
50527   double xlasto = xlast;
50528   while ( xfirsto > 360 ) xfirsto -= 360;
50529   while ( xlasto  > 360 ) xlasto  -= 360;
50530 
50531   if ( gridtype != GRID_GAUSSIAN_REDUCED ) GRIB_CHECK(my_grib_set_long(gh, "Ni", nlon), 0);
50532   GRIB_CHECK(my_grib_set_double(gh, "longitudeOfFirstGridPointInDegrees", xfirsto), 0);
50533   GRIB_CHECK(my_grib_set_double(gh, "longitudeOfLastGridPointInDegrees",  xlasto), 0);
50534   if ( gridtype != GRID_GAUSSIAN_REDUCED ) GRIB_CHECK(my_grib_set_double(gh, "iDirectionIncrementInDegrees", xinc), 0);
50535 
50536   GRIB_CHECK(my_grib_set_long(gh, "Nj", (long)nlat), 0);
50537   GRIB_CHECK(my_grib_set_double(gh, "latitudeOfFirstGridPointInDegrees",  yfirst), 0);
50538   GRIB_CHECK(my_grib_set_double(gh, "latitudeOfLastGridPointInDegrees",   ylast), 0);
50539 
50540   long xscan = xfirst > xlast;
50541   GRIB_CHECK(my_grib_set_long(gh, "iScansNegatively", xscan), 0);
50542   xscan = yfirst < ylast;
50543   GRIB_CHECK(my_grib_set_long(gh, "jScansPositively", xscan), 0);
50544 
50545   if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
50546     {
50547       int np = gridInqNP(gridID);
50548       if ( np == 0 ) np = nlat/2;
50549       GRIB_CHECK(my_grib_set_long(gh, "numberOfParallelsBetweenAPoleAndTheEquator", np), 0);
50550     }
50551   else
50552     {
50553       GRIB_CHECK(my_grib_set_double(gh, "jDirectionIncrementInDegrees", yinc), 0);
50554     }
50555 
50556   if ( gridIsRotated )
50557     {
50558       double xpole = 0, ypole = 0, angle = 0;
50559       gridInqParamRLL(gridID, &xpole, &ypole, &angle);
50560 
50561       xpole += 180;
50562       if ( fabs(ypole) > 0 ) ypole = -ypole; // change from north to south pole
50563       if ( fabs(angle) > 0 ) angle = -angle;
50564       GRIB_CHECK(my_grib_set_double(gh, "latitudeOfSouthernPoleInDegrees",  ypole), 0);
50565       GRIB_CHECK(my_grib_set_double(gh, "longitudeOfSouthernPoleInDegrees", xpole), 0);
50566       GRIB_CHECK(my_grib_set_double(gh, "angleOfRotation", angle), 0);
50567     }
50568 
50569   if ( uvRelativeToGrid >= 0 ) GRIB_CHECK(my_grib_set_long(gh, "uvRelativeToGrid", uvRelativeToGrid), 0);
50570 }
50571 
50572 static
radiusToShapeOfTheEarth(double radius)50573 long radiusToShapeOfTheEarth(double radius)
50574 {
50575   long shapeOfTheEarth = 0;
50576 
50577   if      (IS_EQUAL(radius, 6367470.)) shapeOfTheEarth = 0;
50578   else if (IS_EQUAL(radius, 6378160.)) shapeOfTheEarth = 2;
50579   else if (IS_EQUAL(radius, 6371229.)) shapeOfTheEarth = 6;
50580   else if (IS_EQUAL(radius, 6371200.)) shapeOfTheEarth = 8;
50581 
50582   return shapeOfTheEarth;
50583 }
50584 
50585 static
gribapiDefGridLCC(grib_handle * gh,int editionNumber,int gridID,int uvRelativeToGrid)50586 void gribapiDefGridLCC(grib_handle *gh, int editionNumber, int gridID, int uvRelativeToGrid)
50587 {
50588   const long xsize = (long) gridInqXsize(gridID);
50589   const long ysize = (long) gridInqYsize(gridID);
50590 
50591   double lon_0, lat_0, lat_1, lat_2, a, rf, xval_0, yval_0, x_0, y_0;
50592   gridInqParamLCC(gridID, CDI_Grid_Missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0);
50593   gridVerifyGribParamLCC(CDI_Grid_Missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0);
50594   if ( xval_0 < 0 ) xval_0 += 360;
50595   if ( lon_0 < 0 ) lon_0 += 360;
50596   const bool lsouth = (lat_1 < 0);
50597   if ( lsouth ) { lat_1 = -lat_2; lat_2 = -lat_2; }
50598   int projflag = 0;
50599   if ( lsouth ) gribbyte_set_bit(&projflag, 1);
50600 
50601   double xinc = gridInqXinc(gridID);
50602   double yinc = gridInqYinc(gridID);
50603 
50604   static const char mesg[] = "lambert";
50605   size_t len = sizeof(mesg) -1;
50606   GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
50607 
50608   GRIB_CHECK(my_grib_set_long(gh, "Nx", xsize), 0);
50609   GRIB_CHECK(my_grib_set_long(gh, "Ny", ysize), 0);
50610   GRIB_CHECK(my_grib_set_long(gh, "DxInMetres", lround(xinc)), 0);
50611   GRIB_CHECK(my_grib_set_long(gh, "DyInMetres", lround(yinc)), 0);
50612   GRIB_CHECK(my_grib_set_double(gh, "longitudeOfFirstGridPointInDegrees", xval_0), 0);
50613   GRIB_CHECK(my_grib_set_double(gh, "latitudeOfFirstGridPointInDegrees", yval_0), 0);
50614   GRIB_CHECK(my_grib_set_double(gh, "LoVInDegrees", lon_0), 0);
50615   GRIB_CHECK(my_grib_set_double(gh, "Latin1InDegrees", lat_1), 0);
50616   GRIB_CHECK(my_grib_set_double(gh, "Latin2InDegrees", lat_2), 0);
50617   GRIB_CHECK(my_grib_set_long(gh, "projectionCentreFlag", projflag), 0);
50618 
50619 
50620   const long shapeOfTheEarth = radiusToShapeOfTheEarth(a);
50621   if ( shapeOfTheEarth ) GRIB_CHECK(my_grib_set_long(gh, "shapeOfTheEarth", shapeOfTheEarth), 0);
50622 
50623   if ( uvRelativeToGrid >= 0 ) GRIB_CHECK(my_grib_set_long(gh, "uvRelativeToGrid", uvRelativeToGrid), 0);
50624 
50625   const long earthIsOblate = (IS_EQUAL(a, 6378160.) && IS_EQUAL(rf, 297.));
50626   if ( earthIsOblate ) GRIB_CHECK(my_grib_set_long(gh, "earthIsOblate", earthIsOblate), 0);
50627 
50628   int scanflag = 0;
50629   gribbyte_set_bit(&scanflag, 2);
50630   if ( editionNumber <= 1 )
50631     GRIB_CHECK(my_grib_set_long(gh, "scanningMode", (long)scanflag), 0);
50632 }
50633 
50634 static
gribapiDefGridSTERE(grib_handle * gh,int gridID)50635 void gribapiDefGridSTERE(grib_handle *gh, int gridID)
50636 {
50637   const long xsize = (long) gridInqXsize(gridID);
50638   const long ysize = (long) gridInqYsize(gridID);
50639 
50640   double lon_0, lat_ts, lat_0, a, xval_0, yval_0, x_0, y_0;
50641   gridInqParamSTERE(gridID, CDI_Grid_Missval, &lon_0, &lat_ts, &lat_0, &a, &xval_0, &yval_0, &x_0, &y_0);
50642   gridVerifyGribParamSTERE(CDI_Grid_Missval, &lon_0, &lat_ts, &lat_0, &a, &xval_0, &yval_0, &x_0, &y_0);
50643   if ( xval_0 < 0 ) xval_0 += 360;
50644   int projflag = 0;
50645 
50646   const double xinc = gridInqXinc(gridID);
50647   const double yinc = gridInqYinc(gridID);
50648 
50649   static const char mesg[] = "polar_stereographic";
50650   size_t len = sizeof(mesg) -1;
50651   GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
50652 
50653   GRIB_CHECK(my_grib_set_long(gh, "Nx", xsize), 0);
50654   GRIB_CHECK(my_grib_set_long(gh, "Ny", ysize), 0);
50655   GRIB_CHECK(my_grib_set_long(gh, "DxInMetres", lround(xinc)), 0);
50656   GRIB_CHECK(my_grib_set_long(gh, "DyInMetres", lround(yinc)), 0);
50657   GRIB_CHECK(my_grib_set_double(gh, "longitudeOfFirstGridPointInDegrees", xval_0), 0);
50658   GRIB_CHECK(my_grib_set_double(gh, "latitudeOfFirstGridPointInDegrees", yval_0), 0);
50659   GRIB_CHECK(my_grib_set_double(gh, "LaDInDegrees", lat_ts), 0);
50660   GRIB_CHECK(my_grib_set_double(gh, "orientationOfTheGridInDegrees", lon_0), 0);
50661   const long southPoleOnProjectionPlane = IS_EQUAL(lat_0, -90.);
50662   GRIB_CHECK(my_grib_set_double(gh, "southPoleOnProjectionPlane", southPoleOnProjectionPlane), 0);
50663   GRIB_CHECK(my_grib_set_long(gh, "projectionCentreFlag", projflag), 0);
50664 
50665   const long shapeOfTheEarth = radiusToShapeOfTheEarth(a);
50666   if ( shapeOfTheEarth ) GRIB_CHECK(my_grib_set_long(gh, "shapeOfTheEarth", shapeOfTheEarth), 0);
50667 
50668   GRIB_CHECK(my_grib_set_long(gh, "resolutionAndComponentFlags", 8), 0);
50669   GRIB_CHECK(my_grib_set_long(gh, "iScansNegatively", 0), 0);
50670   GRIB_CHECK(my_grib_set_long(gh, "jScansPositively", 1), 0);
50671 }
50672 
50673 static
gribapiDefGridGME(grib_handle * gh,int gridID,long gridsize)50674 void gribapiDefGridGME(grib_handle *gh, int gridID, long gridsize)
50675 {
50676   GRIB_CHECK(my_grib_set_long(gh, "gridDefinitionTemplateNumber", GRIB2_GTYPE_GME), 0);
50677 
50678   int nd = 0, ni = 0, ni2 = 0, ni3 = 0;
50679   gridInqParamGME(gridID, &nd, &ni, &ni2, &ni3);
50680   GRIB_CHECK(my_grib_set_long(gh, "nd", nd), 0);
50681   GRIB_CHECK(my_grib_set_long(gh, "Ni", ni), 0);
50682   GRIB_CHECK(my_grib_set_long(gh, "n2", ni2), 0);
50683   GRIB_CHECK(my_grib_set_long(gh, "n3", ni3), 0);
50684   GRIB_CHECK(my_grib_set_long(gh, "latitudeOfThePolePoint", 90000000), 0);
50685   GRIB_CHECK(my_grib_set_long(gh, "longitudeOfThePolePoint", 0), 0);
50686 
50687   GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridsize), 0);
50688   GRIB_CHECK(my_grib_set_long(gh, "totalNumberOfGridPoints", gridsize), 0);
50689 }
50690 
50691 static
gribapiDefGridUnstructured(grib_handle * gh,int gridID)50692 void gribapiDefGridUnstructured(grib_handle *gh, int gridID)
50693 {
50694   static bool warning = true;
50695 
50696   const int status = my_grib_set_long(gh, "gridDefinitionTemplateNumber", GRIB2_GTYPE_UNSTRUCTURED);
50697   if ( status != 0 && warning )
50698     {
50699       warning = false;
50700       Warning("Can't write reference grid!");
50701       Warning("gridDefinitionTemplateNumber %d not found (grib2/template.3.%d.def)!",
50702               GRIB2_GTYPE_UNSTRUCTURED, GRIB2_GTYPE_UNSTRUCTURED);
50703     }
50704   else
50705     {
50706       int number = 0;
50707       cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDUSED, &number);
50708       if ( number < 0 ) number = 0;
50709       GRIB_CHECK(my_grib_set_long(gh, "numberOfGridUsed", number), 0);
50710 
50711       int position = 0;
50712       cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_NUMBEROFGRIDINREFERENCE, &position);
50713       if ( position < 0 ) position = 0;
50714       GRIB_CHECK(my_grib_set_long(gh, "numberOfGridInReference", position), 0);
50715 
50716       unsigned char uuid[CDI_UUID_SIZE];
50717       size_t len = CDI_UUID_SIZE;
50718       memset(uuid, 0, len);
50719       int length = CDI_UUID_SIZE;
50720       cdiInqKeyBytes(gridID, CDI_GLOBAL, CDI_KEY_UUID, uuid, &length);
50721       if (grib_set_bytes(gh, "uuidOfHGrid", uuid, &len) != 0)
50722         Warning("Can't write UUID!");
50723     }
50724 }
50725 
50726 static
gribapiDefGridSpectral(grib_handle * gh,int gridID)50727 void gribapiDefGridSpectral(grib_handle *gh, int gridID)
50728 {
50729   const int trunc = gridInqTrunc(gridID);
50730   enum { numTruncAtt = 3 };
50731   static const char truncAttNames[numTruncAtt][2] = { "J", "K", "M" };
50732   for (size_t i = 0; i < numTruncAtt; ++i)
50733     GRIB_CHECK(my_grib_set_long(gh, truncAttNames[i], trunc), 0);
50734 
50735   if ( gridInqComplexPacking(gridID) )
50736     {
50737       static const char truncAttNames2[numTruncAtt][3] = { "JS", "KS", "MS" };
50738       for (size_t i = 0; i < numTruncAtt; ++i)
50739         GRIB_CHECK(my_grib_set_long(gh, truncAttNames2[i], 20), 0);
50740     }
50741 }
50742 
50743 static
gribapiDefPackingType(grib_handle * gh,bool lieee,bool lspectral,bool lcomplex,int comptype,size_t gridsize)50744 void gribapiDefPackingType(grib_handle *gh, bool lieee, bool lspectral, bool lcomplex, int comptype, size_t gridsize)
50745 {
50746   static const char mesg_spectral_complex[] = "spectral_complex";
50747   static const char mesg_spectral_simple[] = "spectral_simple";
50748   static const char mesg_grid_jpeg[] = "grid_jpeg";
50749   static const char mesg_grid_ccsds[] = "grid_ccsds";
50750   static const char mesg_ieee[] = "grid_ieee";
50751   static const char mesg_simple[] = "grid_simple";
50752   const char *mesg = mesg_simple;
50753 
50754   if ( lspectral )
50755     {
50756       mesg = lcomplex ? mesg_spectral_complex : mesg_spectral_simple;
50757     }
50758   else if ( comptype == CDI_COMPRESS_JPEG && gridsize > 1 )
50759     {
50760       mesg = mesg_grid_jpeg;
50761     }
50762   else if ( (comptype == CDI_COMPRESS_SZIP || comptype == CDI_COMPRESS_AEC) && gridsize > 1 )
50763     {
50764       mesg = mesg_grid_ccsds;
50765     }
50766   else if ( lieee )
50767     {
50768       mesg = mesg_ieee;
50769     }
50770 
50771   size_t len = strlen(mesg);
50772   GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
50773 }
50774 
50775 static
gribapiDefGrid(int editionNumber,grib_handle * gh,int gridID,int comptype,int datatype,int uvRelativeToGrid)50776 void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype, int datatype, int uvRelativeToGrid)
50777 {
50778   const size_t gridsize = gridInqSize(gridID);
50779   bool gridIsRotated = false;
50780   bool gridIsCurvilinear = false;
50781   const int gridtype = grbGetGridtype(&gridID, gridsize, &gridIsRotated, &gridIsCurvilinear);
50782 
50783   bool lieee = (editionNumber == 2 && (datatype == CDI_DATATYPE_FLT32 || datatype == CDI_DATATYPE_FLT64));
50784   bool lspectral = (gridtype == GRID_SPECTRAL);
50785   bool lcomplex = (lspectral && gridInqComplexPacking(gridID));
50786 
50787   if ( lieee ) comptype = 0;
50788   if ( lspectral ) lieee = false;
50789 
50790   if ( lspectral ) // gridType needs to be defined before packingType !!!
50791     {
50792       static const char mesg[] = "sh";
50793       size_t len = sizeof (mesg) -1;
50794       GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
50795     }
50796 
50797   gribapiDefPackingType(gh, lieee, lspectral, lcomplex, comptype, gridsize);
50798 
50799   if ( lieee ) GRIB_CHECK(my_grib_set_long(gh, "precision", datatype == CDI_DATATYPE_FLT64 ? 2 : 1), 0);
50800 
50801   if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", (long)gridsize), 0);
50802 
50803   switch (gridtype)
50804     {
50805     case GRID_LONLAT:
50806     case GRID_GAUSSIAN:
50807     case GRID_GAUSSIAN_REDUCED:
50808     case GRID_TRAJECTORY:
50809       {
50810         gribapiDefGridRegular(gh, gridID, gridtype, gridIsRotated, gridIsCurvilinear, uvRelativeToGrid);
50811 	break;
50812       }
50813     case CDI_PROJ_LCC:
50814       {
50815         gribapiDefGridLCC(gh, editionNumber, gridID, uvRelativeToGrid);
50816 	break;
50817       }
50818     case CDI_PROJ_STERE:
50819       {
50820         gribapiDefGridSTERE(gh, gridID);
50821 	break;
50822       }
50823     case GRID_SPECTRAL:
50824       {
50825         gribapiDefGridSpectral(gh, gridID);
50826 	break;
50827       }
50828     case GRID_GME:
50829       {
50830         if ( editionNumber <= 1 ) Error("GME grid can't be stored in GRIB edition %d!", editionNumber);
50831         gribapiDefGridGME(gh, gridID, (long) gridsize);
50832 	break;
50833       }
50834     case GRID_UNSTRUCTURED:
50835       {
50836         if ( editionNumber <= 1 ) Error("Unstructured grid can't be stored in GRIB edition %d!", editionNumber);
50837         gribapiDefGridUnstructured(gh, gridID);
50838 	break;
50839       }
50840     default:
50841       {
50842 	Error("Unsupported grid type: %s", gridNamePtr(gridtype));
50843 	break;
50844       }
50845     }
50846 }
50847 
50848 static
getLevelFactor(double level,long * factor,long * out_scaled_value)50849 void getLevelFactor(double level, long *factor, long *out_scaled_value)
50850 {
50851   double scaled_value  = level;
50852   long   iscaled_value = lround(scaled_value);
50853   long   i;
50854 
50855   const double eps = 1.e-8;
50856   for ( i=0; (fabs(scaled_value - (double) iscaled_value) >= eps) && i < 7; i++ )
50857     {
50858       scaled_value *= 10.;
50859       iscaled_value = lround(scaled_value);
50860     }
50861 
50862   (*factor)           = i;
50863   (*out_scaled_value) = iscaled_value;
50864 }
50865 
50866 static
gribapiDefLevelType(grib_handle * gh,int gcinit,const char * keyname,long leveltype)50867 void gribapiDefLevelType(grib_handle *gh, int gcinit, const char *keyname, long leveltype)
50868 {
50869   bool lset = false;
50870   if ( (leveltype == GRIB1_LTYPE_ISOBARIC_PA || leveltype == 99 || leveltype == 100) && gribEditionNumber(gh) == 1 )
50871     {
50872       if ( gribGetLong(gh, "indicatorOfTypeOfLevel") != leveltype ) lset = true;
50873     }
50874 
50875   if ( !gcinit || lset ) GRIB_CHECK(my_grib_set_long(gh, keyname, leveltype), 0);
50876 }
50877 
50878 static
grib1DefLevel(grib_handle * gh,int gcinit,long leveltype,bool lbounds,double level,double dlevel1,double dlevel2)50879 void grib1DefLevel(grib_handle *gh, int gcinit, long leveltype, bool lbounds, double level, double dlevel1, double dlevel2)
50880 {
50881   gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", leveltype);
50882 
50883   if ( lbounds )
50884     {
50885       GRIB_CHECK(my_grib_set_long(gh, "topLevel", lround(dlevel1)), 0);
50886       GRIB_CHECK(my_grib_set_long(gh, "bottomLevel", lround(dlevel2)), 0);
50887     }
50888   else
50889     {
50890       GRIB_CHECK(my_grib_set_long(gh, "level", lround(level)), 0);
50891     }
50892 }
50893 
50894 static
grib2DefLevel(grib_handle * gh,int gcinit,long leveltype1,long leveltype2,bool lbounds,double level,double dlevel1,double dlevel2)50895 void grib2DefLevel(grib_handle *gh, int gcinit, long leveltype1, long leveltype2, bool lbounds, double level, double dlevel1, double dlevel2)
50896 {
50897   gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", leveltype1);
50898   if ( lbounds ) gribapiDefLevelType(gh, gcinit, "typeOfSecondFixedSurface", leveltype2);
50899 
50900   if ( !lbounds ) dlevel1 = level;
50901 
50902   long scaled_level, factor;
50903   getLevelFactor(dlevel1, &factor, &scaled_level);
50904   GRIB_CHECK(my_grib_set_long(gh, "scaleFactorOfFirstFixedSurface", factor), 0);
50905   GRIB_CHECK(my_grib_set_long(gh, "scaledValueOfFirstFixedSurface", scaled_level), 0);
50906 
50907   if ( lbounds )
50908     {
50909       getLevelFactor(dlevel2, &factor, &scaled_level);
50910       GRIB_CHECK(my_grib_set_long(gh, "scaleFactorOfSecondFixedSurface", factor), 0);
50911       GRIB_CHECK(my_grib_set_long(gh, "scaledValueOfSecondFixedSurface", scaled_level), 0);
50912     }
50913 }
50914 
50915 static
gribapiDefLevel(int editionNumber,grib_handle * gh,int zaxisID,int levelID,int gcinit,int proddef_template_num)50916 void gribapiDefLevel(int editionNumber, grib_handle *gh, int zaxisID, int levelID, int gcinit, int proddef_template_num)
50917 {
50918   char units[CDI_MAX_NAME];
50919   bool lbounds = false;
50920 
50921   int zaxistype = zaxisInqType(zaxisID);
50922   int ltype = 0, ltype2 = -1;
50923   cdiInqKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE, &ltype);
50924   cdiInqKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_TYPEOFSECONDFIXEDSURFACE, &ltype2);
50925   double level = zaxisInqLevels(zaxisID, NULL) ? zaxisInqLevel(zaxisID, levelID) : levelID+1;
50926 
50927   double dlevel1 = level, dlevel2 = 0;
50928   if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
50929     {
50930       lbounds = true;
50931       dlevel1 = zaxisInqLbound(zaxisID, levelID);
50932       dlevel2 = zaxisInqUbound(zaxisID, levelID);
50933     }
50934 
50935   if ( zaxistype == ZAXIS_GENERIC && ltype == 0 )
50936     {
50937       Message("Changed zaxis type from %s to %s", zaxisNamePtr(zaxistype), zaxisNamePtr(ZAXIS_PRESSURE));
50938       zaxistype = ZAXIS_PRESSURE;
50939       zaxisChangeType(zaxisID, zaxistype);
50940       cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, "Pa");
50941     }
50942 
50943   long grib_ltype = (editionNumber <= 1) ? zaxisTypeToGrib1ltype(zaxistype) : zaxisTypeToGrib2ltype(zaxistype);
50944   long grib_ltype2 = (ltype != ltype2 && ltype2 != -1) ? ltype2 : grib_ltype;
50945 
50946   switch (zaxistype)
50947     {
50948     case ZAXIS_SURFACE:
50949     case ZAXIS_MEANSEA:
50950     case ZAXIS_HEIGHT:
50951     case ZAXIS_ALTITUDE:
50952     case ZAXIS_SIGMA:
50953     case ZAXIS_DEPTH_BELOW_SEA:
50954     case ZAXIS_ISENTROPIC:
50955       {
50956         if ( zaxistype == ZAXIS_HEIGHT )
50957           {
50958             double sf = 1;
50959             int length = CDI_MAX_NAME;
50960             cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, units, &length);
50961             if ( units[1] == 'm' && !units[2] )
50962               {
50963                 if      ( units[0] == 'c' ) sf = 0.01;
50964                 else if ( units[0] == 'd' ) sf = 0.1;
50965                 else if ( units[0] == 'k' ) sf = 1000;
50966               }
50967             if ( IS_NOT_EQUAL(sf, 1) )
50968               {
50969                 level   *= sf;
50970                 dlevel1 *= sf;
50971                 dlevel2 *= sf;
50972               }
50973           }
50974 
50975         if ( editionNumber <= 1 )
50976           {
50977             grib1DefLevel(gh, gcinit, grib_ltype, lbounds, level, dlevel1, dlevel2);
50978           }
50979         else
50980           {
50981             /* PRODUCT DEFINITION TEMPLATE NUMBER 32:
50982 
50983                "Analysis or forecast at a horizontal level or in a horizontal layer at a point
50984                 in time for simulate (synthetic) satellite data"
50985 
50986                The key/value pairs that are set in "grib2DefLevel" do not exist for this template.
50987             */
50988             if ( proddef_template_num != 32 )
50989               grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype2, lbounds, level, dlevel1, dlevel2);
50990           }
50991 
50992 	break;
50993       }
50994     case ZAXIS_CLOUD_BASE:
50995     case ZAXIS_CLOUD_TOP:
50996     case ZAXIS_ISOTHERM_ZERO:
50997     case ZAXIS_TROPOPAUSE:
50998     case ZAXIS_TOA:
50999     case ZAXIS_SEA_BOTTOM:
51000     case ZAXIS_LAKE_BOTTOM:
51001     case ZAXIS_SEDIMENT_BOTTOM:
51002     case ZAXIS_SEDIMENT_BOTTOM_TA:
51003     case ZAXIS_SEDIMENT_BOTTOM_TW:
51004     case ZAXIS_MIX_LAYER:
51005     case ZAXIS_ATMOSPHERE:
51006       {
51007         if ( editionNumber <= 1 )
51008           grib1DefLevel(gh, gcinit, grib_ltype, lbounds, level, dlevel1, dlevel2);
51009         else
51010           grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype2, lbounds, level, dlevel1, dlevel2);
51011 
51012         break;
51013       }
51014     case ZAXIS_HYBRID:
51015     case ZAXIS_HYBRID_HALF:
51016       {
51017         if ( editionNumber <= 1 )
51018           {
51019             grib_ltype = lbounds ? GRIB1_LTYPE_HYBRID_LAYER : GRIB1_LTYPE_HYBRID;
51020             grib1DefLevel(gh, gcinit, grib_ltype, lbounds, level, dlevel1, dlevel2);
51021           }
51022         else
51023           {
51024             grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype, lbounds, level, dlevel1, dlevel2);
51025           }
51026 
51027         if ( !gcinit )
51028           {
51029             int vctsize = zaxisInqVctSize(zaxisID);
51030             if ( vctsize > 0 )
51031               {
51032                 GRIB_CHECK(my_grib_set_long(gh, "PVPresent", 1), 0);
51033                 GRIB_CHECK(grib_set_double_array(gh, "pv", zaxisInqVctPtr(zaxisID), (size_t)vctsize), 0);
51034               }
51035           }
51036 
51037 	break;
51038       }
51039     case ZAXIS_PRESSURE:
51040       {
51041 	if ( level < 0 ) Warning("Pressure level of %f Pa is below zero!", level);
51042 
51043         int length = CDI_MAX_NAME;
51044         cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, units, &length);
51045         if ( units[0] && (units[0] != 'P') | (units[1] != 'a') )
51046           {
51047             level   *= 100;
51048             dlevel1 *= 100;
51049             dlevel2 *= 100;
51050           }
51051 
51052         if ( editionNumber <= 1 )
51053           {
51054             double dum;
51055             if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
51056               grib_ltype = GRIB1_LTYPE_ISOBARIC_PA;
51057             else
51058               level /= 100;
51059 
51060             grib1DefLevel(gh, gcinit, grib_ltype, lbounds, level, dlevel1, dlevel2);
51061 	  }
51062 	else
51063 	  {
51064             if ( ltype2 == -1 ) ltype2 = GRIB2_LTYPE_ISOBARIC;
51065             grib2DefLevel(gh, gcinit, GRIB2_LTYPE_ISOBARIC, ltype2, lbounds, level, dlevel1, dlevel2);
51066 	  }
51067 
51068 	break;
51069       }
51070     case ZAXIS_SNOW:
51071       {
51072         if ( editionNumber <= 1 )
51073           ; // not available
51074 	else
51075           {
51076             grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype, lbounds, level, dlevel1, dlevel2);
51077           }
51078 
51079 	break;
51080       }
51081     case ZAXIS_DEPTH_BELOW_LAND:
51082       {
51083         int length = CDI_MAX_NAME;
51084         cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, units, &length);
51085         double sf; //scalefactor
51086 
51087 	if ( editionNumber <= 1 )
51088 	  {
51089 	    if      ( memcmp(units, "mm", 2) == 0 ) sf =   0.1;
51090 	    else if ( memcmp(units, "cm", 2) == 0 ) sf =   1; // cm
51091 	    else if ( memcmp(units, "dm", 2) == 0 ) sf =  10;
51092 	    else                                    sf = 100;
51093 
51094             grib1DefLevel(gh, gcinit, grib_ltype, lbounds, level*sf, dlevel1*sf, dlevel2*sf);
51095 	  }
51096 	else
51097 	  {
51098 	    if      ( memcmp(units, "mm", 2) == 0 ) sf = 0.001;
51099 	    else if ( memcmp(units, "cm", 2) == 0 ) sf = 0.01;
51100 	    else if ( memcmp(units, "dm", 2) == 0 ) sf = 0.1;
51101 	    else                                    sf = 1; // meter
51102 
51103             grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype, lbounds, level*sf, dlevel1*sf, dlevel2*sf);
51104 	  }
51105 
51106 	break;
51107       }
51108     case ZAXIS_REFERENCE:
51109       {
51110         if ( !gcinit ) GRIB_CHECK(my_grib_set_long(gh, "genVertHeightCoords", 1), 0);
51111 
51112         if ( editionNumber <= 1 )
51113           ; // not available
51114         else
51115           {
51116             if ( lbounds )
51117               {
51118                 gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", grib_ltype);
51119                 gribapiDefLevelType(gh, gcinit, "typeOfSecondFixedSurface", grib_ltype2);
51120                 GRIB_CHECK(my_grib_set_long(gh, "topLevel", (long) dlevel1), 0);
51121                 GRIB_CHECK(my_grib_set_long(gh, "bottomLevel", (long) dlevel2), 0);
51122               }
51123             else
51124               {
51125                 grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype2, lbounds, level, dlevel1, dlevel2);
51126               }
51127 
51128             GRIB_CHECK(my_grib_set_long(gh, "NV", 6), 0);
51129             int number = 0;
51130             cdiInqKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_NUMBEROFVGRIDUSED, &number);
51131             GRIB_CHECK(my_grib_set_long(gh, "numberOfVGridUsed", number), 0);
51132             int nlev = 0;
51133             cdiInqKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_NLEV, &nlev);
51134             GRIB_CHECK(my_grib_set_long(gh, "nlev", nlev), 0);
51135             unsigned char uuid[CDI_UUID_SIZE];
51136             int length = CDI_UUID_SIZE;
51137             memset(uuid, 0, length);
51138             cdiInqKeyBytes(zaxisID, CDI_GLOBAL, CDI_KEY_UUID, uuid, &length);
51139             size_t len = CDI_UUID_SIZE;
51140             if ( grib_set_bytes(gh, "uuidOfVGrid", uuid, &len) != 0 ) Warning("Can't write UUID!");
51141           }
51142 
51143         break;
51144       }
51145     case ZAXIS_GENERIC:
51146       {
51147 	if ( editionNumber <= 1 )
51148           {
51149             grib1DefLevel(gh, gcinit, ltype, lbounds, level, dlevel1, dlevel2);
51150           }
51151         else
51152           {
51153             grib2DefLevel(gh, gcinit, ltype, ltype, lbounds, level, dlevel1, dlevel2);
51154           }
51155 
51156 	break;
51157       }
51158     default:
51159       {
51160 	Error("Unsupported zaxis type: %s", zaxisNamePtr(zaxistype));
51161 	break;
51162       }
51163     }
51164 }
51165 
51166 
gribapiGetScanningMode(grib_handle * gh)51167 int gribapiGetScanningMode(grib_handle *gh)
51168 {
51169   long iScansNegatively, jScansPositively, jPointsAreConsecutive;
51170   GRIB_CHECK(grib_get_long(gh, "iScansNegatively", &iScansNegatively), 0);
51171   GRIB_CHECK(grib_get_long(gh, "jScansPositively", &jScansPositively), 0);
51172   GRIB_CHECK(grib_get_long(gh, "jPointsAreConsecutive", &jPointsAreConsecutive), 0);
51173   int scanningMode
51174     = 128*(bool)iScansNegatively
51175     + 64 *(bool)jScansPositively
51176     + 32 *(bool)jPointsAreConsecutive;
51177   if (cdiDebugExt>=30)
51178     printf("gribapiGetScanningMode(): Scanning mode = %02d (%1d%1d%1d)*32; \n",\
51179             scanningMode,(int)jPointsAreConsecutive,(int)jScansPositively,(int)iScansNegatively);
51180 
51181  return scanningMode;
51182 }
51183 
51184 
gribapiSetScanningMode(grib_handle * gh,int scanningMode)51185 void gribapiSetScanningMode(grib_handle *gh, int scanningMode)
51186 {
51187   // 127: reserved for testing; generated test data will be in 64 scanning mode
51188   //if (scanningMode== 127)  scanningMode = 64;
51189 
51190   const long iScansNegatively      = (scanningMode & 128)/128;
51191   const long jScansPositively      = (scanningMode & 64)/64;
51192   const long jPointsAreConsecutive = (scanningMode & 32)/32;
51193 
51194   if (cdiDebugExt>=30)
51195   {
51196     long paramId, levelTypeId, levelId, uvRelativeToGrid;
51197     GRIB_CHECK(grib_get_long(gh, "uvRelativeToGrid", &uvRelativeToGrid), 0);
51198     GRIB_CHECK(grib_get_long(gh, "indicatorOfParameter", &paramId), 0);
51199     GRIB_CHECK(grib_get_long(gh, "indicatorOfTypeOfLevel", &levelTypeId), 0);
51200     GRIB_CHECK(grib_get_long(gh, "level", &levelId), 0);
51201     printf("gribapiSetScanningMode(): (param,ltype,level) = (%3d,%3d,%4d); Scanning mode = %02d (%1d%1d%1d)*32;  uvRelativeToGrid = %02d\n",\
51202             (int)paramId, (int)levelTypeId, (int)levelId,
51203             scanningMode,(int)jPointsAreConsecutive,(int)jScansPositively,(int)iScansNegatively,
51204             (int)uvRelativeToGrid);
51205   }
51206 
51207   GRIB_CHECK(my_grib_set_long(gh, "iScansNegatively", iScansNegatively), 0);
51208   GRIB_CHECK(my_grib_set_long(gh, "jScansPositively", jScansPositively), 0);
51209   GRIB_CHECK(my_grib_set_long(gh, "jPointsAreConsecutive", jPointsAreConsecutive), 0);
51210 }
51211 
51212 
51213   /*
51214     TABLE 8. SCANNING MODE FLAG
51215 
51216     (GDS Octet 28)
51217     BIT     VALUE     MEANING
51218     1       0       Points scan in +i direction
51219             1       Points scan in -i direction
51220     2       0       Points scan in -j direction
51221             1       Points scan in +j direction
51222     3       0       Adjacent points in i direction are consecutive
51223                       (FORTRAN: (I,J))
51224             1       Adjacent points in j direction are consecutive
51225                     (FORTRAN: (J,I))
51226 
51227     => Scanning Mode     0 0 0 0 0 0 0 0  (00 dec)  +i, -j; i direction consecutive (row-major    order West->East   & North->South)
51228     => Scanning Mode     0 1 0 0 0 0 0 0  (64 dec)  +i, +j; i direction consecutive (row-major    order West->East   & South->North )
51229     => Scanning Mode     1 1 0 0 0 0 0 0  (96 dec)  +i, +j; j direction consecutive (column-major order South->North & West->East )
51230 
51231     NOTE:  South->North  - As if you would plot the data as image on the screen
51232                            where [0,0] of the data is the top-left pixel.
51233 
51234                            grib2ppm LAMH_D11_201302150000_00000_oro | display ppm:-
51235                            ImageMagick (display): [0,0] of an image belongs to the top-left pixel
51236     [DEFAULT] : 64 dec
51237 
51238     iScansNegatively = 0;
51239     jScansPositively = 1;
51240     jPointsAreConsecutive = 0;    => Scanning Mode 64
51241 
51242     cdo selindexbox,1,726,100,550 LAMH_D11_201302150000_00000_oro LAMH_D11_201302150000_00000_oro_cropped
51243     grib2ppm LAMH_D11_201302150000_00000_oro_cropped | /usr/bin/display ppm:- &
51244     # ^^^ this image will be missing the souther parts of data
51245 
51246     grib2ppm LAMH_D11_201302150000_00000_oro | /usr/bin/display ppm:- &
51247     # ^ full domain data
51248   */
51249 
51250 #ifdef HIRLAM_EXTENSIONS
51251 static void
verticallyFlipGridDefinitionWhenScanningModeChanged(grib_handle * gh,double yfirst,double ylast,double yinc)51252 verticallyFlipGridDefinitionWhenScanningModeChanged(grib_handle *gh, double yfirst, double ylast, double yinc )
51253 {
51254   /*
51255   Nj = 550;
51256   latitudeOfFirstGridPointInDegrees = -30.8;
51257   latitudeOfLastGridPointInDegrees = 24.1;
51258   iScansNegatively = 0;
51259   jScansPositively = 0;
51260   jPointsAreConsecutive = 0;
51261   jDirectionIncrementInDegrees = 0.1;
51262 
51263   When switching from scanning mode 0 <=> 64
51264   yfirst = -30.8 + (550-1)*0.1
51265 
51266   yfirst = yfirst + (ysize-1) * yinc
51267   yinc   = -1.0*yinc
51268 
51269   */
51270 
51271 
51272   //long jDim=0;
51273   //GRIB_CHECK(grib_get_long(gh, "Nj", &jDim), 0);
51274 
51275   double latitudeOfFirstGridPointInDegrees;
51276   double latitudeOfLastGridPointInDegrees;
51277   double jDirectionIncrementInDegrees;
51278 
51279   //GRIB_CHECK(grib_get_double(gh, "latitudeOfFirstGridPointInDegrees", &latitudeOfFirstGridPointInDegrees), 0);  // yfirst
51280   //GRIB_CHECK(grib_get_double(gh, "latitudeOfLastGridPointInDegrees", &latitudeOfLastGridPointInDegrees), 0);    // ylast
51281   //GRIB_CHECK(grib_get_double(gh, "jDirectionIncrementInDegrees", &jDirectionIncrementInDegrees), 0);  // yinc
51282 
51283   if (cdiDebugExt>=10)
51284   {
51285       Message(" BEFORE: yfirst = %f; ylast = %f; yinc = %f; ", yfirst,ylast, yinc);
51286   }
51287 
51288   GRIB_CHECK(my_grib_set_double(gh, "latitudeOfFirstGridPointInDegrees", ylast), 0);
51289   GRIB_CHECK(my_grib_set_double(gh, "latitudeOfLastGridPointInDegrees", yfirst), 0);
51290   //yinc *= -1.0; // don't set yinc here ...
51291   //GRIB_CHECK(my_grib_set_double(gh, "jDirectionIncrementInDegrees", yinc), 0);
51292 
51293   if (cdiDebugExt>=10)
51294   {
51295     GRIB_CHECK(grib_get_double(gh, "latitudeOfFirstGridPointInDegrees", &latitudeOfFirstGridPointInDegrees), 0);  // yfirst
51296     GRIB_CHECK(grib_get_double(gh, "latitudeOfLastGridPointInDegrees", &latitudeOfLastGridPointInDegrees), 0);    // ylast
51297     GRIB_CHECK(grib_get_double(gh, "jDirectionIncrementInDegrees", &jDirectionIncrementInDegrees), 0);  // yinc
51298     Message("CHANGED INTO:  yfirst = %f, ylast = %f, yinc = %f",latitudeOfFirstGridPointInDegrees,latitudeOfLastGridPointInDegrees, jDirectionIncrementInDegrees);
51299   }
51300 }
51301 
51302 static void
convertDataScanningMode(int scanModeIN,int scanModeOUT,double * data,size_t gridsize,size_t iDim,size_t jDim)51303 convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
51304                         size_t gridsize, size_t iDim, size_t jDim)
51305 {
51306   size_t i,j;
51307   size_t idxIN, idxOUT;
51308 
51309    // 127: reserved for testing; it will generate test data in 64 scanning mode
51310   if (scanModeOUT== 127)  // fill with testdata ...
51311   {
51312       scanModeOUT = 64;
51313       if (cdiDebugExt>=30) printf("convertDataScanningMode(): Generating test data in 64 scanning mode..\n");
51314       for (j=0; j<jDim; j++)
51315       {
51316         const size_t jXiDim = j*iDim;
51317         for (i=0; i<iDim; i++)
51318         {
51319           idxIN = i + jXiDim;
51320           data[idxIN] = (double) (100.0*j +i);
51321         }
51322       }
51323   }
51324 
51325   if ( (iDim*jDim)!= gridsize)
51326   {
51327     if (cdiDebugExt>=30) printf("convertDataScanningMode(): ERROR: (iDim*jDim)!= gridsize;  (%zu * %zu) != %zu\n", iDim,jDim, gridsize);
51328     return;
51329   }
51330   if (cdiDebugExt>=30) printf("convertDataScanningMode(): scanModeIN=%02d => scanModeOUT=%02d ; where: (iDim * jDim == gridsize)  (%zu*%zu == %zu)\n",scanModeIN, scanModeOUT, iDim,jDim, gridsize);
51331 
51332   if (cdiDebugExt>=100)
51333   {
51334       printf("convertDataScanningMode(): data IN:\n");
51335       for (j=0; j<jDim; j++)
51336       {
51337         size_t jXiDim = j*iDim;
51338         for (i=0; i<iDim; i++)
51339         {
51340           idxIN = i + jXiDim;
51341           printf("%03.0f, ",data[idxIN]);
51342         }
51343         printf("\n");
51344       }
51345   }
51346 
51347   if (scanModeIN==scanModeOUT)
51348   {
51349     if (cdiDebugExt>=30) printf("convertDataScanningMode(): INFO: Nothing to do;  scanModeIN==scanModeOUT..\n");
51350     return;
51351   }
51352 
51353   if (0)
51354   {
51355       return;
51356       if (scanModeOUT==00)
51357       {
51358           if (cdiDebugExt>0) printf("convertDataScanningMode(): Leave data unchaged BUT set scanModeOUT=00.\n");
51359           // CHECK:  Looks like that GRIB-API provide (no matter what) data in the scannning mode 00, even it is store in the gribfile as 64 !!
51360           return;
51361       }
51362   }
51363   double *dataCopy = (double *) malloc(gridsize*sizeof(double));
51364   memcpy((void*)dataCopy,(void*) data, gridsize*sizeof(double));
51365 
51366   if (scanModeIN==64)  // Scanning Mode (00 dec)  +i, -j; i direction consecutive (row-major    order West->East   & South->North )
51367   {                    // Scanning Mode (64 dec)  +i, +j; i direction consecutive (row-major    order West->East   & North->South )
51368                        // Scanning Mode (96 dec)  +i, +j; j direction consecutive (column-major order North->South & West->East )
51369       if (scanModeOUT==00)
51370       // CHECK:  Looks like that GRIB-API provide (no matter what) data in the scannning mode 00, even it is store in the gribfile as 64 !!
51371 #define VERTICAL_FLIP
51372 #ifdef VERTICAL_FLIP
51373       { // flip the data vertically ..
51374         idxIN= 0; idxOUT= (jDim-1)*iDim;
51375         if (cdiDebugExt>=30) printf("convertDataScanningMode():  copying rows nr. (%04d : %04zu)\n",0,jDim-1);
51376         for (j=0; j<jDim; j++)
51377         {
51378           memcpy((void*)&data[idxOUT], (void*)&dataCopy[idxIN], iDim*sizeof(double));
51379           idxIN  += iDim; idxOUT -= iDim;
51380         }
51381       } // end if (scanModeOUT==00)*/
51382 #endif
51383 #ifdef HORIZONTAL_FLIP
51384       { // flip data horizontally ...
51385         if (1)
51386         {
51387             if (cdiDebugExt>=30) printf("convertDataScanningMode():  copying columns nr. (%04d : %04d);\n", 0, iDim-1);
51388             for (i=0; i<iDim; i++)
51389             {
51390               for (j=0; j<jDim; j++)
51391               {
51392                 size_t jXiDim = j*iDim;
51393                 idxIN  = i           + jXiDim;
51394                 //data[idxIN] = (double) (100.0*j +i);  // just some testdata ..
51395                 idxOUT = iDim - i -1 + jXiDim;
51396                 //printf("[%03d=>%03d] = %f;",idxIN,idxOUT,dataCopy[idxIN]);
51397                 data[idxOUT] =  dataCopy[idxIN];
51398               }
51399             }
51400         }
51401       } // end if (scanModeOUT==00)
51402 #endif
51403 
51404       if (scanModeOUT==96)
51405       { // transpose the data
51406         if (cdiDebugExt>=30) printf("convertDataScanningMode():  transpose data rows=>columns nr. (%04d : %04zu) => (%04d : %04zu);\n", 0, iDim-1, 0, jDim-1);
51407         for (j=0; j<jDim; j++)
51408         {
51409           size_t jXiDim = j*iDim;
51410           for (i=0; i<iDim; i++)
51411           {
51412             idxIN  = i + jXiDim;
51413             idxOUT = j + i*jDim;
51414             //printf("[%03d=>%03d] = %f;",idxIN,idxOUT,dataCopy[idxIN]);
51415             data[idxOUT] =  dataCopy[idxIN];
51416           }
51417           //printf(".\n");
51418         }
51419       } // end if (scanModeOUT==96)
51420   } // end if (scanModeIN==64)
51421 
51422   if (scanModeIN==00)  // Scanning Mode (00 dec)  +i, -j; i direction consecutive (row-major    order West->East   & South->North )
51423   {                    // Scanning Mode (64 dec)  +i, +j; i direction consecutive (row-major    order West->East   & North->South )
51424                        // Scanning Mode (96 dec)  +i, +j; j direction consecutive (column-major order North->South & West->East )
51425     if (scanModeOUT==64)
51426       { // flip the data vertically ..
51427         idxIN= 0; idxOUT= (jDim-1)*iDim;
51428         for (j=0; j<jDim; j++)
51429         {
51430           if (cdiDebugExt>=25) printf("convertDataScanningMode():  copying row nr. %04zu; [idxIN=%08zu] => [idxOUT=%08zu]\n",j, idxIN, idxOUT);
51431           memcpy((void*)&data[idxOUT], (void*)&dataCopy[idxIN], iDim*sizeof(double));
51432           idxIN  += iDim; idxOUT -= iDim;
51433         }
51434       } // end if (scanModeOUT==64)
51435 
51436       if (scanModeOUT==96)
51437       { // transpose the data
51438         size_t jInv;
51439         for (j=0; j<jDim; j++)
51440         {
51441           if (cdiDebugExt>=30) printf("convertDataScanningMode():  processing row nr. %04zu;\n", j);
51442           jInv = (jDim-1) -j;
51443           for (i=0; i<iDim; i++)
51444             data[j + i*jDim] =  dataCopy[i + jInv*iDim];  // source data has -j
51445         }
51446       } // end if (scanModeOUT==96)
51447   } // end if (scanModeIN==00)
51448 
51449   if (scanModeIN==96)  // Scanning Mode (00 dec)  +i, -j; i direction consecutive (row-major    order West->East   & South->North )
51450   {                    // Scanning Mode (64 dec)  +i, +j; i direction consecutive (row-major    order West->East   & North->South )
51451                        // Scanning Mode (96 dec)  +i, +j; j direction consecutive (column-major order North->South & West->East )
51452     if (scanModeOUT==64)
51453       { // transpose the data
51454         for (j=0; j<jDim; j++)
51455         {
51456           if (cdiDebugExt>=30) printf("convertDataScanningMode():  processing row nr. %04zu;\n", j);
51457           size_t jXiDim = j*iDim;
51458           for (i=0; i<iDim; i++)
51459             //data[j + i*jDim] =  dataCopy[i + j*iDim];
51460             data[i + jXiDim] =  dataCopy[j + i*jDim];
51461         }
51462       } // end if (scanModeOUT==64)
51463 
51464       if (scanModeOUT==00)
51465       { // transpose the data
51466         idxIN= 0; idxOUT= 0;
51467         size_t jInv;
51468         for (j=0; j<jDim; j++)
51469         {
51470           if (cdiDebugExt>=30) printf("convertDataScanningMode():  processing row nr. %04zu;\n", j);
51471           jInv = (jDim-1) -j;
51472           size_t jXiDim = j*iDim;
51473           for (i=0; i<iDim; i++)
51474             //data[jInv + iXjDim] =  dataCopy[i + jXiDim];  // target data has -j
51475             data[i + jXiDim] =  dataCopy[jInv + i*jDim];  // target data has -j
51476         }
51477       } // end if (scanModeOUT==00)
51478   } // end if (scanModeIN==96)
51479 
51480   if (cdiDebugExt>=100)
51481   {
51482       printf("convertDataScanningMode(): data OUT (new scanning mode):\n");
51483       for (j=0; j<jDim; j++)
51484       {
51485         size_t jXiDim = j*iDim;
51486         for (i=0; i<iDim; i++)
51487         {
51488           idxIN = i + jXiDim;
51489           printf("%03.0f, ",data[idxIN]);
51490         }
51491         printf("\n");
51492       }
51493   }
51494 
51495   free(dataCopy); return;
51496 }
51497 #endif //HIRLAM_EXTENSIONS
51498 
51499 static
gribapiSetExtMode(grib_handle * gh,int gridID,size_t datasize,const double * data)51500 void gribapiSetExtMode(grib_handle *gh, int gridID, size_t datasize, const double *data)
51501 {
51502   /*
51503   Nj = 550;
51504   latitudeOfFirstGridPointInDegrees = -30.8;
51505   latitudeOfLastGridPointInDegrees = 24.1;
51506   iScansNegatively = 0;
51507   jScansPositively = 0;
51508   jPointsAreConsecutive = 0;
51509   jDirectionIncrementInDegrees = 0.1; */
51510 #ifndef HIRLAM_EXTENSIONS
51511   (void)data;
51512   (void)datasize;
51513 #endif
51514   int gridtype = gridInqType(gridID);
51515   if ( gridtype == GRID_PROJECTION )
51516     {
51517       int projtype = gridInqProjType(gridID);
51518       if      ( projtype == CDI_PROJ_RLL )   gridtype = GRID_LONLAT;
51519       else if ( projtype == CDI_PROJ_LCC )   gridtype = CDI_PROJ_LCC;
51520       else if ( projtype == CDI_PROJ_STERE ) gridtype = CDI_PROJ_STERE;
51521     }
51522 
51523   if ( gridtype == GRID_GENERIC || gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN ||
51524        gridtype == GRID_GAUSSIAN_REDUCED || gridtype == CDI_PROJ_LCC )
51525     {
51526 #ifdef HIRLAM_EXTENSIONS
51527       int scanModeIN = 0;
51528       cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_SCANNINGMODE, &scanModeIN);
51529 
51530       if (cdiDebugExt>=100)
51531         {
51532           size_t gridsize = gridInqSize(gridID);
51533           Message("(scanModeIN=%d; gridsize=%zu", scanModeIN, gridsize);
51534         }
51535 
51536       if ( cdiGribDataScanningMode.active )   // allowed modes: <0, 64, 96>; Default is 64
51537         {
51538           size_t iDim = gridInqXsize(gridID);
51539           size_t jDim = gridInqYsize(gridID);
51540 
51541           double yfirst = gridInqYval(gridID,      0);
51542           double ylast  = gridInqYval(gridID, jDim-1);
51543           double yinc   = gridInqYinc(gridID);
51544 
51545           int scanModeOUT = cdiGribDataScanningMode.value;
51546           convertDataScanningMode(scanModeIN, scanModeOUT, (double*)data, datasize, iDim, jDim);
51547           // This will overrule the old scanning mode of the given grid
51548           if (cdiDebugExt>=10) Message("Set GribDataScanningMode (%d) => (%d)", scanModeIN, cdiGribDataScanningMode.value);
51549           gribapiSetScanningMode(gh, cdiGribDataScanningMode.value);
51550 
51551           if (((scanModeIN==00) && (cdiGribDataScanningMode.value==64)) ||
51552               ((scanModeIN==64) && (cdiGribDataScanningMode.value==00)) )
51553             verticallyFlipGridDefinitionWhenScanningModeChanged(gh, yfirst, ylast, yinc);
51554         }
51555       else
51556         {
51557           if (cdiDebugExt>=100) Message("Set GribDataScanningMode => (%d) based on used grid", scanModeIN);
51558           gribapiSetScanningMode(gh, scanModeIN);
51559         }
51560 #endif
51561     }
51562 }
51563 
51564 /* #define GRIBAPIENCODETEST 1 */
51565 
gribapiEncode(int varID,int levelID,int vlistID,int gridID,int zaxisID,int64_t vdate,int vtime,int tsteptype,int numavg,size_t datasize,const double * data,size_t nmiss,void ** gribbuffer,size_t * gribbuffersize,int comptype,void * gribContainer)51566 size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID,
51567 		     int64_t vdate, int vtime, int tsteptype, int numavg,
51568 		     size_t datasize, const double *data, size_t nmiss, void **gribbuffer, size_t *gribbuffersize,
51569 		     int comptype, void *gribContainer)
51570 {
51571   void *dummy = NULL;
51572   /*  int ensID, ensCount, forecast_type; *//* Ensemble Data */
51573   long editionNumber = 2;
51574 
51575   // extern unsigned char _grib_template_GRIB2[];
51576   cdi_check_gridsize_int_limit("GRIB", datasize);
51577 
51578   int param    = vlistInqVarParam(vlistID, varID);
51579   int datatype = vlistInqVarDatatype(vlistID, varID);
51580   int typeOfGeneratingProcess = 0;
51581   cdiInqKeyInt(vlistID, varID, CDI_KEY_TYPEOFGENERATINGPROCESS, &typeOfGeneratingProcess);
51582   int productDefinitionTemplate = 0;
51583   cdiInqKeyInt(vlistID, varID, CDI_KEY_PRODUCTDEFINITIONTEMPLATE, &productDefinitionTemplate);
51584 
51585   int uvRelativeToGrid = -1;
51586   cdiInqKeyInt(vlistID, varID, CDI_KEY_UVRELATIVETOGRID, &uvRelativeToGrid);
51587 
51588   char name[256], stdname[256];
51589   vlistInqVarName(vlistID, varID, name);
51590   vlistInqVarStdname(vlistID, varID, stdname);
51591 
51592 #ifdef  GRIBAPIENCODETEST
51593   grib_handle *gh = (grib_handle *) gribHandleNew(editionNumber);
51594 #else
51595   gribContainer_t *gc = (gribContainer_t *) gribContainer;
51596   assert(gc != NULL);
51597   grib_handle *gh = (struct grib_handle *) gc->gribHandle;
51598 #endif
51599 
51600   GRIB_CHECK(grib_get_long(gh, "editionNumber", &editionNumber), 0);
51601 
51602   if ( editionNumber == 2 )
51603     {
51604       if ( ! gc->init )
51605         {
51606           int backgroundProcess = 0;
51607           cdiInqKeyInt(vlistID, varID, CDI_KEY_BACKGROUNDPROCESS, &backgroundProcess);
51608           GRIB_CHECK(my_grib_set_long(gh, "typeOfGeneratingProcess", typeOfGeneratingProcess), 0);
51609           GRIB_CHECK(my_grib_set_long(gh, "backgroundProcess", backgroundProcess), 0);
51610           int status, tablesVersion, localTablesVersion;
51611           status = cdiInqKeyInt(vlistID, varID, CDI_KEY_TABLESVERSION, &tablesVersion);
51612           if ( status == 0 ) GRIB_CHECK(my_grib_set_long(gh, "tablesVersion", (long)tablesVersion), 0);
51613           status = cdiInqKeyInt(vlistID, varID, CDI_KEY_LOCALTABLESVERSION, &localTablesVersion);
51614           if ( status == 0 ) GRIB_CHECK(my_grib_set_long(gh, "localTablesVersion", (long)localTablesVersion), 0);
51615           int typeOfProcessedData = 0;
51616           status = cdiInqKeyInt(vlistID, varID, CDI_KEY_TYPEOFPROCESSEDDATA, &typeOfProcessedData);
51617           if ( status == 0 ) GRIB_CHECK(my_grib_set_long(gh, "typeOfProcessedData", (long)typeOfProcessedData), 0);
51618           /*
51619           int constituentType = 0;
51620           status = cdiInqKeyInt(vlistID, varID, CDI_KEY_CONSTITUENTTYPE, &constituentType);
51621           if ( status == 0 ) GRIB_CHECK(my_grib_set_long(gh, "constituentType", (long)constituentType), 0);
51622           */
51623         }
51624     }
51625 
51626   gribapiDefTime((int)editionNumber, productDefinitionTemplate, typeOfGeneratingProcess,
51627                  gh, vdate, vtime, tsteptype, numavg, vlistInqTaxis(vlistID), gc->init);
51628 
51629   {
51630     int typeOfTimeIncrement = 0;
51631     int status = cdiInqKeyInt(vlistID, varID, CDI_KEY_TYPEOFTIMEINCREMENT, &typeOfTimeIncrement);
51632     if ( status == 0 ) grib_set_long(gh, "typeOfTimeIncrement", (long)typeOfTimeIncrement);
51633   }
51634 
51635   {
51636     int status, perturbationNumber, numberOfForecastsInEnsemble, typeOfEnsembleForecast;
51637     status = cdiInqKeyInt(vlistID, varID, CDI_KEY_TYPEOFENSEMBLEFORECAST, &typeOfEnsembleForecast);
51638     if ( status == 0 ) grib_set_long(gh, "typeOfEnsembleForecast", typeOfEnsembleForecast);
51639     status = cdiInqKeyInt(vlistID, varID, CDI_KEY_NUMBEROFFORECASTSINENSEMBLE, &numberOfForecastsInEnsemble);
51640     if ( status == 0 ) grib_set_long(gh, "numberOfForecastsInEnsemble", numberOfForecastsInEnsemble);
51641     status = cdiInqKeyInt(vlistID, varID, CDI_KEY_PERTURBATIONNUMBER, &perturbationNumber);
51642     if ( status == 0 ) grib_set_long(gh, "perturbationNumber", perturbationNumber);
51643   }
51644 
51645   if ( ! gc->init ) gribapiDefInstitut(gh, vlistID, varID);
51646   if ( ! gc->init ) gribapiDefModel(gh, vlistID, varID);
51647 
51648   if ( ! gc->init ) gribapiDefParam((int)editionNumber, gh, param, name, stdname);
51649 
51650   if ( ! gc->init && editionNumber == 2 )
51651     {
51652       int shapeOfTheEarth = 0;
51653       cdiInqKeyInt(vlistID, varID, CDI_KEY_SHAPEOFTHEEARTH, &shapeOfTheEarth);
51654       GRIB_CHECK(my_grib_set_long(gh, "shapeOfTheEarth", (long)shapeOfTheEarth), 0);
51655 
51656       int grib2LocalSectionNumber, section2PaddingLength;
51657       int mpimType, mpimClass, mpimUser;
51658       if ( cdiInqKeyInt(vlistID, varID, CDI_KEY_MPIMTYPE, &mpimType) == CDI_NOERR &&
51659            cdiInqKeyInt(vlistID, varID, CDI_KEY_MPIMCLASS, &mpimClass) == CDI_NOERR &&
51660            cdiInqKeyInt(vlistID, varID, CDI_KEY_MPIMUSER, &mpimUser) == CDI_NOERR )
51661         {
51662           grib_set_long(gh, "grib2LocalSectionPresent", 1);
51663           grib_set_long(gh, "grib2LocalSectionNumber", 1);
51664           grib_set_long(gh, "mpimType", mpimType);
51665           grib_set_long(gh, "mpimClass", mpimClass);
51666           grib_set_long(gh, "mpimUser", mpimUser);
51667 
51668           int revNumLen = 20;
51669           unsigned char revNumber[revNumLen];
51670           if ( cdiInqKeyBytes(vlistID, varID, CDI_KEY_REVNUMBER, revNumber, &revNumLen) == CDI_NOERR )
51671             {
51672               size_t revNumLenS = revNumLen;
51673               grib_set_bytes(gh, "revNumber", revNumber, &revNumLenS);
51674             }
51675           int revStatus;
51676           if ( cdiInqKeyInt(vlistID, varID, CDI_KEY_REVSTATUS, &revStatus) == CDI_NOERR )
51677             grib_set_long(gh, "revStatus", revStatus);
51678         }
51679       else if ( cdiInqKeyInt(vlistID, varID, CDI_KEY_GRIB2LOCALSECTIONNUMBER, &grib2LocalSectionNumber) == CDI_NOERR &&
51680                 cdiInqKeyInt(vlistID, varID, CDI_KEY_SECTION2PADDINGLENGTH, &section2PaddingLength) == CDI_NOERR )
51681         {
51682           grib_set_long(gh, "grib2LocalSectionPresent", 1);
51683           grib_set_long(gh, "grib2LocalSectionNumber", grib2LocalSectionNumber);
51684           unsigned char *section2Padding = (unsigned char*) Malloc(section2PaddingLength);
51685           cdiInqKeyBytes(vlistID, varID, CDI_KEY_SECTION2PADDING, section2Padding, &section2PaddingLength);
51686           size_t len = section2PaddingLength;
51687           grib_set_bytes(gh, "section2Padding", section2Padding, &len);
51688           Free(section2Padding);
51689         }
51690     }
51691 
51692   // bitsPerValue have to be defined first (complex packing)
51693   GRIB_CHECK(my_grib_set_long(gh, "bitsPerValue", (long)grbBitsPerValue(datatype)), 0);
51694 
51695   if ( ! gc->init ) gribapiDefGrid((int)editionNumber, gh, gridID, comptype, datatype, uvRelativeToGrid);
51696 
51697   gribapiDefLevel((int)editionNumber, gh, zaxisID, levelID, gc->init, productDefinitionTemplate);
51698 
51699   vlist_t *vlistptr = vlist_to_pointer(vlistID);
51700   //if (!gc->init)
51701   {
51702     int ret = 0;
51703 
51704     /* NOTE: Optional key/value pairs: Note that we do not distinguish between tiles here! */
51705 
51706     for ( int i=0; i<vlistptr->vars[varID].opt_grib_nentries; i++ )
51707       {
51708         if ( vlistptr->vars[varID].opt_grib_kvpair[i].update )
51709           {
51710             //DR: Fix for multi-level fields (otherwise only the 1st level is correct)
51711             if ( zaxisInqSize(zaxisID)==(levelID+1) )
51712               vlistptr->vars[varID].opt_grib_kvpair[i].update = false;
51713 
51714             if (vlistptr->vars[varID].opt_grib_kvpair[i].data_type == t_double)
51715               {
51716                 if ( CDI_Debug )
51717                   Message("key \"%s\"  :   double value = %g\n",
51718                           vlistptr->vars[varID].opt_grib_kvpair[i].keyword,
51719                           vlistptr->vars[varID].opt_grib_kvpair[i].dbl_val);
51720                 my_grib_set_double(gh, vlistptr->vars[varID].opt_grib_kvpair[i].keyword,
51721                                    vlistptr->vars[varID].opt_grib_kvpair[i].dbl_val);
51722                 GRIB_CHECK(ret, 0);
51723               }
51724             if (vlistptr->vars[varID].opt_grib_kvpair[i].data_type == t_int)
51725               {
51726                 if ( CDI_Debug )
51727                   Message("key \"%s\"  :   integer value = %d\n",
51728                           vlistptr->vars[varID].opt_grib_kvpair[i].keyword,
51729                           vlistptr->vars[varID].opt_grib_kvpair[i].int_val);
51730                 my_grib_set_long(gh, vlistptr->vars[varID].opt_grib_kvpair[i].keyword,
51731                                  (long) vlistptr->vars[varID].opt_grib_kvpair[i].int_val);
51732                 GRIB_CHECK(ret, 0);
51733               }
51734           }
51735       }
51736   }
51737 
51738   if ( nmiss > 0 )
51739     {
51740       GRIB_CHECK(my_grib_set_long(gh, "bitmapPresent", 1), 0);
51741       GRIB_CHECK(my_grib_set_double(gh, "missingValue", vlistInqVarMissval(vlistID, varID)), 0);
51742     }
51743 
51744   gribapiSetExtMode(gh, gridID, datasize, data);
51745 
51746   GRIB_CHECK(grib_set_double_array(gh, "values", data, datasize), 0);
51747 
51748   /* get the size of coded message  */
51749   size_t recsize = 0;
51750   GRIB_CHECK(grib_get_message(gh, (const void **)&dummy, &recsize), 0);
51751   recsize += 512; /* add some space for possible filling */
51752   *gribbuffersize = recsize;
51753   *gribbuffer = Malloc(*gribbuffersize);
51754 
51755   if ( ! gc->init && editionNumber == 2 )
51756     {
51757       long pdis;
51758       grib_get_long(gh, "discipline", &pdis);
51759       if ( pdis != 255 )
51760         {
51761           char cdi_name[CDI_MAX_NAME]; cdi_name[0] = 0;
51762           vlistInqVarName(vlistID, varID, cdi_name);
51763           char grb_name[256];
51764           gribapiGetString(gh, "shortName", grb_name, sizeof(grb_name));
51765           strToLower(cdi_name);
51766           strToLower(grb_name);
51767           bool checkName = (!grb_name[0] && strncmp(cdi_name, "param", 5) == 0) ? false : true;
51768           if ( checkName && ((strlen(cdi_name) != strlen(grb_name)) || !strStartsWith(cdi_name, grb_name)) )
51769             Message("*** GRIB2 shortName does not correspond to chosen variable name: \"%s\" (\"%s\").",
51770                     grb_name[0]?grb_name:"unknown", cdi_name);
51771         }
51772     }
51773 
51774   /* get a copy of the coded message */
51775   GRIB_CHECK(grib_get_message_copy(gh, *gribbuffer, &recsize), 0);
51776 
51777 #ifdef  GRIBAPIENCODETEST
51778   gribHandleDelete(gh);
51779 #endif
51780 
51781   gc->init = true;
51782 
51783   return recsize;
51784 }
51785 
51786 
gribapiChangeParameterIdentification(grib_handle * gh,int code,int ltype,int level)51787 void gribapiChangeParameterIdentification(grib_handle *gh, int code, int ltype, int level)
51788 {
51789   //  timeRangeIndicator: could be included later
51790   if (code!=-1) GRIB_CHECK(my_grib_set_long(gh, "indicatorOfParameter", code), 0);
51791   if (ltype!=-1) GRIB_CHECK(my_grib_set_long(gh, "indicatorOfTypeOfLevel", ltype), 0);
51792   if (level!=-1) GRIB_CHECK(my_grib_set_long(gh, "level", level), 0);
51793 }
51794 
51795 #endif
51796 
51797 /*
51798  * Local Variables:
51799  * c-file-style: "Java"
51800  * c-basic-offset: 2
51801  * indent-tabs-mode: nil
51802  * show-trailing-whitespace: t
51803  * require-trailing-newline: t
51804  * End:
51805  */
51806 #ifdef HAVE_CONFIG_H
51807 #endif
51808 
51809 #include <float.h>
51810 
51811 
51812 
51813 
51814 #ifdef HAVE_LIBIEG
51815 
51816 static
iegInqDatatype(int prec)51817 int iegInqDatatype(int prec)
51818 {
51819   return (prec == EXSE_DOUBLE_PRECISION) ? CDI_DATATYPE_FLT64 : CDI_DATATYPE_FLT32;
51820 }
51821 
51822 static
iegDefDatatype(int datatype)51823 int iegDefDatatype(int datatype)
51824 {
51825   if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
51826     Error("CDI/IEG library does not support complex numbers!");
51827 
51828   if ( datatype != CDI_DATATYPE_FLT32 && datatype != CDI_DATATYPE_FLT64 )
51829     datatype = CDI_DATATYPE_FLT32;
51830 
51831   return (datatype == CDI_DATATYPE_FLT64) ? EXSE_DOUBLE_PRECISION : EXSE_SINGLE_PRECISION;
51832 }
51833 
iegReadRecord(stream_t * streamptr,double * data,size_t * nmiss)51834 void iegReadRecord(stream_t *streamptr, double *data, size_t *nmiss)
51835 {
51836   int vlistID = streamptr->vlistID;
51837   int fileID  = streamptr->fileID;
51838   int tsID    = streamptr->curTsID;
51839   int vrecID  = streamptr->tsteps[tsID].curRecID;
51840   int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
51841   int varID   = streamptr->tsteps[tsID].records[recID].varID;
51842   off_t recpos = streamptr->tsteps[tsID].records[recID].position;
51843 
51844   fileSetPos(fileID, recpos, SEEK_SET);
51845 
51846   void *iegp = streamptr->record->exsep;
51847   int status = iegRead(fileID, iegp);
51848   if ( status != 0 ) Error("Could not read IEG record!");
51849 
51850   iegInqDataDP(iegp, data);
51851 
51852   double missval = vlistInqVarMissval(vlistID, varID);
51853   int gridID  = vlistInqVarGrid(vlistID, varID);
51854   size_t size = gridInqSize(gridID);
51855 
51856   streamptr->numvals += size;
51857 
51858   *nmiss = 0;
51859   for ( size_t i = 0; i < size; i++ )
51860     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
51861       {
51862 	data[i] = missval;
51863 	(*nmiss)++;
51864       }
51865 }
51866 
51867 static
iegGetZaxisType(int iegleveltype)51868 int iegGetZaxisType(int iegleveltype)
51869 {
51870   int leveltype = 0;
51871 
51872   switch ( iegleveltype )
51873     {
51874     case IEG_LTYPE_SURFACE:
51875       {
51876 	leveltype = ZAXIS_SURFACE;
51877 	break;
51878       }
51879     case IEG_LTYPE_99:
51880     case IEG_LTYPE_ISOBARIC:
51881       {
51882 	leveltype = ZAXIS_PRESSURE;
51883 	break;
51884       }
51885     case IEG_LTYPE_HEIGHT:
51886       {
51887 	leveltype = ZAXIS_HEIGHT;
51888 	break;
51889       }
51890     case IEG_LTYPE_ALTITUDE:
51891       {
51892 	leveltype = ZAXIS_ALTITUDE;
51893 	break;
51894       }
51895     case IEG_LTYPE_HYBRID:
51896     case IEG_LTYPE_HYBRID_LAYER:
51897       {
51898 	leveltype = ZAXIS_HYBRID;
51899 	break;
51900       }
51901     case IEG_LTYPE_LANDDEPTH:
51902     case IEG_LTYPE_LANDDEPTH_LAYER:
51903       {
51904 	leveltype = ZAXIS_DEPTH_BELOW_LAND;
51905 	break;
51906       }
51907     case IEG_LTYPE_SEADEPTH:
51908       {
51909 	leveltype = ZAXIS_DEPTH_BELOW_SEA;
51910 	break;
51911       }
51912     default:
51913       {
51914 	leveltype = ZAXIS_GENERIC;
51915 	break;
51916       }
51917     }
51918 
51919   return leveltype;
51920 }
51921 
51922 
iegDefTime(int * pdb,int64_t date,int time,int taxisID)51923 static void iegDefTime(int *pdb, int64_t date, int time, int taxisID)
51924 {
51925   int timetype = (taxisID != -1) ? taxisInqType(taxisID) : -1;
51926   if ( timetype == TAXIS_ABSOLUTE || timetype == TAXIS_RELATIVE )
51927     {
51928       int year, month, day, hour, minute, second;
51929       cdiDecodeDate(date, &year, &month, &day);
51930       cdiDecodeTime(time, &hour, &minute, &second);
51931 
51932       IEG_P_Year(pdb)     = year;
51933       IEG_P_Month(pdb)    = month;
51934       IEG_P_Day(pdb)      = day;
51935       IEG_P_Hour(pdb)     = hour;
51936       IEG_P_Minute(pdb)   = minute;
51937 
51938       pdb[15] = 1;
51939       pdb[16] = 0;
51940       pdb[17] = 0;
51941       pdb[18] = 10;
51942       pdb[36] = 1;
51943     }
51944 
51945   pdb[5] = 128;
51946 }
51947 
51948 /* find smallest power of 10 in [1000,10000000] that upon
51949  * multiplication results in fractional part close to zero for all
51950  * arguments */
51951 static double
calc_resfac(double xfirst,double xlast,double xinc,double yfirst,double ylast,double yinc)51952 calc_resfac(double xfirst, double xlast, double xinc, double yfirst, double ylast, double yinc)
51953 {
51954   double resfac = 1000.0;
51955   enum {
51956     nPwrOf10 = 5,
51957     nMultTests = 6,
51958   };
51959   static const double scaleFactors[nPwrOf10]
51960     = { 1000, 10000, 100000, 1000000, 10000000 };
51961   double vals[nMultTests] = { xfirst, xlast, xinc, yfirst, ylast, yinc };
51962 
51963   for (size_t j = 0; j < nPwrOf10; ++j )
51964     {
51965       double scaleBy = scaleFactors[j];
51966       bool fractionalScale = false;
51967       for (size_t i = 0; i < nMultTests; ++i )
51968         {
51969           fractionalScale = fractionalScale || fabs(vals[i]*scaleBy - round(vals[i]*scaleBy)) > FLT_EPSILON;
51970         }
51971       if ( !fractionalScale )
51972         {
51973           resfac = scaleBy;
51974           break;
51975         }
51976     }
51977 
51978   return resfac;
51979 }
51980 
51981 static
iegDefGrid(int * gdb,int gridID)51982 void iegDefGrid(int *gdb, int gridID)
51983 {
51984   int projID = gridInqProj(gridID);
51985   if ( projID != CDI_UNDEFID && gridInqProjType(projID) == CDI_PROJ_RLL ) gridID = projID;
51986 
51987   int gridtype = gridInqType(gridID);
51988   int projtype = CDI_UNDEFID;
51989   if ( gridtype == GRID_PROJECTION && gridInqProjType(gridID) == CDI_PROJ_RLL ) projtype = CDI_PROJ_RLL;
51990 
51991   size_t xsize = gridInqXsize(gridID);
51992   size_t ysize = gridInqYsize(gridID);
51993 
51994   cdi_check_gridsize_int_limit("IEG", xsize*ysize);
51995 
51996   if ( gridtype == GRID_GENERIC )
51997     {
51998       if ( (ysize == 32  || ysize == 48 || ysize == 64 || ysize == 96  || ysize == 160) &&
51999 	   (xsize == 2*ysize || xsize == 1) )
52000 	{
52001 	  gridtype = GRID_GAUSSIAN;
52002 	  gridChangeType(gridID, gridtype);
52003 	}
52004       else if ( (xsize == 1 && ysize == 1) || (xsize == 0 && ysize == 0) )
52005 	{
52006 	  gridtype = GRID_LONLAT;
52007 	  gridChangeType(gridID, gridtype);
52008 	}
52009       else if ( gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL) )
52010 	{
52011 	  gridtype = GRID_LONLAT;
52012 	  gridChangeType(gridID, gridtype);
52013 	}
52014     }
52015   else if ( gridtype == GRID_CURVILINEAR )
52016     {
52017       gridtype = GRID_LONLAT;
52018     }
52019 
52020   bool lrotated = (projtype == CDI_PROJ_RLL);
52021 
52022   if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || projtype == CDI_PROJ_RLL )
52023     {
52024       double xfirst = 0, xlast = 0, xinc = 0;
52025       double yfirst = 0, ylast = 0, yinc = 0;
52026 
52027       if ( xsize == 0 ) xsize = 1;
52028       else
52029 	{
52030 	  xfirst = gridInqXval(gridID,       0);
52031 	  xlast  = gridInqXval(gridID, xsize-1);
52032 	  xinc   = gridInqXinc(gridID);
52033 	}
52034 
52035       if ( ysize == 0 ) ysize = 1;
52036       else
52037 	{
52038 	  yfirst = gridInqYval(gridID,       0);
52039 	  ylast  = gridInqYval(gridID, ysize-1);
52040 	  yinc   = gridInqYinc(gridID);
52041 	}
52042 
52043       if ( gridtype == GRID_GAUSSIAN )
52044 	IEG_G_GridType(gdb) = 4;
52045       else if ( lrotated )
52046 	IEG_G_GridType(gdb) = 10;
52047       else
52048 	IEG_G_GridType(gdb) = 0;
52049 
52050       double resfac = calc_resfac(xfirst, xlast, xinc, yfirst, ylast, yinc);
52051       int iresfac = (int)resfac;
52052       if ( iresfac == 1000 ) iresfac = 0;
52053 
52054       IEG_G_ResFac(gdb)   = iresfac;
52055 
52056       IEG_G_NumLon(gdb)   = (int)xsize;
52057       IEG_G_NumLat(gdb)   = (int)ysize;
52058       IEG_G_FirstLat(gdb) = (int)lround(yfirst*resfac);
52059       IEG_G_LastLat(gdb)  = (int)lround(ylast*resfac);
52060       IEG_G_FirstLon(gdb) = (int)lround(xfirst*resfac);
52061       IEG_G_LastLon(gdb)  = (int)lround(xlast*resfac);
52062       IEG_G_LonIncr(gdb)  = (int)lround(xinc*resfac);
52063       if ( fabs(xinc*resfac - IEG_G_LonIncr(gdb)) > FLT_EPSILON )
52064 	IEG_G_LonIncr(gdb) = 0;
52065 
52066       if ( gridtype == GRID_GAUSSIAN )
52067 	IEG_G_LatIncr(gdb) = (int)ysize/2;
52068       else
52069 	{
52070 	  IEG_G_LatIncr(gdb) = (int)lround(yinc*resfac);
52071 	  if ( fabs(yinc*resfac - IEG_G_LatIncr(gdb)) > FLT_EPSILON )
52072 	    IEG_G_LatIncr(gdb) = 0;
52073 
52074 	  if ( IEG_G_LatIncr(gdb) < 0 ) IEG_G_LatIncr(gdb) = -IEG_G_LatIncr(gdb);
52075 	}
52076 
52077       if ( IEG_G_NumLon(gdb) > 1 && IEG_G_NumLat(gdb) == 1 )
52078 	if ( IEG_G_LonIncr(gdb) != 0 && IEG_G_LatIncr(gdb) == 0 ) IEG_G_LatIncr(gdb) = IEG_G_LonIncr(gdb);
52079 
52080       if ( IEG_G_NumLon(gdb) == 1 && IEG_G_NumLat(gdb) > 1 )
52081 	if ( IEG_G_LonIncr(gdb) == 0 && IEG_G_LatIncr(gdb) != 0 ) IEG_G_LonIncr(gdb) = IEG_G_LatIncr(gdb);
52082 
52083       IEG_G_ResFlag(gdb) = (IEG_G_LatIncr(gdb) == 0 || IEG_G_LonIncr(gdb) == 0) ? 0 : 128;
52084 
52085       if ( lrotated )
52086 	{
52087           double xpole = 0, ypole = 0, angle = 0;
52088           gridInqParamRLL(gridID, &xpole, &ypole, &angle);
52089 
52090 	  IEG_G_LatSP(gdb) = - (int)lround(ypole * resfac);
52091 	  IEG_G_LonSP(gdb) =   (int)lround((xpole + 180) * resfac);
52092 	  IEG_G_Size(gdb)  = 42;
52093 	}
52094       else
52095 	{
52096 	  IEG_G_Size(gdb)  = 32;
52097 	}
52098     }
52099   else
52100     {
52101       Error("Unsupported grid type: %s", gridNamePtr(gridtype));
52102     }
52103 
52104   IEG_G_ScanFlag(gdb) = 64;
52105 }
52106 
52107 static
pdbDefLevel(int * pdb,int leveltype,int level1,int level2)52108 void pdbDefLevel(int *pdb, int leveltype, int level1, int level2)
52109 {
52110   IEG_P_LevelType(pdb) = leveltype;
52111   IEG_P_Level1(pdb)    = level1;
52112   IEG_P_Level2(pdb)    = level2;
52113 }
52114 
52115 static
iegDefLevel(int * pdb,int * gdb,double * vct,int zaxisID,int levelID)52116 void iegDefLevel(int *pdb, int *gdb, double *vct, int zaxisID, int levelID)
52117 {
52118   double level;
52119 
52120   int leveltype = zaxisInqType(zaxisID);
52121   if ( leveltype == ZAXIS_GENERIC )
52122     {
52123       Message("Changed zaxis type from %s to %s",
52124 	      zaxisNamePtr(leveltype), zaxisNamePtr(ZAXIS_PRESSURE));
52125       leveltype = ZAXIS_PRESSURE;
52126       zaxisChangeType(zaxisID, leveltype);
52127       cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, "Pa");
52128     }
52129 
52130   /*  IEG_G_NumVCP(gdb) = 0; */
52131 
52132   switch (leveltype)
52133     {
52134     case ZAXIS_SURFACE:
52135       {
52136         pdbDefLevel(pdb, IEG_LTYPE_SURFACE, 0, (int)(zaxisInqLevel(zaxisID, levelID)));
52137 	break;
52138       }
52139     case ZAXIS_HYBRID:
52140       {
52141 	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
52142           pdbDefLevel(pdb, IEG_LTYPE_HYBRID_LAYER, (int)(zaxisInqLbound(zaxisID, levelID)),
52143                       (int)(zaxisInqUbound(zaxisID, levelID)));
52144 	else
52145           pdbDefLevel(pdb, IEG_LTYPE_HYBRID, 0, (int)(zaxisInqLevel(zaxisID, levelID)));
52146 
52147 	int vctsize = zaxisInqVctSize(zaxisID);
52148 	if ( vctsize > 100 )
52149 	  {
52150             static bool vct_warning = true;
52151 	    /*	    IEG_G_NumVCP(gdb) = 0; */
52152 	    if ( vct_warning )
52153 	      {
52154 		Warning("VCT size of %d is too large (maximum is 100). Set to 0!", vctsize);
52155 		vct_warning = false;
52156 	      }
52157 	  }
52158 	else
52159 	  {
52160 	    IEG_G_Size(gdb) += (vctsize*4);
52161 	    memcpy(vct, zaxisInqVctPtr(zaxisID), (size_t)vctsize/2*sizeof(double));
52162 	    memcpy(vct+50, zaxisInqVctPtr(zaxisID)+vctsize/2, (size_t)vctsize/2*sizeof(double));
52163 	  }
52164 	break;
52165       }
52166     case ZAXIS_PRESSURE:
52167       {
52168 	level = zaxisInqLevel(zaxisID, levelID);
52169 	if ( level < 0 ) Warning("pressure level of %f Pa is below 0.", level);
52170 
52171  	char units[CDI_MAX_NAME];
52172         int length = CDI_MAX_NAME;
52173         cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, units, &length);
52174 	if ( memcmp(units, "hPa", 3) == 0 || memcmp(units, "mb",2 ) == 0 )
52175 	  level = level*100;
52176 
52177 	double dum;
52178 	int ilevel = (int) level;
52179 	if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
52180           pdbDefLevel(pdb, IEG_LTYPE_99, 0, ilevel);
52181 	else
52182           pdbDefLevel(pdb, IEG_LTYPE_ISOBARIC, 0, ilevel/100);
52183 
52184         break;
52185       }
52186     case ZAXIS_HEIGHT:
52187       {
52188 	level = zaxisInqLevel(zaxisID, levelID);
52189         pdbDefLevel(pdb, IEG_LTYPE_HEIGHT, 0, (int)level);
52190 	break;
52191       }
52192     case ZAXIS_ALTITUDE:
52193       {
52194 	level = zaxisInqLevel(zaxisID, levelID);
52195         pdbDefLevel(pdb, IEG_LTYPE_ALTITUDE, 0, (int)level);
52196 	break;
52197       }
52198     case ZAXIS_DEPTH_BELOW_LAND:
52199       {
52200 	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
52201           pdbDefLevel(pdb, IEG_LTYPE_LANDDEPTH_LAYER, (int)(zaxisInqLbound(zaxisID, levelID)), (int)(zaxisInqUbound(zaxisID, levelID)));
52202 	else
52203           pdbDefLevel(pdb, IEG_LTYPE_LANDDEPTH, 0, (int)(zaxisInqLevel(zaxisID, levelID)));
52204 
52205 	break;
52206       }
52207     case ZAXIS_DEPTH_BELOW_SEA:
52208       {
52209 	level = zaxisInqLevel(zaxisID, levelID);
52210         pdbDefLevel(pdb, IEG_LTYPE_SEADEPTH, 0, (int)level);
52211 	break;
52212       }
52213     case ZAXIS_ISENTROPIC:
52214       {
52215 	level = zaxisInqLevel(zaxisID, levelID);
52216         pdbDefLevel(pdb, 113, 0, (int)level);
52217 	break;
52218       }
52219     default:
52220       {
52221 	Error("Unsupported zaxis type: %s", zaxisNamePtr(leveltype));
52222 	break;
52223       }
52224     }
52225 }
52226 
52227 
iegCopyRecord(stream_t * streamptr2,stream_t * streamptr1)52228 void iegCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
52229 {
52230   streamFCopyRecord(streamptr2, streamptr1, "IEG");
52231 }
52232 
52233 
iegDefRecord(stream_t * streamptr)52234 void iegDefRecord(stream_t *streamptr)
52235 {
52236   Record *record = streamptr->record;
52237 
52238   int vlistID = streamptr->vlistID;
52239   int byteorder = streamptr->byteorder;
52240 
52241   int varID   = record->varID;
52242   int levelID = record->levelID;
52243   int tsID    = streamptr->curTsID;
52244 
52245   int gridID  = vlistInqVarGrid(vlistID, varID);
52246   int zaxisID = vlistInqVarZaxis(vlistID, varID);
52247 
52248   iegrec_t *iegp = (iegrec_t*) record->exsep;
52249   iegInitMem(iegp);
52250   for ( int i = 0; i < 37; i++ ) iegp->ipdb[i] = -1;
52251 
52252   iegp->byteswap = getByteswap(byteorder);
52253 
52254   int param = vlistInqVarParam(vlistID, varID);
52255   int pdis, pcat, pnum;
52256   cdiDecodeParam(param, &pnum, &pcat, &pdis);
52257   IEG_P_Parameter(iegp->ipdb) = pnum;
52258   if ( pdis == 255 ) IEG_P_CodeTable(iegp->ipdb) = pcat;
52259 
52260   int64_t date = streamptr->tsteps[tsID].taxis.vdate;
52261   int time = streamptr->tsteps[tsID].taxis.vtime;
52262   iegDefTime(iegp->ipdb, date, time, vlistInqTaxis(vlistID));
52263   iegDefGrid(iegp->igdb, gridID);
52264   iegDefLevel(iegp->ipdb, iegp->igdb, iegp->vct, zaxisID, levelID);
52265 
52266   iegp->dprec = iegDefDatatype(record->prec);
52267 }
52268 
52269 
iegWriteRecord(stream_t * streamptr,const double * data)52270 void iegWriteRecord(stream_t *streamptr, const double *data)
52271 {
52272   Record *record = streamptr->record;
52273   iegrec_t *iegp = (iegrec_t*) record->exsep;
52274 
52275   int fileID = streamptr->fileID;
52276   size_t gridsize = gridInqSize(record->gridID);
52277 
52278   double refval = data[0];
52279   for ( size_t i = 1; i < gridsize; i++ )
52280     if ( data[i] < refval ) refval = data[i];
52281 
52282   iegp->refval = refval;
52283 
52284   iegDefDataDP(iegp, data);
52285   iegWrite(fileID, iegp);
52286 }
52287 
52288 static
iegAddRecord(stream_t * streamptr,int param,int * pdb,int * gdb,double * vct,size_t recsize,off_t position,int prec)52289 void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vct,
52290 		  size_t recsize, off_t position, int prec)
52291 {
52292   const int vlistID = streamptr->vlistID;
52293   const int tsID    = streamptr->curTsID;
52294   const int recID   = recordNewEntry(streamptr, tsID);
52295   record_t *record = &streamptr->tsteps[tsID].records[recID];
52296 
52297   int level1, level2;
52298   if ( IEG_P_LevelType(pdb) == IEG_LTYPE_HYBRID_LAYER )
52299     {
52300       level1 = IEG_P_Level1(pdb);
52301       level2 = IEG_P_Level2(pdb);
52302     }
52303   else
52304     {
52305       level1 = IEG_P_Level2(pdb);
52306       level2 = 0;
52307       if ( IEG_P_LevelType(pdb) == 100 ) level1 *= 100;
52308     }
52309 
52310   record->size     = recsize;
52311   record->position = position;
52312   record->param    = param;
52313   record->ilevel   = level1;
52314   record->ilevel2  = level2;
52315   record->ltype    = IEG_P_LevelType(pdb);
52316 
52317   int gridtype = (IEG_G_GridType(gdb) == 0) ? GRID_LONLAT :
52318                  (IEG_G_GridType(gdb) == 10) ? GRID_PROJECTION :
52319                  (IEG_G_GridType(gdb) == 4) ? GRID_GAUSSIAN : GRID_GENERIC;
52320 
52321   grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
52322   grid_init(grid);
52323   cdiGridTypeInit(grid, gridtype, IEG_G_NumLon(gdb)*IEG_G_NumLat(gdb));
52324   const size_t xsize = (size_t)IEG_G_NumLon(gdb);
52325   const size_t ysize = (size_t)IEG_G_NumLat(gdb);
52326   grid->x.size = xsize;
52327   grid->y.size = ysize;
52328   grid->x.inc  = 0;
52329   grid->y.inc  = 0;
52330   grid->x.flag = 0;
52331 
52332   int iresfac = IEG_G_ResFac(gdb);
52333   if ( iresfac == 0 ) iresfac = 1000;
52334   const double resfac = 1./(double) iresfac;
52335 
52336   /* if ( IEG_G_FirstLon != 0 || IEG_G_LastLon != 0 ) */
52337   {
52338     if ( xsize > 1 )
52339       {
52340 	if ( IEG_G_ResFlag(gdb) && IEG_G_LonIncr(gdb) > 0 )
52341 	  grid->x.inc = IEG_G_LonIncr(gdb) * resfac;
52342 	else
52343 	  grid->x.inc = (IEG_G_LastLon(gdb) - IEG_G_FirstLon(gdb)) * resfac / (xsize - 1);
52344 
52345 	/* correct xinc if necessary */
52346 	if ( IEG_G_FirstLon(gdb) == 0 && IEG_G_LastLon(gdb) > 354000 )
52347 	  {
52348 	    const double xinc = 360. / xsize;
52349             /* FIXME: why not use grid->x.inc != xinc as condition? */
52350 	    if ( fabs(grid->x.inc-xinc) > 0.0 )
52351 	      {
52352 		grid->x.inc = xinc;
52353 		if ( CDI_Debug ) Message("set xinc to %g", grid->x.inc);
52354 	      }
52355 	  }
52356       }
52357     grid->x.first = IEG_G_FirstLon(gdb) * resfac;
52358     grid->x.last  = IEG_G_LastLon(gdb)  * resfac;
52359     grid->x.flag  = 2;
52360   }
52361   grid->y.flag = 0;
52362   /* if ( IEG_G_FirstLat != 0 || IEG_G_LastLat != 0 ) */
52363   {
52364     if ( ysize > 1 )
52365       {
52366 	if ( IEG_G_ResFlag(gdb) && IEG_G_LatIncr(gdb) > 0 )
52367 	  grid->y.inc = IEG_G_LatIncr(gdb) * resfac;
52368 	else
52369 	  grid->y.inc = (IEG_G_LastLat(gdb) - IEG_G_FirstLat(gdb)) * resfac / (ysize - 1);
52370       }
52371     grid->y.first = IEG_G_FirstLat(gdb) * resfac;
52372     grid->y.last  = IEG_G_LastLat(gdb)  * resfac;
52373     grid->y.flag  = 2;
52374   }
52375 
52376   double xpole = 0, ypole = 0;
52377   if ( IEG_G_GridType(gdb) == 10 )
52378     {
52379       xpole =   IEG_G_LonSP(gdb) * resfac - 180;
52380       ypole = - IEG_G_LatSP(gdb) * resfac;
52381       grid->projtype = CDI_PROJ_RLL;
52382     }
52383 
52384   struct addIfNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
52385   const int gridID = gridAdded.Id;
52386   if ( !gridAdded.isNew ) Free(grid);
52387   else if ( gridtype == GRID_PROJECTION ) gridDefParamRLL(gridID, xpole, ypole, 0);
52388 
52389   int leveltype = iegGetZaxisType(IEG_P_LevelType(pdb));
52390   if ( leveltype == ZAXIS_HYBRID )
52391     {
52392       double tmpvct[100];
52393       size_t vctsize = (size_t)IEG_G_NumVCP(gdb);
52394 
52395       for ( size_t i = 0; i < vctsize/2; i++ ) tmpvct[i] = vct[i];
52396       for ( size_t i = 0; i < vctsize/2; i++ ) tmpvct[i+vctsize/2] = vct[i+50];
52397 
52398       varDefVCT(vctsize, tmpvct);
52399     }
52400 
52401   const int lbounds = IEG_P_LevelType(pdb) == IEG_LTYPE_HYBRID_LAYER ? 1 : 0;
52402 
52403   const int datatype = iegInqDatatype(prec);
52404 
52405   int varID, levelID = 0;
52406   varAddRecord(recID, param, gridID, leveltype, lbounds, level1, level2, 0, 0,
52407 	       datatype, &varID, &levelID, TSTEP_INSTANT, 0, -1,
52408                NULL, NULL, NULL, NULL);
52409 
52410   record->varID   = (short)varID;
52411   record->levelID = (short)levelID;
52412 
52413   streamptr->tsteps[tsID].nallrecs++;
52414   streamptr->nrecs++;
52415 
52416   if ( CDI_Debug )
52417     Message("varID = %d gridID = %d levelID = %d", varID, gridID, levelID);
52418 }
52419 
52420 #if 0
52421 static
52422 void iegCmpRecord(stream_t *streamptr, int tsID, int recID, off_t position, int param,
52423 		  int level, size_t xsize, size_t ysize)
52424 {
52425   int varID = 0;
52426   int levelID = 0;
52427 
52428   record_t *record  = &streamptr->tsteps[tsID].records[recID];
52429 
52430   if ( param != (*record).param || level != (*record).ilevel )
52431     Error("inconsistent timestep");
52432 
52433   (*record).position = position;
52434   /*
52435   varID   = (*record).varID;
52436   levelID = (*record).levelID;
52437 
52438   streamptr->vars[varID].level[levelID] = recID;
52439 
52440   streamptr->tsteps[tsID].nallrecs++;
52441   streamptr->nrecs++;
52442   */
52443   if ( CDI_Debug )
52444     Message("varID = %d levelID = %d", varID, levelID);
52445 }
52446 #endif
52447 
52448 static
iegDateTime(int * pdb,int64_t * date,int * time)52449 void iegDateTime(int *pdb, int64_t *date, int *time)
52450 {
52451   int ryear   = IEG_P_Year(pdb);
52452   int rmonth  = IEG_P_Month(pdb);
52453   int rday    = IEG_P_Day(pdb);
52454 
52455   int rhour   = IEG_P_Hour(pdb);
52456   int rminute = IEG_P_Minute(pdb);
52457 
52458   if ( rminute == -1 ) rminute = 0;
52459 
52460   *date = cdiEncodeDate(ryear, rmonth, rday);
52461   *time = cdiEncodeTime(rhour, rminute, 0);
52462 }
52463 
52464 static
iegScanTimestep1(stream_t * streamptr)52465 void iegScanTimestep1(stream_t *streamptr)
52466 {
52467   DateTime datetime0 = { LONG_MIN, LONG_MIN };
52468   off_t recpos;
52469   iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
52470 
52471   streamptr->curTsID = 0;
52472 
52473   int tsID = tstepsNewEntry(streamptr);
52474   if ( tsID != 0 ) Error("Internal problem! tstepsNewEntry returns %d", tsID);
52475   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
52476 
52477   const int fileID = streamptr->fileID;
52478 
52479   int nrecs = 0;
52480   while ( true )
52481     {
52482       recpos = fileGetPos(fileID);
52483       if ( iegRead(fileID, iegp) != 0 )
52484 	{
52485 	  streamptr->ntsteps = 1;
52486 	  break;
52487 	}
52488 
52489       const size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
52490 
52491       const int prec   = iegp->dprec;
52492       const int rcode  = IEG_P_Parameter(iegp->ipdb);
52493       const int tabnum = IEG_P_CodeTable(iegp->ipdb);
52494       const int param  = cdiEncodeParam(rcode, tabnum, 255);
52495       int rlevel = (IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER) ? IEG_P_Level1(iegp->ipdb) : IEG_P_Level2(iegp->ipdb);
52496 
52497       if ( IEG_P_LevelType(iegp->ipdb) == 100 ) rlevel *= 100;
52498 
52499       int64_t vdate = 0;
52500       int vtime = 0;
52501       iegDateTime(iegp->ipdb, &vdate, &vtime);
52502       DateTime datetime = { .date = vdate, .time = vtime};
52503 
52504       if ( nrecs == 0 )
52505 	{
52506 	  datetime0 = datetime;
52507           taxis->vdate = vdate;
52508           taxis->vtime = vtime;
52509 	}
52510       else
52511 	{
52512           record_t *records = streamptr->tsteps[tsID].records;
52513 	  for ( int recID = 0; recID < nrecs; recID++ )
52514             if ( param == records[recID].param && rlevel == records[recID].ilevel )
52515               goto tstepScanLoopFinished;
52516 
52517 	  if ( datetimeDiffer(datetime, datetime0) )
52518 	    Warning("Inconsistent verification time for param %d level %d", param, rlevel);
52519 	}
52520 
52521       nrecs++;
52522 
52523       if ( CDI_Debug )
52524 	Message("%4d%8d%4d%8d%8ld%6d", nrecs, (int)recpos, param, rlevel, (long)vdate, vtime);
52525 
52526       iegAddRecord(streamptr, param, iegp->ipdb, iegp->igdb, iegp->vct, recsize, recpos, prec);
52527     }
52528 
52529   tstepScanLoopFinished:
52530   streamptr->rtsteps = 1;
52531 
52532   cdi_generate_vars(streamptr);
52533 
52534   const int taxisID = taxisCreate(TAXIS_ABSOLUTE);
52535   taxis->type  = TAXIS_ABSOLUTE;
52536   taxis->rdate = taxis->vdate;
52537   taxis->rtime = taxis->vtime;
52538 
52539   const int vlistID = streamptr->vlistID;
52540   vlistDefTaxis(vlistID, taxisID);
52541 
52542   vlist_check_contents(vlistID);
52543 
52544   streamScanResizeRecords1(streamptr);
52545 
52546   streamScanTsFixNtsteps(streamptr, recpos);
52547   streamScanTimeConstAdjust(streamptr, taxis);
52548 }
52549 
52550 static
iegScanTimestep2(stream_t * streamptr)52551 int iegScanTimestep2(stream_t *streamptr)
52552 {
52553   off_t recpos = 0;
52554   iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
52555 
52556   streamptr->curTsID = 1;
52557 
52558   const int vlistID = streamptr->vlistID;
52559   const int fileID  = streamptr->fileID;
52560 
52561   const int tsID = streamptr->rtsteps;
52562   if ( tsID != 1 ) Error("Internal problem! unexpected timestep %d", tsID+1);
52563 
52564   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
52565 
52566   fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
52567 
52568   cdi_create_records(streamptr, tsID);
52569   record_t *records = streamptr->tsteps[tsID].records;
52570 
52571   const int nrecords = streamScanInitRecords2(streamptr);
52572 
52573   for ( int rindex = 0; rindex <= nrecords; rindex++ )
52574     {
52575       recpos = fileGetPos(fileID);
52576       if ( iegRead(fileID, iegp) != 0 )
52577 	{
52578 	  streamptr->ntsteps = 2;
52579 	  break;
52580 	}
52581 
52582       const size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
52583 
52584       const int rcode  = IEG_P_Parameter(iegp->ipdb);
52585       const int tabnum = IEG_P_CodeTable(iegp->ipdb);
52586       const int param  = cdiEncodeParam(rcode, tabnum, 255);
52587       int rlevel = (IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER) ? IEG_P_Level1(iegp->ipdb) : IEG_P_Level2(iegp->ipdb);
52588 
52589       if ( IEG_P_LevelType(iegp->ipdb) == 100 ) rlevel *= 100;
52590 
52591       int64_t vdate = 0;
52592       int vtime = 0;
52593       iegDateTime(iegp->ipdb, &vdate, &vtime);
52594 
52595       if ( rindex == 0 )
52596 	{
52597 	  taxis->type  = TAXIS_ABSOLUTE;
52598 	  taxis->vdate = vdate;
52599 	  taxis->vtime = vtime;
52600 	}
52601 
52602       bool nextstep = false;
52603       int recID = 0;
52604       for ( recID = 0; recID < nrecords; recID++ )
52605 	{
52606 	  if ( param == records[recID].param && rlevel == records[recID].ilevel )
52607 	    {
52608 	      if ( records[recID].used )
52609 		{
52610 		  nextstep = true;
52611 		}
52612 	      else
52613 		{
52614 		  records[recID].used = true;
52615 		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
52616 		}
52617 	      break;
52618 	    }
52619 	}
52620       if ( recID == nrecords )
52621 	{
52622 	  char paramstr[32];
52623 	  cdiParamToString(param, paramstr, sizeof(paramstr));
52624 	  Warning("param %s level %d not defined at timestep 1", paramstr, rlevel);
52625 	  return CDI_EUFSTRUCT;
52626 	}
52627 
52628       if ( nextstep ) break;
52629 
52630       if ( CDI_Debug )
52631 	Message("%4d%8d%4d%8d%8ld%6d", rindex+1, (int)recpos, param, rlevel, (long)vdate, vtime);
52632 
52633       if ( param != records[recID].param || rlevel != records[recID].ilevel )
52634 	{
52635 	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
52636 		  tsID, recID, records[recID].param, param, records[recID].ilevel, rlevel);
52637 	  return CDI_EUFSTRUCT;
52638 	}
52639 
52640       records[recID].position = recpos;
52641       records[recID].size = recsize;
52642     }
52643 
52644   int nrecs = 0;
52645   for ( int recID = 0; recID < nrecords; recID++ )
52646     {
52647       if ( ! records[recID].used )
52648 	{
52649           vlistDefVarTimetype(vlistID, records[recID].varID, TIME_CONSTANT);
52650 	}
52651       else
52652 	{
52653 	  nrecs++;
52654 	}
52655     }
52656   streamptr->tsteps[tsID].nrecs = nrecs;
52657 
52658   streamptr->rtsteps = 2;
52659 
52660   streamScanTsFixNtsteps(streamptr, recpos);
52661 
52662   return 0;
52663 }
52664 
52665 
iegInqContents(stream_t * streamptr)52666 int iegInqContents(stream_t *streamptr)
52667 {
52668   streamptr->curTsID = 0;
52669 
52670   iegScanTimestep1(streamptr);
52671 
52672   const int status = (streamptr->ntsteps == -1) ? iegScanTimestep2(streamptr) : 0;
52673 
52674   fileSetPos(streamptr->fileID, 0, SEEK_SET);
52675 
52676   return status;
52677 }
52678 
52679 static
iegScanTimestep(stream_t * streamptr)52680 long iegScanTimestep(stream_t *streamptr)
52681 {
52682   off_t recpos = 0;
52683   iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
52684 
52685   if ( streamptr->rtsteps == 0 ) Error("Internal problem! Missing contents.");
52686 
52687   int tsID = streamptr->rtsteps;
52688   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
52689 
52690   int nrecs = 0;
52691   if ( streamptr->tsteps[tsID].recordSize == 0 )
52692     {
52693       cdi_create_records(streamptr, tsID);
52694       record_t *records = streamptr->tsteps[tsID].records;
52695 
52696       nrecs = streamScanInitRecords(streamptr, tsID);
52697 
52698       const int fileID = streamptr->fileID;
52699 
52700       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
52701 
52702       for ( int rindex = 0; rindex <= nrecs; rindex++ )
52703 	{
52704 	  recpos = fileGetPos(fileID);
52705 	  if ( iegRead(fileID, iegp) != 0 )
52706 	    {
52707 	      streamptr->ntsteps = streamptr->rtsteps + 1;
52708 	      break;
52709 	    }
52710 
52711 	  const size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
52712 
52713 	  const int rcode  = IEG_P_Parameter(iegp->ipdb);
52714 	  const int tabnum = IEG_P_CodeTable(iegp->ipdb);
52715 	  const int param  = cdiEncodeParam(rcode, tabnum, 255);
52716           int rlevel = (IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER) ? IEG_P_Level1(iegp->ipdb) : IEG_P_Level2(iegp->ipdb);
52717 
52718 	  if ( IEG_P_LevelType(iegp->ipdb) == 100 ) rlevel *= 100;
52719 
52720           int64_t vdate = 0;
52721           int vtime = 0;
52722 	  iegDateTime(iegp->ipdb, &vdate, &vtime);
52723 
52724 	  // if ( rindex == nrecs ) break; gcc-4.5 internal compiler error
52725 	  if ( rindex == nrecs ) continue;
52726 	  const int recID = streamptr->tsteps[tsID].recIDs[rindex];
52727 
52728 	  if ( rindex == 0 )
52729 	    {
52730 	      taxis->type  = TAXIS_ABSOLUTE;
52731 	      taxis->vdate = vdate;
52732 	      taxis->vtime = vtime;
52733 	    }
52734 
52735           if ( param != records[recID].param || rlevel != records[recID].ilevel )
52736 	    {
52737 	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
52738 		      tsID, recID, records[recID].param, param, records[recID].ilevel, rlevel);
52739 	      Error("Invalid, unsupported or inconsistent record structure");
52740 	    }
52741 
52742 	  records[recID].position = recpos;
52743 	  records[recID].size = recsize;
52744 
52745 	  if ( CDI_Debug )
52746 	    Message("%4d%8d%4d%8d%8ld%6d", rindex, (int)recpos, param, rlevel, (long)vdate, vtime);
52747 	}
52748 
52749       streamptr->rtsteps++;
52750 
52751       if ( streamptr->ntsteps != streamptr->rtsteps )
52752 	{
52753 	  tsID = tstepsNewEntry(streamptr);
52754 	  if ( tsID != streamptr->rtsteps )
52755 	    Error("Internal error. tsID = %d", tsID);
52756 
52757 	  streamptr->tsteps[tsID-1].next   = true;
52758 	  streamptr->tsteps[tsID].position = recpos;
52759 	}
52760 
52761       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
52762       streamptr->tsteps[tsID].position = recpos;
52763     }
52764 
52765   if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
52766     {
52767       Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
52768       streamptr->ntsteps = tsID;
52769     }
52770 
52771   return streamptr->ntsteps;
52772 }
52773 
52774 
iegInqTimestep(stream_t * streamptr,int tsID)52775 int iegInqTimestep(stream_t *streamptr, int tsID)
52776 {
52777   if ( tsID == 0 && streamptr->rtsteps == 0 )
52778     Error("Call to cdiInqContents missing!");
52779 
52780   if ( CDI_Debug )
52781     Message("tsID = %d rtsteps = %d", tsID, streamptr->rtsteps);
52782 
52783   long ntsteps = CDI_UNDEFID;
52784   while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == CDI_UNDEFID )
52785     ntsteps = iegScanTimestep(streamptr);
52786 
52787   int nrecs = 0;
52788   if ( !(tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID) )
52789     {
52790       streamptr->curTsID = tsID;
52791       nrecs = streamptr->tsteps[tsID].nrecs;
52792     }
52793 
52794   return nrecs;
52795 }
52796 
52797 
iegReadVarSliceDP(stream_t * streamptr,int varID,int levID,double * data,size_t * nmiss)52798 void iegReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, size_t *nmiss)
52799 {
52800   if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
52801 
52802   void *iegp = streamptr->record->exsep;
52803 
52804   int vlistID  = streamptr->vlistID;
52805   int fileID   = streamptr->fileID;
52806   /* NOTE: tiles are not supported here! */
52807   double missval = vlistInqVarMissval(vlistID, varID);
52808   size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
52809   int tsid     = streamptr->curTsID;
52810 
52811   off_t currentfilepos = fileGetPos(fileID);
52812 
52813   /* NOTE: tiles are not supported here! */
52814   int recID = streamptr->vars[varID].recordTable[0].recordID[levID];
52815   off_t recpos = streamptr->tsteps[tsid].records[recID].position;
52816   fileSetPos(fileID, recpos, SEEK_SET);
52817   iegRead(fileID, iegp);
52818   iegInqDataDP(iegp, data);
52819 
52820   fileSetPos(fileID, currentfilepos, SEEK_SET);
52821 
52822   *nmiss = 0;
52823   for ( size_t i = 0; i < gridsize; i++ )
52824     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
52825       {
52826 	data[i] = missval;
52827 	(*nmiss)++;
52828       }
52829 }
52830 
52831 
iegReadVarDP(stream_t * streamptr,int varID,double * data,size_t * nmiss)52832 void iegReadVarDP(stream_t *streamptr, int varID, double *data, size_t *nmiss)
52833 {
52834   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
52835 
52836   int vlistID = streamptr->vlistID;
52837   size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
52838   size_t nlevs    = (size_t) streamptr->vars[varID].recordTable[0].nlevs;
52839 
52840   for ( size_t levID = 0; levID < nlevs; levID++)
52841     iegReadVarSliceDP(streamptr, varID, (int)levID, &data[levID*gridsize], nmiss);
52842 }
52843 
52844 
iegWriteVarSliceDP(stream_t * streamptr,int varID,int levID,const double * data)52845 void iegWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
52846 {
52847   if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
52848 
52849   iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
52850   iegInitMem(iegp);
52851   for ( int i = 0; i < 37; i++ ) iegp->ipdb[i] = -1;
52852 
52853   int vlistID  = streamptr->vlistID;
52854   int fileID   = streamptr->fileID;
52855   int tsID     = streamptr->curTsID;
52856   int gridID   = vlistInqVarGrid(vlistID, varID);
52857   int zaxisID  = vlistInqVarZaxis(vlistID, varID);
52858 
52859   int param    = vlistInqVarParam(vlistID, varID);
52860   int pdis, pcat, pnum;
52861   cdiDecodeParam(param, &pnum, &pcat, &pdis);
52862   IEG_P_Parameter(iegp->ipdb) = pnum;
52863   if ( pdis == 255 ) IEG_P_CodeTable(iegp->ipdb) = pcat;
52864 
52865   int64_t date = streamptr->tsteps[tsID].taxis.vdate;
52866   int time     = streamptr->tsteps[tsID].taxis.vtime;
52867   iegDefTime(iegp->ipdb, date, time, vlistInqTaxis(vlistID));
52868   iegDefGrid(iegp->igdb, gridID);
52869   iegDefLevel(iegp->ipdb, iegp->igdb, iegp->vct, zaxisID, levID);
52870 
52871   iegp->dprec = iegDefDatatype(vlistInqVarDatatype(vlistID, varID));
52872 
52873   size_t gridsize = gridInqSize(gridID);
52874 
52875   double refval = data[0];
52876   for ( size_t i = 1; i < gridsize; i++ )
52877     if ( data[i] < refval ) refval = data[i];
52878 
52879   iegp->refval = refval;
52880 
52881   iegDefDataDP(iegp, data);
52882   iegWrite(fileID, iegp);
52883 }
52884 
52885 
iegWriteVarDP(stream_t * streamptr,int varID,const double * data)52886 void iegWriteVarDP(stream_t *streamptr, int varID, const double *data)
52887 {
52888   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
52889 
52890   int vlistID = streamptr->vlistID;
52891   size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
52892   size_t nlevs    = (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
52893 
52894   for ( size_t levID = 0;  levID < nlevs; levID++ )
52895     iegWriteVarSliceDP(streamptr, varID, (int)levID, &data[levID*gridsize]);
52896 }
52897 
52898 #endif /* HAVE_LIBIEG */
52899 /*
52900  * Local Variables:
52901  * c-file-style: "Java"
52902  * c-basic-offset: 2
52903  * indent-tabs-mode: nil
52904  * show-trailing-whitespace: t
52905  * require-trailing-newline: t
52906  * End:
52907  */
52908 #ifdef  HAVE_CONFIG_H
52909 #endif
52910 
52911 #include <limits.h>
52912 #include <stdio.h>
52913 #include <string.h>
52914 
52915 
52916 
52917 
recordInitEntry(record_t * record)52918 void recordInitEntry(record_t *record)
52919 {
52920   record->position  = CDI_UNDEFID;
52921   record->size      = 0;
52922   record->gridsize  = 0;
52923   record->param     = 0;
52924   record->ilevel    = CDI_UNDEFID;
52925   record->used      = false;
52926   record->tsteptype = CDI_UNDEFID;
52927   record->varID     = CDI_UNDEFID;
52928   record->levelID   = CDI_UNDEFID;
52929   memset(record->varname, 0, sizeof(record->varname));
52930   varScanKeysInit(&record->scanKeys);
52931   memset(&record->tiles, 0, sizeof(record->tiles));
52932 }
52933 
52934 
recordNewEntry(stream_t * streamptr,int tsID)52935 int recordNewEntry(stream_t *streamptr, int tsID)
52936 {
52937   size_t recordID = 0;
52938   size_t recordSize = (size_t)streamptr->tsteps[tsID].recordSize;
52939   record_t *records = streamptr->tsteps[tsID].records;
52940   /*
52941     Look for a free slot in record.
52942     (Create the table the first time through).
52943   */
52944   if ( ! recordSize )
52945     {
52946       recordSize = 1;   /*  <<<<----  */
52947       records = (record_t *) Malloc(recordSize * sizeof (record_t));
52948 
52949       for ( size_t i = 0; i < recordSize; i++ )
52950 	records[i].used = CDI_UNDEFID;
52951     }
52952   else
52953     {
52954       while ( recordID < recordSize && records[recordID].used != CDI_UNDEFID )
52955         ++recordID;
52956     }
52957   /*
52958     If the table overflows, double its size.
52959   */
52960   if ( recordID == recordSize )
52961     {
52962       if (recordSize <= INT_MAX / 2)
52963         recordSize *= 2;
52964       else if (recordSize < INT_MAX)
52965         recordSize = INT_MAX;
52966       else
52967         Error("Cannot handle this many records!\n");
52968       records = (record_t *) Realloc(records, recordSize * sizeof (record_t));
52969 
52970       for ( size_t i = recordID; i < recordSize; i++ )
52971 	records[i].used = CDI_UNDEFID;
52972     }
52973 
52974   recordInitEntry(&records[recordID]);
52975 
52976   records[recordID].used = 1;
52977 
52978   streamptr->tsteps[tsID].recordSize = (int)recordSize;
52979   streamptr->tsteps[tsID].records    = records;
52980 
52981   return (int)recordID;
52982 }
52983 
52984 static
cdiInitRecord(stream_t * streamptr)52985 void cdiInitRecord(stream_t *streamptr)
52986 {
52987   Record *record = (Record *) Malloc(sizeof(Record));
52988   streamptr->record = record;
52989 
52990   record->param      = 0;
52991   record->level      = 0;
52992   record->date       = 0;
52993   record->time       = 0;
52994   record->gridID     = 0;
52995   record->buffer     = NULL;
52996   record->buffersize = 0;
52997   record->position   = 0;
52998   record->varID      = 0;
52999   record->levelID    = CDI_UNDEFID;
53000 }
53001 
53002 
streamInqRecord(int streamID,int * varID,int * levelID)53003 void streamInqRecord(int streamID, int *varID, int *levelID)
53004 {
53005   check_parg(varID);
53006   check_parg(levelID);
53007 
53008   stream_t *streamptr = stream_to_pointer(streamID);
53009 
53010   cdiDefAccesstype(streamID, TYPE_REC);
53011 
53012   if ( ! streamptr->record ) cdiInitRecord(streamptr);
53013 
53014   int tsID   = streamptr->curTsID;
53015   int rindex = streamptr->tsteps[tsID].curRecID + 1;
53016 
53017   if ( rindex >= streamptr->tsteps[tsID].nrecs )
53018     Error("record %d not available at timestep %d", rindex+1, tsID+1);
53019 
53020   int recID  = streamptr->tsteps[tsID].recIDs[rindex];
53021 
53022   if ( recID == -1 || recID >= streamptr->tsteps[tsID].nallrecs )
53023     Error("Internal problem! tsID = %d recID = %d", tsID, recID);
53024 
53025   *varID   = streamptr->tsteps[tsID].records[recID].varID;
53026   int lindex = streamptr->tsteps[tsID].records[recID].levelID;
53027 
53028   int isub = subtypeInqActiveIndex(streamptr->vars[*varID].subtypeID);
53029   *levelID = streamptr->vars[*varID].recordTable[isub].lindex[lindex];
53030 
53031   if ( CDI_Debug )
53032     Message("streamID = %d tsID = %d, recID = %d, varID = %d, levelID = %d", streamID, tsID, recID, *varID, *levelID);
53033 
53034   streamptr->curTsID = tsID;
53035   streamptr->tsteps[tsID].curRecID = rindex;
53036 }
53037 
53038 /*
53039 @Function  streamDefRecord
53040 @Title     Define the next record
53041 
53042 @Prototype void streamDefRecord(int streamID, int varID, int levelID)
53043 @Parameter
53044     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
53045     @Item  varID     Variable identifier.
53046     @Item  levelID   Level identifier.
53047 
53048 @Description
53049 The function streamDefRecord defines the meta-data of the next record.
53050 @EndFunction
53051 */
streamDefRecord(int streamID,int varID,int levelID)53052 void streamDefRecord(int streamID, int varID, int levelID)
53053 {
53054   stream_t *streamptr = stream_to_pointer(streamID);
53055 
53056   int tsID = streamptr->curTsID;
53057 
53058   if ( tsID == CDI_UNDEFID )
53059     {
53060       tsID++;
53061       streamDefTimestep(streamID, tsID);
53062     }
53063 
53064   if ( ! streamptr->record ) cdiInitRecord(streamptr);
53065 
53066   int vlistID = streamptr->vlistID;
53067   int gridID  = vlistInqVarGrid(vlistID, varID);
53068   int zaxisID = vlistInqVarZaxis(vlistID, varID);
53069   int param   = vlistInqVarParam(vlistID, varID);
53070   int level   = (int)(zaxisInqLevel(zaxisID, levelID));
53071 
53072   Record *record = streamptr->record;
53073   record->varID    = varID;
53074   record->levelID  = levelID;
53075   record->param    = param;
53076   record->level    = level;
53077   record->date     = streamptr->tsteps[tsID].taxis.vdate;
53078   record->time     = streamptr->tsteps[tsID].taxis.vtime;
53079   record->gridID   = gridID;
53080   record->prec     = vlistInqVarDatatype(vlistID, varID);
53081 
53082   switch (cdiBaseFiletype(streamptr->filetype))
53083     {
53084 #ifdef HAVE_LIBGRIB
53085     case CDI_FILETYPE_GRB:
53086     case CDI_FILETYPE_GRB2:
53087       grbDefRecord(streamptr);
53088       break;
53089 #endif
53090 #ifdef HAVE_LIBSERVICE
53091     case CDI_FILETYPE_SRV:
53092       srvDefRecord(streamptr);
53093       break;
53094 #endif
53095 #ifdef HAVE_LIBEXTRA
53096     case CDI_FILETYPE_EXT:
53097       extDefRecord(streamptr);
53098       break;
53099 #endif
53100 #ifdef HAVE_LIBIEG
53101     case CDI_FILETYPE_IEG:
53102       iegDefRecord(streamptr);
53103       break;
53104 #endif
53105 #ifdef HAVE_LIBNETCDF
53106     case CDI_FILETYPE_NETCDF:
53107       if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
53108       cdfDefRecord(streamptr);
53109       break;
53110 #endif
53111     default:
53112       Error("%s support not compiled in!", strfiletype(streamptr->filetype));
53113       break;
53114     }
53115 }
53116 
53117 
streamCopyRecord(int streamID2,int streamID1)53118 void streamCopyRecord(int streamID2, int streamID1)
53119 {
53120   stream_t *streamptr1 = stream_to_pointer(streamID1),
53121     *streamptr2 = stream_to_pointer(streamID2);
53122   int filetype1 = streamptr1->filetype,
53123     filetype2 = streamptr2->filetype,
53124     filetype  = CDI_FILETYPE_UNDEF;
53125 
53126   if (cdiBaseFiletype(filetype1) == cdiBaseFiletype(filetype2)) filetype = filetype2;
53127 
53128   if ( filetype == CDI_FILETYPE_UNDEF )
53129     Error("Streams have different file types (%s -> %s)!", strfiletype(filetype1), strfiletype(filetype2));
53130 
53131   switch (cdiBaseFiletype(filetype))
53132     {
53133 #ifdef HAVE_LIBGRIB
53134     case CDI_FILETYPE_GRB:
53135     case CDI_FILETYPE_GRB2:
53136       grbCopyRecord(streamptr2, streamptr1);
53137       break;
53138 #endif
53139 #ifdef HAVE_LIBSERVICE
53140     case CDI_FILETYPE_SRV:
53141       srvCopyRecord(streamptr2, streamptr1);
53142       break;
53143 #endif
53144 #ifdef HAVE_LIBEXTRA
53145     case CDI_FILETYPE_EXT:
53146       extCopyRecord(streamptr2, streamptr1);
53147       break;
53148 #endif
53149 #ifdef HAVE_LIBIEG
53150     case CDI_FILETYPE_IEG:
53151       iegCopyRecord(streamptr2, streamptr1);
53152       break;
53153 #endif
53154 #ifdef HAVE_LIBNETCDF
53155     case CDI_FILETYPE_NETCDF:
53156       cdfCopyRecord(streamptr2, streamptr1);
53157       break;
53158 #endif
53159     default:
53160       {
53161 	Error("%s support not compiled in!", strfiletype(filetype));
53162 	break;
53163       }
53164     }
53165 }
53166 
53167 
cdi_create_records(stream_t * streamptr,int tsID)53168 void cdi_create_records(stream_t *streamptr, int tsID)
53169 {
53170   unsigned nrecords, maxrecords;
53171 
53172   tsteps_t *sourceTstep = streamptr->tsteps;
53173   tsteps_t *destTstep = sourceTstep + tsID;
53174 
53175   if ( destTstep->records ) return;
53176 
53177   int vlistID = streamptr->vlistID;
53178 
53179   if ( tsID == 0 )
53180     {
53181       maxrecords = 0;
53182       int nvars = streamptr->nvars;
53183       for ( int varID = 0; varID < nvars; varID++)
53184         for (int isub=0; isub<streamptr->vars[varID].subtypeSize; isub++)
53185           maxrecords += (unsigned)streamptr->vars[varID].recordTable[isub].nlevs;
53186     }
53187   else
53188     {
53189       maxrecords = (unsigned)sourceTstep->recordSize;
53190     }
53191 
53192   if ( tsID == 0 )
53193     {
53194       nrecords = maxrecords;
53195     }
53196   else if ( tsID == 1 )
53197     {
53198       nrecords = 0;
53199       maxrecords = (unsigned)sourceTstep->recordSize;
53200       for ( unsigned recID = 0; recID < maxrecords; recID++ )
53201 	{
53202 	  int varID = sourceTstep->records[recID].varID;
53203 	  nrecords += (varID == CDI_UNDEFID /* varID = CDI_UNDEFID for write mode !!! */
53204                        || vlistInqVarTimetype(vlistID, varID) != TIME_CONSTANT);
53205           //    printf("varID nrecords %d %d %d \n", varID, nrecords, vlistInqVarTsteptype(vlistID, varID));
53206 	}
53207     }
53208   else
53209     {
53210       nrecords = (unsigned)streamptr->tsteps[1].nallrecs;
53211     }
53212   //  printf("tsID, nrecords %d %d\n", tsID, nrecords);
53213 
53214   record_t *records = NULL;
53215   if ( maxrecords > 0 ) records = (record_t *) Malloc(maxrecords*sizeof(record_t));
53216 
53217   destTstep->records    = records;
53218   destTstep->recordSize = (int)maxrecords;
53219   destTstep->nallrecs   = (int)nrecords;
53220 
53221   if ( tsID == 0 )
53222     {
53223       for ( unsigned recID = 0; recID < maxrecords; recID++ )
53224         recordInitEntry(&destTstep->records[recID]);
53225     }
53226   else
53227     {
53228       memcpy(destTstep->records, sourceTstep->records, (size_t)maxrecords*sizeof(record_t));
53229 
53230       for ( unsigned recID = 0; recID < maxrecords; recID++ )
53231 	{
53232           record_t *curRecord = &sourceTstep->records[recID];
53233           destTstep->records[recID].used = curRecord->used;
53234           if ( curRecord->used != CDI_UNDEFID && curRecord->varID != -1 ) /* curRecord->varID = -1 for write mode !!! */
53235             {
53236               if ( vlistInqVarTimetype(vlistID, curRecord->varID) != TIME_CONSTANT )
53237                 {
53238                   destTstep->records[recID].position = CDI_UNDEFID;
53239                   destTstep->records[recID].size     = 0;
53240                   destTstep->records[recID].used     = false;
53241                 }
53242             }
53243 	}
53244     }
53245 }
53246 
53247 
streamFCopyRecord(stream_t * streamptr2,stream_t * streamptr1,const char * container_name)53248 void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1, const char *container_name)
53249 {
53250   int fileID1 = streamptr1->fileID;
53251   int fileID2 = streamptr2->fileID;
53252 
53253   int tsID    = streamptr1->curTsID;
53254   int vrecID  = streamptr1->tsteps[tsID].curRecID;
53255   int recID   = streamptr1->tsteps[tsID].recIDs[vrecID];
53256   off_t recpos  = streamptr1->tsteps[tsID].records[recID].position;
53257   size_t recsize = streamptr1->tsteps[tsID].records[recID].size;
53258 
53259   if (fileSetPos(fileID1, recpos, SEEK_SET) != 0)
53260     Error("Cannot seek input file for %s record copy!", container_name);
53261 
53262   char *buffer = (char *) Malloc(recsize);
53263 
53264   if (fileRead(fileID1, buffer, recsize) != recsize)
53265     Error("Failed to read record from %s file for copying!", container_name);
53266 
53267   if (fileWrite(fileID2, buffer, recsize) != recsize)
53268     Error("Failed to write record to %s file when copying!", container_name);
53269 
53270   Free(buffer);
53271 }
53272 /*
53273  * Local Variables:
53274  * c-file-style: "Java"
53275  * c-basic-offset: 2
53276  * indent-tabs-mode: nil
53277  * show-trailing-whitespace: t
53278  * require-trailing-newline: t
53279  * End:
53280  */
53281 #ifdef HAVE_CONFIG_H
53282 #endif
53283 
53284 
53285 
53286 
53287 #ifdef HAVE_LIBSERVICE
53288 
53289 static
srvInqDatatype(int prec)53290 int srvInqDatatype(int prec)
53291 {
53292   return (prec == EXSE_DOUBLE_PRECISION) ? CDI_DATATYPE_FLT64 : CDI_DATATYPE_FLT32;
53293 }
53294 
53295 static
srvDefDatatype(int datatype)53296 int srvDefDatatype(int datatype)
53297 {
53298   if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
53299     Error("CDI/SERVICE library does not support complex numbers!");
53300 
53301   if ( datatype != CDI_DATATYPE_FLT32 && datatype != CDI_DATATYPE_FLT64 )
53302     datatype = CDI_DATATYPE_FLT32;
53303 
53304   return (datatype == CDI_DATATYPE_FLT64) ? EXSE_DOUBLE_PRECISION : EXSE_SINGLE_PRECISION;
53305 }
53306 
53307 /* not used
53308 int srvInqRecord(stream_t *streamptr, int *varID, int *levelID)
53309 {
53310   int status;
53311   int fileID;
53312   int icode, ilevel;
53313   int zaxisID = -1;
53314   int header[8];
53315   int vlistID;
53316   void *srvp = streamptr->record->exsep;
53317 
53318   vlistID = streamptr->vlistID;
53319   fileID  = streamptr->fileID;
53320 
53321   *varID   = -1;
53322   *levelID = -1;
53323 
53324   status = srvRead(fileID, srvp);
53325   if ( status != 0 ) return (0);
53326 
53327   srvInqHeader(srvp, header);
53328 
53329   icode  = header[0];
53330   ilevel = header[1];
53331 
53332   *varID = vlistInqVarID(vlistID, icode);
53333 
53334   if ( *varID == CDI_UNDEFID ) Error("Code %d undefined", icode);
53335 
53336   zaxisID = vlistInqVarZaxis(vlistID, *varID);
53337 
53338   *levelID = zaxisInqLevelID(zaxisID, (double) ilevel);
53339 
53340   return 1;
53341 }
53342 */
53343 
srvReadRecord(stream_t * streamptr,double * data,size_t * nmiss)53344 void srvReadRecord(stream_t *streamptr, double *data, size_t *nmiss)
53345 {
53346   int vlistID  = streamptr->vlistID;
53347   int fileID   = streamptr->fileID;
53348   int tsID     = streamptr->curTsID;
53349   int vrecID   = streamptr->tsteps[tsID].curRecID;
53350   int recID    = streamptr->tsteps[tsID].recIDs[vrecID];
53351   int varID    = streamptr->tsteps[tsID].records[recID].varID;
53352   off_t recpos = streamptr->tsteps[tsID].records[recID].position;
53353 
53354   fileSetPos(fileID, recpos, SEEK_SET);
53355 
53356   void *srvp = streamptr->record->exsep;
53357   int status = srvRead(fileID, srvp);
53358   if ( status != 0 ) Error("Failed to read record from SRV file");
53359 
53360   int header[8];
53361   srvInqHeader(srvp, header);
53362   srvInqDataDP(srvp, data);
53363 
53364   double missval = vlistInqVarMissval(vlistID, varID);
53365   int gridID  = vlistInqVarGrid(vlistID, varID);
53366   size_t size = gridInqSize(gridID);
53367 
53368   streamptr->numvals += size;
53369 
53370   *nmiss = 0;
53371   for ( size_t i = 0; i < size; i++ )
53372     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
53373       {
53374 	data[i] = missval;
53375 	(*nmiss)++;
53376       }
53377 }
53378 
53379 
srvCopyRecord(stream_t * streamptr2,stream_t * streamptr1)53380 void srvCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
53381 {
53382   streamFCopyRecord(streamptr2, streamptr1, "SRV");
53383 }
53384 
53385 
srvDefRecord(stream_t * streamptr)53386 void srvDefRecord(stream_t *streamptr)
53387 {
53388   Record *record = streamptr->record;
53389 
53390   int pdis, pcat, pnum;
53391   cdiDecodeParam(record->param, &pnum, &pcat, &pdis);
53392 
53393   int header[8];
53394   header[0] = pnum;
53395   header[1] = record->level;
53396   header[2] = record->date;
53397   header[3] = record->time;
53398 
53399   int gridID = record->gridID;
53400   size_t xsize = gridInqXsize(gridID),
53401          ysize = gridInqYsize(gridID);
53402   if ( xsize == 0 || ysize == 0 )
53403     {
53404       xsize = gridInqSize(gridID);
53405       ysize = 1;
53406     }
53407   if ( gridInqType(gridID) == GRID_UNSTRUCTURED ) ysize = 1;
53408   if ( gridInqSize(gridID) != xsize*ysize )
53409     Error("Internal problem with gridsize!");
53410 
53411   cdi_check_gridsize_int_limit("SERVICE", gridInqSize(gridID));
53412 
53413   header[4] = (int)xsize;
53414   header[5] = (int)ysize;
53415   header[6] = 0;
53416   header[7] = 0;
53417 
53418   srvrec_t *srvp = (srvrec_t*) record->exsep;
53419   srvp->dprec = srvDefDatatype(record->prec);
53420 
53421   srvDefHeader(srvp, header);
53422 }
53423 
53424 
srvWriteRecord(stream_t * streamptr,const double * data)53425 void srvWriteRecord(stream_t *streamptr, const double *data)
53426 {
53427   void *srvp = streamptr->record->exsep;
53428   srvDefDataDP(srvp, data);
53429   srvWrite(streamptr->fileID, srvp);
53430 }
53431 
53432 static
srv_add_record(stream_t * streamptr,int param,int level,size_t xsize,size_t ysize,size_t recsize,off_t position,int prec)53433 void srv_add_record(stream_t *streamptr, int param, int level, size_t xsize, size_t ysize,
53434                     size_t recsize, off_t position, int prec)
53435 {
53436   const int vlistID = streamptr->vlistID;
53437   const int tsID    = streamptr->curTsID;
53438   const int recID   = recordNewEntry(streamptr, tsID);
53439   record_t *record = &streamptr->tsteps[tsID].records[recID];
53440 
53441   record->size     = recsize;
53442   record->position = position;
53443   record->param    = param;
53444   record->ilevel   = level;
53445 
53446   grid_t *grid = (grid_t*) Malloc(sizeof(*grid));
53447   grid_init(grid);
53448   cdiGridTypeInit(grid, GRID_GENERIC, xsize*ysize);
53449   grid->x.size = xsize;
53450   grid->y.size = ysize;
53451   struct addIfNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
53452   const int gridID = gridAdded.Id;
53453   if (!gridAdded.isNew) Free(grid);
53454 
53455   const int leveltype = ZAXIS_GENERIC;
53456   const int datatype = srvInqDatatype(prec);
53457 
53458   int varID, levelID = 0;
53459   varAddRecord(recID, param, gridID, leveltype, 0, level, 0, 0, 0,
53460 	       datatype, &varID, &levelID, TSTEP_INSTANT, 0, -1,
53461                NULL, NULL, NULL, NULL);
53462 
53463   xassert(varID <= SHRT_MAX && levelID <= SHRT_MAX);
53464   record->varID   = (short)varID;
53465   record->levelID = (short)levelID;
53466 
53467   streamptr->tsteps[tsID].nallrecs++;
53468   streamptr->nrecs++;
53469 
53470   if ( CDI_Debug )
53471     Message("varID = %d gridID = %d levelID = %d", varID, gridID, levelID);
53472 }
53473 
53474 static
srvScanTimestep1(stream_t * streamptr)53475 void srvScanTimestep1(stream_t *streamptr)
53476 {
53477   DateTime datetime0 = { LONG_MIN, LONG_MIN };
53478   off_t recpos;
53479   srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
53480 
53481   streamptr->curTsID = 0;
53482 
53483   int tsID  = tstepsNewEntry(streamptr);
53484   if ( tsID != 0 ) Error("Internal problem! tstepsNewEntry returns %d", tsID);
53485   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
53486 
53487   const int fileID = streamptr->fileID;
53488 
53489   int nrecs = 0;
53490   while ( true )
53491     {
53492       recpos = fileGetPos(fileID);
53493       if ( srvRead(fileID, srvp) != 0 )
53494 	{
53495 	  streamptr->ntsteps = 1;
53496 	  break;
53497 	}
53498 
53499       const size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
53500 
53501       int header[8];
53502       srvInqHeader(srvp, header);
53503 
53504       const int prec   = srvp->dprec;
53505       const int rcode  = header[0];
53506       const int rlevel = header[1];
53507       const int vdate  = header[2];
53508       const int vtime  = header[3];
53509       const int rxsize = header[4];
53510       const int rysize = header[5];
53511       const int param  = cdiEncodeParam(rcode, 255, 255);
53512       DateTime datetime = { .date = vdate, .time = vtime };
53513 
53514       if ( nrecs == 0 )
53515 	{
53516 	  datetime0 = datetime;
53517           taxis->vdate = vdate;
53518           taxis->vtime = vtime;
53519 	}
53520       else
53521 	{
53522           record_t *records = streamptr->tsteps[tsID].records;
53523 	  for ( int recID = 0; recID < nrecs; recID++ )
53524             if ( param == records[recID].param && rlevel == records[recID].ilevel )
53525               goto tstepScanLoopFinished;
53526 
53527 	  if ( datetimeDiffer(datetime, datetime0) )
53528 	    Warning("Inconsistent verification time for code %d level %d", rcode, rlevel);
53529 	}
53530 
53531       nrecs++;
53532 
53533       if ( CDI_Debug )
53534 	Message("%4d%8d%4d%8d%8d%6d", nrecs, (int)recpos, rcode, rlevel, vdate, vtime);
53535 
53536       srv_add_record(streamptr, param, rlevel, rxsize, rysize, recsize, recpos, prec);
53537     }
53538 
53539   tstepScanLoopFinished:
53540   streamptr->rtsteps = 1;
53541 
53542   cdi_generate_vars(streamptr);
53543 
53544   const int taxisID = taxisCreate(TAXIS_ABSOLUTE);
53545   taxis->type = TAXIS_ABSOLUTE;
53546   taxis->rdate = taxis->vdate;
53547   taxis->rtime = taxis->vtime;
53548 
53549   const int vlistID = streamptr->vlistID;
53550   vlistDefTaxis(vlistID, taxisID);
53551 
53552   vlist_check_contents(vlistID);
53553 
53554   streamScanResizeRecords1(streamptr);
53555 
53556   streamScanTsFixNtsteps(streamptr, recpos);
53557   streamScanTimeConstAdjust(streamptr, taxis);
53558 }
53559 
53560 static
srvScanTimestep2(stream_t * streamptr)53561 int srvScanTimestep2(stream_t *streamptr)
53562 {
53563   int header[8];
53564   off_t recpos = 0;
53565   void *srvp = streamptr->record->exsep;
53566 
53567   streamptr->curTsID = 1;
53568 
53569   const int vlistID = streamptr->vlistID;
53570   const int fileID  = streamptr->fileID;
53571 
53572   const int tsID = streamptr->rtsteps;
53573   if ( tsID != 1 ) Error("Internal problem! unexpected timestep %d", tsID+1);
53574 
53575   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
53576 
53577   fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
53578 
53579   cdi_create_records(streamptr, tsID);
53580   record_t *records = streamptr->tsteps[tsID].records;
53581 
53582   const int nrecords = streamScanInitRecords2(streamptr);
53583 
53584   for ( int rindex = 0; rindex <= nrecords; rindex++ )
53585     {
53586       recpos = fileGetPos(fileID);
53587       if ( srvRead(fileID, srvp) != 0 )
53588 	{
53589 	  streamptr->ntsteps = 2;
53590 	  break;
53591 	}
53592 
53593       const size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
53594 
53595       srvInqHeader(srvp, header);
53596 
53597       const int rcode  = header[0];
53598       const int rlevel = header[1];
53599       const int vdate  = header[2];
53600       const int vtime  = header[3];
53601       const int param  = cdiEncodeParam(rcode, 255, 255);
53602 
53603       if ( rindex == 0 )
53604 	{
53605 	  taxis->type  = TAXIS_ABSOLUTE;
53606 	  taxis->vdate = vdate;
53607 	  taxis->vtime = vtime;
53608 	}
53609 
53610       bool nextstep = false;
53611       int recID;
53612       for ( recID = 0; recID < nrecords; recID++ )
53613 	{
53614 	  if ( param == records[recID].param && rlevel == records[recID].ilevel )
53615 	    {
53616 	      if ( records[recID].used )
53617 		{
53618 		  nextstep = true;
53619 		}
53620 	      else
53621 		{
53622 		  records[recID].used = true;
53623 		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
53624 		}
53625 	      break;
53626 	    }
53627 	}
53628       if ( recID == nrecords )
53629 	{
53630 	  Warning("Code %d level %d not found at timestep %d", rcode, rlevel, tsID+1);
53631 	  return CDI_EUFSTRUCT;
53632 	}
53633 
53634       if ( nextstep ) break;
53635 
53636       if ( CDI_Debug )
53637 	Message("%4d%8d%4d%8d%8d%6d", rindex+1, (int)recpos, rcode, rlevel, vdate, vtime);
53638 
53639       if ( param != records[recID].param || rlevel != records[recID].ilevel )
53640 	{
53641 	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
53642 		  tsID, recID, records[recID].param, param, records[recID].ilevel, rlevel);
53643 	  return CDI_EUFSTRUCT;
53644 	}
53645 
53646       records[recID].position = recpos;
53647       records[recID].size = recsize;
53648     }
53649 
53650   int nrecs = 0;
53651   for ( int recID = 0; recID < nrecords; recID++ )
53652     {
53653       if ( ! records[recID].used )
53654 	{
53655           vlistDefVarTimetype(vlistID, records[recID].varID, TIME_CONSTANT);
53656 	}
53657       else
53658 	{
53659 	  nrecs++;
53660 	}
53661     }
53662   streamptr->tsteps[tsID].nrecs = nrecs;
53663 
53664   streamptr->rtsteps = 2;
53665 
53666   streamScanTsFixNtsteps(streamptr, recpos);
53667 
53668   return 0;
53669 }
53670 
53671 
srvInqContents(stream_t * streamptr)53672 int srvInqContents(stream_t *streamptr)
53673 {
53674   streamptr->curTsID = 0;
53675 
53676   srvScanTimestep1(streamptr);
53677 
53678   const int status = (streamptr->ntsteps == -1) ? srvScanTimestep2(streamptr) : 0;
53679 
53680   fileSetPos(streamptr->fileID, 0, SEEK_SET);
53681 
53682   return status;
53683 }
53684 
53685 static
srvScanTimestep(stream_t * streamptr)53686 long srvScanTimestep(stream_t *streamptr)
53687 {
53688   int header[8];
53689   off_t recpos = 0;
53690   int nrecs = 0;
53691   void *srvp = streamptr->record->exsep;
53692 
53693   int tsID = streamptr->rtsteps;
53694   taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
53695 
53696   if ( streamptr->tsteps[tsID].recordSize == 0 )
53697     {
53698       cdi_create_records(streamptr, tsID);
53699       record_t *records = streamptr->tsteps[tsID].records;
53700 
53701       nrecs = streamScanInitRecords(streamptr, tsID);
53702 
53703       const int fileID = streamptr->fileID;
53704 
53705       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
53706 
53707       for ( int rindex = 0; rindex <= nrecs; rindex++ )
53708 	{
53709 	  recpos = fileGetPos(fileID);
53710 	  if ( srvRead(fileID, srvp) != 0 )
53711 	    {
53712 	      streamptr->ntsteps = streamptr->rtsteps + 1;
53713 	      break;
53714 	    }
53715 
53716 	  const size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
53717 
53718 	  srvInqHeader(srvp, header);
53719 
53720 	  const int rcode  = header[0];
53721 	  const int rlevel = header[1];
53722 	  const int vdate  = header[2];
53723 	  const int vtime  = header[3];
53724 	  const int param  = cdiEncodeParam(rcode, 255, 255);
53725 
53726 	  // if ( rindex == nrecs ) break; gcc-4.5 internal compiler error
53727 	  if ( rindex == nrecs ) continue;
53728 	  const int recID = streamptr->tsteps[tsID].recIDs[rindex];
53729 
53730 	  if ( rindex == 0 )
53731 	    {
53732 	      taxis->type  = TAXIS_ABSOLUTE;
53733 	      taxis->vdate = vdate;
53734 	      taxis->vtime = vtime;
53735 	    }
53736 
53737           if ( param != records[recID].param || rlevel != records[recID].ilevel )
53738 	    {
53739 	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
53740 		      tsID, recID, records[recID].param, param, records[recID].ilevel, rlevel);
53741 	      Error("Invalid, unsupported or inconsistent record structure!");
53742 	    }
53743 
53744 	  records[recID].position = recpos;
53745 	  records[recID].size = recsize;
53746 
53747 	  if ( CDI_Debug )
53748 	    Message("%4d%8d%4d%8d%8d%6d", rindex, (int)recpos, rcode, rlevel, vdate, vtime);
53749 	}
53750 
53751       streamptr->rtsteps++;
53752 
53753       if ( streamptr->ntsteps != streamptr->rtsteps )
53754 	{
53755 	  tsID = tstepsNewEntry(streamptr);
53756 	  if ( tsID != streamptr->rtsteps )
53757 	    Error("Internal error. tsID = %d", tsID);
53758 
53759 	  streamptr->tsteps[tsID-1].next   = true;
53760 	  streamptr->tsteps[tsID].position = recpos;
53761 	}
53762 
53763       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
53764       streamptr->tsteps[tsID].position = recpos;
53765     }
53766 
53767   if ( nrecs > 0 && nrecs < streamptr->tsteps[tsID].nrecs )
53768     {
53769       Warning("Incomplete timestep. Stop scanning at timestep %d.", tsID);
53770       streamptr->ntsteps = tsID;
53771     }
53772 
53773   return streamptr->ntsteps;
53774 }
53775 
53776 
srvInqTimestep(stream_t * streamptr,int tsID)53777 int srvInqTimestep(stream_t *streamptr, int tsID)
53778 {
53779   if ( tsID == 0 && streamptr->rtsteps == 0 )
53780     Error("Call to cdiInqContents missing!");
53781 
53782   if ( CDI_Debug )
53783     Message("tsID = %d rtsteps = %d", tsID, streamptr->rtsteps);
53784 
53785   long ntsteps = CDI_UNDEFID;
53786   while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == CDI_UNDEFID )
53787     ntsteps = srvScanTimestep(streamptr);
53788 
53789   int nrecs = 0;
53790   if ( !(tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID) )
53791     {
53792       streamptr->curTsID = tsID;
53793       nrecs = streamptr->tsteps[tsID].nrecs;
53794     }
53795 
53796   return nrecs;
53797 }
53798 
53799 
srvReadVarSliceDP(stream_t * streamptr,int varID,int levID,double * data,size_t * nmiss)53800 void srvReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, size_t *nmiss)
53801 {
53802   if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
53803 
53804   void *srvp = streamptr->record->exsep;
53805 
53806   int vlistID  = streamptr->vlistID;
53807   int fileID   = streamptr->fileID;
53808   /* NOTE: tiles are not supported here! */
53809   double missval = vlistInqVarMissval(vlistID, varID);
53810   size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
53811   int tsid     = streamptr->curTsID;
53812 
53813   off_t currentfilepos = fileGetPos(fileID);
53814 
53815   /* NOTE: tiles are not supported here! */
53816   int recID = streamptr->vars[varID].recordTable[0].recordID[levID];
53817   off_t recpos = streamptr->tsteps[tsid].records[recID].position;
53818   fileSetPos(fileID, recpos, SEEK_SET);
53819   if ( srvRead(fileID, srvp) < 0 ) abort();
53820   int header[8];
53821   srvInqHeader(srvp, header);
53822   srvInqDataDP(srvp, data);
53823 
53824   fileSetPos(fileID, currentfilepos, SEEK_SET);
53825 
53826   *nmiss = 0;
53827   for ( size_t i = 0; i < gridsize; i++ )
53828     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
53829       {
53830 	data[i] = missval;
53831 	(*nmiss)++;
53832       }
53833 }
53834 
53835 
srvReadVarDP(stream_t * streamptr,int varID,double * data,size_t * nmiss)53836 void srvReadVarDP(stream_t *streamptr, int varID, double *data, size_t *nmiss)
53837 {
53838   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
53839 
53840   int vlistID = streamptr->vlistID;
53841   size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
53842   size_t nlevs    = (size_t) streamptr->vars[varID].recordTable[0].nlevs;
53843 
53844   for ( size_t levID = 0; levID < nlevs; levID++)
53845     srvReadVarSliceDP(streamptr, varID, (int)levID, &data[levID*gridsize], nmiss);
53846 }
53847 
53848 
srvWriteVarSliceDP(stream_t * streamptr,int varID,int levID,const double * data)53849 void srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
53850 {
53851   if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
53852 
53853   int vlistID  = streamptr->vlistID;
53854   int fileID   = streamptr->fileID;
53855   int tsID     = streamptr->curTsID;
53856   int gridID   = vlistInqVarGrid(vlistID, varID);
53857 
53858   int pdis, pcat, pnum;
53859   cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
53860 
53861   int header[8];
53862   header[0] = pnum;
53863   header[1] = (int)(zaxisInqLevel(vlistInqVarZaxis(vlistID, varID), levID));
53864   header[2] = streamptr->tsteps[tsID].taxis.vdate;
53865   header[3] = streamptr->tsteps[tsID].taxis.vtime;
53866 
53867   size_t xsize = gridInqXsize(gridID);
53868   size_t ysize = gridInqYsize(gridID);
53869   if ( xsize == 0 || ysize == 0 )
53870     {
53871       xsize = gridInqSize(gridID);
53872       ysize = 1;
53873     }
53874   if ( gridInqType(gridID) == GRID_UNSTRUCTURED ) ysize = 1;
53875   if ( gridInqSize(gridID) != xsize*ysize )
53876     Error("Internal problem with gridsize!");
53877 
53878   cdi_check_gridsize_int_limit("SERVICE", gridInqSize(gridID));
53879 
53880   header[4] = xsize;
53881   header[5] = ysize;
53882   header[6] = 0;
53883   header[7] = 0;
53884 
53885   int datatype = vlistInqVarDatatype(vlistID, varID);
53886 
53887   srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
53888   srvp->dprec = srvDefDatatype(datatype);
53889 
53890   srvDefHeader(srvp, header);
53891   srvDefDataDP(srvp, data);
53892   srvWrite(fileID, srvp);
53893 }
53894 
53895 
srvWriteVarDP(stream_t * streamptr,int varID,const double * data)53896 void srvWriteVarDP(stream_t *streamptr, int varID, const double *data)
53897 {
53898   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
53899 
53900   int vlistID = streamptr->vlistID;
53901   size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
53902   size_t nlevs    = (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
53903 
53904   for ( size_t levID = 0; levID < nlevs; levID++ )
53905     srvWriteVarSliceDP(streamptr, varID, (int)levID, &data[levID*gridsize]);
53906 }
53907 
53908 #endif /* HAVE_LIBSERVICE */
53909 
53910 /*
53911  * Local Variables:
53912  * c-file-style: "Java"
53913  * c-basic-offset: 2
53914  * indent-tabs-mode: nil
53915  * show-trailing-whitespace: t
53916  * require-trailing-newline: t
53917  * End:
53918  */
53919 
53920 
53921 
streamvar_init_recordtable(stream_t * streamptr,int varID,int isub)53922 static void streamvar_init_recordtable(stream_t *streamptr, int varID, int isub)
53923 {
53924   streamptr->vars[varID].recordTable[isub].nlevs    = 0;
53925   streamptr->vars[varID].recordTable[isub].recordID = NULL;
53926   streamptr->vars[varID].recordTable[isub].lindex   = NULL;
53927 }
53928 
53929 
53930 static
streamvar_init_entry(stream_t * streamptr,int varID)53931 void streamvar_init_entry(stream_t *streamptr, int varID)
53932 {
53933   streamptr->vars[varID].ncvarid      = CDI_UNDEFID;
53934   streamptr->vars[varID].defmiss      = false;
53935 
53936   streamptr->vars[varID].subtypeSize  = 0;
53937   streamptr->vars[varID].recordTable  = NULL;
53938 
53939   streamptr->vars[varID].gridID       = CDI_UNDEFID;
53940   streamptr->vars[varID].zaxisID      = CDI_UNDEFID;
53941   streamptr->vars[varID].tsteptype    = CDI_UNDEFID;
53942   streamptr->vars[varID].subtypeID    = CDI_UNDEFID;
53943 }
53944 
53945 static
streamvar_new_entry(stream_t * streamptr)53946 int streamvar_new_entry(stream_t *streamptr)
53947 {
53948   int varID = 0;
53949   int streamvarSize = streamptr->varsAllocated;
53950   svarinfo_t *streamvar = streamptr->vars;
53951   /*
53952     Look for a free slot in streamvar.
53953     (Create the table the first time through).
53954   */
53955   if ( ! streamvarSize )
53956     {
53957       streamvarSize = 2;
53958       streamvar = (svarinfo_t *) Malloc((size_t)streamvarSize * sizeof(svarinfo_t));
53959       if ( streamvar == NULL )
53960 	{
53961           Message("streamvarSize = %d", streamvarSize);
53962 	  SysError("Allocation of svarinfo_t failed");
53963 	}
53964 
53965       for ( int i = 0; i < streamvarSize; i++ )
53966 	streamvar[i].isUsed = false;
53967     }
53968   else
53969     {
53970       while ( varID < streamvarSize )
53971 	{
53972 	  if ( ! streamvar[varID].isUsed ) break;
53973 	  varID++;
53974 	}
53975     }
53976   /*
53977     If the table overflows, double its size.
53978   */
53979   if ( varID == streamvarSize )
53980     {
53981       streamvarSize = 2*streamvarSize;
53982       streamvar = (svarinfo_t *) Realloc(streamvar,
53983                                  (size_t)streamvarSize * sizeof (svarinfo_t));
53984       if ( streamvar == NULL )
53985 	{
53986           Message("streamvarSize = %d", streamvarSize);
53987 	  SysError("Reallocation of svarinfo_t failed");
53988 	}
53989       varID = streamvarSize/2;
53990 
53991       for ( int i = varID; i < streamvarSize; i++ )
53992 	streamvar[i].isUsed = false;
53993     }
53994 
53995   streamptr->varsAllocated = streamvarSize;
53996   streamptr->vars          = streamvar;
53997 
53998   streamvar_init_entry(streamptr, varID);
53999 
54000   streamptr->vars[varID].isUsed = true;
54001 
54002   return varID;
54003 }
54004 
54005 
54006 static void
allocate_record_table_entry(stream_t * streamptr,int varID,int subID,int nlevs)54007 allocate_record_table_entry(stream_t *streamptr, int varID, int subID, int nlevs)
54008 {
54009   int *level    = (int *) Malloc((size_t)nlevs * sizeof (int));
54010   int *lindex   = (int *) Malloc((size_t)nlevs * sizeof (int));
54011 
54012   for ( int levID = 0; levID < nlevs; levID++ )
54013     {
54014       level[levID]    = CDI_UNDEFID;
54015       lindex[levID]   = levID;
54016     }
54017 
54018   streamptr->vars[varID].recordTable[subID].nlevs    = nlevs;
54019   streamptr->vars[varID].recordTable[subID].recordID = level;
54020   streamptr->vars[varID].recordTable[subID].lindex   = lindex;
54021 }
54022 
54023 
stream_new_var(stream_t * streamptr,int gridID,int zaxisID,int tilesetID)54024 int stream_new_var(stream_t *streamptr, int gridID, int zaxisID, int tilesetID)
54025 {
54026   if ( CDI_Debug )
54027     Message("gridID = %d  zaxisID = %d", gridID, zaxisID);
54028 
54029   int varID = streamvar_new_entry(streamptr);
54030   int nlevs = zaxisInqSize(zaxisID);
54031 
54032   streamptr->nvars++;
54033 
54034   streamptr->vars[varID].gridID  = gridID;
54035   streamptr->vars[varID].zaxisID = zaxisID;
54036 
54037   int nsub = 1;
54038   if (tilesetID != CDI_UNDEFID)
54039     nsub = subtypeInqSize(tilesetID); /* e.g. no of tiles */
54040   if ( CDI_Debug )
54041     Message("varID %d: create %d tiles with %d level(s), zaxisID=%d", varID, nsub, nlevs,zaxisID);
54042   streamptr->vars[varID].recordTable = (sleveltable_t *) Malloc((size_t)nsub * sizeof (sleveltable_t));
54043   if( streamptr->vars[varID].recordTable == NULL )
54044     SysError("Allocation of leveltable failed!");
54045   streamptr->vars[varID].subtypeSize = nsub;
54046 
54047   for (int isub=0; isub<nsub; isub++) {
54048     streamvar_init_recordtable(streamptr, varID, isub);
54049     allocate_record_table_entry(streamptr, varID, isub, nlevs);
54050     if ( CDI_Debug )
54051       Message("streamptr->vars[varID].recordTable[isub].recordID[0]=%d",
54052               streamptr->vars[varID].recordTable[isub].recordID[0]);
54053   }
54054 
54055   streamptr->vars[varID].subtypeID = tilesetID;
54056 
54057   return varID;
54058 }
54059 /*
54060  * Local Variables:
54061  * c-file-style: "Java"
54062  * c-basic-offset: 2
54063  * indent-tabs-mode: nil
54064  * show-trailing-whitespace: t
54065  * require-trailing-newline: t
54066  * End:
54067  */
54068 #ifdef HAVE_CONFIG_H
54069 #endif
54070 
54071 #ifdef HAVE_LIBGRIB
54072 
54073 
54074 
54075 static
grbEncode(int filetype,int memtype,int varID,int levelID,int vlistID,int gridID,int zaxisID,int date,int time,int tsteptype,int numavg,size_t datasize,const void * data,size_t nmiss,void ** gribbuffer,int comptype,void * gribContainer)54076 size_t grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
54077 		 int date, int time, int tsteptype, int numavg,
54078 		 size_t datasize, const void *data, size_t nmiss, void **gribbuffer,
54079 		 int comptype, void *gribContainer)
54080 {
54081   size_t nbytes = 0;
54082 
54083 #ifdef HAVE_LIBCGRIBEX
54084   if ( filetype == CDI_FILETYPE_GRB && !CDI_gribapi_grib1 )
54085     {
54086       size_t gribbuffersize = datasize*4+3000;
54087       *gribbuffer = Malloc(gribbuffersize);
54088 
54089       nbytes = cgribexEncode(memtype, varID, levelID, vlistID, gridID, zaxisID,
54090 			     date, time, tsteptype, numavg,
54091 			     datasize, data, nmiss, *gribbuffer, gribbuffersize);
54092     }
54093   else
54094 #endif
54095 #ifdef HAVE_LIBGRIB_API
54096     {
54097       const void *datap = data;
54098       if ( memtype == MEMTYPE_FLOAT )
54099         {
54100           const float *dataf = (const float*) data;
54101           double *datad = (double*) Malloc(datasize*sizeof(double));
54102           for ( size_t i = 0; i < datasize; ++i ) datad[i] = (double) dataf[i];
54103           datap = (const void*) datad;
54104         }
54105 
54106       size_t gribbuffersize;
54107       nbytes = gribapiEncode(varID, levelID, vlistID, gridID, zaxisID,
54108 			     date, time, tsteptype, numavg,
54109 			     (long) datasize, datap, nmiss, gribbuffer, &gribbuffersize,
54110 			     comptype, gribContainer);
54111 
54112       if ( memtype == MEMTYPE_FLOAT ) Free((void*)datap);
54113     }
54114 #else
54115     {
54116       Error("ecCodes support not compiled in!");
54117       (void)gribContainer;
54118       (void)comptype;
54119     }
54120 #endif
54121 
54122   return nbytes;
54123 }
54124 
54125 static
grbSzip(int filetype,void * gribbuffer,size_t gribbuffersize)54126 size_t grbSzip(int filetype, void *gribbuffer, size_t gribbuffersize)
54127 {
54128   size_t buffersize = gribbuffersize + 1000; /* compressed record can be greater than source record */
54129   void *buffer = Malloc(buffersize);
54130 
54131   /*  memcpy(buffer, gribbuffer, gribbuffersize); */
54132 
54133   size_t nbytes = 0;
54134   if ( filetype == CDI_FILETYPE_GRB )
54135     {
54136       nbytes = (size_t)gribZip((unsigned char *)gribbuffer, (long) gribbuffersize, (unsigned char *)buffer, (long) buffersize);
54137     }
54138   else
54139     {
54140       static int lszip_warn = 1;
54141       if ( lszip_warn ) Warning("Szip compression of GRIB2 records not implemented!");
54142       lszip_warn = 0;
54143       nbytes = gribbuffersize;
54144     }
54145 
54146   Free(buffer);
54147 
54148   return nbytes;
54149 }
54150 
54151 
grbCopyRecord(stream_t * streamptr2,stream_t * streamptr1)54152 void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
54153 {
54154   const int filetype = streamptr1->filetype;
54155   const int fileID1 = streamptr1->fileID;
54156   const int fileID2 = streamptr2->fileID;
54157   const int tsID    = streamptr1->curTsID;
54158   const int vrecID  = streamptr1->tsteps[tsID].curRecID;
54159   const int recID   = streamptr1->tsteps[tsID].recIDs[vrecID];
54160   const off_t recpos  = streamptr1->tsteps[tsID].records[recID].position;
54161   const size_t recsize = streamptr1->tsteps[tsID].records[recID].size;
54162 
54163   fileSetPos(fileID1, recpos, SEEK_SET);
54164 
54165   // round up recsize to next multiple of 8
54166   const size_t gribbuffersize = ((recsize + 7U) & ~7U);
54167 
54168   unsigned char *gribbuffer = (unsigned char *) Malloc(gribbuffersize);
54169 
54170   if (fileRead(fileID1, gribbuffer, recsize) != recsize)
54171     Error("Could not read GRIB record for copying!");
54172 
54173   size_t nbytes = recsize;
54174 
54175 #ifdef HAVE_LIBCGRIBEX
54176   if ( filetype == CDI_FILETYPE_GRB && !CDI_gribapi_grib1 )
54177     {
54178       if ( cdiGribChangeParameterID.active )
54179         {
54180           // Even if you are stream-copy records you might need to change a bit of grib-header !
54181           void *gh = cgribex_handle_new_from_meassage((void*) gribbuffer, recsize);
54182           cgribexChangeParameterIdentification(gh, cdiGribChangeParameterID.code, cdiGribChangeParameterID.ltype, cdiGribChangeParameterID.lev);
54183           cgribex_handle_delete(gh);
54184           cdiGribChangeParameterID.active = false; // after grib attributes have been changed turn it off again
54185         }
54186     }
54187   else
54188 #endif
54189 #ifdef HAVE_LIBGRIB_API
54190     {
54191       if ( cdiGribChangeParameterID.active )
54192         {
54193           // Even if you are stream-copy records you might need to change a bit of grib-header !
54194           void *gh = (void*)grib_handle_new_from_message(NULL, (void*) gribbuffer, recsize);
54195           gribapiChangeParameterIdentification(gh, cdiGribChangeParameterID.code, cdiGribChangeParameterID.ltype, cdiGribChangeParameterID.lev);
54196           grib_handle_delete(gh);
54197           cdiGribChangeParameterID.active = false; // after grib attributes have been changed turn it off again
54198         }
54199     }
54200 #else
54201     {
54202       Error("ecCodes support not compiled in!");
54203     }
54204 #endif
54205 
54206 #ifdef HAVE_LIBGRIB_API
54207 #ifdef HIRLAM_EXTENSIONS
54208   // Even if you are stream-copy records you might need to change a bit of grib-header !
54209 
54210   if ( cdiGribDataScanningMode.active )
54211     // allowed modes: <0, 64, 96>; Default is 64
54212     // This will overrule the old scanning mode of the given grid
54213     {
54214       grib_handle *gh = NULL;
54215       gh = grib_handle_new_from_message(NULL, (void *) gribbuffer, recsize);
54216 
54217       const int scanModeIN = gribapiGetScanningMode(gh);
54218 
54219       grib_handle_delete(gh);
54220 
54221       if (cdiDebugExt>=20) Message("Change GribDataScanningMode => %d (scanModeIN = %d)", cdiGribDataScanningMode.value, scanModeIN);
54222 
54223       if (scanModeIN != cdiGribDataScanningMode.value)
54224         {
54225           size_t nmiss = 0;
54226 
54227           const int vlistID = streamptr1->vlistID;
54228           const int varID   = streamptr1->tsteps[tsID].records[recID].varID;
54229           const int levelID = streamptr1->tsteps[tsID].records[recID].levelID;
54230           const int gridID  = vlistInqVarGrid(vlistID, varID);
54231 
54232           size_t gridsize = gridInqSize(gridID);
54233           if ( vlistNumber(vlistID) != CDI_REAL ) gridsize *= 2;
54234           double *data = (double *) malloc(gridsize*sizeof(double));
54235 
54236           if (cdiDebugExt>=20) Message(" processing varID %d; levelID %d",varID,levelID);
54237 
54238           grb_write_var_slice(streamptr2, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
54239 
54240           free(data);
54241         }
54242     }
54243 #endif // HIRLAM_EXTENSIONS
54244 #endif
54245 
54246   if ( filetype == CDI_FILETYPE_GRB )
54247     {
54248       size_t unzipsize;
54249       const int izip = gribGetZip(recsize, gribbuffer, &unzipsize);
54250 
54251       if ( izip == 0 && (streamptr2->comptype == CDI_COMPRESS_SZIP || streamptr2->comptype == CDI_COMPRESS_AEC) )
54252           nbytes = grbSzip(filetype, gribbuffer, nbytes);
54253     }
54254 
54255   while ( nbytes & 7 ) gribbuffer[nbytes++] = 0;
54256 
54257   const size_t nwrite = fileWrite(fileID2, gribbuffer, nbytes);
54258   if ( nwrite != nbytes )
54259     {
54260       perror(__func__);
54261       Error("Could not write record for copying!");
54262     }
54263 
54264   Free(gribbuffer);
54265 }
54266 
54267 
grb_write_var_slice(stream_t * streamptr,int varID,int levelID,int memtype,const void * data,size_t nmiss)54268 void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss)
54269 {
54270   void *gribbuffer = NULL;
54271   void *gc = NULL;
54272 
54273   int filetype  = streamptr->filetype;
54274   int fileID    = streamptr->fileID;
54275   int vlistID   = streamptr->vlistID;
54276   int gridID    = vlistInqVarGrid(vlistID, varID);
54277   int zaxisID   = vlistInqVarZaxis(vlistID, varID);
54278   int tsteptype = vlistInqVarTsteptype(vlistID, varID);
54279   int comptype  = streamptr->comptype;
54280   int tsID      = streamptr->curTsID;
54281   int date      = streamptr->tsteps[tsID].taxis.vdate;
54282   int time      = streamptr->tsteps[tsID].taxis.vtime;
54283   int numavg    = (tsteptype == TSTEP_AVG) ? streamptr->tsteps[tsID].taxis.numavg : 0;
54284 
54285   if ( CDI_Debug )
54286     Message("gridID = %d zaxisID = %d", gridID, zaxisID);
54287 
54288   size_t datasize = gridInqSize(gridID);
54289 
54290 #ifdef HAVE_LIBCGRIBEX
54291   if ( filetype == CDI_FILETYPE_GRB && !CDI_gribapi_grib1 )
54292     {
54293     }
54294   else
54295 #endif
54296     {
54297 #ifdef GRIBCONTAINER2D
54298       gribContainer_t **gribContainers =  (gribContainer_t **) streamptr->gribContainers;
54299       gc = (void *) &gribContainers[varID][levelID];
54300 #else
54301       gribContainer_t *gribContainers =  (gribContainer_t *) streamptr->gribContainers;
54302       gc = (void *) &gribContainers[varID];
54303 #endif
54304     }
54305 
54306   if ( comptype != CDI_COMPRESS_JPEG && comptype != CDI_COMPRESS_SZIP && comptype != CDI_COMPRESS_AEC ) comptype = CDI_COMPRESS_NONE;
54307 
54308   if ( filetype == CDI_FILETYPE_GRB && !CDI_gribapi_grib1 && comptype == CDI_COMPRESS_JPEG )
54309     {
54310       static int ljpeg_warn = 1;
54311       if ( ljpeg_warn ) Warning("JPEG compression of GRIB1 records not available!");
54312       ljpeg_warn = 0;
54313     }
54314 
54315   size_t nbytes = grbEncode(filetype, memtype, varID, levelID, vlistID, gridID, zaxisID, date, time, tsteptype, numavg,
54316                             datasize, data, nmiss, &gribbuffer, comptype, gc);
54317 
54318   if ( filetype == CDI_FILETYPE_GRB && (streamptr->comptype == CDI_COMPRESS_SZIP || streamptr->comptype == CDI_COMPRESS_AEC) )
54319     nbytes = grbSzip(filetype, gribbuffer, nbytes);
54320 
54321   size_t (*myFileWrite)(int fileID, const void *restrict buffer, size_t len, int tsID)
54322     = (size_t (*)(int, const void *restrict, size_t, int))
54323     namespaceSwitchGet(NSSWITCH_FILE_WRITE).func;
54324 
54325   const size_t nwrite = myFileWrite(fileID, gribbuffer, nbytes, tsID);
54326   if ( nwrite != nbytes )
54327     {
54328       perror(__func__);
54329       Error("Failed to write GRIB slice!");
54330     }
54331 
54332   if ( gribbuffer ) Free(gribbuffer);
54333 }
54334 
54335 
grb_write_var(stream_t * streamptr,int varID,int memtype,const void * data,size_t nmiss)54336 void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss)
54337 {
54338   int vlistID  = streamptr->vlistID,
54339     gridID   = vlistInqVarGrid(vlistID, varID),
54340     zaxisID  = vlistInqVarZaxis(vlistID, varID),
54341     nlevs    = zaxisInqSize(zaxisID);
54342   size_t gridsize = gridInqSize(gridID);
54343   double missval = vlistInqVarMissval(vlistID, varID);
54344 
54345   size_t chunkLen = gridsize;
54346   if ( memtype == MEMTYPE_FLOAT )
54347     for ( int levelID = 0; levelID < nlevs; levelID++ )
54348       {
54349         const float *restrict fdata = ((const float *)data)+levelID*gridsize;
54350 
54351         size_t nmiss_slice = 0;
54352         if ( nmiss )
54353           for ( size_t i = 0; i < chunkLen; ++i )
54354             nmiss_slice += DBL_IS_EQUAL(fdata[i], missval);
54355 
54356         grb_write_var_slice(streamptr, varID, levelID, memtype, fdata, nmiss_slice);
54357       }
54358   else
54359     for ( int levelID = 0; levelID < nlevs; levelID++ )
54360       {
54361         const double *restrict ddata = ((const double *)data)+levelID*gridsize;
54362 
54363         size_t nmiss_slice = 0;
54364         if ( nmiss )
54365           for ( size_t i = 0; i < chunkLen; ++i )
54366             nmiss_slice += DBL_IS_EQUAL(ddata[i], missval);
54367 
54368         grb_write_var_slice(streamptr, varID, levelID, memtype, ddata, nmiss_slice);
54369       }
54370 }
54371 
54372 
grb_write_record(stream_t * streamptr,int memtype,const void * data,size_t nmiss)54373 void grb_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss)
54374 {
54375   int varID   = streamptr->record->varID;
54376   int levelID = streamptr->record->levelID;
54377 
54378   grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
54379 }
54380 
54381 
54382 #endif
54383 #ifdef HAVE_CONFIG_H
54384 #endif
54385 
54386 #ifdef HAVE_LIBGRIB
54387 
54388 
54389 
54390 static
grbDecode(int filetype,int memtype,void * cgribexp,void * gribbuffer,size_t gribsize,void * data,size_t datasize,int unreduced,size_t * nmiss,double missval)54391 int grbDecode(int filetype, int memtype, void *cgribexp, void *gribbuffer, size_t gribsize, void *data, size_t datasize,
54392 	      int unreduced, size_t *nmiss, double missval)
54393 {
54394   int status = 0;
54395 
54396 #ifdef HAVE_LIBCGRIBEX
54397   if ( filetype == CDI_FILETYPE_GRB && !CDI_gribapi_grib1 )
54398     {
54399 #ifdef HAVE_LIBGRIB_API
54400       extern int cdiNAdditionalGRIBKeys;
54401       if ( cdiNAdditionalGRIBKeys > 0 )
54402 	Error("CGRIBEX decode does not support reading of additional GRIB keys!");
54403 #endif
54404       status = cgribexDecode(memtype, cgribexp, gribbuffer, gribsize, data, datasize, unreduced, nmiss, missval);
54405     }
54406   else
54407 #endif
54408 #ifdef HAVE_LIBGRIB_API
54409     {
54410       void *datap = (memtype == MEMTYPE_FLOAT) ? Malloc(datasize*sizeof(double)) : data;
54411 
54412       status = gribapiDecode(gribbuffer, gribsize, datap, datasize, unreduced, nmiss, missval);
54413 
54414       if ( memtype == MEMTYPE_FLOAT )
54415         {
54416           float *dataf = (float*) data;
54417           double *datad = (double*) datap;
54418           for ( size_t i = 0; i < datasize; ++i ) dataf[i] = (float) datad[i];
54419           Free(datap);
54420         }
54421     }
54422 #else
54423     {
54424       Error("ecCodes support not compiled in!");
54425     }
54426 #endif
54427 
54428   return status;
54429 }
54430 
54431 // Decompresses the grib data in gribbuffer.
54432 static
grbUnzipRecord(void * gribbuffer,size_t * gribsize)54433 int grbUnzipRecord(void *gribbuffer, size_t *gribsize)
54434 {
54435   int zip = 0;
54436 
54437   const size_t igribsize = *gribsize;
54438   size_t ogribsize = *gribsize;
54439 
54440   int izip;
54441   size_t unzipsize;
54442   if ( (izip = gribGetZip(igribsize, (unsigned char *)gribbuffer, &unzipsize)) > 0 )
54443     {
54444       zip = izip;
54445       if ( izip == 128 ) /* szip */
54446 	{
54447 	  if ( unzipsize < igribsize )
54448 	    {
54449 	      fprintf(stderr, "Decompressed size smaller than compressed size (in %zu; out %zu)!\n", igribsize, unzipsize);
54450 	      return 0;
54451 	    }
54452 
54453 	  unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
54454 
54455 	  void *buffer = Malloc(igribsize);
54456 	  memcpy(buffer, gribbuffer, igribsize);
54457 
54458 	  ogribsize = (size_t)gribUnzip(gribbuffer, (long)unzipsize, buffer, (long)igribsize);
54459 
54460           Free(buffer);
54461 
54462 	  if ( ogribsize <= 0 ) Error("Decompression problem!");
54463 	}
54464       else
54465 	{
54466 	  Error("Decompression for %d not implemented!", izip);
54467 	}
54468     }
54469 
54470   *gribsize = ogribsize;
54471 
54472   return zip;
54473 }
54474 
54475 
54476 typedef struct DecodeArgs {
54477   int recID, *outZip, filetype, memtype, unreduced;
54478   void *cgribexp, *gribbuffer, *data;
54479   size_t recsize, gridsize, nmiss;
54480   double missval;
54481 } DecodeArgs;
54482 
54483 
54484 static
grb_decode_record(void * untypedArgs)54485 int grb_decode_record(void *untypedArgs)
54486 {
54487   DecodeArgs *args = untypedArgs;
54488   *args->outZip = grbUnzipRecord(args->gribbuffer, &args->recsize);
54489   grbDecode(args->filetype, args->memtype, args->cgribexp, args->gribbuffer, args->recsize, args->data, args->gridsize,
54490             args->unreduced, &args->nmiss, args->missval);
54491   return 0;
54492 }
54493 
54494 static
grb_read_raw_data(stream_t * streamptr,int recID,int memtype,void * gribbuffer,void * data,bool resetFilePos)54495 DecodeArgs grb_read_raw_data(stream_t *streamptr, int recID, int memtype, void *gribbuffer, void *data, bool resetFilePos)
54496 {
54497   const int vlistID = streamptr->vlistID;
54498   const int fileID = streamptr->fileID;
54499   const int tsID = streamptr->curTsID;	// FIXME: This should be looked up from the given recID
54500   const off_t recpos = streamptr->tsteps[tsID].records[recID].position;
54501   const size_t recsize = streamptr->tsteps[tsID].records[recID].size;
54502   const int varID = streamptr->tsteps[tsID].records[recID].varID;
54503 
54504   const int gridID = vlistInqVarGrid(vlistID, varID);
54505   const size_t gridsize = gridInqSize(gridID);
54506   if ( CDI_Debug ) Message("gridID = %d gridsize = %zu", gridID, gridsize);
54507 
54508   if ( recsize == 0 ) Error("Internal problem! Recordsize is zero for record %d at timestep %d", recID+1, tsID+1);
54509 
54510   void *cgribexp = (gribbuffer && streamptr->record->cgribexp) ? streamptr->record->cgribexp : NULL;
54511   if (!gribbuffer) gribbuffer = Malloc(streamptr->record->buffersize);
54512   if (!data) data = Malloc(gridsize*(memtype == MEMTYPE_FLOAT ? sizeof(float) : sizeof(double)));
54513 
54514   if (resetFilePos)
54515     {
54516       const off_t currentfilepos = fileGetPos(fileID);
54517       fileSetPos(fileID, recpos, SEEK_SET);
54518       if (fileRead(fileID, gribbuffer, recsize) != recsize) Error("Failed to read GRIB record");
54519       fileSetPos(fileID, currentfilepos, SEEK_SET);
54520     }
54521   else
54522     {
54523       fileSetPos(fileID, recpos, SEEK_SET);
54524       if (fileRead(fileID, gribbuffer, recsize) != recsize) Error("Failed to read GRIB record");
54525       streamptr->numvals += gridsize;
54526     }
54527 
54528   return (DecodeArgs){
54529     .recID = recID,
54530     .outZip = &streamptr->tsteps[tsID].records[recID].zip,
54531     .filetype = streamptr->filetype,
54532     .memtype = memtype,
54533     .cgribexp = cgribexp,
54534     .gribbuffer = gribbuffer,
54535     .recsize = recsize,
54536     .data = data,
54537     .gridsize = gridsize,
54538     .unreduced = streamptr->unreduced,
54539     .nmiss = 0,
54540     .missval = vlistInqVarMissval(vlistID, varID),
54541   };
54542 }
54543 
54544 typedef struct JobDescriptor {
54545   DecodeArgs args;
54546   AsyncJob *job;
54547 } JobDescriptor;
54548 
54549 static
JobDescriptor_startJob(AsyncManager * jobManager,JobDescriptor * me,stream_t * streamptr,int recID,int memtype,bool resetFilePos)54550 void JobDescriptor_startJob(AsyncManager *jobManager, JobDescriptor *me, stream_t *streamptr, int recID, int memtype, bool resetFilePos)
54551 {
54552   me->args = grb_read_raw_data(streamptr, recID, memtype, NULL, NULL, resetFilePos);
54553   me->job = AsyncWorker_requestWork(jobManager, grb_decode_record, &me->args);
54554   if (!me->job) xabort("error while trying to send job to worker thread");
54555 }
54556 
54557 static
JobDescriptor_finishJob(AsyncManager * jobManager,JobDescriptor * me,void * data,size_t * nmiss)54558 void JobDescriptor_finishJob(AsyncManager *jobManager, JobDescriptor *me, void *data, size_t *nmiss)
54559 {
54560   if (AsyncWorker_wait(jobManager, me->job)) xabort("error executing job in worker thread");
54561   memcpy(data, me->args.data, me->args.gridsize*(me->args.memtype == MEMTYPE_FLOAT ? sizeof(float) : sizeof(double)));
54562   *nmiss = me->args.nmiss;
54563 
54564   Free(me->args.gribbuffer);
54565   Free(me->args.data);
54566   me->args.recID = -1;	// mark as inactive
54567 }
54568 
54569 static
grb_read_next_record(stream_t * streamptr,int recID,int memtype,void * data,size_t * nmiss,bool resetFilePos)54570 void grb_read_next_record(stream_t *streamptr, int recID, int memtype, void *data, size_t *nmiss, bool resetFilePos)
54571 {
54572   bool jobFound = false;
54573 
54574   int workerCount = streamptr->numWorker;
54575   if (workerCount > 0)
54576     {
54577       if (workerCount > streamptr->tsteps[0].nrecs) workerCount = streamptr->tsteps[0].nrecs;
54578 
54579       AsyncManager *jobManager = (AsyncManager *) streamptr->jobManager;
54580       JobDescriptor *jobs = (JobDescriptor *) streamptr->jobs;
54581 
54582       // if this is the first call, init and start worker threads
54583       tsteps_t *timestep = &streamptr->tsteps[streamptr->curTsID];
54584 
54585       if (!jobs)
54586         {
54587           jobs = malloc(workerCount*sizeof*jobs);
54588           streamptr->jobs = jobs;
54589           for (int i = 0; i < workerCount; i++) jobs[i].args.recID = -1;
54590           if (AsyncWorker_init(&jobManager, workerCount)) xabort("error while trying to start worker threads");
54591           streamptr->jobManager = jobManager;
54592         }
54593 
54594       if (recID == 0) streamptr->nextRecID = 0;
54595       if (recID == 0) streamptr->cachedTsID = streamptr->curTsID; // no active workers -> we may start processing records of a new timestep
54596 
54597       if (streamptr->cachedTsID == streamptr->curTsID)
54598         {
54599           // Start as many new jobs as possible.
54600           for (int i = 0; streamptr->nextRecID < timestep->nrecs && i < workerCount; i++)
54601             {
54602               JobDescriptor *jd = &jobs[i];
54603               if (jd->args.recID < 0)
54604                 {
54605                   JobDescriptor_startJob(jobManager, jd, streamptr, timestep->recIDs[streamptr->nextRecID++], memtype, resetFilePos);
54606                 }
54607             }
54608 
54609           // search for a job descriptor with the given recID, and use its results if it exists
54610           for (int i = 0; !jobFound && i < workerCount; i++)
54611             {
54612               JobDescriptor *jd = &jobs[i];
54613               if (jd->args.recID == recID)
54614                 {
54615                   jobFound = true;
54616                   JobDescriptor_finishJob(jobManager, jd, data, nmiss);
54617                   if (streamptr->nextRecID < timestep->nrecs)
54618                     {
54619                       JobDescriptor_startJob(jobManager, jd, streamptr, timestep->recIDs[streamptr->nextRecID++], memtype, resetFilePos);
54620                     }
54621                 }
54622             }
54623         }
54624     }
54625 
54626   // perform the work synchronously if we didn't start a job for it yet
54627   if (!jobFound)
54628     {
54629       DecodeArgs args = grb_read_raw_data(streamptr, recID, memtype, streamptr->record->buffer, data, resetFilePos);
54630       grb_decode_record(&args);
54631       *nmiss = args.nmiss;
54632     }
54633 }
54634 
54635 
grb_read_record(stream_t * streamptr,int memtype,void * data,size_t * nmiss)54636 void grb_read_record(stream_t *streamptr, int memtype, void *data, size_t *nmiss)
54637 {
54638   const int tsID = streamptr->curTsID;
54639   const int vrecID = streamptr->tsteps[tsID].curRecID;
54640   const int recID = streamptr->tsteps[tsID].recIDs[vrecID];
54641 
54642   grb_read_next_record(streamptr, recID, memtype, data, nmiss, false);
54643 }
54644 
54645 
grb_read_var_slice(stream_t * streamptr,int varID,int levelID,int memtype,void * data,size_t * nmiss)54646 void grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, size_t *nmiss)
54647 {
54648   const int isub = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
54649   const int recID = streamptr->vars[varID].recordTable[isub].recordID[levelID];
54650 
54651   grb_read_next_record(streamptr, recID, memtype, data, nmiss, true);
54652 }
54653 
54654 
grb_read_var(stream_t * streamptr,int varID,int memtype,void * data,size_t * nmiss)54655 void grb_read_var(stream_t *streamptr, int varID, int memtype, void *data, size_t *nmiss)
54656 {
54657   const int vlistID = streamptr->vlistID;
54658   const int fileID = streamptr->fileID;
54659 
54660   const int gridID = vlistInqVarGrid(vlistID, varID);
54661   const size_t gridsize = gridInqSize(gridID);
54662 
54663   const off_t currentfilepos = fileGetPos(fileID);
54664 
54665   const int isub = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
54666   const int nlevs = streamptr->vars[varID].recordTable[0].nlevs;
54667 
54668   if ( CDI_Debug ) Message("nlevs = %d gridID = %d gridsize = %zu", nlevs, gridID, gridsize);
54669 
54670   *nmiss = 0;
54671   for (int levelID = 0; levelID < nlevs; levelID++)
54672     {
54673       const int recID = streamptr->vars[varID].recordTable[isub].recordID[levelID];
54674 
54675       void *datap = NULL;
54676       if ( memtype == MEMTYPE_FLOAT )
54677         datap = (float*)data + levelID*gridsize;
54678       else
54679         datap = (double*)data + levelID*gridsize;
54680 
54681       size_t imiss;
54682       grb_read_next_record(streamptr, recID, memtype, datap, &imiss, false);
54683       *nmiss += imiss;
54684     }
54685 
54686   fileSetPos(fileID, currentfilepos, SEEK_SET);
54687 }
54688 
54689 #endif
54690 #ifndef  VLIST_VAR_H
54691 #define  VLIST_VAR_H
54692 
54693 #ifdef  HAVE_CONFIG_H
54694 #endif
54695 
54696 #ifndef  VLIST_H
54697 #endif
54698 
54699 int  vlistVarGetPackSize(vlist_t *p, int varID, void *context);
54700 void vlistVarPack(vlist_t *p, int varID, char * buffer, int bufferSize, int * pos, void *context);
54701 void vlistVarUnpack(int vlistID, char * buf, int size, int *position, int, void *context);
54702 int vlistVarCompare(vlist_t *a, int varIDA, vlist_t *b, int varIDB);
54703 void vlistDefVarIOrank( int, int, int );
54704 int  vlistInqVarIOrank( int, int );
54705 
54706 void cdiVlistCreateVarLevInfo(vlist_t *vlistptr, int varID);
54707 
54708 #endif
54709 /*
54710  * Local Variables:
54711  * c-file-style: "Java"
54712  * c-basic-offset: 2
54713  * indent-tabs-mode: nil
54714  * show-trailing-whitespace: t
54715  * require-trailing-newline: t
54716  * End:
54717  */
54718 #ifdef HAVE_CONFIG_H
54719 #endif
54720 
54721 #ifdef HAVE_LIBNETCDF
54722 
54723 
54724 
cdfDefVarDeflate(int ncid,int ncvarID,int deflate_level)54725 void cdfDefVarDeflate(int ncid, int ncvarID, int deflate_level)
54726 {
54727 #ifdef HAVE_NETCDF4
54728   // Set chunking, shuffle, and deflate.
54729   const int shuffle = 1, deflate = 1;
54730 
54731   if (deflate_level < 1 || deflate_level > 9) deflate_level = 1;
54732 
54733   int status;
54734   if ((status = nc_def_var_deflate(ncid, ncvarID, shuffle, deflate, deflate_level)))
54735     {
54736       Error("nc_def_var_deflate failed; %s", nc_strerror(status));
54737     }
54738 #else
54739   static bool lwarn = true;
54740   if (lwarn)
54741     {
54742       lwarn = false;
54743       Warning("Deflate compression failed, NetCDF4 not available!");
54744     }
54745 #endif
54746 }
54747 
cdfDefVarSzip(int ncid,int ncvarID,int pixels_per_block)54748 void cdfDefVarSzip(int ncid, int ncvarID, int pixels_per_block)
54749 {
54750 #ifdef HAVE_NC_DEF_VAR_SZIP
54751   // Set options_mask.
54752   /*
54753     H5_SZIP_ALLOW_K13_OPTION_MASK   1
54754     H5_SZIP_CHIP_OPTION_MASK        2
54755     H5_SZIP_EC_OPTION_MASK          4
54756     H5_SZIP_NN_OPTION_MASK          32
54757     H5_SZIP_ALL_MASKS (H5_SZIP_CHIP_OPTION_MASK|H5_SZIP_EC_OPTION_MASK|H5_SZIP_NN_OPTION_MASK)
54758   */
54759   int options_mask = 38;
54760   int status;
54761   if ((status = nc_def_var_szip(ncid, ncvarID, options_mask, pixels_per_block)))
54762     Error("nc_def_var_szip failed; %s", nc_strerror(status));
54763 #else
54764   static bool lwarn = true;
54765   if (lwarn)
54766     {
54767       lwarn = false;
54768       Warning("Szip compression failed, NetCDF4/szlib not available!");
54769     }
54770 #endif
54771 }
54772 
54773 #ifdef HAVE_NETCDF4
54774 static
cdfTypeComplexFloat(stream_t * streamptr)54775 nc_type cdfTypeComplexFloat(stream_t *streamptr)
54776 {
54777   if (streamptr->nc_complex_float_id == CDI_UNDEFID)
54778     {
54779       typedef struct complex_float { float r, i; } complex_float;
54780       const int fileID = streamptr->fileID;
54781       int nc_complex_id;
54782       int status;
54783       status = nc_def_compound(fileID, sizeof(complex_float), "complex_float", &nc_complex_id);
54784       if (status != NC_NOERR) Error("%s", nc_strerror(status));
54785       status = nc_insert_compound(fileID, nc_complex_id, "r", NC_COMPOUND_OFFSET(complex_float, r), NC_FLOAT);
54786       if (status != NC_NOERR) Error("%s", nc_strerror(status));
54787       status = nc_insert_compound(fileID, nc_complex_id, "i", NC_COMPOUND_OFFSET(complex_float, i), NC_FLOAT);
54788       if (status != NC_NOERR) Error("%s", nc_strerror(status));
54789       streamptr->nc_complex_float_id = nc_complex_id;
54790     }
54791 
54792   return (nc_type) streamptr->nc_complex_float_id;
54793 }
54794 
54795 static
cdfTypeComplexDouble(stream_t * streamptr)54796 nc_type cdfTypeComplexDouble(stream_t *streamptr)
54797 {
54798   if (streamptr->nc_complex_double_id == CDI_UNDEFID)
54799     {
54800       typedef struct complex_double { double r, i; } complex_double;
54801       const int fileID  = streamptr->fileID;
54802       int nc_complex_id;
54803       int status;
54804       status = nc_def_compound(fileID, sizeof(complex_double), "complex_double", &nc_complex_id);
54805       if (status != NC_NOERR) Error("%s", nc_strerror(status));
54806       status = nc_insert_compound(fileID, nc_complex_id, "r", NC_COMPOUND_OFFSET(complex_double, r), NC_DOUBLE);
54807       if (status != NC_NOERR) Error("%s", nc_strerror(status));
54808       status = nc_insert_compound(fileID, nc_complex_id, "i", NC_COMPOUND_OFFSET(complex_double, i), NC_DOUBLE);
54809       if (status != NC_NOERR) Error("%s", nc_strerror(status));
54810       streamptr->nc_complex_double_id = nc_complex_id;
54811     }
54812 
54813   return (nc_type) streamptr->nc_complex_double_id;
54814 }
54815 #endif
54816 
cdfDefDatatype(int datatype,stream_t * streamptr)54817 nc_type cdfDefDatatype(int datatype, stream_t *streamptr)
54818 {
54819   nc_type xtype = NC_FLOAT;
54820 
54821   if ( streamptr->filetype == CDI_FILETYPE_NC4 )
54822     {
54823       if      ( datatype == CDI_DATATYPE_INT8   ) xtype = NC_BYTE;
54824       else if ( datatype == CDI_DATATYPE_INT16  ) xtype = NC_SHORT;
54825       else if ( datatype == CDI_DATATYPE_INT32  ) xtype = NC_INT;
54826 #ifdef  HAVE_NETCDF4
54827       else if ( datatype == CDI_DATATYPE_UINT8  ) xtype = NC_UBYTE;
54828       else if ( datatype == CDI_DATATYPE_UINT16 ) xtype = NC_USHORT;
54829       else if ( datatype == CDI_DATATYPE_UINT32 ) xtype = NC_UINT;
54830       else if ( datatype == CDI_DATATYPE_CPX32  ) xtype = cdfTypeComplexFloat(streamptr);
54831       else if ( datatype == CDI_DATATYPE_CPX64  ) xtype = cdfTypeComplexDouble(streamptr);
54832 #else
54833       else if ( datatype == CDI_DATATYPE_UINT8  ) xtype = NC_SHORT;
54834       else if ( datatype == CDI_DATATYPE_UINT16 ) xtype = NC_INT;
54835       else if ( datatype == CDI_DATATYPE_UINT32 ) xtype = NC_INT;
54836       else if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
54837         Error("CDI library does not support complex numbers with NetCDF4 classic!");
54838 #endif
54839       else if ( datatype == CDI_DATATYPE_FLT64  ) xtype = NC_DOUBLE;
54840       else if ( datatype == CDI_DATATYPE_FLT32  ) xtype = NC_FLOAT;
54841     }
54842   else
54843     {
54844       if      ( datatype == CDI_DATATYPE_INT8   ) xtype = NC_BYTE;
54845       else if ( datatype == CDI_DATATYPE_INT16  ) xtype = NC_SHORT;
54846       else if ( datatype == CDI_DATATYPE_INT32  ) xtype = NC_INT;
54847       else if ( datatype == CDI_DATATYPE_UINT8  ) xtype = NC_SHORT;
54848       else if ( datatype == CDI_DATATYPE_UINT16 ) xtype = NC_INT;
54849       else if ( datatype == CDI_DATATYPE_UINT32 ) xtype = NC_INT;
54850       else if ( datatype == CDI_DATATYPE_FLT64  ) xtype = NC_DOUBLE;
54851       else if ( datatype == CDI_DATATYPE_FLT32  ) xtype = NC_FLOAT;
54852       else if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
54853         Error("CDI library does not support complex numbers with NetCDF classic!");
54854     }
54855 
54856   return xtype;
54857 }
54858 
54859 static
cdfDefVarMissval(stream_t * streamptr,int varID,int dtype,int lcheck)54860 void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
54861 {
54862   if ( streamptr->vars[varID].defmiss == false )
54863     {
54864       const int vlistID = streamptr->vlistID;
54865       const int fileID  = streamptr->fileID;
54866       const int ncvarID = streamptr->vars[varID].ncvarid;
54867       const double missval = vlistInqVarMissval(vlistID, varID);
54868 
54869       if ( lcheck && streamptr->ncmode == 2 ) cdf_redef(fileID);
54870 
54871       nc_type xtype = cdfDefDatatype(dtype, streamptr);
54872       if ( xtype == NC_BYTE && missval > 127 && missval < 256 ) xtype = NC_INT;
54873 
54874       if ( lcheck == 0 ||
54875            streamptr->ncmode != 2 ||
54876            streamptr->filetype == CDI_FILETYPE_NC ||
54877            streamptr->filetype == CDI_FILETYPE_NC2||
54878            streamptr->filetype == CDI_FILETYPE_NC5 )
54879         cdf_put_att_double(fileID, ncvarID, "_FillValue", xtype, 1, &missval);
54880 
54881       cdf_put_att_double(fileID, ncvarID, "missing_value", xtype, 1, &missval);
54882 
54883       if ( lcheck && streamptr->ncmode == 2 ) cdf_enddef(fileID);
54884 
54885       streamptr->vars[varID].defmiss = true;
54886     }
54887 }
54888 
54889 static
cdfDefInstituteGlobal(const stream_t * streamptr)54890 void cdfDefInstituteGlobal(const stream_t *streamptr)
54891 {
54892   const int vlistID = streamptr->vlistID;
54893   const int fileID  = streamptr->fileID;
54894   const int instID  = vlistInqInstitut(vlistID);
54895 
54896   if ( instID != CDI_UNDEFID )
54897     {
54898       const char *longname = institutInqLongnamePtr(instID);
54899       if ( longname )
54900 	{
54901 	  const size_t len = strlen(longname);
54902 	  if ( len > 0 )
54903 	    {
54904 	      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
54905 	      cdf_put_att_text(fileID, NC_GLOBAL, "institution", len, longname);
54906 	      if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
54907 	    }
54908 	}
54909     }
54910 }
54911 
54912 static
cdfDefSourceGlobal(const stream_t * streamptr)54913 void cdfDefSourceGlobal(const stream_t *streamptr)
54914 {
54915   const int vlistID = streamptr->vlistID;
54916   const int fileID  = streamptr->fileID;
54917   const int modelID = vlistInqModel(vlistID);
54918 
54919   if ( modelID != CDI_UNDEFID )
54920     {
54921       const char *longname = modelInqNamePtr(modelID);
54922       if ( longname )
54923 	{
54924           size_t len = strlen(longname);
54925 	  if ( len > 0 )
54926 	    {
54927 	      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
54928 	      cdf_put_att_text(fileID, NC_GLOBAL, "source", len, longname);
54929 	      if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
54930 	    }
54931 	}
54932     }
54933 }
54934 
54935 static inline
resizeBuf(void ** buf,size_t * bufSize,size_t reqSize)54936 void *resizeBuf(void **buf, size_t *bufSize, size_t reqSize)
54937 {
54938   if ( reqSize > *bufSize )
54939     {
54940       *buf = Realloc(*buf, reqSize);
54941       *bufSize = reqSize;
54942     }
54943   return *buf;
54944 }
54945 
54946 static
cdfDefineCellMethods(stream_t * streamptr,int cdiID,int varID,int fileID,int ncvarID)54947 void cdfDefineCellMethods(stream_t *streamptr, int cdiID, int varID, int fileID, int ncvarID)
54948 {
54949   taxis_t *taxis = &streamptr->tsteps[0].taxis;
54950   if (!taxis->has_bounds) return;
54951 
54952   int time_varid = streamptr->basetime.ncvarid;
54953   char timeVarName[CDI_MAX_NAME];
54954   cdf_inq_varname(fileID, time_varid, timeVarName);
54955 
54956   int stepType = vlistInqVarTsteptype(cdiID, varID);
54957 
54958   const char *cellMethod = NULL;
54959   if      (stepType == TSTEP_AVG)   cellMethod = "mean";
54960   else if (stepType == TSTEP_SUM)   cellMethod = "sum";
54961   else if (stepType == TSTEP_RANGE) cellMethod = "range";
54962   else if (stepType == TSTEP_MIN)   cellMethod = "minimum";
54963   else if (stepType == TSTEP_MAX)   cellMethod = "maximum";
54964 
54965   if (cellMethod)
54966     {
54967       const char *attname = "cell_methods";
54968       char atttxt[CDI_MAX_NAME+10];
54969       sprintf(atttxt, "%s: %s", timeVarName, cellMethod);
54970       cdf_put_att_text(fileID, ncvarID, attname, strlen(atttxt), atttxt);
54971     }
54972 }
54973 
cdfDefineAttributes(int cdiID,int varID,int fileID,int ncvarID)54974 void cdfDefineAttributes(int cdiID, int varID, int fileID, int ncvarID)
54975 {
54976   int atttype, attlen;
54977   size_t len;
54978   char attname[CDI_MAX_NAME+1];
54979   void *attBuf = NULL;
54980   size_t attBufSize = 0;
54981 
54982   int natts;
54983   cdiInqNatts(cdiID, varID, &natts);
54984 
54985   for ( int iatt = 0; iatt < natts; ++iatt )
54986     {
54987       cdiInqAtt(cdiID, varID, iatt, attname, &atttype, &attlen);
54988 
54989       if ( attlen == 0 ) continue;
54990 
54991       if ( atttype == CDI_DATATYPE_TXT )
54992         {
54993           size_t attSize = (size_t)attlen*sizeof(char);
54994           char *atttxt = (char *)resizeBuf(&attBuf, &attBufSize, attSize);
54995           cdiInqAttTxt(cdiID, varID, attname, attlen, atttxt);
54996           len = (size_t)attlen;
54997           cdf_put_att_text(fileID, ncvarID, attname, len, atttxt);
54998         }
54999       else if ( atttype == CDI_DATATYPE_INT8  || atttype == CDI_DATATYPE_UINT8  ||
55000                 atttype == CDI_DATATYPE_INT16 || atttype == CDI_DATATYPE_UINT16 ||
55001                 atttype == CDI_DATATYPE_INT32 || atttype == CDI_DATATYPE_UINT32 )
55002         {
55003           size_t attSize = (size_t)attlen*sizeof(int);
55004           int *attint = (int *)resizeBuf(&attBuf, &attBufSize, attSize);
55005           cdiInqAttInt(cdiID, varID, attname, attlen, &attint[0]);
55006           len = (size_t)attlen;
55007           nc_type xtype = (atttype == CDI_DATATYPE_INT8)   ? NC_BYTE :
55008                           (atttype == CDI_DATATYPE_INT16)  ? NC_SHORT :
55009 #ifdef  HAVE_NETCDF4
55010                           (atttype == CDI_DATATYPE_UINT8)  ? NC_UBYTE :
55011                           (atttype == CDI_DATATYPE_UINT16) ? NC_USHORT :
55012                           (atttype == CDI_DATATYPE_UINT32) ? NC_UINT :
55013 #endif
55014                           NC_INT;
55015           cdf_put_att_int(fileID, ncvarID, attname, xtype, len, attint);
55016         }
55017       else if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
55018         {
55019           size_t attSize = (size_t)attlen * sizeof(double);
55020           double *attflt = (double *)resizeBuf(&attBuf, &attBufSize, attSize);
55021           cdiInqAttFlt(cdiID, varID, attname, attlen, attflt);
55022           len = (size_t)attlen;
55023           if ( atttype == CDI_DATATYPE_FLT32 )
55024             {
55025               float attflt_sp[8];
55026               float *pattflt_sp = (len > 8) ? (float*) malloc(len*sizeof(float)) : attflt_sp;
55027               for ( size_t i = 0; i < len; ++i ) pattflt_sp[i] = (float)attflt[i];
55028               cdf_put_att_float(fileID, ncvarID, attname, NC_FLOAT, len, pattflt_sp);
55029               if (len > 8) free(pattflt_sp);
55030             }
55031           else
55032             cdf_put_att_double(fileID, ncvarID, attname, NC_DOUBLE, len, attflt);
55033         }
55034     }
55035 
55036   Free(attBuf);
55037 }
55038 
55039 static
cdfDefineInstituteName(int vlistID,int varID,int fileID,int ncvarID)55040 void cdfDefineInstituteName(int vlistID, int varID, int fileID, int ncvarID)
55041 {
55042   const int instID = vlistInqVarInstitut(vlistID, varID);
55043   if (instID != CDI_UNDEFID)
55044     {
55045       const char *name = institutInqNamePtr(instID);
55046       if (name) cdf_put_att_text(fileID, ncvarID, "institution", strlen(name), name);
55047     }
55048 }
55049 
55050 static
cdfDefGlobalAtts(stream_t * streamptr)55051 void cdfDefGlobalAtts(stream_t *streamptr)
55052 {
55053   if ( streamptr->globalatts ) return;
55054 
55055   const int vlistID = streamptr->vlistID;
55056   const int fileID  = streamptr->fileID;
55057 
55058   cdfDefSourceGlobal(streamptr);
55059   cdfDefInstituteGlobal(streamptr);
55060 
55061   int natts;
55062   cdiInqNatts(vlistID, CDI_GLOBAL, &natts);
55063 
55064   if ( natts > 0 && streamptr->ncmode == 2 ) cdf_redef(fileID);
55065 
55066   cdfDefineAttributes(vlistID, CDI_GLOBAL, fileID, NC_GLOBAL);
55067 
55068   if ( natts > 0 && streamptr->ncmode == 2 ) cdf_enddef(fileID);
55069 
55070   streamptr->globalatts = 1;
55071 }
55072 
55073 static
cdf_get_gmapvarname(int gridID,char * gmapvarname)55074 void cdf_get_gmapvarname(int gridID, char *gmapvarname)
55075 {
55076   int pgridID = gridID;
55077   char gmapname[CDI_MAX_NAME];
55078   int length = CDI_MAX_NAME;
55079   cdiInqKeyString(pgridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_NAME, gmapname, &length);
55080 
55081   if ( !gmapname[0] )
55082     {
55083       int projID = gridInqProj(gridID);
55084       if ( projID != CDI_UNDEFID )
55085         {
55086           pgridID = projID;
55087           length = CDI_MAX_NAME;
55088           cdiInqKeyString(pgridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_NAME, gmapname, &length);
55089         }
55090     }
55091 
55092   if ( gmapname[0] )
55093     {
55094       length = CDI_MAX_NAME;
55095       cdiInqKeyString(pgridID, CDI_GLOBAL, CDI_KEY_GRIDMAP_VARNAME, gmapvarname, &length);
55096     }
55097 }
55098 
55099 static
nc_grid_index(stream_t * streamptr,int gridID)55100 int nc_grid_index(stream_t *streamptr, int gridID)
55101 {
55102   int index = 0;
55103   const int vlistID = streamptr->vlistID;
55104   const int ngrids = vlistNgrids(vlistID);
55105   for ( index = 0; index < ngrids; ++index )
55106     if ( streamptr->ncgrid[index].gridID == gridID ) break;
55107 
55108   assert(index < ngrids);
55109 
55110   return index;
55111 }
55112 
55113 static
xtype2ppb(nc_type xtype)55114 int xtype2ppb(nc_type xtype)
55115 {
55116   int ppb = 32;
55117 
55118   if      (xtype == NC_BYTE)   ppb = 8;
55119   else if (xtype == NC_SHORT)  ppb = 16;
55120 #ifdef  HAVE_NETCDF4
55121   else if (xtype == NC_UBYTE)  ppb = 8;
55122   else if (xtype == NC_USHORT) ppb = 16;
55123 #endif
55124 
55125   return ppb;
55126 }
55127 
55128 static
cdfDefVarCompression(const stream_t * streamptr,int ncvarID,bool lchunk,nc_type xtype)55129 void cdfDefVarCompression(const stream_t *streamptr, int ncvarID, bool lchunk, nc_type xtype)
55130 {
55131   if ( streamptr->comptype == CDI_COMPRESS_ZIP )
55132     {
55133       if ( lchunk && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C) )
55134         {
55135           cdfDefVarDeflate(streamptr->fileID, ncvarID, streamptr->complevel);
55136         }
55137       else
55138         {
55139           if ( lchunk )
55140             {
55141               static bool lwarn = true;
55142               if ( lwarn )
55143                 {
55144                   lwarn = false;
55145                   Warning("Deflate compression is only available for NetCDF4!");
55146                 }
55147             }
55148         }
55149     }
55150   else if ( streamptr->comptype == CDI_COMPRESS_SZIP )
55151     {
55152       if ( lchunk && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C) )
55153         {
55154           cdfDefVarSzip(streamptr->fileID, ncvarID, xtype2ppb(xtype));
55155         }
55156       else
55157         {
55158           if ( lchunk )
55159             {
55160               static bool lwarn = true;
55161               if ( lwarn )
55162                 {
55163                   lwarn = false;
55164                   Warning("SZIP compression is only available for NetCDF4!");
55165                 }
55166             }
55167         }
55168     }
55169 }
55170 
55171 static
cdfDefVarPacking(const stream_t * streamptr,int ncvarID,nc_type xtype,int vlistID,int varID)55172 void cdfDefVarPacking(const stream_t *streamptr, int ncvarID, nc_type xtype, int vlistID, int varID)
55173 {
55174   //  if ( xtype == NC_BYTE || xtype == NC_SHORT || xtype == NC_INT )
55175     {
55176       const double addoffset   = vlistInqVarAddoffset(vlistID, varID);
55177       const double scalefactor = vlistInqVarScalefactor(vlistID, varID);
55178       const bool laddoffset   = IS_NOT_EQUAL(addoffset, 0);
55179       const bool lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
55180 
55181       if ( laddoffset || lscalefactor )
55182         {
55183           nc_type astype = (xtype == NC_FLOAT) ? NC_FLOAT : NC_DOUBLE;
55184           if ( (astype == NC_DOUBLE) &&
55185                IS_EQUAL(addoffset,   (double) ((float) addoffset)) &&
55186                IS_EQUAL(scalefactor, (double) ((float) scalefactor)) )
55187             {
55188               astype = NC_FLOAT;
55189             }
55190 
55191           cdf_put_att_double(streamptr->fileID, ncvarID, "add_offset",   astype, 1, &addoffset);
55192           cdf_put_att_double(streamptr->fileID, ncvarID, "scale_factor", astype, 1, &scalefactor);
55193         }
55194     }
55195 }
55196 
55197 static
cdfAppendCoordinates(int fileID,int ncvarID,char coordinates[CDI_MAX_NAME])55198 void cdfAppendCoordinates(int fileID, int ncvarID, char coordinates[CDI_MAX_NAME])
55199 {
55200   if (ncvarID != CDI_UNDEFID)
55201     {
55202       size_t len = strlen(coordinates);
55203       if (len) coordinates[len++] = ' ';
55204       cdf_inq_varname(fileID, ncvarID, coordinates+len);
55205     }
55206 }
55207 
55208 static
cdfDefineCoordinates(const stream_t * streamptr,int ncvarID,int nczvarID,int gridtype,int gridID,int gridindex,int xid,int yid,size_t gridsize,char axis[5],size_t iax)55209 void cdfDefineCoordinates(const stream_t *streamptr, int ncvarID, int nczvarID, int gridtype, int gridID, int gridindex,
55210                           int xid, int yid, size_t gridsize, char axis[5], size_t iax)
55211 {
55212   const int fileID  = streamptr->fileID;
55213 
55214   if ( gridtype != GRID_GENERIC && gridtype != GRID_LONLAT &&
55215        gridtype != GRID_PROJECTION && gridtype != GRID_CURVILINEAR && gridtype != GRID_CHARXY )
55216     {
55217       const size_t len = strlen(gridNamePtr(gridtype));
55218       if ( len > 0 ) cdf_put_att_text(fileID, ncvarID, "CDI_grid_type", len, gridNamePtr(gridtype));
55219     }
55220 
55221   char gmapvarname[CDI_MAX_NAME]; gmapvarname[0] = 0;
55222   cdf_get_gmapvarname(gridID, gmapvarname);
55223   if ( gmapvarname[0] ) cdf_put_att_text(fileID, ncvarID, "grid_mapping", strlen(gmapvarname), gmapvarname);
55224 
55225   if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
55226     {
55227       const int numLPE = gridInqNP(gridID);
55228       if (numLPE > 0)
55229         cdf_put_att_int(fileID, ncvarID, "CDI_grid_num_LPE", NC_INT, 1, &numLPE);
55230     }
55231 
55232   if ( gridtype == GRID_GAUSSIAN_REDUCED )
55233     {
55234       const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
55235       if (ncyvarID != CDI_UNDEFID)
55236         {
55237           char name[CDI_MAX_NAME]; name[0] = 0;
55238           cdf_inq_varname(fileID, ncyvarID, name);
55239           size_t len = strlen(name);
55240           cdf_put_att_text(fileID, ncvarID, "CDI_grid_latitudes", len, name);
55241         }
55242 
55243       const int ncrpvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_RP];
55244       if (ncrpvarID != CDI_UNDEFID)
55245         {
55246           char name[CDI_MAX_NAME]; name[0] = 0;
55247           cdf_inq_varname(fileID, ncrpvarID, name);
55248           size_t len = strlen(name);
55249           cdf_put_att_text(fileID, ncvarID, "CDI_grid_reduced_points", len, name);
55250         }
55251     }
55252 
55253   // define coordinates attribute
55254 
55255   char coordinates[CDI_MAX_NAME]; coordinates[0] = 0;
55256 
55257   if (nczvarID != CDI_UNDEFID) cdfAppendCoordinates(fileID, nczvarID, coordinates);
55258 
55259   if ( gridtype == GRID_TRAJECTORY )
55260     {
55261       cdf_put_att_text(fileID, ncvarID, "coordinates", 9, "tlon tlat");
55262     }
55263   else if ( gridtype == GRID_LONLAT && xid == CDI_UNDEFID && yid == CDI_UNDEFID && gridsize == 1 )
55264     {
55265       const int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
55266       const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
55267       cdfAppendCoordinates(fileID, ncyvarID, coordinates);
55268       cdfAppendCoordinates(fileID, ncxvarID, coordinates);
55269     }
55270   else if ( gridtype == GRID_GAUSSIAN_REDUCED )
55271     {
55272       /*
55273       const int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
55274       const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
55275       cdfAppendCoordinates(fileID, ncyvarID, coordinates);
55276       cdfAppendCoordinates(fileID, ncxvarID, coordinates);
55277       */
55278     }
55279   else if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
55280     {
55281       const int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
55282       const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
55283       const int ncavarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_A];
55284       // CMOR order: coordinates = "lat lon"
55285       if ( CDI_Coordinates_Lon_Lat )
55286         {
55287           cdfAppendCoordinates(fileID, ncxvarID, coordinates);
55288           cdfAppendCoordinates(fileID, ncyvarID, coordinates);
55289         }
55290       else
55291         {
55292           cdfAppendCoordinates(fileID, ncyvarID, coordinates);
55293           cdfAppendCoordinates(fileID, ncxvarID, coordinates);
55294         }
55295 
55296       if ( ncavarID != CDI_UNDEFID )
55297         {
55298           char cellarea[CDI_MAX_NAME] = "area: ";
55299           size_t len = strlen(cellarea);
55300           cdf_inq_varname(fileID, ncavarID, cellarea+len);
55301           len = strlen(cellarea);
55302           cdf_put_att_text(fileID, ncvarID, "cell_measures", len, cellarea);
55303         }
55304 
55305       if ( gridtype == GRID_UNSTRUCTURED )
55306         {
55307           int position = gridInqPosition(gridID);
55308           if ( position > 0 )
55309             cdf_put_att_int(fileID, ncvarID, "number_of_grid_in_reference", NC_INT, 1, &position);
55310         }
55311     }
55312   else if ( gridtype == GRID_SPECTRAL || gridtype == GRID_FOURIER )
55313     {
55314       axis[iax++] = '-';
55315       axis[iax++] = '-';
55316       cdf_put_att_text(fileID, ncvarID, "axis", iax, axis);
55317       int gridTruncation = gridInqTrunc(gridID);
55318       cdf_put_att_int(fileID, ncvarID, "truncation", NC_INT, 1, &gridTruncation);
55319     }
55320   else if ( gridtype == GRID_CHARXY )
55321     {
55322       if ( gridInqXIsc(gridID) )
55323         {
55324           const int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
55325           cdfAppendCoordinates(fileID, ncxvarID, coordinates);
55326         }
55327       else if ( gridInqYIsc(gridID) )
55328         {
55329           const int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
55330           cdfAppendCoordinates(fileID, ncyvarID, coordinates);
55331         }
55332     }
55333 
55334   const size_t len = strlen(coordinates);
55335   if ( len ) cdf_put_att_text(fileID, ncvarID, "coordinates", len, coordinates);
55336 }
55337 
55338 static
cdfDefineDimsAndChunks(const stream_t * streamptr,int varID,int xid,int yid,int zid,size_t gridsize,const int dimorder[3],int dims[4],bool lchunk,size_t chunks[4],char axis[5],size_t * piax)55339 int cdfDefineDimsAndChunks(const stream_t *streamptr, int varID, int xid, int yid, int zid, size_t gridsize, const int dimorder[3], int dims[4], bool lchunk, size_t chunks[4], char axis[5], size_t *piax)
55340 {
55341   const int fileID  = streamptr->fileID;
55342   const int vlistID = streamptr->vlistID;
55343 
55344   size_t iax = *piax;
55345   int ndims = 0;
55346 
55347   for (int i = 0; i < 4; ++i) chunks[i] = 0;
55348 
55349   size_t xsize = 0, ysize = 0;
55350   if ( xid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, xid, &xsize);
55351   if ( yid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, yid, &ysize);
55352 
55353   const int timetype = vlistInqVarTimetype(vlistID, varID);
55354   if ( vlistHasTime(vlistID) && timetype != TIME_CONSTANT )
55355     {
55356       const int tid = streamptr->basetime.ncdimid;
55357       if (tid == CDI_UNDEFID) Error("Internal problem, time undefined!");
55358       axis[iax++] = 'T';
55359       chunks[ndims] = 1;
55360       dims[ndims] = tid;
55361       ndims++;
55362     }
55363 
55364   int chunktype = vlistInqVarChunkType(vlistID, varID);
55365   const size_t chunk_size_max = 65536;
55366   const size_t chunk_size_lim = 1073741823;
55367   if ( chunktype != CDI_CHUNK_LINES && gridsize > chunk_size_lim )
55368     {
55369       if ( CDI_Debug ) fprintf(stderr, "gridsize > %zu, changed chunktype to CDI_CHUNK_LINES!\n", chunk_size_lim);
55370       chunktype = CDI_CHUNK_LINES;
55371     }
55372 
55373   for ( int id = 0; id < 3; ++id )
55374     {
55375       if ( dimorder[id] == 3 && zid != CDI_UNDEFID )
55376         {
55377           axis[iax++] = 'Z';
55378           chunks[ndims] = 1;
55379           dims[ndims] = zid;
55380           ndims++;
55381         }
55382       else if ( dimorder[id] == 2 && yid != CDI_UNDEFID )
55383         {
55384           if ( chunktype == CDI_CHUNK_AUTO )
55385             chunks[ndims] = (chunk_size_max > gridsize) ? ysize : chunk_size_max/xsize;
55386           else
55387             chunks[ndims] = (chunktype == CDI_CHUNK_LINES) ? 1 : ysize;
55388           dims[ndims] = yid;
55389           ndims++;
55390         }
55391       else if ( dimorder[id] == 1 && xid != CDI_UNDEFID )
55392         {
55393           if ( chunktype == CDI_CHUNK_AUTO && yid == CDI_UNDEFID )
55394             chunks[ndims] = (chunk_size_max > xsize) ? xsize : chunk_size_max;
55395           else
55396             chunks[ndims] = (xsize > chunk_size_lim) ? chunk_size_lim : xsize;
55397           dims[ndims] = xid;
55398           ndims++;
55399         }
55400     }
55401 
55402   if ( CDI_Debug )
55403     fprintf(stderr, "lchunk %d chunktype %d  chunks %zu %zu %zu %zu\n", lchunk, chunktype, chunks[0], chunks[1], chunks[2], chunks[3]);
55404 
55405   *piax = iax;
55406   return ndims;
55407 }
55408 
55409 static
cdfDefineAttrLeveltype(int fileID,int ncvarID,int zaxisID,int zaxistype)55410 void cdfDefineAttrLeveltype(int fileID, int ncvarID, int zaxisID, int zaxistype)
55411 {
55412   if ( zaxistype == ZAXIS_CLOUD_BASE          ||
55413        zaxistype == ZAXIS_CLOUD_TOP           ||
55414        zaxistype == ZAXIS_ISOTHERM_ZERO       ||
55415        zaxistype == ZAXIS_TROPOPAUSE          ||
55416        zaxistype == ZAXIS_TOA                 ||
55417        zaxistype == ZAXIS_SEA_BOTTOM          ||
55418        zaxistype == ZAXIS_LAKE_BOTTOM         ||
55419        zaxistype == ZAXIS_SEDIMENT_BOTTOM     ||
55420        zaxistype == ZAXIS_SEDIMENT_BOTTOM_TA  ||
55421        zaxistype == ZAXIS_SEDIMENT_BOTTOM_TW  ||
55422        zaxistype == ZAXIS_MIX_LAYER           ||
55423        zaxistype == ZAXIS_ATMOSPHERE )
55424     {
55425       char varname[CDI_MAX_NAME];
55426       int length = CDI_MAX_NAME;
55427       cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_NAME, varname, &length);
55428       cdf_put_att_text(fileID, ncvarID, "level_type", strlen(varname), varname);
55429     }
55430 }
55431 
55432 static
cdfDefineAttrEnsemble(int fileID,int ncvarID,int vlistID,int varID)55433 void cdfDefineAttrEnsemble(int fileID, int ncvarID, int vlistID, int varID)
55434 {
55435   int perturbationNumber, numberOfForecastsInEnsemble, typeOfEnsembleForecast;
55436   if ( cdiInqKeyInt(vlistID, varID, CDI_KEY_PERTURBATIONNUMBER, &perturbationNumber) == 0 )
55437     cdf_put_att_int(fileID, ncvarID, "realization", NC_INT, 1, &perturbationNumber);
55438   if ( cdiInqKeyInt(vlistID, varID, CDI_KEY_NUMBEROFFORECASTSINENSEMBLE, &numberOfForecastsInEnsemble) == 0 )
55439     cdf_put_att_int(fileID, ncvarID, "ensemble_members", NC_INT, 1, &numberOfForecastsInEnsemble);
55440   if ( cdiInqKeyInt(vlistID, varID, CDI_KEY_TYPEOFENSEMBLEFORECAST, &typeOfEnsembleForecast) == 0 )
55441     cdf_put_att_int(fileID, ncvarID, "forecast_init_type", NC_INT, 1, &typeOfEnsembleForecast);
55442 }
55443 
55444 static
cdfCheckVarname(int fileID,char name[CDI_MAX_NAME])55445 void cdfCheckVarname(int fileID, char name[CDI_MAX_NAME])
55446 {
55447   if ( name[0] )
55448     {
55449       int ncvarID;
55450       char varname[CDI_MAX_NAME];
55451       sprintf(varname, "%s", name);
55452       char *varname2 = varname+strlen(varname);
55453       unsigned iz = 0;
55454 
55455       do
55456         {
55457           if ( iz ) sprintf(varname2, "_%u", iz+1);
55458 
55459           if ( nc_inq_varid(fileID, varname, &ncvarID) != NC_NOERR ) break;
55460 
55461           ++iz;
55462         }
55463       while ( iz <= 99 );
55464 
55465       if (iz > 99) Error("Variable name %s already exsist!", name);
55466 
55467       if ( strcmp(name, varname) != 0 )
55468         Warning("Changed %s entry of variable name '%s' to '%s'!", (iz==1)?"double":"multiple", name, varname);
55469 
55470       strcpy(name, varname);
55471     }
55472 }
55473 
55474 static
cdfGenVarname(int fileID,char name[CDI_MAX_NAME],int pnum,int pcat,int * pdis,int * pcode)55475 void cdfGenVarname(int fileID, char name[CDI_MAX_NAME], int pnum, int pcat, int *pdis, int *pcode)
55476 {
55477   char varname[CDI_MAX_NAME];
55478 
55479   int code = *pcode;
55480   if ( code < 0 ) code = -code;
55481   if ( pnum < 0 ) pnum = -pnum;
55482 
55483   if ( *pdis == 255 )
55484     sprintf(varname, "var%d", code);
55485   else
55486     sprintf(varname, "param%d.%d.%d", pnum, pcat, *pdis);
55487 
55488   char *varname2 = varname+strlen(varname);
55489   int ncvarID;
55490   unsigned iz = 0;
55491 
55492   do
55493     {
55494       if ( iz ) sprintf(varname2, "_%u", iz+1);
55495 
55496       if ( nc_inq_varid(fileID, varname, &ncvarID) != NC_NOERR ) break;
55497 
55498       ++iz;
55499     }
55500   while ( iz <= 99 );
55501 
55502   if (iz > 99) Error("Variable name %s already exsist!", name);
55503 
55504   strcpy(name, varname);
55505   *pcode = 0;
55506   *pdis = 255;
55507 }
55508 
55509 static
cdfDefVar(stream_t * streamptr,int varID)55510 int cdfDefVar(stream_t *streamptr, int varID)
55511 {
55512   if (streamptr->vars[varID].ncvarid != CDI_UNDEFID)
55513     return streamptr->vars[varID].ncvarid;
55514 
55515   const int fileID  = streamptr->fileID;
55516   if (CDI_Debug) Message("streamID = %d, fileID = %d, varID = %d", streamptr->self, fileID, varID);
55517 
55518   const int vlistID = streamptr->vlistID;
55519   const int param = vlistInqVarParam(vlistID, varID);
55520   int code = vlistInqVarCode(vlistID, varID);
55521   int pnum, pcat, pdis;
55522   cdiDecodeParam(param, &pnum, &pcat, &pdis);
55523 
55524   const int gridID = vlistInqVarGrid(vlistID, varID);
55525   const size_t gridsize = gridInqSize(gridID);
55526   const int gridtype = gridInqType(gridID);
55527   const int gridindex = nc_grid_index(streamptr, gridID);
55528   const int xid = (gridtype != GRID_TRAJECTORY) ? streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] : CDI_UNDEFID;
55529   const int yid = (gridtype != GRID_TRAJECTORY && gridtype != GRID_GAUSSIAN_REDUCED) ?
55530     streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y] : CDI_UNDEFID;
55531 
55532   const int zaxisID = vlistInqVarZaxis(vlistID, varID);
55533   const int zaxistype = zaxisInqType(zaxisID);
55534   const int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
55535   const int zid = streamptr->zaxisID[zaxisindex];
55536 
55537   int dimorder[3]; // ZYX and ZXY
55538   vlistInqVarDimorder(vlistID, varID, &dimorder);
55539   const bool lchunk = (dimorder[0] == 3) ? (gridsize >= 32) : false;
55540 
55541   if ( ((dimorder[0]>0)+(dimorder[1]>0)+(dimorder[2]>0)) < ((xid!=CDI_UNDEFID)+(yid!=CDI_UNDEFID)+(zid!=CDI_UNDEFID)) )
55542     {
55543       printf("zid=%d  yid=%d  xid=%d\n", zid, yid, xid);
55544       Error("Internal problem, dimension order missing!");
55545     }
55546 
55547   size_t iax = 0;
55548   char axis[5];
55549   int dims[4];
55550   size_t chunks[4];
55551   int ndims = cdfDefineDimsAndChunks(streamptr, varID, xid, yid, zid, gridsize, dimorder, dims, lchunk, chunks, axis, &iax);
55552 
55553   char name[CDI_MAX_NAME];
55554   int length = CDI_MAX_NAME;
55555   cdiInqKeyString(vlistID, varID, CDI_KEY_NAME, name, &length);
55556 
55557   char longname[CDI_MAX_NAME];
55558   vlistInqVarLongname(vlistID, varID, longname);
55559 
55560   char units[CDI_MAX_NAME];
55561   vlistInqVarUnits(vlistID, varID, units);
55562 
55563   char stdname[CDI_MAX_NAME];
55564   length = CDI_MAX_NAME;
55565   cdiInqKeyString(vlistID, varID, CDI_KEY_STDNAME, stdname, &length);
55566 
55567   const int tableID  = vlistInqVarTable(vlistID, varID);
55568   if (!name[0]) tableInqEntry(tableID, code, -1, name, longname, units);
55569   if (name[0]) cdfCheckVarname(fileID, name);
55570   else         cdfGenVarname(fileID, name, pnum, pcat, &pdis, &code);
55571 
55572   const int dtype = vlistInqVarDatatype(vlistID, varID);
55573   const nc_type xtype = cdfDefDatatype(dtype, streamptr);
55574 
55575   int ncvarID = -1;
55576   cdf_def_var(fileID, name, xtype, ndims, dims, &ncvarID);
55577 
55578 #ifdef  HAVE_NETCDF4
55579   if (lchunk && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C))
55580     cdf_def_var_chunking(fileID, ncvarID, NC_CHUNKED, chunks);
55581 #endif
55582 
55583   cdfDefVarCompression(streamptr, ncvarID, lchunk, xtype);
55584 
55585   if ( *stdname )  cdf_put_att_text(fileID, ncvarID, "standard_name", strlen(stdname), stdname);
55586   if ( *longname ) cdf_put_att_text(fileID, ncvarID, "long_name", strlen(longname), longname);
55587   if ( *units )    cdf_put_att_text(fileID, ncvarID, "units", strlen(units), units);
55588 
55589   if ( code > 0 && pdis == 255 )
55590     cdf_put_att_int(fileID, ncvarID, "code", NC_INT, 1, &code);
55591 
55592   if ( pdis != 255 )
55593     {
55594       char paramstr[32];
55595       cdiParamToString(param, paramstr, sizeof(paramstr));
55596       cdf_put_att_text(fileID, ncvarID, "param", strlen(paramstr), paramstr);
55597     }
55598 
55599   if ( tableID != CDI_UNDEFID )
55600     {
55601       int tablenum = tableInqNum(tableID);
55602       if (tablenum > 0) cdf_put_att_int(fileID, ncvarID, "table", NC_INT, 1, &tablenum);
55603     }
55604 
55605   const bool zaxisIsScalar = (zid == CDI_UNDEFID) ? (zaxisInqScalar(zaxisID) > 0) : false;
55606   const int nczvarID = (zaxisIsScalar || zaxistype == ZAXIS_CHAR) ? streamptr->nczvarID[zaxisindex] : CDI_UNDEFID;
55607 
55608   cdfDefineCoordinates(streamptr, ncvarID, nczvarID, gridtype, gridID, gridindex, xid, yid, gridsize, axis, iax);
55609 
55610   cdfDefVarPacking(streamptr, ncvarID, xtype, vlistID, varID);
55611 
55612   if ( dtype == CDI_DATATYPE_UINT8 && xtype == NC_BYTE )
55613     {
55614       const int validrange[2] = {0, 255};
55615       cdf_put_att_int(fileID, ncvarID, "valid_range", NC_SHORT, 2, validrange);
55616       cdf_put_att_text(fileID, ncvarID, "_Unsigned", 4, "true");
55617     }
55618 
55619   streamptr->vars[varID].ncvarid = ncvarID;
55620 
55621   if ( vlistInqVarMissvalUsed(vlistID, varID) )
55622     cdfDefVarMissval(streamptr, varID, vlistInqVarDatatype(vlistID, varID), 0);
55623 
55624   if (zid == CDI_UNDEFID) cdfDefineAttrLeveltype(fileID, ncvarID, zaxisID, zaxistype);
55625 
55626   cdfDefineAttrEnsemble(fileID, ncvarID, vlistID, varID);
55627 
55628   // Attribute: cell_methods
55629   cdfDefineCellMethods(streamptr, vlistID, varID, fileID, ncvarID);
55630 
55631   // Attributes
55632   cdfDefineAttributes(vlistID, varID, fileID, ncvarID);
55633 
55634   // Institute
55635   if (vlistInqInstitut(vlistID) == CDI_UNDEFID) cdfDefineInstituteName(vlistID, varID, fileID, ncvarID);
55636 
55637   return ncvarID;
55638 }
55639 
55640 
cdfEndDef(stream_t * streamptr)55641 void cdfEndDef(stream_t *streamptr)
55642 {
55643   cdfDefGlobalAtts(streamptr);
55644 
55645   if ( streamptr->accessmode == 0 )
55646     {
55647       const int fileID = streamptr->fileID;
55648       if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
55649 
55650       const int nvars = streamptr->nvars;
55651       for ( int varID = 0; varID < nvars; varID++ )
55652 	cdfDefVar(streamptr, varID);
55653 
55654       if ( streamptr->ncmode == 2 )
55655         {
55656           if ( CDI_Netcdf_Hdr_Pad == 0UL )
55657             cdf_enddef(fileID);
55658           else
55659             cdf__enddef(fileID, CDI_Netcdf_Hdr_Pad);
55660         }
55661 
55662       streamptr->accessmode = 1;
55663     }
55664 }
55665 
55666 static
cdfWriteGridTraj(stream_t * streamptr,int gridID)55667 void cdfWriteGridTraj(stream_t *streamptr, int gridID)
55668 {
55669   const int gridindex = nc_grid_index(streamptr, gridID);
55670   const int lonID = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
55671   const int latID = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
55672   const size_t index = (size_t)streamptr->curTsID;
55673 
55674   const double xlon = gridInqXval(gridID, 0);
55675   const double xlat = gridInqYval(gridID, 0);
55676 
55677   cdf_put_var1_double(streamptr->fileID, lonID, &index, &xlon);
55678   cdf_put_var1_double(streamptr->fileID, latID, &index, &xlat);
55679 }
55680 
55681 static
cdf_write_var_data(int fileID,int vlistID,int varID,int ncvarID,int dtype,size_t nvals,size_t xsize,size_t ysize,bool swapxy,size_t * start,size_t * count,int memtype,const void * data,size_t nmiss)55682 void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarID, int dtype, size_t nvals, size_t xsize, size_t ysize,
55683                         bool swapxy, size_t *start, size_t *count, int memtype, const void *data, size_t nmiss)
55684 {
55685   const double *pdata_dp = (const double *) data;
55686   double *mdata_dp = NULL;
55687   double *sdata_dp = NULL;
55688   const float *pdata_sp = (const float *) data;
55689   float *mdata_sp = NULL;
55690   float *sdata_sp = NULL;
55691 
55692   /*  if ( dtype == CDI_DATATYPE_INT8 || dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 ) */
55693     {
55694       const double missval      = vlistInqVarMissval(vlistID, varID);
55695       const double addoffset    = vlistInqVarAddoffset(vlistID, varID);
55696       const double scalefactor  = vlistInqVarScalefactor(vlistID, varID);
55697       const bool laddoffset     = IS_NOT_EQUAL(addoffset, 0);
55698       const bool lscalefactor   = IS_NOT_EQUAL(scalefactor, 1);
55699 
55700       if ( laddoffset || lscalefactor )
55701         {
55702           if ( memtype == MEMTYPE_FLOAT )
55703             {
55704               mdata_sp = (float *) Malloc(nvals*sizeof(float));
55705               memcpy(mdata_sp, pdata_sp, nvals*sizeof(float));
55706               pdata_sp = mdata_sp;
55707 
55708               if ( nmiss > 0 )
55709                 {
55710                   for ( size_t i = 0; i < nvals; i++ )
55711                     {
55712                       double temp = mdata_sp[i];
55713                       if ( !DBL_IS_EQUAL(temp, missval) )
55714                         {
55715                           if ( laddoffset )   temp -= addoffset;
55716                           if ( lscalefactor ) temp /= scalefactor;
55717                           mdata_sp[i] = (float)temp;
55718                         }
55719                     }
55720                 }
55721               else
55722                 {
55723                   for ( size_t i = 0; i < nvals; i++ )
55724                     {
55725                       double temp = mdata_sp[i];
55726                       if ( laddoffset )   temp -= addoffset;
55727                       if ( lscalefactor ) temp /= scalefactor;
55728                       mdata_sp[i] = (float)temp;
55729                     }
55730                 }
55731             }
55732           else
55733             {
55734               mdata_dp = (double *) Malloc(nvals*sizeof(double));
55735               memcpy(mdata_dp, pdata_dp, nvals*sizeof(double));
55736               pdata_dp = mdata_dp;
55737 
55738               if ( nmiss > 0 )
55739                 {
55740                   for ( size_t i = 0; i < nvals; i++ )
55741                     {
55742                       if ( !DBL_IS_EQUAL(mdata_dp[i], missval) )
55743                         {
55744                           if ( laddoffset )   mdata_dp[i] -= addoffset;
55745                           if ( lscalefactor ) mdata_dp[i] /= scalefactor;
55746                         }
55747                     }
55748                 }
55749               else
55750                 {
55751                   for ( size_t i = 0; i < nvals; i++ )
55752                     {
55753                       if ( laddoffset )   mdata_dp[i] -= addoffset;
55754                       if ( lscalefactor ) mdata_dp[i] /= scalefactor;
55755                     }
55756                 }
55757             }
55758         }
55759 
55760       if ( dtype == CDI_DATATYPE_UINT8 || dtype == CDI_DATATYPE_INT8 ||
55761            dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 )
55762         {
55763           if ( memtype == MEMTYPE_FLOAT )
55764             {
55765               if ( mdata_sp == NULL )
55766                 {
55767                   mdata_sp = (float *) Malloc(nvals*sizeof(float));
55768                   memcpy(mdata_sp, pdata_sp, nvals*sizeof(float));
55769                   pdata_sp = mdata_sp;
55770                 }
55771 
55772               for ( size_t i = 0; i < nvals; i++ ) mdata_sp[i] = roundf(mdata_sp[i]);
55773 
55774               if ( dtype == CDI_DATATYPE_UINT8 )
55775                 {
55776                   nc_type xtype;
55777                   cdf_inq_vartype(fileID, ncvarID, &xtype);
55778                   if ( xtype == NC_BYTE )
55779                     {
55780                       for ( size_t i = 0; i < nvals; ++i )
55781                         if ( mdata_sp[i] > 127 ) mdata_sp[i] -= 256;
55782                     }
55783                 }
55784             }
55785           else
55786             {
55787               if ( mdata_dp == NULL )
55788                 {
55789                   mdata_dp = (double *) Malloc(nvals*sizeof(double));
55790                   memcpy(mdata_dp, pdata_dp, nvals*sizeof(double));
55791                   pdata_dp = mdata_dp;
55792                 }
55793 
55794               for ( size_t i = 0; i < nvals; i++ ) mdata_dp[i] = round(mdata_dp[i]);
55795 
55796               if ( dtype == CDI_DATATYPE_UINT8 )
55797                 {
55798                   nc_type xtype;
55799                   cdf_inq_vartype(fileID, ncvarID, &xtype);
55800                   if ( xtype == NC_BYTE )
55801                     {
55802                       for ( size_t i = 0; i < nvals; ++i )
55803                         if ( mdata_dp[i] > 127 ) mdata_dp[i] -= 256;
55804                     }
55805                 }
55806             }
55807         }
55808 
55809       if ( CDF_Debug && memtype != MEMTYPE_FLOAT )
55810         {
55811           double fmin =  1.0e200;
55812           double fmax = -1.0e200;
55813           for ( size_t i = 0; i < nvals; ++i )
55814             {
55815               if ( !DBL_IS_EQUAL(pdata_dp[i], missval) )
55816                 {
55817                   if ( pdata_dp[i] < fmin ) fmin = pdata_dp[i];
55818                   if ( pdata_dp[i] > fmax ) fmax = pdata_dp[i];
55819                 }
55820             }
55821           Message("nvals = %zu, nmiss = %d, missval = %g, minval = %g, maxval = %g",
55822                   nvals, nmiss, missval, fmin, fmax);
55823         }
55824     }
55825 
55826   if ( swapxy ) // implemented only for cdf_write_var_slice()
55827     {
55828       size_t gridsize = xsize*ysize;
55829       if ( memtype == MEMTYPE_FLOAT )
55830         {
55831           sdata_sp = (float *) Malloc(gridsize*sizeof(float));
55832           for ( size_t j = 0; j < ysize; ++j )
55833             for ( size_t i = 0; i < xsize; ++i )
55834               sdata_sp[i*ysize+j] = pdata_sp[j*xsize+i];
55835           pdata_sp = sdata_sp;
55836         }
55837       else
55838         {
55839           sdata_dp = (double *) Malloc(gridsize*sizeof (double));
55840           for ( size_t j = 0; j < ysize; ++j )
55841             for ( size_t i = 0; i < xsize; ++i )
55842               sdata_dp[i*ysize+j] = pdata_dp[j*xsize+i];
55843           pdata_dp = sdata_dp;
55844         }
55845     }
55846 
55847   if (dtype == CDI_DATATYPE_CPX32 || dtype == CDI_DATATYPE_CPX64)
55848     {
55849       void *pdata = (memtype == MEMTYPE_FLOAT) ? (void*)pdata_sp : (void*)pdata_dp;
55850       float *cdata_sp = NULL;
55851       double *cdata_dp = NULL;
55852       if (memtype == MEMTYPE_FLOAT && dtype == CDI_DATATYPE_CPX64)
55853         {
55854           cdata_dp = (double *) Malloc(2*nvals*sizeof(double));
55855           for (size_t i = 0; i < nvals; i++)
55856             {
55857               cdata_dp[2*i] = (double)(pdata_sp[2*i]);
55858               cdata_dp[2*i+1] = (double)(pdata_sp[2*i+1]);
55859             }
55860           pdata = cdata_dp;
55861         }
55862       else if (memtype == MEMTYPE_DOUBLE && dtype == CDI_DATATYPE_CPX32)
55863         {
55864           cdata_sp = (float *) Malloc(2*nvals*sizeof(float));
55865           for (size_t i = 0; i < nvals; i++)
55866             {
55867               cdata_sp[2*i] = (float)(pdata_dp[2*i]);
55868               cdata_sp[2*i+1] = (float)(pdata_dp[2*i+1]);
55869             }
55870           pdata = cdata_sp;
55871         }
55872 
55873       cdf_put_vara(fileID, ncvarID, start, count, pdata);
55874       if (cdata_sp) Free(cdata_sp);
55875       if (cdata_dp) Free(cdata_dp);
55876     }
55877   else
55878     {
55879       if ( memtype == MEMTYPE_FLOAT )
55880         cdf_put_vara_float(fileID, ncvarID, start, count, pdata_sp);
55881       else
55882         cdf_put_vara_double(fileID, ncvarID, start, count, pdata_dp);
55883     }
55884 
55885   if ( mdata_dp ) Free(mdata_dp);
55886   if ( sdata_dp ) Free(sdata_dp);
55887   if ( mdata_sp ) Free(mdata_sp);
55888   if ( sdata_sp ) Free(sdata_sp);
55889 }
55890 
55891 static
cdfGetXYZid(stream_t * streamptr,int gridID,int zaxisID,int * xid,int * yid,int * zid)55892 void cdfGetXYZid(stream_t *streamptr, int gridID, int zaxisID, int *xid, int *yid, int *zid)
55893 {
55894   *xid = CDI_UNDEFID;
55895   *yid = CDI_UNDEFID;
55896 
55897   const int gridtype = gridInqType(gridID);
55898   if (gridtype == GRID_TRAJECTORY)
55899     {
55900       cdfWriteGridTraj(streamptr, gridID);
55901     }
55902   else
55903     {
55904       const int gridindex = nc_grid_index(streamptr, gridID);
55905       *xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
55906       if (gridtype != GRID_GAUSSIAN_REDUCED)
55907         *yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
55908     }
55909 
55910   const int vlistID = streamptr->vlistID;
55911   const int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
55912   *zid = streamptr->zaxisID[zaxisindex];
55913 }
55914 
55915 static
cdfDefineStartAndCount(stream_t * streamptr,int varID,int xid,int yid,int zid,size_t start[5],size_t count[5],size_t * xsize,size_t * ysize)55916 void cdfDefineStartAndCount(stream_t *streamptr, int varID, int xid, int yid, int zid, size_t start[5], size_t count[5], size_t *xsize, size_t *ysize)
55917 {
55918   size_t ndims = 0;
55919   *xsize = 0;
55920   *ysize = 0;
55921 
55922   const int vlistID = streamptr->vlistID;
55923   const int fileID  = streamptr->fileID;
55924 
55925   const long ntsteps = streamptr->ntsteps;
55926   if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
55927 
55928   const int timetype = vlistInqVarTimetype(vlistID, varID);
55929 
55930   if ( vlistHasTime(vlistID) && timetype != TIME_CONSTANT )
55931     {
55932       start[ndims] = (size_t)ntsteps - 1;
55933       count[ndims] = 1;
55934       ndims++;
55935     }
55936 
55937   if ( zid != CDI_UNDEFID )
55938     {
55939       const int zaxisID = vlistInqVarZaxis(vlistID, varID);
55940       start[ndims] = 0;
55941       count[ndims] = (size_t)zaxisInqSize(zaxisID);
55942       ndims++;
55943     }
55944 
55945   if ( yid != CDI_UNDEFID )
55946     {
55947       start[ndims] = 0;
55948       size_t size;
55949       cdf_inq_dimlen(fileID, yid, &size);
55950       /*      count[ndims] = gridInqYsize(gridID); */
55951       count[ndims] = size;
55952       ndims++;
55953     }
55954 
55955   if ( xid != CDI_UNDEFID )
55956     {
55957       start[ndims] = 0;
55958       size_t size;
55959       cdf_inq_dimlen(fileID, xid, &size);
55960       /*      count[ndims] = gridInqXsize(gridID); */
55961       count[ndims] = size;
55962       ndims++;
55963     }
55964 
55965   if ( CDI_Debug )
55966     for (size_t idim = 0; idim < ndims; idim++)
55967       Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
55968 }
55969 
cdf_write_var(stream_t * streamptr,int varID,int memtype,const void * data,size_t nmiss)55970 void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss)
55971 {
55972   if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
55973 
55974   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
55975 
55976   const int vlistID = streamptr->vlistID;
55977   const int fileID  = streamptr->fileID;
55978 
55979   const int ncvarID = cdfDefVar(streamptr, varID);
55980 
55981   const int gridID   = vlistInqVarGrid(vlistID, varID);
55982   const int zaxisID  = vlistInqVarZaxis(vlistID, varID);
55983 
55984   int xid, yid, zid;
55985   cdfGetXYZid(streamptr, gridID, zaxisID, &xid, &yid, &zid);
55986 
55987   size_t xsize, ysize;
55988   size_t start[5], count[5];
55989   cdfDefineStartAndCount(streamptr, varID, xid, yid, zid, start, count, &xsize, &ysize);
55990 
55991   if ( streamptr->ncmode == 1 )
55992     {
55993       cdf_enddef(fileID);
55994       streamptr->ncmode = 2;
55995     }
55996 
55997   const int dtype = vlistInqVarDatatype(vlistID, varID);
55998 
55999   if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
56000 
56001   const size_t nvals = gridInqSize(gridID) * (size_t)(zaxisInqSize(zaxisID));
56002 
56003   bool swapxy = false;
56004   cdf_write_var_data(fileID, vlistID, varID, ncvarID, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
56005 }
56006 
56007 static
cdfDefineStartAndCountChunk(stream_t * streamptr,const int rect[][2],int varID,int xid,int yid,int zid,size_t start[5],size_t count[5],size_t * xsize,size_t * ysize)56008 void cdfDefineStartAndCountChunk(stream_t *streamptr, const int rect[][2], int varID, int xid, int yid, int zid, size_t start[5], size_t count[5], size_t *xsize, size_t *ysize)
56009 {
56010   size_t ndims = 0;
56011   *xsize = 0;
56012   *ysize = 0;
56013 
56014   const int vlistID = streamptr->vlistID;
56015   const int fileID  = streamptr->fileID;
56016 
56017   const long ntsteps = streamptr->ntsteps;
56018   if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
56019 
56020   const int timetype = vlistInqVarTimetype(vlistID, varID);
56021 
56022   if ( vlistHasTime(vlistID) && timetype != TIME_CONSTANT )
56023     {
56024       start[ndims] = (size_t)ntsteps - 1;
56025       count[ndims] = 1;
56026       ndims++;
56027     }
56028 
56029   if ( zid != CDI_UNDEFID )
56030     {
56031       const int zaxisID  = vlistInqVarZaxis(vlistID, varID);
56032       int size = zaxisInqSize(zaxisID);
56033       xassert(rect[2][0] >= 0 && rect[2][0] <= rect[2][1] && rect[2][1] <= size);
56034       start[ndims] = (size_t)rect[2][0];
56035       count[ndims] = (size_t)rect[2][1] - (size_t)rect[2][0] + 1;
56036       ndims++;
56037     }
56038 
56039   if ( yid != CDI_UNDEFID )
56040     {
56041       size_t size;
56042       cdf_inq_dimlen(fileID, yid, &size);
56043       xassert(rect[1][0] >= 0 && rect[1][0] <= rect[1][1] && (size_t)rect[1][1] <= size);
56044       start[ndims] = (size_t)rect[1][0];
56045       count[ndims] = (size_t)rect[1][1] - (size_t)rect[1][0] + 1;
56046       ndims++;
56047     }
56048 
56049   if ( xid != CDI_UNDEFID )
56050     {
56051       size_t size;
56052       cdf_inq_dimlen(fileID, xid, &size);
56053       xassert(rect[0][0] >= 0 && rect[0][0] <= rect[0][1] && (size_t)rect[0][1] <= size);
56054       start[ndims] = (size_t)rect[0][0];
56055       count[ndims] = (size_t)rect[0][1] - (size_t)rect[0][0] + 1;
56056       ndims++;
56057     }
56058 
56059   if ( CDI_Debug )
56060     for (size_t idim = 0; idim < ndims; idim++)
56061       Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
56062 }
56063 
cdf_write_var_chunk(stream_t * streamptr,int varID,int memtype,const int rect[][2],const void * data,size_t nmiss)56064 void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
56065                          const int rect[][2], const void *data, size_t nmiss)
56066 {
56067   if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
56068 
56069   const int streamID = streamptr->self;
56070 
56071   if ( CDI_Debug )
56072     Message("streamID = %d  varID = %d", streamID, varID);
56073 
56074   const int vlistID = streamInqVlist(streamID);
56075   const int fileID  = streamInqFileID(streamID);
56076 
56077   const int ncvarID = cdfDefVar(streamptr, varID);
56078 
56079   const int gridID   = vlistInqVarGrid(vlistID, varID);
56080   const int zaxisID  = vlistInqVarZaxis(vlistID, varID);
56081 
56082   int xid, yid, zid;
56083   cdfGetXYZid(streamptr, gridID, zaxisID, &xid, &yid, &zid);
56084 
56085   size_t xsize, ysize;
56086   size_t start[5], count[5];
56087   cdfDefineStartAndCountChunk(streamptr, rect, varID, xid, yid, zid, start, count, &xsize, &ysize);
56088 
56089   if ( streamptr->ncmode == 1 )
56090     {
56091       cdf_enddef(fileID);
56092       streamptr->ncmode = 2;
56093     }
56094 
56095   const int dtype = vlistInqVarDatatype(vlistID, varID);
56096 
56097   if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
56098 
56099   const size_t nvals = gridInqSize(gridID) * (size_t)(zaxisInqSize(zaxisID));
56100 
56101   bool swapxy = false;
56102   cdf_write_var_data(fileID, vlistID, varID, ncvarID, dtype, nvals,
56103                      xsize, ysize, swapxy, start, count, memtype, data, nmiss);
56104 }
56105 
56106 static
cdfDefineStartAndCountSlice(stream_t * streamptr,int varID,int levelID,int dimorder[3],int xid,int yid,int zid,size_t start[5],size_t count[5],size_t * xsize,size_t * ysize)56107 void cdfDefineStartAndCountSlice(stream_t *streamptr, int varID, int levelID, int dimorder[3], int xid, int yid, int zid, size_t start[5], size_t count[5], size_t *xsize, size_t *ysize)
56108 {
56109   size_t ndims = 0;
56110   *xsize = 0;
56111   *ysize = 0;
56112 
56113   const int vlistID = streamptr->vlistID;
56114   const int fileID  = streamptr->fileID;
56115 
56116   const long ntsteps = streamptr->ntsteps;
56117   if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
56118 
56119   const int timetype = vlistInqVarTimetype(vlistID, varID);
56120 
56121   if ( vlistHasTime(vlistID) && timetype != TIME_CONSTANT )
56122     {
56123       start[ndims] = (size_t)ntsteps - 1;
56124       count[ndims] = 1;
56125       ndims++;
56126     }
56127 
56128   for ( int id = 0; id < 3; ++id )
56129     {
56130       if ( dimorder[id] == 3 && zid != CDI_UNDEFID )
56131         {
56132           start[ndims] = (size_t)levelID;
56133           count[ndims] = 1;
56134           ndims++;
56135         }
56136       else if ( dimorder[id] == 2 && yid != CDI_UNDEFID )
56137         {
56138           start[ndims] = 0;
56139           cdf_inq_dimlen(fileID, yid, ysize);
56140           count[ndims] = *ysize;
56141           ndims++;
56142         }
56143       else if ( dimorder[id] == 1 && xid != CDI_UNDEFID )
56144         {
56145           start[ndims] = 0;
56146           cdf_inq_dimlen(fileID, xid, xsize);
56147           count[ndims] = *xsize;
56148           ndims++;
56149         }
56150     }
56151 
56152   if ( CDI_Debug )
56153     for (size_t idim = 0; idim < ndims; idim++)
56154       Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
56155 }
56156 
56157 
cdf_write_var_slice(stream_t * streamptr,int varID,int levelID,int memtype,const void * data,size_t nmiss)56158 void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss)
56159 {
56160   if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
56161 
56162   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
56163 
56164   const int vlistID = streamptr->vlistID;
56165   const int fileID  = streamptr->fileID;
56166 
56167   const int ncvarID = cdfDefVar(streamptr, varID);
56168 
56169   const int gridID   = vlistInqVarGrid(vlistID, varID);
56170   const int zaxisID  = vlistInqVarZaxis(vlistID, varID);
56171 
56172   int xid, yid, zid;
56173   cdfGetXYZid(streamptr, gridID, zaxisID, &xid, &yid, &zid);
56174 
56175   int dimorder[3];
56176   vlistInqVarDimorder(vlistID, varID, &dimorder);
56177   const bool swapxy = (dimorder[2] == 2 || dimorder[0] == 1) && xid != CDI_UNDEFID && yid != CDI_UNDEFID;
56178 
56179   size_t xsize, ysize;
56180   size_t start[5], count[5];
56181   cdfDefineStartAndCountSlice(streamptr, varID, levelID, dimorder, xid, yid, zid, start, count, &xsize, &ysize);
56182 
56183   const int dtype = vlistInqVarDatatype(vlistID, varID);
56184 
56185   if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
56186 
56187   const size_t nvals = gridInqSize(gridID);
56188 
56189   cdf_write_var_data(fileID, vlistID, varID, ncvarID, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
56190 }
56191 
56192 
cdf_write_record(stream_t * streamptr,int memtype,const void * data,size_t nmiss)56193 void cdf_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss)
56194 {
56195   const int varID   = streamptr->record->varID;
56196   const int levelID = streamptr->record->levelID;
56197   cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
56198 }
56199 
56200 #endif
56201 
56202 /*
56203  * Local Variables:
56204  * c-file-style: "Java"
56205  * c-basic-offset: 2
56206  * indent-tabs-mode: nil
56207  * show-trailing-whitespace: t
56208  * require-trailing-newline: t
56209  * End:
56210  */
56211 #ifdef HAVE_CONFIG_H
56212 #endif
56213 
56214 #ifdef HAVE_LIBNETCDF
56215 
56216 #include <limits.h>
56217 #include <float.h>
56218 
56219 
56220 
56221 static
cdfReadGridTraj(stream_t * streamptr,int gridID)56222 void cdfReadGridTraj(stream_t *streamptr, int gridID)
56223 {
56224   const int vlistID = streamptr->vlistID;
56225   const int fileID  = streamptr->fileID;
56226 
56227   const int gridindex = vlistGridIndex(vlistID, gridID);
56228   const int lonID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
56229   const int latID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
56230 
56231   const int tsID = streamptr->curTsID;
56232   const size_t index = (size_t)tsID;
56233 
56234   double xlon, xlat;
56235   cdf_get_var1_double(fileID, lonID, &index, &xlon);
56236   cdf_get_var1_double(fileID, latID, &index, &xlat);
56237 
56238   gridDefXvals(gridID, &xlon);
56239   gridDefYvals(gridID, &xlat);
56240 }
56241 
56242 static
cdfGetSlapDescription(stream_t * streamptr,int varID,size_t (* start)[4],size_t (* count)[4])56243 void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], size_t (*count)[4])
56244 {
56245   const int vlistID = streamptr->vlistID;
56246   const int tsID = streamptr->curTsID;
56247   const int gridID = vlistInqVarGrid(vlistID, varID);
56248   const int zaxisID = vlistInqVarZaxis(vlistID, varID);
56249   const int timetype = vlistInqVarTimetype(vlistID, varID);
56250   const int gridindex = vlistGridIndex(vlistID, gridID);
56251 
56252   if ( CDI_Debug ) Message("tsID = %d", tsID);
56253 
56254   int xid = CDI_UNDEFID, yid = CDI_UNDEFID;
56255   if ( gridInqType(gridID) == GRID_TRAJECTORY )
56256     {
56257       cdfReadGridTraj(streamptr, gridID);
56258     }
56259   else
56260     {
56261       xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
56262       yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
56263     }
56264   const int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
56265   const int zid = streamptr->zaxisID[zaxisindex];
56266 
56267   int ndims = 0;
56268 #define addDimension(startCoord, length) do \
56269     { \
56270       (*start)[ndims] = startCoord; \
56271       (*count)[ndims] = length; \
56272       ndims++; \
56273     } while(0)
56274   if ( timetype != TIME_CONSTANT ) addDimension((size_t)tsID, 1);
56275   if ( zid != CDI_UNDEFID ) addDimension(0, (size_t)zaxisInqSize(zaxisID));
56276   if ( yid != CDI_UNDEFID ) addDimension(0, gridInqYsize(gridID));
56277   if ( xid != CDI_UNDEFID ) addDimension(0, gridInqXsize(gridID));
56278 #undef addDimension
56279 
56280   assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
56281   assert(ndims <= (int)(sizeof(*count)/sizeof(**count)));
56282 
56283   if ( CDI_Debug )
56284     for (int idim = 0; idim < ndims; idim++)
56285       Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
56286 }
56287 
56288 //Scans the data array for missVals, optionally applying first a scale factor and then an offset.
56289 //Returns the number of missing + out-of-range values encountered.
56290 static
cdfDoInputDataTransformationDP(int vlistID,int varID,size_t valueCount,double * data)56291 size_t cdfDoInputDataTransformationDP(int vlistID, int varID, size_t valueCount, double *data)
56292 {
56293   double missVal = vlistInqVarMissval(vlistID, varID);
56294   const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
56295   double validRange[2];
56296   if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
56297     validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
56298   double validMin = validRange[0];
56299   double validMax = validRange[1];
56300   double offset = vlistInqVarAddoffset(vlistID, varID);
56301   double scaleFactor = vlistInqVarScalefactor(vlistID, varID);
56302 
56303   const bool haveOffset = IS_NOT_EQUAL(offset, 0);
56304   const bool haveScaleFactor = IS_NOT_EQUAL(scaleFactor, 1);
56305   size_t missValCount = 0;
56306 
56307   if ( IS_EQUAL(validMin, VALIDMISS) ) validMin = DBL_MIN;
56308   if ( IS_EQUAL(validMax, VALIDMISS) ) validMax = DBL_MAX;
56309 
56310   bool haveRangeCheck = (IS_NOT_EQUAL(validMax, DBL_MAX)) | (IS_NOT_EQUAL(validMin,DBL_MIN));
56311   assert(!haveRangeCheck || haveMissVal);
56312 
56313   switch ((int)haveMissVal | ((int)haveScaleFactor << 1)
56314           | ((int)haveOffset << 2) | ((int)haveRangeCheck << 3))
56315     {
56316     case 15: /* haveRangeCheck & haveMissVal & haveScaleFactor & haveOffset */
56317       for ( size_t i = 0; i < valueCount; i++ )
56318         {
56319           int outOfRange = data[i] < validMin || data[i] > validMax;
56320           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
56321           missValCount += (size_t)(outOfRange | isMissVal);
56322           data[i] = outOfRange ? missVal
56323             : isMissVal ? data[i] : data[i] * scaleFactor + offset;
56324         }
56325       break;
56326     case 13: /* haveRangeCheck & haveMissVal & haveOffset */
56327       for ( size_t i = 0; i < valueCount; i++ )
56328         {
56329           int outOfRange = data[i] < validMin || data[i] > validMax;
56330           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
56331           missValCount += (size_t)(outOfRange | isMissVal);
56332           data[i] = outOfRange ? missVal
56333             : isMissVal ? data[i] : data[i] + offset;
56334         }
56335       break;
56336     case 11: /* haveRangeCheck & haveMissVal & haveScaleFactor */
56337       for ( size_t i = 0; i < valueCount; i++ )
56338         {
56339           int outOfRange = data[i] < validMin || data[i] > validMax;
56340           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
56341           missValCount += (size_t)(outOfRange | isMissVal);
56342           data[i] = outOfRange ? missVal
56343             : isMissVal ? data[i] : data[i] * scaleFactor;
56344         }
56345       break;
56346     case 9: /* haveRangeCheck & haveMissVal */
56347       for ( size_t i = 0; i < valueCount; i++ )
56348         {
56349           int outOfRange = data[i] < validMin || data[i] > validMax;
56350           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
56351           missValCount += (size_t)(outOfRange | isMissVal);
56352           data[i] = outOfRange ? missVal : data[i];
56353         }
56354       break;
56355     case 7: /* haveMissVal & haveScaleFactor & haveOffset */
56356       for ( size_t i = 0; i < valueCount; i++ )
56357         if ( DBL_IS_EQUAL(data[i], missVal) )
56358           missValCount++;
56359         else
56360           data[i] = data[i] * scaleFactor + offset;
56361       break;
56362     case 6: /* haveOffset & haveScaleFactor */
56363       for ( size_t i = 0; i < valueCount; i++ )
56364         data[i] = data[i] * scaleFactor + offset;
56365       break;
56366     case 5: /* haveMissVal & haveOffset */
56367       for ( size_t i = 0; i < valueCount; i++ )
56368         if ( DBL_IS_EQUAL(data[i], missVal) )
56369           missValCount++;
56370         else
56371           data[i] += offset;
56372       break;
56373     case 4: /* haveOffset */
56374       for ( size_t i = 0; i < valueCount; i++ )
56375         data[i] += offset;
56376       break;
56377     case 3: /* haveMissVal & haveScaleFactor */
56378       for ( size_t i = 0; i < valueCount; i++ )
56379         if ( DBL_IS_EQUAL(data[i], missVal) )
56380           missValCount++;
56381         else
56382           data[i] *= scaleFactor;
56383       break;
56384     case 2: /* haveScaleFactor */
56385       for ( size_t i = 0; i < valueCount; i++ )
56386         data[i] *= scaleFactor;
56387       break;
56388     case 1: /* haveMissVal */
56389       for ( size_t i = 0; i < valueCount; i++ )
56390         missValCount += (unsigned)DBL_IS_EQUAL(data[i], missVal);
56391       break;
56392     }
56393 
56394   return missValCount;
56395 }
56396 
56397 static
cdfDoInputDataTransformationSP(int vlistID,int varID,size_t valueCount,float * data)56398 size_t cdfDoInputDataTransformationSP(int vlistID, int varID, size_t valueCount, float *data)
56399  {
56400   double missVal = vlistInqVarMissval(vlistID, varID);
56401   const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
56402   double validRange[2];
56403   if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange)))
56404     validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
56405   double validMin = validRange[0];
56406   double validMax = validRange[1];
56407   double offset = vlistInqVarAddoffset(vlistID, varID);
56408   double scaleFactor = vlistInqVarScalefactor(vlistID, varID);
56409 
56410   const bool haveOffset = IS_NOT_EQUAL(offset, 0);
56411   const bool haveScaleFactor = IS_NOT_EQUAL(scaleFactor, 1);
56412   size_t missValCount = 0;
56413 
56414   if ( IS_EQUAL(validMin, VALIDMISS) ) validMin = DBL_MIN;
56415   if ( IS_EQUAL(validMax, VALIDMISS) ) validMax = DBL_MAX;
56416 
56417   bool haveRangeCheck = (IS_NOT_EQUAL(validMax, DBL_MAX)) | (IS_NOT_EQUAL(validMin,DBL_MIN));
56418   assert(!haveRangeCheck || haveMissVal);
56419 
56420   switch ((int)haveMissVal | ((int)haveScaleFactor << 1)
56421           | ((int)haveOffset << 2) | ((int)haveRangeCheck << 3))
56422     {
56423     case 15: /* haveRangeCheck & haveMissVal & haveScaleFactor & haveOffset */
56424       for ( size_t i = 0; i < valueCount; i++ )
56425         {
56426           int outOfRange = data[i] < validMin || data[i] > validMax;
56427           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
56428           missValCount += (size_t)(outOfRange | isMissVal);
56429           data[i] = outOfRange ? (float)missVal
56430             : isMissVal ? data[i] : (float)(data[i] * scaleFactor + offset);
56431         }
56432       break;
56433     case 13: /* haveRangeCheck & haveMissVal & haveOffset */
56434       for ( size_t i = 0; i < valueCount; i++ )
56435         {
56436           int outOfRange = data[i] < validMin || data[i] > validMax;
56437           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
56438           missValCount += (size_t)(outOfRange | isMissVal);
56439           data[i] = outOfRange ? (float)missVal
56440             : isMissVal ? data[i] : (float)(data[i] + offset);
56441         }
56442       break;
56443     case 11: /* haveRangeCheck & haveMissVal & haveScaleFactor */
56444       for ( size_t i = 0; i < valueCount; i++ )
56445         {
56446           int outOfRange = data[i] < validMin || data[i] > validMax;
56447           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
56448           missValCount += (size_t)(outOfRange | isMissVal);
56449           data[i] = outOfRange ? (float)missVal
56450             : isMissVal ? data[i] : (float)(data[i] * scaleFactor);
56451         }
56452       break;
56453     case 9: /* haveRangeCheck & haveMissVal */
56454       for ( size_t i = 0; i < valueCount; i++ )
56455         {
56456           int outOfRange = data[i] < validMin || data[i] > validMax;
56457           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
56458           missValCount += (size_t)(outOfRange | isMissVal);
56459           data[i] = outOfRange ? (float)missVal : data[i];
56460         }
56461       break;
56462     case 7: /* haveMissVal & haveScaleFactor & haveOffset */
56463       for ( size_t i = 0; i < valueCount; i++ )
56464         if ( DBL_IS_EQUAL(data[i], missVal) )
56465           missValCount++;
56466         else
56467           data[i] = (float)(data[i] * scaleFactor + offset);
56468       break;
56469     case 6: /* haveOffset & haveScaleFactor */
56470       for ( size_t i = 0; i < valueCount; i++ )
56471         data[i] = (float)(data[i] * scaleFactor + offset);
56472       break;
56473     case 5: /* haveMissVal & haveOffset */
56474       for ( size_t i = 0; i < valueCount; i++ )
56475         if ( DBL_IS_EQUAL(data[i], missVal) )
56476           missValCount++;
56477         else
56478           data[i] = (float)(data[i] + offset);
56479       break;
56480     case 4: /* haveOffset */
56481       for ( size_t i = 0; i < valueCount; i++ )
56482         data[i] = (float)(data[i] + offset);
56483       break;
56484     case 3: /* haveMissVal & haveScaleFactor */
56485       for ( size_t i = 0; i < valueCount; i++ )
56486         if ( DBL_IS_EQUAL(data[i], missVal) )
56487           missValCount++;
56488         else
56489           data[i] = (float)(data[i] * scaleFactor);
56490       break;
56491     case 2: /* haveScaleFactor */
56492       for ( size_t i = 0; i < valueCount; i++ )
56493         data[i] = (float)(data[i] * scaleFactor);
56494       break;
56495     case 1: /* haveMissVal */
56496       for ( size_t i = 0; i < valueCount; i++ )
56497         missValCount += (unsigned)DBL_IS_EQUAL(data[i], missVal);
56498       break;
56499     }
56500 
56501   return missValCount;
56502 }
56503 
56504 static
min_size(size_t a,size_t b)56505 size_t min_size(size_t a, size_t b)
56506 {
56507   return a < b ? a : b;
56508 }
56509 
56510 static
transpose2dArrayDP(int gridId,double * data)56511 void transpose2dArrayDP(int gridId, double *data)
56512 {
56513   size_t inWidth = gridInqYsize(gridId);
56514   size_t inHeight = gridInqXsize(gridId);
56515 
56516   const size_t cacheBlockSize = 256;   // Purely an optimization parameter. Current value of 32 means we are handling 8kB blocks,
56517                                        // which should be a decent compromise on many architectures.
56518   double **out = (double**) malloc(inWidth*sizeof(double*));
56519   double **temp = (double**) malloc(inHeight*sizeof(double*));
56520   temp[0] = (double *) malloc(inHeight*inWidth*sizeof(double));
56521   memcpy(temp[0], data, inHeight*inWidth*sizeof(double));
56522   for (size_t i = 0; i < inWidth; i++) out[i] = data + (inHeight*i);
56523   for (size_t i = 1; i < inHeight; i++) temp[i] = temp[0] + (inWidth*i);
56524 
56525   /*
56526   for ( size_t y = 0; y < inHeight; ++y )
56527     for ( size_t x = 0; x < inWidth; ++x )
56528       out[x][y] = temp[y][x];
56529   */
56530 
56531   for ( size_t yBlock = 0; yBlock < inHeight; yBlock += cacheBlockSize )
56532     for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
56533       for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
56534         for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
56535           {
56536             out[x][y] = temp[y][x];
56537           }
56538 
56539   free(out);
56540   free(temp[0]);
56541   free(temp);
56542 }
56543 
56544 static
transpose2dArraySP(size_t gridId,float * data)56545 void transpose2dArraySP(size_t gridId, float *data)
56546 {
56547   size_t inWidth = gridInqYsize(gridId);
56548   size_t inHeight = gridInqXsize(gridId);
56549 
56550   const size_t cacheBlockSize = 256;   // Purely an optimization parameter. Current value of 32 means we are handling 8kB blocks,
56551                                        // which should be a decent compromise on many architectures.
56552   float **out = (float**) malloc(inWidth*sizeof(float*));
56553   float **temp = (float**) malloc(inHeight*sizeof(float*));
56554   temp[0] = (float *) malloc(inHeight*inWidth*sizeof(float));
56555   memcpy(temp[0], data, inHeight*inWidth*sizeof(float));
56556   for (size_t i = 0; i < inWidth; i++) out[i] = data + (inHeight*i);
56557   for (size_t i = 1; i < inHeight; i++) temp[i] = temp[0] + (inWidth*i);
56558 
56559   /*
56560   for ( size_t y = 0; y < inHeight; ++y )
56561     for ( size_t x = 0; x < inWidth; ++x )
56562       out[x][y] = temp[y][x];
56563   */
56564 
56565   for ( size_t yBlock = 0; yBlock < inHeight; yBlock += cacheBlockSize )
56566     for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
56567       for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
56568         for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
56569           {
56570             out[x][y] = temp[y][x];
56571           }
56572 
56573   free(out);
56574   free(temp[0]);
56575   free(temp);
56576 }
56577 
56578 static
cdfInqDimIds(stream_t * streamptr,int varId,int (* outDimIds)[3])56579 void cdfInqDimIds(stream_t *streamptr, int varId, int (*outDimIds)[3])
56580 {
56581   const int gridId = vlistInqVarGrid(streamptr->vlistID, varId);
56582   const int gridindex = vlistGridIndex(streamptr->vlistID, gridId);
56583 
56584   (*outDimIds)[0] = (*outDimIds)[1] = (*outDimIds)[2] = CDI_UNDEFID;
56585   switch ( gridInqType(gridId) )
56586     {
56587       case GRID_TRAJECTORY:
56588         cdfReadGridTraj(streamptr, gridId);
56589         break;
56590 
56591       case GRID_UNSTRUCTURED:
56592         (*outDimIds)[0] = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
56593         break;
56594 
56595       case GRID_GAUSSIAN_REDUCED:
56596         (*outDimIds)[0] = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
56597         break;
56598 
56599       default:
56600         (*outDimIds)[0] = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
56601         (*outDimIds)[1] = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
56602         break;
56603     }
56604 
56605   const int zaxisID = vlistInqVarZaxis(streamptr->vlistID, varId);
56606   const int zaxisindex = vlistZaxisIndex(streamptr->vlistID, zaxisID);
56607   (*outDimIds)[2] = streamptr->zaxisID[zaxisindex];
56608 }
56609 
56610 static
cdfGetSkipDim(int fileId,int ncvarid,int (* dimIds)[3])56611 int cdfGetSkipDim(int fileId, int ncvarid, int (*dimIds)[3])
56612 {
56613   if((*dimIds)[0] != CDI_UNDEFID) return 0;
56614   if((*dimIds)[1] != CDI_UNDEFID) return 0;
56615 
56616   int nvdims;
56617   cdf_inq_varndims(fileId, ncvarid, &nvdims);
56618   if(nvdims != 3) return 0;
56619 
56620   int varDimIds[3];
56621   cdf_inq_vardimid(fileId, ncvarid, varDimIds);
56622 
56623   size_t size = 0;
56624   if ( (*dimIds)[2] == varDimIds[2] )
56625     {
56626       cdf_inq_dimlen(fileId, varDimIds[1], &size);
56627       if ( size == 1 ) return 1;
56628     }
56629   else if ( (*dimIds)[2] == varDimIds[1] )
56630     {
56631       cdf_inq_dimlen(fileId, varDimIds[2], &size);
56632       if ( size == 1 ) return 2;
56633     }
56634 
56635   return 0;
56636 }
56637 
56638 static
cdfGetSliceSlapDescription(stream_t * streamptr,int varID,int levelID,bool * outSwapXY,size_t (* start)[4],size_t (* count)[4])56639 void cdfGetSliceSlapDescription(stream_t *streamptr, int varID, int levelID, bool *outSwapXY, size_t (*start)[4], size_t (*count)[4])
56640 {
56641   const int tsID = streamptr->curTsID;
56642   if ( CDI_Debug ) Message("tsID = %d", tsID);
56643 
56644   const int fileId = streamptr->fileID;
56645   const int vlistID = streamptr->vlistID;
56646   const int ncvarid = streamptr->vars[varID].ncvarid;
56647 
56648   const int gridId = vlistInqVarGrid(vlistID, varID);
56649   const int timetype = vlistInqVarTimetype(vlistID, varID);
56650   const size_t gridsize = gridInqSize(gridId);
56651 
56652   streamptr->numvals += gridsize;
56653 
56654   int dimIds[3]; // this array joins the old variables xid, yid, and zid
56655   cdfInqDimIds(streamptr, varID, &dimIds);
56656 
56657   const int skipdim = cdfGetSkipDim(fileId, ncvarid, &dimIds);
56658 
56659   int dimorder[3];
56660   vlistInqVarDimorder(vlistID, varID, &dimorder);
56661 
56662   *outSwapXY = (dimorder[2] == 2 || dimorder[0] == 1) && dimIds[0] != CDI_UNDEFID && dimIds[1] != CDI_UNDEFID ;
56663 
56664   int ndims = 0;
56665 
56666 #define addDimension(startIndex, extent) do {   \
56667       (*start)[ndims] = startIndex; \
56668       (*count)[ndims] = extent; \
56669       ndims++; \
56670   } while(0)
56671 
56672   if ( timetype != TIME_CONSTANT ) addDimension((size_t)tsID, 1);
56673   if ( skipdim == 1 ) addDimension(0, 1);
56674 
56675   for ( int id = 0; id < 3; ++id )
56676     {
56677       size_t size;
56678       const int curDimId = dimIds[dimorder[id]-1];
56679       if ( curDimId == CDI_UNDEFID ) continue;
56680       switch ( dimorder[id] )
56681         {
56682           case 1:
56683           case 2:
56684             cdf_inq_dimlen(fileId, curDimId, &size);
56685             addDimension(0, size);
56686             break;
56687           case 3:
56688             addDimension((size_t)levelID, 1);
56689             break;
56690           default:
56691             Error("Internal errror: Malformed dimension order encountered. Please report this bug.\n");
56692         }
56693     }
56694 
56695   if ( skipdim == 2 ) addDimension(0, 1);
56696 
56697   assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
56698   assert(ndims <= (int)(sizeof(*count)/sizeof(**count)));
56699 
56700 #undef addDimension
56701 
56702   if ( CDI_Debug )
56703     for (int idim = 0; idim < ndims; idim++)
56704       Message("dim = %d  start = %d  count = %d", idim, (*start)[idim], (*count)[idim]);
56705 
56706   int nvdims;
56707   cdf_inq_varndims(fileId, ncvarid, &nvdims);
56708 
56709   if ( nvdims != ndims )
56710     {
56711       char name[CDI_MAX_NAME];
56712       vlistInqVarName(vlistID, varID, name);
56713       Error("Internal error, variable %s has an unsupported array structure!", name);
56714     }
56715 }
56716 
56717 static
getSizeVar3D(int vlistID,int varID)56718 size_t getSizeVar3D(int vlistID, int varID)
56719 {
56720   const int gridID  = vlistInqVarGrid(vlistID, varID);
56721   const int zaxisID = vlistInqVarZaxis(vlistID, varID);
56722   return gridInqSize(gridID) * (size_t)zaxisInqSize(zaxisID);
56723 }
56724 
56725 
56726 static
cdfReadDataSliceSP2DP(int fileID,int ncvarid,size_t length,size_t start[4],size_t count[4],double * data)56727 void cdfReadDataSliceSP2DP(int fileID, int ncvarid, size_t length, size_t start[4], size_t count[4], double *data)
56728 {
56729   float *data_fp = (float *) Malloc(length*sizeof(*data_fp));
56730   cdf_get_vara_float(fileID, ncvarid, start, count, data_fp);
56731   for ( size_t i = 0; i < length; i++ ) data[i] = (double) data_fp[i];
56732   Free(data_fp);
56733 }
56734 
56735 static
cdfReadDataSliceDP2SP(int fileID,int ncvarid,size_t length,size_t start[4],size_t count[4],float * data)56736 void cdfReadDataSliceDP2SP(int fileID, int ncvarid, size_t length, size_t start[4], size_t count[4], float *data)
56737 {
56738   double *data_dp = (double *) Malloc(length*sizeof(*data_dp));
56739   cdf_get_vara_double(fileID, ncvarid, start, count, data_dp);
56740   for ( size_t i = 0; i < length; i++ ) data[i] = (float) data_dp[i];
56741   Free(data_dp);
56742 }
56743 
56744 static
cdfCheckDataDP_UINT8(int fileID,int ncvarid,int vlistID,int varID,size_t length,double * data)56745 void cdfCheckDataDP_UINT8(int fileID, int ncvarid, int vlistID, int varID, size_t length, double *data)
56746 {
56747   if ( vlistInqVarDatatype(vlistID, varID) == CDI_DATATYPE_UINT8 )
56748     {
56749       nc_type xtype;
56750       cdf_inq_vartype(fileID, ncvarid, &xtype);
56751       if ( xtype == NC_BYTE )
56752         {
56753           for ( size_t i = 0; i < length; i++ )
56754             if ( data[i] < 0 ) data[i] += 256;
56755         }
56756     }
56757 }
56758 
56759 static
cdfCheckDataSP_UINT8(int fileID,int ncvarid,int vlistID,int varID,size_t length,float * data)56760 void cdfCheckDataSP_UINT8(int fileID, int ncvarid, int vlistID, int varID, size_t length, float *data)
56761 {
56762   if ( vlistInqVarDatatype(vlistID, varID) == CDI_DATATYPE_UINT8 )
56763     {
56764       nc_type xtype;
56765       cdf_inq_vartype(fileID, ncvarid, &xtype);
56766       if ( xtype == NC_BYTE )
56767         {
56768           for ( size_t i = 0; i < length; i++ )
56769             if ( data[i] < 0 ) data[i] += 256;
56770         }
56771     }
56772 }
56773 
56774 static
cdfReadDataDP(stream_t * streamptr,int varID,size_t length,size_t start[4],size_t count[4],double * data)56775 void cdfReadDataDP(stream_t *streamptr, int varID, size_t length, size_t start[4], size_t count[4], double *data)
56776 {
56777   const int vlistID = streamptr->vlistID;
56778   const int fileID = streamptr->fileID;
56779   const int ncvarid = streamptr->vars[varID].ncvarid;
56780   const int datatype = vlistInqVarDatatype(vlistID, varID);
56781 
56782   if (datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64)
56783     {
56784       cdf_get_vara(fileID, ncvarid, start, count, data);
56785       if (datatype == CDI_DATATYPE_CPX32)
56786         {
56787           for (long i = (long)length-1; i >= 0; i--)
56788             {
56789               data[2*i] = (double)(((float*)data)[2*i]);
56790               data[2*i+1] = (double)(((float*)data)[2*i+1]);
56791             }
56792         }
56793     }
56794   else
56795     {
56796       if ( datatype == CDI_DATATYPE_FLT32 )
56797         {
56798           cdfReadDataSliceSP2DP(fileID, ncvarid, length, start, count, data);
56799         }
56800       else
56801         {
56802           cdf_get_vara_double(fileID, ncvarid, start, count, data);
56803 
56804           cdfCheckDataDP_UINT8(fileID, ncvarid, vlistID, varID, length, data);
56805         }
56806     }
56807 }
56808 
56809 static
cdfReadDataSP(stream_t * streamptr,int varID,size_t length,size_t start[4],size_t count[4],float * data)56810 void cdfReadDataSP(stream_t *streamptr, int varID, size_t length, size_t start[4], size_t count[4], float *data)
56811 {
56812   const int vlistID = streamptr->vlistID;
56813   const int fileID = streamptr->fileID;
56814   const int ncvarid = streamptr->vars[varID].ncvarid;
56815   const int datatype = vlistInqVarDatatype(vlistID, varID);
56816 
56817   if (datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64)
56818     {
56819       if (datatype == CDI_DATATYPE_CPX64)
56820         {
56821           double *cdata = (double *) Malloc(2*length*sizeof(double));
56822           cdf_get_vara(fileID, ncvarid, start, count, cdata);
56823           for (size_t i = 0; i < length; i++)
56824             {
56825               data[2*i] = (float)(cdata[2*i]);
56826               data[2*i+1] = (float)(cdata[2*i+1]);
56827             }
56828           Free(cdata);
56829         }
56830       else
56831         {
56832           cdf_get_vara(fileID, ncvarid, start, count, data);
56833         }
56834     }
56835   else
56836     {
56837       if ( datatype == CDI_DATATYPE_FLT64 )
56838         {
56839           cdfReadDataSliceDP2SP(fileID, ncvarid, length, start, count, data);
56840         }
56841       else
56842         {
56843           cdf_get_vara_float(fileID, ncvarid, start, count, data);
56844 
56845           cdfCheckDataSP_UINT8(fileID, ncvarid, vlistID, varID, length, data);
56846         }
56847     }
56848 }
56849 
56850 static
cdfReadVarDP(stream_t * streamptr,int varID,double * data,size_t * nmiss)56851 void cdfReadVarDP(stream_t *streamptr, int varID, double *data, size_t *nmiss)
56852 {
56853   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
56854 
56855   const int vlistID = streamptr->vlistID;
56856 
56857   size_t start[4], count[4];
56858   cdfGetSlapDescription(streamptr, varID, &start, &count);
56859 
56860   const size_t length = getSizeVar3D(vlistID, varID);
56861   cdfReadDataDP(streamptr, varID, length, start, count, data);
56862 
56863   *nmiss = cdfDoInputDataTransformationDP(vlistID, varID, length, data);
56864 }
56865 
56866 static
cdfReadVarSP(stream_t * streamptr,int varID,float * data,size_t * nmiss)56867 void cdfReadVarSP(stream_t *streamptr, int varID, float *data, size_t *nmiss)
56868 {
56869   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
56870 
56871   const int vlistID = streamptr->vlistID;
56872 
56873   size_t start[4], count[4];
56874   cdfGetSlapDescription(streamptr, varID, &start, &count);
56875 
56876   const size_t length = getSizeVar3D(vlistID, varID);
56877   cdfReadDataSP(streamptr, varID, length, start, count, data);
56878 
56879   *nmiss = cdfDoInputDataTransformationSP(vlistID, varID, length, data);
56880 }
56881 
56882 
cdf_read_var(stream_t * streamptr,int varID,int memtype,void * data,size_t * nmiss)56883 void cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, size_t *nmiss)
56884 {
56885   if ( memtype == MEMTYPE_DOUBLE )
56886     cdfReadVarDP(streamptr, varID, (double*) data, nmiss);
56887   else
56888     cdfReadVarSP(streamptr, varID, (float*) data, nmiss);
56889 }
56890 
56891 static
cdfReadVarSliceDP(stream_t * streamptr,int varID,int levelID,double * data,size_t * nmiss)56892 void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data, size_t *nmiss)
56893 {
56894   if ( CDI_Debug )
56895     Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
56896 
56897   bool swapxy;
56898   size_t start[4], count[4];
56899   cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
56900 
56901   const int vlistID = streamptr->vlistID;
56902   const int gridId = vlistInqVarGrid(vlistID, varID);
56903   const size_t length = gridInqSize(gridId);
56904   cdfReadDataDP(streamptr, varID, length, start, count, data);
56905 
56906   if ( swapxy ) transpose2dArrayDP(gridId, data);
56907 
56908   *nmiss = cdfDoInputDataTransformationDP(vlistID, varID, length, data);
56909 }
56910 
56911 static
cdfReadVarSliceSP(stream_t * streamptr,int varID,int levelID,float * data,size_t * nmiss)56912 void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data, size_t *nmiss)
56913 {
56914   if ( CDI_Debug )
56915     Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
56916 
56917   bool swapxy;
56918   size_t start[4], count[4];
56919   cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
56920 
56921   const int vlistID = streamptr->vlistID;
56922   const int gridId = vlistInqVarGrid(vlistID, varID);
56923   const size_t length = gridInqSize(gridId);
56924   cdfReadDataSP(streamptr, varID, length, start, count, data);
56925 
56926   if ( swapxy ) transpose2dArraySP(gridId, data);
56927 
56928   *nmiss = cdfDoInputDataTransformationSP(vlistID, varID, length, data);
56929 }
56930 
56931 
cdf_read_var_slice(stream_t * streamptr,int varID,int levelID,int memtype,void * data,size_t * nmiss)56932 void cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, size_t *nmiss)
56933 {
56934   if ( memtype == MEMTYPE_DOUBLE )
56935     cdfReadVarSliceDP(streamptr, varID, levelID, (double*) data, nmiss);
56936   else
56937     cdfReadVarSliceSP(streamptr, varID, levelID, (float*) data, nmiss);
56938 }
56939 
56940 
cdf_read_record(stream_t * streamptr,int memtype,void * data,size_t * nmiss)56941 void cdf_read_record(stream_t *streamptr, int memtype, void *data, size_t *nmiss)
56942 {
56943   if ( CDI_Debug ) Message("streamID = %d", streamptr->self);
56944 
56945   const int tsID    = streamptr->curTsID;
56946   const int vrecID  = streamptr->tsteps[tsID].curRecID;
56947   const int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
56948   const int varID   = streamptr->tsteps[tsID].records[recID].varID;
56949   const int levelID = streamptr->tsteps[tsID].records[recID].levelID;
56950 
56951   if ( memtype == MEMTYPE_DOUBLE )
56952     cdfReadVarSliceDP(streamptr, varID, levelID, (double*) data, nmiss);
56953   else
56954     cdfReadVarSliceSP(streamptr, varID, levelID, (float*) data, nmiss);
56955 }
56956 
56957 //----------------------------------------------------------------------------
56958 // Parallel Version
56959 //----------------------------------------------------------------------------
56960 
cdfReadVarSliceDPPart(stream_t * streamptr,int varID,int levelID,int varType,int startpoint,size_t length,double * data,size_t * nmiss)56961 void cdfReadVarSliceDPPart(stream_t *streamptr, int varID, int levelID, int varType, int startpoint, size_t length, double *data, size_t *nmiss)
56962 {
56963   (void)(varType);
56964 
56965   if ( CDI_Debug )
56966     Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
56967 
56968   const int vlistID = streamptr->vlistID;
56969 
56970   bool swapxy;
56971   size_t start[4], count[4];
56972   cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
56973 
56974   const int gridId = vlistInqVarGrid(vlistID, varID);
56975   const size_t gridsize = gridInqSize(gridId);
56976 
56977   unsigned int position = 0;
56978   for (int i=0 ; i<4 ; i++)
56979     if (count[i] == gridsize)
56980       position = i;
56981 
56982   start[position] = start[position]+startpoint;
56983   count[position] = length;
56984 
56985   cdfReadDataDP(streamptr, varID, length, start, count, data);
56986 
56987   if ( swapxy ) transpose2dArrayDP(gridId, data);
56988 
56989   *nmiss = cdfDoInputDataTransformationDP(vlistID, varID, length, data);
56990 }
56991 
cdfReadVarSliceSPPart(stream_t * streamptr,int varID,int levelID,int varType,int startpoint,size_t length,float * data,size_t * nmiss)56992 void cdfReadVarSliceSPPart(stream_t *streamptr, int varID, int levelID, int varType, int startpoint, size_t length, float *data, size_t *nmiss)
56993 {
56994   (void)(varType);
56995 
56996   if ( CDI_Debug )
56997     Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
56998 
56999   const int vlistID = streamptr->vlistID;
57000 
57001   bool swapxy;
57002   size_t start[4], count[4];
57003   cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
57004 
57005   const int gridId = vlistInqVarGrid(vlistID, varID);
57006   size_t gridsize = gridInqSize(gridId);
57007 
57008   unsigned int position = 0;
57009   for (int i=0 ; i<4 ; i++)
57010     if (count[i] == gridsize)
57011       position = i;
57012 
57013   start[position] = start[position]+startpoint;
57014   count[position] = length;
57015 
57016   cdfReadDataSP(streamptr, varID, length, start, count, data);
57017 
57018   if ( swapxy ) transpose2dArraySP(gridId, data);
57019 
57020   *nmiss = cdfDoInputDataTransformationSP(vlistID, varID, length, data);
57021 }
57022 
57023 static
cdiStreamReadVarSlicePart(int streamID,int varID,int levelID,int varType,int start,size_t size,int memtype,void * data,size_t * nmiss)57024 int cdiStreamReadVarSlicePart(int streamID, int varID, int levelID, int varType, int start, size_t size, int memtype, void *data, size_t *nmiss)
57025 {
57026   int status = 0;
57027 
57028   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
57029 
57030   check_parg(data);
57031   check_parg(nmiss);
57032 
57033   stream_t *streamptr = stream_to_pointer(streamID);
57034   const int filetype = streamptr->filetype;
57035 
57036   *nmiss = 0;
57037 
57038   // currently we only care for netcdf data
57039   switch (filetype)
57040     {
57041 #if defined (HAVE_LIBNETCDF)
57042     case CDI_FILETYPE_NC:
57043     case CDI_FILETYPE_NC2:
57044     case CDI_FILETYPE_NC4:
57045     case CDI_FILETYPE_NC4C:
57046     case CDI_FILETYPE_NC5:
57047       {
57048         if ( memtype == MEMTYPE_FLOAT )
57049           cdfReadVarSliceSPPart(streamptr, varID, levelID, varType, start, size, (float *)data, nmiss);
57050         else
57051           cdfReadVarSliceDPPart(streamptr, varID, levelID, varType, start, size, (double *)data, nmiss);
57052         break;
57053       }
57054 #endif
57055     default:
57056       {
57057         Error("%s support not compiled in!", strfiletype(filetype));
57058         status = 2;
57059         break;
57060       }
57061     }
57062 
57063   return status;
57064 }
57065 
57066 
cdfReadVarDPPart(stream_t * streamptr,int varID,int varType,int startpoint,size_t length,double * data,size_t * nmiss)57067 void cdfReadVarDPPart(stream_t *streamptr, int varID, int varType, int startpoint, size_t length, double *data, size_t *nmiss)
57068 {
57069   (void)(varType);
57070   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
57071 
57072   const int vlistID = streamptr->vlistID;
57073   const int ncvarid = streamptr->vars[varID].ncvarid;
57074 
57075   size_t start[4], count[4];
57076   cdfGetSlapDescription(streamptr, varID, &start, &count);
57077 
57078   const int ltime = TIME_CONSTANT != vlistInqVarTimetype(vlistID, varID);
57079   start[1+ltime] = start[1+ltime]+startpoint;
57080   count[1+ltime] = length;
57081 
57082   cdf_get_vara_double(streamptr->fileID, ncvarid, start, count, data);
57083 
57084   *nmiss = cdfDoInputDataTransformationDP(vlistID, varID, length, data);
57085 }
57086 
cdfReadVarSPPart(stream_t * streamptr,int varID,int varType,int startpoint,size_t length,float * data,size_t * nmiss)57087 void cdfReadVarSPPart(stream_t *streamptr, int varID, int varType, int startpoint, size_t length, float *data, size_t *nmiss)
57088 {
57089   (void)(varType);
57090   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
57091 
57092   const int vlistID = streamptr->vlistID;
57093   const int ncvarid = streamptr->vars[varID].ncvarid;
57094 
57095   size_t start[4], count[4];
57096   cdfGetSlapDescription(streamptr, varID, &start, &count);
57097 
57098   const int ltime = TIME_CONSTANT != vlistInqVarTimetype(vlistID, varID);
57099   start[1+ltime] = start[1+ltime]+startpoint;
57100   count[1+ltime] = length;
57101 
57102   cdf_get_vara_float(streamptr->fileID, ncvarid, start, count, data);
57103 
57104   *nmiss = cdfDoInputDataTransformationSP(vlistID, varID, length, data);
57105 }
57106 
57107 static
cdiStreamReadVarPart(int streamID,int varID,int varType,int start,size_t size,int memtype,void * data,size_t * nmiss)57108 void cdiStreamReadVarPart(int streamID, int varID, int varType, int start, size_t size, int memtype, void *data, size_t *nmiss)
57109 {
57110   (void)(varType);
57111   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
57112 
57113   check_parg(data);
57114   check_parg(nmiss);
57115 
57116   stream_t *streamptr = stream_to_pointer(streamID);
57117   const int filetype = streamptr->filetype;
57118 
57119   *nmiss = 0;
57120 
57121   // currently we only care for netcdf data
57122   switch (filetype)
57123     {
57124 #if defined (HAVE_LIBNETCDF)
57125     case CDI_FILETYPE_NC:
57126     case CDI_FILETYPE_NC2:
57127     case CDI_FILETYPE_NC4:
57128     case CDI_FILETYPE_NC4C:
57129     case CDI_FILETYPE_NC5:
57130       {
57131         if ( memtype == MEMTYPE_FLOAT )
57132           cdfReadVarSPPart(streamptr, varID, varType, start, size, (float *)data, nmiss);
57133         else
57134           cdfReadVarDPPart(streamptr, varID, varType, start, size, (double *)data, nmiss);
57135 
57136         break;
57137       }
57138 #endif
57139     default:
57140       {
57141         Error("%s support not compiled in!", strfiletype(filetype));
57142         break;
57143       }
57144     }
57145 }
57146 
streamReadVarSlicePart(int streamID,int varID,int levelID,int varType,int start,size_t size,void * data,size_t * nmiss,int memtype)57147 void streamReadVarSlicePart(int streamID, int varID, int levelID, int varType, int start, size_t size, void *data, size_t *nmiss, int memtype)
57148 {
57149   if ( cdiStreamReadVarSlicePart(streamID, varID, levelID, varType, start, size, memtype, data, nmiss) )
57150     {
57151       Error("Unexpected error returned from cdiStreamReadVarSlicePart()!");
57152     }
57153 }
57154 
streamReadVarPart(int streamID,int varID,int varType,int start,size_t size,void * data,size_t * nmiss,int memtype)57155 void streamReadVarPart(int streamID, int varID, int varType, int start, size_t size, void *data, size_t *nmiss, int memtype)
57156 {
57157   cdiStreamReadVarPart(streamID, varID, varType, start, size, memtype, data, nmiss);
57158 }
57159 
57160 #endif
57161 
57162 /* Subroutines and data structures for storing "subtypes".             */
57163 /*                                                                     */
57164 /* A subtype is, for example, a list of TILES. This can be interpreted */
57165 /* as an additional axis like the vertical axis.                       */
57166 /*                                                                     */
57167 /* @author 02/2015 F. Prill, DWD                                       */
57168 /*                                                                     */
57169 /*  DATA LAYOUT:                                                       */
57170 /*                                                                     */
57171 /*  A subtype contains several "subtype entries", each of which        */
57172 /*  contains a linked list of subtype attributes.                      */
57173 /*                                                                     */
57174 /*  The number of subtype entries is not specified in advance, but the */
57175 /*  list of entries is itself dynamically growing. There is no         */
57176 /*  guaranteed ordering of the entries, therefore each entry must be   */
57177 /*  identifiable by its attributes.                                    */
57178 /*                                                                     */
57179 /*  [subtype_t]                                                        */
57180 /*      |                                                              */
57181 /*      |------- globals                  [subtype_entry_t]            */
57182 /*      |          |--- atts              [subtype_attr_t]             */
57183 /*      |                                                              */
57184 /*      |------- entries                                               */
57185 /*                 |- entry #0                                         */
57186 /*                 |  |--- atts              [subtype_attr_t]          */
57187 /*                 |- entry #1                                         */
57188 /*                 |  |--- atts              [subtype_attr_t]          */
57189 /*                 |- entry #2                                         */
57190 /*                 .  |--- atts              [subtype_attr_t]          */
57191 /*                 .                                                   */
57192 
57193 
57194 /* Literal constants corresponding to the different subtypes of the
57195    enumeration "subtype_kind". */
57196 static const char* subtypeName[] = {
57197   "tileset"
57198 };
57199 
57200 const char * const cdiSubtypeAttributeName[] = {
57201   "tileIndex",
57202   "totalNumberOfTileAttributePairs",
57203   "tileClassification",
57204   "numberOfTiles",
57205   "numberOfTileAttributes",
57206   "tileAttribute"
57207 };
57208 
57209 
57210 /* prototypes: */
57211 static int    subtypeCompareP    (subtype_t *z1, subtype_t *z2);
57212 static void   subtypeDestroyP    ( void * subtype_ptr );
57213 static void   subtypePrintP      ( void * subtype_ptr, FILE * fp );
57214 static int    subtypeGetPackSize ( void * subtype_ptr, void *context);
57215 static void   subtypePack        ( void * subtype_ptr, void * buffer, int size, int *pos, void *context);
57216 static int    subtypeTxCode      ( void );
57217 
57218 static const resOps subtypeOps = {
57219   (int (*) (void *, void *)) subtypeCompareP,
57220   (void (*)(void *))         subtypeDestroyP,
57221   (void (*)(void *, FILE *)) subtypePrintP,
57222   (int (*) (void *, void *)) subtypeGetPackSize,
57223                              subtypePack,
57224                              subtypeTxCode
57225 };
57226 
57227 enum {
57228   differ = 1,
57229 };
57230 
57231 
57232 
57233 /* ------------------------------------------------------------------- */
57234 /* SUBROUTINES FOR ATTRIBUTE LISTS                                     */
57235 /* ------------------------------------------------------------------- */
57236 
57237 
attribute_to_index(const char * key)57238 static int attribute_to_index(const char *key)
57239 {
57240   if (key == NULL)  Error("Internal error!");
57241   for (int i=0; i<nSubtypeAttributes; i++)
57242     if ( strcmp(key, cdiSubtypeAttributeName[i]) == 0 ) return i;
57243   return -1;
57244 }
57245 
57246 
57247 
57248 /*
57249   @Function  subtypeAttrNewList
57250   @Title     Create new linked list of subtype attributes.
57251   @EndFunction
57252 */
subtypeAttrNewList(struct subtype_entry_t * head,int key,int val)57253 static struct subtype_attr_t* subtypeAttrNewList(struct subtype_entry_t* head, int key, int val)
57254 {
57255   if (head == NULL)  Error("Internal error!");
57256   struct subtype_attr_t *ptr = (struct subtype_attr_t*) Malloc(sizeof(struct subtype_attr_t));
57257   if(NULL == ptr)  Error("Node creation failed");
57258   ptr->key   = key;
57259   ptr->val   = val;
57260   ptr->next  = NULL;
57261 
57262   head->atts = ptr;
57263   return ptr;
57264 }
57265 
57266 
57267 /*
57268   @Function  subtypeAttrInsert
57269 
57270   @Title Add subtype attribute to linked list, s.t. the result is a
57271          smallest-to-largest ordered list.
57272   @EndFunction
57273 */
subtypeAttrInsert(struct subtype_entry_t * head,int key,int val)57274 static struct subtype_attr_t* subtypeAttrInsert(struct subtype_entry_t* head, int key, int val)
57275 {
57276   if (head == NULL)  Error("Internal error!");
57277   if (head->atts == NULL)  return (subtypeAttrNewList(head, key, val));
57278 
57279   /* create new attribute */
57280   struct subtype_attr_t* ptr = (struct subtype_attr_t*) Malloc(sizeof(struct subtype_attr_t));
57281   if(NULL == ptr)    Error("Node creation failed");
57282 
57283   ptr->key   = key;
57284   ptr->val   = val;
57285   ptr->next  = NULL;
57286 
57287   /* find the right place for insertion: */
57288   if (head->atts->key >= key) {
57289     /* insert at position 0 */
57290     ptr->next = head->atts;
57291     head->atts = ptr;
57292   } else {
57293     struct subtype_attr_t** predec = &head->atts;
57294     while (((*predec)->next != NULL) && ((*predec)->next->key < key)) {
57295       predec = &((*predec)->next);
57296     }
57297     ptr->next = (*predec)->next;
57298     (*predec)->next = ptr;
57299   }
57300   return ptr;
57301 }
57302 
57303 
57304 /* Recursively free a linked list with attributes. */
subtypeAttrDestroy(struct subtype_attr_t * head)57305 static void subtypeAttrDestroy(struct subtype_attr_t* head)
57306 {
57307   if (head == NULL) return;
57308   subtypeAttrDestroy(head->next);
57309   Free(head);
57310   head = NULL;
57311 }
57312 
57313 
57314 /* Find an attribute in linked list by its key or return NULL
57315    otherwise. */
subtypeAttrFind(struct subtype_attr_t * head,int key)57316 static struct subtype_attr_t* subtypeAttrFind(struct subtype_attr_t* head, int key)
57317 {
57318   if (head == NULL)
57319     return NULL;
57320   else if (head->key == key)
57321     return head;
57322   else
57323     return subtypeAttrFind(head->next, key);
57324 }
57325 
57326 
57327 /* Recursively compares two subtype attribute lists under the implicit
57328    assumptions that both lists are ordered by their keys and that keys
57329    are unique. */
subtypeAttsCompare(struct subtype_attr_t * a1,struct subtype_attr_t * a2)57330 static int subtypeAttsCompare(struct subtype_attr_t *a1, struct subtype_attr_t *a2)
57331 {
57332   if ((a1 == NULL) && (a2 == NULL))
57333     return 0;
57334   else if ((a1 == NULL) && (a2 != NULL))
57335     {
57336       return differ;
57337     }
57338   else if ((a1 != NULL) && (a2 == NULL))
57339     {
57340       return differ;
57341     }
57342 
57343   if (a1->key != a2->key)
57344     {
57345       return differ;
57346     }
57347   if (a1->val != a2->val)
57348     return differ;
57349 
57350   return subtypeAttsCompare(a1->next, a2->next);
57351 }
57352 
57353 
57354 /* (Recursively) duplicate linked list of attributes. */
subtypeAttsDuplicate(struct subtype_attr_t * a1,struct subtype_entry_t * dst)57355 static void subtypeAttsDuplicate(struct subtype_attr_t *a1, struct subtype_entry_t* dst)
57356 {
57357   if (a1 == NULL)  return;
57358   /* duplicate "a1->key", "a1->val" */
57359   subtypeAttsDuplicate(a1->next, dst);
57360   (void) subtypeAttrInsert(dst, a1->key, a1->val);
57361 }
57362 
57363 
57364 
57365 /* ------------------------------------------------------------------- */
57366 /* SUBROUTINES FOR LIST OF ENTRIES                                     */
57367 /* ------------------------------------------------------------------- */
57368 
57369 
57370 /*
57371   @Function  subtypeEntryNewList
57372   @Title     Create new linked list of subtype entries.
57373   @EndFunction
57374 */
subtypeEntryNewList(subtype_t * head)57375 static struct subtype_entry_t* subtypeEntryNewList(subtype_t* head)
57376 {
57377   struct subtype_entry_t *ptr = (struct subtype_entry_t*) Malloc(sizeof(struct subtype_entry_t));
57378   if(NULL == ptr)  Error("Node creation failed");
57379   ptr->atts      = NULL;
57380   ptr->next      = NULL;
57381   head->entries  = ptr;
57382   head->nentries = 0;
57383   ptr->self      = head->nentries++;
57384   return ptr;
57385 }
57386 
57387 
57388 /*
57389   @Function  subtypeEntryInsert
57390 
57391   @Title Add subtype entry to the head of a linked list.
57392   @EndFunction
57393 */
subtypeEntryInsert(subtype_t * head)57394 struct subtype_entry_t* subtypeEntryInsert(subtype_t* head)
57395 {
57396   if (head == NULL)  Error("Internal error!");
57397   if (head->entries == NULL)  return (subtypeEntryNewList(head));
57398 
57399   /* create new entry */
57400   struct subtype_entry_t* ptr = (struct subtype_entry_t*) Malloc(sizeof(struct subtype_entry_t));
57401   if(NULL == ptr)    Error("Node creation failed");
57402 
57403   ptr->atts     = NULL;
57404   ptr->self     = head->nentries++;
57405 
57406   /* find the right place for insertion: */
57407   if (head->entries->self >= ptr->self) {
57408     /* insert at position 0 */
57409     ptr->next     = head->entries;
57410     head->entries = ptr;
57411   } else {
57412     struct subtype_entry_t** predec = &head->entries;
57413     while (((*predec)->next != NULL) && ((*predec)->next->self < ptr->self)) {
57414       predec = &((*predec)->next);
57415     }
57416     ptr->next = (*predec)->next;
57417     (*predec)->next = ptr;
57418   }
57419   return ptr;
57420 }
57421 
57422 
57423 /*
57424   @Function  subtypeEntryAppend
57425 
57426   @Title Append subtype entry to the end of a linked list.
57427   @EndFunction
57428 */
subtypeEntryAppend(subtype_t * head)57429 static struct subtype_entry_t* subtypeEntryAppend(subtype_t* head)
57430 {
57431   if (head == NULL)  Error("Internal error!");
57432   if (head->entries == NULL)  return (subtypeEntryNewList(head));
57433 
57434   /* create new entry */
57435   struct subtype_entry_t* ptr = (struct subtype_entry_t*) Malloc(sizeof(struct subtype_entry_t));
57436   if(NULL == ptr)    Error("Node creation failed");
57437 
57438   ptr->atts     = NULL;
57439   ptr->next     = NULL;
57440   ptr->self     = head->nentries++;
57441 
57442   /* find last position of linked list */
57443   struct subtype_entry_t* prec_ptr = head->entries;
57444   while (prec_ptr->next != NULL)
57445     prec_ptr = prec_ptr->next;
57446 
57447   prec_ptr->next  = ptr;
57448   return ptr;
57449 }
57450 
57451 
57452 /* Recursively free a list of subtype entries. */
subtypeEntryDestroy(struct subtype_entry_t * entry)57453 static void subtypeEntryDestroy(struct subtype_entry_t *entry)
57454 {
57455   if (entry == NULL) return;
57456   subtypeEntryDestroy(entry->next);
57457   subtypeAttrDestroy(entry->atts);
57458   Free(entry);
57459   entry = NULL;
57460 }
57461 
57462 
57463 /* Compares two subtype entries. */
subtypeEntryCompare(struct subtype_entry_t * e1,struct subtype_entry_t * e2)57464 static int subtypeEntryCompare(struct subtype_entry_t *e1, struct subtype_entry_t *e2)
57465 {
57466   if (e1 == NULL)  Error("Internal error!");
57467   if (e2 == NULL)  Error("Internal error!");
57468   return
57469     (e1->self == e2->self) &&
57470     subtypeAttsCompare(e1->atts, e2->atts);
57471 }
57472 
57473 
57474 /* (Recursively) duplicate list of entries. */
subtypeEntryDuplicate(struct subtype_entry_t * a1,subtype_t * dst)57475 static void subtypeEntryDuplicate(struct subtype_entry_t *a1, subtype_t* dst)
57476 {
57477   if (a1 == NULL) return;
57478   /* append entry to dst pointer */
57479   struct subtype_entry_t *ptr = subtypeEntryAppend(dst);
57480   /* duplicate attributes */
57481   subtypeAttsDuplicate(a1->atts, ptr);
57482   ptr->self = a1->self;
57483   /* call next link in linked list */
57484   subtypeEntryDuplicate(a1->next, dst);
57485 }
57486 
57487 
57488 
57489 /* ------------------------------------------------------------------- */
57490 /* SUBROUTINES FOR THE SUBTYPE ITSELF                                  */
57491 /* ------------------------------------------------------------------- */
57492 
57493 /* Print-out subtype data structure together with its attributes. */
subtypePrintKernel(subtype_t * subtype_ptr,FILE * fp)57494 static void subtypePrintKernel(subtype_t *subtype_ptr, FILE *fp)
57495 {
57496   if (subtype_ptr == NULL)  Error("Internal error!");
57497   fprintf(fp, "# %s (subtype ID %d)\n", subtypeName[subtype_ptr->subtype], subtype_ptr->self);
57498   /* print global attributes of this subtype */
57499   struct subtype_attr_t* ptr = subtype_ptr->globals.atts;
57500   if (ptr != NULL)  fprintf(fp, "#\n# global attributes:\n");
57501   while (ptr != NULL) {
57502     fprintf(fp, "#   %-40s   (%2d) : %d\n", cdiSubtypeAttributeName[ptr->key], ptr->key, ptr->val);
57503     ptr = ptr->next;
57504   }
57505   /* print attributes for each subtype */
57506   fprintf(fp, "# %d local entries:\n", subtype_ptr->nentries);
57507   struct subtype_entry_t *entry = subtype_ptr->entries;
57508   while (entry != NULL) {
57509     fprintf(fp, "# subtype entry %d\n", entry->self);
57510     ptr = entry->atts;
57511     if (ptr != NULL)  fprintf(fp, "#   attributes:\n");
57512     while (ptr != NULL) {
57513       fprintf(fp, "#     %-40s (%2d) : %d\n", cdiSubtypeAttributeName[ptr->key], ptr->key, ptr->val);
57514       ptr = ptr->next;
57515     }
57516     entry = entry->next;
57517   }
57518   fprintf(fp, "\n");
57519 }
57520 
57521 
57522 /* Compares two subtype data structures. Pointer version of this
57523    method. */
subtypeCompareP(subtype_t * s1,subtype_t * s2)57524 static int subtypeCompareP(subtype_t *s1, subtype_t *s2)
57525 {
57526   xassert(s1 && s2);
57527   if (s1->subtype != s2->subtype) return differ;
57528   if (subtypeEntryCompare(&s1->globals, &s2->globals) != 0) return differ;
57529 
57530   struct subtype_entry_t *entry1 = s1->entries;
57531   struct subtype_entry_t *entry2 = s2->entries;
57532   while ((entry1 != NULL) && (entry2 != NULL)) {
57533     if (subtypeEntryCompare(entry1, entry2) != 0)  return differ;
57534     entry1 = entry1->next;
57535     entry2 = entry2->next;
57536   }
57537   /* compare list lengths: */
57538   if ((entry1 != NULL) || (entry2 != NULL))  return differ;
57539   return 0;
57540 }
57541 
57542 
57543 /* Clean up data structure. */
subtypeDestroyP(void * ptr)57544 static void subtypeDestroyP(void *ptr)
57545 {
57546   subtype_t *subtype_ptr = (subtype_t*) ptr;
57547   /* destroy global attributes */
57548   subtypeAttrDestroy(subtype_ptr->globals.atts);
57549   /* destroy list of subtype entries */
57550   subtypeEntryDestroy(subtype_ptr->entries);
57551   subtype_ptr->entries = NULL;
57552   Free(subtype_ptr);
57553   subtype_ptr = NULL;
57554 }
57555 
57556 
57557 /* Non-static wrapper function for "subtypeDestroyP". */
subtypeDestroyPtr(void * ptr)57558 void subtypeDestroyPtr(void *ptr)
57559 {
57560   subtypeDestroyP(ptr);
57561 }
57562 
57563 
57564 /* Non-static wrapper function for "subtypeCompareP". */
subtypeComparePtr(int s1_ID,subtype_t * s2)57565 int subtypeComparePtr(int s1_ID, subtype_t *s2)
57566 {
57567   subtype_t *subtype_ptr = (subtype_t *)reshGetVal(s1_ID, &subtypeOps);
57568   if (subtype_ptr == NULL)  Error("Internal error");
57569   return subtypeCompareP(subtype_ptr,s2);
57570 }
57571 
57572 
57573 /* Print-out subtype data structure together with its attributes.
57574    Pointer version of this method. */
subtypePrintP(void * subtype_ptr,FILE * fp)57575 static void subtypePrintP(void * subtype_ptr, FILE * fp)
57576 {  subtypePrintKernel((subtype_t *)subtype_ptr, fp); }
57577 
57578 
57579 
57580 /* Print-out subtype data structure together with its attributes. */
subtypePrintPtr(subtype_t * subtype_ptr)57581 void subtypePrintPtr(subtype_t* subtype_ptr)
57582 {
57583   subtypePrintKernel(subtype_ptr, stdout);
57584 }
57585 
57586 
57587 /* Fill subtype data structure with default values. */
subtypeDefaultValue(subtype_t * subtype_ptr)57588 static void subtypeDefaultValue(subtype_t *subtype_ptr)
57589 {
57590   if (subtype_ptr == NULL)  Error("Internal error!");
57591   subtype_ptr->self                 = CDI_UNDEFID;
57592   subtype_ptr->nentries             = 0;
57593   subtype_ptr->entries              = NULL;
57594   subtype_ptr->globals.atts         = NULL;
57595   subtype_ptr->globals.next         = NULL;
57596   subtype_ptr->globals.self         = -1;
57597   subtype_ptr->active_subtype_index = 0;
57598 }
57599 
57600 
subtypeAllocate(subtype_t ** subtype_ptr2,int subtype)57601 void subtypeAllocate(subtype_t **subtype_ptr2, int subtype)
57602 {
57603   /* allocate new subtype */
57604   (*subtype_ptr2) = (subtype_t *) Malloc(sizeof(subtype_t));
57605   subtype_t* subtype_ptr = *subtype_ptr2;
57606   subtypeDefaultValue(subtype_ptr);
57607   subtype_ptr->subtype = subtype;
57608   subtype_ptr->self    = CDI_UNDEFID;
57609 }
57610 
57611 
57612 /* Create a copy of an existing subtype data structure. */
subtypeDuplicate(subtype_t * subtype_ptr,subtype_t ** dst_ptr)57613 void subtypeDuplicate(subtype_t *subtype_ptr, subtype_t **dst_ptr)
57614 {
57615   if (subtype_ptr == NULL)  Error("Internal error!");
57616   subtypeAllocate(dst_ptr, subtype_ptr->subtype);
57617   subtype_t *dst = (*dst_ptr);
57618   /* create duplicate of subtype globals */
57619   subtypeAttsDuplicate(subtype_ptr->globals.atts, &dst->globals);
57620   dst->globals.self = subtype_ptr->globals.self;
57621   /* create duplicate of subtype entries */
57622   subtypeEntryDuplicate( subtype_ptr->entries, dst);
57623 }
57624 
57625 
57626 /* Register subtype object at resource handler. */
subtypePush(subtype_t * subtype_ptr)57627 int subtypePush(subtype_t *subtype_ptr)
57628 {
57629   if (subtype_ptr == NULL)  Error("Internal error!");
57630   subtype_ptr->self = reshPut(subtype_ptr, &subtypeOps);
57631   return subtype_ptr->self; /* subtypeID */
57632 }
57633 
57634 
57635 
57636 /* Sets an attribute for a subtype (for example a set of TILES). If
57637    the attribute has already been defined, then its value is
57638    overwritten. */
subtypeDefGlobalDataP(subtype_t * subtype_ptr,int key,int val)57639 void subtypeDefGlobalDataP(subtype_t *subtype_ptr, int key, int val)
57640 {
57641   if (subtype_ptr == NULL)  Error("Internal error!");
57642   /* find entry in linked list or append otherwise */
57643   struct subtype_attr_t* att_ptr = subtypeAttrFind(subtype_ptr->globals.atts, key);
57644   if (att_ptr == NULL)
57645     subtypeAttrInsert(&subtype_ptr->globals, key, val);
57646   else
57647     att_ptr->val = val;
57648 }
57649 
57650 
57651 /* Sets an attribute for a subtype (for example a set of TILES). If
57652    the attribute has already been defined, then its value is
57653    overwritten. */
subtypeDefGlobalData(int subtypeID,int key,int val)57654 void subtypeDefGlobalData(int subtypeID, int key, int val)
57655 {
57656   subtype_t *subtype_ptr = (subtype_t *)reshGetVal(subtypeID, &subtypeOps);
57657   subtypeDefGlobalDataP(subtype_ptr, key, val);
57658 }
57659 
57660 
57661 /* Retrieves an attribute for a subtype (for example a set of TILES).
57662    If the attribute has not been defined, then return -1. */
subtypeGetGlobalDataP(subtype_t * subtype_ptr,int key)57663 int subtypeGetGlobalDataP(subtype_t *subtype_ptr, int key)
57664 {
57665   if (subtype_ptr == NULL)  Error("Internal error!");
57666   /* find entry in linked list */
57667   struct subtype_attr_t* att_ptr = subtypeAttrFind(subtype_ptr->globals.atts, key);
57668   if (att_ptr == NULL)
57669     return -1;
57670   else
57671     return att_ptr->val;
57672 }
57673 
57674 
57675 /* Retrieves an attribute for a subtype (for example a set of TILES) .
57676    If the attribute has not been defined, then return -1. */
subtypeGetGlobalData(int subtypeID,int key)57677 int subtypeGetGlobalData(int subtypeID, int key)
57678 {
57679   subtype_t *subtype_ptr = (subtype_t *)reshGetVal(subtypeID, &subtypeOps);
57680   return subtypeGetGlobalDataP(subtype_ptr, key);
57681 }
57682 
57683 
57684 /* Sets an attribute for a single subtype entry (e.g. a single TILE).
57685    If the attribute has already been defined, then its value is
57686    overwritten. */
subtypeDefEntryDataP(struct subtype_entry_t * subtype_entry_ptr,int key,int val)57687 void subtypeDefEntryDataP(struct subtype_entry_t *subtype_entry_ptr, int key, int val)
57688 {
57689   if (subtype_entry_ptr == NULL)  Error("Internal error!");
57690   /* find entry in linked list or append otherwise */
57691   struct subtype_attr_t* att_ptr = subtypeAttrFind(subtype_entry_ptr->atts, key);
57692   if (att_ptr == NULL)
57693     subtypeAttrInsert(subtype_entry_ptr, key, val);
57694   else
57695     att_ptr->val = val;
57696 }
57697 
57698 
57699 
57700 /* ------------------------------------------------------------------- */
57701 /* IMPLEMENTATIONS FOR KEY-VALUE-PAIR QUERIES                          */
57702 /* ------------------------------------------------------------------- */
57703 
57704 
57705 /* Generate a "query object" out of a key-value pair. */
keyValuePair(const char * key,int value)57706 subtype_query_t keyValuePair(const char* key, int value)
57707 {
57708   subtype_query_t result;
57709   result.nAND = 1;
57710   result.key_value_pairs[0][0] = attribute_to_index(key);
57711   result.key_value_pairs[1][0] = value;
57712   if (CDI_Debug) {
57713     Message("key  %s matches %d", key, result.key_value_pairs[0][0]);
57714     Message("%d --?-- %d", result.key_value_pairs[0][0], result.key_value_pairs[1][0]);
57715   }
57716   return result;
57717 }
57718 
57719 
57720 /* Generate an AND-combined "query object" out of two previous query
57721    objects. */
matchAND(subtype_query_t q1,subtype_query_t q2)57722 subtype_query_t matchAND(subtype_query_t q1, subtype_query_t q2)
57723 {
57724   if ((q1.nAND + q2.nAND) > MAX_KV_PAIRS_MATCH)  Error("Internal error");
57725   subtype_query_t result;
57726   memset(&result, 0, sizeof(subtype_query_t));
57727   result.nAND = q1.nAND;
57728   for (int i=0; i<q1.nAND; i++)
57729     {
57730       result.key_value_pairs[0][i] = q1.key_value_pairs[0][i];
57731       result.key_value_pairs[1][i] = q1.key_value_pairs[1][i];
57732     }
57733   for (int i=0; i<q2.nAND; i++)
57734     {
57735       result.key_value_pairs[0][result.nAND] = q2.key_value_pairs[0][i];
57736       result.key_value_pairs[1][result.nAND] = q2.key_value_pairs[1][i];
57737       result.nAND++;
57738     }
57739 
57740   if (CDI_Debug) {
57741     Message("combined criterion:");
57742     for (int i=0; i<result.nAND; i++)
57743       Message("%d --?-- %d", result.key_value_pairs[0][i], result.key_value_pairs[1][i]);
57744   }
57745   return result;
57746 }
57747 
57748 
57749 
57750 /* ------------------------------------------------------------------- */
57751 /* SPECIFIC IMPLEMENTATIONS FOR TILE SETS                              */
57752 /* ------------------------------------------------------------------- */
57753 
57754 
57755 /* Integrate tile set "s2" into the tile set "subtype1_ID":
57756 
57757    Insert all entries set 2 to set 1 together with its attributes.
57758 */
tilesetInsertP(subtype_t * s1,subtype_t * s2)57759 void tilesetInsertP(subtype_t *s1, subtype_t *s2)
57760 {
57761   if (s1 == NULL)  Error("Internal error!");
57762   if (s2 == NULL)  Error("Internal error!");
57763   struct subtype_entry_t
57764     *entry1 = s1->entries,
57765     *entry2 = s2->entries;
57766   struct subtype_attr_t *att_ptr2;
57767 
57768   /* test all entries of set 2 against set 1, to check if entry
57769      already exists: */
57770   if (subtypeAttsCompare(s1->globals.atts, s2->globals.atts) != differ)
57771     {
57772       while (entry1 != NULL) {
57773         int found = 1;
57774         entry2 = s2->entries;
57775         while (entry2 != NULL) {
57776           found &= (subtypeAttsCompare(entry1->atts, entry2->atts) != differ);
57777           entry2 = entry2->next;
57778         }
57779         if (found)
57780           {
57781             return;
57782           }
57783         entry1 = entry1->next;
57784       }
57785 
57786       entry2 = s2->entries;
57787       while (entry2 != NULL) {
57788         entry1 = subtypeEntryInsert(s1);
57789 
57790         att_ptr2 = entry2->atts;
57791         while (att_ptr2 != NULL) {
57792           (void) subtypeAttrInsert(entry1, att_ptr2->key, att_ptr2->val);
57793           att_ptr2 = att_ptr2->next;
57794         }
57795         entry2 = entry2->next;
57796       }
57797     }
57798   else
57799     {
57800       fprintf(stderr, "\n# SUBTYPE A:\n");
57801       subtypePrintKernel(s1, stderr);
57802       fprintf(stderr, "\n# SUBTYPE B:\n");
57803       subtypePrintKernel(s2, stderr);
57804       Error("Attempting to insert subtype entry into subtype with different global attributes!");
57805     }
57806 }
57807 
57808 
57809 
57810 /* ------------------------------------------------------------------- */
57811 /* IMPLEMENTATIONS FOR ROUTINES VISIBLE THROUGH CDI.H                  */
57812 /* ------------------------------------------------------------------- */
57813 
57814 
57815 /*
57816   @Function  subtypeCreate
57817   @Title     Create a variable subtype
57818 
57819   @Prototype int subtypeCreate(int subtype)
57820   @Parameter
57821   @Item  subtype  The type of the variable subtype, one of the set of predefined CDI variable subtypes.
57822   The valid CDI variable subtypes are @func{SUBTYPE_TILES}
57823 
57824   @Description
57825   The function @func{subtypeCreate} creates a variable subtype.
57826 
57827   @Result
57828   @func{subtypeCreate} returns an identifier to the variable subtype.
57829 
57830   @EndFunction
57831 */
subtypeCreate(int subtype)57832 int subtypeCreate(int subtype)
57833 {
57834   if ( CDI_Debug )  Message("subtype: %d ", subtype);
57835   Message("subtype: %d ", subtype);
57836 
57837   /* allocate new subtype */
57838   subtype_t *subtype_ptr;
57839   subtypeAllocate(&subtype_ptr, subtype);
57840   /* register object at resource handler */
57841   return subtypePush(subtype_ptr);
57842 }
57843 
57844 
57845 /* Print-out subtype data structure together with its attributes. */
subtypePrint(int subtypeID)57846 void subtypePrint(int subtypeID)
57847 {
57848   subtype_t *subtype_ptr = (subtype_t *)reshGetVal(subtypeID, &subtypeOps);
57849   subtypePrintKernel(subtype_ptr, stdout);
57850 }
57851 
57852 
57853 /* Compares two subtype data structures. */
subtypeCompare(int subtypeID1,int subtypeID2)57854 int subtypeCompare(int subtypeID1, int subtypeID2)
57855 {
57856   subtype_t *subtype_ptr1 = (subtype_t *)reshGetVal(subtypeID1, &subtypeOps);
57857   subtype_t *subtype_ptr2 = (subtype_t *)reshGetVal(subtypeID2, &subtypeOps);
57858   return subtypeCompareP(subtype_ptr1,subtype_ptr2);
57859 }
57860 
57861 
57862 /*  Get the size of a subtype (e.g. no. of tiles). */
subtypeInqSize(int subtypeID)57863 int subtypeInqSize(int subtypeID)
57864 {
57865   if ( subtypeID == CDI_UNDEFID )
57866     {
57867       return 0;
57868     }
57869   else
57870     {
57871       subtype_t *subtype_ptr = (subtype_t *)reshGetVal(subtypeID, &subtypeOps);
57872       return subtype_ptr->nentries;
57873     }
57874 }
57875 
57876 
57877 /* Get the currently active index of a subtype (e.g. current tile index). */
subtypeInqActiveIndex(int subtypeID)57878 int subtypeInqActiveIndex(int subtypeID)
57879 {
57880   if (subtypeID == CDI_UNDEFID)  return 0;
57881   subtype_t *subtype_ptr = (subtype_t *)reshGetVal(subtypeID, &subtypeOps);
57882   return subtype_ptr->active_subtype_index;
57883 }
57884 
57885 
57886 /* Set the currently active index of a subtype (e.g. current tile index). */
subtypeDefActiveIndex(int subtypeID,int index)57887 void subtypeDefActiveIndex(int subtypeID, int index)
57888 {
57889   subtype_t *subtype_ptr = (subtype_t *)reshGetVal(subtypeID, &subtypeOps);
57890   subtype_ptr->active_subtype_index = index;
57891 }
57892 
57893 
57894 /* subtypeInqSubEntry: Returns subtype entry ID for a given
57895    criterion. */
subtypeInqSubEntry(int subtypeID,subtype_query_t criterion)57896 int subtypeInqSubEntry(int subtypeID, subtype_query_t criterion)
57897 {
57898   subtype_t *subtype_ptr = (subtype_t *)reshGetVal(subtypeID, &subtypeOps);
57899   struct subtype_entry_t *entry = subtype_ptr->entries;
57900   /* loop over all entries of this subtype */
57901   while (entry != NULL) {
57902     {
57903       int match = 1;
57904       /* test if this entry matches ALL criteria. */
57905       for (int j=0; (j<criterion.nAND) && (match); j++)
57906         {
57907           if (CDI_Debug)  Message("check criterion %d :  %d --?-- %d", j,
57908                                   criterion.key_value_pairs[0][j], criterion.key_value_pairs[1][j]);
57909           struct subtype_attr_t* att_ptr =
57910             subtypeAttrFind(entry->atts, criterion.key_value_pairs[0][j]);
57911           if (att_ptr == NULL)
57912             {
57913               match = 0;
57914               if (CDI_Debug)  Message("did not find %d", criterion.key_value_pairs[0][j]);
57915             }
57916           else
57917             {
57918               if (CDI_Debug)  Message("found %d", criterion.key_value_pairs[0][j]);
57919               match &= (att_ptr->val == criterion.key_value_pairs[1][j]);
57920             }
57921         }
57922       if (match) return entry->self;
57923     }
57924     entry = entry->next;
57925   }
57926   return CDI_UNDEFID;
57927 }
57928 
57929 
subtypeInqTile(int subtypeID,int tileindex,int attribute)57930 int subtypeInqTile(int subtypeID, int tileindex, int attribute)
57931 {
57932   return subtypeInqSubEntry(subtypeID,
57933                             matchAND(keyValuePair(cdiSubtypeAttributeName[SUBTYPE_ATT_TILEINDEX], tileindex),
57934                                      keyValuePair(cdiSubtypeAttributeName[SUBTYPE_ATT_TILEATTRIBUTE], attribute)));
57935 }
57936 
subtypeInqAttribute(int subtypeID,int index,const char * key,int * outValue)57937 int subtypeInqAttribute(int subtypeID, int index, const char* key, int* outValue)
57938 {
57939   //Validate input params.
57940   if(subtypeID == CDI_UNDEFID) xabort("CDI_UNDEFID was passed to %s() as a subtypeID. Please check the origin of that ID.", __func__);
57941   subtype_t *subtype_ptr = (subtype_t *)reshGetVal(subtypeID, &subtypeOps);
57942   if(!subtype_ptr) xabort("Internal error: subtypeID %d resolved to NULL.", subtypeID);
57943 
57944   if((unsigned)index >= (unsigned)subtype_ptr->nentries)
57945     {
57946       xabort("index argument of %s() is out of range. Expected 0 <= index < %d, but got index = %d.", __func__, subtype_ptr->nentries, index);
57947     }
57948 
57949 #ifndef __cplusplus
57950   if(!outValue) outValue = &(int){0};
57951 #else
57952   int dummy = 0;
57953   if(!outValue) outValue = &dummy;
57954 #endif
57955 
57956   if(!key) return CDI_EINVAL;
57957   int iKey = attribute_to_index(key);
57958   if(iKey < 0) return CDI_EINVAL;
57959 
57960   //Find the entry.
57961   struct subtype_entry_t* entry = subtype_ptr->entries;
57962   for(; index--; entry = entry->next) if(!entry) xabort("internal error: preliminary end of subtype entry list");
57963 
57964   //Find the attribute.
57965   for(struct subtype_attr_t* attribute = entry->atts; attribute; attribute = attribute->next)
57966     {
57967       if(attribute->key == iKey)
57968         {
57969           *outValue = attribute->val;
57970           return CDI_NOERR;
57971         }
57972     }
57973 
57974   //Failed to find the attribute if this point is reached.
57975   return CDI_EINVAL;
57976 }
57977 
57978 /* Construct a new subtype for a tile set. If a corresponding subtype
57979  * already exists, then we return this subtype ID instead.
57980  *
57981  * See comment on subtype.c::tilesetMatchingPtr for the specification
57982  * of the term "corresponding" tile set.
57983  */
vlistDefTileSubtype(int vlistID,subtype_t * tiles)57984 int vlistDefTileSubtype(int vlistID, subtype_t *tiles)
57985 {
57986   int subtypeID = CDI_UNDEFID;
57987 
57988   /* loop over subtypes and search for an identical tileset */
57989   vlist_t *vlistptr = vlist_to_pointer(vlistID);
57990   int      tileset_defined = 0;
57991   for (int isub=0; isub<vlistptr->nsubtypes; isub++)
57992     {
57993       /* get the ID of the "isub"th subtype */
57994       subtypeID = vlistptr->subtypeIDs[isub];
57995       if (subtypeComparePtr(subtypeID, tiles) == 0)
57996         {
57997           tileset_defined = 1;
57998           break;
57999         }
58000     }
58001 
58002   /* tile set seems to be new: register at resource handler. */
58003   if (tileset_defined == 0)  {
58004     subtype_t *tiles_duplicate = NULL;
58005     subtypeDuplicate(tiles, &tiles_duplicate);
58006     subtypeID = vlistptr->subtypeIDs[vlistptr->nsubtypes++] = subtypePush(tiles_duplicate);
58007   }
58008 
58009   return subtypeID;
58010 }
58011 
58012 
58013 
vlistInsertTrivialTileSubtype(int vlistID)58014 int vlistInsertTrivialTileSubtype(int vlistID)
58015 {
58016   /* first, generate a subtype */
58017   subtype_t *subtype_ptr;
58018   subtypeAllocate(&subtype_ptr, SUBTYPE_TILES);
58019 
58020   /* create a tile set that contains only one tile/attribute pair. */
58021   (void) subtypeEntryInsert(subtype_ptr);
58022 
58023   /* register tile */
58024   vlist_t *vlistptr = vlist_to_pointer(vlistID);
58025   int subtypeID = vlistptr->subtypeIDs[vlistptr->nsubtypes++] = subtypePush(subtype_ptr);
58026   return subtypeID;
58027 }
58028 
58029 
58030 
58031 
58032 /* ------------------------------------------------------------------- */
58033 /* NOT YET IMPLEMENTED                                                 */
58034 /* ------------------------------------------------------------------- */
58035 
subtypeGetPackSize(void * subtype_ptr,void * context)58036 static int subtypeGetPackSize( void * subtype_ptr, void *context)
58037 {
58038   (void)subtype_ptr; (void)context;
58039   Error("Not yet implemented for subtypes!");
58040   return 0;
58041 }
58042 
subtypePack(void * subtype_ptr,void * buffer,int size,int * pos,void * context)58043 static void subtypePack( void * subtype_ptr, void * buffer, int size, int *pos, void *context)
58044 {
58045   (void)subtype_ptr; (void)buffer; (void)size; (void)pos; (void)context;
58046   Error("Not yet implemented for subtypes!");
58047 }
58048 
subtypeTxCode(void)58049 static int subtypeTxCode( void )
58050 {  Error("Not yet implemented for subtypes!");  return 0; }
58051 
58052 
58053 /*
58054  * Local Variables:
58055  * c-file-style: "Java"
58056  * c-basic-offset: 2
58057  * indent-tabs-mode: nil
58058  * show-trailing-whitespace: t
58059  * require-trailing-newline: t
58060  * End:
58061  */
58062 #include <inttypes.h>
58063 #include <stdio.h>
58064 
58065 
swap4byte(void * ptr,size_t size)58066 void swap4byte(void *ptr, size_t size)
58067 {
58068   int32_t *ptrtmp = (int32_t *)ptr;
58069 
58070   for (size_t i = 0; i < size; ++i)
58071     ptrtmp[i] = (((ptrtmp[i] >> 24) & 0x00ff) | ((ptrtmp[i] & 0x00ff) << 24) |
58072                  ((ptrtmp[i] >>  8) & 0xff00) | ((ptrtmp[i] & 0xff00) <<  8));
58073 }
58074 
swap8byte(void * ptr,size_t size)58075 void swap8byte(void *ptr, size_t size)
58076 {
58077   int64_t *ptrtmp = (int64_t *)ptr;
58078 
58079   for (size_t i = 0; i < size; ++i)
58080     ptrtmp[i] = (((ptrtmp[i] >> 56) & 0x000000ff) | ((ptrtmp[i] & 0x000000ff) << 56) |
58081                  ((ptrtmp[i] >> 40) & 0x0000ff00) | ((ptrtmp[i] & 0x0000ff00) << 40) |
58082                  ((ptrtmp[i] >> 24) & 0x00ff0000) | ((ptrtmp[i] & 0x00ff0000) << 24) |
58083                  ((ptrtmp[i] >>  8) & 0xff000000) | ((ptrtmp[i] & 0xff000000) <<  8));
58084 }
58085 /*
58086  * Local Variables:
58087  * c-file-style: "Java"
58088  * c-basic-offset: 2
58089  * indent-tabs-mode: nil
58090  * show-trailing-whitespace: t
58091  * require-trailing-newline: t
58092  * End:
58093  */
58094 #ifndef TABLEPAR_H
58095 #define TABLEPAR_H
58096 
58097 enum {
58098   TABLE_DUP_NAME = 1 << 0,
58099   TABLE_DUP_LONGNAME = 1 << 1,
58100   TABLE_DUP_UNITS = 1 << 2,
58101 };
58102 
58103 typedef struct
58104 {
58105   int id;	        // Parameter number (GRIB)
58106   int ltype;	        // Level type (GRIB)
58107   int dupflags;         // keep track of which attributes got strdup'ed
58108   const char *name;	// Parameter name
58109   const char *longname; // Parameter long name
58110   const char *units;	// Parameter units
58111 }
58112 param_type;
58113 
58114 
58115 void tableLink(int tableID, const param_type *pars, int npars);
58116 int tableDef(int modelID, int tablegribID, const char *tablename);
58117 
58118 int tableInqParCode(int tableID, char *name, int *code);
58119 
58120 #endif
58121 /*
58122  * Local Variables:
58123  * c-file-style: "Java"
58124  * c-basic-offset: 2
58125  * indent-tabs-mode: nil
58126  * show-trailing-whitespace: t
58127  * require-trailing-newline: t
58128  * End:
58129  */
58130 /* Automatically generated, do not edit! */
58131 #ifndef TABLE_H
58132 #define TABLE_H
58133 
58134 static const param_type echam4[] = {
58135   {   4, -1, 0, "precip",      "total precipitation",                      "m/s"      },
58136   {  34, -1, 0, "low_cld",     "low cloud",                                 NULL      },
58137   {  35, -1, 0, "mid_cld",     "mid cloud",                                 NULL      },
58138   {  36, -1, 0, "hih_cld",     "high cloud",                                NULL      },
58139   { 129, -1, 0, "geosp",       "surface geopotential (orography)",         "m^2/s^2"  },
58140   { 130, -1, 0, "t",           "temperature",                              "K"        },
58141   { 131, -1, 0, "u",           "u-velocity",                               "m/s"      },
58142   { 132, -1, 0, "v",           "v-velocity",                               "m/s"      },
58143   { 133, -1, 0, "sq",          "specific humidity",                        "kg/kg"    },
58144   { 134, -1, 0, "aps",         "Surface pressure",                         "Pa"       },
58145   { 135, -1, 0, "omega",       "vertical velocity",                        "Pa/s"     },
58146   { 138, -1, 0, "svo",         "vorticity",                                "1/s"      },
58147   { 139, -1, 0, "ts",          "surface temperature",                      "K"        },
58148   { 140, -1, 0, "ws",          "soil wetness",                             "m"        },
58149   { 141, -1, 0, "sn",          "snow depth",                               "m"        },
58150   { 142, -1, 0, "aprl",        "large scale precipitation",                "m/s"      },
58151   { 143, -1, 0, "aprc",        "convective  precipitation",                "m/s"      },
58152   { 144, -1, 0, "aprs",        "snow fall",                                "m/s"      },
58153   { 145, -1, 0, "vdis",        "boundary layer dissipation",               "W/m^2"    },
58154   { 146, -1, 0, "ahfs",        "surface sensible heat flux",               "W/m^2"    },
58155   { 147, -1, 0, "ahfl",        "surface latent heat flux",                 "W/m^2"    },
58156   { 148, -1, 0, "stream",      "streamfunction",                           "m^2/s"    },
58157   { 149, -1, 0, "velopot",     "velocity potential",                       "m^2/s"    },
58158   { 151, -1, 0, "slp",         "mean sea level pressure",                  "Pa"       },
58159   { 152, -1, 0, "lsp",         "log surface pressure",                      NULL      },
58160   { 153, -1, 0, "sx",          "liquid water content",                     "kg/kg"    },
58161   { 155, -1, 0, "sd",          "divergence",                               "1/s"      },
58162   { 156, -1, 0, "geopoth",     "geopotential height",                      "m"        },
58163   { 157, -1, 0, "rhumidity",   "relative humidity",                        "fraction" },
58164   { 158, -1, 0, "var158",      "tendency of surface pressure",             "Pa/s"     },
58165   { 159, -1, 0, "ustar3",      "ustar3",                                   "m^3/s^3"  },
58166   { 160, -1, 0, "runoff",      "surface runoff",                           "m/s"      },
58167   { 161, -1, 0, "alwc",        "liquid water content",                     "kg/kg"    },
58168   { 162, -1, 0, "aclc",        "cloud cover",                              "fraction" },
58169   { 163, -1, 0, "aclcv",       "total cloud cover",                        "fraction" },
58170   { 164, -1, 0, "aclcov",      "total cloud cover",                        "fraction" },
58171   { 165, -1, 0, "u10",         "10m u-velocity",                           "m/s"      },
58172   { 166, -1, 0, "v10",         "10m v-velocity",                           "m/s"      },
58173   { 167, -1, 0, "temp2",       "2m temperature",                           "K"        },
58174   { 168, -1, 0, "dew2",        "2m dew point temperature",                 "K"        },
58175   { 169, -1, 0, "tsurf",       "surface temperature",                      "K"        },
58176   { 170, -1, 0, "td",          "deep soil temperature",                    "K"        },
58177   { 171, -1, 0, "wind10",      "10m windspeed",                            "m/s"      },
58178   { 172, -1, 0, "slm",         "land sea mask",                            "fraction" },
58179   { 173, -1, 0, "az0",         "surface roughness length",                 "m"        },
58180   { 174, -1, 0, "alb",         "surface background albedo",                "fraction" },
58181   { 175, -1, 0, "albedo",      "surface albedo",                           "fraction" },
58182   { 176, -1, 0, "srads",       "net surface solar radiation",              "W/m^2"    },
58183   { 177, -1, 0, "trads",       "net surface thermal radiation",            "W/m^2"    },
58184   { 178, -1, 0, "srad0",       "net top solar radiation",                  "W/m^2"    },
58185   { 179, -1, 0, "trad0",       "top thermal radiation (OLR)",              "W/m^2"    },
58186   { 180, -1, 0, "ustr",        "surface u-stress",                         "Pa"       },
58187   { 181, -1, 0, "vstr",        "surface v-stress",                         "Pa"       },
58188   { 182, -1, 0, "evap",        "surface evaporation",                      "m/s"      },
58189   { 183, -1, 0, "tdcl",        "soil temperature",                         "K"        },
58190   { 185, -1, 0, "srafs",       "net surf. solar radiation   (clear sky)",  "W/m^2"    },
58191   { 186, -1, 0, "trafs",       "net surf. thermal radiation (clear sky)",  "W/m^2"    },
58192   { 187, -1, 0, "sraf0",       "net top solar radiation     (clear sky)",  "W/m^2"    },
58193   { 188, -1, 0, "traf0",       "net top thermal radiation   (clear sky)",  "W/m^2"    },
58194   { 189, -1, 0, "sclfs",       "surface solar cloud forcing",              "W/m^2"    },
58195   { 190, -1, 0, "tclfs",       "surface thermal cloud forcing",            "W/m^2"    },
58196   { 191, -1, 0, "sclf0",       "top solar cloud forcing",                  "W/m^2"    },
58197   { 192, -1, 0, "tclf0",       "top thermal cloud forcing",                "W/m^2"    },
58198   { 193, -1, 0, "wl",          "skin reservoir content",                   "m"        },
58199   { 194, -1, 0, "wlm1",        "skin reservoir content of plants",         "m"        },
58200   { 195, -1, 0, "ustrgw",      "u-gravity wave stress",                    "Pa"       },
58201   { 196, -1, 0, "vstrgw",      "v-gravity wave stress",                    "Pa"       },
58202   { 197, -1, 0, "vdisgw",      "gravity wave dissipation",                 "W/m^2"    },
58203   { 198, -1, 0, "vgrat",       "vegetation ratio",                         "fraction" },
58204   { 199, -1, 0, "varor",       "orographic variance",                      "m^2"      },
58205   { 200, -1, 0, "vlt",         "leaf area index",                           NULL      },
58206   { 201, -1, 0, "t2max",       "maximum 2m-temperature",                   "K"        },
58207   { 202, -1, 0, "t2min",       "minimum 2m-temperature",                   "K"        },
58208   { 203, -1, 0, "srad0u",      "top solar radiation upward",               "W/m^2"    },
58209   { 204, -1, 0, "sradsu",      "surface solar radiation upward",           "W/m^2"    },
58210   { 205, -1, 0, "tradsu",      "surface thermal radiation upward",         "W/m^2"    },
58211   { 206, -1, 0, "tsn",         "snow temperature",                         "K"        },
58212   { 207, -1, 0, "td3",         "soil temperature 3",                       "K"        },
58213   { 208, -1, 0, "td4",         "soil temperature 4",                       "K"        },
58214   { 209, -1, 0, "td5",         "soil temperature 5",                       "K"        },
58215   { 210, -1, 0, "seaice",      "sea ice cover",                            "fraction" },
58216   { 211, -1, 0, "siced",       "sea ice depth",                            "m"        },
58217   { 212, -1, 0, "forest",      "vegetation type",                          "fraction" },
58218   { 213, -1, 0, "teff",        "(effective) sea-ice skin temperature",     "K"        },
58219   { 214, -1, 0, "tsmax",       "maximum surface temperature",              "K"        },
58220   { 215, -1, 0, "tsmin",       "minimum surface temperature",              "K"        },
58221   { 216, -1, 0, "wimax",       "maximum 10m-wind speed",                   "m/s"      },
58222   { 217, -1, 0, "topmax",      "maximum height of convective cloud tops",  "Pa"       },
58223   { 218, -1, 0, "snmel",       "snow melt",                                "m/s"      },
58224   { 219, -1, 0, "runtoc",      "surface runoff into ocean",                 NULL      },
58225   { 220, -1, 0, "tslin",       "land: residual surface heat budget",       "W/m^2"    },
58226   { 221, -1, 0, "dsnac",       "snow depth change",                        "m/s"      },
58227   { 222, -1, 0, "alwcac",      "liquid water content",                     "kg/kg"    },
58228   { 223, -1, 0, "aclcac",      "cloud cover",                              "fraction" },
58229   { 224, -1, 0, "tke",         "turbulent kinetic energy",                  NULL      },
58230   { 225, -1, 0, "tkem1",       "turbulent kinetic energy (t-1)",            NULL      },
58231   { 226, -1, 0, "fao",         "FAO data set (soil data flags)",            NULL      },
58232   { 227, -1, 0, "rgcgn",       "heat capacity of soil",                     NULL      },
58233   { 228, -1, 0, "sodif",       "soil diffusivity",                          NULL      },
58234   { 229, -1, 0, "wsmx",        "field capacity of soil",                   "m"        },
58235   { 230, -1, 0, "qvi",         "vertically integrated specific humidity",  "kg/m^2"   },
58236   { 231, -1, 0, "alwcvi",      "vertically integrated liquid water cont.", "kg/m^2"   },
58237   { 232, -1, 0, "glac",        "glacier mask",                             "fraction" },
58238   { 233, -1, 0, "runlnd",      "surface runoff not running into ocean",     NULL      },
58239   { 259, -1, 0, "windspeed",   "windspeed (sqrt(u^2+v^2))",                 NULL      },
58240   { 260, -1, 0, "precip",      "total precipitation",                      "m/s"      },
58241   { 261, -1, 0, "net_top",     "total top radiation",                       NULL      },
58242   { 262, -1, 0, "net_bot",     "total surface radiation",                   NULL      },
58243   { 263, -1, 0, "net_heat",    "net surface heat flux",                     NULL      },
58244   { 264, -1, 0, "net_water",   "total surface water",                       NULL      },
58245   { 268, -1, 0, "sw_atm",       NULL,                                       NULL      },
58246   { 269, -1, 0, "lw_atm",       NULL,                                       NULL      },
58247   { 270, -1, 0, "net_atm",      NULL,                                       NULL      },
58248   { 271, -1, 0, "surf_runoff", "surface runoff",                            NULL      },
58249   { 275, -1, 0, "fresh_water",  NULL,                                       NULL      },
58250 };
58251 
58252 static const param_type echam5[] = {
58253   {   4, -1, 0, "precip",     "total precipitation",                       "kg/m^2s" },
58254   {  79, -1, 0, "swnirac",    "net surface NIR flux acc.",                 "W/m^2"   },
58255   {  80, -1, 0, "swdifnirac", "fraction of diffuse NIR acc.",              "W/m^2"   },
58256   {  81, -1, 0, "swvisac",    "net surface visible flux acc.",             "W/m^2"   },
58257   {  82, -1, 0, "swdifvisac", "fraction of diffuse visible acc.",          "W/m^2"   },
58258   {  83, -1, 0, "ocu",        "ocean eastw. velocity (coupled mode)",      "m/s"     },
58259   {  84, -1, 0, "ocv",        "ocean northw. velocity (coupled mode)",     "m/s"     },
58260   {  85, -1, 0, "tradl",      "net LW radiation 200mb",                    "W/m^2"   },
58261   {  86, -1, 0, "sradl",      "net SW radiation 200mb",                    "W/m^2"   },
58262   {  87, -1, 0, "trafl",      "net LW radiation 200mb (clear sky)",        "W/m^2"   },
58263   {  88, -1, 0, "srafl",      "net SW radiation 200mb (clear sky)",        "W/m^2"   },
58264   {  89, -1, 0, "amlcorac",   "mixed layer flux correction",               "W/m^2"   },
58265   {  90, -1, 0, "amlheatac",  "mixed layer heat content",                  "J/m^2"   },
58266   {  91, -1, 0, "trfliac",    "net LW radiation over ice",                 "W/m^2"   },
58267   {  92, -1, 0, "trflwac",    "net LW radiation over water",               "W/m^2"   },
58268   {  93, -1, 0, "trfllac",    "net LW radiation over land",                "W/m^2"   },
58269   {  94, -1, 0, "sofliac",    "net SW radiation over ice",                 "W/m^2"   },
58270   {  95, -1, 0, "soflwac",    "net SW radiation over water",               "W/m^2"   },
58271   {  96, -1, 0, "sofllac",    "net SW radiation over land",                "W/m^2"   },
58272   {  97, -1, 0, "friac",      "ice cover (fraction of grid box)",           NULL     },
58273   { 102, -1, 0, "tsi",        "surface temperature of ice",                "K"       },
58274   { 103, -1, 0, "tsw",        "surface temperature of water",              "K"       },
58275   { 104, -1, 0, "ustri",      "zonal      wind stress over ice",           "Pa"      },
58276   { 105, -1, 0, "vstri",      "meridional wind stress over ice",           "Pa"      },
58277   { 106, -1, 0, "ustrw",      "zonal      wind stress over water",         "Pa"      },
58278   { 107, -1, 0, "vstrw",      "meridional wind stress over water",         "Pa"      },
58279   { 108, -1, 0, "ustrl",      "zonal      wind stress over land",          "Pa"      },
58280   { 109, -1, 0, "vstrl",      "meridional wind stress over land",          "Pa"      },
58281   { 110, -1, 0, "ahfliac",    "latent heat flux over ice",                 "W/m^2"   },
58282   { 111, -1, 0, "ahflwac",    "latent heat flux over water",               "W/m^2"   },
58283   { 112, -1, 0, "ahfllac",    "latent heat flux over land",                "W/m^2"   },
58284   { 113, -1, 0, "evapiac",    "evaporation over ice",                      "kg/m^2s" },
58285   { 114, -1, 0, "evapwac",    "evaporation over water",                    "kg/m^2s" },
58286   { 115, -1, 0, "evaplac",    "evaporation over land",                     "kg/m^2s" },
58287   { 116, -1, 0, "az0i",       "roughness length over ice",                 "m"       },
58288   { 117, -1, 0, "az0w",       "roughness length over water",               "m"       },
58289   { 118, -1, 0, "az0l",       "roughness length over land",                "m"       },
58290   { 119, -1, 0, "ahfsiac",    "sensible heat flux over ice",               "W/m^2"   },
58291   { 120, -1, 0, "ahfswac",    "sensible heat flux over water",             "W/m^2"   },
58292   { 121, -1, 0, "ahfslac",    "sensible heat flux over land",              "W/m^2"   },
58293   { 122, -1, 0, "alsoi",      "albedo of ice",                              NULL     },
58294   { 123, -1, 0, "alsow",      "albedo of water",                            NULL     },
58295   { 124, -1, 0, "alsol",      "albedo of land",                             NULL     },
58296   { 125, -1, 0, "ahfice",     "conductive heat flux through ice",          "W/m^2"   },
58297   { 126, -1, 0, "qres",       "residual heat flux for melting sea ice",    "W/m^2"   },
58298   { 127, -1, 0, "alake",      "lake fraction",                              NULL     },
58299   { 128, -1, 0, "rintop",     "low level inversion",                        NULL     },
58300   { 129, -1, 0, "geosp",      "surface geopotential (orography)",          "m^2/s^2" },
58301   { 130, -1, 0, "t",          "temperature",                               "K"       },
58302   { 131, -1, 0, "u",          "u-velocity",                                "m/s"     },
58303   { 132, -1, 0, "v",          "v-velocity",                                "m/s"     },
58304   { 133, -1, 0, "q",          "specific humidity",                         "kg/kg"   },
58305   { 134, -1, 0, "aps",        "surface pressure",                          "Pa"      },
58306   { 135, -1, 0, "omega",      "vertical velocity",                         "Pa/s"    },
58307   { 136, -1, 0, "acdnc",      "cloud droplet number concentration",        "1/m^3"   },
58308   { 137, -1, 0, "apmeb",      "(P-E) error",                               "kg/m^2s" },
58309   { 138, -1, 0, "svo",        "vorticity",                                 "1/s"     },
58310   { 139, -1, 0, "tslm1",      "surface temperature of land",               "K"       },
58311   { 140, -1, 0, "ws",         "soil wetness",                              "m"       },
58312   { 141, -1, 0, "sn",         "water equivalent snow depth",               "m"       },
58313   { 142, -1, 0, "aprl",       "large scale precipitation",                 "kg/m^2s" },
58314   { 143, -1, 0, "aprc",       "convective  precipitation",                 "kg/m^2s" },
58315   { 144, -1, 0, "aprs",       "snow fall",                                 "kg/m^2s" },
58316   { 145, -1, 0, "vdis",       "boundary layer dissipation",                "W/m^2"   },
58317   { 146, -1, 0, "ahfs",       "sensible heat flux",                        "W/m^2"   },
58318   { 147, -1, 0, "ahfl",       "latent heat flux",                          "W/m^2"   },
58319   { 148, -1, 0, "stream",     "streamfunction",                            "m^2/s"   },
58320   { 149, -1, 0, "velopot",    "velocity potential",                        "m^2/s"   },
58321   { 150, -1, 0, "xivi",       "vertically integrated cloud ice",           "kg/m^2"  },
58322   { 151, -1, 0, "slp",        "mean sea level pressure",                   "Pa"      },
58323   { 152, -1, 0, "lsp",        "log surface pressure",                       NULL     },
58324   { 153, -1, 0, "xl",         "cloud water",                               "kg/kg"   },
58325   { 154, -1, 0, "xi",         "cloud ice",                                 "kg/kg"   },
58326   { 155, -1, 0, "sd",         "divergence",                                "1/s"     },
58327   { 156, -1, 0, "geopoth",    "geopotential height",                       "m"       },
58328   { 157, -1, 0, "rhumidity",  "relative humidity",                          NULL     },
58329   { 159, -1, 0, "wind10w",    "10m windspeed over water",                  "m/s"     },
58330   { 160, -1, 0, "runoff",     "surface runoff and drainage",               "kg/m^2s" },
58331   { 161, -1, 0, "drain",      "drainage",                                  "kg/m^2s" },
58332   { 162, -1, 0, "aclc",       "cloud cover",                                NULL     },
58333   { 164, -1, 0, "aclcov",     "total cloud cover",                          NULL     },
58334   { 165, -1, 0, "u10",        "10m u-velocity",                            "m/s"     },
58335   { 166, -1, 0, "v10",        "10m v-velocity",                            "m/s"     },
58336   { 167, -1, 0, "temp2",      "2m temperature",                            "K"       },
58337   { 168, -1, 0, "dew2",       "2m dew point temperature",                  "K"       },
58338   { 169, -1, 0, "tsurf",      "surface temperature",                       "K"       },
58339   { 170, -1, 0, "xvar",       "variance of total water amount",            "kg/kg"   },
58340   { 171, -1, 0, "wind10",     "10m windspeed",                             "m/s"     },
58341   { 172, -1, 0, "slm",        "land sea mask (1. = land, 0. = sea/lakes)",  NULL     },
58342   { 173, -1, 0, "az0",        "roughness length",                          "m"       },
58343   { 174, -1, 0, "alb",        "surface background albedo",                  NULL     },
58344   { 175, -1, 0, "albedo",     "surface albedo",                             NULL     },
58345   { 176, -1, 0, "srads",      "net surface SW radiation",                  "W/m^2"   },
58346   { 177, -1, 0, "trads",      "net surface LW radiation",                  "W/m^2"   },
58347   { 178, -1, 0, "srad0",      "net top SW radiation",                      "W/m^2"   },
58348   { 179, -1, 0, "trad0",      "net top LW radiation (-OLR)",               "W/m^2"   },
58349   { 180, -1, 0, "ustr",       "u-stress",                                  "Pa"      },
58350   { 181, -1, 0, "vstr",       "v-stress",                                  "Pa"      },
58351   { 182, -1, 0, "evap",       "evaporation",                               "kg/m^2s" },
58352   { 183, -1, 0, "xskew",      "skewness of total water amount qv+qi+ql",    NULL     },
58353   { 184, -1, 0, "srad0d",     "top incoming SW radiation",                 "W/m^2"   },
58354   { 185, -1, 0, "srafs",      "net surface SW radiation (clear sky)",      "W/m^2"   },
58355   { 186, -1, 0, "trafs",      "net surface LW radiation (clear sky)",      "W/m^2"   },
58356   { 187, -1, 0, "sraf0",      "net top SW radiation   (clear sky)",        "W/m^2"   },
58357   { 188, -1, 0, "traf0",      "net top LW radiation   (clear sky)",        "W/m^2"   },
58358   { 189, -1, 0, "sclfs",      "net surface SW cloud forcing (176-185)",    "W/m^2"   },
58359   { 190, -1, 0, "tclfs",      "net surface LW cloud forcing (177-186)",    "W/m^2"   },
58360   { 191, -1, 0, "sclf0",      "net SW top cloud forcing (178-187)",        "W/m^2"   },
58361   { 192, -1, 0, "tclf0",      "net LW top cloud forcing (179-188)",        "W/m^2"   },
58362   { 193, -1, 0, "wl",         "skin reservoir content",                    "m"       },
58363   { 194, -1, 0, "slf",        "fractional land cover",                      NULL     },
58364   { 195, -1, 0, "ustrgw",     "u-gravity wave stress",                     "Pa"      },
58365   { 196, -1, 0, "vstrgw",     "v-gravity wave stress",                     "Pa"      },
58366   { 197, -1, 0, "vdisgw",     "gravity wave dissipation",                  "W/m^2"   },
58367   { 198, -1, 0, "vgrat",      "vegetation ratio",                           NULL     },
58368   { 199, -1, 0, "orostd",     "orographic standard deviation",             "m"       },
58369   { 200, -1, 0, "vlt",        "leaf area index",                            NULL     },
58370   { 201, -1, 0, "t2max",      "maximum 2m-temperature",                    "K"       },
58371   { 202, -1, 0, "t2min",      "minimum 2m-temperature",                    "K"       },
58372   { 203, -1, 0, "srad0u",     "top SW radiation upward",                   "W/m^2"   },
58373   { 204, -1, 0, "sradsu",     "surface SW radiation upward",               "W/m^2"   },
58374   { 205, -1, 0, "tradsu",     "surface LW radiation upward",               "W/m^2"   },
58375   { 206, -1, 0, "grndflux",   "surface ground heat flux",                   NULL     },
58376   { 207, -1, 0, "tsoil",      "deep soil temperatures (5 layers)",         "K"       },
58377   { 208, -1, 0, "ahfcon",     "conductive heat flux through ice",          "W/m^2"   },
58378   { 209, -1, 0, "ahfres",     "res. heat flux for melting ice",            "W/m^2"   },
58379   { 210, -1, 0, "seaice",     "ice cover (fraction of ice+water)",          NULL     },
58380   { 211, -1, 0, "siced",      "ice thickness",                             "m"       },
58381   { 212, -1, 0, "forest",     "forest fraction",                            NULL     },
58382   { 213, -1, 0, "gld",        "glacier thickness",                         "m"       },
58383   { 214, -1, 0, "sni",        "water equivalent of snow on ice",           "m"       },
58384   { 215, -1, 0, "rogl",       "glacier runoff",                            "kg/m^2s" },
58385   { 216, -1, 0, "wimax",      "maximum 10m-wind speed",                    "m/s"     },
58386   { 217, -1, 0, "topmax",     "maximum height of convective cloud tops",   "Pa"      },
58387   { 218, -1, 0, "snmel",      "snow melt",                                 "kg/m^2s" },
58388   { 219, -1, 0, "runtoc",     "surface runoff into ocean",                 "kg/m^2s" },
58389   { 220, -1, 0, "runlnd",     "surface runoff not running into ocean",     "kg/m^2s" },
58390   { 221, -1, 0, "apmegl",     "P-E over land ice",                         "kg/m^2s" },
58391   { 222, -1, 0, "snacl",      "snow accumulation over land",               "kg/m^2s" },
58392   { 223, -1, 0, "aclcac",     "cloud cover",                                NULL     },
58393   { 224, -1, 0, "tke",        "turbulent kinetic energy",                  "m^2/s^2" },
58394   { 225, -1, 0, "tkem1",      "turbulent kinetic energy (t-1)",            "m^2/s^2" },
58395   { 226, -1, 0, "fao",        "FAO data set (soil data flags) 0...5",       NULL     },
58396   { 227, -1, 0, "rgcgn",      "heat capacity of soil",                      NULL     },
58397   { 228, -1, 0, "sodif",      "soil diffusivity",                          "m^2/s"   },
58398   { 229, -1, 0, "wsmx",       "field capacity of soil",                    "m"       },
58399   { 230, -1, 0, "qvi",        "vertically integrated water vapor",         "kg/m^2"  },
58400   { 231, -1, 0, "xlvi",       "vertically integrated cloud water",         "kg/m^2"  },
58401   { 232, -1, 0, "glac",       "fraction of land covered by glaciers",       NULL     },
58402   { 233, -1, 0, "snc",        "snow depth at the canopy",                  "m"       },
58403   { 234, -1, 0, "rtype",      "type of convection",                        "0...3"   },
58404   { 235, -1, 0, "abso4",      "anthropogenic sulfur burden",               "kg/m^2"  },
58405   { 236, -1, 0, "ao3",        "ipcc ozone",                                "kg/m^2"  },
58406   { 237, -1, 0, "tropo",      "WMO defined tropopause height",             "Pa"      },
58407   { 259, -1, 0, "windspeed",  "windspeed (sqrt(u^2+v^2))",                 "m/s"     },
58408   { 260, -1, 0, "precip",     "total precipitation  (142+143)",            "kg/m^2s" },
58409   { 261, -1, 0, "net_top",    "total top radiation  (178+179)",            "W/m^2"   },
58410   { 262, -1, 0, "net_bot",    "total surface radiation (176+177)",         "W/m^2"   },
58411   { 272, -1, 0, "mastrfu",    "mass stream function",                      "kg/s"    },
58412 };
58413 
58414 static const param_type echam6[] = {
58415   {   4, -1, 0, "precip",         "total precipitation",                       "kg m-2 s-1" },
58416   {  34, -1, 0, "low_cld",        "low cloud",                                  NULL        },
58417   {  35, -1, 0, "mid_cld",        "mid cloud",                                  NULL        },
58418   {  36, -1, 0, "hih_cld",        "high cloud",                                 NULL        },
58419   {  68, -1, 0, "fage",           "aging factor of snow on ice",                NULL        },
58420   {  69, -1, 0, "snifrac",        "fraction of ice covered with snow",          NULL        },
58421   {  70, -1, 0, "barefrac",       "bare ice fraction",                          NULL        },
58422   {  71, -1, 0, "alsom",          "albedo of melt ponds",                       NULL        },
58423   {  72, -1, 0, "alsobs",         "albedo of bare ice and snow",                NULL        },
58424   {  73, -1, 0, "sicepdw",        "melt pond depth on sea-ice",                "m"          },
58425   {  74, -1, 0, "sicepdi",        "ice thickness on melt pond",                "m"          },
58426   {  75, -1, 0, "tsicepdi",       "ice temperature on frozen melt pond",       "K"          },
58427   {  76, -1, 0, "sicepres",       "residual heat flux",                        "W m-2"      },
58428   {  77, -1, 0, "ameltdepth",     "total melt pond depth",                     "m"          },
58429   {  78, -1, 0, "ameltfrac",      "fractional area of melt ponds on sea-ice",   NULL        },
58430   {  79, -1, 0, "albedo_vis_dir", "surface albedo visible range direct",        NULL        },
58431   {  80, -1, 0, "albedo_nir_dir", "surface albedo NIR range direct",            NULL        },
58432   {  81, -1, 0, "albedo_vis_dif", "surface albedo visible range diffuse",       NULL        },
58433   {  82, -1, 0, "albedo_nir_dif", "surface albedo NIR range diffuse",           NULL        },
58434   {  83, -1, 0, "ocu",            "ocean eastw. velocity (coupled mode)",      "m/s"        },
58435   {  84, -1, 0, "ocv",            "ocean northw. velocity (coupled mode)",     "m/s"        },
58436   {  85, -1, 0, "tradl",          "thermal radiation 200mb",                   "W m-2"      },
58437   {  86, -1, 0, "sradl",          "solar radiation 200mb",                     "W m-2"      },
58438   {  87, -1, 0, "trafl",          "thermal radiation 200mb (clear sky)",       "W m-2"      },
58439   {  88, -1, 0, "srafl",          "solar radiation 200mb (clear sky)",         "W m-2"      },
58440   {  89, -1, 0, "amlcorac",       "mixed layer flux correction",               "W m-2"      },
58441   {  90, -1, 0, "amlheatac",      "mixed layer heat content",                  "J m-2"      },
58442   {  91, -1, 0, "trfliac",        "LW flux over ice",                          "W m-2"      },
58443   {  92, -1, 0, "trflwac",        "LW flux over water",                        "W m-2"      },
58444   {  93, -1, 0, "trfllac",        "LW flux over land",                         "W m-2"      },
58445   {  94, -1, 0, "sofliac",        "SW flux over ice",                          "W m-2"      },
58446   {  95, -1, 0, "soflwac",        "SW flux over water",                        "W m-2"      },
58447   {  96, -1, 0, "sofllac",        "SW flux over land",                         "W m-2"      },
58448   {  97, -1, 0, "friac",          "ice cover (fraction of grid box)",           NULL        },
58449   { 102, -1, 0, "tsi",            "surface temperature of ice",                "K"          },
58450   { 103, -1, 0, "tsw",            "surface temperature of water",              "K"          },
58451   { 104, -1, 0, "ustri",          "zonal      wind stress over ice",           "Pa"         },
58452   { 105, -1, 0, "vstri",          "meridional wind stress over ice",           "Pa"         },
58453   { 106, -1, 0, "ustrw",          "zonal      wind stress over water",         "Pa"         },
58454   { 107, -1, 0, "vstrw",          "meridional wind stress over water",         "Pa"         },
58455   { 108, -1, 0, "ustrl",          "zonal      wind stress over land",          "Pa"         },
58456   { 109, -1, 0, "vstrl",          "meridional wind stress over land",          "Pa"         },
58457   { 110, -1, 0, "ahfliac",        "latent heat flux over ice",                 "W m-2"      },
58458   { 111, -1, 0, "ahflwac",        "latent heat flux over water",               "W m-2"      },
58459   { 112, -1, 0, "ahfllac",        "latent heat flux over land",                "W m-2"      },
58460   { 113, -1, 0, "evapiac",        "evaporation over ice",                      "kg m-2 s-1" },
58461   { 114, -1, 0, "evapwac",        "evaporation over water",                    "kg m-2 s-1" },
58462   { 115, -1, 0, "evaplac",        "evaporation over land",                     "kg m-2 s-1" },
58463   { 116, -1, 0, "az0i",           "roughness length over ice",                 "m"          },
58464   { 117, -1, 0, "az0w",           "roughness length over water",               "m"          },
58465   { 118, -1, 0, "az0l",           "roughness length over land",                "m"          },
58466   { 119, -1, 0, "ahfsiac",        "sensible heat flux over ice",               "W m-2"      },
58467   { 120, -1, 0, "ahfswac",        "sensible heat flux over water",             "W m-2"      },
58468   { 121, -1, 0, "ahfslac",        "sensible heat flux over land",              "W m-2"      },
58469   { 122, -1, 0, "alsoi",          "albedo of ice",                              NULL        },
58470   { 123, -1, 0, "alsow",          "albedo of water",                            NULL        },
58471   { 124, -1, 0, "alsol",          "albedo of land",                             NULL        },
58472   { 125, -1, 0, "ahfice",         "conductive heat flux",                      "W m-2"      },
58473   { 126, -1, 0, "qres",           "residual heat flux for melting sea ice",    "W m-2"      },
58474   { 127, -1, 0, "alake",          "lake fraction of grid box",                 "fraction"   },
58475   { 128, -1, 0, "rintop",         "low level inversion",                        NULL        },
58476   { 129, -1, 0, "geosp",          "surface geopotential (orography)",          "m^2/s^2"    },
58477   { 130, -1, 0, "t",              "temperature",                               "K"          },
58478   { 131, -1, 0, "u",              "u-velocity",                                "m/s"        },
58479   { 132, -1, 0, "v",              "v-velocity",                                "m/s"        },
58480   { 133, -1, 0, "q",              "specific humidity",                         "kg/kg"      },
58481   { 134, -1, 0, "aps",            "surface pressure",                          "Pa"         },
58482   { 135, -1, 0, "omega",          "vertical velocity",                         "Pa/s"       },
58483   { 136, -1, 0, "acdnc",          "cloud droplet number concentration",        "1 m-3"      },
58484   { 137, -1, 0, "apmeb",          "vert. integr. tendencies of water",         "kg m-2 s-1" },
58485   { 138, -1, 0, "svo",            "vorticity",                                 "1/s"        },
58486   { 139, -1, 0, "tslm1",          "surface temperature of land",               "K"          },
58487   { 140, -1, 0, "ws",             "soil wetness",                              "m"          },
58488   { 141, -1, 0, "sn",             "snow depth",                                "m"          },
58489   { 142, -1, 0, "aprl",           "large scale precipitation",                 "kg m-2 s-1" },
58490   { 143, -1, 0, "aprc",           "convective  precipitation",                 "kg m-2 s-1" },
58491   { 144, -1, 0, "aprs",           "snow fall",                                 "kg m-2 s-1" },
58492   { 145, -1, 0, "vdis",           "boundary layer dissipation",                "W m-2"      },
58493   { 146, -1, 0, "ahfs",           "sensible heat flux",                        "W m-2"      },
58494   { 147, -1, 0, "ahfl",           "latent heat flux",                          "W m-2"      },
58495   { 148, -1, 0, "stream",         "streamfunction",                            "m^2/s"      },
58496   { 149, -1, 0, "velopot",        "velocity potential",                        "m^2/s"      },
58497   { 150, -1, 0, "xivi",           "vertically integrated cloud ice",           "kg m-2"     },
58498   { 151, -1, 0, "slp",            "mean sea level pressure",                   "Pa"         },
58499   { 152, -1, 0, "lsp",            "log surface pressure",                       NULL        },
58500   { 153, -1, 0, "xl",             "cloud water",                               "kg/kg"      },
58501   { 154, -1, 0, "xi",             "cloud ice",                                 "kg/kg"      },
58502   { 155, -1, 0, "sd",             "divergence",                                "1/s"        },
58503   { 156, -1, 0, "geopoth",        "geopotential height",                       "m"          },
58504   { 157, -1, 0, "rhumidity",      "relative humidity",                         "fraction"   },
58505   { 158, -1, 0, "var158",         "tendency of surface pressure",              "Pa/s"       },
58506   { 159, -1, 0, "wind10w",        "10m windspeed over water",                  "m/s"        },
58507   { 160, -1, 0, "runoff",         "surface runoff and drainage",               "kg m-2 s-1" },
58508   { 161, -1, 0, "drain",          "drainage",                                  "kg m-2 s-1" },
58509   { 162, -1, 0, "aclc",           "cloud cover",                                NULL        },
58510   { 163, -1, 0, "aclcv",          "total cloud cover",                          NULL        },
58511   { 164, -1, 0, "aclcov",         "total cloud cover (mean)",                   NULL        },
58512   { 165, -1, 0, "u10",            "10m u-velocity",                            "m/s"        },
58513   { 166, -1, 0, "v10",            "10m v-velocity",                            "m/s"        },
58514   { 167, -1, 0, "temp2",          "2m temperature",                            "K"          },
58515   { 168, -1, 0, "dew2",           "2m dew point temperature",                  "K"          },
58516   { 169, -1, 0, "tsurf",          "surface temperature",                       "K"          },
58517   { 170, -1, 0, "xvar",           "variance of total water amount qv+qi+ql",   "kg/kg"      },
58518   { 171, -1, 0, "wind10",         "10m windspeed",                             "m/s"        },
58519   { 172, -1, 0, "slm",            "land sea mask (1. = land, 0. = sea/lakes)",  NULL        },
58520   { 173, -1, 0, "az0",            "roughness length",                          "m"          },
58521   { 174, -1, 0, "alb",            "surface background albedo",                  NULL        },
58522   { 175, -1, 0, "albedo",         "surface albedo",                             NULL        },
58523   { 176, -1, 0, "srads",          "net surface solar radiation",               "W m-2"      },
58524   { 177, -1, 0, "trads",          "net surface thermal radiation",             "W m-2"      },
58525   { 178, -1, 0, "srad0",          "net top solar radiation",                   "W m-2"      },
58526   { 179, -1, 0, "trad0",          "top thermal radiation (OLR)",               "W m-2"      },
58527   { 180, -1, 0, "ustr",           "u-stress",                                  "Pa"         },
58528   { 181, -1, 0, "vstr",           "v-stress",                                  "Pa"         },
58529   { 182, -1, 0, "evap",           "evaporation",                               "kg m-2 s-1" },
58530   { 183, -1, 0, "xskew",          "skewness of total water amount qv+qi+ql",    NULL        },
58531   { 184, -1, 0, "srad0d",         "top incoming solar radiation",              "W m-2"      },
58532   { 185, -1, 0, "srafs",          "net surf. solar radiation   (clear sky)",   "W m-2"      },
58533   { 186, -1, 0, "trafs",          "net surf. thermal radiation (clear sky)",   "W m-2"      },
58534   { 187, -1, 0, "sraf0",          "net top solar radiation     (clear sky)",   "W m-2"      },
58535   { 188, -1, 0, "traf0",          "net top thermal radiation   (clear sky)",   "W m-2"      },
58536   { 189, -1, 0, "sclfs",          "surface solar cloud forcing",               "W m-2"      },
58537   { 190, -1, 0, "tclfs",          "surface thermal cloud forcing",             "W m-2"      },
58538   { 191, -1, 0, "sclf0",          "SW top cloud forcing (178-187)",            "W m-2"      },
58539   { 192, -1, 0, "tclf0",          "LW top cloud forcing (179-188)",            "W m-2"      },
58540   { 193, -1, 0, "wl",             "skin reservoir content",                    "m"          },
58541   { 194, -1, 0, "slf",            "sea land fraction",                          NULL        },
58542   { 195, -1, 0, "ustrgw",         "u-gravity wave stress",                     "Pa"         },
58543   { 196, -1, 0, "vstrgw",         "v-gravity wave stress",                     "Pa"         },
58544   { 197, -1, 0, "vdisgw",         "gravity wave dissipation",                  "W m-2"      },
58545   { 198, -1, 0, "vgrat",          "vegetation ratio",                           NULL        },
58546   { 199, -1, 0, "orostd",         "orographic standard deviation",             "m"          },
58547   { 200, -1, 0, "vlt",            "leaf area index",                            NULL        },
58548   { 201, -1, 0, "t2max",          "maximum 2m-temperature",                    "K"          },
58549   { 202, -1, 0, "t2min",          "minimum 2m-temperature",                    "K"          },
58550   { 203, -1, 0, "srad0u",         "top solar radiation upward",                "W m-2"      },
58551   { 204, -1, 0, "sradsu",         "surface solar radiation upward",            "W m-2"      },
58552   { 205, -1, 0, "tradsu",         "surface thermal radiation upward",          "W m-2"      },
58553   { 206, -1, 0, "grndflux",       "surface ground heat flux",                   NULL        },
58554   { 207, -1, 0, "tsoil",          "deep soil temperatures (5 layers)",         "K"          },
58555   { 208, -1, 0, "ahfcon",         "conductive heat flux through ice",          "W m-2"      },
58556   { 209, -1, 0, "ahfres",         "melting of ice",                            "W m-2"      },
58557   { 210, -1, 0, "seaice",         "ice cover (fraction of 1-SLM)",              NULL        },
58558   { 211, -1, 0, "siced",          "ice depth",                                 "m"          },
58559   { 212, -1, 0, "forest",         "forest fraction",                            NULL        },
58560   { 213, -1, 0, "gld",            "glacier depth",                             "m"          },
58561   { 214, -1, 0, "sni",            "water equivalent of snow on ice",           "m"          },
58562   { 215, -1, 0, "rogl",           "glacier runoff",                            "kg m-2 s-1" },
58563   { 216, -1, 0, "wimax",          "maximum 10m-wind speed",                    "m/s"        },
58564   { 217, -1, 0, "topmax",         "maximum height of convective cloud tops",   "Pa"         },
58565   { 218, -1, 0, "snmel",          "snow melt",                                 "kg m-2 s-1" },
58566   { 219, -1, 0, "runtoc",         "surface runoff into ocean",                 "kg m-2 s-1" },
58567   { 220, -1, 0, "runlnd",         "surface runoff not running into ocean",     "kg m-2 s-1" },
58568   { 221, -1, 0, "apmegl",         "P-E over land ice",                         "kg m-2 s-1" },
58569   { 222, -1, 0, "snacl",          "snow accumulation over land",               "kg m-2 s-1" },
58570   { 223, -1, 0, "aclcac",         "cloud cover",                                NULL        },
58571   { 224, -1, 0, "tke",            "turbulent kinetic energy",                  "m^2/s^2"    },
58572   { 225, -1, 0, "tkem1",          "turbulent kinetic energy (t-1)",            "m^2/s^2"    },
58573   { 226, -1, 0, "fao",            "FAO data set (soil data flags)",            "0...5"      },
58574   { 227, -1, 0, "rgcgn",          "heat capacity of soil",                      NULL        },
58575   { 228, -1, 0, "sodif",          "diffusivity of soil and land ice",          "m^2/s"      },
58576   { 229, -1, 0, "wsmx",           "field capacity of soil",                    "m"          },
58577   { 230, -1, 0, "qvi",            "vertically integrated water vapor",         "kg m-2"     },
58578   { 231, -1, 0, "xlvi",           "vertically integrated cloud water",         "kg m-2"     },
58579   { 232, -1, 0, "glac",           "fraction of land covered by glaciers",       NULL        },
58580   { 233, -1, 0, "snc",            "snow depth at the canopy",                  "m"          },
58581   { 234, -1, 0, "rtype",          "type of convection",                        "0...3"      },
58582   { 235, -1, 0, "abso4",          "antropogenic sulfur burden",                "kg m-2"     },
58583   { 236, -1, 0, "ao3",            "ipcc ozone",                                "kg m-2"     },
58584   { 237, -1, 0, "tropo",          "WMO defined tropopause height",             "Pa"         },
58585   { 259, -1, 0, "windspeed",      "windspeed (sqrt(u^2+v^2))",                 "m/s"        },
58586   { 260, -1, 0, "precip",         "total precipitation  (142+143)",            "kg m-2 s-1" },
58587   { 261, -1, 0, "net_top",        "total top radiation  (178+179)",            "W m-2"      },
58588   { 262, -1, 0, "net_bot",        "total surface radiation (176+177)",         "W m-2"      },
58589   { 272, -1, 0, "mastfru",        "mass stream function",                      "kg/s"       },
58590 };
58591 
58592 static const param_type mpiom1[] = {
58593   {   2, -1, 0, "THO",      "temperature",                     "C"        },
58594   {   5, -1, 0, "SAO",      "salinity",                        "psu"      },
58595   {   3, -1, 0, "UKO",      "zon. velocity",                   "m/s"      },
58596   {   4, -1, 0, "VKE",      "mer. velocity",                   "m/s"      },
58597   { 303, -1, 0, "UKOMFL",   "zon. velocity (divergence free)", "m/s"      },
58598   { 304, -1, 0, "VKEMFL",   "mer. velocity (divergence free)", "m/s"      },
58599   {   7, -1, 0, "WO",       "ver. velocity",                   "m/s"      },
58600   {   8, -1, 0, "RHO",      "insitu density",                  "kg/m**3"  },
58601   {   6, -1, 0, "PO",       "pressure",                        "Pa"       },
58602   {  67, -1, 0, "EMINPO",   "freshwaterflux by restoring",     "m/s"      },
58603   {  70, -1, 0, "FLUM",     "total heatflux",                  "W/m**2"   },
58604   {  79, -1, 0, "PEM",      "total freshwaterflux",            "m/s"      },
58605   {  13, -1, 0, "SICTHO",   "ice thickness",                   "m"        },
58606   {  15, -1, 0, "SICOMO",   "ice compactness",                 "frac."    },
58607   {  35, -1, 0, "SICUO",    "zon. ice velocity",               "m/s"      },
58608   {  36, -1, 0, "SICVE",    "mer. ice velocity",               "m/s"      },
58609   {  92, -1, 0, "TAFO",     "surface air temperature",         "C"        },
58610   { 164, -1, 0, "FCLOU",    "cloud cover",                      NULL      },
58611   {  52, -1, 0, "TXO",      "surface u-stress",                "Pa/1025." },
58612   {  53, -1, 0, "TYE",      "surface v-stress",                "Pa/1025." },
58613   { 260, -1, 0, "FPREC",    "prescr. precipitation",           "m/s"      },
58614   {  80, -1, 0, "FSWR",     "downward shortwave rad.",         "W/m**2"   },
58615   {  81, -1, 0, "FTDEW",    "dewpoint temperature",            "K"        },
58616   { 171, -1, 0, "FU10",     "10m windspeed",                   "m/s"      },
58617   { 141, -1, 0, "SICSNO",   "snow thickness",                  "m"        },
58618   { 176, -1, 0, "QSWO",     "heat flux shortwave",             "W/m**2"   },
58619   { 177, -1, 0, "QLWO",     "heat flux longwave",              "W/m**2"   },
58620   { 147, -1, 0, "QLAO",     "heat flux latent",                "W/m**2"   },
58621   { 146, -1, 0, "QSEO",     "heat flux sensible",              "W/m**2"   },
58622   {  65, -1, 0, "PRECO",    "net freshwater flux + runoff",    "m/s"      },
58623   {   1, -1, 0, "ZO",       "sealevel",                        "m"        },
58624   {  82, -1, 0, "Z1O",      "sealevel change",                 "m"        },
58625   {  69, -1, 0, "KCONDEP",  "depth of convection",             "level"    },
58626   {  27, -1, 0, "PSIUWE",   "hor. bar. streamfunction",        "Sv"       },
58627   {  83, -1, 0, "AMLD",     "mixed layer depth",               "m"        },
58628   { 172, -1, 0, "WETO",     "landseamask (pressure points)",    NULL      },
58629   { 507, -1, 0, "AMSUE",    "landseamask (vector points v)",    NULL      },
58630   { 508, -1, 0, "AMSUO",    "landseamask (vector points u)",    NULL      },
58631   {  84, -1, 0, "DEPTO",    "depth at pressure points",        "m"        },
58632   { 484, -1, 0, "DEUTO",    "depth at vector points (u)",      "m"        },
58633   { 584, -1, 0, "DEUTE",    "depth at vector points (v)",      "m"        },
58634   { 184, -1, 0, "DDUO",     "level thickness (vector u )",     "m"        },
58635   { 284, -1, 0, "DDUE",     "level thickness (vector v )",     "m"        },
58636   { 384, -1, 0, "DDPO",     "level thickness (pressure )",     "m"        },
58637   {  85, -1, 0, "DLXP",     "grid distance x",                 "m"        },
58638   {  86, -1, 0, "DLYP",     "grid distance y",                 "m"        },
58639   { 185, -1, 0, "DLXU",     "grid distance x  (vector u)",     "m"        },
58640   { 186, -1, 0, "DLYU",     "grid distance y  (vector u)",     "m"        },
58641   { 285, -1, 0, "DLXV",     "grid distance x  (vector v)",     "m"        },
58642   { 286, -1, 0, "DLYV",     "grid distance y  (vector v)",     "m"        },
58643   {  54, -1, 0, "GILA",     "latitude in radiants",            "rad"      },
58644   {  55, -1, 0, "GIPH",     "longitude in radiants",           "rad"      },
58645   { 354, -1, 0, "ALAT",     "latitude in degrees (pressure)",  "deg"      },
58646   { 355, -1, 0, "ALON",     "longitude in degrees (pressure)", "deg"      },
58647   { 154, -1, 0, "ALATU",    "latitude in degrees (vector u)",  "deg"      },
58648   { 155, -1, 0, "ALONU",    "longitude in degrees (vector u)", "deg"      },
58649   { 254, -1, 0, "ALATV",    "latitude in degrees (vector v)",  "deg"      },
58650   { 255, -1, 0, "ALONV",    "longitude in degrees (vector v)", "deg"      },
58651   { 110, -1, 0, "AVO",      "vertical impuls diffusion",       "m**2/s"   },
58652   { 111, -1, 0, "DVO",      "vertical T,S diffusion",          "m**2/s"   },
58653   { 142, -1, 0, "SICTRU",   "seaice transport x",              "m**2/s"   },
58654   { 143, -1, 0, "SICTRV",   "seaice transport y",              "m**2/s"   },
58655   { 612, -1, 0, "WTMIX",    "wind mixing",                     "m**2/s"   },
58656   { 183, -1, 0, "zmld",     "mixed layer depth (SJ)",          "m"        },
58657   { 207, -1, 0, "WGO",      "GM vertical velocity",            "m/s"      },
58658   { 305, -1, 0, "rivrun",   "RiverRunoff",                     "m/s"      },
58659   { 158, -1, 0, "TMCDO",    "mon. mean depth of convection",   "level"    },
58660   { 247, -1, 0, "DQSWO",    "heatflux sw over water",          "W/m**2"   },
58661   { 248, -1, 0, "DQLWO",    "heatflux lw over water",          "W/m**2"   },
58662   { 249, -1, 0, "DQSEO",    "heatflux se over water",          "W/m**2"   },
58663   { 250, -1, 0, "DQLAO",    "heatflux la over water",          "W/m**2"   },
58664   { 251, -1, 0, "DQTHO",    "heatflux net over water",         "W/m**2"   },
58665   { 252, -1, 0, "DQSWI",    "heatflux sw over seaice",         "W/m**2"   },
58666   { 253, -1, 0, "DQLWI",    "heatflux lw over seaice",         "W/m**2"   },
58667   { 254, -1, 0, "DQSEI",    "heatflux se over seaice",         "W/m**2"   },
58668   { 255, -1, 0, "DQLAI",    "heatflux la over seaice",         "W/m**2"   },
58669   { 256, -1, 0, "DQTHI",    "heatflux net over seaice",        "W/m**2"   },
58670   { 257, -1, 0, "DTICEO",   "Equi. temp over seaice",          "K"        },
58671   { 270, -1, 0, "AOFLNHWO", "oasis net heat flux water",       "W/m**2"   },
58672   { 271, -1, 0, "AOFLSHWO", "oasis downward short wave",       "W/m**2"   },
58673   { 272, -1, 0, "AOFLRHIO", "oasis residual heat flux ice",    "W/m**2"   },
58674   { 273, -1, 0, "AOFLCHIO", "oasis conduct. heat flux ice",    "W/m**2"   },
58675   { 274, -1, 0, "AOFLFRWO", "oasis fluid fresh water flux",    "m/s"      },
58676   { 275, -1, 0, "AOFLFRIO", "oasis solid fresh water flux",    "m/s"      },
58677   { 276, -1, 0, "AOFLTXWO", "oasis wind stress water x",       "Pa/102"   },
58678   { 277, -1, 0, "AOFLTYWO", "oasis wind stress water y",       "Pa/102"   },
58679   { 278, -1, 0, "AOFLTXIO", "oasis wind stress ice x",         "Pa/102"   },
58680   { 279, -1, 0, "AOFLTYIO", "oasis wind stress ice x",         "Pa/102"   },
58681   { 280, -1, 0, "AOFLWSVO", "oasis wind speed",                "m/s"      },
58682 };
58683 
58684 static const param_type ecmwf[] = {
58685   {   1, -1, 0, "STRF",     "Stream function",                                            "m**2 s**-1"            },
58686   {   2, -1, 0, "VPOT",     "Velocity potential",                                         "m**2 s**-1"            },
58687   {   3, -1, 0, "PT",       "Potential temperature",                                      "K"                     },
58688   {   4, -1, 0, "EQPT",     "Equivalent potential temperature",                           "K"                     },
58689   {   5, -1, 0, "SEPT",     "Saturated equivalent potential temperature",                 "K"                     },
58690   {  11, -1, 0, "UDVW",     "U component of divergent wind",                              "m s**-1"               },
58691   {  12, -1, 0, "VDVW",     "V component of divergent wind",                              "m s**-1"               },
58692   {  13, -1, 0, "URTW",     "U component of rotational wind",                             "m s**-1"               },
58693   {  14, -1, 0, "VRTW",     "V component of rotational wind",                             "m s**-1"               },
58694   {  21, -1, 0, "UCTP",     "Unbalanced component of temperature",                        "K"                     },
58695   {  22, -1, 0, "UCLN",     "Unbalanced component of logarithm of surface pressure",       NULL                   },
58696   {  23, -1, 0, "UCDV",     "Unbalanced component of divergence",                         "s**-1"                 },
58697   {  26, -1, 0, "CL",       "Lake cover",                                                  NULL                   },
58698   {  27, -1, 0, "CVL",      "Low vegetation cover",                                        NULL                   },
58699   {  28, -1, 0, "CVH",      "High vegetation cover",                                       NULL                   },
58700   {  29, -1, 0, "TVL",      "Type of low vegetation",                                      NULL                   },
58701   {  30, -1, 0, "TVH",      "Type of high vegetation",                                     NULL                   },
58702   {  31, -1, 0, "CI",       "Sea-ice cover",                                               NULL                   },
58703   {  32, -1, 0, "ASN",      "Snow albedo",                                                 NULL                   },
58704   {  33, -1, 0, "RSN",      "Snow density kg",                                            "m**-3"                 },
58705   {  34, -1, 0, "SSTK",     "Sea surface temperature",                                    "K"                     },
58706   {  35, -1, 0, "ISTL1",    "Ice surface temperature layer 1",                            "K"                     },
58707   {  36, -1, 0, "ISTL2",    "Ice surface temperature layer 2",                            "K"                     },
58708   {  37, -1, 0, "ISTL3",    "Ice surface temperature layer 3",                            "K"                     },
58709   {  38, -1, 0, "ISTL4",    "Ice surface temperature layer 4",                            "K"                     },
58710   {  39, -1, 0, "SWVL1",    "Volumetric soil water layer 1",                              "m**3 m**-3"            },
58711   {  40, -1, 0, "SWVL2",    "Volumetric soil water layer 2",                              "m**3 m**-3"            },
58712   {  41, -1, 0, "SWVL3",    "Volumetric soil water layer 3",                              "m**3 m**-3"            },
58713   {  42, -1, 0, "SWVL4",    "Volumetric soil water layer 4",                              "m**3 m**-3"            },
58714   {  43, -1, 0, "SLT",      "Soil type",                                                   NULL                   },
58715   {  44, -1, 0, "ES",       "Snow evaporation m of water",                                 NULL                   },
58716   {  45, -1, 0, "SMLT",     "Snowmelt m of water",                                         NULL                   },
58717   {  46, -1, 0, "SDUR",     "Solar duration",                                             "s"                     },
58718   {  47, -1, 0, "DSRP",     "Direct solar radiation",                                     "w m**-2"               },
58719   {  48, -1, 0, "MAGSS",    "Magnitude of surface stress",                                "N m**-2 s"             },
58720   {  49, -1, 0, "WG10",     "Wind gust at 10 metres",                                     "m s**-1"               },
58721   {  50, -1, 0, "LSPF",     "Large-scale precipitation fraction",                         "s"                     },
58722   {  51, -1, 0, "MX2T24",   "Maximum 2 metre temperature",                                "K"                     },
58723   {  52, -1, 0, "MN2T24",   "Minimum 2 metre temperature",                                "K"                     },
58724   {  53, -1, 0, "MONT",     "Montgomery potential",                                       "m**2 s**-2"            },
58725   {  54, -1, 0, "PRES",     "Pressure",                                                   "Pa"                    },
58726   {  55, -1, 0, "MEAN2T24", "Mean 2 metre temperature past 24 hours",                     "K"                     },
58727   {  56, -1, 0, "MEAN2D24", "Mean 2 metre dewpoint temperature past 24 hours",            "K"                     },
58728   {  60, -1, 0, "PV",       "Potential vorticity",                                        "K m**2 kg**-1 s**-1"   },
58729   { 127, -1, 0, "AT",       "Atmospheric tide",                                            NULL                   },
58730   { 128, -1, 0, "BV",       "Budget values",                                               NULL                   },
58731   { 129, -1, 0, "Z",        "Geopotential",                                               "m**2 s**-2"            },
58732   { 130, -1, 0, "T",        "Temperature",                                                "K"                     },
58733   { 131, -1, 0, "U",        "U velocity",                                                 "m s**-1"               },
58734   { 132, -1, 0, "V",        "V velocity",                                                 "m s**-1"               },
58735   { 133, -1, 0, "Q",        "Specific humidity",                                          "kg kg**-1"             },
58736   { 134, -1, 0, "SP",       "Surface pressure",                                           "Pa"                    },
58737   { 135, -1, 0, "W",        "Vertical velocity",                                          "Pa s**-1"              },
58738   { 136, -1, 0, "TCW",      "Total column water",                                         "kg m**-2"              },
58739   { 137, -1, 0, "TCWV",     "Total column water vapour",                                  "kg m**-2"              },
58740   { 138, -1, 0, "VO",       "Vorticity (relative)",                                       "s**-1"                 },
58741   { 139, -1, 0, "STL1",     "Soil temperature level 1",                                   "K"                     },
58742   { 140, -1, 0, "SWL1",     "Soil wetness level 1 m of water",                             NULL                   },
58743   { 141, -1, 0, "SD",       "Snow depth         1 m of water equivalent",                  NULL                   },
58744   { 142, -1, 0, "LSP",      "Stratiform precipitation (Large scale precipitation)",       "m"                     },
58745   { 143, -1, 0, "CP",       "Convective precipitation",                                   "m"                     },
58746   { 144, -1, 0, "SF",       "Snowfall (convective + stratiform)",                         "m"                     },
58747   { 145, -1, 0, "BLD",      "Boundary layer dissipation",                                 "W m**-2 s"             },
58748   { 146, -1, 0, "SSHF",     "Surface sensible heat flux",                                 "W m**-2 s"             },
58749   { 147, -1, 0, "SLHF",     "Surface latent heat flux",                                   "W m**-2 s"             },
58750   { 148, -1, 0, "CHNK",     "Charnock",                                                    NULL                   },
58751   { 149, -1, 0, "SNR",      "Surface net radiation",                                      "W m**-2 s"             },
58752   { 150, -1, 0, "TNR",      "Top net radiation",                                           NULL                   },
58753   { 151, -1, 0, "MSL",      "Mean sea-level pressure",                                    "Pa"                    },
58754   { 152, -1, 0, "LNSP",     "Logarithm of surface pressure",                               NULL                   },
58755   { 153, -1, 0, "SWHR",     "Short-wave heating rate",                                    "K"                     },
58756   { 154, -1, 0, "LWHR",     "Long-wave heating rate",                                     "K"                     },
58757   { 155, -1, 0, "D",        "Divergence",                                                 "s**-1"                 },
58758   { 156, -1, 0, "GH",       "Height m Geopotential height",                                NULL                   },
58759   { 157, -1, 0, "R",        "Relative humidity",                                          "%"                     },
58760   { 158, -1, 0, "TSP",      "Tendency of surface pressure",                               "Pa s**-1"              },
58761   { 159, -1, 0, "BLH",      "Boundary layer height",                                      "m"                     },
58762   { 160, -1, 0, "SDOR",     "Standard deviation of orography",                             NULL                   },
58763   { 161, -1, 0, "ISOR",     "Anisotropy of sub-gridscale orography",                       NULL                   },
58764   { 162, -1, 0, "ANOR",     "Angle of sub-gridscale orography",                           "rad"                   },
58765   { 163, -1, 0, "SLOR",     "Slope of sub-gridscale orography",                            NULL                   },
58766   { 164, -1, 0, "TCC",      "Total cloud cover",                                           NULL                   },
58767   { 165, -1, 0, "U10M",     "10 metre U wind component",                                  "m s**-1"               },
58768   { 166, -1, 0, "V10M",     "10 metre V wind component",                                  "m s**-1"               },
58769   { 167, -1, 0, "T2M",      "2 metre temperature",                                        "K"                     },
58770   { 168, -1, 0, "D2M",      "2 metre dewpoint temperature",                               "K"                     },
58771   { 169, -1, 0, "SSRD",     "Surface solar radiation downwards",                          "W m**-2 s"             },
58772   { 170, -1, 0, "STL2",     "Soil temperature level 2",                                   "K"                     },
58773   { 171, -1, 0, "SWL2",     "Soil wetness level 2",                                       "m of water"            },
58774   { 172, -1, 0, "LSM",      "Land/sea mask",                                               NULL                   },
58775   { 173, -1, 0, "SR",       "Surface roughness",                                          "m"                     },
58776   { 174, -1, 0, "AL",       "Albedo",                                                      NULL                   },
58777   { 175, -1, 0, "STRD",     "Surface thermal radiation downwards",                        "W m**-2 s"             },
58778   { 176, -1, 0, "SSR",      "Surface solar radiation",                                    "W m**-2 s"             },
58779   { 177, -1, 0, "STR",      "Surface thermal radiation",                                  "W m**-2 s"             },
58780   { 178, -1, 0, "TSR",      "Top solar radiation",                                        "W m**-2 s"             },
58781   { 179, -1, 0, "TTR",      "Top thermal radiation",                                      "W m**-2 s"             },
58782   { 180, -1, 0, "EWSS",     "East/West surface stress",                                   "N m**-2 s"             },
58783   { 181, -1, 0, "NSSS",     "North/South surface stress",                                 "N m**-2 s"             },
58784   { 182, -1, 0, "E",        "Evaporation",                                                "m of water"            },
58785   { 183, -1, 0, "STL3",     "Soil temperature level 3",                                   "K"                     },
58786   { 184, -1, 0, "SWL3",     "Soil wetness level 3",                                       "m of water"            },
58787   { 185, -1, 0, "CCC",      "Convective cloud cover",                                      NULL                   },
58788   { 186, -1, 0, "LCC",      "Low cloud cover",                                             NULL                   },
58789   { 187, -1, 0, "MCC",      "Medium cloud cover",                                          NULL                   },
58790   { 188, -1, 0, "HCC",      "High cloud cover",                                            NULL                   },
58791   { 189, -1, 0, "SUND",     "Sunshine duration",                                          "s"                     },
58792   { 190, -1, 0, "EWOV",     "EW component of subgrid orographic variance",                "m**2"                  },
58793   { 191, -1, 0, "NSOV",     "NS component of subgrid orographic variance",                "m**2"                  },
58794   { 192, -1, 0, "NWOV",     "NWSE component of subgrid orographic variance",              "m**2"                  },
58795   { 193, -1, 0, "NEOV",     "NESW component of subgrid orographic variance",              "m**2"                  },
58796   { 194, -1, 0, "BTMP",     "Brightness temperature",                                     "K"                     },
58797   { 195, -1, 0, "LGWS",     "Lat. component of gravity wave stress",                      "N m**-2 s"             },
58798   { 196, -1, 0, "MGWS",     "Meridional component of gravity wave stress",                "N m**-2 s"             },
58799   { 197, -1, 0, "GWD",      "Gravity wave dissipation",                                   "W m**-2 s"             },
58800   { 198, -1, 0, "SRC",      "Skin reservoir content",                                     "m of water"            },
58801   { 199, -1, 0, "VEG",      "Vegetation fraction",                                         NULL                   },
58802   { 200, -1, 0, "VSO",      "Variance of sub-gridscale orography",                        "m**2"                  },
58803   { 201, -1, 0, "MX2T",     "Maximum 2 metre temperature since previous post-processing", "K"                     },
58804   { 202, -1, 0, "MN2T",     "Minimum 2 metre temperature since previous post-processing", "K"                     },
58805   { 203, -1, 0, "O3",       "Ozone mass mixing ratio",                                    "kg kg**-1"             },
58806   { 204, -1, 0, "PAW",      "Precipiation analysis weights",                               NULL                   },
58807   { 205, -1, 0, "RO",       "Runoff",                                                     "m"                     },
58808   { 206, -1, 0, "TCO3",     "Total column ozone",                                         "kg m**-2"              },
58809   { 207, -1, 0, "WS10",     "10 meter windspeed",                                         "m s**-1"               },
58810   { 208, -1, 0, "TSRC",     "Top net solar radiation, clear sky",                         "W m**-2"               },
58811   { 209, -1, 0, "TTRC",     "Top net thermal radiation, clear sky",                       "W m**-2"               },
58812   { 210, -1, 0, "SSRC",     "Surface net solar radiation, clear sky",                     "W m**-2"               },
58813   { 211, -1, 0, "STRC",     "Surface net thermal radiation, clear sky",                   "W m**-2"               },
58814   { 212, -1, 0, "SI",       "Solar insolation",                                           "W m**-2"               },
58815   { 214, -1, 0, "DHR",      "Diabatic heating by radiation",                              "K"                     },
58816   { 215, -1, 0, "DHVD",     "Diabatic heating by vertical diffusion",                     "K"                     },
58817   { 216, -1, 0, "DHCC",     "Diabatic heating by cumulus convection",                     "K"                     },
58818   { 217, -1, 0, "DHLC",     "Diabatic heating large-scale condensation",                  "K"                     },
58819   { 218, -1, 0, "VDZW",     "Vertical diffusion of zonal wind",                           "m s**-1"               },
58820   { 219, -1, 0, "VDMW",     "Vertical diffusion of meridional wind",                      "m s**-1"               },
58821   { 220, -1, 0, "EWGD",     "EW gravity wave drag tendency",                              "m s**-1"               },
58822   { 221, -1, 0, "NSGD",     "NS gravity wave drag tendency",                              "m s**-1"               },
58823   { 222, -1, 0, "CTZW",     "Convective tendency of zonal wind",                          "m s**-1"               },
58824   { 223, -1, 0, "CTMW",     "Convective tendency of meridional wind",                     "m s**-1"               },
58825   { 224, -1, 0, "VDH",      "Vertical diffusion of humidity",                             "kg kg**-1"             },
58826   { 225, -1, 0, "HTCC",     "Humidity tendency by cumulus convection",                    "kg kg**-1"             },
58827   { 226, -1, 0, "HTLC",     "Humidity tendency large-scale condensation",                 "kg kg**-1"             },
58828   { 227, -1, 0, "CRNH",     "Change from removing negative humidity",                     "kg kg**-1"             },
58829   { 228, -1, 0, "TP",       "Total precipitation",                                        "m"                     },
58830   { 229, -1, 0, "IEWS",     "Instantaneous X surface stress",                             "N m**-2"               },
58831   { 230, -1, 0, "INSS",     "Instantaneous Y surface stress",                             "N m**-2"               },
58832   { 231, -1, 0, "ISHF",     "Instantaneous surface heat flux",                            "W m**-2"               },
58833   { 232, -1, 0, "IE",       "Instantaneous moisture flux",                                "kg m**-2 s"            },
58834   { 233, -1, 0, "ASQ",      "Apparent surface humidity",                                  "kg kg**-1"             },
58835   { 234, -1, 0, "LSRH",     "Logarithm of surface roughness length for heat",              NULL                   },
58836   { 235, -1, 0, "SKT",      "Skin temperature",                                           "K"                     },
58837   { 236, -1, 0, "STL4",     "Soil temperature level 4",                                   "K"                     },
58838   { 237, -1, 0, "SWL4",     "Soil wetness level 4",                                       "m"                     },
58839   { 238, -1, 0, "TSN",      "Temperature of snow layer",                                  "K"                     },
58840   { 239, -1, 0, "CSF",      "Convective snowfall",                                        "m of water equivalent" },
58841   { 240, -1, 0, "LSF",      "Large-scale snowfall",                                       "m of water equivalent" },
58842   { 241, -1, 0, "ACF",      "Accumulated cloud fraction tendency",                         NULL                   },
58843   { 242, -1, 0, "ALW",      "Accumulated liquid water tendency",                           NULL                   },
58844   { 243, -1, 0, "FAL",      "Forecast albedo",                                             NULL                   },
58845   { 244, -1, 0, "FSR",      "Forecast surface roughness",                                 "m"                     },
58846   { 245, -1, 0, "FLSR",     "Forecast log of surface roughness for heat",                  NULL                   },
58847   { 246, -1, 0, "CLWC",     "Cloud liquid water content",                                 "kg kg**-1"             },
58848   { 247, -1, 0, "CIWC",     "Cloud ice water content",                                    "kg kg**-1"             },
58849   { 248, -1, 0, "CC",       "Cloud cover",                                                 NULL                   },
58850   { 249, -1, 0, "AIW",      "Accumulated ice water tendency",                              NULL                   },
58851   { 250, -1, 0, "ICE",      "Ice age",                                                     NULL                   },
58852   { 251, -1, 0, "ATTE",     "Adiabatic tendency of temperature",                          "K"                     },
58853   { 252, -1, 0, "ATHE",     "Adiabatic tendency of humidity",                             "kg kg**-1"             },
58854   { 253, -1, 0, "ATZE",     "Adiabatic tendency of zonal wind",                           "m s**-1"               },
58855   { 254, -1, 0, "ATMW",     "Adiabatic tendency of meridional wind",                      "m s**-1"               },
58856 };
58857 
58858 static const param_type remo[] = {
58859   {  14, -1, 0, "FTKVM",     "turbulent transfer coefficient of momentum in the atmosphere",   NULL           },
58860   {  15, -1, 0, "FTKVH",     "turbulent transfer coefficient of heat in the atmosphere",       NULL           },
58861   {  38, -1, 0, "U10ER",     "10m u-velocity",                                                "m/s"           },
58862   {  39, -1, 0, "V10ER",     "10m v-velocity",                                                "m/s"           },
58863   {  40, -1, 0, "CAPE",      "convetive available potential energy",                           NULL           },
58864   {  41, -1, 0, "GHPBL",     "height of the planetary boudary layer",                         "gpm"           },
58865   {  42, -1, 0, "BETA",      "BETA",                                                           NULL           },
58866   {  43, -1, 0, "WMINLOK",   "WMINLOK",                                                        NULL           },
58867   {  44, -1, 0, "WMAXLOK",   "WMAXLOK",                                                        NULL           },
58868   {  45, -1, 0, "VBM10M",    "maximum of the expected gust velocity near the surface",        "m/s"           },
58869   {  46, -1, 0, "BFLHS",     "surface sensible heat flux",                                    "W/m**2"        },
58870   {  47, -1, 0, "BFLQDS",    "surface latent heat flux",                                      "W/m**2"        },
58871   {  48, -1, 0, "TMCM",      "turbulent transfer coefficient of momentum at the surface",      NULL           },
58872   {  49, -1, 0, "TRSOL",     "TRSOL",                                                          NULL           },
58873   {  50, -1, 0, "TMCH",      "turbulent transfer coefficient of heat at the surface",          NULL           },
58874   {  51, -1, 0, "EMTEF",     "EMTEF",                                                          NULL           },
58875   {  52, -1, 0, "TRSOF",     "TRSOF",                                                          NULL           },
58876   {  53, -1, 0, "DRAIN",     "drainage",                                                      "mm"            },
58877   {  54, -1, 0, "TSL",       "surface temperature (land)",                                    "K"             },
58878   {  55, -1, 0, "TSW",       "surface temperature (water)",                                   "K"             },
58879   {  56, -1, 0, "TSI",       "surface temperature (ice)",                                     "K"             },
58880   {  57, -1, 0, "USTRL",     "surface u-stress (land)",                                       "Pa"            },
58881   {  58, -1, 0, "USTRW",     "surface u-stress (water)",                                      "Pa"            },
58882   {  59, -1, 0, "USTRI",     "surface u-stress (ice)",                                        "Pa"            },
58883   {  60, -1, 0, "VSTRL",     "surface v-stress (land)",                                       "Pa"            },
58884   {  61, -1, 0, "VSTRW",     "surface v-stress (water)",                                      "Pa"            },
58885   {  62, -1, 0, "VSTRI",     "surface v-stress (ice)",                                        "Pa"            },
58886   {  63, -1, 0, "EVAPL",     "surface evaporation (land)",                                    "mm"            },
58887   {  64, -1, 0, "EVAPW",     "surface evaporation (water)",                                   "mm"            },
58888   {  65, -1, 0, "EVAPI",     "surface evaporation (ice)",                                     "mm"            },
58889   {  66, -1, 0, "AHFLL",     "surface latent heat flux (land)",                               "W/m**2"        },
58890   {  67, -1, 0, "AHFLW",     "surface latent heat flux (water)",                              "W/m**2"        },
58891   {  68, -1, 0, "AHFLI",     "surface latent heat flux (ice)",                                "W/m**2"        },
58892   {  69, -1, 0, "AHFSL",     "surface sensible heat flux (land)",                             "W/m**2"        },
58893   {  70, -1, 0, "AHFSW",     "surface sensible heat flux (water)",                            "W/m**2"        },
58894   {  71, -1, 0, "AHFSI",     "surface sensible heat flux (ice)",                              "W/m**2"        },
58895   {  72, -1, 0, "AZ0L",      "surface roughness length (land)",                               "m"             },
58896   {  73, -1, 0, "AZ0W",      "surface roughness length (water)",                              "m"             },
58897   {  74, -1, 0, "AZ0I",      "surface roughness length (ice)",                                "m"             },
58898   {  75, -1, 0, "ALSOL",     "surface albedo (land)",                                         "fract."        },
58899   {  76, -1, 0, "ALSOW",     "surface albedo (water)",                                        "fract."        },
58900   {  77, -1, 0, "ALSOI",     "surface albedo (ice)",                                          "fract."        },
58901   {  81, -1, 0, "TMCHL",     "turbulent transfer coefficient of heat at the surface (land)",   NULL           },
58902   {  82, -1, 0, "TMCHW",     "turbulent transfer coefficient of heat at the surface (water)",  NULL           },
58903   {  83, -1, 0, "TMCHI",     "turbulent transfer coefficient of heat at the surface (ice)",    NULL           },
58904   {  84, -1, 0, "QDBL",      "specific humidity surface (land)",                              "kg/kg"         },
58905   {  85, -1, 0, "QDBW",      "specific humidity surface (water)",                             "kg/kg"         },
58906   {  86, -1, 0, "QDBI",      "specific humidity surface (ice)",                               "kg/kg"         },
58907   {  87, -1, 0, "BFLHSL",    "surface sensible heat flux (land)",                             "W/m**2"        },
58908   {  88, -1, 0, "BFLHSW",    "surface sensible heat flux (water)",                            "W/m**2"        },
58909   {  89, -1, 0, "BFLHSI",    "surface sensible heat flux (ice)",                              "W/m**2"        },
58910   {  90, -1, 0, "BFLQDSL",   "surface latent heat flux (land)",                               "W/m**2"        },
58911   {  91, -1, 0, "BFLQDSW",   "surface latent heat flux (water)",                              "W/m**2"        },
58912   {  92, -1, 0, "BFLQDSI",   "surface latent heat flux (ice)",                                "W/m**2"        },
58913   {  93, -1, 0, "AHFICE",    "sea-ice: conductive heat",                                      "W/m"           },
58914   {  94, -1, 0, "QRES",      "residual heat flux for melting sea ice",                        "W/m**2"        },
58915   {  95, -1, 0, "SRFL",      "SRFL",                                                           NULL           },
58916   {  96, -1, 0, "QDBOXS",    "horizontal transport of water vapour",                          "kg/m**2"       },
58917   {  97, -1, 0, "QWBOXS",    "horizontal transport of cloud water",                           "kg/m**2"       },
58918   {  98, -1, 0, "EKBOXS",    "horizontal transport of kinetic energy",                        "(3600*J)/m**2" },
58919   {  99, -1, 0, "FHBOXS",    "horizontal transport of sensible heat",                         "(3600*J)/m**2" },
58920   { 100, -1, 0, "FIBOXS",    "horizontal transport of potential energy",                      "(3600*J)/m**2" },
58921   { 101, -1, 0, "TLAMBDA",   "heat conductivity of dry soil",                                 "W/(K*m)"       },
58922   { 103, -1, 0, "DLAMBDA",   "parameter for increasing the heat conductivity of the soil",     NULL           },
58923   { 104, -1, 0, "PORVOL",    "pore volume",                                                    NULL           },
58924   { 105, -1, 0, "FCAP",      "field capacity of soil",                                         NULL           },
58925   { 106, -1, 0, "WI3",       "fraction of frozen soil",                                        NULL           },
58926   { 107, -1, 0, "WI4",       "fraction of frozen soil",                                        NULL           },
58927   { 108, -1, 0, "WI5",       "fraction of frozen soil",                                        NULL           },
58928   { 109, -1, 0, "WI",        "fraction of frozen soil",                                        NULL           },
58929   { 110, -1, 0, "WICL",      "fraction of frozen soil",                                        NULL           },
58930   { 112, -1, 0, "QDB",       "specific humidity surface",                                     "kg/kg"         },
58931   { 129, -1, 0, "FIB",       "surface geopotential (orography)",                              "m"             },
58932   { 130, -1, 0, "T",         "temperature",                                                   "K"             },
58933   { 131, -1, 0, "U",         "u-velocity",                                                    "m/s"           },
58934   { 132, -1, 0, "V",         "v-velocity",                                                    "m/s"           },
58935   { 133, -1, 0, "QD",        "specific humidity",                                             "kg/kg"         },
58936   { 134, -1, 0, "PS",        "Surface pressure",                                              "Pa"            },
58937   { 135, -1, 0, "VERVEL",    "Vertical velocity",                                             "Pa/s"          },
58938   { 138, -1, 0, "SVO",       "vorticity",                                                     "1/s"           },
58939   { 139, -1, 0, "TS",        "surface temperature",                                           "K"             },
58940   { 140, -1, 0, "WS",        "soil wetness",                                                  "m"             },
58941   { 141, -1, 0, "SN",        "snow depth",                                                    "m"             },
58942   { 142, -1, 0, "APRL",      "large scale precipitation",                                     "mm"            },
58943   { 143, -1, 0, "APRC",      "convective  precipitation",                                     "mm"            },
58944   { 144, -1, 0, "APRS",      "snow fall",                                                     "mm"            },
58945   { 145, -1, 0, "VDIS",      "boundary layer dissipation",                                    "W/m**2"        },
58946   { 146, -1, 0, "AHFS",      "surface sensible heat flux",                                    "W/m**2"        },
58947   { 147, -1, 0, "AHFL",      "surface latent heat flux",                                      "W/m**2"        },
58948   { 148, -1, 0, "STREAM",    "streamfunction",                                                "m**2/s"        },
58949   { 149, -1, 0, "VELOPOT",   "velocity potential",                                            "m**2/s"        },
58950   { 151, -1, 0, "PSRED",     "mean sea level pressure",                                       "Pa"            },
58951   { 152, -1, 0, "LSP",       "log surface pressure",                                           NULL           },
58952   { 153, -1, 0, "QW",        "liquid water content",                                          "kg/kg"         },
58953   { 155, -1, 0, "SD",        "divergence",                                                    "1/s"           },
58954   { 156, -1, 0, "FI",        "geopotential height",                                           "gpm"           },
58955   { 159, -1, 0, "USTAR3",    "ustar**3",                                                      "m**3/s**3"     },
58956   { 160, -1, 0, "RUNOFF",    "surface runoff",                                                "mm"            },
58957   { 162, -1, 0, "ACLC",      "cloud cover",                                                   "fract."        },
58958   { 163, -1, 0, "ACLCV",     "total cloud cover",                                             "fract."        },
58959   { 164, -1, 0, "ACLCOV",    "total cloud cover",                                             "fract."        },
58960   { 165, -1, 0, "U10",       "10m u-velocity",                                                "m/s"           },
58961   { 166, -1, 0, "V10",       "10m v-velocity",                                                "m/s"           },
58962   { 167, -1, 0, "TEMP2",     "2m temperature",                                                "K"             },
58963   { 168, -1, 0, "DEW2",      "2m dew point temperature",                                      "K"             },
58964   { 169, -1, 0, "TSURF",     "surface temperature (land)",                                    "K"             },
58965   { 170, -1, 0, "TD",        "deep soil temperature",                                         "K"             },
58966   { 171, -1, 0, "WIND10",    "10m windspeed",                                                 "m/s"           },
58967   { 172, -1, 0, "BLA",       "land sea mask",                                                 "fract."        },
58968   { 173, -1, 0, "AZ0",       "surface roughness length",                                      "m"             },
58969   { 174, -1, 0, "ALB",       "surface background albedo",                                     "fract."        },
58970   { 175, -1, 0, "ALBEDO",    "surface albedo",                                                "fract."        },
58971   { 176, -1, 0, "SRADS",     "net surface solar radiation",                                   "W/m**2"        },
58972   { 177, -1, 0, "TRADS",     "net surface thermal radiation",                                 "W/m**2"        },
58973   { 178, -1, 0, "SRAD0",     "net top solar radiation",                                       "W/m**2"        },
58974   { 179, -1, 0, "TRAD0",     "top thermal radiation (OLR)",                                   "W/m**2"        },
58975   { 180, -1, 0, "USTR",      "surface u-stress",                                              "Pa"            },
58976   { 181, -1, 0, "VSTR",      "surface v-stress",                                              "Pa"            },
58977   { 182, -1, 0, "EVAP",      "surface evaporation",                                           "mm"            },
58978   { 183, -1, 0, "TDCL",      "soil temperature",                                              "K"             },
58979   { 185, -1, 0, "SRAFS",     "net surf. solar radiation   (clear sky)",                       "W/m**2"        },
58980   { 186, -1, 0, "TRAFS",     "net surf. thermal radiation (clear sky)",                       "W/m**2"        },
58981   { 187, -1, 0, "SRAF0",     "net top solar radiation     (clear sky)",                       "W/m**2"        },
58982   { 188, -1, 0, "TRAF0",     "net top thermal radiation   (clear sky)",                       "W/m**2"        },
58983   { 189, -1, 0, "SCLFS",     "surface solar cloud forcing",                                   "W/m**2"        },
58984   { 190, -1, 0, "TCLFS",     "surface thermal cloud forcing",                                 "W/m**2"        },
58985   { 191, -1, 0, "SCLF0",     "top solar cloud forcing",                                       "W/m**2"        },
58986   { 192, -1, 0, "TCLF0",     "top thermal cloud forcing",                                     "W/m**2"        },
58987   { 194, -1, 0, "WL",        "skin reservoir content",                                        "m"             },
58988   { 195, -1, 0, "USTRGW",    "u-gravity wave stress",                                         "Pa"            },
58989   { 196, -1, 0, "VSTRGW",    "v-gravity wave stress",                                         "Pa"            },
58990   { 197, -1, 0, "VDISGW",    "gravity wave dissipation",                                      "W/m**2"        },
58991   { 198, -1, 0, "VGRAT",     "vegetation ratio",                                               NULL           },
58992   { 199, -1, 0, "VAROR",     "orographic variance (for surface runoff)",                       NULL           },
58993   { 200, -1, 0, "VLT",       "leaf area index",                                                NULL           },
58994   { 201, -1, 0, "T2MAX",     "maximum 2m-temperature",                                        "K"             },
58995   { 202, -1, 0, "T2MIN",     "minimum 2m-temperature",                                        "K"             },
58996   { 203, -1, 0, "SRAD0U",    "top solar radiation upward",                                    "W/m**2"        },
58997   { 204, -1, 0, "SRADSU",    "surface solar radiation upward",                                "W/m**2"        },
58998   { 205, -1, 0, "TRADSU",    "surface thermal radiation upward",                              "W/m**2"        },
58999   { 206, -1, 0, "TSN",       "snow temperature",                                              "K"             },
59000   { 207, -1, 0, "TD3",       "soil temperature",                                              "K"             },
59001   { 208, -1, 0, "TD4",       "soil temperature",                                              "K"             },
59002   { 209, -1, 0, "TD5",       "soil temperature",                                              "K"             },
59003   { 210, -1, 0, "SEAICE",    "sea ice cover",                                                 "fract."        },
59004   { 211, -1, 0, "SICED",     "sea ice depth",                                                 "m"             },
59005   { 212, -1, 0, "FOREST",    "vegetation type",                                                NULL           },
59006   { 213, -1, 0, "TEFF",      "(effective) sea-ice skin temperature",                          "K"             },
59007   { 214, -1, 0, "TSMAX",     "maximum surface temperature",                                   "K"             },
59008   { 215, -1, 0, "TSMIN",     "minimum surface temperature",                                   "K"             },
59009   { 216, -1, 0, "WIMAX",     "maximum 10m-wind speed",                                        "m/s"           },
59010   { 217, -1, 0, "TOPMAX",    "maximum height of convective cloud tops",                       "Pa"            },
59011   { 218, -1, 0, "SNMEL",     "snow melt",                                                     "mm"            },
59012   { 220, -1, 0, "TSLIN",     "land: residual surface heat budget",                            "W/m**2"        },
59013   { 221, -1, 0, "DSNAC",     "snow depth change",                                             "mm"            },
59014   { 222, -1, 0, "EMTER",     "EMTER",                                                          NULL           },
59015   { 223, -1, 0, "ACLCAC",    "cloud cover",                                                   "fract."        },
59016   { 224, -1, 0, "TKE",       "turbulent kinetic energy",                                       NULL           },
59017   { 226, -1, 0, "FAO",       "FAO data set (soil data flags)",                                 NULL           },
59018   { 227, -1, 0, "RGCGN",     "heat capacity of soil",                                          NULL           },
59019   { 229, -1, 0, "WSMX",      "field capacity of soil",                                         NULL           },
59020   { 230, -1, 0, "QVI",       "vertically integrated specific humidity",                       "kg/m**2"       },
59021   { 231, -1, 0, "ALWCVI",    "vertically integrated liquid water cont.",                      "kg/m**2"       },
59022   { 232, -1, 0, "GLAC",      "glacier mask",                                                   NULL           },
59023   { 253, -1, 0, "PHI",       "latitude in real coordinates",                                  "degrees_north" },
59024   { 254, -1, 0, "RLA",       "longitude in real coordinates",                                 "degrees_east"  },
59025   { 259, -1, 0, "WINDSPEED", "windspeed (sqrt(u**2+v**2))",                                    NULL           },
59026   { 260, -1, 0, "PRECIP",    "total precipitation",                                            NULL           },
59027 };
59028 
59029 static const param_type cosmo002[] = {
59030   {   1, -1, 0, "P",         "pressure",                                          "Pa"         },
59031   {   2, -1, 0, "PMSL",      "mean sea level pressure",                           "Pa"         },
59032   {   3, -1, 0, "DPSDT",     "surface pressure change",                           "Pa s-1"     },
59033   {   6, -1, 0, "FI",        "geopotential",                                      "m2 s-2"     },
59034   {   8, -1, 0, "HH",        "height",                                            "m"          },
59035   {  10, -1, 0, "TO3",       "vertical integrated ozone content",                 "Dobson"     },
59036   {  11, -1, 0, "T",         "temperature",                                       "K"          },
59037   {  15, -1, 0, "TMAX",      "2m maximum temperature",                            "K"          },
59038   {  16, -1, 0, "TMIN",      "2m minimum temperature",                            "K"          },
59039   {  17, -1, 0, "TD",        "2m dew point temperature",                          "K"          },
59040   {  31, -1, 0, "DD",        "undefined",                                         "undefined"  },
59041   {  32, -1, 0, "FF",        "undefined",                                         "undefined"  },
59042   {  33, -1, 0, "U",         "U-component of wind",                               "m s-1"      },
59043   {  34, -1, 0, "V",         "V-component of wind",                               "m s-1"      },
59044   {  39, -1, 0, "OMEGA",     "omega",                                             "Pa s-1"     },
59045   {  40, -1, 0, "W",         "vertical wind velocity",                            "m s-1"      },
59046   {  51, -1, 0, "QV",        "specific humidity",                                 "kg kg-1"    },
59047   {  52, -1, 0, "RELHUM",    "relative humidity",                                 "%"          },
59048   {  54, -1, 0, "TQV",       "precipitable water",                                "kg m-2"     },
59049   {  57, -1, 0, "AEVAP",     "surface evaporation",                               "kg m-2"     },
59050   {  58, -1, 0, "TQI",       "vertical integrated cloud ice",                     "kg m-2"     },
59051   {  59, -1, 0, "TOT_PR",    "total precipitation rate",                          "kg m-2 s-1" },
59052   {  61, -1, 0, "TOT_PREC",  "total precipitation amount",                        "kg m-2"     },
59053   {  65, -1, 0, "W_SNOW",    "surface snow amount",                               "m"          },
59054   {  66, -1, 0, "H_SNOW",    "thickness of snow",                                 "m"          },
59055   {  71, -1, 0, "CLCT",      "total cloud cover",                                 "1"          },
59056   {  72, -1, 0, "CLC_CON",   "convective cloud area fraction",                    "1"          },
59057   {  73, -1, 0, "CLCL",      "low cloud cover",                                   "1"          },
59058   {  74, -1, 0, "CLCM",      "medium cloud cover",                                "1"          },
59059   {  75, -1, 0, "CLCH",      "high cloud cover",                                  "1"          },
59060   {  76, -1, 0, "TQC",       "vertical integrated cloud water",                   "kg m-2"     },
59061   {  78, -1, 0, "SNOW_CON",  "convective snowfall",                               "kg m-2"     },
59062   {  79, -1, 0, "SNOW_GSP",  "large scale snowfall",                              "kg m-2"     },
59063   {  81, -1, 0, "FR_LAND",   "land-sea fraction",                                 "1"          },
59064   {  83, -1, 0, "Z0",        "surface roughness length",                          "m"          },
59065   {  84, -1, 0, "ALB_RAD",   "surface albedo",                                    "1"          },
59066   {  85, -1, 0, "TSOIL",     "soil surface temperature",                          "K"          },
59067   {  86, -1, 0, "WSOIL",     "water content of 1. soil layer",                    "m"          },
59068   {  87, -1, 0, "PLCOV",     "vegetation area fraction",                          "1"          },
59069   {  90, -1, 0, "RUNOFF",    "subsurface runoff",                                 "kg m-2"     },
59070   {  91, -1, 0, "FR_ICE",    "sea ice area fraction",                             "1"          },
59071   {  92, -1, 0, "H_ICE",     "sea ice thickness",                                 "m"          },
59072   { 111, -1, 0, "ASOB",      "averaged surface net downward shortwave radiation", "W m-2"      },
59073   { 112, -1, 0, "ATHB",      "averaged surface net downward longwave radiation",  "W m-2"      },
59074   { 113, -1, 0, "ASOB",      "averaged TOA net downward shortwave radiation",     "W m-2"      },
59075   { 114, -1, 0, "ATHB",      "averaged TOA outgoing longwave radiation",          "W m-2"      },
59076   { 115, -1, 0, "ASWDIR",    "direct downward sw radiation at the surface",       "W m-2"      },
59077   { 116, -1, 0, "ASWDIFD",   "diffuse downward sw radiation at the surface",      "W m-2"      },
59078   { 117, -1, 0, "ASWDIFU",   "diffuse upwnward sw radiation at the surface",      "W m-2"      },
59079   { 118, -1, 0, "ALWD",      "downward lw radiation at the surface",              "W m-2"      },
59080   { 119, -1, 0, "ALWU",      "upward lw radiation at the surface",                "W m-2"      },
59081   { 121, -1, 0, "ALHFL",     "averaged surface latent heat flux",                 "W m-2"      },
59082   { 122, -1, 0, "ASHFL",     "averaged surface sensible heat flux",               "W m-2"      },
59083   { 124, -1, 0, "AUMFL",     "averaged eastward stress",                          "Pa"         },
59084   { 125, -1, 0, "AVMFL",     "averaged northward stress",                         "Pa"         },
59085   { 128, -1, 0, "SUNSH",     "undefined",                                         "undefined"  },
59086   { 129, -1, 0, "SUNSH2",    "undefined",                                         "undefined"  },
59087   { 130, -1, 0, "SUN_SUM",   "undefined",                                         "undefined"  },
59088   { 131, -1, 0, "SUN_SUM2",  "undefined",                                         "undefined"  },
59089   { 133, -1, 0, "FCOR",      "undefined",                                         "undefined"  },
59090   { 134, -1, 0, "SKYVIEW",   "sky-view factor",                                   "1"          },
59091   { 137, -1, 0, "SWDIR_COR", "topo correction of direct solar radiarion",         "1"          },
59092 };
59093 
59094 static const param_type cosmo201[] = {
59095   {   5, -1, 0, "APAB",      "&",                                                         "W m-2"      },
59096   {  13, -1, 0, "SOHR_RAD",  "&",                                                         "K s-1"      },
59097   {  14, -1, 0, "THHR_RAD",  "&",                                                         "K s-1"      },
59098   {  20, -1, 0, "DURSUN",    "duration of sunshine",                                      "s"          },
59099   {  29, -1, 0, "CLC",       "cloud area fraction",                                       "1"          },
59100   {  30, -1, 0, "CLC_SGS",   "grid scale cloud area fraction",                            "1"          },
59101   {  31, -1, 0, "QC",        "specific cloud liquid water content",                       "kg kg-1"    },
59102   {  33, -1, 0, "QI",        "specific cloud ice content",                                "kg kg-1"    },
59103   {  35, -1, 0, "QR",        "specific rain content",                                     "kg kg-1"    },
59104   {  36, -1, 0, "QS",        "specific snow content",                                     "kg kg-1"    },
59105   {  37, -1, 0, "TQR",       "total rain water content vertically integrated",            "kg m-2"     },
59106   {  38, -1, 0, "TQS",       "total snow content vertically integrated",                  "kg m-2"     },
59107   {  39, -1, 0, "QG",        "specific graupel content",                                  "kg kg-1"    },
59108   {  40, -1, 0, "TQG",       "total graupel content vertically integrated",               "kg m-2"     },
59109   {  41, -1, 0, "TWATER",    "cloud condensed water content",                             "kg m-2"     },
59110   {  42, -1, 0, "TDIV_HUM",  "atmosphere water divergence",                               "kg m-2"     },
59111   {  43, -1, 0, "QC_RAD",    "sub scale specific cloud liquid water content",             "kg kg-1"    },
59112   {  44, -1, 0, "QI_RAD",    "sub scale specific cloud ice content",                      "kg kg-1"    },
59113   {  61, -1, 0, "CLW_CON",   "convective cloud liquid water",                             "1"          },
59114   {  68, -1, 0, "HBAS_CON",  "height of convective cloud base",                           "m"          },
59115   {  69, -1, 0, "HTOP_CON",  "height of convective cloud top",                            "m"          },
59116   {  70, -1, 0, "HBAS_CONI", "height of convective cloud base",                           "m"          },
59117   {  71, -1, 0, "HTOP_CONI", "height of convective cloud top",                            "m"          },
59118   {  72, -1, 0, "BAS_CON",   "index of convective cloud base",                            "1"          },
59119   {  73, -1, 0, "TOP_CON",   "index of convective cloud top",                             "1"          },
59120   {  74, -1, 0, "DT_CON",    "convective tendency of temperature",                        "K s-1"      },
59121   {  75, -1, 0, "DQV_CON",   "convective tendency of specific humidity",                  "s-1"        },
59122   {  78, -1, 0, "DU_CON",    "convective tendency of u-wind component",                   "m s-2"      },
59123   {  79, -1, 0, "DV_CON",    "convective tendency of v-wind component",                   "m s-2"      },
59124   {  82, -1, 0, "HTOP_DC",   "height of dry convection top",                              "m"          },
59125   {  84, -1, 0, "HZEROCL",   "height of freezing level",                                  "m"          },
59126   {  85, -1, 0, "SNOWLMT",   "height of the snow fall limit in m above sea level",        "m"          },
59127   {  86, -1, 0, "HCBAS",     "height of cloud base",                                      "m"          },
59128   {  87, -1, 0, "HCTOP",     "height of cloud top",                                       "m"          },
59129   {  91, -1, 0, "C_T_LK",    "&",                                                         "1"          },
59130   {  92, -1, 0, "GAMSO_LK",  "&",                                                         "m-1"        },
59131   {  93, -1, 0, "DP_BS_LK",  "&",                                                         "m"          },
59132   {  94, -1, 0, "H_B1_LK",   "&",                                                         "m"          },
59133   {  95, -1, 0, "H_ML_LK",   "&",                                                         "m"          },
59134   {  96, -1, 0, "DEPTH_LK",  "lake depth",                                                "m"          },
59135   {  97, -1, 0, "FETCH_LK",  "wind fetch over lake",                                      "m"          },
59136   {  99, -1, 0, "QRS",       "precipitation water (water loading)",                       "1"          },
59137   { 100, -1, 0, "PRR_GSP",   "mass flux density of large scale rainfall",                 "kg m-2 s-1" },
59138   { 101, -1, 0, "PRS_GSP",   "mass flux density of large scale snowfall",                 "kg m-2 s-1" },
59139   { 102, -1, 0, "RAIN_GSP",  "large scale rainfall",                                      "kg m-2"     },
59140   { 111, -1, 0, "PRR_CON",   "mass flux density of convective rainfall",                  "kg m-2 s-1" },
59141   { 112, -1, 0, "PRS_CON",   "mass flux density of convective snowfall",                  "kg m-2 s-1" },
59142   { 113, -1, 0, "RAIN_CON",  "convective rainfall",                                       "kg m-2"     },
59143   { 129, -1, 0, "FRESHSNW",  "freshness of snow",                                         "undefined"  },
59144   { 131, -1, 0, "PRG_GSP",   "mass flux density of large scale graupel",                  "kg m-2 s-1" },
59145   { 132, -1, 0, "GRAU_GSP",  "large scale graupel",                                       "kg m-2"     },
59146   { 133, -1, 0, "RHO_SNOW",  "density of snow",                                           "kg m-3"     },
59147   { 139, -1, 0, "PP",        "deviation from reference pressure",                         "Pa"         },
59148   { 140, -1, 0, "RCLD",      "standard deviation of saturation deficit",                  "undefined"  },
59149   { 143, -1, 0, "CAPE_MU",   "cape of most unstable parcel",                              "J kg-1"     },
59150   { 144, -1, 0, "CIN_MU",    "convective inhibition of most unstable parcel",             "J kg-1"     },
59151   { 145, -1, 0, "CAPE_ML",   "cape of mean surface layer parcel",                         "J kg-1"     },
59152   { 146, -1, 0, "CIN_ML",    "convective inhibition of mean surface layer parcel",        "J kg-1"     },
59153   { 147, -1, 0, "TKE_CON",   "convective turbulent kinetic energy",                       "undefined"  },
59154   { 148, -1, 0, "TKETENS",   "tendency of turbulent kinetic energy",                      "undefined"  },
59155   { 152, -1, 0, "TKE",       "turbulent kinetic energy",                                  "m2 s-2"     },
59156   { 153, -1, 0, "TKVM",      "diffusion coefficient of momentum",                         "m2 s-1"     },
59157   { 154, -1, 0, "TKVH",      "diffusion coefficient of heat",                             "m2 s-1"     },
59158   { 170, -1, 0, "TCM",       "drag coefficient of momentum",                              "1"          },
59159   { 171, -1, 0, "TCH",       "drag coefficient of heat",                                  "1"          },
59160   { 187, -1, 0, "VMAX",      "maximum turbulent wind gust in 10m",                        "m s-1"      },
59161   { 190, -1, 0, "TSOIL",     "&",                                                         "K"          },
59162   { 191, -1, 0, "TSOIL",     "&",                                                         "K"          },
59163   { 192, -1, 0, "TSOIL",     "&",                                                         "K"          },
59164   { 193, -1, 0, "TSOIL",     "mixed layer temperature",                                   "K"          },
59165   { 194, -1, 0, "TSOIL",     "mean temperature of water column",                          "K"          },
59166   { 197, -1, 0, "TSOIL",     "soil temperature",                                          "K"          },
59167   { 198, -1, 0, "W_SO",      "soil water content",                                        "m"          },
59168   { 199, -1, 0, "W_SO_ICE",  "soil frozen water content",                                 "m"          },
59169   { 200, -1, 0, "W_I",       "canopy water amount",                                       "m"          },
59170   { 203, -1, 0, "TSOIL",     "snow surface temperature",                                  "K"          },
59171   { 215, -1, 0, "TSOIL",     "temperature of ice upper surface",                          "K"          },
59172   { 230, -1, 0, "dBZ",       "unattenuated radar reflectivity in Rayleigh approximation", "1"          },
59173   { 240, -1, 0, "MFLX_CON",  "convective mass flux density",                              "kg m-2 s-1" },
59174   { 241, -1, 0, "CAPE_CON",  "&",                                                         "J kg-1"     },
59175   { 243, -1, 0, "QCVG_CON",  "&",                                                         "s-1"        },
59176 };
59177 
59178 static const param_type cosmo202[] = {
59179   {  46, -1, 0, "SSO_STDH",  "standard deviation of subgrid scale height",                "m"         },
59180   {  47, -1, 0, "SSO_GAMMA", "anisotropy of topography",                                  "-"         },
59181   {  48, -1, 0, "SSO_THETA", "angle between principal axis of orography and global east", "-"         },
59182   {  49, -1, 0, "SSO_SIGMA", "mean slope of subgrid scale orography",                     "-"         },
59183   {  55, -1, 0, "FR_LAKE",   "fraction of inland lake water",                             "1"         },
59184   {  57, -1, 0, "SOILTYP",   "soil type",                                                 "1"         },
59185   {  61, -1, 0, "LAI",       "leaf area index",                                           "1"         },
59186   {  62, -1, 0, "ROOTDP",    "root depth",                                                "m"         },
59187   {  64, -1, 0, "HMO3",      "air pressure at ozone maximum",                             "Pa"        },
59188   {  65, -1, 0, "VIO3",      "vertical integrated ozone amount",                          "Pa"        },
59189   {  67, -1, 0, "PLCOV_MX",  "vegetation area fraction maximum",                          "1"         },
59190   {  68, -1, 0, "PLCOV_MN",  "vegetation area fraction minimum",                          "1"         },
59191   {  69, -1, 0, "LAI_MX",    "leaf area index maximum",                                   "1"         },
59192   {  70, -1, 0, "LAI_MN",    "leaf area index minimum",                                   "1"         },
59193   {  75, -1, 0, "FOR_E",     "ground fraction covered by evergreen forest",               "-"         },
59194   {  76, -1, 0, "FOR_D",     "ground fraction covered by deciduous forest",               "-"         },
59195   { 104, -1, 0, "DQVDT",     "tendency of water vapor",                                   "s-1"       },
59196   { 105, -1, 0, "QVSFLX",    "surface flux of water vapour",                              "s-1m-2"    },
59197   { 113, -1, 0, "FC",        "coriolis parameter",                                        "s-1"       },
59198   { 114, -1, 0, "RLAT",      "latitude",                                                  "radian"    },
59199   { 115, -1, 0, "RLON",      "longitude",                                                 "radian"    },
59200   { 121, -1, 0, "ZTD",       "integrated total atmospheric refractivity",                 "undefined" },
59201   { 122, -1, 0, "ZWD",       "integrated wet atmospheric refractivity",                   "undefined" },
59202   { 123, -1, 0, "ZHD",       "integrated dry atmospheric refractivity",                   "undefined" },
59203   { 180, -1, 0, "O3",        "ozone mass mixing ratio",                                   "kg kg-1"   },
59204   { 200, -1, 0, "I131a",     "undefined",                                                 "undefined" },
59205   { 201, -1, 0, "I131a_DD",  "undefined",                                                 "undefined" },
59206   { 202, -1, 0, "I131a_WD",  "undefined",                                                 "undefined" },
59207   { 203, -1, 0, "Cs137",     "undefined",                                                 "undefined" },
59208   { 204, -1, 0, "Cs137_DD",  "undefined",                                                 "undefined" },
59209   { 205, -1, 0, "Cs137_WD",  "undefined",                                                 "undefined" },
59210   { 206, -1, 0, "Te132",     "undefined",                                                 "undefined" },
59211   { 207, -1, 0, "Te132_DD",  "undefined",                                                 "undefined" },
59212   { 208, -1, 0, "Te132_WD",  "undefined",                                                 "undefined" },
59213   { 209, -1, 0, "Zr95",      "undefined",                                                 "undefined" },
59214   { 210, -1, 0, "Zr95_DD",   "undefined",                                                 "undefined" },
59215   { 211, -1, 0, "Zr95_WD",   "undefined",                                                 "undefined" },
59216   { 212, -1, 0, "Kr85",      "undefined",                                                 "undefined" },
59217   { 213, -1, 0, "Kr85_DD",   "undefined",                                                 "undefined" },
59218   { 214, -1, 0, "Kr85_WD",   "undefined",                                                 "undefined" },
59219   { 215, -1, 0, "TRACER",    "undefined",                                                 "undefined" },
59220   { 216, -1, 0, "TRACER_DD", "undefined",                                                 "undefined" },
59221   { 217, -1, 0, "TRACER_WD", "undefined",                                                 "undefined" },
59222   { 218, -1, 0, "Xe133",     "undefined",                                                 "undefined" },
59223   { 219, -1, 0, "Xe133_DD",  "undefined",                                                 "undefined" },
59224   { 220, -1, 0, "Xe133_WD",  "undefined",                                                 "undefined" },
59225   { 221, -1, 0, "I131g",     "undefined",                                                 "undefined" },
59226   { 222, -1, 0, "I131g_DD",  "undefined",                                                 "undefined" },
59227   { 223, -1, 0, "I131g_WD",  "undefined",                                                 "undefined" },
59228   { 224, -1, 0, "I131o",     "undefined",                                                 "undefined" },
59229   { 225, -1, 0, "I131o_DD",  "undefined",                                                 "undefined" },
59230   { 226, -1, 0, "I131o_WD",  "undefined",                                                 "undefined" },
59231   { 227, -1, 0, "Ba140",     "undefined",                                                 "undefined" },
59232   { 228, -1, 0, "Ba140_DD",  "undefined",                                                 "undefined" },
59233   { 229, -1, 0, "Ba140_WD",  "undefined",                                                 "undefined" },
59234   { 230, -1, 0, "Sr90",      "undefined",                                                 "undefined" },
59235   { 231, -1, 0, "Sr90_DD",   "undefined",                                                 "undefined" },
59236   { 232, -1, 0, "Sr90_WD",   "undefined",                                                 "undefined" },
59237   { 233, -1, 0, "Ru103",     "undefined",                                                 "undefined" },
59238   { 234, -1, 0, "Ru103_DD",  "undefined",                                                 "undefined" },
59239   { 235, -1, 0, "Ru103_WD",  "undefined",                                                 "undefined" },
59240 };
59241 
59242 static const param_type cosmo203[] = {
59243   { 135, -1, 0, "LCL_ML",   "undefined",                  "undefined" },
59244   { 136, -1, 0, "LFC_ML",   "undefined",                  "undefined" },
59245   { 137, -1, 0, "CAPE_3KM", "undefined",                  "undefined" },
59246   { 138, -1, 0, "SWISS00",  "swiss00 index",              "1"         },
59247   { 139, -1, 0, "SWISS12",  "swiss12 index",              "1"         },
59248   { 147, -1, 0, "SLI",      "surface lifted index",       "K"         },
59249   { 149, -1, 0, "SI",       "showalter index",            "K"         },
59250   { 155, -1, 0, "BRN",      "undefined",                  "undefined" },
59251   { 156, -1, 0, "HPBL",     "undefined",                  "undefined" },
59252   { 203, -1, 0, "CLDEPTH",  "normalized cloud depth",     "1"         },
59253   { 204, -1, 0, "CLCT_MOD", "modified_total_cloud_cover", "1"         },
59254 };
59255 
59256 static const param_type cosmo205[] = {
59257   {   1, -1, 0, "SYNME5", "synthetic satellite images Meteosat5", "-" },
59258   {   2, -1, 0, "SYNME6", "synthetic satellite images Meteosat6", "-" },
59259   {   3, -1, 0, "SYNME7", "synthetic satellite images Meteosat7", "-" },
59260   {   4, -1, 0, "SYNMSG", "synthetic satellite images MSG",       "-" },
59261 };
59262 
59263 static const param_type cosmo250[] = {
59264   {   1, -1, 0, "QNH",       "sea level air pressure",                                         "hPa"                                },
59265   {  11, -1, 0, "TSOIL",     "2m temperature",                                                 "K"                                  },
59266   {  12, -1, 0, "TSOIL",     "2m temperature",                                                 "K"                                  },
59267   {  13, -1, 0, "D_T_2M_K",  "kalman correction to 2m temperature",                            "K"                                  },
59268   {  14, -1, 0, "TSOIL",     "2m temperature",                                                 "K"                                  },
59269   {  15, -1, 0, "TSOIL",     "2m temperature",                                                 "K"                                  },
59270   {  16, -1, 0, "RH_ICE",    "relative humidity over ice",                                     "%"                                  },
59271   {  17, -1, 0, "TD",        "dew point temperature",                                          "K"                                  },
59272   {  18, -1, 0, "D_TD",      "dew point depression",                                           "K"                                  },
59273   {  19, -1, 0, "THETAE",    "equivalent potential temperature",                               "K"                                  },
59274   {  20, -1, 0, "TD_2M_K",   "2m dew point temperature",                                       "K"                                  },
59275   {  21, -1, 0, "D_TD_2M_K", "kalman correction to 2m dew point temperature",                  "K"                                  },
59276   {  22, -1, 0, "TD_2M_OLD", "2m dew point temperature",                                       "K"                                  },
59277   {  23, -1, 0, "TD_2M_BUZ", "2m dew point temperature",                                       "K"                                  },
59278   {  24, -1, 0, "HI",        "heat index",                                                     "Fahrenheit"                         },
59279   {  25, -1, 0, "DURSUN_M",  "maximum duration of sunshine",                                   "s"                                  },
59280   {  26, -1, 0, "DURSUN_R",  "relative duration of sunshine",                                  "%"                                  },
59281   {  52, -1, 0, "RH_2M_K",   "2m relative humidity",                                           "%"                                  },
59282   {  53, -1, 0, "D_RH_2M_K", "kalman correction to 2m relative humidity",                      "%"                                  },
59283   {  58, -1, 0, "CLI_RATIO", "cloud ice ratio (Qi/Qc+Qi)",                                     "%"                                  },
59284   {  61, -1, 0, "TOT_SNOW",  "total precipitation in snow",                                    "kg/m**2"                            },
59285   {  62, -1, 0, "TOT_RAIN",  "total precipitation in rain",                                    "kg/m**2"                            },
59286   {  63, -1, 0, "TOT_CON",   "total convective precipitation",                                 "kg/m**2"                            },
59287   {  64, -1, 0, "TOT_GSP",   "total large scale precipitation",                                "kg/m**2"                            },
59288   {  65, -1, 0, "SNOW_%",    "percentage of precipitation in snow",                            "%"                                  },
59289   {  66, -1, 0, "CONV_%",    "percentage of convective precipitation",                         "%"                                  },
59290   {  67, -1, 0, "VORTP_ABS", "absolute",                                                       "VORTP_ABS 67 -1 absolute vorticity" },
59291   {  68, -1, 0, "VORTP_REL", "relative",                                                       "VORTP_REL 68 -1 relative vorticity" },
59292   {  70, -1, 0, "PDIFF_CON", "pressure difference between cloud base and cloud top",           "Pa"                                 },
59293   {  71, -1, 0, "TTOP_CON",  "temperature at cloud top",                                       "K"                                  },
59294   {  80, -1, 0, "GEM",       "emissivity of the ground",                                       "%"                                  },
59295   {  82, -1, 0, "Z0LOC",     "local surface roughness length",                                 "m"                                  },
59296   { 110, -1, 0, "LUM",       "luminosity",                                                     "klux"                               },
59297   { 111, -1, 0, "GLOB",      "global shortwave radiation at surface",                          "W/m**2"                             },
59298   { 112, -1, 0, "LW_IN_TG",  "incoming longwave radiation at surface",                         "W/m**2"                             },
59299   { 113, -1, 0, "LW_IN_TS",  "incoming longwave radiation at surface",                         "W/m**2"                             },
59300   { 114, -1, 0, "LW_IN_T2M", "incoming longwave radiation at surface",                         "W/m**2"                             },
59301   { 115, -1, 0, "SWISS_WE",  "Swiss",                                                          "SWISS_WE 115 1 Swiss coordinates"   },
59302   { 116, -1, 0, "SWISS_SN",  "Swiss",                                                          "SWISS_SN 116 1 Swiss coordinates"   },
59303   { 150, -1, 0, "KOINDEX",   "KO index",                                                       "K"                                  },
59304   { 151, -1, 0, "TTINDEX",   "total-totals index",                                             "K"                                  },
59305   { 152, -1, 0, "DCI",       "deep convection index",                                          "K"                                  },
59306   { 153, -1, 0, "SWEAT",     "severe weather thread index",                                    "undefined"                          },
59307   { 154, -1, 0, "ADEDO2",    "adedokun 2 index",                                               "K"                                  },
59308   { 160, -1, 0, "C_TSTORM",  "thunderstorm index using AdaBoost classifier",                   "undefined"                          },
59309   { 161, -1, 0, "CN_TSTORM", "thunderstorm probabilty using AdaBoost classifier",              "%"                                  },
59310   { 200, -1, 0, "WSHEARL",   "wind shear between surface and 3 km asl",                        "1/s"                                },
59311   { 201, -1, 0, "WSHEARM",   "wind shear between surface and 6 km asl",                        "1/s"                                },
59312   { 202, -1, 0, "WSHEARU",   "wind shear between 3 km (or surface) and 6 km asl",              "1/s"                                },
59313   { 211, -1, 0, "VWIN",      "maximum OLD turbulent wind gust in 10m",                         "m s-1"                              },
59314   { 212, -1, 0, "VW10M_20",  "maximum 10m wind speed",                                         "m s-1"                              },
59315   { 213, -1, 0, "VW10M_25",  "duration of VWIN_10M above 25 knots",                            "s"                                  },
59316   { 214, -1, 0, "VW10M_30",  "duration of VWIN_10M above 30 knots",                            "s"                                  },
59317   { 215, -1, 0, "VW10M_35",  "duration of VWIN_10M above 35 knots",                            "s"                                  },
59318   { 216, -1, 0, "VW10M_40",  "duration of VWIN_10M above 40 knots",                            "s"                                  },
59319   { 217, -1, 0, "VW10M_45",  "duration of VWIN_10M above 45 knots",                            "s"                                  },
59320   { 218, -1, 0, "VW10M_50",  "duration of VWIN_10M above 50 knots",                            "s"                                  },
59321   { 219, -1, 0, "VOLD",      "maximum turbulent wind gust in 10m",                             "m s-1"                              },
59322   { 220, -1, 0, "VJPS",      "maximum turbulent wind gust in 10m",                             "m s-1"                              },
59323   { 221, -1, 0, "VBRA",      "maximum Brasseur turbulent wind gust in 10m",                    "m s-1"                              },
59324   { 222, -1, 0, "VB10M_20",  "duration of VBRA_10M above 20 knots",                            "s"                                  },
59325   { 223, -1, 0, "VB10M_25",  "duration of VBRA_10M above 25 knots",                            "s"                                  },
59326   { 224, -1, 0, "VB10M_30",  "duration of VBRA_10M above 30 knots",                            "s"                                  },
59327   { 225, -1, 0, "VB10M_35",  "duration of VBRA_10M above 35 knots",                            "s"                                  },
59328   { 226, -1, 0, "VB10M_40",  "duration of VBRA_10M above 40 knots",                            "s"                                  },
59329   { 227, -1, 0, "VB10M_45",  "duration of VBRA_10M above 45 knots",                            "s"                                  },
59330   { 228, -1, 0, "VB10M_50",  "duration of VBRA_10M above 50 knots",                            "s"                                  },
59331   { 231, -1, 0, "VCON",      "maximum convective wind gust in 10m",                            "m s-1"                              },
59332   { 232, -1, 0, "VC10M_20",  "duration of VCON_10M above 20 knots",                            "s"                                  },
59333   { 233, -1, 0, "VC10M_25",  "duration of VCON_10M above 25 knots",                            "s"                                  },
59334   { 234, -1, 0, "VC10M_30",  "duration of VCON_10M above 30 knots",                            "s"                                  },
59335   { 235, -1, 0, "VC10M_35",  "duration of VCON_10M above 35 knots",                            "s"                                  },
59336   { 236, -1, 0, "VC10M_40",  "duration of VCON_10M above 40 knots",                            "s"                                  },
59337   { 237, -1, 0, "VC10M_45",  "duration of VCON_10M above 45 knots",                            "s"                                  },
59338   { 238, -1, 0, "VC10M_50",  "duration of VCON_10M above 50 knots",                            "s"                                  },
59339   { 241, -1, 0, "FMAX",      "maximum wind speed at k=ke",                                     "m s-1"                              },
59340   { 242, -1, 0, "USTARMAX",  "maximal u*=SQRT(Drag_coef)*fmax_10m",                            "m s-1"                              },
59341   { 243, -1, 0, "GLOB_DIF",  "global diffuse shortwave radiation at the surface",              "W/m**2"                             },
59342   { 244, -1, 0, "GLOB_DIR",  "global direct (beam) shortwave radiation at the surface",        "W/m**2"                             },
59343   { 245, -1, 0, "GLOB_vE",   "global shortwave radiation on a vertical surface facing east",   "W/m**2"                             },
59344   { 246, -1, 0, "GLOB_vS",   "global shortwave radiation on a vertical surface facing south",  "W/m**2"                             },
59345   { 247, -1, 0, "GLOB_vW",   "global shortwave radiation on a vertical surface facing west",   "W/m**2"                             },
59346   { 248, -1, 0, "GLOB_vN",   "global shortwave radiation on a vertical surface facing north",  "W/m**2"                             },
59347   { 249, -1, 0, "LW_TG_vS",  "incoming longwave radiation on a vertical surface facing south", "W/m**2"                             },
59348   { 250, -1, 0, "ENTH",      "enthalpy",                                                       "kJ/kg"                              },
59349   { 251, -1, 0, "ENTH",      "enthalpy",                                                       "kJ/kg"                              },
59350   { 252, -1, 0, "MIXRAT",    "mixing ratio",                                                   "g/kg"                               },
59351   { 253, -1, 0, "MIXRAT",    "mixing ratio",                                                   "g/kg"                               },
59352   { 254, -1, 0, "TW",        "wet bulb temperature",                                           "degC"                               },
59353   { 255, -1, 0, "TW",        "wet bulb temperature",                                           "degC"                               },
59354 };
59355 
59356 
59357 static
tableDefault(void)59358 void tableDefault(void)
59359 {
59360 
59361   // define table : echam4
59362   {
59363     int instID  = institutInq(98, 255, "MPIMET", NULL);
59364     if ( instID == -1 )
59365       instID  = institutDef(98, 255, "MPIMET", NULL);
59366 
59367     int modelID = modelInq(instID, 0, "ECHAM4");
59368     if ( modelID == -1 )
59369       modelID = modelDef(instID, 0, "ECHAM4");
59370 
59371     int tableID = tableDef(modelID, 128, "echam4");
59372 
59373     tableLink(tableID, echam4, sizeof(echam4) / sizeof(param_type));
59374   }
59375 
59376   // define table : echam5
59377   {
59378     int instID  = institutInq(98, 232, "MPIMET", NULL);
59379     if ( instID == -1 )
59380       instID  = institutDef(98, 232, "MPIMET", NULL);
59381 
59382     int modelID = modelInq(instID, 0, "ECHAM5");
59383     if ( modelID == -1 )
59384       modelID = modelDef(instID, 0, "ECHAM5");
59385 
59386     int tableID = tableDef(modelID, 128, "echam5");
59387 
59388     tableLink(tableID, echam5, sizeof(echam5) / sizeof(param_type));
59389   }
59390 
59391   // define table : echam6
59392   {
59393     int instID  = institutInq(0, 0, "MPIMET", NULL);
59394     if ( instID == -1 )
59395       instID  = institutDef(0, 0, "MPIMET", NULL);
59396 
59397     int modelID = modelInq(instID, 0, "ECHAM6");
59398     if ( modelID == -1 )
59399       modelID = modelDef(instID, 0, "ECHAM6");
59400 
59401     int tableID = tableDef(modelID, 128, "echam6");
59402 
59403     tableLink(tableID, echam6, sizeof(echam6) / sizeof(param_type));
59404   }
59405 
59406   // define table : mpiom1
59407   {
59408     int instID  = institutInq(0, 0, "MPIMET", NULL);
59409     if ( instID == -1 )
59410       instID  = institutDef(0, 0, "MPIMET", NULL);
59411 
59412     int modelID = modelInq(instID, 0, "MPIOM1");
59413     if ( modelID == -1 )
59414       modelID = modelDef(instID, 0, "MPIOM1");
59415 
59416     int tableID = tableDef(modelID, 128, "mpiom1");
59417 
59418     tableLink(tableID, mpiom1, sizeof(mpiom1) / sizeof(param_type));
59419   }
59420 
59421   // define table : ecmwf
59422   {
59423     int instID  = institutInq(0, 0, "ECMWF", NULL);
59424     if ( instID == -1 )
59425       instID  = institutDef(0, 0, "ECMWF", NULL);
59426 
59427     int modelID = modelInq(instID, 0, "");
59428     if ( modelID == -1 )
59429       modelID = modelDef(instID, 0, "");
59430 
59431     int tableID = tableDef(modelID, 128, "ecmwf");
59432 
59433     tableLink(tableID, ecmwf, sizeof(ecmwf) / sizeof(param_type));
59434   }
59435 
59436   // define table : remo
59437   {
59438     int instID  = institutInq(0, 0, "MPIMET", NULL);
59439     if ( instID == -1 )
59440       instID  = institutDef(0, 0, "MPIMET", NULL);
59441 
59442     int modelID = modelInq(instID, 0, "REMO");
59443     if ( modelID == -1 )
59444       modelID = modelDef(instID, 0, "REMO");
59445 
59446     int tableID = tableDef(modelID, 128, "remo");
59447 
59448     tableLink(tableID, remo, sizeof(remo) / sizeof(param_type));
59449   }
59450 
59451   // define table : cosmo002
59452   {
59453     int instID  = institutInq(0, 0, "MCH", NULL);
59454     if ( instID == -1 )
59455       instID  = institutDef(0, 0, "MCH", NULL);
59456 
59457     int modelID = modelInq(instID, 0, "COSMO");
59458     if ( modelID == -1 )
59459       modelID = modelDef(instID, 0, "COSMO");
59460 
59461     int tableID = tableDef(modelID, 002, "cosmo002");
59462 
59463     tableLink(tableID, cosmo002, sizeof(cosmo002) / sizeof(param_type));
59464   }
59465 
59466   // define table : cosmo201
59467   {
59468     int instID  = institutInq(0, 0, "MCH", NULL);
59469     if ( instID == -1 )
59470       instID  = institutDef(0, 0, "MCH", NULL);
59471 
59472     int modelID = modelInq(instID, 0, "COSMO");
59473     if ( modelID == -1 )
59474       modelID = modelDef(instID, 0, "COSMO");
59475 
59476     int tableID = tableDef(modelID, 201, "cosmo201");
59477 
59478     tableLink(tableID, cosmo201, sizeof(cosmo201) / sizeof(param_type));
59479   }
59480 
59481   // define table : cosmo202
59482   {
59483     int instID  = institutInq(0, 0, "MCH", NULL);
59484     if ( instID == -1 )
59485       instID  = institutDef(0, 0, "MCH", NULL);
59486 
59487     int modelID = modelInq(instID, 0, "COSMO");
59488     if ( modelID == -1 )
59489       modelID = modelDef(instID, 0, "COSMO");
59490 
59491     int tableID = tableDef(modelID, 202, "cosmo202");
59492 
59493     tableLink(tableID, cosmo202, sizeof(cosmo202) / sizeof(param_type));
59494   }
59495 
59496   // define table : cosmo203
59497   {
59498     int instID  = institutInq(0, 0, "MCH", NULL);
59499     if ( instID == -1 )
59500       instID  = institutDef(0, 0, "MCH", NULL);
59501 
59502     int modelID = modelInq(instID, 0, "COSMO");
59503     if ( modelID == -1 )
59504       modelID = modelDef(instID, 0, "COSMO");
59505 
59506     int tableID = tableDef(modelID, 203, "cosmo203");
59507 
59508     tableLink(tableID, cosmo203, sizeof(cosmo203) / sizeof(param_type));
59509   }
59510 
59511   // define table : cosmo205
59512   {
59513     int instID  = institutInq(0, 0, "MCH", NULL);
59514     if ( instID == -1 )
59515       instID  = institutDef(0, 0, "MCH", NULL);
59516 
59517     int modelID = modelInq(instID, 0, "COSMO");
59518     if ( modelID == -1 )
59519       modelID = modelDef(instID, 0, "COSMO");
59520 
59521     int tableID = tableDef(modelID, 205, "cosmo205");
59522 
59523     tableLink(tableID, cosmo205, sizeof(cosmo205) / sizeof(param_type));
59524   }
59525 
59526   // define table : cosmo250
59527   {
59528     int instID  = institutInq(0, 0, "MCH", NULL);
59529     if ( instID == -1 )
59530       instID  = institutDef(0, 0, "MCH", NULL);
59531 
59532     int modelID = modelInq(instID, 0, "COSMO");
59533     if ( modelID == -1 )
59534       modelID = modelDef(instID, 0, "COSMO");
59535 
59536     int tableID = tableDef(modelID, 250, "cosmo250");
59537 
59538     tableLink(tableID, cosmo250, sizeof(cosmo250) / sizeof(param_type));
59539   }
59540 }
59541 
59542 #endif  /* TABLE_H */
59543 #include <stddef.h>
59544 #include <string.h>
59545 #include <ctype.h>
59546 
59547 
59548 
59549 
59550 #define MAX_TABLE  256
59551 #define MAX_PARS   1024
59552 
59553 typedef struct
59554 {
59555   bool   used;
59556   int    npars;
59557   int    modelID;
59558   int    number;
59559   char  *name;
59560   param_type *pars;
59561 }
59562 paramtab_type;
59563 
59564 static paramtab_type parTable[MAX_TABLE];
59565 static int  parTableSize = MAX_TABLE;
59566 static int  parTableNum  = 0;
59567 static int  ParTableInit = 0;
59568 
59569 static char *tablePath = NULL;
59570 
59571 static void tableDefModelID(int tableID, int modelID);
59572 static void tableDefNum(int tableID, int tablenum);
59573 
59574 static
tableDefEntry(int tableID,int id,int ltype,const char * name,const char * longname,const char * units)59575 void tableDefEntry(int tableID, int id, int ltype, const char *name,
59576 		   const char *longname, const char *units)
59577 {
59578   if ( tableID >= 0 && tableID < MAX_TABLE && parTable[tableID].used) { } else
59579     Error("Invalid table ID %d", tableID);
59580 
59581   int item = parTable[tableID].npars++;
59582   parTable[tableID].pars[item].id       = id;
59583   parTable[tableID].pars[item].ltype    = ltype;
59584   parTable[tableID].pars[item].dupflags = 0;
59585   parTable[tableID].pars[item].name     = NULL;
59586   parTable[tableID].pars[item].longname = NULL;
59587   parTable[tableID].pars[item].units    = NULL;
59588 
59589   if ( name && name[0] )
59590     {
59591       parTable[tableID].pars[item].name     = strdupx(name);
59592       parTable[tableID].pars[item].dupflags |= TABLE_DUP_NAME;
59593     }
59594   if ( longname && longname[0] )
59595     {
59596       parTable[tableID].pars[item].longname = strdupx(longname);
59597       parTable[tableID].pars[item].dupflags |= TABLE_DUP_LONGNAME;
59598     }
59599   if ( units && units[0] )
59600     {
59601       parTable[tableID].pars[item].units    = strdupx(units);
59602       parTable[tableID].pars[item].dupflags |= TABLE_DUP_UNITS;
59603     }
59604 }
59605 
tableLink(int tableID,const param_type * pars,int npars)59606 void tableLink(int tableID, const param_type *pars, int npars)
59607 {
59608   for ( int item = 0; item < npars; item++ )
59609     {
59610       parTable[tableID].pars[item].id       = pars[item].id;
59611       parTable[tableID].pars[item].ltype    = pars[item].ltype;
59612       parTable[tableID].pars[item].dupflags = 0;
59613       parTable[tableID].pars[item].name     = pars[item].name;
59614       parTable[tableID].pars[item].longname = pars[item].longname;
59615       parTable[tableID].pars[item].units    = pars[item].units;
59616     }
59617 
59618   parTable[tableID].npars = npars;
59619 }
59620 
parTableInitEntry(int tableID)59621 static void parTableInitEntry(int tableID)
59622 {
59623   parTable[tableID].used    = false;
59624   parTable[tableID].pars    = NULL;
59625   parTable[tableID].npars   = 0;
59626   parTable[tableID].modelID = CDI_UNDEFID;
59627   parTable[tableID].number  = CDI_UNDEFID;
59628   parTable[tableID].name    = NULL;
59629 }
59630 
tableGetPath(void)59631 static void tableGetPath(void)
59632 {
59633   char *path = getenv("TABLEPATH");
59634   if ( path ) tablePath = strdupx(path);
59635   // printf("tablePath = %s\n", tablePath);
59636 }
59637 
parTableFinalize(void)59638 static void parTableFinalize(void)
59639 {
59640   for (int tableID = 0; tableID < MAX_TABLE; ++tableID)
59641     if (parTable[tableID].used)
59642       {
59643         int npars = parTable[tableID].npars;
59644         for (int item = 0; item < npars; ++item)
59645           {
59646             if (parTable[tableID].pars[item].dupflags & TABLE_DUP_NAME)
59647               Free((void *)parTable[tableID].pars[item].name);
59648             if (parTable[tableID].pars[item].dupflags & TABLE_DUP_LONGNAME)
59649               Free((void *)parTable[tableID].pars[item].longname);
59650             if (parTable[tableID].pars[item].dupflags & TABLE_DUP_UNITS)
59651               Free((void *)parTable[tableID].pars[item].units);
59652           }
59653         Free(parTable[tableID].pars);
59654         Free(parTable[tableID].name);
59655       }
59656 }
59657 
parTableInit(void)59658 static void parTableInit(void)
59659 {
59660   ParTableInit = 1;
59661 
59662   atexit(parTableFinalize);
59663   if ( cdiPartabIntern ) tableDefault();
59664 
59665   tableGetPath();
59666 }
59667 
tableNewEntry()59668 static int tableNewEntry()
59669 {
59670   int tableID = 0;
59671 
59672   static int init = 0;
59673   if ( ! init )
59674     {
59675       for ( tableID = 0; tableID < parTableSize; tableID++ )
59676 	parTableInitEntry(tableID);
59677       init = 1;
59678     }
59679 
59680   // Look for a free slot in parTable.
59681   for ( tableID = 0; tableID < parTableSize; tableID++ )
59682     {
59683       if ( ! parTable[tableID].used ) break;
59684     }
59685 
59686   if ( tableID == parTableSize ) Error("no more entries!");
59687 
59688   parTable[tableID].used = true;
59689   parTableNum++;
59690 
59691   return tableID;
59692 }
59693 
59694 static int
decodeForm1(char * pline,char * name,char * longname,char * units)59695 decodeForm1(char *pline, char *name, char *longname, char *units)
59696 {
59697   char *pstart, *pend;
59698 
59699   /* FIXME: parse success isn't verified */
59700   /* long level =  */strtol(pline, &pline, 10);
59701   while ( isspace((int) *pline) ) pline++;
59702 
59703   pstart = pline;
59704   while ( ! (isspace((int) *pline) || *pline == 0) ) pline++;
59705   size_t len = (size_t)(pline - pstart);
59706   if ( len > 0 )
59707     {
59708       memcpy(name, pstart, len);
59709       name[len] = 0;
59710     }
59711   else
59712     return 0;
59713 
59714   if ( pline[0] == 0 ) return 0;
59715 
59716   /* Format 1 : code name add mult longname [units] */
59717   /* FIXME: successful parse isn't verified */
59718   /* double add  =  */strtod(pline, &pline);
59719   /* FIXME: successful parse isn't verified */
59720   /* double mult =  */strtod(pline, &pline);
59721 
59722   while ( isspace((int) *pline) ) pline++;
59723 
59724   len = strlen(pline);
59725   if ( len > 0 )
59726     {
59727       pstart = pline;
59728       pend = strrchr(pline, '[');
59729       if ( pend == pstart )
59730         len = 0;
59731       else
59732         {
59733           if ( pend )
59734             pend--;
59735           else
59736             pend = pstart + len;
59737           while ( isspace((int) *pend) ) pend--;
59738           len = (size_t)(pend - pstart + 1);
59739         }
59740       if ( len > 0 )
59741 	{
59742 	  memcpy(longname, pstart, len);
59743 	  longname[len] = 0;
59744 	}
59745       pstart = strrchr(pline, '[');
59746       if ( pstart )
59747 	{
59748 	  pstart++;
59749 	  while ( isspace((int) *pstart) ) pstart++;
59750 	  pend = strchr(pstart, ']');
59751 	  if ( ! pend ) return 0;
59752 	  pend--;
59753 	  while ( isspace((int) *pend) ) pend--;
59754 	  len = (size_t)(pend - pstart + 1);
59755 	  if ( len > 0 )
59756 	    {
59757 	      memcpy(units, pstart, len);
59758 	      units[len] = 0;
59759 	    }
59760 	}
59761     }
59762 
59763   return 0;
59764 }
59765 
59766 static int
decodeForm2(char * pline,char * name,char * longname,char * units)59767 decodeForm2(char *pline, char *name, char *longname, char *units)
59768 {
59769   // Format 2 : code | name | longname | units
59770   char *pend;
59771 
59772   pline = strchr(pline, '|');
59773   pline++;
59774 
59775   while ( isspace((int) *pline) ) pline++;
59776   if (*pline != '|')
59777     {
59778       pend = strchr(pline, '|');
59779       if ( ! pend )
59780         {
59781           pend = pline;
59782           while ( ! isspace((int) *pend) ) pend++;
59783           size_t len = (size_t)(pend - pline);
59784           if ( len > 0 )
59785             {
59786               memcpy(name, pline, len);
59787               name[len] = 0;
59788             }
59789           return 0;
59790         }
59791       else
59792         {
59793           pend--;
59794           while ( isspace((int) *pend) ) pend--;
59795           size_t len = (size_t)(pend - pline + 1);
59796           if ( len > 0 )
59797             {
59798               memcpy(name, pline, len);
59799               name[len] = 0;
59800             }
59801         }
59802     }
59803   else
59804     name[0] = '\0';
59805 
59806   pline = strchr(pline, '|');
59807   pline++;
59808   while ( isspace((int) *pline) ) pline++;
59809   pend = strchr(pline, '|');
59810   if ( !pend ) pend = strchr(pline, 0);
59811   pend--;
59812   while ( isspace((int) *pend) ) pend--;
59813   {
59814     size_t len = (size_t)(pend - pline + 1);
59815     if ( len > 0 )
59816       {
59817         memcpy(longname, pline, len);
59818         longname[len] = 0;
59819       }
59820   }
59821 
59822   pline = strchr(pline, '|');
59823   if ( pline )
59824     {
59825       pline++;
59826       while ( isspace((int) *pline) ) pline++;
59827       pend = strchr(pline, '|');
59828       if ( !pend ) pend = strchr(pline, 0);
59829       pend--;
59830       while ( isspace((int) *pend) ) pend--;
59831       ptrdiff_t len = pend - pline + 1;
59832       if ( len < 0 ) len = 0;
59833       memcpy(units, pline, (size_t)len);
59834       units[len] = 0;
59835     }
59836 
59837   return 0;
59838 }
59839 
59840 
tableRead(const char * tablefile)59841 int tableRead(const char *tablefile)
59842 {
59843   char line[1024], *pline;
59844   int lnr = 0;
59845   char name[256], longname[256], units[256];
59846   int err;
59847   int tableID = CDI_UNDEFID;
59848 
59849   FILE *tablefp = fopen(tablefile, "r");
59850   if ( tablefp == NULL ) return tableID;
59851 
59852   char *tablename = strrchr(tablefile, '/');
59853   if ( tablename == 0 ) tablename = (char *) tablefile;
59854   else                  tablename++;
59855 
59856   tableID = tableDef(-1, 0, tablename);
59857 
59858   while ( fgets(line, 1023, tablefp) )
59859     {
59860       size_t len = strlen(line);
59861       if ( line[len-1] == '\n' ) line[len-1] = '\0';
59862       lnr++;
59863       int id      = CDI_UNDEFID;
59864       int ltype   = CDI_UNDEFID;
59865       name[0]     = 0;
59866       longname[0] = 0;
59867       units[0]    = 0;
59868       if ( line[0] == '#' ) continue;
59869       pline = line;
59870 
59871       len = strlen(pline);
59872       if ( len < 4 ) continue;
59873       while ( isspace((int) *pline) ) pline++;
59874       id = atoi(pline);
59875       // if ( id > 255 ) id -= 256;
59876       if ( id == 0 ) continue;
59877 
59878       while ( isdigit((int) *pline) ) pline++;
59879 
59880       if ( *pline == ';' || *pline == ':' )
59881         {
59882           pline++;
59883           ltype = atoi(pline);
59884           while ( isdigit((int) *pline) ) pline++;
59885 
59886           if ( *pline == ';' || *pline == ':' )
59887             {
59888               pline++;
59889               while ( isdigit((int) *pline) ) pline++;
59890             }
59891         }
59892 
59893       while ( isdigit((int) *pline) ) pline++;
59894 
59895       if ( strchr(pline, '|') )
59896 	err = decodeForm2(pline, name, longname, units);
59897       else
59898 	err = decodeForm1(pline, name, longname, units);
59899 
59900       if ( err ) continue;
59901 
59902       if ( name[0] == 0 ) sprintf(name, "var%d", id);
59903 
59904       tableDefEntry(tableID, id, ltype, name, longname, units);
59905     }
59906 
59907   return tableID;
59908 }
59909 
59910 
tableFromEnv(int modelID,int tablenum)59911 static int tableFromEnv(int modelID, int tablenum)
59912 {
59913   char tablename[256] = {'\0'};
59914   size_t tablenameLen = 0;
59915   int instID;
59916 
59917   const char *name2Use;
59918   {
59919     const char *modelName, *instName;
59920     if ( (modelName = modelInqNamePtr(modelID)) )
59921       name2Use = modelName;
59922     else if ( (instID = modelInqInstitut(modelID)) != CDI_UNDEFID
59923               && (instName = institutInqNamePtr(instID)) )
59924       name2Use = instName;
59925     else
59926       return CDI_UNDEFID;
59927   }
59928   tablenameLen = strlen(name2Use);
59929   memcpy(tablename, name2Use, tablenameLen);
59930   if ( tablenum )
59931     tablenameLen
59932       += (size_t)(sprintf(tablename+tablenameLen, "_%03d", tablenum));
59933   size_t lenp = 0, lenf = tablenameLen;
59934   if ( tablePath )
59935     lenp = strlen(tablePath);
59936   /* if (tablePath) printf("tablePath = %s\n", tablePath); */
59937   /* if (tablename) printf("tableName = %s\n", tablename); */
59938   char *tablefile = (char *) Malloc(lenp+lenf+3);
59939   if ( tablePath )
59940     {
59941       strcpy(tablefile, tablePath);
59942       strcat(tablefile, "/");
59943     }
59944   else
59945     tablefile[0] = '\0';
59946   strcat(tablefile, tablename);
59947   /* if (tablefile) printf("tableFile = %s\n", tablefile); */
59948 
59949   int tableID = tableRead(tablefile);
59950   if ( tableID != CDI_UNDEFID )
59951     {
59952       tableDefModelID(tableID, modelID);
59953       tableDefNum(tableID, tablenum);
59954     }
59955   /* printf("tableID = %d %s\n", tableID, tablefile); */
59956   Free(tablefile);
59957 
59958   return tableID;
59959 }
59960 
tableInq(int modelID,int tablenum,const char * tablename)59961 int tableInq(int modelID, int tablenum, const char *tablename)
59962 {
59963   int tableID = CDI_UNDEFID;
59964   int modelID2 = CDI_UNDEFID;
59965   char tablefile[256] = {'\0'};
59966 
59967   if ( ! ParTableInit ) parTableInit();
59968 
59969   if ( tablename )
59970     {
59971       strcpy(tablefile, tablename);
59972       /*
59973       printf("tableInq: tablefile = >%s<\n", tablefile);
59974       */
59975       /* search for internal table */
59976       for ( tableID = 0; tableID < MAX_TABLE; tableID++ )
59977 	{
59978 	  if ( parTable[tableID].used && parTable[tableID].name )
59979 	    {
59980 	      /* len = strlen(parTable[tableID].name); */
59981 	      size_t len = strlen(tablename);
59982 	      if ( memcmp(parTable[tableID].name, tablename, len) == 0 ) break;
59983 	    }
59984 	}
59985       if ( tableID == MAX_TABLE ) tableID = CDI_UNDEFID;
59986       if ( CDI_Debug )
59987 	Message("tableID = %d tablename = %s", tableID, tablename);
59988     }
59989   else
59990     {
59991       for ( tableID = 0; tableID < MAX_TABLE; tableID++ )
59992 	{
59993 	  if ( parTable[tableID].used )
59994 	    {
59995 	      if ( parTable[tableID].modelID == modelID &&
59996 		   parTable[tableID].number  == tablenum ) break;
59997 	    }
59998 	}
59999 
60000       if ( tableID == MAX_TABLE ) tableID = CDI_UNDEFID;
60001 
60002       if ( tableID == CDI_UNDEFID )
60003 	{
60004 	  if ( modelID != CDI_UNDEFID )
60005 	    {
60006               const char *modelName;
60007 	      if ( (modelName = modelInqNamePtr(modelID)) )
60008 		{
60009 		  strcpy(tablefile, modelName);
60010 		  size_t len = strlen(tablefile);
60011 		  for ( size_t i = 0; i < len; i++)
60012 		    if ( tablefile[i] == '.' ) tablefile[i] = '\0';
60013 		  modelID2 = modelInq(-1, 0, tablefile);
60014 		}
60015 	    }
60016 	  if ( modelID2 != CDI_UNDEFID )
60017 	    for ( tableID = 0; tableID < MAX_TABLE; tableID++ )
60018 	      {
60019 		if ( parTable[tableID].used )
60020 		  {
60021 		    if ( parTable[tableID].modelID == modelID2 &&
60022 			 parTable[tableID].number  == tablenum ) break;
60023 		  }
60024 	      }
60025 	}
60026 
60027       if ( tableID == MAX_TABLE ) tableID = CDI_UNDEFID;
60028 
60029       if ( tableID == CDI_UNDEFID && modelID != CDI_UNDEFID )
60030 	tableID = tableFromEnv(modelID, tablenum);
60031 
60032       if ( CDI_Debug )
60033 	if ( tablename )
60034 	  Message("tableID = %d tablename = %s", tableID, tablename);
60035     }
60036 
60037   return tableID;
60038 }
60039 
tableDef(int modelID,int tablenum,const char * tablename)60040 int tableDef(int modelID, int tablenum, const char *tablename)
60041 {
60042   int tableID = CDI_UNDEFID;
60043 
60044   if ( ! ParTableInit ) parTableInit();
60045   /*
60046   if ( ! (modelID == CDI_UNDEFID && tablenum == 0) )
60047     tableID = tableInq(modelID, tablenum, tablename);
60048     */
60049   if ( tableID == CDI_UNDEFID )
60050     {
60051       tableID = tableNewEntry();
60052 
60053       parTable[tableID].modelID = modelID;
60054       parTable[tableID].number  = tablenum;
60055       if ( tablename )
60056 	parTable[tableID].name = strdupx(tablename);
60057 
60058       parTable[tableID].pars = (param_type *) Malloc(MAX_PARS * sizeof(param_type));
60059     }
60060 
60061   return tableID;
60062 }
60063 
60064 static
tableDefModelID(int tableID,int modelID)60065 void tableDefModelID(int tableID, int modelID)
60066 {
60067   parTable[tableID].modelID = modelID;
60068 }
60069 
60070 static
tableDefNum(int tableID,int tablenum)60071 void tableDefNum(int tableID, int tablenum)
60072 {
60073   parTable[tableID].number  = tablenum;
60074 }
60075 
60076 
tableInqNum(int tableID)60077 int tableInqNum(int tableID)
60078 {
60079   int number = 0;
60080 
60081   if ( tableID >= 0 && tableID < MAX_TABLE )
60082     number = parTable[tableID].number;
60083 
60084   return number;
60085 }
60086 
60087 
tableInqModel(int tableID)60088 int tableInqModel(int tableID)
60089 {
60090   int modelID = -1;
60091 
60092   if ( tableID >= 0 && tableID < MAX_TABLE )
60093     modelID = parTable[tableID].modelID;
60094 
60095   return modelID;
60096 }
60097 
60098 
partabCheckID(int item)60099 static void partabCheckID(int item)
60100 {
60101   if ( item < 0 || item >= parTableSize ) Error("item %d undefined!", item);
60102 
60103   if ( ! parTable[item].name ) Error("item %d name undefined!", item);
60104 }
60105 
60106 
tableInqNamePtr(int tableID)60107 const char *tableInqNamePtr(int tableID)
60108 {
60109   const char *tablename = NULL;
60110 
60111   if ( CDI_Debug ) Message("tableID = %d", tableID);
60112 
60113   if ( ! ParTableInit ) parTableInit();
60114 
60115   if ( tableID >= 0 && tableID < parTableSize )
60116     if ( parTable[tableID].name )
60117       tablename = parTable[tableID].name;
60118 
60119   return tablename;
60120 }
60121 
60122 
tableWrite(const char * ptfile,int tableID)60123 void tableWrite(const char *ptfile, int tableID)
60124 {
60125   size_t maxname = 4, maxlname = 10, maxunits = 2;
60126   int instID = CDI_UNDEFID;
60127   int center = 0, subcenter = 0;
60128   const char *instnameptr = NULL, *modelnameptr = NULL;
60129 
60130   if ( CDI_Debug )
60131     Message("write parameter table %d to %s", tableID, ptfile);
60132 
60133   if ( tableID == CDI_UNDEFID )
60134     {
60135       Warning("parameter table ID undefined");
60136       return;
60137     }
60138 
60139   partabCheckID(tableID);
60140 
60141   FILE *ptfp = fopen(ptfile, "w");
60142 
60143   int npars = parTable[tableID].npars;
60144 
60145   for ( int item = 0; item < npars; item++)
60146     {
60147       if ( parTable[tableID].pars[item].name )
60148 	{
60149 	  size_t lenname = strlen(parTable[tableID].pars[item].name);
60150 	  if ( lenname  > maxname )  maxname  = lenname;
60151 	}
60152 
60153       if ( parTable[tableID].pars[item].longname )
60154 	{
60155 	  size_t lenlname = strlen(parTable[tableID].pars[item].longname);
60156 	  if ( lenlname > maxlname ) maxlname = lenlname;
60157 	}
60158 
60159       if ( parTable[tableID].pars[item].units )
60160 	{
60161 	  size_t lenunits = strlen(parTable[tableID].pars[item].units);
60162 	  if ( lenunits > maxunits ) maxunits = lenunits;
60163 	}
60164     }
60165 
60166   int tablenum = tableInqNum(tableID);
60167   int modelID = parTable[tableID].modelID;
60168   if ( modelID != CDI_UNDEFID )
60169     {
60170       modelnameptr = modelInqNamePtr(modelID);
60171       instID = modelInqInstitut(modelID);
60172     }
60173   if ( instID != CDI_UNDEFID )
60174     {
60175       center = institutInqCenter(instID);
60176       subcenter = institutInqSubcenter(instID);
60177       instnameptr = institutInqNamePtr(instID);
60178     }
60179 
60180   fprintf(ptfp, "# Parameter table\n");
60181   fprintf(ptfp, "#\n");
60182   if ( tablenum )
60183     fprintf(ptfp, "# TABLE_ID=%d\n", tablenum);
60184   fprintf(ptfp, "# TABLE_NAME=%s\n", parTable[tableID].name);
60185   if ( modelnameptr )
60186     fprintf(ptfp, "# TABLE_MODEL=%s\n", modelnameptr);
60187   if ( instnameptr )
60188     fprintf(ptfp, "# TABLE_INSTITUT=%s\n", instnameptr);
60189   if ( center )
60190     fprintf(ptfp, "# TABLE_CENTER=%d\n", center);
60191   if ( subcenter )
60192     fprintf(ptfp, "# TABLE_SUBCENTER=%d\n", subcenter);
60193   fprintf(ptfp, "#\n");
60194   fprintf(ptfp, "#\n");
60195   fprintf(ptfp, "# id       = parameter ID\n");
60196   fprintf(ptfp, "# name     = variable name\n");
60197   fprintf(ptfp, "# title    = long name (description)\n");
60198   fprintf(ptfp, "# units    = variable units\n");
60199   fprintf(ptfp, "#\n");
60200   fprintf(ptfp, "# The format of each record is:\n");
60201   fprintf(ptfp, "#\n");
60202   fprintf(ptfp, "# id | %-*s | %-*s | %-*s\n",
60203 	  (int)maxname,  "name",
60204 	  (int)maxlname, "title",
60205 	  (int)maxunits, "units");
60206 
60207   for ( int item = 0; item < npars; item++)
60208     {
60209       const char *name = parTable[tableID].pars[item].name,
60210         *longname = parTable[tableID].pars[item].longname,
60211         *units = parTable[tableID].pars[item].units;
60212       if ( name == NULL ) name = " ";
60213       if ( longname == NULL ) longname = " ";
60214       if ( units == NULL ) units = " ";
60215       fprintf(ptfp, "%4d | %-*s | %-*s | %-*s\n",
60216 	      parTable[tableID].pars[item].id,
60217 	      (int)maxname, name,
60218 	      (int)maxlname, longname,
60219 	      (int)maxunits, units);
60220     }
60221 
60222   fclose(ptfp);
60223 }
60224 
60225 
tableFWriteC(FILE * ptfp,int tableID)60226 void tableFWriteC(FILE *ptfp, int tableID)
60227 {
60228   const char chelp[] = "";
60229   size_t maxname = 0, maxlname = 0, maxunits = 0;
60230   char tablename[256];
60231 
60232 
60233   if ( tableID == CDI_UNDEFID )
60234     {
60235       Warning("parameter table ID undefined");
60236       return;
60237     }
60238 
60239   partabCheckID(tableID);
60240 
60241   int npars = parTable[tableID].npars;
60242 
60243   for ( int item = 0; item < npars; item++)
60244     {
60245       if ( parTable[tableID].pars[item].name )
60246 	{
60247 	  size_t lenname = strlen(parTable[tableID].pars[item].name);
60248 	  if ( lenname  > maxname )  maxname  = lenname;
60249 	}
60250 
60251       if ( parTable[tableID].pars[item].longname )
60252 	{
60253 	  size_t lenlname = strlen(parTable[tableID].pars[item].longname);
60254 	  if ( lenlname > maxlname ) maxlname = lenlname;
60255 	}
60256 
60257       if ( parTable[tableID].pars[item].units )
60258 	{
60259 	  size_t lenunits = strlen(parTable[tableID].pars[item].units);
60260 	  if ( lenunits > maxunits ) maxunits = lenunits;
60261 	}
60262     }
60263 
60264   strncpy(tablename, parTable[tableID].name, sizeof (tablename));
60265   tablename[sizeof (tablename) - 1] = '\0';
60266   {
60267     size_t len = strlen(tablename);
60268     for (size_t i = 0; i < len; i++ )
60269       if ( tablename[i] == '.' ) tablename[i] = '_';
60270   }
60271   fprintf(ptfp, "static const param_type %s[] = {\n", tablename);
60272 
60273   for ( int item = 0; item < npars; item++ )
60274     {
60275       size_t len = strlen(parTable[tableID].pars[item].name),
60276         llen = parTable[tableID].pars[item].longname
60277         ? strlen(parTable[tableID].pars[item].longname) : 0,
60278         ulen = parTable[tableID].pars[item].units
60279         ? strlen(parTable[tableID].pars[item].units) : 0;
60280       fprintf(ptfp, "  {%4d, -1, 0, \"%s\", %-*s%c%s%s, %-*s%c%s%s %-*s},\n",
60281 	      parTable[tableID].pars[item].id,
60282 	      parTable[tableID].pars[item].name, (int)(maxname-len), chelp,
60283               llen?'"':' ',
60284               llen?parTable[tableID].pars[item].longname:"NULL",
60285               llen?"\"":"",
60286               (int)(maxlname-(llen?llen:3)), chelp,
60287               ulen?'"':' ',
60288               ulen?parTable[tableID].pars[item].units:"NULL",
60289               ulen?"\"":"",
60290               (int)(maxunits-(ulen?ulen:3)), chelp);
60291     }
60292 
60293   fprintf(ptfp, "};\n\n");
60294 }
60295 
60296 
tableInqEntry(int tableID,int id,int ltype,char * name,char * longname,char * units)60297 void tableInqEntry(int tableID, int id, int ltype, char *name, char *longname, char *units)
60298 {
60299   if ( ((tableID >= 0) & (tableID < MAX_TABLE)) | (tableID == CDI_UNDEFID) ) { } else
60300     Error("Invalid table ID %d", tableID);
60301 
60302   if ( tableID != CDI_UNDEFID )
60303     {
60304       int npars = parTable[tableID].npars;
60305       for ( int item = 0; item < npars; item++ )
60306 	{
60307 	  if ( parTable[tableID].pars[item].id == id &&
60308                (parTable[tableID].pars[item].ltype == -1 || ltype == -1 ||
60309                 parTable[tableID].pars[item].ltype == ltype) )
60310 	    {
60311 	      if ( name && parTable[tableID].pars[item].name )
60312 		strcpy(name, parTable[tableID].pars[item].name);
60313 	      if ( longname && parTable[tableID].pars[item].longname )
60314 		strcpy(longname, parTable[tableID].pars[item].longname);
60315 	      if ( units && parTable[tableID].pars[item].units )
60316 		strcpy(units, parTable[tableID].pars[item].units);
60317 
60318 	      break;
60319 	    }
60320 	}
60321     }
60322 }
60323 
60324 
tableInqParCode(int tableID,char * varname,int * code)60325 int tableInqParCode(int tableID, char *varname, int *code)
60326 {
60327   int err = 1;
60328 
60329   if ( tableID != CDI_UNDEFID && varname != NULL )
60330     {
60331       int npars = parTable[tableID].npars;
60332       for ( int item = 0; item < npars; item++ )
60333 	{
60334 	  if ( parTable[tableID].pars[item].name
60335                && strcmp(parTable[tableID].pars[item].name, varname) == 0 )
60336             {
60337               *code = parTable[tableID].pars[item].id;
60338               err = 0;
60339               break;
60340             }
60341 	}
60342     }
60343 
60344   return err;
60345 }
60346 
60347 
tableInqNumber(void)60348 int tableInqNumber(void)
60349 {
60350   if ( ! ParTableInit ) parTableInit();
60351 
60352   return parTableNum;
60353 }
60354 /*
60355  * Local Variables:
60356  * c-file-style: "Java"
60357  * c-basic-offset: 2
60358  * indent-tabs-mode: nil
60359  * show-trailing-whitespace: t
60360  * require-trailing-newline: t
60361  * End:
60362  */
60363 #include <stddef.h>
60364 
60365 
60366 
60367 static int DefaultTimeType = TAXIS_ABSOLUTE;
60368 static int DefaultTimeUnit = TUNIT_HOUR;
60369 
60370 
60371 static const char *Timeunits[] = {
60372   "undefined",
60373   "seconds",
60374   "minutes",
60375   "quarters",
60376   "30minutes",
60377   "hours",
60378   "3hours",
60379   "6hours",
60380   "12hours",
60381   "days",
60382   "months",
60383   "years",
60384 };
60385 
60386 
60387 static int    taxisCompareP    ( void * taxisptr1, void * taxisptr2 );
60388 static void   taxisDestroyP    ( void * taxisptr );
60389 static void   taxisPrintKernel(taxis_t *taxisptr, FILE * fp);
60390 static int    taxisGetPackSize ( void * taxisptr, void *context );
60391 static void   taxisPack        ( void * taxisptr, void *buf, int size,
60392 				 int *position, void *context );
60393 static int    taxisTxCode      ( void );
60394 
60395 const resOps taxisOps = {
60396   taxisCompareP,
60397   taxisDestroyP,
60398   (void (*)(void *, FILE *))taxisPrintKernel,
60399   taxisGetPackSize,
60400   taxisPack,
60401   taxisTxCode
60402 };
60403 
60404 #define container_of(ptr, type, member) \
60405   ((type *)(void*)((unsigned char *)ptr - offsetof(type,member)))
60406 
60407 struct refcount_string
60408 {
60409   int ref_count;
60410   char string[];
60411 };
60412 
60413 static char *
new_refcount_string(size_t len)60414 new_refcount_string(size_t len)
60415 {
60416   struct refcount_string *container
60417     = (struct refcount_string *) Malloc(sizeof (*container) + len + 1);
60418   container->ref_count = 1;
60419   return container->string;
60420 }
60421 
60422 static void
delete_refcount_string(void * p)60423 delete_refcount_string(void *p)
60424 {
60425   if (p)
60426     {
60427       struct refcount_string *container
60428         = container_of(p, struct refcount_string, string);
60429       if (!--(container->ref_count))
60430         Free(container);
60431     }
60432 }
60433 
60434 static char *
dup_refcount_string(char * p)60435 dup_refcount_string(char *p)
60436 {
60437   if (p)
60438     {
60439       struct refcount_string *container
60440         = container_of(p, struct refcount_string, string);
60441       ++(container->ref_count);
60442     }
60443   return p;
60444 }
60445 
60446 
60447 #undef container_of
60448 
60449 static int  TAXIS_Debug = 0;   /* If set to 1, debugging */
60450 
60451 
tunitNamePtr(int unitID)60452 const char *tunitNamePtr(int unitID)
60453 {
60454   int size = sizeof(Timeunits)/sizeof(*Timeunits);
60455   return (unitID > 0 && unitID < size) ? Timeunits[unitID] : Timeunits[0];
60456 }
60457 
60458 static
taxisDefaultValue(taxis_t * taxisptr)60459 void taxisDefaultValue(taxis_t* taxisptr)
60460 {
60461   taxisptr->self        = CDI_UNDEFID;
60462   taxisptr->used        = false;
60463   taxisptr->datatype    = CDI_DATATYPE_FLT64;
60464   taxisptr->type        = DefaultTimeType;
60465   taxisptr->sdate       = 0;
60466   taxisptr->stime       = 0;
60467   taxisptr->vdate       = 0;
60468   taxisptr->vtime       = 0;
60469   taxisptr->rdate       = CDI_UNDEFID;
60470   taxisptr->rtime       = 0;
60471   taxisptr->fdate       = CDI_UNDEFID;
60472   taxisptr->ftime       = 0;
60473   taxisptr->calendar    = CDI_Default_Calendar;
60474   taxisptr->unit        = DefaultTimeUnit;
60475   taxisptr->numavg      = 0;
60476   taxisptr->climatology = false;
60477   taxisptr->has_bounds  = false;
60478   taxisptr->vdate_lb    = 0;
60479   taxisptr->vtime_lb    = 0;
60480   taxisptr->vdate_ub    = 0;
60481   taxisptr->vtime_ub    = 0;
60482   taxisptr->fc_unit     = DefaultTimeUnit;
60483   taxisptr->fc_period   = 0;
60484   taxisptr->name        = NULL;
60485   taxisptr->longname    = NULL;
60486   taxisptr->units       = NULL;
60487 }
60488 
60489 static taxis_t *
taxisNewEntry(cdiResH resH)60490 taxisNewEntry(cdiResH resH)
60491 {
60492   taxis_t *taxisptr = (taxis_t*) Malloc(sizeof(taxis_t));
60493 
60494   taxisDefaultValue(taxisptr);
60495   if (resH == CDI_UNDEFID)
60496     taxisptr->self = reshPut(taxisptr, &taxisOps);
60497   else
60498     {
60499       taxisptr->self = resH;
60500       reshReplace(resH, taxisptr, &taxisOps);
60501     }
60502 
60503   return taxisptr;
60504 }
60505 
60506 static
taxisInit(void)60507 void taxisInit(void)
60508 {
60509   static bool taxisInitialized = false;
60510 
60511   if ( taxisInitialized ) return;
60512 
60513   taxisInitialized = true;
60514 
60515   char *env = getenv("TAXIS_DEBUG");
60516   if ( env ) TAXIS_Debug = atoi(env);
60517 }
60518 
60519 /*
60520 @Function  taxisCreate
60521 @Title     Create a Time axis
60522 
60523 @Prototype int taxisCreate(int taxistype)
60524 @Parameter
60525     @Item  taxistype  The type of the Time axis, one of the set of predefined CDI time axis types.
60526                       The valid CDI time axis types are @func{TAXIS_ABSOLUTE} and @func{TAXIS_RELATIVE}.
60527 
60528 @Description
60529 The function @func{taxisCreate} creates a Time axis.
60530 
60531 @Result
60532 @func{taxisCreate} returns an identifier to the Time axis.
60533 
60534 @Example
60535 Here is an example using @func{taxisCreate} to create a relative T-axis with a standard calendar.
60536 
60537 @Source
60538    ...
60539 int taxisID;
60540    ...
60541 taxisID = taxisCreate(TAXIS_RELATIVE);
60542 taxisDefCalendar(taxisID, CALENDAR_STANDARD);
60543 taxisDefRdate(taxisID, 19850101);
60544 taxisDefRtime(taxisID, 120000);
60545    ...
60546 @EndSource
60547 @EndFunction
60548 */
taxisCreate(int taxistype)60549 int taxisCreate(int taxistype)
60550 {
60551   if ( CDI_Debug ) Message("taxistype: %d", taxistype);
60552 
60553   taxisInit ();
60554 
60555   taxis_t *taxisptr = taxisNewEntry(CDI_UNDEFID);
60556   taxisptr->type = taxistype;
60557 
60558   int taxisID = taxisptr->self;
60559 
60560   if ( CDI_Debug ) Message("taxisID: %d", taxisID);
60561 
60562   return taxisID;
60563 }
60564 
60565 
taxisDestroyKernel(taxis_t * taxisptr)60566 void taxisDestroyKernel(taxis_t *taxisptr)
60567 {
60568   delete_refcount_string(taxisptr->name);
60569   delete_refcount_string(taxisptr->longname);
60570   delete_refcount_string(taxisptr->units);
60571 }
60572 
60573 /*
60574 @Function  taxisDestroy
60575 @Title     Destroy a Time axis
60576 
60577 @Prototype void taxisDestroy(int taxisID)
60578 @Parameter
60579     @Item  taxisID  Time axis ID, from a previous call to @func{taxisCreate}
60580 
60581 @EndFunction
60582 */
taxisDestroy(int taxisID)60583 void taxisDestroy(int taxisID)
60584 {
60585   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
60586   reshRemove(taxisID, &taxisOps);
60587   taxisDestroyKernel(taxisptr);
60588   Free(taxisptr);
60589 }
60590 
60591 
taxisDestroyP(void * taxisptr)60592 void taxisDestroyP( void * taxisptr )
60593 {
60594   taxisDestroyKernel((taxis_t *)taxisptr);
60595   Free(taxisptr);
60596 }
60597 
60598 
taxisDuplicate(int taxisID1)60599 int taxisDuplicate(int taxisID1)
60600 {
60601   taxis_t *taxisptr1 = (taxis_t *)reshGetVal(taxisID1, &taxisOps);
60602   taxis_t *taxisptr2 = taxisNewEntry(CDI_UNDEFID);
60603 
60604   int taxisID2 = taxisptr2->self;
60605 
60606   if ( CDI_Debug ) Message("taxisID2: %d", taxisID2);
60607 
60608   ptaxisCopy(taxisptr2, taxisptr1);
60609 
60610   return taxisID2;
60611 }
60612 
60613 
taxisDefType(int taxisID,int taxistype)60614 void taxisDefType(int taxisID, int taxistype)
60615 {
60616   taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
60617 
60618   if ( taxisptr->type != taxistype )
60619     {
60620       taxisptr->type = taxistype;
60621       taxisptr->datatype = CDI_DATATYPE_FLT64;
60622       if ( taxisptr->units )
60623         {
60624           delete_refcount_string(taxisptr->units);
60625           taxisptr->units = NULL;
60626         }
60627       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60628     }
60629 }
60630 
60631 /*
60632 @Function  taxisDefVdate
60633 @Title     Define the verification date
60634 
60635 @Prototype void taxisDefVdate(int taxisID, int64_t vdate)
60636 @Parameter
60637     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate}
60638     @Item  vdate    Verification date (YYYYMMDD)
60639 
60640 @Description
60641 The function @func{taxisDefVdate} defines the verification date of a Time axis.
60642 
60643 @EndFunction
60644 */
taxisDefVdate(int taxisID,int64_t vdate)60645 void taxisDefVdate(int taxisID, int64_t vdate)
60646 {
60647   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
60648 
60649   if (taxisptr->vdate != vdate)
60650     {
60651       taxisptr->vdate = vdate;
60652       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60653     }
60654 }
60655 
60656 /*
60657 @Function  taxisDefVtime
60658 @Title     Define the verification time
60659 
60660 @Prototype void taxisDefVtime(int taxisID, int vtime)
60661 @Parameter
60662     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate}
60663     @Item  vtime    Verification time (hhmmss)
60664 
60665 @Description
60666 The function @func{taxisDefVtime} defines the verification time of a Time axis.
60667 
60668 @EndFunction
60669 */
taxisDefVtime(int taxisID,int vtime)60670 void taxisDefVtime(int taxisID, int vtime)
60671 {
60672   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
60673 
60674   if (taxisptr->vtime != vtime)
60675     {
60676       taxisptr->vtime = vtime;
60677       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60678     }
60679 }
60680 
60681 /*
60682 @Function  taxisDefRdate
60683 @Title     Define the reference date
60684 
60685 @Prototype void taxisDefRdate(int taxisID, int64_t rdate)
60686 @Parameter
60687     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate}
60688     @Item  rdate    Reference date (YYYYMMDD)
60689 
60690 @Description
60691 The function @func{taxisDefRdate} defines the reference date of a Time axis.
60692 
60693 @EndFunction
60694 */
taxisDefRdate(int taxisID,int64_t rdate)60695 void taxisDefRdate(int taxisID, int64_t rdate)
60696 {
60697   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
60698 
60699   if (taxisptr->rdate != rdate)
60700     {
60701       taxisptr->rdate = rdate;
60702 
60703       if ( taxisptr->units )
60704         {
60705           delete_refcount_string(taxisptr->units);
60706           taxisptr->units = NULL;
60707         }
60708       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60709     }
60710 }
60711 
60712 /*
60713 @Function  taxisDefRtime
60714 @Title     Define the reference time
60715 
60716 @Prototype void taxisDefRtime(int taxisID, int rtime)
60717 @Parameter
60718     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate}
60719     @Item  rtime    Reference time (hhmmss)
60720 
60721 @Description
60722 The function @func{taxisDefRtime} defines the reference time of a Time axis.
60723 
60724 @EndFunction
60725 */
taxisDefRtime(int taxisID,int rtime)60726 void taxisDefRtime(int taxisID, int rtime)
60727 {
60728   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
60729 
60730   if (taxisptr->rtime != rtime)
60731     {
60732       taxisptr->rtime = rtime;
60733       if ( taxisptr->units )
60734         {
60735           delete_refcount_string(taxisptr->units);
60736           taxisptr->units = NULL;
60737         }
60738       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60739     }
60740 }
60741 
60742 /*
60743 @Function  taxisDefFdate
60744 @Title     Define the forecast reference date
60745 
60746 @Prototype void taxisDefFdate(int taxisID, int64_t fdate)
60747 @Parameter
60748     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate}
60749     @Item  fdate    Forecast reference date (YYYYMMDD)
60750 
60751 @Description
60752 The function @func{taxisDefFdate} defines the forecast reference date of a Time axis.
60753 
60754 @EndFunction
60755 */
taxisDefFdate(int taxisID,int64_t fdate)60756 void taxisDefFdate(int taxisID, int64_t fdate)
60757 {
60758   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
60759 
60760   if (taxisptr->fdate != fdate)
60761     {
60762       taxisptr->fdate = fdate;
60763       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60764     }
60765 }
60766 
60767 /*
60768 @Function  taxisDefFtime
60769 @Title     Define the forecast reference time
60770 
60771 @Prototype void taxisDefFtime(int taxisID, int ftime)
60772 @Parameter
60773     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate}
60774     @Item  ftime    Forecast reference time (hhmmss)
60775 
60776 @Description
60777 The function @func{taxisDefFtime} defines the forecast reference time of a Time axis.
60778 
60779 @EndFunction
60780 */
taxisDefFtime(int taxisID,int ftime)60781 void taxisDefFtime(int taxisID, int ftime)
60782 {
60783   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
60784 
60785   if (taxisptr->ftime != ftime)
60786     {
60787       taxisptr->ftime = ftime;
60788       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60789     }
60790 }
60791 
60792 /*
60793 @Function  taxisDefCalendar
60794 @Title     Define the calendar
60795 
60796 @Prototype void taxisDefCalendar(int taxisID, int calendar)
60797 @Parameter
60798     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate}
60799     @Item  calendar The type of the calendar, one of the set of predefined CDI calendar types.
60800                     The valid CDI calendar types are @func{CALENDAR_STANDARD}, @func{CALENDAR_PROLEPTIC},
60801                     @func{CALENDAR_360DAYS}, @func{CALENDAR_365DAYS} and @func{CALENDAR_366DAYS}.
60802 
60803 @Description
60804 The function @func{taxisDefCalendar} defines the calendar of a Time axis.
60805 
60806 @EndFunction
60807 */
taxisDefCalendar(int taxisID,int calendar)60808 void taxisDefCalendar(int taxisID, int calendar)
60809 {
60810   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
60811 
60812   if (taxisptr->calendar != calendar)
60813     {
60814       taxisptr->calendar = calendar;
60815       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60816     }
60817 }
60818 
60819 
taxisDefTunit(int taxisID,int unit)60820 void taxisDefTunit(int taxisID, int unit)
60821 {
60822   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
60823 
60824   if (taxisptr->unit != unit)
60825     {
60826       taxisptr->unit = unit;
60827       if ( taxisptr->units )
60828         {
60829           delete_refcount_string(taxisptr->units);
60830           taxisptr->units = NULL;
60831         }
60832       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60833     }
60834 }
60835 
60836 
taxisDefForecastTunit(int taxisID,int unit)60837 void taxisDefForecastTunit(int taxisID, int unit)
60838 {
60839   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
60840 
60841   if (taxisptr->fc_unit != unit)
60842     {
60843       taxisptr->fc_unit = unit;
60844       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60845     }
60846 }
60847 
60848 
taxisDefForecastPeriod(int taxisID,double fc_period)60849 void taxisDefForecastPeriod(int taxisID, double fc_period)
60850 {
60851   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
60852 
60853   if ( IS_NOT_EQUAL(taxisptr->fc_period, fc_period) )
60854     {
60855       taxisptr->fc_period = fc_period;
60856       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60857     }
60858 }
60859 
60860 
taxisDefNumavg(int taxisID,int numavg)60861 void taxisDefNumavg(int taxisID, int numavg)
60862 {
60863   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
60864 
60865   if (taxisptr->numavg != numavg)
60866     {
60867       taxisptr->numavg = numavg;
60868       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60869     }
60870 }
60871 
60872 /*
60873 The type of the time axis, one of the set of predefined CDI time types.
60874 The valid CDI time types are TAXIS_ABSOLUTE and TAXIS_RELATIVE.
60875 */
taxisInqType(int taxisID)60876 int taxisInqType(int taxisID)
60877 {
60878   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
60879   return taxisptr->type;
60880 }
60881 
60882 
taxisHasBounds(int taxisID)60883 int taxisHasBounds(int taxisID)
60884 {
60885   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
60886   return taxisptr->has_bounds;
60887 }
60888 
60889 
taxisWithBounds(int taxisID)60890 void taxisWithBounds(int taxisID)
60891 {
60892   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
60893 
60894   if ( taxisptr->has_bounds == false )
60895     {
60896       taxisptr->has_bounds = true;
60897       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60898     }
60899 }
60900 
60901 
taxisDeleteBounds(int taxisID)60902 void taxisDeleteBounds(int taxisID)
60903 {
60904   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
60905 
60906   if ( taxisptr->has_bounds )
60907     {
60908       taxisptr->has_bounds = false;
60909       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
60910     }
60911 }
60912 
60913 
taxisCopyTimestep(int taxisID2,int taxisID1)60914 void taxisCopyTimestep(int taxisID2, int taxisID1)
60915 {
60916   taxis_t *taxisptr1 = (taxis_t *)reshGetVal(taxisID1, &taxisOps),
60917           *taxisptr2 = (taxis_t *)reshGetVal(taxisID2, &taxisOps);
60918 
60919   reshLock();
60920 
60921   /* reference date/time and units can't be changed after streamDefVlist().
60922   if (taxisptr2->units && taxisptr2->rdate != CDI_UNDEFID)
60923     {
60924       if (taxisptr2->rdate != taxisptr1->rdate || taxisptr2->rtime != taxisptr1->rtime)
60925         {
60926           delete_refcount_string(taxisptr2->units);
60927           taxisptr2->units = NULL;
60928         }
60929     }
60930 
60931   taxisptr2->rdate = taxisptr1->rdate;
60932   taxisptr2->rtime = taxisptr1->rtime;
60933   */
60934 
60935   taxisptr2->sdate = taxisptr1->sdate;
60936   taxisptr2->stime = taxisptr1->stime;
60937 
60938   taxisptr2->vdate = taxisptr1->vdate;
60939   taxisptr2->vtime = taxisptr1->vtime;
60940 
60941   if ( taxisptr2->has_bounds )
60942     {
60943       taxisptr2->vdate_lb = taxisptr1->vdate_lb;
60944       taxisptr2->vtime_lb = taxisptr1->vtime_lb;
60945       taxisptr2->vdate_ub = taxisptr1->vdate_ub;
60946       taxisptr2->vtime_ub = taxisptr1->vtime_ub;
60947     }
60948 
60949   taxisptr2->fdate = taxisptr1->fdate;
60950   taxisptr2->ftime = taxisptr1->ftime;
60951 
60952   taxisptr2->fc_unit   = taxisptr1->fc_unit;
60953   taxisptr2->fc_period = taxisptr1->fc_period;
60954 
60955   reshSetStatus(taxisID2, &taxisOps, RESH_DESYNC_IN_USE);
60956   reshUnlock();
60957 }
60958 
60959 /*
60960 @Function  taxisInqVdate
60961 @Title     Get the verification date
60962 
60963 @Prototype int64_t taxisInqVdate(int taxisID)
60964 @Parameter
60965     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate} or @fref{vlistInqTaxis}
60966 
60967 @Description
60968 The function @func{taxisInqVdate} returns the verification date of a Time axis.
60969 
60970 @Result
60971 @func{taxisInqVdate} returns the verification date.
60972 
60973 @EndFunction
60974 */
taxisInqVdate(int taxisID)60975 int64_t taxisInqVdate(int taxisID)
60976 {
60977   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
60978   return taxisptr->vdate;
60979 }
60980 
60981 
taxisInqSdate(int taxisID)60982 int64_t taxisInqSdate(int taxisID)
60983 {
60984   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
60985   return taxisptr->sdate;
60986 }
60987 
60988 
taxisInqVdateBounds(int taxisID,int64_t * vdate_lb,int64_t * vdate_ub)60989 void taxisInqVdateBounds(int taxisID, int64_t *vdate_lb, int64_t *vdate_ub)
60990 {
60991   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
60992 
60993   *vdate_lb = taxisptr->vdate_lb;
60994   *vdate_ub = taxisptr->vdate_ub;
60995 }
60996 
60997 
taxisDefVdateBounds(int taxisID,int64_t vdate_lb,int64_t vdate_ub)60998 void taxisDefVdateBounds(int taxisID, int64_t vdate_lb, int64_t vdate_ub)
60999 {
61000   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
61001 
61002   if ( taxisptr->vdate_lb != vdate_lb
61003        || taxisptr->vdate_ub != vdate_ub
61004        || taxisptr->has_bounds == false )
61005     {
61006       taxisptr->vdate_lb = vdate_lb;
61007       taxisptr->vdate_ub = vdate_ub;
61008       taxisptr->has_bounds = true;
61009       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
61010     }
61011 }
61012 
61013 /*
61014 @Function  taxisInqVtime
61015 @Title     Get the verification time
61016 
61017 @Prototype int taxisInqVtime(int taxisID)
61018 @Parameter
61019     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate} or @fref{vlistInqTaxis}
61020 
61021 @Description
61022 The function @func{taxisInqVtime} returns the verification time of a Time axis.
61023 
61024 @Result
61025 @func{taxisInqVtime} returns the verification time.
61026 
61027 @EndFunction
61028 */
taxisInqVtime(int taxisID)61029 int taxisInqVtime(int taxisID)
61030 {
61031   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
61032   return taxisptr->vtime;
61033 }
61034 
61035 
taxisInqStime(int taxisID)61036 int taxisInqStime(int taxisID)
61037 {
61038   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
61039   return taxisptr->stime;
61040 }
61041 
61042 
taxisInqVtimeBounds(int taxisID,int * vtime_lb,int * vtime_ub)61043 void taxisInqVtimeBounds(int taxisID, int *vtime_lb, int *vtime_ub)
61044 {
61045   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
61046 
61047   *vtime_lb = taxisptr->vtime_lb;
61048   *vtime_ub = taxisptr->vtime_ub;
61049 }
61050 
61051 
taxisDefVtimeBounds(int taxisID,int vtime_lb,int vtime_ub)61052 void taxisDefVtimeBounds(int taxisID, int vtime_lb, int vtime_ub)
61053 {
61054   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
61055 
61056   if ( taxisptr->vtime_lb != vtime_lb
61057        || taxisptr->vtime_ub != vtime_ub
61058        || taxisptr->has_bounds == false )
61059     {
61060       taxisptr->vtime_lb = vtime_lb;
61061       taxisptr->vtime_ub = vtime_ub;
61062       taxisptr->has_bounds = true;
61063       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
61064     }
61065 }
61066 
61067 /*
61068 @Function  taxisInqRdate
61069 @Title     Get the reference date
61070 
61071 @Prototype int64_t taxisInqRdate(int taxisID)
61072 @Parameter
61073     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate} or @fref{vlistInqTaxis}
61074 
61075 @Description
61076 The function @func{taxisInqRdate} returns the reference date of a Time axis.
61077 
61078 @Result
61079 @func{taxisInqRdate} returns the reference date.
61080 
61081 @EndFunction
61082 */
taxisInqRdate(int taxisID)61083 int64_t taxisInqRdate(int taxisID)
61084 {
61085   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
61086 
61087   if ( taxisptr->rdate == -1 )
61088     {
61089       taxisptr->rdate = taxisptr->vdate;
61090       taxisptr->rtime = taxisptr->vtime;
61091       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
61092     }
61093 
61094   return taxisptr->rdate;
61095 }
61096 
61097 /*
61098 @Function  taxisInqRtime
61099 @Title     Get the reference time
61100 
61101 @Prototype int taxisInqRtime(int taxisID)
61102 @Parameter
61103     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate} or @fref{vlistInqTaxis}
61104 
61105 @Description
61106 The function @func{taxisInqRtime} returns the reference time of a Time axis.
61107 
61108 @Result
61109 @func{taxisInqRtime} returns the reference time.
61110 
61111 @EndFunction
61112 */
taxisInqRtime(int taxisID)61113 int taxisInqRtime(int taxisID)
61114 {
61115   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
61116 
61117   if ( taxisptr->rdate == -1 )
61118     {
61119       taxisptr->rdate = taxisptr->vdate;
61120       taxisptr->rtime = taxisptr->vtime;
61121       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
61122     }
61123 
61124   return taxisptr->rtime;
61125 }
61126 
61127 /*
61128 @Function  taxisInqFdate
61129 @Title     Get the forecast reference date
61130 
61131 @Prototype int64_t taxisInqFdate(int taxisID)
61132 @Parameter
61133     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate} or @fref{vlistInqTaxis}
61134 
61135 @Description
61136 The function @func{taxisInqFdate} returns the forecast reference date of a Time axis.
61137 
61138 @Result
61139 @func{taxisInqFdate} returns the forecast reference date.
61140 
61141 @EndFunction
61142 */
taxisInqFdate(int taxisID)61143 int64_t taxisInqFdate(int taxisID)
61144 {
61145   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
61146 
61147   if ( taxisptr->fdate == -1 )
61148     {
61149       taxisptr->fdate = taxisptr->vdate;
61150       taxisptr->ftime = taxisptr->vtime;
61151     }
61152 
61153   return taxisptr->fdate;
61154 }
61155 
61156 /*
61157 @Function  taxisInqFtime
61158 @Title     Get the forecast reference time
61159 
61160 @Prototype int taxisInqFtime(int taxisID)
61161 @Parameter
61162     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate} or @fref{vlistInqTaxis}
61163 
61164 @Description
61165 The function @func{taxisInqFtime} returns the forecast reference time of a Time axis.
61166 
61167 @Result
61168 @func{taxisInqFtime} returns the forecast reference time.
61169 
61170 @EndFunction
61171 */
taxisInqFtime(int taxisID)61172 int taxisInqFtime(int taxisID)
61173 {
61174   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
61175 
61176   if ( taxisptr->fdate == -1 )
61177     {
61178       taxisptr->fdate = taxisptr->vdate;
61179       taxisptr->ftime = taxisptr->vtime;
61180     }
61181 
61182   return taxisptr->ftime;
61183 }
61184 
61185 /*
61186 @Function  taxisInqCalendar
61187 @Title     Get the calendar
61188 
61189 @Prototype int taxisInqCalendar(int taxisID)
61190 @Parameter
61191     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate} or @fref{vlistInqTaxis}
61192 
61193 @Description
61194 The function @func{taxisInqCalendar} returns the calendar of a Time axis.
61195 
61196 @Result
61197 @func{taxisInqCalendar} returns the type of the calendar,
61198 one of the set of predefined CDI calendar types.
61199 The valid CDI calendar types are @func{CALENDAR_STANDARD}, @func{CALENDAR_PROLEPTIC},
61200 @func{CALENDAR_360DAYS}, @func{CALENDAR_365DAYS} and @func{CALENDAR_366DAYS}.
61201 
61202 @EndFunction
61203 */
taxisInqCalendar(int taxisID)61204 int taxisInqCalendar(int taxisID)
61205 {
61206   taxis_t *taxisptr = (taxis_t *) reshGetVal ( taxisID, &taxisOps );
61207   return taxisptr->calendar;
61208 }
61209 
61210 
taxisInqTunit(int taxisID)61211 int taxisInqTunit(int taxisID)
61212 {
61213   taxis_t *taxisptr = (taxis_t *) reshGetVal ( taxisID, &taxisOps );
61214   return taxisptr->unit;
61215 }
61216 
61217 
taxisInqForecastTunit(int taxisID)61218 int taxisInqForecastTunit(int taxisID)
61219 {
61220   taxis_t *taxisptr = (taxis_t *) reshGetVal ( taxisID, &taxisOps );
61221   return taxisptr->fc_unit;
61222 }
61223 
61224 
taxisInqForecastPeriod(int taxisID)61225 double taxisInqForecastPeriod(int taxisID)
61226 {
61227   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
61228   return taxisptr->fc_period;
61229 }
61230 
61231 
taxisInqNumavg(int taxisID)61232 int taxisInqNumavg(int taxisID)
61233 {
61234   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
61235   return taxisptr->numavg;
61236 }
61237 
61238 
taxisPtr(int taxisID)61239 taxis_t *taxisPtr(int taxisID)
61240 {
61241   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
61242   return taxisptr;
61243 }
61244 
61245 
ptaxisDefDatatype(taxis_t * taxisptr,int datatype)61246 void ptaxisDefDatatype(taxis_t *taxisptr, int datatype)
61247 {
61248   taxisptr->datatype = datatype;
61249 }
61250 
61251 
ptaxisDefName(taxis_t * taxisptr,const char * name)61252 void ptaxisDefName(taxis_t *taxisptr, const char *name)
61253 {
61254   if ( name )
61255     {
61256       size_t len = strlen(name);
61257       delete_refcount_string(taxisptr->name);
61258       char *taxisname = taxisptr->name = new_refcount_string(len);
61259       strcpy(taxisname, name);
61260     }
61261 }
61262 
61263 
ptaxisDefLongname(taxis_t * taxisptr,const char * longname)61264 void ptaxisDefLongname(taxis_t *taxisptr, const char *longname)
61265 {
61266   if ( longname )
61267     {
61268       size_t len = strlen(longname);
61269       delete_refcount_string(taxisptr->longname);
61270       char *taxislongname = taxisptr->longname = new_refcount_string(len);
61271       strcpy(taxislongname, longname);
61272     }
61273 }
61274 
61275 
ptaxisDefUnits(taxis_t * taxisptr,const char * units)61276 void ptaxisDefUnits(taxis_t *taxisptr, const char *units)
61277 {
61278   if ( units )
61279     {
61280       size_t len = strlen(units);
61281       delete_refcount_string(taxisptr->units);
61282       char *taxisunits = taxisptr->units = new_refcount_string(len);
61283       strcpy(taxisunits, units);
61284     }
61285 }
61286 
61287 
61288 static void
cdiDecodeTimevalue(int timeunit,double timevalue,int64_t * days,int * secs)61289 cdiDecodeTimevalue(int timeunit, double timevalue, int64_t *days, int *secs)
61290 {
61291   *days = 0;
61292   *secs = 0;
61293 
61294   if ( timeunit == TUNIT_MINUTE )
61295     {
61296       timevalue *= 60;
61297       timeunit = TUNIT_SECOND;
61298     }
61299   else if ( timeunit == TUNIT_HOUR )
61300     {
61301       timevalue /= 24;
61302       timeunit = TUNIT_DAY;
61303     }
61304 
61305   if ( timeunit == TUNIT_SECOND )
61306     {
61307       *days = (int) (timevalue/86400);
61308       double seconds = timevalue - *days*86400.;
61309       *secs = (int)lround(seconds);
61310       if ( *secs < 0 ) { *days -= 1; *secs += 86400; };
61311       /*
61312       {
61313 	double cval = *days*86400. + *secs;
61314 	if ( cval != timevalue )
61315 	  printf("TUNIT_SECOND error: %g %g %d %d\n", timevalue, cval, *days, *secs);
61316       }
61317       */
61318     }
61319   else if ( timeunit == TUNIT_DAY )
61320     {
61321       *days = (int) timevalue;
61322       double seconds = (timevalue - *days)*86400;
61323       *secs = (int)lround(seconds);
61324       if ( *secs < 0 ) { *days -= 1; *secs += 86400; };
61325       /*
61326       {
61327 	double cval = *days + *secs/86400.;
61328 	if ( cval != timevalue )
61329 	  printf("TUNIT_DAY error: %g %g %d %d\n", timevalue, cval, *days, *secs);
61330       }
61331       */
61332     }
61333   else
61334     {
61335       static bool lwarn = true;
61336       if ( lwarn )
61337 	{
61338 	  Warning("timeunit %s unsupported!", tunitNamePtr(timeunit));
61339 	  lwarn = false;
61340 	}
61341     }
61342 }
61343 
61344 static
cdiEncodeTimevalue(int days,int secs,int timeunit,double * timevalue)61345 void cdiEncodeTimevalue(int days, int secs, int timeunit, double *timevalue)
61346 {
61347   if ( timeunit == TUNIT_SECOND )
61348     {
61349       *timevalue = days*86400. + secs;
61350     }
61351   else if ( timeunit == TUNIT_MINUTE  ||
61352 	    timeunit == TUNIT_QUARTER ||
61353 	    timeunit == TUNIT_30MINUTES )
61354     {
61355       *timevalue = days*1440. + secs/60.;
61356     }
61357   else if ( timeunit == TUNIT_HOUR   ||
61358 	    timeunit == TUNIT_3HOURS ||
61359 	    timeunit == TUNIT_6HOURS ||
61360 	    timeunit == TUNIT_12HOURS )
61361     {
61362       *timevalue = days*24. + secs/3600.;
61363     }
61364   else if ( timeunit == TUNIT_DAY )
61365     {
61366       *timevalue = days + secs/86400.;
61367     }
61368   else
61369     {
61370       static bool lwarn = true;
61371       if ( lwarn )
61372 	{
61373 	  Warning("timeunit %s unsupported!", tunitNamePtr(timeunit));
61374 	  lwarn = false;
61375 	}
61376     }
61377 }
61378 
61379 
timeval2vtime(double timevalue,taxis_t * taxis,int64_t * vdate,int * vtime)61380 void timeval2vtime(double timevalue, taxis_t *taxis, int64_t *vdate, int *vtime)
61381 {
61382   int64_t rdate = taxis->rdate;
61383   int rtime = taxis->rtime;
61384 
61385   if ( DBL_IS_EQUAL(timevalue, 0.) )
61386     {
61387       *vdate = rdate;
61388       *vtime = rtime;
61389       return;
61390     }
61391 
61392   int year, month, day, hour, minute, second;
61393   cdiDecodeDate(rdate, &year, &month, &day);
61394   cdiDecodeTime(rtime, &hour, &minute, &second);
61395 
61396   int timeunit = taxis->unit;
61397   int calendar = taxis->calendar;
61398 
61399   if ( timeunit == TUNIT_MONTH && calendar == CALENDAR_360DAYS )
61400     {
61401       timeunit = TUNIT_DAY;
61402       timevalue *= 30;
61403     }
61404 
61405   if ( timeunit == TUNIT_MONTH || timeunit == TUNIT_YEAR )
61406     {
61407       if ( timeunit == TUNIT_YEAR ) timevalue *= 12;
61408 
61409       int nmon = (int) timevalue;
61410       double fmon = timevalue - nmon;
61411 
61412       month += nmon;
61413 
61414       while ( month > 12 ) { month -= 12; year++; }
61415       while ( month <  1 ) { month += 12; year--; }
61416 
61417       int dpm = days_per_month(calendar, year, month);
61418       timeunit = TUNIT_DAY;
61419       timevalue = fmon*dpm;
61420     }
61421 
61422   int64_t julday, days;
61423   int secofday, secs;
61424   encode_caldaysec(calendar, year, month, day, hour, minute, second, &julday, &secofday);
61425 
61426   cdiDecodeTimevalue(timeunit, timevalue, &days, &secs);
61427 
61428   julday_add(days, secs, &julday, &secofday);
61429 
61430   decode_caldaysec(calendar, julday, secofday, &year, &month, &day, &hour, &minute, &second);
61431 
61432   *vdate = cdiEncodeDate(year, month, day);
61433   *vtime = cdiEncodeTime(hour, minute, second);
61434 }
61435 
61436 
vtime2timeval(int64_t vdate,int vtime,taxis_t * taxis)61437 double vtime2timeval(int64_t vdate, int vtime, taxis_t *taxis)
61438 {
61439   double value = 0;
61440   int64_t julday1, julday2, days;
61441   int secofday1, secofday2, secs;
61442 
61443   int timeunit = (*taxis).unit;
61444   int calendar = (*taxis).calendar;
61445 
61446   int64_t rdate = (*taxis).rdate;
61447   int rtime = (*taxis).rtime;
61448   if ( rdate == -1 )
61449     {
61450       rdate = (*taxis).vdate;
61451       rtime = (*taxis).vtime;
61452     }
61453 
61454   if ( rdate == 0 && rtime == 0 && vdate == 0 && vtime == 0 ) return value;
61455 
61456   int ryear, rmonth;
61457   int year, month, day, hour, minute, second;
61458   cdiDecodeDate(rdate, &ryear, &rmonth, &day);
61459   cdiDecodeTime(rtime, &hour, &minute, &second);
61460 
61461   encode_caldaysec(calendar, ryear, rmonth, day, hour, minute, second, &julday1, &secofday1);
61462 
61463   cdiDecodeDate(vdate, &year, &month, &day);
61464   cdiDecodeTime(vtime, &hour, &minute, &second);
61465 
61466   int timeunit0 = timeunit;
61467 
61468   if ( timeunit == TUNIT_MONTH && calendar == CALENDAR_360DAYS )
61469     {
61470       timeunit = TUNIT_DAY;
61471     }
61472 
61473   if ( timeunit == TUNIT_MONTH || timeunit == TUNIT_YEAR )
61474     {
61475       value = (year-ryear)*12 - rmonth + month;
61476 
61477       int nmonth = (int) value;
61478       month -= nmonth;
61479 
61480       while ( month > 12 ) { month -= 12; year++; }
61481       while ( month <  1 ) { month += 12; year--; }
61482 
61483       int dpm = days_per_month(calendar, year, month);
61484 
61485       encode_caldaysec(calendar, year, month, day, hour, minute, second, &julday2, &secofday2);
61486 
61487       julday_sub(julday1, secofday1, julday2, secofday2, &days, &secs);
61488 
61489       value += (days+secs/86400.)/dpm;
61490 
61491       if ( timeunit == TUNIT_YEAR ) value = value/12;
61492     }
61493   else
61494     {
61495       encode_caldaysec(calendar, year, month, day, hour, minute, second, &julday2, &secofday2);
61496 
61497       julday_sub(julday1, secofday1, julday2, secofday2, &days, &secs);
61498 
61499       cdiEncodeTimevalue(days, secs, timeunit, &value);
61500     }
61501 
61502   if ( timeunit0 == TUNIT_MONTH && calendar == CALENDAR_360DAYS )
61503     {
61504       value /= 30;
61505     }
61506 
61507   return value;
61508 }
61509 
61510 
61511 static
conv_timeval(double timevalue,int64_t * rvdate,int * rvtime)61512 void conv_timeval(double timevalue, int64_t *rvdate, int *rvtime)
61513 {
61514   int daysec;
61515 
61516   int64_t vdate = (int) timevalue;
61517   if ( vdate < 0 )
61518     daysec = (int) (-(timevalue - vdate)*86400 + 0.01);
61519   else
61520     daysec = (int) ( (timevalue - vdate)*86400 + 0.01);
61521 
61522   int hour   =  daysec / 3600;
61523   int minute = (daysec - hour*3600)/60;
61524   int second =  daysec - hour*3600 - minute*60;
61525   int vtime  = cdiEncodeTime(hour, minute, second);
61526 
61527   *rvdate = vdate;
61528   *rvtime = vtime;
61529 }
61530 
61531 
61532 static
splitTimevalue(double timevalue,int timeunit,int64_t * date,int * time)61533 void splitTimevalue(double timevalue, int timeunit, int64_t *date, int *time)
61534 {
61535   int64_t vdate = 0;
61536   int vtime = 0;
61537 
61538   if ( timeunit == TUNIT_SECOND )
61539     {
61540       timevalue /= 86400;
61541       conv_timeval(timevalue, &vdate, &vtime);
61542     }
61543   else if ( timeunit == TUNIT_HOUR )
61544     {
61545       timevalue /= 24;
61546       conv_timeval(timevalue, &vdate, &vtime);
61547     }
61548   else if ( timeunit == TUNIT_DAY )
61549     {
61550       conv_timeval(timevalue, &vdate, &vtime);
61551     }
61552   else if ( timeunit == TUNIT_MONTH )
61553     {
61554       vdate = (int64_t) timevalue*100 - ((timevalue < 0) * 2 - 1);
61555       vtime = 0;
61556     }
61557   else if ( timeunit == TUNIT_YEAR )
61558     {
61559       {
61560         static bool lwarn = true;
61561         if (lwarn && (fabs(timevalue - (int64_t) timevalue) > 0))
61562           {
61563             Warning("Fraction of a year is not supported!!");
61564             lwarn = false;
61565           }
61566       }
61567 
61568       {
61569         static bool lwarn = true;
61570         if ( timevalue < -214700 )
61571           {
61572             if ( lwarn )
61573               {
61574                 Warning("Year %g out of range, set to -214700", timevalue);
61575                 lwarn = false;
61576               }
61577             timevalue = -214700;
61578           }
61579         else if ( timevalue > 214700 )
61580           {
61581             if ( lwarn )
61582               {
61583                 Warning("Year %g out of range, set to 214700", timevalue);
61584                 lwarn = false;
61585               }
61586             timevalue = 214700;
61587           }
61588       }
61589 
61590       vdate = (int64_t) timevalue*10000;
61591       vdate += timevalue < 0 ? -101 : 101;
61592       vtime = 0;
61593     }
61594   else
61595     {
61596       static bool lwarn = true;
61597       if ( lwarn )
61598 	{
61599 	  Warning("timeunit %s unsupported!", tunitNamePtr(timeunit));
61600 	  lwarn = false;
61601 	}
61602     }
61603 
61604   /* verify date and time */
61605 
61606   int year, month, day;
61607   cdiDecodeDate(vdate, &year, &month, &day);
61608   int hour, minute, second;
61609   cdiDecodeTime(vtime, &hour, &minute, &second);
61610 
61611   if ( month > 17 || day > 31 || hour > 23 || minute > 59 || second > 59 )
61612     {
61613       if ( (month  > 17 || day > 31) && (year < -9999 || year > 9999) ) year = 1;
61614       if ( month  > 17 ) month  = 1;
61615       if ( day    > 31 ) day    = 1;
61616       if ( hour   > 23 ) hour   = 0;
61617       if ( minute > 59 ) minute = 0;
61618       if ( second > 59 ) second = 0;
61619 
61620       vdate = cdiEncodeDate(year, month, day);
61621       vtime = cdiEncodeTime(hour, minute, second);
61622 
61623       static bool lwarn = true;
61624       if ( lwarn )
61625         {
61626           lwarn = false;
61627           Warning("Reset wrong date/time to %4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d!",
61628                   year, month, day, hour, minute, second);
61629         }
61630     }
61631 
61632   *date = vdate;
61633   *time = vtime;
61634 }
61635 
61636 
cdiSetForecastPeriod(double timevalue,taxis_t * taxis)61637 void cdiSetForecastPeriod(double timevalue, taxis_t *taxis)
61638 {
61639   int64_t julday, days;
61640   int secofday, secs;
61641 
61642   (*taxis).fc_period = timevalue;
61643 
61644   int timeunit = (*taxis).fc_unit;
61645   int calendar = (*taxis).calendar;
61646 
61647   int64_t vdate = (*taxis).vdate;
61648   int vtime = (*taxis).vtime;
61649 
61650   if ( vdate == 0 && vtime == 0 && DBL_IS_EQUAL(timevalue, 0.) ) return;
61651 
61652   int year, month, day, hour, minute, second;
61653   cdiDecodeDate(vdate, &year, &month, &day);
61654   cdiDecodeTime(vtime, &hour, &minute, &second);
61655 
61656   if ( timeunit == TUNIT_MONTH && calendar == CALENDAR_360DAYS )
61657     {
61658       timeunit = TUNIT_DAY;
61659       timevalue *= 30;
61660     }
61661 
61662   if ( timeunit == TUNIT_MONTH || timeunit == TUNIT_YEAR )
61663     {
61664       int nmon, dpm;
61665       double fmon;
61666 
61667       if ( timeunit == TUNIT_YEAR ) timevalue *= 12;
61668 
61669       nmon = (int) timevalue;
61670       fmon = timevalue - nmon;
61671 
61672       month -= nmon;
61673 
61674       while ( month > 12 ) { month -= 12; year++; }
61675       while ( month <  1 ) { month += 12; year--; }
61676 
61677       dpm = days_per_month(calendar, year, month);
61678       timeunit = TUNIT_DAY;
61679       timevalue = fmon*dpm;
61680     }
61681 
61682   encode_caldaysec(calendar, year, month, day, hour, minute, second, &julday, &secofday);
61683 
61684   cdiDecodeTimevalue(timeunit, timevalue, &days, &secs);
61685 
61686   julday_add(-days, -secs, &julday, &secofday);
61687 
61688   decode_caldaysec(calendar, julday, secofday, &year, &month, &day, &hour, &minute, &second);
61689 
61690   (*taxis).fdate = cdiEncodeDate(year, month, day);
61691   (*taxis).ftime = cdiEncodeTime(hour, minute, second);
61692 }
61693 
61694 
cdiDecodeTimeval(double timevalue,taxis_t * taxis,int64_t * date,int * time)61695 void cdiDecodeTimeval(double timevalue, taxis_t *taxis, int64_t *date, int *time)
61696 {
61697   if ( taxis->type == TAXIS_ABSOLUTE )
61698     splitTimevalue(timevalue, taxis->unit, date, time);
61699   else
61700     timeval2vtime(timevalue, taxis, date, time);
61701 }
61702 
61703 
cdiEncodeTimeval(int64_t date,int time,taxis_t * taxis)61704 double cdiEncodeTimeval(int64_t date, int time, taxis_t *taxis)
61705 {
61706   double timevalue;
61707 
61708   if ( taxis->type == TAXIS_ABSOLUTE )
61709     {
61710       if ( taxis->unit == TUNIT_YEAR )
61711 	{
61712 	  int year, month, day;
61713 	  cdiDecodeDate(date, &year, &month, &day);
61714 
61715 	  timevalue = year;
61716 	}
61717       else if ( taxis->unit == TUNIT_MONTH )
61718 	{
61719 	  int year, month, day;
61720 	  cdiDecodeDate(date, &year, &month, &day);
61721           timevalue = date/100
61722             + copysign((double)(day != 0) * 0.5, (double)date);
61723         }
61724       else
61725 	{
61726 	  int hour, minute, second;
61727 	  cdiDecodeTime(time, &hour, &minute, &second);
61728           timevalue = copysign(1.0, (double)date)
61729             * (fabs((double)date) + (hour*3600 + minute*60 + second)/86400.);
61730 	}
61731     }
61732   else
61733     timevalue = vtime2timeval(date, time, taxis);
61734 
61735   return timevalue;
61736 }
61737 
61738 
ptaxisInit(taxis_t * taxisptr)61739 void ptaxisInit(taxis_t *taxisptr)
61740 {
61741   taxisDefaultValue ( taxisptr );
61742 }
61743 
61744 
ptaxisCopy(taxis_t * dest,taxis_t * source)61745 void ptaxisCopy(taxis_t *dest, taxis_t *source)
61746 {
61747   reshLock ();
61748 
61749   /* memcpy(dest, source, sizeof(taxis_t)); */
61750   dest->used        = source->used;
61751   dest->datatype    = source->datatype;
61752   dest->type        = source->type;
61753   dest->sdate       = source->sdate;
61754   dest->stime       = source->stime;
61755   dest->vdate       = source->vdate;
61756   dest->vtime       = source->vtime;
61757   dest->rdate       = source->rdate;
61758   dest->rtime       = source->rtime;
61759   dest->fdate       = source->fdate;
61760   dest->ftime       = source->ftime;
61761   dest->calendar    = source->calendar;
61762   dest->unit        = source->unit;
61763   dest->numavg      = source->numavg;
61764   dest->climatology = source->climatology;
61765   dest->has_bounds  = source->has_bounds;
61766   dest->vdate_lb    = source->vdate_lb;
61767   dest->vtime_lb    = source->vtime_lb;
61768   dest->vdate_ub    = source->vdate_ub;
61769   dest->vtime_ub    = source->vtime_ub;
61770   dest->fc_unit     = source->fc_unit;
61771   dest->fc_period   = source->fc_period;
61772 
61773   dest->climatology = source->climatology;
61774   delete_refcount_string(dest->name);
61775   delete_refcount_string(dest->longname);
61776   delete_refcount_string(dest->units);
61777   dest->name = dup_refcount_string(source->name);
61778   dest->longname = dup_refcount_string(source->longname);
61779   dest->units = dup_refcount_string(source->units);
61780   if (dest->self != CDI_UNDEFID)
61781     reshSetStatus(dest->self, &taxisOps, RESH_DESYNC_IN_USE);
61782 
61783   reshUnlock ();
61784 }
61785 
61786 
61787 static void
taxisPrintKernel(taxis_t * taxisptr,FILE * fp)61788 taxisPrintKernel(taxis_t * taxisptr, FILE * fp)
61789 {
61790   int64_t vdate_lb, vdate_ub;
61791   int vtime_lb, vtime_ub;
61792 
61793   taxisInqVdateBounds ( taxisptr->self, &vdate_lb, &vdate_ub);
61794   taxisInqVtimeBounds ( taxisptr->self, &vtime_lb, &vtime_ub);
61795 
61796   fprintf(fp,
61797           "#\n"
61798           "# taxisID %d\n"
61799           "#\n"
61800           "self        = %d\n"
61801           "used        = %d\n"
61802           "type        = %d\n"
61803           "vdate       = %lld\n"
61804           "vtime       = %d\n"
61805           "rdate       = %lld\n"
61806           "rtime       = %d\n"
61807           "fdate       = %lld\n"
61808           "ftime       = %d\n"
61809           "calendar    = %d\n"
61810           "unit        = %d\n"
61811           "numavg      = %d\n"
61812           "climatology = %d\n"
61813           "has_bounds  = %d\n"
61814           "vdate_lb    = %lld\n"
61815           "vtime_lb    = %d\n"
61816           "vdate_ub    = %lld\n"
61817           "vtime_ub    = %d\n"
61818           "fc_unit     = %d\n"
61819           "fc_period   = %g\n"
61820           "\n", taxisptr->self, taxisptr->self,
61821           (int)taxisptr->used, taxisptr->type,
61822           taxisptr->vdate, taxisptr->vtime,
61823           taxisptr->rdate, taxisptr->rtime,
61824           taxisptr->fdate, taxisptr->ftime,
61825           taxisptr->calendar, taxisptr->unit,
61826           taxisptr->numavg, (int)taxisptr->climatology,
61827           (int) taxisptr->has_bounds,
61828           vdate_lb, vtime_lb, vdate_ub, vtime_ub,
61829           taxisptr->fc_unit, taxisptr->fc_period );
61830 }
61831 
61832 static int
taxisCompareP(void * taxisptr1,void * taxisptr2)61833 taxisCompareP(void *taxisptr1, void *taxisptr2)
61834 {
61835   const taxis_t *t1 = ( const taxis_t * ) taxisptr1,
61836     *t2 = ( const taxis_t * ) taxisptr2;
61837 
61838   xassert ( t1 && t2 );
61839 
61840   return ! ( t1->used        == t2->used        &&
61841 	     t1->type        == t2->type        &&
61842 	     t1->vdate       == t2->vdate       &&
61843 	     t1->vtime       == t2->vtime       &&
61844 	     t1->rdate       == t2->rdate       &&
61845 	     t1->rtime       == t2->rtime       &&
61846 	     t1->fdate       == t2->fdate       &&
61847 	     t1->ftime       == t2->ftime       &&
61848 	     t1->calendar    == t2->calendar    &&
61849 	     t1->unit        == t2->unit        &&
61850 	     t1->fc_unit     == t2->fc_unit     &&
61851 	     t1->numavg      == t2->numavg      &&
61852 	     t1->climatology == t2->climatology &&
61853 	     t1->has_bounds  == t2->has_bounds  &&
61854 	     t1->vdate_lb    == t2->vdate_lb    &&
61855 	     t1->vtime_lb    == t2->vtime_lb    &&
61856 	     t1->vdate_ub    == t2->vdate_ub    &&
61857 	     t1->vtime_ub    == t2->vtime_ub );
61858 }
61859 
61860 
61861 static int
taxisTxCode(void)61862 taxisTxCode ( void )
61863 {
61864   return TAXIS;
61865 }
61866 
61867 enum { taxisNint = 22 };
61868 
61869 static int
taxisGetPackSize(void * p,void * context)61870 taxisGetPackSize(void *p, void *context)
61871 {
61872   taxis_t *taxisptr = (taxis_t*) p;
61873   int packBufferSize
61874     = serializeGetSize(taxisNint, CDI_DATATYPE_INT, context)
61875     + serializeGetSize(1, CDI_DATATYPE_UINT32, context)
61876     + (taxisptr->name ?
61877        serializeGetSize((int)strlen(taxisptr->name), CDI_DATATYPE_TXT, context) : 0)
61878     + (taxisptr->longname ?
61879        serializeGetSize((int)strlen(taxisptr->longname), CDI_DATATYPE_TXT, context) : 0)
61880     + (taxisptr->units ?
61881        serializeGetSize((int)strlen(taxisptr->units), CDI_DATATYPE_TXT, context) : 0);
61882   return packBufferSize;
61883 }
61884 
61885 int
taxisUnpack(char * unpackBuffer,int unpackBufferSize,int * unpackBufferPos,int originNamespace,void * context,int force_id)61886 taxisUnpack(char * unpackBuffer, int unpackBufferSize, int * unpackBufferPos,
61887             int originNamespace, void *context, int force_id)
61888 {
61889   taxis_t * taxisP;
61890   int intBuffer[taxisNint];
61891   uint32_t d;
61892   int idx = 0;
61893 
61894   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
61895                   intBuffer, taxisNint, CDI_DATATYPE_INT, context);
61896   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
61897                   &d, 1, CDI_DATATYPE_UINT32, context);
61898 
61899   xassert(cdiCheckSum(CDI_DATATYPE_INT, taxisNint, intBuffer) == d);
61900 
61901   taxisInit();
61902 
61903   cdiResH targetID = namespaceAdaptKey(intBuffer[idx++], originNamespace);
61904   taxisP = taxisNewEntry(force_id?targetID:CDI_UNDEFID);
61905 
61906   xassert(!force_id || targetID == taxisP->self);
61907 
61908   taxisP->used        = (short)intBuffer[idx++];
61909   taxisP->type        = intBuffer[idx++];
61910   taxisP->vdate       = intBuffer[idx++];
61911   taxisP->vtime       = intBuffer[idx++];
61912   taxisP->rdate       = intBuffer[idx++];
61913   taxisP->rtime       = intBuffer[idx++];
61914   taxisP->fdate       = intBuffer[idx++];
61915   taxisP->ftime       = intBuffer[idx++];
61916   taxisP->calendar    = intBuffer[idx++];
61917   taxisP->unit        = intBuffer[idx++];
61918   taxisP->fc_unit     = intBuffer[idx++];
61919   taxisP->numavg      = intBuffer[idx++];
61920   taxisP->climatology = intBuffer[idx++];
61921   taxisP->has_bounds  = (short)intBuffer[idx++];
61922   taxisP->vdate_lb    = intBuffer[idx++];
61923   taxisP->vtime_lb    = intBuffer[idx++];
61924   taxisP->vdate_ub    = intBuffer[idx++];
61925   taxisP->vtime_ub    = intBuffer[idx++];
61926 
61927   if (intBuffer[idx])
61928     {
61929       int len = intBuffer[idx];
61930       char *name = new_refcount_string((size_t)len);
61931       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
61932                       name, len, CDI_DATATYPE_TXT, context);
61933       name[len] = '\0';
61934       taxisP->name = name;
61935     }
61936   idx++;
61937   if (intBuffer[idx])
61938     {
61939       int len = intBuffer[idx];
61940       char *longname = new_refcount_string((size_t)len);
61941       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
61942                       longname, len, CDI_DATATYPE_TXT, context);
61943       longname[len] = '\0';
61944       taxisP->longname = longname;
61945     }
61946   if (intBuffer[idx])
61947     {
61948       int len = intBuffer[idx];
61949       char *units = new_refcount_string((size_t)len);
61950       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
61951                       units, len, CDI_DATATYPE_TXT, context);
61952       units[len] = '\0';
61953       taxisP->units = units;
61954     }
61955 
61956   reshSetStatus(taxisP->self, &taxisOps,
61957                 reshGetStatus(taxisP->self, &taxisOps) & ~RESH_SYNC_BIT);
61958 
61959   return taxisP->self;
61960 }
61961 
61962 
61963 static void
taxisPack(void * voidP,void * packBuffer,int packBufferSize,int * packBufferPos,void * context)61964 taxisPack(void * voidP, void * packBuffer, int packBufferSize, int * packBufferPos,
61965           void *context)
61966 {
61967   taxis_t *taxisP = (taxis_t *)voidP;
61968   int intBuffer[taxisNint];
61969   uint32_t d;
61970   int idx = 0;
61971 
61972   intBuffer[idx++] = taxisP->self;
61973   intBuffer[idx++] = taxisP->used;
61974   intBuffer[idx++] = taxisP->type;
61975   intBuffer[idx++] = taxisP->vdate;
61976   intBuffer[idx++] = taxisP->vtime;
61977   intBuffer[idx++] = taxisP->rdate;
61978   intBuffer[idx++] = taxisP->rtime;
61979   intBuffer[idx++] = taxisP->fdate;
61980   intBuffer[idx++] = taxisP->ftime;
61981   intBuffer[idx++] = taxisP->calendar;
61982   intBuffer[idx++] = taxisP->unit;
61983   intBuffer[idx++] = taxisP->fc_unit;
61984   intBuffer[idx++] = taxisP->numavg;
61985   intBuffer[idx++] = taxisP->climatology;
61986   intBuffer[idx++] = taxisP->has_bounds;
61987   intBuffer[idx++] = taxisP->vdate_lb;
61988   intBuffer[idx++] = taxisP->vtime_lb;
61989   intBuffer[idx++] = taxisP->vdate_ub;
61990   intBuffer[idx++] = taxisP->vtime_ub;
61991   intBuffer[idx++] = taxisP->name ? (int)strlen(taxisP->name) : 0;
61992   intBuffer[idx++] = taxisP->longname ? (int)strlen(taxisP->longname) : 0;
61993   intBuffer[idx++] = taxisP->units ? (int)strlen(taxisP->units) : 0;
61994 
61995   serializePack(intBuffer, taxisNint, CDI_DATATYPE_INT,
61996                 packBuffer, packBufferSize, packBufferPos, context);
61997   d = cdiCheckSum(CDI_DATATYPE_INT, taxisNint, intBuffer);
61998   serializePack(&d, 1, CDI_DATATYPE_UINT32,
61999                 packBuffer, packBufferSize, packBufferPos, context);
62000   if (taxisP->name)
62001     serializePack(taxisP->name, intBuffer[15], CDI_DATATYPE_TXT,
62002                   packBuffer, packBufferSize, packBufferPos, context);
62003   if (taxisP->longname)
62004     serializePack(taxisP->longname, intBuffer[16], CDI_DATATYPE_TXT,
62005                   packBuffer, packBufferSize, packBufferPos, context);
62006   if (taxisP->units)
62007     serializePack(taxisP->units, intBuffer[16], CDI_DATATYPE_TXT,
62008                   packBuffer, packBufferSize, packBufferPos, context);
62009 
62010 }
62011 
62012 /*
62013  * Local Variables:
62014  * c-file-style: "Java"
62015  * c-basic-offset: 2
62016  * indent-tabs-mode: nil
62017  * show-trailing-whitespace: t
62018  * require-trailing-newline: t
62019  * End:
62020  */
62021 #include <math.h>		/* for floor() */
62022 
62023 
62024 /* convert Julian date into year, months, day */
decode_julday(int calendar,int64_t julday,int * year,int * mon,int * day)62025 void decode_julday(int calendar,
62026 		   int64_t julday, /* Julian day number to convert */
62027 		   int *year,	   /* Gregorian year (out)         */
62028 		   int *mon,	   /* Gregorian month (1-12) (out) */
62029 		   int *day)       /* Gregorian day (1-31) (out)   */
62030 {
62031   int64_t a = julday;
62032 
62033   double b = floor((a - 1867216.25)/36524.25);
62034   double c = a + b - floor(b/4) + 1525;
62035 
62036   if ( calendar == CALENDAR_STANDARD || calendar == CALENDAR_GREGORIAN )
62037     if ( a < 2299161 ) c = a + 1524;
62038 
62039   double d = floor((c - 122.1)/365.25);
62040   double e = floor(365.25*d);
62041   double f = floor((c - e)/30.6001);
62042 
62043   *day  = (int)(c - e - floor(30.6001*f));
62044   *mon  = (int)(f - 1 - 12*floor(f/14));
62045   *year = (int)(d - 4715 - floor((7 + *mon)/10));
62046 }
62047 
62048 
62049 // convert year, month, day into Julian calendar day
encode_julday(int calendar,int year,int month,int day)62050 int64_t encode_julday(int calendar, int year, int month, int day)
62051 {
62052   int iy = (month <= 2) ? year  - 1 : year;
62053   int im = (month <= 2) ? month + 12 : month;
62054   int ib = (iy < 0) ? ((iy+1)/400 - (iy+1)/100) : (iy/400 - iy/100);
62055 
62056   if ( calendar == CALENDAR_STANDARD || calendar == CALENDAR_GREGORIAN )
62057     {
62058       if ( year > 1582 || (year == 1582 && (month > 10 || (month == 10 && day >= 15))) )
62059 	{
62060 	  // 15th October 1582 AD or later
62061 	}
62062       else
62063 	{
62064 	  // 4th October 1582 AD or earlier
62065 	  ib = -2;
62066 	}
62067     }
62068 
62069   int64_t julday = (int64_t) (floor(365.25*iy) + (int64_t)(30.6001*(im+1)) + ib + 1720996.5 + day + 0.5);
62070 
62071   return julday;
62072 }
62073 
62074 
date_to_julday(int calendar,int64_t date)62075 int64_t date_to_julday(int calendar, int64_t date)
62076 {
62077   int year, month, day;
62078   cdiDecodeDate(date, &year, &month, &day);
62079 
62080   int64_t julday = encode_julday(calendar, year, month, day);
62081 
62082   return julday;
62083 }
62084 
62085 
julday_to_date(int calendar,int64_t julday)62086 int64_t julday_to_date(int calendar, int64_t julday)
62087 {
62088   int year, month, day;
62089   decode_julday(calendar, julday, &year, &month, &day);
62090 
62091   int64_t date = cdiEncodeDate(year, month, day);
62092 
62093   return date;
62094 }
62095 
62096 
time_to_sec(int time)62097 int time_to_sec(int time)
62098 {
62099   int hour, minute, second;
62100   cdiDecodeTime(time, &hour, &minute, &second);
62101 
62102   int secofday = hour*3600 + minute*60 + second;
62103 
62104   return secofday;
62105 }
62106 
62107 
sec_to_time(int secofday)62108 int sec_to_time(int secofday)
62109 {
62110   int hour   = secofday/3600;
62111   int minute = secofday/60 - hour*60;
62112   int second = secofday - hour*3600 - minute*60;
62113 
62114   int time = cdiEncodeTime(hour, minute, second);
62115 
62116   return time;
62117 }
62118 
62119 static
adjust_seconds(int64_t * julday,int64_t * secofday)62120 void adjust_seconds(int64_t *julday, int64_t *secofday)
62121 {
62122   int64_t secperday = 86400;
62123 
62124   while ( *secofday >= secperday )
62125     {
62126       *secofday -= secperday;
62127       (*julday)++;
62128     }
62129 
62130   while ( *secofday <  0 )
62131     {
62132       *secofday += secperday;
62133       (*julday)--;
62134     }
62135 }
62136 
62137 
julday_add_seconds(int64_t seconds,int64_t * julday,int * secofday)62138 void julday_add_seconds(int64_t seconds, int64_t *julday, int *secofday)
62139 {
62140   int64_t sec_of_day = *secofday;
62141 
62142   sec_of_day += seconds;
62143 
62144   adjust_seconds(julday, &sec_of_day);
62145 
62146   *secofday = (int) sec_of_day;
62147 }
62148 
62149 /* add days and secs to julday/secofday */
julday_add(int days,int secs,int64_t * julday,int * secofday)62150 void julday_add(int days, int secs, int64_t *julday, int *secofday)
62151 {
62152   int64_t sec_of_day = *secofday;
62153 
62154   sec_of_day += secs;
62155   *julday    += days;
62156 
62157   adjust_seconds(julday, &sec_of_day);
62158 
62159   *secofday = (int) sec_of_day;
62160 }
62161 
62162 /* subtract julday1/secofday1 from julday2/secofday2 and returns the result in seconds */
julday_sub(int64_t julday1,int secofday1,int64_t julday2,int secofday2,int64_t * days,int * secs)62163 double julday_sub(int64_t julday1, int secofday1, int64_t julday2, int secofday2, int64_t *days, int *secs)
62164 {
62165   *days = julday2 - julday1;
62166   *secs = secofday2 - secofday1;
62167 
62168   int64_t sec_of_day = *secs;
62169 
62170   adjust_seconds(days, &sec_of_day);
62171 
62172   *secs = (int) sec_of_day;
62173 
62174   int64_t seconds = (int64_t)(*days) * (int64_t)86400 + sec_of_day;
62175 
62176   return (double)seconds;
62177 }
62178 
62179 
encode_juldaysec(int calendar,int year,int month,int day,int hour,int minute,int second,int64_t * julday,int * secofday)62180 void encode_juldaysec(int calendar, int year, int month, int day, int hour, int minute, int second, int64_t *julday, int *secofday)
62181 {
62182   *julday = encode_julday(calendar, year, month, day);
62183 
62184   *secofday = (hour*60 + minute)*60 + second;
62185 }
62186 
62187 
decode_juldaysec(int calendar,int64_t julday,int secofday,int * year,int * month,int * day,int * hour,int * minute,int * second)62188 void decode_juldaysec(int calendar, int64_t julday, int secofday, int *year, int *month, int *day, int *hour, int *minute, int *second)
62189 {
62190   decode_julday(calendar, julday, year, month, day);
62191 
62192   *hour   = secofday/3600;
62193   *minute = secofday/60 - *hour*60;
62194   *second = secofday - *hour*3600 - *minute*60;
62195 }
62196 
62197 
62198 #ifdef TEST
main(void)62199 int main(void)
62200 {
62201   int nmin;
62202   int64_t vdate0, vdate;
62203   int vtime0, vtime;
62204   int ijulinc;
62205   int j = 0;
62206   int year, mon, day, hour, minute, second;
62207   int64_t julday;
62208   int secofday;
62209   int calendar = CALENDAR_STANDARD;
62210 
62211   /* 1 - Check valid range of years */
62212 
62213   nmin = 11000;
62214   vdate0 = -80001201;
62215   vtime0 = 120500;
62216 
62217   printf("start time: %8ld %4d\n", vdate0, vtime0);
62218 
62219   for ( int i = 0; i < nmin; i++ )
62220     {
62221       cdiDecodeDate(vdate0, &year, &mon, &day);
62222       cdiDecodeTime(vtime0, &hour, &minute, &second);
62223 
62224       julday  = date_to_julday(calendar, vdate0);
62225       secofday = time_to_sec(vtime0);
62226 
62227       vdate = julday_to_date(calendar, julday);
62228       vtime = sec_to_time(secofday);
62229 
62230       if ( vdate0 != vdate || vtime0 != vtime )
62231 	printf("%4d %8ld %4d %8ld %4d %9d %9d\n",
62232 	       ++j, vdate0, vtime0, vdate, vtime, julday, secofday);
62233 
62234       year++;
62235       vdate0 = cdiEncodeDate(year, mon, day);
62236       vtime0 = cdiEncodeTime(hour, minute, second);
62237     }
62238 
62239   printf("stop time: %8ld %4d\n", vdate0, vtime0);
62240 
62241   /* 2 - Check time increment of one minute */
62242 
62243   nmin = 120000;
62244   ijulinc = 60;
62245   vdate0 = 20001201;
62246   vtime0 = 0;
62247 
62248   printf("start time: %8ld %4d\n", vdate0, vtime0);
62249 
62250   julday = date_to_julday(calendar, vdate0);
62251   secofday = time_to_sec(vtime0);
62252   for ( int i = 0; i < nmin; i++ )
62253     {
62254       cdiDecodeDate(vdate0, &year, &mon, &day);
62255       cdiDecodeTime(vtime0, &hour, &minute, &second);
62256 
62257       if ( ++minute >= 60 )
62258 	{
62259 	  minute = 0;
62260 	  if ( ++hour >= 24 )
62261 	    {
62262 	      hour = 0;
62263 	      if ( ++day >= 32 )
62264 		{
62265 		  day = 1;
62266 		  if ( ++mon >= 13 )
62267 		    {
62268 		      mon = 1;
62269 		      year++;
62270 		    }
62271 		}
62272 	    }
62273 	}
62274 
62275       vdate0 = cdiEncodeDate(year, mon, day);
62276       vtime0 = cdiEncodeTime(hour, minute, second);
62277 
62278       julday_add_seconds(ijulinc, &julday, &secofday);
62279 
62280       vdate = julday_to_date(calendar, julday);
62281       vtime = sec_to_time(secofday);
62282       if ( vdate0 != vdate || vtime0 != vtime )
62283 	printf("%4d %8ld %4d %8ld %4d %9d %9d\n",
62284 	       ++j, vdate0, vtime0, vdate, vtime, julday, secofday);
62285     }
62286 
62287   printf("stop time: %8ld %4d\n", vdate0, vtime0);
62288 
62289   return 0;
62290 }
62291 #endif
62292 
62293 
62294 #ifdef TEST2
main(void)62295 int main(void)
62296 {
62297   int julday, secofday;
62298   int year, month, day, hour, minute, second;
62299   int value = 30;
62300   int factor = 86400;
62301   int calendar = CALENDAR_STANDARD;
62302 
62303   year=1979; month=1; day=15; hour=12; minute=30, second=17;
62304 
62305   printf("%d/%02d/%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second);
62306 
62307   encode_juldaysec(calendar, year, month, day, hour, minute, second, &julday, &secofday);
62308 
62309   decode_juldaysec(calendar, julday, secofday, &year, &month, &day, &hour, &minute, &second);
62310   printf("%d/%02d/%02d %02d:%02d:%02d   %d %d\n", year, month, day, hour, minute, second, julday, secofday);
62311 
62312   for ( int i = 0; i < 420; i++ )
62313     {
62314 
62315       decode_juldaysec(calendar, julday, secofday, &year, &month, &day, &hour, &minute, &second);
62316       printf("%2d %d/%02d/%02d %02d:%02d:%02d\n", i, year, month, day, hour, minute, second);
62317       julday_add_seconds(value*factor, &julday, &secofday);
62318     }
62319 
62320   return 0;
62321 }
62322 #endif
62323 /*
62324  * Local Variables:
62325  * c-file-style: "Java"
62326  * c-basic-offset: 2
62327  * indent-tabs-mode: nil
62328  * show-trailing-whitespace: t
62329  * require-trailing-newline: t
62330  * End:
62331  */
62332 #include <limits.h>
62333 
62334 
62335 
62336 
62337 static
tstepsInitEntry(stream_t * streamptr,size_t tsID)62338 void tstepsInitEntry(stream_t *streamptr, size_t tsID)
62339 {
62340   streamptr->tsteps[tsID].curRecID     = CDI_UNDEFID;
62341   streamptr->tsteps[tsID].position     = 0;
62342   streamptr->tsteps[tsID].records      = NULL;
62343   streamptr->tsteps[tsID].recordSize   = 0;
62344   streamptr->tsteps[tsID].nallrecs     = 0;
62345   streamptr->tsteps[tsID].recIDs       = NULL;
62346   streamptr->tsteps[tsID].nrecs        = 0;
62347   streamptr->tsteps[tsID].next         = 0;
62348 
62349   ptaxisInit(&streamptr->tsteps[tsID].taxis);
62350 }
62351 
62352 
tstepsNewEntry(stream_t * streamptr)62353 int tstepsNewEntry(stream_t *streamptr)
62354 {
62355   size_t tsID            = (size_t)streamptr->tstepsNextID++;
62356   size_t tstepsTableSize = (size_t)streamptr->tstepsTableSize;
62357   tsteps_t *tstepsTable  = streamptr->tsteps;
62358 
62359   /*
62360     If the table overflows, double its size.
62361   */
62362   if ( tsID == tstepsTableSize )
62363     {
62364       if ( tstepsTableSize == 0 ) tstepsTableSize = 1;
62365       if ( tstepsTableSize <= INT_MAX / 2)
62366         tstepsTableSize *= 2;
62367       else if ( tstepsTableSize < INT_MAX)
62368         tstepsTableSize = INT_MAX;
62369       else
62370         Error("Resizing of tstep table failed!");
62371       tstepsTable = (tsteps_t *) Realloc(tstepsTable,
62372                                          tstepsTableSize * sizeof (tsteps_t));
62373     }
62374 
62375   streamptr->tstepsTableSize = (int)tstepsTableSize;
62376   streamptr->tsteps          = tstepsTable;
62377 
62378   tstepsInitEntry(streamptr, tsID);
62379 
62380   streamptr->tsteps[tsID].taxis.used = true;
62381 
62382   return (int)tsID;
62383 }
62384 
62385 
cdiCreateTimesteps(stream_t * streamptr)62386 void cdiCreateTimesteps(stream_t *streamptr)
62387 {
62388   if ( streamptr->ntsteps < 0 || streamptr->tstepsTableSize > 0 )
62389     return;
62390 
62391   long ntsteps = (streamptr->ntsteps == 0) ? 1 : streamptr->ntsteps;
62392 
62393   streamptr->tsteps = (tsteps_t *) Malloc((size_t)ntsteps*sizeof(tsteps_t));
62394 
62395   streamptr->tstepsTableSize = (int)ntsteps;
62396   streamptr->tstepsNextID    = (int)ntsteps;
62397 
62398   for ( long tsID = 0; tsID < ntsteps; tsID++ )
62399     {
62400       tstepsInitEntry(streamptr, (size_t)tsID);
62401       streamptr->tsteps[tsID].taxis.used = true;
62402     }
62403 }
62404 /*
62405  * Local Variables:
62406  * c-file-style: "Java"
62407  * c-basic-offset: 2
62408  * indent-tabs-mode: nil
62409  * show-trailing-whitespace: t
62410  * require-trailing-newline: t
62411  * End:
62412  */
62413 #ifdef HAVE_CONFIG_H
62414 #endif
62415 
62416 #define _XOPEN_SOURCE 600
62417 
62418 #include <errno.h>
62419 #include <stdio.h>
62420 #include <stdlib.h>
62421 #include <string.h>
62422 
62423 
62424 
62425 static const char uuidFmt[] = "%02hhx%02hhx%02hhx%02hhx-"
62426   "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-"
62427   "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx";
62428 
62429 enum {
62430   uuidNumHexChars = 36,
62431 };
62432 
62433 
cdiUUID2Str(const unsigned char * uuid,char * uuidstr)62434 void cdiUUID2Str(const unsigned char *uuid, char *uuidstr)
62435 {
62436 
62437   if ( uuid == NULL || uuidstr == NULL ) return;
62438 
62439   int iret = sprintf(uuidstr, uuidFmt,
62440                      uuid[0], uuid[1], uuid[2], uuid[3],
62441                      uuid[4], uuid[5], uuid[6], uuid[7],
62442                      uuid[8], uuid[9], uuid[10], uuid[11],
62443                      uuid[12], uuid[13], uuid[14], uuid[15]);
62444 
62445   if ( iret != uuidNumHexChars ) uuidstr[0] = 0;
62446 }
62447 
62448 
cdiStr2UUID(const char * uuidstr,unsigned char * uuid)62449 int cdiStr2UUID(const char *uuidstr, unsigned char *uuid)
62450 {
62451   if ( uuid == NULL || uuidstr == NULL || strlen(uuidstr) != uuidNumHexChars)
62452     return -1;
62453 
62454   int iret = sscanf(uuidstr, uuidFmt,
62455                     &uuid[0], &uuid[1], &uuid[2], &uuid[3],
62456                     &uuid[4], &uuid[5], &uuid[6], &uuid[7],
62457                     &uuid[8], &uuid[9], &uuid[10], &uuid[11],
62458                     &uuid[12], &uuid[13], &uuid[14], &uuid[15]);
62459   if ( iret != CDI_UUID_SIZE ) return -1;
62460   return iret;
62461 }
62462 
62463 //Returns a malloc'ed string that escapes all spaces and backslashes with backslashes.
cdiEscapeSpaces(const char * string)62464 char* cdiEscapeSpaces(const char* string)
62465 {
62466   //How much memory do we need?
62467   size_t escapeCount = 0, length = 0;
62468   for(; string[length]; ++length)
62469     escapeCount += string[length] == ' ' || string[length] == '\\';
62470 
62471   char* result = (char *) Malloc(length + escapeCount + 1);
62472   if(!result) return NULL;
62473 
62474   //Do the escaping.
62475   for(size_t in = 0, out = 0; in < length; ++out, ++in)
62476     {
62477       if(string[in] == ' ' || string[in] == '\\') result[out++] = '\\';
62478       result[out] = string[in];
62479     }
62480   result[length + escapeCount] = 0;     //termination!
62481   return result;
62482 }
62483 
62484 //input: a space terminated string that may contain escaped characters
62485 //output: a new zero terminated string with the escape characters removed
62486 //*outStringEnd points to the terminating character upon return.
cdiUnescapeSpaces(const char * string,const char ** outStringEnd)62487 char* cdiUnescapeSpaces(const char* string, const char** outStringEnd)
62488 {
62489   //How much memory do we need?
62490   size_t escapeCount = 0, length = 0;
62491   for(const char* current = string; *current && *current != ' '; current++)
62492     {
62493       if(*current == '\\')
62494         {
62495           current++, escapeCount++;
62496           if(!current) return NULL;
62497         }
62498       length++;
62499     }
62500 
62501   char* result = (char *) Malloc(length + 1);
62502   if(!result) return NULL;
62503 
62504   //Do the unescaping.
62505   for(size_t in = 0, out = 0; out < length;)
62506     {
62507       if(string[in] == '\\') in++;
62508       result[out++] = string[in++];
62509     }
62510   result[length] = 0;   //termination!
62511   if(outStringEnd) *outStringEnd = &string[length + escapeCount];
62512   return result;
62513 }
62514 
62515 #if defined(HAVE_DECL_UUID_GENERATE) && defined(HAVE_UUID_UUID_H)
62516 #ifdef HAVE_SYS_TIME_H
62517 #include <sys/time.h>
62518 #endif
62519 #include <uuid/uuid.h>
cdiCreateUUID(unsigned char * uuid)62520 void cdiCreateUUID(unsigned char *uuid)
62521 {
62522   static int uuid_seeded = 0;
62523   static char uuid_rand_state[31 * sizeof (long)];
62524   char *caller_rand_state;
62525   if (uuid_seeded)
62526     caller_rand_state = setstate(uuid_rand_state);
62527   else
62528     {
62529       struct timeval tv;
62530       int status = gettimeofday(&tv, NULL);
62531       if (status != 0)
62532         {
62533           perror("uuid random seed generation failed!");
62534           exit(1);
62535         }
62536       unsigned seed = (unsigned)(tv.tv_sec ^ tv.tv_usec);
62537       caller_rand_state = initstate(seed, uuid_rand_state, sizeof (uuid_rand_state));
62538       uuid_seeded = 1;
62539     }
62540   uuid_generate(uuid);
62541   setstate(caller_rand_state);
62542 }
62543 #elif defined (HAVE_DECL_UUID_CREATE) && defined (HAVE_UUID_H)
62544 #  ifdef HAVE_DECL_UUID_MAKE_V5
62545 #    include <uuid.h>
cdiCreateUUID(unsigned char * uuid)62546 void cdiCreateUUID(unsigned char *uuid)
62547 {
62548   static const char error_stage[][16]
62549     = { "uuid_create", "uuid_create", "uuid_load", "uuid_make", "uuid_export",
62550         "uuid_destroy1", "uuid_destroy2" };
62551   uuid_t *objuuid = NULL, *nsuuid = NULL;
62552   int stage = 0;
62553   uuid_rc_t status;
62554   if ((status = uuid_create(&objuuid)) == UUID_RC_OK)
62555     {
62556       ++stage;
62557       if ((status = uuid_create(&nsuuid)) == UUID_RC_OK)
62558         {
62559           ++stage;
62560           if ((status = uuid_load(nsuuid, "ns:OID")) == UUID_RC_OK)
62561             {
62562               ++stage;
62563               if ((status = uuid_make(objuuid, UUID_MAKE_V5, nsuuid, cdiLibraryVersion()))
62564                   == UUID_RC_OK)
62565                 {
62566                   ++stage;
62567                   size_t datalen = CDI_UUID_SIZE;
62568                   status = uuid_export(objuuid, UUID_FMT_BIN, &uuid, &datalen);
62569                 }
62570             }
62571         }
62572     }
62573   if (status != UUID_RC_OK)
62574     Error("failed to generate UUID at stage %s\n", error_stage[stage]);
62575   stage = 5;
62576   if ((status = uuid_destroy(nsuuid)) != UUID_RC_OK)
62577     Error("failed to generate UUID at stage %s\n", error_stage[stage]);
62578   ++stage;
62579   if ((status = uuid_destroy(objuuid)) != UUID_RC_OK)
62580     Error("failed to generate UUID at stage %s\n", error_stage[stage]);
62581 }
62582 #  else
62583 #include <inttypes.h>
62584 typedef uint8_t u_int8_t;
62585 typedef uint16_t u_int16_t;
62586 typedef uint32_t u_int32_t;
62587 #include <uuid.h>
cdiCreateUUID(unsigned char * uuid)62588 void cdiCreateUUID(unsigned char *uuid)
62589 {
62590   uint32_t status;
62591   uuid_create((uuid_t *)(void *)uuid, &status);
62592   if (status != uuid_s_ok)
62593     {
62594       perror("uuid generation failed!");
62595       exit(1);
62596     }
62597 }
62598 #  endif
62599 #else
62600 #ifdef HAVE_SYS_TIME_H
62601 #include <sys/time.h>
62602 #endif
cdiCreateUUID(unsigned char * uuid)62603 void cdiCreateUUID(unsigned char *uuid)
62604 {
62605   static int uuid_seeded = 0;
62606 #ifndef _SX
62607   static char uuid_rand_state[31 * sizeof (long)];
62608   char *caller_rand_state;
62609   if (uuid_seeded)
62610     caller_rand_state = setstate(uuid_rand_state);
62611   else
62612     {
62613 #ifdef HAVE_SYS_TIME_H
62614       struct timeval tv;
62615       int status = gettimeofday(&tv, NULL);
62616       if (status != 0)
62617         {
62618           perror("failed seed generation!");
62619           exit(1);
62620         }
62621       unsigned seed = tv.tv_sec ^ tv.tv_usec;
62622 #else
62623       unsigned seed = 0;
62624 #endif
62625       caller_rand_state = initstate(seed, uuid_rand_state,
62626                                     sizeof (uuid_rand_state));
62627       uuid_seeded = 1;
62628     }
62629   for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
62630     uuid[i] = (unsigned char)random();
62631 #else
62632   unsigned short caller_rand_state[3];
62633   {
62634     static unsigned short our_rand_state[3];
62635     if (!uuid_seeded)
62636       {
62637 #ifdef HAVE_SYS_TIME_H
62638         struct timeval tv;
62639         int status = gettimeofday(&tv, NULL);
62640         if (status != 0)
62641           {
62642             perror("failed seed generation!");
62643             exit(1);
62644           }
62645         unsigned seed = tv.tv_sec ^ tv.tv_usec;
62646 #else
62647         unsigned seed = 0;
62648 #endif
62649         our_rand_state[0] = 0x330E;
62650         our_rand_state[1] = (unsigned short)(seed & 0xFFFFU);
62651         our_rand_state[2] = (unsigned short)((seed >> 16) & 0xFFFFU);
62652       }
62653     unsigned short *p = seed48(our_rand_state);
62654     uuid_seeded = 1;
62655     memcpy(caller_rand_state, p, sizeof (caller_rand_state));
62656   }
62657   for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
62658     uuid[i] = (unsigned char)lrand48();
62659 #endif
62660   /* encode variant into msb of octet 8 */
62661   uuid[8] = (unsigned char)((uuid[8] & 0x3f) | (1 << 7));
62662   /* encode version 4 ((pseudo-)random uuid) into msb of octet 7 */
62663   uuid[7] = (unsigned char)((uuid[7] & 0x0f) | (4 << 4));
62664 #ifndef _SX
62665   setstate(caller_rand_state);
62666 #else
62667   seed48(caller_rand_state);
62668 #endif
62669 }
62670 #endif
62671 
62672 /*
62673  * Local Variables:
62674  * c-file-style: "Java"
62675  * c-basic-offset: 2
62676  * indent-tabs-mode: nil
62677  * show-trailing-whitespace: t
62678  * require-trailing-newline: t
62679  * End:
62680  */
62681 #ifdef HAVE_CONFIG_H
62682 #endif
62683 
62684 
62685 
62686 
62687 static size_t Vctsize = 0;
62688 static double *Vct = NULL;
62689 
62690 static int numberOfVerticalLevels = 0;
62691 static int numberOfVerticalGrid = 0;
62692 static unsigned char uuidVGrid[CDI_UUID_SIZE];
62693 
62694 
62695 typedef struct
62696 {
62697   int      level1;
62698   int      level2;
62699   int      recID;
62700   int      lindex;
62701 }
62702 leveltable_t;
62703 
62704 
62705 typedef struct
62706 {
62707   int           subtypeIndex; //  corresponding tile in subtype_t structure (subtype->self)
62708   unsigned      nlevels;
62709   int           levelTableSize;
62710   leveltable_t* levelTable;
62711 } subtypetable_t;
62712 
62713 
62714 typedef struct
62715 {
62716   int            varID;
62717   int            param;
62718   int            prec;
62719   int            tsteptype;
62720   VarScanKeys    scanKeys;
62721   int            gridID;
62722   int            zaxistype;
62723   int            ltype1;        // GRIB first level type
62724   int            ltype2;        // GRIB second level type
62725   int            lbounds;
62726   int            level_sf;
62727   int            level_unit;
62728   int            zaxisID;
62729 
62730   int            nsubtypes_alloc;
62731   int            nsubtypes;
62732   subtypetable_t *recordTable;   // ~ two-dimensional record list [nsubtypes_alloc][levelTableSize]
62733 
62734   int            instID;
62735   int            modelID;
62736   int            tableID;
62737   int            comptype;       // compression type
62738   int            complevel;      // compression level
62739   bool           lmissval;
62740   double         missval;
62741   char          *name;
62742 
62743   /* meta-data for specification of tiles (currently only GRIB-API: */
62744   subtype_t     *tiles;
62745 
62746   cdi_keys_t     keys;
62747 
62748   int                 opt_grib_nentries;        // current no. key-value pairs
62749   int                 opt_grib_kvpair_size;     // current allocated size
62750   opt_key_val_pair_t *opt_grib_kvpair;          // (optional) list of keyword/value pairs
62751 }
62752 vartable_t;
62753 
62754 
62755 static vartable_t *vartable;
62756 static unsigned varTablesize = 0;
62757 static unsigned varTableUsed = 0;
62758 
62759 static
paramInitEntry(unsigned varID,int param)62760 void paramInitEntry(unsigned varID, int param)
62761 {
62762   vartable[varID].varID          = (int)varID;
62763   vartable[varID].param          = param;
62764   vartable[varID].prec           = 0;
62765   vartable[varID].tsteptype      = TSTEP_INSTANT;
62766   varScanKeysInit(&vartable[varID].scanKeys);
62767   vartable[varID].gridID         = CDI_UNDEFID;
62768   vartable[varID].zaxistype      = 0;
62769   vartable[varID].ltype1         = 0;
62770   vartable[varID].ltype2         = -1;
62771   vartable[varID].lbounds        = 0;
62772   vartable[varID].level_sf       = 0;
62773   vartable[varID].level_unit     = 0;
62774   vartable[varID].recordTable    = NULL;
62775   vartable[varID].nsubtypes_alloc= 0;
62776   vartable[varID].nsubtypes      = 0;
62777   vartable[varID].instID         = CDI_UNDEFID;
62778   vartable[varID].modelID        = CDI_UNDEFID;
62779   vartable[varID].tableID        = CDI_UNDEFID;
62780   cdiInitKeys(&vartable[varID].keys);
62781   vartable[varID].comptype       = CDI_COMPRESS_NONE;
62782   vartable[varID].complevel      = 1;
62783   vartable[varID].lmissval       = false;
62784   vartable[varID].missval        = 0;
62785   vartable[varID].name           = NULL;
62786   vartable[varID].tiles          = NULL;
62787 }
62788 
62789 // Test if a variable specified by the given meta-data has already been registered in "vartable".
62790 static unsigned
varGetEntry(int param,int gridID,int zaxistype,int ltype1,int tsteptype,const char * name,const VarScanKeys * scanKeys,const var_tile_t * tiles)62791 varGetEntry(int param, int gridID, int zaxistype, int ltype1, int tsteptype, const char *name, const VarScanKeys *scanKeys, const var_tile_t *tiles)
62792 {
62793   for ( unsigned varID = 0; varID < varTablesize; varID++ )
62794     {
62795       // testing for "param" implicitly checks if we are beyond the current vartable size:
62796       if ( vartable[varID].param == param )
62797         {
62798           const int no_of_tiles = tiles ? tiles->numberOfTiles : -1;
62799           const int vt_no_of_tiles = vartable[varID].tiles ?
62800             subtypeGetGlobalDataP(vartable[varID].tiles, SUBTYPE_ATT_NUMBER_OF_TILES) : -1;
62801           if ( (vartable[varID].zaxistype  == zaxistype)               &&
62802                (vartable[varID].ltype1     == ltype1   )               &&
62803                (vartable[varID].tsteptype  == tsteptype)               &&
62804                (scanKeys == NULL || varScanKeysIsEqual(&vartable[varID].scanKeys, scanKeys))  &&
62805                (vartable[varID].gridID     == gridID   )               &&
62806                (vt_no_of_tiles == no_of_tiles) )
62807             {
62808               if ( name && name[0] && vartable[varID].name && vartable[varID].name[0] )
62809                 {
62810                   if ( strcmp(name, vartable[varID].name) == 0 ) return varID;
62811                 }
62812               else
62813                 {
62814                   return varID;
62815                 }
62816             }
62817         }
62818     }
62819 
62820   return (unsigned)-1;
62821 }
62822 
62823 static
varFree(void)62824 void varFree(void)
62825 {
62826   if ( CDI_Debug ) Message("call to varFree");
62827 
62828   for ( size_t varID = 0; varID < varTableUsed; varID++ )
62829     {
62830       if ( vartable[varID].recordTable )
62831         {
62832           for (int isub=0; isub<vartable[varID].nsubtypes_alloc; isub++)
62833             Free(vartable[varID].recordTable[isub].levelTable);
62834           Free(vartable[varID].recordTable);
62835         }
62836 
62837       if ( vartable[varID].name )     Free(vartable[varID].name);
62838       if ( vartable[varID].tiles )    subtypeDestroyPtr(vartable[varID].tiles);
62839 
62840       cdi_keys_t *keysp = &(vartable[varID].keys);
62841       cdiDeleteVarKeys(keysp);
62842 
62843       if ( vartable[varID].opt_grib_kvpair )
62844         {
62845           for (int i=0; i<vartable[varID].opt_grib_nentries; i++)
62846             {
62847               if ( vartable[varID].opt_grib_kvpair[i].keyword )
62848                 Free(vartable[varID].opt_grib_kvpair[i].keyword);
62849             }
62850           Free(vartable[varID].opt_grib_kvpair);
62851         }
62852       vartable[varID].opt_grib_nentries    = 0;
62853       vartable[varID].opt_grib_kvpair_size = 0;
62854       vartable[varID].opt_grib_kvpair      = NULL;
62855     }
62856 
62857   if ( vartable ) Free(vartable);
62858   vartable = NULL;
62859   varTablesize = 0;
62860   varTableUsed = 0;
62861 
62862   if ( Vct ) Free(Vct);
62863   Vct = NULL;
62864   Vctsize = 0;
62865 }
62866 
62867 // Search for a tile subtype with subtypeIndex == tile_index.
tileGetEntry(unsigned varID,int tile_index)62868 static int tileGetEntry(unsigned varID, int tile_index)
62869 {
62870   for (int isub=0; isub<vartable[varID].nsubtypes; isub++)
62871     if (vartable[varID].recordTable[isub].subtypeIndex == tile_index)
62872       return isub;
62873   return CDI_UNDEFID;
62874 }
62875 
62876 
62877 /* Resizes vartable:recordTable data structure, if necessary. */
tileNewEntry(int varID)62878 static int tileNewEntry(int varID)
62879 {
62880   int tileID = 0;
62881   if (vartable[varID].nsubtypes_alloc == 0)
62882     {
62883       /* create table for the first time. */
62884       vartable[varID].nsubtypes_alloc = 2;
62885       vartable[varID].nsubtypes       = 0;
62886       vartable[varID].recordTable     =
62887         (subtypetable_t *) Malloc((size_t)vartable[varID].nsubtypes_alloc * sizeof (subtypetable_t));
62888       if( vartable[varID].recordTable == NULL )
62889         SysError("Allocation of leveltable failed!");
62890 
62891       for (int isub = 0; isub<vartable[varID].nsubtypes_alloc; isub++) {
62892 	vartable[varID].recordTable[isub].levelTable     = NULL;
62893         vartable[varID].recordTable[isub].levelTableSize = 0;
62894         vartable[varID].recordTable[isub].nlevels        = 0;
62895         vartable[varID].recordTable[isub].subtypeIndex   = CDI_UNDEFID;
62896       }
62897     }
62898   else
62899     {
62900       /* data structure large enough; find a free entry. */
62901       while(tileID <  vartable[varID].nsubtypes_alloc)
62902 	{
62903 	  if (vartable[varID].recordTable[tileID].levelTable == NULL) break;
62904 	  tileID++;
62905 	}
62906     }
62907 
62908   /* If the table overflows, double its size. */
62909   if (tileID == vartable[varID].nsubtypes_alloc)
62910     {
62911       tileID = vartable[varID].nsubtypes_alloc;
62912       vartable[varID].nsubtypes_alloc *= 2;
62913       vartable[varID].recordTable   =
62914         (subtypetable_t *) Realloc(vartable[varID].recordTable,
62915                                    (size_t)vartable[varID].nsubtypes_alloc * sizeof (subtypetable_t));
62916       if (vartable[varID].recordTable == NULL)
62917         SysError("Reallocation of leveltable failed");
62918       for(int isub=tileID; isub<vartable[varID].nsubtypes_alloc; isub++) {
62919 	vartable[varID].recordTable[isub].levelTable     = NULL;
62920         vartable[varID].recordTable[isub].levelTableSize = 0;
62921         vartable[varID].recordTable[isub].nlevels        = 0;
62922         vartable[varID].recordTable[isub].subtypeIndex   = CDI_UNDEFID;
62923       }
62924     }
62925 
62926   return tileID;
62927 }
62928 
62929 
levelNewEntry(unsigned varID,int level1,int level2,int tileID)62930 static int levelNewEntry(unsigned varID, int level1, int level2, int tileID)
62931 {
62932   int levelID = 0;
62933   int levelTableSize = vartable[varID].recordTable[tileID].levelTableSize;
62934   leveltable_t *levelTable = vartable[varID].recordTable[tileID].levelTable;
62935 
62936   // Look for a free slot in levelTable. (Create the table the first time through).
62937   if ( ! levelTableSize )
62938     {
62939       levelTableSize = 2;
62940       levelTable = (leveltable_t *) Malloc((size_t)levelTableSize * sizeof (leveltable_t));
62941       for ( int i = 0; i < levelTableSize; i++ ) levelTable[i].recID = CDI_UNDEFID;
62942     }
62943   else
62944     {
62945       while( levelID < levelTableSize && levelTable[levelID].recID != CDI_UNDEFID )
62946         ++levelID;
62947     }
62948 
62949   // If the table overflows, double its size.
62950   if ( levelID == levelTableSize )
62951     {
62952       levelTable = (leveltable_t *) Realloc(levelTable,
62953                                             (size_t)(levelTableSize *= 2)
62954                                             * sizeof (leveltable_t));
62955       for( int i = levelID; i < levelTableSize; i++ )
62956         levelTable[i].recID = CDI_UNDEFID;
62957     }
62958 
62959   levelTable[levelID].level1 = level1;
62960   levelTable[levelID].level2 = level2;
62961   levelTable[levelID].lindex = levelID;
62962 
62963   vartable[varID].recordTable[tileID].nlevels        = (unsigned)levelID+1;
62964   vartable[varID].recordTable[tileID].levelTableSize = levelTableSize;
62965   vartable[varID].recordTable[tileID].levelTable     = levelTable;
62966 
62967   return levelID;
62968 }
62969 
62970 #define  UNDEF_PARAM  -4711
62971 
62972 static unsigned
paramNewEntry(int param)62973 paramNewEntry(int param)
62974 {
62975   unsigned varID = 0;
62976 
62977   // Look for a free slot in vartable. (Create the table the first time through).
62978   if ( ! varTablesize )
62979     {
62980       varTablesize = 2;
62981       vartable = (vartable_t *) Malloc((size_t)varTablesize * sizeof (vartable_t));
62982       if( vartable == NULL )
62983 	{
62984           Message("varTablesize = %d", varTablesize);
62985 	  SysError("Allocation of vartable failed");
62986 	}
62987 
62988       for( unsigned i = 0; i < varTablesize; i++ )
62989         {
62990           vartable[i].param = UNDEF_PARAM;
62991           vartable[i].opt_grib_kvpair      = NULL;
62992           vartable[i].opt_grib_kvpair_size = 0;
62993           vartable[i].opt_grib_nentries    = 0;
62994         }
62995     }
62996   else
62997     {
62998       while( varID < varTablesize )
62999 	{
63000 	  if ( vartable[varID].param == UNDEF_PARAM ) break;
63001 	  varID++;
63002 	}
63003     }
63004 
63005   // If the table overflows, double its size.
63006   if ( varID == varTablesize )
63007     {
63008       vartable = (vartable_t *) Realloc(vartable, (size_t)(varTablesize *= 2)
63009                                         * sizeof (vartable_t));
63010       for ( size_t i = varID; i < varTablesize; i++ )
63011         {
63012           vartable[i].param = UNDEF_PARAM;
63013           vartable[i].opt_grib_kvpair      = NULL;
63014           vartable[i].opt_grib_kvpair_size = 0;
63015           vartable[i].opt_grib_nentries    = 0;
63016         }
63017     }
63018 
63019   paramInitEntry(varID, param);
63020 
63021   return varID;
63022 }
63023 
63024 // Append tile set to a subtype. Return index of the new tile (i.e. the "entry->self" value).
63025 static
varInsertTileSubtype(vartable_t * vptr,const var_tile_t * tiles)63026 int varInsertTileSubtype(vartable_t *vptr, const var_tile_t *tiles)
63027 {
63028   if ( tiles == NULL ) return 0;
63029 
63030   // first, generate a subtype based on the info in "tiles".
63031   subtype_t *subtype_ptr;
63032   subtypeAllocate(&subtype_ptr, SUBTYPE_TILES);
63033   subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_TOTALNO_OF_TILEATTR_PAIRS, tiles->totalno_of_tileattr_pairs);
63034   subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_TILE_CLASSIFICATION      , tiles->tileClassification);
63035   subtypeDefGlobalDataP(subtype_ptr, SUBTYPE_ATT_NUMBER_OF_TILES          , tiles->numberOfTiles);
63036 
63037   // Here, we create a tile set for comparison that contains only one tile/attribute pair (based on "tiles").
63038   struct subtype_entry_t *entry = subtypeEntryInsert(subtype_ptr);
63039   subtypeDefEntryDataP(entry, SUBTYPE_ATT_NUMBER_OF_ATTR, tiles->numberOfAttributes);
63040   subtypeDefEntryDataP(entry, SUBTYPE_ATT_TILEINDEX,      tiles->tileindex);
63041   subtypeDefEntryDataP(entry, SUBTYPE_ATT_TILEATTRIBUTE,  tiles->attribute);
63042 
63043   if (vptr->tiles == NULL) {
63044     vptr->tiles = subtype_ptr;
63045     return 0;
63046   }
63047   else {
63048     tilesetInsertP(vptr->tiles, subtype_ptr);
63049     subtypeDestroyPtr(subtype_ptr);
63050     return vptr->tiles->nentries - 1;
63051   }
63052 
63053   return CDI_UNDEFID;
63054 }
63055 
63056 
varAddRecord(int recID,int param,int gridID,int zaxistype,int lbounds,int level1,int level2,int level_sf,int level_unit,int prec,int * pvarID,int * plevelID,int tsteptype,int ltype1,int ltype2,const char * name,const VarScanKeys * scanKeys,const var_tile_t * tiles,int * tile_index)63057 void varAddRecord(int recID, int param, int gridID, int zaxistype, int lbounds,
63058 		  int level1, int level2, int level_sf, int level_unit, int prec,
63059 		  int *pvarID, int *plevelID, int tsteptype, int ltype1, int ltype2,
63060 		  const char *name, const VarScanKeys *scanKeys, const var_tile_t *tiles, int *tile_index)
63061 {
63062   unsigned varID = (CDI_Split_Ltype105 != 1 || zaxistype != ZAXIS_HEIGHT) ?
63063     varGetEntry(param, gridID, zaxistype, ltype1, tsteptype, name, scanKeys, tiles) : (unsigned) CDI_UNDEFID;
63064 
63065   if ( varID == (unsigned) CDI_UNDEFID )
63066     {
63067       varTableUsed++;
63068       varID = paramNewEntry(param);
63069       vartable[varID].gridID     = gridID;
63070       vartable[varID].zaxistype  = zaxistype;
63071       vartable[varID].ltype1     = ltype1;
63072       vartable[varID].ltype2     = ltype2;
63073       vartable[varID].lbounds    = lbounds;
63074       vartable[varID].level_sf   = level_sf;
63075       vartable[varID].level_unit = level_unit;
63076       vartable[varID].tsteptype  = tsteptype;
63077       if (scanKeys) vartable[varID].scanKeys = *scanKeys;
63078 
63079       if ( name && name[0] )         vartable[varID].name     = strdup(name);
63080     }
63081   else
63082     {
63083       char paramstr[32];
63084       cdiParamToString(param, paramstr, sizeof(paramstr));
63085 
63086       if ( vartable[varID].gridID != gridID )
63087 	{
63088 	  Message("param = %s gridID = %d", paramstr, gridID);
63089 	  Error("horizontal grid must not change for same parameter!");
63090 	}
63091       if ( vartable[varID].zaxistype != zaxistype )
63092 	{
63093 	  Message("param = %s zaxistype = %d", paramstr, zaxistype);
63094 	  Error("zaxistype must not change for same parameter!");
63095 	}
63096     }
63097 
63098   if ( prec > vartable[varID].prec ) vartable[varID].prec = prec;
63099 
63100   // append current tile to tile subtype info.
63101   const int this_tile = varInsertTileSubtype(&vartable[varID], tiles);
63102   int tileID = tileGetEntry(varID, this_tile);
63103   if ( tile_index ) (*tile_index) = this_tile;
63104   if ( tileID == CDI_UNDEFID )
63105     {
63106       tileID = tileNewEntry((int)varID);
63107       vartable[varID].recordTable[tileID].subtypeIndex = this_tile;
63108       vartable[varID].nsubtypes++;
63109     }
63110 
63111   // append current level to level table info
63112   const int levelID = levelNewEntry(varID, level1, level2, tileID);
63113   if (CDI_Debug)
63114     Message("vartable[%d].recordTable[%d].levelTable[%d].recID = %d; level1,2=%d,%d",
63115             varID, tileID, levelID, recID, level1, level2);
63116   vartable[varID].recordTable[tileID].levelTable[levelID].recID = recID;
63117 
63118   *pvarID   = (int) varID;
63119   *plevelID = levelID;
63120 }
63121 
63122 
63123 /*
63124 static
63125 int dblcmp(const void *s1, const void *s2)
63126 {
63127   int cmp = 0;
63128 
63129   if      ( *((double *) s1) < *((double *) s2) ) cmp = -1;
63130   else if ( *((double *) s1) > *((double *) s2) ) cmp =  1;
63131 
63132   return cmp;
63133 }
63134 */
63135 static
cmpLevelTable(const void * s1,const void * s2)63136 int cmpLevelTable(const void* s1, const void* s2)
63137 {
63138   int cmp = 0;
63139   const leveltable_t *x = (const leveltable_t*) s1;
63140   const leveltable_t *y = (const leveltable_t*) s2;
63141   // printf("%g %g  %d %d\n", x->leve11, y->level1, x, y);
63142   if      ( x->level1 < y->level1 ) cmp = -1;
63143   else if ( x->level1 > y->level1 ) cmp =  1;
63144 
63145   return cmp;
63146 }
63147 
63148 static
cmpLevelTableInv(const void * s1,const void * s2)63149 int cmpLevelTableInv(const void* s1, const void* s2)
63150 {
63151   int cmp = 0;
63152   const leveltable_t *x = (const leveltable_t*) s1;
63153   const leveltable_t *y = (const leveltable_t*) s2;
63154   // printf("%g %g  %d %d\n", x->leve11, y->level1, x, y);
63155   if      ( x->level1 < y->level1 ) cmp =  1;
63156   else if ( x->level1 > y->level1 ) cmp = -1;
63157 
63158   return cmp;
63159 }
63160 
63161 
varCopyKeys(int vlistID,int varID)63162 void varCopyKeys(int vlistID, int varID)
63163 {
63164   vlist_t *vlistptr = vlist_to_pointer(vlistID);
63165   cdiInitKeys(&vlistptr->vars[varID].keys);
63166   cdiCopyVarKeys(&vartable[varID].keys, &vlistptr->vars[varID].keys);
63167 }
63168 
63169 
63170 struct cdi_generate_varinfo
63171 {
63172   int        varid;
63173   const char *name;
63174 };
63175 
63176 static
cdi_generate_cmp_varname(const void * s1,const void * s2)63177 int cdi_generate_cmp_varname(const void *s1, const void *s2)
63178 {
63179   const struct cdi_generate_varinfo *x = (const struct cdi_generate_varinfo *)s1,
63180                                     *y = (const struct cdi_generate_varinfo *)s2;
63181   return strcmp(x->name, y->name);
63182 }
63183 
cdi_generate_vars(stream_t * streamptr)63184 void cdi_generate_vars(stream_t *streamptr)
63185 {
63186   const int vlistID = streamptr->vlistID;
63187 
63188   int *varids = (int *) Malloc(varTableUsed*sizeof(int));
63189   for ( size_t varID = 0; varID < varTableUsed; varID++ ) varids[varID] = (int)varID;
63190   /*
63191   if ( streamptr->sortname )
63192     {
63193       size_t varID;
63194       for ( varID = 0; varID < varTableUsed; varID++ )
63195         if (!vartable[varID].name) break;
63196 
63197       if ( varID == varTableUsed )
63198         {
63199           struct cdi_generate_varinfo *varInfo
63200             = (struct cdi_generate_varinfo *) Malloc((size_t)varTableUsed * sizeof(struct cdi_generate_varinfo));
63201 
63202           for ( size_t varID = 0; varID < varTableUsed; varID++ )
63203             {
63204               varInfo[varID].varid = varids[varID];
63205               varInfo[varID].name = vartable[varids[varID]].name;
63206             }
63207           qsort(varInfo, varTableUsed, sizeof(varInfo[0]), cdi_generate_cmp_varname);
63208           for ( size_t varID = 0; varID < varTableUsed; varID++ )
63209             {
63210               varids[varID] = varInfo[varID].varid;
63211             }
63212           Free(varInfo);
63213         }
63214     }
63215   */
63216   for ( size_t index = 0; index < varTableUsed; index++ )
63217     {
63218       const int varid      = varids[index];
63219 
63220       const int gridID     = vartable[varid].gridID;
63221       const int param      = vartable[varid].param;
63222       const int ltype1     = vartable[varid].ltype1;
63223       const int ltype2     = vartable[varid].ltype2;
63224       int zaxistype        = vartable[varid].zaxistype;
63225       if ( ltype1 == 0 && zaxistype == ZAXIS_GENERIC && cdiDefaultLeveltype != -1 )
63226 	zaxistype = cdiDefaultLeveltype;
63227       const int lbounds    = vartable[varid].lbounds;
63228       const int prec       = vartable[varid].prec;
63229       int instID           = vartable[varid].instID;
63230       int modelID          = vartable[varid].modelID;
63231       int tableID          = vartable[varid].tableID;
63232       const int tsteptype  = vartable[varid].tsteptype;
63233       const int comptype   = vartable[varid].comptype;
63234 
63235       double level_sf = 1;
63236       if ( vartable[varid].level_sf != 0 ) level_sf = 1./vartable[varid].level_sf;
63237 
63238       /* consistency check: test if all subtypes have the same levels: */
63239       const unsigned nlevels = vartable[varid].recordTable[0].nlevels;
63240       for ( int isub = 1; isub < vartable[varid].nsubtypes; isub++ ) {
63241         if ( vartable[varid].recordTable[isub].nlevels != nlevels )
63242           {
63243             fprintf(stderr, "var \"%s\": isub = %d / %d :: "
63244                     "nlevels = %d, vartable[varid].recordTable[isub].nlevels = %d\n",
63245                     vartable[varid].name, isub, vartable[varid].nsubtypes,
63246                     nlevels, vartable[varid].recordTable[isub].nlevels);
63247             Error("zaxis size must not change for same parameter!");
63248           }
63249 
63250         const leveltable_t *t1 = vartable[varid].recordTable[isub-1].levelTable;
63251         const leveltable_t *t2 = vartable[varid].recordTable[isub  ].levelTable;
63252         for ( unsigned ilev = 0; ilev < nlevels; ilev++ )
63253           if ((t1[ilev].level1 != t2[ilev].level1)  ||
63254               (t1[ilev].level2 != t2[ilev].level2)  ||
63255               (t1[ilev].lindex != t2[ilev].lindex))
63256             {
63257               fprintf(stderr, "var \"%s\", varID=%d: isub = %d / %d :: "
63258                       "nlevels = %d, vartable[varid].recordTable[isub].nlevels = %d\n",
63259                       vartable[varid].name, varid, isub, vartable[varid].nsubtypes,
63260                       nlevels, vartable[varid].recordTable[isub].nlevels);
63261               Message("t1[ilev].level1=%d / t2[ilev].level1=%d", t1[ilev].level1, t2[ilev].level1);
63262               Message("t1[ilev].level2=%d / t2[ilev].level2=%d", t1[ilev].level2, t2[ilev].level2);
63263               Message("t1[ilev].lindex=%d / t2[ilev].lindex=%d", t1[ilev].lindex, t2[ilev].lindex);
63264               Error("zaxis type must not change for same parameter!");
63265             }
63266       }
63267       leveltable_t *levelTable = vartable[varid].recordTable[0].levelTable;
63268 
63269       if ( ltype1 == 0 && zaxistype == ZAXIS_GENERIC && nlevels == 1 && levelTable[0].level1 == 0 )
63270 	zaxistype = ZAXIS_SURFACE;
63271 
63272       double *dlevels = (double *) Malloc(nlevels*sizeof(double));
63273 
63274       /*
63275       if ( lbounds && zaxistype != ZAXIS_HYBRID && zaxistype != ZAXIS_HYBRID_HALF )
63276 	for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
63277 	  dlevels[levelID] = (level_sf*levelTable[levelID].level1 + level_sf*levelTable[levelID].level2) / 2.0;
63278       else
63279       */
63280 	for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
63281 	  dlevels[levelID] = level_sf*levelTable[levelID].level1;
63282 
63283       if ( nlevels > 1 )
63284 	{
63285           bool linc = true, ldec = true, lsort = false;
63286           for ( unsigned levelID = 1; levelID < nlevels; levelID++ )
63287             {
63288               // check increasing of levels
63289               linc &= (dlevels[levelID] > dlevels[levelID-1]);
63290               // check decreasing of levels
63291               ldec &= (dlevels[levelID] < dlevels[levelID-1]);
63292             }
63293           /*
63294            * always sort pressure z-axis to ensure
63295            * levelTable[levelID1].level1 < levelTable[levelID2].level1 <=> levelID1 > levelID2
63296            * unless already sorted in decreasing order
63297            */
63298           if ( (!linc && !ldec) && zaxistype == ZAXIS_PRESSURE )
63299             {
63300               qsort(levelTable, nlevels, sizeof(leveltable_t), cmpLevelTableInv);
63301               lsort = true;
63302             }
63303           /*
63304            * always sort hybrid and depth-below-land z-axis to ensure
63305            * levelTable[levelID1].level1 < levelTable[levelID2].level1 <=> levelID1 < levelID2
63306            * unless already sorted in increasing order
63307            */
63308           else if ( (!linc && !ldec) ||
63309                     zaxistype == ZAXIS_HYBRID ||
63310                     zaxistype == ZAXIS_DEPTH_BELOW_LAND )
63311             {
63312               qsort(levelTable, nlevels, sizeof(leveltable_t), cmpLevelTable);
63313               lsort = true;
63314             }
63315 
63316           if ( lsort )
63317             {
63318               /*
63319               if ( lbounds && zaxistype != ZAXIS_HYBRID && zaxistype != ZAXIS_HYBRID_HALF )
63320                 for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
63321                   dlevels[levelID] = (level_sf*levelTable[levelID].level1 + level_sf*levelTable[levelID].level2) / 2.0;
63322               else
63323               */
63324                 for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
63325                   dlevels[levelID] = level_sf*levelTable[levelID].level1;
63326             }
63327 	}
63328 
63329       double *dlevels1 = NULL;
63330       double *dlevels2 = NULL;
63331       if ( lbounds )
63332 	{
63333 	  dlevels1 = (double *) Malloc(nlevels*sizeof(double));
63334 	  for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
63335 	    dlevels1[levelID] = level_sf*levelTable[levelID].level1;
63336 	  dlevels2 = (double *) Malloc(nlevels*sizeof(double));
63337 	  for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
63338 	    dlevels2[levelID] = level_sf*levelTable[levelID].level2;
63339         }
63340 
63341       const char **cvals = NULL;
63342       const char *unitptr = cdiUnitNamePtr(vartable[varid].level_unit);
63343       int zaxisID = varDefZaxis(vlistID, zaxistype, (int)nlevels, dlevels, cvals, 0, lbounds, dlevels1, dlevels2,
63344                                 (int)Vctsize, Vct, NULL, NULL, unitptr, 0, 0, ltype1, ltype2);
63345 
63346       if ( CDI_CMOR_Mode && nlevels == 1 && zaxistype != ZAXIS_HYBRID ) zaxisDefScalar(zaxisID);
63347 
63348       if ( zaxisInqType(zaxisID) == ZAXIS_REFERENCE )
63349         {
63350           if ( numberOfVerticalLevels > 0 ) cdiDefKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_NLEV, numberOfVerticalLevels);
63351           if ( numberOfVerticalGrid > 0 ) cdiDefKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_NUMBEROFVGRIDUSED, numberOfVerticalGrid);
63352           if ( !cdiUUIDIsNull(uuidVGrid) ) cdiDefKeyBytes(zaxisID, CDI_GLOBAL, CDI_KEY_UUID, uuidVGrid, CDI_UUID_SIZE);
63353         }
63354 
63355       if ( lbounds ) Free(dlevels1);
63356       if ( lbounds ) Free(dlevels2);
63357       Free(dlevels);
63358 
63359       // define new subtype for tile set
63360       int tilesetID = CDI_UNDEFID;
63361       if ( vartable[varid].tiles ) tilesetID = vlistDefTileSubtype(vlistID, vartable[varid].tiles);
63362 
63363       // generate new variable
63364       int varID = stream_new_var(streamptr, gridID, zaxisID, tilesetID);
63365       varID = vlistDefVarTiles(vlistID, gridID, zaxisID, TIME_VARYING, tilesetID);
63366 
63367       vlistDefVarTsteptype(vlistID, varID, tsteptype);
63368       vlistDefVarParam(vlistID, varID, param);
63369       vlistDefVarDatatype(vlistID, varID, prec);
63370       vlistDefVarCompType(vlistID, varID, comptype);
63371 
63372       varCopyKeys(vlistID, varID);
63373 
63374       if ( vartable[varid].lmissval ) vlistDefVarMissval(vlistID, varID, vartable[varid].missval);
63375       if ( vartable[varid].name ) cdiDefKeyString(vlistID, varID, CDI_KEY_NAME, vartable[varid].name);
63376 
63377       vlist_t *vlistptr = vlist_to_pointer(vlistID);
63378       for ( int i = 0; i < vartable[varid].opt_grib_nentries; i++ )
63379         {
63380           resize_opt_grib_entries(&vlistptr->vars[varID], vlistptr->vars[varID].opt_grib_nentries+1);
63381           vlistptr->vars[varID].opt_grib_nentries += 1;
63382           const int idx = vlistptr->vars[varID].opt_grib_nentries-1;
63383 
63384           vlistptr->vars[varID].opt_grib_kvpair[idx] = vartable[varid].opt_grib_kvpair[i];
63385           vlistptr->vars[varID].opt_grib_kvpair[idx].keyword = NULL;
63386 	  if ( vartable[varid].opt_grib_kvpair[i].keyword )
63387 	    vlistptr->vars[varID].opt_grib_kvpair[idx].keyword =
63388 	      strdupx(vartable[varid].opt_grib_kvpair[i].keyword);
63389           vlistptr->vars[varID].opt_grib_kvpair[i].update = true;
63390         }
63391       // note: if the key is not defined, we do not throw an error!
63392 
63393       if ( CDI_Default_TableID != CDI_UNDEFID )
63394 	{
63395 	  int pdis, pcat, pnum;
63396 	  cdiDecodeParam(param, &pnum, &pcat, &pdis);
63397           char name[CDI_MAX_NAME]; name[0] = 0;
63398           char longname[CDI_MAX_NAME]; longname[0] = 0;
63399           char units[CDI_MAX_NAME]; units[0] = 0;
63400           tableInqEntry(CDI_Default_TableID, pnum, -1, name, longname, units);
63401 	  if ( name[0] )
63402 	    {
63403 	      if ( tableID != CDI_UNDEFID )
63404 		{
63405 		  cdiDefKeyString(vlistID, varID, CDI_KEY_NAME, name);
63406                   if ( longname[0] ) cdiDefKeyString(vlistID, varID, CDI_KEY_LONGNAME, longname);
63407                   if ( units[0] ) cdiDefKeyString(vlistID, varID, CDI_KEY_UNITS, units);
63408                 }
63409 	      else
63410 		tableID = CDI_Default_TableID;
63411 	    }
63412 	  if ( CDI_Default_ModelID != CDI_UNDEFID ) modelID = CDI_Default_ModelID;
63413 	  if ( CDI_Default_InstID  != CDI_UNDEFID )  instID = CDI_Default_InstID;
63414 	}
63415 
63416       if ( instID  != CDI_UNDEFID ) vlistDefVarInstitut(vlistID, varID, instID);
63417       if ( modelID != CDI_UNDEFID ) vlistDefVarModel(vlistID, varID, modelID);
63418       if ( tableID != CDI_UNDEFID ) vlistDefVarTable(vlistID, varID, tableID);
63419     }
63420 
63421   for ( size_t index = 0; index < varTableUsed; index++ )
63422     {
63423       int varid = varids[index];
63424       unsigned nlevels = vartable[varid].recordTable[0].nlevels;
63425 
63426       unsigned nsub = vartable[varid].nsubtypes >= 0 ? (unsigned)vartable[varid].nsubtypes : 0U;
63427       for ( size_t isub = 0; isub < nsub; isub++ )
63428         {
63429           sleveltable_t *restrict streamRecordTable = streamptr->vars[index].recordTable + isub;
63430           leveltable_t *restrict vartableLevelTable = vartable[varid].recordTable[isub].levelTable;
63431           for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
63432             {
63433               streamRecordTable->recordID[levelID] = vartableLevelTable[levelID].recID;
63434               unsigned lindex;
63435               for ( lindex = 0; lindex < nlevels; lindex++ )
63436                 if ( levelID == (unsigned)vartableLevelTable[lindex].lindex )
63437                   break;
63438               if ( lindex == nlevels )
63439                 Error("Internal problem! lindex not found.");
63440               streamRecordTable->lindex[levelID] = (int)lindex;
63441             }
63442         }
63443     }
63444 
63445   Free(varids);
63446 
63447   varFree();
63448 }
63449 
63450 
varDefVCT(size_t vctsize,double * vctptr)63451 void varDefVCT(size_t vctsize, double *vctptr)
63452 {
63453   if ( Vct == NULL && vctptr != NULL && vctsize > 0 )
63454     {
63455       Vctsize = vctsize;
63456       Vct = (double *) Malloc(vctsize*sizeof(double));
63457       memcpy(Vct, vctptr, vctsize*sizeof(double));
63458     }
63459 }
63460 
63461 
varDefZAxisReference(int nhlev,int nvgrid,unsigned char uuid[CDI_UUID_SIZE])63462 void varDefZAxisReference(int nhlev, int nvgrid, unsigned char uuid[CDI_UUID_SIZE])
63463 {
63464   numberOfVerticalLevels = nhlev;
63465   numberOfVerticalGrid = nvgrid;
63466   memcpy(uuidVGrid, uuid, CDI_UUID_SIZE);
63467 }
63468 
63469 
zaxisCompare(int zaxisID,int zaxistype,int nlevels,bool lbounds,const double * levels,const char * longname,const char * units,int ltype1,int ltype2)63470 bool zaxisCompare(int zaxisID, int zaxistype, int nlevels, bool lbounds, const double *levels, const char *longname, const char *units, int ltype1, int ltype2)
63471 {
63472   bool differ = true;
63473 
63474   int ltype1_0 = 0, ltype2_0 = -1;
63475   cdiInqKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE, &ltype1_0);
63476   cdiInqKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_TYPEOFSECONDFIXEDSURFACE, &ltype2_0);
63477   bool ltype1_is_equal = (ltype1 == ltype1_0);
63478   bool ltype2_is_equal = (ltype2 == ltype2_0);
63479 
63480   if ( ltype1_is_equal && ltype2_is_equal && (zaxistype == zaxisInqType(zaxisID) || zaxistype == ZAXIS_GENERIC) )
63481     {
63482       bool zlbounds = (zaxisInqLbounds(zaxisID, NULL) > 0);
63483       if ( nlevels == zaxisInqSize(zaxisID) && zlbounds == lbounds )
63484 	{
63485 	  const double *dlevels = zaxisInqLevelsPtr(zaxisID);
63486           if ( dlevels && levels )
63487             {
63488               int levelID;
63489               for ( levelID = 0; levelID < nlevels; levelID++ )
63490                 {
63491                   if ( fabs(dlevels[levelID] - levels[levelID]) > 1.e-9 )
63492                     break;
63493                 }
63494               if ( levelID == nlevels ) differ = false;
63495             }
63496 
63497 	  if ( ! differ )
63498 	    {
63499               if ( longname && longname[0] )
63500                 {
63501                   char zlongname[CDI_MAX_NAME];
63502                   int length = CDI_MAX_NAME;
63503                   cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_LONGNAME, zlongname, &length);
63504                   if ( zlongname[0] && (strcmp(longname, zlongname) != 0) ) differ = true;
63505                 }
63506               if ( units && units[0] )
63507                 {
63508                   char zunits[CDI_MAX_NAME];
63509                   int length = CDI_MAX_NAME;
63510                   cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, zunits, &length);
63511                   if ( zunits[0] && (strcmp(units, zunits) != 0) ) differ = true;
63512                 }
63513             }
63514 	}
63515     }
63516 
63517   return differ;
63518 }
63519 
63520 struct varDefZAxisSearchState
63521 {
63522   int resIDValue;
63523   int zaxistype;
63524   int nlevels;
63525   bool lbounds;
63526   const double *levels;
63527   const char *longname;
63528   const char *units;
63529   int ltype1;
63530   int ltype2;
63531 };
63532 
63533 static enum cdiApplyRet
varDefZAxisSearch(int id,void * res,void * data)63534 varDefZAxisSearch(int id, void *res, void *data)
63535 {
63536   struct varDefZAxisSearchState *state = (struct varDefZAxisSearchState *)data;
63537   (void)res;
63538   if ( zaxisCompare(id, state->zaxistype, state->nlevels, state->lbounds,
63539                     state->levels, state->longname, state->units, state->ltype1, state->ltype2)
63540       == false)
63541     {
63542       state->resIDValue = id;
63543       return CDI_APPLY_STOP;
63544     }
63545   else
63546     return CDI_APPLY_GO_ON;
63547 }
63548 
63549 
varDefZaxis(int vlistID,int zaxistype,int nlevels,const double * levels,const char ** cvals,size_t clength,bool lbounds,const double * levels1,const double * levels2,int vctsize,const double * vct,char * name,const char * longname,const char * units,int prec,int mode,int ltype1,int ltype2)63550 int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, const char **cvals, size_t clength, bool lbounds,
63551                 const double *levels1, const double *levels2, int vctsize, const double *vct, char *name,
63552 		const char *longname, const char *units, int prec, int mode, int ltype1, int ltype2)
63553 {
63554   /*
63555     mode: 0 search in vlist and zaxis table
63556           1 search in zaxis table
63557    */
63558   int zaxisID = CDI_UNDEFID;
63559   bool zaxisdefined = false;
63560   bool zaxisglobdefined = false;
63561   vlist_t *vlistptr = vlist_to_pointer(vlistID);
63562   int nzaxis = vlistptr->nzaxis;
63563 
63564   if ( ltype2 == 255 ) ltype2 = -1;
63565 
63566   if ( mode == 0 )
63567     for ( int index = 0; index < nzaxis; index++ )
63568       {
63569 	zaxisID = vlistptr->zaxisIDs[index];
63570 
63571 	if ( !zaxisCompare(zaxisID, zaxistype, nlevels, lbounds, levels, longname, units, ltype1, ltype2) )
63572 	  {
63573 	    zaxisdefined = true;
63574 	    break;
63575 	  }
63576       }
63577 
63578   if ( ! zaxisdefined )
63579     {
63580       struct varDefZAxisSearchState query;
63581       query.zaxistype = zaxistype;
63582       query.nlevels = nlevels;
63583       query.levels = levels;
63584       query.lbounds = lbounds;
63585       query.longname = longname;
63586       query.units = units;
63587       query.ltype1 = ltype1;
63588       query.ltype2 = ltype2;
63589 
63590       if ((zaxisglobdefined
63591            = (cdiResHFilterApply(getZaxisOps(), varDefZAxisSearch, &query)
63592               == CDI_APPLY_STOP)))
63593         zaxisID = query.resIDValue;
63594 
63595       if ( mode == 1 && zaxisglobdefined)
63596 	for (int index = 0; index < nzaxis; index++ )
63597 	  if ( vlistptr->zaxisIDs[index] == zaxisID )
63598 	    {
63599 	      zaxisglobdefined = false;
63600 	      break;
63601 	    }
63602     }
63603 
63604   if ( ! zaxisdefined )
63605     {
63606       if ( ! zaxisglobdefined )
63607 	{
63608 	  zaxisID = zaxisCreate(zaxistype, nlevels);
63609 	  if ( levels ) zaxisDefLevels(zaxisID, levels);
63610 	  if ( lbounds )
63611 	    {
63612 	      zaxisDefLbounds(zaxisID, levels1);
63613 	      zaxisDefUbounds(zaxisID, levels2);
63614 	    }
63615 
63616           if ( cvals != NULL && nlevels != 0 && clength != 0 ) zaxisDefCvals(zaxisID, cvals, (int)clength);
63617 
63618 	  if ( (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF) && vctsize > 0 )
63619             zaxisDefVct(zaxisID, vctsize, vct);
63620 
63621 	  if ( name && name[0] ) cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_NAME, name);
63622 	  if ( longname && longname[0] ) cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_LONGNAME, longname);
63623 	  if ( units && units[0] ) cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, units);
63624 	  zaxisDefDatatype(zaxisID, prec);
63625           cdiDefKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE, ltype1);
63626           if ( ltype2 != -1 ) cdiDefKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_TYPEOFSECONDFIXEDSURFACE, ltype2);
63627 	}
63628 
63629       vlistptr->zaxisIDs[nzaxis] = zaxisID;
63630       vlistptr->nzaxis++;
63631     }
63632 
63633   return zaxisID;
63634 }
63635 
63636 
varDefMissval(int varID,double missval)63637 void varDefMissval(int varID, double missval)
63638 {
63639   vartable[varID].lmissval = true;
63640   vartable[varID].missval = missval;
63641 }
63642 
63643 
varDefCompType(int varID,int comptype)63644 void varDefCompType(int varID, int comptype)
63645 {
63646   if ( vartable[varID].comptype == CDI_COMPRESS_NONE )
63647     vartable[varID].comptype = comptype;
63648 }
63649 
63650 
varDefCompLevel(int varID,int complevel)63651 void varDefCompLevel(int varID, int complevel)
63652 {
63653   vartable[varID].complevel = complevel;
63654 }
63655 
63656 
varInqInst(int varID)63657 int varInqInst(int varID)
63658 {
63659   return vartable[varID].instID;
63660 }
63661 
63662 
varDefInst(int varID,int instID)63663 void varDefInst(int varID, int instID)
63664 {
63665   vartable[varID].instID = instID;
63666 }
63667 
63668 
varInqModel(int varID)63669 int varInqModel(int varID)
63670 {
63671   return vartable[varID].modelID;
63672 }
63673 
63674 
varDefModel(int varID,int modelID)63675 void varDefModel(int varID, int modelID)
63676 {
63677   vartable[varID].modelID = modelID;
63678 }
63679 
63680 
varInqTable(int varID)63681 int varInqTable(int varID)
63682 {
63683   return vartable[varID].tableID;
63684 }
63685 
63686 
varDefTable(int varID,int tableID)63687 void varDefTable(int varID, int tableID)
63688 {
63689   vartable[varID].tableID = tableID;
63690 }
63691 
63692 
varDefKeyInt(int varID,int key,int value)63693 void varDefKeyInt(int varID, int key, int value)
63694 {
63695   cdi_keys_t *keysp = &(vartable[varID].keys);
63696   cdiDefVarKeyInt(keysp, key, value);
63697 }
63698 
63699 
varDefKeyBytes(int varID,int key,const unsigned char * bytes,int length)63700 void varDefKeyBytes(int varID, int key, const unsigned char *bytes, int length)
63701 {
63702   cdi_keys_t *keysp = &(vartable[varID].keys);
63703   cdiDefVarKeyBytes(keysp, key, bytes, length);
63704 }
63705 
63706 
varDefKeyString(int varID,int key,const char * string)63707 void varDefKeyString(int varID, int key, const char *string)
63708 {
63709   int length = strlen(string) + 1;
63710   cdi_keys_t *keysp = &(vartable[varID].keys);
63711   cdiDefVarKeyBytes(keysp, key, (const unsigned char *) string, length);
63712 }
63713 
63714 
63715 #ifdef HAVE_LIBGRIB_API
63716 /* Resizes and initializes opt_grib_kvpair data structure. */
63717 static
resize_vartable_opt_grib_entries(vartable_t * var,int nentries)63718 void resize_vartable_opt_grib_entries(vartable_t *var, int nentries)
63719 {
63720   if (var->opt_grib_kvpair_size >= nentries)
63721     {
63722       return;   /* nothing to do; array is still large enough */
63723     }
63724   else
63725     {
63726       if ( CDI_Debug )
63727         Message("resize data structure, %d -> %d", var->opt_grib_kvpair_size, nentries);
63728 
63729       int i, new_size;
63730       new_size = (2*var->opt_grib_kvpair_size) > nentries ? (2*var->opt_grib_kvpair_size) : nentries;
63731       if (CDI_Debug)
63732         Message("resize vartable opt_grib_entries array to size %d", new_size);
63733       opt_key_val_pair_t *tmp = (opt_key_val_pair_t *) Malloc((size_t)new_size * sizeof (opt_key_val_pair_t));
63734       for (i=0; i<var->opt_grib_kvpair_size; i++) {
63735         tmp[i] = var->opt_grib_kvpair[i];
63736       }
63737       for (i=var->opt_grib_kvpair_size; i<new_size; i++) {
63738         tmp[i].int_val =     0;
63739         tmp[i].dbl_val =     0;
63740         tmp[i].update  = false;
63741         tmp[i].keyword =  NULL;
63742       } // for
63743       var->opt_grib_kvpair_size = new_size;
63744       Free(var->opt_grib_kvpair);
63745       var->opt_grib_kvpair = tmp;
63746     }
63747 }
63748 #endif
63749 
63750 #ifdef HAVE_LIBGRIB_API
varDefOptGribInt(int varID,int tile_index,long lval,const char * keyword)63751 void varDefOptGribInt(int varID, int tile_index, long lval, const char *keyword)
63752 {
63753   int idx = -1;
63754   for (int i=0; i<vartable[varID].opt_grib_nentries; i++)
63755     {
63756       if ( (strcmp(keyword, vartable[varID].opt_grib_kvpair[i].keyword) == 0 ) &&
63757            (vartable[varID].opt_grib_kvpair[i].data_type == t_int)             &&
63758            (vartable[varID].opt_grib_kvpair[i].subtype_index == tile_index) )
63759         idx = i;
63760     }
63761 
63762   if (idx == -1)
63763     {
63764       resize_vartable_opt_grib_entries(&vartable[varID], vartable[varID].opt_grib_nentries+1);
63765       vartable[varID].opt_grib_nentries += 1;
63766       idx = vartable[varID].opt_grib_nentries -1;
63767     }
63768   else
63769     {
63770       if (vartable[varID].opt_grib_kvpair[idx].keyword)
63771         Free(vartable[varID].opt_grib_kvpair[idx].keyword);
63772     }
63773   vartable[varID].opt_grib_kvpair[idx].data_type     = t_int;
63774   vartable[varID].opt_grib_kvpair[idx].int_val       = (int) lval;
63775   vartable[varID].opt_grib_kvpair[idx].keyword       = strdupx(keyword);
63776   vartable[varID].opt_grib_kvpair[idx].subtype_index = tile_index;
63777 }
63778 #endif
63779 
63780 
63781 #ifdef HAVE_LIBGRIB_API
varDefOptGribDbl(int varID,int tile_index,double dval,const char * keyword)63782 void varDefOptGribDbl(int varID, int tile_index, double dval, const char *keyword)
63783 {
63784   int idx = -1;
63785   for (int i=0; i<vartable[varID].opt_grib_nentries; i++)
63786     {
63787       if ( (strcmp(keyword, vartable[varID].opt_grib_kvpair[i].keyword) == 0 ) &&
63788            (vartable[varID].opt_grib_kvpair[i].data_type == t_double)          &&
63789            (vartable[varID].opt_grib_kvpair[i].subtype_index == tile_index) )
63790         idx = i;
63791     }
63792 
63793   if (idx == -1)
63794     {
63795       resize_vartable_opt_grib_entries(&vartable[varID], vartable[varID].opt_grib_nentries+1);
63796       vartable[varID].opt_grib_nentries += 1;
63797       idx = vartable[varID].opt_grib_nentries -1;
63798     }
63799   else
63800     {
63801       if (vartable[varID].opt_grib_kvpair[idx].keyword)
63802         Free(vartable[varID].opt_grib_kvpair[idx].keyword);
63803     }
63804   vartable[varID].opt_grib_kvpair[idx].data_type     = t_double;
63805   vartable[varID].opt_grib_kvpair[idx].dbl_val       = dval;
63806   vartable[varID].opt_grib_kvpair[idx].keyword       = strdupx(keyword);
63807   vartable[varID].opt_grib_kvpair[idx].subtype_index = tile_index;
63808 }
63809 #endif
63810 
63811 
63812 #ifdef HAVE_LIBGRIB_API
varOptGribNentries(int varID)63813 int varOptGribNentries(int varID)
63814 {
63815   int nentries = vartable[varID].opt_grib_nentries;
63816   return nentries;
63817 }
63818 #endif
63819 
63820 /*
63821  * Local Variables:
63822  * c-file-style: "Java"
63823  * c-basic-offset: 2
63824  * indent-tabs-mode: nil
63825  * show-trailing-whitespace: t
63826  * require-trailing-newline: t
63827  * End:
63828  */
63829 #ifdef  HAVE_CONFIG_H
63830 #endif
63831 
63832 
63833 
63834 #ifdef  HAVE_LIBGRIB_API
63835 /* list of additional GRIB2 keywords which are read by the open process */
63836 int    cdiNAdditionalGRIBKeys = 0;
63837 char*  cdiAdditionalGRIBKeys[MAX_OPT_GRIB_ENTRIES];
63838 #endif
63839 
63840 static int VLIST_Debug = 0;
63841 
63842 static void vlist_initialize(void);
63843 
63844 #ifdef  HAVE_LIBPTHREAD
63845 #include <pthread.h>
63846 
63847 static pthread_once_t  _vlist_init_thread = PTHREAD_ONCE_INIT;
63848 
63849 #define  VLIST_INIT()        \
63850   pthread_once(&_vlist_init_thread, vlist_initialize)
63851 
63852 #else
63853 
63854 static bool vlistIsInitialized = false;
63855 
63856 #define  VLIST_INIT()               \
63857   if ( !vlistIsInitialized ) vlist_initialize()
63858 #endif
63859 
63860 
63861 static int
vlist_compare(vlist_t * a,vlist_t * b)63862 vlist_compare(vlist_t *a, vlist_t *b)
63863 {
63864   int diff = (a->nvars != b->nvars) | (a->ngrids != b->ngrids)
63865     | (a->nzaxis != b->nzaxis) | (a->instID != b->instID)
63866     | (a->modelID != b->modelID) | (a->tableID != b->tableID)
63867     | (a->ntsteps != b->ntsteps) | (a->atts.nelems != b->atts.nelems);
63868 
63869   int nvars = a->nvars;
63870   for (int varID = 0; varID < nvars; ++varID)
63871     diff |= vlistVarCompare(a, varID, b, varID);
63872 
63873   size_t natts = a->atts.nelems;
63874   for (size_t attID = 0; attID < natts; ++attID)
63875     diff |= cdi_att_compare(&a->atts, &a->atts, (int)attID);
63876 
63877   return diff;
63878 }
63879 
63880 static void vlistPrintKernel(vlist_t *vlistptr, FILE *fp);
63881 static void vlist_delete(vlist_t *vlistptr);
63882 
63883 static int  vlistGetSizeP (void *vlistptr, void *context);
63884 static void vlistPackP    (void *vlistptr, void *buff, int size,
63885                            int *position, void *context);
63886 static int  vlistTxCode   (void);
63887 
63888 #if !defined(__cplusplus)
63889 const
63890 #endif
63891 resOps vlistOps = {
63892   (valCompareFunc)vlist_compare,
63893   (valDestroyFunc)vlist_delete,
63894   (valPrintFunc)vlistPrintKernel,
63895   vlistGetSizeP,
63896   vlistPackP,
63897   vlistTxCode
63898 };
63899 
63900 
vlist_to_pointer(int vlistID)63901 vlist_t *vlist_to_pointer(int vlistID)
63902 {
63903   VLIST_INIT();
63904   return (vlist_t*) reshGetVal(vlistID, &vlistOps);
63905 }
63906 
63907 static
vlist_init_entry(vlist_t * vlistptr)63908 void vlist_init_entry(vlist_t *vlistptr)
63909 {
63910   vlistptr->immutable      = 0;
63911   vlistptr->internal       = 0;
63912   vlistptr->self           = CDI_UNDEFID;
63913   vlistptr->nvars          = 0;
63914   vlistptr->vars           = NULL;
63915   vlistptr->ngrids         = 0;
63916   vlistptr->nzaxis         = 0;
63917   vlistptr->taxisID        = CDI_UNDEFID;
63918   vlistptr->instID         = CDI_Default_InstID;
63919   vlistptr->modelID        = CDI_Default_ModelID;
63920   vlistptr->tableID        = CDI_Default_TableID;
63921   vlistptr->varsAllocated  = 0;
63922   vlistptr->ntsteps        = CDI_UNDEFID;
63923   vlistptr->keys.nalloc    = MAX_KEYS;
63924   vlistptr->keys.nelems    = 0;
63925   for ( int i = 0; i < MAX_KEYS; ++i )
63926     vlistptr->keys.value[i].length = 0;
63927   vlistptr->atts.nalloc    = MAX_ATTRIBUTES;
63928   vlistptr->atts.nelems    = 0;
63929   vlistptr->nsubtypes      = 0;
63930   for ( int i = 0; i < MAX_SUBTYPES_PS; i++ )
63931     vlistptr->subtypeIDs[i] = CDI_UNDEFID;
63932 }
63933 
63934 static
vlist_new_entry(cdiResH resH)63935 vlist_t *vlist_new_entry(cdiResH resH)
63936 {
63937   vlist_t *vlistptr = (vlist_t*) Malloc(sizeof(vlist_t));
63938   vlist_init_entry(vlistptr);
63939   if (resH == CDI_UNDEFID)
63940     vlistptr->self = reshPut(vlistptr, &vlistOps);
63941   else
63942     {
63943       vlistptr->self = resH;
63944       reshReplace(resH, vlistptr, &vlistOps);
63945     }
63946   return vlistptr;
63947 }
63948 
63949 static
vlist_delete_entry(vlist_t * vlistptr)63950 void vlist_delete_entry(vlist_t *vlistptr)
63951 {
63952   int idx = vlistptr->self;
63953 
63954   reshRemove(idx, &vlistOps );
63955 
63956   Free(vlistptr);
63957 
63958   if ( VLIST_Debug )
63959     Message("Removed idx %d from vlist list", idx);
63960 }
63961 
63962 static
vlist_initialize(void)63963 void vlist_initialize(void)
63964 {
63965   char *env = getenv("VLIST_DEBUG");
63966   if ( env ) VLIST_Debug = atoi(env);
63967 #ifndef HAVE_LIBPTHREAD
63968   vlistIsInitialized = true;
63969 #endif
63970 }
63971 
63972 static
vlist_copy(vlist_t * vlistptr2,vlist_t * vlistptr1)63973 void vlist_copy(vlist_t *vlistptr2, vlist_t *vlistptr1)
63974 {
63975   int vlistID2 = vlistptr2->self;
63976   int vlist2internal = vlistptr2->internal;
63977   memcpy(vlistptr2, vlistptr1, sizeof(vlist_t));
63978   vlistptr2->internal = vlist2internal;    //the question who's responsible to destroy the vlist is tied to its containing memory region, so we retain this flag
63979   vlistptr2->immutable = 0;    //this is a copy, so it's mutable, independent of whether the original is mutable or not
63980   vlistptr2->keys.nelems = 0;
63981   vlistptr2->atts.nelems = 0;
63982   vlistptr2->self = vlistID2;
63983 }
63984 
cdiVlistMakeInternal(int vlistID)63985 void cdiVlistMakeInternal(int vlistID)
63986 {
63987   vlist_to_pointer(vlistID)->internal = 1;
63988 }
63989 
cdiVlistMakeImmutable(int vlistID)63990 void cdiVlistMakeImmutable(int vlistID)
63991 {
63992   vlist_to_pointer(vlistID)->immutable = 1;
63993 }
63994 
63995 /*
63996 @Function  vlistCreate
63997 @Title     Create a variable list
63998 
63999 @Prototype int vlistCreate(void)
64000 
64001 @Example
64002 Here is an example using @func{vlistCreate} to create a variable list
64003 and add a variable with @func{vlistDefVar}.
64004 
64005 @Source
64006    ...
64007 int vlistID, varID;
64008    ...
64009 vlistID = vlistCreate();
64010 varID = vlistDefVar(vlistID, gridID, zaxisID, TIME_VARYING);
64011    ...
64012 streamDefVlist(streamID, vlistID);
64013    ...
64014 vlistDestroy(vlistID);
64015    ...
64016 @EndSource
64017 @EndFunction
64018 */
vlistCreate(void)64019 int vlistCreate(void)
64020 {
64021   cdiInitialize();
64022 
64023   VLIST_INIT();
64024 
64025   vlist_t *vlistptr = vlist_new_entry(CDI_UNDEFID);
64026   if ( CDI_Debug ) Message("create vlistID = %d", vlistptr->self);
64027   return vlistptr->self;
64028 }
64029 
64030 static
vlist_delete(vlist_t * vlistptr)64031 void vlist_delete(vlist_t *vlistptr)
64032 {
64033   int vlistID = vlistptr->self;
64034   if ( CDI_Debug ) Message("call to vlist_delete, vlistID = %d", vlistID);
64035 
64036   cdiDeleteKeys(vlistID, CDI_GLOBAL);
64037   cdiDeleteAtts(vlistID, CDI_GLOBAL);
64038 
64039   int nvars = vlistptr->nvars;
64040   var_t *vars = vlistptr->vars;
64041 
64042   for ( int varID = 0; varID < nvars; varID++ )
64043     {
64044       if ( vars[varID].levinfo )  Free(vars[varID].levinfo);
64045 
64046       if ( vlistptr->vars[varID].opt_grib_kvpair )
64047         {
64048           for ( int i = 0; i<vlistptr->vars[varID].opt_grib_nentries; i++ )
64049             {
64050               if ( vlistptr->vars[varID].opt_grib_kvpair[i].keyword )
64051                 Free(vlistptr->vars[varID].opt_grib_kvpair[i].keyword);
64052             }
64053           Free(vlistptr->vars[varID].opt_grib_kvpair);
64054         }
64055       vlistptr->vars[varID].opt_grib_nentries    = 0;
64056       vlistptr->vars[varID].opt_grib_kvpair_size = 0;
64057       vlistptr->vars[varID].opt_grib_kvpair      = NULL;
64058 
64059       cdiDeleteKeys(vlistID, varID);
64060       cdiDeleteAtts(vlistID, varID);
64061     }
64062 
64063   if ( vars ) Free(vars);
64064 
64065   vlist_delete_entry(vlistptr);
64066 }
64067 
64068 
64069 /*
64070 @Function  vlistDestroy
64071 @Title     Destroy a variable list
64072 
64073 @Prototype void vlistDestroy(int vlistID)
64074 @Parameter
64075     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
64076 
64077 @EndFunction
64078 */
vlistDestroy(int vlistID)64079 void vlistDestroy(int vlistID)
64080 {
64081   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64082 
64083   if ( vlistptr->internal )
64084     Warning("Attempt to destroy an internal vlist object by the user (vlistID=%d).", vlistID);
64085   else
64086     vlist_delete(vlistptr);
64087 }
64088 
64089 // destroy an internal vlist object
cdiVlistDestroy_(int vlistID)64090 void cdiVlistDestroy_(int vlistID)
64091 {
64092   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64093 
64094   if(!vlistptr->internal)
64095     Warning("Destroying a vlist object that is owned by the user.\n"
64096             "This is most likely because of a missing vlistDestroy() in the application code.\n"
64097             "If that's not the case, and you are absolutely certain about it, please report the bug.");
64098 
64099   vlist_delete(vlistptr);
64100 }
64101 
64102 static
var_copy_entries(var_t * var2,var_t * var1)64103 void var_copy_entries(var_t *var2, var_t *var1)
64104 {
64105   var2->opt_grib_kvpair_size = 0;
64106   var2->opt_grib_kvpair      = NULL;
64107   var2->opt_grib_nentries    = 0;
64108 
64109   resize_opt_grib_entries(var2, var1->opt_grib_nentries);
64110   var2->opt_grib_nentries = var1->opt_grib_nentries;
64111   if ((var2->opt_grib_nentries > 0) && CDI_Debug )
64112     Message("copy %d optional GRIB keywords", var2->opt_grib_nentries);
64113 
64114   for (int i=0; i<var1->opt_grib_nentries; i++) {
64115     if ( CDI_Debug )  Message("copy entry \"%s\" ...", var1->opt_grib_kvpair[i].keyword);
64116     var2->opt_grib_kvpair[i].keyword = NULL;
64117     if ( var1->opt_grib_kvpair[i].keyword != NULL ) {
64118       var2->opt_grib_kvpair[i]         = var1->opt_grib_kvpair[i];
64119       var2->opt_grib_kvpair[i].keyword = strdupx(var1->opt_grib_kvpair[i].keyword);
64120       var2->opt_grib_kvpair[i].update  = true;
64121       if ( CDI_Debug )  Message("done.");
64122     }
64123     else {
64124       if ( CDI_Debug )  Message("not done.");
64125     }
64126   }
64127 }
64128 
64129 /*
64130 @Function  vlistCopy
64131 @Title     Copy a variable list
64132 
64133 @Prototype void vlistCopy(int vlistID2, int vlistID1)
64134 @Parameter
64135     @Item  vlistID2  Target variable list ID.
64136     @Item  vlistID1  Source variable list ID.
64137 
64138 @Description
64139 The function @func{vlistCopy} copies all entries from vlistID1 to vlistID2.
64140 
64141 @EndFunction
64142 */
vlistCopy(int vlistID2,int vlistID1)64143 void vlistCopy(int vlistID2, int vlistID1)
64144 {
64145   vlist_t *vlistptr1 = vlist_to_pointer(vlistID1);
64146   vlist_t *vlistptr2 = vlist_to_pointer(vlistID2);
64147   if ( CDI_Debug ) Message("call to vlistCopy, vlistIDs %d -> %d", vlistID1, vlistID2);
64148 
64149   var_t *vars1 = vlistptr1->vars;
64150   var_t *vars2 = vlistptr2->vars;
64151   vlist_copy(vlistptr2, vlistptr1);
64152 
64153   vlistptr2->keys.nelems = 0;
64154   cdiCopyKeys(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
64155   vlistptr2->atts.nelems = 0;
64156   cdiCopyAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
64157 
64158   if ( vars1 )
64159     {
64160       int nvars = vlistptr1->nvars;
64161       //vlistptr2->varsAllocated = nvars;
64162 
64163       size_t n = (size_t)vlistptr2->varsAllocated;
64164       vars2 = (var_t *) Realloc(vars2, n*sizeof(var_t));
64165       memcpy(vars2, vars1, n*sizeof(var_t));
64166       vlistptr2->vars = vars2;
64167 
64168       for ( int varID = 0; varID < nvars; varID++ )
64169         {
64170           var_copy_entries(&vars2[varID], &vars1[varID]);
64171           vlistptr2->vars[varID].keys.nelems = 0;
64172 	  cdiCopyKeys(vlistID1, varID, vlistID2, varID);
64173 
64174           vlistptr2->vars[varID].atts.nelems = 0;
64175 	  cdiCopyAtts(vlistID1, varID, vlistID2, varID);
64176 
64177           if ( vars1[varID].levinfo )
64178             {
64179               n = (size_t)zaxisInqSize(vars1[varID].zaxisID);
64180               vars2[varID].levinfo = (levinfo_t *) Malloc(n*sizeof(levinfo_t));
64181               memcpy(vars2[varID].levinfo, vars1[varID].levinfo, n*sizeof(levinfo_t));
64182             }
64183 	}
64184     }
64185 }
64186 
64187 /*
64188 @Function  vlistDuplicate
64189 @Title     Duplicate a variable list
64190 
64191 @Prototype int vlistDuplicate(int vlistID)
64192 @Parameter
64193     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
64194 
64195 @Description
64196 The function @func{vlistDuplicate} duplicates the variable list from vlistID1.
64197 
64198 @Result
64199 @func{vlistDuplicate} returns an identifier to the duplicated variable list.
64200 
64201 @EndFunction
64202 */
vlistDuplicate(int vlistID)64203 int vlistDuplicate(int vlistID)
64204 {
64205   if ( CDI_Debug ) Message("call to vlistDuplicate");
64206 
64207   int vlistIDnew = vlistCreate();
64208   vlistCopy(vlistIDnew, vlistID);
64209   return vlistIDnew;
64210 }
64211 
64212 
vlistClearFlag(int vlistID)64213 void vlistClearFlag(int vlistID)
64214 {
64215   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64216 
64217   for ( int varID = 0; varID < vlistptr->nvars; varID++ )
64218     {
64219       vlistptr->vars[varID].flag = false;
64220       if ( vlistptr->vars[varID].levinfo )
64221         {
64222           int nlevs = zaxisInqSize(vlistptr->vars[varID].zaxisID);
64223           for ( int levID = 0; levID < nlevs; levID++ )
64224             vlistptr->vars[varID].levinfo[levID].flag = false;
64225         }
64226     }
64227 }
64228 
64229 
64230 struct vgzSearchState
64231 {
64232   int resIDValue;
64233   int zaxistype;
64234   int nlevels;
64235   bool lbounds;
64236   const double *levels;
64237 };
64238 
64239 static enum cdiApplyRet
vgzZAxisSearch(int id,void * res,void * data)64240 vgzZAxisSearch(int id, void *res, void *data)
64241 {
64242   struct vgzSearchState *state = (struct vgzSearchState *)data;
64243   (void)res;
64244   if (zaxisCompare(id, state->zaxistype, state->nlevels, state->lbounds,
64245                    state->levels, NULL, NULL, 0, -1)
64246       == false)
64247     {
64248       state->resIDValue = id;
64249       return CDI_APPLY_STOP;
64250     }
64251   else
64252     return CDI_APPLY_GO_ON;
64253 }
64254 
64255 static
vlist_generate_zaxis(int vlistID,int zaxistype,int nlevels,const double * levels,const double * lbounds,const double * ubounds,int vctsize,const double * vct,const char ** cvals,size_t clen)64256 int vlist_generate_zaxis(int vlistID, int zaxistype, int nlevels, const double *levels,
64257                          const double *lbounds, const double *ubounds, int vctsize, const double *vct,
64258                          const char **cvals, size_t clen)
64259 {
64260   int zaxisID = CDI_UNDEFID;
64261   bool zaxisdefined = false;
64262   bool zaxisglobdefined = false;
64263   bool has_bounds = false;
64264   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64265   int nzaxis = vlistptr->nzaxis;
64266 
64267   if ( lbounds && ubounds ) has_bounds = true;
64268 
64269   for ( int index = 0; index < nzaxis; ++index )
64270     {
64271       zaxisID = vlistptr->zaxisIDs[index];
64272 
64273       if ( zaxisCompare(zaxisID, zaxistype, nlevels, has_bounds, levels, NULL, NULL, 0, -1) == false )
64274         {
64275           zaxisdefined = true;
64276           break;
64277         }
64278     }
64279 
64280   if ( ! zaxisdefined )
64281     {
64282       struct vgzSearchState query;
64283       query.zaxistype = zaxistype;
64284       query.nlevels = nlevels;
64285       query.levels = levels;
64286       query.lbounds = has_bounds;
64287 
64288       if ((zaxisglobdefined
64289            = (cdiResHFilterApply(getZaxisOps(), vgzZAxisSearch, &query)
64290               == CDI_APPLY_STOP)))
64291         zaxisID = query.resIDValue;
64292     }
64293 
64294   if ( ! zaxisdefined )
64295     {
64296       if ( ! zaxisglobdefined )
64297 	{
64298 	  zaxisID = zaxisCreate(zaxistype, nlevels);
64299 	  zaxisDefLevels(zaxisID, levels);
64300 
64301           if ( zaxistype == ZAXIS_CHAR )
64302             zaxisDefCvals(zaxisID, cvals, (int)clen);
64303 
64304 	  if ( has_bounds )
64305 	    {
64306 	      zaxisDefLbounds(zaxisID, lbounds);
64307 	      zaxisDefUbounds(zaxisID, ubounds);
64308 	    }
64309 
64310 	  if ( zaxistype == ZAXIS_HYBRID && vctsize > 0 )
64311             zaxisDefVct(zaxisID, vctsize, vct);
64312 	}
64313 
64314       nzaxis = vlistptr->nzaxis;
64315       vlistptr->zaxisIDs[nzaxis] = zaxisID;
64316       vlistptr->nzaxis++;
64317     }
64318 
64319   return zaxisID;
64320 }
64321 
64322 /*
64323 @Function  vlistCopyFlag
64324 @Title     Copy some entries of a variable list
64325 
64326 @Prototype void vlistCopyFlag(int vlistID2, int vlistID1)
64327 @Parameter
64328     @Item  vlistID2  Target variable list ID.
64329     @Item  vlistID1  Source variable list ID.
64330 
64331 @Description
64332 The function @func{vlistCopyFlag} copies all entries with a flag from vlistID1 to vlistID2.
64333 
64334 @EndFunction
64335 */
vlistCopyFlag(int vlistID2,int vlistID1)64336 void vlistCopyFlag(int vlistID2, int vlistID1)
64337 {
64338   vlist_t *vlistptr1 = vlist_to_pointer(vlistID1);
64339   vlist_t *vlistptr2 = vlist_to_pointer(vlistID2);
64340   var_t *vars1 = vlistptr1->vars;
64341   var_t *vars2 = vlistptr2->vars;
64342 
64343   vlist_copy(vlistptr2, vlistptr1);
64344 
64345   vlistptr2->keys.nelems = 0;
64346   cdiCopyKeys(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
64347   vlistptr2->atts.nelems = 0;
64348   cdiCopyAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
64349 
64350   if ( vlistptr1->vars )
64351     {
64352       vlistptr2->ngrids = 0;
64353       vlistptr2->nzaxis = 0;
64354 
64355       int nvars = vlistptr1->nvars;
64356       int nvars2 = 0;
64357       for ( int varID = 0; varID < nvars; varID++ )
64358         nvars2 += vars1[varID].flag;
64359 
64360       vlistptr2->nvars = nvars2;
64361       vlistptr2->varsAllocated = nvars2;
64362       vars2 = (nvars2 > 0) ? (var_t *) Malloc((size_t)nvars2*sizeof(var_t)) : NULL;
64363 
64364       vlistptr2->vars = vars2;
64365 
64366       int varID2 = 0;
64367       for ( int varID = 0; varID < nvars; varID++ )
64368 	if ( vars1[varID].flag )
64369 	  {
64370 	    vlistptr2->vars[varID2].flag = false;
64371 	    int zaxisID   = vlistptr1->vars[varID].zaxisID;
64372 	    int gridID    = vlistptr1->vars[varID].gridID;
64373 	    int subtypeID = vlistptr1->vars[varID].subtypeID;
64374 
64375 	    memcpy(&vars2[varID2], &vars1[varID], sizeof(var_t));
64376 
64377 	    vars1[varID].fvarID = varID2;
64378 	    vars2[varID2].fvarID = varID;
64379 
64380 	    vars2[varID2].mvarID = varID2;
64381 
64382             var_copy_entries(&vars2[varID2], &vars1[varID]);
64383 	    vlistptr2->vars[varID2].keys.nelems = 0;
64384             cdiCopyKeys(vlistID1, varID, vlistID2, varID2);
64385 
64386 	    vlistptr2->vars[varID2].atts.nelems = 0;
64387 	    cdiCopyAtts(vlistID1, varID, vlistID2, varID2);
64388 
64389 	    int nlevs  = zaxisInqSize(vars1[varID].zaxisID);
64390 	    int nlevs2 = 0;
64391             if ( vars1[varID].levinfo )
64392               for ( int levID = 0; levID < nlevs; levID++ )
64393                 nlevs2 += vars1[varID].levinfo[levID].flag;
64394 
64395 	    vars2[varID2].levinfo = (levinfo_t *) Malloc((size_t)nlevs2 * sizeof(levinfo_t));
64396 
64397 	    if ( nlevs != nlevs2 )
64398 	      {
64399 		int nvct = 0;
64400                 double *levels = NULL;
64401 		double *lbounds = NULL, *ubounds = NULL;
64402 		const double *vct = NULL;
64403 
64404                 if ( !vars1[varID].levinfo ) cdiVlistCreateVarLevInfo(vlistptr1, varID);
64405 
64406 		zaxisID = vars1[varID].zaxisID;
64407                 int zaxisType = zaxisInqType(zaxisID);
64408 
64409                 int levID2 = 0;
64410                 for ( int levID = 0; levID < nlevs; levID++ )
64411                   if ( vars1[varID].levinfo[levID].flag )
64412                     {
64413                       vars1[varID].levinfo[levID].flevelID = levID2;
64414                       vars1[varID].levinfo[levID].mlevelID = levID2;
64415                     }
64416 
64417 
64418                 if ( zaxisInqLevels(zaxisID, NULL) )
64419                   {
64420                     levels = (double *) Malloc((size_t)nlevs2 * sizeof (double));
64421 
64422                     levID2 = 0;
64423                     for ( int levID = 0; levID < nlevs; ++levID )
64424                       if ( vars1[varID].levinfo[levID].flag )
64425                         levels[levID2++] = zaxisInqLevel(zaxisID, levID);
64426                   }
64427 
64428                 if ( zaxisType == ZAXIS_HYBRID )
64429                   {
64430                     nvct = zaxisInqVctSize(zaxisID);
64431                     vct  = zaxisInqVctPtr(zaxisID);
64432                   }
64433 
64434                 size_t clen2 = 0;
64435                 char **cvals2 = NULL;
64436 #ifndef USE_MPI
64437                 if ( zaxisType == ZAXIS_CHAR )
64438                   {
64439                     char **cvals1 = zaxisInqCValsPtr(zaxisID);
64440                     size_t clen1 = (size_t)zaxisInqCLen(zaxisID);
64441                     for ( int levID = 0; levID < nlevs; ++levID )
64442                       if ( vars1[varID].levinfo[levID].flag )
64443                           {
64444                             size_t testlen = clen1;
64445                             while ( cvals1[levID][testlen] == ' ' )
64446                               testlen--;
64447                             if ( clen2 < testlen )
64448                               clen2 = testlen;
64449                           }
64450                     cvals2 = (char **) Malloc((size_t)nlevs2 * sizeof (char *));
64451                     levID2 = 0;
64452 
64453                     for ( int levID = 0; levID < nlevs; ++levID )
64454                       if ( vars1[varID].levinfo[levID].flag )
64455                         {
64456                           cvals2[levID2] = (char*) Malloc((size_t)(clen2) * sizeof(char));
64457                           memcpy(cvals2[levID2], cvals1[levID], clen2*sizeof(char));
64458                           levID2++;
64459                         }
64460                   }
64461 #endif
64462 
64463                 if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
64464                   {
64465                     lbounds = (double *) Malloc(2 * (size_t)nlevs2 * sizeof (double));
64466                     ubounds = lbounds + nlevs2;
64467 
64468                     double *lbounds1 = (double *) Malloc(2 * (size_t)nlevs * sizeof (double)),
64469                            *ubounds1 = lbounds1 + nlevs;
64470 
64471                     zaxisInqLbounds(zaxisID, lbounds1);
64472                     zaxisInqUbounds(zaxisID, ubounds1);
64473 
64474                     levID2 = 0;
64475                     for ( int levID = 0; levID < nlevs; ++levID )
64476                       if ( vars1[varID].levinfo[levID].flag )
64477                         {
64478                           lbounds[levID2] = lbounds1[levID];
64479                           ubounds[levID2] = ubounds1[levID];
64480                           levID2++;
64481                         }
64482 
64483                     Free(lbounds1);
64484                   }
64485 
64486 		int zaxisID2 = vlist_generate_zaxis(vlistID2, zaxisType, nlevs2, levels, lbounds, ubounds, nvct, vct, (const char **)cvals2, clen2);
64487 		if ( levels )  Free(levels);
64488                 if ( lbounds ) Free(lbounds);
64489                 if ( cvals2 )
64490                   {
64491                     for ( int levID = 0; levID < nlevs2; ++levID )
64492                       Free(cvals2[levID]);
64493                     Free(cvals2);
64494                   }
64495 
64496                 char ctemp[CDI_MAX_NAME];
64497                 int length = CDI_MAX_NAME;
64498                 cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_NAME, ctemp, &length);
64499                 cdiDefKeyString(zaxisID2, CDI_GLOBAL, CDI_KEY_NAME, ctemp);
64500                 length = CDI_MAX_NAME;
64501                 cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_LONGNAME, ctemp, &length);
64502                 cdiDefKeyString(zaxisID2, CDI_GLOBAL, CDI_KEY_LONGNAME, ctemp);
64503                 length = CDI_MAX_NAME;
64504                 cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, ctemp, &length);
64505                 cdiDefKeyString(zaxisID2, CDI_GLOBAL, CDI_KEY_UNITS, ctemp);
64506 
64507                 zaxisDefDatatype(zaxisID2, zaxisInqDatatype(zaxisID));
64508                 zaxisDefPositive(zaxisID2, zaxisInqPositive(zaxisID));
64509 
64510                 if ( zaxisType == ZAXIS_CHAR )
64511                   {
64512                     char dimname[CDI_MAX_NAME+3];
64513                     length = sizeof(dimname);
64514                     cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_DIMNAME, dimname, &length);
64515                     if ( dimname[0] == 0 ) { memcpy(dimname, "area_type", 10); dimname[10] = 0; }
64516                     cdiDefKeyString(zaxisID2, CDI_GLOBAL, CDI_KEY_DIMNAME, dimname);
64517                   }
64518 
64519                 if ( zaxisType == ZAXIS_GENERIC ) cdiCopyKey(zaxisID, CDI_GLOBAL, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE, zaxisID2);
64520 
64521                 cdiCopyAtts(zaxisID, CDI_GLOBAL, zaxisID2, CDI_GLOBAL);
64522 
64523 		zaxisID = zaxisID2;
64524 		vars2[varID2].zaxisID = zaxisID2;
64525 	      }
64526 
64527 	    for ( int levID = 0; levID < nlevs2; levID++ )
64528 	      {
64529 		vars2[varID2].levinfo[levID].flag  = false;
64530 		vars2[varID2].levinfo[levID].index = -1;
64531 	      }
64532 
64533 	    int levID2 = 0;
64534 	    for ( int levID = 0; levID < nlevs; levID++ )
64535 	      if ( vars1[varID].levinfo[levID].flag )
64536 		{
64537 		  vars2[varID2].levinfo[levID2].flevelID = levID;
64538 		  vars2[varID2].levinfo[levID2].mlevelID = levID2;
64539 		  levID2++;
64540 		}
64541 
64542             vlistAdd2GridIDs(vlistptr2, gridID);
64543             vlistAdd2ZaxisIDs(vlistptr2, zaxisID);
64544             vlistAdd2SubtypeIDs(vlistptr2, subtypeID);
64545 
64546 	    varID2++;
64547 	  }
64548     }
64549 }
64550 
64551 /*
64552 @Function  vlistCat
64553 @Title     Concatenate two variable lists
64554 
64555 @Prototype void vlistCat(int vlistID2, int vlistID1)
64556 @Parameter
64557     @Item  vlistID2  Target variable list ID.
64558     @Item  vlistID1  Source variable list ID.
64559 
64560 @Description
64561 Concatenate the variable list vlistID1 at the end of vlistID2.
64562 
64563 @EndFunction
64564 */
vlistCat(int vlistID2,int vlistID1)64565 void vlistCat(int vlistID2, int vlistID1)
64566 {
64567   vlist_t *vlistptr1 = vlist_to_pointer(vlistID1);
64568   vlist_t *vlistptr2 = vlist_to_pointer(vlistID2);
64569   var_t *vars1 = vlistptr1->vars;
64570   var_t *vars2 = vlistptr2->vars;
64571   int nvars1 = vlistptr1->nvars;
64572   int nvars2 = vlistptr2->nvars;
64573   int nvars = nvars1 + nvars2;
64574   vlistptr2->nvars = nvars;
64575 
64576   if ( nvars > vlistptr2->varsAllocated )
64577     {
64578       vlistptr2->varsAllocated = nvars;
64579       vars2 = (var_t *) Realloc(vars2, (size_t)nvars*sizeof(var_t));
64580       vlistptr2->vars = vars2;
64581     }
64582   memcpy(vars2+nvars2, vars1, (size_t)nvars1 * sizeof(var_t));
64583 
64584   for ( int varID = 0; varID < nvars1; varID++ )
64585     {
64586       int varID2 = varID + nvars2;
64587       vars1[varID].fvarID = varID2;
64588       vars2[varID2].fvarID = varID;
64589 
64590       vars1[varID].mvarID = varID2;
64591       vars2[varID2].mvarID = varID;
64592 
64593       if ( vars1[varID].param < 0 )
64594 	{
64595 	  int pnum, pcat, pdis;
64596 	  cdiDecodeParam(vars1[varID].param, &pnum, &pcat, &pdis);
64597 	  pnum = -(varID2+1);
64598 	  vars2[varID2].param = cdiEncodeParam(pnum, pcat, pdis);
64599 	}
64600 
64601       var_copy_entries(&vars2[varID2], &vars1[varID]);
64602       vars2[varID2].keys.nelems = 0;
64603       cdiCopyKeys(vlistID1, varID, vlistID2, varID2);
64604 
64605       if ( vars1[varID].levinfo )
64606         {
64607           size_t nlevs = (size_t)zaxisInqSize(vars1[varID].zaxisID);
64608           vars2[varID2].levinfo = (levinfo_t *) Malloc(nlevs * sizeof(levinfo_t));
64609           memcpy(vars2[varID2].levinfo, vars1[varID].levinfo,
64610                  nlevs * sizeof(levinfo_t));
64611         }
64612 
64613       vars2[varID2].atts.nelems = 0;
64614       cdiCopyAtts(vlistID1, varID, vlistID2, varID2);
64615 
64616       vlistAdd2GridIDs(vlistptr2, vars1[varID].gridID);
64617       vlistAdd2ZaxisIDs(vlistptr2, vars1[varID].zaxisID);
64618       vlistAdd2SubtypeIDs(vlistptr2, vars1[varID].subtypeID);
64619     }
64620 }
64621 
64622 /*
64623 @Function  vlistMerge
64624 @Title     Merge two variable lists
64625 
64626 @Prototype void vlistMerge(int vlistID2, int vlistID1)
64627 @Parameter
64628     @Item  vlistID2  Target variable list ID.
64629     @Item  vlistID1  Source variable list ID.
64630 
64631 @Description
64632 Merge the variable list vlistID1 to the variable list vlistID2.
64633 
64634 @EndFunction
64635 */
vlistMerge(int vlistID2,int vlistID1)64636 void vlistMerge(int vlistID2, int vlistID1)
64637 {
64638   int varID = 0;
64639   vlist_t *vlistptr1 = vlist_to_pointer(vlistID1);
64640   vlist_t *vlistptr2 = vlist_to_pointer(vlistID2);
64641   var_t *vars1 = vlistptr1->vars;
64642   var_t *vars2 = vlistptr2->vars;
64643   int nvars1 = vlistptr1->nvars;
64644   int nvars2 = vlistptr2->nvars;
64645 
64646   if ( nvars1 == nvars2 )
64647     {
64648       char name1[CDI_MAX_NAME], name2[CDI_MAX_NAME];
64649       for ( varID = 0; varID < nvars2; varID++ )
64650 	{
64651           size_t ngp1 = gridInqSize(vars1[varID].gridID);
64652           size_t ngp2 = gridInqSize(vars2[varID].gridID);
64653           if ( ngp1 != ngp2 ) break;
64654 
64655           int length = CDI_MAX_NAME;
64656           (void)cdiInqKeyString(vlistID1, varID, CDI_KEY_NAME, name1, &length);
64657           length = CDI_MAX_NAME;
64658           (void)cdiInqKeyString(vlistID2, varID, CDI_KEY_NAME, name2, &length);
64659 
64660 	  if ( *name1 && *name2 )
64661 	    {
64662 	      if ( strcmp(name1, name2) != 0 ) break;
64663 	    }
64664 	  else
64665 	    {
64666 	      if ( vars1[varID].param != vars2[varID].param ) break;
64667 	    }
64668 	}
64669     }
64670 
64671   if ( varID == nvars2 ) /* same variables in vlistID1 and vlistID2 */
64672     {
64673       for ( varID = 0; varID < nvars2; varID++ )
64674         {
64675           vars1[varID].fvarID = varID;
64676           vars2[varID].fvarID = varID;
64677 
64678           vars1[varID].mvarID = varID;
64679           vars2[varID].mvarID = varID;
64680 
64681           int nlevs1 = zaxisInqSize(vars1[varID].zaxisID);
64682           int nlevs2 = zaxisInqSize(vars2[varID].zaxisID);
64683 
64684           int nlevs = nlevs1 + nlevs2;
64685 
64686           /*
64687           fprintf(stderr, "var %d %d %d %d %d\n", varID, nlevs1, nlevs2, nlevs, sizeof(levinfo_t));
64688           */
64689           if ( vars1[varID].levinfo )
64690             {
64691               vars2[varID].levinfo = (levinfo_t*) Realloc(vars2[varID].levinfo,
64692                                      (size_t)nlevs * sizeof(levinfo_t));
64693 
64694               memcpy(vars2[varID].levinfo+nlevs2, vars1[varID].levinfo,
64695                      (size_t)nlevs1 * sizeof(levinfo_t));
64696             }
64697           else
64698             cdiVlistCreateVarLevInfo(vlistptr1, varID);
64699 
64700 	  for ( int levID = 0; levID < nlevs1; levID++ )
64701             vars1[varID].levinfo[levID].mlevelID = nlevs2 + levID;
64702 	}
64703 
64704       bool *lvar = (bool *) Calloc((size_t)nvars2, sizeof(bool));
64705 
64706       for ( varID = 0; varID < nvars2; varID++ )
64707         {
64708           if ( lvar[varID] == true ) continue;
64709 
64710           int zaxisID1 = vars1[varID].zaxisID;
64711           int zaxisID2 = vars2[varID].zaxisID;
64712           /*
64713           nlevs1 = zaxisInqSize(vars1[varID].zaxisID);
64714           nlevs2 = zaxisInqSize(vars2[varID].zaxisID);
64715           */
64716           int nlevs1 = zaxisInqSize(zaxisID1);
64717           int nlevs2 = zaxisInqSize(zaxisID2);
64718           /*
64719           fprintf(stderr, "zaxis %d %d %d %d\n", zaxisID1, zaxisID2, nlevs1, nlevs2);
64720           */
64721           int nlevs = nlevs1 + nlevs2;
64722 
64723           int zaxisID = zaxisDuplicate(zaxisID2);
64724           zaxisResize(zaxisID, nlevs);
64725 
64726           if ( zaxisInqLevels(zaxisID1, NULL) )
64727             {
64728               double *levels = (double *) Malloc((size_t)nlevs1 * sizeof(double));
64729 
64730               zaxisInqLevels(zaxisID1, levels);
64731               /*
64732                 for ( levID = 0; levID < nlevs1; levID++ )
64733                 fprintf(stderr, "%d %d %d %d %d %g\n", varID, levID, nlevs1, nlevs2, vars2[varID].nlevs, levels[levID]);
64734               */
64735               for ( int levID = 0; levID < nlevs1; levID++ )
64736                 zaxisDefLevel(zaxisID, nlevs2+levID, levels[levID]);
64737 
64738               Free(levels);
64739             }
64740 
64741           for ( int index = 0; index < vlistptr2->nzaxis; index++ )
64742             if ( vlistptr2->zaxisIDs[index] == zaxisID2 )
64743               vlistptr2->zaxisIDs[index] = zaxisID;
64744 
64745           for ( int varID2 = 0; varID2 < nvars2; varID2++ )
64746             if ( lvar[varID2] == false && vars2[varID2].zaxisID == zaxisID2 )
64747               {
64748                 vars2[varID2].zaxisID = zaxisID;
64749                 lvar[varID2] = true;
64750               }
64751         }
64752 
64753       Free(lvar);
64754     }
64755   else
64756     {
64757       vlistCat(vlistID2, vlistID1);
64758     }
64759 }
64760 
64761 /*
64762 @Function  vlistNvars
64763 @Title     Number of variables in a variable list
64764 
64765 @Prototype int vlistNvars(int vlistID)
64766 @Parameter
64767     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
64768 
64769 @Description
64770 The function @func{vlistNvars} returns the number of variables in the variable list vlistID.
64771 
64772 @Result
64773 @func{vlistNvars} returns the number of variables in a variable list.
64774 
64775 @EndFunction
64776 */
vlistNvars(int vlistID)64777 int vlistNvars(int vlistID)
64778 {
64779   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64780   return vlistptr->nvars;
64781 }
64782 
64783 
vlistNrecs(int vlistID)64784 int vlistNrecs(int vlistID)
64785 {
64786   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64787 
64788   int nrecs = 0;
64789   for ( int varID = 0; varID < vlistptr->nvars; varID++ )
64790     nrecs +=  zaxisInqSize(vlistptr->vars[varID].zaxisID);
64791 
64792   return nrecs;
64793 }
64794 
64795 
vlistNumber(int vlistID)64796 int vlistNumber(int vlistID)
64797 {
64798   int number, number2;
64799   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64800 
64801   int datatype = vlistptr->vars[0].datatype;
64802   if (  datatype== CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
64803     number = CDI_COMP;
64804   else
64805     number = CDI_REAL;
64806 
64807   for ( int varID = 1; varID < vlistptr->nvars; varID++ )
64808     {
64809       datatype = vlistptr->vars[varID].datatype;
64810       if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
64811         number2 = CDI_COMP;
64812       else
64813         number2 = CDI_REAL;
64814 
64815       if ( number2 != number )
64816         {
64817           number = CDI_BOTH;
64818           break;
64819         }
64820     }
64821 
64822   return number;
64823 }
64824 
64825 /*
64826 @Function  vlistNgrids
64827 @Title     Number of grids in a variable list
64828 
64829 @Prototype int vlistNgrids(int vlistID)
64830 @Parameter
64831     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
64832 
64833 @Description
64834 The function @func{vlistNgrids} returns the number of grids in the variable list vlistID.
64835 
64836 @Result
64837 @func{vlistNgrids} returns the number of grids in a variable list.
64838 
64839 @EndFunction
64840 */
vlistNgrids(int vlistID)64841 int vlistNgrids(int vlistID)
64842 {
64843   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64844 
64845   return vlistptr->ngrids;
64846 }
64847 
64848 /*
64849 @Function  vlistNzaxis
64850 @Title     Number of zaxis in a variable list
64851 
64852 @Prototype int vlistNzaxis(int vlistID)
64853 @Parameter
64854     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
64855 
64856 @Description
64857 The function @func{vlistNzaxis} returns the number of zaxis in the variable list vlistID.
64858 
64859 @Result
64860 @func{vlistNzaxis} returns the number of zaxis in a variable list.
64861 
64862 @EndFunction
64863 */
vlistNzaxis(int vlistID)64864 int vlistNzaxis(int vlistID)
64865 {
64866   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64867 
64868   return vlistptr->nzaxis;
64869 }
64870 
64871 
vlistNsubtypes(int vlistID)64872 int vlistNsubtypes(int vlistID)
64873 {
64874   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64875 
64876   return vlistptr->nsubtypes;
64877 }
64878 
64879 
vlistDefNtsteps(int vlistID,int nts)64880 void vlistDefNtsteps(int vlistID, int nts)
64881 {
64882   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64883 
64884   if ( vlistptr->ntsteps != nts )
64885     {
64886       vlistptr->ntsteps = nts;
64887       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
64888     }
64889 }
64890 
64891 // This function is used in CDO!
vlistNtsteps(int vlistID)64892 int vlistNtsteps(int vlistID)
64893 {
64894   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64895 
64896   return (int)vlistptr->ntsteps;
64897 }
64898 
64899 static
vlistPrintKernel(vlist_t * vlistptr,FILE * fp)64900 void vlistPrintKernel(vlist_t *vlistptr, FILE *fp)
64901 {
64902   const int vlistID = vlistptr->self;
64903   fprintf ( fp, "#\n# vlistID %d\n#\n", vlistID);
64904 
64905   const int nvars = vlistptr->nvars;
64906 
64907   fprintf(fp, "nvars    : %d\n"
64908           "ngrids   : %d\n"
64909           "nzaxis   : %d\n"
64910           "nsubtypes: %d\n"
64911           "taxisID  : %d\n"
64912           "instID   : %d\n"
64913           "modelID  : %d\n"
64914           "tableID  : %d\n",
64915           nvars, vlistptr->ngrids, vlistptr->nzaxis, vlistptr->nsubtypes, vlistptr->taxisID,
64916           vlistptr->instID, vlistptr->modelID, vlistptr->tableID);
64917 
64918   if ( nvars > 0 )
64919     {
64920       fprintf(fp, " varID param    gridID zaxisID stypeID tsteptype flag iorank name     longname         units\n");
64921       for ( int varID = 0; varID < nvars; varID++ )
64922         {
64923           int param = vlistptr->vars[varID].param;
64924           int gridID = vlistptr->vars[varID].gridID;
64925           int zaxisID = vlistptr->vars[varID].zaxisID;
64926           int subtypeID = vlistptr->vars[varID].subtypeID;
64927 	  int tsteptype = vlistptr->vars[varID].tsteptype;
64928           char name[CDI_MAX_NAME], longname[CDI_MAX_NAME], units[CDI_MAX_NAME];
64929           int length = CDI_MAX_NAME;
64930           (void)cdiInqKeyString(vlistID, varID, CDI_KEY_NAME, name, &length);
64931           length = CDI_MAX_NAME;
64932           (void)cdiInqKeyString(vlistID, varID, CDI_KEY_LONGNAME, longname, &length);
64933           length = CDI_MAX_NAME;
64934           (void)cdiInqKeyString(vlistID, varID, CDI_KEY_UNITS, units, &length);
64935           int flag = vlistptr->vars[varID].flag;
64936           int iorank = vlistptr->vars[varID].iorank;
64937 
64938           char paramstr[32];
64939           cdiParamToString(param, paramstr, sizeof(paramstr));
64940           fprintf(fp, "%6d %-8s %6d  %6d  %6d  %6d  %5d %6d %-8s %s [%s]\n",
64941                   varID, paramstr, gridID, zaxisID, subtypeID, tsteptype, flag, iorank, name, longname, units);
64942         }
64943 
64944       fputs("\n"
64945             " varID  levID fvarID flevID mvarID mlevID  index  dtype  flag  level\n", fp);
64946       for ( int varID = 0; varID < nvars; varID++ )
64947         {
64948           int zaxisID = vlistptr->vars[varID].zaxisID;
64949           int nlevs = zaxisInqSize(zaxisID);
64950           int fvarID = vlistptr->vars[varID].fvarID;
64951           int mvarID = vlistptr->vars[varID].mvarID;
64952           int dtype    = vlistptr->vars[varID].datatype;
64953           for ( int levID = 0; levID < nlevs; levID++ )
64954             {
64955               levinfo_t li;
64956               if (vlistptr->vars[varID].levinfo)
64957                 li = vlistptr->vars[varID].levinfo[levID];
64958               else
64959                 li = DEFAULT_LEVINFO(levID);
64960               int flevID = li.flevelID;
64961               int mlevID = li.mlevelID;
64962               int index  = li.index;
64963               int flag   = li.flag;
64964 
64965               double level = zaxisInqLevels(zaxisID, NULL) ? zaxisInqLevel(zaxisID, levID) : levID+1;
64966 
64967               fprintf(fp, "%6d %6d %6d %6d %6d %6d %6d %6d %5d  %.9g\n",
64968                       varID, levID, fvarID, flevID, mvarID, mlevID, index, dtype, flag, level);
64969             }
64970         }
64971 
64972       fputs("\n"
64973             " varID  size iorank\n", fp);
64974       for ( int varID = 0; varID < nvars; varID++ )
64975         fprintf(fp, "%3d %8zu %6d\n", varID,
64976                 zaxisInqSize(vlistptr->vars[varID].zaxisID) * gridInqSize(vlistptr->vars[varID].gridID),
64977                 vlistptr->vars[varID].iorank);
64978     }
64979 }
64980 
64981 
vlistPrint(int vlistID)64982 void vlistPrint(int vlistID)
64983 {
64984   if ( vlistID == CDI_UNDEFID ) return;
64985   vlist_t *vlistptr = vlist_to_pointer(vlistID);
64986   vlistPrintKernel(vlistptr, stdout);
64987 }
64988 
64989 /*
64990 @Function  vlistDefTaxis
64991 @Title     Define the time axis
64992 
64993 @Prototype void vlistDefTaxis(int vlistID, int taxisID)
64994 @Parameter
64995     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
64996     @Item  taxisID  Time axis ID, from a previous call to @fref{taxisCreate}.
64997 
64998 @Description
64999 The function @func{vlistDefTaxis} defines the time axis of a variable list.
65000 
65001 @EndFunction
65002 */
vlistDefTaxis(int vlistID,int taxisID)65003 void vlistDefTaxis(int vlistID, int taxisID)
65004 {
65005   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65006 
65007   if ( vlistptr->taxisID != taxisID )
65008     {
65009       //FIXME: This code seems to leak a taxis_t object if `vlistptr->taxisID` was valid before the call to vlistDefTaxis.
65010       vlistptr->taxisID = taxisID;
65011       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
65012     }
65013 }
65014 
65015 /*
65016 @Function  vlistInqTaxis
65017 @Title     Get the time axis
65018 
65019 @Prototype int vlistInqTaxis(int vlistID)
65020 @Parameter
65021     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
65022 
65023 @Description
65024 The function @func{vlistInqTaxis} returns the time axis of a variable list.
65025 
65026 @Result
65027 @func{vlistInqTaxis} returns an identifier to the time axis.
65028 
65029 @EndFunction
65030 */
vlistInqTaxis(int vlistID)65031 int vlistInqTaxis(int vlistID)
65032 {
65033   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65034   return vlistptr->taxisID;
65035 }
65036 
65037 
vlistDefTable(int vlistID,int tableID)65038 void vlistDefTable(int vlistID, int tableID)
65039 {
65040   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65041 
65042   if ( vlistptr->tableID != tableID )
65043     {
65044       vlistptr->tableID = tableID;
65045       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
65046     }
65047 }
65048 
65049 
vlistInqTable(int vlistID)65050 int vlistInqTable(int vlistID)
65051 {
65052   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65053   return vlistptr->tableID;
65054 }
65055 
65056 
vlistDefInstitut(int vlistID,int instID)65057 void vlistDefInstitut(int vlistID, int instID)
65058 {
65059   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65060 
65061   if ( vlistptr->instID != instID )
65062     {
65063       vlistptr->instID = instID;
65064       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
65065     }
65066 }
65067 
65068 
vlistInqInstitut(int vlistID)65069 int vlistInqInstitut(int vlistID)
65070 {
65071   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65072 
65073   int instID = vlistptr->instID;
65074 
65075   if ( instID == CDI_UNDEFID )
65076     {
65077       instID  = vlistInqVarInstitut(vlistID, 0);
65078 
65079       for ( int varID = 1; varID < vlistptr->nvars; varID++ )
65080         if ( instID != vlistInqVarInstitut(vlistID, varID) )
65081           {
65082             instID = CDI_UNDEFID;
65083             break;
65084       }
65085       vlistDefInstitut(vlistID, instID);
65086     }
65087 
65088   return instID;
65089 }
65090 
65091 
vlistDefModel(int vlistID,int modelID)65092 void vlistDefModel(int vlistID, int modelID)
65093 {
65094   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65095 
65096   if ( vlistptr->modelID != modelID )
65097     {
65098       vlistptr->modelID = modelID;
65099       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
65100     }
65101 }
65102 
65103 
vlistInqModel(int vlistID)65104 int vlistInqModel(int vlistID)
65105 {
65106   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65107 
65108   int modelID = vlistptr->modelID;
65109 
65110   if ( modelID == CDI_UNDEFID )
65111     {
65112       modelID = vlistInqVarModel(vlistID, 0);
65113 
65114       for ( int varID = 1; varID < vlistptr->nvars; varID++ )
65115         if ( modelID != vlistInqVarModel(vlistID, varID) )
65116           {
65117             modelID = CDI_UNDEFID;
65118             break;
65119           }
65120 
65121       vlistDefModel(vlistID, modelID);
65122     }
65123 
65124   return modelID;
65125 }
65126 
65127 
vlistGridsizeMax(int vlistID)65128 size_t vlistGridsizeMax(int vlistID)
65129 {
65130   size_t gridsizemax = 0;
65131   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65132 
65133   for ( int index = 0 ; index < vlistptr->ngrids ; index++ )
65134     {
65135       int gridID = vlistptr->gridIDs[index];
65136       size_t gridsize = gridInqSize(gridID);
65137       if ( gridsize > gridsizemax ) gridsizemax = gridsize;
65138     }
65139 
65140   return gridsizemax;
65141 }
65142 
65143 
vlistGrid(int vlistID,int index)65144 int vlistGrid(int vlistID, int index)
65145 {
65146   int gridID = CDI_UNDEFID;
65147   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65148 
65149   if ( index < vlistptr->ngrids && index >= 0 )
65150     gridID = vlistptr->gridIDs[index];
65151 
65152   return gridID;
65153 }
65154 
65155 
vlistGridIndex(int vlistID,int gridID)65156 int vlistGridIndex(int vlistID, int gridID)
65157 {
65158   int index;
65159   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65160 
65161   for ( index = 0 ; index < vlistptr->ngrids ; index++ )
65162     if ( gridID == vlistptr->gridIDs[index] ) break;
65163 
65164   if ( index == vlistptr->ngrids ) index = -1;
65165 
65166   return index;
65167 }
65168 
65169 
vlistChangeGridIndex(int vlistID,int index,int gridID)65170 void vlistChangeGridIndex(int vlistID, int index, int gridID)
65171 {
65172   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65173 
65174   int gridIDold = vlistptr->gridIDs[index];
65175   if (gridIDold != gridID)
65176     {
65177       vlistptr->gridIDs[index] = gridID;
65178 
65179       int nvars = vlistptr->nvars;
65180       for ( int varID = 0; varID < nvars; varID++ )
65181         if ( vlistptr->vars[varID].gridID == gridIDold )
65182           vlistptr->vars[varID].gridID = gridID;
65183       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
65184     }
65185 }
65186 
65187 
vlistChangeGrid(int vlistID,int gridID1,int gridID2)65188 void vlistChangeGrid(int vlistID, int gridID1, int gridID2)
65189 {
65190   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65191 
65192   if (gridID1 != gridID2)
65193     {
65194       int ngrids = vlistptr->ngrids;
65195       for ( int index = 0; index < ngrids; index++ )
65196         {
65197           if ( vlistptr->gridIDs[index] == gridID1 )
65198             {
65199               vlistptr->gridIDs[index] = gridID2;
65200               break;
65201             }
65202         }
65203       int nvars = vlistptr->nvars;
65204       for ( int varID = 0; varID < nvars; varID++ )
65205         if ( vlistptr->vars[varID].gridID == gridID1 )
65206           vlistptr->vars[varID].gridID = gridID2;
65207       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
65208     }
65209 }
65210 
65211 
vlistZaxis(int vlistID,int index)65212 int vlistZaxis(int vlistID, int index)
65213 {
65214   int zaxisID = CDI_UNDEFID;
65215   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65216 
65217   if ( index < vlistptr->nzaxis && index >= 0 )
65218     zaxisID = vlistptr->zaxisIDs[index];
65219 
65220   return zaxisID;
65221 }
65222 
65223 
vlistZaxisIndex(int vlistID,int zaxisID)65224 int vlistZaxisIndex(int vlistID, int zaxisID)
65225 {
65226   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65227 
65228   int index;
65229   for ( index = 0 ; index < vlistptr->nzaxis ; index++ )
65230     if ( zaxisID == vlistptr->zaxisIDs[index] ) break;
65231 
65232   if ( index == vlistptr->nzaxis ) index = -1;
65233 
65234   return index;
65235 }
65236 
65237 
vlistChangeZaxisIndex(int vlistID,int index,int zaxisID)65238 void vlistChangeZaxisIndex(int vlistID, int index, int zaxisID)
65239 {
65240   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65241 
65242   int zaxisIDold = vlistptr->zaxisIDs[index];
65243   if (zaxisIDold != zaxisID)
65244     {
65245       vlistptr->zaxisIDs[index] = zaxisID;
65246 
65247       int nlevs = zaxisInqSize(zaxisID),
65248         nlevsOld = zaxisInqSize(zaxisIDold);
65249       int nvars = vlistptr->nvars;
65250       for ( int varID = 0; varID < nvars; varID++ )
65251         if ( vlistptr->vars[varID].zaxisID == zaxisIDold )
65252           {
65253             vlistptr->vars[varID].zaxisID = zaxisID;
65254             if ( vlistptr->vars[varID].levinfo && nlevs != nlevsOld )
65255               {
65256                 vlistptr->vars[varID].levinfo = (levinfo_t *) Realloc(vlistptr->vars[varID].levinfo, (size_t)nlevs * sizeof (levinfo_t));
65257 
65258                 for ( int levID = 0; levID < nlevs; levID++ )
65259                   vlistptr->vars[varID].levinfo[levID] = DEFAULT_LEVINFO(levID);
65260               }
65261           }
65262       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
65263     }
65264 }
65265 
65266 
vlistChangeZaxis(int vlistID,int zaxisID1,int zaxisID2)65267 void vlistChangeZaxis(int vlistID, int zaxisID1, int zaxisID2)
65268 {
65269   int nlevs1 = zaxisInqSize(zaxisID1), nlevs2 = zaxisInqSize(zaxisID2);
65270   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65271 
65272   int nzaxis = vlistptr->nzaxis;
65273   for ( int index = 0; index < nzaxis; index++ )
65274     {
65275       if ( vlistptr->zaxisIDs[index] == zaxisID1 )
65276         {
65277           vlistptr->zaxisIDs[index] = zaxisID2;
65278           break;
65279         }
65280     }
65281 
65282   int nvars = vlistptr->nvars;
65283   for ( int varID = 0; varID < nvars; varID++ )
65284     if ( vlistptr->vars[varID].zaxisID == zaxisID1 )
65285       {
65286         vlistptr->vars[varID].zaxisID = zaxisID2;
65287 
65288         if ( vlistptr->vars[varID].levinfo && nlevs2 != nlevs1 )
65289           {
65290             vlistptr->vars[varID].levinfo
65291               = (levinfo_t *) Realloc(vlistptr->vars[varID].levinfo,
65292                                       (size_t)nlevs2 * sizeof(levinfo_t));
65293 
65294             for ( int levID = 0; levID < nlevs2; levID++ )
65295               vlistptr->vars[varID].levinfo[levID] = DEFAULT_LEVINFO(levID);
65296           }
65297       }
65298   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
65299 }
65300 
65301 
vlistSubtype(int vlistID,int index)65302 int vlistSubtype(int vlistID, int index)
65303 {
65304   int subtypeID = CDI_UNDEFID;
65305   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65306 
65307   if ( index < vlistptr->nsubtypes && index >= 0 )
65308     subtypeID = vlistptr->subtypeIDs[index];
65309 
65310   return subtypeID;
65311 }
65312 
65313 
vlistSubtypeIndex(int vlistID,int subtypeID)65314 int vlistSubtypeIndex(int vlistID, int subtypeID)
65315 {
65316   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65317 
65318   int index;
65319   for(index = vlistptr->nsubtypes; index--; )
65320     if ( subtypeID == vlistptr->subtypeIDs[index] ) break;
65321 
65322   return index;
65323 }
65324 
65325 
vlistHasTime(int vlistID)65326 int vlistHasTime(int vlistID)
65327 {
65328   bool hastime = false;
65329   vlist_t *vlistptr = vlist_to_pointer(vlistID);
65330 
65331   if ( !(CDI_Reduce_Dim && vlistptr->ntsteps == 1) )
65332     {
65333       for ( int varID = 0; varID <  vlistptr->nvars; varID++ )
65334         if ( vlistptr->vars[varID].timetype != TIME_CONSTANT )
65335           {
65336             hastime = true;
65337             break;
65338           }
65339     }
65340 
65341   return (int)hastime;
65342 }
65343 
65344 enum {
65345   vlist_nints=6,
65346 };
65347 
vlistTxCode(void)65348 static int vlistTxCode ( void )
65349 {
65350   return VLIST;
65351 }
65352 
65353 
65354 static
vlistGetSizeP(void * vlistptr,void * context)65355 int  vlistGetSizeP ( void * vlistptr, void *context)
65356 {
65357   vlist_t *p = (vlist_t*) vlistptr;
65358   int txsize = serializeGetSize(vlist_nints, CDI_DATATYPE_INT, context);
65359   txsize += serializeGetSize(1, CDI_DATATYPE_LONG, context);
65360   txsize += cdiAttsGetSize(p, CDI_GLOBAL, context);
65361   for ( int varID = 0; varID <  p->nvars; varID++ )
65362     txsize += vlistVarGetPackSize(p, varID, context);
65363   return txsize;
65364 }
65365 
65366 
65367 static
vlistPackP(void * vlistptr,void * buf,int size,int * position,void * context)65368 void vlistPackP ( void * vlistptr, void * buf, int size, int *position,
65369                   void *context )
65370 {
65371   int tempbuf[vlist_nints];
65372   vlist_t *p = (vlist_t*) vlistptr;
65373   tempbuf[0] = p->self;
65374   tempbuf[1] = p->nvars;
65375   tempbuf[2] = p->taxisID;
65376   tempbuf[3] = p->tableID;
65377   tempbuf[4] = p->instID;
65378   tempbuf[5] = p->modelID;
65379   serializePack(tempbuf, vlist_nints, CDI_DATATYPE_INT, buf, size, position, context);
65380   serializePack(&p->ntsteps, 1, CDI_DATATYPE_LONG, buf, size, position, context);
65381 
65382   cdiAttsPack(p, CDI_GLOBAL, buf, size, position, context);
65383   for ( int varID = 0; varID < p->nvars; varID++ )
65384     {
65385       vlistVarPack(p, varID, (char *)buf, size, position, context);
65386     }
65387 }
65388 
vlistUnpack(char * buf,int size,int * position,int originNamespace,void * context,int force_id)65389 void vlistUnpack(char * buf, int size, int *position, int originNamespace,
65390                  void *context, int force_id)
65391 {
65392   int tempbuf[vlist_nints];
65393   serializeUnpack(buf, size, position, tempbuf, vlist_nints, CDI_DATATYPE_INT, context);
65394   int nvars = tempbuf[1];
65395   int targetID = namespaceAdaptKey(tempbuf[0], originNamespace);
65396   vlist_t *p = vlist_new_entry(force_id?targetID:CDI_UNDEFID);
65397   xassert(!force_id || p->self == targetID);
65398   if (!force_id)
65399     targetID = p->self;
65400   cdiVlistMakeInternal(p->self);
65401   p->taxisID = namespaceAdaptKey(tempbuf[2], originNamespace);
65402   p->tableID = tempbuf[3];
65403   p->instID = namespaceAdaptKey(tempbuf[4], originNamespace);
65404   p->modelID = namespaceAdaptKey(tempbuf[5], originNamespace);
65405   serializeUnpack(buf, size, position, &p->ntsteps, 1, CDI_DATATYPE_LONG, context);
65406   cdiAttsUnpack(targetID, CDI_GLOBAL, buf, size, position, context);
65407   for (int varID = 0; varID < nvars; varID++ )
65408     vlistVarUnpack(targetID, buf, size, position, originNamespace, context);
65409   reshSetStatus(targetID, &vlistOps, reshGetStatus(targetID, &vlistOps) & ~RESH_SYNC_BIT);
65410 }
65411 
65412 
vlist_check_contents(int vlistID)65413 void vlist_check_contents(int vlistID)
65414 {
65415   int nzaxis = vlistNzaxis(vlistID);
65416   for ( int index = 0; index < nzaxis; index++ )
65417     {
65418       int zaxisID = vlistZaxis(vlistID, index);
65419       if ( zaxisInqType(zaxisID) == ZAXIS_GENERIC )
65420 	cdiCheckZaxis(zaxisID);
65421     }
65422 }
65423 
65424 
65425 /* Resizes and initializes opt_grib_kvpair data structure. */
resize_opt_grib_entries(var_t * var,int nentries)65426 void resize_opt_grib_entries(var_t *var, int nentries)
65427 {
65428   if (var->opt_grib_kvpair_size >= nentries)
65429     {
65430       return;   /* nothing to do; array is still large enough */
65431     }
65432   else
65433     {
65434       if ( CDI_Debug )
65435         Message("resize data structure, %d -> %d", var->opt_grib_kvpair_size, nentries);
65436 
65437       int i, new_size;
65438       new_size = (2*var->opt_grib_kvpair_size) > nentries ? (2*var->opt_grib_kvpair_size) : nentries;
65439       opt_key_val_pair_t *tmp = (opt_key_val_pair_t *) Malloc((size_t)new_size * sizeof (opt_key_val_pair_t));
65440       for (i=0; i<var->opt_grib_kvpair_size; i++) {
65441         tmp[i] = var->opt_grib_kvpair[i];
65442       }
65443       for (i=var->opt_grib_kvpair_size; i<new_size; i++) {
65444         tmp[i].int_val =     0;
65445         tmp[i].dbl_val =     0;
65446         tmp[i].update  = false;
65447         tmp[i].keyword =  NULL;
65448       } // for
65449       var->opt_grib_kvpair_size = new_size;
65450       Free(var->opt_grib_kvpair);
65451       var->opt_grib_kvpair = tmp;
65452     }
65453 }
65454 
65455 /*
65456  * Local Variables:
65457  * c-file-style: "Java"
65458  * c-basic-offset: 2
65459  * indent-tabs-mode: nil
65460  * show-trailing-whitespace: t
65461  * require-trailing-newline: t
65462  * End:
65463  */
65464 
65465 
65466 static
vlist_get_keysp(vlist_t * vlistptr,int varID)65467 cdi_keys_t *vlist_get_keysp(vlist_t *vlistptr, int varID)
65468 {
65469   if      (varID == CDI_GLOBAL) return &vlistptr->keys;
65470   else if (varID >= 0 && varID < vlistptr->nvars) return &(vlistptr->vars[varID].keys);
65471 
65472   return NULL;
65473 }
65474 
65475 static
grid_get_keysp(grid_t * gridptr,int varID)65476 cdi_keys_t *grid_get_keysp(grid_t *gridptr, int varID)
65477 {
65478   if      (varID == CDI_GLOBAL) return &gridptr->keys;
65479   else if (varID == CDI_XAXIS)  return &gridptr->x.keys;
65480   else if (varID == CDI_YAXIS)  return &gridptr->y.keys;
65481 
65482   return NULL;
65483 }
65484 
65485 static
zaxis_get_keysp(zaxis_t * zaxisptr,int varID)65486 cdi_keys_t *zaxis_get_keysp(zaxis_t *zaxisptr, int varID)
65487 {
65488   if (varID == CDI_GLOBAL) return &zaxisptr->keys;
65489 
65490   return NULL;
65491 }
65492 
65493 static
new_key(cdi_keys_t * keysp,int key)65494 cdi_key_t *new_key(cdi_keys_t *keysp, int key)
65495 {
65496   xassert(keysp != NULL);
65497 
65498   if ( keysp->nelems == keysp->nalloc ) return NULL;
65499 
65500   cdi_key_t *keyp = &(keysp->value[keysp->nelems]);
65501   keysp->nelems++;
65502 
65503   keyp->key = key;
65504   keyp->length = 0;
65505   keyp->type = 0;
65506   keyp->v.s = NULL;
65507 
65508   return keyp;
65509 }
65510 
65511 
find_key(cdi_keys_t * keysp,int key)65512 cdi_key_t *find_key(cdi_keys_t *keysp, int key)
65513 {
65514   xassert(keysp != NULL);
65515 
65516   if ( keysp->nelems == 0 ) return NULL;
65517 
65518   for ( size_t keyid = 0; keyid < keysp->nelems; keyid++ )
65519     {
65520       cdi_key_t *keyp =  &(keysp->value[keyid]);
65521       if ( keyp->key == key ) return keyp; // Normal return
65522     }
65523 
65524   return NULL;
65525 }
65526 
65527 static
find_key_const(const cdi_keys_t * keysp,int key)65528 const cdi_key_t *find_key_const(const cdi_keys_t *keysp, int key)
65529 {
65530   xassert(keysp != NULL);
65531 
65532   if ( keysp->nelems == 0 ) return NULL;
65533 
65534   for ( size_t keyid = 0; keyid < keysp->nelems; keyid++ )
65535     {
65536       const cdi_key_t *keyp =  &(keysp->value[keyid]);
65537       if ( keyp->key == key ) return keyp; // Normal return
65538     }
65539 
65540   return NULL;
65541 }
65542 
65543 static
cdi_get_keysp(int objID,int varID)65544 cdi_keys_t *cdi_get_keysp(int objID, int varID)
65545 {
65546   if      ( reshGetTxCode(objID) == GRID )  return grid_get_keysp(grid_to_pointer(objID), varID);
65547   else if ( reshGetTxCode(objID) == ZAXIS ) return zaxis_get_keysp(zaxis_to_pointer(objID), varID);
65548   else if ( reshGetTxCode(objID) == VLIST ) return vlist_get_keysp(vlist_to_pointer(objID), varID);
65549 
65550   return NULL;
65551 }
65552 
65553 
cdi_key_compare(cdi_keys_t * keyspa,cdi_keys_t * keyspb,int keynum)65554 int cdi_key_compare(cdi_keys_t *keyspa, cdi_keys_t *keyspb, int keynum)
65555 {
65556   xassert(keynum >= 0 && keynum < (int)keyspa->nelems && keynum < (int)keyspb->nelems);
65557   cdi_key_t *keypa = keyspa->value + keynum,
65558             *keypb = keyspb->value + keynum;
65559 
65560   if (keypa->key != keypb->key) return 1;
65561 
65562   if (keypa->type != keypb->type) return 1;
65563 
65564   if (keypa->type == KEY_BYTES)
65565     {
65566       if (keypa->length != keypb->length) return 1;
65567       return memcmp(keypa->v.s, keypb->v.s, keypa->length);
65568     }
65569   else if (keypa->type == KEY_FLOAT)
65570     {
65571       if (IS_NOT_EQUAL(keypa->v.d, keypb->v.d)) return 1;
65572     }
65573   else if (keypa->type == KEY_INT)
65574     {
65575       if (keypa->v.i != keypb->v.i) return 1;
65576     }
65577 
65578   return 0;
65579 }
65580 
65581 
cdiDeleteVarKeys(cdi_keys_t * keysp)65582 void cdiDeleteVarKeys(cdi_keys_t *keysp)
65583 {
65584   for ( int keyid = 0; keyid < (int)keysp->nelems; keyid++ )
65585     {
65586       cdi_key_t *keyp = &(keysp->value[keyid]);
65587       if ( keyp->length )
65588         {
65589           free(keyp->v.s);
65590           keyp->v.s = NULL;
65591           keyp->length = 0;
65592         }
65593     }
65594 
65595   keysp->nelems = 0;
65596 }
65597 
65598 
cdiDeleteKeys(int cdiID,int varID)65599 void cdiDeleteKeys(int cdiID, int varID)
65600 {
65601   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
65602   xassert(keysp != NULL);
65603 
65604   cdiDeleteVarKeys(keysp);
65605 }
65606 
65607 
cdiPrintVarKeys(cdi_keys_t * keysp)65608 void cdiPrintVarKeys(cdi_keys_t *keysp)
65609 {
65610   for ( int keyid = 0; keyid < (int)keysp->nelems; keyid++ )
65611     {
65612       cdi_key_t *keyp = &(keysp->value[keyid]);
65613       if (keyp->type == KEY_BYTES)
65614         {
65615           printf("%d key %d length %d value %s\n", keyid+1, keyp->key, keyp->length,  keyp->v.s);
65616         }
65617       else if (keyp->type == KEY_FLOAT)
65618         {
65619           printf("%d key %d value %g\n", keyid+1, keyp->key, keyp->v.d);
65620         }
65621       else if (keyp->type == KEY_INT)
65622         {
65623           printf("%d key %d value %d\n", keyid+1, keyp->key, keyp->v.i);
65624         }
65625     }
65626 }
65627 
65628 
cdiPrintKeys(int cdiID,int varID)65629 void cdiPrintKeys(int cdiID, int varID)
65630 {
65631   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
65632   xassert(keysp != NULL);
65633 
65634   cdiPrintVarKeys(keysp);
65635 }
65636 
65637 //  cdiInqKeyLen: Get the length of the string representation of the key
cdiInqKeyLen(int cdiID,int varID,int key,int * length)65638 int cdiInqKeyLen(int cdiID, int varID, int key, int *length)
65639 {
65640   int status = -1;
65641 
65642   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
65643   xassert(keysp != NULL);
65644 
65645   const cdi_key_t *keyp = find_key(keysp, key);
65646   if ( keyp != NULL )
65647     {
65648       *length = keyp->length;
65649       if ( *length == 0 ) *length = 1;
65650       status = CDI_NOERR;
65651     }
65652 
65653   return status;
65654 }
65655 
65656 static
cdi_define_key(const cdi_key_t * keyp,cdi_keys_t * keysp)65657 void cdi_define_key(const cdi_key_t *keyp, cdi_keys_t *keysp)
65658 {
65659   if      ( keyp->type == KEY_INT )
65660     cdiDefVarKeyInt(keysp, keyp->key, keyp->v.i);
65661   else if ( keyp->type == KEY_FLOAT )
65662     cdiDefVarKeyFloat(keysp, keyp->key, keyp->v.d);
65663   else if ( keyp->type == KEY_BYTES )
65664     cdiDefVarKeyBytes(keysp, keyp->key, keyp->v.s, keyp->length);
65665 }
65666 
65667 
cdiDeleteKey(int cdiID,int varID,int key)65668 int cdiDeleteKey(int cdiID, int varID, int key)
65669 {
65670   int status = -1;
65671 
65672   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
65673   xassert(keysp != NULL);
65674 
65675   cdi_key_t *keyp = find_key(keysp, key);
65676   if ( keyp != NULL ) // key in use
65677     {
65678       if ( keyp->length )
65679         {
65680           free(keyp->v.s);
65681           keyp->v.s = NULL;
65682           keyp->length = 0;
65683         }
65684     }
65685 
65686   return status;
65687 }
65688 
65689 
cdiCopyVarKeys(const cdi_keys_t * keysp1,cdi_keys_t * keysp2)65690 void cdiCopyVarKeys(const cdi_keys_t *keysp1, cdi_keys_t *keysp2)
65691 {
65692   for ( size_t keyid = 0; keyid < keysp1->nelems; keyid++ )
65693     {
65694       const cdi_key_t *keyp = &(keysp1->value[keyid]);
65695       cdi_define_key(keyp, keysp2);
65696     }
65697 }
65698 
65699 
cdiCopyKeys(int cdiID1,int varID1,int cdiID2,int varID2)65700 int cdiCopyKeys(int cdiID1, int varID1, int cdiID2, int varID2)
65701 {
65702   int status = CDI_NOERR;
65703 
65704   cdi_keys_t *keysp1 = cdi_get_keysp(cdiID1, varID1);
65705   xassert(keysp1 != NULL);
65706 
65707   cdi_keys_t *keysp2 = cdi_get_keysp(cdiID2, varID2);
65708   xassert(keysp2 != NULL);
65709 
65710   cdiCopyVarKeys(keysp1, keysp2);
65711 
65712   return status;
65713 }
65714 
65715 
cdiCopyVarKey(const cdi_keys_t * keysp1,int key,cdi_keys_t * keysp2)65716 int cdiCopyVarKey(const cdi_keys_t *keysp1, int key, cdi_keys_t *keysp2)
65717 {
65718   int status = CDI_NOERR;
65719 
65720   const cdi_key_t *keyp = find_key_const (keysp1, key);
65721   if (keyp == NULL) return -1;
65722 
65723   cdi_define_key(keyp, keysp2);
65724 
65725   return status;
65726 }
65727 
65728 
cdiCopyKey(int cdiID1,int varID1,int key,int cdiID2)65729 int cdiCopyKey(int cdiID1, int varID1, int key, int cdiID2)
65730 {
65731   cdi_keys_t *keysp1 = cdi_get_keysp(cdiID1, varID1);
65732   xassert(keysp1 != NULL);
65733 
65734   cdi_keys_t *keysp2 = cdi_get_keysp(cdiID2, varID1);
65735   xassert(keysp2 != NULL);
65736 
65737   return cdiCopyVarKey(keysp1, key, keysp2);
65738 }
65739 
65740 
cdiDefVarKeyInt(cdi_keys_t * keysp,int key,int value)65741 void cdiDefVarKeyInt(cdi_keys_t *keysp, int key, int value)
65742 {
65743   cdi_key_t *keyp = find_key(keysp, key);
65744   if ( keyp == NULL ) keyp = new_key(keysp, key);
65745 
65746   if ( keyp != NULL )
65747     {
65748       //if ( keyp->v.i != value )
65749         {
65750           keyp->type = KEY_INT;
65751           keyp->v.i = value;
65752         }
65753     }
65754 }
65755 
65756 /*
65757 @Function  cdiDefKeyInt
65758 @Title     Define an integer value from a key
65759 
65760 @Prototype int cdiDefKeyInt(int cdiID, int varID, int key, int value)
65761 @Parameter
65762     @Item  cdiID    CDI object ID (vlistID, gridID, zaxisID).
65763     @Item  varID    Variable identifier or CDI_GLOBAL.
65764     @Item  key      The key to be searched.
65765     @Item  value    An integer where the data will be read.
65766 
65767 @Description
65768 The function @func{cdiDefKeyInt} defines an integer value from a key.
65769 
65770 @Result
65771 @func{cdiDefKeyInt} returns CDI_NOERR if OK.
65772 
65773 @EndFunction
65774 */
cdiDefKeyInt(int cdiID,int varID,int key,int value)65775 int cdiDefKeyInt(int cdiID, int varID, int key, int value)
65776 {
65777   int status = CDI_NOERR;
65778 
65779   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
65780   xassert(keysp != NULL);
65781 
65782   cdiDefVarKeyInt(keysp, key, value);
65783 
65784   return status;
65785 }
65786 
65787 /*
65788 @Function  cdiInqKeyInt
65789 @Title     Get an integer value from a key
65790 
65791 @Prototype int cdiInqKeyInt(int cdiID, int varID, int key, int *value)
65792 @Parameter
65793     @Item  cdiID    CDI object ID (vlistID, gridID, zaxisID).
65794     @Item  varID    Variable identifier or CDI_GLOBAL.
65795     @Item  key      The key to be searched..
65796     @Item  value    The address of an integer where the data will be retrieved.
65797 
65798 @Description
65799 The function @func{cdiInqKeyInt} gets an integer value from a key.
65800 
65801 @Result
65802 @func{cdiInqKeyInt} returns CDI_NOERR if key is available.
65803 
65804 @EndFunction
65805 */
cdiInqKeyInt(int cdiID,int varID,int key,int * value)65806 int cdiInqKeyInt(int cdiID, int varID, int key, int *value)
65807 {
65808   int status = -1;
65809 
65810   // if ( varID != CDI_GLOBAL ) status = cdiInqKeyInt(cdiID, CDI_GLOBAL, key, value);
65811 
65812   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
65813   xassert(keysp != NULL);
65814 
65815   cdi_key_t *keyp = find_key(keysp, key);
65816   if ( keyp != NULL ) // key in use
65817     {
65818       if ( keyp->type == KEY_INT )
65819 	{
65820           *value = keyp->v.i;
65821           status = CDI_NOERR;
65822 	}
65823     }
65824 
65825   return status;
65826 }
65827 
65828 
cdiInqVarKeyInt(const cdi_keys_t * keysp,int key)65829 int cdiInqVarKeyInt(const cdi_keys_t *keysp, int key)
65830 {
65831   int value = 0;
65832 
65833   const cdi_key_t *keyp = find_key_const(keysp, key);
65834   if (keyp && keyp->type == KEY_INT ) value = keyp->v.i;
65835 
65836   return value;
65837 }
65838 
65839 
cdiDefVarKeyFloat(cdi_keys_t * keysp,int key,double value)65840 void cdiDefVarKeyFloat(cdi_keys_t *keysp, int key, double value)
65841 {
65842   cdi_key_t *keyp = find_key(keysp, key);
65843   if ( keyp == NULL ) keyp = new_key(keysp, key);
65844 
65845   if ( keyp != NULL )
65846     {
65847       //if ( keyp->v.i != value )
65848         {
65849           keyp->type = KEY_INT;
65850           keyp->v.d = value;
65851         }
65852     }
65853 }
65854 
65855 /*
65856 @Function  cdiDefKeyFloat
65857 @Title     Define a floating point value from a key
65858 
65859 @Prototype int cdiDefKeyFloat(int cdiID, int varID, int key, double value)
65860 @Parameter
65861     @Item  cdiID    CDI object ID (vlistID, gridID, zaxisID).
65862     @Item  varID    Variable identifier or CDI_GLOBAL.
65863     @Item  key      The key to be searched
65864     @Item  value    A double where the data will be read
65865 
65866 @Description
65867 The function @func{cdiDefKeyFloat} defines a CDI floating point value from a key.
65868 
65869 @Result
65870 @func{cdiDefKeyFloat} returns CDI_NOERR if OK.
65871 
65872 @EndFunction
65873 */
cdiDefKeyFloat(int cdiID,int varID,int key,double value)65874 int cdiDefKeyFloat(int cdiID, int varID, int key, double value)
65875 {
65876   int status = CDI_NOERR;
65877 
65878   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
65879   xassert(keysp != NULL);
65880 
65881   cdiDefVarKeyFloat(keysp, key, value);
65882 
65883   return status;
65884 }
65885 
65886 /*
65887 @Function  cdiInqKeyFloat
65888 @Title     Get a floating point value from a key
65889 
65890 @Prototype int cdiInqKeyFloat(int cdiID, int varID, int key, double *value)
65891 @Parameter
65892     @Item  cdiID    CDI object ID (vlistID, gridID, zaxisID).
65893     @Item  varID    Variable identifier or CDI_GLOBAL.
65894     @Item  key      The key to be searched.
65895     @Item  value    The address of a double where the data will be retrieved.
65896 
65897 @Description
65898 The function @func{cdiInqKeyFloat} gets a floating point value from a key.
65899 
65900 @Result
65901 @func{cdiInqKeyFloat} returns CDI_NOERR if key is available.
65902 
65903 @EndFunction
65904 */
cdiInqKeyFloat(int cdiID,int varID,int key,double * value)65905 int cdiInqKeyFloat(int cdiID, int varID, int key, double *value)
65906 {
65907   int status = -1;
65908 
65909   // if ( varID != CDI_GLOBAL ) status = cdiInqKeyFloat(cdiID, CDI_GLOBAL, key, value);
65910 
65911   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
65912   xassert(keysp != NULL);
65913 
65914   cdi_key_t *keyp = find_key(keysp, key);
65915   if ( keyp != NULL ) // key in use
65916     {
65917       if ( keyp->type == KEY_FLOAT )
65918 	{
65919           *value = keyp->v.d;
65920           status = CDI_NOERR;
65921 	}
65922     }
65923 
65924   return status;
65925 }
65926 
65927 
cdiDefVarKeyBytes(cdi_keys_t * keysp,int key,const unsigned char * bytes,int length)65928 void cdiDefVarKeyBytes(cdi_keys_t *keysp, int key, const unsigned char *bytes, int length)
65929 {
65930   cdi_key_t *keyp = find_key(keysp, key);
65931   if ( keyp == NULL ) keyp = new_key(keysp, key);
65932 
65933   if ( keyp != NULL )
65934     {
65935       if ( keyp->length != 0 && keyp->length != length )
65936         {
65937           free(keyp->v.s);
65938           keyp->length = 0;
65939         }
65940       if ( keyp->length == 0 )
65941         {
65942           keyp->v.s = (unsigned char *) malloc((size_t) length);
65943           keyp->length = length;
65944         }
65945 
65946       memcpy(keyp->v.s, bytes, length);
65947       keyp->type = KEY_BYTES;
65948     }
65949 }
65950 
65951 /*
65952 @Function  cdiDefKeyBytes
65953 @Title     Define a byte array from a key
65954 
65955 @Prototype int cdiDefKeyBytes(int cdiID, int varID, int key, const unsigned char *bytes, int length)
65956 @Parameter
65957     @Item  cdiID    CDI object ID (vlistID, gridID, zaxisID).
65958     @Item  varID    Variable identifier or CDI_GLOBAL.
65959     @Item  key      The key to be searched.
65960     @Item  bytes    The address of a byte array where the data will be read.
65961     @Item  length   Length of the byte array
65962 
65963 @Description
65964 The function @func{cdiDefKeyBytes} defines a byte array from a key.
65965 
65966 @Result
65967 @func{cdiDefKeyBytes} returns CDI_NOERR if OK.
65968 
65969 @EndFunction
65970 */
cdiDefKeyBytes(int cdiID,int varID,int key,const unsigned char * bytes,int length)65971 int cdiDefKeyBytes(int cdiID, int varID, int key, const unsigned char *bytes, int length)
65972 {
65973   int status = CDI_NOERR;
65974 
65975   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
65976   xassert(keysp != NULL);
65977 
65978   cdiDefVarKeyBytes(keysp, key, bytes, length);
65979 
65980   return status;
65981 }
65982 
cdiInqVarKeyBytes(const cdi_keys_t * keysp,int key,unsigned char * bytes,int * length)65983 int cdiInqVarKeyBytes(const cdi_keys_t *keysp, int key, unsigned char *bytes, int *length)
65984 {
65985   int status = -1;
65986 
65987   const cdi_key_t *keyp = find_key_const(keysp, key);
65988   if ( keyp != NULL ) // key in use
65989     {
65990       if ( keyp->type == KEY_BYTES )
65991 	{
65992           if ( keyp->length < *length ) *length = keyp->length;
65993           memcpy(bytes, keyp->v.s, *length);
65994           status = CDI_NOERR;
65995 	}
65996     }
65997 
65998   return status;
65999 }
66000 
66001 //  cdiInqKeyBytes: Get a byte array from a key
66002 /*
66003 @Function  cdiInqKeyBytes
66004 @Title     Get a byte array from a key
66005 
66006 @Prototype int cdiInqKeyBytes(int cdiID, int varID, int key, unsigned char *bytes, int *length)
66007 @Parameter
66008     @Item  cdiID    CDI object ID (vlistID, gridID, zaxisID).
66009     @Item  varID    Variable identifier or CDI_GLOBAL.
66010     @Item  key      The key to be searched.
66011     @Item  bytes    The address of a byte array where the data will be retrieved.
66012                     The caller must allocate space for the returned byte array.
66013     @Item  length   The allocated length of the byte array on input.
66014 @Description
66015 The function @func{cdiInqKeyBytes} gets a byte array from a key.
66016 
66017 @Result
66018 @func{cdiInqKeyBytes} returns CDI_NOERR if key is available.
66019 
66020 @EndFunction
66021 */
cdiInqKeyBytes(int cdiID,int varID,int key,unsigned char * bytes,int * length)66022 int cdiInqKeyBytes(int cdiID, int varID, int key, unsigned char *bytes, int *length)
66023 {
66024   xassert(bytes != NULL);
66025   xassert(length != NULL);
66026 
66027   // if ( varID != CDI_GLOBAL ) status = cdiInqKeyBytes(cdiID, CDI_GLOBAL, key, bytes, length);
66028 
66029   const cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
66030   xassert(keysp != NULL);
66031 
66032   return cdiInqVarKeyBytes(keysp, key, bytes, length);
66033 }
66034 
66035 /*
66036 @Function  cdiDefKeyString
66037 @Title     Define a string from a key
66038 
66039 @Prototype int cdiDefKeyString(int cdiID, int varID, int key, const char *string)
66040 @Parameter
66041     @Item  cdiID    CDI object ID (vlistID, gridID, zaxisID).
66042     @Item  varID    Variable identifier or CDI_GLOBAL.
66043     @Item  key      The key to be searched.
66044     @Item  string   The address of a string where the data will be read.
66045 
66046 @Description
66047 The function @func{cdiDefKeyString} defines a text string from a key.
66048 
66049 @Result
66050 @func{cdiDefKeyString} returns CDI_NOERR if OK.
66051 
66052 @Example
66053 Here is an example using @func{cdiDefKeyString} to define the name of a variable:
66054 
66055 @Source
66056    ...
66057 int vlistID, varID, status;
66058    ...
66059 vlistID = vlistCreate();
66060 varID = vlistDefVar(vlistID, gridID, zaxisID, TIME_VARYING);
66061    ...
66062 status = cdiDefKeyString(vlistID, varID, CDI_KEY_NAME, "temperature");
66063    ...
66064 @EndSource
66065 @EndFunction
66066 */
cdiDefKeyString(int cdiID,int varID,int key,const char * string)66067 int cdiDefKeyString(int cdiID, int varID, int key, const char *string)
66068 {
66069   xassert(string != NULL);
66070 
66071   int length = strlen(string) + 1;
66072   int status = cdiDefKeyBytes(cdiID, varID, key, (const unsigned char *) string, length);
66073 
66074   return status;
66075 }
66076 
66077 /*
66078 @Function  cdiInqKeyString
66079 @Title     Get a string from a key
66080 
66081 @Prototype int cdiInqKeyString(int cdiID, int varID, int key, char *string, int *length)
66082 @Parameter
66083     @Item  cdiID    CDI object ID (vlistID, gridID, zaxisID).
66084     @Item  varID    Variable identifier or CDI_GLOBAL.
66085     @Item  key      The key to be searched.
66086     @Item  string   The address of a string where the data will be retrieved.
66087                     The caller must allocate space for the returned string.
66088     @Item  length   The allocated length of the string on input.
66089 @Description
66090 The function @func{cdiInqKeyString} gets a text string from a key.
66091 
66092 @Result
66093 @func{cdiInqKeyString} returns CDI_NOERR if key is available.
66094 
66095 @Example
66096 Here is an example using @func{cdiInqKeyString} to get the name of the first variable:
66097 
66098 @Source
66099    ...
66100 #define STRLEN 256
66101    ...
66102 int streamID, vlistID, varID, status;
66103 int length = STRLEN;
66104 char name[STRLEN];
66105    ...
66106 streamID = streamOpenRead(...);
66107 vlistID = streamInqVlist(streamID);
66108    ...
66109 varID = 0;
66110 status = cdiInqKeyString(vlistID, varID, CDI_KEY_NAME, name, &length);
66111    ...
66112 @EndSource
66113 @EndFunction
66114 */
cdiInqKeyString(int cdiID,int varID,int key,char * string,int * length)66115 int cdiInqKeyString(int cdiID, int varID, int key, char *string, int *length)
66116 {
66117   xassert(string != NULL);
66118   xassert(length != NULL);
66119 
66120   int maxlength = *length;
66121   if (maxlength > 0) string[0] = '\0';
66122 
66123   int status = cdiInqKeyBytes(cdiID, varID, key, (unsigned char *) string, length);
66124   if (status != CDI_NOERR) *length = 0;
66125   else string[maxlength-1] = '\0';
66126 
66127   return status;
66128 }
66129 
cdiInqVarKeyStringPtr(cdi_keys_t * keysp,int key)66130 const char *cdiInqVarKeyStringPtr(cdi_keys_t *keysp, int key)
66131 {
66132   const cdi_key_t *keyp = find_key(keysp, key);
66133   if ( keyp != NULL ) // key in use
66134     {
66135       if ( keyp->type == KEY_BYTES ) return (const char *)keyp->v.s;
66136     }
66137 
66138   return NULL;
66139 }
66140 
cdiInitKeys(cdi_keys_t * keysp)66141 void cdiInitKeys(cdi_keys_t *keysp)
66142 {
66143   keysp->nalloc = MAX_KEYS;
66144   keysp->nelems = 0;
66145   for ( int i = 0; i < MAX_KEYS; ++i )
66146     keysp->value[i].length = 0;
66147 }
66148 
66149 /*
66150  * Local Variables:
66151  * c-file-style: "Java"
66152  * c-basic-offset: 2
66153  * indent-tabs-mode: nil
66154  * show-trailing-whitespace: t
66155  * require-trailing-newline: t
66156  * End:
66157  */
66158 #include <assert.h>
66159 #include <limits.h>
66160 #include <stdio.h>
66161 #include <string.h>
66162 
66163 
66164 
66165 
66166 static
get_attsp(vlist_t * vlistptr,int varID)66167 cdi_atts_t *get_attsp(vlist_t *vlistptr, int varID)
66168 {
66169   if ( varID == CDI_GLOBAL ) return &vlistptr->atts;
66170   else if ( varID >= 0 && varID < vlistptr->nvars ) return &(vlistptr->vars[varID].atts);
66171 
66172   return NULL;
66173 }
66174 
66175 static
find_att(cdi_atts_t * attsp,const char * name)66176 cdi_att_t *find_att(cdi_atts_t *attsp, const char *name)
66177 {
66178   xassert(attsp != NULL);
66179 
66180   if ( attsp->nelems == 0 ) return NULL;
66181 
66182   size_t slen = strlen(name);
66183   if ( slen > CDI_MAX_NAME ) slen = CDI_MAX_NAME;
66184 
66185   cdi_att_t *atts = attsp->value;
66186   for ( size_t attid = 0; attid < attsp->nelems; attid++ )
66187     {
66188       cdi_att_t *attp = atts + attid;
66189       if ( attp->namesz == slen && memcmp(attp->name, name, slen) == 0 )
66190         return attp; // Normal return
66191     }
66192 
66193   return NULL;
66194 }
66195 
66196 static
new_att(cdi_atts_t * attsp,const char * name)66197 cdi_att_t *new_att(cdi_atts_t *attsp, const char *name)
66198 {
66199   xassert(attsp != NULL);
66200   xassert(name  != NULL);
66201 
66202   if ( attsp->nelems == attsp->nalloc ) return NULL;
66203 
66204   cdi_att_t *attp = &(attsp->value[attsp->nelems]);
66205   attsp->nelems++;
66206 
66207   size_t slen = strlen(name);
66208   if ( slen > CDI_MAX_NAME ) slen = CDI_MAX_NAME;
66209 
66210   attp->name = (char *) Malloc(slen+1);
66211   memcpy(attp->name, name, slen+1);
66212   attp->namesz = slen;
66213   attp->xvalue = NULL;
66214 
66215   return attp;
66216 }
66217 
66218 static
fill_att(cdi_att_t * attp,int indtype,int exdtype,size_t nelems,size_t xsz,const void * xvalue)66219 void fill_att(cdi_att_t *attp, int indtype, int exdtype, size_t nelems, size_t xsz, const void *xvalue)
66220 {
66221   xassert(attp != NULL);
66222 
66223   attp->xsz = xsz;
66224   attp->indtype = indtype;
66225   attp->exdtype = exdtype;
66226   attp->nelems  = nelems;
66227 
66228   if ( xsz > 0 )
66229     {
66230       attp->xvalue = Realloc(attp->xvalue, xsz);
66231       memcpy(attp->xvalue, xvalue, xsz);
66232     }
66233 }
66234 
66235 static
cdi_get_attsp(int objID,int varID)66236 cdi_atts_t *cdi_get_attsp(int objID, int varID)
66237 {
66238   cdi_atts_t *attsp = NULL;
66239 
66240   if ( varID == CDI_GLOBAL && reshGetTxCode(objID) == GRID )
66241     {
66242       grid_t *gridptr = grid_to_pointer(objID);
66243       attsp = &gridptr->atts;
66244     }
66245   else if ( varID == CDI_GLOBAL && reshGetTxCode(objID) == ZAXIS )
66246     {
66247       zaxis_t *zaxisptr = zaxis_to_pointer(objID);
66248       attsp = &zaxisptr->atts;
66249     }
66250   else
66251     {
66252       vlist_t *vlistptr = vlist_to_pointer(objID);
66253       attsp = get_attsp(vlistptr, varID);
66254     }
66255 
66256   return attsp;
66257 }
66258 
66259 /*
66260 @Function  cdiInqNatts
66261 @Title     Get number of attributes
66262 
66263 @Prototype int cdiInqNatts(int cdiID, int varID, int *nattsp)
66264 @Parameter
66265     @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{streamInqVlist}.
66266     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
66267     @Item  nattsp   Pointer to location for returned number of attributes.
66268 
66269 @Description
66270 The function @func{cdiInqNatts} gets the number of attributes assigned to this variable.
66271 
66272 @EndFunction
66273 */
cdiInqNatts(int cdiID,int varID,int * nattsp)66274 int cdiInqNatts(int cdiID, int varID, int *nattsp)
66275 {
66276   int status = CDI_NOERR;
66277 
66278   cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
66279   xassert(attsp != NULL);
66280 
66281   *nattsp = (int)attsp->nelems;
66282 
66283   return status;
66284 }
66285 
66286 /*
66287 @Function  cdiInqAtt
66288 @Title     Get information about an attribute
66289 
66290 @Prototype int cdiInqAtt(int cdiID, int varID, int attnum, char *name, int *typep, int *lenp)
66291 @Parameter
66292     @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{streamInqVlist}.
66293     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
66294     @Item  attnum   Attribute number (from 0 to natts-1).
66295     @Item  name     Pointer to the location for the returned attribute name. The caller must allocate space for the
66296                     returned string. The maximum possible length, in characters, of
66297                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
66298     @Item  typep    Pointer to location for returned attribute type.
66299     @Item  lenp     Pointer to location for returned attribute number.
66300 
66301 @Description
66302 The function @func{cdiInqAtt} gets information about an attribute.
66303 
66304 @EndFunction
66305 */
cdiInqAtt(int cdiID,int varID,int attnum,char * name,int * typep,int * lenp)66306 int cdiInqAtt(int cdiID, int varID, int attnum, char *name, int *typep, int *lenp)
66307 {
66308   int status = CDI_NOERR;
66309 
66310   xassert(name != NULL);
66311 
66312   cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
66313   xassert(attsp != NULL);
66314 
66315   cdi_att_t *attp = NULL;
66316   if ( attnum >= 0 && attnum < (int)attsp->nelems )
66317     attp = &(attsp->value[attnum]);
66318 
66319   if ( attp != NULL && attp->name ) /* name in use */
66320     {
66321       memcpy(name, attp->name, attp->namesz+1);
66322       *typep  = attp->exdtype;
66323       *lenp   = (int)attp->nelems;
66324     }
66325   else
66326     {
66327       name[0] =  0;
66328       *typep  = -1;
66329       *lenp   =  0;
66330       status  = -1;
66331     }
66332 
66333   return status;
66334 }
66335 
66336 
cdiInqAttLen(int cdiID,int varID,const char * name)66337 int cdiInqAttLen(int cdiID, int varID, const char *name)
66338 {
66339   int length = -1;
66340 
66341   xassert(name != NULL);
66342 
66343   cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
66344   xassert(attsp != NULL);
66345 
66346   for ( int attid = 0; attid < (int)attsp->nelems; attid++ )
66347     {
66348       cdi_att_t *attp = &(attsp->value[attid]);
66349       if (attp->name && strcmp(attp->name, name) == 0) length = (int)attp->nelems;
66350     }
66351 
66352   return length;
66353 }
66354 
66355 
cdiInqAttType(int cdiID,int varID,const char * name)66356 int cdiInqAttType(int cdiID, int varID, const char *name)
66357 {
66358   int type = -1;
66359 
66360   xassert(name != NULL);
66361 
66362   cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
66363   xassert(attsp != NULL);
66364 
66365   for ( int attid = 0; attid < (int)attsp->nelems; attid++ )
66366     {
66367       cdi_att_t *attp = &(attsp->value[attid]);
66368       if (attp->name && strcmp(attp->name, name) == 0) type = attp->exdtype;
66369     }
66370 
66371   return type;
66372 }
66373 
66374 
cdiDeleteAtts(int cdiID,int varID)66375 int cdiDeleteAtts(int cdiID, int varID)
66376 {
66377   int status = CDI_NOERR;
66378 
66379   cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
66380   xassert(attsp != NULL);
66381 
66382   for ( int attid = 0; attid < (int)attsp->nelems; attid++ )
66383     {
66384       cdi_att_t *attp = &(attsp->value[attid]);
66385       if ( attp->name   )
66386         {
66387           Free(attp->name);
66388           attp->name = NULL;
66389           attp->namesz = 0;
66390         }
66391       if ( attp->xvalue ) Free(attp->xvalue);
66392     }
66393 
66394   attsp->nelems = 0;
66395 
66396   return status;
66397 }
66398 
66399 
cdiDelAtt(int cdiID,int varID,const char * name)66400 int cdiDelAtt(int cdiID, int varID, const char *name)
66401 {
66402   int status = CDI_NOERR;
66403 
66404   cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
66405   xassert(attsp != NULL);
66406 
66407   for ( int attid = 0; attid < (int)attsp->nelems; attid++ )
66408     {
66409       cdi_att_t *attp = &(attsp->value[attid]);
66410       if (attp->name && strcmp(attp->name, name) == 0)
66411         {
66412           Free(attp->name);
66413           attp->name = NULL;
66414           attp->namesz = 0;
66415           if ( attp->xvalue )
66416             {
66417               Free(attp->xvalue);
66418               attp->xvalue = NULL;
66419             }
66420         }
66421     }
66422 
66423   return status;
66424 }
66425 
66426 static
cdi_def_att(int indtype,int exdtype,int cdiID,int varID,const char * name,size_t len,size_t xsz,const void * xp)66427 int cdi_def_att(int indtype, int exdtype, int cdiID, int varID, const char *name, size_t len, size_t xsz, const void *xp)
66428 {
66429   int status = CDI_NOERR;
66430 
66431   if ( len != 0 && xp == NULL ) // Null arg
66432     return CDI_EINVAL;
66433 
66434   cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
66435   xassert(attsp != NULL);
66436 
66437   cdi_att_t *attp = find_att(attsp, name);
66438   if ( attp == NULL ) attp = new_att(attsp, name);
66439 
66440   if ( attp != NULL ) fill_att(attp, indtype, exdtype, len, xsz, xp);
66441 
66442   return status;
66443 }
66444 
66445 static
cdi_inq_att(int indtype,int cdiID,int varID,const char * name,size_t mxsz,void * xp)66446 int cdi_inq_att(int indtype, int cdiID, int varID, const char *name, size_t mxsz, void *xp)
66447 {
66448   int status = CDI_NOERR;
66449 
66450   if ( mxsz != 0 && xp == NULL ) // Null arg
66451     return CDI_EINVAL;
66452 
66453   cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
66454   xassert(attsp != NULL);
66455 
66456   cdi_att_t *attp = find_att(attsp, name);
66457   if ( attp != NULL ) // name in use
66458     {
66459       if ( attp->indtype == indtype )
66460 	{
66461 	  size_t xsz = attp->xsz;
66462 	  if ( mxsz < xsz ) xsz = mxsz;
66463 	  if ( xsz > 0 )
66464 	    memcpy(xp, attp->xvalue, xsz);
66465 	}
66466       else
66467 	{
66468 	  Warning("Attribute %s has wrong data type!", name);
66469           status = -2;
66470 	}
66471     }
66472   else
66473     {
66474       //Warning("Internal problem, attribute %s not found!", name);
66475       status = -1;
66476     }
66477 
66478   return status;
66479 }
66480 
66481 
cdiCopyAtts(int cdiID1,int varID1,int cdiID2,int varID2)66482 int cdiCopyAtts(int cdiID1, int varID1, int cdiID2, int varID2)
66483 {
66484   int status = CDI_NOERR;
66485 
66486   cdi_atts_t *attsp1 = cdi_get_attsp(cdiID1, varID1);
66487   xassert(attsp1 != NULL);
66488 
66489   for ( size_t attid = 0; attid < attsp1->nelems; attid++ )
66490     {
66491       cdi_att_t *attp = &(attsp1->value[attid]);
66492       cdi_def_att(attp->indtype, attp->exdtype, cdiID2, varID2, attp->name, attp->nelems, attp->xsz, attp->xvalue);
66493     }
66494 
66495   return status;
66496 }
66497 
66498 /*
66499 @Function  cdiDefAttInt
66500 @Title     Define an integer attribute
66501 
66502 @Prototype int cdiDefAttInt(int cdiID, int varID, const char *name, int type, int len, const int *ip)
66503 
66504 @Parameter
66505     @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{zaxisCreate}.
66506     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
66507     @Item  name     Attribute name.
66508     @Item  type     External data type (@func{CDI_DATATYPE_INT16} or @func{CDI_DATATYPE_INT32}).
66509     @Item  len      Number of values provided for the attribute.
66510     @Item  ip       Pointer to one or more integer values.
66511 
66512 @Description
66513 The function @func{cdiDefAttInt} defines an integer attribute.
66514 
66515 @EndFunction
66516 */
cdiDefAttInt(int cdiID,int varID,const char * name,int type,int len,const int * ip)66517 int cdiDefAttInt(int cdiID, int varID, const char *name, int type, int len, const int *ip)
66518 {
66519   return cdi_def_att(CDI_DATATYPE_INT, type, cdiID, varID, name, (size_t)len, (size_t)len * sizeof(int), ip);
66520 }
66521 
66522 /*
66523 @Function  cdiDefAttFlt
66524 @Title     Define a floating point attribute
66525 
66526 @Prototype int cdiDefAttFlt(int cdiID, int varID, const char *name, int type, int len, const double *dp)
66527 
66528 @Parameter
66529     @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{zaxisCreate}.
66530     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
66531     @Item  name     Attribute name.
66532     @Item  type     External data type (@func{CDI_DATATYPE_FLT32} or @func{CDI_DATATYPE_FLT64}).
66533     @Item  len      Number of values provided for the attribute.
66534     @Item  dp       Pointer to one or more floating point values.
66535 
66536 @Description
66537 The function @func{cdiDefAttFlt} defines a floating point attribute.
66538 
66539 @EndFunction
66540 */
cdiDefAttFlt(int cdiID,int varID,const char * name,int type,int len,const double * dp)66541 int cdiDefAttFlt(int cdiID, int varID, const char *name, int type, int len, const double *dp)
66542 {
66543   return cdi_def_att(CDI_DATATYPE_FLT, type, cdiID, varID, name, (size_t)len, (size_t)len * sizeof(double), dp);
66544 }
66545 
66546 /*
66547 @Function  cdiDefAttTxt
66548 @Title     Define a text attribute
66549 
66550 @Prototype int cdiDefAttTxt(int cdiID, int varID, const char *name, int len, const char *tp)
66551 
66552 @Parameter
66553     @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{zaxisCreate}.
66554     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
66555     @Item  name     Attribute name.
66556     @Item  len      Number of values provided for the attribute.
66557     @Item  tp       Pointer to one or more character values.
66558 
66559 @Description
66560 The function @func{cdiDefAttTxt} defines a text attribute.
66561 
66562 @Example
66563 Here is an example using @func{cdiDefAttTxt} to define the attribute "description":
66564 
66565 @Source
66566    ...
66567 int vlistID, varID, status;
66568 char text[] = "description of the variable";
66569    ...
66570 vlistID = vlistCreate();
66571 varID = vlistDefVar(vlistID, gridID, zaxisID, TIME_VARYING);
66572    ...
66573 status = cdiDefAttTxt(vlistID, varID, "description", LEN(text), text);
66574    ...
66575 @EndSource
66576 @EndFunction
66577 */
cdiDefAttTxt(int cdiID,int varID,const char * name,int len,const char * tp)66578 int cdiDefAttTxt(int cdiID, int varID, const char *name, int len, const char *tp)
66579 {
66580   return cdi_def_att(CDI_DATATYPE_TXT, CDI_DATATYPE_TXT, cdiID, varID, name, (size_t)len, (size_t)len, tp);
66581 }
66582 
66583 /*
66584 @Function  cdiInqAttInt
66585 @Title     Get the value(s) of an integer attribute
66586 
66587 @Prototype int cdiInqAttInt(int cdiID, int varID, const char *name, int mlen, int *ip)
66588 @Parameter
66589     @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{zaxisCreate}.
66590     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
66591     @Item  name     Attribute name.
66592     @Item  mlen     Number of allocated values provided for the attribute.
66593     @Item  ip       Pointer location for returned integer attribute value(s).
66594 
66595 @Description
66596 The function @func{cdiInqAttInt} gets the values(s) of an integer attribute.
66597 
66598 @EndFunction
66599 */
cdiInqAttInt(int cdiID,int varID,const char * name,int mlen,int * ip)66600 int cdiInqAttInt(int cdiID, int varID, const char *name, int mlen, int *ip)
66601 {
66602   return cdi_inq_att(CDI_DATATYPE_INT, cdiID, varID, name, (size_t)mlen * sizeof(int), ip);
66603 }
66604 
66605 /*
66606 @Function  cdiInqAttFlt
66607 @Title     Get the value(s) of a floating point attribute
66608 
66609 @Prototype int cdiInqAttFlt(int cdiID, int varID, const char *name, int mlen, double *dp)
66610 @Parameter
66611     @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{zaxisCreate}.
66612     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
66613     @Item  name     Attribute name.
66614     @Item  mlen     Number of allocated values provided for the attribute.
66615     @Item  dp       Pointer location for returned floating point attribute value(s).
66616 
66617 @Description
66618 The function @func{cdiInqAttFlt} gets the values(s) of a floating point attribute.
66619 
66620 @EndFunction
66621 */
cdiInqAttFlt(int cdiID,int varID,const char * name,int mlen,double * dp)66622 int cdiInqAttFlt(int cdiID, int varID, const char *name, int mlen, double *dp)
66623 {
66624   return cdi_inq_att(CDI_DATATYPE_FLT, cdiID, varID, name, (size_t)mlen * sizeof(double), dp);
66625 }
66626 
66627 /*
66628 @Function  cdiInqAttTxt
66629 @Title     Get the value(s) of a text attribute
66630 
66631 @Prototype int cdiInqAttTxt(int cdiID, int varID, const char *name, int mlen, char *tp)
66632 @Parameter
66633     @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{zaxisCreate}.
66634     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
66635     @Item  name     Attribute name.
66636     @Item  mlen     Number of allocated values provided for the attribute.
66637     @Item  tp       Pointer location for returned text attribute value(s).
66638 
66639 @Description
66640 The function @func{cdiInqAttTxt} gets the values(s) of a text attribute.
66641 
66642 @EndFunction
66643 */
cdiInqAttTxt(int cdiID,int varID,const char * name,int mlen,char * tp)66644 int cdiInqAttTxt(int cdiID, int varID, const char *name, int mlen, char *tp)
66645 {
66646   return cdi_inq_att(CDI_DATATYPE_TXT, cdiID, varID, name, (size_t)mlen * sizeof(char), tp);
66647 }
66648 
66649 enum {
66650   cdi_att_nints = 4,          /* namesz, exdtype, indtype, nelems */
66651 };
66652 
66653 static inline
cdiAttTypeLookup(cdi_att_t * attp)66654 int cdiAttTypeLookup(cdi_att_t *attp)
66655 {
66656   int type;
66657   switch (attp->indtype)
66658   {
66659   case CDI_DATATYPE_FLT:
66660     type = CDI_DATATYPE_FLT64;
66661     break;
66662   case CDI_DATATYPE_INT:
66663   case CDI_DATATYPE_TXT:
66664     type = attp->indtype;
66665     break;
66666   default:
66667     xabort("Unknown datatype encountered in attribute %s: %d\n", attp->name, attp->indtype);
66668   }
66669   return type;
66670 }
66671 
66672 
cdi_att_compare(cdi_atts_t * attspa,cdi_atts_t * attspb,int attnum)66673 int cdi_att_compare(cdi_atts_t *attspa, cdi_atts_t *attspb, int attnum)
66674 {
66675   xassert(attnum >= 0 && attnum < (int)attspa->nelems && attnum < (int)attspb->nelems);
66676   cdi_att_t *attpa = attspa->value + attnum,
66677             *attpb = attspb->value + attnum;
66678 
66679   if (attpa->namesz != attpb->namesz) return 1;
66680 
66681   if (attpa->name && attpb->name && memcmp(attpa->name, attpb->name, attpa->namesz)) return 1;
66682 
66683   if (attpa->indtype != attpb->indtype
66684       || attpa->exdtype != attpb->exdtype
66685       || attpa->nelems != attpb->nelems)
66686     return 1;
66687 
66688   return memcmp(attpa->xvalue, attpb->xvalue, attpa->xsz);
66689 }
66690 
66691 
66692 static
cdiAttGetSize(cdi_atts_t * attsp,int attnum,void * context)66693 int cdiAttGetSize(cdi_atts_t *attsp, int attnum, void *context)
66694 {
66695   xassert(attnum >= 0 && attnum < (int)attsp->nelems);
66696   cdi_att_t *attp = &(attsp->value[attnum]);
66697   int txsize = serializeGetSize(cdi_att_nints, CDI_DATATYPE_INT, context)
66698     + serializeGetSize((int)attp->namesz, CDI_DATATYPE_TXT, context);
66699   txsize += serializeGetSize((int)attp->nelems, cdiAttTypeLookup(attp), context);
66700   return txsize;
66701 }
66702 
66703 
cdiAttsGetSize(void * vp,int varID,void * context)66704 int cdiAttsGetSize(void *vp, int varID, void *context)
66705 {
66706   cdi_atts_t *attsp;
66707   xassert(attsp = get_attsp((vlist_t*) vp, varID));
66708   int txsize = serializeGetSize(1, CDI_DATATYPE_INT, context);
66709   size_t numAtts = attsp->nelems;
66710   for (size_t i = 0; i < numAtts; ++i)
66711     txsize += cdiAttGetSize(attsp, (int)i, context);
66712   return txsize;
66713 }
66714 
66715 static
cdiAttPack(cdi_atts_t * attsp,int attnum,void * buf,int size,int * position,void * context)66716 void cdiAttPack(cdi_atts_t *attsp, int attnum, void *buf, int size, int *position, void *context)
66717 {
66718   int tempbuf[cdi_att_nints];
66719 
66720   xassert(attnum >= 0 && attnum < (int)attsp->nelems);
66721   cdi_att_t *attp = &(attsp->value[attnum]);
66722   tempbuf[0] = (int)attp->namesz;
66723   tempbuf[1] = attp->exdtype;
66724   tempbuf[2] = attp->indtype;
66725   tempbuf[3] = (int)attp->nelems;
66726   serializePack(tempbuf, cdi_att_nints, CDI_DATATYPE_INT, buf, size, position, context);
66727   serializePack(attp->name, (int)attp->namesz, CDI_DATATYPE_TXT, buf, size, position, context);
66728   serializePack(attp->xvalue, (int)attp->nelems, cdiAttTypeLookup(attp),
66729                 buf, size, position, context);
66730 }
66731 
66732 
cdiAttsPack(void * vp,int varID,void * buf,int size,int * position,void * context)66733 void cdiAttsPack(void *vp, int varID, void *buf, int size, int *position, void *context)
66734 {
66735   cdi_atts_t *attsp;
66736   xassert(attsp = get_attsp((vlist_t*) vp, varID));
66737   size_t numAtts = attsp->nelems;
66738   int numAttsI = (int)numAtts;
66739   xassert(numAtts <= INT_MAX);
66740   serializePack(&numAttsI, 1, CDI_DATATYPE_INT, buf, size, position, context);
66741   for (size_t i = 0; i < numAtts; ++i)
66742     cdiAttPack(attsp, (int)i, buf, size, position, context);
66743 }
66744 
66745 static
cdiAttUnpack(int cdiID,int varID,void * buf,int size,int * position,void * context)66746 void cdiAttUnpack(int cdiID, int varID, void *buf, int size, int *position, void *context)
66747 {
66748   int tempbuf[cdi_att_nints];
66749 
66750   serializeUnpack(buf, size, position,
66751                   tempbuf, cdi_att_nints, CDI_DATATYPE_INT, context);
66752   char *attName = (char *) Malloc((size_t)tempbuf[0] + 1);
66753   serializeUnpack(buf, size, position, attName, tempbuf[0], CDI_DATATYPE_TXT, context);
66754   attName[tempbuf[0]] = '\0';
66755   int attVDt;
66756   size_t elemSize;
66757   switch (tempbuf[2])
66758   {
66759   case CDI_DATATYPE_FLT:
66760     attVDt = CDI_DATATYPE_FLT64;
66761     elemSize = sizeof(double);
66762     break;
66763   case CDI_DATATYPE_INT:
66764     attVDt = CDI_DATATYPE_INT;
66765     elemSize = sizeof(int);
66766     break;
66767   case CDI_DATATYPE_TXT:
66768     attVDt = CDI_DATATYPE_TXT;
66769     elemSize = 1;
66770     break;
66771   default:
66772     xabort("Unknown datatype encountered in attribute %s: %d\n",
66773            attName, tempbuf[2]);
66774   }
66775   void *attData = Malloc(elemSize * (size_t)tempbuf[3]);
66776   serializeUnpack(buf, size, position, attData, tempbuf[3], attVDt, context);
66777   cdi_def_att(tempbuf[2], tempbuf[1], cdiID, varID, attName,
66778               (size_t)tempbuf[3], (size_t)tempbuf[3] * elemSize, attData);
66779   Free(attName);
66780   Free(attData);
66781 }
66782 
66783 
cdiAttsUnpack(int cdiID,int varID,void * buf,int size,int * position,void * context)66784 void cdiAttsUnpack(int cdiID, int varID, void *buf, int size, int *position, void *context)
66785 {
66786   int numAtts;
66787   serializeUnpack(buf, size, position, &numAtts, 1, CDI_DATATYPE_INT, context);
66788   for ( int i = 0; i < numAtts; ++i )
66789     cdiAttUnpack(cdiID, varID, buf, size, position, context);
66790 }
66791 
66792 /*
66793  * Local Variables:
66794  * c-file-style: "Java"
66795  * c-basic-offset: 2
66796  * indent-tabs-mode: nil
66797  * show-trailing-whitespace: t
66798  * require-trailing-newline: t
66799  * End:
66800  */
66801 
66802 
66803 static
vlistvarInitEntry(int vlistID,int varID)66804 void vlistvarInitEntry(int vlistID, int varID)
66805 {
66806   vlist_t *vlistptr = vlist_to_pointer(vlistID);
66807 
66808   vlistptr->vars[varID].fvarID        = varID;
66809   vlistptr->vars[varID].mvarID        = varID;
66810   vlistptr->vars[varID].flag          = 0;
66811   vlistptr->vars[varID].param         = 0;
66812   vlistptr->vars[varID].datatype      = CDI_UNDEFID;
66813   vlistptr->vars[varID].timetype      = CDI_UNDEFID;
66814   vlistptr->vars[varID].tsteptype     = TSTEP_INSTANT;
66815   vlistptr->vars[varID].chunktype     = CDI_Chunk_Type;
66816   vlistptr->vars[varID].xyz           = 321;
66817   vlistptr->vars[varID].gridID        = CDI_UNDEFID;
66818   vlistptr->vars[varID].zaxisID       = CDI_UNDEFID;
66819   vlistptr->vars[varID].subtypeID     = CDI_UNDEFID;
66820   vlistptr->vars[varID].instID        = CDI_UNDEFID;
66821   vlistptr->vars[varID].modelID       = CDI_UNDEFID;
66822   vlistptr->vars[varID].tableID       = CDI_UNDEFID;
66823   vlistptr->vars[varID].missvalused   = false;
66824   vlistptr->vars[varID].missval       = CDI_Default_Missval;
66825   vlistptr->vars[varID].addoffset     = 0.0;
66826   vlistptr->vars[varID].scalefactor   = 1.0;
66827   vlistptr->vars[varID].extra         = NULL;
66828   vlistptr->vars[varID].levinfo       = NULL;
66829   vlistptr->vars[varID].comptype      = CDI_COMPRESS_NONE;
66830   vlistptr->vars[varID].complevel     = 1;
66831   vlistptr->vars[varID].keys.nalloc   = MAX_KEYS;
66832   vlistptr->vars[varID].keys.nelems   = 0;
66833   for ( int i = 0; i < MAX_KEYS; ++i )
66834     vlistptr->vars[varID].keys.value[i].length = 0;
66835   vlistptr->vars[varID].atts.nalloc   = MAX_ATTRIBUTES;
66836   vlistptr->vars[varID].atts.nelems   = 0;
66837   vlistptr->vars[varID].lvalidrange   = false;
66838   vlistptr->vars[varID].validrange[0] = VALIDMISS;
66839   vlistptr->vars[varID].validrange[1] = VALIDMISS;
66840   vlistptr->vars[varID].iorank        = CDI_UNDEFID;
66841   vlistptr->vars[varID].opt_grib_kvpair_size = 0;
66842   vlistptr->vars[varID].opt_grib_kvpair      = NULL;
66843   vlistptr->vars[varID].opt_grib_nentries    = 0;
66844 }
66845 
66846 static
vlistvarNewEntry(int vlistID)66847 int vlistvarNewEntry(int vlistID)
66848 {
66849   int varID = 0;
66850   vlist_t *vlistptr = vlist_to_pointer(vlistID);
66851   int vlistvarSize = vlistptr->varsAllocated;
66852   var_t *vlistvar = vlistptr->vars;
66853   // Look for a free slot in vlistvar. (Create the table the first time through).
66854   if ( ! vlistvarSize )
66855     {
66856       vlistvarSize = 2;
66857       vlistvar = (var_t *) Malloc((size_t)vlistvarSize * sizeof (var_t));
66858       for ( int i = 0; i < vlistvarSize; i++ ) vlistvar[i].isUsed = false;
66859     }
66860   else
66861     {
66862       while (varID < vlistvarSize && vlistvar[varID].isUsed)
66863         ++varID;
66864     }
66865   // If the table overflows, double its size.
66866   if ( varID == vlistvarSize )
66867     {
66868       vlistvar = (var_t *) Realloc(vlistvar, (size_t)(vlistvarSize *= 2) * sizeof(var_t));
66869       for ( int i = varID; i < vlistvarSize; i++ ) vlistvar[i].isUsed = false;
66870     }
66871 
66872   vlistptr->varsAllocated = vlistvarSize;
66873   vlistptr->vars          = vlistvar;
66874 
66875   vlistvarInitEntry(vlistID, varID);
66876 
66877   vlistptr->vars[varID].isUsed = true;
66878 
66879   return varID;
66880 }
66881 
vlistCheckVarID(const char * caller,int vlistID,int varID)66882 void vlistCheckVarID(const char *caller, int vlistID, int varID)
66883 {
66884   vlist_t *vlistptr = vlist_to_pointer(vlistID);
66885   if ( vlistptr == NULL ) Errorc("vlist undefined!");
66886 
66887   if ( varID < 0 || varID >= vlistptr->nvars ) Errorc("varID %d undefined!", varID);
66888 
66889   if ( ! vlistptr->vars[varID].isUsed ) Errorc("varID %d undefined!", varID);
66890 }
66891 
66892 
vlistDefVarTiles(int vlistID,int gridID,int zaxisID,int timetype,int tilesetID)66893 int vlistDefVarTiles(int vlistID, int gridID, int zaxisID, int timetype, int tilesetID)
66894 {
66895   if ( CDI_Debug ) Message("gridID = %d  zaxisID = %d  timetype = %d", gridID, zaxisID, timetype);
66896 
66897   const int varID = vlistvarNewEntry(vlistID);
66898 
66899   vlist_t *vlistptr = vlist_to_pointer(vlistID);
66900   vlistptr->nvars++;
66901   vlistptr->vars[varID].gridID    = gridID;
66902   vlistptr->vars[varID].zaxisID   = zaxisID;
66903   vlistptr->vars[varID].timetype = timetype;
66904   vlistptr->vars[varID].subtypeID = tilesetID;
66905 
66906   if ( timetype < 0 )
66907     {
66908       Message("Unexpected time type %d, set to TIME_VARYING!", timetype);
66909       vlistptr->vars[varID].timetype = TIME_VARYING;
66910     }
66911 
66912   vlistAdd2GridIDs(vlistptr, gridID);
66913   vlistAdd2ZaxisIDs(vlistptr, zaxisID);
66914   vlistAdd2SubtypeIDs(vlistptr, tilesetID);
66915 
66916   vlistptr->vars[varID].param = cdiEncodeParam(-(varID + 1), 255, 255);
66917   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
66918 
66919   return varID;
66920 }
66921 
66922 /*
66923 @Function  vlistDefVar
66924 @Title     Define a Variable
66925 
66926 @Prototype int vlistDefVar(int vlistID, int gridID, int zaxisID, int timetype)
66927 @Parameter
66928     @Item  vlistID   Variable list ID, from a previous call to @fref{vlistCreate}.
66929     @Item  gridID    Grid ID, from a previous call to @fref{gridCreate}.
66930     @Item  zaxisID   Z-axis ID, from a previous call to @fref{zaxisCreate}.
66931     @Item  timetype  One of the set of predefined CDI timestep types.
66932                      The valid CDI timestep types are @func{TIME_CONSTANT} and @func{TIME_VARYING}.
66933 
66934 @Description
66935 The function @func{vlistDefVar} adds a new variable to vlistID.
66936 
66937 @Result
66938 @func{vlistDefVar} returns an identifier to the new variable.
66939 
66940 @Example
66941 Here is an example using @func{vlistCreate} to create a variable list
66942 and add a variable with @func{vlistDefVar}.
66943 
66944 @Source
66945    ...
66946 int vlistID, varID;
66947    ...
66948 vlistID = vlistCreate();
66949 varID = vlistDefVar(vlistID, gridID, zaxisID, TIME_VARYING);
66950    ...
66951 streamDefVlist(streamID, vlistID);
66952    ...
66953 vlistDestroy(vlistID);
66954    ...
66955 @EndSource
66956 @EndFunction
66957 */
vlistDefVar(int vlistID,int gridID,int zaxisID,int timetype)66958 int vlistDefVar(int vlistID, int gridID, int zaxisID, int timetype)
66959 {
66960   // call "vlistDefVarTiles" with a trivial tile index:
66961   return vlistDefVarTiles(vlistID, gridID, zaxisID, timetype, CDI_UNDEFID);
66962 }
66963 
66964 void
cdiVlistCreateVarLevInfo(vlist_t * vlistptr,int varID)66965 cdiVlistCreateVarLevInfo(vlist_t *vlistptr, int varID)
66966 {
66967   xassert(varID >= 0 && varID < vlistptr->nvars && vlistptr->vars[varID].levinfo == NULL);
66968 
66969   const int zaxisID = vlistptr->vars[varID].zaxisID;
66970   const size_t nlevs = (size_t)zaxisInqSize(zaxisID);
66971 
66972   vlistptr->vars[varID].levinfo = (levinfo_t*) Malloc(nlevs * sizeof(levinfo_t));
66973 
66974   for (size_t levID = 0; levID < nlevs; levID++ )
66975     vlistptr->vars[varID].levinfo[levID] = DEFAULT_LEVINFO((int)levID);
66976 }
66977 
66978 /*
66979 @Function  vlistDefVarParam
66980 @Title     Define the parameter number of a Variable
66981 
66982 @Prototype void vlistDefVarParam(int vlistID, int varID, int param)
66983 @Parameter
66984     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
66985     @Item  varID    Variable identifier.
66986     @Item  param    Parameter number.
66987 
66988 @Description
66989 The function @func{vlistDefVarParam} defines the parameter number of a variable.
66990 
66991 @EndFunction
66992 */
vlistDefVarParam(int vlistID,int varID,int param)66993 void vlistDefVarParam(int vlistID, int varID, int param)
66994 {
66995   vlistCheckVarID(__func__, vlistID, varID);
66996 
66997   vlist_t *vlistptr = vlist_to_pointer(vlistID);
66998   if (vlistptr->vars[varID].param != param)
66999     {
67000       vlistptr->vars[varID].param = param;
67001       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67002     }
67003 }
67004 
67005 /*
67006 @Function  vlistDefVarCode
67007 @Title     Define the code number of a Variable
67008 
67009 @Prototype void vlistDefVarCode(int vlistID, int varID, int code)
67010 @Parameter
67011     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
67012     @Item  varID    Variable identifier.
67013     @Item  code     Code number.
67014 
67015 @Description
67016 The function @func{vlistDefVarCode} defines the code number of a variable.
67017 
67018 @EndFunction
67019 */
vlistDefVarCode(int vlistID,int varID,int code)67020 void vlistDefVarCode(int vlistID, int varID, int code)
67021 {
67022   vlistCheckVarID(__func__, vlistID, varID);
67023 
67024   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67025   const int param = vlistptr->vars[varID].param;
67026   int pnum, pcat, pdis;
67027   cdiDecodeParam(param, &pnum, &pcat, &pdis);
67028   const int newParam = cdiEncodeParam(code, pcat, pdis);
67029   if (vlistptr->vars[varID].param != newParam)
67030     {
67031       vlistptr->vars[varID].param = newParam;
67032       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67033     }
67034 }
67035 
67036 
vlistInqVar(int vlistID,int varID,int * gridID,int * zaxisID,int * timetype)67037 void vlistInqVar(int vlistID, int varID, int *gridID, int *zaxisID, int *timetype)
67038 {
67039   vlistCheckVarID(__func__, vlistID, varID);
67040 
67041   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67042   *gridID   = vlistptr->vars[varID].gridID;
67043   *zaxisID  = vlistptr->vars[varID].zaxisID;
67044   *timetype = vlistptr->vars[varID].timetype;
67045 }
67046 
67047 /*
67048 @Function  vlistInqVarGrid
67049 @Title     Get the Grid ID of a Variable
67050 
67051 @Prototype int vlistInqVarGrid(int vlistID, int varID)
67052 @Parameter
67053     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67054     @Item  varID    Variable identifier.
67055 
67056 @Description
67057 The function @func{vlistInqVarGrid} returns the grid ID of a Variable.
67058 
67059 @Result
67060 @func{vlistInqVarGrid} returns the grid ID of the Variable.
67061 
67062 @EndFunction
67063 */
vlistInqVarGrid(int vlistID,int varID)67064 int vlistInqVarGrid(int vlistID, int varID)
67065 {
67066   vlistCheckVarID(__func__, vlistID, varID);
67067 
67068   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67069   return vlistptr->vars[varID].gridID;
67070 }
67071 
67072 /*
67073 @Function  vlistInqVarZaxis
67074 @Title     Get the Zaxis ID of a Variable
67075 
67076 @Prototype int vlistInqVarZaxis(int vlistID, int varID)
67077 @Parameter
67078     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67079     @Item  varID    Variable identifier.
67080 
67081 @Description
67082 The function @func{vlistInqVarZaxis} returns the zaxis ID of a variable.
67083 
67084 @Result
67085 @func{vlistInqVarZaxis} returns the zaxis ID of the variable.
67086 
67087 @EndFunction
67088 */
vlistInqVarZaxis(int vlistID,int varID)67089 int vlistInqVarZaxis(int vlistID, int varID)
67090 {
67091   vlistCheckVarID(__func__, vlistID, varID);
67092 
67093   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67094   return vlistptr->vars[varID].zaxisID;
67095 }
67096 
67097 
67098 /*
67099 @Function  vlistInqVarSubtype
67100 @Title     Get the Subtype ID of a Variable
67101 
67102 @Description
67103 The function @func{vlistInqVarSubtype} returns the subtype ID of a variable.
67104 
67105 @Result
67106 @func{vlistInqVarSubtype} returns the subtype ID of the variable.
67107 
67108 @EndFunction
67109 */
vlistInqVarSubtype(int vlistID,int varID)67110 int vlistInqVarSubtype(int vlistID, int varID)
67111 {
67112   vlistCheckVarID(__func__, vlistID, varID);
67113 
67114   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67115   return vlistptr->vars[varID].subtypeID;
67116 }
67117 
67118 
67119 /*
67120 @Function  vlistInqVarParam
67121 @Title     Get the parameter number of a Variable
67122 
67123 @Prototype int vlistInqVarParam(int vlistID, int varID)
67124 @Parameter
67125     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67126     @Item  varID    Variable identifier.
67127 
67128 @Description
67129 The function @func{vlistInqVarParam} returns the parameter number of a variable.
67130 
67131 @Result
67132 @func{vlistInqVarParam} returns the parameter number of the variable.
67133 
67134 @EndFunction
67135 */
vlistInqVarParam(int vlistID,int varID)67136 int vlistInqVarParam(int vlistID, int varID)
67137 {
67138   vlistCheckVarID(__func__, vlistID, varID);
67139 
67140   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67141   return vlistptr->vars[varID].param;
67142 }
67143 
67144 /*
67145 @Function  vlistInqVarCode
67146 @Title     Get the Code number of a Variable
67147 
67148 @Prototype int vlistInqVarCode(int vlistID, int varID)
67149 @Parameter
67150     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67151     @Item  varID    Variable identifier.
67152 
67153 @Description
67154 The function @func{vlistInqVarCode} returns the code number of a variable.
67155 
67156 @Result
67157 @func{vlistInqVarCode} returns the code number of the variable.
67158 
67159 @EndFunction
67160 */
vlistInqVarCode(int vlistID,int varID)67161 int vlistInqVarCode(int vlistID, int varID)
67162 {
67163   vlistCheckVarID(__func__, vlistID, varID);
67164 
67165   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67166 
67167   const int param = vlistptr->vars[varID].param;
67168   int pdis, pcat, pnum;
67169   cdiDecodeParam(param, &pnum, &pcat, &pdis);
67170   int code = pnum;
67171   if ( pdis != 255 ) code = -varID-1; // GRIB2 Parameter
67172 
67173   int tableID = vlistptr->vars[varID].tableID;
67174   if (code < 0 && tableID != -1)
67175     {
67176       char name[CDI_MAX_NAME];
67177       int length = CDI_MAX_NAME;
67178       (void)cdiInqKeyString(vlistID, varID, CDI_KEY_NAME, name, &length);
67179 
67180       if (name[0]) tableInqParCode(tableID, name, &code);
67181     }
67182 
67183   return code;
67184 }
67185 
67186 /*
67187 @Function  vlistInqVarName
67188 @Title     Get the name of a Variable
67189 
67190 @Prototype void vlistInqVarName(int vlistID, int varID, char *name)
67191 @Parameter
67192     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67193     @Item  varID    Variable identifier.
67194     @Item  name     Returned variable name. The caller must allocate space for the
67195                     returned string. The maximum possible length, in characters, of
67196                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
67197 
67198 @Description
67199 The function @func{vlistInqVarName} returns the name of a variable.
67200 
67201 @Result
67202 @func{vlistInqVarName} returns the name of the variable to the parameter name if available,
67203 otherwise the result is an empty string.
67204 
67205 @EndFunction
67206 */
vlistInqVarName(int vlistID,int varID,char * name)67207 void vlistInqVarName(int vlistID, int varID, char *name)
67208 {
67209   int length = CDI_MAX_NAME;
67210   (void)cdiInqKeyString(vlistID, varID, CDI_KEY_NAME, name, &length);
67211 
67212   if (!name[0])
67213     {
67214       vlistCheckVarID(__func__, vlistID, varID);
67215 
67216       vlist_t *vlistptr = vlist_to_pointer(vlistID);
67217 
67218       int param = vlistptr->vars[varID].param;
67219       int pdis, pcat, pnum;
67220       cdiDecodeParam(param, &pnum, &pcat, &pdis);
67221       if ( pdis == 255 )
67222 	{
67223 	  int code = pnum;
67224 	  int tableID = vlistptr->vars[varID].tableID;
67225           tableInqEntry(tableID, code, -1, name, NULL, NULL);
67226 	  if (!name[0]) sprintf(name, "var%d", code);
67227 	}
67228       else
67229 	{
67230 	  sprintf(name, "param%d.%d.%d", pnum, pcat, pdis);
67231 	}
67232     }
67233 }
67234 
67235 /*
67236 @Function vlistCopyVarName
67237 @Tatle    Get the name of a Variable in a safe way
67238 
67239 @Prototype char* vlistCopyVarName(int vlistId, int varId)
67240 @Parameter
67241     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67242     @Item  varID    Variable identifier.
67243 
67244 @Return A pointer to a malloc'ed string. Must be cleaned up with Free().
67245 
67246 @Description
67247 This is the buffer overflow immune version of vlistInqVarName().
67248 The memory for the returned string is allocated to fit the string via Malloc().
67249 
67250 @EndFunction
67251 */
vlistCopyVarName(int vlistID,int varID)67252 char *vlistCopyVarName(int vlistID, int varID)
67253 {
67254   // If a name is set in the variable description, use that.
67255   char name[CDI_MAX_NAME];
67256   int length = CDI_MAX_NAME;
67257   (void)cdiInqKeyString(vlistID, varID, CDI_KEY_NAME, name, &length);
67258   if (name[0]) return strdup(name);
67259 
67260   vlistCheckVarID(__func__, vlistID, varID);
67261   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67262 
67263   // Otherwise we check if we should use the table of parameter descriptions.
67264   int param = vlistptr->vars[varID].param;
67265   int discipline, category, number;
67266   cdiDecodeParam(param, &number, &category, &discipline);
67267   char *result = NULL;
67268   if (discipline == 255)
67269     {
67270       int tableID = vlistptr->vars[varID].tableID;
67271       tableInqEntry(tableID, number, -1, name, NULL, NULL);
67272       if ( name[0] )
67273         result = strdup(name);
67274       else
67275         {
67276           //No luck, fall back to outputting a name of the format "var<num>".
67277           result = (char *) Malloc(3 + 3 * sizeof (int) * CHAR_BIT / 8 + 2);
67278           sprintf(result, "var%d", number);
67279         }
67280     }
67281   else
67282     {
67283       result = (char *) Malloc(5 + 2 + 3 * (3 * sizeof (int) * CHAR_BIT + 1) + 1);
67284       sprintf(result, "param%d.%d.%d", number, category, discipline);
67285     }
67286   //Finally, we fall back to outputting a name of the format "param<num>.<cat>.<dis>".
67287   return result;
67288 }
67289 
67290 /*
67291 @Function  vlistInqVarLongname
67292 @Title     Get the longname of a Variable
67293 
67294 @Prototype void vlistInqVarLongname(int vlistID, int varID, char *longname)
67295 @Parameter
67296     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67297     @Item  varID    Variable identifier.
67298     @Item  longname Long name of the variable. The caller must allocate space for the
67299                     returned string. The maximum possible length, in characters, of
67300                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
67301 
67302 @Description
67303 The function @func{vlistInqVarLongname} returns the longname of a variable if available,
67304 otherwise the result is an empty string.
67305 
67306 @Result
67307 @func{vlistInqVarLongname} returns the longname of the variable to the parameter longname.
67308 
67309 @EndFunction
67310 */
vlistInqVarLongname(int vlistID,int varID,char * longname)67311 void vlistInqVarLongname(int vlistID, int varID, char *longname)
67312 {
67313   int length = CDI_MAX_NAME;
67314   (void)cdiInqKeyString(vlistID, varID, CDI_KEY_LONGNAME, longname, &length);
67315 
67316   if (!longname[0])
67317     {
67318       vlistCheckVarID(__func__, vlistID, varID);
67319 
67320       vlist_t *vlistptr = vlist_to_pointer(vlistID);
67321 
67322       int param = vlistptr->vars[varID].param;
67323       int pdis, pcat, pnum;
67324       cdiDecodeParam(param, &pnum, &pcat, &pdis);
67325       if ( pdis == 255 )
67326 	{
67327 	  int code = pnum;
67328           int tableID = vlistptr->vars[varID].tableID;
67329           tableInqEntry(tableID, code, -1, NULL, longname, NULL);
67330 	}
67331     }
67332 }
67333 
67334 /*
67335 @Function  vlistInqVarStdname
67336 @Title     Get the standard name of a Variable
67337 
67338 @Prototype void vlistInqVarStdname(int vlistID, int varID, char *stdname)
67339 @Parameter
67340     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67341     @Item  varID    Variable identifier.
67342     @Item  stdname  Standard name of the variable. The caller must allocate space for the
67343                     returned string. The maximum possible length, in characters, of
67344                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
67345 
67346 @Description
67347 The function @func{vlistInqVarStdname} returns the standard name of a variable if available,
67348 otherwise the result is an empty string.
67349 
67350 @Result
67351 @func{vlistInqVarStdname} returns the standard name of the variable to the parameter stdname.
67352 
67353 @EndFunction
67354 */
vlistInqVarStdname(int vlistID,int varID,char * stdname)67355 void vlistInqVarStdname(int vlistID, int varID, char *stdname)
67356 {
67357   int length = CDI_MAX_NAME;
67358   (void)cdiInqKeyString(vlistID, varID, CDI_KEY_STDNAME, stdname, &length);
67359 }
67360 
67361 /*
67362 @Function  vlistInqVarUnits
67363 @Title     Get the units of a Variable
67364 
67365 @Prototype void vlistInqVarUnits(int vlistID, int varID, char *units)
67366 @Parameter
67367     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67368     @Item  varID    Variable identifier.
67369     @Item  units    Units of the variable. The caller must allocate space for the
67370                     returned string. The maximum possible length, in characters, of
67371                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
67372 
67373 @Description
67374 The function @func{vlistInqVarUnits} returns the units of a variable if available,
67375 otherwise the result is an empty string.
67376 
67377 @Result
67378 @func{vlistInqVarUnits} returns the units of the variable to the parameter units.
67379 
67380 @EndFunction
67381 */
vlistInqVarUnits(int vlistID,int varID,char * units)67382 void vlistInqVarUnits(int vlistID, int varID, char *units)
67383 {
67384   int length = CDI_MAX_NAME;
67385   (void)cdiInqKeyString(vlistID, varID, CDI_KEY_UNITS, units, &length);
67386 
67387   if (!units[0])
67388     {
67389       vlistCheckVarID(__func__, vlistID, varID);
67390 
67391       vlist_t *vlistptr = vlist_to_pointer(vlistID);
67392 
67393       int param = vlistptr->vars[varID].param;
67394       int pdis, pcat, pnum;
67395       cdiDecodeParam(param, &pnum, &pcat, &pdis);
67396       if ( pdis == 255 )
67397 	{
67398 	  int code = pnum;
67399 	  int tableID = vlistptr->vars[varID].tableID;
67400           tableInqEntry(tableID, code, -1, NULL, NULL, units);
67401 	}
67402     }
67403 }
67404 
67405 // used in MPIOM !
vlistInqVarID(int vlistID,int code)67406 int vlistInqVarID(int vlistID, int code)
67407 {
67408   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67409 
67410   for ( int varID = 0; varID < vlistptr->nvars; varID++ )
67411     {
67412       const int param = vlistptr->vars[varID].param;
67413       int pdis, pcat, pnum;
67414       cdiDecodeParam(param, &pnum, &pcat, &pdis);
67415       if ( pnum == code ) return varID;
67416     }
67417 
67418   return CDI_UNDEFID;
67419 }
67420 
67421 
vlistInqVarSize(int vlistID,int varID)67422 size_t vlistInqVarSize(int vlistID, int varID)
67423 {
67424   vlistCheckVarID(__func__, vlistID, varID);
67425 
67426   int zaxisID, gridID, timetype;
67427   vlistInqVar(vlistID, varID, &gridID, &zaxisID, &timetype);
67428 
67429   const size_t nlevs = (size_t)zaxisInqSize(zaxisID);
67430   const size_t gridsize = gridInqSize(gridID);
67431 
67432   return gridsize*nlevs;
67433 }
67434 
67435 /*
67436 @Function  vlistInqVarDatatype
67437 @Title     Get the data type of a Variable
67438 
67439 @Prototype int vlistInqVarDatatype(int vlistID, int varID)
67440 @Parameter
67441     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67442     @Item  varID    Variable identifier.
67443 
67444 @Description
67445 The function @func{vlistInqVarDatatype} returns the data type of a variable.
67446 
67447 @Result
67448 @func{vlistInqVarDatatype} returns an identifier to the data type of the variable.
67449 The valid CDI data types are @func{CDI_DATATYPE_PACK8}, @func{CDI_DATATYPE_PACK16}, @func{CDI_DATATYPE_PACK24},
67450 @func{CDI_DATATYPE_FLT32}, @func{CDI_DATATYPE_FLT64}, @func{CDI_DATATYPE_INT8}, @func{CDI_DATATYPE_INT16} and
67451 @func{CDI_DATATYPE_INT32}.
67452 
67453 @EndFunction
67454 */
vlistInqVarDatatype(int vlistID,int varID)67455 int vlistInqVarDatatype(int vlistID, int varID)
67456 {
67457   vlistCheckVarID(__func__, vlistID, varID);
67458 
67459   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67460   return vlistptr->vars[varID].datatype;
67461 }
67462 
67463 
vlistInqVarNumber(int vlistID,int varID)67464 int vlistInqVarNumber(int vlistID, int varID)
67465 {
67466   vlistCheckVarID(__func__, vlistID, varID);
67467 
67468   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67469 
67470   int number = CDI_REAL;
67471   if ( vlistptr->vars[varID].datatype == CDI_DATATYPE_CPX32 ||
67472        vlistptr->vars[varID].datatype == CDI_DATATYPE_CPX64 )
67473     number = CDI_COMP;
67474 
67475   return number;
67476 }
67477 
67478 /*
67479 @Function  vlistDefVarDatatype
67480 @Title     Define the data type of a Variable
67481 
67482 @Prototype void vlistDefVarDatatype(int vlistID, int varID, int datatype)
67483 @Parameter
67484     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
67485     @Item  varID    Variable identifier.
67486     @Item  datatype The data type identifier.
67487                     The valid CDI data types are @func{CDI_DATATYPE_PACK8}, @func{CDI_DATATYPE_PACK16},
67488                     @func{CDI_DATATYPE_PACK24}, @func{CDI_DATATYPE_FLT32}, @func{CDI_DATATYPE_FLT64},
67489                     @func{CDI_DATATYPE_INT8}, @func{CDI_DATATYPE_INT16} and @func{CDI_DATATYPE_INT32}.
67490 
67491 @Description
67492 The function @func{vlistDefVarDatatype} defines the data type of a variable.
67493 
67494 @EndFunction
67495 */
vlistDefVarDatatype(int vlistID,int varID,int datatype)67496 void vlistDefVarDatatype(int vlistID, int varID, int datatype)
67497 {
67498   vlistCheckVarID(__func__, vlistID, varID);
67499 
67500   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67501 
67502   if (vlistptr->vars[varID].datatype != datatype)
67503     {
67504       vlistptr->vars[varID].datatype = datatype;
67505 
67506       if ( !vlistptr->vars[varID].missvalused )
67507         switch (datatype)
67508           {
67509           case CDI_DATATYPE_INT8:   vlistptr->vars[varID].missval = -SCHAR_MAX; break;
67510           case CDI_DATATYPE_UINT8:  vlistptr->vars[varID].missval =  UCHAR_MAX; break;
67511           case CDI_DATATYPE_INT16:  vlistptr->vars[varID].missval = -SHRT_MAX;  break;
67512           case CDI_DATATYPE_UINT16: vlistptr->vars[varID].missval =  USHRT_MAX; break;
67513           case CDI_DATATYPE_INT32:  vlistptr->vars[varID].missval = -INT_MAX;   break;
67514           case CDI_DATATYPE_UINT32: vlistptr->vars[varID].missval =  UINT_MAX;  break;
67515           case CDI_DATATYPE_FLT32:  vlistptr->vars[varID].missval =  (float) CDI_Default_Missval;  break;
67516           }
67517       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67518     }
67519 }
67520 
67521 
vlistDefVarInstitut(int vlistID,int varID,int instID)67522 void vlistDefVarInstitut(int vlistID, int varID, int instID)
67523 {
67524   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67525   if (vlistptr->vars[varID].instID != instID)
67526     {
67527       vlistptr->vars[varID].instID = instID;
67528       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67529     }
67530 }
67531 
67532 
vlistInqVarInstitut(int vlistID,int varID)67533 int vlistInqVarInstitut(int vlistID, int varID)
67534 {
67535   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67536   return vlistptr->vars[varID].instID;
67537 }
67538 
67539 
vlistDefVarModel(int vlistID,int varID,int modelID)67540 void vlistDefVarModel(int vlistID, int varID, int modelID)
67541 {
67542   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67543   if (vlistptr->vars[varID].modelID != modelID)
67544     {
67545       vlistptr->vars[varID].modelID = modelID;
67546       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67547     }
67548 }
67549 
67550 
vlistInqVarModel(int vlistID,int varID)67551 int vlistInqVarModel(int vlistID, int varID)
67552 {
67553   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67554   return vlistptr->vars[varID].modelID;
67555 }
67556 
67557 
vlistDefVarTable(int vlistID,int varID,int tableID)67558 void vlistDefVarTable(int vlistID, int varID, int tableID)
67559 {
67560   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67561 
67562   if (vlistptr->vars[varID].tableID != tableID)
67563     {
67564       vlistptr->vars[varID].tableID = tableID;
67565       const int tablenum = tableInqNum(tableID);
67566 
67567       const int param = vlistptr->vars[varID].param;
67568       int pnum, pcat, pdis;
67569       cdiDecodeParam(param, &pnum, &pcat, &pdis);
67570       vlistptr->vars[varID].param = cdiEncodeParam(pnum, tablenum, pdis);
67571       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67572     }
67573 }
67574 
67575 
vlistInqVarTable(int vlistID,int varID)67576 int vlistInqVarTable(int vlistID, int varID)
67577 {
67578   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67579   return vlistptr->vars[varID].tableID;
67580 }
67581 
67582 /*
67583 @Function  vlistDefVarName
67584 @Title     Define the name of a Variable
67585 
67586 @Prototype void vlistDefVarName(int vlistID, int varID, const char *name)
67587 @Parameter
67588     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
67589     @Item  varID    Variable identifier.
67590     @Item  name     Name of the variable.
67591 
67592 @Description
67593 The function @func{vlistDefVarName} defines the name of a variable.
67594 
67595 @EndFunction
67596 */
vlistDefVarName(int vlistID,int varID,const char * name)67597 void vlistDefVarName(int vlistID, int varID, const char *name)
67598 {
67599   (void)cdiDefKeyString(vlistID, varID, CDI_KEY_NAME, name);
67600 }
67601 
67602 /*
67603 @Function  vlistDefVarLongname
67604 @Title     Define the long name of a Variable
67605 
67606 @Prototype void vlistDefVarLongname(int vlistID, int varID, const char *longname)
67607 @Parameter
67608     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
67609     @Item  varID    Variable identifier.
67610     @Item  longname Long name of the variable.
67611 
67612 @Description
67613 The function @func{vlistDefVarLongname} defines the long name of a variable.
67614 
67615 @EndFunction
67616 */
vlistDefVarLongname(int vlistID,int varID,const char * longname)67617 void vlistDefVarLongname(int vlistID, int varID, const char *longname)
67618 {
67619   if (longname) (void)cdiDefKeyString(vlistID, varID, CDI_KEY_LONGNAME, longname);
67620 }
67621 
67622 /*
67623 @Function  vlistDefVarStdname
67624 @Title     Define the standard name of a Variable
67625 
67626 @Prototype void vlistDefVarStdname(int vlistID, int varID, const char *stdname)
67627 @Parameter
67628     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
67629     @Item  varID    Variable identifier.
67630     @Item  stdname  Standard name of the variable.
67631 
67632 @Description
67633 The function @func{vlistDefVarStdname} defines the standard name of a variable.
67634 
67635 @EndFunction
67636 */
vlistDefVarStdname(int vlistID,int varID,const char * stdname)67637 void vlistDefVarStdname(int vlistID, int varID, const char *stdname)
67638 {
67639   if (stdname) (void)cdiDefKeyString(vlistID, varID, CDI_KEY_STDNAME, stdname);
67640 }
67641 
67642 /*
67643 @Function  vlistDefVarUnits
67644 @Title     Define the units of a Variable
67645 
67646 @Prototype void vlistDefVarUnits(int vlistID, int varID, const char *units)
67647 @Parameter
67648     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
67649     @Item  varID    Variable identifier.
67650     @Item  units    Units of the variable.
67651 
67652 @Description
67653 The function @func{vlistDefVarUnits} defines the units of a variable.
67654 
67655 @EndFunction
67656 */
vlistDefVarUnits(int vlistID,int varID,const char * units)67657 void vlistDefVarUnits(int vlistID, int varID, const char *units)
67658 {
67659   if (units) (void)cdiDefKeyString(vlistID, varID, CDI_KEY_UNITS, units);
67660 }
67661 
67662 /*
67663 @Function  vlistInqVarMissval
67664 @Title     Get the missing value of a Variable
67665 
67666 @Prototype double vlistInqVarMissval(int vlistID, int varID)
67667 @Parameter
67668     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67669     @Item  varID    Variable identifier.
67670 
67671 @Description
67672 The function @func{vlistInqVarMissval} returns the missing value of a variable.
67673 
67674 @Result
67675 @func{vlistInqVarMissval} returns the missing value of the variable.
67676 
67677 @EndFunction
67678 */
vlistInqVarMissval(int vlistID,int varID)67679 double vlistInqVarMissval(int vlistID, int varID)
67680 {
67681   vlistCheckVarID(__func__, vlistID, varID);
67682 
67683   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67684   return vlistptr->vars[varID].missval;
67685 }
67686 
67687 /*
67688 @Function  vlistDefVarMissval
67689 @Title     Define the missing value of a Variable
67690 
67691 @Prototype void vlistDefVarMissval(int vlistID, int varID, double missval)
67692 @Parameter
67693     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
67694     @Item  varID    Variable identifier.
67695     @Item  missval  Missing value.
67696 
67697 @Description
67698 The function @func{vlistDefVarMissval} defines the missing value of a variable.
67699 
67700 @EndFunction
67701 */
vlistDefVarMissval(int vlistID,int varID,double missval)67702 void vlistDefVarMissval(int vlistID, int varID, double missval)
67703 {
67704   vlistCheckVarID(__func__, vlistID, varID);
67705 
67706   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67707   vlistptr->vars[varID].missval = missval;
67708   vlistptr->vars[varID].missvalused = true;
67709 }
67710 
67711 /*
67712 @Function  vlistDefVarExtra
67713 @Title     Define extra information of a Variable
67714 
67715 @Prototype void vlistDefVarExtra(int vlistID, int varID, const char *extra)
67716 @Parameter
67717     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
67718     @Item  varID    Variable identifier.
67719     @Item  extra    Extra information.
67720 
67721 @Description
67722 The function @func{vlistDefVarExtra} defines the extra information of a variable.
67723 
67724 @EndFunction
67725 */
vlistDefVarExtra(int vlistID,int varID,const char * extra)67726 void vlistDefVarExtra(int vlistID, int varID, const char *extra)
67727 {
67728   vlistCheckVarID(__func__, vlistID, varID);
67729 
67730   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67731 
67732   if ( extra )
67733     {
67734       if ( vlistptr->vars[varID].extra )
67735 	{
67736 	  Free(vlistptr->vars[varID].extra);
67737 	  vlistptr->vars[varID].extra = NULL;
67738 	}
67739 
67740       vlistptr->vars[varID].extra = strdupx(extra);
67741       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67742     }
67743 }
67744 
67745 /*
67746 @Function  vlistInqVarExtra
67747 @Title     Get extra information of a Variable
67748 
67749 @Prototype void vlistInqVarExtra(int vlistID, int varID, char *extra)
67750 @Parameter
67751     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67752     @Item  varID    Variable identifier.
67753     @Item  extra    Returned variable extra information. The caller must allocate space for the
67754                     returned string. The maximum possible length, in characters, of
67755                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
67756 
67757 @Description
67758 The function @func{vlistInqVarExtra} returns the extra information of a variable.
67759 
67760 @Result
67761 @func{vlistInqVarExtra} returns the extra information of the variable to the parameter extra if available,
67762 otherwise the result is an empty string.
67763 
67764 @EndFunction
67765 */
vlistInqVarExtra(int vlistID,int varID,char * extra)67766 void vlistInqVarExtra(int vlistID, int varID, char *extra)
67767 {
67768   vlistCheckVarID(__func__, vlistID, varID);
67769 
67770   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67771   if ( vlistptr->vars[varID].extra == NULL )
67772     sprintf(extra, "-");
67773   else
67774     strcpy(extra, vlistptr->vars[varID].extra);
67775 }
67776 
67777 
vlistInqVarValidrange(int vlistID,int varID,double * validrange)67778 int vlistInqVarValidrange(int vlistID, int varID, double *validrange)
67779 {
67780   vlistCheckVarID(__func__, vlistID, varID);
67781 
67782   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67783 
67784   if ( validrange != NULL && vlistptr->vars[varID].lvalidrange )
67785     {
67786       validrange[0] = vlistptr->vars[varID].validrange[0];
67787       validrange[1] = vlistptr->vars[varID].validrange[1];
67788     }
67789 
67790   return (int)vlistptr->vars[varID].lvalidrange;
67791 }
67792 
67793 
vlistDefVarValidrange(int vlistID,int varID,const double * validrange)67794 void vlistDefVarValidrange(int vlistID, int varID, const double *validrange)
67795 {
67796   vlistCheckVarID(__func__, vlistID, varID);
67797 
67798   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67799 
67800   vlistptr->vars[varID].validrange[0] = validrange[0];
67801   vlistptr->vars[varID].validrange[1] = validrange[1];
67802   vlistptr->vars[varID].lvalidrange = true;
67803   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67804 }
67805 
67806 
vlistInqVarScalefactor(int vlistID,int varID)67807 double vlistInqVarScalefactor(int vlistID, int varID)
67808 {
67809   vlistCheckVarID(__func__, vlistID, varID);
67810 
67811   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67812   return vlistptr->vars[varID].scalefactor;
67813 }
67814 
67815 
vlistInqVarAddoffset(int vlistID,int varID)67816 double vlistInqVarAddoffset(int vlistID, int varID)
67817 {
67818   vlistCheckVarID(__func__, vlistID, varID);
67819 
67820   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67821   return vlistptr->vars[varID].addoffset;
67822 }
67823 
67824 
vlistDefVarScalefactor(int vlistID,int varID,double scalefactor)67825 void vlistDefVarScalefactor(int vlistID, int varID, double scalefactor)
67826 {
67827   vlistCheckVarID(__func__, vlistID, varID);
67828 
67829   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67830   if ( IS_NOT_EQUAL(vlistptr->vars[varID].scalefactor, scalefactor) )
67831     {
67832       vlistptr->vars[varID].scalefactor = scalefactor;
67833       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67834     }
67835 }
67836 
67837 
vlistDefVarAddoffset(int vlistID,int varID,double addoffset)67838 void vlistDefVarAddoffset(int vlistID, int varID, double addoffset)
67839 {
67840   vlistCheckVarID(__func__, vlistID, varID);
67841 
67842   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67843   if ( IS_NOT_EQUAL(vlistptr->vars[varID].addoffset, addoffset))
67844     {
67845       vlistptr->vars[varID].addoffset = addoffset;
67846       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67847     }
67848 }
67849 
67850 
vlistDefVarTimetype(int vlistID,int varID,int timetype)67851 void vlistDefVarTimetype(int vlistID, int varID, int timetype)
67852 {
67853   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67854   if (vlistptr->vars[varID].timetype != timetype)
67855     {
67856       vlistptr->vars[varID].timetype = timetype;
67857       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67858     }
67859 }
67860 
67861 
vlistInqVarTimetype(int vlistID,int varID)67862 int vlistInqVarTimetype(int vlistID, int varID)
67863 {
67864   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67865   return vlistptr->vars[varID].timetype;
67866 }
67867 
67868 
vlistDefVarTsteptype(int vlistID,int varID,int tsteptype)67869 void vlistDefVarTsteptype(int vlistID, int varID, int tsteptype)
67870 {
67871   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67872   if (vlistptr->vars[varID].tsteptype != tsteptype)
67873     {
67874       vlistptr->vars[varID].tsteptype = tsteptype;
67875       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67876     }
67877 }
67878 
67879 /*
67880 @Function  vlistInqVarTsteptype
67881 @Title     Get the timestep type of a Variable
67882 
67883 @Prototype int vlistInqVarTsteptype(int vlistID, int varID)
67884 @Parameter
67885     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
67886     @Item  varID    Variable identifier.
67887 
67888 @Description
67889 The function @func{vlistInqVarTsteptype} returns the timestep type of a Variable.
67890 
67891 @Result
67892 @func{vlistInqVarTsteptype} returns the timestep type of the Variable,
67893 one of the set of predefined CDI timestep types.
67894 The valid CDI timestep types are @func{TSTEP_INSTANT},
67895 @func{TSTEP_ACCUM}, @func{TSTEP_AVG}, @func{TSTEP_MAX}, @func{TSTEP_MIN} and @func{TSTEP_SD}.
67896 
67897 @EndFunction
67898 */
vlistInqVarTsteptype(int vlistID,int varID)67899 int vlistInqVarTsteptype(int vlistID, int varID)
67900 {
67901   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67902   return vlistptr->vars[varID].tsteptype;
67903 }
67904 
67905 
vlistInqVarMissvalUsed(int vlistID,int varID)67906 int vlistInqVarMissvalUsed(int vlistID, int varID)
67907 {
67908   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67909   return (int)vlistptr->vars[varID].missvalused;
67910 }
67911 
67912 
vlistDefFlag(int vlistID,int varID,int levID,int flag)67913 void vlistDefFlag(int vlistID, int varID, int levID, int flag)
67914 {
67915   vlist_t *vlistptr = vlist_to_pointer(vlistID);
67916 
67917   levinfo_t li = DEFAULT_LEVINFO(levID);
67918   if (vlistptr->vars[varID].levinfo)
67919     ;
67920   else if (flag != li.flag)
67921     cdiVlistCreateVarLevInfo(vlistptr, varID);
67922   else
67923     return;
67924 
67925   vlistptr->vars[varID].levinfo[levID].flag = flag;
67926 
67927   vlistptr->vars[varID].flag = 0;
67928 
67929   int nlevs = zaxisInqSize(vlistptr->vars[varID].zaxisID);
67930   for ( int levelID = 0; levelID < nlevs; levelID++ )
67931     {
67932       if ( vlistptr->vars[varID].levinfo[levelID].flag )
67933         {
67934           vlistptr->vars[varID].flag = 1;
67935           break;
67936         }
67937     }
67938 
67939   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
67940 }
67941 
67942 
vlistInqFlag(int vlistID,int varID,int levID)67943 int vlistInqFlag(int vlistID, int varID, int levID)
67944 {
67945   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67946 
67947   if (vlistptr->vars[varID].levinfo)
67948     return vlistptr->vars[varID].levinfo[levID].flag;
67949   else
67950     {
67951       levinfo_t li = DEFAULT_LEVINFO(levID);
67952       return li.flag;
67953     }
67954 }
67955 
67956 
vlistFindVar(int vlistID,int fvarID)67957 int vlistFindVar(int vlistID, int fvarID)
67958 {
67959   int varID;
67960   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67961 
67962   for ( varID = 0; varID < vlistptr->nvars; varID++ )
67963     {
67964       if ( vlistptr->vars[varID].fvarID == fvarID ) break;
67965     }
67966 
67967   if ( varID == vlistptr->nvars )
67968     {
67969       varID = -1;
67970       Message("varID not found for fvarID %d in vlistID %d!", fvarID, vlistID);
67971     }
67972 
67973   return varID;
67974 }
67975 
67976 
vlistFindLevel(int vlistID,int fvarID,int flevelID)67977 int vlistFindLevel(int vlistID, int fvarID, int flevelID)
67978 {
67979   int levelID = -1;
67980   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
67981 
67982   const int varID = vlistFindVar(vlistID, fvarID);
67983 
67984   if ( varID != -1 )
67985     {
67986       const int nlevs = zaxisInqSize(vlistptr->vars[varID].zaxisID);
67987       for ( levelID = 0; levelID < nlevs; levelID++ )
67988 	{
67989 	  if ( vlistptr->vars[varID].levinfo[levelID].flevelID == flevelID ) break;
67990 	}
67991 
67992       if ( levelID == nlevs )
67993 	{
67994 	  levelID = -1;
67995 	  Message("levelID not found for fvarID %d and levelID %d in vlistID %d!",
67996 		  fvarID, flevelID, vlistID);
67997 	}
67998     }
67999 
68000   return levelID;
68001 }
68002 
68003 
vlistMergedVar(int vlistID,int varID)68004 int vlistMergedVar(int vlistID, int varID)
68005 {
68006   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
68007   return vlistptr->vars[varID].mvarID;
68008 }
68009 
68010 
vlistMergedLevel(int vlistID,int varID,int levelID)68011 int vlistMergedLevel(int vlistID, int varID, int levelID)
68012 {
68013   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
68014 
68015   if (vlistptr->vars[varID].levinfo)
68016     return vlistptr->vars[varID].levinfo[levelID].mlevelID;
68017   else
68018     {
68019       levinfo_t li = DEFAULT_LEVINFO(levelID);
68020       return li.mlevelID;
68021     }
68022 }
68023 
68024 
vlistDefIndex(int vlistID,int varID,int levelID,int index)68025 void vlistDefIndex(int vlistID, int varID, int levelID, int index)
68026 {
68027   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68028 
68029   levinfo_t li = DEFAULT_LEVINFO(levelID);
68030   if (vlistptr->vars[varID].levinfo)
68031     ;
68032   else if (index != li.index)
68033     cdiVlistCreateVarLevInfo(vlistptr, varID);
68034   else
68035     return;
68036 
68037   vlistptr->vars[varID].levinfo[levelID].index = index;
68038   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
68039 }
68040 
68041 
vlistInqIndex(int vlistID,int varID,int levelID)68042 int vlistInqIndex(int vlistID, int varID, int levelID)
68043 {
68044   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
68045 
68046   if (vlistptr->vars[varID].levinfo)
68047     return vlistptr->vars[varID].levinfo[levelID].index;
68048   else
68049     {
68050       levinfo_t li = DEFAULT_LEVINFO(levelID);
68051       return li.index;
68052     }
68053 }
68054 
68055 
vlistChangeVarZaxis(int vlistID,int varID,int zaxisID)68056 void vlistChangeVarZaxis(int vlistID, int varID, int zaxisID)
68057 {
68058   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68059 
68060   vlistCheckVarID(__func__, vlistID, varID);
68061 
68062   const int nlevs1 = zaxisInqSize(vlistptr->vars[varID].zaxisID);
68063   const int nlevs2 = zaxisInqSize(zaxisID);
68064 
68065   if ( nlevs1 != nlevs2 ) Error("Number of levels must not change!");
68066 
68067   const int nvars = vlistptr->nvars;
68068   int found = 0;
68069   const int oldZaxisID = vlistptr->vars[varID].zaxisID;
68070   for ( int i = 0; i < varID; ++i)
68071     found |= (vlistptr->vars[i].zaxisID == oldZaxisID);
68072   for ( int i = varID + 1; i < nvars; ++i)
68073     found |= (vlistptr->vars[i].zaxisID == oldZaxisID);
68074 
68075   if (found)
68076     {
68077       const int nzaxis = vlistptr->nzaxis;
68078       for (int i = 0; i < nzaxis; ++i)
68079 	if (vlistptr->zaxisIDs[i] == oldZaxisID )
68080 	  vlistptr->zaxisIDs[i] = zaxisID;
68081     }
68082   else
68083     vlistAdd2ZaxisIDs(vlistptr, zaxisID);
68084 
68085   vlistptr->vars[varID].zaxisID = zaxisID;
68086   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
68087 }
68088 
68089 
vlistChangeVarGrid(int vlistID,int varID,int gridID)68090 void vlistChangeVarGrid(int vlistID, int varID, int gridID)
68091 {
68092   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68093 
68094   vlistCheckVarID(__func__, vlistID, varID);
68095 
68096   const int nvars = vlistptr->nvars;
68097   int index;
68098   for ( index = 0; index < nvars; index++ )
68099     if ( index != varID )
68100       if ( vlistptr->vars[index].gridID == vlistptr->vars[varID].gridID ) break;
68101 
68102   if ( index == nvars )
68103     {
68104       for ( index = 0; index < vlistptr->ngrids; index++ )
68105 	if ( vlistptr->gridIDs[index] == vlistptr->vars[varID].gridID )
68106 	  vlistptr->gridIDs[index] = gridID;
68107     }
68108   else
68109     vlistAdd2GridIDs(vlistptr, gridID);
68110 
68111   vlistptr->vars[varID].gridID = gridID;
68112   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
68113 }
68114 
68115 
vlistDefVarCompType(int vlistID,int varID,int comptype)68116 void vlistDefVarCompType(int vlistID, int varID, int comptype)
68117 {
68118   vlistCheckVarID(__func__, vlistID, varID);
68119 
68120   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68121   if (vlistptr->vars[varID].comptype != comptype)
68122     {
68123       vlistptr->vars[varID].comptype = comptype;
68124       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
68125     }
68126 }
68127 
68128 
vlistInqVarCompType(int vlistID,int varID)68129 int vlistInqVarCompType(int vlistID, int varID)
68130 {
68131   vlistCheckVarID(__func__, vlistID, varID);
68132 
68133   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
68134   return vlistptr->vars[varID].comptype;
68135 }
68136 
68137 
vlistDefVarCompLevel(int vlistID,int varID,int complevel)68138 void vlistDefVarCompLevel(int vlistID, int varID, int complevel)
68139 {
68140   vlistCheckVarID(__func__, vlistID, varID);
68141 
68142   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68143   if (vlistptr->vars[varID].complevel != complevel)
68144     {
68145       vlistptr->vars[varID].complevel = complevel;
68146       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
68147     }
68148 }
68149 
68150 
vlistInqVarCompLevel(int vlistID,int varID)68151 int vlistInqVarCompLevel(int vlistID, int varID)
68152 {
68153   vlistCheckVarID(__func__, vlistID, varID);
68154 
68155   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
68156   return vlistptr->vars[varID].complevel;
68157 }
68158 
68159 
vlistDefVarChunkType(int vlistID,int varID,int chunktype)68160 void  vlistDefVarChunkType(int vlistID, int varID, int chunktype)
68161 {
68162   vlistCheckVarID(__func__, vlistID, varID);
68163 
68164   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68165   if (vlistptr->vars[varID].chunktype != chunktype)
68166     {
68167       vlistptr->vars[varID].chunktype = chunktype;
68168       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
68169     }
68170 }
68171 
68172 
vlistInqVarChunkType(int vlistID,int varID)68173 int vlistInqVarChunkType(int vlistID, int varID)
68174 {
68175   vlistCheckVarID(__func__, vlistID, varID);
68176 
68177   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68178   return vlistptr->vars[varID].chunktype;
68179 }
68180 
68181 static
vlistEncodeXyz(int (* dimorder)[3])68182 int vlistEncodeXyz(int (*dimorder)[3])
68183 {
68184   return (*dimorder)[0]*100 + (*dimorder)[1]*10 + (*dimorder)[2];
68185 }
68186 
68187 
68188 static
vlistDecodeXyz(int xyz,int (* outDimorder)[3])68189 void vlistDecodeXyz(int xyz, int (*outDimorder)[3])
68190 {
68191   (*outDimorder)[0] = xyz/100, xyz -= (*outDimorder)[0]*100;
68192   (*outDimorder)[1] = xyz/10, xyz -= (*outDimorder)[1]*10;
68193   (*outDimorder)[2] = xyz;
68194 }
68195 
68196 
vlistDefVarXYZ(int vlistID,int varID,int xyz)68197 void vlistDefVarXYZ(int vlistID, int varID, int xyz)
68198 {
68199   vlistCheckVarID(__func__, vlistID, varID);
68200 
68201   if ( xyz == 3 ) xyz = 321;
68202 
68203   /* check xyz dimension order */
68204   {
68205     int dimorder[3];
68206     vlistDecodeXyz(xyz, &dimorder);
68207     int dimx = 0, dimy = 0, dimz = 0;
68208     for ( int id = 0; id < 3; ++id )
68209       {
68210         switch ( dimorder[id] )
68211           {
68212             case 1: dimx++; break;
68213             case 2: dimy++; break;
68214             case 3: dimz++; break;
68215             default: dimorder[id] = 0; break;    //Ensure that we assign a valid dimension to this position.
68216           }
68217      }
68218     if ( dimz > 1 || dimy > 1 || dimx > 1 ) xyz = 321; // ZYX
68219     else
68220       {
68221         if ( dimz == 0 ) for ( int id = 0; id < 3; ++id ) if ( dimorder[id] == 0 ) {dimorder[id] = 3; break;}
68222         if ( dimy == 0 ) for ( int id = 0; id < 3; ++id ) if ( dimorder[id] == 0 ) {dimorder[id] = 2; break;}
68223         if ( dimx == 0 ) for ( int id = 0; id < 3; ++id ) if ( dimorder[id] == 0 ) {dimorder[id] = 1; break;}
68224         xyz = vlistEncodeXyz(&dimorder);
68225       }
68226   }
68227 
68228   assert(xyz == 123 || xyz == 312 || xyz == 231 || xyz == 321 || xyz == 132 || xyz == 213);
68229 
68230   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68231   vlistptr->vars[varID].xyz = xyz;
68232   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
68233 }
68234 
68235 
vlistInqVarDimorder(int vlistID,int varID,int (* outDimorder)[3])68236 void vlistInqVarDimorder(int vlistID, int varID, int (*outDimorder)[3])
68237 {
68238   vlistCheckVarID(__func__, vlistID, varID);
68239 
68240   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
68241   vlistDecodeXyz(vlistptr->vars[varID].xyz, outDimorder);
68242 }
68243 
68244 
vlistInqVarXYZ(int vlistID,int varID)68245 int vlistInqVarXYZ(int vlistID, int varID)
68246 {
68247   vlistCheckVarID(__func__, vlistID, varID);
68248 
68249   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
68250   return vlistptr->vars[varID].xyz;
68251 }
68252 
68253 
vlistDefVarIOrank(int vlistID,int varID,int iorank)68254 void vlistDefVarIOrank(int vlistID, int varID, int iorank)
68255 {
68256   vlistCheckVarID ( __func__, vlistID, varID );
68257 
68258   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68259   if (vlistptr->vars[varID].iorank != iorank)
68260     {
68261       vlistptr->vars[varID].iorank = iorank;
68262       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
68263     }
68264 }
68265 
68266 
vlistInqVarIOrank(int vlistID,int varID)68267 int vlistInqVarIOrank(int vlistID, int varID)
68268 {
68269   vlistCheckVarID(__func__, vlistID, varID);
68270 
68271   const vlist_t *vlistptr = vlist_to_pointer(vlistID);
68272   return vlistptr->vars[varID].iorank;
68273 }
68274 
68275 
vlistVarCompare(vlist_t * a,int varIDA,vlist_t * b,int varIDB)68276 int vlistVarCompare(vlist_t *a, int varIDA, vlist_t *b, int varIDB)
68277 {
68278   xassert(a && b
68279           && varIDA >= 0 && varIDA < a->nvars
68280           && varIDB >= 0 && varIDB < b->nvars);
68281   var_t *pva = a->vars + varIDA, *pvb = b->vars + varIDB;
68282 #define FCMP(f) ((pva->f) != (pvb->f))
68283 #define FCMPFLT(f) (IS_NOT_EQUAL((pva->f), (pvb->f)))
68284 #define FCMPSTR(fs) ((pva->fs) != (pvb->fs) && strcmp((pva->fs), (pvb->fs)))
68285 #define FCMP2(f) (namespaceResHDecode(pva->f).idx       \
68286                   != namespaceResHDecode(pvb->f).idx)
68287   int diff = FCMP(fvarID) | FCMP(mvarID) | FCMP(flag) | FCMP(param)
68288     | FCMP(datatype) | FCMP(timetype) | FCMP(tsteptype)
68289     | FCMP(chunktype) | FCMP(xyz) | FCMP2(gridID) | FCMP2(zaxisID)
68290     | FCMP2(instID) | FCMP2(modelID) | FCMP2(tableID) | FCMP(missvalused)
68291     | FCMPFLT(missval) | FCMPFLT(addoffset) | FCMPFLT(scalefactor)
68292     | FCMPSTR(extra)
68293     | FCMP(comptype) | FCMP(complevel) | FCMP(lvalidrange)
68294     | FCMPFLT(validrange[0]) | FCMPFLT(validrange[1]);
68295 #undef FCMP
68296 #undef FCMPFLT
68297 #undef FCMPSTR
68298 #undef FCMP2
68299   if ((diff |= ((pva->levinfo == NULL) ^ (pvb->levinfo == NULL)))) return 1;
68300 
68301   if (pva->levinfo)
68302     {
68303       const int zaxisID = pva->zaxisID;
68304       const size_t nlevs = (size_t)zaxisInqSize(zaxisID);
68305       diff |= (memcmp(pva->levinfo, pvb->levinfo, sizeof (levinfo_t) * nlevs) != 0);
68306       if (diff) return 1;
68307     }
68308 
68309   const size_t natts = a->vars[varIDA].atts.nelems;
68310   if (natts != b->vars[varIDB].atts.nelems) return 1;
68311   for (size_t attID = 0; attID < natts; ++attID)
68312     diff |= cdi_att_compare(&a->vars[varIDA].atts, &b->vars[varIDB].atts, (int)attID);
68313 
68314   const size_t nkeys = a->vars[varIDA].keys.nelems;
68315   if (nkeys != b->vars[varIDB].keys.nelems) return 1;
68316   for (size_t keyID = 0; keyID < nkeys; ++keyID)
68317     diff |= cdi_key_compare(&a->vars[varIDA].keys, &b->vars[varIDB].keys, (int)keyID);
68318 
68319   return diff;
68320 }
68321 
68322 /*
68323  * Local Variables:
68324  * c-file-style: "Java"
68325  * c-basic-offset: 2
68326  * indent-tabs-mode: nil
68327  * show-trailing-whitespace: t
68328  * require-trailing-newline: t
68329  * End:
68330  */
68331 
68332 enum {
68333   VLISTVAR_PACK_INT_IDX_FLAG,
68334   VLISTVAR_PACK_INT_IDX_GRIDID,
68335   VLISTVAR_PACK_INT_IDX_ZAXISID,
68336   VLISTVAR_PACK_INT_IDX_TIMETYPE,
68337   VLISTVAR_PACK_INT_IDX_DATATYPE,
68338   VLISTVAR_PACK_INT_IDX_PARAM,
68339   VLISTVAR_PACK_INT_IDX_INSTID,
68340   VLISTVAR_PACK_INT_IDX_MODELID,
68341   VLISTVAR_PACK_INT_IDX_TABLEID,
68342   VLISTVAR_PACK_INT_IDX_MISSVALUSED,
68343   VLISTVAR_PACK_INT_IDX_COMPTYPE,
68344   VLISTVAR_PACK_INT_IDX_COMPLEVEL,
68345   VLISTVAR_PACK_INT_IDX_NLEVS,
68346   VLISTVAR_PACK_INT_IDX_IORANK,
68347   VLISTVAR_PACK_INT_IDX_EXTRALEN,
68348   vlistvarNint
68349 };
68350 
68351 enum {
68352   vlistvar_ndbls = 3,
68353 };
68354 
vlistVarGetPackSize(vlist_t * p,int varID,void * context)68355 int vlistVarGetPackSize(vlist_t *p, int varID, void *context)
68356 {
68357   var_t *var = p->vars + varID;
68358   int varsize = serializeGetSize(vlistvarNint, CDI_DATATYPE_INT, context)
68359     + serializeGetSize(vlistvar_ndbls, CDI_DATATYPE_FLT64, context);
68360   if (var->extra)
68361     varsize += serializeGetSize((int)strlen(var->extra), CDI_DATATYPE_TXT, context);
68362   varsize += serializeGetSize(4 * zaxisInqSize(var->zaxisID), CDI_DATATYPE_INT, context);
68363 
68364   varsize += serializeKeysGetPackSize(&var->keys, context);
68365 
68366   varsize += cdiAttsGetSize(p, varID, context);
68367 
68368   return varsize;
68369 }
68370 
vlistVarPack(vlist_t * p,int varID,char * buf,int size,int * position,void * context)68371 void vlistVarPack(vlist_t *p, int varID, char * buf, int size, int *position, void *context)
68372 {
68373   double dtempbuf[vlistvar_ndbls];
68374   var_t *var = p->vars + varID;
68375   int tempbuf[vlistvarNint], extralen;
68376 
68377   tempbuf[VLISTVAR_PACK_INT_IDX_FLAG] = var->flag;
68378   tempbuf[VLISTVAR_PACK_INT_IDX_GRIDID] = var->gridID;
68379   tempbuf[VLISTVAR_PACK_INT_IDX_ZAXISID] = var->zaxisID;
68380   tempbuf[VLISTVAR_PACK_INT_IDX_TIMETYPE] = var->timetype;
68381   tempbuf[VLISTVAR_PACK_INT_IDX_DATATYPE] = var->datatype;
68382   tempbuf[VLISTVAR_PACK_INT_IDX_PARAM] = var->param;
68383   tempbuf[VLISTVAR_PACK_INT_IDX_INSTID] = var->instID;
68384   tempbuf[VLISTVAR_PACK_INT_IDX_MODELID] = var->modelID;
68385   tempbuf[VLISTVAR_PACK_INT_IDX_TABLEID] = var->tableID;
68386   tempbuf[VLISTVAR_PACK_INT_IDX_MISSVALUSED] = (int)var->missvalused;
68387   tempbuf[VLISTVAR_PACK_INT_IDX_COMPTYPE] = var->comptype;
68388   tempbuf[VLISTVAR_PACK_INT_IDX_COMPLEVEL] = var->complevel;
68389   int nlevs = var->levinfo ? zaxisInqSize(var->zaxisID) : 0;
68390   tempbuf[VLISTVAR_PACK_INT_IDX_NLEVS] = nlevs;
68391   tempbuf[VLISTVAR_PACK_INT_IDX_IORANK] = var->iorank;
68392   tempbuf[VLISTVAR_PACK_INT_IDX_EXTRALEN] = extralen = var->extra?(int)strlen(var->extra):0;
68393   dtempbuf[0] = var->missval;
68394   dtempbuf[1] = var->scalefactor;
68395   dtempbuf[2] = var->addoffset;
68396   serializePack(tempbuf, vlistvarNint, CDI_DATATYPE_INT, buf, size, position, context);
68397   serializePack(dtempbuf, vlistvar_ndbls, CDI_DATATYPE_FLT64,buf, size, position, context);
68398   if (extralen)
68399     serializePack(var->extra, extralen, CDI_DATATYPE_TXT, buf, size, position, context);
68400   if (nlevs)
68401     {
68402       int *levbuf = (int*) malloc(nlevs*sizeof(int));
68403       for (int levID = 0; levID < nlevs; ++levID) levbuf[levID] = var->levinfo[levID].flag;
68404       serializePack(levbuf, nlevs, CDI_DATATYPE_INT, buf, size, position, context);
68405       for (int levID = 0; levID < nlevs; ++levID) levbuf[levID] = var->levinfo[levID].index;
68406       serializePack(levbuf, nlevs, CDI_DATATYPE_INT, buf, size, position, context);
68407       for (int levID = 0; levID < nlevs; ++levID) levbuf[levID] = var->levinfo[levID].mlevelID;
68408       serializePack(levbuf, nlevs, CDI_DATATYPE_INT, buf, size, position, context);
68409       for (int levID = 0; levID < nlevs; ++levID) levbuf[levID] = var->levinfo[levID].flevelID;
68410       free(levbuf);
68411     }
68412 
68413   serializeKeysPack(&var->keys, buf, size, position, context);
68414 
68415   cdiAttsPack(p, varID, buf, size, position, context);
68416 }
68417 
vlistVarUnpack(int vlistID,char * buf,int size,int * position,int originNamespace,void * context)68418 void vlistVarUnpack(int vlistID, char * buf, int size, int *position,
68419 		    int originNamespace, void *context)
68420 {
68421   double dtempbuf[vlistvar_ndbls];
68422   int tempbuf[vlistvarNint];
68423   char *varname = NULL;
68424   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68425   serializeUnpack(buf, size, position, tempbuf, vlistvarNint, CDI_DATATYPE_INT, context);
68426   serializeUnpack(buf, size, position, dtempbuf, vlistvar_ndbls, CDI_DATATYPE_FLT64, context);
68427 
68428   /* ------------------------------------------- */
68429   /* NOTE: Tile sets  currently not supported!!! */
68430   /* ------------------------------------------- */
68431 
68432   int newvar = vlistDefVar ( vlistID,
68433 			 namespaceAdaptKey ( tempbuf[VLISTVAR_PACK_INT_IDX_GRIDID], originNamespace ),
68434 			 namespaceAdaptKey ( tempbuf[VLISTVAR_PACK_INT_IDX_ZAXISID], originNamespace ),
68435 			 tempbuf[VLISTVAR_PACK_INT_IDX_TIMETYPE]);
68436   if (tempbuf[VLISTVAR_PACK_INT_IDX_EXTRALEN])
68437     varname = (char *)Malloc((size_t)tempbuf[VLISTVAR_PACK_INT_IDX_EXTRALEN] + 1);
68438   if (tempbuf[VLISTVAR_PACK_INT_IDX_EXTRALEN])
68439     {
68440       serializeUnpack(buf, size, position,
68441                       varname, tempbuf[VLISTVAR_PACK_INT_IDX_EXTRALEN], CDI_DATATYPE_TXT, context);
68442       varname[tempbuf[VLISTVAR_PACK_INT_IDX_EXTRALEN]] = '\0';
68443       vlistDefVarExtra(vlistID, newvar, varname);
68444     }
68445   Free(varname);
68446   vlistDefVarDatatype(vlistID, newvar, tempbuf[VLISTVAR_PACK_INT_IDX_DATATYPE]);
68447   vlistDefVarInstitut ( vlistID, newvar,
68448 			namespaceAdaptKey ( tempbuf[VLISTVAR_PACK_INT_IDX_INSTID], originNamespace ));
68449   vlistDefVarModel ( vlistID, newvar,
68450 		     namespaceAdaptKey ( tempbuf[VLISTVAR_PACK_INT_IDX_MODELID], originNamespace ));
68451   vlistDefVarTable(vlistID, newvar, tempbuf[VLISTVAR_PACK_INT_IDX_TABLEID]);
68452   // FIXME: changing the table might change the param code
68453   vlistDefVarParam(vlistID, newvar, tempbuf[VLISTVAR_PACK_INT_IDX_PARAM]);
68454   if (tempbuf[VLISTVAR_PACK_INT_IDX_MISSVALUSED])
68455     vlistDefVarMissval(vlistID, newvar, dtempbuf[0]);
68456   vlistDefVarScalefactor(vlistID, newvar, dtempbuf[1]);
68457   vlistDefVarAddoffset(vlistID, newvar, dtempbuf[2]);
68458   vlistDefVarCompType(vlistID, newvar, tempbuf[VLISTVAR_PACK_INT_IDX_COMPTYPE]);
68459   vlistDefVarCompLevel(vlistID, newvar, tempbuf[VLISTVAR_PACK_INT_IDX_COMPLEVEL]);
68460   const int nlevs = tempbuf[VLISTVAR_PACK_INT_IDX_NLEVS];
68461   var_t *var = vlistptr->vars + newvar;
68462   if (nlevs)
68463     {
68464       int i, flagSetLev = 0;
68465       cdiVlistCreateVarLevInfo(vlistptr, newvar);
68466 
68467       int *levbuf = (int*) malloc(nlevs*sizeof(int));
68468       serializeUnpack(buf, size, position, levbuf, nlevs, CDI_DATATYPE_INT, context);
68469       for (i = 0; i < nlevs; ++i) vlistDefFlag(vlistID, newvar, i, levbuf[i]);
68470       for (i = 0; i < nlevs; ++i) if (levbuf[i] == tempbuf[0]) flagSetLev = i;
68471       vlistDefFlag(vlistID, newvar, flagSetLev, levbuf[flagSetLev]);
68472       serializeUnpack(buf, size, position, levbuf, nlevs, CDI_DATATYPE_INT, context);
68473       for (i = 0; i < nlevs; ++i) vlistDefIndex(vlistID, newvar, i, levbuf[i]);
68474       serializeUnpack(buf, size, position, levbuf, nlevs, CDI_DATATYPE_INT, context);
68475       for (i = 0; i < nlevs; ++i) var->levinfo[i].mlevelID = levbuf[i];
68476       serializeUnpack(buf, size, position, levbuf, nlevs, CDI_DATATYPE_INT, context);
68477       for (i = 0; i < nlevs; ++i) var->levinfo[i].flevelID = levbuf[i];
68478       free(levbuf);
68479     }
68480   vlistDefVarIOrank(vlistID, newvar, tempbuf[VLISTVAR_PACK_INT_IDX_IORANK]);
68481 
68482   serializeKeysUnpack(buf, size, position, &var->keys, context);
68483 
68484   cdiAttsUnpack(vlistID, newvar, buf, size, position, context);
68485 }
68486 
68487 /*
68488  * Local Variables:
68489  * c-file-style: "Java"
68490  * c-basic-offset: 2
68491  * indent-tabs-mode: nil
68492  * show-trailing-whitespace: t
68493  * require-trailing-newline: t
68494  * End:
68495  */
68496 #ifdef HAVE_CONFIG_H
68497 #endif
68498 
68499 
68500 /* vlistDefVarIntKey: Set an arbitrary keyword/integer value pair for GRIB API */
vlistDefVarIntKey(int vlistID,int varID,const char * name,int value)68501 void vlistDefVarIntKey(int vlistID, int varID, const char *name, int value)
68502 {
68503 #ifdef HAVE_LIBGRIB_API
68504   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68505   if (vlistptr == NULL)  Error("Internal error!");
68506   int idx;
68507 
68508   if ( vlistptr->immutable )
68509     Error("vlistDefVarIntKey() was called on an immutable vlist object (vlistID = %d)\n"
68510           "Either call vlistDefVarIntKey() before passing the vlist object to streamDefVlist(),\n"
68511           "or use the stream-internal vlist by calling streamInqVlist().", vlistID);
68512 
68513   for ( idx=0; idx<vlistptr->vars[varID].opt_grib_nentries; idx++)
68514     if ( (strcmp(name, vlistptr->vars[varID].opt_grib_kvpair[idx].keyword) == 0 ) &&
68515          (vlistptr->vars[varID].opt_grib_kvpair[idx].data_type == t_int) )  break;
68516 
68517   if ( idx < vlistptr->vars[varID].opt_grib_nentries )
68518     {
68519       vlistptr->vars[varID].opt_grib_kvpair[idx].int_val = value;
68520       vlistptr->vars[varID].opt_grib_kvpair[idx].update  = true;
68521     }
68522   else
68523     {
68524       resize_opt_grib_entries(&vlistptr->vars[varID], vlistptr->vars[varID].opt_grib_nentries+1);
68525       vlistptr->vars[varID].opt_grib_nentries += 1;
68526       idx = vlistptr->vars[varID].opt_grib_nentries -1;
68527       vlistptr->vars[varID].opt_grib_kvpair[idx].data_type   = t_int;
68528       vlistptr->vars[varID].opt_grib_kvpair[idx].int_val     = value;
68529       vlistptr->vars[varID].opt_grib_kvpair[idx].update      = true;
68530       if ( name )
68531         vlistptr->vars[varID].opt_grib_kvpair[idx].keyword = strdupx(name);
68532       else
68533         Error("Internal error, name undefined!");
68534     }
68535 
68536   if ( CDI_Debug )
68537     {
68538       Message("define additional GRIB2 key \"%s\" (integer): %d", name, value);
68539       Message("total list of registered, additional GRIB2 keys (total: %d):",
68540               vlistptr->vars[varID].opt_grib_nentries);
68541       for ( idx=0; idx<vlistptr->vars[varID].opt_grib_nentries; idx++)
68542         if (vlistptr->vars[varID].opt_grib_kvpair[idx].data_type == t_int)
68543           Message("%s -> integer %d",
68544                   vlistptr->vars[varID].opt_grib_kvpair[idx].keyword,
68545                   vlistptr->vars[varID].opt_grib_kvpair[idx].int_val);
68546         else if (vlistptr->vars[varID].opt_grib_kvpair[idx].data_type == t_double)
68547           Message("%s -> double %d",
68548                   vlistptr->vars[varID].opt_grib_kvpair[idx].keyword,
68549                   vlistptr->vars[varID].opt_grib_kvpair[idx].dbl_val);
68550         else
68551           Message("%s -> unknown", vlistptr->vars[varID].opt_grib_kvpair[idx].keyword);
68552     }
68553 
68554   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
68555 #else
68556   (void)vlistID;
68557   (void)varID;
68558   (void)name;
68559   (void)value;
68560 #endif
68561 }
68562 
68563 /* vlistDefVarDblKey: Set an arbitrary keyword/double value pair for GRIB API */
vlistDefVarDblKey(int vlistID,int varID,const char * name,double value)68564 void vlistDefVarDblKey(int vlistID, int varID, const char *name, double value)
68565 {
68566 #ifdef HAVE_LIBGRIB_API
68567   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68568   if (vlistptr == NULL)  Error("Internal error!");
68569   int idx;
68570 
68571   if ( vlistptr->immutable )
68572     Error("vlistDefVarDblKey() was called on an immutable vlist object (vlistID = %d)\n"
68573           "Either call vlistDefVarIntKey() before passing the vlist object to streamDefVlist(),\n"
68574           "or use the stream-internal vlist by calling streamInqVlist().", vlistID);
68575 
68576   for ( idx=0; idx<vlistptr->vars[varID].opt_grib_nentries; idx++)
68577     if ( (strcmp(name, vlistptr->vars[varID].opt_grib_kvpair[idx].keyword) == 0 ) &&
68578          (vlistptr->vars[varID].opt_grib_kvpair[idx].data_type == t_double) )  break;
68579 
68580   if ( idx < vlistptr->vars[varID].opt_grib_nentries )
68581     {
68582       vlistptr->vars[varID].opt_grib_kvpair[idx].dbl_val = value;
68583       vlistptr->vars[varID].opt_grib_kvpair[idx].update  = true;
68584     }
68585   else
68586     {
68587       resize_opt_grib_entries(&vlistptr->vars[varID], vlistptr->vars[varID].opt_grib_nentries+1);
68588       vlistptr->vars[varID].opt_grib_nentries += 1;
68589       idx = vlistptr->vars[varID].opt_grib_nentries - 1;
68590       vlistptr->vars[varID].opt_grib_kvpair[idx].data_type = t_double;
68591       vlistptr->vars[varID].opt_grib_kvpair[idx].dbl_val   = value;
68592       vlistptr->vars[varID].opt_grib_kvpair[idx].update    = true;
68593       if ( name )
68594         vlistptr->vars[varID].opt_grib_kvpair[idx].keyword = strdupx(name);
68595       else
68596         Error("Internal error, name undefined!");
68597     }
68598 
68599   if ( CDI_Debug )
68600     {
68601       Message("define additional GRIB2 key \"%s\" (double): %d", name, value);
68602       Message("total list of registered, additional GRIB2 keys (total: %d):",
68603               vlistptr->vars[varID].opt_grib_nentries);
68604       for ( idx=0; idx<vlistptr->vars[varID].opt_grib_nentries; idx++)
68605         if (vlistptr->vars[varID].opt_grib_kvpair[idx].data_type == t_int)
68606           Message("%s -> integer %d",
68607                   vlistptr->vars[varID].opt_grib_kvpair[idx].keyword,
68608                   vlistptr->vars[varID].opt_grib_kvpair[idx].int_val);
68609         else if (vlistptr->vars[varID].opt_grib_kvpair[idx].data_type == t_double)
68610           Message("%s -> double %d",
68611                   vlistptr->vars[varID].opt_grib_kvpair[idx].keyword,
68612                   vlistptr->vars[varID].opt_grib_kvpair[idx].dbl_val);
68613         else
68614           Message("%s -> unknown", vlistptr->vars[varID].opt_grib_kvpair[idx].keyword);
68615     }
68616 
68617   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
68618 #else
68619   (void)vlistID;
68620   (void)varID;
68621   (void)name;
68622   (void)value;
68623 #endif
68624 }
68625 
68626 
68627 /* cdiClearAdditionalKeys: Clears the list of additional GRIB keys. */
cdiClearAdditionalKeys()68628 void cdiClearAdditionalKeys()
68629 {
68630 #ifdef HAVE_LIBGRIB_API
68631   for (int i = 0; i < cdiNAdditionalGRIBKeys; i++)  free(cdiAdditionalGRIBKeys[i]);
68632   cdiNAdditionalGRIBKeys = 0;
68633 #endif
68634 }
68635 
68636 /* cdiDefAdditionalKey: Register an additional GRIB key which is read when file is opened. */
cdiDefAdditionalKey(const char * name)68637 void cdiDefAdditionalKey(const char *name)
68638 {
68639 #ifdef HAVE_LIBGRIB_API
68640   int idx = cdiNAdditionalGRIBKeys;
68641   cdiNAdditionalGRIBKeys++;
68642   if ( idx >= MAX_OPT_GRIB_ENTRIES ) Error("Too many additional keywords!");
68643   if ( name )
68644     cdiAdditionalGRIBKeys[idx] = strdupx(name);
68645   else
68646     Error("Internal error!");
68647 #else
68648   (void)name;
68649 #endif
68650 }
68651 
68652 /* vlistHasVarKey: returns 1 if meta-data key was read, 0 otherwise. */
vlistHasVarKey(int vlistID,int varID,const char * name)68653 int vlistHasVarKey(int vlistID, int varID, const char* name)
68654 {
68655 #ifdef HAVE_LIBGRIB_API
68656   /* check if the GRIB key was previously read and is stored */
68657   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68658 
68659   for (int i=0; i<vlistptr->vars[varID].opt_grib_nentries; i++)
68660     {
68661       if ( strcmp(name, vlistptr->vars[varID].opt_grib_kvpair[i].keyword) == 0 )
68662 	return 1;
68663     }
68664 #else
68665   (void)vlistID;
68666   (void)varID;
68667   (void)name;
68668 #endif
68669   return 0;
68670 }
68671 
68672 /* vlistInqVarDblKey: raw access to GRIB meta-data */
vlistInqVarDblKey(int vlistID,int varID,const char * name)68673 double vlistInqVarDblKey(int vlistID, int varID, const char* name)
68674 {
68675   double value = 0;
68676 #ifdef HAVE_LIBGRIB_API
68677   /* check if the GRIB key was previously read and is stored in "opt_grib_dbl_val" */
68678   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68679 
68680   for (int i=0; i<vlistptr->vars[varID].opt_grib_nentries; i++)
68681     {
68682       int isub = subtypeInqActiveIndex(vlistptr->vars[varID].subtypeID);
68683       if ( (strcmp(name, vlistptr->vars[varID].opt_grib_kvpair[i].keyword) == 0 ) &&
68684            (vlistptr->vars[varID].opt_grib_kvpair[i].data_type == t_double)       &&
68685            (vlistptr->vars[varID].opt_grib_kvpair[i].subtype_index == isub) )
68686         return vlistptr->vars[varID].opt_grib_kvpair[i].dbl_val;
68687     }
68688 #else
68689   (void)vlistID;
68690   (void)varID;
68691   (void)name;
68692 #endif
68693   return value;
68694 }
68695 
68696 
68697 /* vlistInqVarIntKey: raw access to GRIB meta-data */
vlistInqVarIntKey(int vlistID,int varID,const char * name)68698 int vlistInqVarIntKey(int vlistID, int varID, const char* name)
68699 {
68700   long value = 0;
68701 #ifdef HAVE_LIBGRIB_API
68702   /* check if the GRIB key was previously read and is stored in "opt_grib_int_val" */
68703   vlist_t *vlistptr = vlist_to_pointer(vlistID);
68704 
68705   for (int i=0; i<vlistptr->vars[varID].opt_grib_nentries; i++)
68706     {
68707       int isub = subtypeInqActiveIndex(vlistptr->vars[varID].subtypeID);
68708       if ( (strcmp(name, vlistptr->vars[varID].opt_grib_kvpair[i].keyword) == 0 ) &&
68709            (vlistptr->vars[varID].opt_grib_kvpair[i].data_type == t_int)          &&
68710            (vlistptr->vars[varID].opt_grib_kvpair[i].subtype_index == isub) )
68711         return vlistptr->vars[varID].opt_grib_kvpair[i].int_val;
68712     }
68713 
68714 #else
68715   (void)vlistID;
68716   (void)varID;
68717   (void)name;
68718 #endif
68719   return (int) value;
68720 }
68721 
68722 /*
68723  * Local Variables:
68724  * c-file-style: "Java"
68725  * c-basic-offset: 2
68726  * indent-tabs-mode: nil
68727  * show-trailing-whitespace: t
68728  * require-trailing-newline: t
68729  * End:
68730  */
68731 #include <string.h>
68732 #include <math.h>
68733 #include <float.h>
68734 
68735 
68736 
68737 #define  LevelUp    1
68738 #define  LevelDown  2
68739 
68740 
68741 static const struct {
68742   unsigned char positive;   // 1: up;  2: down
68743   const char *name;
68744   const char *longname;
68745   const char *stdname;
68746   const char *units;
68747 }
68748 ZaxistypeEntry[] = {
68749   { /*  0 */ 0, "sfc",               "surface",                "",               ""},
68750   { /*  1 */ 0, "lev",               "generic",                "",               ""},
68751   { /*  2 */ 2, "lev",               "hybrid",                 "",               "level"},
68752   { /*  3 */ 2, "lev",               "hybrid_half",            "",               "level"},
68753   { /*  4 */ 2, "plev",              "pressure",               "air_pressure",   "Pa"},
68754   { /*  5 */ 1, "height",            "height",                 "height",         "m"},
68755   { /*  6 */ 2, "depth",             "depth_below_sea",        "depth",          "m"},
68756   { /*  7 */ 2, "depth",             "depth_below_land",       "",               "cm"},
68757   { /*  8 */ 0, "lev",               "isentropic",             "",               "K"},
68758   { /*  9 */ 0, "lev",               "trajectory",             "",               ""},
68759   { /* 10 */ 1, "alt",               "altitude",               "",               "m"},
68760   { /* 11 */ 0, "lev",               "sigma",                  "",               "level"},
68761   { /* 12 */ 0, "lev",               "meansea",                "",               "level"},
68762   { /* 13 */ 0, "toa",               "top_of_atmosphere",      "",               ""},
68763   { /* 14 */ 0, "seabottom",         "sea_bottom",             "",               ""},
68764   { /* 15 */ 0, "atmosphere",        "atmosphere",             "",               ""},
68765   { /* 16 */ 0, "cloudbase",         "cloud_base",             "",               ""},
68766   { /* 17 */ 0, "cloudtop",          "cloud_top",              "",               ""},
68767   { /* 18 */ 0, "isotherm0",         "isotherm_zero",          "",               ""},
68768   { /* 19 */ 0, "snow",              "snow",                   "",               ""},
68769   { /* 20 */ 0, "lakebottom",        "lake_bottom",            "",               ""},
68770   { /* 21 */ 0, "sedimentbottom",    "sediment_bottom",        "",               ""},
68771   { /* 22 */ 0, "sedimentbottomta",  "sediment_bottom_ta",     "",               ""},
68772   { /* 23 */ 0, "sedimentbottomtw",  "sediment_bottom_tw",     "",               ""},
68773   { /* 24 */ 0, "mixlayer",          "mix_layer",              "",               ""},
68774   { /* 25 */ 0, "height",            "generalized_height",     "height",         ""},
68775   { /* 26 */ 0, "character",         "area_type",              "",               ""},
68776   { /* 27 */ 0, "tropopause",        "tropopause",             "",               ""},
68777 };
68778 
68779 enum {
68780   CDI_NumZaxistype = sizeof(ZaxistypeEntry) / sizeof(ZaxistypeEntry[0]),
68781 };
68782 
68783 
68784 static int    zaxisCompareP    (zaxis_t *z1, zaxis_t *z2);
68785 static void   zaxisDestroyP    ( void * zaxisptr );
68786 static void   zaxisPrintP      ( void * zaxisptr, FILE * fp );
68787 static int    zaxisGetPackSize ( void * zaxisptr, void *context);
68788 static void   zaxisPack        ( void * zaxisptr, void * buffer, int size, int *pos, void *context);
68789 static int    zaxisTxCode      ( void );
68790 
68791 static const resOps zaxisOps = {
68792   (int (*)(void *, void *))zaxisCompareP,
68793   zaxisDestroyP,
68794   zaxisPrintP,
68795   zaxisGetPackSize,
68796   zaxisPack,
68797   zaxisTxCode
68798 };
68799 
getZaxisOps(void)68800 const resOps *getZaxisOps(void)
68801 {
68802   return &zaxisOps;
68803 }
68804 
68805 static int  ZAXIS_Debug = 0;   /* If set to 1, debugging */
68806 
zaxisGetTypeDescription(int zaxisType,int * outPositive,const char ** outName,const char ** outLongName,const char ** outStdName,const char ** outUnit)68807 void zaxisGetTypeDescription(int zaxisType, int *outPositive, const char **outName, const char **outLongName, const char **outStdName, const char **outUnit)
68808 {
68809   if ( zaxisType < 0 || zaxisType >= CDI_NumZaxistype )
68810     {
68811       if (outPositive) *outPositive = 0;
68812       if (outName) *outName = NULL;
68813       if (outLongName) *outLongName = NULL;
68814       if (outStdName) *outStdName = NULL;
68815       if (outUnit) *outUnit = NULL;
68816     }
68817   else
68818     {
68819       if (outPositive) *outPositive = ZaxistypeEntry[zaxisType].positive;
68820       if (outName) *outName = ZaxistypeEntry[zaxisType].name;
68821       if (outLongName && zaxisType != ZAXIS_GENERIC) *outLongName = ZaxistypeEntry[zaxisType].longname;
68822       if (outStdName) *outStdName = ZaxistypeEntry[zaxisType].stdname;
68823       if (outUnit) *outUnit = ZaxistypeEntry[zaxisType].units;
68824     }
68825 }
68826 
68827 
zaxis_to_pointer(int id)68828 zaxis_t *zaxis_to_pointer(int id)
68829 {
68830   return (zaxis_t *)reshGetVal(id, &zaxisOps);
68831 }
68832 
68833 static
zaxis_init(zaxis_t * zaxisptr)68834 void zaxis_init(zaxis_t *zaxisptr)
68835 {
68836   zaxisptr->self          = CDI_UNDEFID;
68837   zaxisptr->vals          = NULL;
68838 #ifndef USE_MPI
68839   zaxisptr->cvals         = NULL;
68840   zaxisptr->clength       = 0;
68841 #endif
68842   zaxisptr->ubounds       = NULL;
68843   zaxisptr->lbounds       = NULL;
68844   zaxisptr->weights       = NULL;
68845   zaxisptr->type          = CDI_UNDEFID;
68846   zaxisptr->positive      = 0;
68847   zaxisptr->scalar        = 0;
68848   zaxisptr->direction     = 0;
68849   zaxisptr->datatype      = CDI_DATATYPE_FLT64;
68850   zaxisptr->size          = 0;
68851   zaxisptr->vctsize       = 0;
68852   zaxisptr->vct           = NULL;
68853 
68854   cdiInitKeys(&zaxisptr->keys);
68855   zaxisptr->atts.nalloc    = MAX_ATTRIBUTES;
68856   zaxisptr->atts.nelems    = 0;
68857 }
68858 
68859 static
zaxisNewEntry(int id)68860 zaxis_t *zaxisNewEntry(int id)
68861 {
68862   zaxis_t *zaxisptr = (zaxis_t *) Malloc(sizeof(zaxis_t));
68863   zaxis_init(zaxisptr);
68864 
68865   if ( id == CDI_UNDEFID )
68866     zaxisptr->self = reshPut(zaxisptr, &zaxisOps);
68867   else
68868     {
68869       zaxisptr->self = id;
68870       reshReplace(id, zaxisptr, &zaxisOps);
68871     }
68872 
68873   return zaxisptr;
68874 }
68875 
68876 static
zaxisInit(void)68877 void zaxisInit(void)
68878 {
68879   static bool zaxisInitialized = false;
68880   if ( zaxisInitialized ) return;
68881   zaxisInitialized = true;
68882 
68883   const char *env = getenv("ZAXIS_DEBUG");
68884   if ( env ) ZAXIS_Debug = atoi(env);
68885 }
68886 
68887 static
zaxis_copy(zaxis_t * zaxisptr2,zaxis_t * zaxisptr1)68888 void zaxis_copy(zaxis_t *zaxisptr2, zaxis_t *zaxisptr1)
68889 {
68890   const int zaxisID2 = zaxisptr2->self;
68891   memcpy(zaxisptr2, zaxisptr1, sizeof(zaxis_t));
68892   zaxisptr2->self = zaxisID2;
68893   cdiInitKeys(&zaxisptr2->keys);
68894   cdiCopyVarKeys(&zaxisptr1->keys, &zaxisptr2->keys);
68895 }
68896 
68897 
cdiZaxisCount(void)68898 unsigned cdiZaxisCount(void)
68899 {
68900   return reshCountType(&zaxisOps);
68901 }
68902 
68903 static
zaxisCreate_(int zaxistype,int size,int id)68904 int zaxisCreate_(int zaxistype, int size, int id)
68905 {
68906   zaxis_t *zaxisptr = zaxisNewEntry(id);
68907 
68908   xassert(size >= 0);
68909   zaxisptr->type = zaxistype;
68910   zaxisptr->size = size;
68911 
68912   if ( zaxistype >= CDI_NumZaxistype || zaxistype < 0 )
68913     Error("Internal problem! zaxistype=%d out of range (min=0/max=%d)!", zaxistype, CDI_NumZaxistype-1);
68914 
68915   const int zaxisID = zaxisptr->self;
68916   cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_NAME, ZaxistypeEntry[zaxistype].name);
68917   if ( zaxistype != ZAXIS_GENERIC ) zaxisDefLongname(zaxisID, ZaxistypeEntry[zaxistype].longname);
68918   cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, ZaxistypeEntry[zaxistype].units);
68919 
68920   const char *stdname = ZaxistypeEntry[zaxistype].stdname;
68921   if ( *stdname )
68922     cdiDefVarKeyBytes(&zaxisptr->keys, CDI_KEY_STDNAME, (const unsigned char*)stdname, (int)strlen(stdname)+1);
68923 
68924   zaxisptr->positive = ZaxistypeEntry[zaxistype].positive;
68925 
68926   return zaxisID;
68927 }
68928 
68929 /*
68930 @Function  zaxisCreate
68931 @Title     Create a vertical Z-axis
68932 
68933 @Prototype int zaxisCreate(int zaxistype, int size)
68934 @Parameter
68935     @Item  zaxistype  The type of the Z-axis, one of the set of predefined CDI Z-axis types.
68936                       The valid CDI Z-axis types are @func{ZAXIS_GENERIC}, @func{ZAXIS_SURFACE},
68937                       @func{ZAXIS_HYBRID}, @func{ZAXIS_SIGMA}, @func{ZAXIS_PRESSURE}, @func{ZAXIS_HEIGHT},
68938                       @func{ZAXIS_ISENTROPIC}, @func{ZAXIS_ALTITUDE}, @func{ZAXIS_MEANSEA}, @func{ZAXIS_TOA},
68939                       @func{ZAXIS_SEA_BOTTOM}, @func{ZAXIS_ATMOSPHERE}, @func{ZAXIS_CLOUD_BASE},
68940                       @func{ZAXIS_CLOUD_TOP}, @func{ZAXIS_ISOTHERM_ZERO}, @func{ZAXIS_SNOW},
68941                       @func{ZAXIS_LAKE_BOTTOM}, @func{ZAXIS_SEDIMENT_BOTTOM}, @func{ZAXIS_SEDIMENT_BOTTOM_TA},
68942                       @func{ZAXIS_SEDIMENT_BOTTOM_TW}, @func{ZAXIS_MIX_LAYER},
68943                       @func{ZAXIS_DEPTH_BELOW_SEA} and @func{ZAXIS_DEPTH_BELOW_LAND}.
68944     @Item  size       Number of levels.
68945 
68946 @Description
68947 The function @func{zaxisCreate} creates a vertical Z-axis.
68948 
68949 @Result
68950 @func{zaxisCreate} returns an identifier to the Z-axis.
68951 
68952 @Example
68953 Here is an example using @func{zaxisCreate} to create a pressure level Z-axis:
68954 
68955 @Source
68956    ...
68957 #define  nlev    5
68958    ...
68959 double levs[nlev] = {101300, 92500, 85000, 50000, 20000};
68960 int zaxisID;
68961    ...
68962 zaxisID = zaxisCreate(ZAXIS_PRESSURE, nlev);
68963 zaxisDefLevels(zaxisID, levs);
68964    ...
68965 @EndSource
68966 @EndFunction
68967 */
zaxisCreate(int zaxistype,int size)68968 int zaxisCreate(int zaxistype, int size)
68969 {
68970   if ( CDI_Debug ) Message("zaxistype: %d size: %d ", zaxistype, size);
68971 
68972   xassert(size);
68973   zaxisInit();
68974 
68975   return zaxisCreate_(zaxistype, size, CDI_UNDEFID);
68976 }
68977 
68978 static
zaxisDestroyKernel(zaxis_t * zaxisptr)68979 void zaxisDestroyKernel( zaxis_t * zaxisptr )
68980 {
68981   xassert ( zaxisptr );
68982 
68983   const int id = zaxisptr->self;
68984 
68985   if ( zaxisptr->vals ) Free( zaxisptr->vals );
68986 #ifndef USE_MPI
68987   if ( zaxisptr->cvals )
68988     {
68989       for ( int i=0; i<zaxisptr->size; i++)
68990         Free(zaxisptr->cvals[i]);
68991       Free( zaxisptr->cvals );
68992     }
68993 #endif
68994   if ( zaxisptr->lbounds ) Free( zaxisptr->lbounds );
68995   if ( zaxisptr->ubounds ) Free( zaxisptr->ubounds );
68996   if ( zaxisptr->weights ) Free( zaxisptr->weights );
68997   if ( zaxisptr->vct )     Free( zaxisptr->vct );
68998 
68999   cdiDeleteKeys(id, CDI_GLOBAL);
69000   cdiDeleteAtts(id, CDI_GLOBAL);
69001 
69002   Free(zaxisptr);
69003 
69004   reshRemove(id, &zaxisOps);
69005 }
69006 
69007 /*
69008 @Function  zaxisDestroy
69009 @Title     Destroy a vertical Z-axis
69010 
69011 @Prototype void zaxisDestroy(int zaxisID)
69012 @Parameter
69013     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate}.
69014 
69015 @EndFunction
69016 */
zaxisDestroy(int zaxisID)69017 void zaxisDestroy(int zaxisID)
69018 {
69019   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69020   zaxisDestroyKernel(zaxisptr);
69021 }
69022 
69023 
69024 static
zaxisDestroyP(void * zaxisptr)69025 void zaxisDestroyP(void *zaxisptr)
69026 {
69027   zaxisDestroyKernel((zaxis_t *) zaxisptr);
69028 }
69029 
69030 
zaxisNamePtr(int zaxistype)69031 const char *zaxisNamePtr(int zaxistype)
69032 {
69033   const char *name = (zaxistype >= 0 && zaxistype < CDI_NumZaxistype)
69034     ? ZaxistypeEntry[zaxistype].longname
69035     : ZaxistypeEntry[ZAXIS_GENERIC].longname;
69036   return name;
69037 }
69038 
69039 
zaxisName(int zaxistype,char * zaxisname)69040 void zaxisName(int zaxistype, char *zaxisname)
69041 {
69042   strcpy(zaxisname, zaxisNamePtr(zaxistype));
69043 }
69044 
69045 /*
69046 @Function  zaxisDefName
69047 @Title     Define the name of a Z-axis
69048 
69049 @Prototype void zaxisDefName(int zaxisID, const char *name)
69050 @Parameter
69051     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate}.
69052     @Item  name     Name of the Z-axis.
69053 
69054 @Description
69055 The function @func{zaxisDefName} defines the name of a Z-axis.
69056 
69057 @EndFunction
69058 */
zaxisDefName(int zaxisID,const char * name)69059 void zaxisDefName(int zaxisID, const char *name)
69060 {
69061   (void)cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_NAME, name);
69062 }
69063 
69064 /*
69065 @Function  zaxisDefLongname
69066 @Title     Define the longname of a Z-axis
69067 
69068 @Prototype void zaxisDefLongname(int zaxisID, const char *longname)
69069 @Parameter
69070     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate}.
69071     @Item  longname Longname of the Z-axis.
69072 
69073 @Description
69074 The function @func{zaxisDefLongname} defines the longname of a Z-axis.
69075 
69076 @EndFunction
69077 */
zaxisDefLongname(int zaxisID,const char * longname)69078 void zaxisDefLongname(int zaxisID, const char *longname)
69079 {
69080   (void)cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_LONGNAME, longname);
69081 }
69082 
69083 /*
69084 @Function  zaxisDefUnits
69085 @Title     Define the units of a Z-axis
69086 
69087 @Prototype void zaxisDefUnits(int zaxisID, const char *units)
69088 @Parameter
69089     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate}.
69090     @Item  units    Units of the Z-axis.
69091 
69092 @Description
69093 The function @func{zaxisDefUnits} defines the units of a Z-axis.
69094 
69095 @EndFunction
69096 */
zaxisDefUnits(int zaxisID,const char * units)69097 void zaxisDefUnits(int zaxisID, const char *units)
69098 {
69099   (void)cdiDefKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, units);
69100 }
69101 
69102 /*
69103 @Function  zaxisInqName
69104 @Title     Get the name of a Z-axis
69105 
69106 @Prototype void zaxisInqName(int zaxisID, char *name)
69107 @Parameter
69108     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate} or @fref{vlistInqVarZaxis}.
69109     @Item  name     Name of the Z-axis. The caller must allocate space for the
69110                     returned string. The maximum possible length, in characters, of
69111                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
69112 
69113 @Description
69114 The function @func{zaxisInqName} returns the name of a Z-axis.
69115 
69116 @Result
69117 @func{zaxisInqName} returns the name of the Z-axis to the parameter name.
69118 
69119 @EndFunction
69120 */
zaxisInqName(int zaxisID,char * name)69121 void zaxisInqName(int zaxisID, char *name)
69122 {
69123   int length = CDI_MAX_NAME;
69124   (void)cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_NAME, name, &length);
69125 }
69126 
zaxisInqNamePtr(int zaxisID)69127 const char *zaxisInqNamePtr(int zaxisID)
69128 {
69129   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69130   return cdiInqVarKeyString(&zaxisptr->keys, CDI_KEY_NAME);
69131 }
69132 
69133 /*
69134 @Function  zaxisInqLongname
69135 @Title     Get the longname of a Z-axis
69136 
69137 @Prototype void zaxisInqLongname(int zaxisID, char *longname)
69138 @Parameter
69139     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate} or @fref{vlistInqVarZaxis}.
69140     @Item  longname Longname of the Z-axis. The caller must allocate space for the
69141                     returned string. The maximum possible length, in characters, of
69142                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
69143 
69144 @Description
69145 The function @func{zaxisInqLongname} returns the longname of a Z-axis.
69146 
69147 @Result
69148 @func{zaxisInqLongname} returns the longname of the Z-axis to the parameter longname.
69149 
69150 @EndFunction
69151 */
zaxisInqLongname(int zaxisID,char * longname)69152 void zaxisInqLongname(int zaxisID, char *longname)
69153 {
69154   int length = CDI_MAX_NAME;
69155   (void)cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_LONGNAME, longname, &length);
69156 }
69157 
69158 /*
69159 @Function  zaxisInqUnits
69160 @Title     Get the units of a Z-axis
69161 
69162 @Prototype void zaxisInqUnits(int zaxisID, char *units)
69163 @Parameter
69164     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate} or @fref{vlistInqVarZaxis}.
69165     @Item  units    Units of the Z-axis. The caller must allocate space for the
69166                     returned string. The maximum possible length, in characters, of
69167                     the string is given by the predefined constant @func{CDI_MAX_NAME}.
69168 
69169 @Description
69170 The function @func{zaxisInqUnits} returns the units of a Z-axis.
69171 
69172 @Result
69173 @func{zaxisInqUnits} returns the units of the Z-axis to the parameter units.
69174 
69175 @EndFunction
69176 */
zaxisInqUnits(int zaxisID,char * units)69177 void zaxisInqUnits(int zaxisID, char *units)
69178 {
69179   int length = CDI_MAX_NAME;
69180   (void)cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_UNITS, units, &length);
69181 }
69182 
69183 
zaxisInqStdname(int zaxisID,char * stdname)69184 void zaxisInqStdname(int zaxisID, char *stdname)
69185 {
69186   int length = CDI_MAX_NAME;
69187   (void)cdiInqKeyString(zaxisID, CDI_GLOBAL, CDI_KEY_STDNAME, stdname, &length);
69188 }
69189 
69190 
zaxisDefDatatype(int zaxisID,int datatype)69191 void zaxisDefDatatype(int zaxisID, int datatype)
69192 {
69193   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69194 
69195   if ( zaxisptr->datatype != datatype )
69196     {
69197       zaxisptr->datatype = datatype;
69198       reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
69199     }
69200 }
69201 
69202 
zaxisInqDatatype(int zaxisID)69203 int zaxisInqDatatype(int zaxisID)
69204 {
69205   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69206   return zaxisptr->datatype;
69207 }
69208 
69209 
zaxisDefPositive(int zaxisID,int positive)69210 void zaxisDefPositive(int zaxisID, int positive)
69211 {
69212   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69213 
69214   if ( zaxisptr->positive != (unsigned)positive )
69215     {
69216       zaxisptr->positive = (unsigned)positive;
69217       reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
69218     }
69219 }
69220 
69221 
zaxisInqPositive(int zaxisID)69222 int zaxisInqPositive(int zaxisID)
69223 {
69224   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69225   return (int)zaxisptr->positive;
69226 }
69227 
69228 
zaxisDefScalar(int zaxisID)69229 void zaxisDefScalar(int zaxisID)
69230 {
69231   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69232 
69233   zaxisptr->scalar = 1;
69234   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
69235 }
69236 
zaxisInqScalar(int zaxisID)69237 int zaxisInqScalar(int zaxisID)
69238 {
69239   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69240   return zaxisptr->scalar;
69241 }
69242 
69243 /*
69244 @Function  zaxisDefLevels
69245 @Title     Define the levels of a Z-axis
69246 
69247 @Prototype void zaxisDefLevels(int zaxisID, const double *levels)
69248 @Parameter
69249     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate}.
69250     @Item  levels   All levels of the Z-axis.
69251 
69252 @Description
69253 The function @func{zaxisDefLevels} defines the levels of a Z-axis.
69254 
69255 @EndFunction
69256 */
zaxisDefLevels(int zaxisID,const double * levels)69257 void zaxisDefLevels(int zaxisID, const double *levels)
69258 {
69259   if ( levels )
69260     {
69261       zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69262       const size_t size = (size_t)zaxisptr->size;
69263       xassert(size);
69264 
69265       if (zaxisptr->vals == NULL && size)
69266         zaxisptr->vals = (double*) Malloc(size*sizeof(double));
69267 
69268       double *vals = zaxisptr->vals;
69269 
69270       for ( size_t ilev = 0; ilev < size; ++ilev )
69271         vals[ilev] = levels[ilev];
69272 
69273       reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
69274     }
69275 }
69276 
69277 
zaxisDefCvals(int zaxisID,const char ** cvals,int clen)69278 void zaxisDefCvals(int zaxisID, const char **cvals, int clen)
69279 {
69280 #ifndef USE_MPI
69281   if ( cvals && clen )
69282     {
69283       zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69284       const size_t size = zaxisptr->size;
69285       xassert(size);
69286 
69287       zaxisptr->clength = clen;
69288       if (size) zaxisptr->cvals = (char**) Malloc(size*sizeof(char *));
69289 
69290       for ( size_t ilev = 0; ilev < size; ++ilev )
69291         {
69292           zaxisptr->cvals[ilev] = (char*) Malloc(clen*sizeof(char));
69293           memcpy(zaxisptr->cvals[ilev], cvals[ilev], clen*sizeof(char));
69294         }
69295       reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
69296     }
69297 #else
69298   Error("This function was disabled!");
69299 #endif
69300 }
69301 
69302 /*
69303 @Function  zaxisDefLevel
69304 @Title     Define one level of a Z-axis
69305 
69306 @Prototype void zaxisDefLevel(int zaxisID, int levelID, double level)
69307 @Parameter
69308     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate}.
69309     @Item  levelID  Level identifier.
69310     @Item  level    Level.
69311 
69312 @Description
69313 The function @func{zaxisDefLevel} defines one level of a Z-axis.
69314 
69315 @EndFunction
69316 */
zaxisDefLevel(int zaxisID,int levelID,double level)69317 void zaxisDefLevel(int zaxisID, int levelID, double level)
69318 {
69319   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69320   const int size = zaxisptr->size;
69321   xassert(size);
69322   xassert(levelID >= 0 && levelID < size);
69323 
69324   if (zaxisptr->vals == NULL && size)
69325     zaxisptr->vals = (double*) Malloc((size_t)size*sizeof(double));
69326 
69327   if ( levelID >= 0 && levelID < size )
69328     zaxisptr->vals[levelID] = level;
69329 
69330   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
69331 }
69332 
69333 
zaxisDefNlevRef(int zaxisID,int nlev)69334 void zaxisDefNlevRef(int zaxisID, int nlev)
69335 {
69336   cdiDefKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_NLEV, nlev);
69337 }
69338 
69339 
zaxisInqNlevRef(int zaxisID)69340 int zaxisInqNlevRef(int zaxisID)
69341 {
69342   int nlev = 0;
69343   cdiInqKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_NLEV, &nlev);
69344   return nlev;
69345 }
69346 
69347 /*
69348 @Function  zaxisDefNumber
69349 @Title     Define the reference number for a generalized Z-axis
69350 
69351 @Prototype void zaxisDefNumber(int zaxisID, int number)
69352 @Parameter
69353     @Item  zaxisID     Z-axis ID, from a previous call to @fref{zaxisCreate}.
69354     @Item  number      Reference number for a generalized Z-axis.
69355 
69356 @Description
69357 The function @func{zaxisDefNumber} defines the reference number for a generalized Z-axis.
69358 
69359 @EndFunction
69360 */
zaxisDefNumber(int zaxisID,int number)69361 void zaxisDefNumber(int zaxisID, int number)
69362 {
69363   cdiDefKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_NUMBEROFVGRIDUSED, number);
69364 }
69365 
69366 /*
69367 @Function  zaxisInqNumber
69368 @Title     Get the reference number to a generalized Z-axis
69369 
69370 @Prototype int zaxisInqNumber(int zaxisID)
69371 @Parameter
69372     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate} or @fref{vlistInqVarZaxis}.
69373 
69374 @Description
69375 The function @func{zaxisInqNumber} returns the reference number to a generalized Z-axis.
69376 
69377 @Result
69378 @func{zaxisInqNumber} returns the reference number to a generalized Z-axis.
69379 @EndFunction
69380 */
zaxisInqNumber(int zaxisID)69381 int zaxisInqNumber(int zaxisID)
69382 {
69383   int referenceNumber = 0;
69384   cdiInqKeyInt(zaxisID, CDI_GLOBAL, CDI_KEY_NUMBEROFVGRIDUSED, &referenceNumber);
69385   return referenceNumber;
69386 }
69387 
69388 /*
69389 @Function  zaxisDefUUID
69390 @Title     Define the UUID for a genralized Z-axis
69391 
69392 @Prototype void zaxisDefUUID(int zaxisID, const char *uuid)
69393 @Parameter
69394     @Item  zaxisID     Z-axis ID, from a previous call to @fref{zaxisCreate}.
69395     @Item  uuid        UUID for a generalized Z-axis.
69396 
69397 @Description
69398 The function @func{zaxisDefUUID} defines the UUID for a generalized  Z-axis.
69399 
69400 @EndFunction
69401 */
zaxisDefUUID(int zaxisID,const unsigned char uuid[CDI_UUID_SIZE])69402 void zaxisDefUUID(int zaxisID, const unsigned char uuid[CDI_UUID_SIZE])
69403 {
69404   cdiDefKeyBytes(zaxisID, CDI_GLOBAL, CDI_KEY_UUID, uuid, CDI_UUID_SIZE);
69405 
69406   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
69407 }
69408 
69409 /*
69410 @Function  zaxisInqUUID
69411 @Title     Get the uuid to a generalized Z-axis
69412 
69413 @Prototype void zaxisInqUUID(int zaxisID, char *uuid)
69414 @Parameter
69415     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate} or @fref{vlistInqVarZaxis}.
69416     @Item uuid A user supplied buffer of at least 16 bytes.
69417 
69418 @Description
69419 The function @func{zaxisInqUUID} returns the UUID to a generalized Z-axis.
69420 
69421 @Result
69422 @func{zaxisInqUUID} returns the UUID to a generalized Z-axis to the parameter uuid.
69423 @EndFunction
69424 */
zaxisInqUUID(int zaxisID,unsigned char uuid[CDI_UUID_SIZE])69425 void zaxisInqUUID(int zaxisID, unsigned char uuid[CDI_UUID_SIZE])
69426 {
69427   memset(uuid, 0, CDI_UUID_SIZE);
69428   int length = CDI_UUID_SIZE;
69429   cdiInqKeyBytes(zaxisID, CDI_GLOBAL, CDI_KEY_UUID, uuid, &length);
69430 }
69431 
69432 /*
69433 @Function  zaxisInqLevel
69434 @Title     Get one level of a Z-axis
69435 
69436 @Prototype double zaxisInqLevel(int zaxisID, int levelID)
69437 @Parameter
69438     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate} or @fref{vlistInqVarZaxis}.
69439     @Item  levelID  Level index (range: 0 to nlevel-1).
69440 
69441 @Description
69442 The function @func{zaxisInqLevel} returns one level of a Z-axis.
69443 
69444 @Result
69445 @func{zaxisInqLevel} returns the level of a Z-axis.
69446 @EndFunction
69447 */
zaxisInqLevel(int zaxisID,int levelID)69448 double zaxisInqLevel(int zaxisID, int levelID)
69449 {
69450   double level = 0;
69451   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69452   if ( zaxisptr->vals && levelID >= 0 && levelID < zaxisptr->size )
69453     level = zaxisptr->vals[levelID];
69454 
69455   return level;
69456 }
69457 
69458 
zaxisInqLbound(int zaxisID,int levelID)69459 double zaxisInqLbound(int zaxisID, int levelID)
69460 {
69461   double level = 0;
69462   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69463   if ( zaxisptr->lbounds && levelID >= 0 && levelID < zaxisptr->size )
69464     level = zaxisptr->lbounds[levelID];
69465 
69466   return level;
69467 }
69468 
69469 
zaxisInqUbound(int zaxisID,int levelID)69470 double zaxisInqUbound(int zaxisID, int levelID)
69471 {
69472   double level = 0;
69473   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69474   if ( zaxisptr->ubounds && levelID >= 0 && levelID < zaxisptr->size )
69475     level = zaxisptr->ubounds[levelID];
69476 
69477   return level;
69478 }
69479 
69480 
zaxisInqLevelsPtr(int zaxisID)69481 const double *zaxisInqLevelsPtr(int zaxisID)
69482 {
69483   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69484   return zaxisptr->vals;
69485 }
69486 
69487 
69488 #ifndef USE_MPI
zaxisInqCValsPtr(int zaxisID)69489 char **zaxisInqCValsPtr(int zaxisID)
69490 {
69491   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69492   return zaxisptr->cvals;
69493 }
69494 #endif
69495 
69496 /*
69497 @Function  zaxisInqLevels
69498 @Title     Get all levels of a Z-axis
69499 
69500 @Prototype void zaxisInqLevels(int zaxisID, double *levels)
69501 @Parameter
69502     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate} or @fref{vlistInqVarZaxis}.
69503     @Item  levels   Pointer to the location into which the levels are read.
69504                     The caller must allocate space for the returned values.
69505 
69506 @Description
69507 The function @func{zaxisInqLevels} returns all levels of a Z-axis.
69508 
69509 @Result
69510 @func{zaxisInqLevels} saves all levels to the parameter @func{levels}.
69511 @EndFunction
69512 */
zaxisInqLevels(int zaxisID,double * levels)69513 int zaxisInqLevels(int zaxisID, double *levels)
69514 {
69515   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69516 
69517   int size = 0;
69518   if ( zaxisptr->vals )
69519     {
69520       size = zaxisptr->size;
69521 
69522       if ( levels )
69523         for ( int i = 0; i < size; i++ )
69524           levels[i] = zaxisptr->vals[i];
69525     }
69526 
69527   return size;
69528 }
69529 
69530 
zaxisInqCLen(int zaxisID)69531 int zaxisInqCLen(int zaxisID)
69532 {
69533   int clen = 0;
69534 #ifndef USE_MPI
69535   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69536   if ( zaxisptr->cvals && zaxisptr->clength)
69537     clen = zaxisptr->clength;
69538 #endif
69539 
69540   return clen;
69541 }
69542 
69543 
zaxisInqCVals(int zaxisID,char *** clevels)69544 int zaxisInqCVals(int zaxisID, char ***clevels)
69545 {
69546   int size = 0;
69547 #ifndef USE_MPI
69548   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69549   if ( zaxisptr->cvals )
69550     {
69551       size = zaxisptr->size;
69552       const size_t clen = zaxisptr->clength;
69553       if ( size && clen )
69554         {
69555           (*clevels) = (char**) Malloc(size*sizeof(char*));
69556           for ( int i = 0; i < size; i++ )
69557             {
69558               (*clevels)[i] = (char*) Malloc(clen*sizeof(char));
69559               memcpy((*clevels)[i], zaxisptr->cvals[i], clen*sizeof(char));
69560             }
69561           }
69562     }
69563 #endif
69564 
69565   return size;
69566 }
69567 
69568 
zaxisInqLbounds(int zaxisID,double * lbounds)69569 int zaxisInqLbounds(int zaxisID, double *lbounds)
69570 {
69571   int size = 0;
69572   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69573   if ( zaxisptr->lbounds )
69574     {
69575       size = zaxisptr->size;
69576 
69577       if ( lbounds )
69578         for ( int i = 0; i < size; i++ )
69579           lbounds[i] = zaxisptr->lbounds[i];
69580     }
69581 
69582   return size;
69583 }
69584 
69585 
zaxisInqUbounds(int zaxisID,double * ubounds)69586 int zaxisInqUbounds(int zaxisID, double *ubounds)
69587 {
69588   int size = 0;
69589   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69590   if ( zaxisptr->ubounds )
69591     {
69592       size = zaxisptr->size;
69593 
69594       if ( ubounds )
69595         for ( int i = 0; i < size; i++ )
69596           ubounds[i] = zaxisptr->ubounds[i];
69597     }
69598 
69599   return size;
69600 }
69601 
69602 
zaxisInqWeights(int zaxisID,double * weights)69603 int zaxisInqWeights(int zaxisID, double *weights)
69604 {
69605   int size = 0;
69606   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69607   if ( zaxisptr->weights )
69608     {
69609       size = zaxisptr->size;
69610 
69611       if ( weights )
69612         for ( int i = 0; i < size; i++ )
69613           weights[i] = zaxisptr->weights[i];
69614     }
69615 
69616   return size;
69617 }
69618 
69619 
zaxisInqLevelID(int zaxisID,double level)69620 int zaxisInqLevelID(int zaxisID, double level)
69621 {
69622   int levelID = CDI_UNDEFID;
69623   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69624   if ( zaxisptr->vals )
69625     {
69626       const int size = zaxisptr->size;
69627       for ( int i = 0; i < size; i++ )
69628         if ( fabs(level-zaxisptr->vals[i]) < DBL_EPSILON )
69629           {
69630             levelID = i;
69631             break;
69632           }
69633     }
69634 
69635   return levelID;
69636 }
69637 
69638 /*
69639 @Function  zaxisInqType
69640 @Title     Get the type of a Z-axis
69641 
69642 @Prototype int zaxisInqType(int zaxisID)
69643 @Parameter
69644     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate} or @fref{vlistInqVarZaxis}.
69645 
69646 @Description
69647 The function @func{zaxisInqType} returns the type of a Z-axis.
69648 
69649 @Result
69650 @func{zaxisInqType} returns the type of the Z-axis,
69651 one of the set of predefined CDI Z-axis types.
69652 The valid CDI Z-axis types are @func{ZAXIS_GENERIC}, @func{ZAXIS_SURFACE},
69653 @func{ZAXIS_HYBRID}, @func{ZAXIS_SIGMA}, @func{ZAXIS_PRESSURE}, @func{ZAXIS_HEIGHT},
69654 @func{ZAXIS_ISENTROPIC}, @func{ZAXIS_ALTITUDE}, @func{ZAXIS_MEANSEA}, @func{ZAXIS_TOA},
69655 @func{ZAXIS_SEA_BOTTOM}, @func{ZAXIS_ATMOSPHERE}, @func{ZAXIS_CLOUD_BASE},
69656 @func{ZAXIS_CLOUD_TOP}, @func{ZAXIS_ISOTHERM_ZERO}, @func{ZAXIS_SNOW},
69657 @func{ZAXIS_LAKE_BOTTOM}, @func{ZAXIS_SEDIMENT_BOTTOM}, @func{ZAXIS_SEDIMENT_BOTTOM_TA},
69658 @func{ZAXIS_SEDIMENT_BOTTOM_TW}, @func{ZAXIS_MIX_LAYER},
69659 @func{ZAXIS_DEPTH_BELOW_SEA} and @func{ZAXIS_DEPTH_BELOW_LAND}.
69660 
69661 @EndFunction
69662 */
zaxisInqType(int zaxisID)69663 int zaxisInqType(int zaxisID)
69664 {
69665   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69666   return zaxisptr->type;
69667 }
69668 
69669 /*
69670 @Function  zaxisInqSize
69671 @Title     Get the size of a Z-axis
69672 
69673 @Prototype int zaxisInqSize(int zaxisID)
69674 @Parameter
69675     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate} or @fref{vlistInqVarZaxis}.
69676 
69677 @Description
69678 The function @func{zaxisInqSize} returns the size of a Z-axis.
69679 
69680 @Result
69681 @func{zaxisInqSize} returns the number of levels of a Z-axis.
69682 
69683 @EndFunction
69684 */
zaxisInqSize(int zaxisID)69685 int zaxisInqSize(int zaxisID)
69686 {
69687   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69688   return zaxisptr->size;
69689 }
69690 
69691 
cdiCheckZaxis(int zaxisID)69692 void cdiCheckZaxis(int zaxisID)
69693 {
69694   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69695 
69696   if ( zaxisInqType(zaxisID) == ZAXIS_GENERIC && zaxisptr->vals )
69697     {
69698       const int size = zaxisptr->size;
69699       if ( size > 1 )
69700         {
69701           /* check direction */
69702           if ( ! zaxisptr->direction )
69703             {
69704               int ups = 0, downs = 0;
69705               for ( int i = 1; i < size; i++ )
69706                 {
69707                   ups += (zaxisptr->vals[i] > zaxisptr->vals[i-1]);
69708                   downs += (zaxisptr->vals[i] < zaxisptr->vals[i-1]);
69709                 }
69710               if ( ups == size-1 )
69711                 {
69712                   zaxisptr->direction = LevelUp;
69713                 }
69714               else if ( downs == size-1 )
69715                 {
69716                   zaxisptr->direction = LevelDown;
69717                 }
69718               else /* !zaxisptr->direction */
69719                 {
69720                   Warning("Direction undefined for zaxisID %d", zaxisID);
69721                 }
69722             }
69723         }
69724     }
69725 }
69726 
69727 
zaxisDefVct(int zaxisID,int size,const double * vct)69728 void zaxisDefVct(int zaxisID, int size, const double *vct)
69729 {
69730   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69731 
69732   if ( zaxisptr->vct == 0 || zaxisptr->vctsize != size )
69733     {
69734       zaxisptr->vctsize = size;
69735       zaxisptr->vct = (double *) Realloc(zaxisptr->vct, (size_t)size*sizeof(double));
69736     }
69737 
69738   if (vct) memcpy(zaxisptr->vct, vct, (size_t)size*sizeof(double));
69739   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
69740 }
69741 
69742 
zaxisInqVct(int zaxisID,double * vct)69743 void zaxisInqVct(int zaxisID, double *vct)
69744 {
69745   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69746   memcpy(vct, zaxisptr->vct, (size_t)zaxisptr->vctsize * sizeof (double));
69747 }
69748 
69749 
zaxisInqVctSize(int zaxisID)69750 int zaxisInqVctSize(int zaxisID)
69751 {
69752   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69753   return zaxisptr->vctsize;
69754 }
69755 
69756 
zaxisInqVctPtr(int zaxisID)69757 const double *zaxisInqVctPtr(int zaxisID)
69758 {
69759   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69760   return zaxisptr->vct;
69761 }
69762 
69763 
zaxisDefLbounds(int zaxisID,const double * lbounds)69764 void zaxisDefLbounds(int zaxisID, const double *lbounds)
69765 {
69766   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69767 
69768   const size_t size = (size_t)zaxisptr->size;
69769 
69770   if ( CDI_Debug )
69771     if ( zaxisptr->lbounds )
69772       Warning("Lower bounds already defined for zaxisID = %d", zaxisID);
69773 
69774   if ( zaxisptr->lbounds == NULL )
69775     zaxisptr->lbounds = (double *) Malloc(size*sizeof(double));
69776 
69777   if (lbounds) memcpy(zaxisptr->lbounds, lbounds, size*sizeof(double));
69778   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
69779 }
69780 
69781 
zaxisDefUbounds(int zaxisID,const double * ubounds)69782 void zaxisDefUbounds(int zaxisID, const double *ubounds)
69783 {
69784   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69785 
69786   const size_t size = (size_t)zaxisptr->size;
69787 
69788   if ( CDI_Debug )
69789     if ( zaxisptr->ubounds )
69790       Warning("Upper bounds already defined for zaxisID = %d", zaxisID);
69791 
69792   if ( zaxisptr->ubounds == NULL )
69793     zaxisptr->ubounds = (double *) Malloc(size*sizeof(double));
69794 
69795   if (ubounds) memcpy(zaxisptr->ubounds, ubounds, size*sizeof(double));
69796   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
69797 }
69798 
69799 
zaxisDefWeights(int zaxisID,const double * weights)69800 void zaxisDefWeights(int zaxisID, const double *weights)
69801 {
69802   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69803 
69804   const size_t size = (size_t)zaxisptr->size;
69805 
69806   if ( CDI_Debug )
69807     if ( zaxisptr->weights != NULL )
69808       Warning("Weights already defined for zaxisID = %d", zaxisID);
69809 
69810   if ( zaxisptr->weights == NULL )
69811     zaxisptr->weights = (double *) Malloc(size*sizeof(double));
69812 
69813   memcpy(zaxisptr->weights, weights, size*sizeof(double));
69814   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
69815 }
69816 
69817 
zaxisChangeType(int zaxisID,int zaxistype)69818 void zaxisChangeType(int zaxisID, int zaxistype)
69819 {
69820   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69821   zaxisptr->type = zaxistype;
69822 }
69823 
69824 
zaxisResize(int zaxisID,int size)69825 void zaxisResize(int zaxisID, int size)
69826 {
69827   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69828 
69829   xassert(size >= 0);
69830 
69831   zaxisptr->size = size;
69832 
69833   if ( zaxisptr->vals )
69834     zaxisptr->vals = (double *) Realloc(zaxisptr->vals, (size_t)size*sizeof(double));
69835 }
69836 
69837 static inline
zaxisCopyKeyStr(zaxis_t * zaxisptr1,zaxis_t * zaxisptr2,int key)69838 void zaxisCopyKeyStr(zaxis_t *zaxisptr1, zaxis_t *zaxisptr2, int key)
69839 {
69840   cdi_key_t *keyp = find_key(&zaxisptr1->keys, key);
69841   if (keyp && keyp->type == KEY_BYTES)
69842     cdiDefVarKeyBytes(&zaxisptr2->keys, key, (const unsigned char*)keyp->v.s, (int)keyp->length);
69843 }
69844 
69845 
zaxisDuplicate(int zaxisID)69846 int zaxisDuplicate(int zaxisID)
69847 {
69848   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
69849 
69850   const int zaxistype = zaxisInqType(zaxisID);
69851   const int zaxissize = zaxisInqSize(zaxisID);
69852 
69853   const int zaxisIDnew = zaxisCreate(zaxistype, zaxissize);
69854   zaxis_t *zaxisptrnew = zaxis_to_pointer(zaxisIDnew);
69855 
69856   zaxis_copy(zaxisptrnew, zaxisptr);
69857 
69858   zaxisCopyKeyStr(zaxisptr, zaxisptrnew, CDI_KEY_NAME);
69859   zaxisCopyKeyStr(zaxisptr, zaxisptrnew, CDI_KEY_LONGNAME);
69860   zaxisCopyKeyStr(zaxisptr, zaxisptrnew, CDI_KEY_UNITS);
69861 
69862   if ( zaxisptr->vals )
69863     {
69864       const size_t size = (size_t)zaxissize;
69865       zaxisptrnew->vals = (double *) Malloc(size * sizeof (double));
69866       memcpy(zaxisptrnew->vals, zaxisptr->vals, size * sizeof (double));
69867     }
69868 
69869   if ( zaxisptr->lbounds )
69870     {
69871       const size_t size = (size_t)zaxissize;
69872       zaxisptrnew->lbounds = (double *) Malloc(size * sizeof (double));
69873       memcpy(zaxisptrnew->lbounds, zaxisptr->lbounds, size * sizeof(double));
69874     }
69875 
69876   if ( zaxisptr->ubounds )
69877     {
69878       const size_t size = (size_t)zaxissize;
69879       zaxisptrnew->ubounds = (double *) Malloc(size * sizeof (double));
69880       memcpy(zaxisptrnew->ubounds, zaxisptr->ubounds, size * sizeof (double));
69881     }
69882 
69883   if ( zaxisptr->vct )
69884     {
69885       const size_t size = (size_t)zaxisptr->vctsize;
69886       if ( size )
69887         {
69888           zaxisptrnew->vctsize = (int)size;
69889           zaxisptrnew->vct = (double *) Malloc(size * sizeof (double));
69890           memcpy(zaxisptrnew->vct, zaxisptr->vct, size * sizeof (double));
69891         }
69892     }
69893 
69894   zaxisptrnew->atts.nelems = 0;
69895   cdiCopyAtts(zaxisID, CDI_GLOBAL, zaxisIDnew, CDI_GLOBAL);
69896 
69897   return zaxisIDnew;
69898 }
69899 
69900 static
zaxisPrintKernel(zaxis_t * zaxisptr,FILE * fp)69901 void zaxisPrintKernel(zaxis_t *zaxisptr, FILE *fp)
69902 {
69903   xassert(zaxisptr);
69904 
69905   const int type    = zaxisptr->type;
69906   const int nlevels = zaxisptr->size;
69907   const int datatype = zaxisptr->datatype;
69908 
69909   const int dig = (datatype == CDI_DATATYPE_FLT64) ? 15 : 7;
69910 
69911   fprintf(fp, "zaxistype = %s\n", zaxisNamePtr(type));
69912   fprintf(fp, "size      = %d\n", nlevels);
69913   if ( nlevels == 1 )
69914     {
69915       const bool zscalar = (bool)zaxisptr->scalar;
69916       if ( zscalar ) fprintf(fp, "scalar    = true\n");
69917     }
69918 
69919   const char *string = cdiInqVarKeyString(&zaxisptr->keys, CDI_KEY_NAME);
69920   if ( string[0] ) fprintf(fp, "name      = %s\n", string);
69921   string = cdiInqVarKeyString(&zaxisptr->keys, CDI_KEY_LONGNAME);
69922   if ( string[0] ) fprintf(fp, "longname  = %s\n", string);
69923   string = cdiInqVarKeyString(&zaxisptr->keys, CDI_KEY_UNITS);
69924   if ( string[0] ) fprintf(fp, "units     = %s\n", string);
69925 
69926   if ( zaxisptr->vals )
69927     {
69928       int nbyte0 = fprintf(fp, "levels    = ");
69929       int nbyte = nbyte0;
69930       for ( int levelID = 0; levelID < nlevels; levelID++ )
69931         {
69932           if ( nbyte > 80 )
69933             {
69934               fprintf(fp, "\n");
69935               fprintf(fp, "%*s", nbyte0, "");
69936               nbyte = nbyte0;
69937             }
69938           nbyte += fprintf(fp, "%.*g ", dig, zaxisptr->vals[levelID]);
69939         }
69940       fprintf(fp, "\n");
69941     }
69942 
69943   if ( zaxisptr->lbounds && zaxisptr->ubounds )
69944     {
69945       int nbyte0 = fprintf(fp, "lbounds   = ");
69946       int nbyte = nbyte0;
69947       for ( int levelID = 0; levelID < nlevels; levelID++ )
69948 	{
69949 	  if ( nbyte > 80 )
69950 	    {
69951 	      fprintf(fp, "\n");
69952 	      fprintf(fp, "%*s", nbyte0, "");
69953 	      nbyte = nbyte0;
69954 	    }
69955 	  nbyte += fprintf(fp, "%.*g ", dig, zaxisptr->lbounds[levelID]);
69956 	}
69957       fprintf(fp, "\n");
69958 
69959       nbyte0 = fprintf(fp, "ubounds   = ");
69960       nbyte = nbyte0;
69961       for ( int levelID = 0; levelID < nlevels; levelID++ )
69962 	{
69963 	  if ( nbyte > 80 )
69964 	    {
69965 	      fprintf(fp, "\n");
69966 	      fprintf(fp, "%*s", nbyte0, "");
69967 	      nbyte = nbyte0;
69968 	    }
69969 	  nbyte += fprintf(fp, "%.*g ", dig, zaxisptr->ubounds[levelID]);
69970 	}
69971       fprintf(fp, "\n");
69972     }
69973 
69974   if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
69975     {
69976       const int vctsize = zaxisptr->vctsize;
69977       const double *vct = zaxisptr->vct;
69978       fprintf(fp, "vctsize   = %d\n", vctsize);
69979       if ( vctsize )
69980         {
69981           int nbyte0 = fprintf(fp, "vct       = ");
69982           int nbyte = nbyte0;
69983           for ( int i = 0; i < vctsize; i++ )
69984             {
69985               if ( nbyte > 70 || i == vctsize/2 )
69986                 {
69987                   fprintf(fp, "\n%*s", nbyte0, "");
69988                   nbyte = nbyte0;
69989                 }
69990               nbyte += fprintf(fp, "%.15g ", vct[i]);
69991             }
69992           fprintf(fp, "\n");
69993         }
69994     }
69995 }
69996 
69997 
69998 static
zaxisPrintP(void * voidptr,FILE * fp)69999 void zaxisPrintP(void * voidptr, FILE * fp)
70000 {
70001   zaxis_t *zaxisptr = ( zaxis_t * ) voidptr;
70002 
70003   xassert ( zaxisptr );
70004 
70005   zaxisPrintKernel(zaxisptr, fp);
70006 }
70007 
70008 
70009 static
zaxisCompareP(zaxis_t * z1,zaxis_t * z2)70010 int zaxisCompareP(zaxis_t *z1, zaxis_t *z2)
70011 {
70012   enum { differ = 1 };
70013   int diff = 0;
70014   xassert(z1 && z2);
70015 
70016   diff |= (z1->type != z2->type)
70017     | (cdiInqVarKeyInt(&z1->keys, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE) != cdiInqVarKeyInt(&z2->keys, CDI_KEY_TYPEOFFIRSTFIXEDSURFACE))
70018     | (z1->direction != z2->direction)
70019     | (z1->datatype != z2->datatype)
70020     | (z1->size != z2->size)
70021     | (z1->vctsize != z2->vctsize)
70022     | (z1->positive != z2->positive);
70023 
70024   if ( diff ) return differ;
70025 
70026   int size = z1->size;
70027   int anyPresent = 0;
70028   int present = (z1->vals != NULL);
70029   diff |= (present ^ (z2->vals != NULL));
70030   anyPresent |= present;
70031   if (!diff && present)
70032     {
70033       const double *p = z1->vals, *q = z2->vals;
70034       for ( int i = 0; i < size; i++ )
70035         diff |= IS_NOT_EQUAL(p[i], q[i]);
70036     }
70037 
70038   present = (z1->lbounds != NULL);
70039   diff |= (present ^ (z2->lbounds != NULL));
70040   anyPresent |= present;
70041   if (!diff && present)
70042     {
70043       const double *p = z1->lbounds, *q = z2->lbounds;
70044       for ( int i = 0; i < size; i++ )
70045         diff |= IS_NOT_EQUAL(p[i], q[i]);
70046     }
70047 
70048   present = (z1->ubounds != NULL);
70049   diff |= (present ^ (z2->ubounds != NULL));
70050   anyPresent |= present;
70051   if (!diff && present)
70052     {
70053       const double *p = z1->ubounds, *q = z2->ubounds;
70054       for ( int i = 0; i < size; ++i )
70055         diff |= IS_NOT_EQUAL(p[i], q[i]);
70056     }
70057 
70058   present = (z1->weights != NULL);
70059   diff |= (present ^ (z2->weights != NULL));
70060   anyPresent |= present;
70061   if (!diff && present)
70062     {
70063       const double *p = z1->weights, *q = z2->weights;
70064       for ( int i = 0; i < size; ++i )
70065         diff |= IS_NOT_EQUAL(p[i], q[i]);
70066     }
70067 
70068   present = (z1->vct != NULL);
70069   diff |= (present ^ (z2->vct != NULL));
70070   if (!diff && present)
70071     {
70072       int vctsize = z1->vctsize;
70073       xassert(vctsize);
70074       const double *p = z1->vct, *q = z2->vct;
70075       for ( int i = 0; i < vctsize; ++i )
70076         diff |= IS_NOT_EQUAL(p[i], q[i]);
70077     }
70078 
70079   if (anyPresent)
70080     xassert(size);
70081 
70082   diff |= strcmp(cdiInqVarKeyString(&z1->keys, CDI_KEY_NAME), cdiInqVarKeyString(&z2->keys, CDI_KEY_NAME))
70083     | strcmp(cdiInqVarKeyString(&z1->keys, CDI_KEY_LONGNAME), cdiInqVarKeyString(&z2->keys, CDI_KEY_LONGNAME))
70084     | strcmp(cdiInqVarKeyString(&z1->keys, CDI_KEY_STDNAME), cdiInqVarKeyString(&z2->keys, CDI_KEY_STDNAME))
70085     | strcmp(cdiInqVarKeyString(&z1->keys, CDI_KEY_UNITS), cdiInqVarKeyString(&z2->keys, CDI_KEY_UNITS));
70086 
70087   return diff != 0;
70088 }
70089 
70090 
70091 static
zaxisTxCode(void)70092 int zaxisTxCode(void)
70093 {
70094   return ZAXIS;
70095 }
70096 
70097 enum { zaxisNint     = 7,
70098        vals     = 1 << 0,
70099        lbounds  = 1 << 1,
70100        ubounds  = 1 << 2,
70101        weights  = 1 << 3,
70102        vct      = 1 << 4,
70103 };
70104 
70105 static
zaxisGetMemberMask(zaxis_t * zaxisP)70106 int zaxisGetMemberMask( zaxis_t * zaxisP )
70107 {
70108   int memberMask = 0;
70109 
70110   if ( zaxisP->vals )      memberMask |= vals;
70111   if ( zaxisP->lbounds )   memberMask |= lbounds;
70112   if ( zaxisP->ubounds )   memberMask |= ubounds;
70113   if ( zaxisP->weights )   memberMask |= weights;
70114   if ( zaxisP->vct )       memberMask |= vct;
70115 
70116   return memberMask;
70117 }
70118 
70119 static int
zaxisGetPackSize(void * voidP,void * context)70120 zaxisGetPackSize(void * voidP, void *context)
70121 {
70122   zaxis_t * zaxisP = ( zaxis_t * ) voidP;
70123   int packBufferSize = serializeGetSize(zaxisNint, CDI_DATATYPE_INT, context)
70124     + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
70125 
70126   if (zaxisP->vals || zaxisP->lbounds || zaxisP->ubounds || zaxisP->weights)
70127     xassert(zaxisP->size);
70128 
70129   if ( zaxisP->vals )
70130     packBufferSize += serializeGetSize(zaxisP->size, CDI_DATATYPE_FLT64, context)
70131       + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
70132 
70133   if ( zaxisP->lbounds )
70134     packBufferSize += serializeGetSize(zaxisP->size, CDI_DATATYPE_FLT64, context)
70135       + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
70136 
70137   if ( zaxisP->ubounds )
70138     packBufferSize += serializeGetSize(zaxisP->size, CDI_DATATYPE_FLT64, context)
70139       + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
70140 
70141   if ( zaxisP->weights )
70142     packBufferSize += serializeGetSize(zaxisP->size, CDI_DATATYPE_FLT64, context)
70143       + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
70144 
70145   if ( zaxisP->vct )
70146     {
70147       xassert ( zaxisP->vctsize );
70148       packBufferSize += serializeGetSize(zaxisP->vctsize, CDI_DATATYPE_FLT64, context)
70149         + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
70150     }
70151 
70152   packBufferSize += serializeKeysGetPackSize(&zaxisP->keys, context);
70153 
70154   packBufferSize += serializeGetSize(1, CDI_DATATYPE_UCHAR, context);
70155 
70156   return packBufferSize;
70157 }
70158 
70159 
70160 void
zaxisUnpack(char * unpackBuffer,int unpackBufferSize,int * unpackBufferPos,int originNamespace,void * context,int force_id)70161 zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
70162             int * unpackBufferPos, int originNamespace, void *context,
70163             int force_id)
70164 {
70165   int intBuffer[zaxisNint], memberMask;
70166   uint32_t d;
70167 
70168   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70169                   intBuffer, zaxisNint, CDI_DATATYPE_INT, context);
70170   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70171                   &d, 1, CDI_DATATYPE_UINT32, context);
70172 
70173   xassert(cdiCheckSum(CDI_DATATYPE_INT, zaxisNint, intBuffer) == d);
70174 
70175   zaxisInit();
70176 
70177   zaxis_t *zaxisP
70178     = zaxisNewEntry(force_id ? namespaceAdaptKey(intBuffer[0], originNamespace)
70179                     : CDI_UNDEFID);
70180 
70181   zaxisP->datatype  = intBuffer[1];
70182   zaxisP->type      = intBuffer[2];
70183   zaxisP->size      = intBuffer[3];
70184   zaxisP->direction = intBuffer[4];
70185   zaxisP->vctsize   = intBuffer[5];
70186   memberMask        = intBuffer[6];
70187 
70188   if (memberMask & vals)
70189     {
70190       int size = zaxisP->size;
70191       xassert(size >= 0);
70192 
70193       zaxisP->vals = (double *) Malloc((size_t)size * sizeof (double));
70194       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70195                       zaxisP->vals, size, CDI_DATATYPE_FLT64, context);
70196       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70197                       &d, 1, CDI_DATATYPE_UINT32, context);
70198       xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, zaxisP->vals) == d);
70199     }
70200 
70201   if (memberMask & lbounds)
70202     {
70203       int size = zaxisP->size;
70204       xassert(size >= 0);
70205 
70206       zaxisP->lbounds = (double *) Malloc((size_t)size * sizeof (double));
70207       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70208                       zaxisP->lbounds, size, CDI_DATATYPE_FLT64, context);
70209       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70210                       &d, 1, CDI_DATATYPE_UINT32, context);
70211       xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, zaxisP->lbounds) == d);
70212     }
70213 
70214   if (memberMask & ubounds)
70215     {
70216       int size = zaxisP->size;
70217       xassert(size >= 0);
70218 
70219       zaxisP->ubounds = (double *) Malloc((size_t)size * sizeof (double));
70220       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70221                       zaxisP->ubounds, size, CDI_DATATYPE_FLT64, context);
70222       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70223                       &d, 1, CDI_DATATYPE_UINT32, context);
70224       xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, zaxisP->ubounds) == d);
70225     }
70226 
70227   if (memberMask & weights)
70228     {
70229       int size = zaxisP->size;
70230       xassert(size >= 0);
70231 
70232       zaxisP->weights = (double *) Malloc((size_t)size * sizeof (double));
70233       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70234                       zaxisP->weights, size, CDI_DATATYPE_FLT64, context);
70235       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70236                       &d, 1, CDI_DATATYPE_UINT32, context);
70237       xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, zaxisP->weights) == d);
70238     }
70239 
70240   if ( memberMask & vct )
70241     {
70242       int size = zaxisP->vctsize;
70243       xassert(size >= 0);
70244 
70245       zaxisP->vct = (double *) Malloc((size_t)size * sizeof (double));
70246       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70247                       zaxisP->vct, size, CDI_DATATYPE_FLT64, context);
70248       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70249                       &d, 1, CDI_DATATYPE_UINT32, context);
70250       xassert(cdiCheckSum(CDI_DATATYPE_FLT64, size, zaxisP->vct) == d);
70251     }
70252 
70253   serializeKeysUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos, &zaxisP->keys, context);
70254 
70255   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
70256                   &zaxisP->positive, 1, CDI_DATATYPE_UINT, context);
70257 
70258   reshSetStatus(zaxisP->self, &zaxisOps,
70259                 reshGetStatus(zaxisP->self, &zaxisOps) & ~RESH_SYNC_BIT);
70260 }
70261 
70262 static void
zaxisPack(void * voidP,void * packBuffer,int packBufferSize,int * packBufferPos,void * context)70263 zaxisPack(void * voidP, void * packBuffer, int packBufferSize,
70264           int * packBufferPos, void *context)
70265 {
70266   zaxis_t   * zaxisP = ( zaxis_t * ) voidP;
70267   int intBuffer[zaxisNint];
70268   int memberMask;
70269   uint32_t d;
70270 
70271   intBuffer[0]  = zaxisP->self;
70272   intBuffer[1]  = zaxisP->datatype;
70273   intBuffer[2]  = zaxisP->type;
70274   intBuffer[3]  = zaxisP->size;
70275   intBuffer[4]  = zaxisP->direction;
70276   intBuffer[5]  = zaxisP->vctsize;
70277   intBuffer[6]  = memberMask = zaxisGetMemberMask ( zaxisP );
70278 
70279   serializePack(intBuffer, zaxisNint, CDI_DATATYPE_INT,
70280                 packBuffer, packBufferSize, packBufferPos, context);
70281   d = cdiCheckSum(CDI_DATATYPE_INT, zaxisNint, intBuffer);
70282   serializePack(&d, 1, CDI_DATATYPE_UINT32,
70283                 packBuffer, packBufferSize, packBufferPos, context);
70284 
70285 
70286   if ( memberMask & vals )
70287     {
70288       xassert(zaxisP->size);
70289       serializePack(zaxisP->vals, zaxisP->size, CDI_DATATYPE_FLT64,
70290                     packBuffer, packBufferSize, packBufferPos, context);
70291       d = cdiCheckSum(CDI_DATATYPE_FLT, zaxisP->size, zaxisP->vals );
70292       serializePack(&d, 1, CDI_DATATYPE_UINT32,
70293                     packBuffer, packBufferSize, packBufferPos, context);
70294     }
70295 
70296   if (memberMask & lbounds)
70297     {
70298       xassert(zaxisP->size);
70299       serializePack(zaxisP->lbounds, zaxisP->size, CDI_DATATYPE_FLT64,
70300                     packBuffer, packBufferSize, packBufferPos, context);
70301       d = cdiCheckSum(CDI_DATATYPE_FLT, zaxisP->size, zaxisP->lbounds);
70302       serializePack(&d, 1, CDI_DATATYPE_UINT32,
70303                     packBuffer, packBufferSize, packBufferPos, context);
70304     }
70305 
70306   if (memberMask & ubounds)
70307     {
70308       xassert(zaxisP->size);
70309 
70310       serializePack(zaxisP->ubounds, zaxisP->size, CDI_DATATYPE_FLT64,
70311                     packBuffer, packBufferSize, packBufferPos, context);
70312       d = cdiCheckSum(CDI_DATATYPE_FLT, zaxisP->size, zaxisP->ubounds);
70313       serializePack(&d, 1, CDI_DATATYPE_UINT32,
70314                     packBuffer, packBufferSize, packBufferPos, context);
70315     }
70316 
70317   if (memberMask & weights)
70318     {
70319       xassert(zaxisP->size);
70320 
70321       serializePack(zaxisP->weights, zaxisP->size, CDI_DATATYPE_FLT64,
70322                     packBuffer, packBufferSize, packBufferPos, context);
70323       d = cdiCheckSum(CDI_DATATYPE_FLT, zaxisP->size, zaxisP->weights);
70324       serializePack(&d, 1, CDI_DATATYPE_UINT32,
70325                     packBuffer, packBufferSize, packBufferPos, context);
70326     }
70327 
70328   if (memberMask & vct)
70329     {
70330       xassert(zaxisP->vctsize);
70331 
70332       serializePack(zaxisP->vct, zaxisP->vctsize, CDI_DATATYPE_FLT64,
70333                     packBuffer, packBufferSize, packBufferPos, context);
70334       d = cdiCheckSum(CDI_DATATYPE_FLT64, zaxisP->vctsize, zaxisP->vct);
70335       serializePack(&d, 1, CDI_DATATYPE_UINT32,
70336                     packBuffer, packBufferSize, packBufferPos, context);
70337     }
70338 
70339   serializeKeysPack(&zaxisP->keys, packBuffer, packBufferSize, packBufferPos, context);
70340 
70341   serializePack(&zaxisP->positive, 1, CDI_DATATYPE_UINT,
70342                 packBuffer, packBufferSize, packBufferPos, context);
70343 }
70344 
70345 
cdiZaxisGetIndexList(unsigned nzaxis,int * zaxisResHs)70346 void cdiZaxisGetIndexList(unsigned nzaxis, int *zaxisResHs)
70347 {
70348   reshGetResHListOfType(nzaxis, zaxisResHs, &zaxisOps);
70349 }
70350 
70351 /*
70352  * Local Variables:
70353  * c-file-style: "Java"
70354  * c-basic-offset: 2
70355  * indent-tabs-mode: nil
70356  * show-trailing-whitespace: t
70357  * require-trailing-newline: t
70358  * End:
70359  */
70360 static const char cdi_libvers[] = "1.9.9";
cdiLibraryVersion(void)70361 const char *cdiLibraryVersion(void)
70362 {
70363   return cdi_libvers;
70364 }
70365 #if defined (HAVE_CF_INTERFACE)
70366 #undef realloc
70367 #undef malloc
70368 #undef calloc
70369 #undef free
70370 #undef DOUBLE_PRECISION
70371 /* cfortran.h  4.4 */
70372 /* http://www-zeus.desy.de/~burow/cfortran/                   */
70373 /* Burkhard Burow  burow@desy.de                 1990 - 2002. */
70374 
70375 #ifndef __CFORTRAN_LOADED
70376 #define __CFORTRAN_LOADED
70377 
70378 /*
70379    THIS FILE IS PROPERTY OF BURKHARD BUROW. IF YOU ARE USING THIS FILE YOU
70380    SHOULD ALSO HAVE ACCESS TO CFORTRAN.DOC WHICH PROVIDES TERMS FOR USING,
70381    MODIFYING, COPYING AND DISTRIBUTING THE CFORTRAN.H PACKAGE.
70382 */
70383 
70384 /* THIS PACKAGE, I.E. CFORTRAN.H, THIS DOCUMENT, AND THE CFORTRAN.H EXAMPLE
70385 PROGRAMS ARE PROPERTY OF THE AUTHOR WHO RESERVES ALL RIGHTS. THIS PACKAGE AND
70386 THE CODE IT PRODUCES MAY BE FREELY DISTRIBUTED WITHOUT FEES, SUBJECT
70387 (AT YOUR CHOICE) EITHER TO THE GNU LIBRARY GENERAL PUBLIC LICENSE
70388 AT http://www.gnu.org/licenses/lgpl.html OR TO THE FOLLOWING RESTRICTIONS:
70389 - YOU MUST ACCOMPANY ANY COPIES OR DISTRIBUTION WITH THIS (UNALTERED) NOTICE.
70390 - YOU MAY NOT RECEIVE MONEY FOR THE DISTRIBUTION OR FOR ITS MEDIA
70391   (E.G. TAPE, DISK, COMPUTER, PAPER.)
70392 - YOU MAY NOT PREVENT OTHERS FROM COPYING IT FREELY.
70393 - YOU MAY NOT DISTRIBUTE MODIFIED VERSIONS WITHOUT CLEARLY DOCUMENTING YOUR
70394   CHANGES AND NOTIFYING THE AUTHOR.
70395 - YOU MAY NOT MISREPRESENTED THE ORIGIN OF THIS SOFTWARE, EITHER BY EXPLICIT
70396   CLAIM OR BY OMISSION.
70397 
70398 THE INTENT OF THE ABOVE TERMS IS TO ENSURE THAT THE CFORTRAN.H PACKAGE NOT BE
70399 USED FOR PROFIT MAKING ACTIVITIES UNLESS SOME ROYALTY ARRANGEMENT IS ENTERED
70400 INTO WITH ITS AUTHOR.
70401 
70402 THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
70403 EXPRESSED OR IMPLIED. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
70404 SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST
70405 OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. THE AUTHOR IS NOT RESPONSIBLE
70406 FOR ANY SUPPORT OR SERVICE OF THE CFORTRAN.H PACKAGE.
70407 
70408                                               Burkhard Burow
70409                                               burow@desy.de
70410 */
70411 
70412 /* The following modifications were made by the authors of CFITSIO or by me.
70413  * They are flagged below with CFITSIO, the author's initials, or KMCCARTY.
70414  * PDW = Peter Wilson
70415  * DM  = Doug Mink
70416  * LEB = Lee E Brotzman
70417  * MR  = Martin Reinecke
70418  * WDP = William D Pence
70419  * BR  = Bastien ROUCARIES
70420  * -- Kevin McCarty, for Debian (19 Dec. 2005) */
70421 
70422 /*******
70423    Modifications:
70424       Oct 1997: Changed symbol name extname to appendus (PDW/HSTX)
70425                 (Conflicted with a common variable name in FTOOLS)
70426       Nov 1997: If g77Fortran defined, also define f2cFortran (PDW/HSTX)
70427       Feb 1998: Let VMS see the NUM_ELEMS code. Lets programs treat
70428                 single strings as vectors with single elements
70429       Nov 1999: If macintoxh defined, also define f2cfortran (for Mac OS-X)
70430       Apr 2000: If WIN32 defined, also define PowerStationFortran and
70431                 VISUAL_CPLUSPLUS (Visual C++)
70432       Jun 2000: If __GNUC__ and linux defined, also define f2cFortran
70433                 (linux/gcc environment detection)
70434       Apr 2002: If __CYGWIN__ is defined, also define f2cFortran
70435       Nov 2002: If __APPLE__ defined, also define f2cfortran (for Mac OS-X)
70436 
70437       Nov 2003: If __INTEL_COMPILER or INTEL_COMPILER defined, also define
70438                 f2cFortran (KMCCARTY)
70439       Dec 2005: If f2cFortran is defined, enforce REAL functions in FORTRAN
70440                 returning "double" in C.  This was one of the items on
70441 		Burkhard's TODO list. (KMCCARTY)
70442       Dec 2005: Modifications to support 8-byte integers. (MR)
70443 		USE AT YOUR OWN RISK!
70444       Feb 2006  Added logic to typedef the symbol 'LONGLONG' to an appropriate
70445                 intrinsic 8-byte integer datatype  (WDP)
70446       Apr 2006: Modifications to support gfortran (and g77 with -fno-f2c flag)
70447                 since by default it returns "float" for FORTRAN REAL function.
70448                 (KMCCARTY)
70449       May 2008: Revert commenting out of "extern" in COMMON_BLOCK_DEF macro.
70450 		Add braces around do-nothing ";" in 3 empty while blocks to
70451 		get rid of compiler warnings.  Thanks to ROOT developers
70452 		Jacek Holeczek and Rene Brun for these suggestions. (KMCCARTY)
70453       Aug 2008: If __GNUC__ is defined and no FORTRAN compiler is specified
70454 		via a #define or -D, default to gfortran behavior rather than
70455 		g77 behavior. (KMCCARTY)
70456       Oct 2009: Add warning if guessing default fortran. Move g77 above guessing bloc
70457  *******/
70458 
70459 /*
70460   Avoid symbols already used by compilers and system *.h:
70461   __ - OSF1 zukal06 V3.0 347 alpha, cc -c -std1 cfortest.c
70462 
70463 */
70464 
70465 /*
70466    Determine what 8-byte integer data type is available.
70467   'long long' is now supported by most compilers, but older
70468   MS Visual C++ compilers before V7.0 use '__int64' instead. (WDP)
70469 */
70470 
70471 #ifndef LONGLONG_TYPE   /* this may have been previously defined */
70472 #if defined(_MSC_VER)   /* Microsoft Visual C++ */
70473 
70474 #if (_MSC_VER < 1300)   /* versions earlier than V7.0 do not have 'long long' */
70475     typedef __int64 LONGLONG;
70476 #else                   /* newer versions do support 'long long' */
70477     typedef long long LONGLONG;
70478 #endif
70479 
70480 #else
70481     typedef long long LONGLONG;
70482 #endif
70483 
70484 #define LONGLONG_TYPE
70485 #endif
70486 
70487 
70488 /* First prepare for the C compiler. */
70489 
70490 #ifndef ANSI_C_preprocessor /* i.e. user can override. */
70491 #ifdef __CF__KnR
70492 #define ANSI_C_preprocessor 0
70493 #else
70494 #ifdef __STDC__
70495 #define ANSI_C_preprocessor 1
70496 #else
70497 #define _cfleft             1
70498 #define _cfright
70499 #define _cfleft_cfright     0
70500 #define ANSI_C_preprocessor _cfleft/**/_cfright
70501 #endif
70502 #endif
70503 #endif
70504 
70505 #if ANSI_C_preprocessor
70506 #define _0(A,B)   A##B
70507 #define  _(A,B)   _0(A,B)  /* see cat,xcat of K&R ANSI C p. 231 */
70508 #define _2(A,B)   A##B     /* K&R ANSI C p.230: .. identifier is not replaced */
70509 #define _3(A,B,C) _(A,_(B,C))
70510 #else                      /* if it turns up again during rescanning.         */
70511 #define  _(A,B)   A/**/B
70512 #define _2(A,B)   A/**/B
70513 #define _3(A,B,C) A/**/B/**/C
70514 #endif
70515 
70516 #if (defined(vax)&&defined(unix)) || (defined(__vax__)&&defined(__unix__))
70517 #define VAXUltrix
70518 #endif
70519 
70520 #include <stdio.h>     /* NULL [in all machines stdio.h]                      */
70521 #include <string.h>    /* strlen, memset, memcpy, memchr.                     */
70522 #if !( defined(VAXUltrix) || defined(sun) || (defined(apollo)&&!defined(__STDCPP__)) )
70523 #include <stdlib.h>    /* malloc,free                                         */
70524 #else
70525 #include <malloc.h>    /* Had to be removed for DomainOS h105 10.4 sys5.3 425t*/
70526 #ifdef apollo
70527 #define __CF__APOLLO67 /* __STDCPP__ is in Apollo 6.8 (i.e. ANSI) and onwards */
70528 #endif
70529 #endif
70530 
70531 #if !defined(__GNUC__) && !defined(__sun) && (defined(sun)||defined(VAXUltrix)||defined(lynx))
70532 #define __CF__KnR     /* Sun, LynxOS and VAX Ultrix cc only supports K&R.     */
70533                       /* Manually define __CF__KnR for HP if desired/required.*/
70534 #endif                /*       i.e. We will generate Kernighan and Ritchie C. */
70535 /* Note that you may define __CF__KnR before #include cfortran.h, in order to
70536 generate K&R C instead of the default ANSI C. The differences are mainly in the
70537 function prototypes and declarations. All machines, except the Apollo, work
70538 with either style. The Apollo's argument promotion rules require ANSI or use of
70539 the obsolete std_$call which we have not implemented here. Hence on the Apollo,
70540 only C calling FORTRAN subroutines will work using K&R style.*/
70541 
70542 
70543 /* Remainder of cfortran.h depends on the Fortran compiler. */
70544 
70545 /* 11/29/2003 (KMCCARTY): add *INTEL_COMPILER symbols here */
70546 /* 04/05/2006 (KMCCARTY): add gFortran symbol here */
70547 #if defined(CLIPPERFortran) || defined(pgiFortran) || defined(__INTEL_COMPILER) || defined(INTEL_COMPILER) || defined(gFortran)
70548 #define f2cFortran
70549 #endif
70550 
70551 #if defined(g77Fortran)                        /* 11/03/97 PDW (CFITSIO) */
70552 #define f2cFortran
70553 #endif
70554 
70555 /* VAX/VMS does not let us \-split long #if lines. */
70556 /* Split #if into 2 because some HP-UX can't handle long #if */
70557 #if !(defined(NAGf90Fortran)||defined(f2cFortran)||defined(hpuxFortran)||defined(apolloFortran)||defined(sunFortran)||defined(IBMR2Fortran)||defined(CRAYFortran))
70558 #if !(defined(mipsFortran)||defined(DECFortran)||defined(vmsFortran)||defined(CONVEXFortran)||defined(PowerStationFortran)||defined(AbsoftUNIXFortran)||defined(AbsoftProFortran)||defined(SXFortran))
70559 /* If no Fortran compiler is given, we choose one for the machines we know.   */
70560 #if defined(__GNUC__) || defined(WIN32) /* 10/2009 BR: warm if guess */
70561 #warning "Please specify the fortran compiler using -D flags. Try to guess the compiler used"
70562 #endif
70563 #if defined(lynx) || defined(VAXUltrix)
70564 #define f2cFortran    /* Lynx:      Only support f2c at the moment.
70565                          VAXUltrix: f77 behaves like f2c.
70566                            Support f2c or f77 with gcc, vcc with f2c.
70567                            f77 with vcc works, missing link magic for f77 I/O.*/
70568 #endif
70569 /* 04/13/00 DM (CFITSIO): Add these lines for NT */
70570 /*   with PowerStationFortran and and Visual C++ */
70571 #if defined(WIN32) && !defined(__CYGWIN__)
70572 #define PowerStationFortran
70573 #define VISUAL_CPLUSPLUS
70574 #endif
70575 #if        defined(__CYGWIN__)                 /* 04/11/02 LEB (CFITSIO) */
70576 #define       f2cFortran
70577 #define	      gFortran /* 8/26/08 (KMCCARTY) */
70578 #endif
70579 #if        defined(__GNUC__) && defined(linux) /* 06/21/00 PDW (CFITSIO) */
70580 #define       f2cFortran
70581 #define	      gFortran /* 8/26/08 (KMCCARTY) */
70582 #endif
70583 #if defined(macintosh)                         /* 11/1999 (CFITSIO) */
70584 #define f2cFortran
70585 #define	      gFortran /* 8/26/08 (KMCCARTY) */
70586 #endif
70587 #if defined(__APPLE__)                         /* 11/2002 (CFITSIO) */
70588 #define f2cFortran
70589 #define	      gFortran /* 8/26/08 (KMCCARTY) */
70590 #endif
70591 #if defined(__hpux)             /* 921107: Use __hpux instead of __hp9000s300 */
70592 #define       hpuxFortran       /*         Should also allow hp9000s7/800 use.*/
70593 #endif
70594 #if       defined(apollo)
70595 #define           apolloFortran /* __CF__APOLLO67 also defines some behavior. */
70596 #endif
70597 #if          defined(sun) || defined(__sun)
70598 #define              sunFortran
70599 #endif
70600 #if       defined(_IBMR2)
70601 #define            IBMR2Fortran
70602 #endif
70603 #if        defined(_CRAY)
70604 #define             CRAYFortran /*       _CRAYT3E also defines some behavior. */
70605 #endif
70606 #if        defined(_SX)
70607 #define               SXFortran
70608 #endif
70609 #if        defined(__NEC__)
70610 #define               SXFortran
70611 #endif
70612 #if         defined(mips) || defined(__mips)
70613 #define             mipsFortran
70614 #endif
70615 #if          defined(vms) || defined(__vms)
70616 #define              vmsFortran
70617 #endif
70618 #if      defined(__alpha) && defined(__unix__)
70619 #define              DECFortran
70620 #endif
70621 #if   defined(__convex__)
70622 #define           CONVEXFortran
70623 #endif
70624 #if   defined(VISUAL_CPLUSPLUS)
70625 #define     PowerStationFortran
70626 #endif
70627 #endif /* ...Fortran */
70628 #endif /* ...Fortran */
70629 
70630 /* Split #if into 2 because some HP-UX can't handle long #if */
70631 #if !(defined(NAGf90Fortran)||defined(f2cFortran)||defined(hpuxFortran)||defined(apolloFortran)||defined(sunFortran)||defined(IBMR2Fortran)||defined(CRAYFortran))
70632 #if !(defined(mipsFortran)||defined(DECFortran)||defined(vmsFortran)||defined(CONVEXFortran)||defined(PowerStationFortran)||defined(AbsoftUNIXFortran)||defined(AbsoftProFortran)||defined(SXFortran))
70633 /* If your compiler barfs on ' #error', replace # with the trigraph for #     */
70634  #error "cfortran.h:  Can't find your environment among:\
70635     - GNU gcc (gfortran) on Linux.                                       \
70636     - MIPS cc and f77 2.0. (e.g. Silicon Graphics, DECstations, ...)     \
70637     - IBM AIX XL C and FORTRAN Compiler/6000 Version 01.01.0000.0000     \
70638     - VAX   VMS CC 3.1 and FORTRAN 5.4.                                  \
70639     - Alpha VMS DEC C 1.3 and DEC FORTRAN 6.0.                           \
70640     - Alpha OSF DEC C and DEC Fortran for OSF/1 AXP Version 1.2          \
70641     - Apollo DomainOS 10.2 (sys5.3) with f77 10.7 and cc 6.7.            \
70642     - CRAY                                                               \
70643     - NEC SX-4 SUPER-UX                                                  \
70644     - CONVEX                                                             \
70645     - Sun                                                                \
70646     - PowerStation Fortran with Visual C++                               \
70647     - HP9000s300/s700/s800 Latest test with: HP-UX A.08.07 A 9000/730    \
70648     - LynxOS: cc or gcc with f2c.                                        \
70649     - VAXUltrix: vcc,cc or gcc with f2c. gcc or cc with f77.             \
70650     -            f77 with vcc works; but missing link magic for f77 I/O. \
70651     -            NO fort. None of gcc, cc or vcc generate required names.\
70652     - f2c/g77:   Use #define    f2cFortran, or cc -Df2cFortran           \
70653     - gfortran:  Use #define    gFortran,   or cc -DgFortran             \
70654                  (also necessary for g77 with -fno-f2c option)           \
70655     - NAG f90: Use #define NAGf90Fortran, or cc -DNAGf90Fortran          \
70656     - Absoft UNIX F77: Use #define AbsoftUNIXFortran or cc -DAbsoftUNIXFortran \
70657     - Absoft Pro Fortran: Use #define AbsoftProFortran \
70658     - Portland Group Fortran: Use #define pgiFortran \
70659     - Intel Fortran: Use #define INTEL_COMPILER"
70660 /* Compiler must throw us out at this point! */
70661 #endif
70662 #endif
70663 
70664 
70665 #if defined(VAXC) && !defined(__VAXC)
70666 #define OLD_VAXC
70667 #pragma nostandard                       /* Prevent %CC-I-PARAMNOTUSED.       */
70668 #endif
70669 
70670 /* Throughout cfortran.h we use: UN = Uppercase Name.  LN = Lowercase Name.   */
70671 
70672 /* "extname" changed to "appendus" below (CFITSIO) */
70673 #if defined(f2cFortran) || defined(NAGf90Fortran) || defined(DECFortran) || defined(mipsFortran) || defined(apolloFortran) || defined(sunFortran) || defined(CONVEXFortran) || defined(SXFortran) || defined(appendus)
70674 #define CFC_(UN,LN)            _(LN,_)      /* Lowercase FORTRAN symbols.     */
70675 #define orig_fcallsc(UN,LN)    CFC_(UN,LN)
70676 #else
70677 #if defined(CRAYFortran) || defined(PowerStationFortran) || defined(AbsoftProFortran)
70678 #ifdef _CRAY          /* (UN), not UN, circumvents CRAY preprocessor bug.     */
70679 #define CFC_(UN,LN)            (UN)         /* Uppercase FORTRAN symbols.     */
70680 #else                 /* At least VISUAL_CPLUSPLUS barfs on (UN), so need UN. */
70681 #define CFC_(UN,LN)            UN           /* Uppercase FORTRAN symbols.     */
70682 #endif
70683 #define orig_fcallsc(UN,LN)    CFC_(UN,LN)  /* CRAY insists on arg.'s here.   */
70684 #else  /* For following machines one may wish to change the fcallsc default.  */
70685 #define CF_SAME_NAMESPACE
70686 #ifdef vmsFortran
70687 #define CFC_(UN,LN)            LN           /* Either case FORTRAN symbols.   */
70688      /* BUT we usually use UN for C macro to FORTRAN routines, so use LN here,*/
70689      /* because VAX/VMS doesn't do recursive macros.                          */
70690 #define orig_fcallsc(UN,LN)    UN
70691 #else      /* HP-UX without +ppu or IBMR2 without -qextname. NOT reccomended. */
70692 #define CFC_(UN,LN)            LN           /* Lowercase FORTRAN symbols.     */
70693 #define orig_fcallsc(UN,LN)    CFC_(UN,LN)
70694 #endif /*  vmsFortran */
70695 #endif /* CRAYFortran PowerStationFortran */
70696 #endif /* ....Fortran */
70697 
70698 #define fcallsc(UN,LN)               orig_fcallsc(UN,LN)
70699 #define preface_fcallsc(P,p,UN,LN)   CFC_(_(P,UN),_(p,LN))
70700 #define  append_fcallsc(P,p,UN,LN)   CFC_(_(UN,P),_(LN,p))
70701 
70702 #define C_FUNCTION(UN,LN)            fcallsc(UN,LN)
70703 #define FORTRAN_FUNCTION(UN,LN)      CFC_(UN,LN)
70704 
70705 #ifndef COMMON_BLOCK
70706 #ifndef CONVEXFortran
70707 #ifndef CLIPPERFortran
70708 #if     !(defined(AbsoftUNIXFortran)||defined(AbsoftProFortran))
70709 #define COMMON_BLOCK(UN,LN)          CFC_(UN,LN)
70710 #else
70711 #define COMMON_BLOCK(UN,LN)          _(_C,LN)
70712 #endif  /* AbsoftUNIXFortran or AbsoftProFortran */
70713 #else
70714 #define COMMON_BLOCK(UN,LN)          _(LN,__)
70715 #endif  /* CLIPPERFortran */
70716 #else
70717 #define COMMON_BLOCK(UN,LN)          _3(_,LN,_)
70718 #endif  /* CONVEXFortran */
70719 #endif  /* COMMON_BLOCK */
70720 
70721 #ifndef DOUBLE_PRECISION
70722 #if defined(CRAYFortran) && !defined(_CRAYT3E)
70723 #define DOUBLE_PRECISION long double
70724 #else
70725 #define DOUBLE_PRECISION double
70726 #endif
70727 #endif
70728 
70729 #ifndef FORTRAN_REAL
70730 #if defined(CRAYFortran) &&  defined(_CRAYT3E)
70731 #define FORTRAN_REAL double
70732 #else
70733 #define FORTRAN_REAL float
70734 #endif
70735 #endif
70736 
70737 #ifdef CRAYFortran
70738 #ifdef _CRAY
70739 #include <fortran.h>
70740 #else
70741 #include "fortran.h"  /* i.e. if crosscompiling assume user has file. */
70742 #endif
70743 #define FLOATVVVVVVV_cfPP (FORTRAN_REAL *)   /* Used for C calls FORTRAN.     */
70744 /* CRAY's double==float but CRAY says pointers to doubles and floats are diff.*/
70745 #define VOIDP  (void *)  /* When FORTRAN calls C, we don't know if C routine
70746                             arg.'s have been declared float *, or double *.   */
70747 #else
70748 #define FLOATVVVVVVV_cfPP
70749 #define VOIDP
70750 #endif
70751 
70752 #ifdef vmsFortran
70753 #if    defined(vms) || defined(__vms)
70754 #include <descrip.h>
70755 #else
70756 #include "descrip.h"  /* i.e. if crosscompiling assume user has file. */
70757 #endif
70758 #endif
70759 
70760 #ifdef sunFortran
70761 #if defined(sun) || defined(__sun)
70762 #include <math.h>     /* Sun's FLOATFUNCTIONTYPE, ASSIGNFLOAT, RETURNFLOAT.  */
70763 #else
70764 #include "math.h"     /* i.e. if crosscompiling assume user has file. */
70765 #endif
70766 /* At least starting with the default C compiler SC3.0.1 of SunOS 5.3,
70767  * FLOATFUNCTIONTYPE, ASSIGNFLOAT, RETURNFLOAT are not required and not in
70768  * <math.h>, since sun C no longer promotes C float return values to doubles.
70769  * Therefore, only use them if defined.
70770  * Even if gcc is being used, assume that it exhibits the Sun C compiler
70771  * behavior in order to be able to use *.o from the Sun C compiler.
70772  * i.e. If FLOATFUNCTIONTYPE, etc. are in math.h, they required by gcc.
70773  */
70774 #endif
70775 
70776 #ifndef apolloFortran
70777 #define COMMON_BLOCK_DEF(DEFINITION, NAME) extern DEFINITION NAME
70778 #define CF_NULL_PROTO
70779 #else                                         /* HP doesn't understand #elif. */
70780 /* Without ANSI prototyping, Apollo promotes float functions to double.    */
70781 /* Note that VAX/VMS, IBM, Mips choke on 'type function(...);' prototypes. */
70782 #define CF_NULL_PROTO ...
70783 #ifndef __CF__APOLLO67
70784 #define COMMON_BLOCK_DEF(DEFINITION, NAME) \
70785  DEFINITION NAME __attribute((__section(NAME)))
70786 #else
70787 #define COMMON_BLOCK_DEF(DEFINITION, NAME) \
70788  DEFINITION NAME #attribute[section(NAME)]
70789 #endif
70790 #endif
70791 
70792 #ifdef __cplusplus
70793 #undef  CF_NULL_PROTO
70794 #define CF_NULL_PROTO  ...
70795 #endif
70796 
70797 
70798 #ifndef USE_NEW_DELETE
70799 #ifdef __cplusplus
70800 #define USE_NEW_DELETE 1
70801 #else
70802 #define USE_NEW_DELETE 0
70803 #endif
70804 #endif
70805 #if USE_NEW_DELETE
70806 #define _cf_malloc(N) new char[N]
70807 #define _cf_free(P)   delete[] P
70808 #else
70809 #define _cf_malloc(N) (char *)malloc(N)
70810 #define _cf_free(P)   free(P)
70811 #endif
70812 
70813 #ifdef mipsFortran
70814 #define CF_DECLARE_GETARG         int f77argc; char **f77argv
70815 #define CF_SET_GETARG(ARGC,ARGV)  f77argc = ARGC; f77argv = ARGV
70816 #else
70817 #define CF_DECLARE_GETARG
70818 #define CF_SET_GETARG(ARGC,ARGV)
70819 #endif
70820 
70821 #ifdef OLD_VAXC                          /* Allow %CC-I-PARAMNOTUSED.         */
70822 #pragma standard
70823 #endif
70824 
70825 #define AcfCOMMA ,
70826 #define AcfCOLON ;
70827 
70828 /*-------------------------------------------------------------------------*/
70829 
70830 /*               UTILITIES USED WITHIN CFORTRAN.H                          */
70831 
70832 #define _cfMIN(A,B) (A<B?A:B)
70833 
70834 /* 970211 - XIX.145:
70835    firstindexlength  - better name is all_but_last_index_lengths
70836    secondindexlength - better name is         last_index_length
70837  */
70838 #define  firstindexlength(A) (sizeof(A[0])==1 ? 1 : (sizeof(A) / sizeof(A[0])) )
70839 #define secondindexlength(A) (sizeof(A[0])==1 ?      sizeof(A) : sizeof(A[0])  )
70840 
70841 /* Behavior of FORTRAN LOGICAL. All machines' LOGICAL is same size as C's int.
70842 Conversion is automatic except for arrays which require F2CLOGICALV/C2FLOGICALV.
70843 f2c, MIPS f77 [DECstation, SGI], VAX Ultrix f77,
70844 HP-UX f77                                        : as in C.
70845 VAX/VMS FORTRAN, VAX Ultrix fort,
70846 Absoft Unix Fortran, IBM RS/6000 xlf             : LS Bit = 0/1 = TRUE/FALSE.
70847 Apollo                                           : neg.   = TRUE, else FALSE.
70848 [Apollo accepts -1 as TRUE for function values, but NOT all other neg. values.]
70849 [DECFortran for Ultrix RISC is also called f77 but is the same as VAX/VMS.]
70850 [MIPS f77 treats .eqv./.neqv. as .eq./.ne. and hence requires LOGICAL_STRICT.]*/
70851 
70852 #if defined(NAGf90Fortran) || defined(f2cFortran) || defined(mipsFortran) || defined(PowerStationFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran) || defined(AbsoftProFortran) || defined(SXFortran)
70853 /* SX/PowerStationFortran have 0 and 1 defined, others are neither T nor F.   */
70854 /* hpuxFortran800 has 0 and 0x01000000 defined. Others are unknown.           */
70855 #define LOGICAL_STRICT      /* Other Fortran have .eqv./.neqv. == .eq./.ne.   */
70856 #endif
70857 
70858 #define C2FLOGICALV(A,I) \
70859  do {int __i; for(__i=0;__i<I;__i++) A[__i]=C2FLOGICAL(A[__i]); } while (0)
70860 #define F2CLOGICALV(A,I) \
70861  do {int __i; for(__i=0;__i<I;__i++) A[__i]=F2CLOGICAL(A[__i]); } while (0)
70862 
70863 #if defined(apolloFortran)
70864 #define C2FLOGICAL(L) ((L)?-1:(L)&~((unsigned)1<<sizeof(int)*8-1))
70865 #define F2CLOGICAL(L) ((L)<0?(L):0)
70866 #else
70867 #if defined(CRAYFortran)
70868 #define C2FLOGICAL(L) _btol(L)
70869 #define F2CLOGICAL(L) _ltob(&(L))     /* Strangely _ltob() expects a pointer. */
70870 #else
70871 #if defined(IBMR2Fortran) || defined(vmsFortran) || defined(DECFortran) || defined(AbsoftUNIXFortran)
70872 /* How come no AbsoftProFortran ? */
70873 #define C2FLOGICAL(L) ((L)?(L)|1:(L)&~(int)1)
70874 #define F2CLOGICAL(L) ((L)&1?(L):0)
70875 #else
70876 #if defined(CONVEXFortran)
70877 #define C2FLOGICAL(L) ((L) ? ~0 : 0 )
70878 #define F2CLOGICAL(L) (L)
70879 #else   /* others evaluate LOGICALs as for C. */
70880 #define C2FLOGICAL(L) (L)
70881 #define F2CLOGICAL(L) (L)
70882 #ifndef LOGICAL_STRICT
70883 #undef  C2FLOGICALV
70884 #undef  F2CLOGICALV
70885 #define C2FLOGICALV(A,I)
70886 #define F2CLOGICALV(A,I)
70887 #endif  /* LOGICAL_STRICT                     */
70888 #endif  /* CONVEXFortran || All Others        */
70889 #endif  /* IBMR2Fortran vmsFortran DECFortran AbsoftUNIXFortran */
70890 #endif  /* CRAYFortran                        */
70891 #endif  /* apolloFortran                      */
70892 
70893 /* 970514 - In addition to CRAY, there may be other machines
70894             for which LOGICAL_STRICT makes no sense. */
70895 #if defined(LOGICAL_STRICT) && !defined(CRAYFortran)
70896 /* Force C2FLOGICAL to generate only the values for either .TRUE. or .FALSE.
70897    SX/PowerStationFortran only have 0 and 1 defined.
70898    Elsewhere, only needed if you want to do:
70899      logical lvariable
70900      if (lvariable .eq.  .true.) then       ! (1)
70901    instead of
70902      if (lvariable .eqv. .true.) then       ! (2)
70903    - (1) may not even be FORTRAN/77 and that Apollo's f77 and IBM's xlf
70904      refuse to compile (1), so you are probably well advised to stay away from
70905      (1) and from LOGICAL_STRICT.
70906    - You pay a (slight) performance penalty for using LOGICAL_STRICT. */
70907 #undef  C2FLOGICAL
70908 #ifdef hpuxFortran800
70909 #define C2FLOGICAL(L) ((L)?0x01000000:0)
70910 #else
70911 #if defined(apolloFortran) || defined(vmsFortran) || defined(DECFortran)
70912 #define C2FLOGICAL(L) ((L)?-1:0) /* These machines use -1/0 for .true./.false.*/
70913 #else
70914 #define C2FLOGICAL(L) ((L)? 1:0) /* All others     use +1/0 for .true./.false.*/
70915 #endif
70916 #endif
70917 #endif /* LOGICAL_STRICT */
70918 
70919 /* Convert a vector of C strings into FORTRAN strings. */
70920 #ifndef __CF__KnR
c2fstrv(char * cstr,char * fstr,int elem_len,int sizeofcstr)70921 static char *c2fstrv(char* cstr, char *fstr, int elem_len, int sizeofcstr)
70922 #else
70923 static char *c2fstrv(      cstr,       fstr,     elem_len,     sizeofcstr)
70924                      char* cstr; char *fstr; int elem_len; int sizeofcstr;
70925 #endif
70926 { int i,j;
70927 /* elem_len includes \0 for C strings. Fortran strings don't have term. \0.
70928    Useful size of string must be the same in both languages. */
70929 for (i=0; i<sizeofcstr/elem_len; i++) {
70930   for (j=1; j<elem_len && *cstr; j++) *fstr++ = *cstr++;
70931   cstr += 1+elem_len-j;
70932   for (; j<elem_len; j++) *fstr++ = ' ';
70933 } /* 95109 - Seems to be returning the original fstr. */
70934 return fstr-sizeofcstr+sizeofcstr/elem_len; }
70935 
70936 /* Convert a vector of FORTRAN strings into C strings. */
70937 #ifndef __CF__KnR
f2cstrv(char * fstr,char * cstr,int elem_len,int sizeofcstr)70938 static char *f2cstrv(char *fstr, char* cstr, int elem_len, int sizeofcstr)
70939 #else
70940 static char *f2cstrv(      fstr,       cstr,     elem_len,     sizeofcstr)
70941                      char *fstr; char* cstr; int elem_len; int sizeofcstr;
70942 #endif
70943 { int i,j;
70944 /* elem_len includes \0 for C strings. Fortran strings don't have term. \0.
70945    Useful size of string must be the same in both languages. */
70946 cstr += sizeofcstr;
70947 fstr += sizeofcstr - sizeofcstr/elem_len;
70948 for (i=0; i<sizeofcstr/elem_len; i++) {
70949   *--cstr = '\0';
70950   for (j=1; j<elem_len; j++) *--cstr = *--fstr;
70951 } return cstr; }
70952 
70953 /* kill the trailing char t's in string s. */
70954 #ifndef __CF__KnR
kill_trailing(char * s,char t)70955 static char *kill_trailing(char *s, char t)
70956 #else
70957 static char *kill_trailing(      s,      t) char *s; char t;
70958 #endif
70959 {char *e;
70960 e = s + strlen(s);
70961 if (e>s) {                           /* Need this to handle NULL string.*/
70962   while (e>s && *--e==t) {;}         /* Don't follow t's past beginning. */
70963   e[*e==t?0:1] = '\0';               /* Handle s[0]=t correctly.       */
70964 } return s; }
70965 
70966 #ifndef __CF__KnR
70967 static int num_elem(const char *strv, unsigned elem_len, int term_char, int num_term);
70968 #endif
70969 /* kill_trailingn(s,t,e) will kill the trailing t's in string s. e normally
70970 points to the terminating '\0' of s, but may actually point to anywhere in s.
70971 s's new '\0' will be placed at e or earlier in order to remove any trailing t's.
70972 If e<s string s is left unchanged. */
70973 #ifndef __CF__KnR
kill_trailingn(char * s,char t,char * e)70974 static char *kill_trailingn(char *s, char t, char *e)
70975 #else
70976 static char *kill_trailingn(      s,      t,       e) char *s; char t; char *e;
70977 #endif
70978 {
70979 if (e==s) *e = '\0';                 /* Kill the string makes sense here.*/
70980 else if (e>s) {                      /* Watch out for neg. length string.*/
70981   while (e>s && *--e==t){;}          /* Don't follow t's past beginning. */
70982   e[*e==t?0:1] = '\0';               /* Handle s[0]=t correctly.       */
70983 }
70984 (void)num_elem;  /* to prevent not used warnings in gcc (added by TJ) */
70985 
70986  return s; }
70987 
70988 /* Note the following assumes that any element which has t's to be chopped off,
70989 does indeed fill the entire element. */
70990 #ifndef __CF__KnR
vkill_trailing(char * cstr,int elem_len,int sizeofcstr,char t)70991 static char *vkill_trailing(char* cstr, int elem_len, int sizeofcstr, char t)
70992 #else
70993 static char *vkill_trailing(      cstr,     elem_len,     sizeofcstr,      t)
70994                             char* cstr; int elem_len; int sizeofcstr; char t;
70995 #endif
70996 { int i;
70997 for (i=0; i<sizeofcstr/elem_len; i++) /* elem_len includes \0 for C strings. */
70998   kill_trailingn(cstr+elem_len*i,t,cstr+elem_len*(i+1)-1);
70999 return cstr; }
71000 
71001 #ifdef vmsFortran
71002 typedef struct dsc$descriptor_s fstring;
71003 #define DSC$DESCRIPTOR_A(DIMCT)  		                               \
71004 struct {                                                                       \
71005   unsigned short dsc$w_length;	        unsigned char	 dsc$b_dtype;	       \
71006   unsigned char	 dsc$b_class;	                 char	*dsc$a_pointer;	       \
71007            char	 dsc$b_scale;	        unsigned char	 dsc$b_digits;         \
71008   struct {                                                                     \
71009     unsigned		       : 3;	  unsigned dsc$v_fl_binscale : 1;      \
71010     unsigned dsc$v_fl_redim    : 1;       unsigned dsc$v_fl_column   : 1;      \
71011     unsigned dsc$v_fl_coeff    : 1;       unsigned dsc$v_fl_bounds   : 1;      \
71012   } dsc$b_aflags;	                                                       \
71013   unsigned char	 dsc$b_dimct;	        unsigned long	 dsc$l_arsize;	       \
71014            char	*dsc$a_a0;	                 long	 dsc$l_m [DIMCT];      \
71015   struct {                                                                     \
71016     long dsc$l_l;                         long dsc$l_u;                        \
71017   } dsc$bounds [DIMCT];                                                        \
71018 }
71019 typedef DSC$DESCRIPTOR_A(1) fstringvector;
71020 /*typedef DSC$DESCRIPTOR_A(2) fstringarrarr;
71021   typedef DSC$DESCRIPTOR_A(3) fstringarrarrarr;*/
71022 #define initfstr(F,C,ELEMNO,ELEMLEN)                                           \
71023 ( (F).dsc$l_arsize=  ( (F).dsc$w_length                        =(ELEMLEN) )    \
71024                     *( (F).dsc$l_m[0]=(F).dsc$bounds[0].dsc$l_u=(ELEMNO)  ),   \
71025   (F).dsc$a_a0    =  ( (F).dsc$a_pointer=(C) ) - (F).dsc$w_length          ,(F))
71026 
71027 #endif      /* PDW: 2/10/98 (CFITSIO) -- Let VMS see NUM_ELEMS definitions */
71028 #define _NUM_ELEMS      -1
71029 #define _NUM_ELEM_ARG   -2
71030 #define NUM_ELEMS(A)    A,_NUM_ELEMS
71031 #define NUM_ELEM_ARG(B) *_2(A,B),_NUM_ELEM_ARG
71032 #define TERM_CHARS(A,B) A,B
71033 #ifndef __CF__KnR
num_elem(const char * strv,unsigned elem_len,int term_char,int num_term)71034 static int num_elem(const char *strv, unsigned elem_len, int term_char, int num_term)
71035 #else
71036 static int num_elem(      strv,          elem_len,     term_char,     num_term)
71037                     char *strv; unsigned elem_len; int term_char; int num_term;
71038 #endif
71039 /* elem_len is the number of characters in each element of strv, the FORTRAN
71040 vector of strings. The last element of the vector must begin with at least
71041 num_term term_char characters, so that this routine can determine how
71042 many elements are in the vector. */
71043 {
71044 unsigned num,i;
71045 if (num_term == _NUM_ELEMS || num_term == _NUM_ELEM_ARG)
71046   return term_char;
71047 if (num_term <=0) num_term = (int)elem_len;
71048 for (num=0; ; num++) {
71049   for (i=0; i<(unsigned)num_term && *strv==term_char; i++,strv++){;}
71050   if (i==(unsigned)num_term) break;
71051   else strv += elem_len-i;
71052 }
71053 /* to prevent not used warnings in gcc (added by ROOT, changed by TJ
71054  * because of unreachable warnings from clang) */
71055 (void)c2fstrv; (void)f2cstrv; (void)kill_trailing;
71056 (void)vkill_trailing; (void)num_elem;
71057 return (int)num;
71058 }
71059 /* #endif removed 2/10/98 (CFITSIO) */
71060 
71061 /*-------------------------------------------------------------------------*/
71062 
71063 /*           UTILITIES FOR C TO USE STRINGS IN FORTRAN COMMON BLOCKS       */
71064 
71065 /* C string TO Fortran Common Block STRing. */
71066 /* DIM is the number of DIMensions of the array in terms of strings, not
71067    characters. e.g. char a[12] has DIM = 0, char a[12][4] has DIM = 1, etc. */
71068 #define C2FCBSTR(CSTR,FSTR,DIM)                                                \
71069  c2fstrv((char *)CSTR, (char *)FSTR, sizeof(FSTR)/cfelementsof(FSTR,DIM)+1,    \
71070          sizeof(FSTR)+cfelementsof(FSTR,DIM))
71071 
71072 /* Fortran Common Block string TO C STRing. */
71073 #define FCB2CSTR(FSTR,CSTR,DIM)                                                \
71074  vkill_trailing(f2cstrv((char *)FSTR, (char *)CSTR,                            \
71075                         sizeof(FSTR)/cfelementsof(FSTR,DIM)+1,                 \
71076                         sizeof(FSTR)+cfelementsof(FSTR,DIM)),                  \
71077                 sizeof(FSTR)/cfelementsof(FSTR,DIM)+1,                         \
71078                 sizeof(FSTR)+cfelementsof(FSTR,DIM), ' ')
71079 
71080 #define cfDEREFERENCE0
71081 #define cfDEREFERENCE1 *
71082 #define cfDEREFERENCE2 **
71083 #define cfDEREFERENCE3 ***
71084 #define cfDEREFERENCE4 ****
71085 #define cfDEREFERENCE5 *****
71086 #define cfelementsof(A,D) (sizeof(A)/sizeof(_(cfDEREFERENCE,D)(A)))
71087 
71088 /*-------------------------------------------------------------------------*/
71089 
71090 /*               UTILITIES FOR C TO CALL FORTRAN SUBROUTINES               */
71091 
71092 /* Define lookup tables for how to handle the various types of variables.  */
71093 
71094 #ifdef OLD_VAXC                                /* Prevent %CC-I-PARAMNOTUSED. */
71095 #pragma nostandard
71096 #endif
71097 
71098 #define ZTRINGV_NUM(I)       I
71099 #define ZTRINGV_ARGFP(I) (*(_2(A,I))) /* Undocumented. For PINT, etc. */
71100 #define ZTRINGV_ARGF(I) _2(A,I)
71101 #ifdef CFSUBASFUN
71102 #define ZTRINGV_ARGS(I) ZTRINGV_ARGF(I)
71103 #else
71104 #define ZTRINGV_ARGS(I) _2(B,I)
71105 #endif
71106 
71107 #define    PBYTE_cfVP(A,B) PINT_cfVP(A,B)
71108 #define  PDOUBLE_cfVP(A,B)
71109 #define   PFLOAT_cfVP(A,B)
71110 #ifdef ZTRINGV_ARGS_allows_Pvariables
71111 /* This allows Pvariables for ARGS. ARGF machinery is above ARGFP.
71112  * B is not needed because the variable may be changed by the Fortran routine,
71113  * but because B is the only way to access an arbitrary macro argument.       */
71114 #define     PINT_cfVP(A,B) int  B = (int)A;              /* For ZSTRINGV_ARGS */
71115 #else
71116 #define     PINT_cfVP(A,B)
71117 #endif
71118 #define PLOGICAL_cfVP(A,B) int *B;      /* Returning LOGICAL in FUNn and SUBn */
71119 #define    PLONG_cfVP(A,B) PINT_cfVP(A,B)
71120 #define   PSHORT_cfVP(A,B) PINT_cfVP(A,B)
71121 
71122 #define        VCF_INT_S(T,A,B) _(T,VVVVVVV_cfTYPE) B = A;
71123 #define        VCF_INT_F(T,A,B) _(T,_cfVCF)(A,B)
71124 /* _cfVCF table is directly mapped to _cfCCC table. */
71125 #define     BYTE_cfVCF(A,B)
71126 #define   DOUBLE_cfVCF(A,B)
71127 #if !defined(__CF__KnR)
71128 #define    FLOAT_cfVCF(A,B)
71129 #else
71130 #define    FLOAT_cfVCF(A,B) FORTRAN_REAL B = A;
71131 #endif
71132 #define      INT_cfVCF(A,B)
71133 #define  LOGICAL_cfVCF(A,B)
71134 #define     LONG_cfVCF(A,B)
71135 #define    SHORT_cfVCF(A,B)
71136 
71137 /* 980416
71138    Cast (void (*)(CF_NULL_PROTO)) causes SunOS CC 4.2 occasionally to barf,
71139    while the following equivalent typedef is fine.
71140    For consistency use the typedef on all machines.
71141  */
71142 typedef void (*cfCAST_FUNCTION)(CF_NULL_PROTO);
71143 
71144 #define VCF(TN,I)       _Icf4(4,V,TN,_(A,I),_(B,I),F)
71145 #define VVCF(TN,AI,BI)  _Icf4(4,V,TN,AI,BI,S)
71146 #define        INT_cfV(T,A,B,F) _(VCF_INT_,F)(T,A,B)
71147 #define       INTV_cfV(T,A,B,F)
71148 #define      INTVV_cfV(T,A,B,F)
71149 #define     INTVVV_cfV(T,A,B,F)
71150 #define    INTVVVV_cfV(T,A,B,F)
71151 #define   INTVVVVV_cfV(T,A,B,F)
71152 #define  INTVVVVVV_cfV(T,A,B,F)
71153 #define INTVVVVVVV_cfV(T,A,B,F)
71154 #define PINT_cfV(      T,A,B,F) _(T,_cfVP)(A,B)
71155 #define PVOID_cfV(     T,A,B,F)
71156 #if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran) || defined(AbsoftProFortran)
71157 #define    ROUTINE_cfV(T,A,B,F) void (*B)(CF_NULL_PROTO) = (cfCAST_FUNCTION)A;
71158 #else
71159 #define    ROUTINE_cfV(T,A,B,F)
71160 #endif
71161 #define     SIMPLE_cfV(T,A,B,F)
71162 #ifdef vmsFortran
71163 #define     STRING_cfV(T,A,B,F) static struct {fstring f; unsigned clen;} B =  \
71164                                        {{0,DSC$K_DTYPE_T,DSC$K_CLASS_S,NULL},0};
71165 #define    PSTRING_cfV(T,A,B,F) static fstring B={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,NULL};
71166 #define    STRINGV_cfV(T,A,B,F) static fstringvector B =                       \
71167   {sizeof(A),DSC$K_DTYPE_T,DSC$K_CLASS_A,NULL,0,0,{0,0,1,1,1},1,0,NULL,0,{1,0}};
71168 #define   PSTRINGV_cfV(T,A,B,F) static fstringvector B =                       \
71169           {0,DSC$K_DTYPE_T,DSC$K_CLASS_A,NULL,0,0,{0,0,1,1,1},1,0,NULL,0,{1,0}};
71170 #else
71171 #define     STRING_cfV(T,A,B,F) struct {unsigned int clen, flen; char *nombre;} B;
71172 #define    STRINGV_cfV(T,A,B,F) struct {char *s, *fs; unsigned flen; char *nombre;} B;
71173 #define    PSTRING_cfV(T,A,B,F) int     B;
71174 #define   PSTRINGV_cfV(T,A,B,F) struct{char *fs; unsigned int sizeofA,flen;}B;
71175 #endif
71176 #define    ZTRINGV_cfV(T,A,B,F)  STRINGV_cfV(T,A,B,F)
71177 #define   PZTRINGV_cfV(T,A,B,F) PSTRINGV_cfV(T,A,B,F)
71178 
71179 /* Note that the actions of the A table were performed inside the AA table.
71180    VAX Ultrix vcc, and HP-UX cc, didn't evaluate arguments to functions left to
71181    right, so we had to split the original table into the current robust two. */
71182 #define ACF(NAME,TN,AI,I)      _(TN,_cfSTR)(4,A,NAME,I,AI,_(B,I),0)
71183 #define   DEFAULT_cfA(M,I,A,B)
71184 #define   LOGICAL_cfA(M,I,A,B) B=C2FLOGICAL(B);
71185 #define  PLOGICAL_cfA(M,I,A,B) A=C2FLOGICAL(A);
71186 #define    STRING_cfA(M,I,A,B)  STRING_cfC(M,I,A,B,sizeof(A))
71187 #define   PSTRING_cfA(M,I,A,B) PSTRING_cfC(M,I,A,B,sizeof(A))
71188 #ifdef vmsFortran
71189 #define  AATRINGV_cfA(    A,B, sA,filA,silA)                                   \
71190  initfstr(B,_cf_malloc((sA)-(filA)),(filA),(silA)-1),                          \
71191           c2fstrv(A,B.dsc$a_pointer,(silA),(sA));
71192 #define APATRINGV_cfA(    A,B, sA,filA,silA)                                   \
71193  initfstr(B,A,(filA),(silA)-1),c2fstrv(A,A,(silA),(sA));
71194 #else
71195 #define  AATRINGV_cfA(    A,B, sA,filA,silA)                                   \
71196      (B.s=_cf_malloc((sA)-(filA)),B.fs=c2fstrv(A,B.s,(B.flen=(silA)-1)+1,(sA)));
71197 #define APATRINGV_cfA(    A,B, sA,filA,silA)                                   \
71198  B.fs=c2fstrv(A,A,(B.flen=(silA)-1)+1,B.sizeofA=(sA));
71199 #endif
71200 #define   STRINGV_cfA(M,I,A,B)                                                 \
71201     AATRINGV_cfA((char *)A,B,sizeof(A),firstindexlength(A),secondindexlength(A))
71202 #define  PSTRINGV_cfA(M,I,A,B)                                                 \
71203    APATRINGV_cfA((char *)A,B,sizeof(A),firstindexlength(A),secondindexlength(A))
71204 #define   ZTRINGV_cfA(M,I,A,B)  AATRINGV_cfA( (char *)A,B,                     \
71205                     (_3(M,_ELEMS_,I))*(( _3(M,_ELEMLEN_,I))+1),                \
71206                               (_3(M,_ELEMS_,I)),(_3(M,_ELEMLEN_,I))+1)
71207 #define  PZTRINGV_cfA(M,I,A,B) APATRINGV_cfA( (char *)A,B,                     \
71208                     (_3(M,_ELEMS_,I))*(( _3(M,_ELEMLEN_,I))+1),                \
71209                               (_3(M,_ELEMS_,I)),(_3(M,_ELEMLEN_,I))+1)
71210 
71211 #define    PBYTE_cfAAP(A,B) &A
71212 #define  PDOUBLE_cfAAP(A,B) &A
71213 #define   PFLOAT_cfAAP(A,B) FLOATVVVVVVV_cfPP &A
71214 #define     PINT_cfAAP(A,B) &A
71215 #define PLOGICAL_cfAAP(A,B) B= &A         /* B used to keep a common W table. */
71216 #define    PLONG_cfAAP(A,B) &A
71217 #define   PSHORT_cfAAP(A,B) &A
71218 
71219 #define AACF(TN,AI,I,C) _SEP_(TN,C,cfCOMMA) _Icf(3,AA,TN,AI,_(B,I))
71220 #define        INT_cfAA(T,A,B) &B
71221 #define       INTV_cfAA(T,A,B) _(T,VVVVVV_cfPP) A
71222 #define      INTVV_cfAA(T,A,B) _(T,VVVVV_cfPP)  A[0]
71223 #define     INTVVV_cfAA(T,A,B) _(T,VVVV_cfPP)   A[0][0]
71224 #define    INTVVVV_cfAA(T,A,B) _(T,VVV_cfPP)    A[0][0][0]
71225 #define   INTVVVVV_cfAA(T,A,B) _(T,VV_cfPP)     A[0][0][0][0]
71226 #define  INTVVVVVV_cfAA(T,A,B) _(T,V_cfPP)      A[0][0][0][0][0]
71227 #define INTVVVVVVV_cfAA(T,A,B) _(T,_cfPP)       A[0][0][0][0][0][0]
71228 #define       PINT_cfAA(T,A,B) _(T,_cfAAP)(A,B)
71229 #define      PVOID_cfAA(T,A,B) (void *) A
71230 #if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran)
71231 #define    ROUTINE_cfAA(T,A,B) &B
71232 #else
71233 #define    ROUTINE_cfAA(T,A,B) (cfCAST_FUNCTION)A
71234 #endif
71235 #define     STRING_cfAA(T,A,B)  STRING_cfCC(T,A,B)
71236 #define    PSTRING_cfAA(T,A,B) PSTRING_cfCC(T,A,B)
71237 #ifdef vmsFortran
71238 #define    STRINGV_cfAA(T,A,B) &B
71239 #else
71240 #ifdef CRAYFortran
71241 #define    STRINGV_cfAA(T,A,B) _cptofcd(B.fs,B.flen)
71242 #else
71243 #define    STRINGV_cfAA(T,A,B) B.fs
71244 #endif
71245 #endif
71246 #define   PSTRINGV_cfAA(T,A,B) STRINGV_cfAA(T,A,B)
71247 #define    ZTRINGV_cfAA(T,A,B) STRINGV_cfAA(T,A,B)
71248 #define   PZTRINGV_cfAA(T,A,B) STRINGV_cfAA(T,A,B)
71249 
71250 #if defined(vmsFortran) || defined(CRAYFortran)
71251 #define JCF(TN,I)
71252 #define KCF(TN,I)
71253 #else
71254 #define JCF(TN,I)    _(TN,_cfSTR)(1,J,_(B,I), 0,0,0,0)
71255 #if defined(AbsoftUNIXFortran)
71256 #define  DEFAULT_cfJ(B) ,0
71257 #else
71258 #define  DEFAULT_cfJ(B)
71259 #endif
71260 #define  LOGICAL_cfJ(B) DEFAULT_cfJ(B)
71261 #define PLOGICAL_cfJ(B) DEFAULT_cfJ(B)
71262 #define   STRING_cfJ(B) ,B.flen
71263 #define  PSTRING_cfJ(B) ,B
71264 #define  STRINGV_cfJ(B) STRING_cfJ(B)
71265 #define PSTRINGV_cfJ(B) STRING_cfJ(B)
71266 #define  ZTRINGV_cfJ(B) STRING_cfJ(B)
71267 #define PZTRINGV_cfJ(B) STRING_cfJ(B)
71268 
71269 /* KCF is identical to DCF, except that KCF ZTRING is not empty. */
71270 #define KCF(TN,I)    _(TN,_cfSTR)(1,KK,_(B,I), 0,0,0,0)
71271 #if defined(AbsoftUNIXFortran)
71272 #define  DEFAULT_cfKK(B) , unsigned B
71273 #else
71274 #define  DEFAULT_cfKK(B)
71275 #endif
71276 #define  LOGICAL_cfKK(B) DEFAULT_cfKK(B)
71277 #define PLOGICAL_cfKK(B) DEFAULT_cfKK(B)
71278 #define   STRING_cfKK(B) , unsigned B
71279 #define  PSTRING_cfKK(B) STRING_cfKK(B)
71280 #define  STRINGV_cfKK(B) STRING_cfKK(B)
71281 #define PSTRINGV_cfKK(B) STRING_cfKK(B)
71282 #define  ZTRINGV_cfKK(B) STRING_cfKK(B)
71283 #define PZTRINGV_cfKK(B) STRING_cfKK(B)
71284 #endif
71285 
71286 #define WCF(TN,AN,I)      _(TN,_cfSTR)(2,W,AN,_(B,I), 0,0,0)
71287 #define  DEFAULT_cfW(A,B)
71288 #define  LOGICAL_cfW(A,B)
71289 #define PLOGICAL_cfW(A,B) *B=F2CLOGICAL(*B);
71290 #define   STRING_cfW(A,B) (B.nombre=A,B.nombre[B.clen]!='\0'?B.nombre[B.clen]='\0':0); /* A?="constnt"*/
71291 #define  PSTRING_cfW(A,B) kill_trailing(A,' ');
71292 #ifdef vmsFortran
71293 #define  STRINGV_cfW(A,B) _cf_free(B.dsc$a_pointer);
71294 #define PSTRINGV_cfW(A,B)                                                      \
71295   vkill_trailing(f2cstrv((char*)A, (char*)A,                                   \
71296                            B.dsc$w_length+1, B.dsc$l_arsize+B.dsc$l_m[0]),     \
71297                    B.dsc$w_length+1, B.dsc$l_arsize+B.dsc$l_m[0], ' ');
71298 #else
71299 #define  STRINGV_cfW(A,B) _cf_free(B.s);
71300 #define PSTRINGV_cfW(A,B) vkill_trailing(                                      \
71301          f2cstrv((char*)A,(char*)A,B.flen+1,B.sizeofA), B.flen+1,B.sizeofA,' ');
71302 #endif
71303 #define  ZTRINGV_cfW(A,B)      STRINGV_cfW(A,B)
71304 #define PZTRINGV_cfW(A,B)     PSTRINGV_cfW(A,B)
71305 
71306 #define   NCF(TN,I,C)       _SEP_(TN,C,cfCOMMA) _Icf(2,N,TN,_(A,I),0)
71307 #define  NNCF(TN,I,C)        UUCF(TN,I,C)
71308 #define NNNCF(TN,I,C)       _SEP_(TN,C,cfCOLON) _Icf(2,N,TN,_(A,I),0)
71309 #define        INT_cfN(T,A) _(T,VVVVVVV_cfTYPE) * A
71310 #define       INTV_cfN(T,A) _(T,VVVVVV_cfTYPE)  * A
71311 #define      INTVV_cfN(T,A) _(T,VVVVV_cfTYPE)   * A
71312 #define     INTVVV_cfN(T,A) _(T,VVVV_cfTYPE)    * A
71313 #define    INTVVVV_cfN(T,A) _(T,VVV_cfTYPE)     * A
71314 #define   INTVVVVV_cfN(T,A) _(T,VV_cfTYPE)      * A
71315 #define  INTVVVVVV_cfN(T,A) _(T,V_cfTYPE)       * A
71316 #define INTVVVVVVV_cfN(T,A) _(T,_cfTYPE)        * A
71317 #define       PINT_cfN(T,A) _(T,_cfTYPE)        * A
71318 #define      PVOID_cfN(T,A) void *                A
71319 #if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran)
71320 #define    ROUTINE_cfN(T,A) void (**A)(CF_NULL_PROTO)
71321 #else
71322 #define    ROUTINE_cfN(T,A) void ( *A)(CF_NULL_PROTO)
71323 #endif
71324 #ifdef vmsFortran
71325 #define     STRING_cfN(T,A) fstring *             A
71326 #define    STRINGV_cfN(T,A) fstringvector *       A
71327 #else
71328 #ifdef CRAYFortran
71329 #define     STRING_cfN(T,A) _fcd                  A
71330 #define    STRINGV_cfN(T,A) _fcd                  A
71331 #else
71332 #define     STRING_cfN(T,A) char *                A
71333 #define    STRINGV_cfN(T,A) char *                A
71334 #endif
71335 #endif
71336 #define    PSTRING_cfN(T,A)   STRING_cfN(T,A) /* CRAY insists on arg.'s here. */
71337 #define   PNSTRING_cfN(T,A)   STRING_cfN(T,A) /* CRAY insists on arg.'s here. */
71338 #define   PPSTRING_cfN(T,A)   STRING_cfN(T,A) /* CRAY insists on arg.'s here. */
71339 #define   PSTRINGV_cfN(T,A)  STRINGV_cfN(T,A)
71340 #define    ZTRINGV_cfN(T,A)  STRINGV_cfN(T,A)
71341 #define   PZTRINGV_cfN(T,A) PSTRINGV_cfN(T,A)
71342 
71343 
71344 /* Apollo 6.7, CRAY, old Sun, VAX/Ultrix vcc/cc and new ultrix
71345    can't hack more than 31 arg's.
71346    e.g. ultrix >= 4.3 gives message:
71347        zow35> cc -c -DDECFortran cfortest.c
71348        cfe: Fatal: Out of memory: cfortest.c
71349        zow35>
71350    Old __hpux had the problem, but new 'HP-UX A.09.03 A 9000/735' is fine
71351    if using -Aa, otherwise we have a problem.
71352  */
71353 #ifndef MAX_PREPRO_ARGS
71354 #if !defined(__GNUC__) && (defined(VAXUltrix) || defined(__CF__APOLLO67) || (defined(sun)&&!defined(__sun)) || defined(_CRAY) || defined(__ultrix__) || (defined(__hpux)&&defined(__CF__KnR)))
71355 #define MAX_PREPRO_ARGS 31
71356 #else
71357 #define MAX_PREPRO_ARGS 99
71358 #endif
71359 #endif
71360 
71361 #if defined(AbsoftUNIXFortran) || defined(AbsoftProFortran)
71362 /* In addition to explicit Absoft stuff, only Absoft requires:
71363    - DEFAULT coming from _cfSTR.
71364      DEFAULT could have been called e.g. INT, but keep it for clarity.
71365    - M term in CFARGT14 and CFARGT14FS.
71366  */
71367 #define ABSOFT_cf1(T0) _(T0,_cfSTR)(0,ABSOFT1,0,0,0,0,0)
71368 #define ABSOFT_cf2(T0) _(T0,_cfSTR)(0,ABSOFT2,0,0,0,0,0)
71369 #define ABSOFT_cf3(T0) _(T0,_cfSTR)(0,ABSOFT3,0,0,0,0,0)
71370 #define DEFAULT_cfABSOFT1
71371 #define LOGICAL_cfABSOFT1
71372 #define  STRING_cfABSOFT1 ,MAX_LEN_FORTRAN_FUNCTION_STRING
71373 #define DEFAULT_cfABSOFT2
71374 #define LOGICAL_cfABSOFT2
71375 #define  STRING_cfABSOFT2 ,unsigned D0
71376 #define DEFAULT_cfABSOFT3
71377 #define LOGICAL_cfABSOFT3
71378 #define  STRING_cfABSOFT3 ,D0
71379 #else
71380 #define ABSOFT_cf1(T0)
71381 #define ABSOFT_cf2(T0)
71382 #define ABSOFT_cf3(T0)
71383 #endif
71384 
71385 /* _Z introduced to cicumvent IBM and HP silly preprocessor warning.
71386    e.g. "Macro CFARGT14 invoked with a null argument."
71387  */
71388 #define _Z
71389 
71390 #define  CFARGT14S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)                \
71391  S(T1,1)   S(T2,2)   S(T3,3)    S(T4,4)    S(T5,5)    S(T6,6)    S(T7,7)       \
71392  S(T8,8)   S(T9,9)   S(TA,10)   S(TB,11)   S(TC,12)   S(TD,13)   S(TE,14)
71393 #define  CFARGT27S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
71394  S(T1,1)   S(T2,2)   S(T3,3)    S(T4,4)    S(T5,5)    S(T6,6)    S(T7,7)       \
71395  S(T8,8)   S(T9,9)   S(TA,10)   S(TB,11)   S(TC,12)   S(TD,13)   S(TE,14)      \
71396  S(TF,15)  S(TG,16)  S(TH,17)   S(TI,18)   S(TJ,19)   S(TK,20)   S(TL,21)      \
71397  S(TM,22)  S(TN,23)  S(TO,24)   S(TP,25)   S(TQ,26)   S(TR,27)
71398 
71399 #define  CFARGT14FS(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)           \
71400  F(T1,1,0) F(T2,2,1) F(T3,3,1)  F(T4,4,1)  F(T5,5,1)  F(T6,6,1)  F(T7,7,1)     \
71401  F(T8,8,1) F(T9,9,1) F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1)    \
71402  M       CFARGT14S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
71403 #define  CFARGT27FS(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
71404  F(T1,1,0)  F(T2,2,1)  F(T3,3,1)  F(T4,4,1)  F(T5,5,1)  F(T6,6,1)  F(T7,7,1)   \
71405  F(T8,8,1)  F(T9,9,1)  F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1)  \
71406  F(TF,15,1) F(TG,16,1) F(TH,17,1) F(TI,18,1) F(TJ,19,1) F(TK,20,1) F(TL,21,1)  \
71407  F(TM,22,1) F(TN,23,1) F(TO,24,1) F(TP,25,1) F(TQ,26,1) F(TR,27,1)             \
71408  M       CFARGT27S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
71409 
71410 #if !(defined(PowerStationFortran)||defined(hpuxFortran800))
71411 /*  Old CFARGT14 -> CFARGT14FS as seen below, for Absoft cross-compile yields:
71412       SunOS> cc -c -Xa -DAbsoftUNIXFortran c.c
71413       "c.c", line 406: warning: argument mismatch
71414     Haven't checked if this is ANSI C or a SunOS bug. SunOS -Xs works ok.
71415     Behavior is most clearly seen in example:
71416       #define A 1 , 2
71417       #define  C(X,Y,Z) x=X. y=Y. z=Z.
71418       #define  D(X,Y,Z) C(X,Y,Z)
71419       D(x,A,z)
71420     Output from preprocessor is: x = x . y = 1 . z = 2 .
71421  #define CFARGT14(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
71422        CFARGT14FS(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
71423 */
71424 #define  CFARGT14(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)             \
71425  F(T1,1,0) F(T2,2,1) F(T3,3,1)  F(T4,4,1)  F(T5,5,1)  F(T6,6,1)  F(T7,7,1)     \
71426  F(T8,8,1) F(T9,9,1) F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1)    \
71427  M       CFARGT14S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
71428 #define  CFARGT27(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
71429  F(T1,1,0)  F(T2,2,1)  F(T3,3,1)  F(T4,4,1)  F(T5,5,1)  F(T6,6,1)  F(T7,7,1)   \
71430  F(T8,8,1)  F(T9,9,1)  F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1)  \
71431  F(TF,15,1) F(TG,16,1) F(TH,17,1) F(TI,18,1) F(TJ,19,1) F(TK,20,1) F(TL,21,1)  \
71432  F(TM,22,1) F(TN,23,1) F(TO,24,1) F(TP,25,1) F(TQ,26,1) F(TR,27,1)             \
71433  M       CFARGT27S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
71434 
71435 #define  CFARGT20(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
71436  F(T1,1,0)  F(T2,2,1)  F(T3,3,1)  F(T4,4,1)  F(T5,5,1)  F(T6,6,1)  F(T7,7,1)   \
71437  F(T8,8,1)  F(T9,9,1)  F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1)  \
71438  F(TF,15,1) F(TG,16,1) F(TH,17,1) F(TI,18,1) F(TJ,19,1) F(TK,20,1)             \
71439  S(T1,1)    S(T2,2)    S(T3,3)    S(T4,4)    S(T5,5)    S(T6,6)    S(T7,7)     \
71440  S(T8,8)    S(T9,9)    S(TA,10)   S(TB,11)   S(TC,12)   S(TD,13)   S(TE,14)    \
71441  S(TF,15)   S(TG,16)   S(TH,17)   S(TI,18)   S(TJ,19)   S(TK,20)
71442 #define CFARGTA14(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE) \
71443  F(T1,A1,1,0)  F(T2,A2,2,1)  F(T3,A3,3,1) F(T4,A4,4,1)  F(T5,A5,5,1)  F(T6,A6,6,1)  \
71444  F(T7,A7,7,1)  F(T8,A8,8,1)  F(T9,A9,9,1) F(TA,AA,10,1) F(TB,AB,11,1) F(TC,AC,12,1) \
71445  F(TD,AD,13,1) F(TE,AE,14,1) S(T1,1)      S(T2,2)       S(T3,3)       S(T4,4)       \
71446  S(T5,5)       S(T6,6)       S(T7,7)      S(T8,8)       S(T9,9)       S(TA,10)      \
71447  S(TB,11)      S(TC,12)      S(TD,13)     S(TE,14)
71448 #if MAX_PREPRO_ARGS>31
71449 #define CFARGTA20(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) \
71450  F(T1,A1,1,0)  F(T2,A2,2,1)  F(T3,A3,3,1)  F(T4,A4,4,1)  F(T5,A5,5,1)  F(T6,A6,6,1)  \
71451  F(T7,A7,7,1)  F(T8,A8,8,1)  F(T9,A9,9,1)  F(TA,AA,10,1) F(TB,AB,11,1) F(TC,AC,12,1) \
71452  F(TD,AD,13,1) F(TE,AE,14,1) F(TF,AF,15,1) F(TG,AG,16,1) F(TH,AH,17,1) F(TI,AI,18,1) \
71453  F(TJ,AJ,19,1) F(TK,AK,20,1) S(T1,1)       S(T2,2)       S(T3,3)       S(T4,4)       \
71454  S(T5,5)       S(T6,6)       S(T7,7)       S(T8,8)       S(T9,9)       S(TA,10)      \
71455  S(TB,11)      S(TC,12)      S(TD,13)      S(TE,14)      S(TF,15)      S(TG,16)      \
71456  S(TH,17)      S(TI,18)      S(TJ,19)      S(TK,20)
71457 #define CFARGTA27(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) \
71458  F(T1,A1,1,0)  F(T2,A2,2,1)  F(T3,A3,3,1)  F(T4,A4,4,1)  F(T5,A5,5,1)  F(T6,A6,6,1)  \
71459  F(T7,A7,7,1)  F(T8,A8,8,1)  F(T9,A9,9,1)  F(TA,AA,10,1) F(TB,AB,11,1) F(TC,AC,12,1) \
71460  F(TD,AD,13,1) F(TE,AE,14,1) F(TF,AF,15,1) F(TG,AG,16,1) F(TH,AH,17,1) F(TI,AI,18,1) \
71461  F(TJ,AJ,19,1) F(TK,AK,20,1) F(TL,AL,21,1) F(TM,AM,22,1) F(TN,AN,23,1) F(TO,AO,24,1) \
71462  F(TP,AP,25,1) F(TQ,AQ,26,1) F(TR,AR,27,1) S(T1,1)       S(T2,2)       S(T3,3)       \
71463  S(T4,4)       S(T5,5)       S(T6,6)       S(T7,7)       S(T8,8)       S(T9,9)       \
71464  S(TA,10)      S(TB,11)      S(TC,12)      S(TD,13)      S(TE,14)      S(TF,15)      \
71465  S(TG,16)      S(TH,17)      S(TI,18)      S(TJ,19)      S(TK,20)      S(TL,21)      \
71466  S(TM,22)      S(TN,23)      S(TO,24)      S(TP,25)      S(TQ,26)      S(TR,27)
71467 #endif
71468 #else
71469 #define  CFARGT14(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)             \
71470  F(T1,1,0) S(T1,1) F(T2,2,1)  S(T2,2)  F(T3,3,1)  S(T3,3)  F(T4,4,1)  S(T4,4)  \
71471  F(T5,5,1) S(T5,5) F(T6,6,1)  S(T6,6)  F(T7,7,1)  S(T7,7)  F(T8,8,1)  S(T8,8)  \
71472  F(T9,9,1) S(T9,9) F(TA,10,1) S(TA,10) F(TB,11,1) S(TB,11) F(TC,12,1) S(TC,12) \
71473  F(TD,13,1) S(TD,13) F(TE,14,1) S(TE,14)
71474 #define  CFARGT27(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
71475  F(T1,1,0)  S(T1,1)  F(T2,2,1)  S(T2,2)  F(T3,3,1)  S(T3,3)  F(T4,4,1)  S(T4,4)  \
71476  F(T5,5,1)  S(T5,5)  F(T6,6,1)  S(T6,6)  F(T7,7,1)  S(T7,7)  F(T8,8,1)  S(T8,8)  \
71477  F(T9,9,1)  S(T9,9)  F(TA,10,1) S(TA,10) F(TB,11,1) S(TB,11) F(TC,12,1) S(TC,12) \
71478  F(TD,13,1) S(TD,13) F(TE,14,1) S(TE,14) F(TF,15,1) S(TF,15) F(TG,16,1) S(TG,16) \
71479  F(TH,17,1) S(TH,17) F(TI,18,1) S(TI,18) F(TJ,19,1) S(TJ,19) F(TK,20,1) S(TK,20) \
71480  F(TL,21,1) S(TL,21) F(TM,22,1) S(TM,22) F(TN,23,1) S(TN,23) F(TO,24,1) S(TO,24) \
71481  F(TP,25,1) S(TP,25) F(TQ,26,1) S(TQ,26) F(TR,27,1) S(TR,27)
71482 
71483 #define  CFARGT20(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
71484  F(T1,1,0)  S(T1,1)  F(T2,2,1)  S(T2,2)  F(T3,3,1)  S(T3,3)  F(T4,4,1)  S(T4,4)  \
71485  F(T5,5,1)  S(T5,5)  F(T6,6,1)  S(T6,6)  F(T7,7,1)  S(T7,7)  F(T8,8,1)  S(T8,8)  \
71486  F(T9,9,1)  S(T9,9)  F(TA,10,1) S(TA,10) F(TB,11,1) S(TB,11) F(TC,12,1) S(TC,12) \
71487  F(TD,13,1) S(TD,13) F(TE,14,1) S(TE,14) F(TF,15,1) S(TF,15) F(TG,16,1) S(TG,16) \
71488  F(TH,17,1) S(TH,17) F(TI,18,1) S(TI,18) F(TJ,19,1) S(TJ,19) F(TK,20,1) S(TK,20)
71489 #define CFARGTA14(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE) \
71490  F(T1,A1,1,0)  S(T1,1)  F(T2,A2,2,1)  S(T2,2)  F(T3,A3,3,1)  S(T3,3)           \
71491  F(T4,A4,4,1)  S(T4,4)  F(T5,A5,5,1)  S(T5,5)  F(T6,A6,6,1)  S(T6,6)           \
71492  F(T7,A7,7,1)  S(T7,7)  F(T8,A8,8,1)  S(T8,8)  F(T9,A9,9,1)  S(T9,9)           \
71493  F(TA,AA,10,1) S(TA,10) F(TB,AB,11,1) S(TB,11) F(TC,AC,12,1) S(TC,12)          \
71494  F(TD,AD,13,1) S(TD,13) F(TE,AE,14,1) S(TE,14)
71495 #if MAX_PREPRO_ARGS>31
71496 #define CFARGTA20(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) \
71497  F(T1,A1,1,0)  S(T1,1)  F(T2,A2,2,1)  S(T2,2)  F(T3,A3,3,1)  S(T3,3)           \
71498  F(T4,A4,4,1)  S(T4,4)  F(T5,A5,5,1)  S(T5,5)  F(T6,A6,6,1)  S(T6,6)           \
71499  F(T7,A7,7,1)  S(T7,7)  F(T8,A8,8,1)  S(T8,8)  F(T9,A9,9,1)  S(T9,9)           \
71500  F(TA,AA,10,1) S(TA,10) F(TB,AB,11,1) S(TB,11) F(TC,AC,12,1) S(TC,12)          \
71501  F(TD,AD,13,1) S(TD,13) F(TE,AE,14,1) S(TE,14) F(TF,AF,15,1) S(TF,15)          \
71502  F(TG,AG,16,1) S(TG,16) F(TH,AH,17,1) S(TH,17) F(TI,AI,18,1) S(TI,18)          \
71503  F(TJ,AJ,19,1) S(TJ,19) F(TK,AK,20,1) S(TK,20)
71504 #define CFARGTA27(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) \
71505  F(T1,A1,1,0)  S(T1,1)  F(T2,A2,2,1)  S(T2,2)  F(T3,A3,3,1)  S(T3,3)           \
71506  F(T4,A4,4,1)  S(T4,4)  F(T5,A5,5,1)  S(T5,5)  F(T6,A6,6,1)  S(T6,6)           \
71507  F(T7,A7,7,1)  S(T7,7)  F(T8,A8,8,1)  S(T8,8)  F(T9,A9,9,1)  S(T9,9)           \
71508  F(TA,AA,10,1) S(TA,10) F(TB,AB,11,1) S(TB,11) F(TC,AC,12,1) S(TC,12)          \
71509  F(TD,AD,13,1) S(TD,13) F(TE,AE,14,1) S(TE,14) F(TF,AF,15,1) S(TF,15)          \
71510  F(TG,AG,16,1) S(TG,16) F(TH,AH,17,1) S(TH,17) F(TI,AI,18,1) S(TI,18)          \
71511  F(TJ,AJ,19,1) S(TJ,19) F(TK,AK,20,1) S(TK,20) F(TL,AL,21,1) S(TL,21)          \
71512  F(TM,AM,22,1) S(TM,22) F(TN,AN,23,1) S(TN,23) F(TO,AO,24,1) S(TO,24)          \
71513  F(TP,AP,25,1) S(TP,25) F(TQ,AQ,26,1) S(TQ,26) F(TR,AR,27,1) S(TR,27)
71514 #endif
71515 #endif
71516 
71517 
71518 #define PROTOCCALLSFSUB1( UN,LN,T1) \
71519         PROTOCCALLSFSUB14(UN,LN,T1,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
71520 #define PROTOCCALLSFSUB2( UN,LN,T1,T2) \
71521         PROTOCCALLSFSUB14(UN,LN,T1,T2,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
71522 #define PROTOCCALLSFSUB3( UN,LN,T1,T2,T3) \
71523         PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
71524 #define PROTOCCALLSFSUB4( UN,LN,T1,T2,T3,T4) \
71525         PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
71526 #define PROTOCCALLSFSUB5( UN,LN,T1,T2,T3,T4,T5) \
71527         PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
71528 #define PROTOCCALLSFSUB6( UN,LN,T1,T2,T3,T4,T5,T6) \
71529         PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
71530 #define PROTOCCALLSFSUB7( UN,LN,T1,T2,T3,T4,T5,T6,T7) \
71531         PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
71532 #define PROTOCCALLSFSUB8( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8) \
71533         PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
71534 #define PROTOCCALLSFSUB9( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9) \
71535         PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0,CF_0,CF_0,CF_0,CF_0)
71536 #define PROTOCCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA) \
71537         PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0)
71538 #define PROTOCCALLSFSUB11(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB) \
71539         PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0)
71540 #define PROTOCCALLSFSUB12(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC) \
71541         PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0)
71542 #define PROTOCCALLSFSUB13(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD) \
71543         PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0)
71544 
71545 
71546 #define PROTOCCALLSFSUB15(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF) \
71547         PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,CF_0,CF_0,CF_0,CF_0,CF_0)
71548 #define PROTOCCALLSFSUB16(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG) \
71549         PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,CF_0,CF_0,CF_0,CF_0)
71550 #define PROTOCCALLSFSUB17(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH) \
71551         PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,CF_0,CF_0,CF_0)
71552 #define PROTOCCALLSFSUB18(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI) \
71553         PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,CF_0,CF_0)
71554 #define PROTOCCALLSFSUB19(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ) \
71555         PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,CF_0)
71556 
71557 #define PROTOCCALLSFSUB21(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL) \
71558         PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
71559 #define PROTOCCALLSFSUB22(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM) \
71560         PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,CF_0,CF_0,CF_0,CF_0,CF_0)
71561 #define PROTOCCALLSFSUB23(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN) \
71562         PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,CF_0,CF_0,CF_0,CF_0)
71563 #define PROTOCCALLSFSUB24(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO) \
71564         PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,CF_0,CF_0,CF_0)
71565 #define PROTOCCALLSFSUB25(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP) \
71566         PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,CF_0,CF_0)
71567 #define PROTOCCALLSFSUB26(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ) \
71568         PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,CF_0)
71569 
71570 
71571 #ifndef FCALLSC_QUALIFIER
71572 #ifdef VISUAL_CPLUSPLUS
71573 #define FCALLSC_QUALIFIER __stdcall
71574 #else
71575 #define FCALLSC_QUALIFIER
71576 #endif
71577 #endif
71578 
71579 #ifdef __cplusplus
71580 #define CFextern extern "C"
71581 #else
71582 #define CFextern extern
71583 #endif
71584 
71585 
71586 #ifdef CFSUBASFUN
71587 #define PROTOCCALLSFSUB0(UN,LN) \
71588    PROTOCCALLSFFUN0( VOID,UN,LN)
71589 #define PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
71590    PROTOCCALLSFFUN14(VOID,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
71591 #define PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)\
71592    PROTOCCALLSFFUN20(VOID,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)
71593 #define PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)\
71594    PROTOCCALLSFFUN27(VOID,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
71595 #else
71596 /* Note: Prevent compiler warnings, null #define PROTOCCALLSFSUB14/20 after
71597    #include-ing cfortran.h if calling the FORTRAN wrapper within the same
71598    source code where the wrapper is created. */
71599 #define PROTOCCALLSFSUB0(UN,LN)     _(VOID,_cfPU)(CFC_(UN,LN))();
71600 #ifndef __CF__KnR
71601 #define PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
71602  _(VOID,_cfPU)(CFC_(UN,LN))( CFARGT14(NCF,KCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) );
71603 #define PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)\
71604  _(VOID,_cfPU)(CFC_(UN,LN))( CFARGT20(NCF,KCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) );
71605 #define PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)\
71606  _(VOID,_cfPU)(CFC_(UN,LN))( CFARGT27(NCF,KCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) );
71607 #else
71608 #define PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)     \
71609          PROTOCCALLSFSUB0(UN,LN)
71610 #define PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
71611          PROTOCCALLSFSUB0(UN,LN)
71612 #define PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
71613          PROTOCCALLSFSUB0(UN,LN)
71614 #endif
71615 #endif
71616 
71617 
71618 #ifdef OLD_VAXC                                  /* Allow %CC-I-PARAMNOTUSED. */
71619 #pragma standard
71620 #endif
71621 
71622 
71623 #define CCALLSFSUB1( UN,LN,T1,                        A1)         \
71624         CCALLSFSUB5 (UN,LN,T1,CF_0,CF_0,CF_0,CF_0,A1,0,0,0,0)
71625 #define CCALLSFSUB2( UN,LN,T1,T2,                     A1,A2)      \
71626         CCALLSFSUB5 (UN,LN,T1,T2,CF_0,CF_0,CF_0,A1,A2,0,0,0)
71627 #define CCALLSFSUB3( UN,LN,T1,T2,T3,                  A1,A2,A3)   \
71628         CCALLSFSUB5 (UN,LN,T1,T2,T3,CF_0,CF_0,A1,A2,A3,0,0)
71629 #define CCALLSFSUB4( UN,LN,T1,T2,T3,T4,               A1,A2,A3,A4)\
71630         CCALLSFSUB5 (UN,LN,T1,T2,T3,T4,CF_0,A1,A2,A3,A4,0)
71631 #define CCALLSFSUB5( UN,LN,T1,T2,T3,T4,T5,            A1,A2,A3,A4,A5)          \
71632         CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,0,0,0,0,0)
71633 #define CCALLSFSUB6( UN,LN,T1,T2,T3,T4,T5,T6,         A1,A2,A3,A4,A5,A6)       \
71634         CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,0,0,0,0)
71635 #define CCALLSFSUB7( UN,LN,T1,T2,T3,T4,T5,T6,T7,      A1,A2,A3,A4,A5,A6,A7)    \
71636         CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,0,0,0)
71637 #define CCALLSFSUB8( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,   A1,A2,A3,A4,A5,A6,A7,A8) \
71638         CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,0,0)
71639 #define CCALLSFSUB9( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,A1,A2,A3,A4,A5,A6,A7,A8,A9)\
71640         CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,0)
71641 #define CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA)\
71642         CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,0,0,0,0)
71643 #define CCALLSFSUB11(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB)\
71644         CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,0,0,0)
71645 #define CCALLSFSUB12(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC)\
71646         CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,0,0)
71647 #define CCALLSFSUB13(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD)\
71648         CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,0)
71649 
71650 #ifdef __cplusplus
71651 #define CPPPROTOCLSFSUB0( UN,LN)
71652 #define CPPPROTOCLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
71653 #define CPPPROTOCLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)
71654 #define CPPPROTOCLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
71655 #else
71656 #define CPPPROTOCLSFSUB0(UN,LN) \
71657         PROTOCCALLSFSUB0(UN,LN)
71658 #define CPPPROTOCLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)     \
71659         PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
71660 #define CPPPROTOCLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
71661         PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)
71662 #define CPPPROTOCLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
71663         PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
71664 #endif
71665 
71666 #ifdef CFSUBASFUN
71667 #define CCALLSFSUB0(UN,LN) CCALLSFFUN0(UN,LN)
71668 #define CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE)\
71669         CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE)
71670 #else
71671 /* do{...}while(0) allows if(a==b) FORT(); else BORT(); */
71672 #define CCALLSFSUB0( UN,LN) do{CPPPROTOCLSFSUB0(UN,LN) CFC_(UN,LN)();}while(0)
71673 #define CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE)\
71674 do{VVCF(T1,A1,B1) VVCF(T2,A2,B2) VVCF(T3,A3,B3) VVCF(T4,A4,B4) VVCF(T5,A5,B5)  \
71675    VVCF(T6,A6,B6) VVCF(T7,A7,B7) VVCF(T8,A8,B8) VVCF(T9,A9,B9) VVCF(TA,AA,B10) \
71676    VVCF(TB,AB,B11) VVCF(TC,AC,B12) VVCF(TD,AD,B13) VVCF(TE,AE,B14)             \
71677    CPPPROTOCLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)          \
71678    ACF(LN,T1,A1,1)  ACF(LN,T2,A2,2)  ACF(LN,T3,A3,3)                           \
71679    ACF(LN,T4,A4,4)  ACF(LN,T5,A5,5)  ACF(LN,T6,A6,6)  ACF(LN,T7,A7,7)          \
71680    ACF(LN,T8,A8,8)  ACF(LN,T9,A9,9)  ACF(LN,TA,AA,10) ACF(LN,TB,AB,11)         \
71681    ACF(LN,TC,AC,12) ACF(LN,TD,AD,13) ACF(LN,TE,AE,14)                          \
71682    CFC_(UN,LN)( CFARGTA14(AACF,JCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE) );\
71683    WCF(T1,A1,1)  WCF(T2,A2,2)  WCF(T3,A3,3)  WCF(T4,A4,4)  WCF(T5,A5,5)        \
71684    WCF(T6,A6,6)  WCF(T7,A7,7)  WCF(T8,A8,8)  WCF(T9,A9,9)  WCF(TA,AA,10)       \
71685    WCF(TB,AB,11) WCF(TC,AC,12) WCF(TD,AD,13) WCF(TE,AE,14)      }while(0)
71686 #endif
71687 
71688 
71689 #if MAX_PREPRO_ARGS>31
71690 #define CCALLSFSUB15(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF)\
71691         CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,0,0,0,0,0)
71692 #define CCALLSFSUB16(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG)\
71693         CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,0,0,0,0)
71694 #define CCALLSFSUB17(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH)\
71695         CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,0,0,0)
71696 #define CCALLSFSUB18(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI)\
71697         CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,0,0)
71698 #define CCALLSFSUB19(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ)\
71699         CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,0)
71700 
71701 #ifdef CFSUBASFUN
71702 #define CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH, \
71703         TI,TJ,TK, A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) \
71704         CCALLSFFUN20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH, \
71705         TI,TJ,TK, A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK)
71706 #else
71707 #define CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH, \
71708         TI,TJ,TK, A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) \
71709 do{VVCF(T1,A1,B1)  VVCF(T2,A2,B2)  VVCF(T3,A3,B3)  VVCF(T4,A4,B4)  VVCF(T5,A5,B5)   \
71710    VVCF(T6,A6,B6)  VVCF(T7,A7,B7)  VVCF(T8,A8,B8)  VVCF(T9,A9,B9)  VVCF(TA,AA,B10)  \
71711    VVCF(TB,AB,B11) VVCF(TC,AC,B12) VVCF(TD,AD,B13) VVCF(TE,AE,B14) VVCF(TF,AF,B15)  \
71712    VVCF(TG,AG,B16) VVCF(TH,AH,B17) VVCF(TI,AI,B18) VVCF(TJ,AJ,B19) VVCF(TK,AK,B20)  \
71713    CPPPROTOCLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)  \
71714    ACF(LN,T1,A1,1)  ACF(LN,T2,A2,2)  ACF(LN,T3,A3,3)  ACF(LN,T4,A4,4)          \
71715    ACF(LN,T5,A5,5)  ACF(LN,T6,A6,6)  ACF(LN,T7,A7,7)  ACF(LN,T8,A8,8)          \
71716    ACF(LN,T9,A9,9)  ACF(LN,TA,AA,10) ACF(LN,TB,AB,11) ACF(LN,TC,AC,12)         \
71717    ACF(LN,TD,AD,13) ACF(LN,TE,AE,14) ACF(LN,TF,AF,15) ACF(LN,TG,AG,16)         \
71718    ACF(LN,TH,AH,17) ACF(LN,TI,AI,18) ACF(LN,TJ,AJ,19) ACF(LN,TK,AK,20)         \
71719    CFC_(UN,LN)( CFARGTA20(AACF,JCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) ); \
71720  WCF(T1,A1,1)  WCF(T2,A2,2)  WCF(T3,A3,3)  WCF(T4,A4,4)  WCF(T5,A5,5)  WCF(T6,A6,6)  \
71721  WCF(T7,A7,7)  WCF(T8,A8,8)  WCF(T9,A9,9)  WCF(TA,AA,10) WCF(TB,AB,11) WCF(TC,AC,12) \
71722  WCF(TD,AD,13) WCF(TE,AE,14) WCF(TF,AF,15) WCF(TG,AG,16) WCF(TH,AH,17) WCF(TI,AI,18) \
71723  WCF(TJ,AJ,19) WCF(TK,AK,20) }while(0)
71724 #endif
71725 #endif         /* MAX_PREPRO_ARGS */
71726 
71727 #if MAX_PREPRO_ARGS>31
71728 #define CCALLSFSUB21(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL)\
71729         CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,0,0,0,0,0,0)
71730 #define CCALLSFSUB22(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM)\
71731         CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,0,0,0,0,0)
71732 #define CCALLSFSUB23(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN)\
71733         CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,0,0,0,0)
71734 #define CCALLSFSUB24(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO)\
71735         CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,0,0,0)
71736 #define CCALLSFSUB25(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP)\
71737         CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,0,0)
71738 #define CCALLSFSUB26(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ)\
71739         CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,0)
71740 
71741 #ifdef CFSUBASFUN
71742 #define CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR, \
71743                            A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) \
71744         CCALLSFFUN27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR, \
71745                            A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR)
71746 #else
71747 #define CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR, \
71748                            A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) \
71749 do{VVCF(T1,A1,B1)  VVCF(T2,A2,B2)  VVCF(T3,A3,B3)  VVCF(T4,A4,B4)  VVCF(T5,A5,B5)   \
71750    VVCF(T6,A6,B6)  VVCF(T7,A7,B7)  VVCF(T8,A8,B8)  VVCF(T9,A9,B9)  VVCF(TA,AA,B10)  \
71751    VVCF(TB,AB,B11) VVCF(TC,AC,B12) VVCF(TD,AD,B13) VVCF(TE,AE,B14) VVCF(TF,AF,B15)  \
71752    VVCF(TG,AG,B16) VVCF(TH,AH,B17) VVCF(TI,AI,B18) VVCF(TJ,AJ,B19) VVCF(TK,AK,B20)  \
71753    VVCF(TL,AL,B21) VVCF(TM,AM,B22) VVCF(TN,AN,B23) VVCF(TO,AO,B24) VVCF(TP,AP,B25)  \
71754    VVCF(TQ,AQ,B26) VVCF(TR,AR,B27)                                                  \
71755    CPPPROTOCLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
71756    ACF(LN,T1,A1,1)  ACF(LN,T2,A2,2)  ACF(LN,T3,A3,3)  ACF(LN,T4,A4,4)          \
71757    ACF(LN,T5,A5,5)  ACF(LN,T6,A6,6)  ACF(LN,T7,A7,7)  ACF(LN,T8,A8,8)          \
71758    ACF(LN,T9,A9,9)  ACF(LN,TA,AA,10) ACF(LN,TB,AB,11) ACF(LN,TC,AC,12)         \
71759    ACF(LN,TD,AD,13) ACF(LN,TE,AE,14) ACF(LN,TF,AF,15) ACF(LN,TG,AG,16)         \
71760    ACF(LN,TH,AH,17) ACF(LN,TI,AI,18) ACF(LN,TJ,AJ,19) ACF(LN,TK,AK,20)         \
71761    ACF(LN,TL,AL,21) ACF(LN,TM,AM,22) ACF(LN,TN,AN,23) ACF(LN,TO,AO,24)         \
71762    ACF(LN,TP,AP,25) ACF(LN,TQ,AQ,26) ACF(LN,TR,AR,27)                          \
71763    CFC_(UN,LN)( CFARGTA27(AACF,JCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR,\
71764                                    A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) ); \
71765  WCF(T1,A1,1)  WCF(T2,A2,2)  WCF(T3,A3,3)  WCF(T4,A4,4)  WCF(T5,A5,5)  WCF(T6,A6,6)  \
71766  WCF(T7,A7,7)  WCF(T8,A8,8)  WCF(T9,A9,9)  WCF(TA,AA,10) WCF(TB,AB,11) WCF(TC,AC,12) \
71767  WCF(TD,AD,13) WCF(TE,AE,14) WCF(TF,AF,15) WCF(TG,AG,16) WCF(TH,AH,17) WCF(TI,AI,18) \
71768  WCF(TJ,AJ,19) WCF(TK,AK,20) WCF(TL,AL,21) WCF(TM,AM,22) WCF(TN,AN,23) WCF(TO,AO,24) \
71769  WCF(TP,AP,25) WCF(TQ,AQ,26) WCF(TR,AR,27) }while(0)
71770 #endif
71771 #endif         /* MAX_PREPRO_ARGS */
71772 
71773 /*-------------------------------------------------------------------------*/
71774 
71775 /*               UTILITIES FOR C TO CALL FORTRAN FUNCTIONS                 */
71776 
71777 /*N.B. PROTOCCALLSFFUNn(..) generates code, whether or not the FORTRAN
71778   function is called. Therefore, especially for creator's of C header files
71779   for large FORTRAN libraries which include many functions, to reduce
71780   compile time and object code size, it may be desirable to create
71781   preprocessor directives to allow users to create code for only those
71782   functions which they use.                                                */
71783 
71784 /* The following defines the maximum length string that a function can return.
71785    Of course it may be undefine-d and re-define-d before individual
71786    PROTOCCALLSFFUNn(..) as required. It would also be nice to have this derived
71787    from the individual machines' limits.                                      */
71788 #define MAX_LEN_FORTRAN_FUNCTION_STRING 0x4FE
71789 
71790 /* The following defines a character used by CFORTRAN.H to flag the end of a
71791    string coming out of a FORTRAN routine.                                 */
71792 #define CFORTRAN_NON_CHAR 0x7F
71793 
71794 #ifdef OLD_VAXC                                /* Prevent %CC-I-PARAMNOTUSED. */
71795 #pragma nostandard
71796 #endif
71797 
71798 #define _SEP_(TN,C,cfCOMMA)     _(__SEP_,C)(TN,cfCOMMA)
71799 #define __SEP_0(TN,cfCOMMA)
71800 #define __SEP_1(TN,cfCOMMA)     _Icf(2,SEP,TN,cfCOMMA,0)
71801 #define        INT_cfSEP(T,B) _(A,B)
71802 #define       INTV_cfSEP(T,B) INT_cfSEP(T,B)
71803 #define      INTVV_cfSEP(T,B) INT_cfSEP(T,B)
71804 #define     INTVVV_cfSEP(T,B) INT_cfSEP(T,B)
71805 #define    INTVVVV_cfSEP(T,B) INT_cfSEP(T,B)
71806 #define   INTVVVVV_cfSEP(T,B) INT_cfSEP(T,B)
71807 #define  INTVVVVVV_cfSEP(T,B) INT_cfSEP(T,B)
71808 #define INTVVVVVVV_cfSEP(T,B) INT_cfSEP(T,B)
71809 #define       PINT_cfSEP(T,B) INT_cfSEP(T,B)
71810 #define      PVOID_cfSEP(T,B) INT_cfSEP(T,B)
71811 #define    ROUTINE_cfSEP(T,B) INT_cfSEP(T,B)
71812 #define     SIMPLE_cfSEP(T,B) INT_cfSEP(T,B)
71813 #define       VOID_cfSEP(T,B) INT_cfSEP(T,B)    /* For FORTRAN calls C subr.s.*/
71814 #define     STRING_cfSEP(T,B) INT_cfSEP(T,B)
71815 #define    STRINGV_cfSEP(T,B) INT_cfSEP(T,B)
71816 #define    PSTRING_cfSEP(T,B) INT_cfSEP(T,B)
71817 #define   PSTRINGV_cfSEP(T,B) INT_cfSEP(T,B)
71818 #define   PNSTRING_cfSEP(T,B) INT_cfSEP(T,B)
71819 #define   PPSTRING_cfSEP(T,B) INT_cfSEP(T,B)
71820 #define    ZTRINGV_cfSEP(T,B) INT_cfSEP(T,B)
71821 #define   PZTRINGV_cfSEP(T,B) INT_cfSEP(T,B)
71822 
71823 #if defined(SIGNED_BYTE) || !defined(UNSIGNED_BYTE)
71824 #ifdef OLD_VAXC
71825 #define INTEGER_BYTE               char    /* Old VAXC barfs on 'signed char' */
71826 #else
71827 #define INTEGER_BYTE        signed char    /* default */
71828 #endif
71829 #else
71830 #define INTEGER_BYTE        unsigned char
71831 #endif
71832 #define    BYTEVVVVVVV_cfTYPE INTEGER_BYTE
71833 #define  DOUBLEVVVVVVV_cfTYPE DOUBLE_PRECISION
71834 #define   FLOATVVVVVVV_cfTYPE FORTRAN_REAL
71835 #define     INTVVVVVVV_cfTYPE int
71836 #define LOGICALVVVVVVV_cfTYPE int
71837 #define    LONGVVVVVVV_cfTYPE long
71838 #define LONGLONGVVVVVVV_cfTYPE LONGLONG   /* added by MR December 2005 */
71839 #define   SHORTVVVVVVV_cfTYPE short
71840 #define          PBYTE_cfTYPE INTEGER_BYTE
71841 #define        PDOUBLE_cfTYPE DOUBLE_PRECISION
71842 #define         PFLOAT_cfTYPE FORTRAN_REAL
71843 #define           PINT_cfTYPE int
71844 #define       PLOGICAL_cfTYPE int
71845 #define          PLONG_cfTYPE long
71846 #define      PLONGLONG_cfTYPE LONGLONG  /* added by MR December 2005 */
71847 #define         PSHORT_cfTYPE short
71848 
71849 #define CFARGS0(A,T,V,W,X,Y,Z) _3(T,_cf,A)
71850 #define CFARGS1(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V)
71851 #define CFARGS2(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V,W)
71852 #define CFARGS3(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V,W,X)
71853 #define CFARGS4(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V,W,X,Y)
71854 #define CFARGS5(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V,W,X,Y,Z)
71855 
71856 #define  _Icf(N,T,I,X,Y)                 _(I,_cfINT)(N,T,I,X,Y,0)
71857 #define _Icf4(N,T,I,X,Y,Z)               _(I,_cfINT)(N,T,I,X,Y,Z)
71858 #define           BYTE_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z)
71859 #define         DOUBLE_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INT,B,X,Y,Z,0)
71860 #define          FLOAT_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z)
71861 #define            INT_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z)
71862 #define        LOGICAL_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z)
71863 #define           LONG_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z)
71864 #define       LONGLONG_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
71865 #define          SHORT_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z)
71866 #define          PBYTE_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z)
71867 #define        PDOUBLE_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,PINT,B,X,Y,Z,0)
71868 #define         PFLOAT_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z)
71869 #define           PINT_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z)
71870 #define       PLOGICAL_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z)
71871 #define          PLONG_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z)
71872 #define      PLONGLONG_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
71873 #define         PSHORT_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z)
71874 #define          BYTEV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z)
71875 #define         BYTEVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z)
71876 #define        BYTEVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
71877 #define       BYTEVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
71878 #define      BYTEVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
71879 #define     BYTEVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
71880 #define    BYTEVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
71881 #define        DOUBLEV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTV,B,X,Y,Z,0)
71882 #define       DOUBLEVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVV,B,X,Y,Z,0)
71883 #define      DOUBLEVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVV,B,X,Y,Z,0)
71884 #define     DOUBLEVVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVVV,B,X,Y,Z,0)
71885 #define    DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVVVV,B,X,Y,Z,0)
71886 #define   DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVVVVV,B,X,Y,Z,0)
71887 #define  DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVVVVVV,B,X,Y,Z,0)
71888 #define         FLOATV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z)
71889 #define        FLOATVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z)
71890 #define       FLOATVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
71891 #define      FLOATVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
71892 #define     FLOATVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
71893 #define    FLOATVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
71894 #define   FLOATVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
71895 #define           INTV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z)
71896 #define          INTVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z)
71897 #define         INTVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
71898 #define        INTVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
71899 #define       INTVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
71900 #define      INTVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
71901 #define     INTVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
71902 #define       LOGICALV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z)
71903 #define      LOGICALVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z)
71904 #define     LOGICALVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
71905 #define    LOGICALVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
71906 #define   LOGICALVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
71907 #define  LOGICALVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
71908 #define LOGICALVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
71909 #define          LONGV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z)
71910 #define         LONGVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z)
71911 #define        LONGVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
71912 #define       LONGVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
71913 #define      LONGVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
71914 #define     LONGVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
71915 #define    LONGVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
71916 #define      LONGLONGV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
71917 #define     LONGLONGVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
71918 #define    LONGLONGVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
71919 #define   LONGLONGVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
71920 #define  LONGLONGVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
71921 #define LONGLONGVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
71922 #define LONGLONGVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
71923 #define         SHORTV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z)
71924 #define        SHORTVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z)
71925 #define       SHORTVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
71926 #define      SHORTVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
71927 #define     SHORTVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
71928 #define    SHORTVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
71929 #define   SHORTVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
71930 #define          PVOID_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,B,B,X,Y,Z,0)
71931 #define        ROUTINE_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
71932 /*CRAY coughs on the first,
71933   i.e. the usual trouble of not being able to
71934   define macros to macros with arguments.
71935   New ultrix is worse, it coughs on all such uses.
71936  */
71937 /*#define       SIMPLE_cfINT                    PVOID_cfINT*/
71938 #define         SIMPLE_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
71939 #define           VOID_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
71940 #define         STRING_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
71941 #define        STRINGV_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
71942 #define        PSTRING_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
71943 #define       PSTRINGV_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
71944 #define       PNSTRING_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
71945 #define       PPSTRING_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
71946 #define        ZTRINGV_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
71947 #define       PZTRINGV_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
71948 #define           CF_0_cfINT(N,A,B,X,Y,Z)
71949 
71950 
71951 #define   UCF(TN,I,C)  _SEP_(TN,C,cfCOMMA) _Icf(2,U,TN,_(A,I),0)
71952 #define  UUCF(TN,I,C)  _SEP_(TN,C,cfCOMMA) _SEP_(TN,1,I)
71953 #define UUUCF(TN,I,C)  _SEP_(TN,C,cfCOLON) _Icf(2,U,TN,_(A,I),0)
71954 #define        INT_cfU(T,A) _(T,VVVVVVV_cfTYPE)   A
71955 #define       INTV_cfU(T,A) _(T,VVVVVV_cfTYPE)  * A
71956 #define      INTVV_cfU(T,A) _(T,VVVVV_cfTYPE)   * A
71957 #define     INTVVV_cfU(T,A) _(T,VVVV_cfTYPE)    * A
71958 #define    INTVVVV_cfU(T,A) _(T,VVV_cfTYPE)     * A
71959 #define   INTVVVVV_cfU(T,A) _(T,VV_cfTYPE)      * A
71960 #define  INTVVVVVV_cfU(T,A) _(T,V_cfTYPE)       * A
71961 #define INTVVVVVVV_cfU(T,A) _(T,_cfTYPE)        * A
71962 #define       PINT_cfU(T,A) _(T,_cfTYPE)        * A
71963 #define      PVOID_cfU(T,A) void  *A
71964 #define    ROUTINE_cfU(T,A) void (*A)(CF_NULL_PROTO)
71965 #define       VOID_cfU(T,A) void   A    /* Needed for C calls FORTRAN sub.s.  */
71966 #define     STRING_cfU(T,A) char  *A    /*            via VOID and wrapper.   */
71967 #define    STRINGV_cfU(T,A) char  *A
71968 #define    PSTRING_cfU(T,A) char  *A
71969 #define   PSTRINGV_cfU(T,A) char  *A
71970 #define    ZTRINGV_cfU(T,A) char  *A
71971 #define   PZTRINGV_cfU(T,A) char  *A
71972 
71973 /* VOID breaks U into U and UU. */
71974 #define       INT_cfUU(T,A) _(T,VVVVVVV_cfTYPE) A
71975 #define      VOID_cfUU(T,A)             /* Needed for FORTRAN calls C sub.s.  */
71976 #define    STRING_cfUU(T,A) const char *A
71977 
71978 
71979 #define      BYTE_cfPU(A)   CFextern INTEGER_BYTE      FCALLSC_QUALIFIER A
71980 #define    DOUBLE_cfPU(A)   CFextern DOUBLE_PRECISION  FCALLSC_QUALIFIER A
71981 #if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
71982 #if defined (f2cFortran) && ! defined (gFortran)
71983 /* f2c/g77 return double from FORTRAN REAL functions. (KMCCARTY, 2005/12/09) */
71984 #define     FLOAT_cfPU(A)   CFextern DOUBLE_PRECISION  FCALLSC_QUALIFIER A
71985 #else
71986 #define     FLOAT_cfPU(A)   CFextern FORTRAN_REAL      FCALLSC_QUALIFIER A
71987 #endif
71988 #else
71989 #define     FLOAT_cfPU(A)   CFextern FLOATFUNCTIONTYPE FCALLSC_QUALIFIER A
71990 #endif
71991 #define       INT_cfPU(A)   CFextern int   FCALLSC_QUALIFIER   A
71992 #define   LOGICAL_cfPU(A)   CFextern int   FCALLSC_QUALIFIER   A
71993 #define      LONG_cfPU(A)   CFextern long  FCALLSC_QUALIFIER   A
71994 #define     SHORT_cfPU(A)   CFextern short FCALLSC_QUALIFIER   A
71995 #define    STRING_cfPU(A)   CFextern void  FCALLSC_QUALIFIER   A
71996 #define      VOID_cfPU(A)   CFextern void  FCALLSC_QUALIFIER   A
71997 
71998 #define    BYTE_cfE INTEGER_BYTE     A0;
71999 #define  DOUBLE_cfE DOUBLE_PRECISION A0;
72000 #if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
72001 #define   FLOAT_cfE FORTRAN_REAL  A0;
72002 #else
72003 #define   FLOAT_cfE FORTRAN_REAL AA0;   FLOATFUNCTIONTYPE A0;
72004 #endif
72005 #define     INT_cfE int    A0;
72006 #define LOGICAL_cfE int    A0;
72007 #define    LONG_cfE long   A0;
72008 #define   SHORT_cfE short  A0;
72009 #define    VOID_cfE
72010 #ifdef vmsFortran
72011 #define  STRING_cfE static char AA0[1+MAX_LEN_FORTRAN_FUNCTION_STRING];        \
72012                        static fstring A0 =                                     \
72013              {MAX_LEN_FORTRAN_FUNCTION_STRING,DSC$K_DTYPE_T,DSC$K_CLASS_S,AA0};\
72014                memset(AA0, CFORTRAN_NON_CHAR, MAX_LEN_FORTRAN_FUNCTION_STRING);\
72015                                     *(AA0+MAX_LEN_FORTRAN_FUNCTION_STRING)='\0';
72016 #else
72017 #ifdef CRAYFortran
72018 #define  STRING_cfE static char AA0[1+MAX_LEN_FORTRAN_FUNCTION_STRING];        \
72019                    static _fcd A0; *(AA0+MAX_LEN_FORTRAN_FUNCTION_STRING)='\0';\
72020                 memset(AA0,CFORTRAN_NON_CHAR, MAX_LEN_FORTRAN_FUNCTION_STRING);\
72021                             A0 = _cptofcd(AA0,MAX_LEN_FORTRAN_FUNCTION_STRING);
72022 #else
72023 /* 'cc: SC3.0.1 13 Jul 1994' barfs on char A0[0x4FE+1];
72024  * char A0[0x4FE +1]; char A0[1+0x4FE]; are both OK.     */
72025 #define STRING_cfE static char A0[1+MAX_LEN_FORTRAN_FUNCTION_STRING];          \
72026                        memset(A0, CFORTRAN_NON_CHAR,                           \
72027                               MAX_LEN_FORTRAN_FUNCTION_STRING);                \
72028                        *(A0+MAX_LEN_FORTRAN_FUNCTION_STRING)='\0';
72029 #endif
72030 #endif
72031 /* ESTRING must use static char. array which is guaranteed to exist after
72032    function returns.                                                     */
72033 
72034 /* N.B.i) The diff. for 0 (Zero) and >=1 arguments.
72035        ii)That the following create an unmatched bracket, i.e. '(', which
72036           must of course be matched in the call.
72037        iii)Commas must be handled very carefully                         */
72038 #define    INT_cfGZ(T,UN,LN) A0=CFC_(UN,LN)(
72039 #define   VOID_cfGZ(T,UN,LN)    CFC_(UN,LN)(
72040 #ifdef vmsFortran
72041 #define STRING_cfGZ(T,UN,LN)    CFC_(UN,LN)(&A0
72042 #else
72043 #if defined(CRAYFortran) || defined(AbsoftUNIXFortran) || defined(AbsoftProFortran)
72044 #define STRING_cfGZ(T,UN,LN)    CFC_(UN,LN)( A0
72045 #else
72046 #define STRING_cfGZ(T,UN,LN)    CFC_(UN,LN)( A0,MAX_LEN_FORTRAN_FUNCTION_STRING
72047 #endif
72048 #endif
72049 
72050 #define     INT_cfG(T,UN,LN)    INT_cfGZ(T,UN,LN)
72051 #define    VOID_cfG(T,UN,LN)   VOID_cfGZ(T,UN,LN)
72052 #define  STRING_cfG(T,UN,LN) STRING_cfGZ(T,UN,LN), /*, is only diff. from _cfG*/
72053 
72054 #define    BYTEVVVVVVV_cfPP
72055 #define     INTVVVVVVV_cfPP     /* These complement FLOATVVVVVVV_cfPP. */
72056 #define  DOUBLEVVVVVVV_cfPP
72057 #define LOGICALVVVVVVV_cfPP
72058 #define    LONGVVVVVVV_cfPP
72059 #define   SHORTVVVVVVV_cfPP
72060 #define          PBYTE_cfPP
72061 #define           PINT_cfPP
72062 #define        PDOUBLE_cfPP
72063 #define       PLOGICAL_cfPP
72064 #define          PLONG_cfPP
72065 #define         PSHORT_cfPP
72066 #define         PFLOAT_cfPP FLOATVVVVVVV_cfPP
72067 
72068 #define BCF(TN,AN,C)        _SEP_(TN,C,cfCOMMA) _Icf(2,B,TN,AN,0)
72069 #define        INT_cfB(T,A) (_(T,VVVVVVV_cfTYPE)) A
72070 #define       INTV_cfB(T,A)            A
72071 #define      INTVV_cfB(T,A)           (A)[0]
72072 #define     INTVVV_cfB(T,A)           (A)[0][0]
72073 #define    INTVVVV_cfB(T,A)           (A)[0][0][0]
72074 #define   INTVVVVV_cfB(T,A)           (A)[0][0][0][0]
72075 #define  INTVVVVVV_cfB(T,A)           (A)[0][0][0][0][0]
72076 #define INTVVVVVVV_cfB(T,A)           (A)[0][0][0][0][0][0]
72077 #define       PINT_cfB(T,A) _(T,_cfPP)&A
72078 #define     STRING_cfB(T,A) (char *)   A
72079 #define    STRINGV_cfB(T,A) (char *)   A
72080 #define    PSTRING_cfB(T,A) (char *)   A
72081 #define   PSTRINGV_cfB(T,A) (char *)   A
72082 #define      PVOID_cfB(T,A) (void *)   A
72083 #define    ROUTINE_cfB(T,A) (cfCAST_FUNCTION)A
72084 #define    ZTRINGV_cfB(T,A) (char *)   A
72085 #define   PZTRINGV_cfB(T,A) (char *)   A
72086 
72087 #define SCF(TN,NAME,I,A)    _(TN,_cfSTR)(3,S,NAME,I,A,0,0)
72088 #define  DEFAULT_cfS(M,I,A)
72089 #define  LOGICAL_cfS(M,I,A)
72090 #define PLOGICAL_cfS(M,I,A)
72091 #define   STRING_cfS(M,I,A) ,sizeof(A)
72092 #define  STRINGV_cfS(M,I,A) ,( (unsigned)0xFFFF*firstindexlength(A) \
72093                               +secondindexlength(A))
72094 #define  PSTRING_cfS(M,I,A) ,sizeof(A)
72095 #define PSTRINGV_cfS(M,I,A) STRINGV_cfS(M,I,A)
72096 #define  ZTRINGV_cfS(M,I,A)
72097 #define PZTRINGV_cfS(M,I,A)
72098 
72099 #define   HCF(TN,I)         _(TN,_cfSTR)(3,H,cfCOMMA, H,_(C,I),0,0)
72100 #define  HHCF(TN,I)         _(TN,_cfSTR)(3,H,cfCOMMA,HH,_(C,I),0,0)
72101 #define HHHCF(TN,I)         _(TN,_cfSTR)(3,H,cfCOLON, H,_(C,I),0,0)
72102 #define  H_CF_SPECIAL       unsigned
72103 #define HH_CF_SPECIAL
72104 #define  DEFAULT_cfH(M,I,A)
72105 #define  LOGICAL_cfH(S,U,B)
72106 #define PLOGICAL_cfH(S,U,B)
72107 #define   STRING_cfH(S,U,B) _(A,S) _(U,_CF_SPECIAL) B
72108 #define  STRINGV_cfH(S,U,B) STRING_cfH(S,U,B)
72109 #define  PSTRING_cfH(S,U,B) STRING_cfH(S,U,B)
72110 #define PSTRINGV_cfH(S,U,B) STRING_cfH(S,U,B)
72111 #define PNSTRING_cfH(S,U,B) STRING_cfH(S,U,B)
72112 #define PPSTRING_cfH(S,U,B) STRING_cfH(S,U,B)
72113 #define  ZTRINGV_cfH(S,U,B)
72114 #define PZTRINGV_cfH(S,U,B)
72115 
72116 /* Need VOID_cfSTR because Absoft forced function types go through _cfSTR. */
72117 /* No spaces inside expansion. They screws up macro catenation kludge.     */
72118 #define           VOID_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72119 #define           BYTE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72120 #define         DOUBLE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72121 #define          FLOAT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72122 #define            INT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72123 #define        LOGICAL_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,LOGICAL,A,B,C,D,E)
72124 #define           LONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72125 #define       LONGLONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
72126 #define          SHORT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72127 #define          BYTEV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72128 #define         BYTEVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72129 #define        BYTEVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72130 #define       BYTEVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72131 #define      BYTEVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72132 #define     BYTEVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72133 #define    BYTEVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72134 #define        DOUBLEV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72135 #define       DOUBLEVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72136 #define      DOUBLEVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72137 #define     DOUBLEVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72138 #define    DOUBLEVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72139 #define   DOUBLEVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72140 #define  DOUBLEVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72141 #define         FLOATV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72142 #define        FLOATVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72143 #define       FLOATVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72144 #define      FLOATVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72145 #define     FLOATVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72146 #define    FLOATVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72147 #define   FLOATVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72148 #define           INTV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72149 #define          INTVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72150 #define         INTVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72151 #define        INTVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72152 #define       INTVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72153 #define      INTVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72154 #define     INTVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72155 #define       LOGICALV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72156 #define      LOGICALVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72157 #define     LOGICALVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72158 #define    LOGICALVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72159 #define   LOGICALVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72160 #define  LOGICALVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72161 #define LOGICALVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72162 #define          LONGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72163 #define         LONGVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72164 #define        LONGVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72165 #define       LONGVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72166 #define      LONGVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72167 #define     LONGVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72168 #define    LONGVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72169 #define      LONGLONGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
72170 #define     LONGLONGVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
72171 #define    LONGLONGVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
72172 #define   LONGLONGVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
72173 #define  LONGLONGVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
72174 #define LONGLONGVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
72175 #define LONGLONGVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
72176 #define         SHORTV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72177 #define        SHORTVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72178 #define       SHORTVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72179 #define      SHORTVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72180 #define     SHORTVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72181 #define    SHORTVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72182 #define   SHORTVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72183 #define          PBYTE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72184 #define        PDOUBLE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72185 #define         PFLOAT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72186 #define           PINT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72187 #define       PLOGICAL_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PLOGICAL,A,B,C,D,E)
72188 #define          PLONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72189 #define      PLONGLONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
72190 #define         PSHORT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72191 #define         STRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,STRING,A,B,C,D,E)
72192 #define        PSTRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PSTRING,A,B,C,D,E)
72193 #define        STRINGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,STRINGV,A,B,C,D,E)
72194 #define       PSTRINGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PSTRINGV,A,B,C,D,E)
72195 #define       PNSTRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PNSTRING,A,B,C,D,E)
72196 #define       PPSTRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PPSTRING,A,B,C,D,E)
72197 #define          PVOID_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72198 #define        ROUTINE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72199 #define         SIMPLE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
72200 #define        ZTRINGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,ZTRINGV,A,B,C,D,E)
72201 #define       PZTRINGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PZTRINGV,A,B,C,D,E)
72202 #define           CF_0_cfSTR(N,T,A,B,C,D,E)
72203 
72204 /* See ACF table comments, which explain why CCF was split into two. */
72205 #define CCF(NAME,TN,I)     _(TN,_cfSTR)(5,C,NAME,I,_(A,I),_(B,I),_(C,I))
72206 #define  DEFAULT_cfC(M,I,A,B,C)
72207 #define  LOGICAL_cfC(M,I,A,B,C)  A=C2FLOGICAL( A);
72208 #define PLOGICAL_cfC(M,I,A,B,C) *A=C2FLOGICAL(*A);
72209 #ifdef vmsFortran
72210 #define   STRING_cfC(M,I,A,B,C) (B.clen=strlen(A),B.f.dsc$a_pointer=A,         \
72211         C==sizeof(char*)||C==(unsigned)(B.clen+1)?B.f.dsc$w_length=B.clen:     \
72212           (memset((A)+B.clen,' ',C-B.clen-1),A[B.f.dsc$w_length=C-1]='\0'));
72213       /* PSTRING_cfC to beware of array A which does not contain any \0.      */
72214 #define  PSTRING_cfC(M,I,A,B,C) (B.dsc$a_pointer=A, C==sizeof(char*) ?         \
72215              B.dsc$w_length=strlen(A):  (A[C-1]='\0',B.dsc$w_length=strlen(A), \
72216        (unsigned)memset((A)+B.dsc$w_length,' ',C-B.dsc$w_length-1), B.dsc$w_length=C-1));
72217 #else
72218 #define   STRING_cfC(M,I,A,B,C) (B.nombre=A,B.clen=(unsigned)strlen(A),                             \
72219                 C==sizeof(char*)||C==(unsigned)(B.clen+1)?B.flen=B.clen:       \
72220                         (unsigned)(memset(B.nombre+B.clen,' ',C-B.clen-1),B.nombre[B.flen=C-1]='\0'));
72221 #define  PSTRING_cfC(M,I,A,B,C) (C==sizeof(char*)? B=strlen(A):                \
72222                     (A[C-1]='\0',B=strlen(A),memset((A)+B,' ',C-B-1),B=C-1));
72223 #endif
72224           /* For CRAYFortran for (P)STRINGV_cfC, B.fs is set, but irrelevant. */
72225 #define  STRINGV_cfC(M,I,A,B,C) \
72226         AATRINGV_cfA(    A,B,(C/0xFFFF)*(C%0xFFFF),C/0xFFFF,C%0xFFFF)
72227 #define PSTRINGV_cfC(M,I,A,B,C) \
72228        APATRINGV_cfA(    A,B,(C/0xFFFF)*(C%0xFFFF),C/0xFFFF,C%0xFFFF)
72229 #define  ZTRINGV_cfC(M,I,A,B,C) \
72230         AATRINGV_cfA(    A,B, (_3(M,_ELEMS_,I))*((_3(M,_ELEMLEN_,I))+1),       \
72231                               (_3(M,_ELEMS_,I)), (_3(M,_ELEMLEN_,I))+1   )
72232 #define PZTRINGV_cfC(M,I,A,B,C) \
72233        APATRINGV_cfA(    A,B, (_3(M,_ELEMS_,I))*((_3(M,_ELEMLEN_,I))+1),       \
72234                               (_3(M,_ELEMS_,I)), (_3(M,_ELEMLEN_,I))+1   )
72235 
72236 #define     BYTE_cfCCC(A,B) &A
72237 #define   DOUBLE_cfCCC(A,B) &A
72238 #if !defined(__CF__KnR)
72239 #define    FLOAT_cfCCC(A,B) &A
72240                                /* Although the VAX doesn't, at least the      */
72241 #else                          /* HP and K&R mips promote float arg.'s of     */
72242 #define    FLOAT_cfCCC(A,B) &B /* unprototyped functions to double. Cannot    */
72243 #endif                         /* use A here to pass the argument to FORTRAN. */
72244 #define      INT_cfCCC(A,B) &A
72245 #define  LOGICAL_cfCCC(A,B) &A
72246 #define     LONG_cfCCC(A,B) &A
72247 #define    SHORT_cfCCC(A,B) &A
72248 #define    PBYTE_cfCCC(A,B)  A
72249 #define  PDOUBLE_cfCCC(A,B)  A
72250 #define   PFLOAT_cfCCC(A,B)  A
72251 #define     PINT_cfCCC(A,B)  A
72252 #define PLOGICAL_cfCCC(A,B)  B=A       /* B used to keep a common W table. */
72253 #define    PLONG_cfCCC(A,B)  A
72254 #define   PSHORT_cfCCC(A,B)  A
72255 
72256 #define CCCF(TN,I,M)           _SEP_(TN,M,cfCOMMA) _Icf(3,CC,TN,_(A,I),_(B,I))
72257 #define        INT_cfCC(T,A,B) _(T,_cfCCC)(A,B)
72258 #define       INTV_cfCC(T,A,B)  A
72259 #define      INTVV_cfCC(T,A,B)  A
72260 #define     INTVVV_cfCC(T,A,B)  A
72261 #define    INTVVVV_cfCC(T,A,B)  A
72262 #define   INTVVVVV_cfCC(T,A,B)  A
72263 #define  INTVVVVVV_cfCC(T,A,B)  A
72264 #define INTVVVVVVV_cfCC(T,A,B)  A
72265 #define       PINT_cfCC(T,A,B) _(T,_cfCCC)(A,B)
72266 #define      PVOID_cfCC(T,A,B)  A
72267 #if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran)
72268 #define    ROUTINE_cfCC(T,A,B) &A
72269 #else
72270 #define    ROUTINE_cfCC(T,A,B)  A
72271 #endif
72272 #define     SIMPLE_cfCC(T,A,B)  A
72273 #ifdef vmsFortran
72274 #define     STRING_cfCC(T,A,B) &B.f
72275 #define    STRINGV_cfCC(T,A,B) &B
72276 #define    PSTRING_cfCC(T,A,B) &B
72277 #define   PSTRINGV_cfCC(T,A,B) &B
72278 #else
72279 #ifdef CRAYFortran
72280 #define     STRING_cfCC(T,A,B) _cptofcd(A,B.flen)
72281 #define    STRINGV_cfCC(T,A,B) _cptofcd(B.s,B.flen)
72282 #define    PSTRING_cfCC(T,A,B) _cptofcd(A,B)
72283 #define   PSTRINGV_cfCC(T,A,B) _cptofcd(A,B.flen)
72284 #else
72285 #define     STRING_cfCC(T,A,B)  A
72286 #define    STRINGV_cfCC(T,A,B)  B.fs
72287 #define    PSTRING_cfCC(T,A,B)  A
72288 #define   PSTRINGV_cfCC(T,A,B)  B.fs
72289 #endif
72290 #endif
72291 #define    ZTRINGV_cfCC(T,A,B)   STRINGV_cfCC(T,A,B)
72292 #define   PZTRINGV_cfCC(T,A,B)  PSTRINGV_cfCC(T,A,B)
72293 
72294 #define    BYTE_cfX  return A0;
72295 #define  DOUBLE_cfX  return A0;
72296 #if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
72297 #define   FLOAT_cfX  return A0;
72298 #else
72299 #define   FLOAT_cfX  ASSIGNFLOAT(AA0,A0); return AA0;
72300 #endif
72301 #define     INT_cfX  return A0;
72302 #define LOGICAL_cfX  return F2CLOGICAL(A0);
72303 #define    LONG_cfX  return A0;
72304 #define   SHORT_cfX  return A0;
72305 #define    VOID_cfX  return   ;
72306 #if defined(vmsFortran) || defined(CRAYFortran)
72307 #define  STRING_cfX  return kill_trailing(                                     \
72308                                       kill_trailing(AA0,CFORTRAN_NON_CHAR),' ');
72309 #else
72310 #define  STRING_cfX  return kill_trailing(                                     \
72311                                       kill_trailing( A0,CFORTRAN_NON_CHAR),' ');
72312 #endif
72313 
72314 #define CFFUN(NAME) _(__cf__,NAME)
72315 
72316 /* Note that we don't use LN here, but we keep it for consistency. */
72317 #define CCALLSFFUN0(UN,LN) CFFUN(UN)()
72318 
72319 #ifdef OLD_VAXC                                  /* Allow %CC-I-PARAMNOTUSED. */
72320 #pragma standard
72321 #endif
72322 
72323 #define CCALLSFFUN1( UN,LN,T1,                        A1)         \
72324         CCALLSFFUN5 (UN,LN,T1,CF_0,CF_0,CF_0,CF_0,A1,0,0,0,0)
72325 #define CCALLSFFUN2( UN,LN,T1,T2,                     A1,A2)      \
72326         CCALLSFFUN5 (UN,LN,T1,T2,CF_0,CF_0,CF_0,A1,A2,0,0,0)
72327 #define CCALLSFFUN3( UN,LN,T1,T2,T3,                  A1,A2,A3)   \
72328         CCALLSFFUN5 (UN,LN,T1,T2,T3,CF_0,CF_0,A1,A2,A3,0,0)
72329 #define CCALLSFFUN4( UN,LN,T1,T2,T3,T4,               A1,A2,A3,A4)\
72330         CCALLSFFUN5 (UN,LN,T1,T2,T3,T4,CF_0,A1,A2,A3,A4,0)
72331 #define CCALLSFFUN5( UN,LN,T1,T2,T3,T4,T5,            A1,A2,A3,A4,A5)          \
72332         CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,0,0,0,0,0)
72333 #define CCALLSFFUN6( UN,LN,T1,T2,T3,T4,T5,T6,         A1,A2,A3,A4,A5,A6)       \
72334         CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,0,0,0,0)
72335 #define CCALLSFFUN7( UN,LN,T1,T2,T3,T4,T5,T6,T7,      A1,A2,A3,A4,A5,A6,A7)    \
72336         CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,0,0,0)
72337 #define CCALLSFFUN8( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,   A1,A2,A3,A4,A5,A6,A7,A8) \
72338         CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,0,0)
72339 #define CCALLSFFUN9( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,A1,A2,A3,A4,A5,A6,A7,A8,A9)\
72340         CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,0)
72341 #define CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA)\
72342         CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,0,0,0,0)
72343 #define CCALLSFFUN11(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB)\
72344         CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,0,0,0)
72345 #define CCALLSFFUN12(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC)\
72346         CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,0,0)
72347 #define CCALLSFFUN13(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD)\
72348         CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,0)
72349 
72350 #define CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE)\
72351 ((CFFUN(UN)(  BCF(T1,A1,0) BCF(T2,A2,1) BCF(T3,A3,1) BCF(T4,A4,1) BCF(T5,A5,1) \
72352               BCF(T6,A6,1) BCF(T7,A7,1) BCF(T8,A8,1) BCF(T9,A9,1) BCF(TA,AA,1) \
72353               BCF(TB,AB,1) BCF(TC,AC,1) BCF(TD,AD,1) BCF(TE,AE,1)              \
72354            SCF(T1,LN,1,A1)  SCF(T2,LN,2,A2)  SCF(T3,LN,3,A3)  SCF(T4,LN,4,A4)  \
72355            SCF(T5,LN,5,A5)  SCF(T6,LN,6,A6)  SCF(T7,LN,7,A7)  SCF(T8,LN,8,A8)  \
72356            SCF(T9,LN,9,A9)  SCF(TA,LN,10,AA) SCF(TB,LN,11,AB) SCF(TC,LN,12,AC) \
72357            SCF(TD,LN,13,AD) SCF(TE,LN,14,AE))))
72358 
72359 /*  N.B. Create a separate function instead of using (call function, function
72360 value here) because in order to create the variables needed for the input
72361 arg.'s which may be const.'s one has to do the creation within {}, but these
72362 can never be placed within ()'s. Therefore one must create wrapper functions.
72363 gcc, on the other hand may be able to avoid the wrapper functions. */
72364 
72365 /* Prototypes are needed to correctly handle the value returned correctly. N.B.
72366 Can only have prototype arg.'s with difficulty, a la G... table since FORTRAN
72367 functions returning strings have extra arg.'s. Don't bother, since this only
72368 causes a compiler warning to come up when one uses FCALLSCFUNn and CCALLSFFUNn
72369 for the same function in the same source code. Something done by the experts in
72370 debugging only.*/
72371 
72372 #define PROTOCCALLSFFUN0(F,UN,LN)                                              \
72373 _(F,_cfPU)( CFC_(UN,LN))(CF_NULL_PROTO);                                       \
72374 static _Icf(2,U,F,CFFUN(UN),0)() {_(F,_cfE) _Icf(3,GZ,F,UN,LN) ABSOFT_cf1(F));_(F,_cfX)}
72375 
72376 #define PROTOCCALLSFFUN1( T0,UN,LN,T1)                                         \
72377         PROTOCCALLSFFUN5 (T0,UN,LN,T1,CF_0,CF_0,CF_0,CF_0)
72378 #define PROTOCCALLSFFUN2( T0,UN,LN,T1,T2)                                      \
72379         PROTOCCALLSFFUN5 (T0,UN,LN,T1,T2,CF_0,CF_0,CF_0)
72380 #define PROTOCCALLSFFUN3( T0,UN,LN,T1,T2,T3)                                   \
72381         PROTOCCALLSFFUN5 (T0,UN,LN,T1,T2,T3,CF_0,CF_0)
72382 #define PROTOCCALLSFFUN4( T0,UN,LN,T1,T2,T3,T4)                                \
72383         PROTOCCALLSFFUN5 (T0,UN,LN,T1,T2,T3,T4,CF_0)
72384 #define PROTOCCALLSFFUN5( T0,UN,LN,T1,T2,T3,T4,T5)                             \
72385         PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0)
72386 #define PROTOCCALLSFFUN6( T0,UN,LN,T1,T2,T3,T4,T5,T6)                          \
72387         PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0)
72388 #define PROTOCCALLSFFUN7( T0,UN,LN,T1,T2,T3,T4,T5,T6,T7)                       \
72389         PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0)
72390 #define PROTOCCALLSFFUN8( T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8)                    \
72391         PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0)
72392 #define PROTOCCALLSFFUN9( T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9)                 \
72393         PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0)
72394 #define PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA)              \
72395         PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0)
72396 #define PROTOCCALLSFFUN11(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB)           \
72397         PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0)
72398 #define PROTOCCALLSFFUN12(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC)        \
72399         PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0)
72400 #define PROTOCCALLSFFUN13(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD)     \
72401         PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0)
72402 
72403 /* HP/UX 9.01 cc requires the blank between '_Icf(3,G,T0,UN,LN) CCCF(T1,1,0)' */
72404 
72405 #ifndef __CF__KnR
72406 #define PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)  \
72407  _(T0,_cfPU)(CFC_(UN,LN))(CF_NULL_PROTO); static _Icf(2,U,T0,CFFUN(UN),0)(     \
72408    CFARGT14FS(UCF,HCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) )          \
72409 {       CFARGT14S(VCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)    _(T0,_cfE) \
72410  CCF(LN,T1,1)  CCF(LN,T2,2)  CCF(LN,T3,3)  CCF(LN,T4,4)  CCF(LN,T5,5)          \
72411  CCF(LN,T6,6)  CCF(LN,T7,7)  CCF(LN,T8,8)  CCF(LN,T9,9)  CCF(LN,TA,10)         \
72412  CCF(LN,TB,11) CCF(LN,TC,12) CCF(LN,TD,13) CCF(LN,TE,14)    _Icf(3,G,T0,UN,LN) \
72413  CFARGT14(CCCF,JCF,ABSOFT_cf1(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)); \
72414  WCF(T1,A1,1)   WCF(T2,A2,2)   WCF(T3,A3,3)   WCF(T4,A4,4)  WCF(T5,A5,5)       \
72415  WCF(T6,A6,6)   WCF(T7,A7,7)   WCF(T8,A8,8)   WCF(T9,A9,9)  WCF(TA,A10,10)     \
72416  WCF(TB,A11,11) WCF(TC,A12,12) WCF(TD,A13,13) WCF(TE,A14,14) _(T0,_cfX)}
72417 #else
72418 #define PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)  \
72419  _(T0,_cfPU)(CFC_(UN,LN))(CF_NULL_PROTO); static _Icf(2,U,T0,CFFUN(UN),0)(     \
72420    CFARGT14FS(UUCF,HHCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) )        \
72421  CFARGT14FS(UUUCF,HHHCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) ;        \
72422 {       CFARGT14S(VCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)    _(T0,_cfE) \
72423  CCF(LN,T1,1)  CCF(LN,T2,2)  CCF(LN,T3,3)  CCF(LN,T4,4)  CCF(LN,T5,5)          \
72424  CCF(LN,T6,6)  CCF(LN,T7,7)  CCF(LN,T8,8)  CCF(LN,T9,9)  CCF(LN,TA,10)         \
72425  CCF(LN,TB,11) CCF(LN,TC,12) CCF(LN,TD,13) CCF(LN,TE,14)    _Icf(3,G,T0,UN,LN) \
72426  CFARGT14(CCCF,JCF,ABSOFT_cf1(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)); \
72427  WCF(T1,A1,1)   WCF(T2,A2,2)   WCF(T3,A3,3)   WCF(T4,A4,4)   WCF(T5,A5,5)      \
72428  WCF(T6,A6,6)   WCF(T7,A7,7)   WCF(T8,A8,8)   WCF(T9,A9,9)   WCF(TA,A10,10)    \
72429  WCF(TB,A11,11) WCF(TC,A12,12) WCF(TD,A13,13) WCF(TE,A14,14) _(T0,_cfX)}
72430 #endif
72431 
72432 /*-------------------------------------------------------------------------*/
72433 
72434 /*               UTILITIES FOR FORTRAN TO CALL C ROUTINES                  */
72435 
72436 #ifdef OLD_VAXC                                /* Prevent %CC-I-PARAMNOTUSED. */
72437 #pragma nostandard
72438 #endif
72439 
72440 #if defined(vmsFortran) || defined(CRAYFortran)
72441 #define   DCF(TN,I)
72442 #define  DDCF(TN,I)
72443 #define DDDCF(TN,I)
72444 #else
72445 #define   DCF(TN,I)          HCF(TN,I)
72446 #define  DDCF(TN,I)         HHCF(TN,I)
72447 #define DDDCF(TN,I)        HHHCF(TN,I)
72448 #endif
72449 
72450 #define QCF(TN,I)       _(TN,_cfSTR)(1,Q,_(B,I), 0,0,0,0)
72451 #define  DEFAULT_cfQ(B)
72452 #define  LOGICAL_cfQ(B)
72453 #define PLOGICAL_cfQ(B)
72454 #define  STRINGV_cfQ(B) char *B; unsigned int _(B,N);
72455 #define   STRING_cfQ(B) char *B=NULL;
72456 #define  PSTRING_cfQ(B) char *B=NULL;
72457 #define PSTRINGV_cfQ(B) STRINGV_cfQ(B)
72458 #define PNSTRING_cfQ(B) char *B=NULL;
72459 #define PPSTRING_cfQ(B)
72460 
72461 #ifdef     __sgi   /* Else SGI gives warning 182 contrary to its C LRM A.17.7 */
72462 #define ROUTINE_orig    *(void**)&
72463 #else
72464 #define ROUTINE_orig     (void *)
72465 #endif
72466 
72467 #define ROUTINE_1     ROUTINE_orig
72468 #define ROUTINE_2     ROUTINE_orig
72469 #define ROUTINE_3     ROUTINE_orig
72470 #define ROUTINE_4     ROUTINE_orig
72471 #define ROUTINE_5     ROUTINE_orig
72472 #define ROUTINE_6     ROUTINE_orig
72473 #define ROUTINE_7     ROUTINE_orig
72474 #define ROUTINE_8     ROUTINE_orig
72475 #define ROUTINE_9     ROUTINE_orig
72476 #define ROUTINE_10    ROUTINE_orig
72477 #define ROUTINE_11    ROUTINE_orig
72478 #define ROUTINE_12    ROUTINE_orig
72479 #define ROUTINE_13    ROUTINE_orig
72480 #define ROUTINE_14    ROUTINE_orig
72481 #define ROUTINE_15    ROUTINE_orig
72482 #define ROUTINE_16    ROUTINE_orig
72483 #define ROUTINE_17    ROUTINE_orig
72484 #define ROUTINE_18    ROUTINE_orig
72485 #define ROUTINE_19    ROUTINE_orig
72486 #define ROUTINE_20    ROUTINE_orig
72487 #define ROUTINE_21    ROUTINE_orig
72488 #define ROUTINE_22    ROUTINE_orig
72489 #define ROUTINE_23    ROUTINE_orig
72490 #define ROUTINE_24    ROUTINE_orig
72491 #define ROUTINE_25    ROUTINE_orig
72492 #define ROUTINE_26    ROUTINE_orig
72493 #define ROUTINE_27    ROUTINE_orig
72494 
72495 #define TCF(NAME,TN,I,M)              _SEP_(TN,M,cfCOMMA) _(TN,_cfT)(NAME,I,_(A,I),_(B,I),_(C,I))
72496 #define           BYTE_cfT(M,I,A,B,D) *A
72497 #define         DOUBLE_cfT(M,I,A,B,D) *A
72498 #define          FLOAT_cfT(M,I,A,B,D) *A
72499 #define            INT_cfT(M,I,A,B,D) *A
72500 #define        LOGICAL_cfT(M,I,A,B,D)  F2CLOGICAL(*A)
72501 #define           LONG_cfT(M,I,A,B,D) *A
72502 #define       LONGLONG_cfT(M,I,A,B,D) *A /* added by MR December 2005 */
72503 #define          SHORT_cfT(M,I,A,B,D) *A
72504 #define          BYTEV_cfT(M,I,A,B,D)  A
72505 #define        DOUBLEV_cfT(M,I,A,B,D)  A
72506 #define         FLOATV_cfT(M,I,A,B,D)  VOIDP A
72507 #define           INTV_cfT(M,I,A,B,D)  A
72508 #define       LOGICALV_cfT(M,I,A,B,D)  A
72509 #define          LONGV_cfT(M,I,A,B,D)  A
72510 #define      LONGLONGV_cfT(M,I,A,B,D)  A /* added by MR December 2005 */
72511 #define         SHORTV_cfT(M,I,A,B,D)  A
72512 #define         BYTEVV_cfT(M,I,A,B,D)  (void *)A /* We have to cast to void *,*/
72513 #define        BYTEVVV_cfT(M,I,A,B,D)  (void *)A /* since we don't know the   */
72514 #define       BYTEVVVV_cfT(M,I,A,B,D)  (void *)A /* dimensions of the array.  */
72515 #define      BYTEVVVVV_cfT(M,I,A,B,D)  (void *)A /* i.e. Unfortunately, can't */
72516 #define     BYTEVVVVVV_cfT(M,I,A,B,D)  (void *)A /* check that the type       */
72517 #define    BYTEVVVVVVV_cfT(M,I,A,B,D)  (void *)A /* matches the prototype.    */
72518 #define       DOUBLEVV_cfT(M,I,A,B,D)  (void *)A
72519 #define      DOUBLEVVV_cfT(M,I,A,B,D)  (void *)A
72520 #define     DOUBLEVVVV_cfT(M,I,A,B,D)  (void *)A
72521 #define    DOUBLEVVVVV_cfT(M,I,A,B,D)  (void *)A
72522 #define   DOUBLEVVVVVV_cfT(M,I,A,B,D)  (void *)A
72523 #define  DOUBLEVVVVVVV_cfT(M,I,A,B,D)  (void *)A
72524 #define        FLOATVV_cfT(M,I,A,B,D)  (void *)A
72525 #define       FLOATVVV_cfT(M,I,A,B,D)  (void *)A
72526 #define      FLOATVVVV_cfT(M,I,A,B,D)  (void *)A
72527 #define     FLOATVVVVV_cfT(M,I,A,B,D)  (void *)A
72528 #define    FLOATVVVVVV_cfT(M,I,A,B,D)  (void *)A
72529 #define   FLOATVVVVVVV_cfT(M,I,A,B,D)  (void *)A
72530 #define          INTVV_cfT(M,I,A,B,D)  (void *)A
72531 #define         INTVVV_cfT(M,I,A,B,D)  (void *)A
72532 #define        INTVVVV_cfT(M,I,A,B,D)  (void *)A
72533 #define       INTVVVVV_cfT(M,I,A,B,D)  (void *)A
72534 #define      INTVVVVVV_cfT(M,I,A,B,D)  (void *)A
72535 #define     INTVVVVVVV_cfT(M,I,A,B,D)  (void *)A
72536 #define      LOGICALVV_cfT(M,I,A,B,D)  (void *)A
72537 #define     LOGICALVVV_cfT(M,I,A,B,D)  (void *)A
72538 #define    LOGICALVVVV_cfT(M,I,A,B,D)  (void *)A
72539 #define   LOGICALVVVVV_cfT(M,I,A,B,D)  (void *)A
72540 #define  LOGICALVVVVVV_cfT(M,I,A,B,D)  (void *)A
72541 #define LOGICALVVVVVVV_cfT(M,I,A,B,D)  (void *)A
72542 #define         LONGVV_cfT(M,I,A,B,D)  (void *)A
72543 #define        LONGVVV_cfT(M,I,A,B,D)  (void *)A
72544 #define       LONGVVVV_cfT(M,I,A,B,D)  (void *)A
72545 #define      LONGVVVVV_cfT(M,I,A,B,D)  (void *)A
72546 #define     LONGVVVVVV_cfT(M,I,A,B,D)  (void *)A
72547 #define    LONGVVVVVVV_cfT(M,I,A,B,D)  (void *)A
72548 #define     LONGLONGVV_cfT(M,I,A,B,D)  (void *)A /* added by MR December 2005 */
72549 #define    LONGLONGVVV_cfT(M,I,A,B,D)  (void *)A /* added by MR December 2005 */
72550 #define   LONGLONGVVVV_cfT(M,I,A,B,D)  (void *)A /* added by MR December 2005 */
72551 #define  LONGLONGVVVVV_cfT(M,I,A,B,D)  (void *)A /* added by MR December 2005 */
72552 #define LONGLONGVVVVVV_cfT(M,I,A,B,D)  (void *)A /* added by MR December 2005 */
72553 #define LONGLONGVVVVVVV_cfT(M,I,A,B,D)  (void *)A /* added by MR December 2005 */
72554 #define        SHORTVV_cfT(M,I,A,B,D)  (void *)A
72555 #define       SHORTVVV_cfT(M,I,A,B,D)  (void *)A
72556 #define      SHORTVVVV_cfT(M,I,A,B,D)  (void *)A
72557 #define     SHORTVVVVV_cfT(M,I,A,B,D)  (void *)A
72558 #define    SHORTVVVVVV_cfT(M,I,A,B,D)  (void *)A
72559 #define   SHORTVVVVVVV_cfT(M,I,A,B,D)  (void *)A
72560 #define          PBYTE_cfT(M,I,A,B,D)  A
72561 #define        PDOUBLE_cfT(M,I,A,B,D)  A
72562 #define         PFLOAT_cfT(M,I,A,B,D)  VOIDP A
72563 #define           PINT_cfT(M,I,A,B,D)  A
72564 #define       PLOGICAL_cfT(M,I,A,B,D)  ((*A=F2CLOGICAL(*A)),A)
72565 #define          PLONG_cfT(M,I,A,B,D)  A
72566 #define      PLONGLONG_cfT(M,I,A,B,D)  A /* added by MR December 2005 */
72567 #define         PSHORT_cfT(M,I,A,B,D)  A
72568 #define          PVOID_cfT(M,I,A,B,D)  A
72569 #if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran)
72570 #define        ROUTINE_cfT(M,I,A,B,D)  _(ROUTINE_,I)  (*A)
72571 #else
72572 #define        ROUTINE_cfT(M,I,A,B,D)  _(ROUTINE_,I)    A
72573 #endif
72574 /* A == pointer to the characters
72575    D == length of the string, or of an element in an array of strings
72576    E == number of elements in an array of strings                             */
72577 #define TTSTR(    A,B,D)                                                       \
72578            ((B=_cf_malloc(D+1))[D]='\0', memcpy(B,A,D), kill_trailing(B,' '))
72579 #define TTTTSTR(  A,B,D)   (!(D<4||A[0]||A[1]||A[2]||A[3]))?NULL:              \
72580                             memchr(A,'\0',D)                 ?A   : TTSTR(A,B,D)
72581 #define TTTTSTRV( A,B,D,E) (_(B,N)=E,B=_cf_malloc(_(B,N)*(D+1)), (void *)      \
72582   vkill_trailing(f2cstrv(A,B,D+1, _(B,N)*(D+1)), D+1,_(B,N)*(D+1),' '))
72583 #ifdef vmsFortran
72584 #define         STRING_cfT(M,I,A,B,D)  TTTTSTR( A->dsc$a_pointer,B,A->dsc$w_length)
72585 #define        STRINGV_cfT(M,I,A,B,D)  TTTTSTRV(A->dsc$a_pointer, B,           \
72586                                              A->dsc$w_length , A->dsc$l_m[0])
72587 #define        PSTRING_cfT(M,I,A,B,D)    TTSTR( A->dsc$a_pointer,B,A->dsc$w_length)
72588 #define       PPSTRING_cfT(M,I,A,B,D)           A->dsc$a_pointer
72589 #else
72590 #ifdef CRAYFortran
72591 #define         STRING_cfT(M,I,A,B,D)  TTTTSTR( _fcdtocp(A),B,_fcdlen(A))
72592 #define        STRINGV_cfT(M,I,A,B,D)  TTTTSTRV(_fcdtocp(A),B,_fcdlen(A),      \
72593                               num_elem(_fcdtocp(A),_fcdlen(A),_3(M,_STRV_A,I)))
72594 #define        PSTRING_cfT(M,I,A,B,D)    TTSTR( _fcdtocp(A),B,_fcdlen(A))
72595 #define       PPSTRING_cfT(M,I,A,B,D)           _fcdtocp(A)
72596 #else
72597 #define         STRING_cfT(M,I,A,B,D)  TTTTSTR( A,B,D)
72598 #define        STRINGV_cfT(M,I,A,B,D)  TTTTSTRV(A,B,D, num_elem(A,D,_3(M,_STRV_A,I)))
72599 #define        PSTRING_cfT(M,I,A,B,D)    TTSTR( A,B,D)
72600 #define       PPSTRING_cfT(M,I,A,B,D)           ((void)D, A)
72601 #endif
72602 #endif
72603 #define       PNSTRING_cfT(M,I,A,B,D)    STRING_cfT(M,I,A,B,D)
72604 #define       PSTRINGV_cfT(M,I,A,B,D)   STRINGV_cfT(M,I,A,B,D)
72605 #define           CF_0_cfT(M,I,A,B,D)
72606 
72607 #define RCF(TN,I)           _(TN,_cfSTR)(3,R,_(A,I),_(B,I),_(C,I),0,0)
72608 #define  DEFAULT_cfR(A,B,D)
72609 #define  LOGICAL_cfR(A,B,D)
72610 #define PLOGICAL_cfR(A,B,D) *A=C2FLOGICAL(*A);
72611 #define   STRING_cfR(A,B,D) if (B) _cf_free(B);
72612 #define  STRINGV_cfR(A,B,D) _cf_free(B);
72613 /* A and D as defined above for TSTRING(V) */
72614 #define RRRRPSTR( A,B,D)    if (B) memcpy(A,B, _cfMIN(strlen(B),D)),           \
72615                   (D>strlen(B)?memset(A+strlen(B),' ', D-strlen(B)):0), _cf_free(B);
72616 #define RRRRPSTRV(A,B,D)    c2fstrv(B,A,D+1,(D+1)*_(B,N)), _cf_free(B);
72617 #ifdef vmsFortran
72618 #define  PSTRING_cfR(A,B,D) RRRRPSTR( A->dsc$a_pointer,B,A->dsc$w_length)
72619 #define PSTRINGV_cfR(A,B,D) RRRRPSTRV(A->dsc$a_pointer,B,A->dsc$w_length)
72620 #else
72621 #ifdef CRAYFortran
72622 #define  PSTRING_cfR(A,B,D) RRRRPSTR( _fcdtocp(A),B,_fcdlen(A))
72623 #define PSTRINGV_cfR(A,B,D) RRRRPSTRV(_fcdtocp(A),B,_fcdlen(A))
72624 #else
72625 #define  PSTRING_cfR(A,B,D) RRRRPSTR( A,B,D)
72626 #define PSTRINGV_cfR(A,B,D) RRRRPSTRV(A,B,D)
72627 #endif
72628 #endif
72629 #define PNSTRING_cfR(A,B,D) PSTRING_cfR(A,B,D)
72630 #define PPSTRING_cfR(A,B,D)
72631 
72632 #define    BYTE_cfFZ(UN,LN) INTEGER_BYTE     FCALLSC_QUALIFIER fcallsc(UN,LN)(
72633 #define  DOUBLE_cfFZ(UN,LN) DOUBLE_PRECISION FCALLSC_QUALIFIER fcallsc(UN,LN)(
72634 #define     INT_cfFZ(UN,LN) int   FCALLSC_QUALIFIER fcallsc(UN,LN)(
72635 #define LOGICAL_cfFZ(UN,LN) int   FCALLSC_QUALIFIER fcallsc(UN,LN)(
72636 #define    LONG_cfFZ(UN,LN) long  FCALLSC_QUALIFIER fcallsc(UN,LN)(
72637 #define LONGLONG_cfFZ(UN,LN) LONGLONG FCALLSC_QUALIFIER fcallsc(UN,LN)( /* added by MR December 2005 */
72638 #define   SHORT_cfFZ(UN,LN) short FCALLSC_QUALIFIER fcallsc(UN,LN)(
72639 #define    VOID_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(
72640 #ifndef __CF__KnR
72641 /* The void is req'd by the Apollo, to make this an ANSI function declaration.
72642    The Apollo promotes K&R float functions to double. */
72643 #if defined (f2cFortran) && ! defined (gFortran)
72644 /* f2c/g77 return double from FORTRAN REAL functions. (KMCCARTY, 2005/12/09) */
72645 #define FLOAT_cfFZ(UN,LN) DOUBLE_PRECISION FCALLSC_QUALIFIER fcallsc(UN,LN)(void
72646 #else
72647 #define FLOAT_cfFZ(UN,LN) FORTRAN_REAL FCALLSC_QUALIFIER fcallsc(UN,LN)(void
72648 #endif
72649 #ifdef vmsFortran
72650 #define  STRING_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(fstring *AS
72651 #else
72652 #ifdef CRAYFortran
72653 #define  STRING_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(_fcd     AS
72654 #else
72655 #if  defined(AbsoftUNIXFortran) || defined(AbsoftProFortran)
72656 #define  STRING_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(char    *AS
72657 #else
72658 #define  STRING_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(char    *AS, unsigned D0
72659 #endif
72660 #endif
72661 #endif
72662 #else
72663 #if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
72664 #if defined (f2cFortran) && ! defined (gFortran)
72665 /* f2c/g77 return double from FORTRAN REAL functions. (KMCCARTY, 2005/12/09) */
72666 #define   FLOAT_cfFZ(UN,LN) DOUBLE_PRECISION  FCALLSC_QUALIFIER fcallsc(UN,LN)(
72667 #else
72668 #define   FLOAT_cfFZ(UN,LN) FORTRAN_REAL      FCALLSC_QUALIFIER fcallsc(UN,LN)(
72669 #endif
72670 #else
72671 #define   FLOAT_cfFZ(UN,LN) FLOATFUNCTIONTYPE FCALLSC_QUALIFIER fcallsc(UN,LN)(
72672 #endif
72673 #if defined(vmsFortran) || defined(CRAYFortran) || defined(AbsoftUNIXFortran)
72674 #define  STRING_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(AS
72675 #else
72676 #define  STRING_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(AS, D0
72677 #endif
72678 #endif
72679 
72680 #define    BYTE_cfF(UN,LN)     BYTE_cfFZ(UN,LN)
72681 #define  DOUBLE_cfF(UN,LN)   DOUBLE_cfFZ(UN,LN)
72682 #ifndef __CF_KnR
72683 #if defined (f2cFortran) && ! defined (gFortran)
72684 /* f2c/g77 return double from FORTRAN REAL functions. (KMCCARTY, 2005/12/09) */
72685 #define   FLOAT_cfF(UN,LN)  DOUBLE_PRECISION FCALLSC_QUALIFIER fcallsc(UN,LN)(
72686 #else
72687 #define   FLOAT_cfF(UN,LN)  FORTRAN_REAL FCALLSC_QUALIFIER fcallsc(UN,LN)(
72688 #endif
72689 #else
72690 #define   FLOAT_cfF(UN,LN)    FLOAT_cfFZ(UN,LN)
72691 #endif
72692 #define     INT_cfF(UN,LN)      INT_cfFZ(UN,LN)
72693 #define LOGICAL_cfF(UN,LN)  LOGICAL_cfFZ(UN,LN)
72694 #define    LONG_cfF(UN,LN)     LONG_cfFZ(UN,LN)
72695 #define LONGLONG_cfF(UN,LN) LONGLONG_cfFZ(UN,LN) /* added by MR December 2005 */
72696 #define   SHORT_cfF(UN,LN)    SHORT_cfFZ(UN,LN)
72697 #define    VOID_cfF(UN,LN)     VOID_cfFZ(UN,LN)
72698 #define  STRING_cfF(UN,LN)   STRING_cfFZ(UN,LN),
72699 
72700 #define     INT_cfFF
72701 #define    VOID_cfFF
72702 #ifdef vmsFortran
72703 #define  STRING_cfFF           fstring *AS;
72704 #else
72705 #ifdef CRAYFortran
72706 #define  STRING_cfFF           _fcd     AS;
72707 #else
72708 #define  STRING_cfFF           char    *AS; unsigned D0;
72709 #endif
72710 #endif
72711 
72712 #define     INT_cfL            A0=
72713 #define  STRING_cfL            A0=
72714 #define    VOID_cfL
72715 
72716 #define    INT_cfK
72717 #define   VOID_cfK
72718 /* KSTRING copies the string into the position provided by the caller. */
72719 #ifdef vmsFortran
72720 #define STRING_cfK                                                             \
72721  memcpy(AS->dsc$a_pointer,A0,_cfMIN(AS->dsc$w_length,(A0==NULL?0:strlen(A0))));\
72722  AS->dsc$w_length>(A0==NULL?0:strlen(A0))?                                     \
72723   memset(AS->dsc$a_pointer+(A0==NULL?0:strlen(A0)),' ',                        \
72724          AS->dsc$w_length-(A0==NULL?0:strlen(A0))):0;
72725 #else
72726 #ifdef CRAYFortran
72727 #define STRING_cfK                                                             \
72728  memcpy(_fcdtocp(AS),A0, _cfMIN(_fcdlen(AS),(A0==NULL?0:strlen(A0))) );        \
72729  _fcdlen(AS)>(A0==NULL?0:strlen(A0))?                                          \
72730   memset(_fcdtocp(AS)+(A0==NULL?0:strlen(A0)),' ',                             \
72731          _fcdlen(AS)-(A0==NULL?0:strlen(A0))):0;
72732 #else
72733 #define STRING_cfK         memcpy(AS,A0, _cfMIN(D0,(A0==NULL?0:strlen(A0))) ); \
72734                  D0>(A0==NULL?0:strlen(A0))?memset(AS+(A0==NULL?0:strlen(A0)), \
72735                                             ' ', D0-(A0==NULL?0:strlen(A0))):0;
72736 #endif
72737 #endif
72738 
72739 /* Note that K.. and I.. can't be combined since K.. has to access data before
72740 R.., in order for functions returning strings which are also passed in as
72741 arguments to work correctly. Note that R.. frees and hence may corrupt the
72742 string. */
72743 #define    BYTE_cfI  return A0;
72744 #define  DOUBLE_cfI  return A0;
72745 #if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
72746 #define   FLOAT_cfI  return A0;
72747 #else
72748 #define   FLOAT_cfI  RETURNFLOAT(A0);
72749 #endif
72750 #define     INT_cfI  return A0;
72751 #ifdef hpuxFortran800
72752 /* Incredibly, functions must return true as 1, elsewhere .true.==0x01000000. */
72753 #define LOGICAL_cfI  return ((A0)?1:0);
72754 #else
72755 #define LOGICAL_cfI  return C2FLOGICAL(A0);
72756 #endif
72757 #define    LONG_cfI  return A0;
72758 #define LONGLONG_cfI  return A0; /* added by MR December 2005 */
72759 #define   SHORT_cfI  return A0;
72760 #define  STRING_cfI  return   ;
72761 #define    VOID_cfI  return   ;
72762 
72763 #ifdef OLD_VAXC                                  /* Allow %CC-I-PARAMNOTUSED. */
72764 #pragma standard
72765 #endif
72766 
72767 #define FCALLSCSUB0( CN,UN,LN)             FCALLSCFUN0(VOID,CN,UN,LN)
72768 #define FCALLSCSUB1( CN,UN,LN,T1)          FCALLSCFUN1(VOID,CN,UN,LN,T1)
72769 #define FCALLSCSUB2( CN,UN,LN,T1,T2)       FCALLSCFUN2(VOID,CN,UN,LN,T1,T2)
72770 #define FCALLSCSUB3( CN,UN,LN,T1,T2,T3)    FCALLSCFUN3(VOID,CN,UN,LN,T1,T2,T3)
72771 #define FCALLSCSUB4( CN,UN,LN,T1,T2,T3,T4) \
72772     FCALLSCFUN4(VOID,CN,UN,LN,T1,T2,T3,T4)
72773 #define FCALLSCSUB5( CN,UN,LN,T1,T2,T3,T4,T5) \
72774     FCALLSCFUN5(VOID,CN,UN,LN,T1,T2,T3,T4,T5)
72775 #define FCALLSCSUB6( CN,UN,LN,T1,T2,T3,T4,T5,T6) \
72776     FCALLSCFUN6(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6)
72777 #define FCALLSCSUB7( CN,UN,LN,T1,T2,T3,T4,T5,T6,T7) \
72778     FCALLSCFUN7(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7)
72779 #define FCALLSCSUB8( CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8) \
72780     FCALLSCFUN8(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8)
72781 #define FCALLSCSUB9( CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9) \
72782     FCALLSCFUN9(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9)
72783 #define FCALLSCSUB10(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA) \
72784    FCALLSCFUN10(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA)
72785 #define FCALLSCSUB11(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB) \
72786    FCALLSCFUN11(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB)
72787 #define FCALLSCSUB12(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC) \
72788    FCALLSCFUN12(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC)
72789 #define FCALLSCSUB13(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD) \
72790    FCALLSCFUN13(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD)
72791 #define FCALLSCSUB14(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
72792    FCALLSCFUN14(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
72793 #define FCALLSCSUB15(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF) \
72794    FCALLSCFUN15(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF)
72795 #define FCALLSCSUB16(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG) \
72796    FCALLSCFUN16(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG)
72797 #define FCALLSCSUB17(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH) \
72798    FCALLSCFUN17(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH)
72799 #define FCALLSCSUB18(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI) \
72800    FCALLSCFUN18(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI)
72801 #define FCALLSCSUB19(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ) \
72802    FCALLSCFUN19(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ)
72803 #define FCALLSCSUB20(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
72804    FCALLSCFUN20(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)
72805 #define FCALLSCSUB21(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL) \
72806    FCALLSCFUN21(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL)
72807 #define FCALLSCSUB22(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM) \
72808    FCALLSCFUN22(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM)
72809 #define FCALLSCSUB23(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN) \
72810    FCALLSCFUN23(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN)
72811 #define FCALLSCSUB24(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO) \
72812    FCALLSCFUN24(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO)
72813 #define FCALLSCSUB25(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP) \
72814    FCALLSCFUN25(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP)
72815 #define FCALLSCSUB26(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ) \
72816    FCALLSCFUN26(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ)
72817 #define FCALLSCSUB27(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
72818    FCALLSCFUN27(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
72819 
72820 
72821 #define FCALLSCFUN1( T0,CN,UN,LN,T1) \
72822         FCALLSCFUN5 (T0,CN,UN,LN,T1,CF_0,CF_0,CF_0,CF_0)
72823 #define FCALLSCFUN2( T0,CN,UN,LN,T1,T2) \
72824         FCALLSCFUN5 (T0,CN,UN,LN,T1,T2,CF_0,CF_0,CF_0)
72825 #define FCALLSCFUN3( T0,CN,UN,LN,T1,T2,T3) \
72826         FCALLSCFUN5 (T0,CN,UN,LN,T1,T2,T3,CF_0,CF_0)
72827 #define FCALLSCFUN4( T0,CN,UN,LN,T1,T2,T3,T4) \
72828         FCALLSCFUN5 (T0,CN,UN,LN,T1,T2,T3,T4,CF_0)
72829 #define FCALLSCFUN5( T0,CN,UN,LN,T1,T2,T3,T4,T5) \
72830         FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0)
72831 #define FCALLSCFUN6( T0,CN,UN,LN,T1,T2,T3,T4,T5,T6) \
72832         FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0)
72833 #define FCALLSCFUN7( T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7) \
72834         FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0)
72835 #define FCALLSCFUN8( T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8) \
72836         FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0)
72837 #define FCALLSCFUN9( T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9) \
72838         FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0)
72839 #define FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA) \
72840         FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0)
72841 #define FCALLSCFUN11(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB) \
72842         FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0)
72843 #define FCALLSCFUN12(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC) \
72844         FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0)
72845 #define FCALLSCFUN13(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD) \
72846         FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0)
72847 
72848 
72849 #define FCALLSCFUN15(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF) \
72850         FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,CF_0,CF_0,CF_0,CF_0,CF_0)
72851 #define FCALLSCFUN16(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG) \
72852         FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,CF_0,CF_0,CF_0,CF_0)
72853 #define FCALLSCFUN17(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH) \
72854         FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,CF_0,CF_0,CF_0)
72855 #define FCALLSCFUN18(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI) \
72856         FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,CF_0,CF_0)
72857 #define FCALLSCFUN19(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ) \
72858         FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,CF_0)
72859 #define FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
72860         FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
72861 #define FCALLSCFUN21(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL) \
72862         FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
72863 #define FCALLSCFUN22(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM) \
72864         FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,CF_0,CF_0,CF_0,CF_0,CF_0)
72865 #define FCALLSCFUN23(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN) \
72866         FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,CF_0,CF_0,CF_0,CF_0)
72867 #define FCALLSCFUN24(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO) \
72868         FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,CF_0,CF_0,CF_0)
72869 #define FCALLSCFUN25(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP) \
72870         FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,CF_0,CF_0)
72871 #define FCALLSCFUN26(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ) \
72872         FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,CF_0)
72873 
72874 
72875 #ifndef __CF__KnR
72876 #define FCALLSCFUN0(T0,CN,UN,LN) CFextern _(T0,_cfFZ)(UN,LN) ABSOFT_cf2(T0))   \
72877         {_Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0) CN(); _Icf(0,K,T0,0,0) _(T0,_cfI)}
72878 
72879 #define FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)    \
72880                                  CFextern _(T0,_cfF)(UN,LN)                    \
72881  CFARGT14(NCF,DCF,ABSOFT_cf2(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) )  \
72882  {                 CFARGT14S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)    \
72883   _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0)      CN(    TCF(LN,T1,1,0)  TCF(LN,T2,2,1) \
72884     TCF(LN,T3,3,1)  TCF(LN,T4,4,1) TCF(LN,T5,5,1)  TCF(LN,T6,6,1)  TCF(LN,T7,7,1) \
72885     TCF(LN,T8,8,1)  TCF(LN,T9,9,1) TCF(LN,TA,10,1) TCF(LN,TB,11,1) TCF(LN,TC,12,1) \
72886     TCF(LN,TD,13,1) TCF(LN,TE,14,1) );                          _Icf(0,K,T0,0,0) \
72887                    CFARGT14S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)  _(T0,_cfI) }
72888 
72889 #define FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)   \
72890                                  CFextern _(T0,_cfF)(UN,LN)                    \
72891  CFARGT27(NCF,DCF,ABSOFT_cf2(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) ) \
72892  {                 CFARGT27S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)   \
72893   _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0)      CN(     TCF(LN,T1,1,0)  TCF(LN,T2,2,1)  \
72894     TCF(LN,T3,3,1)  TCF(LN,T4,4,1)  TCF(LN,T5,5,1)  TCF(LN,T6,6,1)  TCF(LN,T7,7,1)  \
72895     TCF(LN,T8,8,1)  TCF(LN,T9,9,1)  TCF(LN,TA,10,1) TCF(LN,TB,11,1) TCF(LN,TC,12,1) \
72896     TCF(LN,TD,13,1) TCF(LN,TE,14,1) TCF(LN,TF,15,1) TCF(LN,TG,16,1) TCF(LN,TH,17,1) \
72897     TCF(LN,TI,18,1) TCF(LN,TJ,19,1) TCF(LN,TK,20,1) TCF(LN,TL,21,1) TCF(LN,TM,22,1) \
72898     TCF(LN,TN,23,1) TCF(LN,TO,24,1) TCF(LN,TP,25,1) TCF(LN,TQ,26,1) TCF(LN,TR,27,1) ); _Icf(0,K,T0,0,0) \
72899                    CFARGT27S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)  _(T0,_cfI) }
72900 
72901 #else
72902 #define FCALLSCFUN0(T0,CN,UN,LN) CFextern _(T0,_cfFZ)(UN,LN) ABSOFT_cf3(T0)) _Icf(0,FF,T0,0,0)\
72903         {_Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0) CN(); _Icf(0,K,T0,0,0) _(T0,_cfI)}
72904 
72905 #define FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)    \
72906                                  CFextern _(T0,_cfF)(UN,LN)                    \
72907  CFARGT14(NNCF,DDCF,ABSOFT_cf3(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)) _Icf(0,FF,T0,0,0) \
72908        CFARGT14FS(NNNCF,DDDCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE);   \
72909  {                 CFARGT14S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)    \
72910   _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0)      CN(  TCF(LN,T1,1,0) TCF(LN,T2,2,1) \
72911     TCF(LN,T3,3,1) TCF(LN,T4,4,1) TCF(LN,T5,5,1) TCF(LN,T6,6,1) TCF(LN,T7,7,1) \
72912     TCF(LN,T8,8,1) TCF(LN,T9,9,1) TCF(LN,TA,10,1) TCF(LN,TB,11,1) TCF(LN,TC,12,1) \
72913     TCF(LN,TD,13,1) TCF(LN,TE,14,1) );                          _Icf(0,K,T0,0,0) \
72914                    CFARGT14S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)  _(T0,_cfI)}
72915 
72916 #define FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)  \
72917                                  CFextern _(T0,_cfF)(UN,LN)                    \
72918  CFARGT27(NNCF,DDCF,ABSOFT_cf3(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)) _Icf(0,FF,T0,0,0) \
72919        CFARGT27FS(NNNCF,DDDCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR); \
72920  {                 CFARGT27S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)  \
72921   _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0)      CN(     TCF(LN,T1,1,0)  TCF(LN,T2,2,1)  \
72922     TCF(LN,T3,3,1)  TCF(LN,T4,4,1)  TCF(LN,T5,5,1)  TCF(LN,T6,6,1)  TCF(LN,T7,7,1)  \
72923     TCF(LN,T8,8,1)  TCF(LN,T9,9,1)  TCF(LN,TA,10,1) TCF(LN,TB,11,1) TCF(LN,TC,12,1) \
72924     TCF(LN,TD,13,1) TCF(LN,TE,14,1) TCF(LN,TF,15,1) TCF(LN,TG,16,1) TCF(LN,TH,17,1) \
72925     TCF(LN,TI,18,1) TCF(LN,TJ,19,1) TCF(LN,TK,20,1) TCF(LN,TL,21,1) TCF(LN,TM,22,1) \
72926     TCF(LN,TN,23,1) TCF(LN,TO,24,1) TCF(LN,TP,25,1) TCF(LN,TQ,26,1) TCF(LN,TR,27,1) ); _Icf(0,K,T0,0,0) \
72927                    CFARGT27S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)  _(T0,_cfI)}
72928 
72929 #endif
72930 
72931 
72932 #endif	 /* __CFORTRAN_LOADED */
72933 #endif
72934 /* Automatically generated by make_fint.c, don't edit! */
72935 
72936 #ifdef HAVE_CONFIG_H
72937 #include "config.h"
72938 #endif
72939 
72940 #ifndef CDI_H_
72941 #  include "cdi.h"
72942 #endif
72943 
72944 #ifdef HAVE_CF_INTERFACE
72945 
72946 #include <limits.h>
72947 #include <assert.h>
72948 
72949 #ifndef __CFORTRAN_LOADED
72950 #  if defined __clang__
72951 #    pragma GCC diagnostic push
72952 #    pragma GCC diagnostic ignored "-Wreserved-id-macro"
72953 #  endif
72954 #  include "cfortran.h"
72955 #  if defined __clang__
72956 #    pragma GCC diagnostic pop
72957 #  endif
72958 #endif
72959 /* These functions are meant to be called from Fortran and don't
72960  * need an interface declaration in a C header. */
72961 #ifdef __clang__
72962 #  pragma GCC diagnostic ignored "-Wmissing-prototypes"
72963 #endif
72964 
72965 static inline
int64_t_c2f(int64_t value_int64_t)72966 int int64_t_c2f(int64_t value_int64_t)
72967 {
72968   assert(value_int64_t < INT_MAX);
72969   return (int) value_int64_t;
72970 }
72971 
72972 static inline
size_t_c2f(size_t value_size_t)72973 int size_t_c2f(size_t value_size_t)
72974 {
72975   assert(value_size_t < INT_MAX);
72976   return (int) value_size_t;
72977 }
72978 
72979 
72980 /*  Byte order  */
72981 
72982 
72983 /*  Error identifier  */
72984 
72985 
72986 /*  File types  */
72987 
72988 
72989 /*  Compress types  */
72990 
72991 
72992 /*  external data types  */
72993 
72994 
72995 /*  internal data types  */
72996 
72997 
72998 /*  Chunks  */
72999 
73000 
73001 /*  GRID types  */
73002 
73003 
73004 /*  ZAXIS types  */
73005 
73006 
73007 /*  SUBTYPE types  */
73008 
73009 
73010 /*  Data structure defining a key-value search, possibly with multiple
73011    key-value pairs in combination.
73012 
73013    Currently, only multiple pairs combined by AND are supported.  */
73014 
73015 
73016 /*  TIME types  */
73017 
73018 
73019 /*  TSTEP types  */
73020 
73021 
73022 /*  TAXIS types  */
73023 
73024 
73025 /*  TUNIT types  */
73026 
73027 
73028 /*  CALENDAR types  */
73029 
73030 
73031 /*  number of unsigned char needed to store UUID  */
73032 
73033 
73034 /*  Structs that are used to return data to the user  */
73035 
73036 
73037 /*  Opaque types  */
73038 
73039 
73040 /*  CDI control routines  */
73041 
FCALLSCSUB0(cdiReset,CDIRESET,cdireset)73042 FCALLSCSUB0 (cdiReset, CDIRESET, cdireset)
73043 FCALLSCFUN1 (STRING, cdiStringError, CDISTRINGERROR, cdistringerror, INT)
73044 FCALLSCSUB1 (cdiDebug, CDIDEBUG, cdidebug, INT)
73045 FCALLSCFUN0 (STRING, cdiLibraryVersion, CDILIBRARYVERSION, cdilibraryversion)
73046 FCALLSCSUB0 (cdiPrintVersion, CDIPRINTVERSION, cdiprintversion)
73047 FCALLSCFUN1 (INT, cdiHaveFiletype, CDIHAVEFILETYPE, cdihavefiletype, INT)
73048 FCALLSCSUB1 (cdiDefMissval, CDIDEFMISSVAL, cdidefmissval, DOUBLE)
73049 FCALLSCFUN0 (DOUBLE, cdiInqMissval, CDIINQMISSVAL, cdiinqmissval)
73050 FCALLSCFUN0 (DOUBLE, cdiInqGridMissval, CDIINQGRIDMISSVAL, cdiinqgridmissval)
73051 FCALLSCSUB2 (cdiDefGlobal, CDIDEFGLOBAL, cdidefglobal, STRING, INT)
73052 FCALLSCFUN0 (INT, namespaceNew, NAMESPACENEW, namespacenew)
73053 FCALLSCSUB1 (namespaceSetActive, NAMESPACESETACTIVE, namespacesetactive, INT)
73054 FCALLSCFUN0 (INT, namespaceGetActive, NAMESPACEGETACTIVE, namespacegetactive)
73055 FCALLSCSUB1 (namespaceDelete, NAMESPACEDELETE, namespacedelete, INT)
73056 
73057 /*  CDI converter routines  */
73058 
73059 
73060 /*  parameter  */
73061 
73062 FCALLSCSUB3 (cdiParamToString, CDIPARAMTOSTRING, cdiparamtostring, INT, PSTRING, INT)
73063 FCALLSCSUB4 (cdiDecodeParam, CDIDECODEPARAM, cdidecodeparam, INT, PINT, PINT, PINT)
73064 FCALLSCFUN3 (INT, cdiEncodeParam, CDIENCODEPARAM, cdiencodeparam, INT, INT, INT)
73065 
73066 /*  date format:  YYYYMMDD  */
73067 
73068 
73069 /*  time format:    hhmmss  */
73070 
73071 static void cdiDecodeDate_fwrap(int date, int *year, int *month, int *day)
73072 {
73073   cdiDecodeDate((int64_t)date, year, month, day);
73074 }
FCALLSCSUB4(cdiDecodeDate_fwrap,CDIDECODEDATE,cdidecodedate,INT,PINT,PINT,PINT)73075 FCALLSCSUB4 (cdiDecodeDate_fwrap, CDIDECODEDATE, cdidecodedate, INT, PINT, PINT, PINT)
73076 static int cdiEncodeDate_fwrap(int year, int month, int day)
73077 {
73078   int64_t v;
73079   v = cdiEncodeDate(year, month, day);
73080   return int64_t_c2f(v);
73081 }
FCALLSCFUN3(INT,cdiEncodeDate_fwrap,CDIENCODEDATE,cdiencodedate,INT,INT,INT)73082 FCALLSCFUN3 (INT, cdiEncodeDate_fwrap, CDIENCODEDATE, cdiencodedate, INT, INT, INT)
73083 FCALLSCSUB4 (cdiDecodeTime, CDIDECODETIME, cdidecodetime, INT, PINT, PINT, PINT)
73084 FCALLSCFUN3 (INT, cdiEncodeTime, CDIENCODETIME, cdiencodetime, INT, INT, INT)
73085 
73086 /*  STREAM control routines  */
73087 
73088 FCALLSCFUN2 (INT, cdiGetFiletype, CDIGETFILETYPE, cdigetfiletype, STRING, PINT)
73089 FCALLSCFUN1 (INT, streamOpenRead, STREAMOPENREAD, streamopenread, STRING)
73090 FCALLSCFUN2 (INT, streamOpenWrite, STREAMOPENWRITE, streamopenwrite, STRING, INT)
73091 FCALLSCFUN1 (INT, streamOpenAppend, STREAMOPENAPPEND, streamopenappend, STRING)
73092 FCALLSCSUB1 (streamClose, STREAMCLOSE, streamclose, INT)
73093 FCALLSCSUB1 (streamSync, STREAMSYNC, streamsync, INT)
73094 FCALLSCSUB2 (streamDefNumWorker, STREAMDEFNUMWORKER, streamdefnumworker, INT, INT)
73095 FCALLSCSUB2 (streamDefVlist, STREAMDEFVLIST, streamdefvlist, INT, INT)
73096 FCALLSCFUN1 (INT, streamInqVlist, STREAMINQVLIST, streaminqvlist, INT)
73097 FCALLSCFUN1 (INT, streamInqFiletype, STREAMINQFILETYPE, streaminqfiletype, INT)
73098 FCALLSCSUB2 (streamDefByteorder, STREAMDEFBYTEORDER, streamdefbyteorder, INT, INT)
73099 FCALLSCFUN1 (INT, streamInqByteorder, STREAMINQBYTEORDER, streaminqbyteorder, INT)
73100 FCALLSCSUB2 (streamDefCompType, STREAMDEFCOMPTYPE, streamdefcomptype, INT, INT)
73101 FCALLSCFUN1 (INT, streamInqCompType, STREAMINQCOMPTYPE, streaminqcomptype, INT)
73102 FCALLSCSUB2 (streamDefCompLevel, STREAMDEFCOMPLEVEL, streamdefcomplevel, INT, INT)
73103 FCALLSCFUN1 (INT, streamInqCompLevel, STREAMINQCOMPLEVEL, streaminqcomplevel, INT)
73104 FCALLSCFUN2 (INT, streamDefTimestep, STREAMDEFTIMESTEP, streamdeftimestep, INT, INT)
73105 FCALLSCFUN2 (INT, streamInqTimestep, STREAMINQTIMESTEP, streaminqtimestep, INT, INT)
73106 FCALLSCFUN1 (INT, streamInqCurTimestepID, STREAMINQCURTIMESTEPID, streaminqcurtimestepid, INT)
73107 FCALLSCFUN1 (STRING, streamFilename, STREAMFILENAME, streamfilename, INT)
73108 FCALLSCFUN1 (STRING, streamFilesuffix, STREAMFILESUFFIX, streamfilesuffix, INT)
73109 static int streamNvals_fwrap(int streamID)
73110 {
73111   size_t v;
73112   v = streamNvals(streamID);
73113   return size_t_c2f(v);
73114 }
FCALLSCFUN1(INT,streamNvals_fwrap,STREAMNVALS,streamnvals,INT)73115 FCALLSCFUN1 (INT, streamNvals_fwrap, STREAMNVALS, streamnvals, INT)
73116 FCALLSCFUN1 (INT, streamInqNvars, STREAMINQNVARS, streaminqnvars, INT)
73117 
73118 /*  STREAM var I/O routines (random access)  */
73119 
73120 static void streamWriteVar_fwrap(int streamID, int varID, const double data[], int nmiss)
73121 {
73122   streamWriteVar(streamID, varID, data, (size_t)nmiss);
73123 }
FCALLSCSUB4(streamWriteVar_fwrap,STREAMWRITEVAR,streamwritevar,INT,INT,DOUBLEV,INT)73124 FCALLSCSUB4 (streamWriteVar_fwrap, STREAMWRITEVAR, streamwritevar, INT, INT, DOUBLEV, INT)
73125 static void streamWriteVarF_fwrap(int streamID, int varID, const float data[], int nmiss)
73126 {
73127   streamWriteVarF(streamID, varID, data, (size_t)nmiss);
73128 }
FCALLSCSUB4(streamWriteVarF_fwrap,STREAMWRITEVARF,streamwritevarf,INT,INT,FLOATV,INT)73129 FCALLSCSUB4 (streamWriteVarF_fwrap, STREAMWRITEVARF, streamwritevarf, INT, INT, FLOATV, INT)
73130 static void streamReadVar_fwrap(int streamID, int varID, double data[], int *nmiss)
73131 {
73132   size_t nmiss_size_t;
73133   streamReadVar(streamID, varID, data, &nmiss_size_t);
73134   assert(nmiss_size_t < INT_MAX);
73135   *nmiss = nmiss_size_t;
73136 }
FCALLSCSUB4(streamReadVar_fwrap,STREAMREADVAR,streamreadvar,INT,INT,DOUBLEV,PINT)73137 FCALLSCSUB4 (streamReadVar_fwrap, STREAMREADVAR, streamreadvar, INT, INT, DOUBLEV, PINT)
73138 static void streamReadVarF_fwrap(int streamID, int varID, float data[], int *nmiss)
73139 {
73140   size_t nmiss_size_t;
73141   streamReadVarF(streamID, varID, data, &nmiss_size_t);
73142   assert(nmiss_size_t < INT_MAX);
73143   *nmiss = nmiss_size_t;
73144 }
FCALLSCSUB4(streamReadVarF_fwrap,STREAMREADVARF,streamreadvarf,INT,INT,FLOATV,PINT)73145 FCALLSCSUB4 (streamReadVarF_fwrap, STREAMREADVARF, streamreadvarf, INT, INT, FLOATV, PINT)
73146 static void streamWriteVarSlice_fwrap(int streamID, int varID, int levelID, const double data[], int nmiss)
73147 {
73148   streamWriteVarSlice(streamID, varID, levelID, data, (size_t)nmiss);
73149 }
FCALLSCSUB5(streamWriteVarSlice_fwrap,STREAMWRITEVARSLICE,streamwritevarslice,INT,INT,INT,DOUBLEV,INT)73150 FCALLSCSUB5 (streamWriteVarSlice_fwrap, STREAMWRITEVARSLICE, streamwritevarslice, INT, INT, INT, DOUBLEV, INT)
73151 static void streamWriteVarSliceF_fwrap(int streamID, int varID, int levelID, const float data[], int nmiss)
73152 {
73153   streamWriteVarSliceF(streamID, varID, levelID, data, (size_t)nmiss);
73154 }
FCALLSCSUB5(streamWriteVarSliceF_fwrap,STREAMWRITEVARSLICEF,streamwritevarslicef,INT,INT,INT,FLOATV,INT)73155 FCALLSCSUB5 (streamWriteVarSliceF_fwrap, STREAMWRITEVARSLICEF, streamwritevarslicef, INT, INT, INT, FLOATV, INT)
73156 static void streamReadVarSlice_fwrap(int streamID, int varID, int levelID, double data[], int *nmiss)
73157 {
73158   size_t nmiss_size_t;
73159   streamReadVarSlice(streamID, varID, levelID, data, &nmiss_size_t);
73160   assert(nmiss_size_t < INT_MAX);
73161   *nmiss = nmiss_size_t;
73162 }
FCALLSCSUB5(streamReadVarSlice_fwrap,STREAMREADVARSLICE,streamreadvarslice,INT,INT,INT,DOUBLEV,PINT)73163 FCALLSCSUB5 (streamReadVarSlice_fwrap, STREAMREADVARSLICE, streamreadvarslice, INT, INT, INT, DOUBLEV, PINT)
73164 static void streamReadVarSliceF_fwrap(int streamID, int varID, int levelID, float data[], int *nmiss)
73165 {
73166   size_t nmiss_size_t;
73167   streamReadVarSliceF(streamID, varID, levelID, data, &nmiss_size_t);
73168   assert(nmiss_size_t < INT_MAX);
73169   *nmiss = nmiss_size_t;
73170 }
FCALLSCSUB5(streamReadVarSliceF_fwrap,STREAMREADVARSLICEF,streamreadvarslicef,INT,INT,INT,FLOATV,PINT)73171 FCALLSCSUB5 (streamReadVarSliceF_fwrap, STREAMREADVARSLICEF, streamreadvarslicef, INT, INT, INT, FLOATV, PINT)
73172 static void streamWriteVarChunk_fwrap(int streamID, int varID, const int rect[3][2], const double data[], int nmiss)
73173 {
73174   streamWriteVarChunk(streamID, varID, rect, data, (size_t)nmiss);
73175 }
FCALLSCSUB5(streamWriteVarChunk_fwrap,STREAMWRITEVARCHUNK,streamwritevarchunk,INT,INT,INTVV,DOUBLEV,INT)73176 FCALLSCSUB5 (streamWriteVarChunk_fwrap, STREAMWRITEVARCHUNK, streamwritevarchunk, INT, INT, INTVV, DOUBLEV, INT)
73177 
73178 /*  STREAM record I/O routines (sequential access)  */
73179 
73180 FCALLSCSUB3 (streamDefRecord, STREAMDEFRECORD, streamdefrecord, INT, INT, INT)
73181 FCALLSCSUB3 (streamInqRecord, STREAMINQRECORD, streaminqrecord, INT, PINT, PINT)
73182 static void streamWriteRecord_fwrap(int streamID, const double data[], int nmiss)
73183 {
73184   streamWriteRecord(streamID, data, (size_t)nmiss);
73185 }
FCALLSCSUB3(streamWriteRecord_fwrap,STREAMWRITERECORD,streamwriterecord,INT,DOUBLEV,INT)73186 FCALLSCSUB3 (streamWriteRecord_fwrap, STREAMWRITERECORD, streamwriterecord, INT, DOUBLEV, INT)
73187 static void streamWriteRecordF_fwrap(int streamID, const float data[], int nmiss)
73188 {
73189   streamWriteRecordF(streamID, data, (size_t)nmiss);
73190 }
FCALLSCSUB3(streamWriteRecordF_fwrap,STREAMWRITERECORDF,streamwriterecordf,INT,FLOATV,INT)73191 FCALLSCSUB3 (streamWriteRecordF_fwrap, STREAMWRITERECORDF, streamwriterecordf, INT, FLOATV, INT)
73192 static void streamReadRecord_fwrap(int streamID, double data[], int *nmiss)
73193 {
73194   size_t nmiss_size_t;
73195   streamReadRecord(streamID, data, &nmiss_size_t);
73196   assert(nmiss_size_t < INT_MAX);
73197   *nmiss = nmiss_size_t;
73198 }
FCALLSCSUB3(streamReadRecord_fwrap,STREAMREADRECORD,streamreadrecord,INT,DOUBLEV,PINT)73199 FCALLSCSUB3 (streamReadRecord_fwrap, STREAMREADRECORD, streamreadrecord, INT, DOUBLEV, PINT)
73200 static void streamReadRecordF_fwrap(int streamID, float data[], int *nmiss)
73201 {
73202   size_t nmiss_size_t;
73203   streamReadRecordF(streamID, data, &nmiss_size_t);
73204   assert(nmiss_size_t < INT_MAX);
73205   *nmiss = nmiss_size_t;
73206 }
FCALLSCSUB3(streamReadRecordF_fwrap,STREAMREADRECORDF,streamreadrecordf,INT,FLOATV,PINT)73207 FCALLSCSUB3 (streamReadRecordF_fwrap, STREAMREADRECORDF, streamreadrecordf, INT, FLOATV, PINT)
73208 FCALLSCSUB2 (streamCopyRecord, STREAMCOPYRECORD, streamcopyrecord, INT, INT)
73209 
73210 /*  File driven I/O (may yield better performance than using the streamXXX functions)  */
73211 
73212 
73213 /*  Creation & Destruction  */
73214 
73215 
73216 /*  Advancing an iterator  */
73217 
73218 
73219 /*  Introspecting metadata  */
73220 
73221 
73222 /*  All outXXX arguments to these functions may be NULL.  */
73223 
73224 
73225 /*  Reading data  */
73226 
73227 
73228 /*  TODO[NH]: Add functions to read partial fields.  */
73229 
73230 
73231 /*  Direct access to grib fields  */
73232 
73233 
73234 /*  Callthroughs to GRIB-API  */
73235 
73236 
73237 /*  Convenience functions for accessing GRIB-API keys  */
73238 
73239 
73240 /*  VLIST routines  */
73241 
73242 FCALLSCFUN0 (INT, vlistCreate, VLISTCREATE, vlistcreate)
73243 FCALLSCSUB1 (vlistDestroy, VLISTDESTROY, vlistdestroy, INT)
73244 FCALLSCFUN1 (INT, vlistDuplicate, VLISTDUPLICATE, vlistduplicate, INT)
73245 FCALLSCSUB2 (vlistCopy, VLISTCOPY, vlistcopy, INT, INT)
73246 FCALLSCSUB2 (vlistCopyFlag, VLISTCOPYFLAG, vlistcopyflag, INT, INT)
73247 FCALLSCSUB1 (vlistClearFlag, VLISTCLEARFLAG, vlistclearflag, INT)
73248 FCALLSCSUB2 (vlistCat, VLISTCAT, vlistcat, INT, INT)
73249 FCALLSCSUB2 (vlistMerge, VLISTMERGE, vlistmerge, INT, INT)
73250 FCALLSCSUB1 (vlistPrint, VLISTPRINT, vlistprint, INT)
73251 FCALLSCFUN1 (INT, vlistNumber, VLISTNUMBER, vlistnumber, INT)
73252 FCALLSCFUN1 (INT, vlistNvars, VLISTNVARS, vlistnvars, INT)
73253 FCALLSCFUN1 (INT, vlistNgrids, VLISTNGRIDS, vlistngrids, INT)
73254 FCALLSCFUN1 (INT, vlistNzaxis, VLISTNZAXIS, vlistnzaxis, INT)
73255 FCALLSCFUN1 (INT, vlistNsubtypes, VLISTNSUBTYPES, vlistnsubtypes, INT)
73256 FCALLSCSUB2 (vlistDefNtsteps, VLISTDEFNTSTEPS, vlistdefntsteps, INT, INT)
73257 FCALLSCFUN1 (INT, vlistNtsteps, VLISTNTSTEPS, vlistntsteps, INT)
73258 static int vlistGridsizeMax_fwrap(int vlistID)
73259 {
73260   size_t v;
73261   v = vlistGridsizeMax(vlistID);
73262   return size_t_c2f(v);
73263 }
FCALLSCFUN1(INT,vlistGridsizeMax_fwrap,VLISTGRIDSIZEMAX,vlistgridsizemax,INT)73264 FCALLSCFUN1 (INT, vlistGridsizeMax_fwrap, VLISTGRIDSIZEMAX, vlistgridsizemax, INT)
73265 FCALLSCFUN2 (INT, vlistGrid, VLISTGRID, vlistgrid, INT, INT)
73266 FCALLSCFUN2 (INT, vlistGridIndex, VLISTGRIDINDEX, vlistgridindex, INT, INT)
73267 FCALLSCSUB3 (vlistChangeGridIndex, VLISTCHANGEGRIDINDEX, vlistchangegridindex, INT, INT, INT)
73268 FCALLSCSUB3 (vlistChangeGrid, VLISTCHANGEGRID, vlistchangegrid, INT, INT, INT)
73269 FCALLSCFUN2 (INT, vlistZaxis, VLISTZAXIS, vlistzaxis, INT, INT)
73270 FCALLSCFUN2 (INT, vlistZaxisIndex, VLISTZAXISINDEX, vlistzaxisindex, INT, INT)
73271 FCALLSCSUB3 (vlistChangeZaxisIndex, VLISTCHANGEZAXISINDEX, vlistchangezaxisindex, INT, INT, INT)
73272 FCALLSCSUB3 (vlistChangeZaxis, VLISTCHANGEZAXIS, vlistchangezaxis, INT, INT, INT)
73273 FCALLSCFUN1 (INT, vlistNrecs, VLISTNRECS, vlistnrecs, INT)
73274 FCALLSCFUN2 (INT, vlistSubtype, VLISTSUBTYPE, vlistsubtype, INT, INT)
73275 FCALLSCFUN2 (INT, vlistSubtypeIndex, VLISTSUBTYPEINDEX, vlistsubtypeindex, INT, INT)
73276 FCALLSCSUB2 (vlistDefTaxis, VLISTDEFTAXIS, vlistdeftaxis, INT, INT)
73277 FCALLSCFUN1 (INT, vlistInqTaxis, VLISTINQTAXIS, vlistinqtaxis, INT)
73278 FCALLSCSUB2 (vlistDefTable, VLISTDEFTABLE, vlistdeftable, INT, INT)
73279 FCALLSCFUN1 (INT, vlistInqTable, VLISTINQTABLE, vlistinqtable, INT)
73280 FCALLSCSUB2 (vlistDefInstitut, VLISTDEFINSTITUT, vlistdefinstitut, INT, INT)
73281 FCALLSCFUN1 (INT, vlistInqInstitut, VLISTINQINSTITUT, vlistinqinstitut, INT)
73282 FCALLSCSUB2 (vlistDefModel, VLISTDEFMODEL, vlistdefmodel, INT, INT)
73283 FCALLSCFUN1 (INT, vlistInqModel, VLISTINQMODEL, vlistinqmodel, INT)
73284 
73285 /*  VLIST VAR routines  */
73286 
73287 FCALLSCFUN5 (INT, vlistDefVarTiles, VLISTDEFVARTILES, vlistdefvartiles, INT, INT, INT, INT, INT)
73288 FCALLSCFUN4 (INT, vlistDefVar, VLISTDEFVAR, vlistdefvar, INT, INT, INT, INT)
73289 FCALLSCSUB3 (vlistChangeVarGrid, VLISTCHANGEVARGRID, vlistchangevargrid, INT, INT, INT)
73290 FCALLSCSUB3 (vlistChangeVarZaxis, VLISTCHANGEVARZAXIS, vlistchangevarzaxis, INT, INT, INT)
73291 FCALLSCSUB5 (vlistInqVar, VLISTINQVAR, vlistinqvar, INT, INT, PINT, PINT, PINT)
73292 FCALLSCFUN2 (INT, vlistInqVarGrid, VLISTINQVARGRID, vlistinqvargrid, INT, INT)
73293 FCALLSCFUN2 (INT, vlistInqVarZaxis, VLISTINQVARZAXIS, vlistinqvarzaxis, INT, INT)
73294 
73295 /*  used in MPIOM  */
73296 
73297 FCALLSCFUN2 (INT, vlistInqVarID, VLISTINQVARID, vlistinqvarid, INT, INT)
73298 FCALLSCSUB3 (vlistDefVarTimetype, VLISTDEFVARTIMETYPE, vlistdefvartimetype, INT, INT, INT)
73299 FCALLSCFUN2 (INT, vlistInqVarTimetype, VLISTINQVARTIMETYPE, vlistinqvartimetype, INT, INT)
73300 FCALLSCSUB3 (vlistDefVarTsteptype, VLISTDEFVARTSTEPTYPE, vlistdefvartsteptype, INT, INT, INT)
73301 FCALLSCFUN2 (INT, vlistInqVarTsteptype, VLISTINQVARTSTEPTYPE, vlistinqvartsteptype, INT, INT)
73302 FCALLSCSUB3 (vlistDefVarCompType, VLISTDEFVARCOMPTYPE, vlistdefvarcomptype, INT, INT, INT)
73303 FCALLSCFUN2 (INT, vlistInqVarCompType, VLISTINQVARCOMPTYPE, vlistinqvarcomptype, INT, INT)
73304 FCALLSCSUB3 (vlistDefVarCompLevel, VLISTDEFVARCOMPLEVEL, vlistdefvarcomplevel, INT, INT, INT)
73305 FCALLSCFUN2 (INT, vlistInqVarCompLevel, VLISTINQVARCOMPLEVEL, vlistinqvarcomplevel, INT, INT)
73306 FCALLSCSUB3 (vlistDefVarParam, VLISTDEFVARPARAM, vlistdefvarparam, INT, INT, INT)
73307 FCALLSCFUN2 (INT, vlistInqVarParam, VLISTINQVARPARAM, vlistinqvarparam, INT, INT)
73308 FCALLSCSUB3 (vlistDefVarCode, VLISTDEFVARCODE, vlistdefvarcode, INT, INT, INT)
73309 FCALLSCFUN2 (INT, vlistInqVarCode, VLISTINQVARCODE, vlistinqvarcode, INT, INT)
73310 FCALLSCSUB3 (vlistDefVarDatatype, VLISTDEFVARDATATYPE, vlistdefvardatatype, INT, INT, INT)
73311 FCALLSCFUN2 (INT, vlistInqVarDatatype, VLISTINQVARDATATYPE, vlistinqvardatatype, INT, INT)
73312 FCALLSCSUB3 (vlistDefVarChunkType, VLISTDEFVARCHUNKTYPE, vlistdefvarchunktype, INT, INT, INT)
73313 FCALLSCFUN2 (INT, vlistInqVarChunkType, VLISTINQVARCHUNKTYPE, vlistinqvarchunktype, INT, INT)
73314 FCALLSCSUB3 (vlistDefVarXYZ, VLISTDEFVARXYZ, vlistdefvarxyz, INT, INT, INT)
73315 FCALLSCFUN2 (INT, vlistInqVarXYZ, VLISTINQVARXYZ, vlistinqvarxyz, INT, INT)
73316 FCALLSCFUN2 (INT, vlistInqVarNumber, VLISTINQVARNUMBER, vlistinqvarnumber, INT, INT)
73317 FCALLSCSUB3 (vlistDefVarInstitut, VLISTDEFVARINSTITUT, vlistdefvarinstitut, INT, INT, INT)
73318 FCALLSCFUN2 (INT, vlistInqVarInstitut, VLISTINQVARINSTITUT, vlistinqvarinstitut, INT, INT)
73319 FCALLSCSUB3 (vlistDefVarModel, VLISTDEFVARMODEL, vlistdefvarmodel, INT, INT, INT)
73320 FCALLSCFUN2 (INT, vlistInqVarModel, VLISTINQVARMODEL, vlistinqvarmodel, INT, INT)
73321 FCALLSCSUB3 (vlistDefVarTable, VLISTDEFVARTABLE, vlistdefvartable, INT, INT, INT)
73322 FCALLSCFUN2 (INT, vlistInqVarTable, VLISTINQVARTABLE, vlistinqvartable, INT, INT)
73323 FCALLSCSUB3 (vlistDefVarName, VLISTDEFVARNAME, vlistdefvarname, INT, INT, STRING)
73324 FCALLSCSUB3 (vlistInqVarName, VLISTINQVARNAME, vlistinqvarname, INT, INT, PSTRING)
73325 FCALLSCFUN2 (STRING, vlistCopyVarName, VLISTCOPYVARNAME, vlistcopyvarname, INT, INT)
73326 FCALLSCSUB3 (vlistDefVarStdname, VLISTDEFVARSTDNAME, vlistdefvarstdname, INT, INT, STRING)
73327 FCALLSCSUB3 (vlistInqVarStdname, VLISTINQVARSTDNAME, vlistinqvarstdname, INT, INT, PSTRING)
73328 FCALLSCSUB3 (vlistDefVarLongname, VLISTDEFVARLONGNAME, vlistdefvarlongname, INT, INT, STRING)
73329 FCALLSCSUB3 (vlistInqVarLongname, VLISTINQVARLONGNAME, vlistinqvarlongname, INT, INT, PSTRING)
73330 FCALLSCSUB3 (vlistDefVarUnits, VLISTDEFVARUNITS, vlistdefvarunits, INT, INT, STRING)
73331 FCALLSCSUB3 (vlistInqVarUnits, VLISTINQVARUNITS, vlistinqvarunits, INT, INT, PSTRING)
73332 FCALLSCSUB3 (vlistDefVarMissval, VLISTDEFVARMISSVAL, vlistdefvarmissval, INT, INT, DOUBLE)
73333 FCALLSCFUN2 (DOUBLE, vlistInqVarMissval, VLISTINQVARMISSVAL, vlistinqvarmissval, INT, INT)
73334 FCALLSCSUB3 (vlistDefVarExtra, VLISTDEFVAREXTRA, vlistdefvarextra, INT, INT, STRING)
73335 FCALLSCSUB3 (vlistInqVarExtra, VLISTINQVAREXTRA, vlistinqvarextra, INT, INT, PSTRING)
73336 FCALLSCSUB3 (vlistDefVarScalefactor, VLISTDEFVARSCALEFACTOR, vlistdefvarscalefactor, INT, INT, DOUBLE)
73337 FCALLSCFUN2 (DOUBLE, vlistInqVarScalefactor, VLISTINQVARSCALEFACTOR, vlistinqvarscalefactor, INT, INT)
73338 FCALLSCSUB3 (vlistDefVarAddoffset, VLISTDEFVARADDOFFSET, vlistdefvaraddoffset, INT, INT, DOUBLE)
73339 FCALLSCFUN2 (DOUBLE, vlistInqVarAddoffset, VLISTINQVARADDOFFSET, vlistinqvaraddoffset, INT, INT)
73340 static int vlistInqVarSize_fwrap(int vlistID, int varID)
73341 {
73342   size_t v;
73343   v = vlistInqVarSize(vlistID, varID);
73344   return size_t_c2f(v);
73345 }
FCALLSCFUN2(INT,vlistInqVarSize_fwrap,VLISTINQVARSIZE,vlistinqvarsize,INT,INT)73346 FCALLSCFUN2 (INT, vlistInqVarSize_fwrap, VLISTINQVARSIZE, vlistinqvarsize, INT, INT)
73347 FCALLSCSUB4 (vlistDefIndex, VLISTDEFINDEX, vlistdefindex, INT, INT, INT, INT)
73348 FCALLSCFUN3 (INT, vlistInqIndex, VLISTINQINDEX, vlistinqindex, INT, INT, INT)
73349 FCALLSCSUB4 (vlistDefFlag, VLISTDEFFLAG, vlistdefflag, INT, INT, INT, INT)
73350 FCALLSCFUN3 (INT, vlistInqFlag, VLISTINQFLAG, vlistinqflag, INT, INT, INT)
73351 FCALLSCFUN2 (INT, vlistFindVar, VLISTFINDVAR, vlistfindvar, INT, INT)
73352 FCALLSCFUN3 (INT, vlistFindLevel, VLISTFINDLEVEL, vlistfindlevel, INT, INT, INT)
73353 FCALLSCFUN2 (INT, vlistMergedVar, VLISTMERGEDVAR, vlistmergedvar, INT, INT)
73354 FCALLSCFUN3 (INT, vlistMergedLevel, VLISTMERGEDLEVEL, vlistmergedlevel, INT, INT, INT)
73355 FCALLSCSUB0 (cdiClearAdditionalKeys, CDICLEARADDITIONALKEYS, cdiclearadditionalkeys)
73356 FCALLSCSUB1 (cdiDefAdditionalKey, CDIDEFADDITIONALKEY, cdidefadditionalkey, STRING)
73357 FCALLSCSUB4 (vlistDefVarIntKey, VLISTDEFVARINTKEY, vlistdefvarintkey, INT, INT, STRING, INT)
73358 FCALLSCSUB4 (vlistDefVarDblKey, VLISTDEFVARDBLKEY, vlistdefvardblkey, INT, INT, STRING, DOUBLE)
73359 FCALLSCFUN3 (INT, vlistHasVarKey, VLISTHASVARKEY, vlisthasvarkey, INT, INT, STRING)
73360 FCALLSCFUN3 (DOUBLE, vlistInqVarDblKey, VLISTINQVARDBLKEY, vlistinqvardblkey, INT, INT, STRING)
73361 FCALLSCFUN3 (INT, vlistInqVarIntKey, VLISTINQVARINTKEY, vlistinqvarintkey, INT, INT, STRING)
73362 
73363 /*  CDI attributes  */
73364 
73365 FCALLSCFUN3 (INT, cdiInqNatts, CDIINQNATTS, cdiinqnatts, INT, INT, PINT)
73366 FCALLSCFUN6 (INT, cdiInqAtt, CDIINQATT, cdiinqatt, INT, INT, INT, PSTRING, PINT, PINT)
73367 FCALLSCFUN3 (INT, cdiInqAttLen, CDIINQATTLEN, cdiinqattlen, INT, INT, STRING)
73368 FCALLSCFUN3 (INT, cdiInqAttType, CDIINQATTTYPE, cdiinqatttype, INT, INT, STRING)
73369 FCALLSCFUN3 (INT, cdiDelAtt, CDIDELATT, cdidelatt, INT, INT, STRING)
73370 FCALLSCFUN4 (INT, cdiCopyAtts, CDICOPYATTS, cdicopyatts, INT, INT, INT, INT)
73371 FCALLSCFUN6 (INT, cdiDefAttInt, CDIDEFATTINT, cdidefattint, INT, INT, STRING, INT, INT, INTV)
73372 FCALLSCFUN6 (INT, cdiDefAttFlt, CDIDEFATTFLT, cdidefattflt, INT, INT, STRING, INT, INT, DOUBLEV)
73373 FCALLSCFUN5 (INT, cdiDefAttTxt, CDIDEFATTTXT, cdidefatttxt, INT, INT, STRING, INT, PPSTRING)
73374 FCALLSCFUN5 (INT, cdiInqAttInt, CDIINQATTINT, cdiinqattint, INT, INT, STRING, INT, INTV)
73375 FCALLSCFUN5 (INT, cdiInqAttFlt, CDIINQATTFLT, cdiinqattflt, INT, INT, STRING, INT, DOUBLEV)
73376 FCALLSCFUN5 (INT, cdiInqAttTxt, CDIINQATTTXT, cdiinqatttxt, INT, INT, STRING, INT, PPSTRING)
73377 
73378 /*  GRID routines  */
73379 
73380 FCALLSCSUB2 (gridName, GRIDNAME, gridname, INT, PSTRING)
73381 FCALLSCFUN1 (STRING, gridNamePtr, GRIDNAMEPTR, gridnameptr, INT)
73382 FCALLSCSUB1 (gridCompress, GRIDCOMPRESS, gridcompress, INT)
73383 FCALLSCSUB2 (gridDefMaskGME, GRIDDEFMASKGME, griddefmaskgme, INT, INTV)
73384 FCALLSCFUN2 (INT, gridInqMaskGME, GRIDINQMASKGME, gridinqmaskgme, INT, INTV)
73385 FCALLSCSUB2 (gridDefMask, GRIDDEFMASK, griddefmask, INT, INTV)
73386 FCALLSCFUN2 (INT, gridInqMask, GRIDINQMASK, gridinqmask, INT, INTV)
73387 static int gridCreate_fwrap(int gridtype, int size)
73388 {
73389   int v;
73390   v = gridCreate(gridtype, (size_t)size);
73391   return v;
73392 }
FCALLSCFUN2(INT,gridCreate_fwrap,GRIDCREATE,gridcreate,INT,INT)73393 FCALLSCFUN2 (INT, gridCreate_fwrap, GRIDCREATE, gridcreate, INT, INT)
73394 FCALLSCSUB1 (gridDestroy, GRIDDESTROY, griddestroy, INT)
73395 FCALLSCFUN1 (INT, gridDuplicate, GRIDDUPLICATE, gridduplicate, INT)
73396 FCALLSCSUB2 (gridDefProj, GRIDDEFPROJ, griddefproj, INT, INT)
73397 FCALLSCFUN1 (INT, gridInqProj, GRIDINQPROJ, gridinqproj, INT)
73398 FCALLSCFUN1 (INT, gridInqProjType, GRIDINQPROJTYPE, gridinqprojtype, INT)
73399 FCALLSCFUN1 (INT, gridInqType, GRIDINQTYPE, gridinqtype, INT)
73400 static int gridInqSize_fwrap(int gridID)
73401 {
73402   size_t v;
73403   v = gridInqSize(gridID);
73404   return size_t_c2f(v);
73405 }
FCALLSCFUN1(INT,gridInqSize_fwrap,GRIDINQSIZE,gridinqsize,INT)73406 FCALLSCFUN1 (INT, gridInqSize_fwrap, GRIDINQSIZE, gridinqsize, INT)
73407 static void gridDefXsize_fwrap(int gridID, int xsize)
73408 {
73409   gridDefXsize(gridID, (size_t)xsize);
73410 }
FCALLSCSUB2(gridDefXsize_fwrap,GRIDDEFXSIZE,griddefxsize,INT,INT)73411 FCALLSCSUB2 (gridDefXsize_fwrap, GRIDDEFXSIZE, griddefxsize, INT, INT)
73412 static int gridInqXsize_fwrap(int gridID)
73413 {
73414   size_t v;
73415   v = gridInqXsize(gridID);
73416   return size_t_c2f(v);
73417 }
FCALLSCFUN1(INT,gridInqXsize_fwrap,GRIDINQXSIZE,gridinqxsize,INT)73418 FCALLSCFUN1 (INT, gridInqXsize_fwrap, GRIDINQXSIZE, gridinqxsize, INT)
73419 static void gridDefYsize_fwrap(int gridID, int ysize)
73420 {
73421   gridDefYsize(gridID, (size_t)ysize);
73422 }
FCALLSCSUB2(gridDefYsize_fwrap,GRIDDEFYSIZE,griddefysize,INT,INT)73423 FCALLSCSUB2 (gridDefYsize_fwrap, GRIDDEFYSIZE, griddefysize, INT, INT)
73424 static int gridInqYsize_fwrap(int gridID)
73425 {
73426   size_t v;
73427   v = gridInqYsize(gridID);
73428   return size_t_c2f(v);
73429 }
FCALLSCFUN1(INT,gridInqYsize_fwrap,GRIDINQYSIZE,gridinqysize,INT)73430 FCALLSCFUN1 (INT, gridInqYsize_fwrap, GRIDINQYSIZE, gridinqysize, INT)
73431 FCALLSCSUB2 (gridDefNP, GRIDDEFNP, griddefnp, INT, INT)
73432 FCALLSCFUN1 (INT, gridInqNP, GRIDINQNP, gridinqnp, INT)
73433 FCALLSCSUB2 (gridDefXvals, GRIDDEFXVALS, griddefxvals, INT, DOUBLEV)
73434 static int gridInqXvals_fwrap(int gridID, double xvals[])
73435 {
73436   size_t v;
73437   v = gridInqXvals(gridID, xvals);
73438   return size_t_c2f(v);
73439 }
FCALLSCFUN2(INT,gridInqXvals_fwrap,GRIDINQXVALS,gridinqxvals,INT,DOUBLEV)73440 FCALLSCFUN2 (INT, gridInqXvals_fwrap, GRIDINQXVALS, gridinqxvals, INT, DOUBLEV)
73441 static int gridInqXvalsPart_fwrap(int gridID, int start, int size, double xvals[])
73442 {
73443   size_t v;
73444   v = gridInqXvalsPart(gridID, start, (size_t)size, xvals);
73445   return size_t_c2f(v);
73446 }
FCALLSCFUN4(INT,gridInqXvalsPart_fwrap,GRIDINQXVALSPART,gridinqxvalspart,INT,INT,INT,DOUBLEV)73447 FCALLSCFUN4 (INT, gridInqXvalsPart_fwrap, GRIDINQXVALSPART, gridinqxvalspart, INT, INT, INT, DOUBLEV)
73448 FCALLSCFUN1 (INT, gridInqXIsc, GRIDINQXISC, gridinqxisc, INT)
73449 FCALLSCSUB2 (gridDefYvals, GRIDDEFYVALS, griddefyvals, INT, DOUBLEV)
73450 static int gridInqYvals_fwrap(int gridID, double yvals[])
73451 {
73452   size_t v;
73453   v = gridInqYvals(gridID, yvals);
73454   return size_t_c2f(v);
73455 }
FCALLSCFUN2(INT,gridInqYvals_fwrap,GRIDINQYVALS,gridinqyvals,INT,DOUBLEV)73456 FCALLSCFUN2 (INT, gridInqYvals_fwrap, GRIDINQYVALS, gridinqyvals, INT, DOUBLEV)
73457 static int gridInqYvalsPart_fwrap(int gridID, int start, int size, double yvals[])
73458 {
73459   size_t v;
73460   v = gridInqYvalsPart(gridID, start, (size_t)size, yvals);
73461   return size_t_c2f(v);
73462 }
FCALLSCFUN4(INT,gridInqYvalsPart_fwrap,GRIDINQYVALSPART,gridinqyvalspart,INT,INT,INT,DOUBLEV)73463 FCALLSCFUN4 (INT, gridInqYvalsPart_fwrap, GRIDINQYVALSPART, gridinqyvalspart, INT, INT, INT, DOUBLEV)
73464 FCALLSCFUN1 (INT, gridInqYIsc, GRIDINQYISC, gridinqyisc, INT)
73465 
73466 /*  CDI var keys  */
73467 
73468 
73469 /*  String keys  */
73470 
73471 
73472 /*  Integer keys  */
73473 
73474 
73475 /*  Floating point keys  */
73476 
73477 
73478 /*  Byte array keys  */
73479 
73480 FCALLSCFUN4 (INT, cdiDefKeyInt, CDIDEFKEYINT, cdidefkeyint, INT, INT, INT, INT)
73481 FCALLSCFUN4 (INT, cdiInqKeyInt, CDIINQKEYINT, cdiinqkeyint, INT, INT, INT, PINT)
73482 FCALLSCFUN4 (INT, cdiDefKeyFloat, CDIDEFKEYFLOAT, cdidefkeyfloat, INT, INT, INT, DOUBLE)
73483 
73484 /*  cdiInqKeyFloat Get a float value from a key  */
73485 
73486 FCALLSCFUN4 (INT, cdiInqKeyFloat, CDIINQKEYFLOAT, cdiinqkeyfloat, INT, INT, INT, PDOUBLE)
73487 FCALLSCFUN4 (INT, cdiDefKeyString, CDIDEFKEYSTRING, cdidefkeystring, INT, INT, INT, STRING)
73488 FCALLSCFUN5 (INT, cdiInqKeyString, CDIINQKEYSTRING, cdiinqkeystring, INT, INT, INT, PSTRING, PINT)
73489 FCALLSCFUN4 (INT, cdiInqKeyLen, CDIINQKEYLEN, cdiinqkeylen, INT, INT, INT, PINT)
73490 FCALLSCFUN4 (INT, cdiCopyKeys, CDICOPYKEYS, cdicopykeys, INT, INT, INT, INT)
73491 FCALLSCFUN4 (INT, cdiCopyKey, CDICOPYKEY, cdicopykey, INT, INT, INT, INT)
73492 FCALLSCFUN3 (INT, cdiDeleteKey, CDIDELETEKEY, cdideletekey, INT, INT, INT)
73493 
73494 /*  GRID routines  */
73495 
73496 FCALLSCSUB2 (gridDefXname, GRIDDEFXNAME, griddefxname, INT, STRING)
73497 FCALLSCSUB2 (gridInqXname, GRIDINQXNAME, gridinqxname, INT, PSTRING)
73498 FCALLSCSUB2 (gridDefXlongname, GRIDDEFXLONGNAME, griddefxlongname, INT, STRING)
73499 FCALLSCSUB2 (gridInqXlongname, GRIDINQXLONGNAME, gridinqxlongname, INT, PSTRING)
73500 FCALLSCSUB2 (gridDefXunits, GRIDDEFXUNITS, griddefxunits, INT, STRING)
73501 FCALLSCSUB2 (gridInqXunits, GRIDINQXUNITS, gridinqxunits, INT, PSTRING)
73502 FCALLSCSUB2 (gridDefYname, GRIDDEFYNAME, griddefyname, INT, STRING)
73503 FCALLSCSUB2 (gridInqYname, GRIDINQYNAME, gridinqyname, INT, PSTRING)
73504 FCALLSCSUB2 (gridDefYlongname, GRIDDEFYLONGNAME, griddefylongname, INT, STRING)
73505 FCALLSCSUB2 (gridInqYlongname, GRIDINQYLONGNAME, gridinqylongname, INT, PSTRING)
73506 FCALLSCSUB2 (gridDefYunits, GRIDDEFYUNITS, griddefyunits, INT, STRING)
73507 FCALLSCSUB2 (gridInqYunits, GRIDINQYUNITS, gridinqyunits, INT, PSTRING)
73508 FCALLSCSUB2 (gridDefDatatype, GRIDDEFDATATYPE, griddefdatatype, INT, INT)
73509 FCALLSCFUN1 (INT, gridInqDatatype, GRIDINQDATATYPE, gridinqdatatype, INT)
73510 static double gridInqXval_fwrap(int gridID, int index)
73511 {
73512   double v;
73513   v = gridInqXval(gridID, (size_t)index);
73514   return v;
73515 }
FCALLSCFUN2(DOUBLE,gridInqXval_fwrap,GRIDINQXVAL,gridinqxval,INT,INT)73516 FCALLSCFUN2 (DOUBLE, gridInqXval_fwrap, GRIDINQXVAL, gridinqxval, INT, INT)
73517 static double gridInqYval_fwrap(int gridID, int index)
73518 {
73519   double v;
73520   v = gridInqYval(gridID, (size_t)index);
73521   return v;
73522 }
FCALLSCFUN2(DOUBLE,gridInqYval_fwrap,GRIDINQYVAL,gridinqyval,INT,INT)73523 FCALLSCFUN2 (DOUBLE, gridInqYval_fwrap, GRIDINQYVAL, gridinqyval, INT, INT)
73524 FCALLSCFUN1 (DOUBLE, gridInqXinc, GRIDINQXINC, gridinqxinc, INT)
73525 FCALLSCFUN1 (DOUBLE, gridInqYinc, GRIDINQYINC, gridinqyinc, INT)
73526 FCALLSCFUN1 (INT, gridIsCircular, GRIDISCIRCULAR, gridiscircular, INT)
73527 FCALLSCFUN1 (INT, gridInqTrunc, GRIDINQTRUNC, gridinqtrunc, INT)
73528 FCALLSCSUB2 (gridDefTrunc, GRIDDEFTRUNC, griddeftrunc, INT, INT)
73529 
73530 /*  Reference of an unstructured grid  */
73531 
73532 FCALLSCSUB2 (gridDefNumber, GRIDDEFNUMBER, griddefnumber, INT, INT)
73533 FCALLSCFUN1 (INT, gridInqNumber, GRIDINQNUMBER, gridinqnumber, INT)
73534 FCALLSCSUB2 (gridDefPosition, GRIDDEFPOSITION, griddefposition, INT, INT)
73535 FCALLSCFUN1 (INT, gridInqPosition, GRIDINQPOSITION, gridinqposition, INT)
73536 FCALLSCSUB2 (gridDefReference, GRIDDEFREFERENCE, griddefreference, INT, STRING)
73537 FCALLSCFUN2 (INT, gridInqReference, GRIDINQREFERENCE, gridinqreference, INT, PSTRING)
73538 FCALLSCSUB2 (gridDefUUID, GRIDDEFUUID, griddefuuid, INT, PVOID)
73539 FCALLSCSUB2 (gridInqUUID, GRIDINQUUID, gridinquuid, INT, PVOID)
73540 
73541 /*  Rotated Lon/Lat grid  */
73542 
73543 FCALLSCSUB4 (gridDefParamRLL, GRIDDEFPARAMRLL, griddefparamrll, INT, DOUBLE, DOUBLE, DOUBLE)
73544 FCALLSCSUB4 (gridInqParamRLL, GRIDINQPARAMRLL, gridinqparamrll, INT, PDOUBLE, PDOUBLE, PDOUBLE)
73545 
73546 /*  Hexagonal GME grid  */
73547 
73548 FCALLSCSUB5 (gridDefParamGME, GRIDDEFPARAMGME, griddefparamgme, INT, INT, INT, INT, INT)
73549 FCALLSCSUB5 (gridInqParamGME, GRIDINQPARAMGME, gridinqparamgme, INT, PINT, PINT, PINT, PINT)
73550 
73551 /*  Lambert Conformal Conic grid  */
73552 
73553 FCALLSCSUB12 (gridDefParamLCC, GRIDDEFPARAMLCC, griddefparamlcc, INT, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE)
73554 FCALLSCFUN12 (INT, gridInqParamLCC, GRIDINQPARAMLCC, gridinqparamlcc, INT, DOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE)
73555 
73556 /*  Polar stereographic grid  */
73557 
73558 FCALLSCSUB10 (gridDefParamSTERE, GRIDDEFPARAMSTERE, griddefparamstere, INT, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE)
73559 FCALLSCFUN10 (INT, gridInqParamSTERE, GRIDINQPARAMSTERE, gridinqparamstere, INT, DOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE)
73560 FCALLSCSUB2 (gridDefArea, GRIDDEFAREA, griddefarea, INT, DOUBLEV)
73561 FCALLSCSUB2 (gridInqArea, GRIDINQAREA, gridinqarea, INT, DOUBLEV)
73562 FCALLSCFUN1 (INT, gridHasArea, GRIDHASAREA, gridhasarea, INT)
73563 FCALLSCSUB2 (gridDefNvertex, GRIDDEFNVERTEX, griddefnvertex, INT, INT)
73564 FCALLSCFUN1 (INT, gridInqNvertex, GRIDINQNVERTEX, gridinqnvertex, INT)
73565 FCALLSCSUB2 (gridDefXbounds, GRIDDEFXBOUNDS, griddefxbounds, INT, DOUBLEV)
73566 static int gridInqXbounds_fwrap(int gridID, double xbounds[])
73567 {
73568   size_t v;
73569   v = gridInqXbounds(gridID, xbounds);
73570   return size_t_c2f(v);
73571 }
FCALLSCFUN2(INT,gridInqXbounds_fwrap,GRIDINQXBOUNDS,gridinqxbounds,INT,DOUBLEV)73572 FCALLSCFUN2 (INT, gridInqXbounds_fwrap, GRIDINQXBOUNDS, gridinqxbounds, INT, DOUBLEV)
73573 static int gridInqXboundsPart_fwrap(int gridID, int start, int size, double xbounds[])
73574 {
73575   size_t v;
73576   v = gridInqXboundsPart(gridID, start, (size_t)size, xbounds);
73577   return size_t_c2f(v);
73578 }
FCALLSCFUN4(INT,gridInqXboundsPart_fwrap,GRIDINQXBOUNDSPART,gridinqxboundspart,INT,INT,INT,DOUBLEV)73579 FCALLSCFUN4 (INT, gridInqXboundsPart_fwrap, GRIDINQXBOUNDSPART, gridinqxboundspart, INT, INT, INT, DOUBLEV)
73580 FCALLSCSUB2 (gridDefYbounds, GRIDDEFYBOUNDS, griddefybounds, INT, DOUBLEV)
73581 static int gridInqYbounds_fwrap(int gridID, double ybounds[])
73582 {
73583   size_t v;
73584   v = gridInqYbounds(gridID, ybounds);
73585   return size_t_c2f(v);
73586 }
FCALLSCFUN2(INT,gridInqYbounds_fwrap,GRIDINQYBOUNDS,gridinqybounds,INT,DOUBLEV)73587 FCALLSCFUN2 (INT, gridInqYbounds_fwrap, GRIDINQYBOUNDS, gridinqybounds, INT, DOUBLEV)
73588 static int gridInqYboundsPart_fwrap(int gridID, int start, int size, double ybounds[])
73589 {
73590   size_t v;
73591   v = gridInqYboundsPart(gridID, start, (size_t)size, ybounds);
73592   return size_t_c2f(v);
73593 }
FCALLSCFUN4(INT,gridInqYboundsPart_fwrap,GRIDINQYBOUNDSPART,gridinqyboundspart,INT,INT,INT,DOUBLEV)73594 FCALLSCFUN4 (INT, gridInqYboundsPart_fwrap, GRIDINQYBOUNDSPART, gridinqyboundspart, INT, INT, INT, DOUBLEV)
73595 FCALLSCSUB3 (gridDefReducedPoints, GRIDDEFREDUCEDPOINTS, griddefreducedpoints, INT, INT, INTV)
73596 FCALLSCSUB2 (gridInqReducedPoints, GRIDINQREDUCEDPOINTS, gridinqreducedpoints, INT, INTV)
73597 FCALLSCSUB2 (gridChangeType, GRIDCHANGETYPE, gridchangetype, INT, INT)
73598 FCALLSCSUB2 (gridDefComplexPacking, GRIDDEFCOMPLEXPACKING, griddefcomplexpacking, INT, INT)
73599 FCALLSCFUN1 (INT, gridInqComplexPacking, GRIDINQCOMPLEXPACKING, gridinqcomplexpacking, INT)
73600 
73601 /*  ZAXIS routines  */
73602 
73603 FCALLSCSUB2 (zaxisName, ZAXISNAME, zaxisname, INT, PSTRING)
73604 FCALLSCFUN1 (STRING, zaxisNamePtr, ZAXISNAMEPTR, zaxisnameptr, INT)
73605 FCALLSCFUN2 (INT, zaxisCreate, ZAXISCREATE, zaxiscreate, INT, INT)
73606 FCALLSCSUB1 (zaxisDestroy, ZAXISDESTROY, zaxisdestroy, INT)
73607 FCALLSCFUN1 (INT, zaxisInqType, ZAXISINQTYPE, zaxisinqtype, INT)
73608 FCALLSCFUN1 (INT, zaxisInqSize, ZAXISINQSIZE, zaxisinqsize, INT)
73609 FCALLSCFUN1 (INT, zaxisDuplicate, ZAXISDUPLICATE, zaxisduplicate, INT)
73610 FCALLSCSUB2 (zaxisDefLevels, ZAXISDEFLEVELS, zaxisdeflevels, INT, DOUBLEV)
73611 FCALLSCFUN2 (INT, zaxisInqLevels, ZAXISINQLEVELS, zaxisinqlevels, INT, DOUBLEV)
73612 FCALLSCFUN1 (INT, zaxisInqCLen, ZAXISINQCLEN, zaxisinqclen, INT)
73613 FCALLSCSUB3 (zaxisDefLevel, ZAXISDEFLEVEL, zaxisdeflevel, INT, INT, DOUBLE)
73614 FCALLSCFUN2 (DOUBLE, zaxisInqLevel, ZAXISINQLEVEL, zaxisinqlevel, INT, INT)
73615 FCALLSCSUB2 (zaxisDefNlevRef, ZAXISDEFNLEVREF, zaxisdefnlevref, INT, INT)
73616 FCALLSCFUN1 (INT, zaxisInqNlevRef, ZAXISINQNLEVREF, zaxisinqnlevref, INT)
73617 FCALLSCSUB2 (zaxisDefNumber, ZAXISDEFNUMBER, zaxisdefnumber, INT, INT)
73618 FCALLSCFUN1 (INT, zaxisInqNumber, ZAXISINQNUMBER, zaxisinqnumber, INT)
73619 FCALLSCSUB2 (zaxisDefUUID, ZAXISDEFUUID, zaxisdefuuid, INT, PVOID)
73620 FCALLSCSUB2 (zaxisInqUUID, ZAXISINQUUID, zaxisinquuid, INT, PVOID)
73621 FCALLSCSUB2 (zaxisDefName, ZAXISDEFNAME, zaxisdefname, INT, STRING)
73622 FCALLSCSUB2 (zaxisInqName, ZAXISINQNAME, zaxisinqname, INT, PSTRING)
73623 FCALLSCSUB2 (zaxisDefLongname, ZAXISDEFLONGNAME, zaxisdeflongname, INT, STRING)
73624 FCALLSCSUB2 (zaxisInqLongname, ZAXISINQLONGNAME, zaxisinqlongname, INT, PSTRING)
73625 FCALLSCSUB2 (zaxisDefUnits, ZAXISDEFUNITS, zaxisdefunits, INT, STRING)
73626 FCALLSCSUB2 (zaxisInqUnits, ZAXISINQUNITS, zaxisinqunits, INT, PSTRING)
73627 FCALLSCSUB2 (zaxisInqStdname, ZAXISINQSTDNAME, zaxisinqstdname, INT, PSTRING)
73628 FCALLSCSUB2 (zaxisDefDatatype, ZAXISDEFDATATYPE, zaxisdefdatatype, INT, INT)
73629 FCALLSCFUN1 (INT, zaxisInqDatatype, ZAXISINQDATATYPE, zaxisinqdatatype, INT)
73630 FCALLSCSUB2 (zaxisDefPositive, ZAXISDEFPOSITIVE, zaxisdefpositive, INT, INT)
73631 FCALLSCFUN1 (INT, zaxisInqPositive, ZAXISINQPOSITIVE, zaxisinqpositive, INT)
73632 FCALLSCSUB1 (zaxisDefScalar, ZAXISDEFSCALAR, zaxisdefscalar, INT)
73633 FCALLSCFUN1 (INT, zaxisInqScalar, ZAXISINQSCALAR, zaxisinqscalar, INT)
73634 FCALLSCSUB3 (zaxisDefVct, ZAXISDEFVCT, zaxisdefvct, INT, INT, DOUBLEV)
73635 FCALLSCSUB2 (zaxisInqVct, ZAXISINQVCT, zaxisinqvct, INT, DOUBLEV)
73636 FCALLSCFUN1 (INT, zaxisInqVctSize, ZAXISINQVCTSIZE, zaxisinqvctsize, INT)
73637 FCALLSCSUB2 (zaxisDefLbounds, ZAXISDEFLBOUNDS, zaxisdeflbounds, INT, DOUBLEV)
73638 FCALLSCFUN2 (INT, zaxisInqLbounds, ZAXISINQLBOUNDS, zaxisinqlbounds, INT, DOUBLEV)
73639 FCALLSCFUN2 (DOUBLE, zaxisInqLbound, ZAXISINQLBOUND, zaxisinqlbound, INT, INT)
73640 FCALLSCSUB2 (zaxisDefUbounds, ZAXISDEFUBOUNDS, zaxisdefubounds, INT, DOUBLEV)
73641 FCALLSCFUN2 (INT, zaxisInqUbounds, ZAXISINQUBOUNDS, zaxisinqubounds, INT, DOUBLEV)
73642 FCALLSCFUN2 (DOUBLE, zaxisInqUbound, ZAXISINQUBOUND, zaxisinqubound, INT, INT)
73643 FCALLSCSUB2 (zaxisDefWeights, ZAXISDEFWEIGHTS, zaxisdefweights, INT, DOUBLEV)
73644 FCALLSCFUN2 (INT, zaxisInqWeights, ZAXISINQWEIGHTS, zaxisinqweights, INT, DOUBLEV)
73645 FCALLSCSUB2 (zaxisChangeType, ZAXISCHANGETYPE, zaxischangetype, INT, INT)
73646 
73647 /*  TAXIS routines  */
73648 
73649 FCALLSCFUN1 (INT, taxisCreate, TAXISCREATE, taxiscreate, INT)
73650 FCALLSCSUB1 (taxisDestroy, TAXISDESTROY, taxisdestroy, INT)
73651 FCALLSCFUN1 (INT, taxisDuplicate, TAXISDUPLICATE, taxisduplicate, INT)
73652 FCALLSCSUB2 (taxisCopyTimestep, TAXISCOPYTIMESTEP, taxiscopytimestep, INT, INT)
73653 FCALLSCSUB2 (taxisDefType, TAXISDEFTYPE, taxisdeftype, INT, INT)
73654 FCALLSCFUN1 (INT, taxisInqType, TAXISINQTYPE, taxisinqtype, INT)
73655 static void taxisDefVdate_fwrap(int taxisID, int date)
73656 {
73657   taxisDefVdate(taxisID, (int64_t)date);
73658 }
FCALLSCSUB2(taxisDefVdate_fwrap,TAXISDEFVDATE,taxisdefvdate,INT,INT)73659 FCALLSCSUB2 (taxisDefVdate_fwrap, TAXISDEFVDATE, taxisdefvdate, INT, INT)
73660 FCALLSCSUB2 (taxisDefVtime, TAXISDEFVTIME, taxisdefvtime, INT, INT)
73661 static int taxisInqVdate_fwrap(int taxisID)
73662 {
73663   int64_t v;
73664   v = taxisInqVdate(taxisID);
73665   return int64_t_c2f(v);
73666 }
FCALLSCFUN1(INT,taxisInqVdate_fwrap,TAXISINQVDATE,taxisinqvdate,INT)73667 FCALLSCFUN1 (INT, taxisInqVdate_fwrap, TAXISINQVDATE, taxisinqvdate, INT)
73668 FCALLSCFUN1 (INT, taxisInqVtime, TAXISINQVTIME, taxisinqvtime, INT)
73669 static void taxisDefRdate_fwrap(int taxisID, int date)
73670 {
73671   taxisDefRdate(taxisID, (int64_t)date);
73672 }
FCALLSCSUB2(taxisDefRdate_fwrap,TAXISDEFRDATE,taxisdefrdate,INT,INT)73673 FCALLSCSUB2 (taxisDefRdate_fwrap, TAXISDEFRDATE, taxisdefrdate, INT, INT)
73674 FCALLSCSUB2 (taxisDefRtime, TAXISDEFRTIME, taxisdefrtime, INT, INT)
73675 static int taxisInqRdate_fwrap(int taxisID)
73676 {
73677   int64_t v;
73678   v = taxisInqRdate(taxisID);
73679   return int64_t_c2f(v);
73680 }
FCALLSCFUN1(INT,taxisInqRdate_fwrap,TAXISINQRDATE,taxisinqrdate,INT)73681 FCALLSCFUN1 (INT, taxisInqRdate_fwrap, TAXISINQRDATE, taxisinqrdate, INT)
73682 FCALLSCFUN1 (INT, taxisInqRtime, TAXISINQRTIME, taxisinqrtime, INT)
73683 static void taxisDefFdate_fwrap(int taxisID, int date)
73684 {
73685   taxisDefFdate(taxisID, (int64_t)date);
73686 }
FCALLSCSUB2(taxisDefFdate_fwrap,TAXISDEFFDATE,taxisdeffdate,INT,INT)73687 FCALLSCSUB2 (taxisDefFdate_fwrap, TAXISDEFFDATE, taxisdeffdate, INT, INT)
73688 FCALLSCSUB2 (taxisDefFtime, TAXISDEFFTIME, taxisdefftime, INT, INT)
73689 static int taxisInqFdate_fwrap(int taxisID)
73690 {
73691   int64_t v;
73692   v = taxisInqFdate(taxisID);
73693   return int64_t_c2f(v);
73694 }
FCALLSCFUN1(INT,taxisInqFdate_fwrap,TAXISINQFDATE,taxisinqfdate,INT)73695 FCALLSCFUN1 (INT, taxisInqFdate_fwrap, TAXISINQFDATE, taxisinqfdate, INT)
73696 FCALLSCFUN1 (INT, taxisInqFtime, TAXISINQFTIME, taxisinqftime, INT)
73697 FCALLSCFUN1 (INT, taxisHasBounds, TAXISHASBOUNDS, taxishasbounds, INT)
73698 FCALLSCSUB1 (taxisWithBounds, TAXISWITHBOUNDS, taxiswithbounds, INT)
73699 FCALLSCSUB1 (taxisDeleteBounds, TAXISDELETEBOUNDS, taxisdeletebounds, INT)
73700 static void taxisDefVdateBounds_fwrap(int taxisID, int vdate_lb, int vdate_ub)
73701 {
73702   taxisDefVdateBounds(taxisID, (int64_t)vdate_lb, (int64_t)vdate_ub);
73703 }
FCALLSCSUB3(taxisDefVdateBounds_fwrap,TAXISDEFVDATEBOUNDS,taxisdefvdatebounds,INT,INT,INT)73704 FCALLSCSUB3 (taxisDefVdateBounds_fwrap, TAXISDEFVDATEBOUNDS, taxisdefvdatebounds, INT, INT, INT)
73705 FCALLSCSUB3 (taxisDefVtimeBounds, TAXISDEFVTIMEBOUNDS, taxisdefvtimebounds, INT, INT, INT)
73706 static void taxisInqVdateBounds_fwrap(int taxisID, int *vdate_lb, int *vdate_ub)
73707 {
73708   int64_t vdate_lb_int64_t;
73709   int64_t vdate_ub_int64_t;
73710   taxisInqVdateBounds(taxisID, &vdate_lb_int64_t, &vdate_ub_int64_t);
73711   assert(vdate_lb_int64_t < INT_MAX);
73712   *vdate_lb = vdate_lb_int64_t;
73713   assert(vdate_ub_int64_t < INT_MAX);
73714   *vdate_ub = vdate_ub_int64_t;
73715 }
73716 FCALLSCSUB3 (taxisInqVdateBounds_fwrap, TAXISINQVDATEBOUNDS, taxisinqvdatebounds, INT, PINT, PINT)
73717 FCALLSCSUB3 (taxisInqVtimeBounds, TAXISINQVTIMEBOUNDS, taxisinqvtimebounds, INT, PINT, PINT)
73718 FCALLSCSUB2 (taxisDefCalendar, TAXISDEFCALENDAR, taxisdefcalendar, INT, INT)
73719 FCALLSCFUN1 (INT, taxisInqCalendar, TAXISINQCALENDAR, taxisinqcalendar, INT)
73720 FCALLSCSUB2 (taxisDefTunit, TAXISDEFTUNIT, taxisdeftunit, INT, INT)
73721 FCALLSCFUN1 (INT, taxisInqTunit, TAXISINQTUNIT, taxisinqtunit, INT)
73722 FCALLSCSUB2 (taxisDefForecastTunit, TAXISDEFFORECASTTUNIT, taxisdefforecasttunit, INT, INT)
73723 FCALLSCFUN1 (INT, taxisInqForecastTunit, TAXISINQFORECASTTUNIT, taxisinqforecasttunit, INT)
73724 FCALLSCSUB2 (taxisDefForecastPeriod, TAXISDEFFORECASTPERIOD, taxisdefforecastperiod, INT, DOUBLE)
73725 FCALLSCFUN1 (DOUBLE, taxisInqForecastPeriod, TAXISINQFORECASTPERIOD, taxisinqforecastperiod, INT)
73726 FCALLSCSUB2 (taxisDefNumavg, TAXISDEFNUMAVG, taxisdefnumavg, INT, INT)
73727 FCALLSCFUN1 (INT, taxisInqNumavg, TAXISINQNUMAVG, taxisinqnumavg, INT)
73728 FCALLSCFUN1 (STRING, tunitNamePtr, TUNITNAMEPTR, tunitnameptr, INT)
73729 
73730 /*  Institut routines  */
73731 
73732 FCALLSCFUN4 (INT, institutDef, INSTITUTDEF, institutdef, INT, INT, STRING, STRING)
73733 FCALLSCFUN4 (INT, institutInq, INSTITUTINQ, institutinq, INT, INT, STRING, STRING)
73734 FCALLSCFUN0 (INT, institutInqNumber, INSTITUTINQNUMBER, institutinqnumber)
73735 FCALLSCFUN1 (INT, institutInqCenter, INSTITUTINQCENTER, institutinqcenter, INT)
73736 FCALLSCFUN1 (INT, institutInqSubcenter, INSTITUTINQSUBCENTER, institutinqsubcenter, INT)
73737 FCALLSCFUN1 (STRING, institutInqNamePtr, INSTITUTINQNAMEPTR, institutinqnameptr, INT)
73738 FCALLSCFUN1 (STRING, institutInqLongnamePtr, INSTITUTINQLONGNAMEPTR, institutinqlongnameptr, INT)
73739 
73740 /*  Model routines  */
73741 
73742 FCALLSCFUN3 (INT, modelDef, MODELDEF, modeldef, INT, INT, STRING)
73743 FCALLSCFUN3 (INT, modelInq, MODELINQ, modelinq, INT, INT, STRING)
73744 FCALLSCFUN1 (INT, modelInqInstitut, MODELINQINSTITUT, modelinqinstitut, INT)
73745 FCALLSCFUN1 (INT, modelInqGribID, MODELINQGRIBID, modelinqgribid, INT)
73746 FCALLSCFUN1 (STRING, modelInqNamePtr, MODELINQNAMEPTR, modelinqnameptr, INT)
73747 
73748 /*  Table routines  */
73749 
73750 FCALLSCSUB2 (tableWrite, TABLEWRITE, tablewrite, STRING, INT)
73751 FCALLSCFUN1 (INT, tableRead, TABLEREAD, tableread, STRING)
73752 FCALLSCFUN3 (INT, tableDef, TABLEDEF, tabledef, INT, INT, STRING)
73753 FCALLSCFUN1 (STRING, tableInqNamePtr, TABLEINQNAMEPTR, tableinqnameptr, INT)
73754 FCALLSCFUN3 (INT, tableInq, TABLEINQ, tableinq, INT, INT, STRING)
73755 FCALLSCFUN0 (INT, tableInqNumber, TABLEINQNUMBER, tableinqnumber)
73756 FCALLSCFUN1 (INT, tableInqNum, TABLEINQNUM, tableinqnum, INT)
73757 FCALLSCFUN1 (INT, tableInqModel, TABLEINQMODEL, tableinqmodel, INT)
73758 FCALLSCSUB6 (tableInqEntry, TABLEINQENTRY, tableinqentry, INT, INT, INT, PSTRING, PSTRING, PSTRING)
73759 
73760 /*  Subtype routines  */
73761 
73762 FCALLSCFUN1 (INT, subtypeCreate, SUBTYPECREATE, subtypecreate, INT)
73763 
73764 /*  Gives a textual summary of the variable subtype  */
73765 
73766 FCALLSCSUB1 (subtypePrint, SUBTYPEPRINT, subtypeprint, INT)
73767 
73768 /*  Compares two subtype data structures  */
73769 
73770 FCALLSCFUN2 (INT, subtypeCompare, SUBTYPECOMPARE, subtypecompare, INT, INT)
73771 FCALLSCFUN1 (INT, subtypeInqSize, SUBTYPEINQSIZE, subtypeinqsize, INT)
73772 FCALLSCFUN1 (INT, subtypeInqActiveIndex, SUBTYPEINQACTIVEINDEX, subtypeinqactiveindex, INT)
73773 FCALLSCSUB2 (subtypeDefActiveIndex, SUBTYPEDEFACTIVEINDEX, subtypedefactiveindex, INT, INT)
73774 
73775 /*  Generate a "query object" out of a key-value pair  */
73776 
73777 
73778 /*  Generate an AND-combined "query object" out of two previous query objects  */
73779 
73780 FCALLSCFUN3 (INT, subtypeInqTile, SUBTYPEINQTILE, subtypeinqtile, INT, INT, INT)
73781 FCALLSCFUN4 (INT, subtypeInqAttribute, SUBTYPEINQATTRIBUTE, subtypeinqattribute, INT, INT, STRING, PINT)
73782 FCALLSCFUN2 (INT, vlistInqVarSubtype, VLISTINQVARSUBTYPE, vlistinqvarsubtype, INT, INT)
73783 FCALLSCSUB3 (gribapiLibraryVersion, GRIBAPILIBRARYVERSION, gribapilibraryversion, PINT, PINT, PINT)
73784 
73785 #if defined __clang__
73786 #  pragma GCC diagnostic pop
73787 #endif
73788 #endif
73789