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