Improve locale implementation (should now behave identically to bash) and document locale variables behaviour

darcs-hash:20060108230049-ac50b-403f1d00c8483fc4fecc275b62e40b1c3d51bfc1.gz
This commit is contained in:
axel 2006-01-09 09:00:49 +10:00
parent 690648e1b0
commit 906495d713
7 changed files with 138 additions and 36 deletions

View file

@ -104,8 +104,17 @@ static struct winsize termsize;
*/
static int block_count=0;
static string_buffer_t *setlocale_buff=0;
void common_destroy()
{
if( setlocale_buff )
{
sb_destroy( setlocale_buff );
free( setlocale_buff );
}
debug( 3, L"Calls: wcsdupcat %d, wcsdupcat2 %d, wcsndup %d, str2wcs %d, wcs2str %d", c1, c2, c3, c4, c5 );
}
@ -719,27 +728,33 @@ wchar_t *quote_end( const wchar_t *in )
}
void fish_setlocale(int category, const wchar_t *locale)
const wchar_t *wsetlocale(int category, const wchar_t *locale)
{
char *lang = wcs2str( locale );
setlocale(category,lang);
char *lang = locale?wcs2str( locale ):0;
char * res = setlocale(category,lang);
free( lang );
/*
Use ellipsis if on known unicode system, otherwise use $
*/
if( wcslen( locale ) )
char *ctype = setlocale( LC_CTYPE, (void *)0 );
ellipsis_char = (strstr( ctype, ".UTF")||strstr( ctype, ".utf") )?L'\u2026':L'$';
if( !res )
return 0;
if( !setlocale_buff )
{
ellipsis_char = wcsstr( locale, L".UTF")?L'\u2026':L'$';
}
else
{
char *lang = getenv( "LANG" );
if( lang )
ellipsis_char = strstr( lang, ".UTF")?L'\u2026':L'$';
else
ellipsis_char = L'$';
setlocale_buff = malloc( sizeof(string_buffer_t) );
sb_init( setlocale_buff);
}
sb_clear( setlocale_buff );
sb_printf( setlocale_buff, L"%s", res );
return (wchar_t *)setlocale_buff->buff;
}
int contains_str( const wchar_t *a, ... )

View file

