| summaryrefslogtreecommitdiff |
diff options
| author | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2016-05-05 14:59:28 +0200 |
|---|---|---|
| committer | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2016-05-05 14:59:28 +0200 |
| commit | 3405b0c1635843cbb81f042364bfcf238d7dc930 (patch) | |
| tree | 39501fec9ec72863c929a45dbc297412bbf90688 /src/io | |
| parent | c28bb6d31a122ec983e1e0a0dd1a8bd198098c58 (diff) | |
Adds the current code.
It's been running for close to a month on one of the IRC channels I
frequent and seems to be working fine.
One should be aware that, among other missing features, this version
does not store permanently what the bot learns. Indeed, I am currently
using a file with 431848 lines as its initial knowledge bank, making
this particular feature not a high priority one.
Also consider the fact that Zero of One converts text to underscore
before reading it but will not change its own aliases. This could
potentially be a cause for surprises when using uppercase letters in the
latter.
Diffstat (limited to 'src/io')
| -rw-r--r-- | src/io/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | src/io/data_input.c | 98 | ||||
| -rw-r--r-- | src/io/data_input.h | 21 | ||||
| -rw-r--r-- | src/io/data_input_types.h | 16 | ||||
| -rw-r--r-- | src/io/error.h | 146 | ||||
| -rw-r--r-- | src/io/network.c | 483 | ||||
| -rw-r--r-- | src/io/network.h | 27 | ||||
| -rw-r--r-- | src/io/network_types.h | 26 | ||||
| -rw-r--r-- | src/io/parameters.c | 354 | ||||
| -rw-r--r-- | src/io/parameters.h | 13 | ||||
| -rw-r--r-- | src/io/parameters_types.h | 20 |
11 files changed, 1212 insertions, 0 deletions
diff --git a/src/io/CMakeLists.txt b/src/io/CMakeLists.txt new file mode 100644 index 0000000..a13154b --- /dev/null +++ b/src/io/CMakeLists.txt @@ -0,0 +1,8 @@ +set( + SRC_FILES ${SRC_FILES} + ${CMAKE_CURRENT_SOURCE_DIR}/parameters.c + ${CMAKE_CURRENT_SOURCE_DIR}/network.c + ${CMAKE_CURRENT_SOURCE_DIR}/data_input.c +) +set(SRC_FILES ${SRC_FILES} PARENT_SCOPE) + diff --git a/src/io/data_input.c b/src/io/data_input.c new file mode 100644 index 0000000..e31d33b --- /dev/null +++ b/src/io/data_input.c @@ -0,0 +1,98 @@ +#define _POSIX_C_SOURCE 200809L +#include <stdlib.h> +#include <string.h> +#include <stdint.h> /* defines SIZE_MAX */ + +#include "error.h" + +#include "data_input.h" + +int ZoO_data_input_open +( + struct ZoO_data_input di [const static 1], + const char filename [const restrict static 1] +) +{ + /* prevents di [restrict] */ + ZoO_strings_initialize(&(di->string)); + + di->file = fopen(filename, "r"); + + if (di->file == (FILE *) NULL) + { + ZoO_ERROR + ( + "Could not open file '%s' in readonly mode.", + filename + ); + + return -1; + } + + return 0; +} + +int ZoO_data_input_read_line +( + struct ZoO_data_input di [const static 1], + ZoO_index const punctuations_count, + const ZoO_char punctuations [const restrict static punctuations_count] +) +{ + size_t line_size, i, w_start; + ZoO_char * line; + + /* prevents di [restrict] */ + ZoO_strings_finalize(&(di->string)); + + line = (ZoO_char *) NULL; + line_size = 0; + + /* XXX: assumed compatible with ZoO_char */ + + if (getline(&line, &line_size, di->file) < 1) + { + free((void *) line); + + return -1; + } + + line_size = strlen(line); + line[line_size - 1] = '\0'; + + --line_size; /* removed '\n' */ + + if + ( + ZoO_strings_parse + ( + &(di->string), + line_size, + line, + punctuations_count, + punctuations + ) < 0 + ) + { + free((void *) line); + + return -1; + } + + free((void *) line); + + return 0; +} + +void ZoO_data_input_close (struct ZoO_data_input di [const static 1]) +{ + if (di->file != (FILE *) NULL) + { + fclose(di->file); + + di->file = (FILE *) NULL; + } + + /* prevents di [restrict] */ + ZoO_strings_finalize(&(di->string)); +} diff --git a/src/io/data_input.h b/src/io/data_input.h new file mode 100644 index 0000000..a2f004b --- /dev/null +++ b/src/io/data_input.h @@ -0,0 +1,21 @@ +#ifndef _ZoO_IO_DATA_INPUT_H_ +#define _ZoO_IO_DATA_INPUT_H_ + +#include "data_input_types.h" + +int ZoO_data_input_open +( + struct ZoO_data_input di [const static 1], + const char filename [const restrict static 1] +); + +int ZoO_data_input_read_line +( + struct ZoO_data_input di [const static 1], + ZoO_index const punctuations_count, + const ZoO_char punctuations [const restrict static punctuations_count] +); + +void ZoO_data_input_close (struct ZoO_data_input di [const static 1]); + +#endif diff --git a/src/io/data_input_types.h b/src/io/data_input_types.h new file mode 100644 index 0000000..bd2709b --- /dev/null +++ b/src/io/data_input_types.h @@ -0,0 +1,16 @@ +#ifndef _ZoO_IO_DATA_INPUT_TYPES_H_ +#define _ZoO_IO_DATA_INPUT_TYPES_H_ + +#include <stdio.h> + +#include "../pervasive.h" + +#include "../tool/strings.h" + +struct ZoO_data_input +{ + FILE * restrict file; + struct ZoO_strings string; +}; + +#endif diff --git a/src/io/error.h b/src/io/error.h new file mode 100644 index 0000000..e4267a0 --- /dev/null +++ b/src/io/error.h @@ -0,0 +1,146 @@ +#ifndef _ZoO_IO_ERROR_H_ +#define _ZoO_IO_ERROR_H_ + +#include <stdio.h> + +#include "../pervasive.h" + +#define ZoO_DEBUG_ALL 1 + +#ifndef ZoO_DEBUG_ALL + #define ZoO_DEBUG_ALL 0 +#endif + +#ifndef ZoO_DEBUG_PROGRAM_FLOW + #define ZoO_DEBUG_PROGRAM_FLOW (0 || ZoO_DEBUG_ALL) +#endif + +#ifndef ZoO_DEBUG_CONFIG + #define ZoO_DEBUG_CONFIG (0 || ZoO_DEBUG_ALL) +#endif + +#ifndef ZoO_DEBUG_LEARNING + #define ZoO_DEBUG_LEARNING (0 || ZoO_DEBUG_ALL) +#endif + +#ifndef ZoO_DEBUG_NETWORK + #define ZoO_DEBUG_NETWORK (0 || ZoO_DEBUG_ALL) +#endif + +#define ZoO_ENABLE_WARNINGS_OUTPUT 1 +#define ZoO_ENABLE_RUNTIME_ERRORS_OUTPUT 1 +#define ZoO_ENABLE_PROGRAMMING_ERRORS_OUTPUT 1 +#define ZoO_ENABLE_FATAL_ERROR_OUTPUT 1 + +#ifdef ZoO_ENABLE_ERROR_LOCATION + #define ZoO_LOCATION "[" __FILE__ "][" ZoO_TO_STRING(__LINE__) "]" +#else + #define ZoO_LOCATION "" +#endif + +#define ZoO_PRINT_STDERR(symbol, str, ...)\ + fprintf(stderr, "[" symbol "]" ZoO_LOCATION " " str "\n", __VA_ARGS__); + +/* + * Given that we use preprocessor contants as flags, we can expect the compilers + * to remove the test condition for disabled flags. No need to be shy about + * allowing many debug options. + */ + +#define ZoO_DEBUG(flag, str, ...)\ + ZoO_ISOLATE\ + (\ + if (flag)\ + {\ + ZoO_PRINT_STDERR("D", str, __VA_ARGS__);\ + }\ + ) + + +#define ZoO_WARNING(str, ...)\ + ZoO_ISOLATE\ + (\ + if (ZoO_ENABLE_WARNINGS_OUTPUT)\ + {\ + ZoO_PRINT_STDERR("W", str, __VA_ARGS__);\ + }\ + ) + +#define ZoO_ERROR(str, ...)\ + ZoO_ISOLATE\ + (\ + if (ZoO_ENABLE_RUNTIME_ERRORS_OUTPUT)\ + {\ + ZoO_PRINT_STDERR("E", str, __VA_ARGS__);\ + }\ + ) + +#define ZoO_PROG_ERROR(str, ...)\ + ZoO_ISOLATE\ + (\ + if (ZoO_ENABLE_PROGRAMMING_ERRORS_OUTPUT)\ + {\ + ZoO_PRINT_STDERR("P", str, __VA_ARGS__);\ + }\ + ) + +#define ZoO_FATAL(str, ...)\ + ZoO_ISOLATE\ + (\ + if (ZoO_ENABLE_FATAL_ERROR_OUTPUT)\ + {\ + ZoO_PRINT_STDERR("F", str, __VA_ARGS__);\ + }\ + ) + +/* For outputs without dynamic content (static). ******************************/ + +#define ZoO_PRINT_S_STDERR(symbol, str)\ + fprintf(stderr, "[" symbol "]" ZoO_LOCATION " " str "\n"); + +#define ZoO_S_DEBUG(flag, str)\ + ZoO_ISOLATE\ + (\ + if (flag)\ + {\ + ZoO_PRINT_S_STDERR("D", str);\ + }\ + ) + +#define ZoO_S_WARNING(str)\ + ZoO_ISOLATE\ + (\ + if (ZoO_ENABLE_WARNINGS_OUTPUT)\ + {\ + ZoO_PRINT_S_STDERR("W", str);\ + }\ + ) + +#define ZoO_S_ERROR(str)\ + ZoO_ISOLATE\ + (\ + if (ZoO_ENABLE_RUNTIME_ERRORS_OUTPUT)\ + {\ + ZoO_PRINT_S_STDERR("E", str);\ + }\ + ) + +#define ZoO_S_PROG_ERROR(str)\ + ZoO_ISOLATE\ + (\ + if (ZoO_ENABLE_PROGRAMMING_ERRORS_OUTPUT)\ + {\ + ZoO_PRINT_S_STDERR("P", str);\ + }\ + ) + +#define ZoO_S_FATAL(str)\ + ZoO_ISOLATE\ + (\ + if (ZoO_ENABLE_FATAL_ERROR_OUTPUT)\ + {\ + ZoO_PRINT_S_STDERR("F", str);\ + }\ + ) + +#endif diff --git a/src/io/network.c b/src/io/network.c new file mode 100644 index 0000000..c8d05a2 --- /dev/null +++ b/src/io/network.c @@ -0,0 +1,483 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +/* "POSIX.1 does not require the inclusion of <sys/types.h>" */ +/* - man page for setsockopt */ +/* #include <sys/types.h> */ +#include <sys/socket.h> +#include <sys/time.h> + +#include "error.h" + +#include "network.h" + +static int reconnect (struct ZoO_network net [const restrict static 1]) +{ + struct timeval timeout; + int old_errno = errno; + + errno = 0; + timeout.tv_sec = ZoO_NETWORK_TIMEOUT; + timeout.tv_usec = 0; + + if (net->connection != -1) + { + close(net->connection); + } + + net->connection = + socket + ( + net->addrinfo->ai_family, + net->addrinfo->ai_socktype, + net->addrinfo->ai_protocol + ); + + if (net->connection == -1) + { + ZoO_FATAL + ( + "Could not create socket: %s.", + strerror(errno) + ); + + errno = old_errno; + + return -1; + } + + errno = 0; + + if + ( + ( + setsockopt + ( + net->connection, + SOL_SOCKET, + SO_RCVTIMEO, + (const void *) &timeout, + (socklen_t) sizeof(struct timeval) + ) < 0 + ) + || + ( + setsockopt + ( + net->connection, + SOL_SOCKET, + SO_SNDTIMEO, + (const void *) &timeout, + (socklen_t) sizeof(struct timeval) + ) < 0 + ) + ) + { + ZoO_ERROR("Could not set timeout on network socket: %s", strerror(errno)); + + errno = old_errno; + + return -1; + } + + errno = old_errno; + + ZoO_S_DEBUG(ZoO_DEBUG_NETWORK, "(Re)connecting to network..."); + + if + ( + connect + ( + net->connection, + net->addrinfo->ai_addr, + net->addrinfo->ai_addrlen + ) != 0 + ) + { + ZoO_ERROR + ( + "Unable to connect to the network: %s", + strerror(errno) + ); + + errno = old_errno; + + return -1; + } + + errno = old_errno; + + snprintf + ( + net->msg, + 512, + "USER %s 8 * :%s\r\n", + net->user, + net->name + ); + + errno = 0; + + if (write(net->connection, net->msg, strlen(net->msg)) < 1) + { + ZoO_ERROR + ( + "Unable to write to the network: %s", + strerror(errno) + ); + + errno = old_errno; + + return -1; + } + + snprintf + ( + net->msg, + 512, + "NICK %s\r\n", + net->nick + ); + + errno = 0; + + if (write(net->connection, net->msg, strlen(net->msg)) < 1) + { + ZoO_ERROR + ( + "Unable to write to the network: %s", + strerror(errno) + ); + + errno = old_errno; + + return -1; + } + + errno = old_errno; + + net->buffer_remaining = 0; + net->buffer_index = 0; + ZoO_S_DEBUG(ZoO_DEBUG_NETWORK, "(Re)connected."); + + return 0; +} + +int ZoO_network_connect +( + struct ZoO_network net [const static 1], + const char host [const restrict static 1], + const char port [const restrict static 1], + const char channel [const restrict static 1], + const char user [const restrict static 1], + const char name [const restrict static 1], + const char nick [const restrict static 1] +) +{ + int error; + struct addrinfo hints; + const int old_errno = errno; + + net->connection = -1; + net->channel = channel; + net->user = user; + net->name = name; + net->nick = nick; + net->buffer_index = 0; + net->buffer_remaining = 0; + + memset(&hints, 0, sizeof(struct addrinfo)); + memset(net->msg, 0, (sizeof(ZoO_char) * 513)); + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + errno = 0; + + error = getaddrinfo(host, port, &hints, &(net->addrinfo)); + + if (error != 0) + { + if (error == EAI_SYSTEM) + { + ZoO_ERROR + ( + "Could not retrieve server information: %s.", + strerror(errno) + ); + } + else + { + ZoO_FATAL + ( + "Could not retrieve server information: %s.", + gai_strerror(error) + ); + } + + errno = old_errno; + + return -1; + } + + errno = 0; + + + reconnect(net); + + return 0; +} + +int ZoO_network_receive +( + struct ZoO_network net [const restrict static 1], + size_t msg_offset [const restrict static 1], + size_t msg_size [const restrict static 1] +) +{ + int old_errno; + ssize_t in_count, in_index, msg_index, cmd; + + old_errno = errno; + + for (;;) + { + msg_index = 0; + + errno = 0; + + while + ( + ( + (in_count = + read( + net->connection, + (net->buffer + net->buffer_index), + (512 - net->buffer_index) + ) + ) > 0 + ) + ) + { + net->buffer_remaining += in_count; + + for + ( + in_index = 0; + in_index < net->buffer_remaining; + ++in_index + ) + { + net->msg[msg_index] = net->buffer[net->buffer_index + in_index]; + + if + ( + (msg_index == 511) + || + ( + (msg_index > 0) + && (net->msg[msg_index - 1] == '\r') + && (net->msg[msg_index] == '\n') + ) + ) + { + net->msg[msg_index + 1] = '\0'; + + + if (net->buffer_index != net->buffer_remaining) + { + memmove + ( + net->buffer, + (net->buffer + net->buffer_index), + (size_t) net->buffer_remaining + ); + + net->buffer_index = 0; + } + + net->buffer_remaining -= (in_index + 1); + + errno = old_errno; + + goto READ_MSG; + } + + ++msg_index; + } + + net->buffer_remaining = 0; + net->buffer_index = 0; + + errno = 0; + } + + ZoO_ERROR + ( + "Something went wrong while trying to read from the network: %s.", + strerror(errno) + ); + + errno = old_errno; + + if (reconnect(net) < 0) + { + return -1; + } + + continue; + + READ_MSG: + + ZoO_DEBUG(ZoO_DEBUG_NETWORK, "[NET->in] %s\n", net->msg); + + /* XXX: doesn't that prevent net [restrict]? */ + if (ZoO_IS_PREFIX("PING", net->msg)) + { + errno = 0; + + net->msg[1] = 'O'; + + if (write(net->connection, net->msg, strlen(net->msg)) < 1) + { + ZoO_ERROR("Could not reply to PING request: %s", strerror(errno)); + + errno = old_errno; + + if (reconnect(net) < 0) + { + return -1; + } + + continue; + } + + ZoO_DEBUG(ZoO_DEBUG_NETWORK, "[NET->out] %s\n", net->msg); + + errno = old_errno; + } + else if (net->msg[0] == ':') + { + cmd = 0; + + for (in_index = 1; in_index < 512; in_index++) + { + if (net->msg[in_index] == ' ') + { + cmd = (in_index + 1); + + break; + } + } + + if (cmd == 0) + { + continue; + } + + if (ZoO_IS_PREFIX("001", (net->msg + cmd))) + { + snprintf + ( + net->msg, + 512, + "JOIN :%s\r\n", + net->channel + ); + + errno = 0; + + if (write(net->connection, net->msg, strlen(net->msg)) < 1) + { + ZoO_ERROR + ( + "Could not send JOIN request: %s", + strerror(errno) + ); + + errno = old_errno; + + if (reconnect(net) < 0) + { + return -1; + } + } + + ZoO_DEBUG(ZoO_DEBUG_NETWORK, "[NET->out] %s", net->msg); + + continue; + } + + if (ZoO_IS_PREFIX("PRIVMSG", (net->msg + cmd))) + { + for (; in_index < 512; in_index++) + { + if (net->msg[in_index] == ':') + { + cmd = (in_index + 1); + + break; + } + } + + *msg_offset = cmd; + *msg_size = (msg_index - *msg_offset - 1); + + /*net->msg[*msg_size - 1] = '\0'; */ + + return 0; + } + } + } +} + +int ZoO_network_send (struct ZoO_network net [const restrict static 1]) +{ + int const old_errno = errno; + + snprintf + ( + net->buffer, + 512, + "PRIVMSG %s :%s\r\n", + net->channel, + net->msg + ); + + errno = 0; + + if (write(net->connection, net->buffer, strlen(net->buffer)) < 1) + { + ZoO_ERROR + ( + "Could not send PRIVMSG: %s.", + strerror(errno) + ); + + errno = old_errno; + + if (reconnect(net) < 0) + { + return -2; + } + else + { + return -1; + } + } + + errno = old_errno; + + ZoO_DEBUG(ZoO_DEBUG_NETWORK, "[NET->out] %s", net->buffer); + + return 0; +} + +void ZoO_network_disconnect (struct ZoO_network net [const restrict static 1]) +{ + freeaddrinfo(net->addrinfo); + close(net->connection); +} + diff --git a/src/io/network.h b/src/io/network.h new file mode 100644 index 0000000..ac7284a --- /dev/null +++ b/src/io/network.h @@ -0,0 +1,27 @@ +#ifndef _ZoO_IO_NETWORK_H_ +#define _ZoO_IO_NETWORK_H_ +#include "network_types.h" + +int ZoO_network_connect +( + struct ZoO_network net [const static 1], + const char host [const restrict static 1], + const char port [const restrict static 1], + const char channel [const restrict static 1], + const char user [const restrict static 1], + const char name [const restrict static 1], + const char nick [const restrict static 1] +); + +int ZoO_network_receive +( + struct ZoO_network net [const static 1], + size_t msg_offset [const restrict static 1], + size_t msg_size [const restrict static 1] +); + +int ZoO_network_send (struct ZoO_network net [const restrict static 1]); + +void ZoO_network_disconnect (struct ZoO_network net [const restrict static 1]); + +#endif diff --git a/src/io/network_types.h b/src/io/network_types.h new file mode 100644 index 0000000..16c81da --- /dev/null +++ b/src/io/network_types.h @@ -0,0 +1,26 @@ +#ifndef _ZoO_IO_NETWORK_TYPES_H_ +#define _ZoO_IO_NETWORK_TYPES_H_ + +#define POSIX_C_SOURCE + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> + +#include "../pervasive.h" + +struct ZoO_network +{ + size_t buffer_index; + size_t buffer_remaining; + struct addrinfo * addrinfo; + ZoO_char buffer [513]; + ZoO_char msg [513]; + int connection; + const char * restrict channel; + const char * restrict user; + const char * restrict name; + const char * restrict nick; +}; + +#endif diff --git a/src/io/parameters.c b/src/io/parameters.c new file mode 100644 index 0000000..0f7d05c --- /dev/null +++ b/src/io/parameters.c @@ -0,0 +1,354 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "../pervasive.h" + +#include "error.h" + +#include "parameters.h" + +static void load_default_parameters +( + struct ZoO_parameters param [const restrict static 1] +) +{ + param->data_filename = ZoO_DEFAULT_DATA_FILENAME; + + param->irc_server_addr = ZoO_DEFAULT_IRC_SERVER_ADDR; + param->irc_server_port = ZoO_DEFAULT_IRC_SERVER_PORT; + param->irc_server_channel = ZoO_DEFAULT_IRC_SERVER_CHANNEL; + param->irc_username = ZoO_DEFAULT_IRC_USERNAME; + param->irc_realname = ZoO_DEFAULT_IRC_REALNAME; + + param->reply_rate = ZoO_DEFAULT_REPLY_RATE; + + param->aliases_count = 0; + param->aliases = NULL; +} + +static void print_help (const char exec [const restrict static 1]) +{ + printf + ( + "Usage: %s [option_1 option_2 ...] NICKNAME [ALIAS_1 ALIAS_2 ...] \n" + "NICKNAME is used as the IRC nickname value.\n" + "If NICKNAME or any ALIAS is found in an event, the program will reply.\n" + "\nAvailable options:\n" + " [--data-filename | -df] FILENAME\n" + " Learn content from FILENAME before connecting.\n" + " Default: %s.\n" + " [--irc-server-addr | -isa] IRC_SERVER_ADDR\n" + " Connect to this server address.\n" + " Default: %s.\n" + " [--irc-server-port | -isp] IRC_SERVER_PORT\n" + " Connect to this server port.\n" + " Default: %s.\n" + " [--irc-server-channel | -isc] IRC_SERVER_CHANNEL\n" + " Connect to this server's channel.\n" + " Default: %s.\n" + " [--irc-username | -iu] USERNAME\n" + " Connect using this as 'username' (shown in WHOIS).\n" + " Default: %s.\n" + " [--irc-realname | -ir] REALNAME\n" + " Connect using this as 'realname' (shown in WHOIS).\n" + " Default: %s.\n" + " [--reply-rate | -rr] REPLY_RATE\n" + " Chance to reply to an event (integer, range [0, 100]).\n" + " Default: %d.\n", + exec, + ZoO_DEFAULT_DATA_FILENAME, + ZoO_DEFAULT_IRC_SERVER_ADDR, + ZoO_DEFAULT_IRC_SERVER_PORT, + ZoO_DEFAULT_IRC_SERVER_CHANNEL, + ZoO_DEFAULT_IRC_USERNAME, + ZoO_DEFAULT_IRC_REALNAME, + ZoO_DEFAULT_REPLY_RATE + ); +} + +static int parse_string_arg +( + const char * restrict dest [const restrict static 1], + int const i, + const char * restrict argv [const restrict static 1], + int const argc +) +{ + if (i == argc) + { + ZoO_FATAL + ( + "Missing value for parameter '%s'.", + /* Safe: i > 1 */ + argv[i - 1] + ); + + return -1; + } + + *dest = argv[i]; + + return 0; +} + +static int parse_integer_arg +( + int dest [const restrict static 1], + int const i, + const char * argv [const restrict static 1], + int const argc, + int const min_val, + int const max_val +) +{ + long int result; + char * endptr; + const int old_errno = errno; + + if (i == argc) + { + ZoO_FATAL + ( + "Missing value for parameter '%s'.", + /* Safe: i > 1 */ + argv[i - 1] + ); + + return -1; + } + + errno = 0; + + result = strtol(argv[i], &endptr, 10); + + if + ( + (errno != 0) + || ((*endptr) == '\n') + || (result < min_val) + || (result > max_val) + ) + { + ZoO_FATAL + ( + "Invalid or missing value for parameter '%s', accepted range is " + "[%d, %d] (integer).", + /* Safe: i > 1 */ + argv[i - 1], + min_val, + max_val + ); + + errno = old_errno; + + return -1; + } + + *dest = (int) result; + + errno = old_errno; + + return 0; +} + +int ZoO_parameters_initialize +( + struct ZoO_parameters param [const restrict static 1], + int const argc, + const char * argv [const restrict static argc] +) +{ + int i; + + load_default_parameters(param); + + for (i = 1; i < argc; ++i) + { + if + ( + (strcmp(argv[i], "--data-filename") == 0) + || (strcmp(argv[i], "-df") == 0) + ) + { + i += 1; + + if + ( + parse_string_arg + ( + &(param->data_filename), + i, + argv, + argc + ) < 0 + ) + { + return -1; + } + } + else if + ( + (strcmp(argv[i], "--irc-server-addr") == 0) + || (strcmp(argv[i], "-isa") == 0) + ) + { + i += 1; + + if + ( + parse_string_arg + ( + &(param->irc_server_addr), + i, + argv, + argc + ) < 0 + ) + { + return -1; + } + } + else if + ( + (strcmp(argv[i], "--irc-server-port") == 0) + || (strcmp(argv[i], "-isp") == 0) + ) + { + i += 1; + + if + ( + parse_string_arg + ( + &(param->irc_server_port), + i, + argv, + argc + ) < 0 + ) + { + return -1; + } + } + else if + ( + (strcmp(argv[i], "--irc-server-channel") == 0) + || (strcmp(argv[i], "-isc") == 0) + ) + { + i += 1; + + if + ( + parse_string_arg + ( + &(param->irc_server_channel), + i, + argv, + argc + ) < 0 + ) + { + return -1; + } + } + else if + ( + (strcmp(argv[i], "--irc-username") == 0) + || (strcmp(argv[i], "-iu") == 0) + ) + { + i += 1; + + if + ( + parse_string_arg + ( + &(param->irc_username), + i, + argv, + argc + ) < 0 + ) + { + return -1; + } + } + else if + ( + (strcmp(argv[i], "--irc-realname") == 0) + || (strcmp(argv[i], "-in") == 0) + ) + { + i += 1; + + if + ( + parse_string_arg + ( + &(param->irc_realname), + i, + argv, + argc + ) < 0 + ) + { + return -1; + } + } + else if + ( + (strcmp(argv[i], "--reply-rate") == 0) + || (strcmp(argv[i], "-rr") == 0) + ) + { + i += 1; + + if + ( + parse_integer_arg + ( + &(param->reply_rate), + i, + argv, + argc, + 0, + 100 + ) < 0 + ) + { + return -1; + } + } + else if + ( + (strcmp(argv[i], "--help") == 0) + || (strcmp(argv[i], "-h") == 0) + ) + { + print_help(argv[0]); + + return 0; + } + else + { + break; + } + } + + if (i == argc) + { + ZoO_S_FATAL("Missing argument: NICKNAME"); + + print_help(argv[0]); + + return -1; + } + + param->aliases_count = (argc - i); + param->aliases = (argv + i); + + return 1; +} diff --git a/src/io/parameters.h b/src/io/parameters.h new file mode 100644 index 0000000..1011e2b --- /dev/null +++ b/src/io/parameters.h @@ -0,0 +1,13 @@ +#ifndef _ZoO_IO_PARAMETERS_H_ +#define _ZoO_IO_PARAMETERS_H_ + +#include "parameters_types.h" + +int ZoO_parameters_initialize +( + struct ZoO_parameters param [const static 1], + int const argc, + const char * argv [const static argc] +); + +#endif diff --git a/src/io/parameters_types.h b/src/io/parameters_types.h new file mode 100644 index 0000000..6d511d8 --- /dev/null +++ b/src/io/parameters_types.h @@ -0,0 +1,20 @@ +#ifndef _ZoO_IO_PARAMETERS_TYPES_H_ +#define _ZoO_IO_PARAMETERS_TYPES_H_ + +struct ZoO_parameters +{ + const char * restrict data_filename; + + const char * restrict irc_server_addr; + const char * restrict irc_server_port; + const char * restrict irc_server_channel; + const char * restrict irc_username; + const char * restrict irc_realname; + + int reply_rate; + + int aliases_count; + const char * restrict * restrict aliases; +}; + +#endif |


