/*****************************************************************************
* file.c: configuration file handling
*****************************************************************************
- * Copyright (C) 2001-2007 the VideoLAN team
+ * Copyright (C) 2001-2007 VLC authors and VideoLAN
* $Id$
*
* Authors: Gildas Bazin <gbazin@videolan.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
#elif defined(HAVE_USELOCALE)
#include <locale.h>
#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
#include <vlc_common.h>
#include "../libvlc.h"
#include <vlc_fs.h>
#include <vlc_keys.h>
#include <vlc_modules.h>
+#include <vlc_plugin.h>
#include "configuration.h"
#include "modules/modules.h"
psz_filename );
}
-#if !( defined(WIN32) || defined(__APPLE__) || defined(__OS2__) )
+#if !( defined(_WIN32) || defined(__APPLE__) || defined(__OS2__) )
else if( p_stream == NULL && errno == ENOENT )
{
/* This is the fallback for pre XDG Base Directory
continue;
const char *psz_option_value = ptr + 1;
- switch (item->i_type)
+ switch (CONFIG_CLASS(item->i_type))
{
case CONFIG_ITEM_BOOL:
case CONFIG_ITEM_INTEGER:
msg_Warn (p_this, "Integer value (%s) for %s: %m",
psz_option_value, psz_option_name);
else
- item->saved.i = item->value.i = l;
+ item->value.i = l;
break;
}
if (!*psz_option_value)
break; /* ignore empty option */
item->value.f = (float)atof (psz_option_value);
- item->saved.f = item->value.f;
break;
default:
free ((char *)item->value.psz);
- free ((char *)item->saved.psz);
item->value.psz = convert (psz_option_value);
- item->saved.psz = strdupnull (item->value.psz);
break;
}
}
return ret;
}
-/*****************************************************************************
- * config_SaveConfigFile: Save a module's config options.
- *****************************************************************************
- * This will save the specified module's config options to the config file.
- * If psz_module_name is NULL then we save all the modules config options.
- * It's no use to save the config options that kept their default values, so
- * we'll try to be a bit clever here.
- *
- * When we save we mustn't delete the config options of the modules that
- * haven't been loaded. So we cannot just create a new config file with the
- * config structures we've got in memory.
- * I don't really know how to deal with this nicely, so I will use a completly
- * dumb method ;-)
- * I will load the config file in memory, but skipping all the sections of the
- * modules we want to save. Then I will create a brand new file, dump the file
- * loaded in memory and then append the sections of the modules we want to
- * save.
- * Really stupid no ?
- *****************************************************************************/
-static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
- bool b_autosave )
+#undef config_SaveConfigFile
+/**
+ * Saves the in-memory configuration into a file.
+ * @return 0 on success, -1 on error.
+ */
+int config_SaveConfigFile (vlc_object_t *p_this)
{
- module_t *p_parser;
- char *permanent = NULL, *temporary = NULL;
if( config_PrepareDir( p_this ) )
{
return -1;
}
- /* List all available modules */
- module_t **list = module_list_get (NULL);
-
- char *bigbuf = NULL;
- size_t bigsize = 0;
- FILE *file = config_OpenConfigFile (p_this);
- if (file != NULL)
+ /*
+ * Save module config in file
+ */
+ char *temporary;
+ char *permanent = config_GetConfigFile (p_this);
+ if (permanent == NULL)
+ return -1;
+ if (asprintf (&temporary, "%s.%u", permanent, getpid ()) == -1)
+ {
+ free (permanent);
+ return -1;
+ }
+ else
{
struct stat st;
/* Some users make vlcrc read-only to prevent changes.
* The atomic replacement scheme breaks this "feature",
* so we check for read-only by hand. */
- if (fstat (fileno (file), &st)
- || !(st.st_mode & S_IWUSR))
+ if (stat (permanent, &st) == 0 && !(st.st_mode & S_IWUSR))
{
msg_Err (p_this, "configuration file is read-only");
goto error;
}
-
- bigsize = (st.st_size < LONG_MAX) ? st.st_size : 0;
- bigbuf = malloc (bigsize + 1);
- if (bigbuf == NULL)
- goto error;
-
- /* backup file into memory, we only need to backup the sections we
- * won't save later on */
- char *p_index = bigbuf;
- char *line = NULL;
- size_t bufsize;
- ssize_t linelen;
- bool backup = false;
-
- while ((linelen = getline (&line, &bufsize, file)) != -1)
- {
- char *p_index2;
-
- if ((line[0] == '[') && (p_index2 = strchr(line,']')))
- {
- /* we found a new section, check if we need to do a backup */
- backup = true;
- for (int i = 0; (p_parser = list[i]) != NULL; i++)
- {
- if (!strncmp (line + 1, p_parser->psz_object_name,
- strlen (p_parser->psz_object_name))
- && ((psz_module_name == NULL)
- || !strcmp (psz_module_name, p_parser->psz_object_name)))
- {
- backup = false; /* no, we will rewrite it! */
- break;
- }
- }
- }
-
- /* save line if requested and line is valid (doesn't begin with a
- * space, tab, or eol) */
- if (backup && !memchr ("\n\t ", line[0], 3))
- {
- memcpy (p_index, line, linelen);
- p_index += linelen;
- }
- }
- fclose (file);
- file = NULL;
- free (line);
- *p_index = '\0';
- bigsize = p_index - bigbuf;
- }
-
- /*
- * Save module config in file
- */
- permanent = config_GetConfigFile (p_this);
- if (!permanent)
- {
- module_list_free (list);
- goto error;
- }
-
- if (asprintf (&temporary, "%s.%u", permanent, getpid ()) == -1)
- {
- temporary = NULL;
- module_list_free (list);
- goto error;
}
/* Configuration lock must be taken before vlcrc serializer below. */
vlc_rwlock_rdlock (&config_lock);
- /* The temporary configuration file is per-PID. Therefore SaveConfigFile()
+ /* The temporary configuration file is per-PID. Therefore this function
* should be serialized against itself within a given process. */
static vlc_mutex_t lock = VLC_STATIC_MUTEX;
vlc_mutex_lock (&lock);
{
vlc_rwlock_unlock (&config_lock);
vlc_mutex_unlock (&lock);
- module_list_free (list);
goto error;
}
- file = fdopen (fd, "wt");
+ FILE *file = fdopen (fd, "wt");
if (file == NULL)
{
msg_Err (p_this, "cannot create configuration file: %m");
vlc_rwlock_unlock (&config_lock);
close (fd);
vlc_mutex_unlock (&lock);
- module_list_free (list);
goto error;
}
vlc_rwlock_rdlock (&config_lock);*/
/* Look for the selected module, if NULL then save everything */
- for (int i = 0; (p_parser = list[i]) != NULL; i++)
+ size_t count;
+ module_t **list = module_list_get (&count);
+ for (size_t i = 0; i < count; i++)
{
+ module_t *p_parser = list[i];
module_config_t *p_item, *p_end;
- if( psz_module_name && strcmp( psz_module_name,
- p_parser->psz_object_name ) )
- continue;
-
if( !p_parser->i_config_items )
continue;
- if( psz_module_name )
- msg_Dbg( p_this, "saving config for module \"%s\"",
- p_parser->psz_object_name );
-
- fprintf( file, "[%s]", p_parser->psz_object_name );
+ fprintf( file, "[%s]", module_get_object (p_parser) );
if( p_parser->psz_longname )
fprintf( file, " # %s\n\n", p_parser->psz_longname );
else
p_item < p_end;
p_item++ )
{
- if ((p_item->i_type & CONFIG_HINT) /* ignore hint */
+ if (!CONFIG_ITEM(p_item->i_type) /* ignore hint */
|| p_item->b_removed /* ignore deprecated option */
|| p_item->b_unsaveable) /* ignore volatile option */
continue;
- /* Do not save the new value in the configuration file
- * if doing an autosave, and the item is not an "autosaved" one. */
- bool b_retain = b_autosave && !p_item->b_autosave;
-
if (IsConfigIntegerType (p_item->i_type))
{
- int64_t val = b_retain ? p_item->saved.i : p_item->value.i;
+ int64_t val = p_item->value.i;
config_Write (file, p_item->psz_text,
- (p_item->i_type == CONFIG_ITEM_BOOL)
+ (CONFIG_CLASS(p_item->i_type) == CONFIG_ITEM_BOOL)
? N_("boolean") : N_("integer"),
val == p_item->orig.i,
p_item->psz_name, "%"PRId64, val);
- p_item->saved.i = val;
}
else
if (IsConfigFloatType (p_item->i_type))
{
- float val = b_retain ? p_item->saved.f : p_item->value.f;
+ float val = p_item->value.f;
config_Write (file, p_item->psz_text, N_("float"),
val == p_item->orig.f,
p_item->psz_name, "%f", val);
- p_item->saved.f = val;
}
else
{
- const char *psz_value = b_retain ? p_item->saved.psz
- : p_item->value.psz;
+ const char *psz_value = p_item->value.psz;
bool modified;
assert (IsConfigStringType (p_item->i_type));
- if (b_retain && (psz_value == NULL)) /* FIXME: hack */
- psz_value = p_item->orig.psz;
-
- modified =
- (psz_value != NULL)
- ? ((p_item->orig.psz != NULL)
- ? (strcmp (psz_value, p_item->orig.psz) != 0)
- : true)
- : (p_item->orig.psz != NULL);
-
+ modified = !!strcmp (psz_value ? psz_value : "",
+ p_item->orig.psz ? p_item->orig.psz : "");
config_Write (file, p_item->psz_text, N_("string"),
!modified, p_item->psz_name, "%s",
psz_value ? psz_value : "");
-
- if ( !b_retain )
- {
-
- free ((char *)p_item->saved.psz);
- if( (psz_value && p_item->orig.psz &&
- strcmp( psz_value, p_item->orig.psz )) ||
- !psz_value || !p_item->orig.psz)
- p_item->saved.psz = strdupnull (psz_value);
- else
- p_item->saved.psz = NULL;
- }
}
-
- if (!b_retain)
- p_item->b_dirty = false;
}
}
vlc_rwlock_unlock (&config_lock);
freelocale (loc);
}
- /*
- * Restore old settings from the config in file
- */
- if (bigsize)
- fwrite (bigbuf, 1, bigsize, file);
-
/*
* Flush to disk and replace atomically
*/
vlc_unlink (temporary);
vlc_mutex_unlock (&lock);
msg_Err (p_this, "cannot write configuration file");
- clearerr (file);
+ fclose (file);
goto error;
}
-#if !defined( WIN32 ) && !defined( __OS2__ )
-#ifdef __APPLE__
+#if defined(__APPLE__) || defined(__ANDROID__)
fsync (fd); /* Flush from OS */
#else
fdatasync (fd); /* Flush from OS */
+#endif
+#if defined (_WIN32) || defined (__OS2__)
+ /* Windows cannot (re)move open files nor overwrite existing ones */
+ fclose (file);
+ vlc_unlink (permanent);
#endif
/* Atomically replace the file... */
if (vlc_rename (temporary, permanent))
/* (...then synchronize the directory, err, TODO...) */
/* ...and finally close the file */
vlc_mutex_unlock (&lock);
-#endif
+#if !defined (_WIN32) && !defined (__OS2__)
fclose (file);
-#if defined( WIN32 ) || defined( __OS2__ )
- /* Windows cannot remove open files nor overwrite existing ones */
- vlc_unlink (permanent);
- if (vlc_rename (temporary, permanent))
- vlc_unlink (temporary);
- vlc_mutex_unlock (&lock);
#endif
free (temporary);
free (permanent);
- free (bigbuf);
return 0;
error:
- if( file )
- fclose( file );
free (temporary);
free (permanent);
- free (bigbuf);
return -1;
}
int config_AutoSaveConfigFile( vlc_object_t *p_this )
{
- int ret = VLC_SUCCESS;
- bool save = false;
+ int ret = 0;
assert( p_this );
- /* Check if there's anything to save */
- module_t **list = module_list_get (NULL);
vlc_rwlock_rdlock (&config_lock);
- for (size_t i_index = 0; list[i_index] && !save; i_index++)
+ if (config_dirty)
{
- module_t *p_parser = list[i_index];
- module_config_t *p_item, *p_end;
-
- if( !p_parser->i_config_items ) continue;
-
- for( p_item = p_parser->p_config, p_end = p_item + p_parser->confsize;
- p_item < p_end && !save;
- p_item++ )
- {
- save = p_item->b_autosave && p_item->b_dirty;
- }
- }
-
- if (save)
/* Note: this will get the read lock recursively. Ok. */
- ret = SaveConfigFile (p_this, NULL, true);
+ ret = config_SaveConfigFile (p_this);
+ config_dirty = (ret != 0);
+ }
vlc_rwlock_unlock (&config_lock);
- module_list_free (list);
return ret;
}
-
-#undef config_SaveConfigFile
-int config_SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name )
-{
- return SaveConfigFile( p_this, psz_module_name, false );
-}