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));
37 gras_dd_cbps_block_begin(res);
43 gras_dd_cbps_free(gras_dd_cbps_t **state) {
45 gras_dd_cbps_block_end(*state);
46 gras_dict_free ( &( (*state)->space ) );
47 gras_dynar_free( (*state)->stack );
48 gras_dynar_free( (*state)->globals );
57 * Declare a new element in the PS, and give it a value. If an element of that
58 * name already exists, it is masked by the one given here, and will be
59 * seeable again only after a pop to remove the value this push adds.
62 gras_dd_cbps_push(gras_dd_cbps_t *ps,
65 gras_datadesc_type_t *ddt) {
67 gras_dynar_t *p_dynar = NULL;
68 gras_dd_cbps_elm_t *p_var = NULL;
70 gras_dict_get(ps->space, name, (void **)&p_dynar);
73 gras_dynar_new(&p_dynar, sizeof (gras_dd_cbps_elm_t *), NULL);
74 gras_dict_set(ps->space, name, (void **)p_dynar, NULL);
75 /* FIXME: leaking on dynar. Insert in dict with a way to free it */
78 p_var = calloc(1, sizeof(gras_dd_cbps_elm_t));
82 gras_dynar_push(p_dynar, &p_var);
84 gras_dynar_pop(ps->stack, &p_dynar);
85 gras_dynar_push(p_dynar, strdup(name));
86 gras_dynar_push(ps->stack, &p_dynar);
92 * Retrieve an element from the PS, and remove it from the PS. If it's not
93 * present in the current block, it will fail (with abort) and not search
94 * in upper blocks since this denotes a programmation error.
97 gras_dd_cbps_pop (gras_dd_cbps_t *ps,
99 gras_datadesc_type_t **ddt) {
100 gras_dynar_t *p_dynar = NULL;
101 gras_dd_cbps_elm_t *p_elm = NULL;
104 /* FIXME: Error handling */
105 gras_dict_get(ps->space, name, (void **)&p_dynar);
106 gras_dynar_pop(p_dynar, &p_elm);
108 if (!gras_dynar_length(p_dynar)) {
109 gras_dict_remove(ps->space, name);
110 gras_dynar_free_container(p_dynar);
121 gras_dynar_pop(ps->stack, &p_dynar);
123 int l = gras_dynar_length(p_dynar);
128 gras_dynar_get(p_dynar, l, &_name);
129 if (!strcmp(name, _name)) {
130 gras_dynar_remove_at(p_dynar, l, &_name);
136 gras_dynar_push(ps->stack, &p_dynar);
145 * Change the value of an element in the PS.
146 * If it's not present in the current block, look in the upper ones.
147 * If it's not present in any of them, look in the globals
148 * (FIXME: which no function of this API allows to set).
149 * If not present there neither, the code may segfault (Oli?).
151 * Once a reference to an element of that name is found somewhere in the PS,
152 * its value is changed.
155 gras_dd_cbps_set (gras_dd_cbps_t *ps,
158 gras_datadesc_type_t *ddt) {
160 gras_dynar_t *p_dynar = NULL;
161 gras_dd_cbps_elm_t *p_elm = NULL;
163 gras_dict_get(ps->space, name, (void **)&p_dynar);
166 gras_dynar_new(&p_dynar, sizeof (gras_dd_cbps_elm_t *), NULL);
167 gras_dict_set(ps->space, name, (void **)p_dynar, NULL);
169 p_elm = calloc(1, sizeof(gras_dd_cbps_elm_t));
170 gras_dynar_push(ps->globals, &name);
172 gras_dynar_pop(p_dynar, &p_elm);
178 gras_dynar_push(p_dynar, &p_elm);
185 * Get the value of an element in the PS without modifying it.
186 * (note that you get the content of the data struct and not a copy to it)
187 * If it's not present in the current block, look in the upper ones.
188 * If it's not present in any of them, look in the globals
189 * (FIXME: which no function of this API allows to set).
190 * If not present there neither, the code may segfault (Oli?).
193 gras_dd_cbps_get (gras_dd_cbps_t *ps,
195 gras_datadesc_type_t **ddt) {
197 gras_dynar_t *p_dynar = NULL;
198 gras_dd_cbps_elm_t *p_elm = NULL;
200 /* FIXME: Error handling */
201 gras_dict_get(ps->space, name, (void **)&p_dynar);
202 gras_dynar_pop(p_dynar, &p_elm);
203 gras_dynar_push(p_dynar, &p_elm);
214 * gras_dd_cbps_block_begin:
216 * Begins a new block.
218 * Blocks are usefull to remove a whole set of declarations you don't even know
220 * E.g., they constitute an elegent solution to recursive data structures.
222 * push/pop may be used in some cases for that, but if your recursive data
223 * struct contains other structs needing themselves callbacks, you have to
224 * use block_{begin,end} to do the trick.
228 gras_dd_cbps_block_begin(gras_dd_cbps_t *ps) {
230 gras_dynar_t *p_dynar = NULL;
232 gras_dynar_new(&p_dynar, sizeof (char *), NULL);
233 gras_dynar_push(ps->stack, &p_dynar);
237 * gras_dd_cbps_block_begin:
239 * End the current block, and go back to the upper one.
242 gras_dd_cbps_block_end(gras_dd_cbps_t *ps) {
244 gras_dynar_t *p_dynar = NULL;
248 gras_dynar_pop(ps->stack, &p_dynar);
250 gras_dynar_foreach(p_dynar, cursor, name) {
252 gras_dynar_t *p_dynar_elm = NULL;
253 gras_dd_cbps_elm_t *p_elm = NULL;
255 gras_dict_get(ps->space, name, (void **)&p_dynar_elm);
256 gras_dynar_pop(p_dynar_elm, &p_elm);
258 if (!gras_dynar_length(p_dynar_elm)) {
259 gras_dict_remove(ps->space, name);
260 gras_dynar_free_container(p_dynar_elm);
267 gras_dynar_free_container(p_dynar);