From f897e876003aaf7d4928883e8402447d9756c9a1 Mon Sep 17 00:00:00 2001 From: Celine Mercier Date: Fri, 25 Nov 2016 12:04:57 +0100 Subject: [PATCH] When closing a view, it is now automatically checked that all OBI_QUAL columns correspond to their associated OBI_SEQ column --- src/obiview.c | 221 +++++++++++++++++++++++++++----------------------- src/obiview.h | 5 +- 2 files changed, 125 insertions(+), 101 deletions(-) diff --git a/src/obiview.c b/src/obiview.c index f772655..37dba54 100644 --- a/src/obiview.c +++ b/src/obiview.c @@ -368,7 +368,7 @@ char* view_has_definition_column(Obiview_p view); /** - * @brief Internal function checking that the quality column of a view and the sequence column associated to it + * @brief Internal function checking that all the quality columns of a view and their associated sequence columns * correspond properly: * - when a line is defined for either column, it must also be defined for the other column * - when a line is defined, the lengths of the sequence and of the quality must be equal @@ -381,7 +381,7 @@ char* view_has_definition_column(Obiview_p view); * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -char* view_check_quality_matches_seq_column(Obiview_p view); +char* view_check_qual_match_seqs(Obiview_p view); /** @@ -960,9 +960,9 @@ char* view_has_definition_column(Obiview_p view) } -char* view_check_quality_matches_seq_column(Obiview_p view) // TODO Print error if there is one? +char* view_check_qual_match_seqs(Obiview_p view) { - index_t i, j; + index_t i, j, k; index_t nb_elements_per_line; int qual_len; const uint8_t* qual; @@ -970,68 +970,84 @@ char* view_check_quality_matches_seq_column(Obiview_p view) // TODO Print error OBIDMS_column_p qual_column; OBIDMS_column_p seq_column; char* predicate; + bool at_least_one_qual_col; - predicate = (char*) malloc((strlen("The sequences and sequence quality arrays match.") + 1) * sizeof(char)); - if (predicate == NULL) + // Go through all columns in the view and check the predicate for all quality columns + at_least_one_qual_col = false; + for (i=0; i < ((view->infos)->column_count); i++) { - obi_set_errno(OBI_MALLOC_ERROR); - obidebug(1, "\nError allocating memory for predicate character string."); - return NULL; - } - - strcpy(predicate, "The sequences and sequence quality arrays match."); - - qual_column = obi_view_get_column(view, QUALITY_COLUMN); - if (qual_column == NULL) - { - obidebug(1, "\nError checking the predicate: %s", predicate); - return NULL; - } - - seq_column = obi_view_get_column(view, ((qual_column->header)->associated_column).column_name); - //seq_column = obi_open_column(view->dms, ((qual_column->header)->associated_column).column_name, ((qual_column->header)->associated_column).version); - // TODO discuss the fact that it's opened outside of the context of the view or not -> problem if alias. Open from full refs maybe - // TODO if outside of view, make function that opens a column from a column reference structure? - - if (seq_column == NULL) - { - obidebug(1, "\nError checking the predicate: %s", predicate); - return NULL; - } - - nb_elements_per_line = (qual_column->header)->nb_elements_per_line; - // Check that the quality and the sequence columns have the same number of elements per line - if (nb_elements_per_line != (seq_column->header)->nb_elements_per_line) - { - obidebug(1, "\nError checking the predicate: %s", predicate); - return NULL; - } - - for (i=0; i < (view->infos)->line_count; i++) - { - for (j=0; j < nb_elements_per_line; j++) + // Check if it's a quality column + if ((((view->columns)[i])->header)->returned_data_type == OBI_QUAL) { - qual = obi_column_get_obiqual_int_with_elt_idx(qual_column, i, j, &qual_len); - seq = obi_column_get_obiseq_with_elt_idx(seq_column, i, j); - if ((qual != OBIQual_int_NA) && (seq != OBISeq_NA)) + at_least_one_qual_col = true; + // Check that the quality arrays match the sequences of the associated column + qual_column = (view->columns)[i]; + seq_column = obi_open_column(view->dms, ((qual_column->header)->associated_column).column_name, ((qual_column->header)->associated_column).version); + if (seq_column == NULL) { - // Test that the lengths of the quality and the sequence are equal - if (qual_len != (int)strlen(seq)) - { - obidebug(1, "\nError checking the predicate: %s", predicate); - return NULL; - } - } - // Test if one value is NA and not the other - else if (((qual == OBIQual_int_NA) && (seq != OBISeq_NA)) || ((qual != OBIQual_int_NA) && (seq == OBISeq_NA))) - { - obidebug(1, "\nError checking the predicate: %s", predicate); + obidebug(1, "\nError checking the predicate: The sequences and sequence quality arrays match."); return NULL; } + + nb_elements_per_line = (qual_column->header)->nb_elements_per_line; + // Check that the quality and the sequence columns have the same number of elements per line + if (nb_elements_per_line != (seq_column->header)->nb_elements_per_line) + { + obidebug(1, "\nError checking the predicate: The sequences and sequence quality arrays match."); + return NULL; + } + + // Check each sequence and its sequence + for (j=0; j < (view->infos)->line_count; j++) + { + for (k=0; k < nb_elements_per_line; k++) + { + qual = obi_get_qual_int_with_elt_idx_and_col_p_in_view(view, qual_column, j, k, &qual_len); + seq = obi_get_seq_with_elt_idx_and_col_p_in_view(view, seq_column, j, k); + if ((qual != OBIQual_int_NA) && (seq != OBISeq_NA)) + { + // Test that the lengths of the quality and the sequence are equal + if (qual_len != (int)strlen(seq)) + { + obidebug(1, "\nError checking the predicate: The sequences and sequence quality arrays match."); + return NULL; + } + } + // Test if one value is NA and not the other + else if (((qual == OBIQual_int_NA) && (seq != OBISeq_NA)) || ((qual != OBIQual_int_NA) && (seq == OBISeq_NA))) + { + obidebug(1, "\nError checking the predicate: The sequences and sequence quality arrays match."); + return NULL; + } + } + } + + obi_close_column(seq_column); } } - //obi_close_column(seq_column); + if (at_least_one_qual_col) + { + predicate = (char*) malloc((strlen("The sequences and sequence quality arrays match.") + 1) * sizeof(char)); + if (predicate == NULL) + { + obi_set_errno(OBI_MALLOC_ERROR); + obidebug(1, "\nError allocating memory for predicate character string."); + return NULL; + } + strcpy(predicate, "The sequences and sequence quality arrays match."); + } + else + { + predicate = (char*) malloc(1 * sizeof(char)); + if (predicate == NULL) + { + obi_set_errno(OBI_MALLOC_ERROR); + obidebug(1, "\nError allocating memory for predicate character string."); + return NULL; + } + strcpy(predicate, ""); + } return predicate; } @@ -1051,11 +1067,11 @@ char* view_check_all_predicates(Obiview_p view) char* all_predicates_string = NULL; char** all_predicates = NULL; - if (view->nb_predicates == 0) // TODO or no error? discuss + if (view->nb_predicates == 0) { - obi_set_errno(OBIVIEW_ERROR); - obidebug(1, "\nError trying to check predicates of a view with no predicates."); - return NULL; + all_predicates_string = (char*) malloc(1*sizeof(char)); + strcpy(all_predicates_string, ""); + return all_predicates_string; } size_to_allocate = 0; @@ -1073,7 +1089,6 @@ char* view_check_all_predicates(Obiview_p view) { // Initialize predicate in predicate array all_predicates[i] = NULL; - // Check the predicate predicate = view_check_one_predicate(view, (view->predicate_functions)[i]); if (predicate == NULL) @@ -1105,7 +1120,8 @@ char* view_check_all_predicates(Obiview_p view) strcpy(all_predicates_string, all_predicates[0]); for (i=1; i < view->nb_predicates; i++) { - strcat(all_predicates_string, "\n"); + if (strlen(all_predicates_string)) // First predicate not empty + strcat(all_predicates_string, "\n"); strcat(all_predicates_string, all_predicates[i]); } @@ -1271,16 +1287,6 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl // Fill informations strcpy((view->infos)->view_type, (view_to_clone->infos)->view_type); strcpy((view->infos)->created_from, (view_to_clone->infos)->name); - // Copy predicates - view->nb_predicates = view_to_clone->nb_predicates; - if (view->nb_predicates > 0) - { - view->predicate_functions = malloc((view->nb_predicates) * sizeof(char* (*) (Obiview_p))); - for (i=0; i<(view->nb_predicates); i++) - (view->predicate_functions)[i] = (view_to_clone->predicate_functions)[i]; - } - else - view->predicate_functions = NULL; // Write comment specifying the name of the cloned view clone_comment = (char*) malloc((strlen((view_to_clone->infos)->name) + 15)*sizeof(char)); @@ -1313,8 +1319,6 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl view->line_selection = NULL; ((view->infos)->created_from)[0] = '\0'; ((view->infos)->view_type)[0] = '\0'; - view->nb_predicates = 0; - view->predicate_functions = NULL; //view->columns = NULL; // TODO } @@ -1322,6 +1326,18 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl strcpy((view->infos)->name, view_name); (view->infos)->creation_date = time(NULL); + // Fill automatic predicate functions + view->nb_predicates = 1; + view->predicate_functions = malloc((view->nb_predicates) * sizeof(char* (*) (Obiview_p))); + if (view->predicate_functions == NULL) + { + obi_set_errno(OBI_MALLOC_ERROR); + obidebug(1, "\nError allocating memory for view predicates"); + return NULL; + } + (view->predicate_functions)[0] = view_check_qual_match_seqs; + + // Write comments if (write_comments_to_view_file(view, comments) < 0) { obidebug(1, "\nError writing comments when creating a view"); @@ -1403,9 +1419,10 @@ Obiview_p obi_new_view_nuc_seqs(OBIDMS_p dms, const char* view_name, Obiview_p v { Obiview_p view; OBIDMS_column_p associated_nuc_column; + int nb_predicates; if (view_to_clone != NULL) - { // Check that the view to clone is already a NUC_SEQS view (TODO discuss possibility of transforming type of a view) + { // Check that the view to clone is already a NUC_SEQS view if (strcmp((view_to_clone->infos)->view_type, VIEW_TYPE_NUC_SEQS)) { obi_set_errno(OBIVIEW_ERROR); @@ -1452,25 +1469,34 @@ Obiview_p obi_new_view_nuc_seqs(OBIDMS_p dms, const char* view_name, Obiview_p v } } - // Add predicate functions of the view type + // Add predicate functions specific to the view type // TODO macros? if (quality_column) - view->nb_predicates = 5; + nb_predicates = view->nb_predicates + 4; else - view->nb_predicates = 3; + nb_predicates = view->nb_predicates + 3; - view->predicate_functions = malloc((view->nb_predicates) * sizeof(char* (*) (Obiview_p))); + if (view->nb_predicates == 0) + view->predicate_functions = malloc(nb_predicates * sizeof(char* (*) (Obiview_p))); + else + view->predicate_functions = realloc(view->predicate_functions, nb_predicates * sizeof(char* (*) (Obiview_p))); - (view->predicate_functions)[0] = view_has_nuc_sequence_column; - (view->predicate_functions)[1] = view_has_id_column; - (view->predicate_functions)[2] = view_has_definition_column; - if (quality_column) + if (view->predicate_functions == NULL) { - (view->predicate_functions)[3] = view_has_quality_column; - (view->predicate_functions)[4] = view_check_quality_matches_seq_column; + obi_set_errno(OBI_MALLOC_ERROR); + obidebug(1, "\nError allocating memory for view predicates"); + return NULL; } + (view->predicate_functions)[(view->nb_predicates)] = view_has_nuc_sequence_column; + (view->predicate_functions)[(view->nb_predicates) + 1] = view_has_id_column; + (view->predicate_functions)[(view->nb_predicates) + 2] = view_has_definition_column; + if (quality_column) + (view->predicate_functions)[(view->nb_predicates) + 3] = view_has_quality_column; + + view->nb_predicates = nb_predicates; + return view; } @@ -1825,8 +1851,6 @@ int obi_view_delete_column(Obiview_p view, const char* column_name) int i; bool found; - // TODO check that not deleting an obligatory column? - // Check that the view is not read-only if (view->read_only) { @@ -2020,19 +2044,16 @@ int obi_save_and_close_view(Obiview_p view) if (!(view->read_only)) { - if (view->nb_predicates > 0) + predicates = view_check_all_predicates(view); + if (predicates == NULL) { - predicates = view_check_all_predicates(view); - if (predicates == NULL) - { - obidebug(1, "\nView predicates not respected"); - return -1; // TODO reverse view (delete files) - } - else - { - write_comments_to_view_file(view, predicates); - free(predicates); - } + obidebug(1, "\nView predicates not respected"); + return -1; // TODO reverse view (delete files) + } + else + { + write_comments_to_view_file(view, predicates); + free(predicates); } if (obi_save_view(view) < 0) return -1; diff --git a/src/obiview.h b/src/obiview.h index 791bad7..f1ff1c5 100644 --- a/src/obiview.h +++ b/src/obiview.h @@ -464,7 +464,7 @@ int obi_save_view(Obiview_p view); /** * @brief Closes an opened view. * - * @warning Use obi_save_and_close_view() to automatically save the view if it's not already saved in the view file. + * @warning Uses obi_save_and_close_view() to automatically save the view if it's not already saved in the view file. * * @param view A pointer on the view. * @@ -481,6 +481,9 @@ int obi_close_view(Obiview_p view); /** * @brief Closes an opened view, and saves it if it is not read-only (meaning it is not already saved in the view file). * + * The predicates associated with the view are checked before saving it, and -1 is returned if at + * least one predicate is not respected. + * * @param view A pointer on the view. * * @returns A value indicating the success of the operation.