Search
lxdream.org :: lxdream/src/config.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/config.c
changeset 1041:5fcc39857c5c
prev1038:f220d18c0615
next1072:d82e04e6d497
author nkeynes
date Fri Jun 26 05:47:04 2009 +0000 (13 years ago)
permissions -rw-r--r--
last change Refactor path operations into lxpaths.[ch]
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * User configuration support
     5  *
     6  * Copyright (c) 2005 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    19 #include <unistd.h>
    20 #include <stdio.h>
    21 #include <errno.h>
    22 #include <stdlib.h>
    23 #include <string.h>
    24 #include <glib/gmem.h>
    25 #include <glib/gstrfuncs.h>
    26 #include <sys/types.h>
    27 #include <sys/stat.h>
    28 #include "dream.h"
    29 #include "config.h"
    30 #include "lxpaths.h"
    31 #include "maple/maple.h"
    33 #define MAX_ROOT_GROUPS 16
    35 extern struct lxdream_config_entry alsa_config[];
    36 extern struct lxdream_config_entry hotkeys_config[];
    38 gboolean lxdream_load_config_file( const gchar *filename );
    39 gboolean lxdream_save_config_file( const gchar *filename );
    40 gboolean lxdream_load_config_stream( FILE *f );
    41 gboolean lxdream_save_config_stream( FILE *f );
    43 static struct lxdream_config_entry global_config[] =
    44        {{ "bios", N_("Bios ROM"), CONFIG_TYPE_FILE, NULL },
    45         { "flash", N_("Flash ROM"), CONFIG_TYPE_FILE, NULL },
    46         { "default path", N_("Default disc path"), CONFIG_TYPE_PATH, "." },
    47         { "save path", N_("Save-state path"), CONFIG_TYPE_PATH, NULL },
    48         { "vmu path", N_("VMU path"), CONFIG_TYPE_PATH, NULL },
    49         { "bootstrap", N_("Bootstrap IP.BIN"), CONFIG_TYPE_FILE, NULL },
    50         { "gdrom", NULL, CONFIG_TYPE_FILE, NULL },
    51         { "recent", NULL, CONFIG_TYPE_FILELIST, NULL },
    52         { "vmu", NULL, CONFIG_TYPE_FILELIST, NULL },
    53         { "quick state", NULL, CONFIG_TYPE_INTEGER, "0" },
    54         { NULL, CONFIG_TYPE_NONE }};
    56 static struct lxdream_config_entry serial_config[] =
    57        {{ "device", N_("Serial device"), CONFIG_TYPE_FILE, "/dev/ttyS1" },
    58         { NULL, CONFIG_TYPE_NONE }};
    60 struct lxdream_config_group lxdream_config_root[MAX_ROOT_GROUPS+1] = 
    61        {{ "global", global_config },
    62         { "controllers", NULL },
    63         { "hotkeys", hotkeys_config },
    64         { "serial", serial_config },
    65         { NULL, CONFIG_TYPE_NONE }};
    67 static gchar *lxdream_config_load_filename = NULL;
    68 static gchar *lxdream_config_save_filename = NULL;
    70 void lxdream_register_config_group( const gchar *key, lxdream_config_entry_t group )
    71 {
    72     int i;
    73     for( i=0; i<MAX_ROOT_GROUPS; i++ ) {
    74         if( lxdream_config_root[i].key == NULL ) {
    75             lxdream_config_root[i].key = key;
    76             lxdream_config_root[i].params = group;
    77             lxdream_config_root[i+1].key = NULL;
    78             lxdream_config_root[i+1].params = CONFIG_TYPE_NONE;
    79             return;
    80         }
    81     }
    82     ERROR( "Unable to register config group '%s': Too many configuration groups", key );
    83 }
    85 gboolean lxdream_find_config()
    86 {
    87     gboolean result = TRUE;
    88     char *home = getenv("HOME");
    89     if( lxdream_config_save_filename == NULL ) {
    90         /* For compatibility, look for the old ~/.lxdreamrc first. Use it if 
    91          * found, otherwise use the new ~/.lxdream/lxdreamrc.
    92          */
    93         lxdream_config_save_filename = g_strdup_printf("%s/.%s", home, DEFAULT_CONFIG_FILENAME);
    94         if( access(lxdream_config_save_filename, R_OK) != 0 ) {
    95             g_free(lxdream_config_save_filename);
    96             const char *user_path = get_user_data_path();
    97             lxdream_config_save_filename = g_strdup_printf("%s/%s", user_path, DEFAULT_CONFIG_FILENAME);
    98         }
    99     }
   100     if( lxdream_config_load_filename == NULL ) {
   101         char *sysconfig = g_strdup_printf("%s/%s", get_sysconf_path(), DEFAULT_CONFIG_FILENAME);
   102         if( access(lxdream_config_save_filename, R_OK) == 0 ) {
   103             lxdream_config_load_filename = g_strdup(lxdream_config_save_filename);
   104             g_free(sysconfig);
   105         } else if( access( sysconfig, R_OK ) == 0 ) {
   106             lxdream_config_load_filename = sysconfig;
   107         } else {
   108             lxdream_config_load_filename = g_strdup(lxdream_config_save_filename);
   109             g_free(sysconfig);
   110             result = FALSE;
   111         }	
   112     }
   113     return result;
   114 }
   116 void lxdream_set_config_filename( const gchar *filename )
   117 {
   118     if( lxdream_config_load_filename != NULL ) {
   119         g_free(lxdream_config_load_filename);
   120     }
   121     lxdream_config_load_filename = g_strdup(filename);
   122     if( lxdream_config_save_filename != NULL ) {
   123         g_free(lxdream_config_save_filename);
   124     }
   125     lxdream_config_save_filename = g_strdup(filename);
   126 }
   128 void lxdream_set_default_config( )
   129 {
   130     /* Construct platform dependent defaults */
   131     const gchar *user_path = get_user_data_path();
   132     global_config[CONFIG_BIOS_PATH].default_value = g_strdup_printf( "%s/dcboot.rom", user_path ); 
   133     global_config[CONFIG_FLASH_PATH].default_value = g_strdup_printf( "%s/dcflash.rom", user_path ); 
   134     global_config[CONFIG_SAVE_PATH].default_value = g_strdup_printf( "%s/save", user_path ); 
   135     global_config[CONFIG_VMU_PATH].default_value = g_strdup_printf( "%s/vmu", user_path ); 
   136     global_config[CONFIG_BOOTSTRAP].default_value = g_strdup_printf( "%s/IP.BIN", user_path ); 
   138     /* Copy defaults into main values */
   139     struct lxdream_config_group *group = lxdream_config_root;
   140     while( group->key != NULL ) {
   141         struct lxdream_config_entry *param = group->params;
   142         if( param != NULL ) {
   143             while( param->key != NULL ) {
   144                 if( param->value != param->default_value ) {
   145                     if( param->value != NULL )
   146                         free( param->value );
   147                     param->value = (gchar *)param->default_value;
   148                 }
   149                 param++;
   150             }
   151         }
   152         group++;
   153     }
   154     maple_detach_all();
   155 }
   157 const gchar *lxdream_get_global_config_value( int key )
   158 {
   159     return global_config[key].value;
   160 }
   162 GList *lxdream_get_global_config_list_value( int key )
   163 {
   164     GList *result = NULL;
   165     const gchar *str = lxdream_get_global_config_value( key );
   166     if( str != NULL ) {
   167         gchar **strv = g_strsplit(str, ":",0);
   168         int i;
   169         for( i=0; strv[i] != NULL; i++ ) {
   170             result = g_list_append( result, g_strdup(strv[i]) );
   171         }
   172         g_strfreev(strv);
   173     }
   174     return result;
   175 }
   177 void lxdream_set_global_config_list_value( int key, const GList *list )
   178 {
   179     if( list == NULL ) {
   180         lxdream_set_global_config_value( key, NULL );
   181     } else {
   182         const GList *ptr;
   183         int size = 0;
   185         for( ptr = list; ptr != NULL; ptr = g_list_next(ptr) ) {
   186             size += strlen( (gchar *)ptr->data ) + 1;
   187         }
   188         char buf[size];
   189         strcpy( buf, (gchar *)list->data );
   190         for( ptr = g_list_next(list); ptr != NULL; ptr = g_list_next(ptr) ) {
   191             strcat( buf, ":" );
   192             strcat( buf, (gchar *)ptr->data );
   193         }
   194         lxdream_set_global_config_value( key, buf );
   195     }
   196 }
   198 gchar *lxdream_get_global_config_path_value( int key )
   199 {
   200     const gchar *str = lxdream_get_global_config_value(key);
   201     if( str == NULL ) {
   202         return NULL;
   203     } else {
   204         return get_expanded_path(str);
   205     }
   206 }
   208 const gchar *lxdream_set_global_config_path_value( int key, const gchar *value )
   209 {
   210     gchar *temp = get_escaped_path(value);
   211     lxdream_set_global_config_value(key,temp);
   212     g_free(temp);
   213     return lxdream_get_global_config_value(key);
   214 }
   216 void lxdream_set_config_value( lxdream_config_entry_t param, const gchar *value )
   217 {
   218     if( param->value != value ) {
   219         if( param->value != param->default_value && param->value != NULL ) {
   220             free( param->value );
   221         }
   222         param->value = g_strdup(value);
   223     }
   224 }
   226 void lxdream_set_global_config_value( int key, const gchar *value )
   227 {
   228     lxdream_set_config_value(&global_config[key], value);
   229 }
   231 const struct lxdream_config_entry * lxdream_get_global_config_entry( int key )
   232 {
   233     return &global_config[key];
   234 }
   236 gboolean lxdream_set_group_value( lxdream_config_group_t group, const gchar *key, const gchar *value )
   237 {
   238     int i;
   239     for( i=0; group->params[i].key != NULL; i++ ) {
   240         if( strcasecmp( group->params[i].key, key ) == 0 ) {
   241             lxdream_set_config_value( &group->params[i], value );
   242             return TRUE;
   243         }
   244     }
   245     return FALSE;
   246 }
   248 void lxdream_copy_config_list( lxdream_config_entry_t dest, lxdream_config_entry_t src )
   249 {
   250     int i;
   251     for( i=0; src[i].key != NULL; i++ ) {
   252         lxdream_set_config_value( &dest[i], src[i].value );
   253     }
   254 }
   256 gboolean lxdream_load_config( )
   257 {
   258     if( lxdream_config_load_filename == NULL ) {
   259         lxdream_find_config();
   260     }
   261     return lxdream_load_config_file(lxdream_config_load_filename);
   262 }
   264 gboolean lxdream_save_config( )
   265 {
   266     if( lxdream_config_save_filename == NULL ) {
   267         lxdream_find_config();
   268     }
   269     return lxdream_save_config_file(lxdream_config_save_filename);
   270 }
   272 gboolean lxdream_load_config_file( const gchar *filename )
   273 {
   274     FILE *f;
   275     gboolean result;
   277     if( access(filename, F_OK) != 0 ) {
   278         INFO( "Configuration file '%s' does not exist, creating from defaults" );
   279         lxdream_set_default_config();
   280         lxdream_save_config();
   281     }
   283     f = fopen(filename, "ro");
   284     if( f == NULL ) {
   285         ERROR( "Unable to open configuration file '%s': %s", filename, strerror(errno) );
   286         lxdream_set_default_config();
   287         return FALSE;
   288     }
   290     result = lxdream_load_config_stream( f );
   291     fclose(f);
   292     return result;
   293 }
   295 gboolean lxdream_load_config_stream( FILE *f )
   296 {
   298     char buf[512];
   299     int maple_device = -1, maple_subdevice = -1;
   300     struct lxdream_config_group devgroup;
   301     struct lxdream_config_group *group = NULL;
   302     maple_device_t device = NULL;
   303     lxdream_set_default_config();
   305     while( fgets( buf, sizeof(buf), f ) != NULL ) {
   306         g_strstrip(buf);
   307         if( buf[0] == '#' )
   308             continue;
   309         if( *buf == '[' ) {
   310             char *p = strchr(buf, ']');
   311             if( p != NULL ) {
   312                 struct lxdream_config_group *tmp_group;
   313                 maple_device = maple_subdevice = -1;
   314                 *p = '\0';
   315                 g_strstrip(buf+1);
   316                 tmp_group = &lxdream_config_root[0];
   317                 while( tmp_group->key != NULL ) {
   318                     if( strcasecmp(tmp_group->key, buf+1) == 0 ) {
   319                         group = tmp_group;
   320                         break;
   321                     }
   322                     tmp_group++;
   323                 }
   324             }
   325         } else if( group != NULL ) {
   326             char *value = strchr( buf, '=' );
   327             if( value != NULL ) {
   328                 struct lxdream_config_entry *param = group->params;
   329                 *value = '\0';
   330                 value++;
   331                 g_strstrip(buf);
   332                 g_strstrip(value);
   333                 if( strcmp(group->key,"controllers") == 0  ) {
   334                     if( g_strncasecmp( buf, "device ", 7 ) == 0 ) {
   335                         maple_device = strtoul( buf+7, NULL, 0 );
   336                         if( maple_device < 0 || maple_device > 3 ) {
   337                             ERROR( "Device number must be between 0..3 (not '%s')", buf+7);
   338                             continue;
   339                         }
   340                         maple_subdevice = 0;
   341                         device = maple_new_device( value );
   342                         if( device == NULL ) {
   343                             ERROR( "Unrecognized device '%s'", value );
   344                         } else {
   345                             devgroup.key = "controllers";
   346                             devgroup.params = maple_get_device_config(device);
   347                             maple_attach_device( device, maple_device, maple_subdevice );
   348                             group = &devgroup;
   349                         }
   350                         continue;
   351                     } else if( g_strncasecmp( buf, "subdevice ", 10 ) == 0 ) {
   352                         maple_subdevice = strtoul( buf+10, NULL, 0 );
   353                         if( maple_device == -1 ) {
   354                             ERROR( "Subdevice not allowed without primary device" );
   355                         } else if( maple_subdevice < 1 || maple_subdevice > 5 ) {
   356                             ERROR( "Subdevice must be between 1..5 (not '%s')", buf+10 );
   357                         } else if( (device = maple_new_device(value)) == NULL ) {
   358                             ERROR( "Unrecognized subdevice '%s'", value );
   359                         } else {
   360                             devgroup.key = "controllers";
   361                             devgroup.params = maple_get_device_config(device);
   362                             maple_attach_device( device, maple_device, maple_subdevice );
   363                             group = &devgroup;
   364                         }
   365                         continue;
   366                     }
   367                 }
   368                 while( param->key != NULL ) {
   369                     if( strcasecmp( param->key, buf ) == 0 ) {
   370                         param->value = g_strdup(value);
   371                         break;
   372                     }
   373                     param++;
   374                 }
   375             }
   376         }
   377     }
   378     return TRUE;
   379 }
   381 gboolean lxdream_save_config_file( const gchar *filename )
   382 {
   383     FILE *f = fopen(filename, "wo");
   384     gboolean result;
   385     if( f == NULL ) {
   386         ERROR( "Unable to open '%s': %s", filename, strerror(errno) );
   387         return FALSE;
   388     }
   389     result = lxdream_save_config_stream(f);
   390     fclose(f);
   391     return TRUE;
   392 }    
   394 gboolean lxdream_save_config_stream( FILE *f )
   395 {
   396     struct lxdream_config_group *group = &lxdream_config_root[0];
   398     while( group->key != NULL ) {
   399         struct lxdream_config_entry *entry = group->params;
   400         fprintf( f, "[%s]\n", group->key );
   402         if( entry != NULL ) {
   403             while( entry->key != NULL ) {
   404                 if( entry->value != NULL ) {
   405                     fprintf( f, "%s = %s\n", entry->key, entry->value );
   406                 }
   407                 entry++;
   408             }
   409         } else if( strcmp(group->key, "controllers") == 0 ) {
   410             int i,j;
   411             for( i=0; i<4; i++ ) {
   412                 for( j=0; j<6; j++ ) {
   413                     maple_device_t dev = maple_get_device( i, j );
   414                     if( dev != NULL ) {
   415                         if( j == 0 )
   416                             fprintf( f, "Device %d = %s\n", i, dev->device_class->name );
   417                         else 
   418                             fprintf( f, "Subdevice %d = %s\n", j, dev->device_class->name );
   419                         if( dev->get_config != NULL && ((entry = dev->get_config(dev)) != NULL) ) {
   420                             while( entry->key != NULL ) {
   421                                 if( entry->value != NULL ) {
   422                                     fprintf( f, "%*c%s = %s\n", j==0?4:8, ' ',entry->key, entry->value );
   423                                 }
   424                                 entry++;
   425                             }
   426                         }
   427                     }
   428                 }
   429             }
   430         }
   431         fprintf( f, "\n" );
   432         group++;
   433     }
   434     return TRUE;
   435 }
   437 void lxdream_make_config_dir( )
   438 {
   439     const char *user_path = get_user_data_path();
   440     struct stat st;
   442     if( access( user_path, R_OK|X_OK ) == 0 && lstat( user_path, &st ) == 0 &&
   443             (st.st_mode & S_IFDIR) != 0 ) {
   444         /* All good */
   445         return;
   446     }
   448     if( mkdir( user_path, 0777 ) != 0 ) {
   449         ERROR( "Unable to create user configuration directory %s: %s", user_path, strerror(errno) );
   450         return;
   451     }
   453     char *vmupath = g_strdup_printf( "%s/vmu", user_path );
   454     mkdir( vmupath, 0777 );
   455     g_free( vmupath );
   457     char *savepath = g_strdup_printf( "%s/save", user_path );
   458     mkdir( savepath, 0777 );
   459     g_free( vmupath );
   460 }
.