First part of code to allow configurable hotkeys.
[vlc.git] / src / misc / configuration.c
1 /*****************************************************************************
2  * configuration.c management of the modules configuration
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: configuration.c,v 1.62 2003/08/14 19:25:56 sigmunau Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #include <vlc/vlc.h>
25 #include "vlc_keys.h"
26
27 #include <stdio.h>                                              /* sprintf() */
28 #include <stdlib.h>                                      /* free(), strtol() */
29 #include <string.h>                                              /* strdup() */
30 #ifdef HAVE_ERRNO_H
31 #   include <errno.h>                                               /* errno */
32 #endif
33
34 #ifdef HAVE_UNISTD_H
35 #    include <unistd.h>                                          /* getuid() */
36 #endif
37
38 #ifdef HAVE_GETOPT_LONG
39 #   ifdef HAVE_GETOPT_H
40 #       include <getopt.h>                                       /* getopt() */
41 #   endif
42 #else
43 #   include "../extras/getopt.h"
44 #endif
45
46 #if defined(HAVE_GETPWUID)
47 #   include <pwd.h>                                            /* getpwuid() */
48 #endif
49
50 #if defined( HAVE_SYS_STAT_H )
51 #   include <sys/stat.h>
52 #endif
53 #if defined( HAVE_SYS_TYPES_H )
54 #   include <sys/types.h>
55 #endif
56 #if defined( WIN32 ) && !defined( UNDER_CE )
57 #   include <direct.h>
58 #endif
59
60
61 static int ConfigStringToKey( char * );
62
63 /*****************************************************************************
64  * config_GetType: get the type of a variable (bool, int, float, string)
65  *****************************************************************************
66  * This function is used to get the type of a variable from its name.
67  * Beware, this is quite slow.
68  *****************************************************************************/
69 int __config_GetType( vlc_object_t *p_this, const char *psz_name )
70 {
71     module_config_t *p_config;
72     int i_type;
73
74     p_config = config_FindConfig( p_this, psz_name );
75
76     /* sanity checks */
77     if( !p_config )
78     {
79         return 0;
80     }
81
82     switch( p_config->i_type )
83     {
84     case CONFIG_ITEM_BOOL:
85         i_type = VLC_VAR_BOOL;
86         break;
87
88     case CONFIG_ITEM_INTEGER:
89         i_type = VLC_VAR_INTEGER;
90         break;
91
92     case CONFIG_ITEM_FLOAT:
93         i_type = VLC_VAR_FLOAT;
94         break;
95
96     case CONFIG_ITEM_MODULE:
97     case CONFIG_ITEM_STRING:
98         i_type = VLC_VAR_STRING;
99         break;
100
101     case CONFIG_ITEM_FILE:
102         i_type = VLC_VAR_FILE;
103         break;
104
105     case CONFIG_ITEM_DIRECTORY:
106         i_type = VLC_VAR_DIRECTORY;
107         break;
108
109     default:
110         i_type = 0;
111         break;
112     }
113
114     return i_type;
115 }
116
117 /*****************************************************************************
118  * config_GetInt: get the value of an int variable
119  *****************************************************************************
120  * This function is used to get the value of variables which are internally
121  * represented by an integer (CONFIG_ITEM_INTEGER and
122  * CONFIG_ITEM_BOOL).
123  *****************************************************************************/
124 int __config_GetInt( vlc_object_t *p_this, const char *psz_name )
125 {
126     module_config_t *p_config;
127
128     p_config = config_FindConfig( p_this, psz_name );
129
130     /* sanity checks */
131     if( !p_config )
132     {
133         msg_Err( p_this, "option %s does not exist", psz_name );
134         return -1;
135     }
136     if( (p_config->i_type!=CONFIG_ITEM_INTEGER) &&
137         (p_config->i_type!=CONFIG_ITEM_KEY) &&
138         (p_config->i_type!=CONFIG_ITEM_BOOL) )
139     {
140         msg_Err( p_this, "option %s does not refer to an int", psz_name );
141         return -1;
142     }
143
144     return p_config->i_value;
145 }
146
147 /*****************************************************************************
148  * config_GetFloat: get the value of a float variable
149  *****************************************************************************
150  * This function is used to get the value of variables which are internally
151  * represented by a float (CONFIG_ITEM_FLOAT).
152  *****************************************************************************/
153 float __config_GetFloat( vlc_object_t *p_this, const char *psz_name )
154 {
155     module_config_t *p_config;
156
157     p_config = config_FindConfig( p_this, psz_name );
158
159     /* sanity checks */
160     if( !p_config )
161     {
162         msg_Err( p_this, "option %s does not exist", psz_name );
163         return -1;
164     }
165     if( p_config->i_type != CONFIG_ITEM_FLOAT )
166     {
167         msg_Err( p_this, "option %s does not refer to a float", psz_name );
168         return -1;
169     }
170
171     return p_config->f_value;
172 }
173
174 /*****************************************************************************
175  * config_GetPsz: get the string value of a string variable
176  *****************************************************************************
177  * This function is used to get the value of variables which are internally
178  * represented by a string (CONFIG_ITEM_STRING, CONFIG_ITEM_FILE,
179  * CONFIG_ITEM_DIRECTORY, and CONFIG_ITEM_MODULE).
180  *
181  * Important note: remember to free() the returned char* because it's a
182  *   duplicate of the actual value. It isn't safe to return a pointer to the
183  *   actual value as it can be modified at any time.
184  *****************************************************************************/
185 char * __config_GetPsz( vlc_object_t *p_this, const char *psz_name )
186 {
187     module_config_t *p_config;
188     char *psz_value = NULL;
189
190     p_config = config_FindConfig( p_this, psz_name );
191
192     /* sanity checks */
193     if( !p_config )
194     {
195         msg_Err( p_this, "option %s does not exist", psz_name );
196         return NULL;
197     }
198     if( (p_config->i_type!=CONFIG_ITEM_STRING) &&
199         (p_config->i_type!=CONFIG_ITEM_FILE) &&
200         (p_config->i_type!=CONFIG_ITEM_DIRECTORY) &&
201         (p_config->i_type!=CONFIG_ITEM_MODULE) )
202     {
203         msg_Err( p_this, "option %s does not refer to a string", psz_name );
204         return NULL;
205     }
206
207     /* return a copy of the string */
208     vlc_mutex_lock( p_config->p_lock );
209     if( p_config->psz_value ) psz_value = strdup( p_config->psz_value );
210     vlc_mutex_unlock( p_config->p_lock );
211
212     return psz_value;
213 }
214
215 /*****************************************************************************
216  * config_PutPsz: set the string value of a string variable
217  *****************************************************************************
218  * This function is used to set the value of variables which are internally
219  * represented by a string (CONFIG_ITEM_STRING, CONFIG_ITEM_FILE,
220  * CONFIG_ITEM_DIRECTORY, and CONFIG_ITEM_MODULE).
221  *****************************************************************************/
222 void __config_PutPsz( vlc_object_t *p_this,
223                       const char *psz_name, const char *psz_value )
224 {
225     module_config_t *p_config;
226     vlc_value_t oldval, val;
227
228     p_config = config_FindConfig( p_this, psz_name );
229
230     /* sanity checks */
231     if( !p_config )
232     {
233         msg_Warn( p_this, "option %s does not exist", psz_name );
234         return;
235     }
236     if( (p_config->i_type!=CONFIG_ITEM_STRING) &&
237         (p_config->i_type!=CONFIG_ITEM_FILE) &&
238         (p_config->i_type!=CONFIG_ITEM_DIRECTORY) &&
239         (p_config->i_type!=CONFIG_ITEM_MODULE) )
240     {
241         msg_Err( p_this, "option %s does not refer to a string", psz_name );
242         return;
243     }
244
245     vlc_mutex_lock( p_config->p_lock );
246
247     /* backup old value */
248     oldval.psz_string = p_config->psz_value;
249
250     if( psz_value && *psz_value ) p_config->psz_value = strdup( psz_value );
251     else p_config->psz_value = NULL;
252
253     val.psz_string = p_config->psz_value;
254
255     vlc_mutex_unlock( p_config->p_lock );
256
257     if( p_config->pf_callback )
258     {
259         p_config->pf_callback( p_this, psz_name, oldval, val,
260                                p_config->p_callback_data );
261     }
262
263     /* free old string */
264     if( oldval.psz_string ) free( oldval.psz_string );
265 }
266
267 /*****************************************************************************
268  * config_PutInt: set the integer value of an int variable
269  *****************************************************************************
270  * This function is used to set the value of variables which are internally
271  * represented by an integer (CONFIG_ITEM_INTEGER and
272  * CONFIG_ITEM_BOOL).
273  *****************************************************************************/
274 void __config_PutInt( vlc_object_t *p_this, const char *psz_name, int i_value )
275 {
276     module_config_t *p_config;
277     vlc_value_t oldval, val;
278
279     p_config = config_FindConfig( p_this, psz_name );
280
281     /* sanity checks */
282     if( !p_config )
283     {
284         msg_Warn( p_this, "option %s does not exist", psz_name );
285         return;
286     }
287     if( (p_config->i_type!=CONFIG_ITEM_INTEGER) &&
288         (p_config->i_type!=CONFIG_ITEM_KEY) &&
289         (p_config->i_type!=CONFIG_ITEM_BOOL) )
290     {
291         msg_Err( p_this, "option %s does not refer to an int", psz_name );
292         return;
293     }
294
295     /* backup old value */
296     oldval.i_int = p_config->i_value;
297
298     /* if i_min == i_max == 0, then do not use them */
299     if ((p_config->i_min == 0) && (p_config->i_max == 0))
300     {
301         p_config->i_value = i_value;
302     }
303     else if (i_value < p_config->i_min)
304     {
305         p_config->i_value = p_config->i_min;
306     }
307     else if (i_value > p_config->i_max)
308     {
309         p_config->i_value = p_config->i_max;
310     }
311     else
312     {
313         p_config->i_value = i_value;
314     }
315
316     val.i_int = p_config->i_value;
317
318     if( p_config->pf_callback )
319     {
320         p_config->pf_callback( p_this, psz_name, oldval, val,
321                                p_config->p_callback_data );
322     }
323 }
324
325 /*****************************************************************************
326  * config_PutFloat: set the value of a float variable
327  *****************************************************************************
328  * This function is used to set the value of variables which are internally
329  * represented by a float (CONFIG_ITEM_FLOAT).
330  *****************************************************************************/
331 void __config_PutFloat( vlc_object_t *p_this,
332                         const char *psz_name, float f_value )
333 {
334     module_config_t *p_config;
335     vlc_value_t oldval, val;
336
337     p_config = config_FindConfig( p_this, psz_name );
338
339     /* sanity checks */
340     if( !p_config )
341     {
342         msg_Warn( p_this, "option %s does not exist", psz_name );
343         return;
344     }
345     if( p_config->i_type != CONFIG_ITEM_FLOAT )
346     {
347         msg_Err( p_this, "option %s does not refer to a float", psz_name );
348         return;
349     }
350
351     /* backup old value */
352     oldval.f_float = p_config->f_value;
353
354     /* if f_min == f_max == 0, then do not use them */
355     if ((p_config->f_min == 0) && (p_config->f_max == 0))
356     {
357         p_config->f_value = f_value;
358     }
359     else if (f_value < p_config->f_min)
360     {
361         p_config->f_value = p_config->f_min;
362     }
363     else if (f_value > p_config->f_max)
364     {
365         p_config->f_value = p_config->f_max;
366     }
367     else
368     {
369         p_config->f_value = f_value;
370     }
371
372     val.f_float = p_config->f_value;
373
374     if( p_config->pf_callback )
375     {
376         p_config->pf_callback( p_this, psz_name, oldval, val,
377                                p_config->p_callback_data );
378     }
379 }
380
381 /*****************************************************************************
382  * config_FindConfig: find the config structure associated with an option.
383  *****************************************************************************
384  * FIXME: This function really needs to be optimized.
385  * FIXME: And now even more.
386  *****************************************************************************/
387 module_config_t *config_FindConfig( vlc_object_t *p_this, const char *psz_name )
388 {
389     vlc_list_t *p_list;
390     module_t *p_parser;
391     module_config_t *p_item;
392     int i_index;
393
394     if( !psz_name ) return NULL;
395
396     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
397
398     for( i_index = 0; i_index < p_list->i_count; i_index++ )
399     {
400         p_parser = (module_t *)p_list->p_values[i_index].p_object ;
401
402         if( !p_parser->i_config_items )
403             continue;
404
405         for( p_item = p_parser->p_config;
406              p_item->i_type != CONFIG_HINT_END;
407              p_item++ )
408         {
409             if( p_item->i_type & CONFIG_HINT )
410                 /* ignore hints */
411                 continue;
412             if( !strcmp( psz_name, p_item->psz_name ) )
413             {
414                 vlc_list_release( p_list );
415                 return p_item;
416             }
417         }
418     }
419
420     vlc_list_release( p_list );
421
422     return NULL;
423 }
424
425 /*****************************************************************************
426  * config_Duplicate: creates a duplicate of a module's configuration data.
427  *****************************************************************************
428  * Unfortunatly we cannot work directly with the module's config data as
429  * this module might be unloaded from memory at any time (remember HideModule).
430  * This is why we need to create an exact copy of the config data.
431  *****************************************************************************/
432 void config_Duplicate( module_t *p_module, module_config_t *p_orig )
433 {
434     int i, j, i_lines = 1;
435     module_config_t *p_item;
436
437     /* Calculate the structure length */
438     p_module->i_config_items = 0;
439     p_module->i_bool_items = 0;
440
441     for( p_item = p_orig; p_item->i_type != CONFIG_HINT_END; p_item++ )
442     {
443         i_lines++;
444
445         if( p_item->i_type & CONFIG_ITEM )
446         {
447             p_module->i_config_items++;
448         }
449
450         if( p_item->i_type == CONFIG_ITEM_BOOL )
451         {
452             p_module->i_bool_items++;
453         }
454     }
455
456     /* Allocate memory */
457     p_module->p_config = (module_config_t *)malloc( sizeof(module_config_t)
458                                                      * i_lines );
459     if( p_module->p_config == NULL )
460     {
461         msg_Err( p_module, "config error: can't duplicate p_config" );
462         return;
463     }
464
465     /* Do the duplication job */
466     for( i = 0; i < i_lines ; i++ )
467     {
468         p_module->p_config[i].i_type = p_orig[i].i_type;
469         p_module->p_config[i].i_short = p_orig[i].i_short;
470         p_module->p_config[i].i_value = p_orig[i].i_value;
471         p_module->p_config[i].i_value_orig = p_orig[i].i_value;
472         p_module->p_config[i].i_min = p_orig[i].i_min;
473         p_module->p_config[i].i_max = p_orig[i].i_max;
474         p_module->p_config[i].f_value = p_orig[i].f_value;
475         p_module->p_config[i].f_value_orig = p_orig[i].f_value;
476         p_module->p_config[i].f_min = p_orig[i].f_min;
477         p_module->p_config[i].f_max = p_orig[i].f_max;
478         p_module->p_config[i].b_dirty = p_orig[i].b_dirty;
479         p_module->p_config[i].b_advanced = p_orig[i].b_advanced;
480
481         p_module->p_config[i].psz_type = p_orig[i].psz_type ?
482                                    strdup( p_orig[i].psz_type ) : NULL;
483         p_module->p_config[i].psz_name = p_orig[i].psz_name ?
484                                    strdup( p_orig[i].psz_name ) : NULL;
485         p_module->p_config[i].psz_text = p_orig[i].psz_text ?
486                                    strdup( _(p_orig[i].psz_text) ) : NULL;
487         p_module->p_config[i].psz_longtext = p_orig[i].psz_longtext ?
488                                    strdup( _(p_orig[i].psz_longtext) ) : NULL;
489         p_module->p_config[i].psz_value = p_orig[i].psz_value ?
490                                    strdup( p_orig[i].psz_value ) : NULL;
491         p_module->p_config[i].psz_value_orig = p_orig[i].psz_value ?
492                                    strdup( p_orig[i].psz_value ) : NULL;
493
494         p_module->p_config[i].p_lock = &p_module->object_lock;
495
496         /* duplicate the string list */
497         p_module->p_config[i].ppsz_list = NULL;
498         if( p_orig[i].ppsz_list )
499         {
500             for( j = 0; p_orig[i].ppsz_list[j]; j++ );
501             p_module->p_config[i].ppsz_list = malloc( (j+1) *sizeof(char *) );
502             if( p_module->p_config[i].ppsz_list )
503             {
504                 for( j = 0; p_orig[i].ppsz_list[j]; j++ )
505                     p_module->p_config[i].ppsz_list[j] =
506                         strdup( p_orig[i].ppsz_list[j] );
507             }
508             p_module->p_config[i].ppsz_list[j] = NULL;
509         }
510
511         p_module->p_config[i].pf_callback = p_orig[i].pf_callback;
512     }
513 }
514
515 /*****************************************************************************
516  * config_Free: frees a duplicated module's configuration data.
517  *****************************************************************************
518  * This function frees all the data duplicated by config_Duplicate.
519  *****************************************************************************/
520 void config_Free( module_t *p_module )
521 {
522     module_config_t *p_item = p_module->p_config;
523     int i;
524
525     if( p_item == NULL )
526     {
527         return;
528     }
529
530     for( ; p_item->i_type != CONFIG_HINT_END ; p_item++ )
531     {
532         if( p_item->psz_type )
533             free( p_item->psz_type );
534
535         if( p_item->psz_name )
536             free( p_item->psz_name );
537
538         if( p_item->psz_text )
539             free( p_item->psz_text );
540
541         if( p_item->psz_longtext )
542             free( p_item->psz_longtext );
543
544         if( p_item->psz_value )
545             free( p_item->psz_value );
546
547         if( p_item->psz_value_orig )
548             free( p_item->psz_value_orig );
549
550         if( p_item->ppsz_list )
551         {
552             for( i = 0; p_item->ppsz_list[i]; i++ )
553                 free(p_item->ppsz_list[i]);
554             free( p_item->ppsz_list );
555         }
556     }
557
558     free( p_module->p_config );
559     p_module->p_config = NULL;
560 }
561
562 /*****************************************************************************
563  * config_SetCallbacks: sets callback functions in the duplicate p_config.
564  *****************************************************************************
565  * Unfortunatly we cannot work directly with the module's config data as
566  * this module might be unloaded from memory at any time (remember HideModule).
567  * This is why we need to duplicate callbacks each time we reload the module.
568  *****************************************************************************/
569 void config_SetCallbacks( module_config_t *p_new, module_config_t *p_orig )
570 {
571     while( p_new->i_type != CONFIG_HINT_END )
572     {
573         p_new->pf_callback = p_orig->pf_callback;
574         p_new++;
575         p_orig++;
576     }
577 }
578
579 /*****************************************************************************
580  * config_UnsetCallbacks: unsets callback functions in the duplicate p_config.
581  *****************************************************************************
582  * We simply undo what we did in config_SetCallbacks.
583  *****************************************************************************/
584 void config_UnsetCallbacks( module_config_t *p_new )
585 {
586     while( p_new->i_type != CONFIG_HINT_END )
587     {
588         p_new->pf_callback = NULL;
589         p_new++;
590     }
591 }
592
593 /*****************************************************************************
594  * config_ResetAll: reset the configuration data for all the modules.
595  *****************************************************************************/
596 void __config_ResetAll( vlc_object_t *p_this )
597 {
598     int i_index, i;
599     vlc_list_t *p_list;
600     module_t *p_module;
601
602     /* Acquire config file lock */
603     vlc_mutex_lock( &p_this->p_vlc->config_lock );
604
605     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
606
607     for( i_index = 0; i_index < p_list->i_count; i_index++ )
608     {
609         p_module = (module_t *)p_list->p_values[i_index].p_object ;
610         if( p_module->b_submodule ) continue;
611
612         for( i = 0; p_module->p_config[i].i_type != CONFIG_HINT_END; i++ )
613         {
614             p_module->p_config[i].i_value = p_module->p_config[i].i_value_orig;
615             p_module->p_config[i].f_value = p_module->p_config[i].f_value_orig;
616             if( p_module->p_config[i].psz_value )
617                 free( p_module->p_config[i].psz_value );
618             p_module->p_config[i].psz_value =
619                 p_module->p_config[i].psz_value_orig ?
620                 strdup( p_module->p_config[i].psz_value_orig ) : NULL;
621         }
622     }
623
624     vlc_list_release( p_list );
625     vlc_mutex_unlock( &p_this->p_vlc->config_lock );
626 }
627
628 /*****************************************************************************
629  * config_LoadConfigFile: loads the configuration file.
630  *****************************************************************************
631  * This function is called to load the config options stored in the config
632  * file.
633  *****************************************************************************/
634 int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
635 {
636     vlc_list_t *p_list;
637     module_t *p_parser;
638     module_config_t *p_item;
639     FILE *file;
640     char line[1024];
641     char *p_index, *psz_option_name, *psz_option_value;
642     char *psz_filename, *psz_homedir;
643     int i_index;
644
645     psz_homedir = p_this->p_vlc->psz_homedir;
646     if( !psz_homedir )
647     {
648         msg_Err( p_this, "psz_homedir is null" );
649         return -1;
650     }
651     psz_filename = (char *)malloc( strlen("/" CONFIG_DIR "/" CONFIG_FILE) +
652                                    strlen(psz_homedir) + 1 );
653     if( !psz_filename )
654     {
655         msg_Err( p_this, "out of memory" );
656         return -1;
657     }
658     sprintf( psz_filename, "%s/" CONFIG_DIR "/" CONFIG_FILE, psz_homedir );
659
660     msg_Dbg( p_this, "opening config file %s", psz_filename );
661
662     /* Acquire config file lock */
663     vlc_mutex_lock( &p_this->p_vlc->config_lock );
664
665     file = fopen( psz_filename, "rt" );
666     if( !file )
667     {
668         msg_Warn( p_this, "config file %s does not exist yet", psz_filename );
669         free( psz_filename );
670         vlc_mutex_unlock( &p_this->p_vlc->config_lock );
671         return -1;
672     }
673
674     /* Look for the selected module, if NULL then save everything */
675     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
676
677     for( i_index = 0; i_index < p_list->i_count; i_index++ )
678     {
679         p_parser = (module_t *)p_list->p_values[i_index].p_object ;
680
681         if( psz_module_name
682              && strcmp( psz_module_name, p_parser->psz_object_name ) )
683         {
684             continue;
685         }
686
687         /* The config file is organized in sections, one per module. Look for
688          * the interesting section ( a section is of the form [foo] ) */
689         fseek( file, 0L, SEEK_SET );
690         while( fgets( line, 1024, file ) )
691         {
692             if( (line[0] == '[')
693                && (p_index = strchr(line,']'))
694                && (p_index - &line[1]
695                     == (int)strlen(p_parser->psz_object_name))
696                && !memcmp( &line[1], p_parser->psz_object_name,
697                            strlen(p_parser->psz_object_name) ) )
698             {
699 #if 0
700                 msg_Dbg( p_this, "loading config for module \"%s\"",
701                                  p_parser->psz_object_name );
702 #endif
703
704                 break;
705             }
706         }
707         /* either we found the section or we're at the EOF */
708
709         /* Now try to load the options in this section */
710         while( fgets( line, 1024, file ) )
711         {
712             if( line[0] == '[' ) break; /* end of section */
713
714             /* ignore comments or empty lines */
715             if( (line[0] == '#') || (line[0] == '\n') || (line[0] == (char)0) )
716                 continue;
717
718             /* get rid of line feed */
719             if( line[strlen(line)-1] == '\n' )
720                 line[strlen(line)-1] = (char)0;
721
722             /* look for option name */
723             psz_option_name = line;
724             psz_option_value = NULL;
725             p_index = strchr( line, '=' );
726             if( !p_index ) break; /* this ain't an option!!! */
727
728             *p_index = (char)0;
729             psz_option_value = p_index + 1;
730
731             if( !p_parser->i_config_items )
732             {
733                 continue;
734             }
735
736             /* try to match this option with one of the module's options */
737             for( p_item = p_parser->p_config;
738                  p_item->i_type != CONFIG_HINT_END;
739                  p_item++ )
740             {
741                 if( p_item->i_type & CONFIG_HINT )
742                     /* ignore hints */
743                     continue;
744
745                 if( !strcmp( p_item->psz_name, psz_option_name ) )
746                 {
747                     /* We found it */
748                     switch( p_item->i_type )
749                     {
750                     case CONFIG_ITEM_BOOL:
751                     case CONFIG_ITEM_INTEGER:
752                         if( !*psz_option_value )
753                             break;                    /* ignore empty option */
754                         p_item->i_value = atoi( psz_option_value);
755 #if 0
756                         msg_Dbg( p_this, "option \"%s\", value %i",
757                                  p_item->psz_name, p_item->i_value );
758 #endif
759                         break;
760
761                     case CONFIG_ITEM_FLOAT:
762                         if( !*psz_option_value )
763                             break;                    /* ignore empty option */
764                         p_item->f_value = (float)atof( psz_option_value);
765 #if O
766                         msg_Dbg( p_this, "option \"%s\", value %f",
767                                  p_item->psz_name, (double)p_item->f_value );
768 #endif
769                         break;
770                     case CONFIG_ITEM_KEY:
771                         if( !*psz_option_value )
772                             break;                    /* ignore empty option */
773                         p_item->i_value = ConfigStringToKey( psz_option_value );
774                         break;
775
776                     default:
777                         vlc_mutex_lock( p_item->p_lock );
778
779                         /* free old string */
780                         if( p_item->psz_value )
781                             free( p_item->psz_value );
782
783                         p_item->psz_value = *psz_option_value ?
784                             strdup( psz_option_value ) : NULL;
785
786                         vlc_mutex_unlock( p_item->p_lock );
787
788 #if 0
789                         msg_Dbg( p_this, "option \"%s\", value \"%s\"",
790                                  p_item->psz_name,
791                                  p_item->psz_value ? p_item->psz_value : "" );
792 #endif
793                         break;
794                     }
795                 }
796             }
797         }
798
799     }
800
801     vlc_list_release( p_list );
802
803     fclose( file );
804     free( psz_filename );
805
806     vlc_mutex_unlock( &p_this->p_vlc->config_lock );
807
808     return 0;
809 }
810
811 /*****************************************************************************
812  * config_SaveConfigFile: Save a module's config options.
813  *****************************************************************************
814  * This will save the specified module's config options to the config file.
815  * If psz_module_name is NULL then we save all the modules config options.
816  * It's no use to save the config options that kept their default values, so
817  * we'll try to be a bit clever here.
818  *
819  * When we save we mustn't delete the config options of the modules that
820  * haven't been loaded. So we cannot just create a new config file with the
821  * config structures we've got in memory.
822  * I don't really know how to deal with this nicely, so I will use a completly
823  * dumb method ;-)
824  * I will load the config file in memory, but skipping all the sections of the
825  * modules we want to save. Then I will create a brand new file, dump the file
826  * loaded in memory and then append the sections of the modules we want to
827  * save.
828  * Really stupid no ?
829  *****************************************************************************/
830 int __config_SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name )
831 {
832     module_t *p_parser;
833     vlc_list_t *p_list;
834     module_config_t *p_item;
835     FILE *file;
836     char p_line[1024], *p_index2;
837     int i_sizebuf = 0;
838     char *p_bigbuffer, *p_index;
839     vlc_bool_t b_backup;
840     char *psz_filename, *psz_homedir;
841     int i_index;
842
843     /* Acquire config file lock */
844     vlc_mutex_lock( &p_this->p_vlc->config_lock );
845
846     psz_homedir = p_this->p_vlc->psz_homedir;
847     if( !psz_homedir )
848     {
849         msg_Err( p_this, "psz_homedir is null" );
850         vlc_mutex_unlock( &p_this->p_vlc->config_lock );
851         return -1;
852     }
853     psz_filename = (char *)malloc( strlen("/" CONFIG_DIR "/" CONFIG_FILE) +
854                                    strlen(psz_homedir) + 1 );
855     if( !psz_filename )
856     {
857         msg_Err( p_this, "out of memory" );
858         vlc_mutex_unlock( &p_this->p_vlc->config_lock );
859         return -1;
860     }
861     sprintf( psz_filename, "%s/" CONFIG_DIR, psz_homedir );
862
863 #if defined( UNDER_CE )
864     {
865         wchar_t psz_new[ MAX_PATH ];
866         MultiByteToWideChar( CP_ACP, 0, psz_filename, -1, psz_new, MAX_PATH );
867         if( CreateDirectory( psz_new, NULL ) )
868         {
869             msg_Err( p_this, "could not create %s", psz_filename );
870         }
871     }
872
873 #elif defined( HAVE_ERRNO_H )
874 #   if defined( WIN32 )
875     if( mkdir( psz_filename ) && errno != EEXIST )
876 #   else
877     if( mkdir( psz_filename, 0755 ) && errno != EEXIST )
878 #   endif
879     {
880         msg_Err( p_this, "could not create %s (%s)",
881                          psz_filename, strerror(errno) );
882     }
883
884 #else
885     if( mkdir( psz_filename ) )
886     {
887         msg_Err( p_this, "could not create %s", psz_filename );
888     }
889
890 #endif
891
892     strcat( psz_filename, "/" CONFIG_FILE );
893
894
895     msg_Dbg( p_this, "opening config file %s", psz_filename );
896
897     file = fopen( psz_filename, "rt" );
898     if( !file )
899     {
900         msg_Warn( p_this, "config file %s does not exist yet", psz_filename );
901     }
902     else
903     {
904         /* look for file size */
905         fseek( file, 0L, SEEK_END );
906         i_sizebuf = ftell( file );
907         fseek( file, 0L, SEEK_SET );
908     }
909
910     p_bigbuffer = p_index = malloc( i_sizebuf+1 );
911     if( !p_bigbuffer )
912     {
913         msg_Err( p_this, "out of memory" );
914         if( file ) fclose( file );
915         free( psz_filename );
916         vlc_mutex_unlock( &p_this->p_vlc->config_lock );
917         return -1;
918     }
919     p_bigbuffer[0] = 0;
920
921     /* List all available modules */
922     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
923
924     /* backup file into memory, we only need to backup the sections we won't
925      * save later on */
926     b_backup = 0;
927     while( file && fgets( p_line, 1024, file ) )
928     {
929         if( (p_line[0] == '[') && (p_index2 = strchr(p_line,']')))
930         {
931
932             /* we found a section, check if we need to do a backup */
933             for( i_index = 0; i_index < p_list->i_count; i_index++ )
934             {
935                 p_parser = (module_t *)p_list->p_values[i_index].p_object ;
936
937                 if( ((p_index2 - &p_line[1])
938                        == (int)strlen(p_parser->psz_object_name) )
939                     && !memcmp( &p_line[1], p_parser->psz_object_name,
940                                 strlen(p_parser->psz_object_name) ) )
941                 {
942                     if( !psz_module_name )
943                         break;
944                     else if( !strcmp( psz_module_name,
945                                       p_parser->psz_object_name ) )
946                         break;
947                 }
948             }
949
950             if( i_index == p_list->i_count )
951             {
952                 /* we don't have this section in our list so we need to back
953                  * it up */
954                 *p_index2 = 0;
955                 msg_Dbg( p_this, "backing up config for unknown module \"%s\"",
956                                  &p_line[1] );
957                 *p_index2 = ']';
958
959                 b_backup = 1;
960             }
961             else
962             {
963                 b_backup = 0;
964             }
965         }
966
967         /* save line if requested and line is valid (doesn't begin with a
968          * space, tab, or eol) */
969         if( b_backup && (p_line[0] != '\n') && (p_line[0] != ' ')
970             && (p_line[0] != '\t') )
971         {
972             strcpy( p_index, p_line );
973             p_index += strlen( p_line );
974         }
975     }
976     if( file ) fclose( file );
977
978
979     /*
980      * Save module config in file
981      */
982
983     file = fopen( psz_filename, "wt" );
984     if( !file )
985     {
986         msg_Warn( p_this, "could not open config file %s for writing",
987                           psz_filename );
988         free( psz_filename );
989         vlc_list_release( p_list );
990         vlc_mutex_unlock( &p_this->p_vlc->config_lock );
991         return -1;
992     }
993
994     fprintf( file, "###\n###  " COPYRIGHT_MESSAGE "\n###\n\n" );
995
996     /* Look for the selected module, if NULL then save everything */
997     for( i_index = 0; i_index < p_list->i_count; i_index++ )
998     {
999         p_parser = (module_t *)p_list->p_values[i_index].p_object ;
1000
1001         if( psz_module_name && strcmp( psz_module_name,
1002                                        p_parser->psz_object_name ) )
1003             continue;
1004
1005         if( !p_parser->i_config_items )
1006             continue;
1007
1008         msg_Dbg( p_this, "saving config for module \"%s\"",
1009                          p_parser->psz_object_name );
1010
1011         fprintf( file, "[%s]", p_parser->psz_object_name );
1012         if( p_parser->psz_longname )
1013             fprintf( file, " # %s\n\n", p_parser->psz_longname );
1014         else
1015             fprintf( file, "\n\n" );
1016
1017         for( p_item = p_parser->p_config;
1018              p_item->i_type != CONFIG_HINT_END;
1019              p_item++ )
1020         {
1021             char *psz_key;
1022             if( p_item->i_type & CONFIG_HINT )
1023                 /* ignore hints */
1024                 continue;
1025
1026             switch( p_item->i_type )
1027             {
1028             case CONFIG_ITEM_BOOL:
1029             case CONFIG_ITEM_INTEGER:
1030                 if( p_item->psz_text )
1031                     fprintf( file, "# %s (%s)\n", p_item->psz_text,
1032                              (p_item->i_type == CONFIG_ITEM_BOOL) ?
1033                              _("boolean") : _("integer") );
1034                 if( p_item->i_value == p_item->i_value_orig )
1035                     fprintf( file, "#" );
1036                 fprintf( file, "%s=%i\n", p_item->psz_name, p_item->i_value );
1037                 break;
1038             case CONFIG_ITEM_KEY:
1039                 if( p_item->psz_text )
1040                     fprintf( file, "# %s (%s)\n", p_item->psz_text,
1041                              _("key") );
1042                 psz_key = ConfigKeyToString( p_item->i_value );
1043                 fprintf( file, "%s=%s\n", p_item->psz_name,
1044                          psz_key ? psz_key : "" );
1045                 if ( psz_key ) free( psz_key );
1046                 break;
1047                 
1048             case CONFIG_ITEM_FLOAT:
1049                 if( p_item->psz_text )
1050                     fprintf( file, "# %s (%s)\n", p_item->psz_text,
1051                              _("float") );
1052                 if( p_item->f_value == p_item->f_value_orig )
1053                     fprintf( file, "#" );
1054                 fprintf( file, "%s=%f\n", p_item->psz_name,
1055                          (double)p_item->f_value );
1056                 break;
1057
1058             default:
1059                 if( p_item->psz_text )
1060                     fprintf( file, "# %s (%s)\n", p_item->psz_text,
1061                              _("string") );
1062                 if( (!p_item->psz_value && !p_item->psz_value_orig) ||
1063                     (p_item->psz_value && p_item->psz_value_orig &&
1064                      !strcmp( p_item->psz_value, p_item->psz_value_orig )) )
1065                     fprintf( file, "#" );
1066                 fprintf( file, "%s=%s\n", p_item->psz_name,
1067                          p_item->psz_value ? p_item->psz_value : "" );
1068             }
1069         }
1070
1071         fprintf( file, "\n" );
1072     }
1073
1074     vlc_list_release( p_list );
1075
1076     /*
1077      * Restore old settings from the config in file
1078      */
1079     fputs( p_bigbuffer, file );
1080     free( p_bigbuffer );
1081
1082     fclose( file );
1083     free( psz_filename );
1084     vlc_mutex_unlock( &p_this->p_vlc->config_lock );
1085
1086     return 0;
1087 }
1088
1089 /*****************************************************************************
1090  * config_LoadCmdLine: parse command line
1091  *****************************************************************************
1092  * Parse command line for configuration options.
1093  * Now that the module_bank has been initialized, we can dynamically
1094  * generate the longopts structure used by getops. We have to do it this way
1095  * because we don't know (and don't want to know) in advance the configuration
1096  * options used (ie. exported) by each module.
1097  *****************************************************************************/
1098 int __config_LoadCmdLine( vlc_object_t *p_this, int *pi_argc, char *ppsz_argv[],
1099                           vlc_bool_t b_ignore_errors )
1100 {
1101     int i_cmd, i_index, i_opts, i_shortopts, flag, i_verbose = 0;
1102     module_t *p_parser;
1103     vlc_list_t *p_list;
1104     module_config_t *p_item;
1105     struct option *p_longopts;
1106     int i_modules_index;
1107
1108     /* Short options */
1109     module_config_t *pp_shortopts[256];
1110     char *psz_shortopts;
1111
1112     /* Set default configuration and copy arguments */
1113     p_this->p_vlc->i_argc    = *pi_argc;
1114     p_this->p_vlc->ppsz_argv = ppsz_argv;
1115
1116     p_this->p_vlc->p_channel = NULL;
1117
1118 #ifdef SYS_DARWIN
1119     /* When vlc.app is run by double clicking in Mac OS X, the 2nd arg
1120      * is the PSN - process serial number (a unique PID-ish thingie)
1121      * still ok for real Darwin & when run from command line */
1122     if ( (*pi_argc > 1) && (strncmp( ppsz_argv[ 1 ] , "-psn" , 4 ) == 0) )
1123                                         /* for example -psn_0_9306113 */
1124     {
1125         /* GDMF!... I can't do this or else the MacOSX window server will
1126          * not pick up the PSN and not register the app and we crash...
1127          * hence the following kludge otherwise we'll get confused w/ argv[1]
1128          * being an input file name */
1129 #if 0
1130         ppsz_argv[ 1 ] = NULL;
1131 #endif
1132         *pi_argc = *pi_argc - 1;
1133         pi_argc--;
1134         return 0;
1135     }
1136 #endif
1137
1138     /* List all modules */
1139     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
1140
1141     /*
1142      * Generate the longopts and shortopts structures used by getopt_long
1143      */
1144
1145     i_opts = 0;
1146     for( i_modules_index = 0; i_modules_index < p_list->i_count;
1147          i_modules_index++ )
1148     {
1149         p_parser = (module_t *)p_list->p_values[i_modules_index].p_object ;
1150
1151         /* count the number of exported configuration options (to allocate
1152          * longopts). We also need to allocate space for too options when
1153          * dealing with boolean to allow for --foo and --no-foo */
1154         i_opts += p_parser->i_config_items
1155                      + 2 * p_parser->i_bool_items;
1156     }
1157
1158     p_longopts = malloc( sizeof(struct option) * (i_opts + 1) );
1159     if( p_longopts == NULL )
1160     {
1161         msg_Err( p_this, "out of memory" );
1162         vlc_list_release( p_list );
1163         return -1;
1164     }
1165
1166     psz_shortopts = malloc( sizeof( char ) * (2 * i_opts + 1) );
1167     if( psz_shortopts == NULL )
1168     {
1169         msg_Err( p_this, "out of memory" );
1170         free( p_longopts );
1171         vlc_list_release( p_list );
1172         return -1;
1173     }
1174
1175     /* If we are requested to ignore errors, then we must work on a copy
1176      * of the ppsz_argv array, otherwise getopt_long will reorder it for
1177      * us, ignoring the arity of the options */
1178     if( b_ignore_errors )
1179     {
1180         ppsz_argv = (char**)malloc( *pi_argc * sizeof(char *) );
1181         if( ppsz_argv == NULL )
1182         {
1183             msg_Err( p_this, "out of memory" );
1184             free( psz_shortopts );
1185             free( p_longopts );
1186             vlc_list_release( p_list );
1187             return -1;
1188         }
1189         memcpy( ppsz_argv, p_this->p_vlc->ppsz_argv,
1190                 *pi_argc * sizeof(char *) );
1191     }
1192
1193     i_shortopts = 0;
1194     for( i_index = 0; i_index < 256; i_index++ )
1195     {
1196         pp_shortopts[i_index] = NULL;
1197     }
1198
1199     /* Fill the p_longopts and psz_shortopts structures */
1200     i_index = 0;
1201     for( i_modules_index = 0; i_modules_index < p_list->i_count;
1202          i_modules_index++ )
1203     {
1204         p_parser = (module_t *)p_list->p_values[i_modules_index].p_object ;
1205
1206         if( !p_parser->i_config_items )
1207             continue;
1208
1209         for( p_item = p_parser->p_config;
1210              p_item->i_type != CONFIG_HINT_END;
1211              p_item++ )
1212         {
1213             /* Ignore hints */
1214             if( p_item->i_type & CONFIG_HINT )
1215                 continue;
1216
1217             /* Add item to long options */
1218             p_longopts[i_index].name = strdup( p_item->psz_name );
1219             if( p_longopts[i_index].name == NULL ) continue;
1220             p_longopts[i_index].has_arg =
1221                 (p_item->i_type == CONFIG_ITEM_BOOL)?
1222                                                no_argument : required_argument;
1223             p_longopts[i_index].flag = &flag;
1224             p_longopts[i_index].val = 0;
1225             i_index++;
1226
1227             /* When dealing with bools we also need to add the --no-foo
1228              * option */
1229             if( p_item->i_type == CONFIG_ITEM_BOOL )
1230             {
1231                 char *psz_name = malloc( strlen(p_item->psz_name) + 3 );
1232                 if( psz_name == NULL ) continue;
1233                 strcpy( psz_name, "no" );
1234                 strcat( psz_name, p_item->psz_name );
1235
1236                 p_longopts[i_index].name = psz_name;
1237                 p_longopts[i_index].has_arg = no_argument;
1238                 p_longopts[i_index].flag = &flag;
1239                 p_longopts[i_index].val = 1;
1240                 i_index++;
1241
1242                 psz_name = malloc( strlen(p_item->psz_name) + 4 );
1243                 if( psz_name == NULL ) continue;
1244                 strcpy( psz_name, "no-" );
1245                 strcat( psz_name, p_item->psz_name );
1246
1247                 p_longopts[i_index].name = psz_name;
1248                 p_longopts[i_index].has_arg = no_argument;
1249                 p_longopts[i_index].flag = &flag;
1250                 p_longopts[i_index].val = 1;
1251                 i_index++;
1252             }
1253
1254             /* If item also has a short option, add it */
1255             if( p_item->i_short )
1256             {
1257                 pp_shortopts[(int)p_item->i_short] = p_item;
1258                 psz_shortopts[i_shortopts] = p_item->i_short;
1259                 i_shortopts++;
1260                 if( p_item->i_type != CONFIG_ITEM_BOOL )
1261                 {
1262                     psz_shortopts[i_shortopts] = ':';
1263                     i_shortopts++;
1264
1265                     if( p_item->i_short == 'v' )
1266                     {
1267                         psz_shortopts[i_shortopts] = ':';
1268                         i_shortopts++;
1269                     }
1270                 }
1271             }
1272         }
1273     }
1274
1275     /* We don't need the module list anymore */
1276     vlc_list_release( p_list );
1277
1278     /* Close the longopts and shortopts structures */
1279     memset( &p_longopts[i_index], 0, sizeof(struct option) );
1280     psz_shortopts[i_shortopts] = '\0';
1281
1282     /*
1283      * Parse the command line options
1284      */
1285     opterr = 0;
1286     optind = 1;
1287     while( ( i_cmd = getopt_long( *pi_argc, ppsz_argv, psz_shortopts,
1288                                   p_longopts, &i_index ) ) != EOF )
1289     {
1290         /* A long option has been recognized */
1291         if( i_cmd == 0 )
1292         {
1293             module_config_t *p_conf;
1294             char *psz_name = (char *)p_longopts[i_index].name;
1295
1296             /* Check if we deal with a --nofoo or --no-foo long option */
1297             if( flag ) psz_name += psz_name[2] == '-' ? 3 : 2;
1298
1299             /* Store the configuration option */
1300             p_conf = config_FindConfig( p_this, psz_name );
1301
1302             if( p_conf ) switch( p_conf->i_type )
1303             {
1304             case CONFIG_ITEM_STRING:
1305             case CONFIG_ITEM_FILE:
1306             case CONFIG_ITEM_DIRECTORY:
1307             case CONFIG_ITEM_MODULE:
1308                 config_PutPsz( p_this, psz_name, optarg );
1309                 break;
1310             case CONFIG_ITEM_INTEGER:
1311                 config_PutInt( p_this, psz_name, atoi(optarg));
1312                 break;
1313             case CONFIG_ITEM_FLOAT:
1314                 config_PutFloat( p_this, psz_name, (float)atof(optarg) );
1315                 break;
1316             case CONFIG_ITEM_KEY:
1317                 config_PutInt( p_this, psz_name, ConfigStringToKey( optarg ) );
1318                 break;
1319             case CONFIG_ITEM_BOOL:
1320                 config_PutInt( p_this, psz_name, !flag );
1321                 break;
1322             }
1323
1324             continue;
1325         }
1326
1327         /* A short option has been recognized */
1328         if( pp_shortopts[i_cmd] != NULL )
1329         {
1330             switch( pp_shortopts[i_cmd]->i_type )
1331             {
1332             case CONFIG_ITEM_STRING:
1333             case CONFIG_ITEM_FILE:
1334             case CONFIG_ITEM_DIRECTORY:
1335             case CONFIG_ITEM_MODULE:
1336                 config_PutPsz( p_this, pp_shortopts[i_cmd]->psz_name, optarg );
1337                 break;
1338             case CONFIG_ITEM_INTEGER:
1339                 if( i_cmd == 'v' )
1340                 {
1341                     if( optarg )
1342                     {
1343                         if( *optarg == 'v' ) /* eg. -vvv */
1344                         {
1345                             i_verbose++;
1346                             while( *optarg == 'v' )
1347                             {
1348                                 i_verbose++;
1349                                 optarg++;
1350                             }
1351                         }
1352                         else
1353                         {
1354                             i_verbose += atoi( optarg ); /* eg. -v2 */
1355                         }
1356                     }
1357                     else
1358                     {
1359                         i_verbose++; /* -v */
1360                     }
1361                     config_PutInt( p_this, pp_shortopts[i_cmd]->psz_name,
1362                                            i_verbose );
1363                 }
1364                 else
1365                 {
1366                     config_PutInt( p_this, pp_shortopts[i_cmd]->psz_name,
1367                                            atoi(optarg) );
1368                 }
1369                 break;
1370             case CONFIG_ITEM_BOOL:
1371                 config_PutInt( p_this, pp_shortopts[i_cmd]->psz_name, 1 );
1372                 break;
1373             }
1374
1375             continue;
1376         }
1377
1378         /* Internal error: unknown option */
1379         if( !b_ignore_errors )
1380         {
1381             fprintf( stderr, "%s: unknown option ",
1382                              p_this->p_vlc->psz_object_name );
1383             if( optopt )
1384             {
1385                 fprintf( stderr, "`-%c'\n", optopt );
1386             }
1387             else
1388             {
1389                 fprintf( stderr, "`%s'\n", ppsz_argv[optind-1] );
1390             }
1391             fprintf( stderr, "Try `%s --help' for more information.\n",
1392                              p_this->p_vlc->psz_object_name );
1393
1394             free( p_longopts );
1395             free( psz_shortopts );
1396             return -1;
1397         }
1398     }
1399
1400     /* Free allocated resources */
1401     for( i_index = 0; p_longopts[i_index].name; i_index++ )
1402         free( (char *)p_longopts[i_index].name );
1403     free( p_longopts );
1404     free( psz_shortopts );
1405     if( b_ignore_errors ) free( ppsz_argv );
1406
1407     return 0;
1408 }
1409
1410 /*****************************************************************************
1411  * config_GetHomeDir: find the user's home directory.
1412  *****************************************************************************
1413  * This function will try by different ways to find the user's home path.
1414  * Note that this function is not reentrant, it should be called only once
1415  * at the beginning of main where the result will be stored for later use.
1416  *****************************************************************************/
1417 char *config_GetHomeDir( void )
1418 {
1419     char *p_tmp, *p_homedir = NULL;
1420
1421 #if defined(HAVE_GETPWUID)
1422     struct passwd *p_pw = NULL;
1423 #endif
1424
1425 #if defined(WIN32) || defined(UNDER_CE)
1426     typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD,
1427                                                LPTSTR );
1428 #   define CSIDL_FLAG_CREATE 0x8000
1429 #   define CSIDL_APPDATA 0x1A
1430 #   define SHGFP_TYPE_CURRENT 0
1431
1432     HINSTANCE shfolder_dll;
1433     SHGETFOLDERPATH SHGetFolderPath ;
1434
1435     /* load the shfolder dll to retrieve SHGetFolderPath */
1436     if( ( shfolder_dll = LoadLibrary("shfolder.dll") ) != NULL )
1437     {
1438         SHGetFolderPath = (void *)GetProcAddress( shfolder_dll,
1439                                                   "SHGetFolderPathA" );
1440         if ( SHGetFolderPath != NULL )
1441         {
1442             p_homedir = (char *)malloc( MAX_PATH );
1443             if( !p_homedir )
1444             {
1445                 return NULL;
1446             }
1447
1448             /* get the "Application Data" folder for the current user */
1449             if( S_OK == SHGetFolderPath( NULL,
1450                                          CSIDL_APPDATA | CSIDL_FLAG_CREATE,
1451                                          NULL, SHGFP_TYPE_CURRENT,
1452                                          p_homedir ) )
1453             {
1454                 FreeLibrary( shfolder_dll );
1455                 return p_homedir;
1456             }
1457             free( p_homedir );
1458         }
1459         FreeLibrary( shfolder_dll );
1460     }
1461 #endif
1462
1463 #if defined(HAVE_GETPWUID)
1464     if( ( p_pw = getpwuid( getuid() ) ) == NULL )
1465 #endif
1466     {
1467         if( ( p_tmp = getenv( "HOME" ) ) == NULL )
1468         {
1469             if( ( p_tmp = getenv( "TMP" ) ) == NULL )
1470             {
1471                 p_tmp = "/tmp";
1472             }
1473         }
1474
1475         p_homedir = strdup( p_tmp );
1476     }
1477 #if defined(HAVE_GETPWUID)
1478     else
1479     {
1480         p_homedir = strdup( p_pw->pw_dir );
1481     }
1482 #endif
1483
1484     return p_homedir;
1485 }
1486
1487
1488
1489 static int ConfigStringToKey( char *psz_key )
1490 {
1491     int i_key = 0;
1492     unsigned int i;
1493     char *psz_parser = strchr( psz_key, '-' );
1494     while( psz_parser && psz_parser != psz_key )
1495     {
1496         for ( i = 0; i < sizeof(modifiers) / sizeof(key_descriptor_t); i++ )
1497         {
1498             if ( !strncasecmp( modifiers[i].psz_key_string, psz_key, strlen( modifiers[i].psz_key_string ) ) )
1499             {
1500                 i_key |= modifiers[i].i_key_code;
1501             }
1502         }
1503         psz_key = psz_parser + 1;
1504         psz_parser = strchr( psz_key, '-' );
1505     }
1506     for ( i = 0; i < sizeof(keys) / sizeof( key_descriptor_t ); i++ )
1507     {
1508         if ( !strcasecmp( keys[i].psz_key_string, psz_key ) )
1509         {
1510             i_key |= keys[i].i_key_code;
1511             break;
1512         }
1513     }
1514     return i_key;
1515 }
1516
1517
1518 static char *ConfigKeyToString( int i_key )
1519 {
1520     char *psz_key = malloc( 100 );
1521     char *p;
1522     int i;
1523     if ( !psz_key )
1524     {
1525         return NULL;
1526     }
1527     *psz_key = '\0';
1528     p = psz_key;
1529     for( i = 0; i < sizeof(modifiers) / sizeof(key_descriptor_t); i++ )
1530     {
1531         if ( i_key & modifiers[i].i_key_code )
1532         {
1533             p += sprintf( p, "%s-", modifiers[i].psz_key_string );
1534         }
1535     }
1536     for( i = 0; i < sizeof(keys) / sizeof( key_descriptor_t); i++)
1537     {
1538         if ( ( i_key & ~KEY_MODIFIER ) == keys[i].i_key_code )
1539         {
1540             p += sprintf( p, "%s", keys[i].psz_key_string );
1541             break;
1542         }
1543     }
1544     return psz_key;
1545 }