1 //========================================================================
5 // Implementation of ISO C internationalisation (i18n) locales
7 //========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //========================================================================
41 //#####DESCRIPTIONBEGIN####
43 // Author(s): jlarmour
44 // Contributors: jjohnstn
50 //####DESCRIPTIONEND####
52 //========================================================================
56 #include <pkgconf/libc_i18n.h> // Configuration header
60 #include <cyg/infra/cyg_type.h> // Common type definitions and support
61 #include <cyg/infra/cyg_trac.h> // Common tracing support
62 #include <cyg/infra/cyg_ass.h> // Common assertion support
63 #include <locale.h> // struct lconv
64 #include <string.h> // several string functions
65 #include <limits.h> // CHAR_MAX
66 #include "internal.h" // locale type definitions
70 // define the "C" locale
71 static const Cyg_libc_locale_t
74 { ".", "", "", "", "", "", "", "", "", "",
75 CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
83 // define the "C-EUCJP" locale (C locale with Japanese EUCJP mb support)
84 #ifdef CYGFUN_LIBC_I18N_LOCALE_C_EUCJP
85 static const Cyg_libc_locale_t
88 { ".", "", "", "", "", "", "", "", "", "",
89 CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
98 // define the "C-SJIS" locale (C locale with Japanese SJIS mb support)
99 #ifdef CYGFUN_LIBC_I18N_LOCALE_C_SJIS
100 static const Cyg_libc_locale_t
103 { ".", "", "", "", "", "", "", "", "", "",
104 CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
113 // define the "C-JIS" locale (C locale with Japanese JIS mb support)
114 #ifdef CYGFUN_LIBC_I18N_LOCALE_C_JIS
115 static const Cyg_libc_locale_t
118 { ".", "", "", "", "", "", "", "", "", "",
119 CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
128 // only one locale now, but leave room for expansion
129 static const Cyg_libc_locale_t *all_locales[] = { &C_locale,
130 #ifdef CYGFUN_LIBC_I18N_LOCALE_C_EUCJP
133 #ifdef CYGFUN_LIBC_I18N_LOCALE_C_SJIS
136 #ifdef CYGFUN_LIBC_I18N_LOCALE_C_JIS
143 // the maximum size of a multibyte character including state info
144 #ifdef CYGINT_LIBC_I18N_MB_REQUIRED
145 int __mb_cur_max = 1;
148 // the current locales. Our default is the C locale
149 static const Cyg_libc_locale_t *current_collate_locale = &C_locale;
150 const Cyg_libc_locale_t *__current_ctype_locale = &C_locale;
151 static const Cyg_libc_locale_t *current_monetary_locale = &C_locale;
152 static const Cyg_libc_locale_t *current_numeric_locale = &C_locale;
153 static const Cyg_libc_locale_t *current_time_locale = &C_locale;
157 static const Cyg_libc_locale_t *
158 find_locale_data( const char *locale_str, cyg_ucount32 checklen )
160 CYG_REPORT_FUNCNAMETYPE( "find_locale_data", "returning %08x" );
161 CYG_REPORT_FUNCARG1( "locale_str=%s", locale_str );
163 const Cyg_libc_locale_t *temp_locale, *curr_locale=NULL;
166 // is it "" i.e. use the default?
167 if (*locale_str=='\0') {
168 curr_locale = &C_locale;
169 CYG_REPORT_RETVAL( curr_locale );
173 for (i=0; i<sizeof(all_locales)/sizeof(Cyg_libc_locale_t *); i++ ) {
175 temp_locale = all_locales[i];
177 if ( !strncmp(temp_locale->name, locale_str, checklen) )
178 curr_locale = temp_locale;
181 CYG_REPORT_RETVAL( curr_locale );
183 } // find_locale_data()
185 typedef int (*mbtowc_fn_type)(wchar_t *, const char *, size_t, int *);
186 // routine used to export mbtowc function to I/O routines
187 externC mbtowc_fn_type
188 __get_current_locale_mbtowc_fn ()
190 if (__current_ctype_locale->mbtowc_fn)
191 return __current_ctype_locale->mbtowc_fn;
196 setlocale( int category, const char *locale )
198 CYG_REPORT_FUNCNAMETYPE("setlocale", "returning %08x");
199 CYG_REPORT_FUNCARG2( "category=%d, locale=%s", category, locale );
202 CYG_CHECK_DATA_PTR( locale, "locale pointer is invalid!" );
206 // special case if locale==NULL, return current locale name
209 CYG_TRACE0( true, "Getting current locale value" );
214 str = current_collate_locale->name;
217 str = __current_ctype_locale->name;
220 str = current_monetary_locale->name;
223 str = current_numeric_locale->name;
226 str = current_time_locale->name;
230 // create static string to give a constructed string back
231 // to the user. The size is the number of categories other
232 // than LC_ALL times the maximum name size, and add a constant
233 // for the delimiting octothorpes
234 static char my_str[ CYGNUM_LIBC_I18N_MAX_LOCALE_NAME_SIZE*5+10 ];
236 strcpy( my_str, "#" );
237 strcat( my_str, current_collate_locale->name );
238 strcat( my_str, "#" );
239 strcat( my_str, __current_ctype_locale->name );
240 strcat( my_str, "#" );
241 strcat( my_str, current_monetary_locale->name );
242 strcat( my_str, "#" );
243 strcat( my_str, current_numeric_locale->name );
244 strcat( my_str, "#" );
245 strcat( my_str, current_time_locale->name );
246 strcat( my_str, "#" );
252 CYG_FAIL("setlocale() passed bad category!" );
257 CYG_REPORT_RETVAL( (char *)str);
261 // we only get here if locale is non-NULL, i.e. we want to set it
263 const Cyg_libc_locale_t *loc;
264 cyg_bool default_locale = (*locale=='\0');
266 CYG_TRACE0( true, "Setting current locale value" );
270 loc = find_locale_data( locale, CYGNUM_LIBC_I18N_MAX_LOCALE_NAME_SIZE );
271 if (loc != NULL) // found it
272 current_collate_locale=loc;
276 loc = find_locale_data( locale, CYGNUM_LIBC_I18N_MAX_LOCALE_NAME_SIZE );
277 if (loc != NULL) // found it
279 __current_ctype_locale=loc;
280 #ifdef CYGINT_LIBC_I18N_MB_REQUIRED
281 __mb_cur_max = loc->mb_cur_max;
287 loc = find_locale_data( locale, CYGNUM_LIBC_I18N_MAX_LOCALE_NAME_SIZE );
288 if (loc != NULL) // found it
289 current_monetary_locale=loc;
293 loc = find_locale_data( locale, CYGNUM_LIBC_I18N_MAX_LOCALE_NAME_SIZE );
294 if (loc != NULL) // found it
295 current_numeric_locale=loc;
299 loc = find_locale_data( locale, CYGNUM_LIBC_I18N_MAX_LOCALE_NAME_SIZE );
300 if (loc != NULL) // found it
301 current_time_locale=loc;
305 // first try and match it exactly
306 loc = find_locale_data( locale, CYGNUM_LIBC_I18N_MAX_LOCALE_NAME_SIZE );
307 if (loc != NULL) { // found it
309 CYG_TRACE0(true, "Matched locale string exactly");
310 current_collate_locale = __current_ctype_locale = loc;
311 current_monetary_locale = current_numeric_locale = loc;
312 current_time_locale = loc;
313 #ifdef CYGINT_LIBC_I18N_MB_REQUIRED
314 __mb_cur_max = loc->mb_cur_max;
318 CYG_TRACE0( true, "Attempting to parse string previously "
319 "returned from setlocale()" );
320 // now try and see if it is a compound string returned
321 // earlier by setlocale( LC_ALL, NULL );
323 // Note we don't do much checking here. This could be
324 // much more rigorous (but at the expense of speed/size?)
326 const Cyg_libc_locale_t *temp_collate_locale,
327 *temp_ctype_locale, *temp_monetary_locale,
328 *temp_numeric_locale, *temp_time_locale;
330 cyg_ucount32 token_len;
335 token_len = strcspn( str, "#" );
336 loc = find_locale_data( str, token_len );
339 temp_collate_locale=loc;
341 token_len = strcspn( str, "#" );
342 loc = find_locale_data( str, token_len );
345 temp_ctype_locale=loc;
347 token_len = strcspn( str, "#" );
348 loc = find_locale_data( str, token_len );
351 temp_monetary_locale=loc;
353 token_len = strcspn( str, "#" );
354 loc = find_locale_data( str, token_len );
357 temp_numeric_locale=loc;
359 token_len = strcspn( str, "#" );
360 loc = find_locale_data( str, token_len );
363 temp_time_locale=loc;
365 token_len = strcspn( str, "#" );
366 loc = find_locale_data( str, token_len );
369 // if we've got this far and loc still isn't NULL,
370 // then everything's fine, and we've matched everything
372 current_collate_locale = temp_collate_locale;
373 __current_ctype_locale = temp_ctype_locale;
374 #ifdef CYGINT_LIBC_I18N_MB_REQUIRED
375 __mb_cur_max = temp_ctype_locale->mb_cur_max;
377 current_monetary_locale = temp_monetary_locale;
378 current_numeric_locale = temp_numeric_locale;
379 current_time_locale = temp_time_locale;
390 break; // case LC_ALL
393 CYG_FAIL("setlocale() passed bad category!" );
399 CYG_REPORT_RETVAL( NULL );
402 else if (default_locale==true) {
403 CYG_REPORT_RETVAL(C_locale.name);
404 return (char *)C_locale.name;
407 CYG_REPORT_RETVAL(locale);
408 return (char *)locale;
412 externC struct lconv *
415 CYG_REPORT_FUNCNAMETYPE( "localeconv", "returning %08x" );
416 CYG_REPORT_FUNCARGVOID();
418 static struct lconv static_lconv;
420 static_lconv.decimal_point =
421 current_numeric_locale->numdata.decimal_point;
423 static_lconv.thousands_sep =
424 current_numeric_locale->numdata.thousands_sep;
426 static_lconv.grouping =
427 current_numeric_locale->numdata.grouping;
429 // we cheat a bit, but it should be worth it - a lot of these are
430 // constants which optimise nicely
431 cyg_ucount32 size_used;
432 size_used = (char *)&static_lconv.int_curr_symbol -
433 (char *)&static_lconv;
435 memcpy( &(static_lconv.int_curr_symbol),
436 &(current_monetary_locale->numdata.int_curr_symbol),
437 sizeof(struct lconv) - size_used );
440 CYG_REPORT_RETVAL( &static_lconv );
441 return &static_lconv;