From 33647dd2c4f4af7c7cb7d99c1a6dac7f1d059a67 Mon Sep 17 00:00:00 2001 From: "@syxhe" Date: Mon, 20 Oct 2025 15:51:49 -0500 Subject: Switch to unity build --- src/shared.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 165 insertions(+), 12 deletions(-) (limited to 'src/shared.c') diff --git a/src/shared.c b/src/shared.c index 40732f0..0a2121b 100644 --- a/src/shared.c +++ b/src/shared.c @@ -1,15 +1,65 @@ /** * @file shared.c * @author syxhe (https://t.me/syxhe) - * @brief *Implementing `shared.h`* + * @brief A collection of functions and macros shared between files, or without a better place * @version 0.1 * @date 2025-06-09 - * + * * @copyright Copyright (c) 2025 - * + * */ -#include "shared.h" +#ifndef __VXGG_REWRITE___SHARED_C___3880294315821___ +#define __VXGG_REWRITE___SHARED_C___3880294315821___ 1 + +#define STATIC_ARRAY_LEN(arr) (sizeof((arr))/sizeof((arr)[0])) + +#define ERRRET(errval, retval) do {\ + errno = (errval);\ + return (retval);\ +} while (0) + +/// Defines how `x___alloc()` functions should exit. `___VXGG___XALLOC_EXIT_ON_ERROR___ > 0` calls `error()`, and thus functions +/// registered with `atexit()` and `on_exit()`. `___VXGG___XALLOC_EXIT_ON_ERROR___ <= 0` calls `abort()` on error. `x___alloc()` +/// type functions will ALWAYS 'abort', doing otherwise defeats the purpose of the function type +#define ___VXGG___XALLOC_EXIT_ON_ERROR___ 1 + +/// Defines whether vxgg functions that can error print out a short warning of the error when one is encountered. +/// `___VXGG___VERBOSE_ERRORS___ > 0` will print diagnostic error messages, and will do nothing otherwise +#define ___VXGG___VERBOSE_ERRORS___ 1 + +//! Macro to exit on an alloc error instead of doing the terrible nested if statement that was being used previously +#define XALLOC_EXIT(msg, ...) do {\ + if(!___VXGG___XALLOC_EXIT_ON_ERROR___)\ + abort();\ + if(!___VXGG___VERBOSE_ERRORS___)\ + exit(EXIT_FAILURE);\ + error(EXIT_FAILURE, errno, (msg)__VA_ARGS__);\ + exit(EXIT_FAILURE); /* Makes gcc happy */\ +} while (0) + +//! Holdover macro because I'm lazy. Used to call either malloc or xmalloc, but the xalloc functions were a bad idea, so I removed them +#define VALLOC(nmemb, size) malloc((nmemb) * (size)) + +//! Error macro that gcc will not complain about +#define ERROR(status, errnum, format, ...) do {error((status), (errnum), (format)__VA_ARGS__); exit((status));} while (0) +//! Spit out a warning using `error` +#define WARN(errnum, format, ...) do {error(0, (errnum), (format)__VA_ARGS__);} while (0) + + +typedef int (*gcallback)(void*); //!< Generic callback signature +typedef void (*fcallback)(void*); //!< free()-like callback signature + +/** + * @brief A locally defined structure designed for easier function cleanup + * + */ +typedef struct cl { + fcallback *callbacks; //!< An array of free()-like callbacks. Actual Type: fcallback callbacks[] + void * *arguments; //!< An array of void pointers. Actual Type: void *arguments[] + int size; //!< The size of each array + int used; //!< The current number of used elements in each array +} cleanup; #include #include @@ -17,6 +67,17 @@ #include #include +#include + +/** + * @brief Read the entire contents of a file descriptor into a malloc()'ed buffer + * + * @param str Pointer to a string. Will be replaced with the malloc()'ed string + * @param initsize The initial size of the malloc()'ed string + * @param fd A file descriptor to read from + * @retval (int)[-1, strlen(str)] Returns the size of the array on success, or -1 on error + * @note The allocated buffer will expand and contract as necessary, but it's recommended to set `initsize` to some value close to or equal to the size of the file being read to reduce the number of resizes + */ int rwbuf(char **str, unsigned long int initsize, int fd) { // Try to read bytes from fd into str // Bytes read == 0, return 0 @@ -32,7 +93,7 @@ int rwbuf(char **str, unsigned long int initsize, int fd) { lstr = calloc(initsize, sizeof(char)); if(!lstr) return -1; - + while((bytesread = read(fd, lstr + (csize - ccap), ccap)) > 0) { ccap -= bytesread; if(ccap <= 0) { @@ -43,7 +104,7 @@ int rwbuf(char **str, unsigned long int initsize, int fd) { if(!tmp) { if(___VXGG___VERBOSE_ERRORS___) error(0, errno, "Could not reallocate enough space for lstr"); - + free(lstr); lstr = NULL; // Need to set this because of the break bytesread = ECODE; @@ -81,6 +142,15 @@ int rwbuf(char **str, unsigned long int initsize, int fd) { } +/** + * @brief Write the entire contents of a buffer into a file descriptor + * + * @param fd The file descriptor to write to + * @param buf The buffer to write from + * @param len The length of the buffer + * @retval (int)[-1, 0] Returns 0 on success, -1 on error + */ + int wwbuf(int fd, const unsigned char *buf, int len) { if(!buf || len <= 0) ERRRET(EINVAL, -1); @@ -89,7 +159,7 @@ int wwbuf(int fd, const unsigned char *buf, int len) { int n = -1; while(total < len) { - if((n = write(fd, buf + total, left)) < 0) + if((n = write(fd, buf + total, left)) < 0) break; total += n; @@ -102,7 +172,12 @@ int wwbuf(int fd, const unsigned char *buf, int len) { // https://beej.us/guide/bgnet/html/split/slightly-advanced-techniques.html#sendall // Thanks Beej! -// dirname but less retarded hopefully +/** + * @brief `dirname()` reimplementation that returns a malloc()'ed string + * + * @param path The filepath to be inspected + * @retval (char*)[NULL, char*] Returns a null-terminated string on success, or `null` on error + */ char * vxdirname(const char * const path) { char *tmp = NULL; if(!path) { // Path being null is a special case which should return early, before anything else (as to avoid null dereference) @@ -201,6 +276,15 @@ char * vxdirname(const char * const path) { } +/** + * @brief Initialize a cleanup object + * + * @param loc The cleanup object to be initialized + * @param callbacks An array of free()-like callbacks. Must be `size` elements long + * @param arguments An array of void pointers. Must be `size` elements long + * @param size The number of elements the callbacks and arguments array are long + * @retval (int)[-1, 0] Returns 0 on success, -1 on error + */ int cleanup_init(cleanup *loc, fcallback callbacks[], void *arguments[], int size) { if(!loc || !callbacks || !arguments || size <= 0) ERRRET(EINVAL, -1); @@ -212,6 +296,14 @@ int cleanup_init(cleanup *loc, fcallback callbacks[], void *arguments[], int siz return 0; } +/** + * @brief Register a new callback and argument onto a cleanup stack + * + * @param loc The cleanup object to modify + * @param cb A free()-like callback to run + * @param arg A piece of data for the callback to run + * @retval (int)[-1, 0] Returns 0 on success, -1 on error + */ int cleanup_register(cleanup *loc, fcallback cb, void *arg) { if(!loc || !cb) ERRRET(EINVAL, -1); if(loc->used >= loc->size || loc->used < 0) ERRRET(ENOMEM, -1); @@ -223,18 +315,39 @@ int cleanup_register(cleanup *loc, fcallback cb, void *arg) { return 0; } -// registers if flag is NOT set +/** + * @brief Conditionally register a callback and argument + * + * @param loc The cleanup object to modify + * @param cb A free()-like callback to run + * @param arg A piece of data for the callback to run + * @param flag Whether or not the register should take place. Will not run if `flag` is non-zero + * @retval (int)[-1, 0] Returns 0 on success or skip, -1 on error + */ int cleanup_cndregister(cleanup *loc, fcallback cb, void *arg, unsigned char flag) { if(flag) return 0; return cleanup_register(loc, cb, arg); } +/** + * @brief Clear a cleanup object + * @attention Does not free any registered callbacks or arguments, just marks them as available space + * + * @param loc The cleanup object to modify + * @retval (int)[-1, 0] Returns 0 on success, -1 on error + */ int cleanup_clear(cleanup *loc) { - if(!loc) ERRRET(EINVAL, -1); + if(!loc) ERRRET(EINVAL, -1); loc->used = 0; return 0; } +/** + * @brief Fires all the registered callbacks and arguments in a cleanup object in FIFO (stack) order + * + * @param loc The cleanup object to fire + * @retval (int)[-1, 0] Returns 0 on success, -1 on error + */ int cleanup_fire(cleanup *loc) { if(!loc) ERRRET(EINVAL, -1); @@ -251,9 +364,49 @@ int cleanup_fire(cleanup *loc) { return 0; } -// Fires if flag is set +/** + * @brief Conditionally fires a cleanup object + * + * @param loc The cleanup object in question + * @param flag Whether the object should be fired. Will skip firing if non-zero + * @retval (int)[-1, 0] Returns 0 on success, -1 on error + */ int cleanup_cndfire(cleanup *loc, unsigned char flag) { if(flag) return cleanup_fire(loc); return 0; -} \ No newline at end of file +} + +/** + * @brief Initializes a set of variables suitable for use in the cleanup macros + * @param size The number of elements long each array should be + */ +#define cleanup_CREATE(size) \ +cleanup __CLEANUP; \ +fcallback __CLEANUP_FUNCS[(size)]; \ +void *__CLEANUP_ARGS[(size)]; \ +unsigned char __FLAG = 0; \ +cleanup_init(&__CLEANUP, __CLEANUP_FUNCS, __CLEANUP_ARGS, (size)) + +//! Register a callback-argument pair using the local cleanup object +#define cleanup_REGISTER(cb, arg) cleanup_register(&__CLEANUP, (cb), (arg)) +//! Conditionally register a callback-argument pair using the local cleanup object +#define cleanup_CNDREGISTER(cb, arg) cleanup_cndregister(&__CLEANUP, (cb), (arg), __FLAG) +//! Clean the local cleanup object +#define cleanup_CLEAR() cleanup_clear(&__CLEANUP) +//! Fire the local cleanup object +#define cleanup_FIRE() cleanup_fire(&__CLEANUP) +//! Conditionally fire the local cleanup object +#define cleanup_CNDFIRE() cleanup_cndfire(&__CLEANUP, __FLAG) +//! Set the local cleanup flag to a non-zero number +#define cleanup_MARK() (__FLAG = 1) +//! Set the local cleanup flag to zero +#define cleanup_UNMARK() (__FLAG = 0) +//! Check if the local cleanup flag is non-zero +#define cleanup_ERRORFLAGGED (__FLAG != 0) +//! Conditionally execute some `code` if the local cleanup flag has not been marked +#define cleanup_CNDEXEC(code) while(!cleanup_ERRORFLAGGED) {code; break;} +//! Conditionally fire the local cleanup object and return `ret` +#define cleanup_CNDFIRERET(ret) do {cleanup_CNDFIRE(); return ret;} while (0) + +#endif \ No newline at end of file -- cgit v1.2.3