Search
lxdream.org :: lxdream/src/config.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/config.c
changeset 1036:af7b0c5905dd
prev1034:7044e01148f0
next1038:f220d18c0615
author nkeynes
date Wed Jun 24 06:06:40 2009 +0000 (13 years ago)
permissions -rw-r--r--
last change Support shell substitutions in config paths
Keep track of last folder in file dialogs
Fix out-of-dateness in GTK path dialog
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@1036
    21
#include <ctype.h>
nkeynes@450
    22
#include <errno.h>
nkeynes@450
    23
#include <stdlib.h>
nkeynes@450
    24
#include <string.h>
nkeynes@1036
    25
#include <wordexp.h>
nkeynes@480
    26
#include <glib/gmem.h>
nkeynes@450
    27
#include <glib/gstrfuncs.h>
nkeynes@450
    28
#include "dream.h"
nkeynes@450
    29
#include "config.h"
nkeynes@450
    30
#include "maple/maple.h"
nkeynes@450
    31
nkeynes@1024
    32
#define MAX_ROOT_GROUPS 16
bhaal22@643
    33
bhaal22@643
    34
extern struct lxdream_config_entry alsa_config[];
nkeynes@1015
    35
extern struct lxdream_config_entry hotkeys_config[];
bhaal22@643
    36
nkeynes@450
    37
gboolean lxdream_load_config_file( const gchar *filename );
nkeynes@450
    38
gboolean lxdream_save_config_file( const gchar *filename );
nkeynes@450
    39
gboolean lxdream_load_config_stream( FILE *f );
nkeynes@450
    40
gboolean lxdream_save_config_stream( FILE *f );
nkeynes@450
    41
nkeynes@450
    42
static struct lxdream_config_entry global_config[] =
nkeynes@736
    43
       {{ "bios", N_("Bios ROM"), CONFIG_TYPE_FILE, "dcboot.rom" },
nkeynes@736
    44
        { "flash", N_("Flash ROM"), CONFIG_TYPE_FILE, "dcflash.rom" },
nkeynes@736
    45
        { "default path", N_("Default disc path"), CONFIG_TYPE_PATH, "." },
nkeynes@736
    46
        { "save path", N_("Save-state path"), CONFIG_TYPE_PATH, "save" },
nkeynes@1034
    47
        { "vmu path", N_("VMU path"), CONFIG_TYPE_PATH, "vmu" },
nkeynes@736
    48
        { "bootstrap", N_("Bootstrap IP.BIN"), CONFIG_TYPE_FILE, "IP.BIN" },
nkeynes@736
    49
        { "gdrom", NULL, CONFIG_TYPE_FILE, NULL },
nkeynes@1034
    50
        { "recent", NULL, CONFIG_TYPE_FILELIST, NULL },
nkeynes@1034
    51
        { "vmu", NULL, CONFIG_TYPE_FILELIST, NULL },
nkeynes@736
    52
        { NULL, CONFIG_TYPE_NONE }};
nkeynes@450
    53
nkeynes@450
    54
static struct lxdream_config_entry serial_config[] =
nkeynes@736
    55
       {{ "device", N_("Serial device"), CONFIG_TYPE_FILE, "/dev/ttyS1" },
nkeynes@736
    56
        { NULL, CONFIG_TYPE_NONE }};
nkeynes@450
    57
nkeynes@1024
    58
struct lxdream_config_group lxdream_config_root[MAX_ROOT_GROUPS+1] = 
nkeynes@736
    59
       {{ "global", global_config },
nkeynes@736
    60
        { "controllers", NULL },
nkeynes@1015
    61
        { "hotkeys", hotkeys_config },
nkeynes@736
    62
        { "serial", serial_config },
nkeynes@736
    63
        { NULL, CONFIG_TYPE_NONE }};
nkeynes@450
    64
nkeynes@450
    65
static gchar *lxdream_config_load_filename = NULL;
nkeynes@450
    66
static gchar *lxdream_config_save_filename = NULL;
nkeynes@450
    67
nkeynes@1024
    68
