]> arthur.barton.de Git - netatalk.git/blob - libatalk/talloc/dalloc.c
dalloc documentation and small fixes
[netatalk.git] / libatalk / talloc / dalloc.c
1 /*
2   Copyright (c) 2012 Frank Lahm <franklahm@gmail.com>
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 2 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13 */
14
15 /*!
16   @file
17   Typesafe, dynamic object store based on talloc
18  
19   Usage:
20
21   //
22   // Define some terminal types:
23   //
24
25   // A key/value store aka dictionary that supports retrieving elements by key
26   typedef dict_t DALLOC_CTX;
27
28   // An ordered set that can store different objects which can be retrieved by number
29   typedef set_t DALLOC_CTX;
30
31   //
32   // Create an dalloc object and add elementes of different type
33   //
34
35   // Allocate a new talloc context
36   TALLOC_CTX *mem_ctx = talloc_new(NULL);
37   // Create a new dalloc object
38   DALLOC_CTX *d = talloc_zero(mem_ctx, DALLOC_CTX);
39  
40   // Store an int value in the object
41   uint64_t i = 1;
42   dalloc_add_copy(d, &i, uint64_t);
43  
44   // Store a string
45   char *str = dalloc_strdup(d, "hello world");
46   dalloc_add(d, str, char *);
47  
48   // Add a nested object, you later can't fetch this directly
49   DALLOC_CTX *nested = talloc_zero(d, DALLOC_CTX);
50   dalloc_add(d, nested, DALLOC_CTX);
51
52   // Add an int value to the nested object, this can be fetched
53   i = 2;
54   dalloc_add_copy(nested, &i, uint64_t);
55
56   // Add a nested set
57   set_t *set = talloc_zero(nested, set_t);
58   dalloc_add(nested, set, set_t);
59  
60   // Add an int value to the set
61   i = 3;
62   dalloc_add_copy(set, &i, uint64_t);
63
64   // Add a dictionary (key/value store)
65   dict_t *dict = talloc_zero(nested, dict_t);
66   dalloc_add(nested, dict, dict_t);
67
68   // Store a string as key in the dict
69   str = dalloc_strdup(d, "key");
70   dalloc_add(dict, str, char *);
71
72   // Add a value for the key
73   i = 4;
74   dalloc_add_copy(dict, &i, uint64_t);
75
76   //
77   // Fetching value references
78   // You can fetch anything that is not a DALLOC_CTXs, because passing
79   // "DALLOC_CTXs" as type to the functions dalloc_get() and dalloc_value_for_key()
80   // tells the function to step into that object and expect more arguments that specify
81   // which element to fetch.
82   //
83
84   // Get reference to an objects element by position
85   uint64_t *p = dalloc_get(d, "uint64_t", 0);
86   // p now points to the first int with a value of 1
87
88   // Get reference to the "hello world" string
89   str = dalloc_get(d, "char *", 1);
90
91   // You can't fetch a pure DALLOC_CTX
92   nested = dalloc_get(d, "DALLOC_CTX", 2);
93   // But you can do this
94   p = dalloc_get(d, "DALLOC_CTX", 2, "uint64_t", 0);
95   // p now points to the value 2
96
97   // You can fetch types that are typedefd DALLOC_CTXs
98   set = dalloc_get(d, "DALLOC_CTX", 2, "set_t", 1);
99
100   // Fetch int from set, note that you must use DALLOC_CTX as type for the set
101   p = dalloc_get(d, "DALLOC_CTX", 2, "DALLOC_CTX", 1, "uint64_t", 0);
102   // p points to 3
103
104   // Fetch value by key from dictionary
105   p = dalloc_value_for_key(d, "DALLOC_CTX", 2, "DALLOC_CTX", 2, "key");
106   // p now point to 4
107 */
108
109 #ifdef HAVE_CONFIG_H
110 #include "config.h"
111 #endif /* HAVE_CONFIG_H */
112
113 #include <string.h>
114 #include <strings.h>
115 #include <stdio.h>
116 #include <stdlib.h>
117 #include <errno.h>
118 #include <stdbool.h>
119 #include <inttypes.h>
120
121 #include <atalk/errchk.h>
122 #include <atalk/util.h>
123 #include <atalk/logger.h>
124 #include <atalk/talloc.h>
125 #include <atalk/bstrlib.h>
126 #include <atalk/dalloc.h>
127
128 /* Use dalloc_add_copy() macro, not this function */
129 int dalloc_add_talloc_chunk(DALLOC_CTX *dd, void *talloc_chunk, void *obj, size_t size)
130 {
131     if (talloc_chunk) {
132         /* Called from dalloc_add_copy() macro */
133         dd->dd_talloc_array = talloc_realloc(dd,
134                                              dd->dd_talloc_array,
135                                              void *,
136                                              talloc_array_length(dd->dd_talloc_array) + 1);
137         memcpy(talloc_chunk, obj, size);
138         dd->dd_talloc_array[talloc_array_length(dd->dd_talloc_array) - 1] = talloc_chunk;
139     } else {
140         /* Called from dalloc_add() macro */
141         dd->dd_talloc_array = talloc_realloc(dd,
142                                              dd->dd_talloc_array,
143                                              void *,
144                                              talloc_array_length(dd->dd_talloc_array) + 1);
145         dd->dd_talloc_array[talloc_array_length(dd->dd_talloc_array) - 1] = obj;
146
147     }
148     return 0;
149 }
150
151 /* Get number of elements, returns 0 if the structure is empty or not initialized */
152 int dalloc_size(DALLOC_CTX *d)
153 {
154     if (!d || !d->dd_talloc_array)
155         return 0;
156     return talloc_array_length(d->dd_talloc_array);
157 }
158
159 /*
160  * Get pointer to value from a DALLOC object
161  *
162  * Returns pointer to object from a DALLOC object. Nested object interation
163  * is supported by using the type string "DALLOC_CTX". Any other type string
164  * designates the requested objects type.
165  */
166 void *dalloc_get(const DALLOC_CTX *d, ...)
167 {
168     EC_INIT;
169     void *p = NULL;
170     va_list args;
171     const char *type;
172     int elem;
173     const char *elemtype;
174
175     va_start(args, d);
176     type = va_arg(args, const char *);
177
178     while (STRCMP(type, ==, "DALLOC_CTX")) {
179         elem = va_arg(args, int);
180         if (elem >= talloc_array_length(d->dd_talloc_array)) {
181             LOG(log_error, logtype_sl, "dalloc_get(%s): bound check error: %d >= %d",
182                 type, elem >= talloc_array_length(d->dd_talloc_array));
183             EC_FAIL;
184         }
185         d = d->dd_talloc_array[elem];
186         type = va_arg(args, const char *);
187     }
188
189     elem = va_arg(args, int);
190     if (elem >= talloc_array_length(d->dd_talloc_array)) {
191         LOG(log_error, logtype_sl, "dalloc_get(%s): bound check error: %d >= %d",
192             type, elem,  talloc_array_length(d->dd_talloc_array));
193         EC_FAIL;
194     }
195
196     if (!(p = talloc_check_name(d->dd_talloc_array[elem], type))) {
197         LOG(log_error, logtype_sl, "dalloc_get(%d/%s): type mismatch: %s",
198             type, elem, talloc_get_name(d->dd_talloc_array[elem]));
199     }
200
201     va_end(args);
202
203 EC_CLEANUP:
204     if (ret != 0)
205         p = NULL;
206     return p;
207 }
208
209 void *dalloc_value_for_key(const DALLOC_CTX *d, ...)
210 {
211     EC_INIT;
212     void *p = NULL;
213     va_list args;
214     const char *type;
215     int elem;
216     const char *elemtype;
217     char *s;
218
219     va_start(args, d);
220     type = va_arg(args, const char *);
221
222     while (STRCMP(type, ==, "DALLOC_CTX")) {
223         elem = va_arg(args, int);
224         AFP_ASSERT(elem < talloc_array_length(d->dd_talloc_array));
225         d = d->dd_talloc_array[elem];
226         type = va_arg(args, const char *);
227     }
228
229     for (elem = 0; elem + 1 < talloc_array_length(d->dd_talloc_array); elem += 2) {
230         if (STRCMP(talloc_get_name(d->dd_talloc_array[elem]), !=, "char *")) {
231             LOG(log_error, logtype_default, "dalloc_value_for_key: key not a string: %s",
232                 talloc_get_name(d->dd_talloc_array[elem]));
233             EC_FAIL;
234         }
235         if (STRCMP((char *)d->dd_talloc_array[elem], ==, type)) {
236             p = d->dd_talloc_array[elem + 1];
237             break;
238         }            
239     }
240     va_end(args);
241
242 EC_CLEANUP:
243     if (ret != 0)
244         p = NULL;
245     return p;
246 }
247
248 char *dalloc_strdup(const void *ctx, const char *string)
249 {
250     EC_INIT;
251     char *p;
252
253     EC_NULL( p = talloc_strdup(ctx, string) );
254     talloc_set_name(p, "char *");
255
256 EC_CLEANUP:
257     if (ret != 0) {
258         if (p)
259             talloc_free(p);
260         p = NULL;
261     }
262     return p;
263 }
264
265 char *dalloc_strndup(const void *ctx, const char *string, size_t n)
266 {
267     EC_INIT;
268     char *p;
269
270     EC_NULL( p = talloc_strndup(ctx, string, n) );
271     talloc_set_name(p, "char *");
272
273 EC_CLEANUP:
274     if (ret != 0) {
275         if (p)
276             talloc_free(p);
277         p = NULL;
278     }
279     return p;
280 }