--- a/src/cx/properties.h Sun Oct 13 15:19:12 2024 +0200 +++ b/src/cx/properties.h Sun Oct 13 16:44:29 2024 +0200 @@ -38,8 +38,11 @@ #include "common.h" #include "string.h" +#include "map.h" #include "array_list.h" +#include <stdio.h> + struct cx_properties_config_s { /** * The key/value delimiter that shall be used. @@ -102,6 +105,15 @@ */ CX_PROPERTIES_INCOMPLETE_DATA, /** + * Not used as a status and never returned by any function. + * + * You can use this enumerator to check for all "good" status results + * by checking if the status is less than \c CX_PROPERTIES_OK. + * + * A "good" status means, that you can refill data and continue parsing. + */ + CX_PROPERTIES_OK, + /** * Input buffer is \c NULL. */ CX_PROPERTIES_NULL_INPUT, @@ -117,9 +129,32 @@ * More internal buffer was needed, but could not be allocated. */ CX_PROPERTIES_BUFFER_ALLOC_FAILED, + /** + * Initializing the properties source failed. + * + * @see cx_properties_read_init_func + */ + CX_PROPERTIES_READ_INIT_FAILED, + /** + * Reading from a properties source failed. + * + * @see cx_properties_read_func + */ + CX_PROPERTIES_READ_FAILED, + /** + * Sinking a k/v-pair failed. + * + * @see cx_properties_sink_func + */ + CX_PROPERTIES_SINK_FAILED, }; /** + * Typedef for the properties status enum. + */ +typedef enum cx_properties_status CxPropertiesStatus; + +/** * Interface for working with properties data. */ struct cx_properties_s { @@ -171,6 +206,134 @@ /** + * Typedef for a properties sink. + */ +typedef struct cx_properties_sink_s CxPropertiesSink; + +/** + * A function that consumes a k/v-pair in a sink. + * + * The sink could be e.g. a map and the sink function would be calling + * a map function to store the k/v-pair. + * + * @param prop the properties interface that wants to sink a k/v-pair + * @param sink the sink + * @param key the key + * @param value the value + * @return zero on success, non-zero when sinking the k/v-pair failed + */ +__attribute__((__nonnull__)) +typedef int(*cx_properties_sink_func)( + CxProperties *prop, + CxPropertiesSink *sink, + cxstring key, + cxstring value +); + +/** + * Defines a sink for k/v-pairs. + */ +struct cx_properties_sink_s { + /** + * The sink object. + */ + void *sink; + /** + * Optional custom data. + */ + void *data; + /** + * A function for consuming k/v-pairs into the sink. + */ + cx_properties_sink_func sink_func; +}; + + +/** + * Typedef for a properties source. + */ +typedef struct cx_properties_source_s CxPropertiesSource; + +/** + * A function that reads data from a source. + * + * When the source is depleted, implementations SHALL provide an empty + * string in the \p target and return zero. + * A non-zero return value is only permitted in case of an error. + * + * The meaning of the optional parameters is implementation-dependent. + * + * @param prop the properties interface that wants to read from the source + * @param src the source + * @param target a string buffer where the read data shall be stored + * @return zero on success, non-zero when reading data failed + */ + __attribute__((__nonnull__)) +typedef int(*cx_properties_read_func)( + CxProperties *prop, + CxPropertiesSource *src, + cxstring *target +); + + /** + * A function that may initialize additional memory for the source. + * + * @param prop the properties interface that wants to read from the source + * @param src the source + * @return zero when initialization was successful, non-zero otherwise + */ + __attribute__((__nonnull__)) +typedef int(*cx_properties_read_init_func)( + CxProperties *prop, + CxPropertiesSource *src +); + +/** + * A function that cleans memory initialized by the read_init_func. + * + * @param prop the properties interface that wants to read from the source + * @param src the source + */ +__attribute__((__nonnull__)) +typedef void(*cx_properties_read_clean_func)( + CxProperties *prop, + CxPropertiesSource *src +); + +/** + * Defines a properties source. + */ +struct cx_properties_source_s { + /** + * The source object. + * + * For example a file stream or a string. + */ + void *src; + /** + * Optional additional data pointer. + */ + void *data_ptr; + /** + * Optional size information. + */ + size_t data_size; + /** + * A function that reads data from the source. + */ + cx_properties_read_func read_func; + /** + * Optional function that may prepare the source for reading data. + */ + cx_properties_read_init_func read_init_func; + /** + * Optional function that cleans additional memory allocated by the + * read_init_func. + */ + cx_properties_read_clean_func read_clean_func; +}; + +/** * Initialize a properties interface. * * @param prop the properties interface @@ -251,6 +414,7 @@ * @param buf a pointer to stack memory * @param capacity the capacity of the stack memory */ +__attribute__((__nonnull__)) void cxPropertiesUseStack( CxProperties *prop, char *buf, @@ -277,10 +441,95 @@ * @return the status code as defined above * @see cxPropertiesFill() */ -enum cx_properties_status cxPropertiesNext( +__attribute__((__nonnull__, __warn_unused_result__)) +CxPropertiesStatus cxPropertiesNext( CxProperties *prop, cxstring *key, cxstring *value ); +/** + * Creates a properties sink for an UCX map. + * + * The values stored in the map will be pointers to strings allocated + * by #cx_strdup_a(). + * The default stdlib allocator will be used, unless you specify a custom + * allocator in the optional \c data of the sink. + * + * @param map the map that shall consume the k/v-pairs. + * @return the sink + * @see cxPropertiesLoad() + */ +__attribute__((__nonnull__, __warn_unused_result__)) +CxPropertiesSink cxPropertiesMapSink(CxMap *map); + +/** + * Creates a properties source based on an UCX string. + * + * @param str the string + * @return the properties source + * @see cxPropertiesLoad() + */ +__attribute__((__warn_unused_result__)) +CxPropertiesSource cxPropertiesStringSource(cxstring str); + +/** + * Creates a properties source based on C string with the specified length. + * + * @param str the string + * @param len the length + * @return the properties source + * @see cxPropertiesLoad() + */ +__attribute__((__nonnull__, __warn_unused_result__)) +CxPropertiesSource cxPropertiesCstrnSource(const char *str, size_t len); + +/** + * Creates a properties source based on a C string. + * + * The length will be determined with strlen(), so the string MUST be + * zero-terminated. + * + * @param str the string + * @return the properties source + * @see cxPropertiesLoad() + */ +__attribute__((__nonnull__, __warn_unused_result__)) +CxPropertiesSource cxPropertiesCstrSource(const char *str); + +/** + * Creates a properties source based on an FILE. + * + * @param file the file + * @param chunk_size how many bytes may be read in one operation + * + * @return the properties source + * @see cxPropertiesLoad() + */ +__attribute__((__nonnull__, __warn_unused_result__)) +CxPropertiesSource cxPropertiesFileSource(FILE *file, size_t chunk_size); + + +/** + * Loads properties data from a source and transfers it to a sink. + * + * This function tries to read as much data from the source as possible. + * When the source was completely consumed and at least on k/v-pair was found, + * the return value will be #CX_PROPERTIES_NO_ERROR. + * When the source was consumed but no k/v-pairs were found, the return value + * will be #CX_PROPERTIES_NO_DATA. + * The other result codes apply, according to their description. + * + * @param prop the properties interface + * @param sink the sink + * @param source the source + * @return the status of the last operation + */ +__attribute__((__nonnull__)) +CxPropertiesStatus cxPropertiesLoad( + CxProperties *prop, + CxPropertiesSink sink, + CxPropertiesSource source +); + #endif // UCX_PROPERTIES