void lxdream_register_config_group( const gchar *key, lxdream_config_entry_t group )
nkeynes@1024
    69
{
nkeynes@1024
    70
    int i;
nkeynes@1024
    71
    for( i=0; i<MAX_ROOT_GROUPS; i++ ) {
nkeynes@1024
    72
        if( lxdream_config_root[i].key == NULL ) {
nkeynes@1024
    73
            lxdream_config_root[i].key = key;
nkeynes@1024
    74
            lxdream_config_root[i].params = group;
nkeynes@1024
    75
            lxdream_config_root[i+1].key = NULL;
nkeynes@1024
    76
            lxdream_config_root[i+1].params = CONFIG_TYPE_NONE;
nkeynes@1024
    77
            return;
nkeynes@1024
    78
        }
nkeynes@1024
    79
    }
nkeynes@1024
    80
    ERROR( "Unable to register config group '%s': Too many configuration groups", key );
nkeynes@1024
    81
}
nkeynes@1024
    82
nkeynes@450
    83
gboolean lxdream_find_config()
nkeynes@450
    84
{
nkeynes@480
    85
    gboolean result = TRUE;
nkeynes@450
    86
    char *home = getenv("HOME");
nkeynes@450
    87
    if( lxdream_config_save_filename == NULL ) {
nkeynes@736
    88
        lxdream_config_save_filename = g_strdup_printf("%s/.%s", home, DEFAULT_CONFIG_FILENAME);
nkeynes@450
    89
    }
nkeynes@450
    90
    if( lxdream_config_load_filename == NULL ) {
nkeynes@866
    91
        char *sysconfig = g_strdup_printf("%s/%s", get_sysconf_path(), DEFAULT_CONFIG_FILENAME);
nkeynes@736
    92
        if( access(lxdream_config_save_filename, R_OK) == 0 ) {
nkeynes@736
    93
            lxdream_config_load_filename = g_strdup(lxdream_config_save_filename);
nkeynes@866
    94
            g_free(sysconfig);
nkeynes@866
    95
        } else if( access( sysconfig, R_OK ) == 0 ) {
nkeynes@866
    96
            lxdream_config_load_filename = sysconfig;
nkeynes@736
    97
        } else if( access( "./" DEFAULT_CONFIG_FILENAME, R_OK ) == 0 ) {
nkeynes@736
    98
            lxdream_config_load_filename = g_strdup("./" DEFAULT_CONFIG_FILENAME);
nkeynes@866
    99
            g_free(sysconfig);
nkeynes@736
   100
        } else {
nkeynes@736
   101
            lxdream_config_load_filename = g_strdup(lxdream_config_save_filename);
nkeynes@866
   102
            g_free(sysconfig);
nkeynes@736
   103
            result = FALSE;
nkeynes@736
   104
        }	
nkeynes@480
   105
    }
nkeynes@480
   106
    return result;
nkeynes@450
   107
}
nkeynes@450
   108
nkeynes@450
   109
void lxdream_set_config_filename( const gchar *filename )
nkeynes@450
   110
{
nkeynes@450
   111
    if( lxdream_config_load_filename != NULL ) {
nkeynes@736
   112
        g_free(lxdream_config_load_filename);
nkeynes@450
   113
    }
nkeynes@450
   114
    lxdream_config_load_filename = g_strdup(filename);
nkeynes@450
   115
    if( lxdream_config_save_filename != NULL ) {
nkeynes@736
   116
        g_free(lxdream_config_save_filename);
nkeynes@450
   117
    }
nkeynes@450
   118
    lxdream_config_save_filename = g_strdup(filename);
nkeynes@450
   119
}
nkeynes@450
   120
nkeynes@450
   121
void lxdream_set_default_config( )
nkeynes@450
   122
{
nkeynes@450
   123
    struct lxdream_config_group *group = lxdream_config_root;
nkeynes@450
   124
    while( group->key != NULL ) {
nkeynes@736
   125
        struct lxdream_config_entry *param = group->params;
nkeynes@736
   126
        if( param != NULL ) {
nkeynes@736
   127
            while( param->key != NULL ) {
nkeynes@736
   128
                if( param->value != param->default_value ) {
nkeynes@736
   129
                    if( param->value != NULL )
nkeynes@736
   130
                        free( param->value );
nkeynes@736
   131
                    param->value = (gchar *)param->default_value;
nkeynes@736
   132
                }
nkeynes@736
   133
                param++;
nkeynes@736
   134
            }
nkeynes@736
   135
        }
nkeynes@736
   136
        group++;
nkeynes@450
   137
    }
nkeynes@450
   138
    maple_detach_all();
nkeynes@450
   139
}
nkeynes@450
   140
nkeynes@1036
   141
const gchar *lxdream_get_global_config_value( int key )
nkeynes@450
   142
{
nkeynes@450
   143
    return global_config[key].value;
nkeynes@450
   144
}
nkeynes@450
   145
nkeynes@1034
   146
GList *lxdream_get_global_config_list_value( int key )
nkeynes@1034
   147
{
nkeynes@1034
   148
    GList *result = NULL;
nkeynes@1036
   149
    const gchar *str = lxdream_get_global_config_value( key );
nkeynes@1034
   150
    if( str != NULL ) {
nkeynes@1034
   151
        gchar **strv = g_strsplit(str, ":",0);
nkeynes@1034
   152
        int i;
nkeynes@1034
   153
        for( i=0; strv[i] != NULL; i++ ) {
nkeynes@1034
   154
            result = g_list_append( result, g_strdup(strv[i]) );
nkeynes@1034
   155
        }
nkeynes@1034
   156
        g_strfreev(strv);
nkeynes@1034
   157
    }
nkeynes@1034
   158
    return result;
nkeynes@1034
   159
}
nkeynes@1034
   160
nkeynes@1034
   161
void lxdream_set_global_config_list_value( int key, const GList *list )
nkeynes@1034
   162
{
nkeynes@1034
   163
    if( list == NULL ) {
nkeynes@1034
   164
        lxdream_set_global_config_value( key, NULL );
nkeynes@1034
   165
    } else {
nkeynes@1036
   166
        const GList *ptr;
nkeynes@1034
   167
        int size = 0;
nkeynes@1034
   168
        
nkeynes@1034
   169
        for( ptr = list; ptr != NULL; ptr = g_list_next(ptr) ) {
nkeynes@1034
   170
            size += strlen( (gchar *)ptr->data ) + 1;
nkeynes@1034
   171
        }
nkeynes@1034
   172
        char buf[size];
nkeynes@1034
   173
        strcpy( buf, (gchar *)list->data );
nkeynes@1034
   174
        for( ptr = g_list_next(list); ptr != NULL; ptr = g_list_next(ptr) ) {
nkeynes@1034
   175
            strcat( buf, ":" );
nkeynes@1034
   176
            strcat( buf, (gchar *)ptr->data );
nkeynes@1034
   177
        }
nkeynes@1034
   178
        lxdream_set_global_config_value( key, buf );
nkeynes@1034
   179
    }
nkeynes@1034
   180
}
nkeynes@1034
   181
nkeynes@1036
   182
gchar *get_expanded_path( const gchar *input )
nkeynes@1036
   183
{
nkeynes@1036
   184
    wordexp_t we;
nkeynes@1036
   185
    if( input == NULL ) {
nkeynes@1036
   186
        return NULL;
nkeynes@1036
   187
    }
nkeynes@1036
   188
    memset(&we,0,sizeof(we));
nkeynes@1036
   189
    int result = wordexp(input, &we, WRDE_NOCMD);
nkeynes@1036
   190
    if( result != 0 || we.we_wordc == 0 ) {
nkeynes@1036
   191
        /* On failure, return the original input unchanged */
nkeynes@1036
   192
        return g_strdup(input);
nkeynes@1036
   193
    } else {
nkeynes@1036
   194
        /* On success, concatenate all 'words' together into a single 
nkeynes@1036
   195
         * space-separated string
nkeynes@1036
   196
         */
nkeynes@1036
   197
        int length = we.we_wordc, i;
nkeynes@1036
   198
        gchar *result, *p;
nkeynes@1036
   199
        
nkeynes@1036
   200
        for( i=0; i<we.we_wordc; i++ ) {
nkeynes@1036
   201
            length += strlen(we.we_wordv[i]);
nkeynes@1036
   202
        }
nkeynes@1036
   203
        p = result = g_malloc(length);
nkeynes@1036
   204
        for( i=0; i<we.we_wordc; i++ ) {
nkeynes@1036
   205
            if( i != 0 )
nkeynes@1036
   206
                *p++ = ' ';
nkeynes@1036
   207
            strcpy( p, we.we_wordv[i] );
nkeynes@1036
   208
            p += strlen(p);
nkeynes@1036
   209
        }
nkeynes@1036
   210
        wordfree(&we);
nkeynes@1036
   211
        return result;
nkeynes@1036
   212
    }        
nkeynes@1036
   213
}
nkeynes@1036
   214
