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