]> git.sesse.net Git - vlc/blobdiff - src/config/file.c
Hack to take care of qt strings with ampersand
[vlc] / src / config / file.c
index c730423510943fb2ac873b0ccfac44ca8ad90b3a..894ebbb14e081062cd69a7f446e5881b0612b9a4 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-#include <vlc/vlc.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
 #include "../libvlc.h"
 #include "vlc_charset.h"
 #include "vlc_keys.h"
 
 #include <errno.h>                                                  /* errno */
-
-#ifdef HAVE_LIMITS_H
-#   include <limits.h>
+#include <assert.h>
+#include <limits.h>
+#ifdef __APPLE__
+#   include <xlocale.h>
+#else
+#include <locale.h>
 #endif
 
-#include "config.h"
+#include "configuration.h"
 #include "modules/modules.h"
 
 static char *ConfigKeyToString( int );
@@ -42,20 +49,28 @@ static inline char *strdupnull (const char *src)
     return src ? strdup (src) : NULL;
 }
 
-static inline char *_strdupnull (const char *src)
+/**
+ * Get the user's configuration file
+ */
+static char *config_GetConfigFile( void )
 {
-    return src ? strdup (_(src)) : NULL;
-}
+    char *psz_dir = config_GetUserConfDir();
+    char *psz_configfile;
 
