3 /* cbps - persistant states for callbacks */
5 /* Authors: Olivier Aumage, Martin Quinson */
6 /* Copyright (C) 2003, 2004 da GRAS posse. */
8 /* This program is free software; you can redistribute it and/or modify it
9 under the terms of the license (GNU LGPL) which comes with this package. */
11 #include "DataDesc/datadesc_private.h"
14 gras_datadesc_type_t *type;
18 struct s_gras_dd_cbps {
21 gras_dynar_t *globals;
25 gras_dd_cbps_new(gras_dd_cbps_t **dst) {
29 if (!(res=malloc(sizeof(gras_dd_cbps_t))))
32 TRY(gras_dict_new(&(res->space)));
33 /* FIXME:leaking on content of dynars*/
34 TRY(gras_dynar_new(&(res->stack), sizeof(gras_dynar_t*), NULL));
35 TRY(gras_dynar_new(&(res->globals), sizeof(char*), NULL));
42 gras_dd_cbps_free(gras_dd_cbps_t **state) {
44 gras_dict_free ( &( (*state)->space ) );
45 gras_dynar_free( (*state)->stack );
46 gras_dynar_free( (*state)->globals );
55 * Declare a new element in the PS, and give it a value. If an element of that
56 * name already exists, it is masked by the one given here, and will be
57 * seeable again only after a pop to remove the value this push adds.
60 gras_dd_cbps_push(gras_dd_cbps_t *ps,
63 gras_datadesc_type_t *ddt) {
65 gras_dynar_t *p_dynar = NULL;
66 gras_dd_cbps_elm_t *p_var = NULL;
68 gras_dict_get(ps->space, name, (void **)&p_dynar);
71 gras_dynar_new(&p_dynar, sizeof (gras_dd_cbps_elm_t *), NULL);
72 gras_dict_set(ps->space, name, (void **)p_dynar, NULL);
73 /* FIXME: leaking on dynar. Insert in dict with a way to free it */
76 p_var = calloc(1, sizeof(gras_dd_cbps_elm_t));
80 gras_dynar_push(p_dynar, &p_var);
82 gras_dynar_pop(ps->stack, &p_dynar);
83 gras_dynar_push(p_dynar, &name);
84 gras_dynar_push(ps->stack, &p_dynar);
90 * Retrieve an element from the PS, and remove it from the PS. If it's not
91 * present in the current block, it will fail (with abort) and not search
92 * in upper blocks since this denotes a programmation error.
95 gras_dd_cbps_pop (gras_dd_cbps_t *ps,
97 gras_datadesc_type_t **ddt) {
98 gras_dynar_t *p_dynar = NULL;
99 gras_dd_cbps_elm_t *p_elm = NULL;
102 /* FIXME: Error handling */
103 gras_dict_get(ps->space, name, (void **)&p_dynar);
104 gras_dynar_pop(p_dynar, &p_elm);
106 if (!gras_dynar_length(p_dynar)) {
107 gras_dict_remove(ps->space, name);
108 gras_dynar_free_container(p_dynar);
119 gras_dynar_pop(ps->stack, &p_dynar);
121 int l = gras_dynar_length(p_dynar);
126 gras_dynar_get(p_dynar, l, &_name);
127 if (!strcmp(name, _name)) {
128 gras_dynar_remove_at(p_dynar, l, &_name);
134 gras_dynar_push(ps->stack, &p_dynar);
143 * Change the value of an element in the PS.
144 * If it's not present in the current block, look in the upper ones.
145 * If it's not present in any of them, look in the globals
146 * (FIXME: which no function of this API allows to set).
147 * If not present there neither, the code may segfault (Oli?).
149 * Once a reference to an element of that name is found somewhere in the PS,
150 * its value is changed.
153 gras_dd_cbps_set (gras_dd_cbps_t *ps,
156 gras_datadesc_type_t *ddt) {
158 gras_dynar_t *p_dynar = NULL;
159 gras_dd_cbps_elm_t *p_elm = NULL;
161 gras_dict_get(ps->space, name, (void **)&p_dynar);
164 gras_dynar_new(&p_dynar, sizeof (gras_dd_cbps_elm_t *), NULL);
165 gras_dict_set(ps->space, name, (void **)p_dynar, NULL);
167 p_elm = calloc(1, sizeof(gras_dd_cbps_elm_t));
168 gras_dynar_push(ps->globals, &name);
170 gras_dynar_pop(p_dynar, &p_elm);
176 gras_dynar_push(p_dynar, &p_elm);
183 * Get the value of an element in the PS without modifying it.
184 * (note that you get the content of the data struct and not a copy to it)
185 * If it's not present in the current block, look in the upper ones.
186 * If it's not present in any of them, look in the globals
187 * (FIXME: which no function of this API allows to set).
188 * If not present there neither, the code may segfault (Oli?).
191 gras_dd_cbps_get (gras_dd_cbps_t *ps,
193 gras_datadesc_type_t **ddt) {
195 gras_dynar_t *p_dynar = NULL;
196 gras_dd_cbps_elm_t *p_elm = NULL;
198 /* FIXME: Error handling */
199 gras_dict_get(ps->space, name, (void **)&p_dynar);
200 gras_dynar_pop(p_dynar, &p_elm);
201 gras_dynar_push(p_dynar, &p_elm);
212 * gras_dd_cbps_block_begin:
214 * Begins a new block.
216 * Blocks are usefull to remove a whole set of declarations you don't even know
218 * E.g., they constitute an elegent solution to recursive data structures.
220 * push/pop may be used in some cases for that, but if your recursive data
221 * struct contains other structs needing themselves callbacks, you have to
222 * use block_{begin,end} to do the trick.
226 gras_dd_cbps_block_begin(gras_dd_cbps_t *ps) {
228 gras_dynar_t *p_dynar = NULL;
230 gras_dynar_new(&p_dynar, sizeof (char *), NULL);
231 gras_dynar_push(ps->stack, &p_dynar);
235 * gras_dd_cbps_block_begin:
237 * End the current block, and go back to the upper one.
240 gras_dd_cbps_block_end(gras_dd_cbps_t *ps) {
242 gras_dynar_t *p_dynar = NULL;
246 gras_dynar_pop(ps->stack, &p_dynar);
248 gras_dynar_foreach(p_dynar, cursor, name) {
250 gras_dynar_t *p_dynar_elm = NULL;
251 gras_dd_cbps_elm_t *p_elm = NULL;
253 gras_dict_get(ps->space, name, (void **)&p_dynar_elm);
254 gras_dynar_pop(p_dynar_elm, &p_elm);
256 if (!gras_dynar_length(p_dynar_elm)) {
257 gras_dict_remove(ps->space, name);
258 gras_dynar_free_container(p_dynar_elm);
265 gras_dynar_free_container(p_dynar);