From b00fce853801c886b9767184d90a186f9962c591 Mon Sep 17 00:00:00 2001 From: Konstantin Pereiaslov Date: Mon, 4 Sep 2023 01:50:54 -0500 Subject: [PATCH] Move argument parsing to a separate file --- Makefile | 2 +- arguments_parsing.c | 147 ++++++++++++++++++++++++++++++++++++++++++++ arguments_parsing.h | 14 +++++ main.c | 139 +---------------------------------------- 4 files changed, 163 insertions(+), 139 deletions(-) create mode 100644 arguments_parsing.c create mode 100644 arguments_parsing.h diff --git a/Makefile b/Makefile index b0d1093..2d1c47e 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CC=gcc ifeq ($(PREFIX),) PREFIX := /usr endif -SOURCES = time_utils.c sleep_utils.c tty_utils.c main.c process_handling.c +SOURCES = time_utils.c sleep_utils.c tty_utils.c process_handling.c arguments_parsing.c main.c OBJECTS = $(SOURCES:.c=.o) all: executable diff --git a/arguments_parsing.c b/arguments_parsing.c new file mode 100644 index 0000000..ffcd624 --- /dev/null +++ b/arguments_parsing.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include +#include + +#include "output_settings.h" +#include "arguments_parsing.h" +#include "tty_utils.h" + +const long TIMEOUT_MAX_SUPPORTED_VALUE = 100000000; //~3 years +const long TIMEOUT_MIN_SUPPORTED_VALUE = 1; +const long START_MONITOR_AFTER_MAX_SUPPORTED_VALUE = TIMEOUT_MAX_SUPPORTED_VALUE*1000; +const long START_MONITOR_AFTER_MIN_SUPPORTED_VALUE = 0; + +void print_usage(char *binary_name) { + printf("Usage: %s [OPTIONS] shell_command_to_run [shell_command_arguments]\n", binary_name); + printf("\nOptions:\n"); + printf(" --timeout, -t Set the user idle time after which the command can run in seconds (default: 300 seconds).\n"); + printf(" --start-monitor-after, -a Set an initial delay in milliseconds before monitoring starts. During this time command runs unrestricted. This helps to catch quick errors. (default: 300 ms).\n"); + printf(" --verbose, -v Enable verbose output for monitoring.\n"); + printf(" --debug Enable debugging output.\n"); + printf(" --quiet, -q Suppress all program output except errors.\n"); + printf(" --version, -V Print the program version information.\n"); +} +void print_version() { + printf("runwhenidle %s\n", VERSION); +} + +char *read_remaining_arguments_as_char(int argc, + char *const *argv) { + if (optind == argc) { //there is one argument remaining + char *last_and_only_argument = strdup(argv[optind]); + return last_and_only_argument; + } + + size_t memory_to_be_allocated_for_remaining_arguments_string = 0; + for (int i = optind; i < argc; i++) { + memory_to_be_allocated_for_remaining_arguments_string += + strlen(argv[i]) + 1; // +1 for space separator or null terminator + } + + char *remaining_arguments_string = NULL; // Variable to store the remaining_arguments_string + + // Allocate memory for the remaining_arguments_string + remaining_arguments_string = malloc(memory_to_be_allocated_for_remaining_arguments_string); + if (remaining_arguments_string == NULL) { + //not using fprintf_error here intentionally + fprintf(stderr, "Failed to allocate memory while parsing command to be ran.\n"); + exit(1); + } + + size_t current_length_of_all_arguments = 0; + for (int i = optind; i < argc; i++) { + size_t current_argument_length = strlen(argv[i]); + memcpy(remaining_arguments_string + current_length_of_all_arguments, argv[i], current_argument_length); + current_length_of_all_arguments += current_argument_length; + remaining_arguments_string[current_length_of_all_arguments++] = ' '; // Add space separator + } + assert(current_length_of_all_arguments == memory_to_be_allocated_for_remaining_arguments_string); + remaining_arguments_string[current_length_of_all_arguments - 1] = '\0'; // Replace the last space separator with a null terminator + + return remaining_arguments_string; +} + +char *parse_command_line_arguments(int argc, char *argv[]) { + struct option long_options[] = { + {"timeout", required_argument, NULL, 't'}, + {"start-monitor-after", required_argument, NULL, 'a'}, + {"verbose", no_argument, NULL, 'v'}, + {"debug", no_argument, NULL, 'd'}, + {"quiet", no_argument, NULL, 'q'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {NULL, 0, NULL, 0} + }; + + // Parse command line options + int option; + while ((option = getopt_long(argc, argv, "+hvqt:a:V", long_options, NULL)) != -1) { + switch (option) { + case 't': { + + long timeout_arg_value = strtol(optarg, NULL, 10); + if (timeout_arg_value < TIMEOUT_MIN_SUPPORTED_VALUE || + timeout_arg_value > TIMEOUT_MAX_SUPPORTED_VALUE || errno != 0) { + fprintf_error("Invalid timeout value: \"%s\". Range supported: %ld-%ld", optarg, + TIMEOUT_MIN_SUPPORTED_VALUE, TIMEOUT_MAX_SUPPORTED_VALUE); + print_usage(argv[0]); + exit(1); + } + user_idle_timeout_ms = timeout_arg_value * 1000; + break; + } + case 'a': { + start_monitor_after_ms = strtol(optarg, NULL, 10); + + if (start_monitor_after_ms < START_MONITOR_AFTER_MIN_SUPPORTED_VALUE || errno != 0) { + fprintf_error( "Invalid start-monitor-after time value: \"%s\" Range supported: %ld-%ld.\n", optarg, + START_MONITOR_AFTER_MIN_SUPPORTED_VALUE, START_MONITOR_AFTER_MAX_SUPPORTED_VALUE + ); + print_usage(argv[0]); + exit(1); + } + break; + } + case 'V': + print_version(); + exit(0); + case 'v': + verbose = 1; + break; + case 'd': + debug = 1; + verbose = 1; + break; + case 'q': + quiet = 1; + break; + case 'h': + print_usage(argv[0]); + exit(0); + break; + default: + print_usage(argv[0]); + exit(1); + } + } + if (debug) fprintf(stderr, "verbose: %i, debug: %i, quiet: %i, user_idle_timeout_ms: %i, start_monitoring_after_ms: %lld\n", verbose, debug, quiet, user_idle_timeout_ms, start_monitor_after_ms); + if (optind >= argc) { + print_usage(argv[0]); + exit(1); + } + if (quiet && debug) { + fprintf_error("Incompatible options --quiet|-q and --debug used"); + print_usage(argv[0]); + exit(1); + } + if (quiet && verbose) { + fprintf_error("Incompatible options --quiet|-q and --verbose|-v used"); + print_usage(argv[0]); + exit(1); + } + + return read_remaining_arguments_as_char(argc, argv); +} diff --git a/arguments_parsing.h b/arguments_parsing.h new file mode 100644 index 0000000..491ba36 --- /dev/null +++ b/arguments_parsing.h @@ -0,0 +1,14 @@ +#ifndef RUNWHENIDLE_ARGUMENTS_PARSING_H +#define RUNWHENIDLE_ARGUMENTS_PARSING_H +extern long start_monitor_after_ms; +extern long unsigned user_idle_timeout_ms; + +/** + * Parses command line arguments and sets relevant program options. + * + * @param argc The number of command line arguments. + * @param argv An array of strings representing the command line arguments. + * @return A character pointer to the remaining command line arguments as a single string. + */ +char *parse_command_line_arguments(int argc, char *argv[]); +#endif //RUNWHENIDLE_ARGUMENTS_PARSING_H diff --git a/main.c b/main.c index ecc29f7..a6857b1 100644 --- a/main.c +++ b/main.c @@ -3,15 +3,13 @@ #include #include #include -#include -#include -#include #include #include "sleep_utils.h" #include "time_utils.h" #include "tty_utils.h" #include "process_handling.h" +#include "arguments_parsing.h" #ifndef VERSION #define VERSION 'unkown' @@ -25,10 +23,6 @@ long start_monitor_after_ms = 300; long unsigned user_idle_timeout_ms = 300000; long long polling_interval_ms = 1000; const long long POLLING_INTERVAL_BEFORE_STARTING_MONITORING_MS = 100; -const long TIMEOUT_MAX_SUPPORTED_VALUE = 100000000; //~3 years -const long TIMEOUT_MIN_SUPPORTED_VALUE = 1; -const long START_MONITOR_AFTER_MAX_SUPPORTED_VALUE = TIMEOUT_MAX_SUPPORTED_VALUE*1000; -const long START_MONITOR_AFTER_MIN_SUPPORTED_VALUE = 0; int xscreensaver_is_available; Display *x_display; @@ -40,55 +34,6 @@ volatile sig_atomic_t command_paused = 0; pid_t pid; -void print_usage(char *binary_name) { - printf("Usage: %s [OPTIONS] shell_command_to_run [shell_command_arguments]\n", binary_name); - printf("\nOptions:\n"); - printf(" --timeout, -t Set the user idle time after which the command can run in seconds (default: 300 seconds).\n"); - printf(" --start-monitor-after, -a Set an initial delay in milliseconds before monitoring starts. During this time command runs unrestricted. This helps to catch quick errors. (default: 300 ms).\n"); - printf(" --verbose, -v Enable verbose output for monitoring.\n"); - printf(" --debug Enable debugging output.\n"); - printf(" --quiet, -q Suppress all program output except errors.\n"); - printf(" --version, -V Print the program version information.\n"); -} -void print_version() { - printf("runwhenidle %s\n", VERSION); -} - -char *read_remaining_arguments_as_char(int argc, - char *const *argv) { - if (optind == argc) { //there is one argument remaining - char *last_and_only_argument = strdup(argv[optind]); - return last_and_only_argument; - } - - size_t memory_to_be_allocated_for_remaining_arguments_string = 0; - for (int i = optind; i < argc; i++) { - memory_to_be_allocated_for_remaining_arguments_string += - strlen(argv[i]) + 1; // +1 for space separator or null terminator - } - - char *remaining_arguments_string = NULL; // Variable to store the remaining_arguments_string - - // Allocate memory for the remaining_arguments_string - remaining_arguments_string = malloc(memory_to_be_allocated_for_remaining_arguments_string); - if (remaining_arguments_string == NULL) { - //not using fprintf_error here intentionally - fprintf(stderr, "Failed to allocate memory while parsing command to be ran.\n"); - exit(1); - } - - size_t current_length_of_all_arguments = 0; - for (int i = optind; i < argc; i++) { - size_t current_argument_length = strlen(argv[i]); - memcpy(remaining_arguments_string + current_length_of_all_arguments, argv[i], current_argument_length); - current_length_of_all_arguments += current_argument_length; - remaining_arguments_string[current_length_of_all_arguments++] = ' '; // Add space separator - } - assert(current_length_of_all_arguments == memory_to_be_allocated_for_remaining_arguments_string); - remaining_arguments_string[current_length_of_all_arguments - 1] = '\0'; // Replace the last space separator with a null terminator - - return remaining_arguments_string; -} long unsigned query_user_idle_time() { if (xscreensaver_is_available) { @@ -186,88 +131,6 @@ long long pause_or_resume_command_depending_on_user_activity( return sleep_time_ms; } -char *parse_command_line_arguments(int argc, char *argv[]) {// Define command line options - struct option long_options[] = { - {"timeout", required_argument, NULL, 't'}, - {"start-monitor-after", required_argument, NULL, 'a'}, - {"verbose", no_argument, NULL, 'v'}, - {"debug", no_argument, NULL, 'd'}, - {"quiet", no_argument, NULL, 'q'}, - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'V'}, - {NULL, 0, NULL, 0} - }; - - // Parse command line options - int option; - while ((option = getopt_long(argc, argv, "+hvqt:a:V", long_options, NULL)) != -1) { - switch (option) { - case 't': { - - long timeout_arg_value = strtol(optarg, NULL, 10); - if (timeout_arg_value < TIMEOUT_MIN_SUPPORTED_VALUE || - timeout_arg_value > TIMEOUT_MAX_SUPPORTED_VALUE || errno != 0) { - fprintf_error("Invalid timeout value: \"%s\". Range supported: %ld-%ld", optarg, - TIMEOUT_MIN_SUPPORTED_VALUE, TIMEOUT_MAX_SUPPORTED_VALUE); - print_usage(argv[0]); - exit(1); - } - user_idle_timeout_ms = timeout_arg_value * 1000; - break; - } - case 'a': { - start_monitor_after_ms = strtol(optarg, NULL, 10); - - if (start_monitor_after_ms < START_MONITOR_AFTER_MIN_SUPPORTED_VALUE || errno != 0) { - fprintf_error( "Invalid start-monitor-after time value: \"%s\" Range supported: %ld-%ld.\n", optarg, - START_MONITOR_AFTER_MIN_SUPPORTED_VALUE, START_MONITOR_AFTER_MAX_SUPPORTED_VALUE - ); - print_usage(argv[0]); - exit(1); - } - break; - } - case 'V': - print_version(); - exit(0); - case 'v': - verbose = 1; - break; - case 'd': - debug = 1; - verbose = 1; - break; - case 'q': - quiet = 1; - break; - case 'h': - print_usage(argv[0]); - exit(0); - break; - default: - print_usage(argv[0]); - exit(1); - } - } - if (debug) fprintf(stderr, "verbose: %i, debug: %i, quiet: %i, user_idle_timeout_ms: %i, start_monitoring_after_ms: %lld\n", verbose, debug, quiet, user_idle_timeout_ms, start_monitor_after_ms); - if (optind >= argc) { - print_usage(argv[0]); - exit(1); - } - if (quiet && debug) { - fprintf_error("Incompatible options --quiet|-q and --debug used"); - print_usage(argv[0]); - exit(1); - } - if (quiet && verbose) { - fprintf_error("Incompatible options --quiet|-q and --verbose|-v used"); - print_usage(argv[0]); - exit(1); - } - - return read_remaining_arguments_as_char(argc, argv); -} - int main(int argc, char *argv[]) { char *shell_command_to_run = parse_command_line_arguments(argc, argv);