hey mme pavoshko
This commit is contained in:
parent
def6ecb013
commit
d5a774a533
5 changed files with 205 additions and 91 deletions
|
|
@ -1,9 +1,13 @@
|
|||
#ifndef ARCHIVE_H
|
||||
#define ARCHIVE_H
|
||||
|
||||
#include "tar.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* @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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
return ARG_VALID;
|
||||
}
|
||||
|
||||
// Returns true if config is valid, false otherwise
|
||||
static bool check_config(struct config *cfg)
|
||||
/**
|
||||
*
|
||||
*/
|
||||
bool validate_config(struct config *cfg)
|
||||
{
|
||||
// TODO
|
||||
// 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;
|
||||
}
|
||||
|
||||
int args_handler(int argc, char **argv, struct config *config)
|
||||
enum arg_error_code 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)
|
||||
{
|
||||
int err = handle_opt(argv, opt, config);
|
||||
switch (err)
|
||||
{
|
||||
case ARG_VALID:
|
||||
if (check_config(config))
|
||||
return ARG_VALID;
|
||||
config_destroy(config);
|
||||
if (config == NULL || argv == NULL)
|
||||
return ARG_INVALID;
|
||||
|
||||
case ARG_HELP:
|
||||
print_usage();
|
||||
config_destroy(config);
|
||||
// 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;
|
||||
|
||||
default:
|
||||
print_usage();
|
||||
config_destroy(config);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
void print_config(struct config *config)
|
||||
// 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;
|
||||
}
|
||||
|
||||
void print_config(const struct config *config)
|
||||
{
|
||||
if (config == NULL)
|
||||
{
|
||||
puts("Config is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
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] <file.tar> [<files>]");
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Note: archive_file points to argv, so we don't free it
|
||||
|
||||
free(config);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
#ifndef ARGS_H
|
||||
#define ARGS_H
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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 */
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
#ifndef EXTRACT_H
|
||||
#define EXTRACT_H
|
||||
|
||||
#include "tar.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* @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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue