/** * 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. */ /* * * Description: routines for grib indexing form a set of files * * Author: Enrico Fucile * * */ #include "grib_api_internal.h" #define GRIB_START_ARRAY_SIZE 5000 #define GRIB_ARRAY_INCREMENT 1000 #define SWAP(a,b) temp=(a);(a)=(b);(b)=temp; #define GRIB_ORDER_BY_ASC 1 #define GRIB_ORDER_BY_DESC -1 GRIB_INLINE static int grib_inline_strcmp(const char* a,const char* b) { if (*a != *b) return 1; while((*a!=0 && *b!=0) && *(a) == *(b) ) {a++;b++;} return (*a==0 && *b==0) ? 0 : 1; } static grib_fieldset* grib_fieldset_create_from_keys(grib_context* c,char** keys,int nkeys,int* err); static grib_fieldset* grib_fieldset_create_from_order_by(grib_context* c,grib_order_by* ob, int* err); static int grib_fieldset_resize(grib_fieldset* set,size_t newsize); static void grib_trim(char** x); static grib_order_by* grib_fieldset_new_order_by(grib_context* c,char* z); static int grib_fieldset_compare(grib_fieldset* set,int* i,int* j); static void grib_fieldset_sort(grib_fieldset* set, int beg, int end); static int grib_fieldset_columns_resize(grib_fieldset* set,size_t newsize); static grib_int_array* grib_fieldset_create_int_array(grib_context* c,size_t size); static int grib_fieldset_resize_int_array(grib_int_array* a,size_t newsize); static void grib_fieldset_delete_int_array(grib_int_array* f); static void grib_fieldset_delete_columns(grib_fieldset* set); static grib_field** grib_fieldset_create_fields(grib_context* c,size_t size); static void grib_fieldset_delete_fields(grib_fieldset* set); static int grib_fieldset_resize_fields(grib_fieldset* set,size_t newsize); static int grib_fieldset_set_order_by(grib_fieldset* set,grib_order_by* ob); /* --------------- grib_column functions ------------------*/ int grib_fieldset_new_column(grib_fieldset* set,int id,char* key,int type) { grib_column* column=0; grib_context* c; int err=0; if (!set) return GRIB_INVALID_ARGUMENT; c=set->context; set->columns[id].errors=(int*)grib_context_malloc_clear(c, sizeof(int)*GRIB_START_ARRAY_SIZE); switch (type) { case GRIB_TYPE_LONG: set->columns[id].long_values=(long*)grib_context_malloc_clear(c, sizeof(long)*GRIB_START_ARRAY_SIZE); if (!set->columns[id].long_values) { grib_context_log(c, GRIB_LOG_ERROR, "grib_fieldset_new_column : Cannot malloc %d bytes", sizeof(long)*GRIB_START_ARRAY_SIZE); err=GRIB_OUT_OF_MEMORY; return err; } break; case GRIB_TYPE_DOUBLE: set->columns[id].double_values=(double*)grib_context_malloc_clear(c, sizeof(double)*GRIB_START_ARRAY_SIZE); if (!set->columns[id].double_values) { grib_context_log(c, GRIB_LOG_ERROR, "grib_fieldset_new_column : Cannot malloc %d bytes", sizeof(double)*GRIB_START_ARRAY_SIZE); err=GRIB_OUT_OF_MEMORY; return err; } break; case GRIB_TYPE_STRING: set->columns[id].string_values=(char**)grib_context_malloc_clear(c, sizeof(char*)*GRIB_START_ARRAY_SIZE); if (!set->columns[id].string_values) { grib_context_log(c, GRIB_LOG_ERROR, "grib_fieldset_new_column : Cannot malloc %d bytes", sizeof(char*)*GRIB_START_ARRAY_SIZE); err=GRIB_OUT_OF_MEMORY; return err; } break; default: grib_context_log(c, GRIB_LOG_ERROR, "grib_fieldset_new_column : unknown column type %d",type); grib_context_free(c,column); return err; } set->columns[id].context=c; set->columns[id].name=grib_context_strdup(c,key); set->columns[id].type=type; set->columns[id].values_array_size=GRIB_START_ARRAY_SIZE; set->columns[id].size=0; return err; } static void grib_fieldset_delete_columns(grib_fieldset* set) { int i=0; grib_context* c; if (!set) return; c=set->context; for (i=0;icolumns_size;i++) { int j=0; switch (set->columns[i].type) { case GRIB_TYPE_LONG: grib_context_free(c,set->columns[i].long_values); break; case GRIB_TYPE_DOUBLE: grib_context_free(c,set->columns[i].double_values); break; case GRIB_TYPE_STRING: for (j=0;jcolumns[i].size;j++) grib_context_free(c,set->columns[i].string_values[j]); break; default: grib_context_log(c, GRIB_LOG_ERROR, "grib_fieldset_new_column : unknown column type %d",set->columns[i].type); } grib_context_free(c,set->columns[i].errors); grib_context_free(c,set->columns[i].name); } grib_context_free(c,set->columns); } static int grib_fieldset_columns_resize(grib_fieldset* set,size_t newsize) { double* newdoubles; long* newlongs; char** newstrings; int* newerrors; int i=0; grib_context* c; if (!set || !set->columns) return GRIB_INVALID_ARGUMENT; c=set->context; if (newsize <= set->columns[0].values_array_size) return 0; for (i=0;icolumns_size;i++) { switch (set->columns[i].type) { case GRIB_TYPE_LONG: newlongs=(long*)grib_context_realloc(c,set->columns[i].long_values, newsize*sizeof(long)); if (!newlongs ) { grib_context_log(c, GRIB_LOG_ERROR, "grib_fieldset_columns_resize : Cannot malloc %d bytes",newsize-set->columns[i].values_array_size); return GRIB_OUT_OF_MEMORY; } else set->columns[i].long_values=newlongs; break; case GRIB_TYPE_DOUBLE: newdoubles=(double*)grib_context_realloc(c,set->columns[i].double_values, newsize*sizeof(double)); if (!newdoubles) { grib_context_log(c, GRIB_LOG_ERROR, "grib_fieldset_columns_resize : Cannot malloc %d bytes",newsize-set->columns[i].values_array_size); return GRIB_OUT_OF_MEMORY; } else set->columns[i].double_values=newdoubles; break; case GRIB_TYPE_STRING: newstrings=(char**)grib_context_realloc(c,set->columns[i].string_values, newsize*sizeof(char*)); if (!newstrings) { grib_context_log(c, GRIB_LOG_ERROR, "grib_fieldset_columns_resize : Cannot malloc %d bytes",newsize-set->columns[i].values_array_size); return GRIB_OUT_OF_MEMORY; } else set->columns[i].string_values=newstrings; break; } newerrors=(int*)grib_context_realloc(c,set->columns[i].errors,newsize*sizeof(int)); if (!newerrors) { grib_context_log(c, GRIB_LOG_ERROR, "grib_fieldset_columns_resize : Cannot malloc %d bytes", set->columns[i].errors,newsize*sizeof(int)); return GRIB_OUT_OF_MEMORY; } else set->columns[i].errors=newerrors; set->columns[i].values_array_size=newsize; } return GRIB_SUCCESS; } int grib_fieldset_column_copy_from_handle(grib_handle* h,grib_fieldset* set,int i) { int err=0; long lval=0; double dval=0; char sval[1024]; size_t slen=1024; if (!set || !h || set->columns[i].type == 0) return GRIB_INVALID_ARGUMENT; if (set->columns[i].size >= set->columns[i].values_array_size) grib_fieldset_columns_resize(set,set->columns[i].values_array_size+GRIB_ARRAY_INCREMENT); switch (set->columns[i].type) { case GRIB_TYPE_LONG: err=grib_get_long(h,set->columns[i].name,&lval); set->columns[i].long_values[set->columns[i].size]=lval; break; case GRIB_TYPE_DOUBLE: err=grib_get_double(h,set->columns[i].name,&dval); set->columns[i].double_values[set->columns[i].size]=dval; break; case GRIB_TYPE_STRING: err=grib_get_string(h,set->columns[i].name,sval,&slen); set->columns[i].string_values[set->columns[i].size]=grib_context_strdup(h->context,sval); break; } set->columns[i].errors[set->columns[i].size]=err; set->columns[i].size++; return err; } /* --------------- grib_fieldset functions ------------------*/ grib_fieldset* grib_fieldset_new_from_files(grib_context* c,char* filenames[], int nfiles, char** keys,int nkeys, char* where_string,char* order_by_string,int* err) { int i=0; int ret=GRIB_SUCCESS; grib_order_by* ob=NULL; grib_fieldset* set=0; if (!c) c=grib_context_get_default( ); if (( (!keys || nkeys==0) && !order_by_string ) || !filenames ) { *err=GRIB_INVALID_ARGUMENT; return NULL; } if (order_by_string) { ob=grib_fieldset_new_order_by(c,order_by_string); if (!ob) { *err=GRIB_INVALID_ORDERBY; return NULL; } } if ( !keys || nkeys==0 ) { set=grib_fieldset_create_from_order_by(c,ob,err); } else { set=grib_fieldset_create_from_keys(c,keys,nkeys,err); } *err=GRIB_SUCCESS; for (i=0;iorder_by && ob) *err=grib_fieldset_set_order_by(set,ob); if (*err!=GRIB_SUCCESS) return NULL; grib_fieldset_sort(set,0,set->size-1); grib_fieldset_rewind(set); } return set; } static grib_fieldset* grib_fieldset_create_from_keys(grib_context* c,char** keys,int nkeys, int* err) { grib_fieldset* set=0; size_t msize=0,size=0; int i=0; int type=0; int default_type=GRIB_TYPE_STRING; if (!c) c=grib_context_get_default( ); size=GRIB_START_ARRAY_SIZE; msize=sizeof(grib_fieldset); set=(grib_fieldset*)grib_context_malloc_clear(c,msize); if (!set) { grib_context_log(c, GRIB_LOG_ERROR, "grib_fieldset_create : Cannot malloc %d bytes",msize); return NULL; } set->context=c; set->fields_array_size=size; set->size=0; set->current=-1; set->fields=0; set->filter=0; set->order=0; set->columns=0; set->where=0; set->order_by=0; set->fields=grib_fieldset_create_fields(set->context,size); set->order=grib_fieldset_create_int_array(c,size); set->filter=grib_fieldset_create_int_array(c,size); for (i=0;ifilter->size;i++) set->filter->el[i]=i; set->columns=(grib_column*)grib_context_malloc_clear(c,sizeof(grib_column)*nkeys); if (!set->columns) { grib_context_log(c,GRIB_LOG_ERROR,"grib_fieldset_new_query: memory allocation error"); *err=GRIB_OUT_OF_MEMORY; return NULL; } for (i=0;icolumns_size=nkeys; return set; } static grib_fieldset* grib_fieldset_create_from_order_by(grib_context* c,grib_order_by* ob, int* err) { char** keys=NULL; size_t nkeys=0; int i=0; grib_fieldset* set=NULL; grib_order_by* next=ob; while(next) {nkeys++;next=next->next;} keys=grib_context_malloc_clear( c,nkeys*sizeof(char*)); next=ob; i=0; while(next) {keys[i++]=next->key;next=next->next;} set=grib_fieldset_create_from_keys(c,keys,nkeys,err); grib_context_free(c,keys); return set; } int grib_fieldset_apply_where(grib_fieldset* set,const char* where_string) { int err=GRIB_NOT_IMPLEMENTED; grib_math* m=0; if (!set) return GRIB_INVALID_ARGUMENT; m=grib_math_new(set->context,where_string,&err); print_math(m); printf("\n"); return err; } int grib_fieldset_apply_order_by(grib_fieldset* set,const char* order_by_string) { int err=0; grib_order_by* ob=NULL; if (!set) return GRIB_INVALID_ARGUMENT; if (set->order_by) { grib_fieldset_delete_order_by(set->context,set->order_by); set->order_by=0; } ob=grib_fieldset_new_order_by(set->context,(char*)order_by_string); if ((err=grib_fieldset_set_order_by(set,ob)) != GRIB_SUCCESS) return err; if (set->order_by) grib_fieldset_sort(set,0,set->size-1); grib_fieldset_rewind(set); return err; } static int grib_fieldset_compare(grib_fieldset* set,int* i,int* j) { int ret=0; double d=0; int idkey=0; grib_order_by* ob=0; int ii=0,jj=0; int *order=0,*filter=0; if (!set || !set->order_by) return GRIB_INVALID_ARGUMENT; ob=set->order_by; order=set->order->el; filter=set->filter->el; ii=*(set->filter->el+*(order+*i)); jj=*(set->filter->el+*(order+*j)); while (ob) { idkey=ob->idkey; switch (set->columns[idkey].type) { case GRIB_TYPE_STRING: ret=strcmp(set->columns[idkey].string_values[ii], set->columns[idkey].string_values[jj]); break; case GRIB_TYPE_DOUBLE: d=set->columns[idkey].double_values[ii]- set->columns[idkey].double_values[jj]; if (d > 0 ) ret=1; else if ( d == 0) ret=0; else ret=-1; break; case GRIB_TYPE_LONG: ret=set->columns[idkey].long_values[ii]- set->columns[idkey].long_values[jj]; break; default: return GRIB_INVALID_TYPE; } if (ret!=0) { ret*=ob->mode; break; } ob=ob->next; } return ret; } static void grib_fieldset_sort(grib_fieldset* set, int beg, int end) { double temp; int l=0,r=0; if (end > beg) { l = beg + 1; r = end; while (l < r) { if ( grib_fieldset_compare(set,&l,&beg) <= 0 ) { l++; } else if(grib_fieldset_compare(set,&r,&beg) >= 0 ) { r--; } else { SWAP(set->order->el[l],set->order->el[r]) } } if (grib_fieldset_compare(set,&l,&beg) < 0) { SWAP(set->order->el[l],set->order->el[beg]) l--; } else { l--; SWAP(set->order->el[l],set->order->el[beg]) } grib_fieldset_sort(set, beg, l); grib_fieldset_sort(set, r, end); } } void grib_fieldset_delete_order_by(grib_context* c,grib_order_by* order_by) { grib_order_by* ob=order_by; if (!c) c=grib_context_get_default(); while (order_by) { if (order_by->key) free(order_by->key); ob=order_by; order_by=order_by->next; grib_context_free( c,ob); } return; } static grib_order_by* grib_fieldset_new_order_by(grib_context* c,char* obstr) { char *t1=0,*t2=0,*p=0; int id=0; char *z=0,*zs=0; int mode,mode_default=GRIB_ORDER_BY_ASC; grib_order_by *ob,*sob; if (!obstr) return NULL; z=grib_context_strdup(c,obstr); zs=z; grib_trim(&z); if (strlen(z)==0) {return 0;} ob=(grib_order_by*)grib_context_malloc_clear(c,sizeof(grib_order_by)); sob=ob; ob->key=0; ob->idkey=0; ob->mode=0; ob->next=0; if (z) t1=strtok(z,","); while (t1) { grib_trim(&t1); t2=grib_context_strdup(c,t1); p=t2; while ( *p != ' ' && *p != '\0' ) p++; mode=mode_default; if (p != t2) { while ( *p == ' ' && *p != '\0' ) p++; if (*p != '\0') { *(p-1)='\0'; if (!grib_inline_strcmp(p,"asc")) mode=GRIB_ORDER_BY_ASC; if (!grib_inline_strcmp(p,"desc")) mode=GRIB_ORDER_BY_DESC; } grib_trim(&p); } grib_trim(&t2); id=-1; t1=strtok(NULL,","); if (ob->key) { ob->next=(grib_order_by*)grib_context_malloc_clear(c,sizeof(grib_order_by)); ob=ob->next; ob->key=0; ob->next=0; } ob->mode=mode; ob->key=t2; ob->idkey=id; } if (z) grib_context_free(c,z); return sob; } void grib_fieldset_delete(grib_fieldset* set) { grib_context* c=0; if (!set) return; c=set->context; grib_fieldset_delete_columns(set); grib_fieldset_delete_fields(set); grib_fieldset_delete_int_array(set->order); grib_fieldset_delete_int_array(set->filter); grib_context_free( c, set); } int grib_fieldset_add(grib_fieldset* set,char* filename) { int ret=GRIB_SUCCESS; int err=0; int i=0; grib_handle* h=0; int nkeys; grib_file* file; double offset=0; long length=0; grib_context* c=0; if (!set || !filename ) return GRIB_INVALID_ARGUMENT; c=set->context; nkeys=set->columns_size; file=grib_file_open(filename,"r",&err); if (!file || !file->handle) return err; while((h = grib_handle_new_from_file(c,file->handle,&ret)) != NULL || ret != GRIB_SUCCESS ) { if (!h) return ret; err=GRIB_SUCCESS; for (i=0;icolumns_size;i++) { err=grib_fieldset_column_copy_from_handle(h,set,i); if (err != GRIB_SUCCESS) ret=err; } if (err==GRIB_SUCCESS || err==GRIB_NOT_FOUND) { if (set->fields_array_size < set->columns[0].values_array_size) { ret=grib_fieldset_resize(set,set->columns[0].values_array_size); if (ret!=GRIB_SUCCESS) return ret; } offset=0; ret=grib_get_double(h,"offset",&offset); set->fields[set->size]=(grib_field*)grib_context_malloc_clear(c,sizeof(grib_field)); set->fields[set->size]->file=file; file->refcount++; set->fields[set->size]->offset=(off_t)offset; ret=grib_get_long(h,"totalLength",&length); set->fields[set->size]->length=length; set->filter->el[set->size]=set->size; set->order->el[set->size]=set->size; set->size=set->columns[0].size; } grib_handle_delete(h); } if (h) grib_handle_delete(h); grib_file_close(file->name,&err); grib_fieldset_rewind(set); return ret; } static int grib_fieldset_resize(grib_fieldset* set,size_t newsize) { int err=0; err=grib_fieldset_resize_fields(set,newsize); if (err != 0) return err; grib_fieldset_resize_int_array(set->order,newsize); if (err != 0) return err; grib_fieldset_resize_int_array(set->filter,newsize); if (err != 0) return err; set->fields_array_size=newsize; return GRIB_SUCCESS; } void grib_fieldset_rewind(grib_fieldset* set) { if (set) set->current=0; } grib_handle* grib_fieldset_next_handle(grib_fieldset* set,int* err) { grib_handle* h; *err=GRIB_SUCCESS; h=grib_fieldset_retrieve(set,set->current,err); if (*err==GRIB_SUCCESS) { set->current++; } return h; } int grib_fieldset_count(grib_fieldset* set) { return set->size; } grib_handle* grib_fieldset_retrieve(grib_fieldset* set,int i,int* err) { grib_handle* h=0; grib_field* field=0; *err=GRIB_SUCCESS; if ( !set ) { *err=GRIB_INVALID_ARGUMENT; return NULL; } if (i >= set->size) return NULL; field=set->fields[set->filter->el[set->order->el[i]]]; grib_file_open(field->file->name,"r",err); if (*err!=GRIB_SUCCESS) return NULL; fseeko(field->file->handle,field->offset,SEEK_SET); h=grib_handle_new_from_file(set->context,field->file->handle,err); if (*err!=GRIB_SUCCESS) return NULL; grib_file_close(field->file->name,err); return h; } static grib_int_array* grib_fieldset_create_int_array(grib_context* c,size_t size) { grib_int_array* a; int i=0; if (!c) c=grib_context_get_default(); a=(grib_int_array*)grib_context_malloc_clear(c,sizeof(grib_int_array)); if (!a) { grib_context_log(c, GRIB_LOG_ERROR, "grib_fieldset_create_int_array : Cannot malloc %d bytes", sizeof(grib_int_array)); return NULL; } a->el=(int*)grib_context_malloc_clear(c,sizeof(int)*size); if (!a->el) { grib_context_log(c, GRIB_LOG_ERROR, "grib_fieldset_create_int_array : Cannot malloc %d bytes", sizeof(int)*size); return NULL; } a->size=size; a->context=c; for (i=0;iel[i]=i; return a; } static int grib_fieldset_resize_int_array(grib_int_array* a,size_t newsize) { int* el; int err=0; if (!a) return GRIB_INVALID_ARGUMENT; newsize=newsize*sizeof(int); el=(int*)grib_context_realloc(a->context,a->el,newsize); if (!el) { grib_context_log(a->context, GRIB_LOG_ERROR, "grib_fieldset_resize_int_array : Cannot malloc %d bytes", newsize); return GRIB_OUT_OF_MEMORY; } else a->el=el; a->size=newsize; return err; } static void grib_fieldset_delete_int_array(grib_int_array* f) { grib_context* c=f->context; if (!f) return; grib_context_free(c,f->el); grib_context_free(c,f); } static grib_field** grib_fieldset_create_fields(grib_context* c,size_t size) { int i; grib_field** fields=(grib_field**)grib_context_malloc_clear(c,size*sizeof(grib_field*)); if (!fields) return NULL; for (i=0;icontext,set->fields,newsize*sizeof(grib_field*)); if (!fields) { grib_context_log(set->context, GRIB_LOG_ERROR, "grib_fieldset_resize_fields : Cannot malloc %d bytes", newsize*sizeof(grib_field*)); return GRIB_OUT_OF_MEMORY; } else set->fields=fields; for (i=set->fields_array_size;ifields[i]=0; set->fields_array_size=newsize; return err; } static void grib_fieldset_delete_fields(grib_fieldset* set) { int i; for (i=0;isize;i++) { if (!set->fields[i]) continue; set->fields[i]->file->refcount--; grib_context_free(set->context,set->fields[i]); } grib_context_free(set->context,set->fields); } static void grib_trim(char** x) { char* p=0; while (**x == ' ' && **x != '\0' ) (*x)++; if (**x == '\0') return; p=(*x)+strlen(*x)-1; while ( *p == ' ' ) {*p='\0';p--;} if ( *p == ' ' ) *p='\0'; } static int grib_fieldset_set_order_by(grib_fieldset* set,grib_order_by* ob) { grib_order_by* next=ob; char* p=NULL; int i=0; while(next) { next->idkey=-1; p=next->key; while (*p!= 0 && *p != ':') p++; if (*p ==':') *p=0; for (i=0;icolumns_size; i++) { if (!grib_inline_strcmp(next->key,set->columns[i].name)) { next->idkey=i; break; } } if (next->idkey == -1) { grib_context_log(set->context,GRIB_LOG_ERROR, "Unable to apply the order by. Key missing from the fieldset.\n"); return GRIB_MISSING_KEY; } next=next->next; } set->order_by=ob; return GRIB_SUCCESS; }