1 /*
2 LICENSE INFORMATION:
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public
5 License as published by the Free Software Foundation; either
6 version 2 of the License, or (at your option) any later version.
7 
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 General Public License for more details.
12 
13 You should have received a copy of the GNU General Public
14 License along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 Copyright (c) 2002 Bruno T. C. de Oliveira
17 
18 INFORMA��ES DE LICEN�A:
19 Este programa � um software de livre distribui��o; voc� pode
20 redistribu�-lo e/ou modific�-lo sob os termos da GNU General
21 Public License, conforme publicado pela Free Software Foundation,
22 pela vers�o 2 da licen�a ou qualquer vers�o posterior.
23 
24 Este programa � distribu�do na esperan�a de que ele ser� �til
25 aos seus usu�rios, por�m, SEM QUAISQUER GARANTIAS; sem sequer
26 a garantia impl�cita de COMERCIABILIDADE ou DE ADEQUA��O A
27 QUALQUER FINALIDADE ESPEC�FICA. Consulte a GNU General Public
28 License para obter mais detalhes (uma c�pia acompanha este
29 programa, armazenada no arquivo COPYING).
30 */
31 
32 /* This is a set of convenience macros and functions for enabling
33  * "automatic" destruction of dynamically-allocated objects when
34  * exitting the scope of a function. This is especially useful
35  * in functions that can return at several points, and it would be
36  * difficult to keep track of what is allocated at which point in order
37  * to free everything correctly.
38  *
39  * The philosophy is this:
40  *
41  * void my_func(...) {
42  *    Brick *my_brick;
43  *    Camel *my_camel;
44  *    char *my_string;
45  *
46  *    autod_begin;
47  *    autod_register(my_brick, brick_destroy);  // also sets my_brick = NULL
48  *    autod_register(my_camel, camel_destroy);  // also sets my_camel = NULL
49  *    autod_register(my_string, free);          // also sets my_string = NULL
50  *
51  *    // do what you want with my_brick, my_camel and my_string
52  *
53  *    if (somefunc() == ERROR)
54  *       autod_return;  // this takes care of destroying my_brick,
55  *                      // my_camel and my_string, by calling the
56  *                      // destructor function specified when registering
57  *
58  *    // do more stuff with my_brick, my_camel, my_string
59  *
60  *    autod_return;  // don't forget to put this at the end
61  * }
62  *
63  * Sometimes you will want to return a registered object, which means
64  * that it should not be free'd (the caller will get ownership of the
65  * object). In this case, use autod_return_obj(v), and all registered
66  * pointers will be free'd except v, which will be returned.
67  *
68  * Also, notice you should never do:
69  *
70  *      my_camel = other_camel;
71  *
72  * Because the original value of my_camel will be lost and will not
73  * be free'd (memory leak). Instead, you should do:
74  *
75  *      if (my_camel) camel_destroy(my_camel);
76  *      my_camel = other_camel;
77  *
78  * Since this occurs often, a convenience macro is provided:
79  *
80  *      autod_assign(my_camel, other_camel);
81  *
82  * This takes care of destroying the old camel before assigning the new one
83  * (this sentence really sounds weird).
84  */
85 
86 
87 #ifndef btco_bores_autod_h
88 #define btco_bores_autod_h
89 
90 #include <stdlib.h>
91 
92 typedef void (*autod_destructor_t)(void*);
93 
94 typedef struct AutodRegistryNode_ {
95    void **ptr;
96    autod_destructor_t destructor;
97    struct AutodRegistryNode_ *next;
98 } AutodRegistryNode;
99 
100 #define autod_begin  AutodRegistryNode autodregistry_head; \
101                      autodregistry_head.next = 0
102 
103 #define autod_register(ptr, d) do_autod_register(&autodregistry_head, \
104                                      (void**)&ptr, (autod_destructor_t)d)
105 
106 #define autod_return_value(v) { do_autod_cleanup(&autodregistry_head, 0); return v; }
107 #define autod_return_obj(v) { do_autod_cleanup(&autodregistry_head, (void*)v); return v; }
108 #define autod_return { do_autod_cleanup(&autodregistry_head, 0); return; }
109 #define autod_assign(ptr, newvalue) do_autod_assign(&autodregistry_head, \
110                                       (void**)&ptr, newvalue)
111 
112 void do_autod_register(AutodRegistryNode *head, void **ptr,
113                                         autod_destructor_t destr);
114 
115 void do_autod_assign(AutodRegistryNode *head, void **ptr, void *newvalue);
116 
117 void do_autod_cleanup(AutodRegistryNode *head, void *ignore_ptr);
118 
119 
120 #endif
121 
122 
123