| 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 26 * POSSIBILITY OF SUCH DAMAGE. |
26 * POSSIBILITY OF SUCH DAMAGE. |
| 27 */ |
27 */ |
| 28 /** |
28 /** |
| 29 * \file properties.h |
29 * @file properties.h |
| 30 * \brief Interface for parsing data from properties files. |
30 * @brief Interface for parsing data from properties files. |
| 31 * \author Mike Becker |
31 * @author Mike Becker |
| 32 * \author Olaf Wintermann |
32 * @author Olaf Wintermann |
| 33 * \copyright 2-Clause BSD License |
33 * @copyright 2-Clause BSD License |
| 34 */ |
34 */ |
| 35 |
35 |
| 36 #ifndef UCX_PROPERTIES_H |
36 #ifndef UCX_PROPERTIES_H |
| 37 #define UCX_PROPERTIES_H |
37 #define UCX_PROPERTIES_H |
| 38 |
38 |
| 57 * This is '=' by default. |
57 * This is '=' by default. |
| 58 */ |
58 */ |
| 59 char delimiter; |
59 char delimiter; |
| 60 |
60 |
| 61 /** |
61 /** |
| |
62 * The first comment character. |
| |
63 * This is '#' by default. |
| |
64 */ |
| |
65 char comment1; |
| |
66 |
| |
67 /** |
| |
68 * The second comment character. |
| |
69 * This is not set by default. |
| |
70 */ |
| |
71 char comment2; |
| |
72 |
| |
73 /** |
| |
74 * The third comment character. |
| |
75 * This is not set by default. |
| |
76 */ |
| |
77 char comment3; |
| |
78 |
| |
79 /* |
| 62 * The character, when appearing at the end of a line, continues that line. |
80 * The character, when appearing at the end of a line, continues that line. |
| 63 * This is '\' by default. |
81 * This is '\' by default. |
| 64 */ |
82 */ |
| 65 // char continuation; // TODO: line continuation in properties |
83 /** |
| 66 |
84 * Reserved for future use. |
| 67 /** |
85 */ |
| 68 * The first comment character. |
86 char continuation; |
| 69 * This is '#' by default. |
|
| 70 */ |
|
| 71 char comment1; |
|
| 72 |
|
| 73 /** |
|
| 74 * The second comment character. |
|
| 75 * This is not set by default. |
|
| 76 */ |
|
| 77 char comment2; |
|
| 78 |
|
| 79 /** |
|
| 80 * The third comment character. |
|
| 81 * This is not set by default. |
|
| 82 */ |
|
| 83 char comment3; |
|
| 84 }; |
87 }; |
| 85 |
88 |
| 86 /** |
89 /** |
| 87 * Typedef for the properties config. |
90 * Typedef for the properties config. |
| 88 */ |
91 */ |
| 89 typedef struct cx_properties_config_s CxPropertiesConfig; |
92 typedef struct cx_properties_config_s CxPropertiesConfig; |
| 90 |
93 |
| 91 /** |
94 /** |
| 92 * Default properties configuration. |
95 * Default properties configuration. |
| 93 */ |
96 */ |
| |
97 cx_attr_export |
| 94 extern const CxPropertiesConfig cx_properties_config_default; |
98 extern const CxPropertiesConfig cx_properties_config_default; |
| 95 |
99 |
| 96 /** |
100 /** |
| 97 * Status codes for the properties interface. |
101 * Status codes for the properties interface. |
| 98 */ |
102 */ |
| 114 CX_PROPERTIES_INCOMPLETE_DATA, |
118 CX_PROPERTIES_INCOMPLETE_DATA, |
| 115 /** |
119 /** |
| 116 * Not used as a status and never returned by any function. |
120 * Not used as a status and never returned by any function. |
| 117 * |
121 * |
| 118 * You can use this enumerator to check for all "good" status results |
122 * You can use this enumerator to check for all "good" status results |
| 119 * by checking if the status is less than \c CX_PROPERTIES_OK. |
123 * by checking if the status is less than @c CX_PROPERTIES_OK. |
| 120 * |
124 * |
| 121 * A "good" status means, that you can refill data and continue parsing. |
125 * A "good" status means, that you can refill data and continue parsing. |
| 122 */ |
126 */ |
| 123 CX_PROPERTIES_OK, |
127 CX_PROPERTIES_OK, |
| 124 /** |
128 /** |
| 125 * Input buffer is \c NULL. |
129 * Input buffer is @c NULL. |
| 126 */ |
130 */ |
| 127 CX_PROPERTIES_NULL_INPUT, |
131 CX_PROPERTIES_NULL_INPUT, |
| 128 /** |
132 /** |
| 129 * The line contains a delimiter, but no key. |
133 * The line contains a delimiter, but no key. |
| 130 */ |
134 */ |
| 201 * |
205 * |
| 202 * @param prop the properties interface that wants to sink a k/v-pair |
206 * @param prop the properties interface that wants to sink a k/v-pair |
| 203 * @param sink the sink |
207 * @param sink the sink |
| 204 * @param key the key |
208 * @param key the key |
| 205 * @param value the value |
209 * @param value the value |
| 206 * @return zero on success, non-zero when sinking the k/v-pair failed |
210 * @retval zero success |
| |
211 * @retval non-zero sinking the k/v-pair failed |
| 207 */ |
212 */ |
| 208 cx_attr_nonnull |
213 cx_attr_nonnull |
| 209 typedef int(*cx_properties_sink_func)( |
214 typedef int(*cx_properties_sink_func)( |
| 210 CxProperties *prop, |
215 CxProperties *prop, |
| 211 CxPropertiesSink *sink, |
216 CxPropertiesSink *sink, |
| 239 |
244 |
| 240 /** |
245 /** |
| 241 * A function that reads data from a source. |
246 * A function that reads data from a source. |
| 242 * |
247 * |
| 243 * When the source is depleted, implementations SHALL provide an empty |
248 * When the source is depleted, implementations SHALL provide an empty |
| 244 * string in the \p target and return zero. |
249 * string in the @p target and return zero. |
| 245 * A non-zero return value is only permitted in case of an error. |
250 * A non-zero return value is only permitted in case of an error. |
| 246 * |
251 * |
| 247 * The meaning of the optional parameters is implementation-dependent. |
252 * The meaning of the optional parameters is implementation-dependent. |
| 248 * |
253 * |
| 249 * @param prop the properties interface that wants to read from the source |
254 * @param prop the properties interface that wants to read from the source |
| 250 * @param src the source |
255 * @param src the source |
| 251 * @param target a string buffer where the read data shall be stored |
256 * @param target a string buffer where the read data shall be stored |
| 252 * @return zero on success, non-zero when reading data failed |
257 * @retval zero success |
| |
258 * @retval non-zero reading the data failed |
| 253 */ |
259 */ |
| 254 cx_attr_nonnull |
260 cx_attr_nonnull |
| 255 typedef int(*cx_properties_read_func)( |
261 typedef int(*cx_properties_read_func)( |
| 256 CxProperties *prop, |
262 CxProperties *prop, |
| 257 CxPropertiesSource *src, |
263 CxPropertiesSource *src, |
| 261 /** |
267 /** |
| 262 * A function that may initialize additional memory for the source. |
268 * A function that may initialize additional memory for the source. |
| 263 * |
269 * |
| 264 * @param prop the properties interface that wants to read from the source |
270 * @param prop the properties interface that wants to read from the source |
| 265 * @param src the source |
271 * @param src the source |
| 266 * @return zero when initialization was successful, non-zero otherwise |
272 * @retval zero initialization was successful |
| |
273 * @retval non-zero otherwise |
| 267 */ |
274 */ |
| 268 cx_attr_nonnull |
275 cx_attr_nonnull |
| 269 typedef int(*cx_properties_read_init_func)( |
276 typedef int(*cx_properties_read_init_func)( |
| 270 CxProperties *prop, |
277 CxProperties *prop, |
| 271 CxPropertiesSource *src |
278 CxPropertiesSource *src |
| 322 * @param prop the properties interface |
329 * @param prop the properties interface |
| 323 * @param config the properties configuration |
330 * @param config the properties configuration |
| 324 * @see cxPropertiesInitDefault() |
331 * @see cxPropertiesInitDefault() |
| 325 */ |
332 */ |
| 326 cx_attr_nonnull |
333 cx_attr_nonnull |
| |
334 cx_attr_export |
| 327 void cxPropertiesInit(CxProperties *prop, CxPropertiesConfig config); |
335 void cxPropertiesInit(CxProperties *prop, CxPropertiesConfig config); |
| 328 |
336 |
| 329 /** |
337 /** |
| 330 * Destroys the properties interface. |
338 * Destroys the properties interface. |
| 331 * |
339 * |
| 332 * \note Even when you are certain that you did not use the interface in a |
340 * @note Even when you are certain that you did not use the interface in a |
| 333 * way that caused a memory allocation, you should call this function anyway. |
341 * way that caused a memory allocation, you should call this function anyway. |
| 334 * Future versions of the library might add features that need additional memory |
342 * Future versions of the library might add features that need additional memory |
| 335 * and you really don't want to search the entire code where you might need |
343 * and you really don't want to search the entire code where you might need |
| 336 * add call to this function. |
344 * add call to this function. |
| 337 * |
345 * |
| 338 * @param prop the properties interface |
346 * @param prop the properties interface |
| 339 */ |
347 */ |
| 340 cx_attr_nonnull |
348 cx_attr_nonnull |
| |
349 cx_attr_export |
| 341 void cxPropertiesDestroy(CxProperties *prop); |
350 void cxPropertiesDestroy(CxProperties *prop); |
| 342 |
351 |
| 343 /** |
352 /** |
| 344 * Destroys and re-initializes the properties interface. |
353 * Destroys and re-initializes the properties interface. |
| 345 * |
354 * |
| 356 } |
365 } |
| 357 |
366 |
| 358 /** |
367 /** |
| 359 * Initialize a properties parser with the default configuration. |
368 * Initialize a properties parser with the default configuration. |
| 360 * |
369 * |
| 361 * @param prop the properties interface |
370 * @param prop (@c CxProperties*) the properties interface |
| 362 * @see cxPropertiesInit() |
371 * @see cxPropertiesInit() |
| 363 */ |
372 */ |
| 364 #define cxPropertiesInitDefault(prop) \ |
373 #define cxPropertiesInitDefault(prop) \ |
| 365 cxPropertiesInit(prop, cx_properties_config_default) |
374 cxPropertiesInit(prop, cx_properties_config_default) |
| 366 |
375 |
| 379 * an allocation of a new buffer and copying the previous contents. |
388 * an allocation of a new buffer and copying the previous contents. |
| 380 * |
389 * |
| 381 * @param prop the properties interface |
390 * @param prop the properties interface |
| 382 * @param buf a pointer to the data |
391 * @param buf a pointer to the data |
| 383 * @param len the length of the data |
392 * @param len the length of the data |
| 384 * @return non-zero when a memory allocation was necessary but failed |
393 * @retval zero success |
| |
394 * @retval non-zero a memory allocation was necessary but failed |
| 385 * @see cxPropertiesFill() |
395 * @see cxPropertiesFill() |
| 386 */ |
396 */ |
| 387 cx_attr_nonnull |
397 cx_attr_nonnull |
| 388 cx_attr_access_r(2, 3) |
398 cx_attr_access_r(2, 3) |
| |
399 cx_attr_export |
| 389 int cxPropertiesFilln( |
400 int cxPropertiesFilln( |
| 390 CxProperties *prop, |
401 CxProperties *prop, |
| 391 const char *buf, |
402 const char *buf, |
| 392 size_t len |
403 size_t len |
| 393 ); |
404 ); |
| 435 * the additional data is appended - inevitably leading to |
446 * the additional data is appended - inevitably leading to |
| 436 * an allocation of a new buffer and copying the previous contents. |
447 * an allocation of a new buffer and copying the previous contents. |
| 437 * |
448 * |
| 438 * @param prop the properties interface |
449 * @param prop the properties interface |
| 439 * @param str the text to fill in |
450 * @param str the text to fill in |
| 440 * @return non-zero when a memory allocation was necessary but failed |
451 * @retval zero success |
| |
452 * @retval non-zero a memory allocation was necessary but failed |
| 441 * @see cxPropertiesFilln() |
453 * @see cxPropertiesFilln() |
| 442 */ |
454 */ |
| 443 #define cxPropertiesFill(prop, str) _Generic((str), \ |
455 #define cxPropertiesFill(prop, str) _Generic((str), \ |
| 444 cxstring: cx_properties_fill_cxstr, \ |
456 cxstring: cx_properties_fill_cxstr, \ |
| 445 cxmutstr: cx_properties_fill_mutstr, \ |
457 cxmutstr: cx_properties_fill_mutstr, \ |
| 503 * If no more key/value-pairs are found, #CX_PROPERTIES_NO_DATA is returned. |
516 * If no more key/value-pairs are found, #CX_PROPERTIES_NO_DATA is returned. |
| 504 * |
517 * |
| 505 * When an incomplete line is encountered, #CX_PROPERTIES_INCOMPLETE_DATA is |
518 * When an incomplete line is encountered, #CX_PROPERTIES_INCOMPLETE_DATA is |
| 506 * returned, and you can add more data with #cxPropertiesFill(). |
519 * returned, and you can add more data with #cxPropertiesFill(). |
| 507 * |
520 * |
| 508 * \remark The incomplete line will be stored in an internal buffer, which is |
521 * @remark The incomplete line will be stored in an internal buffer, which is |
| 509 * allocated on the heap, by default. If you want to avoid allocations, |
522 * allocated on the heap, by default. If you want to avoid allocations, |
| 510 * you can specify sufficient space with cxPropertiesUseStack() after |
523 * you can specify sufficient space with cxPropertiesUseStack() after |
| 511 * initialization with cxPropertiesInit(). |
524 * initialization with cxPropertiesInit(). |
| 512 * |
525 * |
| 513 * \attention The returned strings will point into a buffer that might not be |
526 * @attention The returned strings will point into a buffer that might not be |
| 514 * available later. It is strongly recommended to copy the strings for further |
527 * available later. It is strongly recommended to copy the strings for further |
| 515 * use. |
528 * use. |
| 516 * |
529 * |
| 517 * @param prop the properties interface |
530 * @param prop the properties interface |
| 518 * @param key a pointer to the cxstring that shall contain the property name |
531 * @param key a pointer to the cxstring that shall contain the property name |
| 519 * @param value a pointer to the cxstring that shall contain the property value |
532 * @param value a pointer to the cxstring that shall contain the property value |
| 520 * @return the status code as defined above |
533 * @retval CX_PROPERTIES_NO_ERROR (zero) a key/value pair was found |
| 521 * @see cxPropertiesFill() |
534 * @retval CX_PROPERTIES_NO_DATA there is no (more) data in the input buffer |
| |
535 * @retval CX_PROPERTIES_INCOMPLETE_DATA the data in the input buffer is incomplete |
| |
536 * (fill more data and try again) |
| |
537 * @retval CX_PROPERTIES_NULL_INPUT the input buffer was never filled |
| |
538 * @retval CX_PROPERTIES_INVALID_EMPTY_KEY the properties data contains an illegal empty key |
| |
539 * @retval CX_PROPERTIES_INVALID_MISSING_DELIMITER the properties data contains a line without delimiter |
| |
540 * @retval CX_PROPERTIES_BUFFER_ALLOC_FAILED an internal allocation was necessary but failed |
| 522 */ |
541 */ |
| 523 cx_attr_nonnull |
542 cx_attr_nonnull |
| 524 cx_attr_nodiscard |
543 cx_attr_nodiscard |
| |
544 cx_attr_export |
| 525 CxPropertiesStatus cxPropertiesNext( |
545 CxPropertiesStatus cxPropertiesNext( |
| 526 CxProperties *prop, |
546 CxProperties *prop, |
| 527 cxstring *key, |
547 cxstring *key, |
| 528 cxstring *value |
548 cxstring *value |
| 529 ); |
549 ); |
| 532 * Creates a properties sink for an UCX map. |
552 * Creates a properties sink for an UCX map. |
| 533 * |
553 * |
| 534 * The values stored in the map will be pointers to strings allocated |
554 * The values stored in the map will be pointers to strings allocated |
| 535 * by #cx_strdup_a(). |
555 * by #cx_strdup_a(). |
| 536 * The default stdlib allocator will be used, unless you specify a custom |
556 * The default stdlib allocator will be used, unless you specify a custom |
| 537 * allocator in the optional \c data of the sink. |
557 * allocator in the optional @c data of the sink. |
| 538 * |
558 * |
| 539 * @param map the map that shall consume the k/v-pairs. |
559 * @param map the map that shall consume the k/v-pairs. |
| 540 * @return the sink |
560 * @return the sink |
| 541 * @see cxPropertiesLoad() |
561 * @see cxPropertiesLoad() |
| 542 */ |
562 */ |
| 543 cx_attr_nonnull |
563 cx_attr_nonnull |
| 544 cx_attr_nodiscard |
564 cx_attr_nodiscard |
| |
565 cx_attr_export |
| 545 CxPropertiesSink cxPropertiesMapSink(CxMap *map); |
566 CxPropertiesSink cxPropertiesMapSink(CxMap *map); |
| 546 |
567 |
| 547 /** |
568 /** |
| 548 * Creates a properties source based on an UCX string. |
569 * Creates a properties source based on an UCX string. |
| 549 * |
570 * |
| 550 * @param str the string |
571 * @param str the string |
| 551 * @return the properties source |
572 * @return the properties source |
| 552 * @see cxPropertiesLoad() |
573 * @see cxPropertiesLoad() |
| 553 */ |
574 */ |
| 554 cx_attr_nodiscard |
575 cx_attr_nodiscard |
| |
576 cx_attr_export |
| 555 CxPropertiesSource cxPropertiesStringSource(cxstring str); |
577 CxPropertiesSource cxPropertiesStringSource(cxstring str); |
| 556 |
578 |
| 557 /** |
579 /** |
| 558 * Creates a properties source based on C string with the specified length. |
580 * Creates a properties source based on C string with the specified length. |
| 559 * |
581 * |
| 563 * @see cxPropertiesLoad() |
585 * @see cxPropertiesLoad() |
| 564 */ |
586 */ |
| 565 cx_attr_nonnull |
587 cx_attr_nonnull |
| 566 cx_attr_nodiscard |
588 cx_attr_nodiscard |
| 567 cx_attr_access_r(1, 2) |
589 cx_attr_access_r(1, 2) |
| |
590 cx_attr_export |
| 568 CxPropertiesSource cxPropertiesCstrnSource(const char *str, size_t len); |
591 CxPropertiesSource cxPropertiesCstrnSource(const char *str, size_t len); |
| 569 |
592 |
| 570 /** |
593 /** |
| 571 * Creates a properties source based on a C string. |
594 * Creates a properties source based on a C string. |
| 572 * |
595 * |
| 603 * This function tries to read as much data from the source as possible. |
628 * This function tries to read as much data from the source as possible. |
| 604 * When the source was completely consumed and at least on k/v-pair was found, |
629 * When the source was completely consumed and at least on k/v-pair was found, |
| 605 * the return value will be #CX_PROPERTIES_NO_ERROR. |
630 * the return value will be #CX_PROPERTIES_NO_ERROR. |
| 606 * When the source was consumed but no k/v-pairs were found, the return value |
631 * When the source was consumed but no k/v-pairs were found, the return value |
| 607 * will be #CX_PROPERTIES_NO_DATA. |
632 * will be #CX_PROPERTIES_NO_DATA. |
| |
633 * In case the source data ends unexpectedly, the #CX_PROPERTIES_INCOMPLETE_DATA |
| |
634 * is returned. In that case you should call this function again with the same |
| |
635 * sink and either an updated source or the same source if the source is able to |
| |
636 * yield the missing data. |
| |
637 * |
| 608 * The other result codes apply, according to their description. |
638 * The other result codes apply, according to their description. |
| 609 * |
639 * |
| 610 * @param prop the properties interface |
640 * @param prop the properties interface |
| 611 * @param sink the sink |
641 * @param sink the sink |
| 612 * @param source the source |
642 * @param source the source |
| 613 * @return the status of the last operation |
643 * @retval CX_PROPERTIES_NO_ERROR (zero) a key/value pair was found |
| 614 */ |
644 * @retval CX_PROPERTIES_READ_INIT_FAILED initializing the source failed |
| 615 cx_attr_nonnull |
645 * @retval CX_PROPERTIES_READ_FAILED reading from the source failed |
| |
646 * @retval CX_PROPERTIES_SINK_FAILED sinking the properties into the sink failed |
| |
647 * @retval CX_PROPERTIES_NO_DATA the source did not provide any key/value pairs |
| |
648 * @retval CX_PROPERTIES_INCOMPLETE_DATA the source did not provide enough data |
| |
649 * @retval CX_PROPERTIES_INVALID_EMPTY_KEY the properties data contains an illegal empty key |
| |
650 * @retval CX_PROPERTIES_INVALID_MISSING_DELIMITER the properties data contains a line without delimiter |
| |
651 * @retval CX_PROPERTIES_BUFFER_ALLOC_FAILED an internal allocation was necessary but failed |
| |
652 */ |
| |
653 cx_attr_nonnull |
| |
654 cx_attr_export |
| 616 CxPropertiesStatus cxPropertiesLoad( |
655 CxPropertiesStatus cxPropertiesLoad( |
| 617 CxProperties *prop, |
656 CxProperties *prop, |
| 618 CxPropertiesSink sink, |
657 CxPropertiesSink sink, |
| 619 CxPropertiesSource source |
658 CxPropertiesSource source |
| 620 ); |
659 ); |