Replace confini with toml
This commit is contained in:
		
							parent
							
								
									25eab5d38e
								
							
						
					
					
						commit
						79b1f3b2cf
					
				
					 27 changed files with 3081 additions and 5926 deletions
				
			
		| 
						 | 
					@ -12,11 +12,17 @@ target_link_libraries(controller -luuid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
option(WIRING_PI_DEBUG "Use WiringPi Debugging Tool (OFF)" OFF)
 | 
					option(WIRING_PI_DEBUG "Use WiringPi Debugging Tool (OFF)" OFF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(CMAKE_C_FLAGS "$ENV{CFLAGS}")
 | 
					set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} $ENV{CFLAGS}")
 | 
				
			||||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -std=gnu99 -Wpedantic -Werror -Wall -Wextra -ffile-prefix-map=${CMAKE_SOURCE_DIR}/src/=")
 | 
					set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D'__FILENAME__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR}/src/)/,,$(abspath $<))\"'")
 | 
				
			||||||
 | 
					set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -std=gnu99 -Wpedantic -Werror -Wall -Wextra")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -fprofile-arcs -ftest-coverage")
 | 
					set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -fprofile-arcs -ftest-coverage")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					file(GLOB_RECURSE ALL_SOURCE_FILES src/*.c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(WIRING_PI_DEBUG)
 | 
					if(WIRING_PI_DEBUG)
 | 
				
			||||||
    message("Showing wiringPi calls as debug")
 | 
					    message("Showing wiringPi calls as debug")
 | 
				
			||||||
    add_definitions("-DWIRING_PI_DEBUG")
 | 
					    add_definitions("-DWIRING_PI_DEBUG")
 | 
				
			||||||
| 
						 | 
					@ -32,7 +38,6 @@ aux_source_directory(vendor VENDOR_SRC)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_dependencies(controller sql)
 | 
					add_dependencies(controller sql)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
configure_file("controller.ini" "controller.ini" COPYONLY)
 | 
					 | 
				
			||||||
