2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 2002 Roman Zippel < zippel @ linux - m68k . org >
* Released under the terms of the GNU GPL v2 .0 .
*/
# include <sys/stat.h>
# include <ctype.h>
2010-08-17 09:40:20 +04:00
# include <errno.h>
2006-06-09 09:12:42 +04:00
# include <fcntl.h>
2011-06-02 00:00:46 +04:00
# include <stdarg.h>
2005-04-17 02:20:36 +04:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include <unistd.h>
# include "lkc.h"
2015-02-24 18:37:13 +03:00
struct conf_printer {
void ( * print_symbol ) ( FILE * , struct symbol * , const char * , void * ) ;
void ( * print_comment ) ( FILE * , const char * , void * ) ;
} ;
2005-11-09 08:34:54 +03:00
static void conf_warning ( const char * fmt , . . . )
__attribute__ ( ( format ( printf , 1 , 2 ) ) ) ;
2010-08-17 12:21:19 +04:00
static void conf_message ( const char * fmt , . . . )
__attribute__ ( ( format ( printf , 1 , 2 ) ) ) ;
2005-11-09 08:34:54 +03:00
static const char * conf_filename ;
2018-01-11 16:39:41 +03:00
static int conf_lineno , conf_warnings ;
2005-11-09 08:34:54 +03:00
2005-04-17 02:20:36 +04:00
const char conf_defname [ ] = " arch/$ARCH/defconfig " ;
2005-11-09 08:34:54 +03:00
static void conf_warning ( const char * fmt , . . . )
{
va_list ap ;
va_start ( ap , fmt ) ;
fprintf ( stderr , " %s:%d:warning: " , conf_filename , conf_lineno ) ;
vfprintf ( stderr , fmt , ap ) ;
fprintf ( stderr , " \n " ) ;
va_end ( ap ) ;
conf_warnings + + ;
}
2010-08-17 12:21:19 +04:00
static void conf_default_message_callback ( const char * fmt , va_list ap )
{
printf ( " # \n # " ) ;
vprintf ( fmt , ap ) ;
printf ( " \n # \n " ) ;
}
static void ( * conf_message_callback ) ( const char * fmt , va_list ap ) =
conf_default_message_callback ;
void conf_set_message_callback ( void ( * fn ) ( const char * fmt , va_list ap ) )
{
conf_message_callback = fn ;
}
static void conf_message ( const char * fmt , . . . )
{
va_list ap ;
va_start ( ap , fmt ) ;
if ( conf_message_callback )
conf_message_callback ( fmt , ap ) ;
2015-01-12 16:18:26 +03:00
va_end ( ap ) ;
2010-08-17 12:21:19 +04:00
}
2006-06-09 09:12:51 +04:00
const char * conf_get_configname ( void )
{
char * name = getenv ( " KCONFIG_CONFIG " ) ;
return name ? name : " .config " ;
}
2009-05-18 03:36:54 +04:00
const char * conf_get_autoconfig_name ( void )
{
char * name = getenv ( " KCONFIG_AUTOCONFIG " ) ;
return name ? name : " include/config/auto.conf " ;
}
2005-06-26 01:59:22 +04:00
static char * conf_expand_value ( const char * in )
2005-04-17 02:20:36 +04:00
{
struct symbol * sym ;
2005-06-26 01:59:22 +04:00
const char * src ;
2005-04-17 02:20:36 +04:00
static char res_value [ SYMBOL_MAXLENGTH ] ;
char * dst , name [ SYMBOL_MAXLENGTH ] ;
res_value [ 0 ] = 0 ;
dst = name ;
while ( ( src = strchr ( in , ' $ ' ) ) ) {
strncat ( res_value , in , src - in ) ;
src + + ;
dst = name ;
while ( isalnum ( * src ) | | * src = = ' _ ' )
* dst + + = * src + + ;
* dst = 0 ;
sym = sym_lookup ( name , 0 ) ;
sym_calc_value ( sym ) ;
strcat ( res_value , sym_get_string_value ( sym ) ) ;
in = src ;
}
strcat ( res_value , in ) ;
return res_value ;
}
char * conf_get_default_confname ( void )
{
struct stat buf ;
static char fullname [ PATH_MAX + 1 ] ;
char * env , * name ;
name = conf_expand_value ( conf_defname ) ;
env = getenv ( SRCTREE ) ;
if ( env ) {
sprintf ( fullname , " %s/%s " , env , name ) ;
if ( ! stat ( fullname , & buf ) )
return fullname ;
}
return name ;
}
2007-11-10 22:01:56 +03:00
static int conf_set_sym_val ( struct symbol * sym , int def , int def_flags , char * p )
{
char * p2 ;
switch ( sym - > type ) {
case S_TRISTATE :
if ( p [ 0 ] = = ' m ' ) {
sym - > def [ def ] . tri = mod ;
sym - > flags | = def_flags ;
break ;
}
2011-05-31 20:30:26 +04:00
/* fall through */
2007-11-10 22:01:56 +03:00
case S_BOOLEAN :
if ( p [ 0 ] = = ' y ' ) {
sym - > def [ def ] . tri = yes ;
sym - > flags | = def_flags ;
break ;
}
if ( p [ 0 ] = = ' n ' ) {
sym - > def [ def ] . tri = no ;
sym - > flags | = def_flags ;
break ;
}
2013-08-06 20:45:07 +04:00
if ( def ! = S_DEF_AUTO )
conf_warning ( " symbol value '%s' invalid for %s " ,
p , sym - > name ) ;
2011-05-31 20:31:57 +04:00
return 1 ;
2007-11-10 22:01:56 +03:00
case S_OTHER :
if ( * p ! = ' " ' ) {
for ( p2 = p ; * p2 & & ! isspace ( * p2 ) ; p2 + + )
;
sym - > type = S_STRING ;
goto done ;
}
2011-05-31 20:30:26 +04:00
/* fall through */
2007-11-10 22:01:56 +03:00
case S_STRING :
if ( * p + + ! = ' " ' )
break ;
for ( p2 = p ; ( p2 = strpbrk ( p2 , " \" \\ " ) ) ; p2 + + ) {
if ( * p2 = = ' " ' ) {
* p2 = 0 ;
break ;
}
memmove ( p2 , p2 + 1 , strlen ( p2 ) ) ;
}
if ( ! p2 ) {
2013-08-06 20:45:07 +04:00
if ( def ! = S_DEF_AUTO )
conf_warning ( " invalid string found " ) ;
2007-11-10 22:01:56 +03:00
return 1 ;
}
2011-05-31 20:30:26 +04:00
/* fall through */
2007-11-10 22:01:56 +03:00
case S_INT :
case S_HEX :
done :
if ( sym_string_valid ( sym , p ) ) {
sym - > def [ def ] . val = strdup ( p ) ;
sym - > flags | = def_flags ;
} else {
2013-08-06 20:45:07 +04:00
if ( def ! = S_DEF_AUTO )
conf_warning ( " symbol value '%s' invalid for %s " ,
p , sym - > name ) ;
2007-11-10 22:01:56 +03:00
return 1 ;
}
break ;
default :
;
}
return 0 ;
}
2012-07-13 22:27:12 +04:00
# define LINE_GROWTH 16
static int add_byte ( int c , char * * lineptr , size_t slen , size_t * n )
{
char * nline ;
size_t new_size = slen + 1 ;
if ( new_size > * n ) {
new_size + = LINE_GROWTH - 1 ;
new_size * = 2 ;
nline = realloc ( * lineptr , new_size ) ;
if ( ! nline )
return - 1 ;
* lineptr = nline ;
* n = new_size ;
}
( * lineptr ) [ slen ] = c ;
return 0 ;
}
static ssize_t compat_getline ( char * * lineptr , size_t * n , FILE * stream )
{
char * line = * lineptr ;
size_t slen = 0 ;
for ( ; ; ) {
int c = getc ( stream ) ;
switch ( c ) {
case ' \n ' :
if ( add_byte ( c , & line , slen , n ) < 0 )
goto e_out ;
slen + + ;
/* fall through */
case EOF :
if ( add_byte ( ' \0 ' , & line , slen , n ) < 0 )
goto e_out ;
* lineptr = line ;
if ( slen = = 0 )
return - 1 ;
return slen ;
default :
if ( add_byte ( c , & line , slen , n ) < 0 )
goto e_out ;
slen + + ;
}
}
e_out :
line [ slen - 1 ] = ' \0 ' ;
* lineptr = line ;
return - 1 ;
}
2006-06-09 09:12:42 +04:00
int conf_read_simple ( const char * name , int def )
2005-04-17 02:20:36 +04:00
{
FILE * in = NULL ;
2012-07-13 22:27:12 +04:00
char * line = NULL ;
size_t line_asize = 0 ;
2005-04-17 02:20:36 +04:00
char * p , * p2 ;
struct symbol * sym ;
2006-06-09 09:12:42 +04:00
int i , def_flags ;
2005-04-17 02:20:36 +04:00
if ( name ) {
in = zconf_fopen ( name ) ;
} else {
2006-06-09 09:12:45 +04:00
struct property * prop ;
2006-06-09 09:12:51 +04:00
name = conf_get_configname ( ) ;
2006-06-09 09:12:38 +04:00
in = zconf_fopen ( name ) ;
if ( in )
goto load ;
2006-12-13 11:34:07 +03:00
sym_add_change_count ( 1 ) ;
2016-01-14 21:13:49 +03:00
if ( ! sym_defconfig_list )
2006-06-09 09:12:45 +04:00
return 1 ;
for_all_defaults ( sym_defconfig_list , prop ) {
if ( expr_calc_value ( prop - > visible . expr ) = = no | |
prop - > expr - > type ! = E_SYMBOL )
continue ;
name = conf_expand_value ( prop - > expr - > left . sym - > name ) ;
2005-04-17 02:20:36 +04:00
in = zconf_fopen ( name ) ;
if ( in ) {
2010-08-17 12:21:19 +04:00
conf_message ( _ ( " using defaults found in %s " ) ,
name ) ;
2006-06-09 09:12:38 +04:00
goto load ;
2005-04-17 02:20:36 +04:00
}
}
}
if ( ! in )
return 1 ;
2006-06-09 09:12:38 +04:00
load :
2005-11-09 08:34:54 +03:00
conf_filename = name ;
conf_lineno = 0 ;
conf_warnings = 0 ;
2006-06-09 09:12:42 +04:00
def_flags = SYMBOL_DEF < < def ;
2005-04-17 02:20:36 +04:00
for_all_symbols ( i , sym ) {
2006-06-09 09:12:42 +04:00
sym - > flags | = SYMBOL_CHANGED ;
sym - > flags & = ~ ( def_flags | SYMBOL_VALID ) ;
2013-06-26 01:37:44 +04:00
if ( sym_is_choice ( sym ) )
sym - > flags | = def_flags ;
2005-04-17 02:20:36 +04:00
switch ( sym - > type ) {
case S_INT :
case S_HEX :
case S_STRING :
2006-06-09 09:12:42 +04:00
if ( sym - > def [ def ] . val )
free ( sym - > def [ def ] . val ) ;
2011-05-31 20:30:26 +04:00
/* fall through */
2005-04-17 02:20:36 +04:00
default :
2006-06-09 09:12:42 +04:00
sym - > def [ def ] . val = NULL ;
sym - > def [ def ] . tri = no ;
2005-04-17 02:20:36 +04:00
}
}
2012-07-13 22:27:12 +04:00
while ( compat_getline ( & line , & line_asize , in ) ! = - 1 ) {
2005-11-09 08:34:54 +03:00
conf_lineno + + ;
2005-04-17 02:20:36 +04:00
sym = NULL ;
2010-08-24 08:14:47 +04:00
if ( line [ 0 ] = = ' # ' ) {
2010-08-15 07:57:43 +04:00
if ( memcmp ( line + 2 , CONFIG_ , strlen ( CONFIG_ ) ) )
2005-04-17 02:20:36 +04:00
continue ;
2010-08-15 07:57:43 +04:00
p = strchr ( line + 2 + strlen ( CONFIG_ ) , ' ' ) ;
2005-04-17 02:20:36 +04:00
if ( ! p )
continue ;
* p + + = 0 ;
if ( strncmp ( p , " is not set " , 10 ) )
continue ;
2006-06-09 09:12:42 +04:00
if ( def = = S_DEF_USER ) {
2010-08-15 07:57:43 +04:00
sym = sym_find ( line + 2 + strlen ( CONFIG_ ) ) ;
2008-09-29 07:27:11 +04:00
if ( ! sym ) {
sym_add_change_count ( 1 ) ;
2010-09-30 23:23:17 +04:00
goto setsym ;
2008-09-29 07:27:11 +04:00
}
2006-06-09 09:12:42 +04:00
} else {
2010-08-15 07:57:43 +04:00
sym = sym_lookup ( line + 2 + strlen ( CONFIG_ ) , 0 ) ;
2006-06-09 09:12:42 +04:00
if ( sym - > type = = S_UNKNOWN )
sym - > type = S_BOOLEAN ;
}
if ( sym - > flags & def_flags ) {
2008-01-04 01:33:44 +03:00
conf_warning ( " override: reassigning to symbol %s " , sym - > name ) ;
2005-04-17 02:20:36 +04:00
}
switch ( sym - > type ) {
case S_BOOLEAN :
case S_TRISTATE :
2006-06-09 09:12:42 +04:00
sym - > def [ def ] . tri = no ;
sym - > flags | = def_flags ;
2005-04-17 02:20:36 +04:00
break ;
default :
;
}
2010-08-15 07:57:43 +04:00
} else if ( memcmp ( line , CONFIG_ , strlen ( CONFIG_ ) ) = = 0 ) {
p = strchr ( line + strlen ( CONFIG_ ) , ' = ' ) ;
2005-04-17 02:20:36 +04:00
if ( ! p )
continue ;
* p + + = 0 ;
p2 = strchr ( p , ' \n ' ) ;
2006-07-13 22:54:07 +04:00
if ( p2 ) {
* p2 - - = 0 ;
if ( * p2 = = ' \r ' )
* p2 = 0 ;
}
2006-06-09 09:12:42 +04:00
if ( def = = S_DEF_USER ) {
2010-08-15 07:57:43 +04:00
sym = sym_find ( line + strlen ( CONFIG_ ) ) ;
2008-09-29 07:27:11 +04:00
if ( ! sym ) {
sym_add_change_count ( 1 ) ;
2010-09-30 23:23:17 +04:00
goto setsym ;
2008-09-29 07:27:11 +04:00
}
2006-06-09 09:12:42 +04:00
} else {
2010-08-15 07:57:43 +04:00
sym = sym_lookup ( line + strlen ( CONFIG_ ) , 0 ) ;
2006-06-09 09:12:42 +04:00
if ( sym - > type = = S_UNKNOWN )
sym - > type = S_OTHER ;
}
if ( sym - > flags & def_flags ) {
2008-01-04 01:33:44 +03:00
conf_warning ( " override: reassigning to symbol %s " , sym - > name ) ;
2005-04-17 02:20:36 +04:00
}
2007-11-10 22:01:56 +03:00
if ( conf_set_sym_val ( sym , def , def_flags , p ) )
continue ;
2010-08-24 08:14:47 +04:00
} else {
if ( line [ 0 ] ! = ' \r ' & & line [ 0 ] ! = ' \n ' )
2016-03-16 23:27:27 +03:00
conf_warning ( " unexpected data: %.*s " ,
( int ) strcspn ( line , " \r \n " ) , line ) ;
2005-04-17 02:20:36 +04:00
continue ;
}
2010-09-30 23:23:17 +04:00
setsym :
2005-04-17 02:20:36 +04:00
if ( sym & & sym_is_choice_value ( sym ) ) {
struct symbol * cs = prop_get_symbol ( sym_get_choice_prop ( sym ) ) ;
2006-06-09 09:12:42 +04:00
switch ( sym - > def [ def ] . tri ) {
2005-04-17 02:20:36 +04:00
case no :
break ;
case mod :
2006-06-09 09:12:42 +04:00
if ( cs - > def [ def ] . tri = = yes ) {
2005-11-09 08:34:54 +03:00
conf_warning ( " %s creates inconsistent choice state " , sym - > name ) ;
2013-06-26 01:37:44 +04:00
cs - > flags & = ~ def_flags ;
2005-11-09 08:34:54 +03:00
}
2005-04-17 02:20:36 +04:00
break ;
case yes :
2008-01-04 01:33:44 +03:00
if ( cs - > def [ def ] . tri ! = no )
conf_warning ( " override: %s changes choice state " , sym - > name ) ;
cs - > def [ def ] . val = sym ;
2005-04-17 02:20:36 +04:00
break ;
}
2008-01-07 23:09:55 +03:00
cs - > def [ def ] . tri = EXPR_OR ( cs - > def [ def ] . tri , sym - > def [ def ] . tri ) ;
2005-04-17 02:20:36 +04:00
}
}
2012-07-13 22:27:12 +04:00
free ( line ) ;
2005-04-17 02:20:36 +04:00
fclose ( in ) ;
2005-11-09 08:34:49 +03:00
return 0 ;
}
int conf_read ( const char * name )
{
2012-01-24 02:29:05 +04:00
struct symbol * sym ;
2018-01-11 16:39:41 +03:00
int conf_unsaved = 0 ;
2012-01-24 02:29:05 +04:00
int i ;
2005-11-09 08:34:49 +03:00
2006-12-13 11:34:07 +03:00
sym_set_change_count ( 0 ) ;
2006-06-09 09:12:38 +04:00
2016-01-14 21:13:49 +03:00
if ( conf_read_simple ( name , S_DEF_USER ) ) {
sym_calc_value ( modules_sym ) ;
2005-11-09 08:34:49 +03:00
return 1 ;
2016-01-14 21:13:49 +03:00
}
sym_calc_value ( modules_sym ) ;
2005-11-09 08:34:49 +03:00
2005-04-17 02:20:36 +04:00
for_all_symbols ( i , sym ) {
sym_calc_value ( sym ) ;
2005-11-09 08:34:54 +03:00
if ( sym_is_choice ( sym ) | | ( sym - > flags & SYMBOL_AUTO ) )
2012-01-24 02:29:05 +04:00
continue ;
2005-11-09 08:34:54 +03:00
if ( sym_has_value ( sym ) & & ( sym - > flags & SYMBOL_WRITE ) ) {
/* check that calculated value agrees with saved value */
switch ( sym - > type ) {
case S_BOOLEAN :
case S_TRISTATE :
2006-06-09 09:12:41 +04:00
if ( sym - > def [ S_DEF_USER ] . tri ! = sym_get_tristate_value ( sym ) )
2005-11-09 08:34:54 +03:00
break ;
if ( ! sym_is_choice ( sym ) )
2012-01-24 02:29:05 +04:00
continue ;
2011-05-31 20:30:26 +04:00
/* fall through */
2005-11-09 08:34:54 +03:00
default :
2006-06-09 09:12:41 +04:00
if ( ! strcmp ( sym - > curr . val , sym - > def [ S_DEF_USER ] . val ) )
2012-01-24 02:29:05 +04:00
continue ;
2005-11-09 08:34:54 +03:00
break ;
}
} else if ( ! sym_has_value ( sym ) & & ! ( sym - > flags & SYMBOL_WRITE ) )
/* no previous value and not saved */
2012-01-24 02:29:05 +04:00
continue ;
2005-11-09 08:34:54 +03:00
conf_unsaved + + ;
/* maybe print value in verbose mode... */
2007-07-09 22:43:58 +04:00
}
for_all_symbols ( i , sym ) {
2005-04-17 02:20:36 +04:00
if ( sym_has_value ( sym ) & & ! sym_is_choice_value ( sym ) ) {
2007-07-09 22:43:58 +04:00
/* Reset values of generates values, so they'll appear
* as new , if they should become visible , but that
* doesn ' t quite work if the Kconfig and the saved
* configuration disagree .
*/
if ( sym - > visible = = no & & ! conf_unsaved )
2006-06-09 09:12:42 +04:00
sym - > flags & = ~ SYMBOL_DEF_USER ;
2005-04-17 02:20:36 +04:00
switch ( sym - > type ) {
case S_STRING :
case S_INT :
case S_HEX :
2007-07-09 22:43:58 +04:00
/* Reset a string value if it's out of range */
if ( sym_string_within_range ( sym , sym - > def [ S_DEF_USER ] . val ) )
break ;
sym - > flags & = ~ ( SYMBOL_VALID | SYMBOL_DEF_USER ) ;
conf_unsaved + + ;
break ;
2005-04-17 02:20:36 +04:00
default :
break ;
}
}
}
2006-12-13 11:34:07 +03:00
sym_add_change_count ( conf_warnings | | conf_unsaved ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-05-16 07:42:09 +04:00
/*
* Kconfig configuration printer
*
* This printer is used when generating the resulting configuration after
* kconfig invocation and ` defconfig ' files . Unset symbol might be omitted by
* passing a non - NULL argument to the printer .
*
*/
static void
kconfig_print_symbol ( FILE * fp , struct symbol * sym , const char * value , void * arg )
{
switch ( sym - > type ) {
case S_BOOLEAN :
case S_TRISTATE :
if ( * value = = ' n ' ) {
bool skip_unset = ( arg ! = NULL ) ;
if ( ! skip_unset )
fprintf ( fp , " # %s%s is not set \n " ,
CONFIG_ , sym - > name ) ;
return ;
}
break ;
default :
break ;
}
fprintf ( fp , " %s%s=%s \n " , CONFIG_ , sym - > name , value ) ;
}
static void
kconfig_print_comment ( FILE * fp , const char * value , void * arg )
2010-08-01 01:35:33 +04:00
{
2011-05-16 07:42:09 +04:00
const char * p = value ;
size_t l ;
for ( ; ; ) {
l = strcspn ( p , " \n " ) ;
fprintf ( fp , " # " ) ;
2010-08-01 01:35:33 +04:00
if ( l ) {
2011-05-16 07:42:09 +04:00
fprintf ( fp , " " ) ;
2011-10-22 18:48:49 +04:00
xfwrite ( p , l , 1 , fp ) ;
2011-05-16 07:42:09 +04:00
p + = l ;
2010-08-01 01:35:33 +04:00
}
2011-05-16 07:42:09 +04:00
fprintf ( fp , " \n " ) ;
if ( * p + + = = ' \0 ' )
2010-08-01 01:35:33 +04:00
break ;
}
}
2011-05-16 07:42:09 +04:00
static struct conf_printer kconfig_printer_cb =
2010-08-01 01:35:33 +04:00
{
2011-05-16 07:42:09 +04:00
. print_symbol = kconfig_print_symbol ,
. print_comment = kconfig_print_comment ,
} ;
/*
* Header printer
*
* This printer is used when generating the ` include / generated / autoconf . h ' file .
*/
static void
header_print_symbol ( FILE * fp , struct symbol * sym , const char * value , void * arg )
{
2010-08-01 01:35:33 +04:00
2010-12-05 09:33:16 +03:00
switch ( sym - > type ) {
2010-08-01 01:35:33 +04:00
case S_BOOLEAN :
2011-07-14 23:31:07 +04:00
case S_TRISTATE : {
const char * suffix = " " ;
2011-05-16 07:42:09 +04:00
switch ( * value ) {
case ' n ' :
2011-07-20 19:38:57 +04:00
break ;
2011-05-16 07:42:09 +04:00
case ' m ' :
suffix = " _MODULE " ;
2011-07-14 23:31:07 +04:00
/* fall through */
2011-05-16 07:42:09 +04:00
default :
2011-07-20 19:38:57 +04:00
fprintf ( fp , " #define %s%s%s 1 \n " ,
CONFIG_ , sym - > name , suffix ) ;
2010-08-01 01:35:33 +04:00
}
2011-07-14 23:31:07 +04:00
break ;
}
case S_HEX : {
const char * prefix = " " ;
if ( value [ 0 ] ! = ' 0 ' | | ( value [ 1 ] ! = ' x ' & & value [ 1 ] ! = ' X ' ) )
prefix = " 0x " ;
fprintf ( fp , " #define %s%s %s%s \n " ,
CONFIG_ , sym - > name , prefix , value ) ;
break ;
}
case S_STRING :
case S_INT :
fprintf ( fp , " #define %s%s %s \n " ,
CONFIG_ , sym - > name , value ) ;
2010-08-01 01:35:33 +04:00
break ;
2011-05-16 07:42:09 +04:00
default :
2010-08-01 01:35:33 +04:00
break ;
2011-05-16 07:42:09 +04:00
}
}
static void
header_print_comment ( FILE * fp , const char * value , void * arg )
{
const char * p = value ;
size_t l ;
fprintf ( fp , " /* \n " ) ;
for ( ; ; ) {
l = strcspn ( p , " \n " ) ;
fprintf ( fp , " * " ) ;
if ( l ) {
fprintf ( fp , " " ) ;
2011-10-22 18:48:49 +04:00
xfwrite ( p , l , 1 , fp ) ;
2011-05-16 07:42:09 +04:00
p + = l ;
}
fprintf ( fp , " \n " ) ;
if ( * p + + = = ' \0 ' )
break ;
}
fprintf ( fp , " */ \n " ) ;
}
static struct conf_printer header_printer_cb =
{
. print_symbol = header_print_symbol ,
. print_comment = header_print_comment ,
} ;
/*
* Tristate printer
*
* This printer is used when generating the ` include / config / tristate . conf ' file .
*/
static void
tristate_print_symbol ( FILE * fp , struct symbol * sym , const char * value , void * arg )
{
if ( sym - > type = = S_TRISTATE & & * value ! = ' n ' )
fprintf ( fp , " %s%s=%c \n " , CONFIG_ , sym - > name , ( char ) toupper ( * value ) ) ;
}
static struct conf_printer tristate_printer_cb =
{
. print_symbol = tristate_print_symbol ,
. print_comment = kconfig_print_comment ,
} ;
static void conf_write_symbol ( FILE * fp , struct symbol * sym ,
struct conf_printer * printer , void * printer_arg )
{
const char * str ;
switch ( sym - > type ) {
2010-08-01 01:35:33 +04:00
case S_OTHER :
case S_UNKNOWN :
break ;
2011-05-16 07:42:09 +04:00
case S_STRING :
str = sym_get_string_value ( sym ) ;
str = sym_escape_string_value ( str ) ;
printer - > print_symbol ( fp , sym , str , printer_arg ) ;
free ( ( void * ) str ) ;
break ;
default :
str = sym_get_string_value ( sym ) ;
printer - > print_symbol ( fp , sym , str , printer_arg ) ;
2010-08-01 01:35:33 +04:00
}
}
2011-05-16 07:42:09 +04:00
static void
conf_write_heading ( FILE * fp , struct conf_printer * printer , void * printer_arg )
{
char buf [ 256 ] ;
snprintf ( buf , sizeof ( buf ) ,
" \n "
" Automatically generated file; DO NOT EDIT. \n "
" %s \n " ,
rootmenu . prompt - > text ) ;
printer - > print_comment ( fp , buf , printer_arg ) ;
}
2010-08-01 01:35:34 +04:00
/*
* Write out a minimal config .
* All values that has default values are skipped as this is redundant .
*/
int conf_write_defconfig ( const char * filename )
{
struct symbol * sym ;
struct menu * menu ;
FILE * out ;
out = fopen ( filename , " w " ) ;
if ( ! out )
return 1 ;
sym_clear_all_valid ( ) ;
/* Traverse all menus to find all relevant symbols */
menu = rootmenu . list ;
while ( menu ! = NULL )
{
sym = menu - > sym ;
if ( sym = = NULL ) {
if ( ! menu_is_visible ( menu ) )
goto next_menu ;
} else if ( ! sym_is_choice ( sym ) ) {
sym_calc_value ( sym ) ;
if ( ! ( sym - > flags & SYMBOL_WRITE ) )
goto next_menu ;
sym - > flags & = ~ SYMBOL_WRITE ;
/* If we cannot change the symbol - skip */
if ( ! sym_is_changable ( sym ) )
goto next_menu ;
/* If symbol equals to default value - skip */
if ( strcmp ( sym_get_string_value ( sym ) , sym_get_string_default ( sym ) ) = = 0 )
goto next_menu ;
/*
* If symbol is a choice value and equals to the
* default for a choice - skip .
2010-08-15 01:22:16 +04:00
* But only if value is bool and equal to " y " and
* choice is not " optional " .
* ( If choice is " optional " then all values can be " n " )
2010-08-01 01:35:34 +04:00
*/
if ( sym_is_choice_value ( sym ) ) {
struct symbol * cs ;
struct symbol * ds ;
cs = prop_get_symbol ( sym_get_choice_prop ( sym ) ) ;
ds = sym_choice_default ( cs ) ;
2010-08-15 01:22:16 +04:00
if ( ! sym_is_optional ( cs ) & & sym = = ds ) {
2010-08-12 11:11:51 +04:00
if ( ( sym - > type = = S_BOOLEAN ) & &
sym_get_tristate_value ( sym ) = = yes )
2010-08-01 01:35:34 +04:00
goto next_menu ;
}
}
2011-05-16 07:42:09 +04:00
conf_write_symbol ( out , sym , & kconfig_printer_cb , NULL ) ;
2010-08-01 01:35:34 +04:00
}
next_menu :
if ( menu - > list ! = NULL ) {
menu = menu - > list ;
}
else if ( menu - > next ! = NULL ) {
menu = menu - > next ;
} else {
while ( ( menu = menu - > parent ) ) {
if ( menu - > next ! = NULL ) {
menu = menu - > next ;
break ;
}
}
}
}
fclose ( out ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
int conf_write ( const char * name )
{
2006-06-09 09:12:39 +04:00
FILE * out ;
2005-04-17 02:20:36 +04:00
struct symbol * sym ;
struct menu * menu ;
const char * basename ;
const char * str ;
2010-09-22 18:59:13 +04:00
char dirname [ PATH_MAX + 1 ] , tmpname [ PATH_MAX + 1 ] , newname [ PATH_MAX + 1 ] ;
2005-04-17 02:20:36 +04:00
char * env ;
dirname [ 0 ] = 0 ;
if ( name & & name [ 0 ] ) {
struct stat st ;
char * slash ;
if ( ! stat ( name , & st ) & & S_ISDIR ( st . st_mode ) ) {
strcpy ( dirname , name ) ;
strcat ( dirname , " / " ) ;
2006-06-09 09:12:51 +04:00
basename = conf_get_configname ( ) ;
2005-04-17 02:20:36 +04:00
} else if ( ( slash = strrchr ( name , ' / ' ) ) ) {
int size = slash - name + 1 ;
memcpy ( dirname , name , size ) ;
dirname [ size ] = 0 ;
if ( slash [ 1 ] )
basename = slash + 1 ;
else
2006-06-09 09:12:51 +04:00
basename = conf_get_configname ( ) ;
2005-04-17 02:20:36 +04:00
} else
basename = name ;
} else
2006-06-09 09:12:51 +04:00
basename = conf_get_configname ( ) ;
2005-04-17 02:20:36 +04:00
2006-06-09 09:12:51 +04:00
sprintf ( newname , " %s%s " , dirname , basename ) ;
env = getenv ( " KCONFIG_OVERWRITECONFIG " ) ;
if ( ! env | | ! * env ) {
sprintf ( tmpname , " %s.tmpconfig.%d " , dirname , ( int ) getpid ( ) ) ;
out = fopen ( tmpname , " w " ) ;
} else {
* tmpname = 0 ;
out = fopen ( newname , " w " ) ;
}
2005-04-17 02:20:36 +04:00
if ( ! out )
return 1 ;
2006-06-09 09:12:51 +04:00
2011-05-16 07:42:09 +04:00
conf_write_heading ( out , & kconfig_printer_cb , NULL ) ;
2005-04-17 02:20:36 +04:00
2006-12-13 11:34:06 +03:00
if ( ! conf_get_changed ( ) )
2005-04-17 02:20:36 +04:00
sym_clear_all_valid ( ) ;
menu = rootmenu . list ;
while ( menu ) {
sym = menu - > sym ;
if ( ! sym ) {
if ( ! menu_is_visible ( menu ) )
goto next ;
str = menu_get_prompt ( menu ) ;
fprintf ( out , " \n "
" # \n "
" # %s \n "
" # \n " , str ) ;
} else if ( ! ( sym - > flags & SYMBOL_CHOICE ) ) {
sym_calc_value ( sym ) ;
if ( ! ( sym - > flags & SYMBOL_WRITE ) )
goto next ;
sym - > flags & = ~ SYMBOL_WRITE ;
2011-05-16 07:42:09 +04:00
conf_write_symbol ( out , sym , & kconfig_printer_cb , NULL ) ;
2005-04-17 02:20:36 +04:00
}
2010-08-01 01:35:33 +04:00
next :
2005-04-17 02:20:36 +04:00
if ( menu - > list ) {
menu = menu - > list ;
continue ;
}
if ( menu - > next )
menu = menu - > next ;
else while ( ( menu = menu - > parent ) ) {
if ( menu - > next ) {
menu = menu - > next ;
break ;
}
}
}
fclose ( out ) ;
2006-06-09 09:12:51 +04:00
if ( * tmpname ) {
2006-10-01 13:48:53 +04:00
strcat ( dirname , basename ) ;
2006-06-09 09:12:51 +04:00
strcat ( dirname , " .old " ) ;
rename ( newname , dirname ) ;
if ( rename ( tmpname , newname ) )
return 1 ;
2005-04-17 02:20:36 +04:00
}
2010-08-17 12:21:19 +04:00
conf_message ( _ ( " configuration written to %s " ) , newname ) ;
2006-06-09 09:12:38 +04:00
2006-12-13 11:34:07 +03:00
sym_set_change_count ( 0 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-06-09 09:12:39 +04:00
2009-09-18 23:49:23 +04:00
static int conf_split_config ( void )
2006-06-09 09:12:42 +04:00
{
2009-05-18 03:36:54 +04:00
const char * name ;
2010-09-22 18:59:13 +04:00
char path [ PATH_MAX + 1 ] ;
2006-06-09 09:12:42 +04:00
char * s , * d , c ;
struct symbol * sym ;
struct stat sb ;
int res , i , fd ;
2009-05-18 03:36:54 +04:00
name = conf_get_autoconfig_name ( ) ;
2006-06-09 09:12:42 +04:00
conf_read_simple ( name , S_DEF_AUTO ) ;
2016-01-14 21:13:49 +03:00
sym_calc_value ( modules_sym ) ;
2006-06-09 09:12:42 +04:00
if ( chdir ( " include/config " ) )
return 1 ;
res = 0 ;
for_all_symbols ( i , sym ) {
sym_calc_value ( sym ) ;
if ( ( sym - > flags & SYMBOL_AUTO ) | | ! sym - > name )
continue ;
if ( sym - > flags & SYMBOL_WRITE ) {
if ( sym - > flags & SYMBOL_DEF_AUTO ) {
/*
* symbol has old and new value ,
* so compare them . . .
*/
switch ( sym - > type ) {
case S_BOOLEAN :
case S_TRISTATE :
if ( sym_get_tristate_value ( sym ) = =
sym - > def [ S_DEF_AUTO ] . tri )
continue ;
break ;
case S_STRING :
case S_HEX :
case S_INT :
if ( ! strcmp ( sym_get_string_value ( sym ) ,
sym - > def [ S_DEF_AUTO ] . val ) )
continue ;
break ;
default :
break ;
}
} else {
/*
* If there is no old value , only ' no ' ( unset )
* is allowed as new value .
*/
switch ( sym - > type ) {
case S_BOOLEAN :
case S_TRISTATE :
if ( sym_get_tristate_value ( sym ) = = no )
continue ;
break ;
default :
break ;
}
}
} else if ( ! ( sym - > flags & SYMBOL_DEF_AUTO ) )
/* There is neither an old nor a new value. */
continue ;
/* else
* There is an old value , but no new value ( ' no ' ( unset )
* isn ' t saved in auto . conf , so the old value is always
* different from ' no ' ) .
*/
/* Replace all '_' and append ".h" */
s = sym - > name ;
d = path ;
while ( ( c = * s + + ) ) {
c = tolower ( c ) ;
* d + + = ( c = = ' _ ' ) ? ' / ' : c ;
}
strcpy ( d , " .h " ) ;
/* Assume directory path already exists. */
fd = open ( path , O_WRONLY | O_CREAT | O_TRUNC , 0644 ) ;
if ( fd = = - 1 ) {
if ( errno ! = ENOENT ) {
res = 1 ;
break ;
}
/*
* Create directory components ,
* unless they exist already .
*/
d = path ;
while ( ( d = strchr ( d , ' / ' ) ) ) {
* d = 0 ;
if ( stat ( path , & sb ) & & mkdir ( path , 0755 ) ) {
res = 1 ;
goto out ;
}
* d + + = ' / ' ;
}
/* Try it again. */
fd = open ( path , O_WRONLY | O_CREAT | O_TRUNC , 0644 ) ;
if ( fd = = - 1 ) {
res = 1 ;
break ;
}
}
close ( fd ) ;
}
out :
if ( chdir ( " ../.. " ) )
return 1 ;
return res ;
}
2006-06-09 09:12:39 +04:00
int conf_write_autoconf ( void )
{
struct symbol * sym ;
2009-05-18 03:36:54 +04:00
const char * name ;
2009-12-07 18:38:33 +03:00
FILE * out , * tristate , * out_h ;
2010-08-01 01:35:33 +04:00
int i ;
2006-06-09 09:12:39 +04:00
2006-06-09 09:12:42 +04:00
sym_clear_all_valid ( ) ;
2006-06-09 09:12:39 +04:00
file_write_dep ( " include/config/auto.conf.cmd " ) ;
2006-06-09 09:12:42 +04:00
if ( conf_split_config ( ) )
return 1 ;
2006-06-09 09:12:39 +04:00
out = fopen ( " .tmpconfig " , " w " ) ;
if ( ! out )
return 1 ;
2009-12-07 18:38:33 +03:00
tristate = fopen ( " .tmpconfig_tristate " , " w " ) ;
if ( ! tristate ) {
fclose ( out ) ;
return 1 ;
}
2006-06-09 09:12:39 +04:00
out_h = fopen ( " .tmpconfig.h " , " w " ) ;
if ( ! out_h ) {
fclose ( out ) ;
2009-12-07 18:38:33 +03:00
fclose ( tristate ) ;
2006-06-09 09:12:39 +04:00
return 1 ;
}
2011-05-16 07:42:09 +04:00
conf_write_heading ( out , & kconfig_printer_cb , NULL ) ;
conf_write_heading ( tristate , & tristate_printer_cb , NULL ) ;
conf_write_heading ( out_h , & header_printer_cb , NULL ) ;
2006-06-09 09:12:39 +04:00
for_all_symbols ( i , sym ) {
sym_calc_value ( sym ) ;
2012-04-13 03:46:33 +04:00
if ( ! ( sym - > flags & SYMBOL_WRITE ) | | ! sym - > name )
2006-06-09 09:12:39 +04:00
continue ;
2010-08-01 01:35:33 +04:00
2012-04-13 03:46:33 +04:00
/* write symbol to auto.conf, tristate and header files */
2011-05-16 07:42:09 +04:00
conf_write_symbol ( out , sym , & kconfig_printer_cb , ( void * ) 1 ) ;
2010-08-01 01:35:33 +04:00
2011-05-16 07:42:09 +04:00
conf_write_symbol ( tristate , sym , & tristate_printer_cb , ( void * ) 1 ) ;
conf_write_symbol ( out_h , sym , & header_printer_cb , NULL ) ;
2006-06-09 09:12:39 +04:00
}
fclose ( out ) ;
2009-12-07 18:38:33 +03:00
fclose ( tristate ) ;
2006-06-09 09:12:39 +04:00
fclose ( out_h ) ;
name = getenv ( " KCONFIG_AUTOHEADER " ) ;
if ( ! name )
2009-10-18 02:49:24 +04:00
name = " include/generated/autoconf.h " ;
2006-06-09 09:12:39 +04:00
if ( rename ( " .tmpconfig.h " , name ) )
return 1 ;
2009-12-07 18:38:33 +03:00
name = getenv ( " KCONFIG_TRISTATE " ) ;
if ( ! name )
name = " include/config/tristate.conf " ;
if ( rename ( " .tmpconfig_tristate " , name ) )
return 1 ;
2009-05-18 03:36:54 +04:00
name = conf_get_autoconfig_name ( ) ;
2006-06-09 09:12:39 +04:00
/*
* This must be the last step , kbuild has a dependency on auto . conf
* and this marks the successful completion of the previous steps .
*/
if ( rename ( " .tmpconfig " , name ) )
return 1 ;
return 0 ;
}
2006-12-13 11:34:06 +03:00
2006-12-13 11:34:07 +03:00
static int sym_change_count ;
2006-12-13 11:34:08 +03:00
static void ( * conf_changed_callback ) ( void ) ;
2006-12-13 11:34:07 +03:00
void sym_set_change_count ( int count )
{
2006-12-13 11:34:08 +03:00
int _sym_change_count = sym_change_count ;
2006-12-13 11:34:07 +03:00
sym_change_count = count ;
2006-12-13 11:34:08 +03:00
if ( conf_changed_callback & &
( bool ) _sym_change_count ! = ( bool ) count )
conf_changed_callback ( ) ;
2006-12-13 11:34:07 +03:00
}
void sym_add_change_count ( int count )
{
2006-12-13 11:34:08 +03:00
sym_set_change_count ( count + sym_change_count ) ;
2006-12-13 11:34:07 +03:00
}
2006-12-13 11:34:06 +03:00
bool conf_get_changed ( void )
{
return sym_change_count ;
}
2006-12-13 11:34:08 +03:00
void conf_set_changed_callback ( void ( * fn ) ( void ) )
{
conf_changed_callback = fn ;
}
2008-05-06 06:55:55 +04:00
2013-04-29 00:36:38 +04:00
static bool randomize_choice_values ( struct symbol * csym )
2010-08-12 11:11:52 +04:00
{
struct property * prop ;
struct symbol * sym ;
struct expr * e ;
int cnt , def ;
2008-05-06 06:55:55 +04:00
2010-08-12 11:11:52 +04:00
/*
2010-12-05 09:41:16 +03:00
* If choice is mod then we may have more items selected
2010-08-12 11:11:52 +04:00
* and if no then no - one .
* In both cases stop .
*/
if ( csym - > curr . tri ! = yes )
2013-04-29 00:36:38 +04:00
return false ;
2010-08-12 11:11:52 +04:00
prop = sym_get_choice_prop ( csym ) ;
/* count entries in choice block */
cnt = 0 ;
expr_list_for_each_sym ( prop - > expr , e , sym )
cnt + + ;
/*
* find a random value and set it to yes ,
* set the rest to no so we have only one set
*/
def = ( rand ( ) % cnt ) ;
cnt = 0 ;
expr_list_for_each_sym ( prop - > expr , e , sym ) {
if ( def = = cnt + + ) {
sym - > def [ S_DEF_USER ] . tri = yes ;
csym - > def [ S_DEF_USER ] . val = sym ;
}
else {
sym - > def [ S_DEF_USER ] . tri = no ;
}
2013-04-28 19:33:15 +04:00
sym - > flags | = SYMBOL_DEF_USER ;
/* clear VALID to get value calculated */
sym - > flags & = ~ SYMBOL_VALID ;
2010-08-12 11:11:52 +04:00
}
csym - > flags | = SYMBOL_DEF_USER ;
/* clear VALID to get value calculated */
csym - > flags & = ~ ( SYMBOL_VALID ) ;
2013-04-29 00:36:38 +04:00
return true ;
2010-08-12 11:11:52 +04:00
}
2013-06-07 07:37:00 +04:00
void set_all_choice_values ( struct symbol * csym )
2008-05-06 06:55:55 +04:00
{
struct property * prop ;
2010-08-12 11:11:52 +04:00
struct symbol * sym ;
2008-05-06 06:55:55 +04:00
struct expr * e ;
2010-08-12 11:11:52 +04:00
prop = sym_get_choice_prop ( csym ) ;
/*
* Set all non - assinged choice values to no
*/
expr_list_for_each_sym ( prop - > expr , e , sym ) {
if ( ! sym_has_value ( sym ) )
sym - > def [ S_DEF_USER ] . tri = no ;
}
csym - > flags | = SYMBOL_DEF_USER ;
/* clear VALID to get value calculated */
2013-06-07 07:37:00 +04:00
csym - > flags & = ~ ( SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES ) ;
2010-08-12 11:11:52 +04:00
}
2013-04-29 00:36:38 +04:00
bool conf_set_all_new_symbols ( enum conf_def_mode mode )
2010-08-12 11:11:52 +04:00
{
struct symbol * sym , * csym ;
2017-12-15 18:38:02 +03:00
int i , cnt , pby , pty , ptm ; /* pby: probability of bool = y
2013-04-13 19:18:36 +04:00
* pty : probability of tristate = y
* ptm : probability of tristate = m
*/
pby = 50 ; pty = ptm = 33 ; /* can't go as the default in switch-case
* below , otherwise gcc whines about
* - Wmaybe - uninitialized */
if ( mode = = def_random ) {
int n , p [ 3 ] ;
char * env = getenv ( " KCONFIG_PROBABILITY " ) ;
n = 0 ;
while ( env & & * env ) {
char * endp ;
int tmp = strtol ( env , & endp , 10 ) ;
if ( tmp > = 0 & & tmp < = 100 ) {
p [ n + + ] = tmp ;
} else {
errno = ERANGE ;
perror ( " KCONFIG_PROBABILITY " ) ;
exit ( 1 ) ;
}
env = ( * endp = = ' : ' ) ? endp + 1 : endp ;
if ( n > = 3 ) {
break ;
}
}
switch ( n ) {
case 1 :
pby = p [ 0 ] ; ptm = pby / 2 ; pty = pby - ptm ;
break ;
case 2 :
pty = p [ 0 ] ; ptm = p [ 1 ] ; pby = pty + ptm ;
break ;
case 3 :
pby = p [ 0 ] ; pty = p [ 1 ] ; ptm = p [ 2 ] ;
break ;
}
if ( pty + ptm > 100 ) {
errno = ERANGE ;
perror ( " KCONFIG_PROBABILITY " ) ;
exit ( 1 ) ;
}
}
2013-04-29 00:36:38 +04:00
bool has_changed = false ;
2008-05-06 06:55:55 +04:00
for_all_symbols ( i , sym ) {
2013-04-25 00:00:04 +04:00
if ( sym_has_value ( sym ) | | ( sym - > flags & SYMBOL_VALID ) )
2008-05-06 06:55:55 +04:00
continue ;
switch ( sym_get_type ( sym ) ) {
case S_BOOLEAN :
case S_TRISTATE :
2013-04-29 00:36:38 +04:00
has_changed = true ;
2008-05-06 06:55:55 +04:00
switch ( mode ) {
case def_yes :
sym - > def [ S_DEF_USER ] . tri = yes ;
break ;
case def_mod :
sym - > def [ S_DEF_USER ] . tri = mod ;
break ;
case def_no :
2014-04-08 02:39:09 +04:00
if ( sym - > flags & SYMBOL_ALLNOCONFIG_Y )
sym - > def [ S_DEF_USER ] . tri = yes ;
else
sym - > def [ S_DEF_USER ] . tri = no ;
2008-05-06 06:55:55 +04:00
break ;
case def_random :
2013-04-13 19:18:36 +04:00
sym - > def [ S_DEF_USER ] . tri = no ;
cnt = rand ( ) % 100 ;
if ( sym - > type = = S_TRISTATE ) {
if ( cnt < pty )
sym - > def [ S_DEF_USER ] . tri = yes ;
else if ( cnt < ( pty + ptm ) )
sym - > def [ S_DEF_USER ] . tri = mod ;
} else if ( cnt < pby )
sym - > def [ S_DEF_USER ] . tri = yes ;
2008-05-06 06:55:55 +04:00
break ;
default :
continue ;
}
2009-03-15 13:05:12 +03:00
if ( ! ( sym_is_choice ( sym ) & & mode = = def_random ) )
2008-05-06 06:55:55 +04:00
sym - > flags | = SYMBOL_DEF_USER ;
break ;
default :
break ;
}
}
2008-10-26 08:12:34 +03:00
sym_clear_all_valid ( ) ;
2008-05-06 06:55:55 +04:00
2009-03-15 13:05:12 +03:00
/*
* We have different type of choice blocks .
2010-12-05 09:41:16 +03:00
* If curr . tri equals to mod then we can select several
2009-03-15 13:05:12 +03:00
* choice symbols in one block .
* In this case we do nothing .
2010-12-05 09:41:16 +03:00
* If curr . tri equals yes then only one symbol can be
2009-03-15 13:05:12 +03:00
* selected in a choice block and we set it to yes ,
* and the rest to no .
*/
2013-06-07 07:37:00 +04:00
if ( mode ! = def_random ) {
for_all_symbols ( i , csym ) {
if ( ( sym_is_choice ( csym ) & & ! sym_has_value ( csym ) ) | |
sym_is_choice_value ( csym ) )
csym - > flags | = SYMBOL_NEED_SET_CHOICE_VALUES ;
}
}
2008-05-06 06:55:55 +04:00
for_all_symbols ( i , csym ) {
if ( sym_has_value ( csym ) | | ! sym_is_choice ( csym ) )
continue ;
sym_calc_value ( csym ) ;
2010-08-12 11:11:52 +04:00
if ( mode = = def_random )
2013-04-29 00:36:38 +04:00
has_changed = randomize_choice_values ( csym ) ;
else {
set_all_choice_values ( csym ) ;
has_changed = true ;
}
2008-05-06 06:55:55 +04:00
}
2013-04-29 00:36:38 +04:00
return has_changed ;
2008-05-06 06:55:55 +04:00
}