+    if( asprintf( &psz_configfile, "%s" DIR_SEP CONFIG_FILE, psz_dir ) == -1 )
+        psz_configfile = NULL;
+    free( psz_dir );
+    return psz_configfile;
+}
 
 static FILE *config_OpenConfigFile( vlc_object_t *p_obj, const char *mode )
 {
-    char *psz_filename = p_obj->p_libvlc->psz_configfile;
+    char *psz_filename = libvlc_priv (p_obj->p_libvlc)->psz_configfile;
     FILE *p_stream;
 
     if( !psz_filename )
     {
-        psz_filename = config_GetConfigFile( p_obj->p_libvlc );
+        psz_filename = config_GetConfigFile();
     }
 
     msg_Dbg( p_obj, "opening config file (%s)", psz_filename );
@@ -74,7 +89,7 @@ static FILE *config_OpenConfigFile( vlc_object_t *p_obj, const char *mode )
          * Specification configs */
         char *psz_old;
         if( asprintf( &psz_old, "%s" DIR_SEP CONFIG_DIR DIR_SEP CONFIG_FILE,
-                  p_obj->p_libvlc->psz_homedir ) != -1 )
+                      config_GetHomeDir() ) != -1 )
         {
             p_stream = utf8_fopen( psz_old, mode );
             if( p_stream )
@@ -85,19 +100,18 @@ static FILE *config_OpenConfigFile( vlc_object_t *p_obj, const char *mode )
                           "VLC will now use %s.", psz_old, psz_filename );
                 char *psz_readme;
                 if( asprintf(&psz_readme,"%s"DIR_SEP CONFIG_DIR DIR_SEP"README",
-                              p_obj->p_libvlc->psz_homedir ) != -1 )
+                              config_GetHomeDir() ) != -1 )
                 {
                     FILE *p_readme = utf8_fopen( psz_readme, "wt" );
                     if( p_readme )
                     {
-                        fputs( "The VLC media player configuration folder has "
-                               "moved to comply with the XDG Base "
-                               "Directory Specification version 0.6. Your "
-                               "configuration has been copied to the new "
-                               "location (", p_readme );
-                        fputs( p_obj->p_libvlc->psz_configdir, p_readme );
-                        fputs( "). You can delete this directory and "
-                               "all its contents.", p_readme );
+                        fprintf( p_readme, "The VLC media player "
+                                 "configuration folder has moved to comply\n"
+                                 "with the XDG Base Directory Specification "
+                                 "version 0.6. Your\nconfiguration has been "
+                                 "copied to the new location:\n%s\nYou can "
+                                 "delete this directory and all its contents.",
+                                  psz_filename);
                         fclose( p_readme );
                     }
                     free( psz_readme );
@@ -109,7 +123,7 @@ static FILE *config_OpenConfigFile( vlc_object_t *p_obj, const char *mode )
 #endif
     else if( p_stream != NULL )
     {
-        p_obj->p_libvlc->psz_configfile = psz_filename;
+        libvlc_priv (p_obj->p_libvlc)->psz_configfile = psz_filename;
     }
 
     return p_stream;
@@ -143,6 +157,7 @@ static int strtoi (const char *str)
  *****************************************************************************/
 int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
 {
+    libvlc_priv_t *priv = libvlc_priv (p_this->p_libvlc);
     vlc_list_t *p_list;
     FILE *file;
 
@@ -151,7 +166,7 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
         return VLC_EGENERIC;
 
     /* Acquire config file lock */
-    vlc_mutex_lock( &p_this->p_libvlc->config_lock );
+    vlc_mutex_lock( &priv->config_lock );
 
     /* Look for the selected module, if NULL then save everything */
     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
@@ -171,6 +186,10 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
     char line[1024], section[1022];
     section[0] = '\0';
 
+    /* Ensure consistent number formatting... */
+    locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
+    locale_t baseloc = uselocale (loc);
+
     while (fgets (line, 1024, file) != NULL)
     {
         /* Ignore comments and empty lines */
@@ -262,7 +281,7 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
                 case CONFIG_ITEM_FLOAT:
                     if( !*psz_option_value )
                         break;                    /* ignore empty option */
-                    p_item->value.f = (float)i18n_atof( psz_option_value);
+                    p_item->value.f = (float)atof (psz_option_value);
                     p_item->saved.f = p_item->value.f;
                     break;
 
@@ -299,8 +318,13 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
     fclose (file);
 
     vlc_list_release( p_list );
+    if (loc != (locale_t)0)
+    {
+        uselocale (baseloc);
+        freelocale (loc);
+    }
 
-    vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
+    vlc_mutex_unlock( &priv->config_lock );
     return 0;
 }
 
@@ -309,7 +333,7 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
  *****************************************************************************/
 int config_CreateDir( vlc_object_t *p_this, const char *psz_dirname )
 {
-    if( !psz_dirname && !*psz_dirname ) return -1;
+    if( !psz_dirname || !*psz_dirname ) return -1;
 
     if( utf8_mkdir( psz_dirname, 0700 ) == 0 )
         return 0;
@@ -342,6 +366,32 @@ int config_CreateDir( vlc_object_t *p_this, const char *psz_dirname )
     return -1;
 }
 
+static int
+config_Write (FILE *file, const char *type, const char *desc,
+              bool comment, const char *name, const char *fmt, ...)
+{
+    va_list ap;
+    int ret;
+
+    if (desc == NULL)
+        desc = "?";
+
+    if (fprintf (file, "# %s (%s)\n%s%s=", desc, _(type),
+                 comment ? "#" : "", name) < 0)
+        return -1;
+
+    va_start (ap, fmt);
+    ret = vfprintf (file, fmt, ap);
+    va_end (ap);
+    if (ret < 0)
+        return -1;
+
+    if (fputs ("\n\n", file) == EOF)
+        return -1;
+    return 0;
+}
+
+
 /*****************************************************************************
  * config_SaveConfigFile: Save a module's config options.
  *****************************************************************************
@@ -362,31 +412,33 @@ int config_CreateDir( vlc_object_t *p_this, const char *psz_dirname )
  * Really stupid no ?
  *****************************************************************************/
 static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
-                           vlc_bool_t b_autosave )
+                           bool b_autosave )
 {
+    libvlc_priv_t *priv = libvlc_priv (p_this->p_libvlc);
     module_t *p_parser;
     vlc_list_t *p_list;
     FILE *file;
     char p_line[1024], *p_index2;
     int i_sizebuf = 0;
     char *p_bigbuffer, *p_index;
-    vlc_bool_t b_backup;
+    bool b_backup;
     int i_index;
 
     /* Acquire config file lock */
-    vlc_mutex_lock( &p_this->p_libvlc->config_lock );
+    vlc_mutex_lock( &priv->config_lock );
 
-    if( p_this->p_libvlc->psz_configfile == NULL )
+    if( libvlc_priv (p_this->p_libvlc)->psz_configfile == NULL )
     {
-        const char *psz_configdir = p_this->p_libvlc->psz_configdir;
+        char *psz_configdir = config_GetUserConfDir();
         if( !psz_configdir ) /* XXX: This should never happen */
         {
             msg_Err( p_this, "no configuration directory defined" );
-            vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
+            vlc_mutex_unlock( &priv->config_lock );
             return -1;
         }
 
         config_CreateDir( p_this, psz_configdir );
+        free( psz_configdir );
     }
 
     file = config_OpenConfigFile( p_this, "rt" );
@@ -401,9 +453,8 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
     p_bigbuffer = p_index = malloc( i_sizebuf+1 );
     if( !p_bigbuffer )
     {
-        msg_Err( p_this, "out of memory" );
         if( file ) fclose( file );
-        vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
+        vlc_mutex_unlock( &priv->config_lock );
         return -1;
     }
     p_bigbuffer[0] = 0;
@@ -477,12 +528,16 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
     {
         vlc_list_release( p_list );
         free( p_bigbuffer );
-        vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
+        vlc_mutex_unlock( &priv->config_lock );
         return -1;
     }
 
     fprintf( file, "\xEF\xBB\xBF###\n###  " COPYRIGHT_MESSAGE "\n###\n\n"
-       "###\n### lines begining with a '#' character are comments\n###\n\n" );
+       "###\n### lines beginning with a '#' character are comments\n###\n\n" );
+
+    /* Ensure consistent number formatting... */
+    locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
+    locale_t baseloc = uselocale (loc);
 
     /* Look for the selected module, if NULL then save everything */
     for( i_index = 0; i_index < p_list->i_count; i_index++ )
