Views: implemented handling of JSON formatted comments
This commit is contained in:
247
src/obiview.c
247
src/obiview.c
@ -38,6 +38,7 @@
|
||||
#include "linked_list.h"
|
||||
#include "utils.h"
|
||||
#include "obiblob.h"
|
||||
#include "libjson/json_utils.h"
|
||||
|
||||
|
||||
#define DEBUG_LEVEL 0 // TODO has to be defined somewhere else (cython compil flag?)
|
||||
@ -122,24 +123,6 @@ static size_t get_platform_view_file_size();
|
||||
static int enlarge_view_file(Obiview_p view, size_t new_size);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Internal function writing new comments in a view file.
|
||||
*
|
||||
* The new comments are concatenated to the pre-existing ones.
|
||||
* The view file is enlarged if necessary.
|
||||
*
|
||||
* @param view A pointer on the view.
|
||||
* @param comments The new comments that should be added.
|
||||
*
|
||||
* @retval 0 if the operation was successfully completed.
|
||||
* @retval -1 if an error occurred.
|
||||
*
|
||||
* @since August 2016
|
||||
* @author Celine Mercier (celine.mercier@metabarcoding.org)
|
||||
*/
|
||||
static int write_comments_to_view_file(Obiview_p view, const char* comments);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Internal function creating a file containing all the informations on a view.
|
||||
*
|
||||
@ -490,14 +473,15 @@ static char* view_check_one_predicate(Obiview_p view, char* (*predicate_function
|
||||
* @brief Internal function checking all the predicates associated with a view.
|
||||
*
|
||||
* @param view The view.
|
||||
* @param write Whether the verified predicates should be written in the view comments.
|
||||
*
|
||||
* @returns A character string describing all the predicates separated by line breaks.
|
||||
* @retval NULL if at least one of the predicates is false or if there was an error.
|
||||
* @retval 0 if the operation was successfully completed.
|
||||
* @retval -1 if at least one of the predicates is false or if there was an error.
|
||||
*
|
||||
* @since July 2016
|
||||
* @author Celine Mercier (celine.mercier@metabarcoding.org)
|
||||
*/
|
||||
static char* view_check_all_predicates(Obiview_p view);
|
||||
static int view_check_all_predicates(Obiview_p view, bool write);
|
||||
|
||||
|
||||
/************************************************************************
|
||||
@ -694,30 +678,6 @@ static int enlarge_view_file(Obiview_p view, size_t new_size)
|
||||
}
|
||||
|
||||
|
||||
static int write_comments_to_view_file(Obiview_p view, const char* comments)
|
||||
{
|
||||
size_t new_size;
|
||||
|
||||
if (comments == NULL)
|
||||
return 0; // TODO or error? discuss
|
||||
|
||||
new_size = (view->infos)->used_size + strlen(comments);
|
||||
|
||||
// Check if the file has to be enlarged
|
||||
if (new_size >= (view->infos)->file_size)
|
||||
{
|
||||
if (enlarge_view_file(view, new_size) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcat((view->infos)->comments, comments);
|
||||
|
||||
(view->infos)->used_size = new_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int create_obiview_file(OBIDMS_p dms, const char* view_name)
|
||||
{
|
||||
char* file_name;
|
||||
@ -1067,7 +1027,6 @@ static int rename_finished_view(Obiview_p view)
|
||||
|
||||
static int finish_view(Obiview_p view)
|
||||
{
|
||||
char* predicates;
|
||||
int i;
|
||||
OBIDMS_column_p column;
|
||||
|
||||
@ -1100,16 +1059,11 @@ static int finish_view(Obiview_p view)
|
||||
}
|
||||
|
||||
// Check predicates
|
||||
predicates = view_check_all_predicates(view);
|
||||
if (predicates == NULL)
|
||||
if (view_check_all_predicates(view, true) < 0)
|
||||
{
|
||||
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, view rollbacked");
|
||||
obi_rollback_view(view); // TODO discuss, maybe never call from C layer
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (save_view(view) < 0)
|
||||
@ -1419,9 +1373,9 @@ static char* view_check_qual_match_seqs(Obiview_p view)
|
||||
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))
|
||||
if ((size_t)qual_len != strlen(seq))
|
||||
{
|
||||
obidebug(1, "\nError checking the predicate for view %s: The sequences and sequence quality arrays match. \n%d, %s, %d", (view->infos)->name, j, seq, qual_len);
|
||||
obidebug(1, "\nError checking the predicate for view %s: The sequences and sequence quality arrays match.", (view->infos)->name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -1471,78 +1425,37 @@ static char* view_check_one_predicate(Obiview_p view, char* (*predicate_function
|
||||
}
|
||||
|
||||
|
||||
static char* view_check_all_predicates(Obiview_p view)
|
||||
static int view_check_all_predicates(Obiview_p view, bool write)
|
||||
{
|
||||
int i, j;
|
||||
size_t size_to_allocate;
|
||||
int i;
|
||||
char* predicate = NULL;
|
||||
char* all_predicates_string = NULL;
|
||||
char** all_predicates = NULL;
|
||||
|
||||
if (view->nb_predicates == 0)
|
||||
{
|
||||
all_predicates_string = (char*) malloc(1*sizeof(char));
|
||||
strcpy(all_predicates_string, "");
|
||||
return all_predicates_string;
|
||||
}
|
||||
|
||||
size_to_allocate = 0;
|
||||
|
||||
// Allocate memory for predicate array
|
||||
all_predicates = (char**) malloc((view->nb_predicates) * sizeof(char*));
|
||||
if (all_predicates == NULL)
|
||||
{
|
||||
obi_set_errno(OBI_MALLOC_ERROR);
|
||||
obidebug(1, "\nError allocating memory for predicate array.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=0; i < view->nb_predicates; i++)
|
||||
{
|
||||
// Initialize predicate in predicate array
|
||||
all_predicates[i] = NULL;
|
||||
// Check the predicate
|
||||
// Check predicate
|
||||
predicate = view_check_one_predicate(view, (view->predicate_functions)[i]);
|
||||
if (predicate == NULL)
|
||||
{
|
||||
// TODO discuss
|
||||
for (j=0; j<=i; j++)
|
||||
free(all_predicates[j]);
|
||||
free(all_predicates);
|
||||
return NULL;
|
||||
// TODO discuss what to do
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
all_predicates[i] = predicate;
|
||||
size_to_allocate = size_to_allocate + strlen(predicate) + 1; // +1 for '\n'
|
||||
}
|
||||
}
|
||||
|
||||
size_to_allocate += 1; // +1 for '\0'
|
||||
|
||||
all_predicates_string = (char*) malloc(size_to_allocate * sizeof(char));
|
||||
if (all_predicates_string == NULL)
|
||||
if ((write) && (predicate[0]!='\0'))
|
||||
{
|
||||
obi_set_errno(OBI_MALLOC_ERROR);
|
||||
obidebug(1, "\nError allocating memory for predicate character string.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Build the character string with all the predicates
|
||||
strcpy(all_predicates_string, all_predicates[0]);
|
||||
for (i=1; i < view->nb_predicates; i++)
|
||||
// Add predicate in comments
|
||||
if (obi_view_add_comment(view, PREDICATE_KEY, predicate) < 0)
|
||||
{
|
||||
if (strlen(all_predicates_string)) // First predicate not empty
|
||||
strcat(all_predicates_string, "\n");
|
||||
strcat(all_predicates_string, all_predicates[i]);
|
||||
obi_set_errno(OBIVIEW_ERROR);
|
||||
obidebug(1, "\nError adding a verified predicate (%s) in the comments of a view.", predicate);
|
||||
free(predicate);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Free everything
|
||||
for (i=0; i < view->nb_predicates; i++)
|
||||
free(all_predicates[i]);
|
||||
free(all_predicates);
|
||||
|
||||
return all_predicates_string;
|
||||
}
|
||||
free(predicate);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1561,8 +1474,8 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl
|
||||
Obiview_p view;
|
||||
int i;
|
||||
index_t line_nb;
|
||||
char* clone_comment;
|
||||
OBIDMS_column_p column;
|
||||
int comments_ok;
|
||||
|
||||
// Check that the DMS is a valid pointer
|
||||
if (dms == NULL)
|
||||
@ -1708,27 +1621,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);
|
||||
|
||||
// Write comment specifying the name of the cloned view
|
||||
clone_comment = (char*) malloc((strlen((view_to_clone->infos)->name) + 15)*sizeof(char));
|
||||
if (clone_comment == NULL)
|
||||
{
|
||||
obi_set_errno(OBI_MALLOC_ERROR);
|
||||
obidebug(1, "\nError allocating memory for a view comment");
|
||||
return NULL;
|
||||
}
|
||||
if (sprintf(clone_comment, "Cloned from %s.\n", (view_to_clone->infos)->name) < 0)
|
||||
{
|
||||
obi_set_errno(OBIVIEW_ERROR);
|
||||
obidebug(1, "\nError building a view comment");
|
||||
return NULL;
|
||||
}
|
||||
if (write_comments_to_view_file(view, clone_comment) < 0)
|
||||
{
|
||||
obidebug(1, "\nError writing comments when creating a view");
|
||||
close_view(view);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Else, fill empty view structure
|
||||
@ -1759,13 +1651,29 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl
|
||||
(view->predicate_functions)[0] = view_check_qual_match_seqs;
|
||||
|
||||
// Write comments
|
||||
if (write_comments_to_view_file(view, comments) < 0)
|
||||
// Comments must be a json string, even empty
|
||||
if ((strcmp(comments, "") == 0) || (comments == NULL))
|
||||
comments_ok = obi_view_write_comments(view, "{}");
|
||||
else
|
||||
comments_ok = obi_view_write_comments(view, comments);
|
||||
if (comments_ok < 0)
|
||||
{
|
||||
obidebug(1, "\nError writing comments when creating a view");
|
||||
close_view(view);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add the comment specifying the name of the cloned view if there is one
|
||||
if (view_to_clone != NULL)
|
||||
{
|
||||
if (obi_view_add_comment(view, "Cloned from", (view_to_clone->infos)->name) < 0)
|
||||
{
|
||||
obidebug(1, "\nError adding comment about cloned view when creating a view");
|
||||
close_view(view);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Store reference for line selection
|
||||
if (view->line_selection == NULL)
|
||||
{
|
||||
@ -2524,6 +2432,69 @@ int obi_view_create_column_alias(Obiview_p view, const char* current_name, const
|
||||
}
|
||||
|
||||
|
||||
int obi_view_write_comments(Obiview_p view, const char* comments)
|
||||
{
|
||||
size_t new_size;
|
||||
|
||||
// Check that the view is not read-only
|
||||
if (view->read_only)
|
||||
{
|
||||
obi_set_errno(OBIVIEW_ERROR);
|
||||
obidebug(1, "\nError trying to write comments in a read-only view");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (comments == NULL)
|
||||
return 0; // TODO or error? discuss
|
||||
|
||||
new_size = sizeof(Obiview_infos_t) + strlen(comments) + 1;
|
||||
|
||||
// Check if the file has to be enlarged
|
||||
if (new_size >= (view->infos)->file_size)
|
||||
{
|
||||
if (enlarge_view_file(view, new_size) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy((view->infos)->comments, comments);
|
||||
|
||||
(view->infos)->used_size = new_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int obi_view_add_comment(Obiview_p view, const char* key, const char* value)
|
||||
{
|
||||
char* new_comments = NULL;
|
||||
|
||||
// Check that the view is not read-only
|
||||
if (view->read_only)
|
||||
{
|
||||
obi_set_errno(OBIVIEW_ERROR);
|
||||
obidebug(1, "\nError trying to add a comment to a read-only view");
|
||||
return -1;
|
||||
}
|
||||
|
||||
new_comments = obi_add_comment((view->infos)->comments, key, value);
|
||||
if (new_comments == NULL)
|
||||
{
|
||||
obidebug(1, "\nError adding a comment to a view, key: %s, value: %s", key, value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (obi_view_write_comments(view, new_comments) < 0)
|
||||
{
|
||||
obidebug(1, "\nError adding a comment to a view, key: %s, value: %s", key, value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(new_comments);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int obi_save_and_close_view(Obiview_p view)
|
||||
{
|
||||
// Finish and save the view if it is not read-only
|
||||
|
@ -59,6 +59,8 @@
|
||||
*/
|
||||
#define ID_PREFIX "seq" /**< The default prefix of sequence identifiers in automatic ID columns.
|
||||
*/
|
||||
#define PREDICATE_KEY "predicates" /**< The key used in the json-formatted view comments to store predicates.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
@ -484,6 +486,44 @@ OBIDMS_column_p* obi_view_get_pointer_on_column_in_view(Obiview_p view, const ch
|
||||
int obi_view_create_column_alias(Obiview_p view, const char* current_name, const char* alias);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Internal function writing new comments in a view file.
|
||||
*
|
||||
* The new comments replace the pre-existing ones.
|
||||
* The view file is enlarged if necessary.
|
||||
*
|
||||
* @param view A pointer on the view.
|
||||
* @param comments The new comments that should be written.
|
||||
*
|
||||
* @retval 0 if the operation was successfully completed.
|
||||
* @retval -1 if an error occurred.
|
||||
*
|
||||
* @since August 2016
|
||||
* @author Celine Mercier (celine.mercier@metabarcoding.org)
|
||||
*/
|
||||
int obi_view_write_comments(Obiview_p view, const char* comments);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds comments to a view file.
|
||||
*
|
||||
* This reads the comments in the JSON format and adds the key value pair.
|
||||
* If the key already exists, the value format is turned into an array and the new value is appended
|
||||
* if it is not already in the array.
|
||||
*
|
||||
* @param column A pointer on an OBIDMS column.
|
||||
* @param key The key.
|
||||
* @param value The value associated with the key.
|
||||
*
|
||||
* @retval 0 if the operation was successfully completed.
|
||||
* @retval -1 if an error occurred.
|
||||
*
|
||||
* @since August 2018
|
||||
* @author Celine Mercier (celine.mercier@metabarcoding.org)
|
||||
*/
|
||||
int obi_view_add_comment(Obiview_p view, const char* key, const char* value);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Closes an opened view, and saves it if it is not read-only (meaning it is not already saved in the view file).
|
||||
*
|
||||
|
Reference in New Issue
Block a user