Thumbnail

rani/cscroll.git

Clone URL: https://git.buni.party/rani/cscroll.git

commit 49cf60f5104b24b5c11cff96110086935f08018e Author: rani <clagv.randomgames@gmail.com> Date: Mon Dec 29 23:32:26 2025 +0000 Add: cvector library; Add: some directory code 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); +}