Replace ini with toml

This commit is contained in:
Tobias Reisinger 2020-11-17 23:13:01 +01:00
parent 97a19135ce
commit 5796f88e05
11 changed files with 242 additions and 5726 deletions

View file

@ -1,16 +0,0 @@
[core]
server-port = 5000
database = emgauwa-core.sqlite
content-dir = /usr/share/webapps/emgauwa
not-found-file = 404.html
not-found-file-mime = text/html
not-found-content = 404 - NOT FOUND
not-found-content-type = text/plain
: 4422 for testing; 4421 for dev-env; 4420 for testing-env; 4419 for prod-env
discovery-port = 4421
: 1886 for testing; 1885 for dev-env; 1884 for testing-env; 1883 for prod-env
mqtt-port = 1885
log-level = debug
log-file = stdout

View file

@ -4,7 +4,7 @@
#include <stdint.h>
#include <mongoose.h>
#include <confini.h>
#include <toml.h>
typedef struct
{
@ -13,16 +13,25 @@ typedef struct
char *database;
char *user;
char *group;
int log_level;
FILE *log_file;
uint16_t server_port;
uint16_t discovery_port;
uint16_t mqtt_port;
char *content_dir;
char *not_found_file;
char *not_found_file_type;
char *not_found_content;
char *not_found_content_type;
struct
{
int level;
FILE *file;
} logging;
struct
{
uint16_t server;
uint16_t discovery;
uint16_t mqtt;
} ports;
struct mg_serve_http_opts http_server_opts;
} config_t;
@ -38,6 +47,9 @@ void
config_load_string(char **holder, const char *value);
int
config_load(IniDispatch *disp, void *config_void);
config_load(config_t *config);
void
config_load_directory(config_t *config, char *directory_name);
#endif /* CORE_CONFIG_H */

View file

@ -22,7 +22,7 @@
#define PIFACE_GPIO_BASE 200
#define DEFAULT_CONFIG_PATH "emgauwa-core.ini"
#define DEFAULT_CONFIG_PATH "emgauwa-core.toml"
#define DEFAULT_DISCOVERY_PORT 4421
#define DEFAULT_MQTT_PORT 1885
#define DEFAULT_SERVER_PORT 5000

View file

