PengZheng commented on code in PR #470: URL: https://github.com/apache/celix/pull/470#discussion_r1382405959
########## libs/utils/src/properties.c: ########## @@ -191,324 +476,423 @@ static void parseLine(const char* line, celix_properties_t *props) { } if (!isComment) { - //printf("putting 'key'/'value' '%s'/'%s' in properties\n", utils_stringTrim(key), utils_stringTrim(value)); + // printf("putting 'key'/'value' '%s'/'%s' in properties\n", utils_stringTrim(key), utils_stringTrim(value)); celix_properties_set(props, celix_utils_trimInPlace(key), celix_utils_trimInPlace(value)); } - if(key) { + if (key) { free(key); - } - if(value) { free(value); } - } +celix_properties_t* celix_properties_loadWithStream(FILE* file) { + if (file == NULL) { + return NULL; + } -/********************************************************************************************************************** - ********************************************************************************************************************** - * Updated API - ********************************************************************************************************************** - **********************************************************************************************************************/ + celix_autoptr(celix_properties_t) props = celix_properties_create(); + if (!props) { + celix_err_push("Failed to create properties"); + return NULL; + } + int rc = fseek(file, 0, SEEK_END); + if (rc != 0) { + celix_err_pushf("Cannot seek to end of file. Got error %i", errno); + return NULL; + } + size_t fileSize = ftell(file); + rc = fseek(file, 0, SEEK_SET); + if (rc != 0) { + celix_err_pushf("Cannot seek to start of file. Got error %i", errno); + return NULL; + } + char* fileBuffer = malloc(fileSize + 1); + if (fileBuffer == NULL) { + celix_err_pushf("Cannot allocate memory for file buffer. Got error %i", errno); + return NULL; + } -celix_properties_t* celix_properties_create(void) { - return hashMap_create(utils_stringHash, utils_stringHash, utils_stringEquals, utils_stringEquals); -} + size_t rs = fread(fileBuffer, sizeof(char), fileSize, file); + if (rs < fileSize) { + fprintf(stderr, "fread read only %zu bytes out of %zu\n", rs, fileSize); + } + fileBuffer[fileSize] = '\0'; // ensure a '\0' at the end of the fileBuffer -void celix_properties_destroy(celix_properties_t *properties) { - if (properties != NULL) { - hash_map_iterator_pt iter = hashMapIterator_create(properties); - while (hashMapIterator_hasNext(iter)) { - hash_map_entry_pt entry = hashMapIterator_nextEntry(iter); - hashMapEntry_clear(entry, true, true); - } - hashMapIterator_destroy(iter); - hashMap_destroy(properties, false, false); + char* savePtr = NULL; + char* line = strtok_r(fileBuffer, "\n", &savePtr); + while (line != NULL) { + celix_properties_parseLine(line, props); + line = strtok_r(NULL, "\n", &savePtr); } + free(fileBuffer); + + return celix_steal_ptr(props); } -celix_properties_t* celix_properties_load(const char *filename) { - FILE *file = fopen(filename, "r"); - if (file == NULL) { +celix_properties_t* celix_properties_loadFromString(const char* input) { + celix_autoptr(celix_properties_t) props = celix_properties_create(); + celix_autofree char* in = celix_utils_strdup(input); + if (!props || !in) { + celix_err_push("Failed to create properties or duplicate input string"); return NULL; } - celix_properties_t *props = celix_properties_loadWithStream(file); - fclose(file); - return props; -} - -celix_properties_t* celix_properties_loadWithStream(FILE *file) { - celix_properties_t *props = NULL; - if (file != NULL ) { - char *saveptr; - char *filebuffer = NULL; - char *line = NULL; - ssize_t file_size = 0; - - props = celix_properties_create(); - fseek(file, 0, SEEK_END); - file_size = ftell(file); - fseek(file, 0, SEEK_SET); + char* line = NULL; + char* saveLinePointer = NULL; + line = strtok_r(in, "\n", &saveLinePointer); + while (line != NULL) { + celix_properties_parseLine(line, props); + line = strtok_r(NULL, "\n", &saveLinePointer); + } + return celix_steal_ptr(props); +} - if (file_size > 0) { - filebuffer = calloc(file_size + 1, sizeof(char)); - if (filebuffer) { - size_t rs = fread(filebuffer, sizeof(char), file_size, file); - if (rs != file_size) { - fprintf(stderr,"fread read only %lu bytes out of %lu\n", (long unsigned int) rs, (long unsigned int) file_size); - } - filebuffer[file_size]='\0'; - line = strtok_r(filebuffer, "\n", &saveptr); - while (line != NULL) { - parseLine(line, props); - line = strtok_r(NULL, "\n", &saveptr); - } - free(filebuffer); +/** + * @brief Store properties string to file and escape the characters '#', '!', '=' and ':' if encountered. + */ +static int celix_properties_storeEscapedString(FILE* file, const char* str) { + int rc = 0; + for (int i = 0; i < strlen(str); i += 1) { + if (str[i] == '#' || str[i] == '!' || str[i] == '=' || str[i] == ':') { + rc = fputc('\\', file); + if (rc == EOF) { + break; } } + rc = fputc(str[i], file); } - - return props; + return rc; } -celix_properties_t* celix_properties_loadFromString(const char *input) { - celix_properties_t *props = celix_properties_create(); +celix_status_t celix_properties_store(celix_properties_t* properties, const char* filename, const char* header) { + FILE* file = fopen(filename, "w+"); + + if (file == NULL) { + celix_err_pushf("Cannot open file '%s'", filename); + return CELIX_FILE_IO_EXCEPTION; + } - char *in = strdup(input); - char *line = NULL; - char *saveLinePointer = NULL; + int rc = 0; - bool firstTime = true; - do { - if (firstTime){ - line = strtok_r(in, "\n", &saveLinePointer); - firstTime = false; - }else { - line = strtok_r(NULL, "\n", &saveLinePointer); + if (header && strstr("\n", header)) { + celix_err_push("Header cannot contain newlines. Ignoring header."); + } else if (header) { + rc = fputc('#', file); + if (rc != 0) { + rc = fputs(header, file); } - - if (line == NULL){ - break; + if (rc != 0) { + rc = fputc('\n', file); } + } - parseLine(line, props); - } while(line != NULL); + CELIX_PROPERTIES_ITERATE(properties, iter) { + const char* val = iter.entry.value; + if (rc != EOF) { + rc = celix_properties_storeEscapedString(file, iter.key); + } + if (rc != EOF) { + rc = fputc('=', file); + } + if (rc != EOF) { + rc = celix_properties_storeEscapedString(file, val); + } + if (rc != EOF) { + rc = fputc('\n', file); + } + } + if (rc != EOF) { + rc = fclose(file); + } else { + fclose(file); + } + if (rc == EOF) { + celix_err_push("Failed to write properties to file"); + return CELIX_FILE_IO_EXCEPTION; + } + return CELIX_SUCCESS; +} - free(in); +celix_properties_t* celix_properties_copy(const celix_properties_t* properties) { + celix_properties_t* copy = celix_properties_create(); Review Comment: If any of the copy failed, we'd better cleanup and return null. Dropping property silently is not a good idea. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: dev-unsubscr...@celix.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org