codepad
[
create a new paste
]
login
|
about
Language:
C
C++
D
Haskell
Lua
OCaml
PHP
Perl
Plain Text
Python
Ruby
Scheme
Tcl
/* * To split into separate files, remove all * lines containing 'ALL_IN_ONE' */ #define ALL_IN_ONE 1 /**** * cleanup.h * 2011, Shao Miller */ #ifndef CLEANUP_H_ #include <stddef.h> /*** Macros */ #define CLEANUP_H_ /** * Block cleanup details */ #define CLEANUP_BLOCK_ cleanup_do_(cleanup_); /** * Function cleanup details */ #define CLEANUP_FUNC_ cleanup_chain_(cleanup_); /** * Perform block cleanup and jump to a label. * Only use for jumping from an inner to an * outer scope. * Note the trailing space after 'goto'. */ #define c_goto \ switch (1) \ while (1) \ if (0) { \ default: { \ CLEANUP_BLOCK_; \ } \ } else \ goto /** * Perform block cleanup and continue a loop */ #define c_continue \ if (1) { \ CLEANUP_BLOCK_; \ continue; \ } else do ; while (0) /** * Perform block cleanup and break out of a * a loop or 'switch' statement */ #define c_break \ if (1) { \ CLEANUP_BLOCK_; \ break; \ } else do ; while (0) /** * Perform function cleanup and return from * a function. * Note the trailing space after 'return' */ #define c_return \ switch (1) \ while (1) \ if (0) { \ default: { \ CLEANUP_FUNC_; \ } \ } else \ return /** * An integer constant expression which * declares an enumeration value that is one * greater than the same-name enumeration * value in the containing scope. This * is for internal use; don't use it */ #define CV_CLEANUP_ ((enum { \ cv_cleanup_ = cv_cleanup_ + 1 \ })1) /** * This macro establishes cleanup context for * a function or compound statement. Use it * only where declarations are allowed, such as * at the beginning of a function or compound * statement in C89. */ #define HAS_CLEANUP \ cleanup_t_ \ new_cleanup_[CV_CLEANUP_] = {{0}}, \ * p_new_cleanup_ = cleanup_init_( \ new_cleanup_, \ cleanup_, \ cv_cleanup_ \ ), \ * cleanup_ = p_new_cleanup_ #ifndef ALL_IN_ONE /* Wrap malloc */ #ifdef malloc #undef malloc #endif #define malloc(size) c_malloc_(cleanup_, (size)) #endif /* ALL_IN_ONE */ /*** Constants */ enum { cv_cleanup_ }; /*** Object types */ /* Internal use; don't use it */ struct s_cleanup_ { struct s_cleanup_ * prev; void * item; }; typedef struct s_cleanup_ cleanup_t_; /*** Objects */ /** * Top-level cleanup context (empty). * Internal use; don't use it */ extern cleanup_t_ cleanup_[1]; /*** Functions */ /* Internal use; don't use these */ extern cleanup_t_ * cleanup_init_( cleanup_t_ *, cleanup_t_ *, int ); extern void * c_malloc_(cleanup_t_ *, size_t); extern void cleanup_do_(cleanup_t_ *); extern void cleanup_chain_(cleanup_t_ *); #endif /* CLEANUP_H_ */ /**** * cleanup.c * 2011, Shao Miller */ #include <stdlib.h> #include <stdio.h> #ifndef ALL_IN_ONE #include "cleanup.h" #endif /* ALL_IN_ONE */ /*** Object types */ /* A cleanable item */ struct s_cleanup_item_ { void * ref; struct s_cleanup_item_ * next; }; typedef struct s_cleanup_item_ s_cleanup_item; /*** Objects */ cleanup_t_ cleanup_[1] = {{0, 0}}; /*** Functions */ cleanup_t_ * cleanup_init_( cleanup_t_ * new, cleanup_t_ * prev, int level ) { new->prev = prev; return new; } void * c_malloc_( cleanup_t_ * cleanup, size_t size ) { s_cleanup_item * item; void * obj; item = (malloc)(sizeof *item); if (!item) return item; obj = (malloc)(size); if (!obj) { free(item); return obj; } item->ref = obj; /* Insert at beginning */ item->next = cleanup->item; cleanup->item = item; return obj; } static char * at_root(cleanup_t_ * cleanup) { if (cleanup == cleanup_) return " (root)"; return ""; } void cleanup_do_(cleanup_t_ * cleanup) { s_cleanup_item * item, * next; printf( "Cleanup @ %p%s\n", (void *) cleanup, at_root(cleanup) ); item = cleanup->item; cleanup->item = 0; while (item) { next = item->next; printf("Freeing object @ %p\n", item->ref); free(item->ref); free(item); item = next; } return; } void cleanup_chain_(cleanup_t_ * cleanup) { printf( "Cleaning chain @ %p%s\n", (void *) cleanup, at_root(cleanup) ); while (cleanup) { cleanup_t_ * next; cleanup_do_(cleanup); next = cleanup->prev; cleanup->prev = 0; cleanup = next; } return; } /**** Test program */ #ifndef ALL_IN_ONE #include <stdio.h> #include "cleanup.h" #endif /* ALL_IN_ONE */ #ifndef malloc /* Wrap malloc the same as cleanup.h does */ #ifdef malloc #undef malloc #endif #define malloc(size) c_malloc_(cleanup_, (size)) #endif /*** Functions */ /* Dummy */ int true_func(int x) { return x + 1; } void test1_c_goto(void) { puts("\ntest1_c_goto():"); /* Inner scope, below */ { HAS_CLEANUP; int * ip1 = malloc(sizeof *ip1); int * ip2 = malloc(sizeof *ip2); printf("ip1: %p\n", (void *) ip1); printf("ip2: %p\n", (void *) ip2); /* Used in an 'if'-'else' */ if (true_func(0)) c_goto outer_scope; else puts("Failed!"); return; } outer_scope: puts("Exiting"); return; } void test2_c_goto(void) { puts("\ntest2_c_goto():"); /* Inner scope, below */ { HAS_CLEANUP; int * ip1 = malloc(sizeof *ip1); int * ip2 = malloc(sizeof *ip2); printf("ip1: %p\n", (void *) ip1); printf("ip2: %p\n", (void *) ip2); c_goto outer_scope; puts("Failed!"); return; } outer_scope: puts("Exiting"); return; } void test3_c_continue(void) { /* Expecting: 4 loops */ int x = 5; puts("\ntest3_c_continue():"); while (--x) { HAS_CLEANUP; int * ip1 = malloc(sizeof *ip1); int * ip2 = malloc(sizeof *ip2); printf("ip1: %p\n", (void *) ip1); printf("ip2: %p\n", (void *) ip2); if (true_func(0)) c_continue; else puts("Oops!"); puts("Failed!"); return; } puts("Exiting"); return; } void test4_c_break(void) { /* Expecting: 1 loop */ int x = 5; puts("\ntest4_c_break():"); while (--x) { HAS_CLEANUP; int * ip1 = malloc(sizeof *ip1); int * ip2 = malloc(sizeof *ip2); printf("ip1: %p\n", (void *) ip1); printf("ip2: %p\n", (void *) ip2); if (true_func(0)) c_break; else puts("Oops!"); puts("Failed!"); return; } puts("Exiting"); return; } /** Function "returning 'void'" */ void test5_c_return(void) { HAS_CLEANUP; int * ip1 = malloc(sizeof *ip1); int * ip2 = malloc(sizeof *ip2); puts("\ntest5_c_return():"); /* Inner scope, below */ { HAS_CLEANUP; int * ip3 = malloc(sizeof *ip3); int * ip4 = malloc(sizeof *ip4); printf("ip1: %p\n", (void *) ip1); printf("ip2: %p\n", (void *) ip2); printf("ip3: %p\n", (void *) ip3); printf("ip4: %p\n", (void *) ip4); if (true_func(0)) { puts("Attempting c_return"); c_return; } else puts("Oops!"); } puts("Failed!"); return; } /** Function returning 'int' */ int test6_c_return(void) { HAS_CLEANUP; int * ip1 = malloc(sizeof *ip1); int * ip2 = malloc(sizeof *ip2); puts("\ntest6_c_return():"); /* Inner scope, below */ { HAS_CLEANUP; int * ip3 = malloc(sizeof *ip3); int * ip4 = malloc(sizeof *ip4); printf("ip1: %p\n", (void *) ip1); printf("ip2: %p\n", (void *) ip2); printf("ip3: %p\n", (void *) ip3); printf("ip4: %p\n", (void *) ip4); if (true_func(0)) { puts("Attempting c_return"); c_return 1; } else puts("Oops!"); } puts("Failed!"); return 0; } /** Function returning 'int' */ int test7_c_return(void) { HAS_CLEANUP; int * ip1 = malloc(sizeof *ip1); int * ip2 = malloc(sizeof *ip2); puts("\ntest7_c_return():"); /* Inner scope, below */ { HAS_CLEANUP; int * ip3 = malloc(sizeof *ip3); int * ip4 = malloc(sizeof *ip4); /* Another inner scope, below */ { HAS_CLEANUP; int * ip5 = malloc(sizeof *ip5); int * ip6 = malloc(sizeof *ip6); printf("ip1: %p\n", (void *) ip1); printf("ip2: %p\n", (void *) ip2); printf("ip3: %p\n", (void *) ip3); printf("ip4: %p\n", (void *) ip4); printf("ip5: %p\n", (void *) ip5); printf("ip6: %p\n", (void *) ip6); if (true_func(0)) { puts("Attempting c_return"); c_return 1; } else puts("Oops!"); } } puts("Failed!"); return 0; } /** Program entry-point */ int main(void) { test1_c_goto(); test2_c_goto(); test3_c_continue(); test4_c_break(); test5_c_return(); if (!test6_c_return()) puts("D'oh!"); if (!test7_c_return()) puts("D'oh!"); return 0; }
Private
[
?
]
Run code
Submit