summaryrefslogtreecommitdiff
path: root/src/shared.c
diff options
context:
space:
mode:
author@syxhe <https://t.me/syxhe>2025-10-20 15:51:49 -0500
committer@syxhe <https://t.me/syxhe>2025-10-20 15:51:49 -0500
commit33647dd2c4f4af7c7cb7d99c1a6dac7f1d059a67 (patch)
tree12925795f7ecc39e566ff78f18c3bfab5539e32f /src/shared.c
parentd5de3e243a8481ad879dd8effc5759d406dc90b7 (diff)
Switch to unity build
Diffstat (limited to 'src/shared.c')
-rw-r--r--src/shared.c177
1 files changed, 165 insertions, 12 deletions
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 @@
1/** 1/**
2 * @file shared.c 2 * @file shared.c
3 * @author syxhe (https://t.me/syxhe) 3 * @author syxhe (https://t.me/syxhe)
4 * @brief *Implementing `shared.h`* 4 * @brief A collection of functions and macros shared between files, or without a better place
5 * @version 0.1 5 * @version 0.1
6 * @date 2025-06-09 6 * @date 2025-06-09
7 * 7 *
8 * @copyright Copyright (c) 2025 8 * @copyright Copyright (c) 2025
9 * 9 *
10 */ 10 */
11 11
12#include "shared.h" 12#ifndef __VXGG_REWRITE___SHARED_C___3880294315821___
13#define __VXGG_REWRITE___SHARED_C___3880294315821___ 1
14
15#define STATIC_ARRAY_LEN(arr) (sizeof((arr))/sizeof((arr)[0]))
16
17#define ERRRET(errval, retval) do {\
18 errno = (errval);\
19 return (retval);\
20} while (0)
21
22/// Defines how `x___alloc()` functions should exit. `___VXGG___XALLOC_EXIT_ON_ERROR___ > 0` calls `error()`, and thus functions
23/// registered with `atexit()` and `on_exit()`. `___VXGG___XALLOC_EXIT_ON_ERROR___ <= 0` calls `abort()` on error. `x___alloc()`
24/// type functions will ALWAYS 'abort', doing otherwise defeats the purpose of the function type
25#define ___VXGG___XALLOC_EXIT_ON_ERROR___ 1
26
27/// Defines whether vxgg functions that can error print out a short warning of the error when one is encountered.
28/// `___VXGG___VERBOSE_ERRORS___ > 0` will print diagnostic error messages, and will do nothing otherwise
29#define ___VXGG___VERBOSE_ERRORS___ 1
30
31//! Macro to exit on an alloc error instead of doing the terrible nested if statement that was being used previously
32#define XALLOC_EXIT(msg, ...) do {\
33 if(!___VXGG___XALLOC_EXIT_ON_ERROR___)\
34 abort();\
35 if(!___VXGG___VERBOSE_ERRORS___)\
36 exit(EXIT_FAILURE);\
37 error(EXIT_FAILURE, errno, (msg)__VA_ARGS__);\
38 exit(EXIT_FAILURE); /* Makes gcc happy */\
39} while (0)
40
41//! 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
42#define VALLOC(nmemb, size) malloc((nmemb) * (size))
43
44//! Error macro that gcc will not complain about
45#define ERROR(status, errnum, format, ...) do {error((status), (errnum), (format)__VA_ARGS__); exit((status));} while (0)
46//! Spit out a warning using `error`
47#define WARN(errnum, format, ...) do {error(0, (errnum), (format)__VA_ARGS__);} while (0)
48
49
50typedef int (*gcallback)(void*); //!< Generic callback signature
51typedef void (*fcallback)(void*); //!< free()-like callback signature
52
53/**
54 * @brief A locally defined structure designed for easier function cleanup
55 *
56 */
57typedef struct cl {
58 fcallback *callbacks; //!< An array of free()-like callbacks. Actual Type: fcallback callbacks[]
59 void * *arguments; //!< An array of void pointers. Actual Type: void *arguments[]
60 int size; //!< The size of each array
61 int used; //!< The current number of used elements in each array
62} cleanup;
13 63
14#include <stdlib.h> 64#include <stdlib.h>
15#include <string.h> 65#include <string.h>
@@ -17,6 +67,17 @@
17#include <errno.h> 67#include <errno.h>
18#include <error.h> 68#include <error.h>
19 69
70#include <threads.h>
71
72/**
73 * @brief Read the entire contents of a file descriptor into a malloc()'ed buffer
74 *
75 * @param str Pointer to a string. Will be replaced with the malloc()'ed string
76 * @param initsize The initial size of the malloc()'ed string
77 * @param fd A file descriptor to read from
78 * @retval (int)[-1, strlen(str)] Returns the size of the array on success, or -1 on error
79 * @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
80 */
20int rwbuf(char **str, unsigned long int initsize, int fd) { 81int rwbuf(char **str, unsigned long int initsize, int fd) {
21 // Try to read bytes from fd into str 82 // Try to read bytes from fd into str
22 // Bytes read == 0, return 0 83 // Bytes read == 0, return 0
@@ -32,7 +93,7 @@ int rwbuf(char **str, unsigned long int initsize, int fd) {
32 lstr = calloc(initsize, sizeof(char)); 93 lstr = calloc(initsize, sizeof(char));
33 if(!lstr) 94 if(!lstr)
34 return -1; 95 return -1;
35 96
36 while((bytesread = read(fd, lstr + (csize - ccap), ccap)) > 0) { 97 while((bytesread = read(fd, lstr + (csize - ccap), ccap)) > 0) {
37 ccap -= bytesread; 98 ccap -= bytesread;
38 if(ccap <= 0) { 99 if(ccap <= 0) {
@@ -43,7 +104,7 @@ int rwbuf(char **str, unsigned long int initsize, int fd) {
43 if(!tmp) { 104 if(!tmp) {
44 if(___VXGG___VERBOSE_ERRORS___) 105 if(___VXGG___VERBOSE_ERRORS___)
45 error(0, errno, "Could not reallocate enough space for lstr"); 106 error(0, errno, "Could not reallocate enough space for lstr");
46 107
47 free(lstr); 108 free(lstr);
48 lstr = NULL; // Need to set this because of the break 109 lstr = NULL; // Need to set this because of the break
49 bytesread = ECODE; 110 bytesread = ECODE;
@@ -81,6 +142,15 @@ int rwbuf(char **str, unsigned long int initsize, int fd) {
81} 142}
82 143
83 144
145/**
146 * @brief Write the entire contents of a buffer into a file descriptor
147 *
148 * @param fd The file descriptor to write to
149 * @param buf The buffer to write from
150 * @param len The length of the buffer
151 * @retval (int)[-1, 0] Returns 0 on success, -1 on error
152 */
153
84int wwbuf(int fd, const unsigned char *buf, int len) { 154int wwbuf(int fd, const unsigned char *buf, int len) {
85 if(!buf || len <= 0) ERRRET(EINVAL, -1); 155 if(!buf || len <= 0) ERRRET(EINVAL, -1);
86 156
@@ -89,7 +159,7 @@ int wwbuf(int fd, const unsigned char *buf, int len) {
89 int n = -1; 159 int n = -1;
90 160
91 while(total < len) { 161 while(total < len) {
92 if((n = write(fd, buf + total, left)) < 0) 162 if((n = write(fd, buf + total, left)) < 0)
93 break; 163 break;
94 164
95 total += n; 165 total += n;
@@ -102,7 +172,12 @@ int wwbuf(int fd, const unsigned char *buf, int len) {
102// https://beej.us/guide/bgnet/html/split/slightly-advanced-techniques.html#sendall 172// https://beej.us/guide/bgnet/html/split/slightly-advanced-techniques.html#sendall
103 // Thanks Beej! 173 // Thanks Beej!
104 174
105// dirname but less retarded hopefully 175/**
176 * @brief `dirname()` reimplementation that returns a malloc()'ed string
177 *
178 * @param path The filepath to be inspected
179 * @retval (char*)[NULL, char*] Returns a null-terminated string on success, or `null` on error
180 */
106char * vxdirname(const char * const path) { 181char * vxdirname(const char * const path) {
107 char *tmp = NULL; 182 char *tmp = NULL;
108 if(!path) { // Path being null is a special case which should return early, before anything else (as to avoid null dereference) 183 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) {
201} 276}
202 277
203 278
279/**
280 * @brief Initialize a cleanup object
281 *
282 * @param loc The cleanup object to be initialized
283 * @param callbacks An array of free()-like callbacks. Must be `size` elements long
284 * @param arguments An array of void pointers. Must be `size` elements long
285 * @param size The number of elements the callbacks and arguments array are long
286 * @retval (int)[-1, 0] Returns 0 on success, -1 on error
287 */
204int cleanup_init(cleanup *loc, fcallback callbacks[], void *arguments[], int size) { 288int cleanup_init(cleanup *loc, fcallback callbacks[], void *arguments[], int size) {
205 if(!loc || !callbacks || !arguments || size <= 0) ERRRET(EINVAL, -1); 289 if(!loc || !callbacks || !arguments || size <= 0) ERRRET(EINVAL, -1);
206 290
@@ -212,6 +296,14 @@ int cleanup_init(cleanup *loc, fcallback callbacks[], void *arguments[], int siz
212 return 0; 296 return 0;
213} 297}
214 298
299/**
300 * @brief Register a new callback and argument onto a cleanup stack
301 *
302 * @param loc The cleanup object to modify
303 * @param cb A free()-like callback to run
304 * @param arg A piece of data for the callback to run
305 * @retval (int)[-1, 0] Returns 0 on success, -1 on error
306 */
215int cleanup_register(cleanup *loc, fcallback cb, void *arg) { 307int cleanup_register(cleanup *loc, fcallback cb, void *arg) {
216 if(!loc || !cb) ERRRET(EINVAL, -1); 308 if(!loc || !cb) ERRRET(EINVAL, -1);
217 if(loc->used >= loc->size || loc->used < 0) ERRRET(ENOMEM, -1); 309 if(loc->used >= loc->size || loc->used < 0) ERRRET(ENOMEM, -1);
@@ -223,18 +315,39 @@ int cleanup_register(cleanup *loc, fcallback cb, void *arg) {
223 return 0; 315 return 0;
224} 316}
225 317
226// registers if flag is NOT set 318/**
319 * @brief Conditionally register a callback and argument
320 *
321 * @param loc The cleanup object to modify
322 * @param cb A free()-like callback to run
323 * @param arg A piece of data for the callback to run
324 * @param flag Whether or not the register should take place. Will not run if `flag` is non-zero
325 * @retval (int)[-1, 0] Returns 0 on success or skip, -1 on error
326 */
227int cleanup_cndregister(cleanup *loc, fcallback cb, void *arg, unsigned char flag) { 327int cleanup_cndregister(cleanup *loc, fcallback cb, void *arg, unsigned char flag) {
228 if(flag) return 0; 328 if(flag) return 0;
229 return cleanup_register(loc, cb, arg); 329 return cleanup_register(loc, cb, arg);
230} 330}
231 331
332/**
333 * @brief Clear a cleanup object
334 * @attention Does not free any registered callbacks or arguments, just marks them as available space
335 *
336 * @param loc The cleanup object to modify
337 * @retval (int)[-1, 0] Returns 0 on success, -1 on error
338 */
232int cleanup_clear(cleanup *loc) { 339int cleanup_clear(cleanup *loc) {
233 if(!loc) ERRRET(EINVAL, -1); 340 if(!loc) ERRRET(EINVAL, -1);
234 loc->used = 0; 341 loc->used = 0;
235 return 0; 342 return 0;
236} 343}
237 344
345/**
346 * @brief Fires all the registered callbacks and arguments in a cleanup object in FIFO (stack) order
347 *
348 * @param loc The cleanup object to fire
349 * @retval (int)[-1, 0] Returns 0 on success, -1 on error
350 */
238int cleanup_fire(cleanup *loc) { 351int cleanup_fire(cleanup *loc) {
239 if(!loc) ERRRET(EINVAL, -1); 352 if(!loc) ERRRET(EINVAL, -1);
240 353
@@ -251,9 +364,49 @@ int cleanup_fire(cleanup *loc) {
251 return 0; 364 return 0;
252} 365}
253 366
254// Fires if flag is set 367/**
368 * @brief Conditionally fires a cleanup object
369 *
370 * @param loc The cleanup object in question
371 * @param flag Whether the object should be fired. Will skip firing if non-zero
372 * @retval (int)[-1, 0] Returns 0 on success, -1 on error
373 */
255int cleanup_cndfire(cleanup *loc, unsigned char flag) { 374int cleanup_cndfire(cleanup *loc, unsigned char flag) {
256 if(flag) 375 if(flag)
257 return cleanup_fire(loc); 376 return cleanup_fire(loc);
258 return 0; 377 return 0;
259} \ No newline at end of file 378}
379
380/**
381 * @brief Initializes a set of variables suitable for use in the cleanup macros
382 * @param size The number of elements long each array should be
383 */
384#define cleanup_CREATE(size) \
385cleanup __CLEANUP; \
386fcallback __CLEANUP_FUNCS[(size)]; \
387void *__CLEANUP_ARGS[(size)]; \
388unsigned char __FLAG = 0; \
389cleanup_init(&__CLEANUP, __CLEANUP_FUNCS, __CLEANUP_ARGS, (size))
390
391//! Register a callback-argument pair using the local cleanup object
392#define cleanup_REGISTER(cb, arg) cleanup_register(&__CLEANUP, (cb), (arg))
393//! Conditionally register a callback-argument pair using the local cleanup object
394#define cleanup_CNDREGISTER(cb, arg) cleanup_cndregister(&__CLEANUP, (cb), (arg), __FLAG)
395//! Clean the local cleanup object
396#define cleanup_CLEAR() cleanup_clear(&__CLEANUP)
397//! Fire the local cleanup object
398#define cleanup_FIRE() cleanup_fire(&__CLEANUP)
399//! Conditionally fire the local cleanup object
400#define cleanup_CNDFIRE() cleanup_cndfire(&__CLEANUP, __FLAG)
401//! Set the local cleanup flag to a non-zero number
402#define cleanup_MARK() (__FLAG = 1)
403//! Set the local cleanup flag to zero
404#define cleanup_UNMARK() (__FLAG = 0)
405//! Check if the local cleanup flag is non-zero
406#define cleanup_ERRORFLAGGED (__FLAG != 0)
407//! Conditionally execute some `code` if the local cleanup flag has not been marked
408#define cleanup_CNDEXEC(code) while(!cleanup_ERRORFLAGGED) {code; break;}
409//! Conditionally fire the local cleanup object and return `ret`
410#define cleanup_CNDFIRERET(ret) do {cleanup_CNDFIRE(); return ret;} while (0)
411
412#endif \ No newline at end of file