/** * Copyright 2005-2007 ECMWF * * Licensed under the GNU Lesser General Public License which * incorporates the terms and conditions of version 3 of the GNU * General Public License. * See LICENSE and gpl-3.0.txt for details. */ #include "grib_api_internal.h" #include #include #include #if GRIB_PTHREADS static pthread_once_t once = PTHREAD_ONCE_INIT; static pthread_mutex_t mutex_mem = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t mutex_c = PTHREAD_MUTEX_INITIALIZER; static void init() { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&mutex_c,&attr); pthread_mutex_init(&mutex_mem,&attr); pthread_mutexattr_destroy(&attr); } #endif #if MANAGE_MEM #else static long cnt = 0; static long cntp = 0; static void default_long_lasting_free(const grib_context* c, void* p) { GRIB_PTHREAD_ONCE(&once,&init); GRIB_MUTEX_LOCK(&mutex_mem); free(p);cntp--; GRIB_MUTEX_UNLOCK(&mutex_mem); } static void* default_long_lasting_malloc(const grib_context* c, size_t size) { void* ret; GRIB_PTHREAD_ONCE(&once,&init); GRIB_MUTEX_LOCK(&mutex_mem); cntp++; ret=malloc(size); GRIB_MUTEX_UNLOCK(&mutex_mem); return ret; } static void default_buffer_free(const grib_context* c, void* p) { GRIB_PTHREAD_ONCE(&once,&init); GRIB_MUTEX_LOCK(&mutex_mem); free(p);cntp--; GRIB_MUTEX_UNLOCK(&mutex_mem); } static void* default_buffer_malloc(const grib_context* c, size_t size) { void* ret; GRIB_PTHREAD_ONCE(&once,&init); GRIB_MUTEX_LOCK(&mutex_mem); cntp++; ret=malloc(size); GRIB_MUTEX_UNLOCK(&mutex_mem); return ret; } static void* default_buffer_realloc(const grib_context* c, void* p, size_t size) { void* ret; GRIB_PTHREAD_ONCE(&once,&init); GRIB_MUTEX_LOCK(&mutex_mem); ret=realloc(p,size); GRIB_MUTEX_UNLOCK(&mutex_mem); return ret; } static void default_free(const grib_context* c, void* p) { GRIB_PTHREAD_ONCE(&once,&init); GRIB_MUTEX_LOCK(&mutex_mem); free(p);cnt--; GRIB_MUTEX_UNLOCK(&mutex_mem); } static void* default_malloc(const grib_context* c, size_t size) { void* ret; GRIB_PTHREAD_ONCE(&once,&init); GRIB_MUTEX_LOCK(&mutex_mem); cnt++; ret=malloc(size); GRIB_MUTEX_UNLOCK(&mutex_mem); return ret; } static void* default_realloc(const grib_context* c, void* p, size_t size) { void* ret; GRIB_PTHREAD_ONCE(&once,&init); GRIB_MUTEX_LOCK(&mutex_mem); ret=realloc(p,size); GRIB_MUTEX_UNLOCK(&mutex_mem); return ret; } #endif static size_t default_read(const grib_context* c, void *ptr, size_t size, void *stream) { return fread(ptr, 1, size, stream); } static off_t default_tell(const grib_context* c, void *stream) { return ftello(stream); } static off_t default_seek(const grib_context* c, off_t offset,int whence, void *stream) { return fseeko(stream,offset,whence); } static int default_feof(const grib_context* c, void *stream) { return feof((FILE*)stream); } static size_t default_write(const grib_context* c,const void *ptr, size_t size, void *stream) { return fwrite(ptr, 1, size, stream); } size_t grib_context_read(const grib_context* c, void *ptr, size_t size, void *stream) { if (!c) c=grib_context_get_default(); return c->read(c,ptr, size, stream); } off_t grib_context_tell(const grib_context* c, void *stream) { if (!c) c=grib_context_get_default(); return c->tell(c,stream); } int grib_context_seek(const grib_context* c, off_t offset ,int whence , void *stream) { if (!c) c=grib_context_get_default(); return c->seek(c,offset,whence,stream); } int grib_context_eof(const grib_context* c, void *stream) { if (!c) c=grib_context_get_default(); return c->eof(c,stream); } size_t grib_context_write(const grib_context* c,const void *ptr, size_t size, void *stream) { if (!c) c=grib_context_get_default(); return c->write(c,ptr, size, stream); } static void default_log(const grib_context* c, int level, const char* mess){ if (!c) c=grib_context_get_default(); if(level == GRIB_LOG_ERROR) { fprintf(c->log_stream, "GRIB_API ERROR : %s\n", mess); /*Assert(1==0);*/ } if(level == GRIB_LOG_FATAL) fprintf(c->log_stream, "GRIB_API ERROR : %s\n", mess); if(level == GRIB_LOG_DEBUG && c->debug>0) fprintf(c->log_stream, "GRIB_API DEBUG : %s\n", mess); if(level == GRIB_LOG_WARNING) fprintf(c->log_stream, "GRIB_API WARNING : %s\n", mess); if(level == GRIB_LOG_INFO) fprintf(c->log_stream, "GRIB_API INFO : %s\n", mess); if(level == GRIB_LOG_FATAL) { Assert(0);} if(getenv("GRIB_API_FAIL_IF_LOG_MESSAGE")) { long n = atol(getenv("GRIB_API_FAIL_IF_LOG_MESSAGE")); if(n >= 1 && level == GRIB_LOG_ERROR) Assert(0); if(n >= 2 && level == GRIB_LOG_WARNING) Assert(0); } } static void default_print(const grib_context* c, void* descriptor, const char* mess) { fprintf(descriptor, "%s", mess); } void grib_context_set_print_proc(grib_context* c, grib_print_proc p) { c = c ? c : grib_context_get_default(); c->print = p; } void grib_context_set_debug(grib_context* c, int mode) { c = c ? c : grib_context_get_default(); c->debug = mode; } void grib_context_set_logging_proc(grib_context* c, grib_log_proc p) { c = c ? c : grib_context_get_default(); c->output_log = p; } long grib_get_api_version(){ return GRIB_API_VERSION; } void grib_print_api_version(FILE* out) { fprintf(out,"%d.%d.%d", GRIB_API_MAJOR_VERSION, GRIB_API_MINOR_VERSION, GRIB_API_REVISION_VERSION); } static grib_context default_grib_context = { 0, /* inited */ 0, /* debug */ 0, /* write_on_fail */ 0, /* no_abort */ 0, /* io_buffer_size */ 0, /* no_big_group_split */ 0, /* no_spd */ 0, /* keep_matrix */ 0, /* grib_definition_files_path */ 0, /* grib_templates_path */ 0, /* grib_concept_path */ 0, /* grib_reader */ 0, /* user data */ GRIB_REAL_MODE8, /* real mode for fortran */ #if MANAGE_MEM &grib_transient_free, /* free_mem */ &grib_transient_malloc, /* alloc_mem */ &grib_transient_realloc, /* realloc_mem */ &grib_permanent_free, /* free_persistant_mem */ &grib_permanent_malloc, /* alloc_persistant_mem */ &grib_buffer_free, /* buffer_free_mem */ &grib_buffer_malloc, /* buffer_alloc_mem */ &grib_buffer_realloc, /* buffer_realloc_mem */ #else &default_free, /* free_mem */ &default_malloc, /* alloc_mem */ &default_realloc, /* realloc_mem */ &default_long_lasting_free, /* free_persistant_mem */ &default_long_lasting_malloc, /* alloc_persistant_mem */ &default_buffer_free, /* free_buffer_mem */ &default_buffer_malloc, /* alloc_buffer_mem */ &default_buffer_realloc, /* realloc_buffer_mem */ #endif &default_read, /* file read procedure */ &default_write, /* file write procedure */ &default_tell, /* lfile tell procedure */ &default_seek, /* lfile seek procedure */ &default_feof, /* file feof procedure */ &default_log, /* logging_procedure */ &default_print, /* print procedure */ 0, /* code tables */ 0, /* files */ 0, /* multigrib support on */ 0, /* multigrib support */ 0, /* grib_definition_files_dir */ 0, /* handle_file_count */ 0, /* handle_total_count */ 0, /* message_file_offset */ 0, /* no_fail_on_wrong_length */ 0, /* gts_header_on */ 0, /* gribex_mode_on */ 0, /* large_constant_fields */ 0, /* keys (grib_trie*) */ 0, /* keys_count */ 0, /* concepts_index */ 0, /* concepts_count */ {0,}, /* concepts */ 0, /* def_files */ 0, /* ieee_packing */ 0, /* blacklist */ 0, /* log_stream */ 0 /* classes */ #if GRIB_PTHREADS ,PTHREAD_MUTEX_INITIALIZER /*mutex*/ #endif }; grib_context* grib_context_get_default(){ GRIB_PTHREAD_ONCE(&once,&init); GRIB_MUTEX_LOCK(&mutex_c); if(!default_grib_context.inited) { const char * write_on_fail = getenv("GRIB_API_WRITE_ON_FAIL"); const char * large_constant_fields = getenv("GRIB_API_LARGE_CONSTANT_FIELDS"); const char * no_abort = getenv("GRIB_API_NO_ABORT"); const char * debug = getenv("GRIB_API_DEBUG"); const char *gribex=getenv("GRIB_GRIBEX_MODE_ON"); const char *ieee_packing=getenv("GRIB_IEEE_PACKING"); const char *io_buffer_size=getenv("GRIB_API_IO_BUFFER_SIZE"); const char *log_stream=getenv("GRIB_API_LOG_STREAM"); const char *no_big_group_split=getenv("GRIB_API_NO_BIG_GROUP_SPLIT"); const char *no_spd=getenv("GRIB_API_NO_SPD"); const char *keep_matrix=getenv("GRIB_API_KEEP_MATRIX"); default_grib_context.inited = 1; default_grib_context.io_buffer_size = io_buffer_size ? atoi(io_buffer_size) : 0; default_grib_context.no_big_group_split = no_big_group_split ? atoi(no_big_group_split) : 0; default_grib_context.no_spd = no_spd ? atoi(no_spd) : 0; default_grib_context.keep_matrix = keep_matrix ? atoi(keep_matrix) : 1; default_grib_context.write_on_fail = write_on_fail ? atoi(write_on_fail) : 0; default_grib_context.no_abort = no_abort ? atoi(no_abort) : 0; default_grib_context.debug = debug ? atoi(debug) : 0; default_grib_context.gribex_mode_on=gribex ? atoi(gribex) : 0; default_grib_context.large_constant_fields = large_constant_fields ? atoi(large_constant_fields) : 0; default_grib_context.ieee_packing=ieee_packing ? atoi(ieee_packing) : 0; default_grib_context.grib_templates_path = getenv("GRIB_SAMPLES_PATH"); default_grib_context.log_stream=stderr; if (!log_stream) { default_grib_context.log_stream=stderr; } else if (!strcmp(log_stream,"stderr") ) { default_grib_context.log_stream=stderr; } else if (!strcmp(log_stream,"stdout") ) { default_grib_context.log_stream=stdout; } if (!default_grib_context.grib_templates_path) default_grib_context.grib_templates_path = getenv("GRIB_TEMPLATES_PATH"); #ifdef GRIB_TEMPLATES_PATH if(!default_grib_context.grib_templates_path) default_grib_context.grib_templates_path = GRIB_TEMPLATES_PATH ; #endif default_grib_context.grib_definition_files_path = getenv("GRIB_DEFINITION_PATH"); #ifdef GRIB_DEFINITION_PATH if(!default_grib_context.grib_definition_files_path) default_grib_context.grib_definition_files_path = GRIB_DEFINITION_PATH ; #endif default_grib_context.keys_count=0; default_grib_context.keys=grib_hash_keys_new(&(default_grib_context), &(default_grib_context.keys_count)); default_grib_context.concepts_index=grib_itrie_new(&(default_grib_context), &(default_grib_context.concepts_count)); default_grib_context.def_files=grib_trie_new(&(default_grib_context)); default_grib_context.classes=grib_trie_new(&(default_grib_context)); } GRIB_MUTEX_UNLOCK(&mutex_c); return &default_grib_context; } /* TODO: use parent */ grib_context* grib_context_new(grib_context* parent) { grib_context* c; #if GRIB_PTHREADS pthread_mutexattr_t attr; #endif if (!parent) parent=grib_context_get_default(); GRIB_PTHREAD_ONCE(&once,&init); GRIB_MUTEX_LOCK(&(parent->mutex)); c = (grib_context*)grib_context_malloc_clear_persistent(&default_grib_context,sizeof(grib_context)); c->inited = default_grib_context.inited; c->debug = default_grib_context.debug; c->real_mode = default_grib_context.real_mode; c->free_mem = default_grib_context.free_mem; c->alloc_mem = default_grib_context.alloc_mem; c->free_persistent_mem = default_grib_context.free_persistent_mem; c->alloc_persistent_mem= default_grib_context.alloc_persistent_mem; c->read = default_grib_context.read; c->write = default_grib_context.write; c->tell = default_grib_context.tell; c->output_log = default_grib_context.output_log; c->print = default_grib_context.print ; c->user_data = default_grib_context.user_data; c->def_files = default_grib_context.def_files; #if GRIB_PTHREADS pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&mutex_c,&attr); pthread_mutexattr_destroy(&attr); #endif GRIB_MUTEX_UNLOCK(&(parent->mutex)); return c; } static int init_definition_files_dir(grib_context* c) { int err=0; char* path=NULL; char* p=NULL; char* dir=NULL; grib_string_list* next=NULL; if (!c) c=grib_context_get_default(); if (c->grib_definition_files_dir) return 0; if (!c->grib_definition_files_path) return GRIB_NO_DEFINITIONS; path=c->grib_definition_files_path; GRIB_PTHREAD_ONCE(&once,&init); GRIB_MUTEX_LOCK(&mutex_c); p=path; while(*p!=':' && *p!='\0') p++; if (*p != ':') { c->grib_definition_files_dir=(grib_string_list*)grib_context_malloc_clear_persistent(c,sizeof(grib_string_list)); c->grib_definition_files_dir->value=grib_context_strdup(c,path); } else { dir=strtok(path,":"); while (dir != NULL) { if (next) { next->next=(grib_string_list*)grib_context_malloc_clear_persistent(c,sizeof(grib_string_list)); next=next->next; } else { c->grib_definition_files_dir=(grib_string_list*)grib_context_malloc_clear_persistent(c,sizeof(grib_string_list)); next=c->grib_definition_files_dir; } next->value=grib_context_strdup(c,dir); dir=strtok(NULL,":"); } } GRIB_MUTEX_UNLOCK(&mutex_c); return err; } char *grib_context_full_path(grib_context* c,const char* basename) { int err=0; char full[1024]={0,}; grib_string_list* dir=NULL; grib_string_list* fullpath=0; if (!c) c=grib_context_get_default(); GRIB_PTHREAD_ONCE(&once,&init); GRIB_MUTEX_LOCK(&mutex_c); if(*basename == '/' || *basename == '.') { GRIB_MUTEX_UNLOCK(&mutex_c); return (char*)basename; } else { if ((fullpath=grib_trie_get(c->def_files,basename))!=NULL) { GRIB_MUTEX_UNLOCK(&mutex_c); return fullpath->value; } if (!c->grib_definition_files_dir) err=init_definition_files_dir(c); if (err != GRIB_SUCCESS) { grib_context_log(c,GRIB_LOG_ERROR, "Unable to find definition files directory"); GRIB_MUTEX_UNLOCK(&mutex_c); return NULL; } dir=c->grib_definition_files_dir; while (dir) { sprintf(full,"%s/%s",dir->value,basename); if (!access(full,F_OK)) { fullpath=grib_context_malloc_clear_persistent(c,sizeof(grib_string_list)); Assert(fullpath); fullpath->value=grib_context_strdup(c,full); grib_trie_insert(c->def_files,basename,fullpath); grib_context_log(c,GRIB_LOG_DEBUG,"Found def file %s",full); GRIB_MUTEX_UNLOCK(&mutex_c); return fullpath->value; } dir=dir->next; } } /* Store missing files so we don't check for them again and again */ grib_trie_insert(c->def_files,basename,&grib_file_not_found); /*grib_context_log(c,GRIB_LOG_ERROR,"Def file \"%s\" not found",basename);*/ GRIB_MUTEX_UNLOCK(&mutex_c); full[0]=0; return NULL; } void grib_context_free(const grib_context* c, void* p){ if (!c) c=grib_context_get_default(); if(p) c->free_mem(c,p); } void grib_context_free_persistent(const grib_context* c, void* p){ if (!c) c=grib_context_get_default(); if(p) c->free_persistent_mem(c,p); } void grib_context_reset(grib_context* c){ if (!c) c=grib_context_get_default(); if(c->grib_reader) { grib_action_file *fr = c->grib_reader->first; grib_action_file *fn = fr; grib_action* a; while(fn){ fr = fn; fn = fn->next; a = fr->root; while(a) { grib_action *na = a->next; grib_free_action(c, a); a = na; } grib_context_free_persistent(c, fr->filename); grib_context_free_persistent(c, fr); } grib_context_free_persistent(c, c->grib_reader); } c->grib_reader = NULL; if(c->codetable) grib_codetable_delete(c); c->codetable = NULL; if(c->grib_definition_files_dir) grib_context_free(c,c->grib_definition_files_dir); if(c->multi_support_on) grib_multi_support_reset(c); } void grib_context_delete( grib_context* c){ if (!c) c=grib_context_get_default(); grib_hash_keys_delete( c->keys); grib_trie_delete(c->def_files); grib_context_reset( c ); if(c != &default_grib_context) grib_context_free_persistent(&default_grib_context,c); } void* grib_context_malloc_persistent(const grib_context* c, size_t size){ void* p = c->alloc_persistent_mem(c,size); if(!p) { grib_context_log(c,GRIB_LOG_FATAL,"grib_context_malloc: error allocating %lu bytes",(unsigned long)size); Assert(1); } return p; } char* grib_context_strdup_persistent(const grib_context* c,const char* s){ char *dup = (char*)grib_context_malloc_persistent(c,(strlen(s)*sizeof(char))+1); if(dup) strcpy(dup,s); return dup; } void* grib_context_malloc_clear_persistent(const grib_context* c, size_t size){ void *p = grib_context_malloc_persistent(c,size); if(p) memset(p,0,size); return p; } void* grib_context_malloc(const grib_context* c, size_t size){ void* p = NULL; if (!c) c=grib_context_get_default(); if(size == 0) return p; else p=c->alloc_mem(c,size); if(!p) { grib_context_log(c,GRIB_LOG_FATAL,"grib_context_malloc: error allocating %lu bytes",(unsigned long)size); Assert(1); } return p; } void* grib_context_realloc(const grib_context* c, void *p,size_t size){ void* q; if (!c) c=grib_context_get_default(); q=c->realloc_mem(c,p,size); if(!q) { grib_context_log(c,GRIB_LOG_FATAL,"grib_context_realloc: error allocating %lu bytes",(unsigned long)size); exit(1); } return q; } char* grib_context_strdup(const grib_context* c,const char* s){ char *dup = (char*)grib_context_malloc(c,(strlen(s)*sizeof(char))+1); if(dup) strcpy(dup,s); return dup; } void* grib_context_malloc_clear(const grib_context* c, size_t size){ void *p = grib_context_malloc(c,size); if(p) memset(p,0,size); return p; } void* grib_context_buffer_malloc(const grib_context* c, size_t size){ void* p = NULL; if (!c) c=grib_context_get_default(); if(size == 0) return p; else p=c->alloc_buffer_mem(c,size); if(!p) { grib_context_log(c,GRIB_LOG_FATAL,"grib_context_buffer_malloc: error allocating %lu bytes",(unsigned long)size); exit(1); } return p; } void grib_context_buffer_free(const grib_context* c, void* p){ if (!c) c=grib_context_get_default(); if(p) c->free_buffer_mem(c,p); } void* grib_context_buffer_realloc(const grib_context* c, void *p,size_t size){ void* q=c->realloc_buffer_mem(c,p,size); if(!q) { grib_context_log(c,GRIB_LOG_FATAL,"grib_context_buffer_realloc: error allocating %lu bytes",(unsigned long)size); exit(1); } return q; } void* grib_context_buffer_malloc_clear(const grib_context* c, size_t size){ void *p = grib_context_buffer_malloc(c,size); if(p) memset(p,0,size); return p; } void grib_context_set_memory_proc(grib_context* c, grib_malloc_proc m, grib_free_proc f,grib_realloc_proc r) { c->free_mem = f; c->alloc_mem = m; c->realloc_mem = r; } void grib_context_set_persistent_memory_proc(grib_context* c, grib_malloc_proc m, grib_free_proc f) { c->free_persistent_mem = f; c->alloc_persistent_mem = m; } void grib_context_set_buffer_memory_proc(grib_context* c, grib_malloc_proc m, grib_free_proc f,grib_realloc_proc r) { c->free_buffer_mem = f; c->alloc_buffer_mem = m; c->realloc_buffer_mem = r; } 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) { c->read = read; c->write = write; c->tell = tell; } /* logging procedure */ void grib_context_log(const grib_context *c,int level, const char* fmt, ...) { char msg[1024]; va_list list; /* Save some CPU */ if( (level == GRIB_LOG_DEBUG && c->debug<1) || (level == GRIB_LOG_WARNING && c->debug<2) ) return; va_start(list,fmt); vsprintf(msg, fmt, list); va_end(list); if(level & GRIB_LOG_PERROR) { level = level & ~GRIB_LOG_PERROR; /* #if HAS_STRERROR */ #if 1 strcat(msg," ("); strcat(msg,strerror(errno)); strcat(msg,")"); #else if(errno > 0 && errno < sys_nerr) { strcat(msg," ("); strcat(msg,sys_errlist[errno]); strcat(msg," )"); } #endif } if(c->output_log) c->output_log(c,level,msg); } /* logging procedure */ void grib_context_print(const grib_context *c, void* descriptor,const char* fmt, ...) { char msg[1024]; va_list list; va_start(list,fmt); vsprintf(msg, fmt, list); va_end(list); c->print(c,descriptor,msg); }