@ -1,5 +1,8 @@
#include <bsd/string.h>
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <config.h>
#include <constants.h>
@ -13,72 +16,185 @@ config_t *global_config;
ini_string_match_ii(KEY, disp->data, disp->format))
static int
config_load_log_level(IniDispatch *disp, config_t *config)
config_load_log_level(config_t *config, char *value)
{
if(strcmp(disp->value, "debug") == 0)
if(strcmp(value, "debug") == 0)
{
setlogmask(LOG_UPTO(LOG_DEBUG));
config->log_level = LOG_DEBUG;
config->logging.level = LOG_DEBUG;
return 0;
}
if(strcmp(disp->value, "info") == 0)
if(strcmp(value, "info") == 0)
{
setlogmask(LOG_UPTO(LOG_INFO));
config->log_level = LOG_INFO;
config->logging.level = LOG_INFO;
return 0;
}
if(strcmp(disp->value, "notice") == 0)
if(strcmp(value, "notice") == 0)
{
setlogmask(LOG_UPTO(LOG_NOTICE));
config->log_level = LOG_NOTICE;
config->logging.level = LOG_NOTICE;
return 0;
}
if(strcmp(disp->value, "warning") == 0)
if(strcmp(value, "warning") == 0)
{
setlogmask(LOG_UPTO(LOG_WARNING));
config->log_level = LOG_WARNING;
config->logging.level = LOG_WARNING;
return 0;
}
if(strcmp(disp->value, "err") == 0)
if(strcmp(value, "err") == 0)
{
setlogmask(LOG_UPTO(LOG_ERR));
config->log_level = LOG_ERR;
config->logging.level = LOG_ERR;
return 0;
}
if(strcmp(disp->value, "crit") == 0)
if(strcmp(value, "crit") == 0)
{
setlogmask(LOG_UPTO(LOG_CRIT));
config->log_level = LOG_CRIT;
config->logging.level = LOG_CRIT;
return 0;
}
if(strcmp(disp->value, "emerg") == 0)
if(strcmp(value, "emerg") == 0)
{
setlogmask(LOG_UPTO(LOG_EMERG));
config->log_level = LOG_EMERG;
config->logging.level = LOG_EMERG;
return 0;
}
LOGGER_WARNING("invalid log-level '%s'\n", disp->value);
LOGGER_WARNING("invalid log-level '%s'\n", value);
return 0;
}
static int
config_load_log_file(IniDispatch *disp, config_t *config)
config_load_log_file(config_t *config, char *value)
{
if(strcmp(disp->value, "stdout") == 0)
if(strcmp(value, "stdout") == 0)
{
config->log_file = stdout;
config->logging.file = stdout;
return 0;
}
if(strcmp(disp->value, "stderr") == 0)
if(strcmp(value, "stderr") == 0)
{
config->log_file = stderr;
config->logging.file = stderr;
return 0;
}
config->log_file = fopen(disp->value, "a+");
config->logging.file = fopen(value, "a+");
return 0;
}
static void
config_load_section_core(config_t *config, toml_table_t* core)
{
toml_datum_t config_entry;
config_entry = toml_string_in(core, "database");
if(config_entry.ok)
{
config_load_string(&config->database, config_entry.u.s);
free(config_entry.u.s);
}
config_entry = toml_string_in(core, "user");
if(config_entry.ok)
{
config_load_string(&config->user, config_entry.u.s);
free(config_entry.u.s);
}
config_entry = toml_string_in(core, "group");
if(config_entry.ok)
{
config_load_string(&config->group, config_entry.u.s);
free(config_entry.u.s);
}
config_entry = toml_string_in(core, "content-dir");
if(config_entry.ok)
{
config_load_string(&config->content_dir, config_entry.u.s);
free(config_entry.u.s);
}
config_entry = toml_string_in(core, "not-found-file");
if(config_entry.ok)
{
config_load_string(&config->not_found_file, config_entry.u.s);
free(config_entry.u.s);
}
config_entry = toml_string_in(core, "not-found-file-type");
if(config_entry.ok)
{
config_load_string(&config->not_found_file_type, config_entry.u.s);
free(config_entry.u.s);
}
config_entry = toml_string_in(core, "not-found-content");
if(config_entry.ok)
{
config_load_string(&config->not_found_content, config_entry.u.s);
free(config_entry.u.s);
}
config_entry = toml_string_in(core, "not-found-content-type");
if(config_entry.ok)
{
config_load_string(&config->not_found_content_type, config_entry.u.s);
free(config_entry.u.s);
}
config_entry = toml_string_in(core, "include");
if(config_entry.ok)
{
config_load_string(&config->include, config_entry.u.s);
free(config_entry.u.s);
}
}
static void
config_load_section_logging(config_t *config, toml_table_t* logging)
{
toml_datum_t config_entry;
config_entry = toml_string_in(logging, "level");
if(config_entry.ok)
{
config_load_log_level(config, config_entry.u.s);
free(config_entry.u.s);
}
config_entry = toml_string_in(logging, "file");
if(config_entry.ok)
{
config_load_log_file(config, config_entry.u.s);
free(config_entry.u.s);
}
}
static void
config_load_section_ports(config_t *config, toml_table_t* ports)
{
toml_datum_t config_entry;
config_entry = toml_int_in(ports, "server");
if(config_entry.ok)
{
config->ports.server = config_entry.u.i;
}
config_entry = toml_int_in(ports, "discovery");
if(config_entry.ok)
{
config->ports.discovery = config_entry.u.i;
}
config_entry = toml_int_in(ports, "mqtt");
if(config_entry.ok)
{
config->ports.mqtt = config_entry.u.i;
}
}
void
config_init()
{
@ -86,12 +202,12 @@ config_init()
config_load_string(&global_config->file, DEFAULT_CONFIG_PATH);
global_config->discovery_port = DEFAULT_DISCOVERY_PORT;
global_config->mqtt_port = DEFAULT_MQTT_PORT;
global_config->server_port = DEFAULT_SERVER_PORT;
global_config->ports.discovery = DEFAULT_DISCOVERY_PORT;
global_config->ports.mqtt = DEFAULT_MQTT_PORT;
global_config->ports.server = DEFAULT_SERVER_PORT;
global_config->log_level = LOG_DEBUG;
global_config->log_file = stdout;
global_config->logging.level = LOG_DEBUG;
global_config->logging.file = stdout;
global_config->user = NULL;
global_config->group = NULL;
@ -136,80 +252,71 @@ config_load_string(char **holder, const char *value)
}
int
config_load(IniDispatch *disp, void *config_void)
config_load(config_t *config)
{
config_t *config = (config_t*)config_void;
FILE *fp;
toml_table_t* config_toml;
char errbuf[256];
if(disp->type == INI_KEY)
{
if(CONFINI_IS_KEY("core", "include"))
{
config_load_string(&config->include, disp->value);
return 0;
/* Open the file and parse content */
fp = fopen(global_config->file, "r");
if(fp == NULL) {
LOGGER_CRIT("unable to open config file '%s'\n", global_config->file);
exit(1);
}
if(CONFINI_IS_KEY("core", "database"))
config_toml = toml_parse_file(fp, errbuf, sizeof(errbuf));
fclose(fp);
if(config_toml == NULL) {
LOGGER_CRIT("unable to parse config file '%s': %s\n", global_config->file, errbuf);
exit(1);
}
toml_table_t* core = toml_table_in(config_toml, "core");
if(core)
{
config_load_string(&config->database, disp->value);
return 0;
config_load_section_core(config, core);
}
if(CONFINI_IS_KEY("core", "user"))
toml_table_t* logging = toml_table_in(config_toml, "logging");
if(logging)
{
config_load_string(&config->user, disp->value);
return 0;
config_load_section_logging(config, logging);
}
if(CONFINI_IS_KEY("core", "group"))
toml_table_t* ports = toml_table_in(config_toml, "ports");
if(ports)
{
config_load_string(&config->group, disp->value);
return 0;
}
if(CONFINI_IS_KEY("core", "content-dir"))
{
config_load_string(&config->content_dir, disp->value);
return 0;
}
if(CONFINI_IS_KEY("core", "not-found-file"))
{
config_load_string(&config->not_found_file, disp->value);
return 0;
}
if(CONFINI_IS_KEY("core", "not-found-file-type"))
{
config_load_string(&config->not_found_file_type, disp->value);
return 0;
}
if(CONFINI_IS_KEY("core", "not-found-content"))
{
config_load_string(&config->not_found_content, disp->value);
return 0;
}
if(CONFINI_IS_KEY("core", "not-found-content-type"))
{
config_load_string(&config->not_found_content_type, disp->value);
return 0;
}
if(CONFINI_IS_KEY("core", "log-level"))
{
return config_load_log_level(disp, config);
}
if(CONFINI_IS_KEY("core", "log-file"))
{
return config_load_log_file(disp, config);
}
if(CONFINI_IS_KEY("core", "server-port"))
{
config->server_port = atoi(disp->value);
return 0;
}
if(CONFINI_IS_KEY("core", "discovery-port"))
{
config->discovery_port = atoi(disp->value);
return 0;
}
if(CONFINI_IS_KEY("core", "mqtt-port"))
{
config->mqtt_port = atoi(disp->value);
return 0;
}
config_load_section_ports(config, ports);
}
toml_free(config_toml);
return 0;
}
void
config_load_directory(config_t *config, char *directory_name)
{
struct dirent *pDirent;
DIR *pDir;
(void)config;
pDir = opendir (directory_name);
if(pDir == NULL)
{
LOGGER_CRIT("cannot open directory '%s': %s\n", directory_name, strerror(errno));
exit(1);
}
// Process each entry.
while((pDirent = readdir(pDir)) != NULL)
{
LOGGER_DEBUG("including: %s\n", pDirent->d_name);
}
// Close directory and exit.
closedir(pDir);
}

View file

@ -125,7 +125,7 @@ api_v1_controllers_discover_PUT(struct mg_connection *nc, struct http_message *h
payload[0] = discover_server_port;
LOGGER_DEBUG("sending udp broadcast\n");
if(send_udp_broadcast("255.255.255.255", global_config->discovery_port, payload, sizeof(payload)) < 0)
if(send_udp_broadcast("255.255.255.255", global_config->ports.discovery, payload, sizeof(payload)) < 0)
{
M_RESPONSE_MSG(LOGGER_ERR, response, 500, "the server failed to send discovery broadcast");
return;

View file

@ -17,7 +17,7 @@ const char *COLOR_EMERG = COLOR_MAGENTA;
void
logger_log(int level, const char *filename, int line, const char *func, const char *msg, ...)
{
if(global_config->log_level < level || level == LOG_NONE )
if(global_config->logging.level < level || level == LOG_NONE )
{
return;
}
@ -82,8 +82,8 @@ logger_log(int level, const char *filename, int line, const char *func, const ch
syslog(level, "%s", log_line + timestamp_len + 1);
fprintf(global_config->log_file, "%s", log_line);
fflush(global_config->log_file);
fprintf(global_config->logging.file, "%s", log_line);
fflush(global_config->logging.file);
free(buffer);
free(log_line);

View file

@ -3,7 +3,6 @@
#include <string.h>
#include <syslog.h>
#include <confini.h>
#include <mongoose.h>
#include <cache.h>
@ -62,23 +61,16 @@ main(int argc, const char** argv)
cli_parse(argc, argv, global_config);
FILE * const ini_file = fopen(global_config->file, "rb");
if(ini_file == NULL)
config_load(global_config);
if(global_config->logging.file == NULL)
{
LOGGER_CRIT("config file '%s' was not found\n", global_config->file);
exit(1);
}
if(load_ini_file(ini_file, INI_DEFAULT_FORMAT, NULL, config_load, global_config))
{
LOGGER_CRIT("unable to parse ini file\n");
exit(1);
global_config->logging.file = stdout;
}
fclose(ini_file);
if(global_config->log_file == NULL)
if(global_config->include)
{
global_config->log_file = stdout;
config_load_directory(global_config, global_config->include);
}
LOGGER_DEBUG("Loaded config from %s\n", global_config->file);
@ -91,20 +83,20 @@ main(int argc, const char** argv)
mg_mgr_init(&mgr, NULL);
char address[100];
sprintf(address, "tcp://0.0.0.0:%u", global_config->server_port);
sprintf(address, "tcp://0.0.0.0:%u", global_config->ports.server);
struct mg_connection *c_http = mg_bind(&mgr, address, handler_http);
if(c_http == NULL)
{
LOGGER_CRIT("failed to bind http server to port %u\n", global_config->server_port);
LOGGER_CRIT("failed to bind http server to port %u\n", global_config->ports.server);
exit(1);
}
mg_set_protocol_http_websocket(c_http);
sprintf(address, "tcp://0.0.0.0:%u", global_config->mqtt_port);
sprintf(address, "tcp://0.0.0.0:%u", global_config->ports.mqtt);
struct mg_connection *c_mqtt = mg_bind(&mgr, address, handler_mqtt);
if(c_mqtt == NULL)
{
LOGGER_CRIT("failed to bind mqtt server to port %u\n", global_config->mqtt_port);
LOGGER_CRIT("failed to bind mqtt server to port %u\n", global_config->ports.mqtt);
exit(1);
}
mg_mqtt_broker_init(&brk, NULL);

View file

@ -1,16 +0,0 @@
[core]
server-port = 5000
database = core.sqlite
content-dir = .
not-found-file = 404.html
not-found-file-mime = text/html
not-found-content = 404 - NOT FOUND
not-found-content-type = text/plain
: 4422 for testing; 4421 for dev-env; 4420 for testing-env; 4419 for prod-env
discovery-port = 4422
: 1886 for testing; 1885 for dev-env; 1884 for testing-env; 1883 for prod-env
mqtt-port = 1886
log-level = debug
log-file = stdout

View file

@ -41,7 +41,7 @@ touch $working_dir/index.html
cp $1 $working_dir/core
valgrind_emgauwa $working_dir/core -c $source_dir/emgauwa-core-testing.ini >>$working_dir/core.log 2>&1 &
valgrind_emgauwa $working_dir/core -c $source_dir/emgauwa-core-testing.toml >>$working_dir/core.log 2>&1 &
core_id=$!
@ -62,7 +62,7 @@ kill $core_id
kill $controller_id
timestamp=$(date -Iseconds)
for backup_file in core.log controller.log valgrind.log core.sqlite; do
for backup_file in core.log controller.log valgrind.log emgauwa-core.sqlite; do
mv $backup_file $timestamp.$backup_file
ln -sf $timestamp.$backup_file latest.$backup_file
done

5016
vendor/confini.c vendored

File diff suppressed because it is too large Load diff

547
vendor/confini.h vendored
View file

@ -1,547 +0,0 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
/**
@file confini.h
@brief libconfini header
@author Stefano Gioffr&eacute;
@copyright GNU General Public License, version 3 or any later version
@version 1.14.0
@date 2016-2020
@see https://madmurphy.github.io/libconfini
**/
#ifndef _LIBCONFINI_HEADER_
#define _LIBCONFINI_HEADER_
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* PRIVATE (HEADER-SCOPED) MACROS */
#define __INIFORMAT_TABLE_CB_FIELDS__(NAME, OFFSET, SIZE, DEFVAL) \
unsigned char NAME:SIZE;
#define __INIFORMAT_TABLE_CB_DEFAULT__(NAME, OFFSET, SIZE, DEFVAL) DEFVAL,
#define __INIFORMAT_TABLE_CB_ZERO__(NAME, OFFSET, SIZE, DEFVAL) 0,
#define _LIBCONFINI_INIFORMAT_TYPE_ \
struct IniFormat { INIFORMAT_TABLE_AS(__INIFORMAT_TABLE_CB_FIELDS__) }
#define _LIBCONFINI_DEFAULT_FORMAT_ \
{ INIFORMAT_TABLE_AS(__INIFORMAT_TABLE_CB_DEFAULT__) }
#define _LIBCONFINI_UNIXLIKE_FORMAT_ \
{ INIFORMAT_TABLE_AS(__INIFORMAT_TABLE_CB_ZERO__) }
/* PUBLIC MACROS */
/**
@brief Calls a user-given macro (that accepts four arguments) for each row
of the table
**/
/*
NOTE: The following table and the order of its rows **define** (and link
together) both the #IniFormat and #IniFormatNum data types declared in this
header
*/
#define INIFORMAT_TABLE_AS(_____) /* IniFormat table *\
NAME BIT SIZE DEFAULT
*/\
_____( delimiter_symbol, 0, 7, INI_EQUALS ) \
_____( case_sensitive, 7, 1, false )/*
*/\
_____( semicolon_marker, 8, 2, INI_DISABLED_OR_COMMENT ) \
_____( hash_marker, 10, 2, INI_DISABLED_OR_COMMENT ) \
_____( section_paths, 12, 2, INI_ABSOLUTE_AND_RELATIVE ) \
_____( multiline_nodes, 14, 2, INI_MULTILINE_EVERYWHERE )/*
*/\
_____( no_single_quotes, 16, 1, false ) \
_____( no_double_quotes, 17, 1, false ) \
_____( no_spaces_in_names, 18, 1, false ) \
_____( implicit_is_not_empty, 19, 1, false ) \
_____( do_not_collapse_values, 20, 1, false ) \
_____( preserve_empty_quotes, 21, 1, false ) \
_____( disabled_after_space, 22, 1, false ) \
_____( disabled_can_be_implicit, 23, 1, false )
/**
@brief Checks whether a format does **not** support escape sequences
**/
#define INIFORMAT_HAS_NO_ESC(FORMAT) \
(FORMAT.multiline_nodes == INI_NO_MULTILINE && \
FORMAT.no_double_quotes && FORMAT.no_single_quotes)
/* PUBLIC TYPEDEFS */
/**
@brief 24-bit bitfield representing the format of an INI file (INI
dialect)
**/
typedef _LIBCONFINI_INIFORMAT_TYPE_ IniFormat;
/**
@brief Global statistics about an INI file
**/
typedef struct IniStatistics {
const IniFormat format;
const size_t bytes;
const size_t members;
} IniStatistics;
/**
@brief Dispatch of a single INI node
**/
typedef struct IniDispatch {
const IniFormat format;
uint8_t type;
char * data;
char * value;
const char * append_to;
size_t d_len;
size_t v_len;
size_t at_len;
size_t dispatch_id;
} IniDispatch;
/**
@brief The unique ID of an INI format (24-bit maximum)
**/
typedef uint32_t IniFormatNum;
/**
@brief Callback function for handling an #IniStatistics structure
**/
typedef int (* IniStatsHandler) (
IniStatistics * statistics,
void * user_data
);
/**
@brief Callback function for handling an #IniDispatch structure
**/
typedef int (* IniDispHandler) (
IniDispatch * dispatch,
void * user_data
);
/**
@brief Callback function for handling an INI string belonging to a
sequence of INI strings
**/
typedef int (* IniStrHandler) (
char * ini_string,
size_t string_length,
size_t string_num,
IniFormat format,
void * user_data
);
/**
@brief Callback function for handling a selected fragment of an INI string
**/
typedef int (* IniSubstrHandler) (
const char * ini_string,
size_t fragm_offset,
size_t fragm_length,
size_t fragm_num,
IniFormat format,
void * user_data
);
/* PUBLIC FUNCTIONS */
extern int strip_ini_cache (
register char * const ini_source,
const size_t ini_length,
const IniFormat format,
const IniStatsHandler f_init,
const IniDispHandler f_foreach,
void * const user_data
);
extern int load_ini_file (
FILE * const ini_file,
const IniFormat format,
const IniStatsHandler f_init,
const IniDispHandler f_foreach,
void * const user_data
);
extern int load_ini_path (
const char * const path,
const IniFormat format,
const IniStatsHandler f_init,
const IniDispHandler f_foreach,
void * const user_data
);
extern bool ini_string_match_ss (
const char * const simple_string_a,
const char * const simple_string_b,
const IniFormat format
);
extern bool ini_string_match_si (
const char * const simple_string,
const char * const ini_string,
const IniFormat format
);
extern bool ini_string_match_ii (
const char * const ini_string_a,
const char * const ini_string_b,
const IniFormat format
);
extern bool ini_array_match (
const char * const ini_string_a,
const char * const ini_string_b,
const char delimiter,
const IniFormat format
);
extern size_t ini_unquote (
char * const ini_string,
const IniFormat format
);
extern size_t ini_string_parse (
char * const ini_string,
const IniFormat format
);
extern size_t ini_array_get_length (
const char * const ini_string,
const char delimiter,
const IniFormat format
);
extern int ini_array_foreach (
const char * const ini_string,
const char delimiter,
const IniFormat format,
const IniSubstrHandler f_foreach,
void * const user_data
);
extern size_t ini_array_shift (
const char ** const ini_strptr,
const char delimiter,
const IniFormat format
);
extern size_t ini_array_collapse (
char * const ini_string,
const char delimiter,
const IniFormat format
);
extern char * ini_array_break (
char * const ini_string,
const char delimiter,
const IniFormat format
);
extern char * ini_array_release (
char ** const ini_strptr,
const char delimiter,
const IniFormat format
);
extern int ini_array_split (
char * const ini_string,
const char delimiter,
const IniFormat format,
const IniStrHandler f_foreach,
void * const user_data
);
extern void ini_global_set_lowercase_mode (
const bool lowercase
);
extern void ini_global_set_implicit_value (
char * const implicit_value,
const size_t implicit_v_len
);
extern IniFormatNum ini_fton (
const IniFormat format
);
extern IniFormat ini_ntof (
const IniFormatNum format_id
);
extern int ini_get_bool (
const char * const ini_string,
const int when_fail
);
/* PUBLIC LINKS */
extern int (* const ini_get_int) (
const char * ini_string
);
extern long int (* const ini_get_lint) (
const char * ini_string
);
extern long long int (* const ini_get_llint) (
const char * ini_string
);
extern double (* const ini_get_double) (
const char * ini_string
);
/**
@brief Legacy support, soon to be replaced with a `float` data type --
please **do not use `ini_get_float()`!**
**/
#define ini_get_float \
_Pragma("GCC warning \"function `ini_get_float()` is deprecated for parsing a `double` data type; use `ini_get_double()` instead\"") \
ini_get_double
/* PUBLIC CONSTANTS AND VARIABLES */
/**
@brief Error mask (flags not present in user-generated interruptions)
**/
#define CONFINI_ERROR 252
/**
@brief Error codes
**/
enum ConfiniInterruptNo {
CONFINI_SUCCESS = 0, /**< There have been no interruptions, everything
went well [value=0] **/
CONFINI_IINTR = 1, /**< Interrupted by the user during `f_init()`
[value=1] **/
CONFINI_FEINTR = 2, /**< Interrupted by the user during `f_foreach()`
[value=2] **/
CONFINI_ENOENT = 4, /**< File inaccessible [value=4] **/
CONFINI_ENOMEM = 5, /**< Error allocating virtual memory [value=5] **/
CONFINI_EIO = 6, /**< Error reading the file [value=6] **/
CONFINI_EOOR = 7, /**< Out-of-range error: callbacks are more than
expected [value=7] **/
CONFINI_EBADF = 8, /**< The stream specified is not a seekable stream
[value=8] **/
CONFINI_EFBIG = 9, /**< File too large [value=9] **/
CONFINI_EROADDR = 10 /**< Address is read-only [value=10] **/
};
/**
@brief INI node types
**/
enum IniNodeType {
INI_UNKNOWN = 0, /**< This is a node impossible to categorize
[value=0] **/
INI_VALUE = 1, /**< Not used by **libconfini** (values are
dispatched together with keys) -- but
available for user's implementations
[value=1] **/
INI_KEY = 2, /**< This is a key [value=2] **/
INI_SECTION = 3, /**< This is a section or a section path
[value=3] **/
INI_COMMENT = 4, /**< This is a comment [value=4] **/
INI_INLINE_COMMENT = 5, /**< This is an inline comment [value=5] **/
INI_DISABLED_KEY = 6, /**< This is a disabled key [value=6] **/
INI_DISABLED_SECTION = 7 /**< This is a disabled section path
[value=7] **/
};
/**
@brief Common array and key-value delimiters (but a delimiter may also be
any other ASCII character not present in this list)
**/
enum IniDelimiters {
INI_ANY_SPACE = 0, /**< In multi-line INIs:
`/(?:\\(?:\n\r?|\r\n?)|[\t \v\f])+/`, in
non-multi-line INIs: `/[\t \v\f])+/` **/
INI_EQUALS = '=', /**< Equals character (`=`) **/
INI_COLON = ':', /**< Colon character (`:`) **/
INI_DOT = '.', /**< Dot character (`.`) **/
INI_COMMA = ',' /**< Comma character (`,`) **/
};
/**
@brief Possible values of #IniFormat::semicolon_marker and
#IniFormat::hash_marker (i.e., meaning of `/\s+;/` and `/\s+#/` in
respect to a format)
**/
enum IniCommentMarker {
INI_DISABLED_OR_COMMENT = 0, /**< This marker opens a comment or a
disabled entry **/
INI_ONLY_COMMENT = 1, /**< This marker opens a comment **/
INI_IGNORE = 2, /**< This marker opens a comment that has
been marked for deletion and must not
be dispatched or counted **/
INI_IS_NOT_A_MARKER = 3 /**< This is not a marker at all, but a
normal character instead **/
};
/**
@brief Possible values of #IniFormat::section_paths
**/
enum IniSectionPaths {
INI_ABSOLUTE_AND_RELATIVE = 0, /**< Section paths starting with a dot
express nesting to the current parent,
to root otherwise **/
INI_ABSOLUTE_ONLY = 1, /**< Section paths starting with a dot will
be cleaned of their leading dot and
appended to root **/
INI_ONE_LEVEL_ONLY = 2, /**< Format supports sections, but the dot
does not express nesting and is not a
meta-character **/
INI_NO_SECTIONS = 3 /**< Format does *not* support sections --
`/\[[^\]]*\]/g`, if any, will be
treated as keys! **/
};
/**
@brief Possible values of #IniFormat::multiline_nodes
**/
enum IniMultiline {
INI_MULTILINE_EVERYWHERE = 0, /**< Comments, section paths and keys
-- disabled or not -- are allowed
to be multi-line **/
INI_BUT_COMMENTS = 1, /**< Only section paths and keys --
disabled or not -- are allowed to
be multi-line **/
INI_BUT_DISABLED_AND_COMMENTS = 2, /**< Only active section paths and
active keys are allowed to be
multi-line **/
INI_NO_MULTILINE = 3 /**< Multi-line escape sequences are
disabled **/
};
/**
@brief A model format for standard INI files
**/
static const IniFormat INI_DEFAULT_FORMAT = _LIBCONFINI_DEFAULT_FORMAT_;
/**
@brief A model format for Unix-like .conf files (where space characters
are delimiters between keys and values)
**/
/* All fields are set to `0` here. */
static const IniFormat INI_UNIXLIKE_FORMAT = _LIBCONFINI_UNIXLIKE_FORMAT_;
/**
@brief If set to `true`, key and section names in case-insensitive INI
formats will be dispatched lowercase, verbatim otherwise (default
value: `false`)
**/
extern bool INI_GLOBAL_LOWERCASE_MODE;
/**
@brief Value to be assigned to implicit keys (default value: `NULL`)
**/
extern char * INI_GLOBAL_IMPLICIT_VALUE;
/**
@brief Length of the value assigned to implicit keys (default value: `0`)
**/
extern size_t INI_GLOBAL_IMPLICIT_V_LEN;
/* CLEAN THE PRIVATE ENVIRONMENT */
#undef _LIBCONFINI_UNIXLIKE_FORMAT_
#undef _LIBCONFINI_DEFAULT_FORMAT_
#undef _LIBCONFINI_INIFORMAT_TYPE_
#undef __INIFORMAT_TABLE_CB_ZERO__
#undef __INIFORMAT_TABLE_CB_DEFAULT__
#undef __INIFORMAT_TABLE_CB_FIELDS__
/* END OF `_LIBCONFINI_HEADER_` */
#ifdef __cplusplus
}
#endif
#endif
/* EOF */