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