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
|
#ifndef ARCHIVE_H
|
||||||
#define ARCHIVE_H
|
#define ARCHIVE_H
|
||||||
|
|
||||||
|
#include "tar.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/* @brief Archives the listed `files` into `archive_name`
|
/* @brief Archives the listed `files` into `archive_name`
|
||||||
* @return 0 on success, the corresponding error code otherwise
|
* @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
|
#endif // ARCHIVE_H
|
||||||
|
|
|
||||||
|
|
@ -9,116 +9,179 @@
|
||||||
|
|
||||||
static void print_files_array(char **input_files)
|
static void print_files_array(char **input_files)
|
||||||
{
|
{
|
||||||
|
if (input_files == NULL)
|
||||||
|
{
|
||||||
|
puts(" (none)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
while (*input_files != NULL)
|
while (*input_files != NULL)
|
||||||
{
|
{
|
||||||
printf(" - ");
|
printf(" - %s\n", *input_files);
|
||||||
puts(*input_files);
|
|
||||||
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)
|
switch (opt)
|
||||||
{
|
{
|
||||||
// Archive mode
|
case 'h':
|
||||||
|
return ARG_HELP;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
if (cfg->mode != UNDEFINED)
|
if (cfg->mode != UNDEFINED)
|
||||||
return ARG_INVALID;
|
return ARG_INVALID;
|
||||||
cfg->mode = ARCHIVE;
|
cfg->mode = ARCHIVE;
|
||||||
return ARG_ARCHIVE;
|
return ARG_VALID;
|
||||||
|
|
||||||
// Extract mode
|
|
||||||
case 'x':
|
case 'x':
|
||||||
if (cfg->mode != UNDEFINED)
|
if (cfg->mode != UNDEFINED)
|
||||||
return ARG_INVALID;
|
return ARG_INVALID;
|
||||||
cfg->mode = EXTRACT;
|
cfg->mode = EXTRACT;
|
||||||
break;
|
return ARG_VALID;
|
||||||
|
|
||||||
|
case 'v':
|
||||||
|
cfg->verbose = true;
|
||||||
|
return ARG_VALID;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return ARG_INVALID;
|
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;
|
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
|
if (config == NULL || argv == NULL)
|
||||||
{ "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);
|
|
||||||
return ARG_INVALID;
|
return ARG_INVALID;
|
||||||
|
|
||||||
case ARG_HELP:
|
// Init config
|
||||||
print_usage();
|
config->mode = UNDEFINED;
|
||||||
config_destroy(config);
|
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;
|
return ARG_HELP;
|
||||||
|
}
|
||||||
default:
|
if (err != ARG_VALID)
|
||||||
print_usage();
|
{
|
||||||
config_destroy(config);
|
|
||||||
return ARG_INVALID;
|
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",
|
printf("Mode: %s\n",
|
||||||
config->mode == EXTRACT ? "EXTRACT"
|
config->mode == EXTRACT ? "EXTRACT"
|
||||||
: config->mode == ARCHIVE ? "ARCHIVE"
|
: config->mode == ARCHIVE ? "ARCHIVE"
|
||||||
: "UNDEFINED");
|
: "UNDEFINED");
|
||||||
|
|
||||||
|
printf("Archive file: %s\n",
|
||||||
|
config->archive_file ? config->archive_file : "NULL");
|
||||||
|
|
||||||
printf("Input file(s):\n");
|
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);
|
print_files_array(config->input_files);
|
||||||
else
|
else
|
||||||
puts("-> NULL");
|
puts(" (none)");
|
||||||
|
|
||||||
printf("Verbose: %B\n", config->verbose);
|
printf("Verbose: %s\n", config->verbose ? "true" : "false");
|
||||||
printf("Show help message: %B\n", config->show_help);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_usage(void)
|
void print_usage(void)
|
||||||
{
|
{
|
||||||
puts("Usage: epitar -[xcvh] <file.tar> [<files>]");
|
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)
|
void print_invalid_option(void)
|
||||||
|
|
@ -129,12 +192,16 @@ void print_invalid_option(void)
|
||||||
|
|
||||||
void config_destroy(struct config *config)
|
void config_destroy(struct config *config)
|
||||||
{
|
{
|
||||||
char **current_str = config->input_files;
|
if (config == NULL)
|
||||||
while (current_str != NULL && *current_str != 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);
|
free(config);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
#ifndef ARGS_H
|
#ifndef CONFIG_H
|
||||||
#define ARGS_H
|
#define CONFIG_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#define ARG_VALID 0
|
enum arg_error_code
|
||||||
#define ARG_INVALID 1
|
{
|
||||||
#define ARG_HELP 2
|
ARG_VALID = 0,
|
||||||
#define ARG_ARCHIVE 3
|
ARG_INVALID,
|
||||||
|
ARG_HELP,
|
||||||
|
};
|
||||||
|
|
||||||
enum tar_mode
|
enum operation_mode
|
||||||
{
|
{
|
||||||
UNDEFINED,
|
UNDEFINED,
|
||||||
EXTRACT,
|
EXTRACT,
|
||||||
|
|
@ -19,15 +21,13 @@ enum tar_mode
|
||||||
struct config
|
struct config
|
||||||
{
|
{
|
||||||
/* Defines what action the program will perform */
|
/* Defines what action the program will perform */
|
||||||
enum tar_mode mode;
|
enum operation_mode mode;
|
||||||
/* File(s) to archive/extract */
|
/* Archive file name */
|
||||||
|
char *archive_file;
|
||||||
|
/* File(s) to archive (Archive mode only) */
|
||||||
char **input_files;
|
char **input_files;
|
||||||
/* Program output after archiving */
|
|
||||||
char *output_file;
|
|
||||||
/* Enable or disable verbose mode */
|
/* Enable or disable verbose mode */
|
||||||
bool verbose;
|
bool verbose;
|
||||||
/* Show the help message */
|
|
||||||
bool show_help;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -38,19 +38,25 @@ struct config
|
||||||
* This function will handle the memory allocation.
|
* This function will handle the memory allocation.
|
||||||
* @return 0 on success, non-zero on failure.
|
* @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.
|
/** Prints the parsed arguments for debugging purposes.
|
||||||
* @param options Pointer to args_options structure containing parsed options.
|
* @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_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
|
#ifndef EXTRACT_H
|
||||||
#define EXTRACT_H
|
#define EXTRACT_H
|
||||||
|
|
||||||
|
#include "tar.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/* @brief Extract and write files from `archive_name`
|
/* @brief Extract and write files from `archive_name`
|
||||||
* @return 0 on success, the corresponding error code otherwise
|
* @return 0 on success, the corresponding error code otherwise
|
||||||
*/
|
*/
|
||||||
int extract(char *archive_name);
|
int extract(char *archive_name, bool verbose);
|
||||||
|
|
||||||
#endif // EXTRACT_H
|
#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