]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/language/c/libc/i18n/v2_0/src/locale.cxx
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / language / c / libc / i18n / v2_0 / src / locale.cxx
1 //========================================================================
2 //
3 //      locale.cxx
4 //
5 //      Implementation of ISO C internationalisation (i18n) locales
6 //
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.
12 //
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.
16 //
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
20 // for more details.
21 //
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.
25 //
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.
32 //
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.
35 //
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####
42 //
43 // Author(s):    jlarmour
44 // Contributors: jjohnstn
45 // Date:         2000-04-18
46 // Purpose:     
47 // Description: 
48 // Usage:       
49 //
50 //####DESCRIPTIONEND####
51 //
52 //========================================================================
53
54 // CONFIGURATION
55
56 #include <pkgconf/libc_i18n.h>     // Configuration header
57
58 // INCLUDES
59
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
67
68 // CONSTANTS
69
70 // define the "C" locale
71 static const Cyg_libc_locale_t
72 C_locale = { 
73   (char *)"C",
74   { (char *)".", (char *)"", (char *)"", (char *)"", (char *)"", (char *)"", (char *)"", (char *)"", (char *)"", (char *)"",
75     CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
76     CHAR_MAX, CHAR_MAX
77   },
78   1,
79   NULL,
80   NULL,
81 };
82
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
86 C_EUCJP_locale = { 
87   "C-EUCJP",
88   { ".", "", "", "", "", "", "", "", "", "",
89     CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
90     CHAR_MAX, CHAR_MAX
91   },
92   2,
93   &__mbtowc_jp,
94   &__wctomb_jp,
95 };
96 #endif
97
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
101 C_SJIS_locale = { 
102   "C-SJIS",
103   { ".", "", "", "", "", "", "", "", "", "",
104     CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
105     CHAR_MAX, CHAR_MAX
106   },
107   2,
108   &__mbtowc_jp,
109   &__wctomb_jp,
110 };
111 #endif
112
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
116 C_JIS_locale = { 
117   "C-JIS",
118   { ".", "", "", "", "", "", "", "", "", "",
119     CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
120     CHAR_MAX, CHAR_MAX
121   },
122   8,
123   &__mbtowc_jp,
124   &__wctomb_jp,
125 };
126 #endif
127
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
131                                                   &C_EUCJP_locale,
132 #endif
133 #ifdef CYGFUN_LIBC_I18N_LOCALE_C_SJIS
134                                                   &C_SJIS_locale,
135 #endif
136 #ifdef CYGFUN_LIBC_I18N_LOCALE_C_JIS
137                                                   &C_JIS_locale,
138 #endif
139 };
140
141 // GLOBALS
142
143 // the maximum size of a multibyte character including state info
144 #ifdef CYGINT_LIBC_I18N_MB_REQUIRED
145 int __mb_cur_max = 1;
146 #endif
147
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;
154
155 // FUNCTIONS
156
157 static const Cyg_libc_locale_t *
158 find_locale_data( const char *locale_str, cyg_ucount32 checklen )
159 {
160     CYG_REPORT_FUNCNAMETYPE( "find_locale_data", "returning %08x" );
161     CYG_REPORT_FUNCARG1( "locale_str=%s", locale_str );
162
163     const Cyg_libc_locale_t *temp_locale, *curr_locale=NULL;
164     cyg_ucount32 i;
165
166     // is it "" i.e. use the default?
167     if (*locale_str=='\0') {
168         curr_locale = &C_locale;
169         CYG_REPORT_RETVAL( curr_locale );
170         return curr_locale;
171     } // if
172
173     for (i=0; i<sizeof(all_locales)/sizeof(Cyg_libc_locale_t *); i++ ) {
174
175         temp_locale = all_locales[i];
176
177         if ( !strncmp(temp_locale->name, locale_str, checklen) )
178             curr_locale = temp_locale;
179     } // for
180
181     CYG_REPORT_RETVAL( curr_locale );
182     return curr_locale;
183 } // find_locale_data()
184
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 ()
189 {
190     if (__current_ctype_locale->mbtowc_fn)
191       return __current_ctype_locale->mbtowc_fn;
192     return &__mbtowc_c;
193 }
194
195 externC char *
196 setlocale( int category, const char *locale )
197 {
198     CYG_REPORT_FUNCNAMETYPE("setlocale", "returning %08x");
199     CYG_REPORT_FUNCARG2( "category=%d, locale=%s", category, locale );
200
201     if (locale != NULL)
202         CYG_CHECK_DATA_PTR( locale, "locale pointer is invalid!" );
203
204     const char *str;
205
206     // special case if locale==NULL, return current locale name
207     if (locale==NULL) {
208
209         CYG_TRACE0( true, "Getting current locale value" );
210
211         switch (category) {
212
213         case LC_COLLATE:
214             str = current_collate_locale->name;
215             break;
216         case LC_CTYPE:
217             str = __current_ctype_locale->name;
218             break;
219         case LC_MONETARY:
220             str = current_monetary_locale->name;
221             break;
222         case LC_NUMERIC:
223             str = current_numeric_locale->name;
224             break;
225         case LC_TIME:
226             str = current_time_locale->name;
227             break;
228         case LC_ALL:
229
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 ];
235
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, "#" );
247
248             str = &my_str[0];
249             break;
250         default:
251             str=NULL;
252             CYG_FAIL("setlocale() passed bad category!" );
253             break;
254
255         } // switch
256
257         CYG_REPORT_RETVAL( (char *)str);
258         return (char *)str;
259     } // if
260         
261     // we only get here if locale is non-NULL, i.e. we want to set it
262
263     const Cyg_libc_locale_t *loc;
264     cyg_bool default_locale = (*locale=='\0');
265
266     CYG_TRACE0( true, "Setting current locale value" );
267
268     switch( category ) {
269     case LC_COLLATE:
270         loc = find_locale_data( locale, CYGNUM_LIBC_I18N_MAX_LOCALE_NAME_SIZE );
271         if (loc != NULL)      // found it
272             current_collate_locale=loc;
273         break;
274         
275     case LC_CTYPE:
276         loc = find_locale_data( locale, CYGNUM_LIBC_I18N_MAX_LOCALE_NAME_SIZE );
277         if (loc != NULL)      // found it
278           {
279             __current_ctype_locale=loc;
280 #ifdef CYGINT_LIBC_I18N_MB_REQUIRED
281             __mb_cur_max = loc->mb_cur_max;
282 #endif
283           }
284         break;
285         
286     case LC_MONETARY:
287         loc = find_locale_data( locale, CYGNUM_LIBC_I18N_MAX_LOCALE_NAME_SIZE );
288         if (loc != NULL)      // found it
289             current_monetary_locale=loc;
290         break;
291         
292     case LC_NUMERIC:
293         loc = find_locale_data( locale, CYGNUM_LIBC_I18N_MAX_LOCALE_NAME_SIZE );
294         if (loc != NULL)      // found it
295             current_numeric_locale=loc;
296         break;
297         
298     case LC_TIME:
299         loc = find_locale_data( locale, CYGNUM_LIBC_I18N_MAX_LOCALE_NAME_SIZE );
300         if (loc != NULL)      // found it
301             current_time_locale=loc;
302         break;
303         
304     case LC_ALL:
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
308
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;
315 #endif
316         } // if
317         else {
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 );
322
323             // Note we don't do much checking here. This could be
324             // much more rigorous (but at the expense of speed/size?)
325
326             const Cyg_libc_locale_t *temp_collate_locale,
327                 *temp_ctype_locale, *temp_monetary_locale,
328                 *temp_numeric_locale, *temp_time_locale;
329
330             cyg_ucount32 token_len;
331
332             str = &locale[0];
333             if ( *str=='#' ) {
334                 ++str;
335                 token_len = strcspn( str, "#" );
336                 loc = find_locale_data( str, token_len );
337
338                 if (loc!=NULL) {
339                     temp_collate_locale=loc;
340                     str += token_len+1;
341                     token_len = strcspn( str, "#" );
342                     loc = find_locale_data( str, token_len );
343
344                     if (loc!=NULL) {
345                         temp_ctype_locale=loc;
346                         str += token_len+1;
347                         token_len = strcspn( str, "#" );
348                         loc = find_locale_data( str, token_len );
349
350                         if (loc!=NULL) {
351                             temp_monetary_locale=loc;
352                             str += token_len+1;
353                             token_len = strcspn( str, "#" );
354                             loc = find_locale_data( str, token_len );
355
356                             if (loc!=NULL) {
357                                 temp_numeric_locale=loc;
358                                 str += token_len+1;
359                                 token_len = strcspn( str, "#" );
360                                 loc = find_locale_data( str, token_len );
361
362                                 if (loc!=NULL) {
363                                     temp_time_locale=loc;
364                                     str += token_len+1;
365                                     token_len = strcspn( str, "#" );
366                                     loc = find_locale_data( str, token_len );
367
368                                     if (loc!=NULL) {
369                       // if we've got this far and loc still isn't NULL,
370                       // then everything's fine, and we've matched everything
371                                         
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;
376 #endif
377                       current_monetary_locale = temp_monetary_locale;
378                       current_numeric_locale = temp_numeric_locale;
379                       current_time_locale = temp_time_locale;
380
381                                     } // if
382                                 } // if
383                             } // if
384                         } // if
385                     } // if
386                 } // if
387             } // if
388             
389         } // else
390         break; // case LC_ALL
391         
392     default:
393             CYG_FAIL("setlocale() passed bad category!" );
394             loc=NULL;
395             break;
396     } // switch
397
398     if (loc==NULL) {
399         CYG_REPORT_RETVAL( NULL );
400         return NULL;
401     } // if
402     else if (default_locale==true) {
403         CYG_REPORT_RETVAL(C_locale.name);
404         return (char *)C_locale.name;
405     } // else if
406     else {
407         CYG_REPORT_RETVAL(locale);
408         return (char *)locale;
409     } // else
410 } // setlocale()
411
412 externC struct lconv *
413 localeconv( void )
414 {
415     CYG_REPORT_FUNCNAMETYPE( "localeconv", "returning %08x" );
416     CYG_REPORT_FUNCARGVOID();
417
418     static struct lconv static_lconv;
419
420     static_lconv.decimal_point = 
421         current_numeric_locale->numdata.decimal_point;
422
423     static_lconv.thousands_sep = 
424         current_numeric_locale->numdata.thousands_sep;
425
426     static_lconv.grouping = 
427         current_numeric_locale->numdata.grouping;
428
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;
434
435     memcpy( &(static_lconv.int_curr_symbol),
436             &(current_monetary_locale->numdata.int_curr_symbol),
437             sizeof(struct lconv) - size_used );
438             
439
440     CYG_REPORT_RETVAL( &static_lconv );
441     return &static_lconv;
442 } // localeconv()
443
444 // EOF locale.cxx