This is just an example of how it might work. Any constructive criticism? I did not feel that typedefs added anything to the readability of the code.
Is it even possible to declare and use a generic function pointer with a variable number of arguments of different types?
Code:
#include <stdio.h>
#include <stdlib.h>
#define MAX_CLEANUP_STACK_SIZE 200
/*
** The stack for our cleanup implementation.
**
** The stack pointer points to the top of the
** stack, i.e. the last element that got pushed onto the stack is
** cleanup_stack_ptr - 1.
*/
struct cleanup_handler
{
void (*func)(void *arg);
void *arg;
};
struct cleanup_handler cleanup_stack[MAX_CLEANUP_STACK_SIZE];
unsigned int cleanup_stack_ptr = 0;
/*
** Push a cleanup frame onto the stack.
**
** A frame begins by setting the member variable func of the cleanup_handler
** struct to NULL.
*/
void cleanup_push_frame(void)
{
cleanup_stack[cleanup_stack_ptr].func = NULL;
cleanup_stack[cleanup_stack_ptr].arg = NULL;
if (cleanup_stack_ptr+1 > MAX_CLEANUP_STACK_SIZE) {
fprintf(stderr, "Warning: cleanup_stack is full\n");
} else {
++cleanup_stack_ptr;
}
}
/*
** Push a frame onto the stack.
*/
void cleanup_push_func(void (*func)(void *arg), void *arg)
{
cleanup_stack[cleanup_stack_ptr].func =func;
cleanup_stack[cleanup_stack_ptr].arg = arg;
/* This should NEVER happen! */
if (cleanup_stack_ptr+1 > MAX_CLEANUP_STACK_SIZE) {
fprintf(stderr, "Warning: cleanup_stack is full\n");
} else {
++cleanup_stack_ptr;
}
}
/*
** Call all cleanup handlers in the current stack frame, and then remove the
** frame from the stack.
*/
void cleanup_pop_frame(void)
{
if (cleanup_stack_ptr != 0) {
--cleanup_stack_ptr;
}
while (cleanup_stack_ptr > 0 &&
cleanup_stack[cleanup_stack_ptr].func != NULL) {
cleanup_stack[cleanup_stack_ptr].func(
cleanup_stack[cleanup_stack_ptr].arg);
--cleanup_stack_ptr;
}
}
/*
** Pop all frames from the stack.
*/
void cleanup_pop_all(void)
{
while (cleanup_stack_ptr > 0) {
cleanup_pop_frame();
}
}
void foo(int *i)
{
printf("%d\n", *i);
}
void bar(float *f)
{
printf("%f\n", *f);
}
int main(void)
{
int i = 1;
float b = 2;
cleanup_push_frame();
cleanup_push_func((void *)foo, &i);
cleanup_push_func((void *)bar, &b);
cleanup_pop_all();
return(EXIT_SUCCESS);
}