nkeynes@1036
   215
/**
nkeynes@1036
   216
 * Test if we need to escape a path to prevent substitution mangling. 
nkeynes@1036
   217
 * @return TRUE if the input value contains any character that doesn't
nkeynes@1036
   218
 * match [a-zA-Z0-9._@%/] (this will escape slightly more than it needs to,
nkeynes@1036
   219
 * but is safe)
nkeynes@1036
   220
 */
nkeynes@1036
   221
gboolean path_needs_escaping( const gchar *value )
nkeynes@1036
   222
{
nkeynes@1036
   223
   const gchar *p = value;
nkeynes@1036
   224
   while( *p ) {
nkeynes@1036
   225
       if( !isalnum(*p) && *p != '.' && *p != '_' &&
nkeynes@1036
   226
               *p != '@' && *p != '%' && *p != '/' ) {
nkeynes@1036
   227
           return TRUE;
nkeynes@1036
   228
       }
nkeynes@1036
   229
       p++;
nkeynes@1036
   230
   }
nkeynes@1036
   231
   return FALSE;
nkeynes@1036
   232
}
nkeynes@1036
   233
nkeynes@1036
   234
gchar *get_escaped_path( const gchar *value )
nkeynes@1036
   235
{
nkeynes@1036
   236
    if( value != NULL && path_needs_escaping(value) ) {
nkeynes@1036
   237
        /* Escape with "", and backslash the remaining characters:
nkeynes@1036
   238
         *   \ " $ `
nkeynes@1036
   239
         */
nkeynes@1036
   240
        char buf[strlen(value)*2+3];  
nkeynes@1036
   241
        const char *s = value;
nkeynes@1036
   242
        char *p = buf;
nkeynes@1036
   243
        *p++ = '\"';
nkeynes@1036
   244
        while( *s ) {
nkeynes@1036
   245
            if( *s == '\\' || *s == '"' || *s == '$' || *s == '`' ) {
nkeynes@1036
   246
                *p++ = '\\';
nkeynes@1036
   247
            }
nkeynes@1036
   248
            *p++ = *s++;
nkeynes@1036
   249
        }
nkeynes@1036
   250
        *p++ = '\"';
nkeynes@1036
   251
        *p = '\0';
nkeynes@1036
   252
        return g_strdup(buf);
nkeynes@1036
   253
    } else {
nkeynes@1036
   254
        return g_strdup(value);
nkeynes@1036
   255
    }
nkeynes@1036
   256
}
nkeynes@1036
   257
nkeynes@1036
   258
gchar *lxdream_get_global_config_path_value( int key )
nkeynes@1036
   259
{
nkeynes@1036
   260
    const gchar *str = lxdream_get_global_config_value(key);
nkeynes@1036
   261
    if( str == NULL ) {
nkeynes@1036
   262
        return NULL;
nkeynes@1036
   263
    } else {
nkeynes@1036
   264
        return get_expanded_path(str);
nkeynes@1036
   265
    }
nkeynes@1036
   266
}
nkeynes@1036
   267
nkeynes@1036
   268
const gchar *lxdream_set_global_config_path_value( int key, const gchar *value )
nkeynes@1036
   269
{
nkeynes@1036
   270
    gchar *temp = get_escaped_path(value);
nkeynes@1036
   271
    lxdream_set_global_config_value(key,temp);
nkeynes@1036
   272
    g_free(temp);
nkeynes@1036
   273
    return lxdream_get_global_config_value(key);
nkeynes@1036
   274
}
nkeynes@1036
   275
nkeynes@460
   276
void lxdream_set_config_value( lxdream_config_entry_t param, const gchar *value )
nkeynes@450
   277
{
nkeynes@475
   278
    if( param->value != value ) {
nkeynes@736
   279
        if( param->value != param->default_value && param->value != NULL ) {
nkeynes@736
   280
            free( param->value );
nkeynes@736
   281
        }
nkeynes@736
   282
        param->value = g_strdup(value);
nkeynes@450
   283
    }
nkeynes@450
   284
}
nkeynes@450
   285
nkeynes@460
   286
void lxdream_set_global_config_value( int key, const gchar *value )
nkeynes@460
   287
{
nkeynes@460
   288
    lxdream_set_config_value(&global_config[key], value);
nkeynes@460
   289
}
nkeynes@460
   290
nkeynes@1036
   291
const struct lxdream_config_entry * lxdream_get_global_config_entry( int key )
nkeynes@724
   292
{
nkeynes@724
   293
    return &global_config[key];
nkeynes@724
   294
}
nkeynes@724
   295
nkeynes@458
   296
gboolean lxdream_set_group_value( lxdream_config_group_t group, const gchar *key, const gchar *value )
nkeynes@458
   297
{
nkeynes@458
   298
    int i;
nkeynes@458
   299
    for( i=0; group->params[i].key != NULL; i++ ) {
nkeynes@736
   300
        if( strcasecmp( group->params[i].key, key ) == 0 ) {
nkeynes@736
   301
            lxdream_set_config_value( &group->params[i], value );
nkeynes@736
   302
            return TRUE;
nkeynes@736
   303
        }
nkeynes@458
   304
    }
nkeynes@458
   305
    return FALSE;
nkeynes@458
   306
}
nkeynes@458
   307
nkeynes@460
   308
void lxdream_copy_config_list( lxdream_config_entry_t dest, lxdream_config_entry_t src )
nkeynes@460
   309
{
nkeynes@460
   310
    int i;
nkeynes@460
   311
    for( i=0; src[i].key != NULL; i++ ) {
nkeynes@736
   312
        lxdream_set_config_value( &dest[i], src[i].value );
nkeynes@460
   313
    }
nkeynes@460
   314
}
nkeynes@460
   315
nkeynes@450
   316
gboolean lxdream_load_config( )
nkeynes@450
   317
{
nkeynes@450
   318
    if( lxdream_config_load_filename == NULL ) {
nkeynes@736
   319
        lxdream_find_config();
nkeynes@450
   320
    }
nkeynes@450
   321
    return lxdream_load_config_file(lxdream_config_load_filename);
nkeynes@450
   322
}
nkeynes@450
   323
nkeynes@450
   324
gboolean lxdream_save_config( )
nkeynes@450
   325
{
nkeynes@450
   326
    if( lxdream_config_save_filename == NULL ) {
nkeynes@736
   327
        lxdream_find_config();
nkeynes@450
   328
    }
nkeynes@450
   329
    return lxdream_save_config_file(lxdream_config_save_filename);
nkeynes@450
   330
}
nkeynes@450
   331
nkeynes@450
   332
gboolean lxdream_load_config_file( const gchar *filename )
nkeynes@450
   333
{
nkeynes@450
   334
    FILE *f;
nkeynes@450
   335
    gboolean result;
nkeynes@450
   336
nkeynes@450
   337
    if( access(filename, F_OK) != 0 ) {
nkeynes@736
   338
        INFO( "Configuration file '%s' does not exist, creating from defaults" );
nkeynes@736
   339
        lxdream_set_default_config();
nkeynes@736
   340
        lxdream_save_config();
nkeynes@450
   341
    }
nkeynes@450
   342
nkeynes@450
   343
    f = fopen(filename, "ro");
nkeynes@450
   344
    if( f == NULL ) {
nkeynes@736
   345
        ERROR( "Unable to open configuration file '%s': %s", filename, strerror(errno) );
nkeynes@736
   346
        lxdream_set_default_config();
nkeynes@736
   347
        return FALSE;
nkeynes@450
   348
    }
nkeynes@450
   349
nkeynes@450
   350
    result = lxdream_load_config_stream( f );
nkeynes@450
   351
    fclose(f);
nkeynes@450
   352
    return result;
nkeynes@450
   353
}
nkeynes@450
   354
nkeynes@450
   355
