diff -r 71e7e9ba4b97 -r d2d42cb1d59e src/properties.c --- a/src/properties.c Sun Oct 13 15:19:12 2024 +0200 +++ b/src/properties.c Sun Oct 13 16:44:29 2024 +0200 @@ -92,6 +92,7 @@ char *dest = prop->buf + prop->buf_size; memcpy(dest, src, len); prop->buf_size += len; + prop->text_pos += len; return 0; } @@ -137,7 +138,7 @@ prop->flags |= CX_PROPERTIES_FLAG_USE_STACK; } -enum cx_properties_status cxPropertiesNext( +CxPropertiesStatus cxPropertiesNext( CxProperties *prop, cxstring *key, cxstring *value @@ -171,7 +172,7 @@ prop->text_pos = 0; prop->buf_size = 0; - enum cx_properties_status result; + CxPropertiesStatus result; result = cxPropertiesNext(prop, key, value); // restore original buffer @@ -199,6 +200,9 @@ } } else { // still not enough data + if (cx_properties_rescue_input(prop)) { + return CX_PROPERTIES_BUFFER_ALLOC_FAILED; + } return CX_PROPERTIES_INCOMPLETE_DATA; } } @@ -241,6 +245,9 @@ if (c != '\n') { // we don't have enough data for a line + if (cx_properties_rescue_input(prop)) { + return CX_PROPERTIES_BUFFER_ALLOC_FAILED; + } return CX_PROPERTIES_INCOMPLETE_DATA; } @@ -284,3 +291,167 @@ assert(prop->text_pos == prop->text_size); return CX_PROPERTIES_NO_DATA; } + +static int cx_properties_sink_map( + __attribute__((__unused__)) CxProperties *prop, + CxPropertiesSink *sink, + cxstring key, + cxstring value +) { + CxMap *map = sink->sink; + CxAllocator *alloc = sink->data; + cxmutstr v = cx_strdup_a(alloc, value); + int r = cx_map_put_cxstr(map, key, v.ptr); + if (r != 0) cx_strfree_a(alloc, &v); + return r; +} + +CxPropertiesSink cxPropertiesMapSink(CxMap *map) { + CxPropertiesSink sink; + sink.sink = map; + sink.data = cxDefaultAllocator; + sink.sink_func = cx_properties_sink_map; + return sink; +} + +static int cx_properties_read_string( + CxProperties *prop, + CxPropertiesSource *src, + cxstring *target +) { + if (prop->text == src->src) { + // when the input buffer already contains the string + // we have nothing more to provide + target->length = 0; + } else { + target->ptr = src->src; + target->length = src->data_size; + } + return 0; +} + +static int cx_properties_read_file( + __attribute__((__unused__)) CxProperties *prop, + CxPropertiesSource *src, + cxstring *target +) { + target->ptr = src->data_ptr; + target->length = fread(src->data_ptr, 1, src->data_size, src->src); + return ferror(src->src); +} + +static int cx_properties_read_init_file( + __attribute__((__unused__)) CxProperties *prop, + CxPropertiesSource *src +) { + src->data_ptr = malloc(src->data_size); + if (src->data_ptr == NULL) return 1; + return 0; +} + +static void cx_properties_read_clean_file( + __attribute__((__unused__)) CxProperties *prop, + CxPropertiesSource *src +) { + free(src->data_ptr); +} + +CxPropertiesSource cxPropertiesStringSource(cxstring str) { + CxPropertiesSource src; + src.src = (void*) str.ptr; + src.data_size = str.length; + src.read_func = cx_properties_read_string; + src.read_init_func = NULL; + src.read_clean_func = NULL; + return src; +} + +CxPropertiesSource cxPropertiesCstrnSource(const char *str, size_t len) { + CxPropertiesSource src; + src.src = (void*) str; + src.data_size = len; + src.read_func = cx_properties_read_string; + src.read_init_func = NULL; + src.read_clean_func = NULL; + return src; +} + +CxPropertiesSource cxPropertiesCstrSource(const char *str) { + CxPropertiesSource src; + src.src = (void*) str; + src.data_size = strlen(str); + src.read_func = cx_properties_read_string; + src.read_init_func = NULL; + src.read_clean_func = NULL; + return src; +} + +CxPropertiesSource cxPropertiesFileSource(FILE *file, size_t chunk_size) { + CxPropertiesSource src; + src.src = file; + src.data_size = chunk_size; + src.read_func = cx_properties_read_file; + src.read_init_func = cx_properties_read_init_file; + src.read_clean_func = cx_properties_read_clean_file; + return src; +} + +CxPropertiesStatus cxPropertiesLoad( + CxProperties *prop, + CxPropertiesSink sink, + CxPropertiesSource source +) { + assert(source.read_func != NULL); + assert(sink.sink_func != NULL); + + // initialize reader + if (source.read_init_func != NULL) { + if (source.read_init_func(prop, &source)) { + return CX_PROPERTIES_READ_INIT_FAILED; + } + } + + // transfer the data from the source to the sink + CxPropertiesStatus status; + bool found = false; + while (true) { + // read input + cxstring input; + if (source.read_func(prop, &source, &input)) { + status = CX_PROPERTIES_READ_FAILED; + break; + } + + // no more data - break + if (input.length == 0) { + status = found ? CX_PROPERTIES_NO_ERROR : CX_PROPERTIES_NO_DATA; + break; + } + + // set the input buffer and read the k/v-pairs + cxPropertiesInput(prop, input.ptr, input.length); + + CxPropertiesStatus kv_status; + do { + cxstring key, value; + kv_status = cxPropertiesNext(prop, &key, &value); + if (kv_status == CX_PROPERTIES_NO_ERROR) { + found = true; + if (sink.sink_func(prop, &sink, key, value)) { + kv_status = CX_PROPERTIES_SINK_FAILED; + } + } + } while (kv_status == CX_PROPERTIES_NO_ERROR); + + if (kv_status > CX_PROPERTIES_OK) { + status = kv_status; + break; + } + } + + if (source.read_clean_func != NULL) { + source.read_clean_func(prop, &source); + } + + return status; +}