PengZheng commented on code in PR #470: URL: https://github.com/apache/celix/pull/470#discussion_r1378791024
########## 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(); + if (properties == NULL) { + return copy; + } - return props; + CELIX_PROPERTIES_ITERATE(properties, iter) { + if (iter.entry.valueType == CELIX_PROPERTIES_VALUE_TYPE_STRING) { + celix_properties_set(copy, iter.key, iter.entry.value); + } else if (iter.entry.valueType == CELIX_PROPERTIES_VALUE_TYPE_LONG) { + celix_properties_setLong(copy, iter.key, iter.entry.typed.longValue); + } else if (iter.entry.valueType == CELIX_PROPERTIES_VALUE_TYPE_DOUBLE) { + celix_properties_setDouble(copy, iter.key, iter.entry.typed.doubleValue); + } else if (iter.entry.valueType == CELIX_PROPERTIES_VALUE_TYPE_BOOL) { + celix_properties_setBool(copy, iter.key, iter.entry.typed.boolValue); + } else /*version*/ { + assert(iter.entry.valueType == CELIX_PROPERTIES_VALUE_TYPE_VERSION); + celix_properties_setVersion(copy, iter.key, iter.entry.typed.versionValue); + } + } + return copy; } -void celix_properties_store(celix_properties_t *properties, const char *filename, const char *header) { - FILE *file = fopen (filename, "w+" ); - char *str; +celix_properties_value_type_e celix_properties_getType(const celix_properties_t* properties, const char* key) { + celix_properties_entry_t* entry = celix_stringHashMap_get(properties->map, key); + return entry == NULL ? CELIX_PROPERTIES_VALUE_TYPE_UNSET : entry->valueType; +} - if (file != NULL) { - if (hashMap_size(properties) > 0) { - hash_map_iterator_pt iterator = hashMapIterator_create(properties); - while (hashMapIterator_hasNext(iterator)) { - hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator); - str = hashMapEntry_getKey(entry); - for (int i = 0; i < strlen(str); i += 1) { - if (str[i] == '#' || str[i] == '!' || str[i] == '=' || str[i] == ':') { - fputc('\\', file); - } - fputc(str[i], file); - } +const char* celix_properties_get(const celix_properties_t* properties, const char* key, const char* defaultValue) { + celix_properties_entry_t* entry = celix_properties_getEntry(properties, key); + if (entry != NULL) { + return entry->value; + } + return defaultValue; +} - fputc('=', file); +celix_properties_entry_t* celix_properties_getEntry(const celix_properties_t* properties, const char* key) { + celix_properties_entry_t* entry = NULL; + if (properties) { + entry = celix_stringHashMap_get(properties->map, key); + } + return entry; +} - str = hashMapEntry_getValue(entry); - for (int i = 0; i < strlen(str); i += 1) { - if (str[i] == '#' || str[i] == '!' || str[i] == '=' || str[i] == ':') { - fputc('\\', file); - } - fputc(str[i], file); - } +celix_status_t celix_properties_set(celix_properties_t* properties, const char* key, const char* value) { + return celix_properties_createAndSetEntry(properties, key, &value, NULL, NULL, NULL, NULL); +} - fputc('\n', file); +celix_status_t celix_properties_setWithoutCopy(celix_properties_t* properties, char* key, char* value) { + if (properties != NULL && key != NULL && value != NULL) { + celix_properties_entry_t* entry = celix_properties_createEntryWithNoCopy(properties, value); + if (!entry) { + celix_err_push("Failed to create entry for property."); + free(key); + free(value); + return CELIX_ENOMEM; + } - } - hashMapIterator_destroy(iterator); + bool alreadyExist = celix_stringHashMap_hasKey(properties->map, key); + celix_status_t status = celix_stringHashMap_put(properties->map, key, entry); Review Comment: Memory leak when error. -- 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