Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
9169 | turbocat | 1 | /* |
2 | * OpenTyrian: A modern cross-platform port of Tyrian |
||
3 | * Copyright (C) 2015 The OpenTyrian Development Team |
||
4 | * |
||
5 | * This program is free software; you can redistribute it and/or |
||
6 | * modify it under the terms of the GNU General Public License |
||
7 | * as published by the Free Software Foundation; either version 2 |
||
8 | * of the License, or (at your option) any later version. |
||
9 | * |
||
10 | * This program is distributed in the hope that it will be useful, |
||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
13 | * GNU General Public License for more details. |
||
14 | * |
||
15 | * You should have received a copy of the GNU General Public License |
||
16 | * along with this program; if not, write to the Free Software |
||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||
18 | */ |
||
19 | /*! |
||
20 | * \file config_file.h |
||
21 | * \author Carl Reinke |
||
22 | * \date 2015 |
||
23 | * \copyright GNU General Public License v2+ or Mozilla Public License 2.0 |
||
24 | */ |
||
25 | #ifndef CONFIG_FILE_H |
||
26 | #define CONFIG_FILE_H |
||
27 | |||
28 | #include |
||
29 | #include |
||
30 | #include |
||
31 | #include |
||
32 | #include |
||
33 | |||
34 | #ifndef COMPILE_TIME_ASSERT |
||
35 | /*! |
||
36 | * \brief Cause compile error if compile-time computable condition fails. |
||
37 | * |
||
38 | * \param[in] name the unique identifier of the assertion |
||
39 | * \param[in] cond the condition |
||
40 | */ |
||
41 | #define COMPILE_TIME_ASSERT(name, cond) typedef int assert_ ## name[(cond) * 2 - 1] |
||
42 | #endif |
||
43 | |||
44 | #ifndef COUNTOF |
||
45 | /*! |
||
46 | * \brief Calculate the number of elements in a fixed-length array. |
||
47 | * |
||
48 | * \param[in] a the fixed-length array |
||
49 | * \return the number of elements in the array |
||
50 | */ |
||
51 | #define COUNTOF(a) (sizeof(a) / sizeof(*(a))) |
||
52 | #endif |
||
53 | |||
54 | /* string type */ |
||
55 | |||
56 | /*! |
||
57 | * \brief A short-string-optimizing string type. |
||
58 | * |
||
59 | * This struct allows for storing up to 15 characters (plus a terminating \c '\0') inline. For |
||
60 | * longer strings memory will be allocated. |
||
61 | * |
||
62 | * The tag for this union is the last character of \p short_buf: |
||
63 | * \li if \c '\0' then \p short_buf is valid, |
||
64 | * \li otherwise \p long_buf is valid. |
||
65 | */ |
||
66 | typedef union |
||
67 | { |
||
68 | /*! |
||
69 | * \brief The inline buffer for short strings. |
||
70 | */ |
||
71 | char short_buf[16]; |
||
72 | |||
73 | /*! |
||
74 | * \brief The buffer for long strings. |
||
75 | * |
||
76 | * May be \c NULL. |
||
77 | */ |
||
78 | char *long_buf; |
||
79 | } ConfigString; |
||
80 | |||
81 | /*! \cond suppress_doxygen */ |
||
82 | COMPILE_TIME_ASSERT(string_short_buf_sufficient, sizeof(char *) + 1 <= COUNTOF(((ConfigString *)NULL)->short_buf)); |
||
83 | /*! \endcond */ |
||
84 | |||
85 | /*! \cond suppress_doxygen */ |
||
86 | #define CONFIG_STRING_LONG_TAG(s) ((s).short_buf[COUNTOF((s).short_buf) - 1]) |
||
87 | /*! \endcond */ |
||
88 | |||
89 | /*! |
||
90 | * \brief Return a C-string backed by a string. |
||
91 | * |
||
92 | * \param[in] string the string |
||
93 | * \return the C-string |
||
94 | */ |
||
95 | static inline const char *config_string_to_cstr( const ConfigString *string ) |
||
96 | { |
||
97 | assert(string != NULL); |
||
98 | char is_long = CONFIG_STRING_LONG_TAG(*string); |
||
99 | return is_long ? |
||
100 | string->long_buf : |
||
101 | string->short_buf; |
||
102 | } |
||
103 | |||
104 | /* config types */ |
||
105 | |||
106 | /*! |
||
107 | * \brief An option consisting of one (an item) or many (a list) values. |
||
108 | */ |
||
109 | typedef struct |
||
110 | { |
||
111 | /*! |
||
112 | * \brief The key of the option. |
||
113 | */ |
||
114 | ConfigString key; |
||
115 | |||
116 | /*! |
||
117 | * \brief The number of values in the option if it is a 'list' option. |
||
118 | * |
||
119 | * If \c 0 then the option \e may be an 'item' option. |
||
120 | * |
||
121 | * \see ::ConfigOption::value |
||
122 | */ |
||
123 | unsigned int values_count; |
||
124 | |||
125 | /*! |
||
126 | * \brief The value or values. |
||
127 | * |
||
128 | * The tag for this union is \p value_count: |
||
129 | * \li if \c 0 then \p value is valid, |
||
130 | * \li otherwise \p values is valid. |
||
131 | */ |
||
132 | union |
||
133 | { |
||
134 | /*! |
||
135 | * \brief The value of an 'item' option or an empty 'list' option. |
||
136 | * |
||
137 | * If this field is \c NULL then the option is an empty 'list' option. |
||
138 | */ |
||
139 | ConfigString value; |
||
140 | |||
141 | /*! |
||
142 | * \brief The values of a non-empty 'list' option. |
||
143 | */ |
||
144 | ConfigString *values; |
||
145 | } v; |
||
146 | } ConfigOption; |
||
147 | |||
148 | /*! |
||
149 | * \brief A section consisting of options. |
||
150 | */ |
||
151 | typedef struct |
||
152 | { |
||
153 | /*! |
||
154 | * \brief The type of the section. |
||
155 | */ |
||
156 | ConfigString type; |
||
157 | |||
158 | /*! |
||
159 | * \brief The optional name of the section. |
||
160 | * |
||
161 | * May be \c NULL. |
||
162 | */ |
||
163 | ConfigString name; |
||
164 | |||
165 | /*! |
||
166 | * \brief The number of options in the section. |
||
167 | */ |
||
168 | unsigned int options_count; |
||
169 | |||
170 | /*! |
||
171 | * \brief The options in the section. |
||
172 | * |
||
173 | * \c NULL if \p options_count is \c 0. |
||
174 | */ |
||
175 | ConfigOption *options; |
||
176 | } ConfigSection; |
||
177 | |||
178 | /*! |
||
179 | * \brief A configuration consisting of sections. |
||
180 | */ |
||
181 | typedef struct |
||
182 | { |
||
183 | /*! |
||
184 | * \brief The number of sections in the configuration. |
||
185 | */ |
||
186 | unsigned int sections_count; |
||
187 | |||
188 | /*! |
||
189 | * \brief The sections in the configuration. |
||
190 | * |
||
191 | * \c NULL if \p sections_count is \c 0. |
||
192 | */ |
||
193 | ConfigSection *sections; |
||
194 | } Config; |
||
195 | |||
196 | /* config manipulators */ |
||
197 | |||
198 | /*! |
||
199 | * \brief Initialize a configuration. |
||
200 | * |
||
201 | * \param[in] config the configuration |
||
202 | * \return void |
||
203 | */ |
||
204 | extern void config_init( Config *config ); |
||
205 | |||
206 | /*! |
||
207 | * \brief Release any memory allocated inside a configuration. |
||
208 | * |
||
209 | * \param[in] config the configuration |
||
210 | * \return void |
||
211 | */ |
||
212 | extern void config_deinit( Config *config ); |
||
213 | |||
214 | /*! |
||
215 | * \brief Parse a configuration from a file. |
||
216 | * |
||
217 | * \param[in] config the uninitalized configuration |
||
218 | * \param[in] file the file handle |
||
219 | * \return whether parsing succeeded |
||
220 | */ |
||
221 | extern bool config_parse( Config *config, FILE *file ); |
||
222 | |||
223 | /*! |
||
224 | * \brief Write a configuration to a file. |
||
225 | * |
||
226 | * \param[in] config the configuration |
||
227 | * \param[in] file the file handle |
||
228 | * \return void |
||
229 | */ |
||
230 | extern void config_write( const Config *config, FILE *file ); |
||
231 | |||
232 | /* config section accessors/manipulators -- by type, name */ |
||
233 | |||
234 | /*! \see ::config_add_section() */ |
||
235 | extern ConfigSection *config_add_section_len( Config *config, const char *type, size_t type_len, const char *name, size_t name_len ); |
||
236 | |||
237 | /*! |
||
238 | * \brief Add a section to a configuration. |
||
239 | * |
||
240 | * \param[in] config the configuration to contain the section |
||
241 | * \param[in] type the type of the section |
||
242 | * \param[in] name the name of the section; may be \c NULL |
||
243 | * \return the added section; \c NULL if out of memory |
||
244 | */ |
||
245 | static inline ConfigSection *config_add_section( Config *config, const char *type, const char *name) |
||
246 | { |
||
247 | assert(type != NULL); |
||
248 | return config_add_section_len(config, type, strlen(type), name, name == NULL ? 0 : strlen(name)); |
||
249 | } |
||
250 | |||
251 | // TODO: extern Config *config_remove_section( Config *config, unsigned int i ); |
||
252 | |||
253 | /*! |
||
254 | * \brief Iterate sections by type. |
||
255 | * |
||
256 | * \param[in] config the configuration containing the sections |
||
257 | * \param[in] type the type of the section |
||
258 | * \param[in,out] save the saved state of the iterator; initialize \c *save to \c NULL before |
||
259 | * iteration |
||
260 | * \return the section; \c NULL if iteration finished |
||
261 | */ |
||
262 | extern ConfigSection *config_find_sections( Config *config, const char *type, ConfigSection **save ); |
||
263 | |||
264 | /*! |
||
265 | * \brief Find a section by type and name. |
||
266 | * |
||
267 | * \param[in] config the configuration containing the section |
||
268 | * \param[in] type the type of the section |
||
269 | * \param[in] name the name of the section |
||
270 | * \return the section; \c NULL if it does not exist |
||
271 | */ |
||
272 | extern ConfigSection *config_find_section( Config *config, const char *type, const char *name ); |
||
273 | |||
274 | /*! |
||
275 | * \brief Find a section by type and name, creating the section if it did not exist. |
||
276 | * |
||
277 | * \param[in] config the configuration containing the section |
||
278 | * \param[in] type the type of the section |
||
279 | * \param[in] name the name of the section; may be \c NULL |
||
280 | * \return the section; \c NULL if out of memory |
||
281 | */ |
||
282 | extern ConfigSection *config_find_or_add_section( Config *config, const char *type, const char *name ); |
||
283 | |||
284 | /* config option accessors/manipulators -- by key */ |
||
285 | |||
286 | /*! \see ::config_set_option() */ |
||
287 | extern ConfigOption *config_set_option_len( ConfigSection *section, const char *key, size_t key_len, const char *value, size_t value_len ); |
||
288 | |||
289 | /*! |
||
290 | * \brief Set a value of an 'item' option by key, creating the option if necessary. |
||
291 | * |
||
292 | * \param[in] section the section containing the option |
||
293 | * \param[in] key the option key |
||
294 | * \param[in] value the item value; \c NULL to set an emtpy 'list' option instead of an 'item' |
||
295 | * option (can be used to delete an 'item' option) |
||
296 | * \return the option; \c NULL if out of memory |
||
297 | */ |
||
298 | static inline ConfigOption *config_set_option( ConfigSection *section, const char *key, const char *value) |
||
299 | { |
||
300 | assert(key != NULL); |
||
301 | return config_set_option_len(section, key, strlen(key), value, value == NULL ? 0 : strlen(value)); |
||
302 | } |
||
303 | |||
304 | /*! |
||
305 | * \brief Get an option by key. |
||
306 | * |
||
307 | * \param[in] section the section containing the option |
||
308 | * \param[in] key the option key |
||
309 | * \return the option; \c NULL if it does not exist |
||
310 | */ |
||
311 | extern ConfigOption *config_get_option( const ConfigSection *section, const char *key ); |
||
312 | |||
313 | /*! \see ::config_get_or_set_option() */ |
||
314 | extern ConfigOption *config_get_or_set_option_len( ConfigSection *section, const char *key, size_t key_len, const char *value, size_t value_len ); |
||
315 | |||
316 | /*! |
||
317 | * \brief Get an option by key, creating an 'item' option if the option did not exist. |
||
318 | * |
||
319 | * \param[in] section the section containing the option |
||
320 | * \param[in] key the option key |
||
321 | * \param[in] value the default item value; \c NULL to set an empty 'list' option instead of an |
||
322 | * 'item' option |
||
323 | * \return the option; \c NULL if out of memory |
||
324 | */ |
||
325 | static inline ConfigOption *config_get_or_set_option( ConfigSection *section, const char *key, const char *value ) |
||
326 | { |
||
327 | assert(key != NULL); |
||
328 | return config_get_or_set_option_len(section, key, strlen(key), value, value == NULL ? 0 : strlen(value)); |
||
329 | } |
||
330 | |||
331 | /*! \see ::config_set_string_option() */ |
||
332 | extern void config_set_string_option_len( ConfigSection *section, const char *key, size_t key_len, const char *value, size_t value_len ); |
||
333 | |||
334 | /*! |
||
335 | * \brief Set a string value of an 'item' option by key, creating the option if necessary. |
||
336 | * |
||
337 | * \param[in] section the section containing the option |
||
338 | * \param[in] key the option key |
||
339 | * \param[in] value the item value |
||
340 | * \return void |
||
341 | */ |
||
342 | static inline void config_set_string_option( ConfigSection *section, const char *key, const char *value ) |
||
343 | { |
||
344 | assert(key != NULL); |
||
345 | config_set_string_option_len(section, key, strlen(key), value, value == NULL ? 0 : strlen(value)); |
||
346 | } |
||
347 | |||
348 | /*! |
||
349 | * \brief Get a string value of an 'item' option by key. |
||
350 | * |
||
351 | * \param[in] section the section containing the option |
||
352 | * \param[in] key the option key |
||
353 | * \param[out] out_value the item value if a valid option exists; otherwise unset |
||
354 | * \return whether \p out_value was set |
||
355 | */ |
||
356 | extern bool config_get_string_option( const ConfigSection *section, const char *key, const char **out_value ); |
||
357 | |||
358 | /*! |
||
359 | * \brief Get a string value of an 'item' option by key, setting the option if it was invalid or |
||
360 | * creating the option if it did not exist. |
||
361 | * |
||
362 | * \param[in] section the section containing the option |
||
363 | * \param[in] key the option key |
||
364 | * \param[in] value the default item value |
||
365 | * \return the value |
||
366 | */ |
||
367 | extern const char *config_get_or_set_string_option( ConfigSection *section, const char *key, const char *value ); |
||
368 | |||
369 | /*! |
||
370 | * \brief The styles of boolean values. |
||
371 | */ |
||
372 | typedef enum |
||
373 | { |
||
374 | ZERO_ONE = 0, |
||
375 | NO_YES = 1, |
||
376 | OFF_ON = 2, |
||
377 | FALSE_TRUE = 3, |
||
378 | } ConfigBoolStyle; |
||
379 | |||
380 | /*! |
||
381 | * \brief Set a boolean value of an 'item' option by key, creating the option if necessary. |
||
382 | * |
||
383 | * \param[in] section the section containing the option |
||
384 | * \param[in] key the option key |
||
385 | * \param[in] value the item value |
||
386 | * \param[in] style the style of boolean value |
||
387 | * \return void |
||
388 | */ |
||
389 | extern void config_set_bool_option( ConfigSection *section, const char *key, bool value, ConfigBoolStyle style ); |
||
390 | |||
391 | /*! |
||
392 | * \brief Get a boolean value of an 'item' option by key. |
||
393 | * |
||
394 | * \param[in] section the section containing the option |
||
395 | * \param[in] key the option key |
||
396 | * \param[out] out_value the item value if a valid option exists; otherwise unset |
||
397 | * \return whether \p out_value was set |
||
398 | */ |
||
399 | extern bool config_get_bool_option( const ConfigSection *section, const char *key, bool *out_value ); |
||
400 | |||
401 | /*! |
||
402 | * \brief Get a boolean value of an 'item' option by key, setting the option if it was invalid or |
||
403 | * creating the option if it did not exist. |
||
404 | * |
||
405 | * \param[in] section the section containing the option |
||
406 | * \param[in] key the option key |
||
407 | * \param[in] value the default item value |
||
408 | * \param[in] style the style of boolean value |
||
409 | * \return the value |
||
410 | */ |
||
411 | extern bool config_get_or_set_bool_option( ConfigSection *section, const char *key, bool value, ConfigBoolStyle style ); |
||
412 | |||
413 | /*! |
||
414 | * \brief Set an integer value of an 'item' option by key, creating the option if necessary. |
||
415 | * |
||
416 | * \param[in] section the section containing the option |
||
417 | * \param[in] key the option key |
||
418 | * \param[in] value the item value |
||
419 | * \return void |
||
420 | */ |
||
421 | extern void config_set_int_option( ConfigSection *section, const char *key, int value ); |
||
422 | |||
423 | /*! |
||
424 | * \brief Get an integer value of an 'item' option by key. |
||
425 | * |
||
426 | * \param[in] section the section containing the option |
||
427 | * \param[in] key the option key |
||
428 | * \param[out] out_value the item value if a valid option exists; otherwise unset |
||
429 | * \return whether \p out_value was set |
||
430 | */ |
||
431 | extern bool config_get_int_option( const ConfigSection *section, const char *key, int *out_value ); |
||
432 | |||
433 | /*! |
||
434 | * \brief Get an integer value of an 'item' option by key, setting the option if it was invalid or |
||
435 | * creating the option if it did not exist. |
||
436 | * |
||
437 | * \param[in] section the section containing the option |
||
438 | * \param[in] key the option key |
||
439 | * \param[in] value the default item value |
||
440 | * \return the value |
||
441 | */ |
||
442 | extern int config_get_or_set_int_option( ConfigSection *section, const char *key, int value ); |
||
443 | |||
444 | /*! |
||
445 | * \brief Set an unsigned integer value of an 'item' option by key, creating the option if |
||
446 | * necessary. |
||
447 | * |
||
448 | * \param[in] section the section containing the option |
||
449 | * \param[in] key the option key |
||
450 | * \param[in] value the item value |
||
451 | * \return void |
||
452 | */ |
||
453 | extern void config_set_uint_option( ConfigSection *section, const char *key, unsigned int value ); |
||
454 | |||
455 | /*! |
||
456 | * \brief Get an unsigned integer value of an 'item' option by key. |
||
457 | * |
||
458 | * \param[in] section the section containing the option |
||
459 | * \param[in] key the option key |
||
460 | * \param[out] out_value the item value if a valid option exists; otherwise unset |
||
461 | * \return whether \p out_value was set |
||
462 | */ |
||
463 | extern bool config_get_uint_option( const ConfigSection *section, const char *key, unsigned int *out_value ); |
||
464 | |||
465 | /*! |
||
466 | * \brief Get an unsigned integer value of an 'item' option by key, setting the option if it was |
||
467 | * invalid or creating the option if it did not exist. |
||
468 | * |
||
469 | * \param[in] section the section containing the option |
||
470 | * \param[in] key the option key |
||
471 | * \param[in] value the default item value |
||
472 | * \return the value |
||
473 | */ |
||
474 | extern unsigned int config_get_or_set_uint_option( ConfigSection *section, const char *key, unsigned int value ); |
||
475 | |||
476 | /* config option accessors/manipulators -- by reference */ |
||
477 | |||
478 | /*! \see ::config_set_value() */ |
||
479 | extern ConfigOption *config_set_value_len( ConfigOption *option, const char *value, size_t value_len ); |
||
480 | |||
481 | /*! |
||
482 | * \brief Set the value of an 'item' option. |
||
483 | * |
||
484 | * \param[in] option the option |
||
485 | * \param[in] value the value |
||
486 | * \return the option; \c NULL if out of memory |
||
487 | */ |
||
488 | static inline ConfigOption *config_set_value( ConfigOption *option, const char *value ) |
||
489 | { |
||
490 | return config_set_value_len(option, value, value == NULL ? 0 : strlen(value)); |
||
491 | } |
||
492 | |||
493 | /*! \see ::config_add_value() */ |
||
494 | extern ConfigOption *config_add_value_len( ConfigOption *option, const char *value, size_t value_len ); |
||
495 | |||
496 | /*! |
||
497 | * \brief Add a value to a 'list' option. |
||
498 | * |
||
499 | * \param[in] option the option |
||
500 | * \param[in] value the value |
||
501 | * \return the option; \c NULL if out of memory |
||
502 | */ |
||
503 | static inline ConfigOption *config_add_value( ConfigOption *option, const char *value ) |
||
504 | { |
||
505 | assert(value != NULL); |
||
506 | return config_add_value_len(option, value, strlen(value)); |
||
507 | } |
||
508 | |||
509 | /*! |
||
510 | * \brief Remove a value from a 'list' option. |
||
511 | * |
||
512 | * \param[in] option the option |
||
513 | * \param[in] i the index of the value |
||
514 | * \return the option; \c NULL if out of memory or invalid \p index |
||
515 | */ |
||
516 | extern ConfigOption *config_remove_value( ConfigOption *option, unsigned int i ); |
||
517 | |||
518 | /*! |
||
519 | * \brief Get the value of an 'item' option. |
||
520 | * |
||
521 | * \param[in] option the option |
||
522 | * \return the value; \c NULL if \p option was \c NULL or was a 'list' option |
||
523 | */ |
||
524 | extern const char *config_get_value( const ConfigOption *option ); |
||
525 | |||
526 | /*! |
||
527 | * \brief Get the value that indicates whether the option is a 'list' option. |
||
528 | * |
||
529 | * \param[in] option the option |
||
530 | * \return whether the option is a 'list' option |
||
531 | */ |
||
532 | static inline bool config_is_value_list( const ConfigOption *option ) |
||
533 | { |
||
534 | assert(option != NULL); |
||
535 | return option->values_count > 0 || |
||
536 | config_string_to_cstr(&option->v.value) == NULL; |
||
537 | } |
||
538 | |||
539 | /*! |
||
540 | * \brief Get the number of values assigned to the option. |
||
541 | * |
||
542 | * \param[in] option the option |
||
543 | * \return \c 1 if the option is an 'item' option; the number of elements if the option is a 'list' |
||
544 | * option |
||
545 | */ |
||
546 | static inline unsigned int config_get_value_count( const ConfigOption *option ) |
||
547 | { |
||
548 | assert(option != NULL); |
||
549 | return option->values_count == 0 ? |
||
550 | (config_string_to_cstr(&option->v.value) == NULL ? 0 : 1) : |
||
551 | option->values_count; |
||
552 | } |
||
553 | |||
554 | /*! |
||
555 | * \brief Iterate over the values assigned to the option. |
||
556 | * |
||
557 | * \param[out] string_value the value variable to declare |
||
558 | * \param[in] option the option |
||
559 | */ |
||
560 | #define foreach_option_value( string_value, option ) \ |
||
561 | for (ConfigOption *_option = (option); _option != NULL; _option = NULL) \ |
||
562 | for (ConfigString *_values_begin = _option->values_count == 0 ? &_option->v.value : &_option->v.values[0], \ |
||
563 | *_values_end = _option->values_count == 0 ? _values_begin + 1 : &_option->v.values[_option->values_count], \ |
||
564 | *_value = _values_begin; _value < _values_end; ++_value) \ |
||
565 | for (const char *(string_value) = config_string_to_cstr(_value); (string_value) != NULL; (string_value) = NULL) |
||
566 | |||
567 | /*! |
||
568 | * \brief Iterate over the values assigned to the option. |
||
569 | * |
||
570 | * \param[out] i the index variable to declare |
||
571 | * \param[out] string_value the value variable to declare |
||
572 | * \param[in] option the option |
||
573 | */ |
||
574 | #define foreach_option_i_value( i, string_value, option ) \ |
||
575 | for (unsigned int (i) = 0; (i) == 0; (i) = ~0) \ |
||
576 | for (ConfigOption *_option = (option); _option != NULL; _option = NULL) \ |
||
577 | for (ConfigString *_values_begin = _option->values_count == 0 ? &_option->v.value : &_option->v.values[0], \ |
||
578 | *_values_end = _option->values_count == 0 ? _values_begin + 1 : &_option->v.values[_option->values_count], \ |
||
579 | *_value = _values_begin; _value < _values_end; ++_value, (i) = _value - _values_begin) \ |
||
580 | for (const char *(string_value) = config_string_to_cstr(_value); (string_value) != NULL; (string_value) = NULL) |
||
581 | |||
582 | /*! |
||
583 | * \brief Remove a value from an option during iteration. Should be followed by \c continue. |
||
584 | */ |
||
585 | #define foreach_remove_option_value() \ |
||
586 | { \ |
||
587 | extern void config_oom( void ); \ |
||
588 | unsigned int _value_i = _value - _values_begin; \ |
||
589 | if (config_remove_value(_option, _value_i) == NULL) \ |
||
590 | config_oom(); \ |
||
591 | _values_begin = _option->values_count == 0 ? &_option->v.value : &_option->v.values[0]; \ |
||
592 | _values_end = _option->values_count == 0 ? _values_begin + 1 : &_option->v.values[_option->values_count]; \ |
||
593 | _value = _values_begin + _value_i - 1; \ |
||
594 | } |
||
595 | |||
596 | #endif>>=> |