diff --git a/src/eccodes_prototypes.h b/src/eccodes_prototypes.h index 1ec90f91d..76d5656c1 100644 --- a/src/eccodes_prototypes.h +++ b/src/eccodes_prototypes.h @@ -154,6 +154,7 @@ int grib_nearest_smaller_value(grib_accessor* a, double val, double* nearest); size_t grib_preferred_size(grib_accessor* a, int from_handle); grib_accessor* grib_next_accessor(grib_accessor* a); void grib_resize(grib_accessor* a, size_t new_size); +int grib_compare_accessors(grib_accessor* a1, grib_accessor* a2, int compare_flags); int grib_accessor_add_attribute(grib_accessor* a, grib_accessor* attr, int nest_if_clash); int grib_accessor_replace_attribute(grib_accessor* a, grib_accessor* attr); int grib_accessor_delete_attribute(grib_accessor* a, const char* name); @@ -1277,6 +1278,7 @@ void grib_print_values(const char* title, grib_values* values); int grib_values_check(grib_handle* h, grib_values* values, int count); int grib_key_equal(grib_handle* h1, grib_handle* h2, const char* key, int type, int* err); int codes_copy_key(grib_handle* h1, grib_handle* h2, const char* key, int type); +int codes_compare_key(grib_handle* h1, grib_handle* h2, const char* key, int compare_flags); /* grib_errors.cc*/ const char* grib_get_error_message(int code); diff --git a/src/grib_accessor.cc b/src/grib_accessor.cc index 90066e00c..58cf51c0e 100644 --- a/src/grib_accessor.cc +++ b/src/grib_accessor.cc @@ -652,50 +652,48 @@ void grib_resize(grib_accessor* a, size_t new_size) return; } -// int grib_compare_accessors(grib_accessor* a1, grib_accessor* a2, int compare_flags) -// { -// int ret = 0; -// long type1 = 0; -// long type2 = 0; -// int type_mismatch = 0; -// grib_accessor_class* c1 = NULL; - -// if ((compare_flags & GRIB_COMPARE_NAMES) && grib_inline_strcmp(a1->name, a2->name)) -// return GRIB_NAME_MISMATCH; - -// if (compare_flags & GRIB_COMPARE_TYPES) { -// type1 = grib_accessor_get_native_type(a1); -// type2 = grib_accessor_get_native_type(a2); - -// type_mismatch = type1 != type2 ? 1 : 0; -// } - -// ret = GRIB_UNABLE_TO_COMPARE_ACCESSORS; -// c1 = a1->cclass; -// while (c1) { -// if (c1->compare) { -// ret = c1->compare(a1, a2); -// break; -// } -// c1 = c1->super ? *(c1->super) : NULL; -// } - -// if (ret == GRIB_VALUE_MISMATCH && type_mismatch) -// ret = GRIB_TYPE_AND_VALUE_MISMATCH; - -// return ret; -// } - -/* -int grib_accessor_clear_attributes(grib_accessor* a) +int grib_compare_accessors(grib_accessor* a1, grib_accessor* a2, int compare_flags) { - int id; - for (id=0;idattributes[id]=NULL; + int ret = 0; + long type1 = 0; + long type2 = 0; + int type_mismatch = 0; + grib_accessor_class* c1 = NULL; + + if ((compare_flags & GRIB_COMPARE_NAMES) && grib_inline_strcmp(a1->name, a2->name)) + return GRIB_NAME_MISMATCH; + + if (compare_flags & GRIB_COMPARE_TYPES) { + type1 = grib_accessor_get_native_type(a1); + type2 = grib_accessor_get_native_type(a2); + + type_mismatch = type1 != type2 ? 1 : 0; } - return 0; + + ret = GRIB_UNABLE_TO_COMPARE_ACCESSORS; + c1 = a1->cclass; + while (c1) { + if (c1->compare) { + ret = c1->compare(a1, a2); + break; + } + c1 = c1->super ? *(c1->super) : NULL; + } + + if (ret == GRIB_VALUE_MISMATCH && type_mismatch) + ret = GRIB_TYPE_AND_VALUE_MISMATCH; + + return ret; } - */ + +// int grib_accessor_clear_attributes(grib_accessor* a) +// { +// int id; +// for (id=0;idattributes[id]=NULL; +// } +// return 0; +// } int grib_accessor_add_attribute(grib_accessor* a, grib_accessor* attr, int nest_if_clash) { diff --git a/src/grib_accessor_class_ascii.cc b/src/grib_accessor_class_ascii.cc index 24856f3d5..46d18b63d 100644 --- a/src/grib_accessor_class_ascii.cc +++ b/src/grib_accessor_class_ascii.cc @@ -250,19 +250,8 @@ static int compare(grib_accessor* a, grib_accessor* b) char* bval = 0; int err = 0; - size_t alen = 0; - size_t blen = 0; - long count = 0; - - err = grib_value_count(a, &count); - if (err) - return err; - alen = count; - - err = grib_value_count(b, &count); - if (err) - return err; - blen = count; + size_t alen = a->length+1; + size_t blen = b->length+1; if (alen != blen) return GRIB_COUNT_MISMATCH; @@ -270,11 +259,13 @@ static int compare(grib_accessor* a, grib_accessor* b) aval = (char*)grib_context_malloc(a->context, alen * sizeof(char)); bval = (char*)grib_context_malloc(b->context, blen * sizeof(char)); - grib_unpack_string(a, aval, &alen); - grib_unpack_string(b, bval, &blen); + err = grib_unpack_string(a, aval, &alen); + if (err) return err; + err = grib_unpack_string(b, bval, &blen); + if (err) return err; retval = GRIB_SUCCESS; - if (strcmp(aval, bval)) + if (!STR_EQUAL(aval, bval)) retval = GRIB_STRING_VALUE_MISMATCH; grib_context_free(a->context, aval); diff --git a/src/grib_value.cc b/src/grib_value.cc index aeb07fcd6..d9ef8bcd3 100644 --- a/src/grib_value.cc +++ b/src/grib_value.cc @@ -2083,3 +2083,19 @@ int codes_copy_key(grib_handle* h1, grib_handle* h2, const char* key, int type) return GRIB_INVALID_TYPE; } } + +int codes_compare_key(grib_handle* h1, grib_handle* h2, const char* key, int compare_flags) +{ + grib_accessor* a1 = grib_find_accessor(h1, key); + if (!a1) { + grib_context_log(h1->context, GRIB_LOG_ERROR, "Key %s not found in first message", key); + return GRIB_NOT_FOUND; + } + grib_accessor* a2 = grib_find_accessor(h2, key); + if (!a2) { + grib_context_log(h1->context, GRIB_LOG_ERROR, "Key %s not found in second message", key); + return GRIB_NOT_FOUND; + } + + return grib_compare_accessors(a1, a2, GRIB_COMPARE_TYPES); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ef07dbd64..827d91ef8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -45,6 +45,7 @@ list(APPEND test_c_bins bufr_coordinate_descriptors codes_new_from_samples codes_set_samples_path + codes_compare_keys grib_sh_ieee64 grib_ieee grib_set_bytes diff --git a/tests/codes_compare_keys.cc b/tests/codes_compare_keys.cc new file mode 100644 index 000000000..1bc8ad337 --- /dev/null +++ b/tests/codes_compare_keys.cc @@ -0,0 +1,57 @@ +/* + * (C) Copyright 2005- 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" + +int main(int argc, char* argv[]) +{ + FILE* f1 = NULL; + FILE* f2 = NULL; + grib_handle* h1 = NULL; + grib_handle* h2 = NULL; + int err = 0; + int failed = 0; + + Assert(argc == 3); + f1 = fopen(argv[1], "rb"); + f2 = fopen(argv[2], "rb"); + Assert(f1 && f2); + + while ((h1 = grib_handle_new_from_file(0, f1, &err)) != NULL && (h2 = grib_handle_new_from_file(0, f2, &err)) != NULL) { + grib_keys_iterator* kiter = NULL; + + /* Use namespace of NULL to get ALL keys */ + /* Set flags to 0 to not filter any keys */ + //kiter = grib_keys_iterator_new(h1, /*flags=*/0, /*namespace=*/NULL); + kiter = grib_keys_iterator_new(h1, /*flags=*/GRIB_KEYS_ITERATOR_SKIP_COMPUTED, /*namespace=*/NULL); + Assert(kiter); + + while (grib_keys_iterator_next(kiter)) { + const char* name = grib_keys_iterator_get_name(kiter); + Assert(name); + //printf("Comparing key '%s' ...\n", name); + err = codes_compare_key(h1, h2, name, 0); + if (err) { + printf("key: %s (%s)\n", name, grib_get_error_message(err)); + failed = 1; + } + } + + grib_keys_iterator_delete(kiter); + grib_handle_delete(h1); + grib_handle_delete(h2); + } + fclose(f1); + fclose(f2); + if (failed) { + fprintf(stderr, "\nComparison failed: One or more keys different\n"); + } + return err; +}