diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f0ffa8a00..e8af938f7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -216,6 +216,7 @@ list( APPEND grib_api_srcs grib_dumper_class_debug.c grib_dumper_class_default.c grib_dumper_class_keys.c + grib_dumper_class_json.c grib_dumper_class_c_code.c grib_dumper_class_wmo.c grib_dumper_class.c diff --git a/src/Makefile.am b/src/Makefile.am index 2c406cc6c..7029f96fe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -229,6 +229,7 @@ libgrib_api_la_prototypes= \ grib_dumper_class_debug.c \ grib_dumper_class_default.c \ grib_dumper_class_keys.c \ + grib_dumper_class_json.c \ grib_dumper_class_c_code.c \ grib_dumper_class_wmo.c \ grib_dumper_class.c \ diff --git a/src/grib_api_prototypes.h b/src/grib_api_prototypes.h index 40f0af6ed..80ef49fe4 100644 --- a/src/grib_api_prototypes.h +++ b/src/grib_api_prototypes.h @@ -662,6 +662,8 @@ void grib_dump_footer(grib_dumper *d, grib_handle *h); /* grib_dumper_class_keys.c */ +/* grib_dumper_class_json.c */ + /* grib_dumper_class_c_code.c */ /* grib_dumper_class_wmo.c */ diff --git a/src/grib_dumper_class.h b/src/grib_dumper_class.h index e49908af4..5307ce8e0 100644 --- a/src/grib_dumper_class.h +++ b/src/grib_dumper_class.h @@ -4,6 +4,7 @@ extern grib_dumper_class* grib_dumper_class_compare; extern grib_dumper_class* grib_dumper_class_debug; extern grib_dumper_class* grib_dumper_class_default; extern grib_dumper_class* grib_dumper_class_file; +extern grib_dumper_class* grib_dumper_class_json; extern grib_dumper_class* grib_dumper_class_keys; extern grib_dumper_class* grib_dumper_class_serialize; extern grib_dumper_class* grib_dumper_class_string; diff --git a/src/grib_dumper_class_json.c b/src/grib_dumper_class_json.c new file mode 100644 index 000000000..a1e0b1e56 --- /dev/null +++ b/src/grib_dumper_class_json.c @@ -0,0 +1,319 @@ +/* + * Copyright 2005-2012 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * + * In applying this licence, ECMWF does not waive the privileges and immunities granted to it by + * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction. + */ + +#include "grib_api_internal.h" +#include +/* + This is used by make_class.pl + + START_CLASS_DEF + CLASS = dumper + IMPLEMENTS = dump_long;dump_bits + IMPLEMENTS = dump_double;dump_string + IMPLEMENTS = dump_bytes;dump_values + IMPLEMENTS = dump_label;dump_section + IMPLEMENTS = init;destroy + MEMBERS = long section_offset + MEMBERS = long begin + MEMBERS = long end + END_CLASS_DEF + + */ + + +/* START_CLASS_IMP */ + +/* + +Don't edit anything between START_CLASS_IMP and END_CLASS_IMP +Instead edit values between START_CLASS_DEF and END_CLASS_DEF +or edit "dumper.class" and rerun ./make_class.pl + +*/ + +static void init_class (grib_dumper_class*); +static int init (grib_dumper* d); +static int destroy (grib_dumper*); +static void dump_long (grib_dumper* d, grib_accessor* a,const char* comment); +static void dump_bits (grib_dumper* d, grib_accessor* a,const char* comment); +static void dump_double (grib_dumper* d, grib_accessor* a,const char* comment); +static void dump_string (grib_dumper* d, grib_accessor* a,const char* comment); +static void dump_bytes (grib_dumper* d, grib_accessor* a,const char* comment); +static void dump_values (grib_dumper* d, grib_accessor* a); +static void dump_label (grib_dumper* d, grib_accessor* a,const char* comment); +static void dump_section (grib_dumper* d, grib_accessor* a,grib_block_of_accessors* block); + +typedef struct grib_dumper_json { + grib_dumper dumper; +/* Members defined in json */ + long section_offset; + long begin; + long end; +} grib_dumper_json; + + +static grib_dumper_class _grib_dumper_class_json = { + 0, /* super */ + "json", /* name */ + sizeof(grib_dumper_json), /* size */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* init */ + &destroy, /* free mem */ + &dump_long, /* dump long */ + &dump_double, /* dump double */ + &dump_string, /* dump string */ + &dump_label, /* dump labels */ + &dump_bytes, /* dump bytes */ + &dump_bits, /* dump bits */ + &dump_section, /* dump section */ + &dump_values, /* dump values */ + 0, /* header */ + 0, /* footer */ +}; + +grib_dumper_class* grib_dumper_class_json = &_grib_dumper_class_json; + +/* END_CLASS_IMP */ + +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 int depth=2; + +static void init_class (grib_dumper_class* c){} + +static int init(grib_dumper* d) +{ + grib_dumper_json *self = (grib_dumper_json*)d; + self->section_offset=0; + + return GRIB_SUCCESS; +} + +static int destroy (grib_dumper* d) +{ + return GRIB_SUCCESS; +} + +static void dump_values(grib_dumper* d,grib_accessor* a) +{ + grib_dumper_json *self = (grib_dumper_json*)d; + double value; size_t size = 1; + double *values=NULL; + int err = 0; + int i,tab; + long more=0; + long count=0; + int mydepth=depth+2; + + count=grib_value_count(a); + size=count; + + if ( (a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0) + return; + + if (size>1) { + values=grib_context_malloc_clear(a->parent->h->context,sizeof(double)*size); + err=grib_unpack_double(a,values,&size); + } else { + err=grib_unpack_double(a,&value,&size); + } + + if(!(d->option_flags & GRIB_DUMP_FLAG_ALL_DATA) && size > 3) { + more = size - 3; + size = 3; + } else more=0; + + if (!self->begin) fprintf(self->dumper.out,",\n"); + else self->begin=0; + + if (size>1) { + int cols=4; + int count=0; + int lens=strlen(a->name); + fprintf(self->dumper.out,"%-*s",mydepth," "); + fprintf(self->dumper.out,"\"%s\" : [ ",a->name); + tab=lens+mydepth+7; + for (i=0;icols || i==0) {fprintf(self->dumper.out,"\n%-*s",tab," ");count=0;} + fprintf(self->dumper.out,"%g, ",values[i]); + count++; + } + if (count>cols) fprintf(self->dumper.out,"\n%-*s",tab," "); + fprintf(self->dumper.out,"%g ",values[i]); + if (more) + fprintf(self->dumper.out,"\n%-*s... %ld more values",tab," ",more); + + tab=lens+mydepth+5; + fprintf(self->dumper.out,"\n%-*s] ",tab," "); + grib_context_free(a->parent->h->context,values); + } else { + fprintf(self->dumper.out,"%-*s",mydepth," "); + if( ((a->flags & GRIB_ACCESSOR_FLAG_CAN_BE_MISSING) != 0) && grib_is_missing_internal(a) ) + fprintf(self->dumper.out,"\"%s\" : null",a->name); + else + fprintf(self->dumper.out,"\"%s\" : %g",a->name,value); + } + +} + +static void dump_long(grib_dumper* d,grib_accessor* a,const char* comment) +{ + grib_dumper_json *self = (grib_dumper_json*)d; + long value; size_t size = 1; + long *values=NULL; + int err = 0; + int i,tab; + long count=0; + long more=0; + int mydepth=depth+2; + + count = grib_value_count(a); + size=count; + + if ( (a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0) + return; + + if (size>1) { + values=grib_context_malloc_clear(a->parent->h->context,sizeof(long)*size); + err=grib_unpack_long(a,values,&size); + } else { + err=grib_unpack_long(a,&value,&size); + } + + if(!(d->option_flags & GRIB_DUMP_FLAG_ALL_DATA) && size > 3) { + more = size - 3; + size = 3; + } else more=0; + + if (!self->begin) fprintf(self->dumper.out,",\n"); + else self->begin=0; + + if (size>1) { + int cols=9; + int count=0; + int lens=strlen(a->name); + fprintf(self->dumper.out,"%-*s",mydepth," "); + fprintf(self->dumper.out,"\"%s\" : [ ",a->name); + tab=lens+mydepth+7; + for (i=0;icols || i==0) {fprintf(self->dumper.out,"\n%-*s",tab," ");count=0;} + fprintf(self->dumper.out,"%ld, ",values[i]); + count++; + } + if (count>cols) fprintf(self->dumper.out,"\n%-*s",tab," "); + fprintf(self->dumper.out,"%ld ",values[i]); + if (more) + fprintf(self->dumper.out,"\n%-*s... %ld more values",tab," ",more); + + tab=lens+mydepth+5; + fprintf(self->dumper.out,"\n%-*s] ",tab," "); + grib_context_free(a->parent->h->context,values); + } else { + fprintf(self->dumper.out,"%-*s",mydepth," "); + if( ((a->flags & GRIB_ACCESSOR_FLAG_CAN_BE_MISSING) != 0) && grib_is_missing_internal(a) ) + fprintf(self->dumper.out,"\"%s\" : null",a->name); + else + fprintf(self->dumper.out,"\"%s\" : %ld",a->name,value); + } + +} + +static void dump_bits(grib_dumper* d,grib_accessor* a,const char* comment) +{ +} + +static void dump_double(grib_dumper* d,grib_accessor* a,const char* comment) +{ + grib_dumper_json *self = (grib_dumper_json*)d; + double value; size_t size = 1; + int mydepth=depth+2; + + grib_unpack_double(a,&value,&size); + if ( (a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0) + return; + + if (!self->begin) fprintf(self->dumper.out,",\n"); + else self->begin=0; + + fprintf(self->dumper.out,"%-*s",mydepth," "); + if( ((a->flags & GRIB_ACCESSOR_FLAG_CAN_BE_MISSING) != 0) && grib_is_missing_internal(a) ) + fprintf(self->dumper.out,"\"%s\" : null",a->name); + else + fprintf(self->dumper.out,"\"%s\" : %g",a->name,value); + +} + +static void dump_string(grib_dumper* d,grib_accessor* a,const char* comment) +{ + grib_dumper_json *self = (grib_dumper_json*)d; + char *value=NULL; + char *p = NULL; + size_t size = 0; + grib_context* c=NULL; + int err = grib_get_string_length(a->parent->h,a->name,&size); + int mydepth=depth+2; + + c=a->parent->h->context; + if (size==0) return; + + if ( (a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0) + return; + + value=grib_context_malloc_clear(c,size); + if (!value) { + grib_context_log(c,GRIB_LOG_FATAL,"unable to allocate %d bytes",(int)size); + return; + } + + if (!self->begin) fprintf(self->dumper.out,",\n"); + else self->begin=0; + + err = grib_unpack_string(a,value,&size); + p=value; + + while(*p) { if(!isprint(*p)) *p = '.'; p++; } + + fprintf(self->dumper.out,"%-*s",mydepth," "); + if( ((a->flags & GRIB_ACCESSOR_FLAG_CAN_BE_MISSING) != 0) && grib_is_missing_internal(a) ) + fprintf(self->dumper.out,"\"%s\" : null",a->name); + else + fprintf(self->dumper.out,"\"%s\" : \"%s\"",a->name,value); + + grib_context_free(c,value); +} + +static void dump_bytes(grib_dumper* d,grib_accessor* a,const char* comment) +{ +} + +static void dump_label(grib_dumper* d,grib_accessor* a,const char* comment) +{ +} + +static void dump_section(grib_dumper* d,grib_accessor* a,grib_block_of_accessors* block) +{ + grib_dumper_json *self = (grib_dumper_json*)d; + + if ( !grib_inline_strcmp(a->name,"GRIB") ) { + fprintf(self->dumper.out,"{\n"); + self->begin=1; + grib_dump_accessors_block(d,block); + fprintf(self->dumper.out,"\n}\n"); + } + else { + grib_dump_accessors_block(d,block); + } +} + diff --git a/src/grib_dumper_factory.h b/src/grib_dumper_factory.h index f1be3862f..edad83d7d 100644 --- a/src/grib_dumper_factory.h +++ b/src/grib_dumper_factory.h @@ -2,6 +2,7 @@ { "c_code", &grib_dumper_class_c_code, }, { "debug", &grib_dumper_class_debug, }, { "default", &grib_dumper_class_default, }, +{ "json", &grib_dumper_class_json, }, { "keys", &grib_dumper_class_keys, }, { "serialize", &grib_dumper_class_serialize, }, { "wmo", &grib_dumper_class_wmo, }, diff --git a/tools/grib_dump.c b/tools/grib_dump.c index c7273d69d..4658eb2d8 100644 --- a/tools/grib_dump.c +++ b/tools/grib_dump.c @@ -21,6 +21,7 @@ grib_option grib_options[]={ {"O",0,"Octet mode. WMO documentation style dump.\n",0,1,0}, {"D",0,0,0,1,0}, {"d",0,"Print all data values.\n",0,1,0}, + {"j",0,0,0,1,0}, {"C",0,0,0,1,0}, {"t",0,0,0,1,0}, {"H",0,0,0,1,0}, @@ -39,6 +40,7 @@ grib_option grib_options[]={ char* grib_tool_description="Dump the content of a grib file in different formats."; char* grib_tool_name="grib_dump"; char* grib_tool_usage="[options] grib_file grib_file ..."; +static int json=0; int grib_options_count=sizeof(grib_options)/sizeof(grib_option); @@ -55,15 +57,20 @@ int grib_tool_before_getopt(grib_runtime_options* options) { int grib_tool_init(grib_runtime_options* options) { - int opt=grib_options_on("C")+grib_options_on("O")+grib_options_on("D"); + int opt=grib_options_on("C")+grib_options_on("O")+grib_options_on("D")+grib_options_on("j"); options->dump_mode = "default"; if (opt > 1) { - printf("%s: simultaneous C/O/D options not allowed\n",grib_tool_name); + printf("%s: simultaneous j/C/O/D options not allowed\n",grib_tool_name); exit(1); } + if (grib_options_on("j")) { + options->dump_mode = "json"; + json=1; + } + if (grib_options_on("C")) { options->dump_mode = "c_code"; if (grib_options_on("d")) @@ -108,6 +115,7 @@ int grib_tool_new_filename_action(grib_runtime_options* options,const char* file int grib_tool_new_file_action(grib_runtime_options* options,grib_tools_file* file) { char tmp[1024]; if (!options->current_infile->name) return 0; + if (json) return 0; sprintf(tmp,"FILE: %s ",options->current_infile->name); if (!grib_options_on("C")) fprintf(stdout,"***** %s\n",tmp); @@ -132,12 +140,16 @@ int grib_tool_new_handle_action(grib_runtime_options* options, grib_handle* h) { for (i=0;iprint_keys_count;i++) grib_set_flag(h,options->print_keys[i].name,GRIB_ACCESSOR_FLAG_DUMP); + if(json) { + } + else { sprintf(tmp,"MESSAGE %d ( length=%ld )",options->handle_count,length); if (!grib_options_on("C")) fprintf(stdout,"#============== %-38s ==============\n",tmp); if (!strcmp(options->dump_mode,"default")) { GRIB_CHECK_NOLINE(grib_get_string(h,"identifier",identifier,&idlen),0); printf("%s {\n",identifier); + } } grib_dump_content(h,stdout,options->dump_mode,options->dump_flags,0); diff --git a/tools/grib_options.c b/tools/grib_options.c index 28ae9279f..85f4e3368 100644 --- a/tools/grib_options.c +++ b/tools/grib_options.c @@ -43,6 +43,7 @@ grib_options_help grib_options_help_list[] ={ {"G",0,"GRIBEX compatibility mode.\n"}, {"i:","index", "\n\t\tData value corresponding to the given index is printed.\n"}, + {"j",0,"JSON mode (JavaScript Object Notation).\n"}, {"l:","Latitude,Longitude[,MODE,file]", "\n\t\tValue close to the point of a Latitude/Longitude." "\n\t\tAllowed values for MODE are:"