configure_file("version.h.in" "version.h" @ONLY)
 | 
					configure_file("version.h.in" "version.h" @ONLY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,21 +52,43 @@ add_custom_target(sql
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_custom_target(run
 | 
					add_custom_target(run
 | 
				
			||||||
    COMMAND ./controller start
 | 
					    COMMAND ${CMAKE_BINARY_DIR}/controller
 | 
				
			||||||
    DEPENDS controller
 | 
					    DEPENDS controller
 | 
				
			||||||
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
 | 
					    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
 | 
				
			||||||
)
 | 
					 | 
				
			||||||
add_custom_target(debug
 | 
					 | 
				
			||||||
    COMMAND valgrind ./controller start
 | 
					 | 
				
			||||||
    DEPENDS controller
 | 
					 | 
				
			||||||
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
add_custom_target(debug-full
 | 
					 | 
				
			||||||
    COMMAND valgrind --leak-check=full --show-leak-kinds=all ./controller start
 | 
					 | 
				
			||||||
    DEPENDS controller
 | 
					 | 
				
			||||||
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_custom_target(docs
 | 
					add_custom_target(docs
 | 
				
			||||||
    COMMAND doxygen
 | 
					    COMMAND doxygen
 | 
				
			||||||
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
 | 
					    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IF(CMAKE_BUILD_TYPE MATCHES Debug)
 | 
				
			||||||
 | 
					    message(STATUS "loading debug targets")
 | 
				
			||||||
 | 
					    add_custom_target(debug
 | 
				
			||||||
 | 
					        COMMAND gdb ${CMAKE_BINARY_DIR}/controller
 | 
				
			||||||
 | 
					        DEPENDS controller
 | 
				
			||||||
 | 
					        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    add_custom_target(valgrind
 | 
				
			||||||
 | 
					        COMMAND valgrind -s ${CMAKE_BINARY_DIR}/controller
 | 
				
			||||||
 | 
					        DEPENDS controller
 | 
				
			||||||
 | 
					        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    add_custom_target(valgrind-leak
 | 
				
			||||||
 | 
					        COMMAND valgrind --leak-check=full --show-leak-kinds=all ${CMAKE_BINARY_DIR}/controller
 | 
				
			||||||
 | 
					        DEPENDS controller
 | 
				
			||||||
 | 
					        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    add_custom_target(
 | 
				
			||||||
 | 
					        clang-tidy
 | 
				
			||||||
 | 
					        COMMAND /usr/bin/clang-tidy
 | 
				
			||||||
 | 
					        ${ALL_SOURCE_FILES}
 | 
				
			||||||
 | 
					        --header-filter=${CMAKE_SOURCE_DIR}/include/*
 | 
				
			||||||
 | 
					        --
 | 
				
			||||||
 | 
					        -std=gnu99
 | 
				
			||||||
 | 
					        -I${CMAKE_SOURCE_DIR}/include
 | 
				
			||||||
 | 
					        -I${CMAKE_SOURCE_DIR}/vendor
 | 
				
			||||||
 | 
					        -I${CMAKE_BINARY_DIR}
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					ENDIF(CMAKE_BUILD_TYPE MATCHES Debug)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,69 +0,0 @@
 | 
				
			||||||
[controller]
 | 
					 | 
				
			||||||
name = new emgauwa device
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
: 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
 | 
					 | 
				
			||||||
mqtt-host = localhost
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
relay-count = 10
 | 
					 | 
				
			||||||
relays-init = 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
database = controller.sqlite
 | 
					 | 
				
			||||||
log-level = debug
 | 
					 | 
				
			||||||
log-file = stdout
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[relay-0]
 | 
					 | 
				
			||||||
driver = piface
 | 
					 | 
				
			||||||
pin = 0
 | 
					 | 
				
			||||||
inverted = 0
 | 
					 | 
				
			||||||
init = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[relay-1]
 | 
					 | 
				
			||||||
driver = piface
 | 
					 | 
				
			||||||
pin = 1
 | 
					 | 
				
			||||||
inverted = 0
 | 
					 | 
				
			||||||
init = 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[relay-2]
 | 
					 | 
				
			||||||
driver = gpio
 | 
					 | 
				
			||||||
pin = 5
 | 
					 | 
				
			||||||
inverted = 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[relay-3]
 | 
					 | 
				
			||||||
driver = gpio
 | 
					 | 
				
			||||||
pin = 4
 | 
					 | 
				
			||||||
inverted = 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[relay-4]
 | 
					 | 
				
			||||||
driver = gpio
 | 
					 | 
				
			||||||
pin = 3
 | 
					 | 
				
			||||||
inverted = 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[relay-5]
 | 
					 | 
				
			||||||
driver = gpio
 | 
					 | 
				
			||||||
pin = 2
 | 
					 | 
				
			||||||
inverted = 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[relay-6]
 | 
					 | 
				
			||||||
driver = gpio
 | 
					 | 
				
			||||||
pin = 1
 | 
					 | 
				
			||||||
inverted = 1
 | 
					 | 
				
			||||||
pulse-duration = 3
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[relay-7]
 | 
					 | 
				
			||||||
driver = gpio
 | 
					 | 
				
			||||||
pin = 0
 | 
					 | 
				
			||||||
inverted = 1
 | 
					 | 
				
			||||||
pulse-duration = 3
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[relay-8]
 | 
					 | 
				
			||||||
driver = gpio
 | 
					 | 
				
			||||||
pin = 16
 | 
					 | 
				
			||||||
inverted = 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[relay-9]
 | 
					 | 
				
			||||||
driver = gpio
 | 
					 | 
				
			||||||
pin = 15
 | 
					 | 
				
			||||||
inverted = 1
 | 
					 | 
				
			||||||
							
								
								
									
										66
									
								
								emgauwa-controller.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								emgauwa-controller.conf
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,66 @@
 | 
				
			||||||
 | 
					[controller]
 | 
				
			||||||
 | 
					database = "emgauwa-controller.sqlite"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mqtt-host = "127.0.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ports]
 | 
				
			||||||
 | 
					# 4422 for testing; 4421 for dev-env; 4420 for testing-env; 4419 for prod-env
 | 
				
			||||||
 | 
					discovery = 4421
 | 
				
			||||||
 | 
					# 1886 for testing; 1885 for dev-env; 1884 for testing-env; 1883 for prod-env
 | 
				
			||||||
 | 
					mqtt = 1885
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[logging]
 | 
				
			||||||
 | 
					level = "debug"
 | 
				
			||||||
 | 
					file = "stdout"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[relays]]
 | 
				
			||||||
 | 
					driver = "piface"
 | 
				
			||||||
 | 
					pin = 0
 | 
				
			||||||
 | 
					inverted = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[relays]]
 | 
				
			||||||
 | 
					driver = "piface"
 | 
				
			||||||
 | 
					pin = 1
 | 
				
			||||||
 | 
					inverted = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[relays]]
 | 
				
			||||||
 | 
					driver = "gpio"
 | 
				
			||||||
 | 
					pin = 5
 | 
				
			||||||
 | 
					inverted = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[relays]]
 | 
				
			||||||
 | 
					driver = "gpio"
 | 
				
			||||||
 | 
					pin = 4
 | 
				
			||||||
 | 
					inverted = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[relays]]
 | 
				
			||||||
 | 
					driver = "gpio"
 | 
				
			||||||
 | 
					pin = 3
 | 
				
			||||||
 | 
					inverted = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[relays]]
 | 
				
			||||||
 | 
					driver = "gpio"
 | 
				
			||||||
 | 
					pin = 2
 | 
				
			||||||
 | 
					inverted = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[relays]]
 | 
				
			||||||
 | 
					driver = "gpio"
 | 
				
			||||||
 | 
					pin = 1
 | 
				
			||||||
 | 
					inverted = 1
 | 
				
			||||||
 | 
					pulse-duration = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[relays]]
 | 
				
			||||||
 | 
					driver = "gpio"
 | 
				
			||||||
 | 
					pin = 0
 | 
				
			||||||
 | 
					inverted = 1
 | 
				
			||||||
 | 
					pulse-duration = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[relays]]
 | 
				
			||||||
 | 
					driver = "gpio"
 | 
				
			||||||
 | 
					pin = 16
 | 
				
			||||||
 | 
					inverted = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[relays]]
 | 
				
			||||||
 | 
					driver = "gpio"
 | 
				
			||||||
 | 
					pin = 15
 | 
				
			||||||
 | 
					inverted = 1
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								emgauwa-controller.sqlite
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								emgauwa-controller.sqlite
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										13
									
								
								include/cli.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								include/cli.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					#ifndef CONTROLLER_CLI_H
 | 
				
			||||||
 | 
					#define CONTROLLER_CLI_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct cli
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const char *config_file;
 | 
				
			||||||
 | 
					    int demo_mode;
 | 
				
			||||||
 | 
					} cli_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					cli_parse(int argc, const char **argv, cli_t *cli);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CONTROLLER_CLI_H */
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,8 @@
 | 
				
			||||||
#define CONTROLLER_CONFIG_H
 | 
					#define CONTROLLER_CONFIG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <confini.h>
 | 
					
 | 
				
			||||||
 | 
					#include <toml.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <constants.h>
 | 
					#include <constants.h>
 | 
				
			||||||
#include <enums.h>
 | 
					#include <enums.h>
 | 
				
			||||||
| 
						 | 
					@ -16,27 +17,50 @@ typedef struct
 | 
				
			||||||
    uint8_t pulse_duration;
 | 
					    uint8_t pulse_duration;
 | 
				
			||||||
} config_relay_t;
 | 
					} config_relay_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					 | 
				
			||||||
config_load(IniDispatch *disp, void *config_void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct
 | 
					typedef struct
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *file;
 | 
					    char *name;
 | 
				
			||||||
    char database[256];
 | 
					    char *database;
 | 
				
			||||||
    char user[256];
 | 
					    char *user;
 | 
				
			||||||
    char group[256];
 | 
					    char *group;
 | 
				
			||||||
    int log_level;
 | 
					    char *mqtt_host;
 | 
				
			||||||
    FILE *log_file;
 | 
					    char *include;
 | 
				
			||||||
    run_type_t run_type;
 | 
					 | 
				
			||||||
    char name[MAX_NAME_LENGTH + 1];
 | 
					 | 
				
			||||||
    uint16_t discovery_port;
 | 
					 | 
				
			||||||
    uint16_t mqtt_port;
 | 
					 | 
				
			||||||
    char mqtt_host[256];
 | 
					 | 
				
			||||||
    uint8_t relay_count;
 | 
					 | 
				
			||||||
    int relays_init;
 | 
					    int relays_init;
 | 
				
			||||||
 | 
					    uint8_t relay_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int level;
 | 
				
			||||||
 | 
					        FILE *file;
 | 
				
			||||||
 | 
					    } logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        uint16_t discovery;
 | 
				
			||||||
 | 
					        uint16_t mqtt;
 | 
				
			||||||
 | 
					    } ports;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    config_relay_t *relay_configs;
 | 
					    config_relay_t *relay_configs;
 | 
				
			||||||
} config_t;
 | 
					} config_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern config_t global_config;
 | 
					extern config_t *global_config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					config_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					config_free();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					config_load_string(char **holder, const char *value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					config_load(config_t *config, const char *cli_config_file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					config_load_file(config_t *config, const char *file_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					config_load_directory(config_t *config, const char *directory_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif //CONTROLLER_CONFIG_H
 | 
					#endif //CONTROLLER_CONFIG_H
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,13 +14,6 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define MAX_NAME_LENGTH 128
 | 
					#define MAX_NAME_LENGTH 128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * @brief Maximum number of dbs for the databases for the MDB_env
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Used when calling mdb_env_set_maxdbs() in database_setup()
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define MDB_MAXDBS 8
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @brief How many milli seconds to wait until poll timeout in main loop
 | 
					 * @brief How many milli seconds to wait until poll timeout in main loop
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -28,4 +21,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PIFACE_GPIO_BASE 200
 | 
					#define PIFACE_GPIO_BASE 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEFAULT_CONTROLLER_NAME "emgauwa-controller"
 | 
				
			||||||
 | 
					#define DEFAULT_CONFIG_PATH "emgauwa-controller.conf"
 | 
				
			||||||
 | 
					#define DEFAULT_GLOBAL_CONFIG_PATH "/etc/emgauwa/controller.conf"
 | 
				
			||||||
 | 
					#define DEFAULT_DATABASE_PATH "emgauwa-controller.sqlite"
 | 
				
			||||||
 | 
					#define DEFAULT_DISCOVERY_PORT 4421
 | 
				
			||||||
 | 
					#define DEFAULT_MQTT_PORT 1885
 | 
				
			||||||
 | 
					#define DEFAULT_MQTT_HOST "127.0.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* CONTROLLER_CONTANTS_H */
 | 
					#endif /* CONTROLLER_CONTANTS_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,10 +22,4 @@ typedef enum
 | 
				
			||||||
    RELAY_DRIVER_PIFACE,
 | 
					    RELAY_DRIVER_PIFACE,
 | 
				
			||||||
} relay_driver_t;
 | 
					} relay_driver_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    RUN_TYPE_START,
 | 
					 | 
				
			||||||
    RUN_TYPE_TEST,
 | 
					 | 
				
			||||||
} run_type_t;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* CONTROLLER_ENUMS_H */
 | 
					#endif /* CONTROLLER_ENUMS_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,9 +25,6 @@ helper_get_port(int sock);
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
helper_open_discovery_socket(uint16_t discovery_port);
 | 
					helper_open_discovery_socket(uint16_t discovery_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					 | 
				
			||||||
helper_parse_cli(int argc, const char **argv, config_t *config);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
helper_get_weekday(const struct tm *time_struct);
 | 
					helper_get_weekday(const struct tm *time_struct);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,30 +3,31 @@
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <argparse.h>
 | 
					#include <argparse.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cli.h>
 | 
				
			||||||
#include <config.h>
 | 
					#include <config.h>
 | 
				
			||||||
#include <logger.h>
 | 
					#include <logger.h>
 | 
				
			||||||
#include <helpers.h>
 | 
					#include <helpers.h>
 | 
				
			||||||
#include <version.h>
 | 
					#include <version.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *const usage[] = {
 | 
					static const char *const usage[] = {
 | 
				
			||||||
    "controller [options] [[--] args]",
 | 
					 | 
				
			||||||
    "controller [options]",
 | 
					    "controller [options]",
 | 
				
			||||||
    NULL,
 | 
					    NULL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PERM_READ  (1<<0)
 | 
					 | 
				
			||||||
#define PERM_WRITE (1<<1)
 | 
					 | 
				
			||||||
#define PERM_EXEC  (1<<2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
helper_parse_cli(int argc, const char **argv, config_t *config)
 | 
					cli_parse(int argc, const char **argv, cli_t *cli)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    cli->config_file = NULL;
 | 
				
			||||||
 | 
					    cli->demo_mode = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int version = 0;
 | 
					    int version = 0;
 | 
				
			||||||
    struct argparse_option options[] =
 | 
					    struct argparse_option options[] =
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        OPT_HELP(),
 | 
					        OPT_HELP(),
 | 
				
			||||||
        OPT_GROUP("Basic options"),
 | 
					        OPT_GROUP("Basic options"),
 | 
				
			||||||
        OPT_STRING('c', "config", &config->file, "path to config file", NULL, 0, OPT_NONEG),
 | 
					        OPT_STRING('c', "config", &cli->config_file, "path to config file", NULL, 0, OPT_NONEG),
 | 
				
			||||||
 | 
					        OPT_BOOLEAN('d', "demo", &cli->demo_mode, "demo mode", NULL, 0, OPT_NONEG),
 | 
				
			||||||
        OPT_BOOLEAN('v', "version", &version, "print version", NULL, 0, OPT_NONEG),
 | 
					        OPT_BOOLEAN('v', "version", &version, "print version", NULL, 0, OPT_NONEG),
 | 
				
			||||||
        OPT_END(),
 | 
					        OPT_END(),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
| 
						 | 
					@ -38,33 +39,11 @@ helper_parse_cli(int argc, const char **argv, config_t *config)
 | 
				
			||||||
            "\nA brief description of what the program does and how it works.",
 | 
					            "\nA brief description of what the program does and how it works.",
 | 
				
			||||||
            "\nAdditional description of the program after the description of the arguments."
 | 
					            "\nAdditional description of the program after the description of the arguments."
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    argc = argparse_parse(&argparse, argc, argv);
 | 
					    argparse_parse(&argparse, argc, argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(version)
 | 
					    if(version)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        printf("%s\n", EMGAUWA_CONTROLLER_VERSION);
 | 
					        printf("%s\n", EMGAUWA_CONTROLLER_VERSION);
 | 
				
			||||||
        exit(0);
 | 
					        exit(0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(argc == 1)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(strcmp(argv[0], "start") == 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            config->run_type = RUN_TYPE_START;
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(strcmp(argv[0], "test") == 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            config->run_type = RUN_TYPE_TEST;
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        LOGGER_CRIT("bad action '%s' given ('start', 'test')\n", argv[0]);
 | 
					 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LOGGER_CRIT("no action given ('start', 'test')\n");
 | 
					 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										473
									
								
								src/config.c
									
										
									
									
									
								
							
							
						
						
									
										473
									
								
								src/config.c
									
										
									
									
									
								
							| 
						 | 
					@ -1,141 +1,87 @@
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					#include <dirent.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <helpers.h>
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					#include <config.h>
 | 
				
			||||||
 | 
					#include <constants.h>
 | 
				
			||||||
#include <logger.h>
 | 
					#include <logger.h>
 | 
				
			||||||
#include <confini.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CONFINI_IS_KEY(SECTION, KEY) \
 | 
					config_t *global_config;
 | 
				
			||||||
    (ini_array_match(SECTION, disp->append_to, '.', disp->format) && \
 | 
					 | 
				
			||||||
     ini_string_match_ii(KEY, disp->data, disp->format))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
config_load_log_level(IniDispatch *disp, config_t *config)
 | 
					config_load_log_level(config_t *config, char *value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if(strcasecmp(disp->value, "debug") == 0)
 | 
					    if(strcmp(value, "debug") == 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        setlogmask(LOG_UPTO(LOG_DEBUG));
 | 
					        setlogmask(LOG_UPTO(LOG_DEBUG));
 | 
				
			||||||
        config->log_level = LOG_DEBUG;
 | 
					        config->logging.level = LOG_DEBUG;
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if(strcasecmp(disp->value, "info") == 0)
 | 
					    if(strcmp(value, "info") == 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        setlogmask(LOG_UPTO(LOG_INFO));
 | 
					        setlogmask(LOG_UPTO(LOG_INFO));
 | 
				
			||||||
        config->log_level = LOG_INFO;
 | 
					        config->logging.level = LOG_INFO;
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if(strcasecmp(disp->value, "notice") == 0)
 | 
					    if(strcmp(value, "notice") == 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        setlogmask(LOG_UPTO(LOG_NOTICE));
 | 
					        setlogmask(LOG_UPTO(LOG_NOTICE));
 | 
				
			||||||
        config->log_level = LOG_NOTICE;
 | 
					        config->logging.level = LOG_NOTICE;
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if(strcasecmp(disp->value, "warning") == 0)
 | 
					    if(strcmp(value, "warning") == 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        setlogmask(LOG_UPTO(LOG_WARNING));
 | 
					        setlogmask(LOG_UPTO(LOG_WARNING));
 | 
				
			||||||
        config->log_level = LOG_WARNING;
 | 
					        config->logging.level = LOG_WARNING;
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if(strcasecmp(disp->value, "err") == 0)
 | 
					    if(strcmp(value, "err") == 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        setlogmask(LOG_UPTO(LOG_ERR));
 | 
					        setlogmask(LOG_UPTO(LOG_ERR));
 | 
				
			||||||
        config->log_level = LOG_ERR;
 | 
					        config->logging.level = LOG_ERR;
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if(strcasecmp(disp->value, "crit") == 0)
 | 
					    if(strcmp(value, "crit") == 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        setlogmask(LOG_UPTO(LOG_CRIT));
 | 
					        setlogmask(LOG_UPTO(LOG_CRIT));
 | 
				
			||||||
        config->log_level = LOG_CRIT;
 | 
					        config->logging.level = LOG_CRIT;
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if(strcasecmp(disp->value, "emerg") == 0)
 | 
					    if(strcmp(value, "emerg") == 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        setlogmask(LOG_UPTO(LOG_EMERG));
 | 
					        setlogmask(LOG_UPTO(LOG_EMERG));
 | 
				
			||||||
        config->log_level = LOG_EMERG;
 | 
					        config->logging.level = LOG_EMERG;
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    LOGGER_WARNING("invalid log-level '%s'\n", disp->value);
 | 
					    LOGGER_WARNING("invalid log-level '%s'\n", value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
config_load_log_file(IniDispatch *disp, config_t *config)
 | 
					config_load_log_file(config_t *config, char *value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if(strcasecmp(disp->value, "stdout") == 0)
 | 
					    if(strcmp(value, "stdout") == 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        config->log_file = stdout;
 | 
					        config->logging.file = stdout;
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if(strcasecmp(disp->value, "stderr") == 0)
 | 
					    if(strcmp(value, "stderr") == 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        config->log_file = stderr;
 | 
					        config->logging.file = stderr;
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    config->log_file = fopen(disp->value, "a+");
 | 
					    config->logging.file = fopen(value, "a+");
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					static void
 | 
				
			||||||
config_load(IniDispatch *disp, void *config_void)
 | 
					config_init_relay_configs(config_t *config)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    config_t *config = (config_t*)config_void;
 | 
					 | 
				
			||||||
    char relay_section_name[10]; // "relay-255\0" is longest name 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(disp->type == INI_KEY)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(CONFINI_IS_KEY("controller", "name"))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            strncpy(config->name, disp->value, MAX_NAME_LENGTH);
 | 
					 | 
				
			||||||
            config->name[MAX_NAME_LENGTH] = '\0';
 | 
					 | 
				
			||||||
            return 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(CONFINI_IS_KEY("controller", "database"))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            strcpy(config->database, disp->value);
 | 
					 | 
				
			||||||
            return 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(CONFINI_IS_KEY("controller", "user"))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            strcpy(config->user, disp->value);
 | 
					 | 
				
			||||||
            return 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(CONFINI_IS_KEY("controller", "group"))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            strcpy(config->group, disp->value);
 | 
					 | 
				
			||||||
            return 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(CONFINI_IS_KEY("controller", "log-level"))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return config_load_log_level(disp, config);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(CONFINI_IS_KEY("controller", "log-file"))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return config_load_log_file(disp, config);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(CONFINI_IS_KEY("controller", "discovery-port"))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            config->discovery_port = atoi(disp->value);
 | 
					 | 
				
			||||||
            return 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(CONFINI_IS_KEY("controller", "mqtt-port"))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            config->mqtt_port = atoi(disp->value);
 | 
					 | 
				
			||||||
            return 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(CONFINI_IS_KEY("controller", "mqtt-host"))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            strcpy(config->mqtt_host, disp->value);
 | 
					 | 
				
			||||||
            return 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(CONFINI_IS_KEY("controller", "relays-init"))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            config->relays_init = atoi(disp->value);
 | 
					 | 
				
			||||||
            return 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(CONFINI_IS_KEY("controller", "relay-count"))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            config->relay_count = atoi(disp->value);
 | 
					 | 
				
			||||||
    config->relay_configs = malloc(sizeof(config_relay_t) * config->relay_count);
 | 
					    config->relay_configs = malloc(sizeof(config_relay_t) * config->relay_count);
 | 
				
			||||||
    for(uint8_t i = 0; i < config->relay_count; ++i)
 | 
					    for(uint8_t i = 0; i < config->relay_count; ++i)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					@ -145,47 +91,352 @@ config_load(IniDispatch *disp, void *config_void)
 | 
				
			||||||
        config->relay_configs[i].pin = 0;
 | 
					        config->relay_configs[i].pin = 0;
 | 
				
			||||||
        config->relay_configs[i].pulse_duration = 0;
 | 
					        config->relay_configs[i].pulse_duration = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
            return 0;
 | 
					}
 | 
				
			||||||
        }
 | 
					
 | 
				
			||||||
        for(uint8_t i = 0; i < config->relay_count; ++i)
 | 
					static void
 | 
				
			||||||
 | 
					config_load_section_controller(config_t *config, toml_table_t* controller)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    toml_datum_t config_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_entry = toml_string_in(controller, "name");
 | 
				
			||||||
 | 
					    if(config_entry.ok)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
            sprintf(relay_section_name, "relay-%u", i);
 | 
					        config_load_string(&config->name, config_entry.u.s);
 | 
				
			||||||
            if(CONFINI_IS_KEY(relay_section_name, "pin"))
 | 
					        free(config_entry.u.s);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_entry = toml_string_in(controller, "database");
 | 
				
			||||||
 | 
					    if(config_entry.ok)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
                config->relay_configs[i].pin = atoi(disp->value);
 | 
					        config_load_string(&config->database, config_entry.u.s);
 | 
				
			||||||
                return 0;
 | 
					        free(config_entry.u.s);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
            if(CONFINI_IS_KEY(relay_section_name, "inverted"))
 | 
					
 | 
				
			||||||
 | 
					    config_entry = toml_string_in(controller, "user");
 | 
				
			||||||
 | 
					    if(config_entry.ok)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
                config->relay_configs[i].inverted = atoi(disp->value);
 | 
					        config_load_string(&config->user, config_entry.u.s);
 | 
				
			||||||
                return 0;
 | 
					        free(config_entry.u.s);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
            if(CONFINI_IS_KEY(relay_section_name, "init"))
 | 
					
 | 
				
			||||||
 | 
					    config_entry = toml_string_in(controller, "group");
 | 
				
			||||||
 | 
					    if(config_entry.ok)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
                config->relay_configs[i].init = atoi(disp->value);
 | 
					        config_load_string(&config->group, config_entry.u.s);
 | 
				
			||||||
                return 0;
 | 
					        free(config_entry.u.s);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
            if(CONFINI_IS_KEY(relay_section_name, "pulse-duration"))
 | 
					
 | 
				
			||||||
 | 
					    config_entry = toml_string_in(controller, "mqtt-host");
 | 
				
			||||||
 | 
					    if(config_entry.ok)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
                config->relay_configs[i].pulse_duration = atoi(disp->value);
 | 
					        config_load_string(&config->mqtt_host, config_entry.u.s);
 | 
				
			||||||
                return 0;
 | 
					        free(config_entry.u.s);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
            if(CONFINI_IS_KEY(relay_section_name, "driver"))
 | 
					
 | 
				
			||||||
 | 
					    config_entry = toml_int_in(controller, "relays-init");
 | 
				
			||||||
 | 
					    if(config_entry.ok)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
                if(strcasecmp(disp->value, "gpio") == 0)
 | 
					        config->relays_init = config_entry.u.i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_entry = toml_string_in(controller, "include");
 | 
				
			||||||
 | 
					    if(config_entry.ok)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
                    config->relay_configs[i].driver = RELAY_DRIVER_GPIO;
 | 
					        config_load_string(&config->include, config_entry.u.s);
 | 
				
			||||||
                    return 0;
 | 
					        free(config_entry.u.s);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
                if(strcasecmp(disp->value, "piface") == 0)
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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->relay_configs[i].driver = RELAY_DRIVER_PIFACE;
 | 
					        config_load_log_level(config, config_entry.u.s);
 | 
				
			||||||
                    return 0;
 | 
					        free(config_entry.u.s);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
                LOGGER_WARNING("invalid driver '%s' in section '%s'\n", disp->value, relay_section_name);
 | 
					
 | 
				
			||||||
                return 0;
 | 
					    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, "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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					config_load_section_relay(config_t *config, toml_table_t* relay, int relay_num)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    toml_datum_t config_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_entry = toml_int_in(relay, "pin");
 | 
				
			||||||
 | 
					    if(config_entry.ok)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config->relay_configs[relay_num].pin = config_entry.u.i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_entry = toml_int_in(relay, "inverted");
 | 
				
			||||||
 | 
					    if(config_entry.ok)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config->relay_configs[relay_num].inverted = config_entry.u.i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_entry = toml_int_in(relay, "init");
 | 
				
			||||||
 | 
					    if(config_entry.ok)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config->relay_configs[relay_num].init = config_entry.u.i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_entry = toml_int_in(relay, "pulse-duration");
 | 
				
			||||||
 | 
					    if(config_entry.ok)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config->relay_configs[relay_num].pulse_duration = config_entry.u.i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_entry = toml_string_in(relay, "driver");
 | 
				
			||||||
 | 
					    if(config_entry.ok)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for(int i = 0; config_entry.u.s[i] != '\0'; ++i)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            config_entry.u.s[i] = tolower(config_entry.u.s[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(strcmp(config_entry.u.s, "gpio") == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            config->relay_configs[relay_num].driver = RELAY_DRIVER_GPIO;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if(strcmp(config_entry.u.s, "piface") == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            config->relay_configs[relay_num].driver = RELAY_DRIVER_PIFACE;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOGGER_WARNING("invalid driver '%s' in section for relay %d\n", config_entry.u.s, relay_num);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        free(config_entry.u.s);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					config_init()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    global_config = calloc(1, sizeof(config_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_load_string(&global_config->name, DEFAULT_CONTROLLER_NAME);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_load_string(&global_config->database, DEFAULT_DATABASE_PATH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_load_string(&global_config->mqtt_host, DEFAULT_MQTT_HOST);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    global_config->user = NULL;
 | 
				
			||||||
 | 
					    global_config->group = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    global_config->include = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    global_config->relays_init = 0;
 | 
				
			||||||
 | 
					    global_config->relay_count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_load_string(&global_config->mqtt_host, "127.0.0.1");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    global_config->ports.mqtt = DEFAULT_MQTT_PORT;
 | 
				
			||||||
 | 
					    global_config->ports.discovery = DEFAULT_DISCOVERY_PORT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    global_config->logging.level = LOG_DEBUG;
 | 
				
			||||||
 | 
					    global_config->logging.file = stdout;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					config_free()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    free(global_config->name);
 | 
				
			||||||
 | 
					    free(global_config->database);
 | 
				
			||||||
 | 
					    free(global_config->user);
 | 
				
			||||||
 | 
					    free(global_config->group);
 | 
				
			||||||
 | 
					    free(global_config->mqtt_host);
 | 
				
			||||||
 | 
					    free(global_config->include);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(global_config);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					config_load_string(char **holder, const char *value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(*holder)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        free(*holder);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    size_t value_len = strlen(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *new_holder = malloc(sizeof(char) * (value_len + 1));
 | 
				
			||||||
 | 
					    strcpy(new_holder, value);
 | 
				
			||||||
 | 
					    new_holder[value_len] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *holder = new_holder;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					config_try_file(const char *path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(access(path, F_OK) != 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 1; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(access(path, R_OK) != 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 1; 
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					config_load(config_t *config, const char *cli_config_file)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(cli_config_file)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(config_try_file(cli_config_file) == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            config_load_file(config, cli_config_file);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        LOGGER_CRIT("unable to open the passed config file '%s'\n", cli_config_file);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(config_try_file(DEFAULT_CONFIG_PATH) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config_load_file(config, DEFAULT_CONFIG_PATH);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(config_try_file(DEFAULT_GLOBAL_CONFIG_PATH) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config_load_file(config, DEFAULT_GLOBAL_CONFIG_PATH);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					config_load_file(config_t *config, const char *file_name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    FILE *fp;
 | 
				
			||||||
 | 
					    toml_table_t* config_toml;
 | 
				
			||||||
 | 
					    char errbuf[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Open the file and parse content */
 | 
				
			||||||
 | 
					    fp = fopen(file_name, "r");
 | 
				
			||||||
 | 
					    if(fp == NULL) {
 | 
				
			||||||
 | 
					        LOGGER_CRIT("unable to open config file '%s'\n", file_name);
 | 
				
			||||||
 | 
					        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", file_name, errbuf);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    toml_table_t* controller = toml_table_in(config_toml, "controller");
 | 
				
			||||||
 | 
					    if(controller)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config_load_section_controller(config, controller);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    toml_table_t* logging = toml_table_in(config_toml, "logging");
 | 
				
			||||||
 | 
					    if(logging)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        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_array_t* relays = toml_array_in(config_toml, "relays");
 | 
				
			||||||
 | 
					    if(relays)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config->relay_count = toml_array_nelem(relays);
 | 
				
			||||||
 | 
					        config_init_relay_configs(config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(int i = 0; i < config->relay_count; ++i)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            config_load_section_relay(config, toml_table_at(relays, i), i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    toml_free(config_toml);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LOGGER_DEBUG("Loaded config from %s\n", file_name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					config_load_directory(config_t *config, const char *directory_name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct dirent *directory_entry;
 | 
				
			||||||
 | 
					    DIR *directory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    (void)config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    directory = opendir(directory_name);
 | 
				
			||||||
 | 
					    if(directory == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LOGGER_CRIT("cannot open directory '%s': %s\n", directory_name, strerror(errno));
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while((directory_entry = readdir(directory)) != NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        struct stat sb;
 | 
				
			||||||
 | 
					        const char *entry_name = directory_entry->d_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        size_t copied = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add 2 for '/' and '\0'.
 | 
				
			||||||
 | 
					        size_t path_len = strlen(directory_name) + strlen(entry_name) + 1;
 | 
				
			||||||
 | 
					        char *path = malloc(sizeof(char) * (path_len + 1));
 | 
				
			||||||
 | 
					        path[0] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        strncat(path + copied, directory_name, path_len - copied);
 | 
				
			||||||
 | 
					        copied = strlen(path);
 | 
				
			||||||
 | 
					        if(path[copied - 1] != '/')
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            strncat(path + copied, "/", path_len - copied);
 | 
				
			||||||
 | 
					            copied = strlen(path);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        strncat(path + copied, entry_name, path_len - copied);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(stat(path, &sb))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            LOGGER_WARNING("failed to get info for '%s': %s\n", path, strerror(errno));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(S_ISREG(sb.st_mode))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            config_load_file(config, path);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        free(path);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    closedir(directory);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ struct mg_connection*
 | 
				
			||||||
connection_discovery_bind(struct mg_mgr *mgr)
 | 
					connection_discovery_bind(struct mg_mgr *mgr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char address[32];
 | 
					    char address[32];
 | 
				
			||||||
    sprintf(address, "udp://0.0.0.0:%u", global_config.discovery_port);
 | 
					    sprintf(address, "udp://0.0.0.0:%u", global_config->ports.discovery);
 | 
				
			||||||
    struct mg_connection *c = mg_bind(mgr, address, handler_discovery);
 | 
					    struct mg_connection *c = mg_bind(mgr, address, handler_discovery);
 | 
				
			||||||
    return c;
 | 
					    return c;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ struct mg_connection*
 | 
				
			||||||
connection_mqtt_connect(struct mg_mgr *mgr)
 | 
					connection_mqtt_connect(struct mg_mgr *mgr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char address[512];
 | 
					    char address[512];
 | 
				
			||||||
    sprintf(address, "tcp://%s:%u", global_config.mqtt_host, global_config.mqtt_port);
 | 
					    sprintf(address, "tcp://%s:%u", global_config->mqtt_host, global_config->ports.mqtt);
 | 
				
			||||||
    struct mg_connection *c = mg_connect(mgr, address, handler_mqtt);
 | 
					    struct mg_connection *c = mg_connect(mgr, address, handler_mqtt);
 | 
				
			||||||
    return c;
 | 
					    return c;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@ static int in_transaction;
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
database_init()
 | 
					database_init()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int rc = sqlite3_open(global_config.database, &global_database);
 | 
					    int rc = sqlite3_open(global_config->database, &global_database);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(rc)
 | 
					    if(rc)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,9 +53,9 @@ handler_command_relay_pulse(mpack_node_t map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint8_t relay_num = mpack_node_u8(mpack_node_map_uint(map, COMMAND_MAPPING_RELAY_NUM));
 | 
					    uint8_t relay_num = mpack_node_u8(mpack_node_map_uint(map, COMMAND_MAPPING_RELAY_NUM));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(relay_num > global_config.relay_count)
 | 
					    if(relay_num > global_config->relay_count)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        LOGGER_WARNING("relay %d is not available (relay count: %d\n", relay_num, global_config.relay_count);
 | 
					        LOGGER_WARNING("relay %d is not available (relay count: %d\n", relay_num, global_config->relay_count);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,7 +65,7 @@ handler_command_relay_pulse(mpack_node_t map)
 | 
				
			||||||
    int duration = mpack_node_u8(mpack_node_map_uint(map, COMMAND_MAPPING_PULSE_DURATION));
 | 
					    int duration = mpack_node_u8(mpack_node_map_uint(map, COMMAND_MAPPING_PULSE_DURATION));
 | 
				
			||||||
    if(duration == 0)
 | 
					    if(duration == 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        duration = global_config.relay_configs[relay_num].pulse_duration;
 | 
					        duration = global_config->relay_configs[relay_num].pulse_duration;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    target_relay->pulse_timer = duration;
 | 
					    target_relay->pulse_timer = duration;
 | 
				
			||||||
    LOGGER_DEBUG("pulsing relay %d for %ds\n", relay_num, duration);
 | 
					    LOGGER_DEBUG("pulsing relay %d for %ds\n", relay_num, duration);
 | 
				
			||||||
| 
						 | 
					@ -87,9 +87,9 @@ handler_command_relay_name_set(mpack_node_t map)
 | 
				
			||||||
    uint8_t relay_num = mpack_node_u8(mpack_node_map_uint(map, COMMAND_MAPPING_RELAY_NUM));
 | 
					    uint8_t relay_num = mpack_node_u8(mpack_node_map_uint(map, COMMAND_MAPPING_RELAY_NUM));
 | 
				
			||||||
    const char *relay_name = mpack_node_str(mpack_node_map_uint(map, COMMAND_MAPPING_NAME));
 | 
					    const char *relay_name = mpack_node_str(mpack_node_map_uint(map, COMMAND_MAPPING_NAME));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(relay_num > global_config.relay_count)
 | 
					    if(relay_num > global_config->relay_count)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        LOGGER_WARNING("relay %d is not available (relay count: %d\n", relay_num, global_config.relay_count);
 | 
					        LOGGER_WARNING("relay %d is not available (relay count: %d\n", relay_num, global_config->relay_count);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    relay_set_name(global_controller->relays[relay_num], relay_name);
 | 
					    relay_set_name(global_controller->relays[relay_num], relay_name);
 | 
				
			||||||
| 
						 | 
					@ -120,7 +120,7 @@ handler_command_schedule_update(mpack_node_t map)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int *relay_ids = junction_relay_schedule_get_relay_ids_with_schedule(new_schedule->id);
 | 
					    int *relay_ids = junction_relay_schedule_get_relay_ids_with_schedule(new_schedule->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for(int i = 0; i < global_config.relay_count; ++i)
 | 
					    for(int i = 0; i < global_config->relay_count; ++i)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        for(int j = 0; relay_ids[j] != 0; ++j)
 | 
					        for(int j = 0; relay_ids[j] != 0; ++j)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
| 
						 | 
					@ -140,9 +140,9 @@ handler_command_relay_schedules_set(mpack_node_t map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint8_t relay_num = mpack_node_u8(mpack_node_map_uint(map, COMMAND_MAPPING_RELAY_NUM));
 | 
					    uint8_t relay_num = mpack_node_u8(mpack_node_map_uint(map, COMMAND_MAPPING_RELAY_NUM));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(relay_num > global_config.relay_count)
 | 
					    if(relay_num > global_config->relay_count)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        LOGGER_WARNING("relay %d is not available (relay count: %d\n", relay_num, global_config.relay_count);
 | 
					        LOGGER_WARNING("relay %d is not available (relay count: %d\n", relay_num, global_config->relay_count);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@ handler_discovery(struct mg_connection *c, int ev, void *ev_data)
 | 
				
			||||||
        mpack_write_uint(&writer, DISCOVERY_MAPPING_COMMAND_PORT);
 | 
					        mpack_write_uint(&writer, DISCOVERY_MAPPING_COMMAND_PORT);
 | 
				
			||||||
        mpack_write_u16(&writer, global_controller->command_port);
 | 
					        mpack_write_u16(&writer, global_controller->command_port);
 | 
				
			||||||
        mpack_write_uint(&writer, DISCOVERY_MAPPING_RELAY_COUNT);
 | 
					        mpack_write_uint(&writer, DISCOVERY_MAPPING_RELAY_COUNT);
 | 
				
			||||||
        mpack_write_u8(&writer, global_config.relay_count);
 | 
					        mpack_write_u8(&writer, global_config->relay_count);
 | 
				
			||||||
        mpack_write_uint(&writer, DISCOVERY_MAPPING_NAME);
 | 
					        mpack_write_uint(&writer, DISCOVERY_MAPPING_NAME);
 | 
				
			||||||
        mpack_write_cstr(&writer, global_controller->name);
 | 
					        mpack_write_cstr(&writer, global_controller->name);
 | 
				
			||||||
        mpack_finish_map(&writer);
 | 
					        mpack_finish_map(&writer);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,13 +28,13 @@ handler_loop(struct mg_connection *c_mqtt)
 | 
				
			||||||
    localtime_r(×tamp, &time_last);
 | 
					    localtime_r(×tamp, &time_last);
 | 
				
			||||||
    timestamp = time(NULL);
 | 
					    timestamp = time(NULL);
 | 
				
			||||||
    localtime_r(×tamp, &time_now);
 | 
					    localtime_r(×tamp, &time_now);
 | 
				
			||||||
    for(uint_fast8_t i = 0; i < global_config.relay_count; ++i)
 | 
					    for(uint_fast8_t i = 0; i < global_config->relay_count; ++i)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        relay_t *relay = global_controller->relays[i];
 | 
					        relay_t *relay = global_controller->relays[i];
 | 
				
			||||||
        int is_on = 0;
 | 
					        int is_on = 0;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        int is_on_schedule = relay_is_on_schedule(relay, &time_now);
 | 
					        int is_on_schedule = relay_is_on_schedule(relay, &time_now);
 | 
				
			||||||
        int pulse_relay = global_config.relay_configs[i].pulse_duration;
 | 
					        int pulse_relay = global_config->relay_configs[i].pulse_duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(is_on_schedule)
 | 
					        if(is_on_schedule)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
| 
						 | 
					@ -73,17 +73,17 @@ handler_loop(struct mg_connection *c_mqtt)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        relay->is_on = is_on;
 | 
					        relay->is_on = is_on;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(global_config.relay_configs[i].inverted)
 | 
					        if(global_config->relay_configs[i].inverted)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            is_on = !is_on;
 | 
					            is_on = !is_on;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        switch(global_config.relay_configs[i].driver)
 | 
					        switch(global_config->relay_configs[i].driver)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            case RELAY_DRIVER_GPIO:
 | 
					            case RELAY_DRIVER_GPIO:
 | 
				
			||||||
                driver_gpio_set(global_config.relay_configs[i].pin, is_on);
 | 
					                driver_gpio_set(global_config->relay_configs[i].pin, is_on);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case RELAY_DRIVER_PIFACE:
 | 
					            case RELAY_DRIVER_PIFACE:
 | 
				
			||||||
                driver_piface_set(global_config.relay_configs[i].pin, is_on);
 | 
					                driver_piface_set(global_config->relay_configs[i].pin, is_on);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            default:
 | 
					            default:
 | 
				
			||||||
                LOGGER_WARNING("relay %d is not using a driver\n", i);
 | 
					                LOGGER_WARNING("relay %d is not using a driver\n", i);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,8 +59,8 @@ get_gid_for_group(char *group)
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
helper_drop_privileges()
 | 
					helper_drop_privileges()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uid_t uid = get_uid_for_user(global_config.user);
 | 
					    uid_t uid = get_uid_for_user(global_config->user);
 | 
				
			||||||
    gid_t gid = get_gid_for_group(global_config.group);
 | 
					    gid_t gid = get_gid_for_group(global_config->group);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    LOGGER_DEBUG("drop privileges to %lu:%lu\n", uid, gid);
 | 
					    LOGGER_DEBUG("drop privileges to %lu:%lu\n", uid, gid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										29
									
								
								src/logger.c
									
										
									
									
									
								
							
							
						
						
									
										29
									
								
								src/logger.c
									
										
									
									
									
								
							| 
						 | 
					@ -17,10 +17,11 @@ const char *COLOR_EMERG = COLOR_MAGENTA;
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
logger_log(int level, const char *filename, int line, const char *func, const char *msg, ...)
 | 
					logger_log(int level, const char *filename, int line, const char *func, const char *msg, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if(global_config.log_level < level)
 | 
					    if(global_config->logging.level < level)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    va_list args;
 | 
				
			||||||
    const char *level_str;
 | 
					    const char *level_str;
 | 
				
			||||||
    const char *color;
 | 
					    const char *color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,24 +63,28 @@ logger_log(int level, const char *filename, int line, const char *func, const ch
 | 
				
			||||||
    time_t rawtime;
 | 
					    time_t rawtime;
 | 
				
			||||||
    time(&rawtime);
 | 
					    time(&rawtime);
 | 
				
			||||||
    strftime(timestamp_str, 32, "%Y-%m-%d %H:%M:%S", localtime(&rawtime));
 | 
					    strftime(timestamp_str, 32, "%Y-%m-%d %H:%M:%S", localtime(&rawtime));
 | 
				
			||||||
 | 
					    size_t timestamp_len = strlen(timestamp_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char *buffer = malloc(sizeof(char) * (128 + strlen(msg)));
 | 
					    char *buffer = malloc(sizeof(char) * (128 + strlen(msg) + timestamp_len));
 | 
				
			||||||
    sprintf(buffer, "%s[%5s] %s:%d:%s " COLOR_NONE "%s", color, level_str, filename, line, func, msg);
 | 
					    sprintf(buffer, "%s %s[%5s] %s:%d:%s " COLOR_NONE "%s", timestamp_str, color, level_str, filename, line, func, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //fprintf(stream, "%s %s:%d:%s " COLOR_NONE, timestamp_str, filename, line, func);
 | 
					    // start arg va_list and find log_len
 | 
				
			||||||
 | 
					 | 
				
			||||||
    va_list args;
 | 
					 | 
				
			||||||
    va_start(args, msg);
 | 
					    va_start(args, msg);
 | 
				
			||||||
    vsyslog(level, buffer, args);
 | 
					    size_t log_len = vsnprintf(NULL, 0, buffer, args); // NOLINT(clang-analyzer-valist.Uninitialized): clang-tidy bug
 | 
				
			||||||
    va_end(args);
 | 
					    va_end(args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char *buffer_timed = malloc(sizeof(char) * (strlen(timestamp_str) + strlen(buffer) + 2));
 | 
					    char *log_line = malloc(sizeof(char) * (log_len + 1));
 | 
				
			||||||
    sprintf(buffer_timed, "%s %s", timestamp_str, buffer);
 | 
					
 | 
				
			||||||
 | 
					    // start arg va_list again and write log_line
 | 
				
			||||||
    va_start(args, msg);
 | 
					    va_start(args, msg);
 | 
				
			||||||
    vfprintf(global_config.log_file, buffer_timed, args);
 | 
					    vsprintf(log_line, buffer, args); // NOLINT(clang-analyzer-valist.Uninitialized): clang-tidy bug
 | 
				
			||||||
    fflush(global_config.log_file);
 | 
					 | 
				
			||||||
    va_end(args);
 | 
					    va_end(args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    syslog(level, "%s", log_line + timestamp_len + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fprintf(global_config->logging.file, "%s", log_line);
 | 
				
			||||||
 | 
					    fflush(global_config->logging.file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    free(buffer);
 | 
					    free(buffer);
 | 
				
			||||||
    free(buffer_timed);
 | 
					    free(log_line);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										61
									
								
								src/main.c
									
										
									
									
									
								
							
							
						
						
									
										61
									
								
								src/main.c
									
										
									
									
									
								
							| 
						 | 
					@ -6,6 +6,7 @@
 | 
				
			||||||
#include <signal.h>
 | 
					#include <signal.h>
 | 
				
			||||||
#include <syslog.h>
 | 
					#include <syslog.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cli.h>
 | 
				
			||||||
#include <logger.h>
 | 
					#include <logger.h>
 | 
				
			||||||
#include <mongoose.h>
 | 
					#include <mongoose.h>
 | 
				
			||||||
#include <models/controller.h>
 | 
					#include <models/controller.h>
 | 
				
			||||||
| 
						 | 
					@ -21,9 +22,6 @@
 | 
				
			||||||
#include <wiringPi.h>
 | 
					#include <wiringPi.h>
 | 
				
			||||||
#include <piFace.h>
 | 
					#include <piFace.h>
 | 
				
			||||||
#include <wiring_debug.h>
 | 
					#include <wiring_debug.h>
 | 
				
			||||||
#include <confini.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
config_t global_config;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct mg_mgr mgr;
 | 
					static struct mg_mgr mgr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,7 +41,7 @@ terminate(int signum)
 | 
				
			||||||
    controller_free(global_controller);
 | 
					    controller_free(global_controller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    LOGGER_DEBUG("freeing relay configs config\n");
 | 
					    LOGGER_DEBUG("freeing relay configs config\n");
 | 
				
			||||||
    free(global_config.relay_configs);
 | 
					    free(global_config->relay_configs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    exit(signum);
 | 
					    exit(signum);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -66,45 +64,28 @@ main(int argc, const char** argv)
 | 
				
			||||||
    signal(SIGABRT, terminate);
 | 
					    signal(SIGABRT, terminate);
 | 
				
			||||||
    signal(SIGTERM, terminate);
 | 
					    signal(SIGTERM, terminate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    openlog("emgauwa-controller", 0, LOG_USER);
 | 
				
			||||||
    setlogmask(LOG_UPTO(LOG_INFO));
 | 
					    setlogmask(LOG_UPTO(LOG_INFO));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /******************** LOAD CONFIG ********************/
 | 
					    /******************** LOAD CONFIG ********************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    global_config.file = "controller.ini";
 | 
					    config_init();
 | 
				
			||||||
    global_config.discovery_port = 4421;
 | 
					 | 
				
			||||||
    global_config.mqtt_port = 1885;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    global_config.relay_count = 0;
 | 
					    cli_t cli;
 | 
				
			||||||
    global_config.relays_init = -1;
 | 
					    cli_parse(argc, argv, &cli);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    global_config.log_level = LOG_INFO;
 | 
					    config_load(global_config, cli.config_file);
 | 
				
			||||||
    global_config.log_file = stdout;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    strcpy(global_config.user, "");
 | 
					    if(global_config->logging.file == NULL)
 | 
				
			||||||
    strcpy(global_config.group, "");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    helper_parse_cli(argc, argv, &global_config);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    FILE * const ini_file = fopen(global_config.file, "rb");
 | 
					 | 
				
			||||||
    if(ini_file == NULL)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        LOGGER_CRIT("config file '%s' was not found\n", global_config.file);
 | 
					        global_config->logging.file = stdout;
 | 
				
			||||||
        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);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fclose(ini_file);
 | 
					    if(global_config->include)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(global_config.log_file == NULL)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        global_config.log_file = stdout;
 | 
					        config_load_directory(global_config, global_config->include);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    openlog("emgauwa-controller", 0, LOG_USER);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(sizeof(time_t) < 8)
 | 
					    if(sizeof(time_t) < 8)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					@ -146,38 +127,38 @@ main(int argc, const char** argv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int piface_setup = 0;
 | 
					    int piface_setup = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for(uint_fast8_t i = 0; i < global_config.relay_count; ++i)
 | 
					    for(uint_fast8_t i = 0; i < global_config->relay_count; ++i)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int relay_default = global_config.relay_configs[i].init;
 | 
					        int relay_default = global_config->relay_configs[i].init;
 | 
				
			||||||
        if(relay_default == -1)
 | 
					        if(relay_default == -1)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            relay_default = global_config.relays_init;
 | 
					            relay_default = global_config->relays_init;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if(relay_default == -1)
 | 
					        if(relay_default == -1)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            relay_default = global_config.relay_configs[i].inverted;
 | 
					            relay_default = global_config->relay_configs[i].inverted;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(global_config.relay_configs[i].driver == RELAY_DRIVER_GPIO)
 | 
					        if(global_config->relay_configs[i].driver == RELAY_DRIVER_GPIO)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            pinMode(global_config.relay_configs[i].pin, OUTPUT);
 | 
					            pinMode(global_config->relay_configs[i].pin, OUTPUT);
 | 
				
			||||||
            driver_gpio_set(global_config.relay_configs[i].pin, relay_default);
 | 
					            driver_gpio_set(global_config->relay_configs[i].pin, relay_default);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if(global_config.relay_configs[i].driver == RELAY_DRIVER_PIFACE)
 | 
					        if(global_config->relay_configs[i].driver == RELAY_DRIVER_PIFACE)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if(!piface_setup)
 | 
					            if(!piface_setup)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                piFaceSetup(PIFACE_GPIO_BASE);
 | 
					                piFaceSetup(PIFACE_GPIO_BASE);
 | 
				
			||||||
                piface_setup = 1;
 | 
					                piface_setup = 1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            driver_piface_set(global_config.relay_configs[i].pin, relay_default);
 | 
					            driver_piface_set(global_config->relay_configs[i].pin, relay_default);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /******************** CHECK FOR TESTING RUN ********************/
 | 
					    /******************** CHECK FOR TESTING RUN ********************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(global_config.run_type == RUN_TYPE_TEST)
 | 
					    if(cli.demo_mode)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        runner_test(global_controller);
 | 
					        runner_test(global_controller);
 | 
				
			||||||
        terminate(0);
 | 
					        terminate(0);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,9 +56,9 @@ controller_db_select_mapper(sqlite3_stmt *stmt)
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    new_controller->relays = malloc(sizeof(relay_t) * global_config.relay_count);
 | 
					    new_controller->relays = malloc(sizeof(relay_t) * global_config->relay_count);
 | 
				
			||||||
    uint8_t i;
 | 
					    uint8_t i;
 | 
				
			||||||
    for(i = 0; i < global_config.relay_count; ++i)
 | 
					    for(i = 0; i < global_config->relay_count; ++i)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        new_controller->relays[i] = relay_load(i);
 | 
					        new_controller->relays[i] = relay_load(i);
 | 
				
			||||||
        if(!new_controller->relays[i])
 | 
					        if(!new_controller->relays[i])
 | 
				
			||||||
| 
						 | 
					@ -198,14 +198,14 @@ controller_create(void)
 | 
				
			||||||
    new_controller->id = 0;
 | 
					    new_controller->id = 0;
 | 
				
			||||||
    uuid_generate(new_controller->uid);
 | 
					    uuid_generate(new_controller->uid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    strncpy(new_controller->name, global_config.name, MAX_NAME_LENGTH);
 | 
					    strncpy(new_controller->name, global_config->name, MAX_NAME_LENGTH);
 | 
				
			||||||
    new_controller->name[MAX_NAME_LENGTH] = '\0';
 | 
					    new_controller->name[MAX_NAME_LENGTH] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    new_controller->command_port = 0;
 | 
					    new_controller->command_port = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    new_controller->relays = malloc(sizeof(relay_t) * global_config.relay_count);
 | 
					    new_controller->relays = malloc(sizeof(relay_t) * global_config->relay_count);
 | 
				
			||||||
    uint8_t i;
 | 
					    uint8_t i;
 | 
				
			||||||
    for(i = 0; i < global_config.relay_count; ++i)
 | 
					    for(i = 0; i < global_config->relay_count; ++i)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        new_controller->relays[i] = relay_load(i);
 | 
					        new_controller->relays[i] = relay_load(i);
 | 
				
			||||||
        if(!new_controller->relays[i])
 | 
					        if(!new_controller->relays[i])
 | 
				
			||||||
| 
						 | 
					@ -228,7 +228,7 @@ controller_set_name(controller_t *controller, const char *name)
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
controller_free(controller_t *controller)
 | 
					controller_free(controller_t *controller)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    for(int i = 0; i < global_config.relay_count; ++i)
 | 
					    for(int i = 0; i < global_config->relay_count; ++i)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        relay_free(controller->relays[i]);
 | 
					        relay_free(controller->relays[i]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -249,7 +249,7 @@ controller_debug(controller_t *controller)
 | 
				
			||||||
    LOGGER_DEBUG("(1/3) %s @ %p\n", uuid_str, (void*)controller);
 | 
					    LOGGER_DEBUG("(1/3) %s @ %p\n", uuid_str, (void*)controller);
 | 
				
			||||||
    LOGGER_DEBUG("(2/3) name: %s\n", controller->name);
 | 
					    LOGGER_DEBUG("(2/3) name: %s\n", controller->name);
 | 
				
			||||||
    LOGGER_DEBUG("(3/3) relays @ %p:\n", (void*)controller->relays);
 | 
					    LOGGER_DEBUG("(3/3) relays @ %p:\n", (void*)controller->relays);
 | 
				
			||||||
    for(int i = 0; i < global_config.relay_count; ++i)
 | 
					    for(int i = 0; i < global_config->relay_count; ++i)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        relay_debug(controller->relays[i]);
 | 
					        relay_debug(controller->relays[i]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,12 +24,12 @@ junction_relay_schedule_insert(uint8_t weekday, int relay_id, int schedule_id)
 | 
				
			||||||
    if (rc != SQLITE_DONE)
 | 
					    if (rc != SQLITE_DONE)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        LOGGER_ERR("error inserting data: %s\n", sqlite3_errmsg(global_database));
 | 
					        LOGGER_ERR("error inserting data: %s\n", sqlite3_errmsg(global_database));
 | 
				
			||||||
        return false;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return true;
 | 
					    return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
| 
						 | 
					@ -67,12 +67,12 @@ junction_relay_schedule_insert_weekdays(int relay_id, int *schedule_ids)
 | 
				
			||||||
    if (rc != SQLITE_DONE)
 | 
					    if (rc != SQLITE_DONE)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        LOGGER_ERR("error inserting data: %s", sqlite3_errmsg(global_database));
 | 
					        LOGGER_ERR("error inserting data: %s", sqlite3_errmsg(global_database));
 | 
				
			||||||
        return false;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sqlite3_finalize(stmt);
 | 
					    sqlite3_finalize(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return true;
 | 
					    return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,7 +73,7 @@ relay_db_select(sqlite3_stmt *stmt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int row = 0;
 | 
					    int row = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while(true)
 | 
					    for(;;)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int s;
 | 
					        int s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,22 +9,22 @@ void
 | 
				
			||||||
runner_test()
 | 
					runner_test()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // from x down to 0 to turn all relays off in the end
 | 
					    // from x down to 0 to turn all relays off in the end
 | 
				
			||||||
    for(uint_fast8_t i = 0; i < global_config.relay_count; ++i)
 | 
					    for(uint_fast8_t i = 0; i < global_config->relay_count; ++i)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        for(int test_run = 2; test_run >= 0; --test_run)
 | 
					        for(int test_run = 2; test_run >= 0; --test_run)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            int is_active = test_run % 2;
 | 
					            int is_active = test_run % 2;
 | 
				
			||||||
            if(global_config.relay_configs[i].inverted)
 | 
					            if(global_config->relay_configs[i].inverted)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                is_active = !is_active;
 | 
					                is_active = !is_active;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            switch(global_config.relay_configs[i].driver)
 | 
					            switch(global_config->relay_configs[i].driver)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                case RELAY_DRIVER_GPIO:
 | 
					                case RELAY_DRIVER_GPIO:
 | 
				
			||||||
                    driver_gpio_set(global_config.relay_configs[i].pin, is_active);
 | 
					                    driver_gpio_set(global_config->relay_configs[i].pin, is_active);
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                case RELAY_DRIVER_PIFACE:
 | 
					                case RELAY_DRIVER_PIFACE:
 | 
				
			||||||
                    driver_piface_set(global_config.relay_configs[i].pin, is_active);
 | 
					                    driver_piface_set(global_config->relay_configs[i].pin, is_active);
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                default:
 | 
					                default:
 | 
				
			||||||
                    LOGGER_WARNING("relay %d is not using a driver\n", i);
 | 
					                    LOGGER_WARNING("relay %d is not using a driver\n", i);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										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  */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										2274
									
								
								vendor/toml.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2274
									
								
								vendor/toml.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										175
									
								
								vendor/toml.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								vendor/toml.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,175 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  MIT License
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  Copyright (c) 2017 - 2019 CK Tan
 | 
				
			||||||
 | 
					  https://github.com/cktan/tomlc99
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					  of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					  in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					  copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					  furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					  copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					  SOFTWARE.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					#ifndef TOML_H
 | 
				
			||||||
 | 
					#define TOML_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					#define TOML_EXTERN extern "C"
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define TOML_EXTERN extern
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct toml_timestamp_t toml_timestamp_t;
 | 
				
			||||||
 | 
					typedef struct toml_table_t toml_table_t;
 | 
				
			||||||
 | 
					typedef struct toml_array_t toml_array_t;
 | 
				
			||||||
 | 
					typedef struct toml_datum_t toml_datum_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Parse a file. Return a table on success, or 0 otherwise. 
 | 
				
			||||||
 | 
					 * Caller must toml_free(the-return-value) after use.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp, 
 | 
				
			||||||
 | 
															  char* errbuf,
 | 
				
			||||||
 | 
															  int errbufsz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Parse a string containing the full config. 
 | 
				
			||||||
 | 
					 * Return a table on success, or 0 otherwise.
 | 
				
			||||||
 | 
					 * Caller must toml_free(the-return-value) after use.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TOML_EXTERN toml_table_t* toml_parse(char* conf, /* NUL terminated, please. */
 | 
				
			||||||
 | 
														 char* errbuf,
 | 
				
			||||||
 | 
														 int errbufsz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Free the table returned by toml_parse() or toml_parse_file(). Once 
 | 
				
			||||||
 | 
					 * this function is called, any handles accessed through this tab 
 | 
				
			||||||
 | 
					 * directly or indirectly are no longer valid.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TOML_EXTERN void toml_free(toml_table_t* tab);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Timestamp types. The year, month, day, hour, minute, second, z 
 | 
				
			||||||
 | 
					 * fields may be NULL if they are not relevant. e.g. In a DATE
 | 
				
			||||||
 | 
					 * type, the hour, minute, second and z fields will be NULLs.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct toml_timestamp_t {
 | 
				
			||||||
 | 
						struct { /* internal. do not use. */
 | 
				
			||||||
 | 
							int year, month, day;
 | 
				
			||||||
 | 
							int hour, minute, second, millisec;
 | 
				
			||||||
 | 
							char z[10];
 | 
				
			||||||
 | 
						} __buffer;
 | 
				
			||||||
 | 
						int *year, *month, *day;
 | 
				
			||||||
 | 
						int *hour, *minute, *second, *millisec;
 | 
				
			||||||
 | 
						char* z;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*-----------------------------------------------------------------
 | 
				
			||||||
 | 
					 *  Enhanced access methods 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct toml_datum_t {
 | 
				
			||||||
 | 
						int ok;
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							toml_timestamp_t* ts; /* ts must be freed after use */
 | 
				
			||||||
 | 
							char*   s; /* string value. s must be freed after use */
 | 
				
			||||||
 | 
							int     b; /* bool value */
 | 
				
			||||||
 | 
							int64_t i; /* int value */
 | 
				
			||||||
 | 
							double  d; /* double value */
 | 
				
			||||||
 | 
						} u;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* on arrays: */
 | 
				
			||||||
 | 
					/* ... retrieve size of array. */
 | 
				
			||||||
 | 
					TOML_EXTERN int toml_array_nelem(const toml_array_t* arr);
 | 
				
			||||||
 | 
					/* ... retrieve values using index. */
 | 
				
			||||||
 | 
					TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t* arr, int idx);
 | 
				
			||||||
 | 
					TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t* arr, int idx);
 | 
				
			||||||
 | 
					TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t* arr, int idx);
 | 
				
			||||||
 | 
					TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t* arr, int idx);
 | 
				
			||||||
 | 
					TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx);
 | 
				
			||||||
 | 
					/* ... retrieve array or table using index. */
 | 
				
			||||||
 | 
					TOML_EXTERN toml_array_t* toml_array_at(const toml_array_t* arr, int idx);
 | 
				
			||||||
 | 
					TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* on tables: */
 | 
				
			||||||
 | 
					/* ... retrieve the key in table at keyidx. Return 0 if out of range. */
 | 
				
			||||||
 | 
					TOML_EXTERN const char* toml_key_in(const toml_table_t* tab, int keyidx);
 | 
				
			||||||
 | 
					/* ... retrieve values using key. */
 | 
				
			||||||
 | 
					TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t* arr, const char* key);
 | 
				
			||||||
 | 
					TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t* arr, const char* key);
 | 
				
			||||||
 | 
					TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t* arr, const char* key);
 | 
				
			||||||
 | 
					TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t* arr, const char* key);
 | 
				
			||||||
 | 
					TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key);
 | 
				
			||||||
 | 
					/* .. retrieve array or table using key. */
 | 
				
			||||||
 | 
					TOML_EXTERN toml_array_t* toml_array_in(const toml_table_t* tab,
 | 
				
			||||||
 | 
															const char* key);
 | 
				
			||||||
 | 
					TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab,
 | 
				
			||||||
 | 
															const char* key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*-----------------------------------------------------------------
 | 
				
			||||||
 | 
					 * lesser used 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* Return the array kind: 't'able, 'a'rray, 'v'alue */
 | 
				
			||||||
 | 
					TOML_EXTERN char toml_array_kind(const toml_array_t* arr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* For array kind 'v'alue, return the type of values 
 | 
				
			||||||
 | 
					   i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp
 | 
				
			||||||
 | 
					   0 if unknown
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					TOML_EXTERN char toml_array_type(const toml_array_t* arr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return the key of an array */
 | 
				
			||||||
 | 
					TOML_EXTERN const char* toml_array_key(const toml_array_t* arr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return the number of key-values in a table */
 | 
				
			||||||
 | 
					TOML_EXTERN int toml_table_nkval(const toml_table_t* tab);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return the number of arrays in a table */
 | 
				
			||||||
 | 
					TOML_EXTERN int toml_table_narr(const toml_table_t* tab);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return the number of sub-tables in a table */
 | 
				
			||||||
 | 
					TOML_EXTERN int toml_table_ntab(const toml_table_t* tab);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return the key of a table*/
 | 
				
			||||||
 | 
					TOML_EXTERN const char* toml_table_key(const toml_table_t* tab);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*--------------------------------------------------------------
 | 
				
			||||||
 | 
					 * misc 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret);
 | 
				
			||||||
 | 
					TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]);
 | 
				
			||||||
 | 
					TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t),
 | 
				
			||||||
 | 
													  void	(*xxfree)(void*));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*--------------------------------------------------------------
 | 
				
			||||||
 | 
					 *  deprecated 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* A raw value, must be processed by toml_rto* before using. */
 | 
				
			||||||
 | 
					typedef const char* toml_raw_t;
 | 
				
			||||||
 | 
					TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key);
 | 
				
			||||||
 | 
					TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t* arr, int idx);
 | 
				
			||||||
 | 
					TOML_EXTERN int toml_rtos(toml_raw_t s, char** ret);
 | 
				
			||||||
 | 
					TOML_EXTERN int toml_rtob(toml_raw_t s, int* ret);
 | 
				
			||||||
 | 
					TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t* ret);
 | 
				
			||||||
 | 
					TOML_EXTERN int toml_rtod(toml_raw_t s, double* ret);
 | 
				
			||||||
 | 
					TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double* ret, char* buf, int buflen);
 | 
				
			||||||
 | 
					TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t* ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* TOML_H */
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue