summaryrefslogtreecommitdiff
path: root/src/shared.h
blob: 3ff7b2d31c4ae0adc348e8381d5e32b84ec585c6 (plain)
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
#ifndef __VXGG_REWRITE___SHARED_H___3880294315821___
#define __VXGG_REWRITE___SHARED_H___3880294315821___ 1

#include <stddef.h>

typedef int (*gcallback)(void*);    // Generic callback signature
typedef void (*fcallback)(void*);   // free()-like callback signature

#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)


#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)

// 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
char * vxdirname(const char * const path);



// A locally defined structure designed for easier function cleanup
typedef struct cl {
    fcallback *callbacks;   // Actual Type: fcallback callbacks[]
    void * *arguments;      // Actual Type: void *arguments[]
    int size;
    int used;
} cleanup;

int cleanup_init(cleanup *loc, fcallback callbacks[], void *arguments[], int size);
int cleanup_register(cleanup *loc, fcallback cb, void *arg);
int cleanup_cndregister(cleanup *loc, fcallback cb, void *arg, unsigned char flag);
int cleanup_clear(cleanup *loc);
int cleanup_fire(cleanup *loc);
int cleanup_cndfire(cleanup *loc, unsigned char flag);

#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))

#define cleanup_REGISTER(cb, arg)       cleanup_register(&__CLEANUP, (cb), (arg))
#define cleanup_CNDREGISTER(cb, arg)    cleanup_cndregister(&__CLEANUP, (cb), (arg), __FLAG)
#define cleanup_CLEAR()                 cleanup_clear(&__CLEANUP)
#define cleanup_FIRE()                  cleanup_fire(&__CLEANUP)
#define cleanup_CNDFIRE()               cleanup_cndfire(&__CLEANUP, __FLAG)
#define cleanup_MARK()                  (__FLAG = 1)
#define cleanup_UNMARK()                (__FLAG = 0)
#define cleanup_ERRORFLAGGED            (__FLAG != 0)
#define cleanup_CNDEXEC(code)           while(!cleanup_ERRORFLAGGED) {code; break;}

#endif