Mercurial > ecos
diff packages/language/c/libc/current/src/i18n/locale.cxx @ 0:3111d98ba7b3 ecos-v1_1-release
Initial commit of eCos version 1.1
| author | jlarmour |
|---|---|
| date | Tue, 11 May 1999 11:16:07 +0000 |
| parents | |
| children | 443894e2e912 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/language/c/libc/current/src/i18n/locale.cxx @@ -0,0 +1,370 @@ +//======================================================================== +// +// locale.cxx +// +// Implementation of ISO C internationalisation (i18n) locales +// +//======================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Cygnus eCos Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://sourceware.cygnus.com/ecos +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Cygnus Operating System, released +// September 30, 1998. +// +// The Initial Developer of the Original Code is Cygnus. Portions created +// by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//======================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): jlarmour@cygnus.com +// Contributors: jlarmour@cygnus.co.uk +// Date: 1998-08-31 +// Purpose: +// Description: +// Usage: +// +//####DESCRIPTIONEND#### +// +//======================================================================== + +// CONFIGURATION + +#include <pkgconf/libc.h> // Configuration header + +// Include the C library? +#ifdef CYGPKG_LIBC + +// INCLUDES + +#include <cyg/infra/cyg_type.h> // Common type definitions and support +#include <cyg/infra/cyg_trac.h> // Common tracing support +#include <cyg/infra/cyg_ass.h> // Common assertion support +#include <locale.h> // struct lconv +#include <string.h> // several string functions +#include <limits.h> // CHAR_MAX +#include "clibincl/i18nsupp.hxx" // Support for i18n functions + +// SYMBOLS + +externC char * +setlocale( int, const char * ) CYGPRI_LIBC_WEAK_ALIAS("_setlocale"); + +externC struct lconv * +localeconv( void ) CYGPRI_LIBC_WEAK_ALIAS("_localeconv"); + +// TYPE DEFINITIONS + +// define a type to encapsulate the locale. In time this will get much +// richer and complete + +typedef struct { + + const char *name; + struct lconv numdata; + +} Cyg_libc_locale_t; + + +// CONSTANTS + +// define the "C" locale +static const Cyg_libc_locale_t +C_locale = { "C", + { ".", "", "", "", "", "", "", "", "", "", + CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, + CHAR_MAX, CHAR_MAX + } + }; + +// only one locale now, but leave room for expansion +static const Cyg_libc_locale_t *all_locales[] = { &C_locale }; + +// GLOBALS + +// the current locales. Our default is the C locale +static const Cyg_libc_locale_t *current_collate_locale = &C_locale; +static const Cyg_libc_locale_t *current_ctype_locale = &C_locale; +static const Cyg_libc_locale_t *current_monetary_locale = &C_locale; +static const Cyg_libc_locale_t *current_numeric_locale = &C_locale; +static const Cyg_libc_locale_t *current_time_locale = &C_locale; + +// FUNCTIONS + +static const Cyg_libc_locale_t * +find_locale_data( const char *locale_str, cyg_ucount32 checklen ) +{ + CYG_REPORT_FUNCNAMETYPE( "find_locale_data", "returning %08x" ); + CYG_REPORT_FUNCARG1( "locale_str=%s", locale_str ); + + const Cyg_libc_locale_t *temp_locale, *curr_locale=NULL; + cyg_ucount32 i; + + // is it "" i.e. use the default? + if (*locale_str=='\0') { + curr_locale = &C_locale; + CYG_REPORT_RETVAL( curr_locale ); + return curr_locale; + } // if + + for (i=0; i<sizeof(all_locales)/sizeof(Cyg_libc_locale_t *); i++ ) { + + temp_locale = all_locales[i]; + + if ( !strncmp(temp_locale->name, locale_str, checklen) ) + curr_locale = temp_locale; + } // for + + CYG_REPORT_RETVAL( curr_locale ); + return curr_locale; +} // find_locale_data() + + +externC char * +_setlocale( int category, const char *locale ) +{ + CYG_REPORT_FUNCNAMETYPE("_setlocale", "returning %08x"); + CYG_REPORT_FUNCARG2( "category=%d, locale=%s", category, locale ); + + if (locale != NULL) + CYG_CHECK_DATA_PTR( locale, "locale pointer is invalid!" ); + + const char *str; + + // special case if locale==NULL, return current locale name + if (locale==NULL) { + + CYG_TRACE0( true, "Getting current locale value" ); + + switch (category) { + + case LC_COLLATE: + str = current_collate_locale->name; + break; + case LC_CTYPE: + str = current_ctype_locale->name; + break; + case LC_MONETARY: + str = current_monetary_locale->name; + break; + case LC_NUMERIC: + str = current_numeric_locale->name; + break; + case LC_TIME: + str = current_time_locale->name; + break; + case LC_ALL: + + // create static string to give a constructed string back + // to the user. The size is the number of categories other + // than LC_ALL times the maximum name size, and add a constant + // for the delimiting octothorpes + static char my_str[ CYGNUM_LIBC_MAX_LOCALE_NAME_SIZE*5+10 ]; + + strcpy( my_str, "#" ); + strcat( my_str, current_collate_locale->name ); + strcat( my_str, "#" ); + strcat( my_str, current_ctype_locale->name ); + strcat( my_str, "#" ); + strcat( my_str, current_monetary_locale->name ); + strcat( my_str, "#" ); + strcat( my_str, current_numeric_locale->name ); + strcat( my_str, "#" ); + strcat( my_str, current_time_locale->name ); + strcat( my_str, "#" ); + + str = &my_str[0]; + break; + default: + str=NULL; + CYG_FAIL("setlocale() passed bad category!" ); + break; + + } // switch + + CYG_REPORT_RETVAL( (char *)str); + return (char *)str; + } // if + + // we only get here if locale is non-NULL, i.e. we want to set it + + const Cyg_libc_locale_t *loc; + cyg_bool default_locale = (*locale=='\0'); + + CYG_TRACE0( true, "Setting current locale value" ); + + switch( category ) { + case LC_COLLATE: + loc = find_locale_data( locale, CYGNUM_LIBC_MAX_LOCALE_NAME_SIZE ); + if (loc != NULL) // found it + current_collate_locale=loc; + break; + + case LC_CTYPE: + loc = find_locale_data( locale, CYGNUM_LIBC_MAX_LOCALE_NAME_SIZE ); + if (loc != NULL) // found it + current_ctype_locale=loc; + break; + + case LC_MONETARY: + loc = find_locale_data( locale, CYGNUM_LIBC_MAX_LOCALE_NAME_SIZE ); + if (loc != NULL) // found it + current_monetary_locale=loc; + break; + + case LC_NUMERIC: + loc = find_locale_data( locale, CYGNUM_LIBC_MAX_LOCALE_NAME_SIZE ); + if (loc != NULL) // found it + current_numeric_locale=loc; + break; + + case LC_TIME: + loc = find_locale_data( locale, CYGNUM_LIBC_MAX_LOCALE_NAME_SIZE ); + if (loc != NULL) // found it + current_time_locale=loc; + break; + + case LC_ALL: + // first try and match it exactly + loc = find_locale_data( locale, CYGNUM_LIBC_MAX_LOCALE_NAME_SIZE ); + if (loc != NULL) { // found it + + CYG_TRACE0(true, "Matched locale string exactly"); + current_collate_locale = current_ctype_locale = loc; + current_monetary_locale = current_numeric_locale = loc; + current_time_locale = loc; + } // if + else { + CYG_TRACE0( true, "Attempting to parse string previously " + "returned from setlocale()" ); + // now try and see if it is a compound string returned + // earlier by setlocale( LC_ALL, NULL ); + + // Note we don't do much checking here. This could be + // much more rigorous (but at the expense of speed/size?) + + const Cyg_libc_locale_t *temp_collate_locale, + *temp_ctype_locale, *temp_monetary_locale, + *temp_numeric_locale, *temp_time_locale; + + cyg_ucount32 token_len; + + str = &locale[0]; + if ( *str=='#' ) { + ++str; + token_len = strcspn( str, "#" ); + loc = find_locale_data( str, token_len ); + if (loc!=NULL) { + temp_collate_locale=loc; + str += token_len+1; + token_len = strcspn( str, "#" ); + loc = find_locale_data( str, token_len ); + } // if + if (loc!=NULL) { + temp_ctype_locale=loc; + str += token_len+1; + token_len = strcspn( str, "#" ); + loc = find_locale_data( str, token_len ); + } // if + if (loc!=NULL) { + temp_monetary_locale=loc; + str += token_len+1; + token_len = strcspn( str, "#" ); + loc = find_locale_data( str, token_len ); + } // if + if (loc!=NULL) { + temp_numeric_locale=loc; + str += token_len+1; + token_len = strcspn( str, "#" ); + loc = find_locale_data( str, token_len ); + } // if + if (loc!=NULL) { + temp_time_locale=loc; + str += token_len+1; + token_len = strcspn( str, "#" ); + loc = find_locale_data( str, token_len ); + } // if + if (loc!=NULL) { + // if we've got this far and loc still isn't NULL, + // then everything's fine, and we've matched everything + + current_collate_locale = temp_collate_locale; + current_ctype_locale = temp_ctype_locale; + current_monetary_locale = temp_monetary_locale; + current_numeric_locale = temp_numeric_locale; + current_time_locale = temp_time_locale; + + } // if + } // if + + } // else + break; // case LC_ALL + + default: + CYG_FAIL("setlocale() passed bad category!" ); + loc=NULL; + break; + } // switch + + if (loc==NULL) { + CYG_REPORT_RETVAL( NULL ); + return NULL; + } // if + else if (default_locale==true) { + CYG_REPORT_RETVAL(C_locale.name); + return (char *)C_locale.name; + } // else if + else { + CYG_REPORT_RETVAL(locale); + return (char *)locale; + } // else +} + +externC struct lconv * +_localeconv( void ) +{ + CYG_REPORT_FUNCNAMETYPE( "_localeconv", "returning %08x" ); + CYG_REPORT_FUNCARGVOID(); + + static struct lconv static_lconv; + + static_lconv.decimal_point = + current_numeric_locale->numdata.decimal_point; + + static_lconv.thousands_sep = + current_numeric_locale->numdata.thousands_sep; + + static_lconv.grouping = + current_numeric_locale->numdata.grouping; + + // we cheat a bit, but it should be worth it - a lot of these are + // constants which optimise nicely + cyg_ucount32 size_used; + size_used = (char *)&static_lconv.int_curr_symbol - + (char *)&static_lconv; + + memcpy( &(static_lconv.int_curr_symbol), + &(current_monetary_locale->numdata.int_curr_symbol), + sizeof(struct lconv) - size_used ); + + + CYG_REPORT_RETVAL( &static_lconv ); + return &static_lconv; +} + + +#endif // ifdef CYGPKG_LIBC + +// EOF locale.cxx
