Bail out immediately if we can't allocate a buffer for carving up $PATH.
[metze/wireshark/wip.git] / conditions.c
1 /* conditions.c
2  * Implementation for condition handler.
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include <config.h>
24
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include "conditions.h"
29
30 /* container for condition classes */
31 static GHashTable *classes = NULL;
32
33 /* condition data structure declaration */
34 struct condition{
35   char       *class_id;
36   void       *user_data;
37   _cnd_eval   eval_func;
38   _cnd_reset  reset_func;
39 };
40
41 /* structure used to store class functions in GHashTable */
42 typedef struct _cnd_class{
43   _cnd_constr constr_func;
44   _cnd_destr  destr_func;
45   _cnd_eval   eval_func;
46   _cnd_reset  reset_func;
47 } _cnd_class;
48
49 /* helper function prototypes */
50 static void _cnd_init(void);
51 static void _cnd_find_hash_key_for_class_id(gpointer, gpointer, gpointer);
52
53 condition *cnd_new(const char *class_id, ...) {
54   va_list     ap;
55   condition  *cnd     = NULL;
56   condition  *cnd_ref = NULL;
57   _cnd_class *cls     = NULL;
58   char       *id      = NULL;
59
60   /* check if hash table is already initialized */
61   _cnd_init();
62
63   /* get class structure for this id */
64   if ((cls = (_cnd_class *)g_hash_table_lookup(classes, class_id)) == NULL) {
65     g_warning("cnd_new: Couldn't find class ID \"%s\"", class_id);
66     return NULL;
67   }
68
69   /* initialize the basic structure */
70   if ((cnd_ref = (condition *)g_malloc(sizeof(condition))) == NULL)
71     return NULL;
72   cnd_ref->user_data  = NULL;
73   cnd_ref->eval_func  = cls->eval_func;
74   cnd_ref->reset_func = cls->reset_func;
75
76   cnd_ref->class_id = g_strdup(class_id);
77
78   /* perform class specific initialization */
79   va_start(ap, class_id);
80   cnd = (cls->constr_func)(cnd_ref, ap);
81   va_end(ap);
82
83   /* check for successful construction */
84   if (cnd == NULL) {
85     g_free(cnd_ref);
86     g_free(id);
87   }
88   return cnd;
89 } /* END cnd_new() */
90
91 void cnd_delete(condition *cnd) {
92   _cnd_class *cls = NULL;
93   const char* class_id;
94   /* check for valid pointer */
95   if (cnd == NULL)
96     return;
97
98   class_id = cnd->class_id;
99   /* check if hash table is already initialized */
100   _cnd_init();
101   /* get the condition class */
102   cls = (_cnd_class *)g_hash_table_lookup(classes, class_id);
103   /* call class specific destructor */
104   if (cls != NULL)
105     (cls->destr_func)(cnd);
106   /* free memory */
107   g_free(cnd->class_id);
108   /* free basic structure */
109   g_free(cnd);
110 } /* END cnd_delete() */
111
112 gboolean cnd_eval(condition *cnd, ...) {
113   va_list ap;
114   gboolean ret_val = FALSE;
115   /* validate cnd */
116   if (cnd == NULL)
117     return FALSE;
118   /* call specific handler */
119   va_start(ap, cnd);
120   ret_val = (cnd->eval_func)(cnd, ap);
121   va_end(ap);
122   return ret_val;
123 } /*  END cnd_eval() */
124
125 void cnd_reset(condition *cnd) {
126   if (cnd != NULL)
127     (cnd->reset_func)(cnd);
128 } /* END cnd_reset() */
129
130 void* cnd_get_user_data(condition *cnd) {
131   return cnd->user_data;
132 } /* END cnd_get_user_data() */
133
134 void cnd_set_user_data(condition *cnd, void *user_data) {
135   cnd->user_data = user_data;
136 } /* END cnd_set_user_data() */
137
138 gboolean cnd_register_class(const char *class_id,
139                             _cnd_constr constr_func,
140                             _cnd_destr  destr_func,
141                             _cnd_eval   eval_func,
142                             _cnd_reset  reset_func) {
143   char *key = NULL;
144   _cnd_class *cls = NULL;
145   /* check for valid parameters */
146   if ((constr_func == NULL) || (destr_func == NULL) ||
147       (eval_func == NULL) || (reset_func == NULL) || (class_id == NULL))
148     return FALSE;
149   /* check if hash table is already initialized */
150   _cnd_init();
151   /* check for unique class id */
152   if (g_hash_table_lookup(classes, class_id) != NULL) {
153     g_warning("cnd_register_class: Duplicate class ID \"%s\"", class_id);
154     return FALSE;
155   }
156   /* GHashTable keys need to be persistent for the lifetime of the hash
157      table. Allocate memory and copy the class id which we use as key. */
158   key = g_strdup(class_id);
159   /* initialize class structure */
160   if ((cls = (_cnd_class*)g_malloc(sizeof(_cnd_class))) == NULL) {
161     g_free(key);
162     return FALSE;
163   }
164   cls->constr_func = constr_func;
165   cls->destr_func  = destr_func;
166   cls->eval_func   = eval_func;
167   cls->reset_func  = reset_func;
168   /* insert new class */
169   g_hash_table_insert(classes, key, cls);
170   return TRUE;
171 } /* END cnd_register_class() */
172
173 static char *pkey = NULL;
174 void cnd_unregister_class(const char* class_id) {
175   const char *key = (const char*)class_id;
176   _cnd_class *cls = NULL;
177   /* check if hash table is already initialized */
178   _cnd_init();
179   /* find the key for this class id and store it in 'pkey' */
180   g_hash_table_foreach(classes,
181                        _cnd_find_hash_key_for_class_id,
182                        (gpointer)key);
183   /* find the class structure for this class id */
184   cls = (_cnd_class*)g_hash_table_lookup(classes, class_id);
185   /* remove constructor from hash table */
186   g_hash_table_remove(classes, class_id);
187   /* free the key */
188   g_free(pkey);
189   pkey = NULL;
190   /* free the value */
191   g_free(cls);
192 } /* END cnd_unregister_class() */
193
194 /*
195  * Initialize hash table.
196  */
197 static void _cnd_init(void) {
198   if (classes != NULL)
199     return;
200   /* create hash table, we use strings as keys */
201   classes = g_hash_table_new(g_str_hash, g_str_equal);
202 } /* END _cnd_init() */
203
204 /*
205  * Callback for function 'g_hash_table_foreach()'.
206  * We don't keep references to hash table keys. Keys have memory allocated
207  * which must be freed when they are not used anymore. This function finds
208  * the reference to a key corresponding to a particular class id. The reference
209  * to the key is stored in a global variable.
210  */
211 void _cnd_find_hash_key_for_class_id(gpointer key,
212                                      gpointer value _U_,
213                                      gpointer user_data) {
214   char *class_id  = (char *)user_data;
215   char *key_value = (char *)key;
216   if (strcmp(class_id, key_value) == 0)
217     pkey = key_value;
218 } /* END _cnd_find_hash_key_for_class_id() */
219
220 /*
221  * Editor modelines
222  *
223  * Local Variables:
224  * c-basic-offset: 2
225  * tab-width: 8
226  * indent-tabs-mode: nil
227  * End:
228  *
229  * ex: set shiftwidth=2 tabstop=8 expandtab:
230  * :indentSize=2:tabSize=8:noTabs=true:
231  */