Subversion Repositories Kolibri OS

Rev

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