Read a configuration file: Difference between revisions
Content added Content deleted
Thundergnat (talk | contribs) (→{{header|Perl 6}}: Update to modern code. A little stricter about proto regex syntax) |
(→C: Added example) |
||
Line 603: | Line 603: | ||
otherfamily(2) = Harry Barber |
otherfamily(2) = Harry Barber |
||
</pre> |
</pre> |
||
=={{header|C}}== |
|||
{{libheader|libconfini}} |
|||
'''optimized''' |
|||
<lang c>#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <confini.h> |
|||
#define bool unsigned char |
|||
#define FALSE 0 |
|||
#define TRUE 1 |
|||
#define CONFIGS_MEMBERS 5 |
|||
#define INI_ARRAY_DELIMITER ',' |
|||
/* Assume that the config file represent a struct containing all the parameters to load */ |
|||
struct configs { |
|||
char *fullname; |
|||
char *favouritefruit; |
|||
bool needspeeling; |
|||
bool seedsremoved; |
|||
char **otherfamily; |
|||
size_t otherfamily_len; |
|||
size_t _configs_left_; |
|||
}; |
|||
static inline void free_non_null (void * ptr) { |
|||
if (ptr) { free(ptr); } |
|||
} |
|||
static int array_part_handler (char * part, size_t partlen, size_t idx, IniFormat ini_format, void * v_array) { |
|||
ini_string_parse(part, ini_format); /* Remove all quotes, if any */ |
|||
((char **) v_array)[idx] = part; |
|||
return 0; |
|||
} |
|||
static char ** make_array (size_t * arrlen, const char * src, const size_t srclen, IniFormat ini_format) { |
|||
/* Allocate a new array of strings and populate it from the stringified source */ |
|||
char ** dest; |
|||
*arrlen = ini_array_get_length(src, INI_ARRAY_DELIMITER, ini_format); |
|||
dest = (char **) malloc(*arrlen * sizeof(char *) + srclen * sizeof(char)); |
|||
char * const str_ptr = (char *) dest + *arrlen * sizeof(char *); |
|||
memcpy(str_ptr, src, srclen); |
|||
ini_array_split(str_ptr, INI_ARRAY_DELIMITER, ini_format, array_part_handler, dest); |
|||
return dest; |
|||
} |
|||
static int configs_member_handler (IniDispatch *this, void *v_confs) { |
|||
struct configs *confs = (struct configs *) v_confs; |
|||
if (this->type != INI_KEY) { |
|||
return 0; |
|||
} |
|||
/* Remove all quotes, if any */ |
|||
this->d_len = ini_string_parse(this->data, this->format); |
|||
if (ini_string_match_ss("FULLNAME", this->data, this->format)) { |
|||
this->v_len = ini_string_parse(this->value, this->format); /* Remove all quotes, if any */ |
|||
confs->fullname = strndup(this->value, this->v_len); |
|||
confs->_configs_left_--; |
|||
} else if (ini_string_match_ss("FAVOURITEFRUIT", this->data, this->format)) { |
|||
this->v_len = ini_string_parse(this->value, this->format); /* Remove all quotes, if any */ |
|||
confs->favouritefruit = strndup(this->value, this->v_len); |
|||
confs->_configs_left_--; |
|||
} else if (ini_string_match_ss("NEEDSPEELING", this->data, this->format)) { |
|||
confs->needspeeling = ini_get_bool(this->value, TRUE); |
|||
confs->_configs_left_--; |
|||
} else if (ini_string_match_ss("SEEDSREMOVED", this->data, this->format)) { |
|||
confs->seedsremoved = ini_get_bool(this->value, TRUE); |
|||
confs->_configs_left_--; |
|||
} else if (ini_string_match_ss("OTHERFAMILY", this->data, this->format)) { |
|||
this->v_len = ini_array_collapse(this->value, INI_ARRAY_DELIMITER, this->format); /* Save memory (not strictly needed) */ |
|||
confs->otherfamily = make_array(&confs->otherfamily_len, this->value, this->v_len + 1, this->format); |
|||
confs->_configs_left_--; |
|||
} |
|||
/* Optimization: stop reading the INI file when we have all we need */ |
|||
return !confs->_configs_left_; |
|||
} |
|||
static int populate_configs (struct configs * confs) { |
|||
/* Define the format of the configuration file */ |
|||
IniFormat config_format = { |
|||
.delimiter_symbol = INI_ANY_SPACE, |
|||
.semicolon_marker = INI_IGNORE, |
|||
.hash_marker = INI_IGNORE, |
|||
.multiline_nodes = INI_NO_MULTILINE, |
|||
.case_sensitive = TRUE, |
|||
.no_spaces_in_names = TRUE, |
|||
.no_single_quotes = FALSE, |
|||
.no_double_quotes = FALSE, |
|||
.implicit_is_not_empty = TRUE, |
|||
.do_not_collapse_values = FALSE, |
|||
.preserve_empty_quotes = FALSE, |
|||
.no_disabled_after_space = FALSE, |
|||
.disabled_can_be_implicit = FALSE |
|||
}; |
|||
*confs = (struct configs) { NULL, NULL, FALSE, FALSE, NULL, 0, CONFIGS_MEMBERS }; |
|||
if (load_ini_path("rosetta.conf", config_format, NULL, configs_member_handler, confs) & CONFINI_ERROR) { |
|||
fprintf(stderr, "Sorry, something went wrong :-(\n"); |
|||
return 1; |
|||
} |
|||
return 0; |
|||
} |
|||
int main () { |
|||
struct configs confs; |
|||
ini_global_set_implicit_value("YES", 0); |
|||
populate_configs(&confs); |
|||
/* Print the configurations parsed */ |
|||
printf( |
|||
"Full name: %s\n" |
|||
"Favorite fruit: %s\n" |
|||
"Need spelling: %s\n" |
|||
"Seeds removed: %s\n", |
|||
confs.fullname, |
|||
confs.favouritefruit, |
|||
confs.needspeeling ? "True" : "False", |
|||
confs.seedsremoved ? "True" : "False" |
|||
); |
|||
for (size_t idx = 0; idx < confs.otherfamily_len; idx++) { |
|||
printf("Other family[%d]: %s\n", idx, confs.otherfamily[idx]); |
|||
} |
|||
/* Free the allocated memory */ |
|||
free_non_null(confs.fullname); |
|||
free_non_null(confs.favouritefruit); |
|||
free_non_null(confs.otherfamily); |
|||
return 0; |
|||
}</lang> |
|||
{{out}} |
|||
<pre>Full name: Foo Barber |
|||
Favorite fruit: banana |
|||
Need spelling: True |
|||
Seeds removed: False |
|||
Other family[0]: Rhu Barber |
|||
Other family[1]: Harry Barber</pre> |
|||
=={{header|C++}}== |
=={{header|C++}}== |