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
|
/*
LICENSE INFORMATION:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Copyright (c) 2002 Bruno T. C. de Oliveira
INFORMAES DE LICENA:
Este programa um software de livre distribuio; voc pode
redistribu-lo e/ou modific-lo sob os termos da GNU General
Public License, conforme publicado pela Free Software Foundation,
pela verso 2 da licena ou qualquer verso posterior.
Este programa distribudo na esperana de que ele ser til
aos seus usurios, porm, SEM QUAISQUER GARANTIAS; sem sequer
a garantia implcita de COMERCIABILIDADE ou DE ADEQUAO A
QUALQUER FINALIDADE ESPECFICA. Consulte a GNU General Public
License para obter mais detalhes (uma cpia acompanha este
programa, armazenada no arquivo COPYING).
*/
/* This is a set of convenience macros and functions for enabling
* "automatic" destruction of dynamically-allocated objects when
* exitting the scope of a function. This is especially useful
* in functions that can return at several points, and it would be
* difficult to keep track of what is allocated at which point in order
* to free everything correctly.
*
* The philosophy is this:
*
* void my_func(...) {
* Brick *my_brick;
* Camel *my_camel;
* char *my_string;
*
* autod_begin;
* autod_register(my_brick, brick_destroy); // also sets my_brick = NULL
* autod_register(my_camel, camel_destroy); // also sets my_camel = NULL
* autod_register(my_string, free); // also sets my_string = NULL
*
* // do what you want with my_brick, my_camel and my_string
*
* if (somefunc() == ERROR)
* autod_return; // this takes care of destroying my_brick,
* // my_camel and my_string, by calling the
* // destructor function specified when registering
*
* // do more stuff with my_brick, my_camel, my_string
*
* autod_return; // don't forget to put this at the end
* }
*
* Sometimes you will want to return a registered object, which means
* that it should not be free'd (the caller will get ownership of the
* object). In this case, use autod_return_obj(v), and all registered
* pointers will be free'd except v, which will be returned.
*
* Also, notice you should never do:
*
* my_camel = other_camel;
*
* Because the original value of my_camel will be lost and will not
* be free'd (memory leak). Instead, you should do:
*
* if (my_camel) camel_destroy(my_camel);
* my_camel = other_camel;
*
* Since this occurs often, a convenience macro is provided:
*
* autod_assign(my_camel, other_camel);
*
* This takes care of destroying the old camel before assigning the new one
* (this sentence really sounds weird).
*/
#ifndef btco_bores_autod_h
#define btco_bores_autod_h
#include <stdlib.h>
typedef void (*autod_destructor_t)(void*);
typedef struct AutodRegistryNode_ {
void **ptr;
autod_destructor_t destructor;
struct AutodRegistryNode_ *next;
} AutodRegistryNode;
#define autod_begin AutodRegistryNode autodregistry_head; \
autodregistry_head.next = 0
#define autod_register(ptr, d) do_autod_register(&autodregistry_head, \
(void**)&ptr, (autod_destructor_t)d)
#define autod_return_value(v) { do_autod_cleanup(&autodregistry_head, 0); return v; }
#define autod_return_obj(v) { do_autod_cleanup(&autodregistry_head, (void*)v); return v; }
#define autod_return { do_autod_cleanup(&autodregistry_head, 0); return; }
#define autod_assign(ptr, newvalue) do_autod_assign(&autodregistry_head, \
(void**)&ptr, newvalue)
void do_autod_register(AutodRegistryNode *head, void **ptr,
autod_destructor_t destr);
void do_autod_assign(AutodRegistryNode *head, void **ptr, void *newvalue);
void do_autod_cleanup(AutodRegistryNode *head, void *ignore_ptr);
#endif
|