Replace ini with toml
This commit is contained in:
		
							parent
							
								
									97a19135ce
								
							
						
					
					
						commit
						5796f88e05
					
				
					 11 changed files with 242 additions and 5726 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										291
									
								
								src/config.c
									
										
									
									
									
								
							
							
						
						
									
										291
									
								
								src/config.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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)
 | 
			
		||||
    /* 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);
 | 
			
		||||
    }
 | 
			
		||||
    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)
 | 
			
		||||
    {
 | 
			
		||||
        if(CONFINI_IS_KEY("core", "include"))
 | 
			
		||||
        config_load_section_core(config, core);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    toml_table_t* logging = toml_table_in(config_toml, "logging");
 | 
			
		||||
    if(logging)
 | 
			
		||||
    {
 | 
			
		||||
            config_load_string(&config->include, disp->value);
 | 
			
		||||
        config_load_section_logging(config, logging);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    toml_table_t* ports = toml_table_in(config_toml, "ports");
 | 
			
		||||
    if(ports)
 | 
			
		||||
    {
 | 
			
		||||
        config_load_section_ports(config, ports);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    toml_free(config_toml);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
        if(CONFINI_IS_KEY("core", "database"))
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
config_load_directory(config_t *config, char *directory_name)
 | 
			
		||||
{
 | 
			
		||||
            config_load_string(&config->database, disp->value);
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        if(CONFINI_IS_KEY("core", "user"))
 | 
			
		||||
    struct dirent *pDirent;
 | 
			
		||||
    DIR *pDir;
 | 
			
		||||
 | 
			
		||||
    (void)config;
 | 
			
		||||
 | 
			
		||||
    pDir = opendir (directory_name);
 | 
			
		||||
    if(pDir == NULL)
 | 
			
		||||
    {
 | 
			
		||||
            config_load_string(&config->user, disp->value);
 | 
			
		||||
            return 0;
 | 
			
		||||
        LOGGER_CRIT("cannot open directory '%s': %s\n", directory_name, strerror(errno));
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
        if(CONFINI_IS_KEY("core", "group"))
 | 
			
		||||
 | 
			
		||||
    // Process each entry.
 | 
			
		||||
 | 
			
		||||
    while((pDirent = readdir(pDir)) != NULL)
 | 
			
		||||
    {
 | 
			
		||||
            config_load_string(&config->group, disp->value);
 | 
			
		||||
            return 0;
 | 
			
		||||
        LOGGER_DEBUG("including: %s\n", pDirent->d_name);
 | 
			
		||||
    }
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
    // Close directory and exit.
 | 
			
		||||
 | 
			
		||||
    closedir(pDir);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										28
									
								
								src/main.c
									
										
									
									
									
								
							
							
						
						
									
										28
									
								
								src/main.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
									
									
								
							
							
						
						
									
										5016
									
								
								vendor/confini.c
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										547
									
								
								vendor/confini.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										547
									
								
								vendor/confini.h
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -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é
 | 
			
		||||
    @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  */
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue