]> git.seodisparate.com - SimpleArchiver/commitdiff
Impl. parser accepting files and dirs
authorStephen Seo <seo.disparate@gmail.com>
Wed, 3 Jul 2024 10:54:44 +0000 (19:54 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Wed, 3 Jul 2024 10:56:26 +0000 (19:56 +0900)
Fix memory leak in hash_map.

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

TODO: Handle symbolic links

CMakeLists.txt
src/data_structures/hash_map.c
src/data_structures/test.c
src/main.c
src/parser.c
src/parser.h
src/platforms.h

index 2b73cb7d011070811c14ce974b08f1e2c1951312..920355470bcb68bcb0affab45e5da96c04402809 100644 (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
 )
index d1f04d1f2a89621ac46d2989976f3c3f3722fbf1..2a5ec6bdd511970b1548808e0cd5fb3a39c3b8cf 100644 (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;
       }
     }
   }
index e5299a6fd8bd5865e37bfdbb636bab3adec63b7c..5d5915644e76f54096eb46fb1a54d117081c04c8 100644 (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.
index 6bb753c6efd7b52c20f12159794dca6d3819ce75..1b12eee3f6445494209d367907f4fa4545fad41a 100644 (file)
 
 #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;
 }
index 0a31d3fb78ec70a907c33b98b1e434be2d5b758c..409d0b2897ff04ac62bdee1ac64835b9394d33ff 100644 (file)
 #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;
+}
index 1dc9175881adfe63e187547cae11825c690f5e9f..73cc7caada6d820b2467c3e11a4c7e42e5d51b4a 100644 (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.
@@ -48,4 +50,7 @@ int simple_archiver_parse_args(int argc, const char **argv,
 
 void simple_archiver_free_parsed(SDArchiverParsed *parsed);
 
+SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
+    const SDArchiverParsed *parsed);
+
 #endif
index c7fd36a3c667b6b7aa780ce194f2b166087a4521..76a3e668f0d50032277129340060008c75b0c379 100644 (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