@@ -511,100 +566,90 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
              p_item < p_end;
              p_item++ )
         {
-            char  *psz_key;
-            int   i_value = p_item->value.i;
-            float f_value = p_item->value.f;
-            const char  *psz_value = p_item->value.psz;
+            /* 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( p_item->i_type & CONFIG_HINT )
-                /* ignore hints */
-                continue;
-            /* Ignore deprecated options */
-            if( p_item->psz_current )
-                continue;
-            if( p_item->b_unsaveable )
-                /*obvious*/
+            if ((p_item->i_type & CONFIG_HINT) /* ignore hint */
+             || p_item->b_removed              /* ignore deprecated option */
+             || p_item->b_unsaveable)          /* ignore volatile option */
                 continue;
 
-            if( b_autosave && !p_item->b_autosave )
+            if (IsConfigIntegerType (p_item->i_type))
             {
-                i_value = p_item->saved.i;
-                f_value = p_item->saved.f;
-                psz_value = p_item->saved.psz;
-                if( !psz_value ) psz_value = p_item->orig.psz;
+                int val = b_retain ? p_item->saved.i : p_item->value.i;
+                if (p_item->i_type == CONFIG_ITEM_KEY)
+                {
+                    char *psz_key = ConfigKeyToString (val);
+                    config_Write (file, p_item->psz_text, N_("key"),
+                                  val == p_item->orig.i,
+                                  p_item->psz_name, "%s",
+                                  psz_key ? psz_key : "");
+                    free (psz_key);
+                }
+                else
+                    config_Write (file, p_item->psz_text,
+                                  (p_item->i_type == CONFIG_ITEM_BOOL)
+                                      ? N_("boolean") : N_("integer"),
+                                  val == p_item->orig.i,
+                                  p_item->psz_name, "%d", val);
+                p_item->saved.i = val;
             }
             else
+            if (IsConfigFloatType (p_item->i_type))
             {
-                p_item->b_dirty = VLC_FALSE;
+                float val = b_retain ? p_item->saved.f : 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;
             }
-
-            switch( p_item->i_type )
+            else
             {
-            case CONFIG_ITEM_BOOL:
-            case CONFIG_ITEM_INTEGER:
-                if( p_item->psz_text )
-                    fprintf( file, "# %s (%s)\n", p_item->psz_text,
-                             (p_item->i_type == CONFIG_ITEM_BOOL) ?
-                             _("boolean") : _("integer") );
-                if( i_value == p_item->orig.i )
-                    fputc ('#', file);
-                fprintf( file, "%s=%i\n", p_item->psz_name, i_value );
-
-                p_item->saved.i = i_value;
-                break;
-
-            case CONFIG_ITEM_KEY:
-                if( p_item->psz_text )
-                    fprintf( file, "# %s (%s)\n", p_item->psz_text,
-                             _("key") );
-                if( i_value == p_item->orig.i )
-                    fputc ('#', file);
-                psz_key = ConfigKeyToString( i_value );
-                fprintf( file, "%s=%s\n", p_item->psz_name,
-                         psz_key ? psz_key : "" );
-                free (psz_key);
-
-                p_item->saved.i = i_value;
-                break;
-
-            case CONFIG_ITEM_FLOAT:
-                if( p_item->psz_text )
-                    fprintf( file, "# %s (%s)\n", p_item->psz_text,
-                             _("float") );
-                if( f_value == p_item->orig.f )
-                    fputc ('#', file);
-                fprintf( file, "%s=%f\n", p_item->psz_name, (double)f_value );
-
-                p_item->saved.f = f_value;
-                break;
-
-            default:
-                if( p_item->psz_text )
-                    fprintf( file, "# %s (%s)\n", p_item->psz_text,
-                             _("string") );
-                if( (!psz_value && !p_item->orig.psz) ||
-                    (psz_value && p_item->orig.psz &&
-                     !strcmp( psz_value, p_item->orig.psz )) )
-                    fputc ('#', file);
-                fprintf( file, "%s=%s\n", p_item->psz_name,
-                         psz_value ?: "" );
-
-                if( b_autosave && !p_item->b_autosave ) break;
-
-                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;
+                const char *psz_value = b_retain ? p_item->saved.psz
+                                                 : 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);
+
+                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;
+                }
             }