@ -256,9 +256,12 @@ wchar_t *quote_end( const wchar_t *in );
void error_reset();
/**
Set the locale, also change the ellipsis character
This function behaves exactly like a wide character equivalent of
the C function setlocale, except that it will also try to detect if
the user is using a Unicode character set, and if so, use the
unicode ellipsis character as ellipsis, instead of '$'.
*/
void fish_setlocale( int category, const wchar_t *locale );
const wchar_t *wsetlocale( int category, const wchar_t *locale );
/**
Checks if \c needle is included in the list of strings specified

View file

@ -655,6 +655,7 @@ values of these variables. They are:
- \c PWD, which is the current working directory.
- \c status, which is the exit status of the last foreground job to exit. If a job contains pipelines, the status of the last command in the pipeline is the status for the job.
- \c USER, which is the username. This variable can only be changed by the root user.
- \c LANG, \cLC_ALL, \c LC_COLLATE, \c LC_CTYPE, \cLC_MESSAGES, \c LC_MONETARY, \c LC_NUMERIC and LC_TIME set the language option for the shell and subprograms. See the section <a href='#variables-locale'>Locale variables</a> for more information.
Variables whose name are in uppercase are exported to the commands
started by fish. This rule is not enforced by fish, but it is good
@ -663,6 +664,22 @@ unexported variables. \c fish also uses several variables
internally. Such variables are prefixed with the string __FISH or
__fish. These should be ignored by the user.
\subsection variables-locale Locale variables
The most common way to set the locale to use a command like 'set -x
LANG en_GB.utf8', which sets the current locale to be the english
language, adapted to great britain, using the UTF-8 character set. For
a list of available locales, use 'locale -a'.
\c LANG, \cLC_ALL, \c LC_COLLATE, \c LC_CTYPE, \cLC_MESSAGES, \c
LC_MONETARY, \c LC_NUMERIC and LC_TIME set the language option for the
shell and subprograms. These variables work as follows: \c LC_ALL
forces all the aspects of the locale to the specified value. If LC_ALL
is set, all other locale variables will be ignored. The other LC_
variables set the specified aspect of the locale information. . LANG
is a fallback value, it will be used if none of the LC_ variables are
specified.
\section builtin-overview Builtins
Many other shells have a large library of builtin commands. Most of

102
env.c
View file

@ -214,6 +214,73 @@ static mode_t get_umask()
return res;
}
/**
Checks if the specified variable is a locale variable
*/
static int is_locale( const wchar_t *key )
{
return contains_str( key, L"LANG", L"LC_ALL", L"LC_COLLATE", L"LC_CTYPE", L"LC_MESSAGES", L"LC_MONETARY", L"LC_NUMERIC", L"LC_TIME", (void *)0);
}
/**
Properly sets all locale information
*/
static void handle_locale()
{
const wchar_t *lc_all = env_get( L"LC_ALL" );
const wchar_t *lang;
int i;
wchar_t *old = wcsdup(wsetlocale( LC_MESSAGES, (void *)0 ));
static const wchar_t *lc[] =
{
L"LC_COLLATE", L"LC_CTYPE", L"LC_MESSAGES", L"LC_MONETARY", L"LC_NUMERIC", L"LC_TIME", (void *)0
}
;
static const int cat[] =
{
LC_COLLATE, LC_CTYPE, LC_MESSAGES, LC_MONETARY, LC_NUMERIC, LC_TIME
}
;
if( lc_all )
{
wsetlocale( LC_ALL, lc_all );
}
else
{
lang = env_get( L"LANG" );
if( lang )
{
wsetlocale( LC_ALL, lang );
}
for( i=0; lc[i]; i++ )
{
const wchar_t *val = env_get( lc[i] );
if( val )
wsetlocale( cat[i], val );
}
}
if( wcscmp( wsetlocale( LC_MESSAGES, (void *)0 ), old ) != 0 )
{
/* Make change known to gettext. */
{
extern int _nl_msg_cat_cntr;
++_nl_msg_cat_cntr;
}
if( is_interactive )
{
debug( 0, _(L"Changing language to english") );
}
}
free( old );
}
/**
Universal variable callback function. This function makes sure the
proper events are triggered when an event occurs.
@ -224,6 +291,9 @@ static void universal_callback( int type,
{
wchar_t *str=0;
if( is_locale( name ) )
handle_locale();
switch( type )
{
case SET:
@ -475,7 +545,7 @@ static env_node_t *env_get_node( const wchar_t *key )
return 0;
}
void env_set( const wchar_t *key,
const wchar_t *val,
int var_mode )
@ -490,26 +560,13 @@ void env_set( const wchar_t *key,
event_t ev;
int is_universal = 0;
if( (var_mode & ENV_USER ) &&
hash_get( &env_read_only, key ) )
{
return;
}
if( wcscmp(key, L"LANG" )==0 )
{
fish_setlocale(LC_ALL,val);
/* Make change known to gettext. */
{
extern int _nl_msg_cat_cntr;
++_nl_msg_cat_cntr;
}
if( is_interactive )
debug( 0, _(L"Changing language to english") );
}
if( wcscmp( key, L"umask" ) == 0)
{
wchar_t *end;
@ -533,7 +590,6 @@ void env_set( const wchar_t *key,
*/
return;
}
/*
Zero element arrays are internaly not coded as null but as this placeholder string
@ -685,9 +741,17 @@ void env_set( const wchar_t *key,
// debug( 1, L"env_set: return from event firing" );
al_destroy( &ev.arguments );
}
if( is_locale( key ) )
{
handle_locale();
}
}
/**
Attempt to remove/free the specified key/value pair from the
specified hash table.
@ -735,6 +799,10 @@ void env_remove( const wchar_t *key, int var_mode )
{
env_universal_remove( key );
}
if( is_locale( key ) )
handle_locale();
}

View file

@ -845,8 +845,7 @@ static void init()
{
struct sigaction act;
program_name = L"fish_pager";
fish_setlocale( LC_ALL, L"" );
wsetlocale( LC_ALL, L"" );
int out = dup( 1 );
close(1);

View file

@ -400,7 +400,7 @@ static void init()
sock = get_socket();
daemonize();
fish_setlocale( LC_ALL, L"" );
wsetlocale( LC_ALL, L"" );
env_universal_common_init( &broadcast );
load();

View file

@ -2114,7 +2114,7 @@ static void eval_job( tokenizer *tok )
tok_get_desc( tok_last_type(tok) ) );
}
return 0;
return;
}
case TOK_ERROR: