OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libc/] [misc/] [locale/] [locale.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/*  Copyright (C) 2002     Manuel Novoa III
2
 *
3
 *  This library is free software; you can redistribute it and/or
4
 *  modify it under the terms of the GNU Library General Public
5
 *  License as published by the Free Software Foundation; either
6
 *  version 2 of the License, or (at your option) any later version.
7
 *
8
 *  This library is distributed in the hope that it will be useful,
9
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
 *  Library General Public License for more details.
12
 *
13
 *  You should have received a copy of the GNU Library General Public
14
 *  License along with this library; if not, write to the Free
15
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16
 */
17
 
18
/* Nov. 1, 2002
19
 * Reworked setlocale() return values and locale arg processing to
20
 *   be more like glibc.  Applications expecting to be able to
21
 *   query locale settings should now work... at the cost of almost
22
 *   doubling the size of the setlocale object code.
23
 * Fixed a bug in the internal fixed-size-string locale specifier code.
24
 *
25
 * Dec 20, 2002
26
 * Added in collation support and updated stub nl_langinfo.
27
 *
28
 * Aug 1, 2003
29
 * Added glibc-like extended locale stuff (newlocale, duplocale, etc).
30
 *
31
 * Aug 18, 2003
32
 * Bug in duplocale... collation data wasn't copied.
33
 * Bug in newlocale... translate 1<<LC_ALL to LC_ALL_MASK.
34
 * Bug in _wchar_utf8sntowcs... fix cut-n-paste error.
35
 *
36
 * Aug 31, 2003
37
 * Hack around bg_BG bug; grouping specified but no thousands separator.
38
 * Also, disable the locale link_warnings for now, as they generate a
39
 * lot of noise when using libstd++.
40
 */
41
 
42
 
43
/*  TODO:
44
 *  Implement the shared mmap code so non-mmu platforms can use this.
45
 *  Add some basic collate functionality similar to what the previous
46
 *    locale support had (8-bit codesets only).
47
 */
48
 
49
#define _GNU_SOURCE
50
 
51
#define __CTYPE_HAS_8_BIT_LOCALES 1
52
 
53
 
54
#include <string.h>
55
#include <stdlib.h>
56
#include <stddef.h>
57
#include <limits.h>
58
#include <stdint.h>
59
#include <assert.h>
60
#include <errno.h>
61
#include <ctype.h>
62
#include <stdio.h>
63
 
64
#ifdef __UCLIBC_MJN3_ONLY__
65
#ifdef L_setlocale
66
#warning TODO: Make the link_warning()s a config option?
67
#endif
68
#endif
69
#undef link_warning
70
#define link_warning(A,B)
71
 
72
#undef __LOCALE_C_ONLY
73
#ifndef __UCLIBC_HAS_LOCALE__
74
#define __LOCALE_C_ONLY
75
#endif /* __UCLIBC_HAS_LOCALE__ */
76
 
77
 
78
#ifdef __LOCALE_C_ONLY
79
 
80
#include <locale.h>
81
 
82
#else  /* __LOCALE_C_ONLY */
83
 
84
#ifdef __UCLIBC_MJN3_ONLY__
85
#ifdef L_setlocale
86
#warning TODO: Fix the __CTYPE_HAS_8_BIT_LOCALES define at the top of the file.
87
#warning TODO: Fix __WCHAR_ENABLED.
88
#endif
89
#endif
90
 
91
/* Need to include this before locale.h and xlocale.h! */
92
#include <bits/uClibc_locale.h>
93
 
94
#undef CODESET_LIST
95
#define CODESET_LIST                    (__locale_mmap->codeset_list)
96
 
97
#ifdef __UCLIBC_HAS_XLOCALE__
98
#include <xlocale.h>
99
#include <locale.h>
100
#else  /* __UCLIBC_HAS_XLOCALE__ */
101
/* We need this internally... */
102
#define __UCLIBC_HAS_XLOCALE__ 1
103
#include <xlocale.h>
104
#include <locale.h>
105
#undef __UCLIBC_HAS_XLOCALE__
106
#endif /* __UCLIBC_HAS_XLOCALE__ */
107
 
108
#include <wchar.h>
109
 
110
#define LOCALE_NAMES                    (__locale_mmap->locale_names5)
111
#define LOCALES                                 (__locale_mmap->locales)
112
#define LOCALE_AT_MODIFIERS     (__locale_mmap->locale_at_modifiers)
113
#define CATEGORY_NAMES                  (__locale_mmap->lc_names)
114
 
115
#ifdef __UCLIBC_MJN3_ONLY__
116
#warning REMINDER: redo the MAX_LOCALE_STR stuff...
117
#endif
118
#define MAX_LOCALE_STR            256 /* TODO: Only sufficient for current case. */
119
#define MAX_LOCALE_CATEGORY_STR    32 /* TODO: Only sufficient for current case. */
120
/* Note: Best if MAX_LOCALE_CATEGORY_STR is a power of 2. */
121
 
122
extern int _locale_set_l(const unsigned char *p, __locale_t base);
123
extern void _locale_init_l(__locale_t base);
124
 
125
#endif /* __LOCALE_C_ONLY */
126
 
127
#undef LOCALE_STRING_SIZE
128
#define LOCALE_SELECTOR_SIZE (2 * __LC_ALL + 2)
129
 
130
#ifdef __UCLIBC_MJN3_ONLY__
131
#ifdef L_setlocale
132
#warning TODO: Create a C locale selector string.
133
#endif
134
#endif
135
#define C_LOCALE_SELECTOR "\x23\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
136
 
137
 
138
#include <langinfo.h>
139
#include <nl_types.h>
140
 
141
/**********************************************************************/
142
#ifdef L_setlocale
143
 
144
#ifdef __LOCALE_C_ONLY
145
 
146
link_warning(setlocale,"REMINDER: The 'setlocale' function supports only C|POSIX locales.")
147
 
148
static const char C_string[] = "C";
149
 
150
char *setlocale(int category, register const char *locale)
151
{
152
        return ( (((unsigned int)(category)) <= LC_ALL)
153
                         && ( (!locale)         /* Request for locale category string. */
154
                                  || (!*locale) /* Implementation-defined default is C. */
155
                                  || ((*locale == 'C') && !locale[1])
156
                                  || (!strcmp(locale, "POSIX"))) )
157
                ? (char *) C_string             /* Always in C/POSIX locale. */
158
                : NULL;
159
}
160
 
161
#else  /* ---------------------------------------------- __LOCALE_C_ONLY */
162
 
163
#ifdef __UCLIBC_HAS_THREADS__
164
link_warning(setlocale,"REMINDER: The 'setlocale' function is _not_ threadsafe except for simple queries.")
165
#endif
166
 
167
#if !defined(__LOCALE_DATA_NUM_LOCALES) || (__LOCALE_DATA_NUM_LOCALES <= 1)
168
#error locales enabled, but not data other than for C locale!
169
#endif
170
 
171
#ifdef __UCLIBC_MJN3_ONLY__
172
#warning TODO: Move posix and utf8 strings.
173
#endif
174
static const char posix[] = "POSIX";
175
static const char utf8[] = "UTF-8";
176
 
177
#ifdef __UCLIBC_MJN3_ONLY__
178
#warning TODO: Fix dimensions of hr_locale.
179
#endif
180
/* Individual category strings start at hr_locale + category * MAX_LOCALE_CATEGORY.
181
 * This holds for LC_ALL as well.
182
 */
183
static char hr_locale[(MAX_LOCALE_CATEGORY_STR * LC_ALL) + MAX_LOCALE_STR];
184
 
185
static void update_hr_locale(const unsigned char *spec)
186
{
187
        const unsigned char *loc;
188
        const unsigned char *s;
189
        char *n;
190
        int i, category, done;
191
 
192
        done = category = 0;
193
        do {
194
                s = spec + 1;
195
                n = hr_locale + category * MAX_LOCALE_CATEGORY_STR;
196
 
197
                if (category == LC_ALL) {
198
                        done = 1;
199
                        for (i = 0 ; i < LC_ALL-1 ; i += 2) {
200
                                if ((s[i] != s[i+2]) || (s[i+1] != s[i+3])) {
201
                                        goto SKIP;
202
                                }
203
                        }
204
                        /* All categories the same, so simplify string by using a single
205
                         * category. */
206
                        category = LC_CTYPE;
207
                }
208
 
209
        SKIP:
210
                i = (category == LC_ALL) ? 0 : category;
211
                s += 2*i;
212
 
213
                do {
214
                        if ((*s != 0xff) || (s[1] != 0xff)) {
215
                                loc = LOCALES
216
                                        + __LOCALE_DATA_WIDTH_LOCALES * ((((int)(*s & 0x7f)) << 7)
217
                                                                                                         + (s[1] & 0x7f));
218
                                if (category == LC_ALL) {
219
                                        n = stpcpy(n, CATEGORY_NAMES + (int) CATEGORY_NAMES[i]);
220
                                        *n++ = '=';
221
                                }
222
                                if (*loc == 0) {
223
                                        *n++ = 'C';
224
                                        *n = 0;
225
                                } else {
226
                                        char at = 0;
227
                                        memcpy(n, LOCALE_NAMES + 5*((*loc)-1), 5);
228
                                        if (n[2] != '_') {
229
                                                at = n[2];
230
                                                n[2] = '_';
231
                                        }
232
                                        n += 5;
233
                                        *n++ = '.';
234
                                        if (loc[2] == 2) {
235
                                                n = stpcpy(n, utf8);
236
                                        } else if (loc[2] >= 3) {
237
                                                n = stpcpy(n, CODESET_LIST + (int)(CODESET_LIST[loc[2] - 3]));
238
                                        }
239
                                        if (at) {
240
                                                const char *q;
241
                                                *n++ = '@';
242
                                                q = LOCALE_AT_MODIFIERS;
243
                                                do {
244
                                                        if (q[1] == at) {
245
                                                                n = stpcpy(n, q+2);
246
                                                                break;
247
                                                        }
248
                                                        q += 2 + *q;
249
                                                } while (*q);
250
                                        }
251
                                }
252
                                *n++ = ';';
253
                        }
254
                        s += 2;
255
                } while (++i < category);
256
                *--n = 0;                  /* Remove trailing ';' and nul-terminate. */
257
 
258
                ++category;
259
        } while (!done);
260
}
261
 
262
char *setlocale(int category, const char *locale)
263
{
264
        if (((unsigned int)(category)) > LC_ALL) {
265
#if 0
266
                __set_errno(EINVAL);    /* glibc sets errno -- SUSv3 doesn't say. */
267
#endif
268
                return NULL;                    /* Illegal/unsupported category. */
269
        }
270
 
271
        if (locale != NULL) {           /* Not just a query... */
272
                if (!__newlocale((1 << category), locale, __global_locale)) {
273
                        return NULL;            /* Failed! */
274
                }
275
                update_hr_locale(__global_locale->cur_locale);
276
        }
277
 
278
        /* Either a query or a successful set, so return current locale string. */
279
        return hr_locale + (category * MAX_LOCALE_CATEGORY_STR);
280
}
281
 
282
#endif /* __LOCALE_C_ONLY */
283
 
284
#endif
285
/**********************************************************************/
286
#ifdef L_localeconv
287
 
288
/* Note: We assume here that the compiler does the sane thing regarding
289
 * placement of the fields in the struct.  If necessary, we could ensure
290
 * this usings an array of offsets but at some size cost. */
291
 
292
#ifdef __LOCALE_C_ONLY
293
 
294
link_warning(localeconv,"REMINDER: The 'localeconv' function is hardwired for C/POSIX locale only.")
295
 
296
static struct lconv the_lconv;
297
 
298
static const char decpt[] = ".";
299
 
300
struct lconv *localeconv(void)
301
{
302
        register char *p = (char *)(&the_lconv);
303
 
304
        *((char **)p) = (char *) decpt;
305
        do {
306
                p += sizeof(char **);
307
                *((char **)p) = (char *) (decpt+1);
308
        } while (p < (char *) &the_lconv.negative_sign);
309
 
310
        p = (&the_lconv.int_frac_digits);
311
        do {
312
                *p = CHAR_MAX;
313
                ++p;
314
        } while (p <= &the_lconv.int_n_sign_posn);
315
 
316
        return &the_lconv;
317
}
318
 
319
#else  /* __LOCALE_C_ONLY */
320
 
321
static struct lconv the_lconv;
322
 
323
struct lconv *localeconv(void)
324
{
325
        register char *p = (char *) &the_lconv;
326
        register char **q = (char **) &(__UCLIBC_CURLOCALE_DATA).decimal_point;
327
 
328
        do {
329
                *((char **)p) = *q;
330
                p += sizeof(char **);
331
                ++q;
332
        } while (p < &the_lconv.int_frac_digits);
333
 
334
        do {
335
                *p = **q;
336
                ++p;
337
                ++q;
338
        } while (p <= &the_lconv.int_n_sign_posn);
339
 
340
        return &the_lconv;
341
}
342
 
343
#endif /* __LOCALE_C_ONLY */
344
 
345
#endif
346
/**********************************************************************/
347
#if defined(L__locale_init) && !defined(__LOCALE_C_ONLY)
348
 
349
static __uclibc_locale_t __global_locale_data;
350
 
351
__locale_t __global_locale = &__global_locale_data;
352
 
353
#ifdef __UCLIBC_HAS_XLOCALE__
354
__locale_t __curlocale_var = &__global_locale_data;
355
#endif
356
 
357
/*----------------------------------------------------------------------*/
358
#ifdef __UCLIBC_MJN3_ONLY__
359
#warning TODO: Move utf8 and ascii strings.
360
#endif
361
static const char utf8[] = "UTF-8";
362
static const char ascii[] = "ASCII";
363
 
364
typedef struct {
365
        uint16_t num_base;
366
        uint16_t num_der;
367
        uint16_t MAX_WEIGHTS;
368
        uint16_t num_index2weight;
369
#define num_index2ruleidx num_index2weight
370
        uint16_t num_weightstr;
371
        uint16_t num_multistart;
372
        uint16_t num_override;
373
        uint16_t num_ruletable;
374
} coldata_header_t;
375
 
376
typedef struct {
377
        uint16_t num_weights;
378
        uint16_t num_starters;
379
        uint16_t ii_shift;
380
        uint16_t ti_shift;
381
        uint16_t ii_len;
382
        uint16_t ti_len;
383
        uint16_t max_weight;
384
        uint16_t num_col_base;
385
        uint16_t max_col_index;
386
        uint16_t undefined_idx;
387
        uint16_t range_low;
388
        uint16_t range_count;
389
        uint16_t range_base_weight;
390
        uint16_t range_rule_offset;
391
 
392
        uint16_t index2weight_offset;
393
        uint16_t index2ruleidx_offset;
394
        uint16_t multistart_offset;
395
        uint16_t wcs2colidt_offset_low;
396
        uint16_t wcs2colidt_offset_hi;
397
} coldata_base_t;
398
 
399
typedef struct {
400
        uint16_t base_idx;
401
        uint16_t undefined_idx;
402
        uint16_t overrides_offset;
403
        uint16_t multistart_offset;
404
} coldata_der_t;
405
 
406
static int init_cur_collate(int der_num, __collate_t *cur_collate)
407
{
408
        const uint16_t *__locale_collate_tbl = __locale_mmap->collate_data;
409
        coldata_header_t *cdh;
410
        coldata_base_t *cdb;
411
        coldata_der_t *cdd;
412
        const uint16_t *p;
413
        size_t n;
414
        uint16_t i, w;
415
 
416
        assert(sizeof(coldata_base_t) == 19*2);
417
        assert(sizeof(coldata_der_t) == 4*2);
418
        assert(sizeof(coldata_header_t) == 8*2);
419
 
420
        if (!der_num) {                         /* C locale... special */
421
                cur_collate->num_weights = 0;
422
                return 1;
423
        }
424
 
425
        --der_num;
426
 
427
        cdh = (coldata_header_t *) __locale_collate_tbl;
428
 
429
#ifdef __UCLIBC_MJN3_ONLY__
430
#warning CONSIDER: Should we assert here?
431
#endif
432
#if 0
433
        if (der_num >= cdh->num_der) {
434
                return 0;
435
        }
436
#else
437
        assert((der_num < cdh->num_der));
438
#endif
439
 
440
        cdd = (coldata_der_t *)(__locale_collate_tbl
441
                                                        + (sizeof(coldata_header_t)
442
                                                           + cdh->num_base * sizeof(coldata_base_t)
443
                                                           + der_num * sizeof(coldata_der_t)
444
                                                           )/2 );
445
 
446
        cdb = (coldata_base_t *)(__locale_collate_tbl
447
                                                         + (sizeof(coldata_header_t)
448
                                                                + cdd->base_idx * sizeof(coldata_base_t)
449
                                                                )/2 );
450
 
451
        memcpy(cur_collate, cdb, offsetof(coldata_base_t,index2weight_offset));
452
        cur_collate->undefined_idx = cdd->undefined_idx;
453
 
454
        cur_collate->ti_mask = (1 << cur_collate->ti_shift)-1;
455
        cur_collate->ii_mask = (1 << cur_collate->ii_shift)-1;
456
 
457
/*      fflush(stdout); */
458
/*      fprintf(stderr,"base=%d  num_col_base: %d  %d\n", cdd->base_idx ,cur_collate->num_col_base, cdb->num_col_base); */
459
 
460
        n = (sizeof(coldata_header_t) + cdh->num_base * sizeof(coldata_base_t)
461
                 + cdh->num_der * sizeof(coldata_der_t))/2;
462
 
463
/*      fprintf(stderr,"n   = %d\n", n); */
464
        cur_collate->index2weight_tbl = __locale_collate_tbl + n + cdb->index2weight_offset;
465
/*      fprintf(stderr,"i2w = %d\n", n + cdb->index2weight_offset); */
466
        n += cdh->num_index2weight;
467
        cur_collate->index2ruleidx_tbl = __locale_collate_tbl + n + cdb->index2ruleidx_offset;
468
/*      fprintf(stderr,"i2r = %d\n", n + cdb->index2ruleidx_offset); */
469
        n += cdh->num_index2ruleidx;
470
        cur_collate->multistart_tbl = __locale_collate_tbl + n + cdd->multistart_offset;
471
/*      fprintf(stderr,"mts = %d\n", n + cdb->multistart_offset); */
472
        n += cdh->num_multistart;
473
        cur_collate->overrides_tbl = __locale_collate_tbl + n + cdd->overrides_offset;
474
/*      fprintf(stderr,"ovr = %d\n", n + cdd->overrides_offset); */
475
        n += cdh->num_override;
476
        cur_collate->ruletable = __locale_collate_tbl + n;
477
/*      fprintf(stderr, "rtb = %d\n", n); */
478
        n += cdh->num_ruletable;
479
        cur_collate->weightstr = __locale_collate_tbl + n;
480
/*      fprintf(stderr,"wts = %d\n", n); */
481
        n += cdh->num_weightstr;
482
        cur_collate->wcs2colidt_tbl = __locale_collate_tbl + n
483
                + (((unsigned long)(cdb->wcs2colidt_offset_hi)) << 16)
484
                + cdb->wcs2colidt_offset_low;
485
/*      fprintf(stderr,"wcs = %lu\n", n + (((unsigned long)(cdb->wcs2colidt_offset_hi)) << 16) */
486
/*                      + cdb->wcs2colidt_offset_low); */
487
 
488
        cur_collate->MAX_WEIGHTS = cdh->MAX_WEIGHTS;
489
 
490
#ifdef __UCLIBC_MJN3_ONLY__
491
#warning CONSIDER: Fix the +1 by increasing max_col_index?
492
#warning CONSIDER: Since this collate info is dependent only on LC_COLLATE ll_cc and not on codeset, we could just globally allocate this for each in a table
493
#endif
494
 
495
        cur_collate->index2weight = calloc(2*cur_collate->max_col_index+2,
496
                                                                           sizeof(uint16_t));
497
        if (!cur_collate->index2weight) {
498
                return 0;
499
        }
500
        cur_collate->index2ruleidx = cur_collate->index2weight
501
                + cur_collate->max_col_index + 1;
502
 
503
        memcpy(cur_collate->index2weight, cur_collate->index2weight_tbl,
504
                   cur_collate->num_col_base * sizeof(uint16_t));
505
        memcpy(cur_collate->index2ruleidx, cur_collate->index2ruleidx_tbl,
506
                   cur_collate->num_col_base * sizeof(uint16_t));
507
 
508
        /* now do the overrides */
509
        p = cur_collate->overrides_tbl;
510
        while (*p > 1) {
511
/*              fprintf(stderr, "processing override -- count = %d\n", *p); */
512
                n = *p++;
513
                w = *p++;
514
                do {
515
                        i = *p++;
516
/*                      fprintf(stderr, "       i=%d (%#x) w=%d *p=%d\n", i, i, w, *p); */
517
                        cur_collate->index2weight[i-1] = w++;
518
                        cur_collate->index2ruleidx[i-1] = *p++;
519
                } while (--n);
520
        }
521
        assert(*p == 1);
522
        while (*++p) {
523
                i = *p;
524
/*              fprintf(stderr, "       i=%d (%#x) w=%d *p=%d\n", i, i, p[1], p[2]); */
525
                cur_collate->index2weight[i-1] = *++p;
526
                cur_collate->index2ruleidx[i-1] = *++p;
527
        }
528
 
529
 
530
        for (i=0 ; i < cur_collate->multistart_tbl[0] ; i++) {
531
                p = cur_collate->multistart_tbl;
532
/*              fprintf(stderr, "%2d of %2d: %d ", i,  cur_collate->multistart_tbl[0], p[i]); */
533
                p += p[i];
534
 
535
                do {
536
                        n = *p++;
537
                        do {
538
                                if (!*p) {              /* found it */
539
/*                                      fprintf(stderr, "found: n=%d (%#lx) |%.*ls|\n", n, (int) *cs->s, n, cs->s); */
540
/*                                      fprintf(stderr, ": %d - single\n", n); */
541
                                        goto FOUND;
542
                                }
543
                                /* the lookup check here is safe since we're assured that *p is a valid colidex */
544
/*                              fprintf(stderr, "lookup(%lc)==%d  *p==%d\n", cs->s[n], lookup(cs->s[n]), (int) *p); */
545
/*                              fprintf(stderr, ": %d - ", n); */
546
                                do {
547
/*                                      fprintf(stderr, "%d|",  *p); */
548
                                } while (*p++);
549
                                break;
550
                        } while (1);
551
                } while (1);
552
        FOUND:
553
                continue;
554
        }
555
 
556
        return 1;
557
}
558
 
559
int _locale_set_l(const unsigned char *p, __locale_t base)
560
{
561
        const char **x;
562
        unsigned char *s = base->cur_locale + 1;
563
        const size_t *stp;
564
        const unsigned char *r;
565
        const uint16_t *io;
566
        const uint16_t *ii;
567
        const unsigned char *d;
568
        int row;                                        /* locale row */
569
        int crow;                                       /* category row */
570
        int len;
571
        int c;
572
        int i = 0;
573
        __collate_t newcol;
574
 
575
        ++p;
576
 
577
        newcol.index2weight = NULL;
578
        if ((p[2*LC_COLLATE] != s[2*LC_COLLATE])
579
                || (p[2*LC_COLLATE + 1] != s[2*LC_COLLATE + 1])
580
                ) {
581
                row  = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f);
582
                assert(row < __LOCALE_DATA_NUM_LOCALES);
583
                if (!init_cur_collate(__locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES
584
                                                                                                          * row + 3 + LC_COLLATE ],
585
                                                          &newcol)
586
                        ) {
587
                        return 0;                        /* calloc failed. */
588
                }
589
                free(base->collate.index2weight);
590
                memcpy(&base->collate, &newcol, sizeof(__collate_t));
591
        }
592
 
593
        do {
594
                if ((*p != *s) || (p[1] != s[1])) {
595
                        row  = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f);
596
                        assert(row < __LOCALE_DATA_NUM_LOCALES);
597
 
598
                        *s = *p;
599
                        s[1] = p[1];
600
 
601
                        if ((i != LC_COLLATE)
602
                                && ((len = __locale_mmap->lc_common_item_offsets_LEN[i]) != 0)
603
                                ) {
604
                                crow = __locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES * row
605
                                                                                           + 3 + i ]
606
                                        * len;
607
 
608
                                x = (const char **)(((char *) base)
609
                                    + base->category_offsets[i]);
610
 
611
                                stp = __locale_mmap->lc_common_tbl_offsets + 4*i;
612
                                r = (const unsigned char *)( ((char *)__locale_mmap) + *stp );
613
                                io = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
614
                                ii = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
615
                                d = (const unsigned char *)( ((char *)__locale_mmap) + *++stp );
616
                                for (c=0 ; c < len ; c++) {
617
                                        *(x + c) = d + ii[ r[crow + c] + io[c] ];
618
                                }
619
                        }
620
                        if (i == LC_CTYPE) {
621
                                c = __locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES * row
622
                                                                                        + 2 ]; /* codeset */
623
                                if (c <= 2) {
624
                                        if (c == 2) {
625
                                                base->codeset = utf8;
626
                                                base->encoding = __ctype_encoding_utf8;
627
                                                /* TODO - fix for bcc */
628
                                                base->mb_cur_max = 6;
629
                                        } else {
630
                                                assert(c==1);
631
                                                base->codeset = ascii;
632
                                                base->encoding = __ctype_encoding_7_bit;
633
                                                base->mb_cur_max = 1;
634
                                        }
635
                                } else {
636
                                        const __codeset_8_bit_t *c8b;
637
                                        r = CODESET_LIST;
638
                                        base->codeset = r + r[c -= 3];
639
                                        base->encoding = __ctype_encoding_8_bit;
640
#ifdef __UCLIBC_MJN3_ONLY__
641
#warning REMINDER: update 8 bit mb_cur_max when translit implemented!
642
#endif
643
                                        /* TODO - update when translit implemented! */
644
                                        base->mb_cur_max = 1;
645
                                        c8b = __locale_mmap->codeset_8_bit + c;
646
#ifdef __CTYPE_HAS_8_BIT_LOCALES
647
                                        base->idx8ctype = c8b->idx8ctype;
648
                                        base->idx8uplow = c8b->idx8uplow;
649
#ifdef __UCLIBC_HAS_WCHAR__
650
                                        base->idx8c2wc = c8b->idx8c2wc;
651
                                        base->idx8wc2c = c8b->idx8wc2c;
652
                                        /* translit  */
653
#endif /* __UCLIBC_HAS_WCHAR__ */
654
 
655
                                        /* What follows is fairly bloated, but it is just a hack
656
                                         * to get the 8-bit codeset ctype stuff functioning.
657
                                         * All of this will be replaced in the next generation
658
                                         * of locale support anyway... */
659
 
660
                                        memcpy(base->__ctype_b_data,
661
                                                   __C_ctype_b - __UCLIBC_CTYPE_B_TBL_OFFSET,
662
                                                   (256 + __UCLIBC_CTYPE_B_TBL_OFFSET)
663
                                                   * sizeof(__ctype_mask_t));
664
                                        memcpy(base->__ctype_tolower_data,
665
                                                   __C_ctype_tolower - __UCLIBC_CTYPE_TO_TBL_OFFSET,
666
                                                   (256 + __UCLIBC_CTYPE_TO_TBL_OFFSET)
667
                                                   * sizeof(__ctype_touplow_t));
668
                                        memcpy(base->__ctype_toupper_data,
669
                                                   __C_ctype_toupper - __UCLIBC_CTYPE_TO_TBL_OFFSET,
670
                                                   (256 + __UCLIBC_CTYPE_TO_TBL_OFFSET)
671
                                                   * sizeof(__ctype_touplow_t));
672
 
673
#define Cctype_TBL_MASK         ((1 << __LOCALE_DATA_Cctype_IDX_SHIFT) - 1)
674
#define Cctype_IDX_OFFSET       (128 >> __LOCALE_DATA_Cctype_IDX_SHIFT)
675
 
676
                                        {
677
                                                int u;
678
                                                __ctype_mask_t m;
679
 
680
                                                for (u=0 ; u < 128 ; u++) {
681
#ifdef __LOCALE_DATA_Cctype_PACKED
682
                                                        c = base->tbl8ctype
683
                                                                [ ((int)(c8b->idx8ctype
684
                                                                                 [(u >> __LOCALE_DATA_Cctype_IDX_SHIFT) ])
685
                                                                   << (__LOCALE_DATA_Cctype_IDX_SHIFT - 1))
686
                                                                  + ((u & Cctype_TBL_MASK) >> 1)];
687
                                                        c = (u & 1) ? (c >> 4) : (c & 0xf);
688
#else
689
                                                        c = base->tbl8ctype
690
                                                                [ ((int)(c8b->idx8ctype
691
                                                                                 [(u >> __LOCALE_DATA_Cctype_IDX_SHIFT) ])
692
                                                                   << __LOCALE_DATA_Cctype_IDX_SHIFT)
693
                                                                  + (u & Cctype_TBL_MASK) ];
694
#endif
695
 
696
                                                        m = base->code2flag[c];
697
 
698
                                                        base->__ctype_b_data
699
                                                                [128 + __UCLIBC_CTYPE_B_TBL_OFFSET + u]
700
                                                                = m;
701
 
702
#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
703
                                                        if (((signed char)(128 + u)) != -1) {
704
                                                                base->__ctype_b_data[__UCLIBC_CTYPE_B_TBL_OFFSET
705
                                                                                                         + ((signed char)(128 + u))]
706
                                                                        = m;
707
                                                        }
708
#endif
709
 
710
                                                        base->__ctype_tolower_data
711
                                                                [128 + __UCLIBC_CTYPE_TO_TBL_OFFSET + u]
712
                                                                = 128 + u;
713
                                                        base->__ctype_toupper_data
714
                                                                [128 + __UCLIBC_CTYPE_TO_TBL_OFFSET + u]
715
                                                                = 128 + u;
716
 
717
                                                        if (m & (_ISlower|_ISupper)) {
718
                                                                c = base->tbl8uplow
719
                                                                        [ ((int)(c8b->idx8uplow
720
                                                                                         [u >> __LOCALE_DATA_Cuplow_IDX_SHIFT])
721
                                                                           << __LOCALE_DATA_Cuplow_IDX_SHIFT)
722
                                                                          + ((128 + u)
723
                                                                                 & ((1 << __LOCALE_DATA_Cuplow_IDX_SHIFT)
724
                                                                                        - 1)) ];
725
                                                                if (m & _ISlower) {
726
                                                                        base->__ctype_toupper_data
727
                                                                                [128 + __UCLIBC_CTYPE_TO_TBL_OFFSET + u]
728
                                                                                = (unsigned char)(128 + u + c);
729
#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
730
                                                                        if (((signed char)(128 + u)) != -1) {
731
                                                                                base->__ctype_toupper_data
732
                                                                                        [__UCLIBC_CTYPE_TO_TBL_OFFSET
733
                                                                                         + ((signed char)(128 + u))]
734
                                                                                        = (unsigned char)(128 + u + c);
735
                                                                        }
736
#endif
737
                                                                } else {
738
                                                                        base->__ctype_tolower_data
739
                                                                                [128 + __UCLIBC_CTYPE_TO_TBL_OFFSET + u]
740
                                                                                = (unsigned char)(128 + u - c);
741
#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
742
                                                                        if (((signed char)(128 + u)) != -1) {
743
                                                                                base->__ctype_tolower_data
744
                                                                                        [__UCLIBC_CTYPE_TO_TBL_OFFSET
745
                                                                                         + ((signed char)(128 + u))]
746
                                                                                        = (unsigned char)(128 + u - c);
747
                                                                        }
748
#endif
749
                                                                }
750
                                                        }
751
                                                }
752
                                        }
753
 
754
#ifdef __UCLIBC_HAS_XLOCALE__
755
                                        base->__ctype_b = base->__ctype_b_data
756
                                                + __UCLIBC_CTYPE_B_TBL_OFFSET;
757
                                        base->__ctype_tolower = base->__ctype_tolower_data
758
                                                + __UCLIBC_CTYPE_TO_TBL_OFFSET;
759
                                        base->__ctype_toupper = base->__ctype_toupper_data
760
                                                + __UCLIBC_CTYPE_TO_TBL_OFFSET;
761
#else  /* __UCLIBC_HAS_XLOCALE__ */
762
                                        __ctype_b = base->__ctype_b_data
763
                                                + __UCLIBC_CTYPE_B_TBL_OFFSET;
764
                                        __ctype_tolower = base->__ctype_tolower_data
765
                                                + __UCLIBC_CTYPE_TO_TBL_OFFSET;
766
                                        __ctype_toupper = base->__ctype_toupper_data
767
                                                + __UCLIBC_CTYPE_TO_TBL_OFFSET;
768
#endif /* __UCLIBC_HAS_XLOCALE__ */
769
 
770
#endif /* __CTYPE_HAS_8_BIT_LOCALES */
771
                                }
772
#ifdef __UCLIBC_MJN3_ONLY__
773
#warning TODO: Put the outdigit string length in the locale_mmap object.
774
#endif
775
                                d = base->outdigit_length;
776
                                x = &base->outdigit0_mb;
777
                                for (c = 0 ; c < 10 ; c++) {
778
                                        ((unsigned char *)d)[c] = strlen(x[c]);
779
                                        assert(d[c] > 0);
780
                                }
781
                        } else if (i == LC_NUMERIC) {
782
                                assert(LC_NUMERIC > LC_CTYPE); /* Need ctype initialized. */
783
 
784
                                base->decimal_point_len
785
                                        = __locale_mbrtowc_l(&base->decimal_point_wc,
786
                                                                                        base->decimal_point, base);
787
                                assert(base->decimal_point_len > 0);
788
                                assert(base->decimal_point[base->decimal_point_len] == 0);
789
 
790
                                if (*base->grouping) {
791
                                        base->thousands_sep_len
792
                                                = __locale_mbrtowc_l(&base->thousands_sep_wc,
793
                                                                                         base->thousands_sep, base);
794
#if 1
795
#ifdef __UCLIBC_MJN3_ONLY__
796
#warning TODO: Remove hack involving grouping without a thousep char (bg_BG).
797
#endif
798
                                        assert(base->thousands_sep_len >= 0);
799
                                        if (base->thousands_sep_len == 0) {
800
                                                base->grouping = base->thousands_sep; /* empty string */
801
                                        }
802
                                        assert(base->thousands_sep[base->thousands_sep_len] == 0);
803
#else
804
                                        assert(base->thousands_sep_len > 0);
805
                                        assert(base->thousands_sep[base->thousands_sep_len] == 0);
806
#endif
807
                                }
808
 
809
/*                      } else if (i == LC_COLLATE) { */
810
/*                              init_cur_collate(__locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES */
811
/*                                                                                                               * row + 3 + i ], */
812
/*                                                               &base->collate); */
813
                        }
814
                }
815
                ++i;
816
                p += 2;
817
                s += 2;
818
        } while (i < LC_ALL);
819
 
820
        return 1;
821
}
822
 
823
static const uint16_t __code2flag[16] = {
824
        0,                                                       /* unclassified = 0 */
825
        _ISprint|_ISgraph|_ISalnum|_ISalpha, /* alpha_nonupper_nonlower */
826
        _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, /* alpha_lower */
827
        _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower|_ISupper, /* alpha_upper_lower */
828
        _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, /* alpha_upper */
829
        _ISprint|_ISgraph|_ISalnum|_ISdigit, /* digit */
830
        _ISprint|_ISgraph|_ISpunct,     /* punct */
831
        _ISprint|_ISgraph,                      /* graph */
832
        _ISprint|_ISspace,                      /* print_space_nonblank */
833
        _ISprint|_ISspace|_ISblank,     /* print_space_blank */
834
                 _ISspace,                      /* space_nonblank_noncntrl */
835
                 _ISspace|_ISblank,     /* space_blank_noncntrl */
836
        _IScntrl|_ISspace,                      /* cntrl_space_nonblank */
837
        _IScntrl|_ISspace|_ISblank,     /* cntrl_space_blank */
838
        _IScntrl                                        /* cntrl_nonspace */
839
};
840
 
841
void _locale_init_l(__locale_t base)
842
{
843
        memset(base->cur_locale, 0, LOCALE_SELECTOR_SIZE);
844
        base->cur_locale[0] = '#';
845
 
846
        memcpy(base->category_item_count,
847
                   __locale_mmap->lc_common_item_offsets_LEN,
848
                   LC_ALL);
849
 
850
        ++base->category_item_count[0]; /* Increment for codeset entry. */
851
        base->category_offsets[0] = offsetof(__uclibc_locale_t, outdigit0_mb);
852
        base->category_offsets[1] = offsetof(__uclibc_locale_t, decimal_point);
853
        base->category_offsets[2] = offsetof(__uclibc_locale_t, int_curr_symbol);
854
        base->category_offsets[3] = offsetof(__uclibc_locale_t, abday_1);
855
/*      base->category_offsets[4] = offsetof(__uclibc_locale_t, collate???); */
856
        base->category_offsets[5] = offsetof(__uclibc_locale_t, yesexpr);
857
 
858
#ifdef __CTYPE_HAS_8_BIT_LOCALES
859
        base->tbl8ctype
860
                = (const unsigned char *) &__locale_mmap->tbl8ctype;
861
    base->tbl8uplow
862
                = (const unsigned char *) &__locale_mmap->tbl8uplow;
863
#ifdef __UCLIBC_HAS_WCHAR__
864
        base->tbl8c2wc
865
                = (const uint16_t *) &__locale_mmap->tbl8c2wc;
866
        base->tbl8wc2c
867
                = (const unsigned char *) &__locale_mmap->tbl8wc2c;
868
        /* translit  */
869
#endif /* __UCLIBC_HAS_WCHAR__ */
870
#endif /* __CTYPE_HAS_8_BIT_LOCALES */
871
#ifdef __UCLIBC_HAS_WCHAR__
872
        base->tblwctype
873
                = (const unsigned char *) &__locale_mmap->tblwctype;
874
        base->tblwuplow
875
                = (const unsigned char *) &__locale_mmap->tblwuplow;
876
        base->tblwuplow_diff
877
                = (const uint16_t *) &__locale_mmap->tblwuplow_diff;
878
/*      base->tblwcomb */
879
/*              = (const unsigned char *) &__locale_mmap->tblwcomb; */
880
        /* width?? */
881
#endif /* __UCLIBC_HAS_WCHAR__ */
882
 
883
        /* Initially, set things up to use the global C ctype tables.
884
         * This is correct for C (ASCII) and UTF-8 based locales (except tr_TR). */
885
#ifdef __UCLIBC_HAS_XLOCALE__
886
        base->__ctype_b = __C_ctype_b;
887
        base->__ctype_tolower = __C_ctype_tolower;
888
        base->__ctype_toupper = __C_ctype_toupper;
889
#else  /* __UCLIBC_HAS_XLOCALE__ */
890
        __ctype_b = __C_ctype_b;
891
        __ctype_tolower = __C_ctype_tolower;
892
        __ctype_toupper = __C_ctype_toupper;
893
#endif /* __UCLIBC_HAS_XLOCALE__ */
894
 
895
#ifdef __UCLIBC_MJN3_ONLY__
896
#warning TODO: Initialize code2flag correctly based on locale_mmap.
897
#endif
898
        base->code2flag = __code2flag;
899
 
900
 
901
        _locale_set_l(C_LOCALE_SELECTOR, base);
902
}
903
 
904
void _locale_init(void)
905
{
906
        /* TODO: mmap the locale file  */
907
 
908
        /* TODO - ??? */
909
        _locale_init_l(__global_locale);
910
}
911
 
912
#endif
913
/**********************************************************************/
914
#if defined(L_nl_langinfo) || defined(L_nl_langinfo_l)
915
 
916
#ifdef __LOCALE_C_ONLY
917
 
918
/* We need to index 320 bytes of data, so you might initially think we
919
 * need to store the offsets in shorts.  But since the offset of the
920
 * 64th item is 182, we'll store "offset - 2*64" for all items >= 64
921
 * and always calculate the data offset as "offset[i] + 2*(i & 64)".
922
 * This allows us to pack the data offsets in an unsigned char while
923
 * also avoiding an "if".
924
 *
925
 * Note: Category order is assumed to be:
926
 *   ctype, numeric, monetary, time, collate, messages, all
927
 */
928
 
929
#define C_LC_ALL 6
930
 
931
/* Combine the data to avoid size penalty for seperate char arrays when
932
 * compiler aligns objects.  The original code is left in as documentation. */
933
#define cat_start nl_data
934
#define C_locale_data (nl_data + C_LC_ALL + 1 + 90)
935
 
936
static const unsigned char nl_data[C_LC_ALL + 1 + 90 + 320] = {
937
/* static const char cat_start[LC_ALL + 1] = { */
938
        '\x00', '\x0b', '\x0e', '\x24', '\x56', '\x56', '\x5a',
939
/* }; */
940
/* static const char item_offset[90] = { */
941
        '\x00', '\x02', '\x04', '\x06', '\x08', '\x0a', '\x0c', '\x0e',
942
        '\x10', '\x12', '\x14', '\x1a', '\x1b', '\x1b', '\x1b', '\x1b',
943
        '\x1b', '\x1b', '\x1b', '\x1b', '\x1b', '\x1c', '\x1c', '\x1c',
944
        '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c',
945
        '\x1c', '\x1c', '\x1c', '\x1e', '\x20', '\x24', '\x28', '\x2c',
946
        '\x30', '\x34', '\x38', '\x3c', '\x43', '\x4a', '\x52', '\x5c',
947
        '\x65', '\x6c', '\x75', '\x79', '\x7d', '\x81', '\x85', '\x89',
948
        '\x8d', '\x91', '\x95', '\x99', '\x9d', '\xa1', '\xa5', '\xad',
949
        '\x36', '\x3c', '\x42', '\x46', '\x4b', '\x50', '\x57', '\x61',
950
        '\x69', '\x72', '\x7b', '\x7e', '\x81', '\x96', '\x9f', '\xa8',
951
        '\xb3', '\xb3', '\xb3', '\xb3', '\xb3', '\xb3', '\xb4', '\xba',
952
        '\xbf', '\xbf',
953
/* }; */
954
/* static const char C_locale_data[320] = { */
955
           '0', '\x00',    '1', '\x00',    '2', '\x00',    '3', '\x00',
956
           '4', '\x00',    '5', '\x00',    '6', '\x00',    '7', '\x00',
957
           '8', '\x00',    '9', '\x00',    'A',    'S',    'C',    'I',
958
           'I', '\x00',    '.', '\x00', '\x7f', '\x00',    '-', '\x00',
959
           'S',    'u',    'n', '\x00',    'M',    'o',    'n', '\x00',
960
           'T',    'u',    'e', '\x00',    'W',    'e',    'd', '\x00',
961
           'T',    'h',    'u', '\x00',    'F',    'r',    'i', '\x00',
962
           'S',    'a',    't', '\x00',    'S',    'u',    'n',    'd',
963
           'a',    'y', '\x00',    'M',    'o',    'n',    'd',    'a',
964
           'y', '\x00',    'T',    'u',    'e',    's',    'd',    'a',
965
           'y', '\x00',    'W',    'e',    'd',    'n',    'e',    's',
966
           'd',    'a',    'y', '\x00',    'T',    'h',    'u',    'r',
967
           's',    'd',    'a',    'y', '\x00',    'F',    'r',    'i',
968
           'd',    'a',    'y', '\x00',    'S',    'a',    't',    'u',
969
           'r',    'd',    'a',    'y', '\x00',    'J',    'a',    'n',
970
        '\x00',    'F',    'e',    'b', '\x00',    'M',    'a',    'r',
971
        '\x00',    'A',    'p',    'r', '\x00',    'M',    'a',    'y',
972
        '\x00',    'J',    'u',    'n', '\x00',    'J',    'u',    'l',
973
        '\x00',    'A',    'u',    'g', '\x00',    'S',    'e',    'p',
974
        '\x00',    'O',    'c',    't', '\x00',    'N',    'o',    'v',
975
        '\x00',    'D',    'e',    'c', '\x00',    'J',    'a',    'n',
976
           'u',    'a',    'r',    'y', '\x00',    'F',    'e',    'b',
977
           'r',    'u',    'a',    'r',    'y', '\x00',    'M',    'a',
978
           'r',    'c',    'h', '\x00',    'A',    'p',    'r',    'i',
979
           'l', '\x00',    'M',    'a',    'y', '\x00',    'J',    'u',
980
           'n',    'e', '\x00',    'J',    'u',    'l',    'y', '\x00',
981
           'A',    'u',    'g',    'u',    's',    't', '\x00',    'S',
982
           'e',    'p',    't',    'e',    'm',    'b',    'e',    'r',
983
        '\x00',    'O',    'c',    't',    'o',    'b',    'e',    'r',
984
        '\x00',    'N',    'o',    'v',    'e',    'm',    'b',    'e',
985
           'r', '\x00',    'D',    'e',    'c',    'e',    'm',    'b',
986
           'e',    'r', '\x00',    'A',    'M', '\x00',    'P',    'M',
987
        '\x00',    '%',    'a',    ' ',    '%',    'b',    ' ',    '%',
988
           'e',    ' ',    '%',    'H',    ':',    '%',    'M',    ':',
989
           '%',    'S',    ' ',    '%',    'Y', '\x00',    '%',    'm',
990
           '/',    '%',    'd',    '/',    '%',    'y', '\x00',    '%',
991
           'H',    ':',    '%',    'M',    ':',    '%',    'S', '\x00',
992
           '%',    'I',    ':',    '%',    'M',    ':',    '%',    'S',
993
           ' ',    '%',    'p', '\x00',    '^',    '[',    'y',    'Y',
994
           ']', '\x00',    '^',    '[',    'n',    'N',    ']', '\x00',
995
};
996
 
997
char *nl_langinfo(nl_item item)
998
{
999
        unsigned int c;
1000
        unsigned int i;
1001
 
1002
        if ((c = _NL_ITEM_CATEGORY(item)) < C_LC_ALL) {
1003
                if ((i = cat_start[c] + _NL_ITEM_INDEX(item)) < cat_start[c+1]) {
1004
/*                      return (char *) C_locale_data + item_offset[i] + (i & 64); */
1005
                        return (char *) C_locale_data + nl_data[C_LC_ALL+1+i] + 2*(i & 64);
1006
                }
1007
        }
1008
        return (char *) cat_start;      /* Conveniently, this is the empty string. */
1009
}
1010
 
1011
#else  /* __LOCALE_C_ONLY */
1012
 
1013
#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
1014
 
1015
char *nl_langinfo(nl_item item)
1016
{
1017
        return __nl_langinfo_l(item, __UCLIBC_CURLOCALE);
1018
}
1019
 
1020
#else  /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1021
 
1022
static const char empty[] = "";
1023
 
1024
char *__XL(nl_langinfo)(nl_item item   __LOCALE_PARAM )
1025
{
1026
        unsigned int c = _NL_ITEM_CATEGORY(item);
1027
        unsigned int i = _NL_ITEM_INDEX(item);
1028
 
1029
        if ((c < LC_ALL) && (i < __LOCALE_PTR->category_item_count[c])) {
1030
                return ((char **)(((char *) __LOCALE_PTR)
1031
                                                  + __LOCALE_PTR->category_offsets[c]))[i];
1032
        }
1033
 
1034
        return (char *) empty;
1035
}
1036
 
1037
#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1038
 
1039
#endif /* __LOCALE_C_ONLY */
1040
 
1041
#endif
1042
/**********************************************************************/
1043
#ifdef L_newlocale
1044
 
1045
#ifdef __UCLIBC_MJN3_ONLY__
1046
#warning TODO: Move posix and utf8 strings.
1047
#endif
1048
static const char posix[] = "POSIX";
1049
static const char utf8[] = "UTF-8";
1050
 
1051
static int find_locale(int category_mask, const char *p,
1052
                                           unsigned char *new_locale)
1053
{
1054
        int i;
1055
        const unsigned char *s;
1056
        uint16_t n;
1057
        unsigned char lang_cult, codeset;
1058
 
1059
#if defined(__LOCALE_DATA_AT_MODIFIERS_LENGTH) && 1
1060
        /* Support standard locale handling for @-modifiers. */
1061
 
1062
#ifdef __UCLIBC_MJN3_ONLY__
1063
#warning REMINDER: Fix buf size in find_locale.
1064
#endif
1065
        char buf[18];   /* TODO: 7+{max codeset name length} */
1066
        const char *q;
1067
 
1068
        if ((q = strchr(p,'@')) != NULL) {
1069
                if ((((size_t)((q-p)-5)) > (sizeof(buf) - 5)) || (p[2] != '_')) {
1070
                        return 0;
1071
                }
1072
                /* locale name at least 5 chars long and 3rd char is '_' */
1073
                s = LOCALE_AT_MODIFIERS;
1074
                do {
1075
                        if (!strcmp(s+2, q+1)) {
1076
                                break;
1077
                        }
1078
                        s += 2 + *s;            /* TODO - fix this throughout */
1079
                } while (*s);
1080
                if (!*s) {
1081
                        return 0;
1082
                }
1083
                assert(q - p < sizeof(buf));
1084
                memcpy(buf, p, q-p);
1085
                buf[q-p] = 0;
1086
                buf[2] = s[1];
1087
                p = buf;
1088
        }
1089
#endif
1090
 
1091
        lang_cult = codeset = 0; /* Assume C and default codeset.  */
1092
        if (((*p == 'C') && !p[1]) || !strcmp(p, posix)) {
1093
                goto FIND_LOCALE;
1094
        }
1095
 
1096
        if ((strlen(p) > 5) && (p[5] == '.')) { /* Codeset in locale name? */
1097
                /* TODO: maybe CODESET_LIST + *s ??? */
1098
                /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */
1099
                codeset = 2;
1100
                if (strcmp(utf8,p+6) != 0) {/* TODO - fix! */
1101
                        s = CODESET_LIST;
1102
                        do {
1103
                                ++codeset;              /* Increment codeset first. */
1104
                                if (!strcmp(CODESET_LIST+*s, p+6)) {
1105
                                        goto FIND_LANG_CULT;
1106
                                }
1107
                        } while (*++s);
1108
                        return 0;                        /* No matching codeset! */
1109
                }
1110
        }
1111
 
1112
 FIND_LANG_CULT:                                /* Find language_culture number. */
1113
        s = LOCALE_NAMES;
1114
        do {                                            /* TODO -- do a binary search? */
1115
                /* TODO -- fix gen_mmap!*/
1116
                ++lang_cult;                    /* Increment first since C/POSIX is 0. */
1117
                if (!strncmp(s,p,5)) { /* Found a matching locale name; */
1118
                        goto FIND_LOCALE;
1119
                }
1120
                s += 5;
1121
        } while (lang_cult < __LOCALE_DATA_NUM_LOCALE_NAMES);
1122
        return 0;                                        /* No matching language_culture! */
1123
 
1124
 FIND_LOCALE:                                   /* Find locale row matching name and codeset */
1125
        s = LOCALES;
1126
        n = 0;
1127
        do {                                            /* TODO -- do a binary search? */
1128
                if ((lang_cult == *s) && ((codeset == s[1]) || (codeset == s[2]))) {
1129
                        i = 1;
1130
                        s = new_locale + 1;
1131
                        do {
1132
                                if (category_mask & i) {
1133
                                        /* Encode current locale row number. */
1134
                                        ((unsigned char *) s)[0] = (n >> 7) | 0x80;
1135
                                        ((unsigned char *) s)[1] = (n & 0x7f) | 0x80;
1136
                                }
1137
                                s += 2;
1138
                                i += i;
1139
                        } while (i < (1 << LC_ALL));
1140
 
1141
                        return i;                       /* Return non-zero */
1142
                }
1143
                s += __LOCALE_DATA_WIDTH_LOCALES;
1144
                ++n;
1145
        } while (n <= __LOCALE_DATA_NUM_LOCALES); /* We started at 1!!! */
1146
 
1147
        return 0;                                        /* Unsupported locale. */
1148
}
1149
 
1150
static unsigned char *composite_locale(int category_mask, const char *locale,
1151
                                                                           unsigned char *new_locale)
1152
{
1153
        char buf[MAX_LOCALE_STR];
1154
        char *t;
1155
        char *e;
1156
        int c;
1157
        int component_mask;
1158
 
1159
        if (!strchr(locale,'=')) {
1160
                if (!find_locale(category_mask, locale, new_locale)) {
1161
                        return NULL;
1162
                }
1163
                return new_locale;
1164
        }
1165
 
1166
        if (strlen(locale) >= sizeof(buf)) {
1167
                return NULL;
1168
        }
1169
        stpcpy(buf, locale);
1170
 
1171
        component_mask = 0;
1172
        t = strtok_r(buf, "=", &e);     /* This can't fail because of strchr test above. */
1173
        do {
1174
                c = 0;
1175
                while (strcmp(CATEGORY_NAMES + (int) CATEGORY_NAMES[c], t)) {
1176
                        if (++c == LC_ALL) { /* Unknown category name! */
1177
                                return NULL;
1178
                        }
1179
                }
1180
                t = strtok_r(NULL, ";", &e);
1181
                c = (1 << c);
1182
                if (component_mask & c) { /* Multiple components for one category. */
1183
                        return NULL;
1184
                }
1185
                component_mask |= c;
1186
                if ((category_mask & c) && (!t || !find_locale(c, t, new_locale))) {
1187
                        return NULL;
1188
                }
1189
        } while ((t = strtok_r(NULL, "=", &e)) != NULL);
1190
 
1191
        if (category_mask & ~component_mask) { /* Category component(s) missing. */
1192
                return NULL;
1193
        }
1194
 
1195
        return new_locale;
1196
}
1197
 
1198
__locale_t __newlocale(int category_mask, const char *locale, __locale_t base)
1199
{
1200
        const unsigned char *p;
1201
        int i, j, k;
1202
        unsigned char new_selector[LOCALE_SELECTOR_SIZE];
1203
 
1204
        if (category_mask == (1 << LC_ALL)) {
1205
                category_mask = LC_ALL_MASK;
1206
        }
1207
 
1208
        if (!locale || (((unsigned int)(category_mask)) > LC_ALL_MASK)) {
1209
        INVALID:
1210
                __set_errno(EINVAL);
1211
                return NULL;  /* No locale or illegal/unsupported category. */
1212
        }
1213
 
1214
#ifdef __UCLIBC_MJN3_ONLY__
1215
#warning TODO: Rename cur_locale to locale_selector.
1216
#endif
1217
        strcpy((char *) new_selector,
1218
                   (base ? (char *) base->cur_locale : C_LOCALE_SELECTOR));
1219
 
1220
        if (!*locale) {                  /* locale == "", so check environment. */
1221
#ifndef __UCLIBC_HAS_THREADS__
1222
                static                          /* If no threads, then envstr can be static. */
1223
#endif /*  __UCLIBC_HAS_THREADS__ */
1224
                        const char *envstr[4] = { "LC_ALL", NULL, "LANG", posix };
1225
 
1226
                i = 1;
1227
                k = 0;
1228
                do {
1229
                        if (category_mask & i) {
1230
                                /* Note: SUSv3 doesn't define a fallback mechanism here.
1231
                                 * So, if LC_ALL is invalid, we do _not_ continue trying
1232
                                 * the other environment vars. */
1233
                                envstr[1] = CATEGORY_NAMES + CATEGORY_NAMES[k];
1234
                                j = 0;
1235
                                do {
1236
                                        p = envstr[j];
1237
                                } while ((++j < 4) && (!(p = getenv(p)) || !*p));
1238
 
1239
 
1240
                                /* The user set something... is it valid? */
1241
                                /* Note: Since we don't support user-supplied locales and
1242
                                 * alternate paths, we don't need to worry about special
1243
                                 * handling for suid/sgid apps. */
1244
                                if (!find_locale(i, p, new_selector)) {
1245
                                        goto INVALID;
1246
                                }
1247
                        }
1248
                        i += i;
1249
                } while (++k < LC_ALL);
1250
        } else if (!composite_locale(category_mask, locale, new_selector)) {
1251
                goto INVALID;
1252
        }
1253
 
1254
#ifdef __UCLIBC_MJN3_ONLY__
1255
#warning TODO: Do a compatible codeset check!
1256
#endif
1257
 
1258
        /* If we get here, the new selector corresponds to a valid locale. */
1259
 
1260
#ifdef __UCLIBC_MJN3_ONLY__
1261
#warning CONSIDER: Probably want a _locale_new func to allow for caching of locales.
1262
#endif
1263
#if 0
1264
        if (base) {
1265
                _locale_set_l(new_selector, base);
1266
        } else {
1267
                base = _locale_new(new_selector);
1268
        }
1269
#else
1270
        if (!base) {
1271
                if ((base = malloc(sizeof(__uclibc_locale_t))) == NULL) {
1272
                        return base;
1273
                }
1274
                _locale_init_l(base);
1275
        }
1276
 
1277
        _locale_set_l(new_selector, base);
1278
#endif
1279
 
1280
        return base;
1281
}
1282
 
