nkeynes@1034 | 1 | /**
|
nkeynes@1035 | 2 | * $Id$
|
nkeynes@1034 | 3 | *
|
nkeynes@1034 | 4 | * VMU management - maintains a list of all known VMUs
|
nkeynes@1034 | 5 | *
|
nkeynes@1034 | 6 | * Copyright (c) 2009 Nathan Keynes.
|
nkeynes@1034 | 7 | *
|
nkeynes@1034 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@1034 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@1034 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@1034 | 11 | * (at your option) any later version.
|
nkeynes@1034 | 12 | *
|
nkeynes@1034 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@1034 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@1034 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@1034 | 16 | * GNU General Public License for more details.
|
nkeynes@1034 | 17 | */
|
nkeynes@1034 | 18 |
|
nkeynes@1034 | 19 | #include <string.h>
|
nkeynes@1034 | 20 | #include <stdlib.h>
|
nkeynes@1034 | 21 | #include <glib/glist.h>
|
nkeynes@1034 | 22 | #include <glib/gstrfuncs.h>
|
nkeynes@1034 | 23 | #include "vmulist.h"
|
nkeynes@1034 | 24 | #include "config.h"
|
nkeynes@1034 | 25 |
|
nkeynes@1034 | 26 | DEFINE_HOOK(vmulist_change_hook, vmulist_change_hook_t);
|
nkeynes@1034 | 27 |
|
nkeynes@1034 | 28 | typedef struct vmulist_entry {
|
nkeynes@1034 | 29 | const gchar *filename;
|
nkeynes@1034 | 30 | vmu_volume_t vol;
|
nkeynes@1034 | 31 | int attach_count;
|
nkeynes@1034 | 32 | } *vmulist_entry_t;
|
nkeynes@1034 | 33 |
|
nkeynes@1034 | 34 | /**
|
nkeynes@1034 | 35 | * Doubly-linked list of vmulist_entry_t maintained in sorted order by display name.
|
nkeynes@1034 | 36 | * Could be augmented with a hashtable if it gets too long
|
nkeynes@1034 | 37 | */
|
nkeynes@1034 | 38 | static GList *vmu_list;
|
nkeynes@1034 | 39 |
|
nkeynes@1034 | 40 | #define ENTRY(it) ((vmulist_entry_t)(it)->data)
|
nkeynes@1034 | 41 | #define VOLUME(it) (ENTRY(it)->vol)
|
nkeynes@1034 | 42 | #define DISPLAY_NAME(it) vmulist_display_name(ENTRY(it))
|
nkeynes@1034 | 43 |
|
nkeynes@1034 | 44 | static const char *vmulist_display_name(vmulist_entry_t ent)
|
nkeynes@1034 | 45 | {
|
nkeynes@1034 | 46 | if( ent->filename == NULL ) {
|
nkeynes@1034 | 47 | return NULL;
|
nkeynes@1034 | 48 | }
|
nkeynes@1034 | 49 | const char *s = strrchr(ent->filename, '/' );
|
nkeynes@1034 | 50 | if( s == NULL || *(s+1) == '\0' ) {
|
nkeynes@1034 | 51 | return ent->filename;
|
nkeynes@1034 | 52 | } else {
|
nkeynes@1034 | 53 | return s+1;
|
nkeynes@1034 | 54 | }
|
nkeynes@1034 | 55 | }
|
nkeynes@1034 | 56 |
|
nkeynes@1034 | 57 | static void vmulist_update_config( void )
|
nkeynes@1034 | 58 | {
|
nkeynes@1034 | 59 | GList *temp = NULL, *it;
|
nkeynes@1034 | 60 |
|
nkeynes@1034 | 61 | for( it = vmu_list; it != NULL; it = g_list_next(it) ) {
|
nkeynes@1034 | 62 | vmulist_entry_t entry = ENTRY(it);
|
nkeynes@1034 | 63 | temp = g_list_append( temp, (char *)entry->filename );
|
nkeynes@1034 | 64 | }
|
nkeynes@1034 | 65 | lxdream_set_global_config_list_value( CONFIG_VMU, temp );
|
nkeynes@1034 | 66 | g_list_free( temp );
|
nkeynes@1034 | 67 | }
|
nkeynes@1034 | 68 |
|
nkeynes@1034 | 69 | static vmulist_entry_t vmulist_get_entry_by_name( const gchar *name )
|
nkeynes@1034 | 70 | {
|
nkeynes@1034 | 71 | GList *it;
|
nkeynes@1034 | 72 | for( it = vmu_list; it != NULL; it = g_list_next(it) ) {
|
nkeynes@1034 | 73 | const gchar *vmu_name = DISPLAY_NAME(it);
|
nkeynes@1034 | 74 | if( name == NULL ? vmu_name == NULL : vmu_name != NULL && strcmp( vmu_name, name ) == 0 ) {
|
nkeynes@1034 | 75 | return ENTRY(it);
|
nkeynes@1034 | 76 | }
|
nkeynes@1034 | 77 | }
|
nkeynes@1034 | 78 | return NULL; // not found
|
nkeynes@1034 | 79 | }
|
nkeynes@1034 | 80 |
|
nkeynes@1034 | 81 | static vmulist_entry_t vmulist_get_entry_by_filename( const gchar *name )
|
nkeynes@1034 | 82 | {
|
nkeynes@1034 | 83 | GList *it;
|
nkeynes@1034 | 84 | for( it = vmu_list; it != NULL; it = g_list_next(it) ) {
|
nkeynes@1034 | 85 | const gchar *vmu_name = ENTRY(it)->filename;
|
nkeynes@1034 | 86 | if( name == NULL ? vmu_name == NULL : vmu_name != NULL && strcmp( vmu_name, name ) == 0 ) {
|
nkeynes@1034 | 87 | return ENTRY(it);
|
nkeynes@1034 | 88 | }
|
nkeynes@1034 | 89 | }
|
nkeynes@1034 | 90 | return NULL; // not found
|
nkeynes@1034 | 91 | }
|
nkeynes@1034 | 92 |
|
nkeynes@1034 | 93 | static vmulist_entry_t vmulist_get_entry_by_volume( vmu_volume_t vol )
|
nkeynes@1034 | 94 | {
|
nkeynes@1034 | 95 | GList *it;
|
nkeynes@1034 | 96 | for( it = vmu_list; it != NULL; it = g_list_next(it) ) {
|
nkeynes@1034 | 97 | if( VOLUME(it) == vol ) {
|
nkeynes@1034 | 98 | return ENTRY(it);
|
nkeynes@1034 | 99 | }
|
nkeynes@1034 | 100 | }
|
nkeynes@1034 | 101 | return NULL; // not found
|
nkeynes@1034 | 102 | }
|
nkeynes@1034 | 103 |
|
nkeynes@1034 | 104 | static vmulist_entry_t vmulist_get_entry_by_index( unsigned int index )
|
nkeynes@1034 | 105 | {
|
nkeynes@1034 | 106 | return (vmulist_entry_t)g_list_nth_data(vmu_list,index);
|
nkeynes@1034 | 107 | }
|
nkeynes@1034 | 108 |
|
nkeynes@1034 | 109 | static gint vmulist_display_name_compare( gconstpointer a, gconstpointer b )
|
nkeynes@1034 | 110 | {
|
nkeynes@1034 | 111 | const char *aname = vmulist_display_name((vmulist_entry_t)a);
|
nkeynes@1034 | 112 | const char *bname = vmulist_display_name((vmulist_entry_t)b);
|
nkeynes@1034 | 113 | if( aname == bname )
|
nkeynes@1034 | 114 | return 0;
|
nkeynes@1034 | 115 | if( aname == NULL )
|
nkeynes@1034 | 116 | return -1;
|
nkeynes@1034 | 117 | if( bname == NULL )
|
nkeynes@1034 | 118 | return 1;
|
nkeynes@1034 | 119 | return strcmp(aname,bname);
|
nkeynes@1034 | 120 | }
|
nkeynes@1034 | 121 |
|
nkeynes@1034 | 122 | /**
|
nkeynes@1034 | 123 | * Add a new entry into the list, maintaining the sorted order.
|
nkeynes@1034 | 124 | * If the filename is already in the list, it is updated instead.
|
nkeynes@1034 | 125 | */
|
nkeynes@1034 | 126 | static vmulist_entry_t vmulist_add_entry( const gchar *filename, vmu_volume_t vol )
|
nkeynes@1034 | 127 | {
|
nkeynes@1034 | 128 | vmulist_entry_t entry = vmulist_get_entry_by_filename(filename);
|
nkeynes@1034 | 129 | if( entry == NULL ) {
|
nkeynes@1034 | 130 | entry = g_malloc( sizeof(struct vmulist_entry) );
|
nkeynes@1034 | 131 | entry->filename = g_strdup(filename);
|
nkeynes@1034 | 132 | entry->vol = vol;
|
nkeynes@1034 | 133 | vmu_list = g_list_insert_sorted(vmu_list, entry, vmulist_display_name_compare );
|
nkeynes@1034 | 134 | } else {
|
nkeynes@1034 | 135 | if( entry->vol != vol && entry->vol != NULL )
|
nkeynes@1034 | 136 | vmu_volume_destroy( entry->vol );
|
nkeynes@1034 | 137 | entry->vol = vol;
|
nkeynes@1034 | 138 | /* NOTE: at the moment this can't require a resort, but if we allow
|
nkeynes@1034 | 139 | * user-editable display names it will
|
nkeynes@1034 | 140 | */
|
nkeynes@1034 | 141 | }
|
nkeynes@1034 | 142 | entry->attach_count = 0;
|
nkeynes@1034 | 143 |
|
nkeynes@1034 | 144 | vmulist_update_config();
|
nkeynes@1034 | 145 | CALL_HOOKS( vmulist_change_hook, VMU_ADDED, g_list_index(vmu_list,entry) );
|
nkeynes@1034 | 146 | return entry;
|
nkeynes@1034 | 147 | }
|
nkeynes@1034 | 148 |
|
nkeynes@1034 | 149 | static void vmulist_remove_entry( vmulist_entry_t entry )
|
nkeynes@1034 | 150 | {
|
nkeynes@1034 | 151 | int idx = g_list_index(vmu_list, entry);
|
nkeynes@1034 | 152 | vmu_list = g_list_remove( vmu_list, entry );
|
nkeynes@1034 | 153 | g_free( (char *)entry->filename );
|
nkeynes@1034 | 154 | g_free( entry );
|
nkeynes@1034 | 155 | vmulist_update_config();
|
nkeynes@1034 | 156 | CALL_HOOKS( vmulist_change_hook, VMU_REMOVED, idx );
|
nkeynes@1034 | 157 | }
|
nkeynes@1034 | 158 |
|
nkeynes@1034 | 159 | static unsigned int vmulist_get_index( vmulist_entry_t entry )
|
nkeynes@1034 | 160 | {
|
nkeynes@1034 | 161 | return g_list_index( vmu_list, entry );
|
nkeynes@1034 | 162 | }
|
nkeynes@1034 | 163 |
|
nkeynes@1034 | 164 | int vmulist_add_vmu( const gchar *filename, vmu_volume_t vol )
|
nkeynes@1034 | 165 | {
|
nkeynes@1034 | 166 | vmulist_entry_t entry = vmulist_add_entry( filename, vol );
|
nkeynes@1034 | 167 | return vmulist_get_index(entry);
|
nkeynes@1034 | 168 | }
|
nkeynes@1034 | 169 |
|
nkeynes@1034 | 170 | void vmulist_remove_vmu( vmu_volume_t vol )
|
nkeynes@1034 | 171 | {
|
nkeynes@1034 | 172 | vmulist_entry_t entry = vmulist_get_entry_by_volume(vol);
|
nkeynes@1034 | 173 | if( entry != NULL ) {
|
nkeynes@1034 | 174 | vmulist_remove_entry(entry);
|
nkeynes@1034 | 175 | }
|
nkeynes@1034 | 176 | }
|
nkeynes@1034 | 177 |
|
nkeynes@1034 | 178 | const char *vmulist_get_name( unsigned int idx )
|
nkeynes@1034 | 179 | {
|
nkeynes@1034 | 180 | vmulist_entry_t entry = vmulist_get_entry_by_index(idx);
|
nkeynes@1034 | 181 | if( entry != NULL ) {
|
nkeynes@1034 | 182 | return vmulist_display_name(entry);
|
nkeynes@1034 | 183 | }
|
nkeynes@1034 | 184 | return NULL;
|
nkeynes@1034 | 185 | }
|
nkeynes@1034 | 186 |
|
nkeynes@1034 | 187 | const char *vmulist_get_filename( unsigned int idx )
|
nkeynes@1034 | 188 | {
|
nkeynes@1034 | 189 | vmulist_entry_t entry = vmulist_get_entry_by_index(idx);
|
nkeynes@1034 | 190 | if( entry != NULL ) {
|
nkeynes@1034 | 191 | return entry->filename;
|
nkeynes@1034 | 192 | }
|
nkeynes@1034 | 193 | return NULL;
|
nkeynes@1034 | 194 | }
|
nkeynes@1034 | 195 |
|
nkeynes@1034 | 196 | const char *vmulist_get_volume_name( vmu_volume_t vol )
|
nkeynes@1034 | 197 | {
|
nkeynes@1034 | 198 | vmulist_entry_t entry = vmulist_get_entry_by_volume(vol);
|
nkeynes@1034 | 199 | if( entry != NULL ) {
|
nkeynes@1034 | 200 | return entry->filename;
|
nkeynes@1034 | 201 | }
|
nkeynes@1034 | 202 | return NULL;
|
nkeynes@1034 | 203 | }
|
nkeynes@1034 | 204 |
|
nkeynes@1034 | 205 | vmu_volume_t vmulist_get_vmu( unsigned int idx )
|
nkeynes@1034 | 206 | {
|
nkeynes@1034 | 207 | vmulist_entry_t entry = vmulist_get_entry_by_index(idx);
|
nkeynes@1034 | 208 | if( entry != NULL ) {
|
nkeynes@1034 | 209 | if( entry->vol == NULL ) {
|
nkeynes@1034 | 210 | entry->vol = vmu_volume_load(entry->filename);
|
nkeynes@1034 | 211 | }
|
nkeynes@1034 | 212 | return entry->vol;
|
nkeynes@1034 | 213 | }
|
nkeynes@1034 | 214 | return NULL;
|
nkeynes@1034 | 215 | }
|
nkeynes@1034 | 216 |
|
nkeynes@1034 | 217 | vmu_volume_t vmulist_get_vmu_by_name( const gchar *name )
|
nkeynes@1034 | 218 | {
|
nkeynes@1034 | 219 | vmulist_entry_t entry = vmulist_get_entry_by_name(name);
|
nkeynes@1034 | 220 | if( entry != NULL ) {
|
nkeynes@1034 | 221 | if( entry->vol == NULL ) {
|
nkeynes@1034 | 222 | entry->vol = vmu_volume_load(entry->filename);
|
nkeynes@1034 | 223 | }
|
nkeynes@1034 | 224 | return entry->vol;
|
nkeynes@1034 | 225 | }
|
nkeynes@1034 | 226 | return NULL;
|
nkeynes@1034 | 227 | }
|
nkeynes@1034 | 228 |
|
nkeynes@1034 | 229 | vmu_volume_t vmulist_get_vmu_by_filename( const gchar *name )
|
nkeynes@1034 | 230 | {
|
nkeynes@1034 | 231 | vmulist_entry_t entry = vmulist_get_entry_by_filename(name);
|
nkeynes@1034 | 232 | if( entry != NULL ) {
|
nkeynes@1034 | 233 | if( entry->vol == NULL ) {
|
nkeynes@1034 | 234 | entry->vol = vmu_volume_load(entry->filename);
|
nkeynes@1034 | 235 | }
|
nkeynes@1034 | 236 | return entry->vol;
|
nkeynes@1034 | 237 | } else {
|
nkeynes@1034 | 238 | vmu_volume_t vol = vmu_volume_load( name );
|
nkeynes@1034 | 239 | vmulist_add_entry( name, vol );
|
nkeynes@1034 | 240 | return vol;
|
nkeynes@1034 | 241 | }
|
nkeynes@1034 | 242 | }
|
nkeynes@1034 | 243 |
|
nkeynes@1034 | 244 | int vmulist_get_index_by_filename( const gchar *name )
|
nkeynes@1034 | 245 | {
|
nkeynes@1034 | 246 | vmulist_entry_t entry = vmulist_get_entry_by_filename(name);
|
nkeynes@1034 | 247 | if( entry != NULL ) {
|
nkeynes@1034 | 248 | return g_list_index( vmu_list, entry );
|
nkeynes@1034 | 249 | }
|
nkeynes@1034 | 250 | return -1;
|
nkeynes@1034 | 251 | }
|
nkeynes@1034 | 252 |
|
nkeynes@1034 | 253 |
|
nkeynes@1034 | 254 | int vmulist_create_vmu( const gchar *filename, gboolean create_only )
|
nkeynes@1034 | 255 | {
|
nkeynes@1034 | 256 | vmu_volume_t vol = vmu_volume_new_default(filename);
|
nkeynes@1034 | 257 |
|
nkeynes@1034 | 258 | if( vmu_volume_save( filename, vol, create_only ) ) {
|
nkeynes@1034 | 259 | return vmulist_add_vmu( filename, vol );
|
nkeynes@1034 | 260 | } else {
|
nkeynes@1034 | 261 | vmu_volume_destroy(vol);
|
nkeynes@1034 | 262 | }
|
nkeynes@1034 | 263 | return -1;
|
nkeynes@1034 | 264 | }
|
nkeynes@1034 | 265 |
|
nkeynes@1034 | 266 | gboolean vmulist_attach_vmu( vmu_volume_t vol, const gchar *where )
|
nkeynes@1034 | 267 | {
|
nkeynes@1034 | 268 | vmulist_entry_t entry = vmulist_get_entry_by_volume(vol);
|
nkeynes@1034 | 269 | if( entry == NULL ) {
|
nkeynes@1034 | 270 | return FALSE;
|
nkeynes@1034 | 271 | }
|
nkeynes@1034 | 272 | entry->attach_count++;
|
nkeynes@1034 | 273 | return TRUE;
|
nkeynes@1034 | 274 | }
|
nkeynes@1034 | 275 |
|
nkeynes@1034 | 276 | void vmulist_detach_vmu( vmu_volume_t vol )
|
nkeynes@1034 | 277 | {
|
nkeynes@1034 | 278 | vmulist_entry_t entry = vmulist_get_entry_by_volume(vol);
|
nkeynes@1034 | 279 | if( entry != NULL && entry->attach_count > 0 ) {
|
nkeynes@1034 | 280 | entry->attach_count--;
|
nkeynes@1034 | 281 | }
|
nkeynes@1034 | 282 | }
|
nkeynes@1034 | 283 |
|
nkeynes@1034 | 284 | unsigned int vmulist_get_size(void)
|
nkeynes@1034 | 285 | {
|
nkeynes@1034 | 286 | return g_list_length(vmu_list);
|
nkeynes@1034 | 287 | }
|
nkeynes@1034 | 288 |
|
nkeynes@1034 | 289 | void vmulist_init( void )
|
nkeynes@1034 | 290 | {
|
nkeynes@1034 | 291 | GList *filenames = lxdream_get_global_config_list_value( CONFIG_VMU );
|
nkeynes@1034 | 292 | GList *ptr;
|
nkeynes@1034 | 293 | for( ptr = filenames; ptr != NULL; ptr = g_list_next(ptr) ) {
|
nkeynes@1034 | 294 | vmulist_add_entry( (gchar *)ptr->data, NULL );
|
nkeynes@1034 | 295 | g_free( ptr->data );
|
nkeynes@1034 | 296 | }
|
nkeynes@1034 | 297 | g_list_free( filenames );
|
nkeynes@1034 | 298 | }
|
nkeynes@1034 | 299 |
|
nkeynes@1034 | 300 | void vmulist_save_all( void )
|
nkeynes@1034 | 301 | {
|
nkeynes@1034 | 302 | GList *it;
|
nkeynes@1034 | 303 | for( it = vmu_list; it != NULL; it = g_list_next(it) ) {
|
nkeynes@1034 | 304 | vmulist_entry_t entry = ENTRY(it);
|
nkeynes@1034 | 305 | if( entry->vol != NULL && vmu_volume_is_dirty(entry->vol) ) {
|
nkeynes@1034 | 306 | vmu_volume_save(entry->filename, entry->vol, FALSE);
|
nkeynes@1034 | 307 | }
|
nkeynes@1034 | 308 | }
|
nkeynes@1034 | 309 | }
|
nkeynes@1034 | 310 |
|
nkeynes@1034 | 311 | void vmulist_shutdown( void )
|
nkeynes@1034 | 312 | {
|
nkeynes@1034 | 313 | vmulist_save_all();
|
nkeynes@1034 | 314 | }
|