gboolean lxdream_load_config_stream( FILE *f )
nkeynes@450
   356
{
nkeynes@450
   357
nkeynes@450
   358
    char buf[512];
nkeynes@450
   359
    int maple_device = -1, maple_subdevice = -1;
nkeynes@450
   360
    struct lxdream_config_group devgroup;
nkeynes@450
   361
    struct lxdream_config_group *group = NULL;
nkeynes@450
   362
    maple_device_t device = NULL;
nkeynes@450
   363
    lxdream_set_default_config();
nkeynes@450
   364
nkeynes@450
   365
    while( fgets( buf, sizeof(buf), f ) != NULL ) {
nkeynes@736
   366
        g_strstrip(buf);
nkeynes@736
   367
        if( buf[0] == '#' )
nkeynes@736
   368
            continue;
nkeynes@736
   369
        if( *buf == '[' ) {
nkeynes@736
   370
            char *p = strchr(buf, ']');
nkeynes@736
   371
            if( p != NULL ) {
nkeynes@736
   372
                struct lxdream_config_group *tmp_group;
nkeynes@736
   373
                maple_device = maple_subdevice = -1;
nkeynes@736
   374
                *p = '\0';
nkeynes@736
   375
                g_strstrip(buf+1);
nkeynes@736
   376
                tmp_group = &lxdream_config_root[0];
nkeynes@736
   377
                while( tmp_group->key != NULL ) {
nkeynes@736
   378
                    if( strcasecmp(tmp_group->key, buf+1) == 0 ) {
nkeynes@736
   379
                        group = tmp_group;
nkeynes@736
   380
                        break;
nkeynes@736
   381
                    }
nkeynes@736
   382
                    tmp_group++;
nkeynes@736
   383
                }
nkeynes@736
   384
            }
nkeynes@736
   385
        } else if( group != NULL ) {
nkeynes@736
   386
            char *value = strchr( buf, '=' );
nkeynes@736
   387
            if( value != NULL ) {
nkeynes@736
   388
                struct lxdream_config_entry *param = group->params;
nkeynes@736
   389
                *value = '\0';
nkeynes@736
   390
                value++;
nkeynes@736
   391
                g_strstrip(buf);
nkeynes@736
   392
                g_strstrip(value);
nkeynes@736
   393
                if( strcmp(group->key,"controllers") == 0  ) {
nkeynes@736
   394
                    if( g_strncasecmp( buf, "device ", 7 ) == 0 ) {
nkeynes@736
   395
                        maple_device = strtoul( buf+7, NULL, 0 );
nkeynes@736
   396
                        if( maple_device < 0 || maple_device > 3 ) {
nkeynes@736
   397
                            ERROR( "Device number must be between 0..3 (not '%s')", buf+7);
nkeynes@736
   398
                            continue;
nkeynes@736
   399
                        }
nkeynes@736
   400
                        maple_subdevice = 0;
nkeynes@736
   401
                        device = maple_new_device( value );
nkeynes@736
   402
                        if( device == NULL ) {
nkeynes@736
   403
                            ERROR( "Unrecognized device '%s'", value );
nkeynes@736
   404
                        } else {
nkeynes@736
   405
                            devgroup.key = "controllers";
nkeynes@736
   406
                            devgroup.params = maple_get_device_config(device);
nkeynes@736
   407
                            maple_attach_device( device, maple_device, maple_subdevice );
nkeynes@736
   408
                            group = &devgroup;
nkeynes@736
   409
                        }
nkeynes@736
   410
                        continue;
nkeynes@736
   411
                    } else if( g_strncasecmp( buf, "subdevice ", 10 ) == 0 ) {
nkeynes@736
   412
                        maple_subdevice = strtoul( buf+10, NULL, 0 );
nkeynes@736
   413
                        if( maple_device == -1 ) {
nkeynes@736
   414
                            ERROR( "Subdevice not allowed without primary device" );
nkeynes@736
   415
                        } else if( maple_subdevice < 1 || maple_subdevice > 5 ) {
nkeynes@736
   416
                            ERROR( "Subdevice must be between 1..5 (not '%s')", buf+10 );
nkeynes@736
   417
                        } else if( (device = maple_new_device(value)) == NULL ) {
nkeynes@736
   418
                            ERROR( "Unrecognized subdevice '%s'", value );
nkeynes@736
   419
                        } else {
nkeynes@736
   420
                            devgroup.key = "controllers";
nkeynes@736
   421
                            devgroup.params = maple_get_device_config(device);
nkeynes@736
   422
                            maple_attach_device( device, maple_device, maple_subdevice );
nkeynes@736
   423
                            group = &devgroup;
nkeynes@736
   424
                        }
nkeynes@736
   425
                        continue;
nkeynes@736
   426
                    }
nkeynes@736
   427
                }
nkeynes@736
   428
                while( param->key != NULL ) {
nkeynes@736
   429
                    if( strcasecmp( param->key, buf ) == 0 ) {
nkeynes@736
   430
                        param->value = g_strdup(value);
nkeynes@736
   431
                        break;
nkeynes@736
   432
                    }
nkeynes@736
   433
                    param++;
nkeynes@736
   434
                }
nkeynes@736
   435
            }
nkeynes@736
   436
        }
nkeynes@450
   437
    }
nkeynes@450
   438
    return TRUE;
nkeynes@450
   439
}
nkeynes@450
   440
