diff --git a/epitar/src/archive.h b/epitar/src/archive.h index f1cdeaa..4556fa7 100644 --- a/epitar/src/archive.h +++ b/epitar/src/archive.h @@ -1,9 +1,13 @@ #ifndef ARCHIVE_H #define ARCHIVE_H +#include "tar.h" + +#include + /* @brief Archives the listed `files` into `archive_name` * @return 0 on success, the corresponding error code otherwise */ -int archive(char *archive_name, char **files); +int archive(char *archive_name, char **files, bool verbose); #endif // ARCHIVE_H diff --git a/epitar/src/config.c b/epitar/src/config.c index 9b50f94..e2d82c6 100644 --- a/epitar/src/config.c +++ b/epitar/src/config.c @@ -9,116 +9,179 @@ static void print_files_array(char **input_files) { + if (input_files == NULL) + { + puts(" (none)"); + return; + } while (*input_files != NULL) { - printf(" - "); - puts(*input_files); + printf(" - %s\n", *input_files); input_files++; } } -// Returns the corresponding ARG_* macro -static int handle_opt(char **argv, char opt, struct config *cfg) +/** + * Handle a single option flag + */ +static int handle_opt(char opt, struct config *cfg) { - // Options without value - // Help - if (opt == 'h') - return ARG_HELP; - - // Options with value - - if (optarg == NULL) - return ARG_INVALID; - switch (opt) { - // Archive mode + case 'h': + return ARG_HELP; + case 'c': if (cfg->mode != UNDEFINED) return ARG_INVALID; cfg->mode = ARCHIVE; - return ARG_ARCHIVE; + return ARG_VALID; - // Extract mode case 'x': if (cfg->mode != UNDEFINED) return ARG_INVALID; cfg->mode = EXTRACT; - break; + return ARG_VALID; + + case 'v': + cfg->verbose = true; + return ARG_VALID; default: return ARG_INVALID; } +} + +/** + * + */ +bool validate_config(struct config *cfg) +{ + // Must have a valid mode + if (cfg->mode == UNDEFINED) + return false; + + // Must have an archive file specified + if (cfg->archive_file == NULL) + return false; + + return true; +} + +enum arg_error_code args_handler(int argc, char **argv, struct config *config) +{ + if (config == NULL || argv == NULL) + return ARG_INVALID; + + // Init config + config->mode = UNDEFINED; + config->archive_file = NULL; + config->input_files = NULL; + config->verbose = false; + + // Parse option flags + int opt; + while ((opt = getopt(argc, argv, "cxvh")) != -1) + { + int err = handle_opt(opt, config); + if (err == ARG_HELP) + { + return ARG_HELP; + } + if (err != ARG_VALID) + { + return ARG_INVALID; + } + } + + int remaining_args = argc - optind; + // Need at least the archive file + if (remaining_args < 1) + { + return ARG_INVALID; + } + + // First argument is the archive file + config->archive_file = argv[optind]; + // Remaining arguments are input files (for archive mode) + int num_input_files = remaining_args - 1; + + if (num_input_files > 0) + { + if (config->mode == EXTRACT) + return ARG_INVALID; + + // Allocate input files array (+ NULL terminator) + config->input_files = malloc((num_input_files + 1) * sizeof(char *)); + if (config->input_files == NULL) + return ARG_INVALID; + + // SHallow copy names pointers + for (int i = 0; i < num_input_files; i++) + { + config->input_files[i] = argv[optind + 1 + i]; + } + + // NULL terminator + config->input_files[num_input_files] = NULL; + } + else + { + // For consistency + config->input_files = malloc(sizeof(char *)); + if (config->input_files == NULL) + return ARG_INVALID; + config->input_files[0] = NULL; + } + + // Validate config + if (!validate_config(config)) + return ARG_INVALID; return ARG_VALID; } -// Returns true if config is valid, false otherwise -static bool check_config(struct config *cfg) +void print_config(const struct config *config) { - // TODO - return true; -} - -int args_handler(int argc, char **argv, struct config *config) -{ - struct option options[] = { // Global - { "archive", required_argument, NULL, 'c' }, - { "extract", required_argument, NULL, 'x' }, - { "verbose", no_argument, NULL, 'v' }, - { "help", no_argument, NULL, 'h' }, - // End - { NULL, 0, NULL, 0 } - }; - - config = calloc(1, sizeof(struct config)); - - char opt; - int optindex = 0; - while ((opt = getopt_long(argc, argv, "cxvh", options, &optindex)) != -1) + if (config == NULL) { - int err = handle_opt(argv, opt, config); - switch (err) - { - case ARG_VALID: - if (check_config(config)) - return ARG_VALID; - config_destroy(config); - return ARG_INVALID; - - case ARG_HELP: - print_usage(); - config_destroy(config); - return ARG_HELP; - - default: - print_usage(); - config_destroy(config); - return ARG_INVALID; - } + puts("Config is NULL"); + return; } -} -void print_config(struct config *config) -{ printf("Mode: %s\n", config->mode == EXTRACT ? "EXTRACT" : config->mode == ARCHIVE ? "ARCHIVE" : "UNDEFINED"); + printf("Archive file: %s\n", + config->archive_file ? config->archive_file : "NULL"); + printf("Input file(s):\n"); - if (config->input_files) + if (config->input_files != NULL && config->input_files[0] != NULL) print_files_array(config->input_files); else - puts("-> NULL"); + puts(" (none)"); - printf("Verbose: %B\n", config->verbose); - printf("Show help message: %B\n", config->show_help); + printf("Verbose: %s\n", config->verbose ? "true" : "false"); } void print_usage(void) { puts("Usage: epitar -[xcvh] []"); + // printf("\n"); + // printf("Options:\n"); + // printf(" -c Create an archive\n"); + // printf(" -x Extract an archive\n"); + // printf(" -v Verbose output\n"); + // printf(" -h Show this help message\n"); + // printf("\n"); + // printf("Examples:\n"); + // printf(" epitar -c archive.tar file1 file2 Create archive with + // files\n"); printf(" epitar -cv archive.tar file1 Create archive + // (verbose)\n"); printf(" epitar -x archive.tar Extract + // archive\n"); printf(" epitar -xv archive.tar Extract + // archive (verbose)\n"); } void print_invalid_option(void) @@ -129,12 +192,16 @@ void print_invalid_option(void) void config_destroy(struct config *config) { - char **current_str = config->input_files; - while (current_str != NULL && *current_str != NULL) + if (config == NULL) + return; + + // Free input files array + if (config->input_files != NULL) { - free(*current_str); - current_str++; + free(config->input_files); } - free(config->input_files); + + // Note: archive_file points to argv, so we don't free it + free(config); } diff --git a/epitar/src/config.h b/epitar/src/config.h index b898358..c429c96 100644 --- a/epitar/src/config.h +++ b/epitar/src/config.h @@ -1,15 +1,17 @@ -#ifndef ARGS_H -#define ARGS_H +#ifndef CONFIG_H +#define CONFIG_H #include #include -#define ARG_VALID 0 -#define ARG_INVALID 1 -#define ARG_HELP 2 -#define ARG_ARCHIVE 3 +enum arg_error_code +{ + ARG_VALID = 0, + ARG_INVALID, + ARG_HELP, +}; -enum tar_mode +enum operation_mode { UNDEFINED, EXTRACT, @@ -19,15 +21,13 @@ enum tar_mode struct config { /* Defines what action the program will perform */ - enum tar_mode mode; - /* File(s) to archive/extract */ + enum operation_mode mode; + /* Archive file name */ + char *archive_file; + /* File(s) to archive (Archive mode only) */ char **input_files; - /* Program output after archiving */ - char *output_file; /* Enable or disable verbose mode */ bool verbose; - /* Show the help message */ - bool show_help; }; /** @@ -38,19 +38,25 @@ struct config * This function will handle the memory allocation. * @return 0 on success, non-zero on failure. */ -int args_handler(int argc, char **argv, struct config *config); +enum arg_error_code args_handler(int argc, char **argv, struct config *config); /** Prints the parsed arguments for debugging purposes. * @param options Pointer to args_options structure containing parsed options. */ -void print_config(struct config *config); +void print_config(const struct config *config); -/* Prints the usage information for the program. +/* Prints the different information messages for the program. */ void print_usage(void); +void print_invalid_option(void); + +/* @brief Check if the config is valid + * @return true if valid, false otherwise + */ +bool validate_config(struct config *cfg); /* */ -void config_destroy(struct config *config); +void destroy_config(struct config *config); -#endif /* ARGS_H */ +#endif /* CONFIG_H */ diff --git a/epitar/src/extract.h b/epitar/src/extract.h index ad6f6df..de7f903 100644 --- a/epitar/src/extract.h +++ b/epitar/src/extract.h @@ -1,9 +1,13 @@ #ifndef EXTRACT_H #define EXTRACT_H +#include "tar.h" + +#include + /* @brief Extract and write files from `archive_name` * @return 0 on success, the corresponding error code otherwise */ -int extract(char *archive_name); +int extract(char *archive_name, bool verbose); #endif // EXTRACT_H diff --git a/epitar/src/main.c b/epitar/src/main.c index 8b13789..1184ebf 100644 --- a/epitar/src/main.c +++ b/epitar/src/main.c @@ -1 +1,34 @@ +#include "archive.h" +#include "config.h" +#include "extract.h" +int main(int argc, char **argv) +{ + // Handle args + struct config config; + enum arg_error_code err = args_handler(argc, argv, &config); + switch (err) + { + case ARG_VALID: + break; + + case ARG_INVALID: + print_invalid_option(); + return 1; + + case ARG_HELP: + print_usage(); + return 0; + } + + if (config.mode == EXTRACT) + { + extract(config.archive_file, config.verbose); + } + else if (config.mode == ARCHIVE) + { + archive(config.archive_file, config.input_files, config.verbose); + } + + return 0; +}