Compare commits

...

2 commits

Author SHA1 Message Date
e06e65e5e8 Impl. parser accepting files and dirs
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 4s
Fix memory leak in hash_map.

Current "main" prints specified files and subfiles of specified
directories.

TODO: Handle symbolic links
2024-07-03 19:56:26 +09:00
8d912ce780 Remove 'extern' from parser.h 2024-07-03 17:55:35 +09:00
7 changed files with 175 additions and 6 deletions

View file

@ -39,4 +39,7 @@ add_executable(test_simplearchiver
src/test.c
src/parser.c
src/helpers.c
src/algorithms/linear_congruential_gen.c
src/data_structures/linked_list.c
src/data_structures/hash_map.c
)

View file

@ -89,6 +89,11 @@ unsigned long long simple_archiver_hash_map_internal_key_to_hash(
return simple_archiver_algo_lcg_defaults(seed);
}
void simple_archiver_hash_map_internal_no_free_fn(
__attribute__((unused)) void *unused) {
return;
}
/// Returns 0 on success.
int simple_archiver_hash_map_internal_rehash(SDArchiverHashMap **hash_map) {
if (!hash_map || !*hash_map) {
@ -116,7 +121,8 @@ int simple_archiver_hash_map_internal_rehash(SDArchiverHashMap **hash_map) {
simple_archiver_hash_map_insert(&new_hash_map, data->value, data->key,
data->key_size, data->value_cleanup_fn,
data->key_cleanup_fn);
node->data = NULL;
data->key_cleanup_fn = simple_archiver_hash_map_internal_no_free_fn;
data->value_cleanup_fn = simple_archiver_hash_map_internal_no_free_fn;
}
}
}

View file

@ -153,6 +153,19 @@ int main(void) {
}
simple_archiver_hash_map_free(&hash_map);
// Rehash test for Memcheck.
hash_map = simple_archiver_hash_map_init();
for (unsigned int idx = 0; idx < SC_SA_DS_HASH_MAP_START_BUCKET_SIZE + 1;
++idx) {
unsigned int *copy_value = malloc(sizeof(unsigned int));
*copy_value = idx;
unsigned int *copy_key = malloc(sizeof(unsigned int));
*copy_key = idx;
simple_archiver_hash_map_insert(&hash_map, copy_value, copy_key,
sizeof(unsigned int), NULL, NULL);
}
simple_archiver_hash_map_free(&hash_map);
}
// Test PriorityHeap.

View file

@ -20,6 +20,12 @@
#include "parser.h"
int print_list_fn(void *data, __attribute__((unused)) void *ud) {
const char *cstr = data;
printf(" %s\n", cstr);
return 0;
}
int main(int argc, const char **argv) {
simple_archiver_print_usage();
@ -28,5 +34,12 @@ int main(int argc, const char **argv) {
simple_archiver_parse_args(argc, argv, &parsed);
__attribute__((cleanup(simple_archiver_list_free)))
SDArchiverLinkedList *filenames =
simple_archiver_parsed_to_filenames(&parsed);
puts("Filenames:");
simple_archiver_list_get(filenames, print_list_fn, NULL);
return 0;
}

View file

@ -22,7 +22,16 @@
#include <stdlib.h>
#include <string.h>
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif
#include "data_structures/hash_map.h"
#include "data_structures/linked_list.h"
#include "parser_internal.h"
#include "platforms.h"
/// Gets the first non "./"-like character in the filename.
unsigned int simple_archiver_parser_internal_filename_idx(
@ -75,6 +84,22 @@ unsigned int simple_archiver_parser_internal_filename_idx(
return idx;
}
int list_get_last_fn(void *data, void *ud) {
char **last = ud;
*last = data;
return 0;
}
void container_no_free_fn(__attribute__((unused)) void *data) { return; }
int list_remove_same_str_fn(void *data, void *ud) {
if (strcmp((char *)data, (char *)ud) == 0) {
return 1;
}
return 0;
}
void simple_archiver_print_usage(void) {
puts("Usage flags:");
puts("-c : create archive file");
@ -216,3 +241,102 @@ void simple_archiver_free_parsed(SDArchiverParsed *parsed) {
parsed->working_files = NULL;
}
}
SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
const SDArchiverParsed *parsed) {
SDArchiverLinkedList *files_list = simple_archiver_list_init();
__attribute__((cleanup(simple_archiver_hash_map_free)))
SDArchiverHashMap *hash_map = simple_archiver_hash_map_init();
int hash_map_sentinel = 1;
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
for (char **iter = parsed->working_files; iter && *iter; ++iter) {
struct stat st;
stat(*iter, &st);
if ((st.st_mode & S_IFMT) == S_IFREG) {
// Is a regular file.
int len = strlen(*iter) + 1;
char *filename = malloc(len);
strncpy(filename, *iter, len);
if (simple_archiver_hash_map_get(hash_map, filename, len - 1) == NULL) {
simple_archiver_list_add(files_list, filename, NULL);
simple_archiver_hash_map_insert(&hash_map, &hash_map_sentinel, filename,
len - 1, container_no_free_fn,
container_no_free_fn);
} else {
free(filename);
}
} else if ((st.st_mode & S_IFMT) == S_IFDIR) {
// Is a directory. TODO handle this.
__attribute__((cleanup(simple_archiver_list_free)))
SDArchiverLinkedList *dir_list = simple_archiver_list_init();
simple_archiver_list_add(dir_list, *iter, container_no_free_fn);
char *next;
while (dir_list->count != 0) {
simple_archiver_list_get(dir_list, list_get_last_fn, &next);
if (!next) {
break;
}
DIR *dir = opendir(next);
struct dirent *dir_entry;
do {
dir_entry = readdir(dir);
if (dir_entry) {
if (strcmp(dir_entry->d_name, ".") == 0 ||
strcmp(dir_entry->d_name, "..") == 0) {
continue;
}
printf("dir entry in %s is %s\n", next, dir_entry->d_name);
int combined_size = strlen(next) + strlen(dir_entry->d_name) + 2;
char *combined_path = malloc(combined_size);
snprintf(combined_path, combined_size, "%s/%s", next,
dir_entry->d_name);
stat(combined_path, &st);
if ((st.st_mode & S_IFMT) == S_IFREG) {
// Is a file.
if (simple_archiver_hash_map_get(hash_map, combined_path,
combined_size - 1) == NULL) {
simple_archiver_list_add(files_list, combined_path, NULL);
simple_archiver_hash_map_insert(
&hash_map, &hash_map_sentinel, combined_path,
combined_size - 1, container_no_free_fn,
container_no_free_fn);
} else {
free(combined_path);
}
} else if ((st.st_mode & S_IFMT) == S_IFDIR) {
// Is a directory.
simple_archiver_list_add_front(dir_list, combined_path, NULL);
} else {
// Unhandled type.
free(combined_path);
}
}
} while (dir_entry != NULL);
closedir(dir);
if (simple_archiver_list_remove(dir_list, list_remove_same_str_fn,
next) == 0) {
break;
}
}
} else {
// Unhandled type.
}
}
#endif
// Remove leading "./" entries from files_list.
for (SDArchiverLLNode *iter = files_list->head->next;
iter != files_list->tail; iter = iter->next) {
unsigned int idx = simple_archiver_parser_internal_filename_idx(iter->data);
if (idx > 0) {
int len = strlen((char *)iter->data) + 1 - idx;
char *substr = malloc(len);
strncpy(substr, (char *)iter->data + idx, len);
free(iter->data);
iter->data = substr;
}
}
return files_list;
}

View file

@ -19,6 +19,8 @@
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_H_
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_H_
#include "data_structures/linked_list.h"
typedef struct SDArchiverParsed {
/// Each bit is a flag.
/// 0b0 - is creating.
@ -36,16 +38,19 @@ typedef struct SDArchiverParsed {
char **working_files;
} SDArchiverParsed;
extern void simple_archiver_print_usage(void);
void simple_archiver_print_usage(void);
extern SDArchiverParsed simple_archiver_create_parsed(void);
SDArchiverParsed simple_archiver_create_parsed(void);
/// Expects the user to pass a pointer to an SDArchiverParsed.
/// This means the user should have a SDArchiverParsed variable
/// and it should be passed with e.g. "&var".
extern int simple_archiver_parse_args(int argc, const char **argv,
SDArchiverParsed *out);
int simple_archiver_parse_args(int argc, const char **argv,
SDArchiverParsed *out);
extern void simple_archiver_free_parsed(SDArchiverParsed *parsed);
void simple_archiver_free_parsed(SDArchiverParsed *parsed);
SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
const SDArchiverParsed *parsed);
#endif

View file

@ -17,6 +17,9 @@
* compiled for.
*/
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_PLATFORMS_H_
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_PLATFORMS_H_
// Determine platform macros
#define SIMPLE_ARCHIVER_PLATFORM_WINDOWS 1
#define SIMPLE_ARCHIVER_PLATFORM_MAC 2
@ -35,3 +38,5 @@
#else
#define SIMPLE_ARCHIVER_PLATFORM SIMPLE_ARCHIVER_PLATFORM_UNKNOWN
#endif
#endif