1 /* Fo
2 * fo-expr-env.c: XSL expression language environment module
3 *
4 * Copyright (C) 1998-2002 Daniel Veillard.
5 * Copyright (C) 2001-2002 Sun Microsystems.
6 * All Rights Reserved.
7 *
8 * Based on an XSL expression language evaluator that was based on the
9 * 'XML Path Language implementation' in 'xpath.c' from libxml2 by
10 * Daniel Veillard.
11 * Copyright (C) 2007 Menteith Consulting Ltd
12 *
13 * !See COPYING for the status of this software.
14 */
15
16 #include "fo-expr-eval.h"
17 #include "fo-expr-func-private.h"
18
19 struct _FoExprEnv
20 {
21 GHashTable *func_hash;
22 gint ref_count;
23 };
24
25 /**
26 * fo_expr_env_get_global_env:
27 *
28 *
29 *
30 * Return value:
31 **/
32 static FoExprEnv*
fo_expr_env_get_global_env(void)33 fo_expr_env_get_global_env (void)
34 {
35 static FoExprEnv *global_env = NULL;
36
37 if (global_env == NULL)
38 {
39 global_env = fo_expr_env_new ();
40
41 fo_expr_env_register_func (global_env,
42 "+",
43 fo_expr_func_add);
44 fo_expr_env_register_func (global_env,
45 "-",
46 fo_expr_func_sub);
47 fo_expr_env_register_func (global_env,
48 "*",
49 fo_expr_func_mul);
50 fo_expr_env_register_func (global_env,
51 "abs",
52 fo_expr_func_abs);
53 fo_expr_env_register_func (global_env,
54 "body-start",
55 fo_expr_func_body_start);
56 fo_expr_env_register_func (global_env,
57 "ceiling",
58 fo_expr_func_ceiling);
59 fo_expr_env_register_func (global_env,
60 "div",
61 fo_expr_func_div);
62 fo_expr_env_register_func (global_env,
63 "floor",
64 fo_expr_func_floor);
65 fo_expr_env_register_func (global_env,
66 "from-nearest-specified-value",
67 fo_expr_func_from_nearest_specified_value);
68 fo_expr_env_register_func (global_env,
69 "from-parent",
70 fo_expr_func_from_parent);
71 fo_expr_env_register_func (global_env,
72 "from-table-column",
73 fo_expr_func_from_table_column);
74 fo_expr_env_register_func (global_env,
75 "inherited-property-value",
76 fo_expr_func_inherited_property_value);
77 fo_expr_env_register_func (global_env,
78 "label-end",
79 fo_expr_func_label_end);
80 fo_expr_env_register_func (global_env,
81 "max",
82 fo_expr_func_max);
83 fo_expr_env_register_func (global_env,
84 "min",
85 fo_expr_func_min);
86 fo_expr_env_register_func (global_env,
87 "mod",
88 fo_expr_func_mod);
89 fo_expr_env_register_func (global_env,
90 "proportional-column-width",
91 fo_expr_func_pcw);
92 fo_expr_env_register_func (global_env,
93 "rgb",
94 fo_expr_func_rgb);
95 fo_expr_env_register_func (global_env,
96 "round",
97 fo_expr_func_round);
98 }
99
100 return global_env;
101 }
102
103 FoExprEnv*
fo_expr_env_new(void)104 fo_expr_env_new (void)
105 {
106 FoExprEnv *env = g_new0 (FoExprEnv, 1);
107
108 env->func_hash = g_hash_table_new (g_str_hash,
109 g_str_equal);
110
111 env->ref_count = 1;
112
113 return env;
114 }
115
116 FoExprEnv*
fo_expr_env_ref(FoExprEnv * env)117 fo_expr_env_ref (FoExprEnv *env)
118 {
119 g_return_val_if_fail (env != NULL, NULL);
120
121 env->ref_count++;
122
123 return env;
124 }
125
126 void
fo_expr_env_unref(FoExprEnv * env)127 fo_expr_env_unref (FoExprEnv *env)
128 {
129 g_return_if_fail (env != NULL);
130 g_return_if_fail (env->ref_count > 0);
131
132 env->ref_count--;
133
134 if (env->ref_count == 0)
135 {
136 g_hash_table_destroy (env->func_hash);
137 g_free (env);
138 env = NULL;
139 }
140 }
141
142 FoExprEnv*
fo_expr_env_register_func(FoExprEnv * env,const gchar * name,FoExprFunc func)143 fo_expr_env_register_func (FoExprEnv *env,
144 const gchar *name,
145 FoExprFunc func)
146 {
147 g_hash_table_insert (env->func_hash,
148 (gchar *) name,
149 func);
150 return env;
151 }
152
153 FoExprFunc
fo_expr_env_get_func(FoExprEnv * env,const gchar * name)154 fo_expr_env_get_func (FoExprEnv *env,
155 const gchar *name)
156 {
157 return (FoExprFunc) g_hash_table_lookup (env->func_hash,
158 name);
159 }
160
161 static gint
fo_expr_env_list_compare_func(gconstpointer a,gconstpointer b)162 fo_expr_env_list_compare_func (gconstpointer a,
163 gconstpointer b)
164 {
165 const FoExprEnv *env = (const FoExprEnv *) a;
166 gchar *name = (gchar *) b;
167
168 if (g_hash_table_lookup (env->func_hash,
169 name))
170 {
171 return 0;
172 }
173 else
174 {
175 return 1;
176 }
177 }
178
179 /**
180 * fo_expr_env_list_new:
181 *
182 * Get a new #FoExprEnvList that is preloaded with a copy of the
183 * global environment.
184 *
185 * The #FoExprEnvList must be freed by the caller using
186 * fo_expr_env_list_free()
187 *
188 * Return value: A new, preloaded #FoExprEnvList
189 **/
190 FoExprEnvList*
fo_expr_env_list_new(void)191 fo_expr_env_list_new (void)
192 {
193 return fo_expr_env_list_prepend (NULL,
194 fo_expr_env_get_global_env ());
195 }
196
197 /**
198 * fo_expr_env_list_free_item:
199 * @data: The item
200 * @user_data: Unused
201 *
202 * Free one item in an #FoExprEnvList
203 **/
204 static void
fo_expr_env_list_free_item(gpointer data,gpointer user_data G_GNUC_UNUSED)205 fo_expr_env_list_free_item (gpointer data,
206 gpointer user_data G_GNUC_UNUSED)
207 {
208 fo_expr_env_unref ((FoExprEnv *) data);
209 }
210
211 /**
212 * fo_expr_env_list_free:
213 * @env_list: The #FoExprEnvList to free
214 *
215 * Free an #FoExprEnvList that was created with fo_expr_env_list_new()
216 **/
217 void
fo_expr_env_list_free(FoExprEnvList * env_list)218 fo_expr_env_list_free (FoExprEnvList *env_list)
219 {
220 g_return_if_fail (env_list != NULL);
221
222 g_slist_foreach (env_list,
223 fo_expr_env_list_free_item,
224 NULL);
225 g_slist_free (env_list);
226 }
227
228 /**
229 * fo_expr_env_list_prepend:
230 * @env_list: The #FoExprEnvList to which to prepend @env.
231 * @env: The new #FoExprEnv.
232 *
233 * Prepend @env to @env_list so that when the returned @env_list is
234 * used in evaluating XSL expressions, the functions in @env have
235 * precedence over the functions in the environments, including the
236 * global environment, that are already in @env_list.
237 *
238 * Return value: The new start of the #FoExprEnvList.
239 **/
240 FoExprEnvList*
fo_expr_env_list_prepend(FoExprEnvList * env_list,FoExprEnv * env)241 fo_expr_env_list_prepend (FoExprEnvList *env_list,
242 FoExprEnv *env)
243 {
244 g_return_val_if_fail (env != NULL, env_list);
245
246 env = fo_expr_env_ref (env);
247
248 return g_slist_prepend (env_list, (gpointer) env);
249 }
250
251 /**
252 * fo_expr_env_list_get_func:
253 * @env_list: #FoExprEnvList
254 * @name: Name of a function
255 *
256 * Get the function in @env_list with name matching @name.
257 *
258 * Return value: #FoExprFunc corresponding to @name, or NULL.
259 **/
260 FoExprFunc
fo_expr_env_list_get_func(const FoExprEnvList * env_list,const gchar * name)261 fo_expr_env_list_get_func (const FoExprEnvList *env_list,
262 const gchar *name)
263 {
264 GSList *env_element =
265 g_slist_find_custom ((FoExprEnvList *) env_list,
266 name,
267 (GCompareFunc) fo_expr_env_list_compare_func);
268
269 if (env_element != NULL)
270 {
271 return fo_expr_env_get_func (env_element->data,
272 name);
273 }
274 else
275 {
276 return NULL;
277 }
278 }
279