-        }
 
-        fputc ('\n', file);
+            if (!b_retain)
+                p_item->b_dirty = false;
+        }
     }
 
     vlc_list_release( p_list );
+    if (loc != (locale_t)0)
+    {
+        uselocale (baseloc);
+        freelocale (loc);
+    }
 
     /*
      * Restore old settings from the config in file
@@ -613,20 +658,21 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
     free( p_bigbuffer );
 
     fclose( file );
-    vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
+    vlc_mutex_unlock( &priv->config_lock );
 
     return 0;
 }
 
 int config_AutoSaveConfigFile( vlc_object_t *p_this )
 {
+    libvlc_priv_t *priv = libvlc_priv (p_this->p_libvlc);
     vlc_list_t *p_list;
     int i_index, i_count;
 
-    if( !p_this ) return -1;
+    assert( p_this );
 
     /* Check if there's anything to save */
-    vlc_mutex_lock( &p_this->p_libvlc->config_lock );
+    vlc_mutex_lock( &priv->config_lock );
     p_list = vlc_list_find( p_this, VLC_OBJECT_MODULE, FIND_ANYWHERE );
     i_count = p_list->i_count;
     for( i_index = 0; i_index < i_count; i_index++ )
@@ -642,30 +688,18 @@ int config_AutoSaveConfigFile( vlc_object_t *p_this )
         {
             if( p_item->b_autosave && p_item->b_dirty ) break;
         }
-        break;
+        if( p_item < p_end ) break;
     }
     vlc_list_release( p_list );
-    vlc_mutex_unlock( &p_this->p_libvlc->config_lock );
+    vlc_mutex_unlock( &priv->config_lock );
 
     if( i_index == i_count ) return VLC_SUCCESS;
-    return SaveConfigFile( p_this, 0, VLC_TRUE );
+    return SaveConfigFile( p_this, 0, true );
 }
 
 int __config_SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name )
 {
-    return SaveConfigFile( p_this, psz_module_name, VLC_FALSE );
-}
-
-/**
- * Get the user's configuration file
- */
-char *config_GetConfigFile( libvlc_int_t *p_libvlc )
-{
-    char *psz_configfile;
-    if( asprintf( &psz_configfile, "%s" DIR_SEP CONFIG_FILE,
-                  p_libvlc->psz_configdir ) == -1 )
-        return NULL;
-    return psz_configfile;
+    return SaveConfigFile( p_this, psz_module_name, false );
 }
 
 /**
@@ -680,7 +714,7 @@ char *config_GetCustomConfigFile( libvlc_int_t *p_libvlc )
         {
             /* This is incomplete: we should also support the ~cmassiot/ syntax */
             char *psz_buf;
-            if( asprintf( &psz_buf, "%s/%s", p_libvlc->psz_homedir,
+            if( asprintf( &psz_buf, "%s/%s", config_GetHomeDir(),
                           psz_configfile + 2 ) == -1 )
             {
                 free( psz_configfile );