2014-07-06 13:18:40 +00:00
|
|
|
/*
|
2018-01-02 11:31:02 +00:00
|
|
|
* Copyright 2005-2018 ECMWF.
|
2014-07-06 13:18:40 +00:00
|
|
|
*
|
|
|
|
* 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_tools.h"
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
GRIB_INLINE static int grib_inline_strcmp(const char* a,const char* b)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
if (*a != *b) return 1;
|
|
|
|
while((*a!=0 && *b!=0) && *(a) == *(b) ) {a++;b++;}
|
|
|
|
return (*a==0 && *b==0) ? 0 : 1;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
GRIB_INLINE static int grib_inline_rstrcmp(const char* a,const char* b)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
char* p=(char*)a;
|
|
|
|
char* q=(char*)b;
|
|
|
|
while (*p != 0) p++;
|
|
|
|
while (*q != 0) q++;
|
|
|
|
q--;p--;
|
|
|
|
if (*q != *p) return 1;
|
|
|
|
while((p!=a && q!=b) && *(p) == *(q) ) {p--;q--;}
|
|
|
|
return (q==b) ? 0 : 1;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef double (*compare_double_proc) (double*,double*,double*);
|
|
|
|
|
|
|
|
typedef struct grib_error grib_error;
|
|
|
|
struct grib_error {
|
2015-01-31 21:58:30 +00:00
|
|
|
char* key;
|
|
|
|
int count;
|
|
|
|
grib_error* next;
|
2014-07-06 13:18:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
grib_error* error_summary;
|
|
|
|
|
|
|
|
compare_double_proc compare_double;
|
|
|
|
double global_tolerance=0;
|
|
|
|
int packingCompare=0;
|
|
|
|
grib_string_list* blacklist=0;
|
2016-08-11 15:35:03 +00:00
|
|
|
grib_string_list* keys_list = NULL; /* Used to determine rank of key */
|
2016-08-11 17:38:51 +00:00
|
|
|
int isLeafKey = 0; /* 0 if key is top-level, 1 if key has no children attributes */
|
2014-07-06 13:18:40 +00:00
|
|
|
int compareAbsolute=1;
|
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
static int compare_handles(grib_handle* handle1, grib_handle* handle2, grib_runtime_options* options);
|
|
|
|
static int compare_values(grib_runtime_options* options, grib_handle* handle1, grib_handle *handle2, const char *name, int type);
|
2016-08-11 17:38:51 +00:00
|
|
|
static int compare_attributes(grib_handle* handle1, grib_handle* handle2, grib_runtime_options* options,
|
|
|
|
grib_accessor* a, const char* prefix, int* err);
|
|
|
|
static int compare_attribute(grib_handle* handle1, grib_handle* handle2, grib_runtime_options* options,
|
|
|
|
grib_accessor* a, const char* prefix, int* err);
|
|
|
|
|
2014-07-06 13:18:40 +00:00
|
|
|
int error=0;
|
|
|
|
int count=0;
|
|
|
|
int lastPrint=0;
|
|
|
|
int force=0;
|
2018-03-12 15:51:04 +00:00
|
|
|
|
2018-03-13 15:56:11 +00:00
|
|
|
/* ECC-651: Boolean 'two_way' set to 1 when '-2' option used */
|
|
|
|
int two_way=0;
|
|
|
|
/* Boolean 'handles_swapped' relevant in 'two_way' mode:
|
2018-03-12 15:51:04 +00:00
|
|
|
* 0 means: h1 is first file, h2 is second file
|
|
|
|
* 1 means: h1 is second file, h2 is first file
|
|
|
|
*/
|
|
|
|
int handles_swapped=0;
|
|
|
|
|
2014-07-06 13:18:40 +00:00
|
|
|
double maxAbsoluteError = 1e-19;
|
|
|
|
int onlyListed=1;
|
|
|
|
int headerMode=0;
|
|
|
|
int morein1=0;
|
|
|
|
int morein2=0;
|
|
|
|
int listFromCommandLine;
|
|
|
|
int verbose=0;
|
|
|
|
int tolerance_factor=1;
|
|
|
|
static int write_error=0;
|
|
|
|
|
2016-08-11 15:35:03 +00:00
|
|
|
/* Create the list of keys (global variable keys_list) */
|
|
|
|
static void new_keys_list()
|
|
|
|
{
|
|
|
|
grib_context* c = grib_context_get_default();
|
2017-06-21 18:21:58 +00:00
|
|
|
keys_list=(grib_string_list*)grib_context_malloc_clear(c, sizeof(grib_string_list));
|
2016-08-11 15:35:03 +00:00
|
|
|
if (!keys_list) {
|
|
|
|
fprintf(stderr, "Failed to allocate memory for keys list");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free the keys list (global variable keys_list) */
|
|
|
|
static void release_keys_list()
|
|
|
|
{
|
|
|
|
grib_string_list* next=keys_list;
|
|
|
|
grib_string_list* cur=keys_list;
|
|
|
|
grib_context* c = grib_context_get_default();
|
|
|
|
while(next) {
|
|
|
|
cur=next;
|
|
|
|
next=next->next;
|
|
|
|
grib_context_free(c,cur->value);
|
|
|
|
grib_context_free(c,cur);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
GRIB_INLINE static double compare_double_absolute(double *a,double *b,double *err)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
double ret=0;
|
|
|
|
double d=fabs(*a-*b);
|
|
|
|
if (d > *err) {
|
|
|
|
ret=d;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
/* return fabs(*a-*b) > *err ? fabs(*a-*b) : 0; */
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int write_count=0;
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
static void write_message(grib_handle* h,const char* str)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
const void *m; size_t s;
|
|
|
|
char fname[1024]={0,};
|
2018-11-01 12:55:47 +00:00
|
|
|
FILE* fh;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
grib_get_message(h,&m,&s);
|
|
|
|
sprintf(fname,"%s_%d.bufr",str,write_count);
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
fh= fopen(fname,"w");
|
|
|
|
if(!fh) {
|
|
|
|
grib_context_log(h->context,(GRIB_LOG_ERROR)|(GRIB_LOG_PERROR),
|
|
|
|
"Error opening %s",fname);
|
|
|
|
exit(GRIB_IO_PROBLEM);
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if(fwrite(m,1,s,fh) != s) {
|
|
|
|
grib_context_log(h->context,(GRIB_LOG_ERROR)|(GRIB_LOG_PERROR),
|
|
|
|
"Error writing to %s",fname);
|
|
|
|
exit(GRIB_IO_PROBLEM);
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
fclose(fh);
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
static void write_messages(grib_handle* handle1, grib_handle* handle2)
|
2015-02-06 13:54:49 +00:00
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
if (!write_error) return;
|
|
|
|
write_count++;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
write_message(handle1,"error1");
|
|
|
|
write_message(handle2,"error2");
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
static double compare_double_relative(double *a,double *b,double *err)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
double relativeError;
|
|
|
|
|
|
|
|
if(fabs(*a) <= maxAbsoluteError || fabs(*b) <= maxAbsoluteError)
|
|
|
|
relativeError = fabs(*a-*b);
|
|
|
|
else if (fabs(*b) > fabs(*a))
|
|
|
|
relativeError = fabs((*a-*b) / *b);
|
|
|
|
else
|
|
|
|
relativeError = fabs((*a-*b) / *a);
|
|
|
|
|
|
|
|
return relativeError > *err ? relativeError : 0;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
static int blacklisted(const char* name)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
grib_string_list* b=blacklist;
|
|
|
|
while (b) {
|
2015-02-06 13:54:49 +00:00
|
|
|
Assert(b->value);
|
2015-01-31 21:58:30 +00:00
|
|
|
if (!strcmp(name,b->value))
|
|
|
|
return 1;
|
|
|
|
b=b->next;
|
|
|
|
}
|
|
|
|
return 0;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
static double relative_error(double a,double b,double err)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
double relativeError;
|
|
|
|
|
|
|
|
if(fabs(a) <= maxAbsoluteError || fabs(b) <= maxAbsoluteError)
|
|
|
|
relativeError = fabs(a-b);
|
|
|
|
else if (fabs(b) > fabs(a))
|
|
|
|
relativeError = fabs((a-b) / b);
|
|
|
|
else
|
|
|
|
relativeError = fabs((a-b) / a);
|
|
|
|
|
|
|
|
return relativeError ;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
grib_option grib_options[]={
|
2016-08-10 12:54:43 +00:00
|
|
|
/* {id, args, help}, on, command_line, value*/
|
|
|
|
/*{"r",0,"Compare files in which the messages are not in the same order. This option is time expensive.\n",0,1,0},*/
|
|
|
|
{"b:",0,0,0,1,0},
|
2018-03-12 15:51:04 +00:00
|
|
|
{"d",0,"Write different messages on files.\n",0,1,0},
|
|
|
|
{"2",0,"Enable two-way comparison.\n",0,1,0},
|
2016-08-10 12:54:43 +00:00
|
|
|
{"T:",0,0,1,0,"B"},
|
|
|
|
{"c:",0,0,0,1,0},
|
|
|
|
{"S:","start","First field to be processed.\n",0,1,0},
|
|
|
|
{"E:","end","Last field to be processed.\n",0,1,0},
|
|
|
|
{"a",0,"-c option modifier. The keys listed with the option -c will be added to the list of keys compared without -c.\n"
|
2015-01-31 21:58:30 +00:00
|
|
|
,0,1,0},
|
2016-08-10 12:54:43 +00:00
|
|
|
{"H",0,"Compare only message headers. Bit-by-bit compare on. Incompatible with -c option.\n",0,1,0},
|
|
|
|
{"R:",0,0,0,1,0},
|
|
|
|
{"A:",0,0,0,1,0},
|
2017-02-10 10:58:54 +00:00
|
|
|
/* {"P",0,"Compare data values using the packing error as tolerance.\n",0,1,0},*/
|
2016-08-10 12:54:43 +00:00
|
|
|
{"t:","factor","Compare data values using factor multiplied by the tolerance specified in options -P -R -A.\n",0,1,0},
|
|
|
|
{"w:",0,0,0,1,0},
|
|
|
|
{"f",0,0,0,1,0},
|
|
|
|
{"F",0,0,1,0,0},
|
|
|
|
{"q",0,0,1,0,0},
|
|
|
|
{"M",0,0,1,0,0},
|
|
|
|
{"I",0,0,1,0,0},
|
|
|
|
{"V",0,0,0,1,0},
|
|
|
|
{"7",0,0,0,1,0},
|
|
|
|
{"v",0,0,0,1,0}
|
2014-07-06 13:18:40 +00:00
|
|
|
};
|
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
grib_handle* global_handle=NULL;
|
2014-07-06 13:18:40 +00:00
|
|
|
int counter=0;
|
|
|
|
int start=-1;
|
|
|
|
int end=-1;
|
|
|
|
|
2018-08-07 12:50:41 +00:00
|
|
|
const char* grib_tool_description=
|
2016-08-04 10:07:00 +00:00
|
|
|
"Compare BUFR messages contained in two files."
|
|
|
|
"\n\tIf some differences are found it fails returning an error code."
|
2018-08-17 16:18:38 +00:00
|
|
|
"\n\tFloating-point values are compared exactly by default, different tolerance can be defined see -P -A -R."
|
2016-08-04 10:07:00 +00:00
|
|
|
"\n\tDefault behaviour: absolute error=0, bit-by-bit compare, same order in files.";
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2018-08-07 12:50:41 +00:00
|
|
|
const char* grib_tool_name="bufr_compare";
|
|
|
|
const char* grib_tool_usage="[options] bufr_file1 bufr_file2";
|
2014-07-06 13:18:40 +00:00
|
|
|
|
|
|
|
int grib_options_count=sizeof(grib_options)/sizeof(grib_option);
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
return grib_tool(argc,argv);
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
int grib_tool_before_getopt(grib_runtime_options* options)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
return 0;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
int grib_tool_init(grib_runtime_options* options)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
int ret=0,i;
|
|
|
|
int nfiles=1;
|
|
|
|
char orderby[]="md5Headers";
|
|
|
|
grib_context* context=grib_context_get_default();
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
options->strict=1;
|
|
|
|
if (grib_options_on("S:"))
|
|
|
|
start=atoi(grib_options_get_option("S:"));
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (grib_options_on("E:"))
|
|
|
|
end=atoi(grib_options_get_option("E:"));
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (grib_options_on("f")) force=1;
|
|
|
|
else force=0;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2018-03-12 15:51:04 +00:00
|
|
|
if (grib_options_on("2")) two_way=1;
|
|
|
|
else two_way=0;
|
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (grib_options_on("d")) write_error=1;
|
|
|
|
else write_error=0;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
verbose = grib_options_on("v");
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
listFromCommandLine=0;
|
|
|
|
if (grib_options_on("c:") || grib_options_on("e"))
|
|
|
|
listFromCommandLine=1;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (grib_options_on("a")) onlyListed=0;
|
|
|
|
else onlyListed=1;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (grib_options_on("H")) headerMode=1;
|
|
|
|
else headerMode=0;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (grib_options_on("H") && grib_options_on("c:")) {
|
2016-08-05 17:38:47 +00:00
|
|
|
fprintf(stderr,"Error: -H and -c options are incompatible. Choose one of the two please.\n");
|
2015-01-31 21:58:30 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (grib_options_on("a") && !grib_options_on("c:")) {
|
2016-08-05 17:38:47 +00:00
|
|
|
fprintf(stderr,"Error: -a option requires -c option. Please define a list of keys with the -c option.\n");
|
2015-01-31 21:58:30 +00:00
|
|
|
exit(1);
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (grib_options_on("b:")) {
|
|
|
|
grib_string_list *next=0;
|
2016-04-14 11:11:48 +00:00
|
|
|
int ii=0;
|
2015-01-31 21:58:30 +00:00
|
|
|
blacklist=(grib_string_list*)grib_context_malloc_clear(context,sizeof(grib_string_list));
|
|
|
|
blacklist->value=grib_context_strdup(context,options->set_values[0].name);
|
|
|
|
next=blacklist;
|
2016-04-14 11:11:48 +00:00
|
|
|
for (ii=1;ii<options->set_values_count;ii++) {
|
2015-01-31 21:58:30 +00:00
|
|
|
next->next=(grib_string_list*)grib_context_malloc_clear(context,sizeof(grib_string_list));
|
2016-04-14 11:11:48 +00:00
|
|
|
next->next->value=grib_context_strdup(context,options->set_values[ii].name);
|
2015-01-31 21:58:30 +00:00
|
|
|
next=next->next;
|
|
|
|
}
|
|
|
|
context->blacklist=blacklist;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (grib_options_on("r")) {
|
|
|
|
char* filename[1];
|
|
|
|
filename[0]=options->infile_extra->name;
|
|
|
|
options->random=1;
|
|
|
|
options->orderby=strdup(orderby);
|
|
|
|
options->idx=grib_fieldset_new_from_files(context,filename,
|
|
|
|
nfiles,0,0,0,orderby,&ret);
|
|
|
|
if (ret) {
|
2016-08-05 17:38:47 +00:00
|
|
|
fprintf(stderr,"unable to create index for input file %s (%s)",
|
|
|
|
options->infile_extra->name, grib_get_error_message(ret));
|
2015-01-31 21:58:30 +00:00
|
|
|
exit(ret);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
options->random=0;
|
|
|
|
options->infile_extra->file=fopen(options->infile_extra->name,"r");
|
|
|
|
|
|
|
|
if (!options->infile_extra->file) {
|
|
|
|
perror(options->infile_extra->name);
|
|
|
|
exit(1);
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
global_tolerance=0;
|
2015-01-31 21:58:30 +00:00
|
|
|
compare_double= &compare_double_absolute;
|
2014-07-06 13:18:40 +00:00
|
|
|
if (grib_options_on("R:")) {
|
2015-01-31 21:58:30 +00:00
|
|
|
global_tolerance=0;
|
|
|
|
for (i=0;i<options->tolerance_count;i++) {
|
|
|
|
if (!strcmp((options->tolerance[i]).name,"all")) {
|
|
|
|
global_tolerance=(options->tolerance[i]).double_value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!strcmp((options->tolerance[i]).name,"global")) {
|
|
|
|
global_tolerance=(options->tolerance[i]).double_value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
compare_double= &compare_double_relative;
|
|
|
|
compareAbsolute=0;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
if (grib_options_on("A:")){
|
|
|
|
if (grib_options_on("R:")) {
|
|
|
|
maxAbsoluteError = atof(grib_options_get_option("A:"));
|
|
|
|
} else {
|
|
|
|
compare_double= &compare_double_absolute;
|
|
|
|
global_tolerance = atof(grib_options_get_option("A:"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (grib_options_on("P")) {
|
|
|
|
packingCompare=1;
|
|
|
|
compare_double= &compare_double_absolute;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grib_options_on("t:"))
|
|
|
|
tolerance_factor=atof(grib_options_get_option("t:"));
|
|
|
|
|
2016-07-05 14:44:55 +00:00
|
|
|
if (grib_options_on("R:")) {
|
|
|
|
char* sarg=grib_options_get_option("R:");
|
|
|
|
options->tolerance_count=MAX_KEYS;
|
|
|
|
ret=parse_keyval_string(grib_tool_name, sarg,1,GRIB_TYPE_DOUBLE,options->tolerance,&(options->tolerance_count));
|
|
|
|
if (ret == GRIB_INVALID_ARGUMENT) {
|
|
|
|
usage();
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-17 10:23:43 +00:00
|
|
|
{
|
|
|
|
/* Check for 2nd file being a directory. If so, we assume user is comparing to a file */
|
|
|
|
/* with the same name as first file in that directory */
|
|
|
|
struct stat s;
|
|
|
|
grib_tools_file* infile = options->infile; /* the 2nd file in comparison */
|
|
|
|
if (infile) {
|
|
|
|
int stat_val = stat(infile->name, &s);
|
|
|
|
if ( stat_val == 0 && S_ISDIR(s.st_mode)) {
|
|
|
|
/* Take the filename of the 1st file and append to dir */
|
|
|
|
char bufr[2048] = {0,};
|
|
|
|
/* options->infile_extra->name is the 1st file */
|
2015-07-24 14:00:28 +00:00
|
|
|
sprintf(bufr, "%s%c%s",
|
2015-07-27 12:27:03 +00:00
|
|
|
infile->name,
|
|
|
|
get_dir_separator_char(),
|
|
|
|
extract_filename(options->infile_extra->name));
|
2015-07-17 10:23:43 +00:00
|
|
|
infile->name = strdup(bufr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-08-31 08:58:24 +00:00
|
|
|
/* Turn off GRIB multi-field support mode. Not relevant for BUFR */
|
|
|
|
grib_multi_support_off(grib_context_get_default());
|
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
return 0;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2016-08-04 10:07:00 +00:00
|
|
|
int grib_tool_new_filename_action(grib_runtime_options* options,const char* file)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
return 0;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
2016-08-04 10:07:00 +00:00
|
|
|
|
|
|
|
int grib_tool_new_file_action(grib_runtime_options* options,grib_tools_file* file)
|
|
|
|
{
|
2018-09-07 16:12:24 +00:00
|
|
|
exit_if_input_is_directory(grib_tool_name, file->name);
|
2015-01-31 21:58:30 +00:00
|
|
|
return 0;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
static void printInfo(grib_handle* h)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
printf("== %d == DIFFERENCE == ",count);
|
|
|
|
lastPrint=count;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
static void print_index_key_values(grib_index* index,int icounter,const char* error_message)
|
2015-02-06 13:54:49 +00:00
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
grib_index_key* keys=index->keys;
|
2016-04-14 11:11:48 +00:00
|
|
|
printf("== %d == ",icounter);
|
2015-01-31 21:58:30 +00:00
|
|
|
if (error_message) printf("%s == ",error_message);
|
|
|
|
while (keys) {
|
|
|
|
printf("%s=%s ",keys->name,keys->value);
|
|
|
|
keys=keys->next;
|
|
|
|
}
|
|
|
|
printf("\n");
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-02-12 18:32:04 +00:00
|
|
|
static grib_handle* grib_handle_new_from_file_x(
|
|
|
|
grib_context* c,FILE* f,int mode,int headers_only,int *err)
|
2015-02-06 13:54:49 +00:00
|
|
|
{
|
2015-02-12 18:32:04 +00:00
|
|
|
return codes_handle_new_from_file(c,f,PRODUCT_BUFR,err);
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
int grib_tool_new_handle_action(grib_runtime_options* options, grib_handle* h)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
int err=0;
|
|
|
|
count++;
|
|
|
|
|
|
|
|
if (options->through_index) {
|
|
|
|
grib_index* idx1=options->index1;
|
|
|
|
verbose=0;
|
|
|
|
counter++;
|
|
|
|
|
|
|
|
if ( start>0 && counter < start ) return 0;
|
|
|
|
if ( end>0 && counter > end ) {
|
|
|
|
options->stop=1;
|
|
|
|
return 0;
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
grib_index_search_same(idx1,h);
|
2016-04-14 11:11:48 +00:00
|
|
|
global_handle=codes_new_from_index(idx1,CODES_BUFR,&err);
|
2015-01-31 21:58:30 +00:00
|
|
|
if (options->verbose) {
|
|
|
|
off_t offset=0;
|
|
|
|
char* filename=grib_get_field_file(options->index2,&offset);
|
|
|
|
printf("file1=\"%s\" ",filename);
|
|
|
|
filename=grib_get_field_file(options->index1,&offset);
|
|
|
|
printf("file2=\"%s\" \n",filename);
|
|
|
|
print_index_key_values(options->index1,counter,NULL);
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if (!global_handle) {
|
2015-01-31 21:58:30 +00:00
|
|
|
if (!options->verbose)
|
|
|
|
print_index_key_values(idx1,counter,"NOT FOUND ");
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if (!global_handle || err!= GRIB_SUCCESS ) {
|
2015-01-31 21:58:30 +00:00
|
|
|
morein1++;
|
2016-04-14 11:11:48 +00:00
|
|
|
if (global_handle) grib_handle_delete(global_handle);
|
2015-01-31 21:58:30 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if(compare_handles(h,global_handle,options)) {
|
2015-01-31 21:58:30 +00:00
|
|
|
error++;
|
|
|
|
if (!force) exit(1);
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
grib_handle_delete(global_handle);
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
return 0;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
} else if (options->random)
|
2016-04-14 11:11:48 +00:00
|
|
|
global_handle = grib_fieldset_next_handle(options->idx,&err);
|
2015-01-31 21:58:30 +00:00
|
|
|
else
|
2016-04-14 11:11:48 +00:00
|
|
|
global_handle=grib_handle_new_from_file_x(h->context,options->infile_extra->file,options->mode,0,&err);
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if (!global_handle || err!= GRIB_SUCCESS ) {
|
2015-01-31 21:58:30 +00:00
|
|
|
morein2++;
|
2016-04-14 11:11:48 +00:00
|
|
|
if (global_handle) grib_handle_delete(global_handle);
|
2015-01-31 21:58:30 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if(compare_handles(global_handle,h,options)) {
|
2015-01-31 21:58:30 +00:00
|
|
|
error++;
|
2018-03-13 15:48:00 +00:00
|
|
|
if (!two_way) {
|
|
|
|
/* If two_way mode: Don't exit yet. Show further differences */
|
|
|
|
if (!force) exit(1);
|
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
2018-03-12 15:51:04 +00:00
|
|
|
if (two_way) {
|
2018-03-13 15:56:11 +00:00
|
|
|
/* ECC-651 and ECC-431 */
|
2018-03-12 15:51:04 +00:00
|
|
|
handles_swapped = 1;
|
2018-04-12 12:34:05 +00:00
|
|
|
if (verbose) printf(" Swapping handles (two-way mode)\n");
|
2018-03-12 15:51:04 +00:00
|
|
|
if(compare_handles(h, global_handle, options)) {
|
|
|
|
error++;
|
|
|
|
if (!force) exit(1);
|
2018-03-13 15:48:00 +00:00
|
|
|
} else {
|
|
|
|
if (error) {
|
|
|
|
/* Error from first pass */
|
|
|
|
if (!force) exit(1);
|
|
|
|
}
|
2018-03-12 15:51:04 +00:00
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
grib_handle_delete(global_handle);
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
return 0;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
int grib_tool_skip_handle(grib_runtime_options* options, grib_handle* h)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
int err=0;
|
|
|
|
if (!options->through_index && !options->random) {
|
2016-04-14 11:11:48 +00:00
|
|
|
global_handle=grib_handle_new_from_file(h->context,options->infile_extra->file,&err);
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if (!global_handle || err!= GRIB_SUCCESS)
|
2015-01-31 21:58:30 +00:00
|
|
|
morein2++;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
grib_handle_delete(global_handle);
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
grib_handle_delete(h);
|
|
|
|
count++;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
return 0;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
void grib_tool_print_key_values(grib_runtime_options* options,grib_handle* h)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
grib_print_key_values(options,h);
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
int grib_tool_finalise_action(grib_runtime_options* options)
|
|
|
|
{
|
2016-08-11 15:35:03 +00:00
|
|
|
grib_error* e = error_summary;
|
2015-01-31 21:58:30 +00:00
|
|
|
int err=0;
|
|
|
|
grib_context* c=grib_context_get_default();
|
2016-08-11 15:35:03 +00:00
|
|
|
error += morein1+morein2;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
/*if (grib_options_on("w:")) return 0;*/
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
printf("\n## ERRORS SUMMARY #######\n");
|
|
|
|
}
|
2016-04-14 11:11:48 +00:00
|
|
|
while ((global_handle=grib_handle_new_from_file(c,options->infile_extra->file,&err))) {
|
2015-01-31 21:58:30 +00:00
|
|
|
morein1++;
|
2016-04-14 11:11:48 +00:00
|
|
|
if (global_handle) grib_handle_delete(global_handle);
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
|
|
|
if (morein1>0) {
|
|
|
|
printf("##\n## Different number of messages \n");
|
|
|
|
printf("## %d more messages in %s than in %s\n",morein1,
|
|
|
|
options->infile_extra->name,options->infile->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (morein2>0) {
|
|
|
|
printf("##\n## Different number of messages \n");
|
|
|
|
printf("## %d more messages in %s than in %s\n",morein2,
|
|
|
|
options->infile->name,options->infile_extra->name);
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (error) {
|
|
|
|
printf("##\n## Summary of different key values \n");
|
|
|
|
while (e) {
|
|
|
|
printf ("## %s ( %d different )\n",e->key,e->count);
|
|
|
|
e=e->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("##\n## %d different messages out of %d\n\n",error,count);
|
|
|
|
}
|
|
|
|
if (options->through_index) {
|
|
|
|
grib_index_delete(options->index1);
|
|
|
|
grib_index_delete(options->index2);
|
|
|
|
}
|
2016-08-11 15:35:03 +00:00
|
|
|
release_keys_list();
|
|
|
|
if (error != 0) exit(1);
|
2015-01-31 21:58:30 +00:00
|
|
|
return 0;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
static void save_error(grib_context* c,const char* key)
|
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
grib_error* e=0;
|
|
|
|
grib_error* next=0;
|
|
|
|
int saved=0;
|
|
|
|
|
|
|
|
if (!error_summary) {
|
|
|
|
error_summary=(grib_error*)grib_context_malloc_clear(c,sizeof(grib_error));
|
|
|
|
error_summary->count=1;
|
|
|
|
error_summary->key=grib_context_strdup(c,key);
|
|
|
|
return;
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
e=error_summary;
|
|
|
|
next=e;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
while (next) {
|
|
|
|
if (!strcmp(next->key,key)) {
|
|
|
|
next->count++;
|
|
|
|
saved=1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
e=next;
|
|
|
|
next=next->next;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (!saved) {
|
|
|
|
e->next=(grib_error*)grib_context_malloc_clear(c,sizeof(grib_error));
|
|
|
|
e->next->count=1;
|
|
|
|
e->next->key=grib_context_strdup(c,key);
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2016-11-28 18:04:06 +00:00
|
|
|
static char* double_as_string(grib_context* c, double v)
|
|
|
|
{
|
2017-06-21 18:21:58 +00:00
|
|
|
char* sval=(char*)grib_context_malloc_clear(c, sizeof(char)*40);
|
2016-11-28 18:04:06 +00:00
|
|
|
if (v == GRIB_MISSING_DOUBLE) sprintf(sval,"MISSING");
|
|
|
|
else sprintf(sval,"%.20e",v);
|
|
|
|
return sval;
|
|
|
|
}
|
2018-03-22 13:49:11 +00:00
|
|
|
|
|
|
|
/* Return the part of the key name without the '#rank#' part */
|
|
|
|
static char* get_keyname_without_rank(const char* name)
|
|
|
|
{
|
|
|
|
char* p=(char*)name;
|
|
|
|
char* end=p;
|
|
|
|
char* ret=NULL;
|
|
|
|
|
|
|
|
if (*p=='#') {
|
|
|
|
strtol(++p,&end,10);
|
|
|
|
if ( *end != '#') {
|
|
|
|
DebugAssert(!"Badly formed rank in key");
|
|
|
|
} else {
|
|
|
|
/* Take everything after 2nd '#' */
|
|
|
|
grib_context* c=grib_context_get_default();
|
|
|
|
end++;
|
|
|
|
ret=grib_context_strdup(c,end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
static int compare_values(grib_runtime_options* options, grib_handle* handle1, grib_handle *handle2, const char *name, int type)
|
2015-02-06 13:54:49 +00:00
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
size_t len1 = 0;
|
|
|
|
size_t len2 = 0;
|
|
|
|
int err=0,i=0;
|
|
|
|
int err1;
|
|
|
|
int err2;
|
|
|
|
int type1,type2;
|
|
|
|
int countdiff;
|
|
|
|
int isangle=0;
|
2015-02-09 17:04:26 +00:00
|
|
|
int isMissing1=0,isMissing2=0;
|
2015-01-31 21:58:30 +00:00
|
|
|
|
|
|
|
char *sval1 = NULL,*sval2 = NULL;
|
|
|
|
unsigned char *uval1 = NULL,*uval2 = NULL;
|
|
|
|
double *dval1 = NULL, *dval2 = NULL;
|
|
|
|
long *lval1 = NULL, *lval2 = NULL;
|
|
|
|
double maxdiff=0;
|
2015-02-06 13:54:49 +00:00
|
|
|
double packingError1=0,packingError2=0;
|
2015-01-31 21:58:30 +00:00
|
|
|
double value_tolerance=0;
|
2016-04-14 11:11:48 +00:00
|
|
|
grib_context* c=handle1->context;
|
2018-06-05 13:33:27 +00:00
|
|
|
const char* first_str = (handles_swapped==0? "1st" : "2nd");
|
|
|
|
const char* second_str = (handles_swapped==0? "2nd" : "1st");
|
2015-01-31 21:58:30 +00:00
|
|
|
|
|
|
|
type1=type;
|
|
|
|
type2=type;
|
2018-04-12 12:34:05 +00:00
|
|
|
if (verbose && !handles_swapped) printf(" comparing %s",name);
|
2015-01-31 21:58:30 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if( type1==GRIB_TYPE_UNDEFINED && (err = grib_get_native_type(handle1,name,&type1)) != GRIB_SUCCESS)
|
2015-01-31 21:58:30 +00:00
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("Oops... cannot get type of [%s] in %s field: %s\n",name, first_str, grib_get_error_message(err));
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
return err;
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if(type2==GRIB_TYPE_UNDEFINED && (err = grib_get_native_type(handle2,name,&type2)) != GRIB_SUCCESS)
|
2014-07-06 13:18:40 +00:00
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
if(err == GRIB_NOT_FOUND)
|
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("[%s] not found in %s field\n",name, second_str);
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
return err;
|
|
|
|
}
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("Oops... cannot get type of [%s] in %s field: %s\n",name, second_str, grib_get_error_message(err));
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
return err;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2016-08-05 17:38:47 +00:00
|
|
|
/* if(type1 != type2) {
|
|
|
|
printInfo(handle1);
|
|
|
|
printf("Warning, [%s] has different types: 1st field: [%s], 2nd field: [%s]\n",
|
|
|
|
name,grib_get_type_name(type1),grib_get_type_name(type2));
|
|
|
|
return GRIB_TYPE_MISMATCH;
|
|
|
|
} */
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if(type1 == GRIB_TYPE_LABEL)
|
|
|
|
return err;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if(type1 == GRIB_TYPE_SECTION)
|
|
|
|
return err;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if((err = grib_get_size(handle1,name,&len1)) != GRIB_SUCCESS)
|
2014-07-06 13:18:40 +00:00
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("Oops... cannot get size of [%s] in %s field: %s\n",name, first_str, grib_get_error_message(err));
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
return err;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if((err = grib_get_size(handle2,name,&len2)) != GRIB_SUCCESS)
|
2015-01-31 21:58:30 +00:00
|
|
|
{
|
|
|
|
if(err == GRIB_NOT_FOUND)
|
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("[%s] not found in %s field\n",name,second_str);
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("Oops... cannot get size of [%s] in %s field: %s\n",name, second_str, grib_get_error_message(err));
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
return err;
|
|
|
|
}
|
2018-03-12 15:51:04 +00:00
|
|
|
|
|
|
|
if (handles_swapped) {
|
|
|
|
/* Comparing a second time with handles swapped. Do not compare keys common to both handles */
|
|
|
|
return GRIB_SUCCESS;
|
|
|
|
}
|
2016-08-05 17:38:47 +00:00
|
|
|
/* if(len1 != len2 && type1 != GRIB_TYPE_STRING) {
|
|
|
|
printInfo(handle1);
|
|
|
|
printf("[%s] has different size: 1st field: %ld, 2nd field: %ld\n",name,(long)len1,(long)len2);
|
|
|
|
save_error(c,name);
|
|
|
|
return GRIB_COUNT_MISMATCH;
|
|
|
|
} */
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-02-09 17:04:26 +00:00
|
|
|
if (options->mode != MODE_BUFR) {
|
|
|
|
/* TODO: Ignore missing values for keys in BUFR. Not yet implemented */
|
2016-04-14 11:11:48 +00:00
|
|
|
isMissing1= ( (grib_is_missing(handle1,name,&err1)==1) && (err1 == 0) ) ? 1 : 0;
|
|
|
|
isMissing2= ( (grib_is_missing(handle2,name,&err2)==1) && (err2 == 0) ) ? 1 : 0;
|
2015-02-09 17:04:26 +00:00
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if ((isMissing1==1) && (isMissing2==1)) {
|
|
|
|
if (verbose) printf(" is set to missing in both fields\n");
|
|
|
|
return GRIB_SUCCESS;
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (isMissing1==1) {
|
2018-03-12 15:51:04 +00:00
|
|
|
if (verbose) printf(" is set to missing in %s field\n", first_str);
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("%s is set to missing in %s field is not missing in %s field\n",name,first_str,second_str);
|
2015-01-31 21:58:30 +00:00
|
|
|
err1 = GRIB_VALUE_MISMATCH;
|
2014-07-06 13:18:40 +00:00
|
|
|
save_error(c,name);
|
2015-01-31 21:58:30 +00:00
|
|
|
return GRIB_VALUE_MISMATCH;
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (isMissing2==1) {
|
2018-03-12 15:51:04 +00:00
|
|
|
if (verbose) printf(" is set to missing in %s field\n", first_str);
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("%s is set to missing in %s field is not missing in %s field\n",name, second_str, first_str);
|
2015-01-31 21:58:30 +00:00
|
|
|
err1 = GRIB_VALUE_MISMATCH;
|
2014-07-06 13:18:40 +00:00
|
|
|
save_error(c,name);
|
2015-01-31 21:58:30 +00:00
|
|
|
return GRIB_VALUE_MISMATCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(type1)
|
|
|
|
{
|
|
|
|
case GRIB_TYPE_STRING:
|
|
|
|
if (verbose) printf(" as string\n");
|
2018-06-29 14:21:10 +00:00
|
|
|
/* See ECC-710: It is very slow getting the key length this way */
|
|
|
|
/*grib_get_string_length(handle1,name,&len1);*/
|
|
|
|
/*grib_get_string_length(handle2,name,&len2);*/
|
|
|
|
len1 = len2 = 4096; /* Significantly faster to use an upper bound */
|
2016-04-14 11:11:48 +00:00
|
|
|
sval1 = (char*)grib_context_malloc(handle1->context,len1*sizeof(char));
|
|
|
|
sval2 = (char*)grib_context_malloc(handle2->context,len2*sizeof(char));
|
2015-01-31 21:58:30 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if((err1 = grib_get_string(handle1,name,sval1,&len1)) != GRIB_SUCCESS)
|
2015-01-31 21:58:30 +00:00
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("Oops... cannot get string value of [%s] in %s field: %s\n",
|
|
|
|
name, first_str, grib_get_error_message(err1));
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if((err2 = grib_get_string(handle2,name,sval2,&len2)) != GRIB_SUCCESS)
|
2014-07-06 13:18:40 +00:00
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("Oops... cannot get string value of [%s] in %s field: %s\n",
|
|
|
|
name, second_str, grib_get_error_message(err2));
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if(err1 == GRIB_SUCCESS && err2 == GRIB_SUCCESS)
|
|
|
|
{
|
|
|
|
if(grib_inline_strcmp(sval1,sval2) != 0)
|
|
|
|
{
|
2018-01-02 16:32:55 +00:00
|
|
|
/* Check if strings are 'missing'.
|
|
|
|
* Note: one string could have all its bits=1 and the other empty */
|
|
|
|
int equal = 0;
|
|
|
|
grib_accessor* a1 = grib_find_accessor(handle1, name);
|
|
|
|
grib_accessor* a2 = grib_find_accessor(handle2, name);
|
|
|
|
int is_miss_1 = grib_is_missing_string(a1, (unsigned char *)sval1, len1);
|
|
|
|
int is_miss_2 = grib_is_missing_string(a2, (unsigned char *)sval2, len2);
|
|
|
|
if ( is_miss_1 && is_miss_2 ) {
|
|
|
|
equal = 1;
|
|
|
|
}
|
|
|
|
if (!equal) {
|
|
|
|
printInfo(handle1);
|
|
|
|
printf("string [%s]: [%s] != [%s]\n", name, sval1, sval2);
|
|
|
|
err1 = GRIB_VALUE_MISMATCH;
|
|
|
|
save_error(c,name);
|
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
grib_context_free(handle1->context,sval1);
|
|
|
|
grib_context_free(handle2->context,sval2);
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if(err1) return err1;
|
|
|
|
if(err2) return err2;
|
|
|
|
|
|
|
|
break;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
|
|
|
case GRIB_TYPE_LONG:
|
2015-01-31 21:58:30 +00:00
|
|
|
if (verbose) printf(" as long\n");
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
lval1 = (long*)grib_context_malloc(handle1->context,len1*sizeof(long));
|
|
|
|
lval2 = (long*)grib_context_malloc(handle2->context,len2*sizeof(long));
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if((err1 = grib_get_long_array(handle1,name,lval1,&len1)) != GRIB_SUCCESS)
|
2015-01-31 21:58:30 +00:00
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("Oops... cannot get long value of [%s] in %s field: %s\n",
|
|
|
|
name, first_str, grib_get_error_message(err1));
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
}
|
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if((err2 = grib_get_long_array(handle2,name,lval2,&len2)) != GRIB_SUCCESS)
|
2015-01-31 21:58:30 +00:00
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("Oops... cannot get long value of [%s] in %s field: %s\n",
|
|
|
|
name,second_str,grib_get_error_message(err2));
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
}
|
|
|
|
|
2015-02-06 13:54:49 +00:00
|
|
|
if(err1 == GRIB_SUCCESS && err2 == GRIB_SUCCESS && len1!=len2)
|
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2015-02-06 13:54:49 +00:00
|
|
|
printf("Different size for \"%s\" [%ld] [%ld]\n",name,(long)len1,(long)len2);
|
2015-09-10 12:58:19 +00:00
|
|
|
err1=GRIB_INTERNAL_ERROR;
|
2015-02-06 13:54:49 +00:00
|
|
|
save_error(c,name);
|
|
|
|
}
|
|
|
|
if(err1 == GRIB_SUCCESS && err2 == GRIB_SUCCESS && len1==len2)
|
2015-01-31 21:58:30 +00:00
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
int ii;
|
2015-01-31 21:58:30 +00:00
|
|
|
countdiff=0;
|
2016-04-14 11:11:48 +00:00
|
|
|
for(ii = 0; ii < len1; ii++)
|
|
|
|
if(lval1[ii] != lval2[ii]) countdiff++;
|
2015-01-31 21:58:30 +00:00
|
|
|
|
|
|
|
if (countdiff) {
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
err1 = GRIB_VALUE_MISMATCH;
|
|
|
|
if(len1 == 1)
|
2016-11-29 18:12:23 +00:00
|
|
|
printf("long [%s]: [%ld] != [%ld]\n", name, *lval1, *lval2);
|
2015-01-31 21:58:30 +00:00
|
|
|
else
|
2016-11-29 18:12:23 +00:00
|
|
|
printf("long [%s] %d out of %ld different\n", name, countdiff, (long)len1);
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
grib_context_free(handle1->context,lval1);
|
|
|
|
grib_context_free(handle2->context,lval2);
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if(err1) return err1;
|
|
|
|
if(err2) return err2;
|
|
|
|
break;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
|
|
|
case GRIB_TYPE_DOUBLE:
|
2015-02-04 09:30:29 +00:00
|
|
|
if (verbose) printf(" as double\n");
|
2016-04-14 11:11:48 +00:00
|
|
|
dval1 = (double*)grib_context_malloc(handle1->context,len1*sizeof(double));
|
|
|
|
dval2 = (double*)grib_context_malloc(handle2->context,len2*sizeof(double));
|
2015-01-31 21:58:30 +00:00
|
|
|
|
|
|
|
isangle=0;
|
|
|
|
value_tolerance=global_tolerance;
|
|
|
|
if (!grib_inline_strcmp(name,"packedValues") || !grib_inline_strcmp(name,"values")
|
|
|
|
|| !grib_inline_strcmp(name,"codedValues")) {
|
|
|
|
packingError1=0;
|
|
|
|
packingError2=0;
|
2016-04-14 11:11:48 +00:00
|
|
|
err1=grib_get_double(handle1,"packingError",&packingError1);
|
|
|
|
err2=grib_get_double(handle2,"packingError",&packingError2);
|
2015-01-31 21:58:30 +00:00
|
|
|
if (packingCompare)
|
|
|
|
value_tolerance = packingError1 > packingError2 ? packingError1 : packingError2;
|
|
|
|
} else if (!grib_inline_strcmp(name,"unpackedValues") ) {
|
|
|
|
packingError1=0;
|
|
|
|
packingError2=0;
|
2016-04-14 11:11:48 +00:00
|
|
|
err1=grib_get_double(handle1,"unpackedError",&packingError1);
|
|
|
|
err2=grib_get_double(handle2,"unpackedError",&packingError2);
|
2015-01-31 21:58:30 +00:00
|
|
|
if (packingCompare)
|
|
|
|
value_tolerance = packingError1 > packingError2 ? packingError1 : packingError2;
|
|
|
|
} else if ( !grib_inline_rstrcmp(name,"InDegrees")) {
|
|
|
|
packingError1=0.0005;
|
|
|
|
packingError2=0.0005;
|
|
|
|
isangle=1;
|
|
|
|
value_tolerance = packingError1 > packingError2 ? packingError1 : packingError2;
|
|
|
|
} else if (!grib_inline_strcmp(name,"referenceValue") ) {
|
|
|
|
packingError1=0;
|
|
|
|
packingError2=0;
|
2016-04-14 11:11:48 +00:00
|
|
|
err1=grib_get_double(handle1,"referenceValueError",&packingError1);
|
|
|
|
err2=grib_get_double(handle2,"referenceValueError",&packingError2);
|
2015-01-31 21:58:30 +00:00
|
|
|
value_tolerance = packingError1 > packingError2 ? packingError1 : packingError2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!compareAbsolute) {
|
2018-03-21 17:52:37 +00:00
|
|
|
int all_specified = 0; /* =1 if relative comparison with "all" specified */
|
2015-01-31 21:58:30 +00:00
|
|
|
for (i=0;i<options->tolerance_count;i++) {
|
2018-03-21 17:52:37 +00:00
|
|
|
if (!strcmp((options->tolerance[i]).name, "all")) {
|
|
|
|
all_specified = 1;
|
2015-01-31 21:58:30 +00:00
|
|
|
value_tolerance=(options->tolerance[i]).double_value;
|
|
|
|
break;
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
2018-03-21 17:52:37 +00:00
|
|
|
if (!all_specified) {
|
2018-03-22 13:49:11 +00:00
|
|
|
char* basename = NULL;
|
2018-03-21 17:52:37 +00:00
|
|
|
for (i=0;i<options->tolerance_count;i++) {
|
2018-03-22 13:49:11 +00:00
|
|
|
if ( strcmp( (options->tolerance[i]).name, name)==0 ) {
|
2018-03-21 17:52:37 +00:00
|
|
|
value_tolerance=(options->tolerance[i]).double_value;
|
|
|
|
break;
|
2018-03-22 13:49:11 +00:00
|
|
|
} else {
|
|
|
|
/* Check if the key without its rank has a relative tolerance */
|
|
|
|
basename = get_keyname_without_rank(name);
|
|
|
|
if ( basename && strcmp( (options->tolerance[i]).name, basename)==0 ) {
|
|
|
|
value_tolerance=(options->tolerance[i]).double_value;
|
|
|
|
break;
|
|
|
|
}
|
2018-03-21 17:52:37 +00:00
|
|
|
}
|
|
|
|
}
|
2018-03-22 13:49:11 +00:00
|
|
|
if (basename) grib_context_free(handle1->context, basename);
|
2018-03-21 17:52:37 +00:00
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if((err1 = grib_get_double_array(handle1,name,dval1,&len1)) != GRIB_SUCCESS)
|
2015-01-31 21:58:30 +00:00
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("Oops... cannot get double value of [%s] in %s field: %s\n",
|
|
|
|
name, first_str, grib_get_error_message(err1));
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if((err2 = grib_get_double_array(handle2,name,dval2,&len2)) != GRIB_SUCCESS)
|
2015-01-31 21:58:30 +00:00
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("Oops... cannot get double value of [%s] in %s field: %s\n",
|
|
|
|
name,second_str,grib_get_error_message(err2));
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
|
|
|
|
if(err1 == GRIB_SUCCESS && err2 == GRIB_SUCCESS && len1!=len2)
|
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2015-01-31 21:58:30 +00:00
|
|
|
printf("Different size for \"%s\" [%ld] [%ld]\n",name,(long)len1,(long)len2);
|
|
|
|
save_error(c,name);
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
if(err1 == GRIB_SUCCESS && err2 == GRIB_SUCCESS && len1==len2)
|
|
|
|
{
|
2018-01-03 16:41:06 +00:00
|
|
|
int imaxdiff;
|
2015-01-31 21:58:30 +00:00
|
|
|
double diff;
|
|
|
|
double *pv1,*pv2,dnew1,dnew2;
|
|
|
|
maxdiff=0;
|
|
|
|
imaxdiff=0;
|
|
|
|
countdiff=0;
|
|
|
|
pv1=dval1;
|
|
|
|
pv2=dval2;
|
|
|
|
if (isangle) {
|
|
|
|
dnew1=*dval1; dnew2=*dval2;
|
|
|
|
pv1=&dnew1; pv2=&dnew2;
|
|
|
|
if (*dval1 < 0 ) dnew1 += 360.0 ;
|
|
|
|
if (*dval2 < 0 ) dnew2 += 360.0 ;
|
|
|
|
if (*dval1 > 360 ) dnew1 -= 360.0 ;
|
|
|
|
if (*dval2 > 360 ) dnew2 -= 360.0 ;
|
|
|
|
}
|
|
|
|
value_tolerance*=tolerance_factor;
|
|
|
|
if (verbose) printf(" (%d values) tolerance=%g\n",(int)len1,value_tolerance);
|
|
|
|
for(i = 0; i < len1; i++) {
|
|
|
|
if((diff=compare_double(pv1++,pv2++,&value_tolerance))!=0) {
|
|
|
|
countdiff++;
|
|
|
|
if (maxdiff < diff) {maxdiff=diff;imaxdiff=i;}
|
|
|
|
err1 = GRIB_VALUE_MISMATCH;
|
|
|
|
}
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if (countdiff) {
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
if (len1>1) {
|
|
|
|
printf("double [%s]: %d out of %ld different\n",name,countdiff,(long)len1);
|
2016-11-28 18:04:06 +00:00
|
|
|
if (dval1[imaxdiff] != GRIB_MISSING_DOUBLE && dval2[imaxdiff] != GRIB_MISSING_DOUBLE) {
|
|
|
|
if (compareAbsolute) printf(" max");
|
|
|
|
printf(" absolute diff. = %.16e,",fabs(dval1[imaxdiff]-dval2[imaxdiff]));
|
|
|
|
if (!compareAbsolute) printf(" max");
|
|
|
|
printf(" relative diff. = %g",relative_error(dval1[imaxdiff],dval2[imaxdiff],value_tolerance));
|
|
|
|
printf("\n\tmax diff. element %d: %.20e %.20e",
|
|
|
|
imaxdiff,dval1[imaxdiff],dval2[imaxdiff]);
|
|
|
|
printf("\n\ttolerance=%.16e",value_tolerance);
|
|
|
|
} else {
|
|
|
|
/* One or both values are missing */
|
2018-01-03 16:41:06 +00:00
|
|
|
char* svalA = double_as_string(c, dval1[imaxdiff]);
|
|
|
|
char* svalB = double_as_string(c, dval2[imaxdiff]);
|
|
|
|
printf("\tdiff. element %d: %s %s", imaxdiff, svalA, svalB);
|
|
|
|
grib_context_free(c,svalA);
|
|
|
|
grib_context_free(c,svalB);
|
2016-11-28 18:04:06 +00:00
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
if (packingError2!=0 || packingError1!=0)
|
|
|
|
printf(" packingError: [%g] [%g]",packingError1,packingError2);
|
|
|
|
|
|
|
|
if (!grib_inline_strcmp(name,"packedValues") || !grib_inline_strcmp(name,"values")
|
|
|
|
|| !grib_inline_strcmp(name,"codedValues")) {
|
|
|
|
double max1,min1,max2,min2;
|
2016-04-14 11:11:48 +00:00
|
|
|
grib_get_double(handle1,"max",&max1);
|
|
|
|
grib_get_double(handle1,"min",&min1);
|
|
|
|
grib_get_double(handle2,"max",&max2);
|
|
|
|
grib_get_double(handle2,"min",&min2);
|
2015-01-31 21:58:30 +00:00
|
|
|
printf("\n\tvalues max= [%g] [%g] min= [%g] [%g]",max1,max2,min1,min2);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
} else {
|
2016-11-28 18:04:06 +00:00
|
|
|
if (dval1[0] != GRIB_MISSING_DOUBLE && dval2[0] != GRIB_MISSING_DOUBLE) {
|
|
|
|
printf("double [%s]: [%.20e] != [%.20e]\n", name, dval1[0], dval2[0]);
|
|
|
|
printf("\tabsolute diff. = %g,",fabs(dval1[0]-dval2[0]));
|
|
|
|
printf(" relative diff. = %g\n",relative_error(dval1[0],dval2[0],value_tolerance));
|
|
|
|
printf("\ttolerance=%g\n",value_tolerance);
|
|
|
|
} else {
|
|
|
|
/* One or both values are missing */
|
2018-01-03 16:41:06 +00:00
|
|
|
char* svalA = double_as_string(c, dval1[0]);
|
|
|
|
char* svalB = double_as_string(c, dval2[0]);
|
|
|
|
printf("double [%s]: [%s] != [%s]\n", name, svalA, svalB);
|
|
|
|
grib_context_free(c,svalA);
|
|
|
|
grib_context_free(c,svalB);
|
2016-11-28 18:04:06 +00:00
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
grib_context_free(handle1->context,dval1);
|
|
|
|
grib_context_free(handle2->context,dval2);
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if(err1) return err1;
|
|
|
|
if(err2) return err2;
|
|
|
|
break;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
|
|
|
case GRIB_TYPE_BYTES:
|
2015-01-31 21:58:30 +00:00
|
|
|
if (verbose) printf(" as bytes\n");
|
|
|
|
if (options->mode==MODE_BUFR) return 0;
|
2015-02-06 13:54:49 +00:00
|
|
|
if (len1<2) len1=512;
|
|
|
|
if (len2<2) len2=512;
|
2016-04-14 11:11:48 +00:00
|
|
|
uval1 = (unsigned char*)grib_context_malloc(handle1->context,len1*sizeof(unsigned char));
|
|
|
|
uval2 = (unsigned char*)grib_context_malloc(handle2->context,len2*sizeof(unsigned char));
|
2015-01-31 21:58:30 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if((err1 = grib_get_bytes(handle1,name,uval1,&len1)) != GRIB_SUCCESS)
|
2015-01-31 21:58:30 +00:00
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("Oops... cannot get bytes value of [%s] in %s field: %s\n",
|
|
|
|
name,first_str,grib_get_error_message(err1));
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
if((err2 = grib_get_bytes(handle2,name,uval2,&len2)) != GRIB_SUCCESS)
|
2014-07-06 13:18:40 +00:00
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2014-07-06 13:18:40 +00:00
|
|
|
save_error(c,name);
|
2018-03-12 15:51:04 +00:00
|
|
|
printf("Oops... cannot get bytes value of [%s] in %s field: %s\n",
|
|
|
|
name,second_str,grib_get_error_message(err2));
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if(err1 == GRIB_SUCCESS && err2 == GRIB_SUCCESS)
|
|
|
|
{
|
|
|
|
if(memcmp(uval1,uval2,len1) != 0)
|
|
|
|
{
|
2016-11-29 18:12:23 +00:00
|
|
|
for(i = 0; i < len1; i++) {
|
2015-01-31 21:58:30 +00:00
|
|
|
if(uval1[i] != uval2[i])
|
|
|
|
{
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
if(len1 == 1)
|
|
|
|
printf("[%s] byte values are different: [%02x] and [%02x]\n",
|
|
|
|
name,uval1[i],uval2[i]);
|
|
|
|
else
|
|
|
|
printf("[%s] byte value %d of %ld are different: [%02x] and [%02x]\n",
|
|
|
|
name,i,(long)len1,uval1[i],uval2[i]);
|
|
|
|
|
|
|
|
err1 = GRIB_VALUE_MISMATCH;
|
|
|
|
break;
|
|
|
|
}
|
2016-11-29 18:12:23 +00:00
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
err1 = GRIB_VALUE_MISMATCH;
|
|
|
|
}
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
grib_context_free(handle1->context,uval1);
|
|
|
|
grib_context_free(handle2->context,uval2);
|
2015-01-31 21:58:30 +00:00
|
|
|
|
|
|
|
if(err1) return err1;
|
|
|
|
if(err2) return err2;
|
|
|
|
break;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
|
|
|
case GRIB_TYPE_LABEL:
|
2015-01-31 21:58:30 +00:00
|
|
|
if (verbose) printf(" as label\n");
|
|
|
|
break;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
|
|
|
default:
|
2015-01-31 21:58:30 +00:00
|
|
|
if (verbose) printf("\n");
|
2016-04-14 11:11:48 +00:00
|
|
|
printInfo(handle1);
|
2015-01-31 21:58:30 +00:00
|
|
|
save_error(c,name);
|
|
|
|
printf("Cannot compare [%s], unsupported type %d\n",name,type1);
|
|
|
|
return GRIB_UNABLE_TO_COMPARE_ACCESSORS;
|
|
|
|
break;
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
return GRIB_SUCCESS;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
2016-08-09 16:22:16 +00:00
|
|
|
|
2016-08-11 17:38:51 +00:00
|
|
|
static int compare_attributes(grib_handle* handle1, grib_handle* handle2, grib_runtime_options* options,
|
|
|
|
grib_accessor* a, const char* prefix, int* err)
|
|
|
|
{
|
|
|
|
int i=0, ret=0;
|
|
|
|
while (i < MAX_ACCESSOR_ATTRIBUTES && a->attributes[i])
|
|
|
|
{
|
|
|
|
/*long native_type = 0;*/
|
|
|
|
grib_accessor* aa = NULL;
|
|
|
|
if ( (a->attributes[i]->flags & GRIB_ACCESSOR_FLAG_DUMP)== 0 ) {
|
2018-09-06 14:13:33 +00:00
|
|
|
++i; /* next attribute if accessor is not for dumping */
|
2016-08-11 17:38:51 +00:00
|
|
|
continue;
|
|
|
|
}
|
2018-09-06 14:13:33 +00:00
|
|
|
if ( (a->attributes[i]->flags & GRIB_ACCESSOR_FLAG_READ_ONLY)!= 0 ) {
|
|
|
|
++i; /* next attribute if accessor is read-only */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-08-11 17:38:51 +00:00
|
|
|
aa = a->attributes[i];
|
|
|
|
/*native_type = grib_accessor_get_native_type(aa); TODO: read only check? */
|
|
|
|
|
|
|
|
isLeafKey = aa->attributes[0]==NULL ? 1 : 0; /* update global variable */
|
|
|
|
|
|
|
|
if (compare_attribute(handle1, handle2, options, aa, prefix, err)) {
|
2018-11-01 12:55:47 +00:00
|
|
|
(*err)++;
|
2016-08-11 17:38:51 +00:00
|
|
|
write_messages(handle1, handle2);
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
++i; /* next attribute */
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2016-11-29 18:12:23 +00:00
|
|
|
|
2016-08-11 17:38:51 +00:00
|
|
|
static int compare_attribute(grib_handle* handle1, grib_handle* handle2, grib_runtime_options* options,
|
|
|
|
grib_accessor* a, const char* prefix, int* err)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
grib_context* c = handle1->context;
|
2017-06-21 18:21:58 +00:00
|
|
|
char* fullname = (char*)grib_context_malloc_clear( c, sizeof(char)*(strlen(a->name)+strlen(prefix)+5) );
|
2016-08-11 17:38:51 +00:00
|
|
|
sprintf(fullname, "%s->%s", prefix, a->name);
|
|
|
|
if (compare_values(options, handle1, handle2, fullname, GRIB_TYPE_UNDEFINED)) {
|
2018-11-01 12:55:47 +00:00
|
|
|
(*err)++;
|
2016-08-11 17:38:51 +00:00
|
|
|
write_messages(handle1, handle2);
|
|
|
|
ret=1;
|
|
|
|
}
|
|
|
|
/* Recurse if this key has children */
|
|
|
|
if (!isLeafKey) {
|
|
|
|
if (compare_attributes(handle1, handle2, options, a, fullname, err)) {
|
|
|
|
ret=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
grib_context_free(c, fullname);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:55:47 +00:00
|
|
|
static int compare_all_dump_keys(grib_handle* handle1, grib_handle* handle2, grib_runtime_options* options, int *pErr)
|
2016-08-05 17:38:47 +00:00
|
|
|
{
|
2014-07-06 13:18:40 +00:00
|
|
|
int ret=0;
|
|
|
|
const char* name=NULL;
|
|
|
|
grib_keys_iterator* iter = NULL;
|
2016-08-11 15:35:03 +00:00
|
|
|
grib_context* context=handle1->context;
|
|
|
|
|
2016-09-21 17:08:24 +00:00
|
|
|
if (!headerMode) {
|
|
|
|
/* See ECC-333: By setting unpack we get ALL the bufr keys. */
|
|
|
|
/* In headerMode we want just the header ones */
|
2018-09-06 14:13:33 +00:00
|
|
|
grib_set_long(handle1,"skipExtraKeyAttributes",1); /* See ECC-745 */
|
2016-09-21 17:08:24 +00:00
|
|
|
ret = grib_set_long(handle1,"unpack",1);
|
|
|
|
if (ret != GRIB_SUCCESS) {
|
|
|
|
grib_context_log(context, GRIB_LOG_ERROR, "Failed to unpack 1st message: %s", grib_get_error_message(ret));
|
|
|
|
exit(1);
|
|
|
|
}
|
2018-09-06 14:13:33 +00:00
|
|
|
grib_set_long(handle2,"skipExtraKeyAttributes",1); /* See ECC-745 */
|
2016-09-21 17:08:24 +00:00
|
|
|
ret = grib_set_long(handle2,"unpack",1);
|
|
|
|
if (ret != GRIB_SUCCESS) {
|
|
|
|
grib_context_log(context, GRIB_LOG_ERROR, "Failed to unpack 2nd message: %s", grib_get_error_message(ret));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
2016-04-14 11:11:48 +00:00
|
|
|
iter=grib_keys_iterator_new(handle1,0,NULL);
|
2014-07-06 13:18:40 +00:00
|
|
|
|
|
|
|
if (!iter) {
|
2016-08-11 15:35:03 +00:00
|
|
|
grib_context_log(context, GRIB_LOG_ERROR, "unable to create keys iterator");
|
2015-01-31 21:58:30 +00:00
|
|
|
exit(1);
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2016-08-11 18:24:09 +00:00
|
|
|
release_keys_list(); /* The keys list is used to determine the rank */
|
2016-08-11 15:35:03 +00:00
|
|
|
new_keys_list();
|
2016-08-09 16:22:16 +00:00
|
|
|
|
2014-07-06 13:18:40 +00:00
|
|
|
while(grib_keys_iterator_next(iter))
|
|
|
|
{
|
2016-08-11 17:38:51 +00:00
|
|
|
int rank = 0;
|
2016-08-08 17:03:57 +00:00
|
|
|
int dofree = 0;
|
|
|
|
char* prefix = NULL;
|
2015-01-31 21:58:30 +00:00
|
|
|
grib_accessor* xa=grib_keys_iterator_get_accessor(iter);
|
2016-08-11 17:38:51 +00:00
|
|
|
|
|
|
|
isLeafKey = 0; /* clear global variable for each key */
|
2015-01-31 21:58:30 +00:00
|
|
|
name=grib_keys_iterator_get_name(iter);
|
|
|
|
if (blacklisted(name)) continue;
|
|
|
|
if (xa==NULL || ( xa->flags & GRIB_ACCESSOR_FLAG_DUMP )==0 ) continue;
|
2016-08-09 16:22:16 +00:00
|
|
|
|
2016-08-11 17:38:51 +00:00
|
|
|
/* Get full name of key, e.g. '#2#windSpeed' or 'blockNumber' */
|
2016-10-24 15:49:15 +00:00
|
|
|
rank = compute_bufr_key_rank(handle1, keys_list, xa->name);
|
2016-08-08 17:03:57 +00:00
|
|
|
if (rank != 0) {
|
2017-06-21 18:21:58 +00:00
|
|
|
prefix=(char*)grib_context_malloc_clear(context,sizeof(char)*(strlen(xa->name)+10));
|
2016-08-08 17:03:57 +00:00
|
|
|
dofree = 1;
|
|
|
|
sprintf(prefix,"#%d#%s", rank, xa->name);
|
|
|
|
} else {
|
|
|
|
prefix = (char*)xa->name;
|
|
|
|
}
|
2016-08-11 17:38:51 +00:00
|
|
|
|
2016-11-29 15:00:42 +00:00
|
|
|
if (blacklisted(prefix)) continue;
|
|
|
|
|
2016-08-11 17:38:51 +00:00
|
|
|
/* Compare the key itself */
|
|
|
|
if (compare_values(options, handle1, handle2, prefix, GRIB_TYPE_UNDEFINED)) {
|
2018-11-01 12:55:47 +00:00
|
|
|
(*pErr)++;
|
2016-08-11 17:38:51 +00:00
|
|
|
write_messages(handle1, handle2);
|
|
|
|
ret=1;
|
|
|
|
}
|
|
|
|
/* Now compare the key attributes (if any) */
|
2018-11-01 12:55:47 +00:00
|
|
|
if (compare_attributes(handle1, handle2, options, xa, prefix, pErr)) {
|
|
|
|
(*pErr)++;
|
2016-08-11 17:38:51 +00:00
|
|
|
write_messages(handle1, handle2);
|
|
|
|
ret=1;
|
2016-08-08 17:03:57 +00:00
|
|
|
}
|
2016-08-11 15:35:03 +00:00
|
|
|
if (dofree) grib_context_free(context, prefix);
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
grib_keys_iterator_delete(iter);
|
2018-11-01 11:50:00 +00:00
|
|
|
|
|
|
|
/* ECC-356: Handling special case of 'ident' key */
|
|
|
|
name = "ls.ident";
|
|
|
|
if (!blacklisted("ident") && grib_is_defined(handle1, name) && grib_is_defined(handle2, name)) {
|
|
|
|
if (compare_values(options, handle1, handle2, "ident", GRIB_TYPE_STRING)) {
|
2018-11-01 12:55:47 +00:00
|
|
|
(*pErr)++;
|
2018-11-01 11:50:00 +00:00
|
|
|
write_messages(handle1, handle2);
|
|
|
|
ret=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 13:18:40 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-04-14 11:11:48 +00:00
|
|
|
static int compare_handles(grib_handle* handle1, grib_handle* handle2, grib_runtime_options* options)
|
2014-07-06 13:18:40 +00:00
|
|
|
{
|
2015-01-31 21:58:30 +00:00
|
|
|
int err = 0;
|
|
|
|
int i=0;
|
|
|
|
grib_keys_iterator* iter = NULL;
|
|
|
|
const char* name=NULL;
|
2014-07-06 13:18:40 +00:00
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
/* mask only if no -c option or headerMode (-H)*/
|
|
|
|
if (blacklist && ( !listFromCommandLine || headerMode )) {
|
2017-04-27 13:52:53 +00:00
|
|
|
/* See ECC-245, GRIB-573, GRIB-915: Do not change handles in memory */
|
|
|
|
/*
|
2015-01-31 21:58:30 +00:00
|
|
|
grib_string_list* nextb=blacklist;
|
|
|
|
while (nextb) {
|
2016-04-14 11:11:48 +00:00
|
|
|
grib_clear(handle1,nextb->value);
|
|
|
|
grib_clear(handle2,nextb->value);
|
2015-01-31 21:58:30 +00:00
|
|
|
nextb=nextb->next;
|
2017-04-27 13:52:53 +00:00
|
|
|
}*/
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if ( listFromCommandLine && onlyListed ) {
|
|
|
|
for (i=0; i< options->compare_count; i++) {
|
|
|
|
if (blacklisted((char*)options->compare[i].name)) continue;
|
|
|
|
if (options->compare[i].type == GRIB_NAMESPACE) {
|
2017-01-13 17:24:36 +00:00
|
|
|
iter=grib_keys_iterator_new(handle1,0,options->compare[i].name);
|
2015-01-31 21:58:30 +00:00
|
|
|
if (!iter) {
|
2016-08-05 17:38:47 +00:00
|
|
|
grib_context_log(handle1->context, GRIB_LOG_ERROR, "unable to get iterator");
|
2015-01-31 21:58:30 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
while(grib_keys_iterator_next(iter))
|
|
|
|
{
|
|
|
|
name=grib_keys_iterator_get_name(iter);
|
|
|
|
/*printf("----- comparing %s\n",name);*/
|
|
|
|
|
|
|
|
if (blacklisted(name)) continue;
|
2016-04-14 11:11:48 +00:00
|
|
|
if(compare_values(options,handle1,handle2,name,GRIB_TYPE_UNDEFINED)) {
|
2015-01-31 21:58:30 +00:00
|
|
|
err++;
|
2016-04-14 11:11:48 +00:00
|
|
|
write_messages(handle1,handle2);
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
grib_keys_iterator_delete(iter);
|
|
|
|
} else {
|
2016-04-14 11:11:48 +00:00
|
|
|
if( compare_values(options,handle1,handle2,options->compare[i].name,options->compare[i].type))
|
2015-01-31 21:58:30 +00:00
|
|
|
err++;
|
2016-04-14 11:11:48 +00:00
|
|
|
write_messages(handle1,handle2);
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
} else {
|
|
|
|
const void *msg1=NULL,*msg2=NULL;
|
|
|
|
size_t size1=0,size2=0;
|
|
|
|
int memcmp_ret=0;
|
|
|
|
/* int ii=0; */
|
2016-04-14 11:11:48 +00:00
|
|
|
GRIB_CHECK_NOLINE(grib_get_message(handle1,&msg1,&size1),0);
|
|
|
|
GRIB_CHECK_NOLINE(grib_get_message(handle2,&msg2,&size2),0);
|
2015-01-31 21:58:30 +00:00
|
|
|
if (size1==size2 && !(memcmp_ret=memcmp(msg1,msg2,size1))) {
|
|
|
|
return 0;
|
2015-09-03 14:49:24 +00:00
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
#if 0
|
2015-09-03 14:49:24 +00:00
|
|
|
else {
|
|
|
|
int lcount=count,ii;
|
2015-01-31 21:58:30 +00:00
|
|
|
if (options->current_infile) lcount=options->current_infile->filter_handle_count;
|
|
|
|
if (size1 != size2) {
|
|
|
|
printf("#%d different size: %d!=%d\n",lcount,(int)size1,(int)size2);
|
|
|
|
}
|
|
|
|
if (memcmp_ret) {
|
|
|
|
unsigned char *m1=(unsigned char*)msg1;
|
|
|
|
unsigned char *m2=(unsigned char*)msg2;
|
|
|
|
printf("=== list of different bytes for message %d\n",lcount);
|
|
|
|
for (ii=0;ii<size1;ii++) {
|
|
|
|
if (memcmp(m1,m2,1)) {
|
|
|
|
printf(" %d 0x%.2X != 0x%.2X\n",ii,*m1,*m2);
|
|
|
|
}
|
|
|
|
m1++; m2++;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
return err;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-01-31 21:58:30 +00:00
|
|
|
if ( listFromCommandLine ) {
|
|
|
|
for (i=0; i< options->compare_count; i++) {
|
|
|
|
if (blacklisted(name)) continue;
|
|
|
|
if (options->compare[i].type == GRIB_NAMESPACE) {
|
2017-01-13 17:24:36 +00:00
|
|
|
iter=grib_keys_iterator_new(handle1,0,options->compare[i].name);
|
2015-01-31 21:58:30 +00:00
|
|
|
if (!iter) {
|
2016-08-05 17:38:47 +00:00
|
|
|
grib_context_log(handle1->context, GRIB_LOG_ERROR,
|
|
|
|
"ERROR: unable to get keys iterator for %s",options->compare[i].name);
|
2015-01-31 21:58:30 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
while(grib_keys_iterator_next(iter))
|
|
|
|
{
|
|
|
|
name=grib_keys_iterator_get_name(iter);
|
|
|
|
/*printf("----- comparing %s\n",name);*/
|
|
|
|
|
|
|
|
if (blacklisted(name)) continue;
|
2016-04-14 11:11:48 +00:00
|
|
|
if(compare_values(options,handle1,handle2,name,GRIB_TYPE_UNDEFINED)) {
|
2015-01-31 21:58:30 +00:00
|
|
|
err++;
|
2016-04-14 11:11:48 +00:00
|
|
|
write_messages(handle1,handle2);
|
|
|
|
if (compare_all_dump_keys(handle1,handle2,options,&err)) {
|
2015-02-04 09:30:29 +00:00
|
|
|
err++;
|
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
grib_keys_iterator_delete(iter);
|
|
|
|
} else {
|
2016-04-14 11:11:48 +00:00
|
|
|
if( compare_values(options,handle1,handle2,options->compare[i].name,options->compare[i].type)) {
|
2015-01-31 21:58:30 +00:00
|
|
|
err++;
|
2016-04-14 11:11:48 +00:00
|
|
|
write_messages(handle1,handle2);
|
|
|
|
if (compare_all_dump_keys(handle1,handle2,options,&err)) {
|
2015-02-04 09:30:29 +00:00
|
|
|
err++;
|
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
}
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
|
|
|
} else {
|
2016-04-14 11:11:48 +00:00
|
|
|
if (compare_all_dump_keys(handle1,handle2,options,&err)) {
|
2015-02-04 09:30:29 +00:00
|
|
|
err++;
|
|
|
|
}
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
2015-01-31 21:58:30 +00:00
|
|
|
return err;
|
2014-07-06 13:18:40 +00:00
|
|
|
}
|
2015-05-01 09:04:58 +00:00
|
|
|
|
2016-08-30 12:45:02 +00:00
|
|
|
int grib_no_handle_action(grib_runtime_options* options, int err)
|
2016-04-14 11:11:48 +00:00
|
|
|
{
|
|
|
|
fprintf(dump_file,"\t\t\"ERROR: unreadable message\"\n");
|
|
|
|
return 0;
|
2015-05-01 09:04:58 +00:00
|
|
|
}
|