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