chain.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:12k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * chain.c : configuration module chain parsing stuff
  3.  *****************************************************************************
  4.  * Copyright (C) 2002-2007 the VideoLAN team
  5.  * $Id: 8e0c067e3b426a4208d17a59a419a64c7de18c9d $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  8.  *          Laurent Aimar <fenrir@via.ecp.fr>
  9.  *          Eric Petit <titer@videolan.org>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #ifdef HAVE_CONFIG_H
  29. # include "config.h"
  30. #endif
  31. #include <vlc_common.h>
  32. #include "libvlc.h"
  33. #include <vlc_charset.h>
  34. #include "vlc_interface.h"
  35. /*****************************************************************************
  36.  * Local prototypes
  37.  *****************************************************************************/
  38. static bool IsEscapeNeeded( char c )
  39. {
  40.     return c == ''' || c == '"' || c == '\';
  41. }
  42. static bool IsEscape( const char *psz )
  43. {
  44.     if( !psz )
  45.         return false;
  46.     return psz[0] == '\' && IsEscapeNeeded( psz[1] );
  47. }
  48. static bool IsSpace( char c  )
  49. {
  50.     return c == ' ' || c == 't';
  51. }
  52. #define SKIPSPACE( p ) p += strspn( p, " t" )
  53. #define SKIPTRAILINGSPACE( p, e ) 
  54.     do { while( e > p && IsSpace( *(e-1) ) ) e--; } while(0)
  55. /**
  56.  * This function will return a pointer after the end of a string element.
  57.  * It will search the closing element which is
  58.  * } for { (it will handle nested { ... })
  59.  * " for "
  60.  * ' for '
  61.  */
  62. static const char *ChainGetEnd( const char *psz_string )
  63. {
  64.     const char *p = psz_string;
  65.     char c;
  66.     if( !psz_string )
  67.         return NULL;
  68.     /* Look for a opening character */
  69.     SKIPSPACE( p );
  70.     for( ;; p++)
  71.     {
  72.         if( *p == '' || *p == ',' || *p == '}' )
  73.             return p;
  74.         if( *p == '{' || *p == '"' || *p == ''' )
  75.             break;
  76.     }
  77.     /* Set c to the closing character */
  78.     if( *p == '{' )
  79.         c = '}';
  80.     else
  81.         c = *p;
  82.     p++;
  83.     /* Search the closing character, handle nested {..} */
  84.     for( ;; )
  85.     {
  86.         if( *p == '')
  87.             return p;
  88.         if( IsEscape( p ) )
  89.             p += 2;
  90.         else if( *p == c )
  91.             return ++p;
  92.         else if( *p == '{' && c == '}' )
  93.             p = ChainGetEnd( p );
  94.         else
  95.             p++;
  96.     }
  97. }
  98. /**
  99.  * It will extract an option value (=... or {...}).
  100.  * It will remove the initial = if present but keep the {}
  101.  */
  102. static char *ChainGetValue( const char **ppsz_string )
  103. {
  104.     const char *p = *ppsz_string;
  105.     char *psz_value = NULL;
  106.     const char *end;
  107.     bool b_keep_brackets = (*p == '{');
  108.     if( *p == '=' )
  109.         p++;
  110.     end = ChainGetEnd( p );
  111.     if( end <= p )
  112.     {
  113.         psz_value = NULL;
  114.     }
  115.     else
  116.     {
  117.         /* Skip heading and trailing spaces.
  118.          * This ain't necessary but will avoid simple
  119.          * user mistakes. */
  120.         SKIPSPACE( p );
  121.     }
  122.     if( end <= p )
  123.     {
  124.         psz_value = NULL;
  125.     }
  126.     else
  127.     {
  128.         if( *p == ''' || *p == '"' || ( !b_keep_brackets && *p == '{' ) )
  129.         {
  130.             p++;
  131.             if( *(end-1) != ''' && *(end-1) == '"' )
  132.                 SKIPTRAILINGSPACE( p, end );
  133.             if( end - 1 <= p )
  134.                 psz_value = NULL;
  135.             else
  136.                 psz_value = strndup( p, end -1 - p );
  137.         }
  138.         else
  139.         {
  140.             SKIPTRAILINGSPACE( p, end );
  141.             if( end <= p )
  142.                 psz_value = NULL;
  143.             else
  144.                 psz_value = strndup( p, end - p );
  145.         }
  146.     }
  147.     /* */
  148.     if( psz_value )
  149.         config_StringUnescape( psz_value );
  150.     /* */
  151.     *ppsz_string = end;
  152.     return psz_value;
  153. }
  154. char *config_ChainCreate( char **ppsz_name, config_chain_t **pp_cfg,
  155.                           const char *psz_chain )
  156. {
  157.     config_chain_t **pp_next = pp_cfg;
  158.     size_t len;
  159.     *ppsz_name = NULL;
  160.     *pp_cfg    = NULL;
  161.     if( !psz_chain )
  162.         return NULL;
  163.     psz_chain += strspn( psz_chain, " t" );
  164.     /* Look for parameter (a {...} or :...) or end of name (space or nul) */
  165.     len = strcspn( psz_chain, "{: t" );
  166.     *ppsz_name = strndup( psz_chain, len );
  167.     psz_chain += len;
  168.     /* Parse the parameters */
  169.     psz_chain += strspn( psz_chain, " t" );
  170.     if( *psz_chain == '{' )
  171.     {
  172.         /* Parse all name=value[,] elements */
  173.         do
  174.         {
  175.             psz_chain++; /* skip previous delimiter */
  176.             psz_chain += strspn( psz_chain, " t" );
  177.             /* Look for the end of the name (,={}_space_) */
  178.             len = strcspn( psz_chain, "=,{} t" );
  179.             if( len == 0 )
  180.                 continue; /* ignore empty parameter */
  181.             /* Append the new parameter */
  182.             config_chain_t *p_cfg = malloc( sizeof(*p_cfg) );
  183.             if( !p_cfg )
  184.                 break;
  185.             p_cfg->psz_name = strndup( psz_chain, len );
  186.             psz_chain += len;
  187.             p_cfg->psz_value = NULL;
  188.             p_cfg->p_next = NULL;
  189.             *pp_next = p_cfg;
  190.             pp_next = &p_cfg->p_next;
  191.             /* Extract the option value */
  192.             psz_chain += strspn( psz_chain, " t" );
  193.             if( strchr( "={", *psz_chain ) )
  194.             {
  195.                 p_cfg->psz_value = ChainGetValue( &psz_chain );
  196.                 psz_chain += strspn( psz_chain, " t" );
  197.             }
  198.         }
  199.         while( !memchr( "}", *psz_chain, 2 ) );
  200.         if( *psz_chain ) psz_chain++; /* skip '}' */;
  201.         psz_chain += strspn( psz_chain, " t" );
  202.     }
  203.     if( *psz_chain == ':' )
  204.         return strdup( psz_chain + 1 );
  205.     return NULL;
  206. }
  207. void config_ChainDestroy( config_chain_t *p_cfg )
  208. {
  209.     while( p_cfg != NULL )
  210.     {
  211.         config_chain_t *p_next;
  212.         p_next = p_cfg->p_next;
  213.         FREENULL( p_cfg->psz_name );
  214.         FREENULL( p_cfg->psz_value );
  215.         free( p_cfg );
  216.         p_cfg = p_next;
  217.     }
  218. }
  219. void __config_ChainParse( vlc_object_t *p_this, const char *psz_prefix,
  220.                           const char *const *ppsz_options, config_chain_t *cfg )
  221. {
  222.     if( psz_prefix == NULL ) psz_prefix = "";
  223.     size_t plen = 1 + strlen( psz_prefix );
  224.     /* First, var_Create all variables */
  225.     for( size_t i = 0; ppsz_options[i] != NULL; i++ )
  226.     {
  227.         const char *optname = ppsz_options[i];
  228.         if (optname[0] == '*')
  229.             optname++;
  230.         char name[plen + strlen( optname )];
  231.         snprintf( name, sizeof (name), "%s%s", psz_prefix, optname );
  232.         if( var_Create( p_this, name,
  233.                         config_GetType( p_this, name ) | VLC_VAR_DOINHERIT ) )
  234.             return /* VLC_xxx */;
  235.     }
  236.     /* Now parse options and set value */
  237.     for(; cfg; cfg = cfg->p_next )
  238.     {
  239.         vlc_value_t val;
  240.         bool b_yes = true;
  241.         bool b_once = false;
  242.         module_config_t *p_conf;
  243.         int i_type;
  244.         size_t i;
  245.         if( cfg->psz_name == NULL || *cfg->psz_name == '' )
  246.             continue;
  247.         for( i = 0; ppsz_options[i] != NULL; i++ )
  248.         {
  249.             if( !strcmp( ppsz_options[i], cfg->psz_name ) )
  250.             {
  251.                 break;
  252.             }
  253.             if( ( !strncmp( cfg->psz_name, "no-", 3 ) &&
  254.                   !strcmp( ppsz_options[i], cfg->psz_name + 3 ) ) ||
  255.                 ( !strncmp( cfg->psz_name, "no", 2 ) &&
  256.                   !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) )
  257.             {
  258.                 b_yes = false;
  259.                 break;
  260.             }
  261.             if( *ppsz_options[i] == '*' &&
  262.                 !strcmp( &ppsz_options[i][1], cfg->psz_name ) )
  263.             {
  264.                 b_once = true;
  265.                 break;
  266.             }
  267.         }
  268.         if( ppsz_options[i] == NULL )
  269.         {
  270.             msg_Warn( p_this, "option %s is unknown", cfg->psz_name );
  271.             continue;
  272.         }
  273.         /* create name */
  274.         char name[plen + strlen( ppsz_options[i] )];
  275.         const char *psz_name = name;
  276.         snprintf( name, sizeof (name), "%s%s", psz_prefix,
  277.                   b_once ? (ppsz_options[i] + 1) : ppsz_options[i] );
  278.         /* Check if the option is deprecated */
  279.         p_conf = config_FindConfig( p_this, name );
  280.         /* This is basically cut and paste from src/misc/configuration.c
  281.          * with slight changes */
  282.         if( p_conf )
  283.         {
  284.             if( p_conf->b_removed )
  285.             {
  286.                 msg_Err( p_this, "Option %s is not supported anymore.",
  287.                          name );
  288.                 /* TODO: this should return an error and end option parsing
  289.                  * ... but doing this would change the VLC API and all the
  290.                  * modules so i'll do it later */
  291.                 continue;
  292.             }
  293.             if( p_conf->psz_oldname
  294.              && !strcmp( p_conf->psz_oldname, name ) )
  295.             {
  296.                  psz_name = p_conf->psz_name;
  297.                  msg_Warn( p_this, "Option %s is obsolete. Use %s instead.",
  298.                            name, psz_name );
  299.             }
  300.         }
  301.         /* </Check if the option is deprecated> */
  302.         /* get the type of the variable */
  303.         i_type = config_GetType( p_this, psz_name );
  304.         if( !i_type )
  305.         {
  306.             msg_Warn( p_this, "unknown option %s (value=%s)",
  307.                       cfg->psz_name, cfg->psz_value );
  308.             continue;
  309.         }
  310.         i_type &= CONFIG_ITEM;
  311.         if( i_type != VLC_VAR_BOOL && cfg->psz_value == NULL )
  312.         {
  313.             msg_Warn( p_this, "missing value for option %s", cfg->psz_name );
  314.             continue;
  315.         }
  316.         if( i_type != VLC_VAR_STRING && b_once )
  317.         {
  318.             msg_Warn( p_this, "*option_name need to be a string option" );
  319.             continue;
  320.         }
  321.         switch( i_type )
  322.         {
  323.             case VLC_VAR_BOOL:
  324.                 val.b_bool = b_yes;
  325.                 break;
  326.             case VLC_VAR_INTEGER:
  327.                 val.i_int = strtol( cfg->psz_value ? cfg->psz_value : "0",
  328.                                     NULL, 0 );
  329.                 break;
  330.             case VLC_VAR_FLOAT:
  331.                 val.f_float = us_atof( cfg->psz_value ? cfg->psz_value : "0" );
  332.                 break;
  333.             case VLC_VAR_STRING:
  334.             case VLC_VAR_MODULE:
  335.                 val.psz_string = cfg->psz_value;
  336.                 break;
  337.             default:
  338.                 msg_Warn( p_this, "unhandled config var type (%d)", i_type );
  339.                 memset( &val, 0, sizeof( vlc_value_t ) );
  340.                 break;
  341.         }
  342.         if( b_once )
  343.         {
  344.             vlc_value_t val2;
  345.             var_Get( p_this, psz_name, &val2 );
  346.             if( *val2.psz_string )
  347.             {
  348.                 free( val2.psz_string );
  349.                 msg_Dbg( p_this, "ignoring option %s (not first occurrence)", psz_name );
  350.                 continue;
  351.             }
  352.             free( val2.psz_string );
  353.         }
  354.         var_Set( p_this, psz_name, val );
  355.         msg_Dbg( p_this, "set config option: %s to %s", psz_name,
  356.                  cfg->psz_value ? cfg->psz_value : "(null)" );
  357.     }
  358. }
  359. char *config_StringUnescape( char *psz_string )
  360. {
  361.     char *psz_src = psz_string;
  362.     char *psz_dst = psz_string;
  363.     if( !psz_src )
  364.         return NULL;
  365.     while( *psz_src )
  366.     {
  367.         if( IsEscape( psz_src ) )
  368.             psz_src++;
  369.         *psz_dst++ = *psz_src++;
  370.     }
  371.     *psz_dst = '';
  372.     return psz_string;
  373. }
  374. char *config_StringEscape( const char *psz_string )
  375. {
  376.     char *psz_return;
  377.     char *psz_dst;
  378.     int i_escape;
  379.     if( !psz_string )
  380.         return NULL;
  381.     i_escape = 0;
  382.     for( const char *p = psz_string; *p; p++ )
  383.     {
  384.         if( IsEscapeNeeded( *p ) )
  385.             i_escape++;
  386.     }
  387.     psz_return = psz_dst = malloc( strlen( psz_string ) + i_escape + 1 );
  388.     for( const char *p = psz_string; *p; p++ )
  389.     {
  390.         if( IsEscapeNeeded( *p ) )
  391.             *psz_dst++ = '\';
  392.         *psz_dst++ = *p;
  393.     }
  394.     *psz_dst = '';
  395.     return psz_return;
  396. }