From 5dadfb4371b8ba694b8d9431cb6789bf6de485c4 Mon Sep 17 00:00:00 2001 From: Dmitri Pal Date: Fri, 26 Nov 2010 23:11:07 -0500 Subject: New copy and folding functionality * Added method to copy configuration. * Added unit test for it. * Added method to reset boandary for the whole configuration. * Added unit test for it. * Unit test now can read a file save it read again and save. Both saves produce same files! * Reworked the way the parser was dealing with empty lines. It was sutting off the value in the middle if the folded line consisted of just spaces. --- ini/ini_configobj.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ini/ini_configobj.h | 4 ++ ini/ini_parse.c | 74 +++++++++++++-------------- ini/ini_parse_ut.c | 129 +++++++++++++++++++++++++++++++++-------------- 4 files changed, 274 insertions(+), 74 deletions(-) diff --git a/ini/ini_configobj.c b/ini/ini_configobj.c index 4da9a7c..3e5dec4 100644 --- a/ini/ini_configobj.c +++ b/ini/ini_configobj.c @@ -113,3 +113,144 @@ int ini_config_create(struct ini_cfgobj **ini_config) TRACE_FLOW_EXIT(); return error; } + +/* Callback to set the boundary */ +int ini_boundary_cb(const char *property, + int property_len, + int type, + void *data, + int length, + void *custom_data, + int *dummy) +{ + int error = EOK; + struct value_obj *vo = NULL; + uint32_t boundary; + + TRACE_FLOW_ENTRY(); + + boundary = *((uint32_t *)(custom_data)); + /* Banary items are the values */ + if(type == COL_TYPE_BINARY) { + vo = *((struct value_obj **)(data)); + error = value_set_boundary(vo, boundary); + } + + TRACE_FLOW_EXIT(); + return error; +} + +/* Set the folding boundary for multiline values. + * Use before serializing and saving to a file if the + * default boundary of 80 characters does not work for you. + */ +int ini_config_set_wrap(struct ini_cfgobj *ini_config, + uint32_t boundary) +{ + int error = EOK; + + TRACE_FLOW_ENTRY(); + + if (!ini_config) { + TRACE_ERROR_NUMBER("Invalid argument", EINVAL); + return EINVAL; + } + + ini_config->boundary = boundary; + error = col_traverse_collection(ini_config->cfg, + COL_TRAVERSE_DEFAULT, + ini_boundary_cb, + (void *)(&(ini_config->boundary))); + if (error) { + TRACE_ERROR_NUMBER("Failed to set wrapping boundary", error); + return error; + } + + + TRACE_FLOW_EXIT(); + return error; +} + +/* Configuration copy callback */ +static int ini_copy_cb(struct collection_item *item, + void *ext_data, + int *skip) +{ + int error = EOK; + struct value_obj *vo = NULL; + struct value_obj *new_vo = NULL; + + TRACE_FLOW_ENTRY(); + + ext_data = NULL; + *skip = 0; + + /* Banary items are the values */ + if(col_get_item_type(item) == COL_TYPE_BINARY) { + vo = *((struct value_obj **)(col_get_item_data(item))); + + error = value_copy(vo, &new_vo); + if (error) { + TRACE_ERROR_NUMBER("Failed to copy value", error); + return error; + } + + error = col_modify_binary_item(item, + NULL, + &new_vo, + sizeof(struct value_obj *)); + if (error) { + TRACE_ERROR_NUMBER("Failed to copy value", error); + value_destroy(new_vo); + return error; + } + } + + TRACE_FLOW_EXIT(); + return error; +} + +/* Copy configuration */ +int ini_config_copy(struct ini_cfgobj *ini_config, + struct ini_cfgobj **ini_new) +{ + int error = EOK; + struct ini_cfgobj *new_co; + + TRACE_FLOW_ENTRY(); + + if ((!ini_config) || + (!ini_new)) { + TRACE_ERROR_NUMBER("Invalid argument", EINVAL); + return EINVAL; + } + + /* Create a new configuration object */ + errno = 0; + new_co = malloc(sizeof(struct ini_cfgobj)); + if (!new_co) { + error = errno; + TRACE_ERROR_NUMBER("Failed to allocate memory", ENOMEM); + return ENOMEM; + } + + new_co->cfg = NULL; + new_co->boundary = ini_config->boundary; + + error = col_copy_collection_with_cb(&(new_co->cfg), + ini_config->cfg, + INI_CONFIG_NAME, + COL_COPY_NORMAL, + ini_copy_cb, + NULL); + if (error) { + TRACE_ERROR_NUMBER("Failed to copy collection", error); + ini_config_destroy(new_co); + return error; + } + + *ini_new = new_co; + + TRACE_FLOW_EXIT(); + return error; +} diff --git a/ini/ini_configobj.h b/ini/ini_configobj.h index 81578c0..21198db 100644 --- a/ini/ini_configobj.h +++ b/ini/ini_configobj.h @@ -138,6 +138,10 @@ void ini_config_free_errors(char **errors); int ini_config_parse(struct ini_cfgfile *file_ctx, struct ini_cfgobj *ini_config); +/* Copy configuration */ +int ini_config_copy(struct ini_cfgobj *ini_config, + struct ini_cfgobj **ini_new); + /* Function to print errors from the list */ void ini_print_errors(FILE *file, char **error_list); diff --git a/ini/ini_parse.c b/ini/ini_parse.c index 253b78b..c92a163 100644 --- a/ini/ini_parse.c +++ b/ini/ini_parse.c @@ -79,6 +79,20 @@ typedef int (*action_fn)(struct parser_obj *); #define PARSE_DONE 4 /* We are done */ +int is_just_spaces(const char *str, uint32_t len) +{ + uint32_t i; + + TRACE_FLOW_ENTRY(); + + for (i = 0; i < len; i++) { + if (!isspace(str[i])) return 0; + } + + TRACE_FLOW_EXIT(); + return 1; +} + /* Destroy parser object */ void parser_destroy(struct parser_obj *po) @@ -401,14 +415,24 @@ static int handle_space(struct parser_obj *po, uint32_t *action) *action = PARSE_READ; } else { - /* We do not have an active value - * but have a line is starting with a space. - * For now it is error. - * We can change it in future if - * people find it being too restrictive - */ - *action = PARSE_ERROR; - po->last_error = ERR_SPACE; + /* Check if this is a completely empty line */ + if (is_just_spaces(po->last_read, po->last_read_len)) { + error = handle_comment(po, action); + if (error) { + TRACE_ERROR_NUMBER("Failed to process comment", error); + return error; + } + } + else { + /* We do not have an active value + * but have a line is starting with a space. + * For now it is error. + * We can change it in future if + * people find it being too restrictive + */ + *action = PARSE_ERROR; + po->last_error = ERR_SPACE; + } } TRACE_FLOW_EXIT(); @@ -425,6 +449,8 @@ static int handle_kvp(struct parser_obj *po, uint32_t *action) TRACE_FLOW_ENTRY(); + TRACE_INFO_STRING("Last read:", po->last_read); + /* We got a line with KVP */ if (*(po->last_read) == '=') { po->last_error = ERR_NOKEY; @@ -681,20 +707,6 @@ static int handle_section(struct parser_obj *po, uint32_t *action) } -int is_just_spaces(const char *str, uint32_t len) -{ - uint32_t i; - - TRACE_FLOW_ENTRY(); - - for (i = 0; i < len; i++) { - if (!isspace(str[i])) return 0; - } - - TRACE_FLOW_EXIT(); - return 1; -} - /* Inspect the line */ static int parser_inspect(struct parser_obj *po) { @@ -716,20 +728,10 @@ static int parser_inspect(struct parser_obj *po) else if ((*(po->last_read) == ' ') || (*(po->last_read) == '\t')) { - /* Check if this is a completely empty line */ - if (is_just_spaces(po->last_read, po->last_read_len)) { - error = handle_comment(po, &action); - if (error) { - TRACE_ERROR_NUMBER("Failed to process comment", error); - return error; - } - } - else { - error = handle_space(po, &action); - if (error) { - TRACE_ERROR_NUMBER("Failed to process line wrapping", error); - return error; - } + error = handle_space(po, &action); + if (error) { + TRACE_ERROR_NUMBER("Failed to process line wrapping", error); + return error; } } else if (*(po->last_read) == '[') { diff --git a/ini/ini_parse_ut.c b/ini/ini_parse_ut.c index 01b7077..cc37c21 100644 --- a/ini/ini_parse_ut.c +++ b/ini/ini_parse_ut.c @@ -23,13 +23,16 @@ #include #include #include +#include #include "ini_defines.h" #include "ini_configobj.h" +#include "ini_config_priv.h" #include "simplebuffer.h" #include "path_utils.h" #include "config.h" #define TRACE_HOME #include "trace.h" +#include "collection_tools.h" int verbose = 0; char *confdir = NULL; @@ -41,19 +44,19 @@ char *confdir = NULL; typedef int (*test_fn)(void); -int test_one_file(const char *filename) +int test_one_file(const char *in_filename, + const char *out_filename) { int error = EOK; struct ini_cfgfile *file_ctx = NULL; FILE *ff = NULL; - char new_file[100]; struct ini_cfgobj *ini_config = NULL; + struct ini_cfgobj *ini_copy = NULL; char **error_list = NULL; struct simplebuffer *sbobj = NULL; uint32_t left = 0; - char filename_base[96]; - INIOUT(printf("<==== Testing file %s ====>\n", filename)); + INIOUT(printf("<==== Testing file %s ====>\n", in_filename)); /* Create config collection */ error = ini_config_create(&ini_config); @@ -62,7 +65,7 @@ int test_one_file(const char *filename) return error; } - error = ini_config_file_open(filename, + error = ini_config_file_open(in_filename, INI_STOP_ON_NONE, 0, /* TBD */ 0, /* TBD */ @@ -83,12 +86,35 @@ int test_one_file(const char *filename) ini_config_get_filename(file_ctx))); ini_config_get_errors(file_ctx, &error_list); INIOUT(ini_print_errors(stdout, error_list)); + ini_config_free_errors(error_list); } /* We do not return here intentionally */ } ini_config_file_close(file_ctx); + INIOUT(col_debug_collection(ini_config->cfg, COL_TRAVERSE_DEFAULT)); + + /* Copy configuration */ + error = ini_config_copy(ini_config, &ini_copy); + if (error) { + printf("Failed to copy configuration. Error %d.\n", error); + ini_config_destroy(ini_config); + return error; + } + + ini_config_destroy(ini_config); + ini_config = ini_copy; + + INIOUT(col_debug_collection(ini_config->cfg, COL_TRAVERSE_DEFAULT)); + + error = ini_config_set_wrap(ini_config, 5); + if (error) { + printf("Failed to set custom wrapper. Error %d.\n", error); + ini_config_destroy(ini_config); + return error; + } + error = simplebuffer_alloc(&sbobj); if (error) { TRACE_ERROR_NUMBER("Failed to allocate dynamic string.", error); @@ -104,11 +130,8 @@ int test_one_file(const char *filename) return error; } - error = get_basename(filename_base, 96, filename); - sprintf(new_file, "%s.out", filename_base); - errno = 0; - ff = fopen(new_file, "w"); + ff = fopen(out_filename, "w"); if(!ff) { error = errno; printf("Failed to open file for writing. Error %d.\n", error); @@ -143,41 +166,79 @@ int read_save_test(void) { int error = EOK; int i = 0; - int lasterr = EOK; - char *files[5]; - - files[0] = malloc(sizeof(char)*512); - sprintf(files[0], "%s/ini.d/real.conf", confdir); - files[1] = malloc(sizeof(char)*512); - sprintf(files[1], "%s/ini.d/mysssd.conf", confdir); - files[2] = malloc(sizeof(char)*512); - sprintf(files[2], "%s/ini.d/ipa.conf", confdir); - files[3] = malloc(sizeof(char)*512); - sprintf(files[3], "%s/ini.d/test.conf", confdir); - files[4] = NULL; + char infile[PATH_MAX]; + char outfile[PATH_MAX]; + char *srcdir; + const char *files[] = { "real", + "mysssd", + "ipa", + "test", + NULL }; + + + srcdir = getenv("srcdir"); while(files[i]) { - error = test_one_file(files[i]); - INIOUT(printf("Test fo file: %s returned %d\n", files[i], error)); - if (error) lasterr = error; + + sprintf(infile, "%s/ini/ini.d/%s.conf", (srcdir == NULL) ? "." : srcdir, + files[i]); + sprintf(outfile, "%s/%s.conf.out", (srcdir == NULL) ? "." : srcdir, + files[i]); + error = test_one_file(infile, outfile); + INIOUT(printf("Test for file: %s returned %d\n", files[i], error)); i++; } - free(files[3]); - free(files[2]); - free(files[1]); - free(files[0]); + return EOK; +} + +/* Run tests for multiple files */ +int read_again_test(void) +{ + int error = EOK; + int i = 0; + char infile[PATH_MAX]; + char outfile[PATH_MAX]; + char *srcdir; + char command[PATH_MAX * 3]; + const char *files[] = { "real", + "mysssd", + "ipa", + "test", + NULL }; + - return lasterr; + srcdir = getenv("srcdir"); + + while(files[i]) { + + sprintf(infile, "%s/%s.conf.out", (srcdir == NULL) ? "." : srcdir, + files[i]); + sprintf(outfile, "%s/%s.conf.2.out", (srcdir == NULL) ? "." : srcdir, + files[i]); + error = test_one_file(infile, outfile); + INIOUT(printf("Test for file: %s returned %d\n", files[i], error)); + if (error) break; + sprintf(command,"diff -q %s %s", infile, outfile); + error = system(command); + INIOUT(printf("Comparison of %s %s returned: %d\n", + infile, outfile, error)); + if (error) break; + + i++; + } + + return error; } + /* Main function of the unit test */ int main(int argc, char *argv[]) { int error = 0; test_fn tests[] = { read_save_test, + read_again_test, NULL }; - char *srcdir; test_fn t; int i = 0; char *var; @@ -190,14 +251,6 @@ int main(int argc, char *argv[]) INIOUT(printf("Start\n")); - srcdir = getenv("srcdir"); - if(!srcdir) { - confdir = strdup("./ini"); - } else { - confdir = malloc(strlen(srcdir)+5*sizeof(char)); - sprintf(confdir, "%s/ini", srcdir); - } - while ((t = tests[i++])) { error = t(); if (error) { -- cgit