diff --git a/parsing/sources/help.c b/parsing/sources/help.c new file mode 100644 index 0000000..e5a573c --- /dev/null +++ b/parsing/sources/help.c @@ -0,0 +1,29 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* help.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: rparodi +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/03/28 12:38:44 by rparodi #+# #+# */ +/* Updated: 2026/03/28 15:23:53 by rparodi ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include +#include +#include "parsing.h" + +void print_help(size_t size) { + dprintf(2, "Usage: ./ft_ping [OPTION...] HOST ...\nSend ICMP ECHO_REQUEST packets to network hosts.\n\n"); + dprintf(2, "Options:\n"); + + for (size_t i = 0; i < size; i++) + if (_flags[i].is_mandatory != false || BONUS == 1) { + if (isprint(_flags[i].short_option)) + dprintf(2, "\t-%c, --%-15s%-15s%-15s\n", _flags[i].short_option, (_flags[i].long_option ? _flags[i].long_option : ""), (_flags[i].usage ? _flags[i].usage : ""), _flags[i].description); + else + dprintf(2, "\t --%-15s%-15s%-15s\n", (_flags[i].long_option ? _flags[i].long_option : ""), (_flags[i].usage ? _flags[i].usage : ""), _flags[i].description); + } +} diff --git a/parsing/sources/parsing.c b/parsing/sources/parsing.c new file mode 100644 index 0000000..b14daaa --- /dev/null +++ b/parsing/sources/parsing.c @@ -0,0 +1,133 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parsing.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: rparodi +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/03/23 14:49:36 by rparodi #+# #+# */ +/* Updated: 2026/03/28 15:26:13 by rparodi ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "parsing.h" +#include "macro.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const t_args _flags[] = { + {'?', "help", NULL, "print help and exit", true}, + {'W', "linger",",", "time to wait for response", false}, + {'c', "count","", "stop after replies", false}, + {'f', "flood",NULL, "flood ping", false}, + {'l', "preload",",", "send number of packages while waiting replies", false}, + {'n', "numeric",NULL, "no reverse DNS name resolution", false}, + {'p', "pattern",",", "contents of padding byte", false}, + {'q', "quiet", NULL, "reply wait in seconds", false}, + {'v', "verbose",NULL, "verbose output", true}, + {'w', "timeout",",", "reply wait in seconds", false}, + {0, "usage", NULL, "give a short usage message", false}, + {0, NULL, NULL,NULL, true}, +}; + +static struct option *_t_args_to_getopt_long(const size_t size) { + struct option *long_options = (struct option *)calloc((size + 1), sizeof(struct option)); + if (!long_options) { + return NULL; + } + + for (size_t i = 0; i < size; i++) { + long_options[i].name = _flags[i].long_option; + long_options[i].val = _flags[i].short_option; + if (_flags[i].usage == NULL) { + long_options[i].has_arg = no_argument; + } else { + long_options[i].has_arg = required_argument; + } + long_options[i].flag = NULL; + } + + long_options[size] = (struct option){0}; + return long_options; +} + +void parsing_args(int argc, char **argv, t_flags *flags) +{ + const size_t size = args_size(); + size_t j = 0; + char args[2 * size + 1]; + bzero(args, sizeof(args)); + + for (size_t i = 0; i < size; i++) { + if (_flags[i].is_mandatory != false || BONUS == 1) { + args[j++] = _flags[i].short_option; + if (_flags[i].usage != NULL) + args[j++] = ':'; + } + } + + DEBUG_LOG(args); + + struct option *options = _t_args_to_getopt_long(size); + if (!options) { + ERROR_LOG(strerror(ENOMEM)); + exit(ENOMEM); + } + opterr = 1; + int opt; + while ((opt = getopt_long(argc, argv, args, options, NULL)) != -1) { + switch (opt) { + case 'v': + INFO_LOG("argument verbose"); + flags->verbose = true; + break; + case 'f': + INFO_LOG("argument flood"); + flags->flood = true; + break; + case 'n': + INFO_LOG("argument no-reverse"); + flags->reverse_dns = true; + break; + case 'c': + INFO_LOG("argument count"); + flags->count = check_num_arguments(optarg); + break; + case 'q': + INFO_LOG("argument quiet"); + flags->quiet = true; + break; + case 'w': + INFO_LOG("argument wait"); + flags->wait = check_num_arguments(optarg); + break; + case 'W': + INFO_LOG("argument timeout"); + flags->timeout = check_num_arguments(optarg); + break; + case '?': + free(options); + if (optopt != 0) { + if (isprint(optopt)) { + char invalid_option[2] = {optopt, 0}; + WARN_LOG(invalid_option); + } + dprintf(2, "Try 'ping --help' or 'ping --usage' for more information.\n"); + exit(64); + } + print_help(size); + exit(EXIT_SUCCESS); + default: + if (strcmp(options[optind - 1].name, "usage")) + print_usage(size); + } + } + free(options); +} diff --git a/parsing/sources/usage.c b/parsing/sources/usage.c new file mode 100644 index 0000000..b0f67d9 --- /dev/null +++ b/parsing/sources/usage.c @@ -0,0 +1,53 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* usage.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: rparodi +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/03/28 15:07:55 by rparodi #+# #+# */ +/* Updated: 2026/03/28 15:37:34 by rparodi ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "parsing.h" +#include + +static void _print_short_without_option(const size_t size) { + printf("[-"); + for (size_t i = 0; i < size; i++) { + if (isprint(_flags[i].short_option) && !_flags[i].usage) { + printf("%c", _flags[i].short_option); + } + } + printf("]"); +} + +static void _print_short_with_option(const size_t size) { + for (size_t i = 0; i < size; i++) { + if (isprint(_flags[i].short_option) && _flags[i].usage) { + printf(" [-%c NUMBER]", _flags[i].short_option); + } + } +} + +static void _print_long(const size_t size) { + for (size_t i = 0; i < size; i++) { + if (_flags[i].long_option) { + if (!_flags[i].usage) { + printf(" [--%s]", _flags[i].long_option); + } + else { + printf(" [--%s=NUMBER]", _flags[i].long_option); + } + } + } +} + +void print_usage(const size_t size) { + printf("Usage: ft_ping "); + _print_short_without_option(size); + _print_short_with_option(size); + _print_long(size); + putchar('\n'); +} diff --git a/parsing/sources/utils.c b/parsing/sources/utils.c new file mode 100644 index 0000000..11d6fa3 --- /dev/null +++ b/parsing/sources/utils.c @@ -0,0 +1,55 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: rparodi +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/03/28 12:40:08 by rparodi #+# #+# */ +/* Updated: 2026/03/28 15:22:10 by rparodi ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "macro.h" +#include "parsing.h" +#include +#include +#include +#include +#include + +size_t args_size() +{ + size_t i = 0; + while (_flags[i].short_option != 0 || _flags[i].long_option != NULL) { + i++; + } + return i; +} + +static bool _is_valid_number(const char *str) { + if (!str) + return false; + + for (size_t i = 0; str[i]; i++) { + if (!isdigit(str[i])) + return false; + } + return true; +} + +uint64_t check_num_arguments(char *arg) +{ + if (!_is_valid_number(arg)) { + ERROR_LOG(strerror(EINVAL)); + exit(EXIT_FAILURE); + } + + errno = 0; + uint64_t value = strtoull(arg, NULL, 10); + if (errno != 0 || value > UINT64_MAX) { + ERROR_LOG(strerror(errno)) + exit(EXIT_FAILURE); + } + return value; +}