hey mme pavoshko

This commit is contained in:
Gu://em_ 2026-04-06 21:12:22 +02:00
parent def6ecb013
commit d5a774a533
5 changed files with 205 additions and 91 deletions

View file

@ -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

View file

@ -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] <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);
}
free(config->input_files);
// Note: archive_file points to argv, so we don't free it
free(config);
}

View file

@ -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 */

View file

@ -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

View file

@ -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;
}