From 5eb697abccc7ab5bb6738aa12c723ba66b0747ea Mon Sep 17 00:00:00 2001 From: q-posev Date: Mon, 7 Feb 2022 15:57:38 +0100 Subject: [PATCH 1/3] [WIP] refactor read_group set of functions to read data in arbitrary order This fix is required to fix backwards compatibility issue of TEXT back end. In the meantime, the custom garbage collector from generator_tools which was deallocating previously allocated memory (datasets and strings) is no longer valid here since the order of allocation can be atrbitrary. This requires a new custom garbage collector, maybe as a separate functions in TEXT back end --- src/templates_text/templator_text.org | 391 ++++++++++++-------------- 1 file changed, 180 insertions(+), 211 deletions(-) diff --git a/src/templates_text/templator_text.org b/src/templates_text/templator_text.org index 7ad0ff9..4ba799a 100644 --- a/src/templates_text/templator_text.org +++ b/src/templates_text/templator_text.org @@ -318,234 +318,203 @@ trexio_text_read_$group$ (trexio_text_t* const file) return NULL; } - /* Read the dimensioning variables */ int rc = 0; - // START REPEAT GROUP_DSET_ALL - rc = fscanf(f, "%1023s", buffer); - if ((rc != 1) || (strcmp(buffer, "rank_$group_dset$") != 0)) { - FREE(buffer); - fclose(f); - FREE($group$); - return NULL; - } - - rc = fscanf(f, "%u", &($group$->rank_$group_dset$)); - if (rc != 1) { - FREE(buffer); - fclose(f); - FREE($group$); - return NULL; - } /* workaround for the case of missing blocks in the file */ + // START REPEAT GROUP_DSET_ALL uint64_t size_$group_dset$ = 0; - if ($group$->rank_$group_dset$ != 0) size_$group_dset$ = 1; - - for (uint32_t i=0; i<$group$->rank_$group_dset$; ++i){ - - uint32_t j=0; - - rc = fscanf(f, "%1023s %u", buffer, &j); - if ((rc != 2) || (strcmp(buffer, "dims_$group_dset$") != 0) || (j!=i)) { - FREE(buffer); - fclose(f); - FREE($group$); - return NULL; - } - - rc = fscanf(f, "%" SCNu64 "\n", &($group$->dims_$group_dset$[i])); - assert(!(rc != 1)); - if (rc != 1) { - FREE(buffer); - fclose(f); - FREE($group$); - return NULL; - } - - size_$group_dset$ *= $group$->dims_$group_dset$[i]; - } // END REPEAT GROUP_DSET_ALL - // START REPEAT GROUP_NUM - /* Read data */ - unsigned int $group_num$_isSet; - rc = fscanf(f, "%1023s", buffer); - assert(!((rc != 1) || (strcmp(buffer, "$group_num$_isSet") != 0))); - if ((rc != 1) || (strcmp(buffer, "$group_num$_isSet") != 0)) { - FREE(buffer); - fclose(f); - FREE($group$); - return NULL; - } + while(fscanf(f, "%1023s", buffer) != EOF) { - /* additional parameter $group_num$_isSet is needed to suppress warning when fscanf into bool variable using %u or %d */ - rc = fscanf(f, "%u", &($group_num$_isSet)); - $group$->$group_num$_isSet = (bool) $group_num$_isSet; - assert(!(rc != 1)); - if (rc != 1) { - FREE(buffer); - fclose(f); - FREE($group$); - return NULL; - } + if (strcmp(buffer, "EXIT") == 0) { + break; + // START REPEAT GROUP_DSET_ALL + } else if (strcmp(buffer, "rank_$group_dset$") == 0) { - if ($group$->$group_num$_isSet == true) { - rc = fscanf(f, "%1023s", buffer); - assert(!((rc != 1) || (strcmp(buffer, "$group_num$") != 0))); - if ((rc != 1) || (strcmp(buffer, "$group_num$") != 0)) { - FREE(buffer); - fclose(f); - FREE($group$); - return NULL; - } - - rc = fscanf(f, "%$group_num_format_scanf$", &($group$->$group_num$)); - assert(!(rc != 1)); - if (rc != 1) { - FREE(buffer); - fclose(f); - FREE($group$); - return NULL; - } - } - // END REPEAT GROUP_NUM - - // START REPEAT GROUP_ATTR_STR - rc = fscanf(f, "%1023s", buffer); - assert(!((rc != 1) || (strcmp(buffer, "len_$group_str$") != 0))); - if ((rc != 1) || (strcmp(buffer, "len_$group_str$") != 0)) { - FREE(buffer); - fclose(f); - FREE($group$); - return NULL; - } - - rc = fscanf(f, "%" SCNu64 "", &($group$->len_$group_str$)); - assert(!(rc != 1)); - if (rc != 1) { - FREE(buffer); - fclose(f); - FREE($group$); - return NULL; - } - - rc = fscanf(f, "%1023s", buffer); - assert(!((rc != 1) || (strcmp(buffer, "$group_str$") != 0))); - if ((rc != 1) || (strcmp(buffer, "$group_str$") != 0)) { - FREE(buffer); - fclose(f); - FREE($group$->$group_str$); - FREE($group$); - return NULL; - } - - if ($group$->len_$group_str$ != 0) { - - $group$->$group_str$ = CALLOC($group$->len_$group_str$, char); - assert (!($group$->$group_str$ == NULL)); - if ($group$->$group_str$ == NULL) { - FREE(buffer); - fclose(f); - FREE($group$->$group_str$); - FREE($group$); - return NULL; - } - - rc = fscanf(f, " %1023[^\n]", $group$->$group_str$); - assert(!(rc != 1)); - if (rc != 1) { - FREE(buffer); - fclose(f); - FREE($group$->$group_str$); - FREE($group$); - return NULL; - } - - } - // END REPEAT GROUP_ATTR_STR - - // START REPEAT GROUP_DSET_NUM - /* Allocate arrays */ - $group$->$group_dset$ = CALLOC(size_$group_dset$, $group_dset_dtype$); - assert (!($group$->$group_dset$ == NULL)); - if ($group$->$group_dset$ == NULL) { - FREE(buffer); - fclose(f); - FREE($group$->$group_dset$); - FREE($group$); - return NULL; - } - - rc = fscanf(f, "%1023s", buffer); - assert(!((rc != 1) || (strcmp(buffer, "$group_dset$") != 0))); - if ((rc != 1) || (strcmp(buffer, "$group_dset$") != 0)) { - FREE(buffer); - fclose(f); - FREE($group$->$group_dset$); - FREE($group$); - return NULL; - } - - for (uint64_t i=0 ; i$group_dset$[i])); - assert(!(rc != 1)); - if (rc != 1) { - FREE(buffer); - fclose(f); - FREE($group$->$group_dset$); - FREE($group$); - return NULL; - } - } - // END REPEAT GROUP_DSET_NUM - - // START REPEAT GROUP_DSET_STR - rc = fscanf(f, "%1023s", buffer); - assert(!((rc != 1) || (strcmp(buffer, "$group_dset$") != 0))); - if ((rc != 1) || (strcmp(buffer, "$group_dset$") != 0)) { - FREE(buffer); - fclose(f); - FREE($group$); - return NULL; - } - - /* Allocate arrays */ - if(size_$group_dset$ != 0) { - $group$->$group_dset$ = CALLOC(size_$group_dset$, $group_dset_dtype$); - if ($group$->$group_dset$ == NULL) { - FREE(buffer); - fclose(f); - FREE($group$->$group_dset$); - FREE($group$); - return NULL; - } - - /* WARNING: this tmp array allows to avoid allocation of space for each element of array of string - BUT it's size has to be number_of_str*max_len_str where max_len_str is somewhat arbitrary, e.g. 32. - ,*/ - char* tmp_$group_dset$; - tmp_$group_dset$ = CALLOC(size_$group_dset$*32, char); - - for (uint64_t i=0 ; i$group_dset$[i] = tmp_$group_dset$; - /* conventional fcanf with "%s" only return the string before the first space character - ,* to read string with spaces use "%[^\n]" possible with space before or after, i.e. " %[^\n]" - ,* Q: depending on what ? */ - rc = fscanf(f, " %1023[^\n]", tmp_$group_dset$); - assert(!(rc != 1)); + rc = fscanf(f, "%u", &($group$->rank_$group_dset$)); if (rc != 1) { FREE(buffer); fclose(f); - FREE($group$->$group_dset$); FREE($group$); return NULL; } - size_t tmp_$group_dset$_len = strlen($group$->$group_dset$[i]); - tmp_$group_dset$ += tmp_$group_dset$_len + 1; + if ($group$->rank_$group_dset$ != 0) size_$group_dset$ = 1UL; + + for (uint32_t i=0; i<$group$->rank_$group_dset$; ++i){ + + uint32_t j=0; + rc = fscanf(f, "%1023s %u", buffer, &j); + if ((rc != 2) || (strcmp(buffer, "dims_$group_dset$") != 0) || (j!=i)) { + FREE(buffer); + fclose(f); + FREE($group$); + return NULL; + } + + rc = fscanf(f, "%" SCNu64 "\n", &($group$->dims_$group_dset$[i])); + assert(!(rc != 1)); + if (rc != 1) { + FREE(buffer); + fclose(f); + FREE($group$); + return NULL; + } + + size_$group_dset$ *= $group$->dims_$group_dset$[i]; + } + // END REPEAT GROUP_DSET_ALL + // START REPEAT GROUP_DSET_NUM + } else if (strcmp(buffer, "$group_dset$") == 0) { + + /* Allocate arrays */ + $group$->$group_dset$ = CALLOC(size_$group_dset$, $group_dset_dtype$); + if ($group$->$group_dset$ == NULL) { + FREE(buffer); + fclose(f); + FREE($group$); + return NULL; + } + + for (uint64_t i=0 ; i$group_dset$[i])); + if (rc != 1) { + FREE(buffer); + fclose(f); + FREE($group$); + return NULL; + } + } + + // END REPEAT GROUP_DSET_NUM + // START REPEAT GROUP_DSET_STR + } else if (strcmp(buffer, "$group_dset$") == 0) { + + if(size_$group_dset$ != 0) { + /* Allocate arrays */ + $group$->$group_dset$ = CALLOC(size_$group_dset$, $group_dset_dtype$); + if ($group$->$group_dset$ == NULL) { + FREE(buffer); + fclose(f); + FREE($group$); + return NULL; + } + + /* WARNING: this tmp array allows to avoid allocation of space for each element of array of string + BUT it's size has to be number_of_str*max_len_str where max_len_str is somewhat arbitrary, e.g. 32. + ,*/ + char* tmp_$group_dset$; + tmp_$group_dset$ = CALLOC(size_$group_dset$*32, char); + + for (uint64_t i=0 ; i$group_dset$[i] = tmp_$group_dset$; + /* conventional fcanf with "%s" only return the string before the first space character + ,* to read string with spaces use "%[^\n]" possible with space before or after, i.e. " %[^\n]" + ,* Q: depending on what ? */ + rc = fscanf(f, " %1023[^\n]", tmp_$group_dset$); + assert(!(rc != 1)); + if (rc != 1) { + FREE(buffer); + fclose(f); + FREE($group$); + return NULL; + } + + size_t tmp_$group_dset$_len = strlen($group$->$group_dset$[i]); + tmp_$group_dset$ += tmp_$group_dset$_len + 1; + } + } + + // END REPEAT GROUP_DSET_STR + // START REPEAT GROUP_NUM + } else if (strcmp(buffer, "$group_num$_isSet") == 0) { + + unsigned int $group_num$_isSet; + /* additional parameter $group_num$_isSet is needed to suppress warning when fscanf into bool variable using %u or %d */ + rc = fscanf(f, "%u", &($group_num$_isSet)); + $group$->$group_num$_isSet = (bool) $group_num$_isSet; + assert(!(rc != 1)); + if (rc != 1) { + FREE(buffer); + fclose(f); + FREE($group$); + return NULL; + } + + if ($group$->$group_num$_isSet == true) { + rc = fscanf(f, "%1023s", buffer); + assert(!((rc != 1) || (strcmp(buffer, "$group_num$") != 0))); + if ((rc != 1) || (strcmp(buffer, "$group_num$") != 0)) { + FREE(buffer); + fclose(f); + FREE($group$); + return NULL; + } + + rc = fscanf(f, "%$group_num_format_scanf$", &($group$->$group_num$)); + assert(!(rc != 1)); + if (rc != 1) { + FREE(buffer); + fclose(f); + FREE($group$); + return NULL; + } + } + + // END REPEAT GROUP_NUM + // START REPEAT GROUP_ATTR_STR + } else if (strcmp(buffer, "len_$group_str$") == 0) { + + rc = fscanf(f, "%" SCNu64 "", &($group$->len_$group_str$)); + assert(!(rc != 1)); + if (rc != 1) { + FREE(buffer); + fclose(f); + FREE($group$); + return NULL; + } + + rc = fscanf(f, "%1023s", buffer); + assert(!((rc != 1) || (strcmp(buffer, "$group_str$") != 0))); + if ((rc != 1) || (strcmp(buffer, "$group_str$") != 0)) { + FREE(buffer); + fclose(f); + FREE($group$->$group_str$); + FREE($group$); + return NULL; + } + + if ($group$->len_$group_str$ != 0) { + + $group$->$group_str$ = CALLOC($group$->len_$group_str$, char); + assert (!($group$->$group_str$ == NULL)); + if ($group$->$group_str$ == NULL) { + FREE(buffer); + fclose(f); + FREE($group$->$group_str$); + FREE($group$); + return NULL; + } + + rc = fscanf(f, " %1023[^\n]", $group$->$group_str$); + assert(!(rc != 1)); + if (rc != 1) { + FREE(buffer); + fclose(f); + FREE($group$->$group_str$); + FREE($group$); + return NULL; + } + + } + + // END REPEAT GROUP_ATTR_STR + } else { + continue; } + } - // END REPEAT GROUP_DSET_STR FREE(buffer); fclose(f); From 68d34a0ace94f603688698f36eee7aa1dd564e39 Mon Sep 17 00:00:00 2001 From: q-posev Date: Mon, 14 Feb 2022 10:44:04 +0100 Subject: [PATCH 2/3] use built-in trexio_text_free_group function for garbage collection --- src/templates_text/templator_text.org | 80 ++++++++++++++++++++------- tools/generator_tools.py | 41 ++------------ 2 files changed, 66 insertions(+), 55 deletions(-) diff --git a/src/templates_text/templator_text.org b/src/templates_text/templator_text.org index 4ba799a..066fd85 100644 --- a/src/templates_text/templator_text.org +++ b/src/templates_text/templator_text.org @@ -80,12 +80,12 @@ #+begin_src c :tangle struct_text_group_dset.h typedef struct $group$_s { $group_num_dtype_double$ $group_num$; - bool $group_num$_isSet; $group_dset_dtype$* $group_dset$; - uint32_t rank_$group_dset$; - uint32_t to_flush; uint64_t dims_$group_dset$[16]; uint64_t len_$group_str$; + uint32_t rank_$group_dset$; + uint32_t to_flush; + bool $group_num$_isSet; char* $group_str$; char file_name[TREXIO_MAX_FILENAME_LENGTH]; } $group$_t; @@ -319,6 +319,7 @@ trexio_text_read_$group$ (trexio_text_t* const file) } int rc = 0; + trexio_exit_code rc_free = TREXIO_FAILURE; /* workaround for the case of missing blocks in the file */ // START REPEAT GROUP_DSET_ALL @@ -336,7 +337,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if (rc != 1) { FREE(buffer); fclose(f); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } @@ -349,7 +353,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if ((rc != 2) || (strcmp(buffer, "dims_$group_dset$") != 0) || (j!=i)) { FREE(buffer); fclose(f); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } @@ -358,7 +365,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if (rc != 1) { FREE(buffer); fclose(f); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } @@ -373,7 +383,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if ($group$->$group_dset$ == NULL) { FREE(buffer); fclose(f); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } @@ -382,7 +395,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if (rc != 1) { FREE(buffer); fclose(f); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } } @@ -397,7 +413,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if ($group$->$group_dset$ == NULL) { FREE(buffer); fclose(f); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } @@ -417,7 +436,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if (rc != 1) { FREE(buffer); fclose(f); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } @@ -438,7 +460,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if (rc != 1) { FREE(buffer); fclose(f); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } @@ -448,7 +473,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if ((rc != 1) || (strcmp(buffer, "$group_num$") != 0)) { FREE(buffer); fclose(f); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } @@ -457,7 +485,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if (rc != 1) { FREE(buffer); fclose(f); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } } @@ -471,7 +502,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if (rc != 1) { FREE(buffer); fclose(f); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } @@ -480,8 +514,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if ((rc != 1) || (strcmp(buffer, "$group_str$") != 0)) { FREE(buffer); fclose(f); - FREE($group$->$group_str$); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } @@ -492,8 +528,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if ($group$->$group_str$ == NULL) { FREE(buffer); fclose(f); - FREE($group$->$group_str$); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } @@ -502,8 +540,10 @@ trexio_text_read_$group$ (trexio_text_t* const file) if (rc != 1) { FREE(buffer); fclose(f); - FREE($group$->$group_str$); - FREE($group$); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + file->$group$ = $group$; + rc_free = trexio_text_free_$group$(file); + assert(rc_free == TREXIO_SUCCESS); return NULL; } diff --git a/tools/generator_tools.py b/tools/generator_tools.py index ddd0dad..c58e5f4 100644 --- a/tools/generator_tools.py +++ b/tools/generator_tools.py @@ -311,8 +311,6 @@ def special_populate_text_group(fname: str, paths: dict, group_dict: dict, detai subloop_dset = False subloop_num = False loop_body = '' - dset_allocated = [] - str_allocated = [] for line in f_in : @@ -335,25 +333,12 @@ def special_populate_text_group(fname: str, paths: dict, group_dict: dict, detai if ('REPEAT GROUP_DSET_NUM' in line) and (detailed_dset[dset]['group_dset_dtype'] == 'char*'): continue - dset_allocated.append(dset) - - if 'FREE($group$->$group_dset$)' in loop_body: - tmp_string = '' - for dset_alloc in dset_allocated: - tmp_string += f'FREE({group}->{dset_alloc});\n ' - - tmp_body = loop_body.replace('FREE($group$->$group_dset$);', tmp_string) - - populated_body = recursive_replace_line(tmp_body, triggers, detailed_dset[dset]) - f_out.write(populated_body) - else: - save_body = loop_body - populated_body = recursive_replace_line(save_body, triggers, detailed_dset[dset]) - f_out.write(populated_body) + save_body = loop_body + populated_body = recursive_replace_line(save_body, triggers, detailed_dset[dset]) + f_out.write(populated_body) subloop_dset = False loop_body = '' - dset_allocated = [] continue elif 'END REPEAT GROUP_NUM' in line: @@ -374,26 +359,12 @@ def special_populate_text_group(fname: str, paths: dict, group_dict: dict, detai if group != detailed_strings[str]['group']: continue - str_allocated.append(str) - - if 'FREE($group$->$group_str$)' in loop_body: - tmp_string = '' - for str_alloc in str_allocated: - tmp_string += f'FREE({group}->{str_alloc});\n ' - - tmp_body = loop_body.replace('FREE($group$->$group_str$);', tmp_string) - - populated_body = recursive_replace_line(tmp_body, triggers, detailed_strings[str]) - f_out.write(populated_body) - else: - save_body = loop_body - populated_body = recursive_replace_line(save_body, triggers, detailed_strings[str]) - f_out.write(populated_body) + save_body = loop_body + populated_body = recursive_replace_line(save_body, triggers, detailed_strings[str]) + f_out.write(populated_body) subloop_num = False loop_body = '' - str_allocated = [] - continue if not subloop_num and not subloop_dset: From d95e37e6ab5cd30fb33654ff0555dc08e91ab53a Mon Sep 17 00:00:00 2001 From: q-posev Date: Mon, 14 Feb 2022 11:16:17 +0100 Subject: [PATCH 3/3] update ChangeLog --- ChangeLog | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4141f58..f5baf15 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,14 +1,15 @@ -CHANGES +CHANGES ======= 2.2 --- +- Fixed backwards incompatibility of the `TREXIO_TEXT` back end in #82 - Added `TREXIO_AUTO` back end for read-only mode (`r`) in PR #80 - Added unsafe mode (`u`) to `trexio_open`. When enabled, data can be -overwritten (using conventional `trexio_write`) and groups can be deleted -(using new set of `trexio_delete_[group]` functions). Also added `unsafe` -attribute to the `metadata` group to indicate that the file might be +overwritten (using conventional `trexio_write`) and groups can be deleted +(using new set of `trexio_delete_[group]` functions). Also added `unsafe` +attribute to the `metadata` group to indicate that the file might be inconsistent. See PR #79 - Added `trexio_info` function (prints basic info about the library) in PR #78 - Added `trexio_inquire` function (checks validity of TREXIO files) in PR #75 @@ -59,4 +60,3 @@ access to both local and non-local quantities - Using libtool/automake - Rewrote generator -