nkeynes@450
   441
gboolean lxdream_save_config_file( const gchar *filename )
nkeynes@450
   442
{
nkeynes@450
   443
    FILE *f = fopen(filename, "wo");
nkeynes@450
   444
    gboolean result;
nkeynes@450
   445
    if( f == NULL ) {
nkeynes@736
   446
        ERROR( "Unable to open '%s': %s", filename, strerror(errno) );
nkeynes@736
   447
        return FALSE;
nkeynes@450
   448
    }
nkeynes@450
   449
    result = lxdream_save_config_stream(f);
nkeynes@450
   450
    fclose(f);
nkeynes@450
   451
    return TRUE;
nkeynes@450
   452
}    
nkeynes@450
   453
nkeynes@450
   454
gboolean lxdream_save_config_stream( FILE *f )
nkeynes@450
   455
{
nkeynes@450
   456
    struct lxdream_config_group *group = &lxdream_config_root[0];
nkeynes@736
   457
nkeynes@450
   458
    while( group->key != NULL ) {
nkeynes@736
   459
        struct lxdream_config_entry *entry = group->params;
nkeynes@736
   460
        fprintf( f, "[%s]\n", group->key );
nkeynes@736
   461
nkeynes@736
   462
        if( entry != NULL ) {
nkeynes@736
   463
            while( entry->key != NULL ) {
nkeynes@736
   464
                if( entry->value != NULL ) {
nkeynes@736
   465
                    fprintf( f, "%s = %s\n", entry->key, entry->value );
nkeynes@736
   466
                }
nkeynes@736
   467
                entry++;
nkeynes@736
   468
            }
nkeynes@736
   469
        } else if( strcmp(group->key, "controllers") == 0 ) {
nkeynes@736
   470
            int i,j;
nkeynes@736
   471
            for( i=0; i<4; i++ ) {
nkeynes@736
   472
                for( j=0; j<6; j++ ) {
nkeynes@736
   473
                    maple_device_t dev = maple_get_device( i, j );
nkeynes@736
   474
                    if( dev != NULL ) {
nkeynes@736
   475
                        if( j == 0 )
nkeynes@736
   476
                            fprintf( f, "Device %d = %s\n", i, dev->device_class->name );
nkeynes@736
   477
                        else 
nkeynes@736
   478
                            fprintf( f, "Subdevice %d = %s\n", j, dev->device_class->name );
nkeynes@736
   479
                        if( dev->get_config != NULL && ((entry = dev->get_config(dev)) != NULL) ) {
nkeynes@736
   480
                            while( entry->key != NULL ) {
nkeynes@736
   481
                                if( entry->value != NULL ) {
nkeynes@736
   482
                                    fprintf( f, "%*c%s = %s\n", j==0?4:8, ' ',entry->key, entry->value );
nkeynes@736
   483
                                }
nkeynes@736
   484
                                entry++;
nkeynes@736
   485
                            }
nkeynes@736
   486
                        }
nkeynes@736
   487
                    }
nkeynes@736
   488
                }
nkeynes@736
   489
            }
nkeynes@736
   490
        }
nkeynes@736
   491
        fprintf( f, "\n" );
nkeynes@736
   492
        group++;
nkeynes@450
   493
    }
nkeynes@450
   494
    return TRUE;
nkeynes@450
   495
}
.