commit 49cf60f5104b24b5c11cff96110086935f08018e
Author: rani <clagv.randomgames@gmail.com>
Date: Mon Dec 29 23:32:26 2025 +0000
diff --git a/include/cvector.h b/include/cvector.h
new file mode 100644
index 0000000..fec3c6b
--- /dev/null
+++ b/include/cvector.h
@@ -00 +1507 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Evan Teran
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef CVECTOR_H_
+#define CVECTOR_H_
+/**
+ * @copyright Copyright (c) 2015 Evan Teran,
+ * License: The MIT License (MIT)
+ * @brief cvector heap implemented using C library malloc()
+ * @file cvector.h
+ */
+
+/* in case C library malloc() needs extra protection,
+ * allow these defines to be overridden.
+ */
+/* functions for allocation and deallocation need to correspond to each other, fall back to C library functions if not all are overridden */
+#if !defined(cvector_clib_free) || !defined(cvector_clib_malloc) || !defined(cvector_clib_calloc) || !defined(cvector_clib_realloc)
+#ifdef cvector_clib_free
+#undef cvector_clib_free
+#endif
+#ifdef cvector_clib_malloc
+#undef cvector_clib_malloc
+#endif
+#ifdef cvector_clib_calloc
+#undef cvector_clib_calloc
+#endif
+#ifdef cvector_clib_realloc
+#undef cvector_clib_realloc
+#endif
+#include <stdlib.h>
+#define cvector_clib_free free
+#define cvector_clib_malloc malloc
+#define cvector_clib_calloc calloc
+#define cvector_clib_realloc realloc
+#endif
+/* functions independent of memory allocation */
+#ifndef cvector_clib_assert
+#include <assert.h> /* for assert */
+#define cvector_clib_assert assert
+#endif
+#ifndef cvector_clib_memcpy
+#include <string.h> /* for memcpy */
+#define cvector_clib_memcpy memcpy
+#endif
+#ifndef cvector_clib_memmove
+#include <string.h> /* for memmove */
+#define cvector_clib_memmove memmove
+#endif
+
+/* NOTE: Similar to C's qsort and bsearch, you will receive a T*
+ * for a vector of Ts. This means that you cannot use `free` directly
+ * as a destructor. Instead if you have for example a cvector_vector_type(int *)
+ * you will need to supply a function which casts `elem_ptr` to an `int**`
+ * and then does a free on what that pointer points to:
+ *
+ * ex:
+ *
+ * void free_int(void *p) { free(*(int **)p); }
+ */
+typedef void (*cvector_elem_destructor_t)(void *elem_ptr);
+
+typedef struct cvector_metadata_t {
+ size_t size;
+ size_t capacity;
+ cvector_elem_destructor_t elem_destructor;
+} cvector_metadata_t;
+
+/**
+ * @brief cvector_vector_type - The vector type used in this library
+ * @param type The type of vector to act on.
+ */
+#define cvector_vector_type(type) type *
+
+/**
+ * @brief cvector - Syntactic sugar to retrieve a vector type
+ * @param type The type of vector to act on.
+ */
+#define cvector(type) cvector_vector_type(type)
+
+/**
+ * @brief cvector_iterator - The iterator type used for cvector
+ * @param type The type of iterator to act on.
+ */
+#define cvector_iterator(type) cvector_vector_type(type)
+
+/**
+ * @brief cvector_vec_to_base - For internal use, converts a vector pointer to a metadata pointer
+ * @param vec - the vector
+ * @return the metadata pointer of the vector
+ * @internal
+ */
+#define cvector_vec_to_base(vec) \
+ (&((cvector_metadata_t *)(void *)(vec))[-1])
+
+/**
+ * @brief cvector_base_to_vec - For internal use, converts a metadata pointer to a vector pointer
+ * @param ptr - pointer to the metadata
+ * @return the vector
+ * @internal
+ */
+#define cvector_base_to_vec(ptr) \
+ ((void *)&((cvector_metadata_t *)(ptr))[1])
+
+/**
+ * @brief cvector_capacity - gets the current capacity of the vector
+ * @param vec - the vector
+ * @return the capacity as a size_t
+ */
+#define cvector_capacity(vec) \
+ ((vec) ? cvector_vec_to_base(vec)->capacity : (size_t)0)
+
+/**
+ * @brief cvector_size - gets the current size of the vector
+ * @param vec - the vector
+ * @return the size as a size_t
+ */
+#define cvector_size(vec) \
+ ((vec) ? cvector_vec_to_base(vec)->size : (size_t)0)
+
+/**
+ * @brief cvector_elem_destructor - get the element destructor function used
+ * to clean up elements
+ * @param vec - the vector
+ * @return the function pointer as cvector_elem_destructor_t
+ */
+#define cvector_elem_destructor(vec) \
+ ((vec) ? cvector_vec_to_base(vec)->elem_destructor : NULL)
+
+/**
+ * @brief cvector_empty - returns non-zero if the vector is empty
+ * @param vec - the vector
+ * @return non-zero if empty, zero if non-empty
+ */
+#define cvector_empty(vec) \
+ (cvector_size(vec) == 0)
+
+/**
+ * @brief cvector_reserve - Requests that the vector capacity be at least enough
+ * to contain n elements. If n is greater than the current vector capacity, the
+ * function causes the container to reallocate its storage increasing its
+ * capacity to n (or greater).
+ * @param vec - the vector
+ * @param n - Minimum capacity for the vector.
+ * @return void
+ */
+#define cvector_reserve(vec, n) \
+ do { \
+ size_t cv_reserve_cap__ = cvector_capacity(vec); \
+ if (cv_reserve_cap__ < (n)) { \
+ cvector_grow((vec), (n)); \
+ } \
+ } while (0)
+
+/**
+ * @brief cvector_init - Initialize a vector. The vector must be NULL for this to do anything.
+ * @param vec - the vector
+ * @param capacity - vector capacity to reserve
+ * @param elem_destructor_fn - element destructor function
+ * @return void
+ */
+#define cvector_init(vec, capacity, elem_destructor_fn) \
+ do { \
+ if (!(vec)) { \
+ cvector_reserve((vec), capacity); \
+ cvector_set_elem_destructor((vec), (elem_destructor_fn)); \
+ } \
+ } while (0)
+
+/**
+ * @brief cvector_erase - removes the element at index i from the vector
+ * @param vec - the vector
+ * @param i - index of element to remove
+ * @return void
+ */
+#define cvector_erase(vec, i) \
+ do { \
+ if (vec) { \
+ const size_t cv_erase_sz__ = cvector_size(vec); \
+ if ((i) < cv_erase_sz__) { \
+ cvector_elem_destructor_t cv_erase_elem_dtor__ = cvector_elem_destructor(vec); \
+ if (cv_erase_elem_dtor__) { \
+ cv_erase_elem_dtor__(&(vec)[i]); \
+ } \
+ cvector_set_size((vec), cv_erase_sz__ - 1); \
+ cvector_clib_memmove( \
+ (vec) + (i), \
+ (vec) + (i) + 1, \
+ sizeof(*(vec)) * (cv_erase_sz__ - 1 - (i))); \
+ } \
+ } \
+ } while (0)
+
+/**
+ * @brief cvector_clear - erase all of the elements in the vector
+ * @param vec - the vector
+ * @return void
+ */
+#define cvector_clear(vec) \
+ do { \
+ if (vec) { \
+ cvector_elem_destructor_t cv_clear_elem_dtor__ = cvector_elem_destructor(vec); \
+ if (cv_clear_elem_dtor__) { \
+ size_t cv_clear_i__; \
+ for (cv_clear_i__ = 0; cv_clear_i__ < cvector_size(vec); ++cv_clear_i__) { \
+ cv_clear_elem_dtor__(&(vec)[cv_clear_i__]); \
+ } \
+ } \
+ cvector_set_size(vec, 0); \
+ } \
+ } while (0)
+
+/**
+ * @brief cvector_free - frees all memory associated with the vector
+ * @param vec - the vector
+ * @return void
+ */
+#define cvector_free(vec) \
+ do { \
+ if (vec) { \
+ void *cv_free_p__ = cvector_vec_to_base(vec); \
+ cvector_elem_destructor_t cv_free_elem_dtor__ = cvector_elem_destructor(vec); \
+ if (cv_free_elem_dtor__) { \
+ size_t cv_free_i__; \
+ for (cv_free_i__ = 0; cv_free_i__ < cvector_size(vec); ++cv_free_i__) { \
+ cv_free_elem_dtor__(&(vec)[cv_free_i__]); \
+ } \
+ } \
+ cvector_clib_free(cv_free_p__); \
+ } \
+ } while (0)
+
+/**
+ * @brief cvector_begin - returns an iterator to first element of the vector
+ * @param vec - the vector
+ * @return a pointer to the first element (or NULL)
+ */
+#define cvector_begin(vec) \
+ (vec)
+
+/**
+ * @brief cvector_end - returns an iterator to one past the last element of the vector
+ * @param vec - the vector
+ * @return a pointer to one past the last element (or NULL)
+ */
+#define cvector_end(vec) \
+ ((vec) ? &((vec)[cvector_size(vec)]) : NULL)
+
+/* user request to use linear growth algorithm */
+#ifdef CVECTOR_LINEAR_GROWTH
+
+/**
+ * @brief cvector_compute_next_grow - returns an the computed size in next vector grow
+ * size is increased by 1
+ * @param size - current size
+ * @return size after next vector grow
+ */
+#define cvector_compute_next_grow(size) \
+ ((size) + 1)
+
+#else
+
+/**
+ * @brief cvector_compute_next_grow - returns an the computed size in next vector grow
+ * size is increased by multiplication of 2
+ * @param size - current size
+ * @return size after next vector grow
+ */
+#define cvector_compute_next_grow(size) \
+ ((size) ? ((size) << 1) : 1)
+
+#endif /* CVECTOR_LINEAR_GROWTH */
+
+/**
+ * @brief cvector_push_back - adds an element to the end of the vector
+ * @param vec - the vector
+ * @param value - the value to add
+ * @return void
+ */
+#define cvector_push_back(vec, value) \
+ do { \
+ size_t cv_push_back_cap__ = cvector_capacity(vec); \
+ if (cv_push_back_cap__ <= cvector_size(vec)) { \
+ cvector_grow((vec), cvector_compute_next_grow(cv_push_back_cap__)); \
+ } \
+ (vec)[cvector_size(vec)] = (value); \
+ cvector_set_size((vec), cvector_size(vec) + 1); \
+ } while (0)
+
+/**
+ * @brief cvector_insert - insert element at position pos to the vector
+ * @param vec - the vector
+ * @param pos - position in the vector where the new elements are inserted.
+ * @param val - value to be copied (or moved) to the inserted elements.
+ * @return void
+ */
+#define cvector_insert(vec, pos, val) \
+ do { \
+ size_t cv_insert_cap__ = cvector_capacity(vec); \
+ if (cv_insert_cap__ <= cvector_size(vec)) { \
+ cvector_grow((vec), cvector_compute_next_grow(cv_insert_cap__)); \
+ } \
+ if ((pos) < cvector_size(vec)) { \
+ cvector_clib_memmove( \
+ (vec) + (pos) + 1, \
+ (vec) + (pos), \
+ sizeof(*(vec)) * ((cvector_size(vec)) - (pos))); \
+ } \
+ (vec)[(pos)] = (val); \
+ cvector_set_size((vec), cvector_size(vec) + 1); \
+ } while (0)
+
+/**
+ * @brief cvector_pop_back - removes the last element from the vector
+ * @param vec - the vector
+ * @return void
+ */
+#define cvector_pop_back(vec) \
+ do { \
+ cvector_elem_destructor_t cv_pop_back_elem_dtor__ = cvector_elem_destructor(vec); \
+ if (cv_pop_back_elem_dtor__) { \
+ cv_pop_back_elem_dtor__(&(vec)[cvector_size(vec) - 1]); \
+ } \
+ cvector_set_size((vec), cvector_size(vec) - 1); \
+ } while (0)
+
+/**
+ * @brief cvector_copy - copy a vector
+ * @param from - the original vector
+ * @param to - destination to which the function copy to
+ * @return void
+ */
+#define cvector_copy(from, to) \
+ do { \
+ if ((from)) { \
+ cvector_grow(to, cvector_size(from)); \
+ cvector_set_size(to, cvector_size(from)); \
+ cvector_clib_memcpy((to), (from), cvector_size(from) * sizeof(*(from))); \
+ } \
+ } while (0)
+
+/**
+ * @brief cvector_swap - exchanges the content of the vector by the content of another vector of the same type
+ * @param vec - the original vector
+ * @param other - the other vector to swap content with
+ * @param type - the type of both vectors
+ * @return void
+ */
+#define cvector_swap(vec, other, type) \
+ do { \
+ if (vec && other) { \
+ cvector_vector_type(type) cv_swap__ = vec; \
+ vec = other; \
+ other = cv_swap__; \
+ } \
+ } while (0)
+
+/**
+ * @brief cvector_set_capacity - For internal use, sets the capacity variable of the vector
+ * @param vec - the vector
+ * @param size - the new capacity to set
+ * @return void
+ * @internal
+ */
+#define cvector_set_capacity(vec, size) \
+ do { \
+ if (vec) { \
+ cvector_vec_to_base(vec)->capacity = (size); \
+ } \
+ } while (0)
+
+/**
+ * @brief cvector_set_size - For internal use, sets the size variable of the vector
+ * @param vec - the vector
+ * @param _size - the new capacity to set
+ * @return void
+ * @internal
+ */
+#define cvector_set_size(vec, _size) \
+ do { \
+ if (vec) { \
+ cvector_vec_to_base(vec)->size = (_size); \
+ } \
+ } while (0)
+
+/**
+ * @brief cvector_set_elem_destructor - set the element destructor function
+ * used to clean up removed elements. The vector must NOT be NULL for this to do anything.
+ * @param vec - the vector
+ * @param elem_destructor_fn - function pointer of type cvector_elem_destructor_t used to destroy elements
+ * @return void
+ */
+#define cvector_set_elem_destructor(vec, elem_destructor_fn) \
+ do { \
+ if (vec) { \
+ cvector_vec_to_base(vec)->elem_destructor = (elem_destructor_fn); \
+ } \
+ } while (0)
+
+/**
+ * @brief cvector_grow - For internal use, ensures that the vector is at least `count` elements big
+ * @param vec - the vector
+ * @param count - the new capacity to set
+ * @return void
+ * @internal
+ */
+#define cvector_grow(vec, count) \
+ do { \
+ const size_t cv_grow_sz__ = (count) * sizeof(*(vec)) + sizeof(cvector_metadata_t); \
+ if (vec) { \
+ void *cv_grow_p1__ = cvector_vec_to_base(vec); \
+ void *cv_grow_p2__ = cvector_clib_realloc(cv_grow_p1__, cv_grow_sz__); \
+ cvector_clib_assert(cv_grow_p2__); \
+ (vec) = cvector_base_to_vec(cv_grow_p2__); \
+ } else { \
+ void *cv_grow_p__ = cvector_clib_malloc(cv_grow_sz__); \
+ cvector_clib_assert(cv_grow_p__); \
+ (vec) = cvector_base_to_vec(cv_grow_p__); \
+ cvector_set_size((vec), 0); \
+ cvector_set_elem_destructor((vec), NULL); \
+ } \
+ cvector_set_capacity((vec), (count)); \
+ } while (0)
+
+/**
+ * @brief cvector_shrink_to_fit - requests the container to reduce its capacity to fit its size
+ * @param vec - the vector
+ * @return void
+ */
+#define cvector_shrink_to_fit(vec) \
+ do { \
+ if (vec) { \
+ const size_t cv_shrink_to_fit_sz__ = cvector_size(vec); \
+ cvector_grow(vec, cv_shrink_to_fit_sz__); \
+ } \
+ } while (0)
+
+/**
+ * @brief cvector_at - returns a reference to the element at position n in the vector.
+ * @param vec - the vector
+ * @param n - position of an element in the vector.
+ * @return the element at the specified position in the vector.
+ */
+#define cvector_at(vec, n) \
+ ((vec) ? (((int)(n) < 0 || (size_t)(n) >= cvector_size(vec)) ? NULL : &(vec)[n]) : NULL)
+
+/**
+ * @brief cvector_front - returns a reference to the first element in the vector. Unlike member cvector_begin, which returns an iterator to this same element, this function returns a direct reference.
+ * @param vec - the vector
+ * @return a reference to the first element in the vector container.
+ */
+#define cvector_front(vec) \
+ ((vec) ? ((cvector_size(vec) > 0) ? cvector_at(vec, 0) : NULL) : NULL)
+
+/**
+ * @brief cvector_back - returns a reference to the last element in the vector.Unlike member cvector_end, which returns an iterator just past this element, this function returns a direct reference.
+ * @param vec - the vector
+ * @return a reference to the last element in the vector.
+ */
+#define cvector_back(vec) \
+ ((vec) ? ((cvector_size(vec) > 0) ? cvector_at(vec, cvector_size(vec) - 1) : NULL) : NULL)
+
+/**
+ * @brief cvector_resize - resizes the container to contain count elements.
+ * @param vec - the vector
+ * @param count - new size of the vector
+ * @param value - the value to initialize new elements with
+ * @return void
+ */
+#define cvector_resize(vec, count, value) \
+ do { \
+ size_t cv_resize_count__ = (size_t)(count); \
+ size_t cv_resize_sz__ = cvector_size(vec); \
+ if (cv_resize_count__ > cv_resize_sz__) { \
+ cvector_reserve((vec), cv_resize_count__); \
+ cvector_set_size((vec), cv_resize_count__); \
+ do { \
+ (vec)[cv_resize_sz__++] = (value); \
+ } while (cv_resize_sz__ < cv_resize_count__); \
+ } else { \
+ while (cv_resize_count__ < cv_resize_sz__--) { \
+ cvector_pop_back(vec); \
+ } \
+ } \
+ } while (0)
+
+#endif /* CVECTOR_H_ */
diff --git a/include/dir.h b/include/dir.h
new file mode 100644
index 0000000..05a360d
--- /dev/null
+++ b/include/dir.h
@@ -00 +132 @@
+#ifndef DIR_H
+#define DIR_H
+
+#include <stddef.h>
+#include "cvector.h"
+
+enum de_type {
+ DE_FILE,
+ DE_DIR,
+ DE_FIFO,
+ DE_LINK,
+ DE_BLOCK,
+ DE_CHAR,
+ DE_SOCKET,
+ DE_UNKNOWN
+};
+
+typedef struct {
+ enum de_type type;
+ size_t size;
+ char * name;
+} dirent_t;
+
+typedef struct {
+ size_t len;
+ cvector(dirent_t) entries;
+} dir_t;
+
+int dir_list(const char * path, dir_t * dir);
+void dir_free(dir_t * dir);
+
+#endif /* DIR_H */
diff --git a/src/dir.c b/src/dir.c
new file mode 100644
index 0000000..11c12e0
--- /dev/null
+++ b/src/dir.c
@@ -00 +172 @@
+#include <sys/stat.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "dir.h"
+#include "cvector.h"
+
+
+static void dir_entry(int dirfd, const char * name, dirent_t * dirent);
+static void free_dirent(void * p) {
+ free(((dirent_t*)p)->name);
+}
+
+int dir_list(const char * path, dir_t * dir) {
+ dir->len = 0;
+ dir->entries = NULL;
+ cvector_init(dir->entries, 1, free_dirent);
+
+ struct dirent * de;
+ DIR * dp = opendir(path);
+ if (!dp) {
+ return -1;
+ }
+
+ while ((de = readdir(dp))) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
+ continue;
+ }
+
+ dirent_t dirent;
+ dir_entry(dirfd(dp), de->d_name, &dirent);
+ cvector_push_back(dir->entries, dirent);
+ dir->len++;
+ }
+
+ closedir(dp);
+
+ return 0;
+}
+
+void dir_entry(int dirfd, const char * name, dirent_t * dirent) {
+ dirent->type = DE_UNKNOWN;
+ dirent->size = 0;
+ dirent->name = NULL;
+
+ dirent->name = strdup(name);
+
+ struct stat statbuf;
+ if (fstatat(dirfd, name, &statbuf, AT_SYMLINK_NOFOLLOW) < 0) {
+ return;
+ }
+
+ // convert the ugly st_mode to a nice de_type
+ switch (statbuf.st_mode & S_IFMT) {
+ case S_IFSOCK: dirent->type = DE_SOCKET; break;
+ case S_IFLNK: dirent->type = DE_LINK; break;
+ case S_IFREG: dirent->type = DE_FILE; break;
+ case S_IFBLK: dirent->type = DE_BLOCK; break;
+ case S_IFDIR: dirent->type = DE_DIR; break;
+ case S_IFCHR: dirent->type = DE_CHAR; break;
+ case S_IFIFO: dirent->type = DE_FIFO; break;
+ default: dirent->type = DE_UNKNOWN; break;
+ }
+
+ dirent->size = statbuf.st_size;
+}
+
+void dir_free(dir_t * dir) {
+ cvector_free(dir->entries);
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..90ac8bd
--- /dev/null
+++ b/src/main.c
@@ -00 +115 @@
+#include <stdio.h>
+#include <stddef.h>
+
+#include "dir.h"
+
+int main(int argc, char ** argv) {
+ dir_t dir;
+ dir_list(argv[1], &dir);
+
+ for (size_t i = 0; i < dir.len; i++) {
+ printf("%lu %s\n", dir.entries[i].size, dir.entries[i].name);
+ }
+
+ dir_free(&dir);
+}