|
1 /* |
|
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
|
3 * |
|
4 * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * 1. Redistributions of source code must retain the above copyright |
|
10 * notice, this list of conditions and the following disclaimer. |
|
11 * |
|
12 * 2. Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in the |
|
14 * documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
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 |
|
26 * POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 /** |
|
29 * @file properties.h |
|
30 * @brief Interface for parsing data from properties files. |
|
31 * @author Mike Becker |
|
32 * @author Olaf Wintermann |
|
33 * @copyright 2-Clause BSD License |
|
34 */ |
|
35 |
|
36 #ifndef UCX_PROPERTIES_H |
|
37 #define UCX_PROPERTIES_H |
|
38 |
|
39 #include "common.h" |
|
40 #include "string.h" |
|
41 #include "map.h" |
|
42 #include "buffer.h" |
|
43 |
|
44 #include <stdio.h> |
|
45 #include <string.h> |
|
46 |
|
47 #ifdef __cplusplus |
|
48 extern "C" { |
|
49 #endif |
|
50 |
|
51 /** |
|
52 * Configures the expected characters for the properties parser. |
|
53 */ |
|
54 struct cx_properties_config_s { |
|
55 /** |
|
56 * The key/value delimiter that shall be used. |
|
57 * This is '=' by default. |
|
58 */ |
|
59 char delimiter; |
|
60 |
|
61 /** |
|
62 * The character, when appearing at the end of a line, continues that line. |
|
63 * This is '\' by default. |
|
64 */ |
|
65 // char continuation; // TODO: line continuation in properties |
|
66 |
|
67 /** |
|
68 * The first comment character. |
|
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 }; |
|
85 |
|
86 /** |
|
87 * Typedef for the properties config. |
|
88 */ |
|
89 typedef struct cx_properties_config_s CxPropertiesConfig; |
|
90 |
|
91 /** |
|
92 * Default properties configuration. |
|
93 */ |
|
94 extern const CxPropertiesConfig cx_properties_config_default; |
|
95 |
|
96 /** |
|
97 * Status codes for the properties interface. |
|
98 */ |
|
99 enum cx_properties_status { |
|
100 /** |
|
101 * Everything is fine. |
|
102 */ |
|
103 CX_PROPERTIES_NO_ERROR, |
|
104 /** |
|
105 * The input buffer does not contain more data. |
|
106 */ |
|
107 CX_PROPERTIES_NO_DATA, |
|
108 /** |
|
109 * The input ends unexpectedly. |
|
110 * |
|
111 * This either happens when the last line does not terminate with a line |
|
112 * break, or when the input ends with a parsed key but no value. |
|
113 */ |
|
114 CX_PROPERTIES_INCOMPLETE_DATA, |
|
115 /** |
|
116 * Not used as a status and never returned by any function. |
|
117 * |
|
118 * 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. |
|
120 * |
|
121 * A "good" status means, that you can refill data and continue parsing. |
|
122 */ |
|
123 CX_PROPERTIES_OK, |
|
124 /** |
|
125 * Input buffer is @c NULL. |
|
126 */ |
|
127 CX_PROPERTIES_NULL_INPUT, |
|
128 /** |
|
129 * The line contains a delimiter, but no key. |
|
130 */ |
|
131 CX_PROPERTIES_INVALID_EMPTY_KEY, |
|
132 /** |
|
133 * The line contains data, but no delimiter. |
|
134 */ |
|
135 CX_PROPERTIES_INVALID_MISSING_DELIMITER, |
|
136 /** |
|
137 * More internal buffer was needed, but could not be allocated. |
|
138 */ |
|
139 CX_PROPERTIES_BUFFER_ALLOC_FAILED, |
|
140 /** |
|
141 * Initializing the properties source failed. |
|
142 * |
|
143 * @see cx_properties_read_init_func |
|
144 */ |
|
145 CX_PROPERTIES_READ_INIT_FAILED, |
|
146 /** |
|
147 * Reading from a properties source failed. |
|
148 * |
|
149 * @see cx_properties_read_func |
|
150 */ |
|
151 CX_PROPERTIES_READ_FAILED, |
|
152 /** |
|
153 * Sinking a k/v-pair failed. |
|
154 * |
|
155 * @see cx_properties_sink_func |
|
156 */ |
|
157 CX_PROPERTIES_SINK_FAILED, |
|
158 }; |
|
159 |
|
160 /** |
|
161 * Typedef for the properties status enum. |
|
162 */ |
|
163 typedef enum cx_properties_status CxPropertiesStatus; |
|
164 |
|
165 /** |
|
166 * Interface for working with properties data. |
|
167 */ |
|
168 struct cx_properties_s { |
|
169 /** |
|
170 * The configuration. |
|
171 */ |
|
172 CxPropertiesConfig config; |
|
173 |
|
174 /** |
|
175 * The text input buffer. |
|
176 */ |
|
177 CxBuffer input; |
|
178 |
|
179 /** |
|
180 * Internal buffer. |
|
181 */ |
|
182 CxBuffer buffer; |
|
183 }; |
|
184 |
|
185 /** |
|
186 * Typedef for the properties interface. |
|
187 */ |
|
188 typedef struct cx_properties_s CxProperties; |
|
189 |
|
190 |
|
191 /** |
|
192 * Typedef for a properties sink. |
|
193 */ |
|
194 typedef struct cx_properties_sink_s CxPropertiesSink; |
|
195 |
|
196 /** |
|
197 * A function that consumes a k/v-pair in a sink. |
|
198 * |
|
199 * The sink could be e.g. a map and the sink function would be calling |
|
200 * a map function to store the k/v-pair. |
|
201 * |
|
202 * @param prop the properties interface that wants to sink a k/v-pair |
|
203 * @param sink the sink |
|
204 * @param key the key |
|
205 * @param value the value |
|
206 * @retval zero success |
|
207 * @retval non-zero sinking the k/v-pair failed |
|
208 */ |
|
209 cx_attr_nonnull |
|
210 typedef int(*cx_properties_sink_func)( |
|
211 CxProperties *prop, |
|
212 CxPropertiesSink *sink, |
|
213 cxstring key, |
|
214 cxstring value |
|
215 ); |
|
216 |
|
217 /** |
|
218 * Defines a sink for k/v-pairs. |
|
219 */ |
|
220 struct cx_properties_sink_s { |
|
221 /** |
|
222 * The sink object. |
|
223 */ |
|
224 void *sink; |
|
225 /** |
|
226 * Optional custom data. |
|
227 */ |
|
228 void *data; |
|
229 /** |
|
230 * A function for consuming k/v-pairs into the sink. |
|
231 */ |
|
232 cx_properties_sink_func sink_func; |
|
233 }; |
|
234 |
|
235 |
|
236 /** |
|
237 * Typedef for a properties source. |
|
238 */ |
|
239 typedef struct cx_properties_source_s CxPropertiesSource; |
|
240 |
|
241 /** |
|
242 * A function that reads data from a source. |
|
243 * |
|
244 * When the source is depleted, implementations SHALL provide an empty |
|
245 * string in the @p target and return zero. |
|
246 * A non-zero return value is only permitted in case of an error. |
|
247 * |
|
248 * The meaning of the optional parameters is implementation-dependent. |
|
249 * |
|
250 * @param prop the properties interface that wants to read from the source |
|
251 * @param src the source |
|
252 * @param target a string buffer where the read data shall be stored |
|
253 * @retval zero success |
|
254 * @retval non-zero reading the data failed |
|
255 */ |
|
256 cx_attr_nonnull |
|
257 typedef int(*cx_properties_read_func)( |
|
258 CxProperties *prop, |
|
259 CxPropertiesSource *src, |
|
260 cxstring *target |
|
261 ); |
|
262 |
|
263 /** |
|
264 * A function that may initialize additional memory for the source. |
|
265 * |
|
266 * @param prop the properties interface that wants to read from the source |
|
267 * @param src the source |
|
268 * @retval zero initialization was successful |
|
269 * @retval non-zero otherwise |
|
270 */ |
|
271 cx_attr_nonnull |
|
272 typedef int(*cx_properties_read_init_func)( |
|
273 CxProperties *prop, |
|
274 CxPropertiesSource *src |
|
275 ); |
|
276 |
|
277 /** |
|
278 * A function that cleans memory initialized by the read_init_func. |
|
279 * |
|
280 * @param prop the properties interface that wants to read from the source |
|
281 * @param src the source |
|
282 */ |
|
283 cx_attr_nonnull |
|
284 typedef void(*cx_properties_read_clean_func)( |
|
285 CxProperties *prop, |
|
286 CxPropertiesSource *src |
|
287 ); |
|
288 |
|
289 /** |
|
290 * Defines a properties source. |
|
291 */ |
|
292 struct cx_properties_source_s { |
|
293 /** |
|
294 * The source object. |
|
295 * |
|
296 * For example a file stream or a string. |
|
297 */ |
|
298 void *src; |
|
299 /** |
|
300 * Optional additional data pointer. |
|
301 */ |
|
302 void *data_ptr; |
|
303 /** |
|
304 * Optional size information. |
|
305 */ |
|
306 size_t data_size; |
|
307 /** |
|
308 * A function that reads data from the source. |
|
309 */ |
|
310 cx_properties_read_func read_func; |
|
311 /** |
|
312 * Optional function that may prepare the source for reading data. |
|
313 */ |
|
314 cx_properties_read_init_func read_init_func; |
|
315 /** |
|
316 * Optional function that cleans additional memory allocated by the |
|
317 * read_init_func. |
|
318 */ |
|
319 cx_properties_read_clean_func read_clean_func; |
|
320 }; |
|
321 |
|
322 /** |
|
323 * Initialize a properties interface. |
|
324 * |
|
325 * @param prop the properties interface |
|
326 * @param config the properties configuration |
|
327 * @see cxPropertiesInitDefault() |
|
328 */ |
|
329 cx_attr_nonnull |
|
330 void cxPropertiesInit(CxProperties *prop, CxPropertiesConfig config); |
|
331 |
|
332 /** |
|
333 * Destroys the properties interface. |
|
334 * |
|
335 * @note Even when you are certain that you did not use the interface in a |
|
336 * way that caused a memory allocation, you should call this function anyway. |
|
337 * Future versions of the library might add features that need additional memory |
|
338 * and you really don't want to search the entire code where you might need |
|
339 * add call to this function. |
|
340 * |
|
341 * @param prop the properties interface |
|
342 */ |
|
343 cx_attr_nonnull |
|
344 void cxPropertiesDestroy(CxProperties *prop); |
|
345 |
|
346 /** |
|
347 * Destroys and re-initializes the properties interface. |
|
348 * |
|
349 * You might want to use this, to reset the parser after |
|
350 * encountering a syntax error. |
|
351 * |
|
352 * @param prop the properties interface |
|
353 */ |
|
354 cx_attr_nonnull |
|
355 static inline void cxPropertiesReset(CxProperties *prop) { |
|
356 CxPropertiesConfig config = prop->config; |
|
357 cxPropertiesDestroy(prop); |
|
358 cxPropertiesInit(prop, config); |
|
359 } |
|
360 |
|
361 /** |
|
362 * Initialize a properties parser with the default configuration. |
|
363 * |
|
364 * @param prop (@c CxProperties*) the properties interface |
|
365 * @see cxPropertiesInit() |
|
366 */ |
|
367 #define cxPropertiesInitDefault(prop) \ |
|
368 cxPropertiesInit(prop, cx_properties_config_default) |
|
369 |
|
370 /** |
|
371 * Fills the input buffer with data. |
|
372 * |
|
373 * After calling this function, you can parse the data by calling |
|
374 * cxPropertiesNext(). |
|
375 * |
|
376 * @remark The properties interface tries to avoid allocations. |
|
377 * When you use this function and cxPropertiesNext() interleaving, |
|
378 * no allocations are performed. However, you must not free the |
|
379 * pointer to the data in that case. When you invoke the fill |
|
380 * function more than once before calling cxPropertiesNext(), |
|
381 * the additional data is appended - inevitably leading to |
|
382 * an allocation of a new buffer and copying the previous contents. |
|
383 * |
|
384 * @param prop the properties interface |
|
385 * @param buf a pointer to the data |
|
386 * @param len the length of the data |
|
387 * @retval zero success |
|
388 * @retval non-zero a memory allocation was necessary but failed |
|
389 * @see cxPropertiesFill() |
|
390 */ |
|
391 cx_attr_nonnull |
|
392 cx_attr_access_r(2, 3) |
|
393 int cxPropertiesFilln( |
|
394 CxProperties *prop, |
|
395 const char *buf, |
|
396 size_t len |
|
397 ); |
|
398 |
|
399 #ifdef __cplusplus |
|
400 } // extern "C" |
|
401 cx_attr_nonnull |
|
402 static inline int cxPropertiesFill( |
|
403 CxProperties *prop, |
|
404 cxstring str |
|
405 ) { |
|
406 return cxPropertiesFilln(prop, str.ptr, str.length); |
|
407 } |
|
408 |
|
409 cx_attr_nonnull |
|
410 static inline int cxPropertiesFill( |
|
411 CxProperties *prop, |
|
412 cxmutstr str |
|
413 ) { |
|
414 return cxPropertiesFilln(prop, str.ptr, str.length); |
|
415 } |
|
416 |
|
417 cx_attr_nonnull |
|
418 cx_attr_cstr_arg(2) |
|
419 static inline int cxPropertiesFill( |
|
420 CxProperties *prop, |
|
421 const char *str |
|
422 ) { |
|
423 return cxPropertiesFilln(prop, str, strlen(str)); |
|
424 } |
|
425 |
|
426 extern "C" { |
|
427 #else // __cplusplus |
|
428 /** |
|
429 * Fills the input buffer with data. |
|
430 * |
|
431 * After calling this function, you can parse the data by calling |
|
432 * cxPropertiesNext(). |
|
433 * |
|
434 * @attention The properties interface tries to avoid allocations. |
|
435 * When you use this function and cxPropertiesNext() interleaving, |
|
436 * no allocations are performed. However, you must not free the |
|
437 * pointer to the data in that case. When you invoke the fill |
|
438 * function more than once before calling cxPropertiesNext(), |
|
439 * the additional data is appended - inevitably leading to |
|
440 * an allocation of a new buffer and copying the previous contents. |
|
441 * |
|
442 * @param prop the properties interface |
|
443 * @param str the text to fill in |
|
444 * @retval zero success |
|
445 * @retval non-zero a memory allocation was necessary but failed |
|
446 * @see cxPropertiesFilln() |
|
447 */ |
|
448 #define cxPropertiesFill(prop, str) _Generic((str), \ |
|
449 cxstring: cx_properties_fill_cxstr, \ |
|
450 cxmutstr: cx_properties_fill_mutstr, \ |
|
451 char*: cx_properties_fill_str, \ |
|
452 const char*: cx_properties_fill_str) \ |
|
453 (prop, str) |
|
454 |
|
455 /** |
|
456 * @copydoc cxPropertiesFill() |
|
457 */ |
|
458 cx_attr_nonnull |
|
459 static inline int cx_properties_fill_cxstr( |
|
460 CxProperties *prop, |
|
461 cxstring str |
|
462 ) { |
|
463 return cxPropertiesFilln(prop, str.ptr, str.length); |
|
464 } |
|
465 |
|
466 /** |
|
467 * @copydoc cxPropertiesFill() |
|
468 */ |
|
469 cx_attr_nonnull |
|
470 static inline int cx_properties_fill_mutstr( |
|
471 CxProperties *prop, |
|
472 cxmutstr str |
|
473 ) { |
|
474 return cxPropertiesFilln(prop, str.ptr, str.length); |
|
475 } |
|
476 |
|
477 /** |
|
478 * @copydoc cxPropertiesFill() |
|
479 */ |
|
480 cx_attr_nonnull |
|
481 cx_attr_cstr_arg(2) |
|
482 static inline int cx_properties_fill_str( |
|
483 CxProperties *prop, |
|
484 const char *str |
|
485 ) { |
|
486 return cxPropertiesFilln(prop, str, strlen(str)); |
|
487 } |
|
488 #endif |
|
489 |
|
490 /** |
|
491 * Specifies stack memory that shall be used as internal buffer. |
|
492 * |
|
493 * @param prop the properties interface |
|
494 * @param buf a pointer to stack memory |
|
495 * @param capacity the capacity of the stack memory |
|
496 */ |
|
497 cx_attr_nonnull |
|
498 void cxPropertiesUseStack( |
|
499 CxProperties *prop, |
|
500 char *buf, |
|
501 size_t capacity |
|
502 ); |
|
503 |
|
504 /** |
|
505 * Retrieves the next key/value-pair. |
|
506 * |
|
507 * This function returns zero as long as there are key/value-pairs found. |
|
508 * If no more key/value-pairs are found, #CX_PROPERTIES_NO_DATA is returned. |
|
509 * |
|
510 * When an incomplete line is encountered, #CX_PROPERTIES_INCOMPLETE_DATA is |
|
511 * returned, and you can add more data with #cxPropertiesFill(). |
|
512 * |
|
513 * @remark The incomplete line will be stored in an internal buffer, which is |
|
514 * allocated on the heap, by default. If you want to avoid allocations, |
|
515 * you can specify sufficient space with cxPropertiesUseStack() after |
|
516 * initialization with cxPropertiesInit(). |
|
517 * |
|
518 * @attention The returned strings will point into a buffer that might not be |
|
519 * available later. It is strongly recommended to copy the strings for further |
|
520 * use. |
|
521 * |
|
522 * @param prop the properties interface |
|
523 * @param key a pointer to the cxstring that shall contain the property name |
|
524 * @param value a pointer to the cxstring that shall contain the property value |
|
525 * @retval CX_PROPERTIES_NO_ERROR (zero) a key/value pair was found |
|
526 * @retval CX_PROPERTIES_NO_DATA there is no (more) data in the input buffer |
|
527 * @retval CX_PROPERTIES_INCOMPLETE_DATA the data in the input buffer is incomplete |
|
528 * (fill more data and try again) |
|
529 * @retval CX_PROPERTIES_NULL_INPUT the input buffer was never filled |
|
530 * @retval CX_PROPERTIES_INVALID_EMPTY_KEY the properties data contains an illegal empty key |
|
531 * @retval CX_PROPERTIES_INVALID_MISSING_DELIMITER the properties data contains a line without delimiter |
|
532 * @retval CX_PROPERTIES_BUFFER_ALLOC_FAILED an internal allocation was necessary but failed |
|
533 */ |
|
534 cx_attr_nonnull |
|
535 cx_attr_nodiscard |
|
536 CxPropertiesStatus cxPropertiesNext( |
|
537 CxProperties *prop, |
|
538 cxstring *key, |
|
539 cxstring *value |
|
540 ); |
|
541 |
|
542 /** |
|
543 * Creates a properties sink for an UCX map. |
|
544 * |
|
545 * The values stored in the map will be pointers to strings allocated |
|
546 * by #cx_strdup_a(). |
|
547 * The default stdlib allocator will be used, unless you specify a custom |
|
548 * allocator in the optional @c data of the sink. |
|
549 * |
|
550 * @param map the map that shall consume the k/v-pairs. |
|
551 * @return the sink |
|
552 * @see cxPropertiesLoad() |
|
553 */ |
|
554 cx_attr_nonnull |
|
555 cx_attr_nodiscard |
|
556 CxPropertiesSink cxPropertiesMapSink(CxMap *map); |
|
557 |
|
558 /** |
|
559 * Creates a properties source based on an UCX string. |
|
560 * |
|
561 * @param str the string |
|
562 * @return the properties source |
|
563 * @see cxPropertiesLoad() |
|
564 */ |
|
565 cx_attr_nodiscard |
|
566 CxPropertiesSource cxPropertiesStringSource(cxstring str); |
|
567 |
|
568 /** |
|
569 * Creates a properties source based on C string with the specified length. |
|
570 * |
|
571 * @param str the string |
|
572 * @param len the length |
|
573 * @return the properties source |
|
574 * @see cxPropertiesLoad() |
|
575 */ |
|
576 cx_attr_nonnull |
|
577 cx_attr_nodiscard |
|
578 cx_attr_access_r(1, 2) |
|
579 CxPropertiesSource cxPropertiesCstrnSource(const char *str, size_t len); |
|
580 |
|
581 /** |
|
582 * Creates a properties source based on a C string. |
|
583 * |
|
584 * The length will be determined with strlen(), so the string MUST be |
|
585 * zero-terminated. |
|
586 * |
|
587 * @param str the string |
|
588 * @return the properties source |
|
589 * @see cxPropertiesLoad() |
|
590 */ |
|
591 cx_attr_nonnull |
|
592 cx_attr_nodiscard |
|
593 cx_attr_cstr_arg(1) |
|
594 CxPropertiesSource cxPropertiesCstrSource(const char *str); |
|
595 |
|
596 /** |
|
597 * Creates a properties source based on an FILE. |
|
598 * |
|
599 * @param file the file |
|
600 * @param chunk_size how many bytes may be read in one operation |
|
601 * |
|
602 * @return the properties source |
|
603 * @see cxPropertiesLoad() |
|
604 */ |
|
605 cx_attr_nonnull |
|
606 cx_attr_nodiscard |
|
607 cx_attr_access_r(1) |
|
608 CxPropertiesSource cxPropertiesFileSource(FILE *file, size_t chunk_size); |
|
609 |
|
610 |
|
611 /** |
|
612 * Loads properties data from a source and transfers it to a sink. |
|
613 * |
|
614 * This function tries to read as much data from the source as possible. |
|
615 * When the source was completely consumed and at least on k/v-pair was found, |
|
616 * the return value will be #CX_PROPERTIES_NO_ERROR. |
|
617 * When the source was consumed but no k/v-pairs were found, the return value |
|
618 * will be #CX_PROPERTIES_NO_DATA. |
|
619 * The other result codes apply, according to their description. |
|
620 * |
|
621 * @param prop the properties interface |
|
622 * @param sink the sink |
|
623 * @param source the source |
|
624 * @retval CX_PROPERTIES_NO_ERROR (zero) a key/value pair was found |
|
625 * @retval CX_PROPERTIES_READ_INIT_FAILED initializing the source failed |
|
626 * @retval CX_PROPERTIES_READ_FAILED reading from the source failed |
|
627 * @retval CX_PROPERTIES_SINK_FAILED sinking the properties into the sink failed |
|
628 * @retval CX_PROPERTIES_NO_DATA the source did not provide any key/value pairs |
|
629 * @retval CX_PROPERTIES_INVALID_EMPTY_KEY the properties data contains an illegal empty key |
|
630 * @retval CX_PROPERTIES_INVALID_MISSING_DELIMITER the properties data contains a line without delimiter |
|
631 * @retval CX_PROPERTIES_BUFFER_ALLOC_FAILED an internal allocation was necessary but failed |
|
632 */ |
|
633 cx_attr_nonnull |
|
634 CxPropertiesStatus cxPropertiesLoad( |
|
635 CxProperties *prop, |
|
636 CxPropertiesSink sink, |
|
637 CxPropertiesSource source |
|
638 ); |
|
639 |
|
640 #ifdef __cplusplus |
|
641 } // extern "C" |
|
642 #endif |
|
643 |
|
644 #endif // UCX_PROPERTIES_H |