1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
#ifndef __VXGG_REWRITE___SHARED_H___3880294315821___
#define __VXGG_REWRITE___SHARED_H___3880294315821___
#include <stddef.h>
#define STATIC_ARRAY_LEN(arr) (sizeof((arr))/sizeof((arr)[0]))
#define FALSE 0
#define TRUE 1
#define RETURNWERR(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)
// Whether to use `XALLOC` or normal `malloc` functions for acquiring new memory via the `VALLOC()` macro. `> 0`
// enables XALLOC functionality
#define ___VXGG___USE_XALLOC_FOR_VALLOC___ 0
#define VALLOC(nmemb, size) ((___VXGG___USE_XALLOC_FOR_VALLOC___ > 0) ? xmalloc((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)
// `malloc()` with error checking. Calls `exit()` or `abort()` on error, depending on the value of `___VXGG___XALLOC_EXIT_ON_ERROR___`
void * xmalloc(size_t size);
// `calloc()` with error checking. Calls `exit()` or `abort()` on error, depending on the value of `___VXGG___XALLOC_EXIT_ON_ERROR___`
void * xcalloc(size_t nmemb, size_t size);
// `reallocarray()` with error checking. Calls `exit()` or `abort()` on error, depending on the value of `___VXGG___XALLOC_EXIT_ON_ERROR___`
void * xreallocarray(void *ptr, size_t nmemb, size_t size);
// Read the entire contents of a file descriptor into a malloc()'ed buffer
int rwbuf(char **str, unsigned long int initsize, int fd);
// Write the entire contents of a buffer into a file descriptor
int wwbuf(int fd, const unsigned char *buf, int len);
// `dirname()` reimplementation that returns a malloc()'ed string. According to the `x___` naming scheme, exits/aborts on alloc error.
char * xdirname(const char * const path);
// Cleanup callback. Should act like `free()`, in that it doesn't crash if the pointer it's given is null
typedef void (*cleanup_callback)(void*);
// Cleanup struct. Stores a STATICALLY defined array of callbacks and void* arguments
typedef struct cl {
cleanup_callback *funcs;
void **args;
int size;
int used;
} cleanup;
// Initialize a local cleanup stack. `loc`, `funcs` and `args` need to be locally defined, non allocated arrays, and must be at least `size` elements large
int cleanup_init(cleanup * const loc, int size, cleanup_callback funcs[], void *args[]);
// Register a cleanup callback for a given cleanup object
int cleanup_register(cleanup * const loc, cleanup_callback cb, void *arg);
// Register a cleanup callback, if and only if `flag == 0`
int cleanup_cndregister(cleanup * const loc, unsigned char flag, cleanup_callback cb, void *arg);
// Clear the contents of a cleanup stack
int cleanup_clear(cleanup * const loc);
// Get the top callback without removing it from the cleanup stack
cleanup_callback cleanup_peekf(cleanup * const loc);
// Get and remove the top callback from the cleanup stack. Does not return the argument for the given callback
cleanup_callback cleanup_popf(cleanup * const loc);
// Get the top argument without removing it from the cleanup stack
void * cleanup_peeka(cleanup * const loc);
// Get and remove the top argument from the cleanup stack. Does not return the callback it was to be fed into
void * cleanup_popa(cleanup * const loc);
// Fire all the callbacks in the cleanup stack
int cleanup_fire(cleanup * const loc);
/* Cleanup environment creator. Automatically defines the variables `__CLEANUP`, `__CLEANUP_FUNCS`, and `__CLEANUP_ARGS` and initializes
// via `cleanup_init()` using these variables. */
#define cleanup_CREATE(size) \
cleanup __CLEANUP; \
cleanup_callback __CLEANUP_FUNCS[(size)]; \
void *__CLEANUP_ARGS[(size)]; \
unsigned char __FLAG = 0; \
cleanup_init(&__CLEANUP, (size), __CLEANUP_FUNCS, __CLEANUP_ARGS)
#define cleanup_REGISTER(cb, arg) cleanup_register(&__CLEANUP, (cb), (arg))
#define cleanup_CNDREGISTER(cb, arg) cleanup_cndregister(&__CLEANUP, __FLAG, (cb), (arg))
#define cleanup_CLEAR() cleanup_clear(&__CLEANUP)
#define cleanup_PEEKF() cleanup_peekf(&__CLEANUP)
#define cleanup_POPF() cleanup_popf(&__CLEANUP)
#define cleanup_PEEKA() cleanup_peeka(&__CLEANUP)
#define cleanup_POPA() cleanup_popa(&__CLEANUP)
#define cleanup_FIRE() cleanup_fire(&__CLEANUP)
#define cleanup_MARK() (__FLAG = 1)
#define cleanup_UNMARK() (__FLAG = 0)
#define cleanup_ERRORFLAGGED (__FLAG != 0)
#endif
|