2004-04-25 Nick Drochak <ndrochak@gol.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
207 static int inited = 0;
208
209 static void
210 mono_config_init (void)
211 {
212         inited = 1;
213         config_handlers = g_hash_table_new (g_str_hash, g_str_equal);
214         g_hash_table_insert (config_handlers, (gpointer) dllmap_handler.element_name, (gpointer) &dllmap_handler);
215 }
216
217 /* FIXME: error handling */
218
219 /* If assembly is NULL, parse in the global context */
220 static int
221 mono_config_parse_file_with_context (ParseState *state, const char *filename)
222 {
223         GMarkupParseContext *context;
224         char *text;
225         gsize len;
226
227         if (!inited)
228                 mono_config_init ();
229
230         if (!g_file_get_contents (filename, &text, &len, NULL))
231                 return 0;
232         context = g_markup_parse_context_new (&mono_parser, 0, state, NULL);
233         if (g_markup_parse_context_parse (context, text, len, NULL)) {
234                 g_markup_parse_context_end_parse (context, NULL);
235         }
236         g_markup_parse_context_free (context);
237         g_free (text);
238         return 1;
239 }
240
241 static void
242 mono_config_parse_file (const char *filename)
243 {
244         ParseState state = {NULL};
245         mono_config_parse_file_with_context (&state, filename);
246 }
247
248 /* 
249  * use the equivalent lookup code from the GAC when available.
250  * Depending on state, this should give something like:
251  *      aname/version-pubtoken/
252  *      aname/version/
253  *      aname
254  */
255 static char*
256 get_assembly_filename (MonoImage *image, int state)
257 {
258         switch (state) {
259         case 0:
260                 return g_strdup (image->assembly_name);
261         default:
262                 return NULL;
263         }
264 }
265
266 void 
267 mono_config_for_assembly (MonoImage *assembly)
268 {
269         ParseState state = {NULL};
270         int got_it = 0, i;
271         char *aname, *cfg, *cfg_name;
272         const char *home;
273         
274         state.assembly = assembly;
275         cfg_name = g_strdup_printf ("%s.config", assembly->name);
276         mono_config_parse_file_with_context (&state, cfg_name);
277         g_free (cfg_name);
278
279         cfg_name = g_strdup_printf ("%s.config", assembly->assembly_name);
280
281         home = g_get_home_dir ();
282
283         for (i = 0; (aname = get_assembly_filename (assembly, i)) != NULL; ++i) {
284                 cfg = g_build_filename (mono_get_config_dir (), "mono", "assemblies", aname, cfg_name, NULL);
285                 got_it += mono_config_parse_file_with_context (&state, cfg);
286                 g_free (cfg);
287
288 #ifndef PLATFORM_WIN32
289                 cfg = g_build_filename (home, ".mono", "assemblies", aname, cfg_name, NULL);
290                 got_it += mono_config_parse_file_with_context (&state, cfg);
291                 g_free (cfg);
292 #endif
293                 g_free (aname);
294                 if (got_it)
295                         break;
296         }
297         g_free (cfg_name);
298 }
299
300 /*
301  * Pass a NULL filename to parse the default config files
302  * (or the file in the MONO_CONFIG env var).
303  */
304 void
305 mono_config_parse (const char *filename) {
306         const char *home;
307         char *user_cfg;
308         char *mono_cfg;
309         
310         if (filename) {
311                 mono_config_parse_file (filename);
312                 return;
313         }
314
315         home = g_getenv ("MONO_CONFIG");
316         if (home) {
317                 mono_config_parse_file (home);
318                 return;
319         }
320
321         mono_cfg = g_build_filename (mono_get_config_dir (), "mono", "config", NULL);
322         mono_config_parse_file (mono_cfg);
323         g_free (mono_cfg);
324
325 #ifndef PLATFORM_WIN32
326         home = g_get_home_dir ();
327         user_cfg = g_strconcat (home, G_DIR_SEPARATOR_S, ".mono/config", NULL);
328         mono_config_parse_file (user_cfg);
329         g_free (user_cfg);
330 #endif
331 }
332
333 static char *mono_cfg_dir = NULL;
334
335 static void    
336 mono_install_get_config_dir (void)
337 {
338 #ifdef PLATFORM_WIN32
339   int i;
340 #endif
341
342   mono_cfg_dir = getenv ("MONO_CFG_DIR");
343
344   if (!mono_cfg_dir) {
345 #ifndef PLATFORM_WIN32
346     mono_cfg_dir = MONO_CFG_DIR;
347 #else
348     mono_cfg_dir = g_strdup (MONO_CFG_DIR);
349     for (i = strlen (mono_cfg_dir) - 1; i >= 0; i--) {
350         if (mono_cfg_dir [i] == '/')
351             ((char*) mono_cfg_dir) [i] = '\\';
352     }
353 #endif
354   }
355 }
356
357 const char* 
358 mono_get_config_dir (void)
359 {
360         if (!mono_cfg_dir)
361                 mono_install_get_config_dir ();
362         return mono_cfg_dir;
363 }
364