1 /*
2  * (C) Copyright 2005- ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  *
7  * In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
8  * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
9  */
10 
11 #include "grib_api_internal.h"
12 #include <errno.h>
13 #include <stdarg.h>
14 #include <stdlib.h>
15 #ifndef ECCODES_ON_WINDOWS
16 #include <unistd.h>
17 #else
18 #include <fcntl.h> /* Windows: for _O_BINARY */
19 #endif
20 
21 #ifdef ENABLE_FLOATING_POINT_EXCEPTIONS
22 #define _GNU_SOURCE
23 #include <fenv.h>
24 int feenableexcept(int excepts);
25 #endif
26 
27 grib_string_list grib_file_not_found;
28 
29 /* Windows always has a colon in pathnames e.g. C:\temp\file. So instead we use semi-colons as delimiter */
30 /* in order to have multiple definitions/samples directories */
31 #ifdef ECCODES_ON_WINDOWS
32 #define ECC_PATH_DELIMITER_CHAR ';'
33 #define ECC_PATH_DELIMITER_STR ";"
34 #else
35 #define ECC_PATH_DELIMITER_CHAR ':'
36 #define ECC_PATH_DELIMITER_STR ":"
37 #endif
38 
39 #if GRIB_PTHREADS
40 static pthread_once_t once = PTHREAD_ONCE_INIT;
41 
42 static pthread_mutex_t mutex_mem = PTHREAD_MUTEX_INITIALIZER;
43 static pthread_mutex_t mutex_c   = PTHREAD_MUTEX_INITIALIZER;
44 
init()45 static void init()
46 {
47     pthread_mutexattr_t attr;
48     pthread_mutexattr_init(&attr);
49     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
50     pthread_mutex_init(&mutex_c, &attr);
51     pthread_mutex_init(&mutex_mem, &attr);
52     pthread_mutexattr_destroy(&attr);
53 }
54 #elif GRIB_OMP_THREADS
55 static int once = 0;
56 static omp_nest_lock_t mutex_mem;
57 static omp_nest_lock_t mutex_c;
58 
init()59 static void init()
60 {
61     GRIB_OMP_CRITICAL(lock_grib_context_c)
62     {
63         if (once == 0) {
64             omp_init_nest_lock(&mutex_mem);
65             omp_init_nest_lock(&mutex_c);
66             once = 1;
67         }
68     }
69 }
70 #endif
71 
72 
73 #if MANAGE_MEM
74 
75 #else
76 
default_long_lasting_free(const grib_context * c,void * p)77 static void default_long_lasting_free(const grib_context* c, void* p)
78 {
79     free(p);
80 }
81 
default_long_lasting_malloc(const grib_context * c,size_t size)82 static void* default_long_lasting_malloc(const grib_context* c, size_t size)
83 {
84     void* ret;
85     ret = malloc(size);
86     if (!ret) {
87         grib_context_log(c, GRIB_LOG_FATAL, "default_long_lasting_malloc: error allocating %lu bytes", (unsigned long)size);
88         Assert(0);
89     }
90     return ret;
91 }
92 
default_buffer_free(const grib_context * c,void * p)93 static void default_buffer_free(const grib_context* c, void* p)
94 {
95     free(p);
96 }
97 
default_buffer_malloc(const grib_context * c,size_t size)98 static void* default_buffer_malloc(const grib_context* c, size_t size)
99 {
100     void* ret;
101     ret = malloc(size);
102     if (!ret) {
103         grib_context_log(c, GRIB_LOG_FATAL, "default_buffer_malloc: error allocating %lu bytes", (unsigned long)size);
104         Assert(0);
105     }
106     return ret;
107 }
108 
default_buffer_realloc(const grib_context * c,void * p,size_t size)109 static void* default_buffer_realloc(const grib_context* c, void* p, size_t size)
110 {
111     void* ret;
112     ret = realloc(p, size);
113     if (!ret) {
114         grib_context_log(c, GRIB_LOG_FATAL, "default_buffer_realloc: error allocating %lu bytes", (unsigned long)size);
115         Assert(0);
116     }
117     return ret;
118 }
119 
default_free(const grib_context * c,void * p)120 static void default_free(const grib_context* c, void* p)
121 {
122     free(p);
123 }
124 
default_malloc(const grib_context * c,size_t size)125 static void* default_malloc(const grib_context* c, size_t size)
126 {
127     void* ret;
128     ret = malloc(size);
129     if (!ret) {
130         grib_context_log(c, GRIB_LOG_FATAL, "default_malloc: error allocating %lu bytes", (unsigned long)size);
131         Assert(0);
132     }
133     return ret;
134 }
135 
default_realloc(const grib_context * c,void * p,size_t size)136 static void* default_realloc(const grib_context* c, void* p, size_t size)
137 {
138     void* ret;
139     ret = realloc(p, size);
140     if (!ret) {
141         grib_context_log(c, GRIB_LOG_FATAL, "default_realloc: error allocating %lu bytes", (unsigned long)size);
142         Assert(0);
143     }
144     return ret;
145 }
146 #endif
147 
default_read(const grib_context * c,void * ptr,size_t size,void * stream)148 static size_t default_read(const grib_context* c, void* ptr, size_t size, void* stream)
149 {
150     return fread(ptr, 1, size, (FILE*)stream);
151 }
152 
default_tell(const grib_context * c,void * stream)153 static off_t default_tell(const grib_context* c, void* stream)
154 {
155     return ftello((FILE*)stream);
156 }
157 
default_seek(const grib_context * c,off_t offset,int whence,void * stream)158 static off_t default_seek(const grib_context* c, off_t offset, int whence, void* stream)
159 {
160     return fseeko((FILE*)stream, offset, whence);
161 }
162 
default_feof(const grib_context * c,void * stream)163 static int default_feof(const grib_context* c, void* stream)
164 {
165     return feof((FILE*)stream);
166 }
167 
default_write(const grib_context * c,const void * ptr,size_t size,void * stream)168 static size_t default_write(const grib_context* c, const void* ptr, size_t size, void* stream)
169 {
170     return fwrite(ptr, 1, size, (FILE*)stream);
171 }
172 
grib_context_read(const grib_context * c,void * ptr,size_t size,void * stream)173 size_t grib_context_read(const grib_context* c, void* ptr, size_t size, void* stream)
174 {
175     if (!c)
176         c = grib_context_get_default();
177     return c->read(c, ptr, size, stream);
178 }
179 
grib_context_tell(const grib_context * c,void * stream)180 off_t grib_context_tell(const grib_context* c, void* stream)
181 {
182     if (!c)
183         c = grib_context_get_default();
184     return c->tell(c, stream);
185 }
186 
grib_context_seek(const grib_context * c,off_t offset,int whence,void * stream)187 int grib_context_seek(const grib_context* c, off_t offset, int whence, void* stream)
188 {
189     if (!c)
190         c = grib_context_get_default();
191     return c->seek(c, offset, whence, stream);
192 }
193 
grib_context_eof(const grib_context * c,void * stream)194 int grib_context_eof(const grib_context* c, void* stream)
195 {
196     if (!c)
197         c = grib_context_get_default();
198     return c->eof(c, stream);
199 }
200 
grib_context_write(const grib_context * c,const void * ptr,size_t size,void * stream)201 size_t grib_context_write(const grib_context* c, const void* ptr, size_t size, void* stream)
202 {
203     if (!c)
204         c = grib_context_get_default();
205     return c->write(c, ptr, size, stream);
206 }
207 
default_log(const grib_context * c,int level,const char * mess)208 static void default_log(const grib_context* c, int level, const char* mess)
209 {
210     if (!c)
211         c = grib_context_get_default();
212     if (level == GRIB_LOG_ERROR) {
213         fprintf(c->log_stream, "ECCODES ERROR   :  %s\n", mess);
214         /*Assert(1==0);*/
215     }
216     if (level == GRIB_LOG_FATAL)
217         fprintf(c->log_stream, "ECCODES ERROR   :  %s\n", mess);
218     if (level == GRIB_LOG_DEBUG && c->debug > 0)
219         fprintf(c->log_stream, "ECCODES DEBUG   :  %s\n", mess);
220     if (level == GRIB_LOG_WARNING)
221         fprintf(c->log_stream, "ECCODES WARNING :  %s\n", mess);
222     if (level == GRIB_LOG_INFO)
223         fprintf(c->log_stream, "ECCODES INFO    :  %s\n", mess);
224 
225     if (level == GRIB_LOG_FATAL) {
226         Assert(0);
227     }
228 
229     if (getenv("ECCODES_FAIL_IF_LOG_MESSAGE")) {
230         long n = atol(getenv("ECCODES_FAIL_IF_LOG_MESSAGE"));
231         if (n >= 1 && level == GRIB_LOG_ERROR)
232             Assert(0);
233         if (n >= 2 && level == GRIB_LOG_WARNING)
234             Assert(0);
235     }
236 }
237 
default_print(const grib_context * c,void * descriptor,const char * mess)238 static void default_print(const grib_context* c, void* descriptor, const char* mess)
239 {
240     fprintf((FILE*)descriptor, "%s", mess);
241 }
242 
grib_context_set_print_proc(grib_context * c,grib_print_proc p)243 void grib_context_set_print_proc(grib_context* c, grib_print_proc p)
244 {
245     c        = c ? c : grib_context_get_default();
246     c->print = p;
247 }
248 
grib_context_set_debug(grib_context * c,int mode)249 void grib_context_set_debug(grib_context* c, int mode)
250 {
251     c        = c ? c : grib_context_get_default();
252     c->debug = mode;
253 }
254 
grib_context_set_logging_proc(grib_context * c,grib_log_proc p)255 void grib_context_set_logging_proc(grib_context* c, grib_log_proc p)
256 {
257     c             = c ? c : grib_context_get_default();
258     c->output_log = p;
259 }
260 
grib_get_api_version()261 long grib_get_api_version()
262 {
263     return ECCODES_VERSION;
264 }
265 
grib_print_api_version(FILE * out)266 void grib_print_api_version(FILE* out)
267 {
268     fprintf(out, "%d.%d.%d",
269             ECCODES_MAJOR_VERSION,
270             ECCODES_MINOR_VERSION,
271             ECCODES_REVISION_VERSION);
272 
273     if (ECCODES_MAJOR_VERSION < 1) {
274         fprintf(out, "%s", " PRE-RELEASE");
275     }
276 }
277 
grib_get_package_name()278 const char* grib_get_package_name()
279 {
280     return "ecCodes";
281 }
282 
283 #define DEFAULT_FILE_POOL_MAX_OPENED_FILES 0
284 
285 static grib_context default_grib_context = {
286     0,               /* inited                     */
287     0,               /* debug                      */
288     0,               /* write_on_fail              */
289     0,               /* no_abort                   */
290     0,               /* io_buffer_size             */
291     0,               /* no_big_group_split         */
292     0,               /* no_spd                     */
293     0,               /* keep_matrix                */
294     0,               /* grib_definition_files_path */
295     0,               /* grib_samples_path          */
296     0,               /* grib_concept_path          */
297     0,               /* grib_reader                */
298     0,               /* user data                  */
299     GRIB_REAL_MODE8, /* real mode for fortran      */
300 
301 #if MANAGE_MEM
302     &grib_transient_free,    /* free_mem                   */
303     &grib_transient_malloc,  /* alloc_mem                  */
304     &grib_transient_realloc, /* realloc_mem                */
305 
306     &grib_permanent_free,   /* free_persistant_mem        */
307     &grib_permanent_malloc, /* alloc_persistant_mem       */
308 
309     &grib_buffer_free,    /* buffer_free_mem            */
310     &grib_buffer_malloc,  /* buffer_alloc_mem           */
311     &grib_buffer_realloc, /* buffer_realloc_mem         */
312 
313 #else
314 
315     &default_free,    /* free_mem                  */
316     &default_malloc,  /* alloc_mem                 */
317     &default_realloc, /* realloc_mem               */
318 
319     &default_long_lasting_free,   /* free_persistant_mem       */
320     &default_long_lasting_malloc, /* alloc_persistant_mem      */
321 
322     &default_buffer_free,    /* free_buffer_mem           */
323     &default_buffer_malloc,  /* alloc_buffer_mem          */
324     &default_buffer_realloc, /* realloc_buffer_mem        */
325 #endif
326 
327     &default_read,  /* file read procedure        */
328     &default_write, /* file write procedure       */
329     &default_tell,  /* lfile tell procedure       */
330     &default_seek,  /* lfile seek procedure       */
331     &default_feof,  /* file feof procedure        */
332 
333     &default_log,   /* output_log                 */
334     &default_print, /* print                      */
335     0,              /* codetable                  */
336     0,              /* smart_table                */
337     0,              /* outfilename                */
338     0,              /* multi_support_on           */
339     0,              /* multi_support              */
340     0,              /* grib_definition_files_dir  */
341     0,              /* handle_file_count          */
342     0,              /* handle_total_count         */
343     0,              /* message_file_offset        */
344     0,              /* no_fail_on_wrong_length    */
345     0,              /* gts_header_on              */
346     0,              /* gribex_mode_on             */
347     0,              /* large_constant_fields      */
348     0,              /* keys                       */
349     0,              /* keys_count                 */
350     0,              /* concepts_index             */
351     0,              /* concepts_count             */
352     {0,}, /* concepts                   */
353     0, /* hash_array_index           */
354     0, /* hash_array_count           */
355     {0,},                                 /* hash_array                 */
356     0,                                 /* def_files                  */
357     0,                                 /* blocklist                  */
358     0,                                 /* ieee_packing               */
359     0,                                 /* bufrdc_mode                */
360     0,                                 /* bufr_set_to_missing_if_out_of_range */
361     0,                                 /* bufr_multi_element_constant_arrays */
362     0,                                 /* grib_data_quality_checks   */
363     0,                                 /* log_stream                 */
364     0,                                 /* classes                    */
365     0,                                 /* lists                      */
366     0,                                 /* expanded_descriptors       */
367     DEFAULT_FILE_POOL_MAX_OPENED_FILES /* file_pool_max_opened_files */
368 #if GRIB_PTHREADS
369     ,
370     PTHREAD_MUTEX_INITIALIZER /* mutex                      */
371 #endif
372 };
373 
374 /* Hopefully big enough. Note: Definitions and samples path environment variables can contain SEVERAL colon-separated directories */
375 #define ECC_PATH_MAXLEN 8192
376 
grib_context_get_default()377 grib_context* grib_context_get_default()
378 {
379     GRIB_MUTEX_INIT_ONCE(&once, &init);
380     GRIB_MUTEX_LOCK(&mutex_c);
381 
382     if (!default_grib_context.inited) {
383         const char* write_on_fail                       = NULL;
384         const char* large_constant_fields               = NULL;
385         const char* no_abort                            = NULL;
386         const char* debug                               = NULL;
387         const char* gribex                              = NULL;
388         const char* ieee_packing                        = NULL;
389         const char* io_buffer_size                      = NULL;
390         const char* log_stream                          = NULL;
391         const char* no_big_group_split                  = NULL;
392         const char* no_spd                              = NULL;
393         const char* keep_matrix                         = NULL;
394         const char* bufrdc_mode                         = NULL;
395         const char* bufr_set_to_missing_if_out_of_range = NULL;
396         const char* bufr_multi_element_constant_arrays  = NULL;
397         const char* grib_data_quality_checks            = NULL;
398         const char* file_pool_max_opened_files          = NULL;
399 
400 #ifdef ENABLE_FLOATING_POINT_EXCEPTIONS
401         feenableexcept(FE_ALL_EXCEPT & ~FE_INEXACT);
402 #endif
403 
404         write_on_fail                       = codes_getenv("ECCODES_GRIB_WRITE_ON_FAIL");
405         bufrdc_mode                         = getenv("ECCODES_BUFRDC_MODE_ON");
406         bufr_set_to_missing_if_out_of_range = getenv("ECCODES_BUFR_SET_TO_MISSING_IF_OUT_OF_RANGE");
407         bufr_multi_element_constant_arrays  = getenv("ECCODES_BUFR_MULTI_ELEMENT_CONSTANT_ARRAYS");
408         grib_data_quality_checks            = getenv("ECCODES_GRIB_DATA_QUALITY_CHECKS");
409         large_constant_fields               = codes_getenv("ECCODES_GRIB_LARGE_CONSTANT_FIELDS");
410         no_abort                            = codes_getenv("ECCODES_NO_ABORT");
411         debug                               = codes_getenv("ECCODES_DEBUG");
412         gribex                              = codes_getenv("ECCODES_GRIBEX_MODE_ON");
413         ieee_packing                        = codes_getenv("ECCODES_GRIB_IEEE_PACKING");
414         io_buffer_size                      = codes_getenv("ECCODES_IO_BUFFER_SIZE");
415         log_stream                          = codes_getenv("ECCODES_LOG_STREAM");
416         no_big_group_split                  = codes_getenv("ECCODES_GRIB_NO_BIG_GROUP_SPLIT");
417         no_spd                              = codes_getenv("ECCODES_GRIB_NO_SPD");
418         keep_matrix                         = codes_getenv("ECCODES_GRIB_KEEP_MATRIX");
419         file_pool_max_opened_files          = getenv("ECCODES_FILE_POOL_MAX_OPENED_FILES");
420 
421         /* On UNIX, when we read from a file we get exactly what is in the file on disk.
422          * But on Windows a file can be opened in binary or text mode. In binary mode the system behaves exactly as in UNIX.
423          */
424 #ifdef ECCODES_ON_WINDOWS
425         _set_fmode(_O_BINARY);
426 #endif
427 
428         default_grib_context.inited = 1;
429         default_grib_context.io_buffer_size = io_buffer_size ? atoi(io_buffer_size) : 0;
430         default_grib_context.no_big_group_split = no_big_group_split ? atoi(no_big_group_split) : 0;
431         default_grib_context.no_spd = no_spd ? atoi(no_spd) : 0;
432         default_grib_context.keep_matrix = keep_matrix ? atoi(keep_matrix) : 1;
433         default_grib_context.write_on_fail = write_on_fail ? atoi(write_on_fail) : 0;
434         default_grib_context.no_abort = no_abort ? atoi(no_abort) : 0;
435         default_grib_context.debug = debug ? atoi(debug) : 0;
436         default_grib_context.gribex_mode_on = gribex ? atoi(gribex) : 0;
437         default_grib_context.large_constant_fields = large_constant_fields ? atoi(large_constant_fields) : 0;
438         default_grib_context.ieee_packing = ieee_packing ? atoi(ieee_packing) : 0;
439         default_grib_context.grib_samples_path = codes_getenv("ECCODES_SAMPLES_PATH");
440         default_grib_context.log_stream = stderr;
441         if (!log_stream) {
442             default_grib_context.log_stream = stderr;
443         }
444         else if (!strcmp(log_stream, "stderr")) {
445             default_grib_context.log_stream = stderr;
446         }
447         else if (!strcmp(log_stream, "stdout")) {
448             default_grib_context.log_stream = stdout;
449         }
450 
451 #ifdef ECCODES_SAMPLES_PATH
452         if (!default_grib_context.grib_samples_path)
453             default_grib_context.grib_samples_path = ECCODES_SAMPLES_PATH;
454 #endif
455 
456         default_grib_context.grib_definition_files_path = codes_getenv("ECCODES_DEFINITION_PATH");
457 #ifdef ECCODES_DEFINITION_PATH
458         if (!default_grib_context.grib_definition_files_path) {
459             default_grib_context.grib_definition_files_path = strdup(ECCODES_DEFINITION_PATH);
460         }
461         else {
462             default_grib_context.grib_definition_files_path = strdup(default_grib_context.grib_definition_files_path);
463         }
464 #endif
465 
466         /* GRIB-779: Special case for ECMWF testing. Not for external use! */
467         /* Append the new path to our existing path */
468         {
469             const char* test_defs = codes_getenv("_ECCODES_ECMWF_TEST_DEFINITION_PATH");
470             const char* test_samp = codes_getenv("_ECCODES_ECMWF_TEST_SAMPLES_PATH");
471             if (test_defs) {
472                 char buffer[ECC_PATH_MAXLEN]= {0,};
473                 if (default_grib_context.grib_definition_files_path) {
474                     strcpy(buffer, default_grib_context.grib_definition_files_path);
475                     strcat(buffer, ":");
476                 }
477                 strcat(buffer, test_defs);
478                 free(default_grib_context.grib_definition_files_path);
479                 default_grib_context.grib_definition_files_path = strdup(buffer);
480             }
481             if (test_samp) {
482                 char buffer[ECC_PATH_MAXLEN]= {0,};
483                 if (default_grib_context.grib_samples_path) {
484                     strcpy(buffer, default_grib_context.grib_samples_path);
485                     strcat(buffer, ":");
486                 }
487                 strcat(buffer, test_samp);
488                 default_grib_context.grib_samples_path = strdup(buffer);
489             }
490         }
491 
492         /* Definitions path extra: Added at the head of (i.e. before) existing path */
493         {
494             const char* defs_extra = getenv("ECCODES_EXTRA_DEFINITION_PATH");
495             if (defs_extra) {
496                 char buffer[ECC_PATH_MAXLEN]= {0,};
497                 ecc_snprintf(buffer, ECC_PATH_MAXLEN, "%s%c%s", defs_extra, ECC_PATH_DELIMITER_CHAR, default_grib_context.grib_definition_files_path);
498                 free(default_grib_context.grib_definition_files_path);
499                 default_grib_context.grib_definition_files_path = strdup(buffer);
500             }
501         }
502 #ifdef ECCODES_DEFINITION_PATH
503         {
504             /* ECC-1088 */
505             if (strstr(default_grib_context.grib_definition_files_path, ECCODES_DEFINITION_PATH) == NULL) {
506                 char buffer[ECC_PATH_MAXLEN]= {0,};
507                 ecc_snprintf(buffer, ECC_PATH_MAXLEN, "%s%c%s", default_grib_context.grib_definition_files_path,
508                              ECC_PATH_DELIMITER_CHAR, ECCODES_DEFINITION_PATH);
509                 free(default_grib_context.grib_definition_files_path);
510                 default_grib_context.grib_definition_files_path = strdup(buffer);
511             }
512         }
513 #endif
514 
515         /* Samples path extra: Added at the head of (i.e. before) existing path */
516         {
517             const char* samples_extra = getenv("ECCODES_EXTRA_SAMPLES_PATH");
518             if (samples_extra) {
519                 char buffer[ECC_PATH_MAXLEN];
520                 ecc_snprintf(buffer, ECC_PATH_MAXLEN, "%s%c%s", samples_extra, ECC_PATH_DELIMITER_CHAR, default_grib_context.grib_samples_path);
521                 default_grib_context.grib_samples_path = strdup(buffer);
522             }
523         }
524 #ifdef ECCODES_SAMPLES_PATH
525         {
526             if (strstr(default_grib_context.grib_samples_path, ECCODES_SAMPLES_PATH) == NULL) {
527                 char buffer[ECC_PATH_MAXLEN];
528                 ecc_snprintf(buffer, ECC_PATH_MAXLEN, "%s%c%s", default_grib_context.grib_samples_path,
529                              ECC_PATH_DELIMITER_CHAR, ECCODES_SAMPLES_PATH);
530                 default_grib_context.grib_samples_path = strdup(buffer);
531             }
532         }
533 #endif
534 
535         grib_context_log(&default_grib_context, GRIB_LOG_DEBUG, "Definitions path: %s",
536                          default_grib_context.grib_definition_files_path);
537         grib_context_log(&default_grib_context, GRIB_LOG_DEBUG, "Samples path:     %s",
538                          default_grib_context.grib_samples_path);
539 
540         default_grib_context.keys_count = 0;
541         default_grib_context.keys       = grib_hash_keys_new(&(default_grib_context), &(default_grib_context.keys_count));
542 
543         default_grib_context.concepts_index = grib_itrie_new(&(default_grib_context), &(default_grib_context.concepts_count));
544         default_grib_context.hash_array_index = grib_itrie_new(&(default_grib_context), &(default_grib_context.hash_array_count));
545         default_grib_context.def_files = grib_trie_new(&(default_grib_context));
546         default_grib_context.lists = grib_trie_new(&(default_grib_context));
547         default_grib_context.classes = grib_trie_new(&(default_grib_context));
548         default_grib_context.bufrdc_mode = bufrdc_mode ? atoi(bufrdc_mode) : 0;
549         default_grib_context.bufr_set_to_missing_if_out_of_range = bufr_set_to_missing_if_out_of_range ? atoi(bufr_set_to_missing_if_out_of_range) : 0;
550         default_grib_context.bufr_multi_element_constant_arrays = bufr_multi_element_constant_arrays ? atoi(bufr_multi_element_constant_arrays) : 0;
551         default_grib_context.grib_data_quality_checks = grib_data_quality_checks ? atoi(grib_data_quality_checks) : 0;
552         default_grib_context.file_pool_max_opened_files = file_pool_max_opened_files ? atoi(file_pool_max_opened_files) : DEFAULT_FILE_POOL_MAX_OPENED_FILES;
553     }
554 
555     GRIB_MUTEX_UNLOCK(&mutex_c);
556     return &default_grib_context;
557 }
558 
559 #if 0 /* function removed */
560 grib_context* grib_context_new(grib_context* parent)
561 {
562     grib_context* c;
563 #if GRIB_PTHREADS
564     pthread_mutexattr_t attr;
565 #endif
566 
567     if (!parent) parent=grib_context_get_default();
568 
569     GRIB_MUTEX_INIT_ONCE(&once,&init);
570     GRIB_MUTEX_LOCK(&(parent->mutex));
571 
572     c = (grib_context*)grib_context_malloc_clear_persistent(&default_grib_context,sizeof(grib_context));
573 
574     c->inited              = default_grib_context.inited;
575     c->debug               = default_grib_context.debug;
576 
577     c->real_mode           = default_grib_context.real_mode;
578 
579     c->free_mem            = default_grib_context.free_mem;
580     c->alloc_mem           = default_grib_context.alloc_mem;
581 
582     c->free_persistent_mem = default_grib_context.free_persistent_mem;
583     c->alloc_persistent_mem= default_grib_context.alloc_persistent_mem;
584 
585     c->read                = default_grib_context.read;
586     c->write               = default_grib_context.write;
587     c->tell                = default_grib_context.tell;
588 
589     c->output_log          = default_grib_context.output_log;
590     c->print               = default_grib_context.print    ;
591     c->user_data           = default_grib_context.user_data;
592     c->def_files           = default_grib_context.def_files;
593     c->lists               = default_grib_context.lists;
594 
595 #if GRIB_PTHREADS
596     pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
597     pthread_mutex_init(&mutex_c,&attr);
598     pthread_mutexattr_destroy(&attr);
599 #endif
600 
601     GRIB_MUTEX_UNLOCK(&(parent->mutex));
602     return c;
603 }
604 #endif /* function removed */
605 
606 /* GRIB-235: Resolve path to expand symbolic links etc */
607 /* Note: return value is allocated. Client has to free */
codes_resolve_path(grib_context * c,const char * path)608 char* codes_resolve_path(grib_context* c, const char* path)
609 {
610     char* result = NULL;
611 #if defined(ECCODES_HAVE_REALPATH)
612     char resolved[ECC_PATH_MAXLEN + 1];
613     if (!realpath(path, resolved)) {
614         result = grib_context_strdup(c, path); /* Failed to resolve. Use original path */
615     }
616     else {
617         result = grib_context_strdup(c, resolved);
618     }
619 #else
620     result = grib_context_strdup(c, path);
621 #endif
622 
623     return result;
624 }
625 
init_definition_files_dir(grib_context * c)626 static int init_definition_files_dir(grib_context* c)
627 {
628     int err = 0;
629     char path[ECC_PATH_MAXLEN];
630     char* p                = NULL;
631     grib_string_list* next = NULL;
632 
633     if (!c)
634         c = grib_context_get_default();
635 
636     if (c->grib_definition_files_dir)
637         return 0;
638     if (!c->grib_definition_files_path)
639         return GRIB_NO_DEFINITIONS;
640 
641     /* Note: strtok modifies its first argument so we copy */
642     strncpy(path, c->grib_definition_files_path, ECC_PATH_MAXLEN-1);
643 
644     GRIB_MUTEX_INIT_ONCE(&once, &init);
645     GRIB_MUTEX_LOCK(&mutex_c);
646 
647     p = path;
648 
649     while (*p != ECC_PATH_DELIMITER_CHAR && *p != '\0')
650         p++;
651 
652     if (*p != ECC_PATH_DELIMITER_CHAR) {
653         /* No delimiter found so this is a single directory */
654         c->grib_definition_files_dir        = (grib_string_list*)grib_context_malloc_clear_persistent(c, sizeof(grib_string_list));
655         c->grib_definition_files_dir->value = codes_resolve_path(c, path);
656     }
657     else {
658         /* Definitions path contains multiple directories */
659         char* dir = NULL;
660         dir       = strtok(path, ECC_PATH_DELIMITER_STR);
661 
662         while (dir != NULL) {
663             if (next) {
664                 next->next = (grib_string_list*)grib_context_malloc_clear_persistent(c, sizeof(grib_string_list));
665                 next       = next->next;
666             }
667             else {
668                 c->grib_definition_files_dir = (grib_string_list*)grib_context_malloc_clear_persistent(c, sizeof(grib_string_list));
669                 next                         = c->grib_definition_files_dir;
670             }
671             next->value = codes_resolve_path(c, dir);
672             dir         = strtok(NULL, ECC_PATH_DELIMITER_STR);
673         }
674     }
675 
676     GRIB_MUTEX_UNLOCK(&mutex_c);
677 
678     return err;
679 }
680 
grib_context_full_defs_path(grib_context * c,const char * basename)681 char* grib_context_full_defs_path(grib_context* c, const char* basename)
682 {
683     int err         = 0;
684     char full[1024] = {0,};
685     grib_string_list* dir      = NULL;
686     grib_string_list* fullpath = 0;
687     if (!c)
688         c = grib_context_get_default();
689 
690     GRIB_MUTEX_INIT_ONCE(&once, &init);
691 
692     if (*basename == '/' || *basename == '.') {
693         return (char*)basename;
694     }
695     else {
696         GRIB_MUTEX_LOCK(&mutex_c); /* See ECC-604 */
697         fullpath = (grib_string_list*)grib_trie_get(c->def_files, basename);
698         GRIB_MUTEX_UNLOCK(&mutex_c);
699         if (fullpath != NULL) {
700             return fullpath->value;
701         }
702         if (!c->grib_definition_files_dir) {
703             err = init_definition_files_dir(c);
704         }
705 
706         if (err != GRIB_SUCCESS) {
707             grib_context_log(c, GRIB_LOG_ERROR,
708                              "Unable to find definition files directory");
709             return NULL;
710         }
711 
712         dir = c->grib_definition_files_dir;
713 
714         while (dir) {
715             sprintf(full, "%s/%s", dir->value, basename);
716             if (!codes_access(full, F_OK)) {
717                 fullpath = (grib_string_list*)grib_context_malloc_clear_persistent(c, sizeof(grib_string_list));
718                 Assert(fullpath);
719                 fullpath->value = grib_context_strdup(c, full);
720                 GRIB_MUTEX_LOCK(&mutex_c);
721                 grib_trie_insert(c->def_files, basename, fullpath);
722                 grib_context_log(c, GRIB_LOG_DEBUG, "Found def file %s", full);
723                 GRIB_MUTEX_UNLOCK(&mutex_c);
724                 return fullpath->value;
725             }
726             dir = dir->next;
727         }
728     }
729 
730     GRIB_MUTEX_LOCK(&mutex_c);
731     /* Store missing files so we don't check for them again and again */
732     grib_trie_insert(c->def_files, basename, &grib_file_not_found);
733     /*grib_context_log(c,GRIB_LOG_ERROR,"Def file \"%s\" not found",basename);*/
734     GRIB_MUTEX_UNLOCK(&mutex_c);
735     full[0] = 0;
736     return NULL;
737 }
738 
grib_samples_path(const grib_context * c)739 char* grib_samples_path(const grib_context* c)
740 {
741     if (!c)
742         c = grib_context_get_default();
743     return c->grib_samples_path;
744 }
grib_definition_path(const grib_context * c)745 char* grib_definition_path(const grib_context* c)
746 {
747     if (!c)
748         c = grib_context_get_default();
749     return c->grib_definition_files_path;
750 }
751 
grib_context_free(const grib_context * c,void * p)752 void grib_context_free(const grib_context* c, void* p)
753 {
754     if (!c)
755         c = grib_context_get_default();
756     if (p)
757         c->free_mem(c, p);
758 }
759 
grib_context_free_persistent(const grib_context * c,void * p)760 void grib_context_free_persistent(const grib_context* c, void* p)
761 {
762     if (!c)
763         c = grib_context_get_default();
764     if (p)
765         c->free_persistent_mem(c, p);
766 }
767 
grib_context_reset(grib_context * c)768 void grib_context_reset(grib_context* c)
769 {
770     size_t i = 0;
771     if (!c)
772         c = grib_context_get_default();
773 
774     if (c->grib_reader) {
775         grib_action_file* fr = c->grib_reader->first;
776         grib_action_file* fn = fr;
777         grib_action* a;
778 
779         while (fn) {
780             fr = fn;
781             fn = fn->next;
782 
783             a = fr->root;
784             while (a) {
785                 grib_action* na = a->next;
786                 grib_action_delete(c, a);
787                 a = na;
788             }
789             grib_context_free_persistent(c, fr->filename);
790             grib_context_free_persistent(c, fr);
791         }
792         grib_context_free_persistent(c, c->grib_reader);
793     }
794 
795     c->grib_reader = NULL;
796 
797     if (c->codetable)
798         grib_codetable_delete(c);
799     c->codetable = NULL;
800 
801     if (c->smart_table)
802         grib_smart_table_delete(c);
803     c->smart_table = NULL;
804 
805     if (c->grib_definition_files_dir) {
806         grib_string_list* next = c->grib_definition_files_dir;
807         grib_string_list* cur  = NULL;
808         while (next) {
809             cur  = next;
810             next = next->next;
811             grib_context_free(c, cur->value);
812             grib_context_free(c, cur);
813         }
814     }
815 
816     if (c->multi_support_on)
817         grib_multi_support_reset(c);
818 
819     for (i=0; i < MAX_NUM_CONCEPTS; ++i) {
820         grib_concept_value* cv = c->concepts[i];
821         if (cv) {
822             grib_trie_delete_container(cv->index);
823         }
824         while (cv) {
825             grib_concept_value* n = cv->next;
826             grib_concept_value_delete(c, cv);
827             cv = n;
828         }
829     }
830 }
831 
grib_context_delete(grib_context * c)832 void grib_context_delete(grib_context* c)
833 {
834     if (!c)
835         c = grib_context_get_default();
836 
837     grib_hash_keys_delete(c->keys);
838     /*grib_trie_delete(c->def_files);  TODO:masn */
839 
840     grib_context_reset(c);
841     if (c != &default_grib_context)
842         grib_context_free_persistent(&default_grib_context, c);
843 }
844 
codes_bufr_multi_element_constant_arrays_on(grib_context * c)845 void codes_bufr_multi_element_constant_arrays_on(grib_context* c)
846 {
847     if (!c)
848         c = grib_context_get_default();
849     c->bufr_multi_element_constant_arrays = 1;
850 }
codes_bufr_multi_element_constant_arrays_off(grib_context * c)851 void codes_bufr_multi_element_constant_arrays_off(grib_context* c)
852 {
853     if (!c)
854         c = grib_context_get_default();
855     c->bufr_multi_element_constant_arrays = 0;
856 }
857 /*int  codes_get_bufr_multi_element_constant_arrays(grib_context* c);*/
858 
859 
grib_context_set_definitions_path(grib_context * c,const char * path)860 void grib_context_set_definitions_path(grib_context* c, const char* path)
861 {
862     if (!c)
863         c = grib_context_get_default();
864     GRIB_MUTEX_INIT_ONCE(&once, &init);
865     GRIB_MUTEX_LOCK(&mutex_c);
866 
867     c->grib_definition_files_path = strdup(path);
868     grib_context_log(c, GRIB_LOG_DEBUG, "Definitions path changed to: %s", c->grib_definition_files_path);
869 
870     GRIB_MUTEX_UNLOCK(&mutex_c);
871 }
grib_context_set_samples_path(grib_context * c,const char * path)872 void grib_context_set_samples_path(grib_context* c, const char* path)
873 {
874     if (!c)
875         c = grib_context_get_default();
876     GRIB_MUTEX_INIT_ONCE(&once, &init);
877     GRIB_MUTEX_LOCK(&mutex_c);
878 
879     c->grib_samples_path = strdup(path);
880     grib_context_log(c, GRIB_LOG_DEBUG, "Samples path changed to: %s", c->grib_samples_path);
881 
882     GRIB_MUTEX_UNLOCK(&mutex_c);
883 }
884 
grib_context_malloc_persistent(const grib_context * c,size_t size)885 void* grib_context_malloc_persistent(const grib_context* c, size_t size)
886 {
887     void* p = c->alloc_persistent_mem(c, size);
888     if (!p) {
889         grib_context_log(c, GRIB_LOG_FATAL,
890                          "grib_context_malloc_persistent: error allocating %lu bytes", (unsigned long)size);
891         Assert(0);
892     }
893     return p;
894 }
895 
grib_context_strdup_persistent(const grib_context * c,const char * s)896 char* grib_context_strdup_persistent(const grib_context* c, const char* s)
897 {
898     char* dup = (char*)grib_context_malloc_persistent(c, (strlen(s) * sizeof(char)) + 1);
899     if (dup)
900         strcpy(dup, s);
901     return dup;
902 }
903 
grib_context_malloc_clear_persistent(const grib_context * c,size_t size)904 void* grib_context_malloc_clear_persistent(const grib_context* c, size_t size)
905 {
906     void* p = grib_context_malloc_persistent(c, size);
907     if (p)
908         memset(p, 0, size);
909     return p;
910 }
911 
grib_context_malloc(const grib_context * c,size_t size)912 void* grib_context_malloc(const grib_context* c, size_t size)
913 {
914     void* p = NULL;
915     if (!c)
916         c = grib_context_get_default();
917     if (size == 0)
918         return p;
919     else
920         p = c->alloc_mem(c, size);
921     if (!p) {
922         grib_context_log(c, GRIB_LOG_FATAL, "grib_context_malloc: error allocating %lu bytes", (unsigned long)size);
923         Assert(0);
924     }
925     return p;
926 }
927 
grib_context_realloc(const grib_context * c,void * p,size_t size)928 void* grib_context_realloc(const grib_context* c, void* p, size_t size)
929 {
930     void* q;
931     if (!c)
932         c = grib_context_get_default();
933     q = c->realloc_mem(c, p, size);
934     if (!q) {
935         grib_context_log(c, GRIB_LOG_FATAL, "grib_context_realloc: error allocating %lu bytes", (unsigned long)size);
936         return NULL;
937     }
938     return q;
939 }
940 
grib_context_strdup(const grib_context * c,const char * s)941 char* grib_context_strdup(const grib_context* c, const char* s)
942 {
943     char* dup = 0;
944     if (s) {
945         dup = (char*)grib_context_malloc(c, (strlen(s) * sizeof(char)) + 1);
946         if (dup)
947             strcpy(dup, s);
948     }
949     return dup;
950 }
951 
grib_context_malloc_clear(const grib_context * c,size_t size)952 void* grib_context_malloc_clear(const grib_context* c, size_t size)
953 {
954     void* p = grib_context_malloc(c, size);
955     if (p)
956         memset(p, 0, size);
957     return p;
958 }
959 
grib_context_buffer_malloc(const grib_context * c,size_t size)960 void* grib_context_buffer_malloc(const grib_context* c, size_t size)
961 {
962     void* p = NULL;
963     if (!c)
964         c = grib_context_get_default();
965     if (size == 0)
966         return p;
967     else
968         p = c->alloc_buffer_mem(c, size);
969     if (!p) {
970         grib_context_log(c, GRIB_LOG_FATAL, "grib_context_buffer_malloc: error allocating %lu bytes", (unsigned long)size);
971         return NULL;
972     }
973     return p;
974 }
975 
grib_context_buffer_free(const grib_context * c,void * p)976 void grib_context_buffer_free(const grib_context* c, void* p)
977 {
978     if (!c)
979         c = grib_context_get_default();
980     if (p)
981         c->free_buffer_mem(c, p);
982 }
983 
grib_context_buffer_realloc(const grib_context * c,void * p,size_t size)984 void* grib_context_buffer_realloc(const grib_context* c, void* p, size_t size)
985 {
986     void* q = c->realloc_buffer_mem(c, p, size);
987     if (!q) {
988         grib_context_log(c, GRIB_LOG_FATAL, "grib_context_buffer_realloc: error allocating %lu bytes", (unsigned long)size);
989         return NULL;
990     }
991     return q;
992 }
993 
grib_context_buffer_malloc_clear(const grib_context * c,size_t size)994 void* grib_context_buffer_malloc_clear(const grib_context* c, size_t size)
995 {
996     void* p = grib_context_buffer_malloc(c, size);
997     if (p)
998         memset(p, 0, size);
999     return p;
1000 }
1001 
grib_context_set_memory_proc(grib_context * c,grib_malloc_proc m,grib_free_proc f,grib_realloc_proc r)1002 void grib_context_set_memory_proc(grib_context* c, grib_malloc_proc m, grib_free_proc f, grib_realloc_proc r)
1003 {
1004     c->free_mem    = f;
1005     c->alloc_mem   = m;
1006     c->realloc_mem = r;
1007 }
1008 
grib_context_set_persistent_memory_proc(grib_context * c,grib_malloc_proc m,grib_free_proc f)1009 void grib_context_set_persistent_memory_proc(grib_context* c, grib_malloc_proc m, grib_free_proc f)
1010 {
1011     c->free_persistent_mem  = f;
1012     c->alloc_persistent_mem = m;
1013 }
1014 
grib_context_set_buffer_memory_proc(grib_context * c,grib_malloc_proc m,grib_free_proc f,grib_realloc_proc r)1015 void grib_context_set_buffer_memory_proc(grib_context* c, grib_malloc_proc m, grib_free_proc f, grib_realloc_proc r)
1016 {
1017     c->free_buffer_mem    = f;
1018     c->alloc_buffer_mem   = m;
1019     c->realloc_buffer_mem = r;
1020 }
1021 
grib_context_set_data_accessing_proc(grib_context * c,grib_data_read_proc read,grib_data_write_proc write,grib_data_tell_proc tell)1022 void grib_context_set_data_accessing_proc(grib_context* c, grib_data_read_proc read, grib_data_write_proc write, grib_data_tell_proc tell)
1023 {
1024     c->read  = read;
1025     c->write = write;
1026     c->tell  = tell;
1027 }
1028 
1029 /* Logging procedure */
grib_context_log(const grib_context * c,int level,const char * fmt,...)1030 void grib_context_log(const grib_context* c, int level, const char* fmt, ...)
1031 {
1032     /* Save some CPU */
1033     if ((level == GRIB_LOG_DEBUG && c->debug < 1) ||
1034         (level == GRIB_LOG_WARNING && c->debug < 2)) {
1035         return;
1036     }
1037     else {
1038         char msg[1024];
1039         va_list list;
1040         const int errsv = errno;
1041 
1042         va_start(list, fmt);
1043         vsprintf(msg, fmt, list);
1044         va_end(list);
1045 
1046         if (level & GRIB_LOG_PERROR) {
1047             level = level & ~GRIB_LOG_PERROR;
1048 
1049             /* #if HAS_STRERROR */
1050 #if 1
1051             strcat(msg, " (");
1052             strcat(msg, strerror(errsv));
1053             strcat(msg, ")");
1054 #else
1055             if (errsv > 0 && errsv < sys_nerr) {
1056                 strcat(msg, " (");
1057                 strcat(msg, sys_errlist[errsv]);
1058                 strcat(msg, " )");
1059             }
1060 #endif
1061         }
1062 
1063         if (c->output_log)
1064             c->output_log(c, level, msg);
1065     }
1066 }
1067 
1068 /* Logging procedure */
grib_context_print(const grib_context * c,void * descriptor,const char * fmt,...)1069 void grib_context_print(const grib_context* c, void* descriptor, const char* fmt, ...)
1070 {
1071     char msg[1024];
1072     va_list list;
1073     va_start(list, fmt);
1074     vsprintf(msg, fmt, list);
1075     va_end(list);
1076     c->print(c, descriptor, msg);
1077 }
1078 
grib_context_get_handle_file_count(grib_context * c)1079 int grib_context_get_handle_file_count(grib_context* c)
1080 {
1081     int r = 0;
1082     if (!c)
1083         c = grib_context_get_default();
1084     GRIB_MUTEX_INIT_ONCE(&once, &init);
1085     GRIB_MUTEX_LOCK(&mutex_c);
1086     r = c->handle_file_count;
1087     GRIB_MUTEX_UNLOCK(&mutex_c);
1088     return r;
1089 }
grib_context_get_handle_total_count(grib_context * c)1090 int grib_context_get_handle_total_count(grib_context* c)
1091 {
1092     int r = 0;
1093     if (!c)
1094         c = grib_context_get_default();
1095     GRIB_MUTEX_INIT_ONCE(&once, &init);
1096     GRIB_MUTEX_LOCK(&mutex_c);
1097     r = c->handle_total_count;
1098     GRIB_MUTEX_UNLOCK(&mutex_c);
1099     return r;
1100 }
1101 
grib_context_set_handle_file_count(grib_context * c,int new_count)1102 void grib_context_set_handle_file_count(grib_context* c, int new_count)
1103 {
1104     if (!c)
1105         c = grib_context_get_default();
1106     GRIB_MUTEX_INIT_ONCE(&once, &init);
1107     GRIB_MUTEX_LOCK(&mutex_c);
1108     c->handle_file_count = new_count;
1109     GRIB_MUTEX_UNLOCK(&mutex_c);
1110 }
grib_context_set_handle_total_count(grib_context * c,int new_count)1111 void grib_context_set_handle_total_count(grib_context* c, int new_count)
1112 {
1113     if (!c)
1114         c = grib_context_get_default();
1115     GRIB_MUTEX_INIT_ONCE(&once, &init);
1116     GRIB_MUTEX_LOCK(&mutex_c);
1117     c->handle_total_count = new_count;
1118     GRIB_MUTEX_UNLOCK(&mutex_c);
1119 }
1120 
grib_context_increment_handle_file_count(grib_context * c)1121 void grib_context_increment_handle_file_count(grib_context* c)
1122 {
1123     if (!c)
1124         c = grib_context_get_default();
1125     GRIB_MUTEX_INIT_ONCE(&once, &init);
1126     GRIB_MUTEX_LOCK(&mutex_c);
1127     c->handle_file_count++;
1128     GRIB_MUTEX_UNLOCK(&mutex_c);
1129 }
grib_context_increment_handle_total_count(grib_context * c)1130 void grib_context_increment_handle_total_count(grib_context* c)
1131 {
1132     if (!c)
1133         c = grib_context_get_default();
1134     GRIB_MUTEX_INIT_ONCE(&once, &init);
1135     GRIB_MUTEX_LOCK(&mutex_c);
1136     c->handle_total_count++;
1137     GRIB_MUTEX_UNLOCK(&mutex_c);
1138 }
1139 
grib_context_expanded_descriptors_list_get(grib_context * c,const char * key,long * u,size_t size)1140 bufr_descriptors_array* grib_context_expanded_descriptors_list_get(grib_context* c, const char* key, long* u, size_t size)
1141 {
1142     bufr_descriptors_map_list* expandedUnexpandedMapList;
1143     size_t i                       = 0;
1144     int found                      = 0;
1145     bufr_descriptors_array* result = NULL;
1146     if (!c)
1147         c = grib_context_get_default();
1148 
1149     GRIB_MUTEX_INIT_ONCE(&once, &init);
1150     GRIB_MUTEX_LOCK(&mutex_c);
1151 
1152     if (!c->expanded_descriptors) {
1153         c->expanded_descriptors = (grib_trie*)grib_trie_new(c);
1154         result                  = NULL;
1155         goto the_end;
1156     }
1157     expandedUnexpandedMapList = (bufr_descriptors_map_list*)grib_trie_get(c->expanded_descriptors, key);
1158     found                     = 0;
1159     while (expandedUnexpandedMapList) {
1160         if (expandedUnexpandedMapList->unexpanded->n == size) {
1161             found = 1;
1162             for (i = 0; i < size; i++) {
1163                 if (expandedUnexpandedMapList->unexpanded->v[i]->code != u[i]) {
1164                     found = 0;
1165                     break;
1166                 }
1167             }
1168         }
1169         if (found) {
1170             result = expandedUnexpandedMapList->expanded;
1171             goto the_end;
1172         }
1173         expandedUnexpandedMapList = expandedUnexpandedMapList->next;
1174     }
1175 the_end:
1176     GRIB_MUTEX_UNLOCK(&mutex_c);
1177     return result;
1178 }
1179 
grib_context_expanded_descriptors_list_push(grib_context * c,const char * key,bufr_descriptors_array * expanded,bufr_descriptors_array * unexpanded)1180 void grib_context_expanded_descriptors_list_push(grib_context* c,
1181                                                  const char* key, bufr_descriptors_array* expanded, bufr_descriptors_array* unexpanded)
1182 {
1183     bufr_descriptors_map_list* descriptorsList    = NULL;
1184     bufr_descriptors_map_list* next               = NULL;
1185     bufr_descriptors_map_list* newdescriptorsList = NULL;
1186     if (!c)
1187         c = grib_context_get_default();
1188 
1189     GRIB_MUTEX_INIT_ONCE(&once, &init);
1190     GRIB_MUTEX_LOCK(&mutex_c);
1191 
1192     newdescriptorsList             = (bufr_descriptors_map_list*)grib_context_malloc_clear(c, sizeof(bufr_descriptors_map_list));
1193     newdescriptorsList->expanded   = expanded;
1194     newdescriptorsList->unexpanded = unexpanded;
1195 
1196     descriptorsList = (bufr_descriptors_map_list*)grib_trie_get(c->expanded_descriptors, key);
1197     if (descriptorsList) {
1198         next = descriptorsList;
1199         while (next->next) {
1200             next = next->next;
1201         }
1202         next->next = newdescriptorsList;
1203     }
1204     else {
1205         grib_trie_insert(c->expanded_descriptors, key, newdescriptorsList);
1206     }
1207     GRIB_MUTEX_UNLOCK(&mutex_c);
1208 }
1209 
1210 static codes_assertion_failed_proc assertion = NULL;
1211 
codes_set_codes_assertion_failed_proc(codes_assertion_failed_proc proc)1212 void codes_set_codes_assertion_failed_proc(codes_assertion_failed_proc proc)
1213 {
1214     assertion = proc;
1215 }
1216 
codes_assertion_failed(const char * message,const char * file,int line)1217 void codes_assertion_failed(const char* message, const char* file, int line)
1218 {
1219     /* Default behaviour is to abort
1220      * unless user has supplied his own assertion routine */
1221     if (assertion == NULL) {
1222         grib_context* c = grib_context_get_default();
1223         fprintf(stderr, "ecCodes assertion failed: `%s' in %s:%d\n", message, file, line);
1224         if (!c->no_abort) {
1225             abort();
1226         }
1227     }
1228     else {
1229         char buffer[10240];
1230         sprintf(buffer, "ecCodes assertion failed: `%s' in %s:%d", message, file, line);
1231         assertion(buffer);
1232     }
1233 }
1234 
grib_get_gribex_mode(grib_context * c)1235 int grib_get_gribex_mode(grib_context* c)
1236 {
1237     if (!c)
1238         c = grib_context_get_default();
1239     return c->gribex_mode_on;
1240 }
grib_gribex_mode_on(grib_context * c)1241 void grib_gribex_mode_on(grib_context* c)
1242 {
1243     if (!c)
1244         c = grib_context_get_default();
1245     c->gribex_mode_on = 1;
1246 }
grib_gribex_mode_off(grib_context * c)1247 void grib_gribex_mode_off(grib_context* c)
1248 {
1249     if (!c)
1250         c = grib_context_get_default();
1251     c->gribex_mode_on = 0;
1252 }
1253 
grib_gts_header_on(grib_context * c)1254 void grib_gts_header_on(grib_context* c)
1255 {
1256     if (!c)
1257         c = grib_context_get_default();
1258     c->gts_header_on = 1;
1259 }
grib_gts_header_off(grib_context * c)1260 void grib_gts_header_off(grib_context* c)
1261 {
1262     if (!c)
1263         c = grib_context_get_default();
1264     c->gts_header_on = 0;
1265 }
1266 
grib_multi_support_on(grib_context * c)1267 void grib_multi_support_on(grib_context* c)
1268 {
1269     if (!c)
1270         c = grib_context_get_default();
1271     c->multi_support_on = 1;
1272 }
grib_multi_support_off(grib_context * c)1273 void grib_multi_support_off(grib_context* c)
1274 {
1275     if (!c)
1276         c = grib_context_get_default();
1277     c->multi_support_on = 0;
1278 }
1279