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