Wed Jun 16 14:33:22 CEST 2004 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / mono-config.c
1 /*
2  * mono-config.c
3  *
4  * Runtime and assembly configuration file support routines.
5  *
6  * Author: Paolo Molaro (lupus@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10 #include "config.h"
11 #include <glib.h>
12 #include <string.h>
13 #include "mono/metadata/loader.h"
14 #include "mono/metadata/mono-config.h"
15
16 static void start_element (GMarkupParseContext *context, 
17                            const gchar         *element_name,
18                            const gchar        **attribute_names,
19                            const gchar        **attribute_values,
20                            gpointer             user_data,
21                            GError             **error);
22
23 static void end_element   (GMarkupParseContext *context,
24                            const gchar         *element_name,
25                            gpointer             user_data,
26                            GError             **error);
27
28 static void parse_text    (GMarkupParseContext *context,
29                            const gchar         *text,
30                            gsize                text_len,
31                            gpointer             user_data,
32                            GError             **error);
33
34 static void passthrough   (GMarkupParseContext *context,
35                            const gchar         *text,
36                            gsize                text_len,
37                            gpointer             user_data,
38                            GError             **error);
39
40 static void parse_error   (GMarkupParseContext *context,
41                            GError              *error,
42                            gpointer             user_data);
43
44 static const GMarkupParser 
45 mono_parser = {
46         start_element,
47         end_element,
48         parse_text,
49         passthrough,
50         parse_error
51 };
52
53 static GHashTable *config_handlers;
54
55 /* when this interface is stable, export it. */
56 typedef struct MonoParseHandler MonoParseHandler;
57
58 struct MonoParseHandler {
59         const char *element_name;
60         void*(*init)   (MonoImage *assembly);
61         void (*start)  (gpointer user_data, const gchar *name,
62                         const gchar **attributes,
63                         const gchar **values);
64         void (*text)   (gpointer user_data, const char *text, gsize test_len);
65         void (*end)    (gpointer user_data, const char *name);
66         void (*finish) (gpointer user_data);
67 };
68
69 typedef struct {
70         MonoParseHandler *current;
71         void *user_data;
72         MonoImage *assembly;
73         int inited;
74 } ParseState;
75
76 static void start_element (GMarkupParseContext *context, 
77                            const gchar         *element_name,
78                            const gchar        **attribute_names,
79                            const gchar        **attribute_values,
80                            gpointer             user_data,
81                            GError             **error)
82 {
83         ParseState *state = user_data;
84         if (!state->current) {
85                 state->current = g_hash_table_lookup (config_handlers, element_name);
86                 if (state->current && state->current->init)
87                         state->user_data = state->current->init (state->assembly);
88         }
89         if (state->current && state->current->start)
90                 state->current->start (state->user_data, element_name, attribute_names, attribute_values);
91 }
92
93 static void end_element   (GMarkupParseContext *context,
94                            const gchar         *element_name,
95                            gpointer             user_data,
96                            GError             **error)
97 {
98         ParseState *state = user_data;
99         if (state->current) {
100                 if (state->current->end)
101                         state->current->end (state->user_data, element_name);
102                 if (strcmp (state->current->element_name, element_name) == 0) {
103                         if (state->current->finish)
104                                 state->current->finish (state->user_data);
105                         state->current = NULL;
106                         state->user_data = NULL;
107                 }
108         }
109 }
110
111 static void parse_text    (GMarkupParseContext *context,
112                            const gchar         *text,
113                            gsize                text_len,
114                            gpointer             user_data,
115                            GError             **error)
116 {
117         ParseState *state = user_data;
118         if (state->current && state->current->text)
119                 state->current->text (state->user_data, text, text_len);
120 }
121
122 static void passthrough   (GMarkupParseContext *context,
123                            const gchar         *text,
124                            gsize                text_len,
125                            gpointer             user_data,
126                            GError             **error)
127 {
128         /* do nothing */
129 }
130
131 static void parse_error   (GMarkupParseContext *context,
132                            GError              *error,
133                            gpointer             user_data)
134 {
135 }
136
137 typedef struct {
138         char *dll;
139         char *target;
140         MonoImage *assembly;
141 } DllInfo;
142
143 static void*
144 dllmap_init (MonoImage *assembly) {
145         DllInfo *info = g_new0 (DllInfo, 1);
146         info->assembly = assembly;
147         return info;
148 }
149
150 static void
151 dllmap_start (gpointer user_data, 
152               const gchar         *element_name,
153               const gchar        **attribute_names,
154               const gchar        **attribute_values)
155 {
156         int i;
157         DllInfo *info = user_data;
158         
159         if (strcmp (element_name, "dllmap") == 0) {
160                 g_free (info->dll);
161                 g_free (info->target);
162                 info->dll = info->target = NULL;
163                 for (i = 0; attribute_names [i]; ++i) {
164                         if (strcmp (attribute_names [i], "dll") == 0)
165                                 info->dll = g_strdup (attribute_values [i]);
166                         else if (strcmp (attribute_names [i], "target") == 0)
167                                 info->target = g_strdup (attribute_values [i]);
168                 }
169                 mono_dllmap_insert (info->assembly, info->dll, NULL, info->target, NULL);
170         } else if (strcmp (element_name, "dllentry") == 0) {
171                 const char *name = NULL, *target = NULL, *dll = NULL;
172                 for (i = 0; attribute_names [i]; ++i) {
173                         if (strcmp (attribute_names [i], "dll") == 0)
174                                 dll = attribute_values [i];
175                         else if (strcmp (attribute_names [i], "target") == 0)
176                                 target = attribute_values [i];
177                         else if (strcmp (attribute_names [i], "name") == 0)
178                                 name = attribute_values [i];
179                 }
180                 if (!dll)
181                         dll = info->dll;
182                 mono_dllmap_insert (info->assembly, info->dll, name, dll, target);
183         }
184 }
185
186 static void
187 dllmap_finish (gpointer user_data)
188 {
189         DllInfo *info = user_data;
190
191         g_free (info->dll);
192         g_free (info->target);
193         g_free (info);
194 }
195
196 static const MonoParseHandler
197 dllmap_handler = {
198         "dllmap",
199         dllmap_init,
200         dllmap_start,
201         NULL, /* text */
202         NULL, /* end */
203         dllmap_finish
204 };
205
206 static int inited = 0;
207
208 static void
209 mono_config_init (void)
210 {
211         inited = 1;
212         config_handlers = g_hash_table_new (g_str_hash, g_str_equal);
213         g_hash_table_insert (config_handlers, (gpointer) dllmap_handler.element_name, (gpointer) &dllmap_handler);
214 }
215
216 /* FIXME: error handling */
217
218 /* If assembly is NULL, parse in the global context */
219 static int
220 mono_config_parse_file_with_context (ParseState *state, const char *filename)
221 {
222         GMarkupParseContext *context;
223         char *text;
224         gsize len;
225
226         if (!inited)
227                 mono_config_init ();
228
229         if (!g_file_get_contents (filename, &text, &len, NULL))
230                 return 0;
231         context = g_markup_parse_context_new (&mono_parser, 0, state, NULL);
232         if (g_markup_parse_context_parse (context, text, len, NULL)) {
233                 g_markup_parse_context_end_parse (context, NULL);
234         }
235         g_markup_parse_context_free (context);
236         g_free (text);
237         return 1;
238 }
239
240 static void
241 mono_config_parse_file (const char *filename)
242 {
243         ParseState state = {NULL};
244         mono_config_parse_file_with_context (&state, filename);
245 }
246
247 /* 
248  * use the equivalent lookup code from the GAC when available.
249  * Depending on state, this should give something like:
250  *      aname/version-pubtoken/
251  *      aname/version/
252  *      aname
253  */
254 static char*
255 get_assembly_filename (MonoImage *image, int state)
256 {
257         switch (state) {
258         case 0:
259                 return g_strdup (mono_image_get_name (image));
260         default:
261                 return NULL;
262         }
263 }
264
265 void 
266 mono_config_for_assembly (MonoImage *assembly)
267 {
268         ParseState state = {NULL};
269         int got_it = 0, i;
270         char *aname, *cfg, *cfg_name;
271         const char *home;
272         
273         state.assembly = assembly;
274         cfg_name = g_strdup_printf ("%s.config", mono_image_get_filename (assembly));
275         mono_config_parse_file_with_context (&state, cfg_name);
276         g_free (cfg_name);
277
278         cfg_name = g_strdup_printf ("%s.config", mono_image_get_name (assembly));
279
280         home = g_get_home_dir ();
281
282         for (i = 0; (aname = get_assembly_filename (assembly, i)) != NULL; ++i) {
283                 cfg = g_build_filename (mono_get_config_dir (), "mono", "assemblies", aname, cfg_name, NULL);
284                 got_it += mono_config_parse_file_with_context (&state, cfg);
285                 g_free (cfg);
286
287 #ifndef PLATFORM_WIN32
288                 cfg = g_build_filename (home, ".mono", "assemblies", aname, cfg_name, NULL);
289                 got_it += mono_config_parse_file_with_context (&state, cfg);
290                 g_free (cfg);
291 #endif
292                 g_free (aname);
293                 if (got_it)
294                         break;
295         }
296         g_free (cfg_name);
297 }
298
299 /*
300  * Pass a NULL filename to parse the default config files
301  * (or the file in the MONO_CONFIG env var).
302  */
303 void
304 mono_config_parse (const char *filename) {
305         const char *home;
306         char *user_cfg;
307         char *mono_cfg;
308         
309         if (filename) {
310                 mono_config_parse_file (filename);
311                 return;
312         }
313
314         home = g_getenv ("MONO_CONFIG");
315         if (home) {
316                 mono_config_parse_file (home);
317                 return;
318         }
319
320         mono_cfg = g_build_filename (mono_get_config_dir (), "mono", "config", NULL);
321         mono_config_parse_file (mono_cfg);
322         g_free (mono_cfg);
323
324 #ifndef PLATFORM_WIN32
325         home = g_get_home_dir ();
326         user_cfg = g_strconcat (home, G_DIR_SEPARATOR_S, ".mono/config", NULL);
327         mono_config_parse_file (user_cfg);
328         g_free (user_cfg);
329 #endif
330 }
331
332 static char *mono_cfg_dir = NULL;
333
334 static void    
335 mono_install_get_config_dir (void)
336 {
337 #ifdef PLATFORM_WIN32
338   gchar *prefix;
339 #endif
340
341   mono_cfg_dir = g_getenv ("MONO_CFG_DIR");
342
343   if (!mono_cfg_dir) {
344 #ifndef PLATFORM_WIN32
345     mono_cfg_dir = MONO_CFG_DIR;
346 #else
347     prefix = g_path_get_dirname (mono_assembly_getrootdir ());
348     mono_cfg_dir = g_build_filename (prefix, "etc", NULL);
349     g_free (prefix);
350 #endif
351   }
352 }
353
354 const char* 
355 mono_get_config_dir (void)
356 {
357         if (!mono_cfg_dir)
358                 mono_install_get_config_dir ();
359         return mono_cfg_dir;
360 }
361