1283
weak_alias(__newlocale, newlocale)
1284
 
1285
#endif
1286
/**********************************************************************/
1287
#ifdef L_duplocale
1288
 
1289
#ifdef __UCLIBC_MJN3_ONLY__
1290
#warning REMINDER: When we allocate ctype tables, remember to dup them.
1291
#endif
1292
 
1293
__locale_t __duplocale(__locale_t dataset)
1294
{
1295
        __locale_t r;
1296
        uint16_t * i2w;
1297
        size_t n;
1298
 
1299
        assert(dataset != LC_GLOBAL_LOCALE);
1300
 
1301
        if ((r = malloc(sizeof(__uclibc_locale_t))) != NULL) {
1302
                n = 2*dataset->collate.max_col_index+2;
1303
                if ((i2w = calloc(n, sizeof(uint16_t)))
1304
                        != NULL
1305
                        ) {
1306
                        memcpy(r, dataset, sizeof(__uclibc_locale_t));
1307
                        r->collate.index2weight = i2w;
1308
                        memcpy(i2w, dataset->collate.index2weight, n * sizeof(uint16_t));
1309
                } else {
1310
                        free(r);
1311
                        r = NULL;
1312
                }
1313
        }
1314
        return r;
1315
}
1316
 
1317
weak_alias(__duplocale, duplocale)
1318
 
1319
#endif
1320
/**********************************************************************/
1321
#ifdef L_freelocale
1322
 
1323
#ifdef __UCLIBC_MJN3_ONLY__
1324
#warning REMINDER: When we allocate ctype tables, remember to free them.
1325
#endif
1326
 
1327
void __freelocale(__locale_t dataset)
1328
{
1329
        assert(dataset != __global_locale);
1330
        assert(dataset != LC_GLOBAL_LOCALE);
1331
 
1332
        free(dataset->collate.index2weight); /* Free collation data. */
1333
        free(dataset);                          /* Free locale */
1334
}
1335
 
1336
weak_alias(__freelocale, freelocale)
1337
 
1338
#endif
1339
/**********************************************************************/
1340
#ifdef L_uselocale
1341
 
1342
__locale_t __uselocale(__locale_t dataset)
1343
{
1344
        __locale_t old;
1345
 
1346
        if (!dataset) {
1347
                old = __UCLIBC_CURLOCALE;
1348
        } else {
1349
                if (dataset == LC_GLOBAL_LOCALE) {
1350
                        dataset = __global_locale;
1351
                }
1352
#ifdef __UCLIBC_HAS_THREADS__
1353
                old = __curlocale_set(dataset);
1354
#else
1355
                old = __curlocale_var;
1356
                __curlocale_var = dataset;
1357
#endif
1358
        }
1359
 
1360
        if (old == __global_locale) {
1361
                return LC_GLOBAL_LOCALE;
1362
        }
1363
        return old;
1364
}
1365
 
1366
weak_alias(__uselocale, uselocale)
1367
 
1368
#endif
1369
/**********************************************************************/
1370
#ifdef L___curlocale
1371
 
1372
#ifdef __UCLIBC_HAS_THREADS__
1373
 
1374
__locale_t weak_const_function __curlocale(void)
1375
{
1376
    return __curlocale_var; /* This is overriden by the thread version. */
1377
}
1378
 
1379
__locale_t weak_function __curlocale_set(__locale_t newloc)
1380
{
1381
        __locale_t oldloc = __curlocale_var;
1382
        assert(newloc != LC_GLOBAL_LOCALE);
1383
        __curlocale_var = newloc;
1384
        return oldloc;
1385
}
1386
 
1387
#endif
1388
 
1389
#endif
1390
/**********************************************************************/
1391
#ifdef L___locale_mbrtowc_l
1392
 
1393
/* NOTE: This returns an int... not size_t.  Also, it is not a general
1394
 * routine.  It is actually a very stripped-down version of mbrtowc
1395
 * that takes a __locale_t arg.  This is used by strcoll and strxfrm.
1396
 * It is also used above to generate wchar_t versions of the decimal point
1397
 * and thousands seperator. */
1398
 
1399
 
1400
#ifndef __CTYPE_HAS_UTF_8_LOCALES
1401
#warning __CTYPE_HAS_UTF_8_LOCALES not set!
1402
#endif
1403
#ifndef __CTYPE_HAS_8_BIT_LOCALES
1404
#warning __CTYPE_HAS_8_BIT_LOCALES not set!
1405
#endif
1406
 
1407
#define Cc2wc_IDX_SHIFT         __LOCALE_DATA_Cc2wc_IDX_SHIFT
1408
#define Cc2wc_ROW_LEN           __LOCALE_DATA_Cc2wc_ROW_LEN
1409
 
1410
extern size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
1411
                                                                 const char **__restrict src, size_t n,
1412
                                                                 mbstate_t *ps, int allow_continuation);
1413
 
1414
int __locale_mbrtowc_l(wchar_t *__restrict dst,
1415
                                           const char *__restrict src,
1416
                                           __locale_t loc )
1417
{
1418
#ifdef __CTYPE_HAS_UTF_8_LOCALES
1419
        if (loc->encoding == __ctype_encoding_utf8) {
1420
                mbstate_t ps;
1421
                const char *p = src;
1422
                size_t r;
1423
                ps.mask = 0;
1424
                r = _wchar_utf8sntowcs(dst, 1, &p, SIZE_MAX, &ps, 1);
1425
                return (r == 1) ? (p-src) : r; /* Need to return 0 if nul char. */
1426
        }
1427
#endif
1428
 
1429
#ifdef __CTYPE_HAS_8_BIT_LOCALES
1430
        assert((loc->encoding == __ctype_encoding_7_bit) || (loc->encoding == __ctype_encoding_8_bit));
1431
#else
1432
        assert(loc->encoding == __ctype_encoding_7_bit);
1433
#endif
1434
 
1435
        if ((*dst = ((unsigned char)(*src))) < 0x80) {  /* ASCII... */
1436
                return (*src != 0);
1437
        }
1438
 
1439
#ifdef __CTYPE_HAS_8_BIT_LOCALES
1440
        if (loc->encoding == __ctype_encoding_8_bit) {
1441
                wchar_t wc = *dst - 0x80;
1442
                *dst = loc->tbl8c2wc[
1443
                                                (loc->idx8c2wc[wc >> Cc2wc_IDX_SHIFT]
1444
                                                 << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))];
1445
                if (*dst) {
1446
                        return 1;
1447
                }
1448
        }
1449
#endif
1450
 
1451
        return -1;
1452
}
1453
 
1454
#endif
1455
/**********************************************************************/

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.