1 /* Copyright (C) 2002 Manuel Novoa III
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.
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.
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.
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.
26 * Added in collation support and updated stub nl_langinfo.
29 * Added glibc-like extended locale stuff (newlocale, duplocale, etc).
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.
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++.
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).
51 #define __CTYPE_HAS_8_BIT_LOCALES 1
63 libc_hidden_proto(memcpy)
64 libc_hidden_proto(memset)
65 libc_hidden_proto(stpcpy)
66 libc_hidden_proto(strtok_r)
67 libc_hidden_proto(strlen)
68 libc_hidden_proto(strcmp)
69 libc_hidden_proto(strcpy)
70 libc_hidden_proto(strncmp)
71 libc_hidden_proto(strchr)
72 libc_hidden_proto(getenv)
73 /*libc_hidden_proto(fflush)*/
75 #ifdef __UCLIBC_MJN3_ONLY__
77 #warning TODO: Make the link_warning()s a config option?
81 #define link_warning(A,B)
83 #undef __LOCALE_C_ONLY
84 #ifndef __UCLIBC_HAS_LOCALE__
85 #define __LOCALE_C_ONLY
86 #endif /* __UCLIBC_HAS_LOCALE__ */
89 #ifdef __LOCALE_C_ONLY
93 #else /* __LOCALE_C_ONLY */
95 #ifdef __UCLIBC_MJN3_ONLY__
97 #warning TODO: Fix the __CTYPE_HAS_8_BIT_LOCALES define at the top of the file.
98 #warning TODO: Fix __WCHAR_ENABLED.
102 /* Need to include this before locale.h and xlocale.h! */
103 #include <bits/uClibc_locale.h>
106 #define CODESET_LIST (__locale_mmap->codeset_list)
108 #ifdef __UCLIBC_HAS_XLOCALE__
111 #else /* __UCLIBC_HAS_XLOCALE__ */
112 /* We need this internally... */
113 #define __UCLIBC_HAS_XLOCALE__ 1
116 #undef __UCLIBC_HAS_XLOCALE__
117 #endif /* __UCLIBC_HAS_XLOCALE__ */
121 #define LOCALE_NAMES (__locale_mmap->locale_names5)
122 #define LOCALES (__locale_mmap->locales)
123 #define LOCALE_AT_MODIFIERS (__locale_mmap->locale_at_modifiers)
124 #define CATEGORY_NAMES (__locale_mmap->lc_names)
126 #ifdef __UCLIBC_MJN3_ONLY__
127 #warning REMINDER: redo the MAX_LOCALE_STR stuff...
129 #define MAX_LOCALE_STR 256 /* TODO: Only sufficient for current case. */
130 #define MAX_LOCALE_CATEGORY_STR 32 /* TODO: Only sufficient for current case. */
131 /* Note: Best if MAX_LOCALE_CATEGORY_STR is a power of 2. */
133 extern int _locale_set_l(const unsigned char *p, __locale_t base) attribute_hidden;
134 extern void _locale_init_l(__locale_t base) attribute_hidden;
136 #endif /* __LOCALE_C_ONLY */
138 #undef LOCALE_STRING_SIZE
139 #define LOCALE_SELECTOR_SIZE (2 * __LC_ALL + 2)
141 #ifdef __UCLIBC_MJN3_ONLY__
143 #warning TODO: Create a C locale selector string.
146 #define C_LOCALE_SELECTOR "\x23\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
149 #include <langinfo.h>
150 #include <nl_types.h>
152 /**********************************************************************/
155 #ifdef __LOCALE_C_ONLY
157 link_warning(setlocale,"REMINDER: The 'setlocale' function supports only C|POSIX locales.")
159 static const char C_string[] = "C";
161 char *setlocale(int category, register const char *locale)
163 return ( (((unsigned int)(category)) <= LC_ALL)
164 && ( (!locale) /* Request for locale category string. */
165 || (!*locale) /* Implementation-defined default is C. */
166 || ((*locale == 'C') && !locale[1])
167 || (!strcmp(locale, "POSIX"))) )
168 ? (char *) C_string /* Always in C/POSIX locale. */
172 #else /* ---------------------------------------------- __LOCALE_C_ONLY */
174 #ifdef __UCLIBC_HAS_THREADS__
175 link_warning(setlocale,"REMINDER: The 'setlocale' function is _not_ threadsafe except for simple queries.")
178 #if !defined(__LOCALE_DATA_NUM_LOCALES) || (__LOCALE_DATA_NUM_LOCALES <= 1)
179 #error locales enabled, but not data other than for C locale!
182 #ifdef __UCLIBC_MJN3_ONLY__
183 #warning TODO: Move posix and utf8 strings.
185 static const char posix[] = "POSIX";
186 static const char utf8[] = "UTF-8";
188 #ifdef __UCLIBC_MJN3_ONLY__
189 #warning TODO: Fix dimensions of hr_locale.
191 /* Individual category strings start at hr_locale + category * MAX_LOCALE_CATEGORY.
192 * This holds for LC_ALL as well.
194 static char hr_locale[(MAX_LOCALE_CATEGORY_STR * LC_ALL) + MAX_LOCALE_STR];
196 libc_hidden_proto(newlocale)
198 static void update_hr_locale(const unsigned char *spec)
200 const unsigned char *loc;
201 const unsigned char *s;
203 int i, category, done;
208 n = hr_locale + category * MAX_LOCALE_CATEGORY_STR;
210 if (category == LC_ALL) {
212 for (i = 0 ; i < LC_ALL-1 ; i += 2) {
213 if ((s[i] != s[i+2]) || (s[i+1] != s[i+3])) {
217 /* All categories the same, so simplify string by using a single
223 i = (category == LC_ALL) ? 0 : category;
227 if ((*s != 0xff) || (s[1] != 0xff)) {
229 + __LOCALE_DATA_WIDTH_LOCALES * ((((int)(*s & 0x7f)) << 7)
231 if (category == LC_ALL) {
232 n = stpcpy(n, CATEGORY_NAMES + (int) CATEGORY_NAMES[i]);
240 memcpy(n, LOCALE_NAMES + 5*((*loc)-1), 5);
249 } else if (loc[2] >= 3) {
250 n = stpcpy(n, CODESET_LIST + (int)(CODESET_LIST[loc[2] - 3]));
255 q = LOCALE_AT_MODIFIERS;
268 } while (++i < category);
269 *--n = 0; /* Remove trailing ';' and nul-terminate. */
275 char *setlocale(int category, const char *locale)
277 if (((unsigned int)(category)) > LC_ALL) {
279 __set_errno(EINVAL); /* glibc sets errno -- SUSv3 doesn't say. */
281 return NULL; /* Illegal/unsupported category. */
284 if (locale != NULL) { /* Not just a query... */
285 if (!newlocale((1 << category), locale, __global_locale)) {
286 return NULL; /* Failed! */
288 update_hr_locale(__global_locale->cur_locale);
291 /* Either a query or a successful set, so return current locale string. */
292 return hr_locale + (category * MAX_LOCALE_CATEGORY_STR);
295 #endif /* __LOCALE_C_ONLY */
298 /**********************************************************************/
301 /* Note: We assume here that the compiler does the sane thing regarding
302 * placement of the fields in the struct. If necessary, we could ensure
303 * this usings an array of offsets but at some size cost. */
305 #ifdef __LOCALE_C_ONLY
307 link_warning(localeconv,"REMINDER: The 'localeconv' function is hardwired for C/POSIX locale only.")
309 static struct lconv the_lconv;
311 static const char decpt[] = ".";
313 struct lconv *localeconv(void)
315 register char *p = (char *)(&the_lconv);
317 *((char **)p) = (char *) decpt;
319 p += sizeof(char **);
320 *((char **)p) = (char *) (decpt+1);
321 } while (p < (char *) &the_lconv.negative_sign);
323 p = (&the_lconv.int_frac_digits);
327 } while (p <= &the_lconv.int_n_sign_posn);
332 #else /* __LOCALE_C_ONLY */
334 static struct lconv the_lconv;
336 struct lconv *localeconv(void)
338 register char *p = (char *) &the_lconv;
339 register char **q = (char **) &(__UCLIBC_CURLOCALE_DATA).decimal_point;
343 p += sizeof(char **);
345 } while (p < &the_lconv.int_frac_digits);
351 } while (p <= &the_lconv.int_n_sign_posn);
356 #endif /* __LOCALE_C_ONLY */
359 /**********************************************************************/
360 #if defined(L__locale_init) && !defined(__LOCALE_C_ONLY)
362 __uclibc_locale_t __global_locale_data;
364 __locale_t __global_locale = &__global_locale_data;
366 #ifdef __UCLIBC_HAS_XLOCALE__
367 __locale_t __curlocale_var = &__global_locale_data;
370 /*----------------------------------------------------------------------*/
371 #ifdef __UCLIBC_MJN3_ONLY__
372 #warning TODO: Move utf8 and ascii strings.
374 static const char utf8[] = "UTF-8";
375 static const char ascii[] = "ASCII";
380 uint16_t MAX_WEIGHTS;
381 uint16_t num_index2weight;
382 #define num_index2ruleidx num_index2weight
383 uint16_t num_weightstr;
384 uint16_t num_multistart;
385 uint16_t num_override;
386 uint16_t num_ruletable;
390 uint16_t num_weights;
391 uint16_t num_starters;
397 uint16_t num_col_base;
398 uint16_t max_col_index;
399 uint16_t undefined_idx;
401 uint16_t range_count;
402 uint16_t range_base_weight;
403 uint16_t range_rule_offset;
405 uint16_t index2weight_offset;
406 uint16_t index2ruleidx_offset;
407 uint16_t multistart_offset;
408 uint16_t wcs2colidt_offset_low;
409 uint16_t wcs2colidt_offset_hi;
414 uint16_t undefined_idx;
415 uint16_t overrides_offset;
416 uint16_t multistart_offset;
419 static int init_cur_collate(int der_num, __collate_t *cur_collate)
421 const uint16_t *__locale_collate_tbl = __locale_mmap->collate_data;
422 coldata_header_t *cdh;
429 #ifdef __UCLIBC_MJN3_ONLY__
430 #warning kill of x86-specific asserts
433 assert(sizeof(coldata_base_t) == 19*2);
434 assert(sizeof(coldata_der_t) == 4*2);
435 assert(sizeof(coldata_header_t) == 8*2);
438 if (!der_num) { /* C locale... special */
439 cur_collate->num_weights = 0;
445 cdh = (coldata_header_t *) __locale_collate_tbl;
447 #ifdef __UCLIBC_MJN3_ONLY__
448 #warning CONSIDER: Should we assert here?
451 if (der_num >= cdh->num_der) {
455 assert((der_num < cdh->num_der));
458 cdd = (coldata_der_t *)(__locale_collate_tbl
459 + (sizeof(coldata_header_t)
460 + cdh->num_base * sizeof(coldata_base_t)
461 + der_num * sizeof(coldata_der_t)
464 cdb = (coldata_base_t *)(__locale_collate_tbl
465 + (sizeof(coldata_header_t)
466 + cdd->base_idx * sizeof(coldata_base_t)
469 memcpy(cur_collate, cdb, offsetof(coldata_base_t,index2weight_offset));
470 cur_collate->undefined_idx = cdd->undefined_idx;
472 cur_collate->ti_mask = (1 << cur_collate->ti_shift)-1;
473 cur_collate->ii_mask = (1 << cur_collate->ii_shift)-1;
475 /* fflush(stdout); */
476 /* fprintf(stderr,"base=%d num_col_base: %d %d\n", cdd->base_idx ,cur_collate->num_col_base, cdb->num_col_base); */
478 n = (sizeof(coldata_header_t) + cdh->num_base * sizeof(coldata_base_t)
479 + cdh->num_der * sizeof(coldata_der_t))/2;
481 /* fprintf(stderr,"n = %d\n", n); */
482 cur_collate->index2weight_tbl = __locale_collate_tbl + n + cdb->index2weight_offset;
483 /* fprintf(stderr,"i2w = %d\n", n + cdb->index2weight_offset); */
484 n += cdh->num_index2weight;
485 cur_collate->index2ruleidx_tbl = __locale_collate_tbl + n + cdb->index2ruleidx_offset;
486 /* fprintf(stderr,"i2r = %d\n", n + cdb->index2ruleidx_offset); */
487 n += cdh->num_index2ruleidx;
488 cur_collate->multistart_tbl = __locale_collate_tbl + n + cdd->multistart_offset;
489 /* fprintf(stderr,"mts = %d\n", n + cdb->multistart_offset); */
490 n += cdh->num_multistart;
491 cur_collate->overrides_tbl = __locale_collate_tbl + n + cdd->overrides_offset;
492 /* fprintf(stderr,"ovr = %d\n", n + cdd->overrides_offset); */
493 n += cdh->num_override;
494 cur_collate->ruletable = __locale_collate_tbl + n;
495 /* fprintf(stderr, "rtb = %d\n", n); */
496 n += cdh->num_ruletable;
497 cur_collate->weightstr = __locale_collate_tbl + n;
498 /* fprintf(stderr,"wts = %d\n", n); */
499 n += cdh->num_weightstr;
500 cur_collate->wcs2colidt_tbl = __locale_collate_tbl + n
501 + (((unsigned long)(cdb->wcs2colidt_offset_hi)) << 16)
502 + cdb->wcs2colidt_offset_low;
503 /* fprintf(stderr,"wcs = %lu\n", n + (((unsigned long)(cdb->wcs2colidt_offset_hi)) << 16) */
504 /* + cdb->wcs2colidt_offset_low); */
506 cur_collate->MAX_WEIGHTS = cdh->MAX_WEIGHTS;
508 #ifdef __UCLIBC_MJN3_ONLY__
509 #warning CONSIDER: Fix the +1 by increasing max_col_index?
510 #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
513 cur_collate->index2weight = calloc(2*cur_collate->max_col_index+2,
515 if (!cur_collate->index2weight) {
518 cur_collate->index2ruleidx = cur_collate->index2weight
519 + cur_collate->max_col_index + 1;
521 memcpy(cur_collate->index2weight, cur_collate->index2weight_tbl,
522 cur_collate->num_col_base * sizeof(uint16_t));
523 memcpy(cur_collate->index2ruleidx, cur_collate->index2ruleidx_tbl,
524 cur_collate->num_col_base * sizeof(uint16_t));
526 /* now do the overrides */
527 p = cur_collate->overrides_tbl;
529 /* fprintf(stderr, "processing override -- count = %d\n", *p); */
534 /* fprintf(stderr, " i=%d (%#x) w=%d *p=%d\n", i, i, w, *p); */
535 cur_collate->index2weight[i-1] = w++;
536 cur_collate->index2ruleidx[i-1] = *p++;
542 /* fprintf(stderr, " i=%d (%#x) w=%d *p=%d\n", i, i, p[1], p[2]); */
543 cur_collate->index2weight[i-1] = *++p;
544 cur_collate->index2ruleidx[i-1] = *++p;
548 for (i=0 ; i < cur_collate->multistart_tbl[0] ; i++) {
549 p = cur_collate->multistart_tbl;
550 /* fprintf(stderr, "%2d of %2d: %d ", i, cur_collate->multistart_tbl[0], p[i]); */
556 if (!*p) { /* found it */
557 /* fprintf(stderr, "found: n=%d (%#lx) |%.*ls|\n", n, (int) *cs->s, n, cs->s); */
558 /* fprintf(stderr, ": %d - single\n", n); */
561 /* the lookup check here is safe since we're assured that *p is a valid colidex */
562 /* fprintf(stderr, "lookup(%lc)==%d *p==%d\n", cs->s[n], lookup(cs->s[n]), (int) *p); */
563 /* fprintf(stderr, ": %d - ", n); */
565 /* fprintf(stderr, "%d|", *p); */
577 int attribute_hidden _locale_set_l(const unsigned char *p, __locale_t base)
580 unsigned char *s = base->cur_locale + 1;
582 const unsigned char *r;
585 const unsigned char *d;
586 int row; /* locale row */
587 int crow; /* category row */
595 newcol.index2weight = NULL;
596 if ((p[2*LC_COLLATE] != s[2*LC_COLLATE])
597 || (p[2*LC_COLLATE + 1] != s[2*LC_COLLATE + 1])
599 row = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f);
600 assert(row < __LOCALE_DATA_NUM_LOCALES);
601 if (!init_cur_collate(__locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES
602 * row + 3 + LC_COLLATE ],
605 return 0; /* calloc failed. */
607 free(base->collate.index2weight);
608 memcpy(&base->collate, &newcol, sizeof(__collate_t));
612 if ((*p != *s) || (p[1] != s[1])) {
613 row = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f);
614 assert(row < __LOCALE_DATA_NUM_LOCALES);
619 if ((i != LC_COLLATE)
620 && ((len = __locale_mmap->lc_common_item_offsets_LEN[i]) != 0)
622 crow = __locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES * row
626 x = (const char **)(((char *) base)
627 + base->category_offsets[i]);
629 stp = __locale_mmap->lc_common_tbl_offsets + 4*i;
630 r = (const unsigned char *)( ((char *)__locale_mmap) + *stp );
631 io = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
632 ii = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
633 d = (const unsigned char *)( ((char *)__locale_mmap) + *++stp );
634 for (c=0 ; c < len ; c++) {
635 *(x + c) = d + ii[ r[crow + c] + io[c] ];
639 c = __locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES * row
643 base->codeset = utf8;
644 base->encoding = __ctype_encoding_utf8;
645 /* TODO - fix for bcc */
646 base->mb_cur_max = 6;
649 base->codeset = ascii;
650 base->encoding = __ctype_encoding_7_bit;
651 base->mb_cur_max = 1;
654 const __codeset_8_bit_t *c8b;
656 base->codeset = r + r[c -= 3];
657 base->encoding = __ctype_encoding_8_bit;
658 #ifdef __UCLIBC_MJN3_ONLY__
659 #warning REMINDER: update 8 bit mb_cur_max when translit implemented!
661 /* TODO - update when translit implemented! */
662 base->mb_cur_max = 1;
663 c8b = __locale_mmap->codeset_8_bit + c;
664 #ifdef __CTYPE_HAS_8_BIT_LOCALES
665 base->idx8ctype = c8b->idx8ctype;
666 base->idx8uplow = c8b->idx8uplow;
667 #ifdef __UCLIBC_HAS_WCHAR__
668 base->idx8c2wc = c8b->idx8c2wc;
669 base->idx8wc2c = c8b->idx8wc2c;
671 #endif /* __UCLIBC_HAS_WCHAR__ */
673 /* What follows is fairly bloated, but it is just a hack
674 * to get the 8-bit codeset ctype stuff functioning.
675 * All of this will be replaced in the next generation
676 * of locale support anyway... */
678 memcpy(base->__ctype_b_data,
679 __C_ctype_b - __UCLIBC_CTYPE_B_TBL_OFFSET,
680 (256 + __UCLIBC_CTYPE_B_TBL_OFFSET)
681 * sizeof(__ctype_mask_t));
682 memcpy(base->__ctype_tolower_data,
683 __C_ctype_tolower - __UCLIBC_CTYPE_TO_TBL_OFFSET,
684 (256 + __UCLIBC_CTYPE_TO_TBL_OFFSET)
685 * sizeof(__ctype_touplow_t));
686 memcpy(base->__ctype_toupper_data,
687 __C_ctype_toupper - __UCLIBC_CTYPE_TO_TBL_OFFSET,
688 (256 + __UCLIBC_CTYPE_TO_TBL_OFFSET)
689 * sizeof(__ctype_touplow_t));
691 #define Cctype_TBL_MASK ((1 << __LOCALE_DATA_Cctype_IDX_SHIFT) - 1)
692 #define Cctype_IDX_OFFSET (128 >> __LOCALE_DATA_Cctype_IDX_SHIFT)
698 for (u=0 ; u < 128 ; u++) {
699 #ifdef __LOCALE_DATA_Cctype_PACKED
701 [ ((int)(c8b->idx8ctype
702 [(u >> __LOCALE_DATA_Cctype_IDX_SHIFT) ])
703 << (__LOCALE_DATA_Cctype_IDX_SHIFT - 1))
704 + ((u & Cctype_TBL_MASK) >> 1)];
705 c = (u & 1) ? (c >> 4) : (c & 0xf);
708 [ ((int)(c8b->idx8ctype
709 [(u >> __LOCALE_DATA_Cctype_IDX_SHIFT) ])
710 << __LOCALE_DATA_Cctype_IDX_SHIFT)
711 + (u & Cctype_TBL_MASK) ];
714 m = base->code2flag[c];
717 [128 + __UCLIBC_CTYPE_B_TBL_OFFSET + u]
720 #ifdef __UCLIBC_HAS_CTYPE_SIGNED__
721 if (((signed char)(128 + u)) != -1) {
722 base->__ctype_b_data[__UCLIBC_CTYPE_B_TBL_OFFSET
723 + ((signed char)(128 + u))]
728 base->__ctype_tolower_data
729 [128 + __UCLIBC_CTYPE_TO_TBL_OFFSET + u]
731 base->__ctype_toupper_data
732 [128 + __UCLIBC_CTYPE_TO_TBL_OFFSET + u]
735 if (m & (_ISlower|_ISupper)) {
737 [ ((int)(c8b->idx8uplow
738 [u >> __LOCALE_DATA_Cuplow_IDX_SHIFT])
739 << __LOCALE_DATA_Cuplow_IDX_SHIFT)
741 & ((1 << __LOCALE_DATA_Cuplow_IDX_SHIFT)
744 base->__ctype_toupper_data
745 [128 + __UCLIBC_CTYPE_TO_TBL_OFFSET + u]
746 = (unsigned char)(128 + u + c);
747 #ifdef __UCLIBC_HAS_CTYPE_SIGNED__
748 if (((signed char)(128 + u)) != -1) {
749 base->__ctype_toupper_data
750 [__UCLIBC_CTYPE_TO_TBL_OFFSET
751 + ((signed char)(128 + u))]
752 = (unsigned char)(128 + u + c);
756 base->__ctype_tolower_data
757 [128 + __UCLIBC_CTYPE_TO_TBL_OFFSET + u]
758 = (unsigned char)(128 + u - c);
759 #ifdef __UCLIBC_HAS_CTYPE_SIGNED__
760 if (((signed char)(128 + u)) != -1) {
761 base->__ctype_tolower_data
762 [__UCLIBC_CTYPE_TO_TBL_OFFSET
763 + ((signed char)(128 + u))]
764 = (unsigned char)(128 + u - c);
772 #ifdef __UCLIBC_HAS_XLOCALE__
773 base->__ctype_b = base->__ctype_b_data
774 + __UCLIBC_CTYPE_B_TBL_OFFSET;
775 base->__ctype_tolower = base->__ctype_tolower_data
776 + __UCLIBC_CTYPE_TO_TBL_OFFSET;
777 base->__ctype_toupper = base->__ctype_toupper_data
778 + __UCLIBC_CTYPE_TO_TBL_OFFSET;
779 #else /* __UCLIBC_HAS_XLOCALE__ */
780 __ctype_b = base->__ctype_b_data
781 + __UCLIBC_CTYPE_B_TBL_OFFSET;
782 __ctype_tolower = base->__ctype_tolower_data
783 + __UCLIBC_CTYPE_TO_TBL_OFFSET;
784 __ctype_toupper = base->__ctype_toupper_data
785 + __UCLIBC_CTYPE_TO_TBL_OFFSET;
786 #endif /* __UCLIBC_HAS_XLOCALE__ */
788 #endif /* __CTYPE_HAS_8_BIT_LOCALES */
790 #ifdef __UCLIBC_MJN3_ONLY__
791 #warning TODO: Put the outdigit string length in the locale_mmap object.
793 d = base->outdigit_length;
794 x = &base->outdigit0_mb;
795 for (c = 0 ; c < 10 ; c++) {
796 ((unsigned char *)d)[c] = strlen(x[c]);
799 } else if (i == LC_NUMERIC) {
800 assert(LC_NUMERIC > LC_CTYPE); /* Need ctype initialized. */
802 base->decimal_point_len
803 = __locale_mbrtowc_l(&base->decimal_point_wc,
804 base->decimal_point, base);
805 assert(base->decimal_point_len > 0);
806 assert(base->decimal_point[base->decimal_point_len] == 0);
808 if (*base->grouping) {
809 base->thousands_sep_len
810 = __locale_mbrtowc_l(&base->thousands_sep_wc,
811 base->thousands_sep, base);
813 #ifdef __UCLIBC_MJN3_ONLY__
814 #warning TODO: Remove hack involving grouping without a thousep char (bg_BG).
816 assert(base->thousands_sep_len >= 0);
817 if (base->thousands_sep_len == 0) {
818 base->grouping = base->thousands_sep; /* empty string */
820 assert(base->thousands_sep[base->thousands_sep_len] == 0);
822 assert(base->thousands_sep_len > 0);
823 assert(base->thousands_sep[base->thousands_sep_len] == 0);
827 /* } else if (i == LC_COLLATE) { */
828 /* init_cur_collate(__locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES */
829 /* * row + 3 + i ], */
830 /* &base->collate); */
836 } while (i < LC_ALL);
841 static const uint16_t __code2flag[16] = {
842 0, /* unclassified = 0 */
843 _ISprint|_ISgraph|_ISalnum|_ISalpha, /* alpha_nonupper_nonlower */
844 _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, /* alpha_lower */
845 _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower|_ISupper, /* alpha_upper_lower */
846 _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, /* alpha_upper */
847 _ISprint|_ISgraph|_ISalnum|_ISdigit, /* digit */
848 _ISprint|_ISgraph|_ISpunct, /* punct */
849 _ISprint|_ISgraph, /* graph */
850 _ISprint|_ISspace, /* print_space_nonblank */
851 _ISprint|_ISspace|_ISblank, /* print_space_blank */
852 _ISspace, /* space_nonblank_noncntrl */
853 _ISspace|_ISblank, /* space_blank_noncntrl */
854 _IScntrl|_ISspace, /* cntrl_space_nonblank */
855 _IScntrl|_ISspace|_ISblank, /* cntrl_space_blank */
856 _IScntrl /* cntrl_nonspace */
859 void attribute_hidden _locale_init_l(__locale_t base)
861 memset(base->cur_locale, 0, LOCALE_SELECTOR_SIZE);
862 base->cur_locale[0] = '#';
864 memcpy(base->category_item_count,
865 __locale_mmap->lc_common_item_offsets_LEN,
868 ++base->category_item_count[0]; /* Increment for codeset entry. */
869 base->category_offsets[0] = offsetof(__uclibc_locale_t, outdigit0_mb);
870 base->category_offsets[1] = offsetof(__uclibc_locale_t, decimal_point);
871 base->category_offsets[2] = offsetof(__uclibc_locale_t, int_curr_symbol);
872 base->category_offsets[3] = offsetof(__uclibc_locale_t, abday_1);
873 /* base->category_offsets[4] = offsetof(__uclibc_locale_t, collate???); */
874 base->category_offsets[5] = offsetof(__uclibc_locale_t, yesexpr);
876 #ifdef __CTYPE_HAS_8_BIT_LOCALES
878 = (const unsigned char *) &__locale_mmap->tbl8ctype;
880 = (const unsigned char *) &__locale_mmap->tbl8uplow;
881 #ifdef __UCLIBC_HAS_WCHAR__
883 = (const uint16_t *) &__locale_mmap->tbl8c2wc;
885 = (const unsigned char *) &__locale_mmap->tbl8wc2c;
887 #endif /* __UCLIBC_HAS_WCHAR__ */
888 #endif /* __CTYPE_HAS_8_BIT_LOCALES */
889 #ifdef __UCLIBC_HAS_WCHAR__
891 = (const unsigned char *) &__locale_mmap->tblwctype;
893 = (const unsigned char *) &__locale_mmap->tblwuplow;
895 = (const uint16_t *) &__locale_mmap->tblwuplow_diff;
897 /* = (const unsigned char *) &__locale_mmap->tblwcomb; */
899 #endif /* __UCLIBC_HAS_WCHAR__ */
901 /* Initially, set things up to use the global C ctype tables.
902 * This is correct for C (ASCII) and UTF-8 based locales (except tr_TR). */
903 #ifdef __UCLIBC_HAS_XLOCALE__
904 base->__ctype_b = __C_ctype_b;
905 base->__ctype_tolower = __C_ctype_tolower;
906 base->__ctype_toupper = __C_ctype_toupper;
907 #else /* __UCLIBC_HAS_XLOCALE__ */
908 __ctype_b = __C_ctype_b;
909 __ctype_tolower = __C_ctype_tolower;
910 __ctype_toupper = __C_ctype_toupper;
911 #endif /* __UCLIBC_HAS_XLOCALE__ */
913 #ifdef __UCLIBC_MJN3_ONLY__
914 #warning TODO: Initialize code2flag correctly based on locale_mmap.
916 base->code2flag = __code2flag;
919 _locale_set_l(C_LOCALE_SELECTOR, base);
922 void attribute_hidden _locale_init(void)
924 /* TODO: mmap the locale file */
927 _locale_init_l(__global_locale);
931 /**********************************************************************/
932 #if defined(L_nl_langinfo) || defined(L_nl_langinfo_l)
934 #ifdef __LOCALE_C_ONLY
936 /* We need to index 320 bytes of data, so you might initially think we
937 * need to store the offsets in shorts. But since the offset of the
938 * 64th item is 182, we'll store "offset - 2*64" for all items >= 64
939 * and always calculate the data offset as "offset[i] + 2*(i & 64)".
940 * This allows us to pack the data offsets in an unsigned char while
941 * also avoiding an "if".
943 * Note: Category order is assumed to be:
944 * ctype, numeric, monetary, time, collate, messages, all
949 /* Combine the data to avoid size penalty for seperate char arrays when
950 * compiler aligns objects. The original code is left in as documentation. */
951 #define cat_start nl_data
952 #define C_locale_data (nl_data + C_LC_ALL + 1 + 90)
954 static const unsigned char nl_data[C_LC_ALL + 1 + 90 + 320] = {
955 /* static const char cat_start[LC_ALL + 1] = { */
956 '\x00', '\x0b', '\x0e', '\x24', '\x56', '\x56', '\x5a',
958 /* static const char item_offset[90] = { */
959 '\x00', '\x02', '\x04', '\x06', '\x08', '\x0a', '\x0c', '\x0e',
960 '\x10', '\x12', '\x14', '\x1a', '\x1b', '\x1b', '\x1b', '\x1b',
961 '\x1b', '\x1b', '\x1b', '\x1b', '\x1b', '\x1c', '\x1c', '\x1c',
962 '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c',
963 '\x1c', '\x1c', '\x1c', '\x1e', '\x20', '\x24', '\x28', '\x2c',
964 '\x30', '\x34', '\x38', '\x3c', '\x43', '\x4a', '\x52', '\x5c',
965 '\x65', '\x6c', '\x75', '\x79', '\x7d', '\x81', '\x85', '\x89',
966 '\x8d', '\x91', '\x95', '\x99', '\x9d', '\xa1', '\xa5', '\xad',
967 '\x36', '\x3c', '\x42', '\x46', '\x4b', '\x50', '\x57', '\x61',
968 '\x69', '\x72', '\x7b', '\x7e', '\x81', '\x96', '\x9f', '\xa8',
969 '\xb3', '\xb3', '\xb3', '\xb3', '\xb3', '\xb3', '\xb4', '\xba',
972 /* static const char C_locale_data[320] = { */
973 '0', '\x00', '1', '\x00', '2', '\x00', '3', '\x00',
974 '4', '\x00', '5', '\x00', '6', '\x00', '7', '\x00',
975 '8', '\x00', '9', '\x00', 'A', 'S', 'C', 'I',
976 'I', '\x00', '.', '\x00', '\x7f', '\x00', '-', '\x00',
977 'S', 'u', 'n', '\x00', 'M', 'o', 'n', '\x00',
978 'T', 'u', 'e', '\x00', 'W', 'e', 'd', '\x00',
979 'T', 'h', 'u', '\x00', 'F', 'r', 'i', '\x00',
980 'S', 'a', 't', '\x00', 'S', 'u', 'n', 'd',
981 'a', 'y', '\x00', 'M', 'o', 'n', 'd', 'a',
982 'y', '\x00', 'T', 'u', 'e', 's', 'd', 'a',
983 'y', '\x00', 'W', 'e', 'd', 'n', 'e', 's',
984 'd', 'a', 'y', '\x00', 'T', 'h', 'u', 'r',
985 's', 'd', 'a', 'y', '\x00', 'F', 'r', 'i',
986 'd', 'a', 'y', '\x00', 'S', 'a', 't', 'u',
987 'r', 'd', 'a', 'y', '\x00', 'J', 'a', 'n',
988 '\x00', 'F', 'e', 'b', '\x00', 'M', 'a', 'r',
989 '\x00', 'A', 'p', 'r', '\x00', 'M', 'a', 'y',
990 '\x00', 'J', 'u', 'n', '\x00', 'J', 'u', 'l',
991 '\x00', 'A', 'u', 'g', '\x00', 'S', 'e', 'p',
992 '\x00', 'O', 'c', 't', '\x00', 'N', 'o', 'v',
993 '\x00', 'D', 'e', 'c', '\x00', 'J', 'a', 'n',
994 'u', 'a', 'r', 'y', '\x00', 'F', 'e', 'b',
995 'r', 'u', 'a', 'r', 'y', '\x00', 'M', 'a',
996 'r', 'c', 'h', '\x00', 'A', 'p', 'r', 'i',
997 'l', '\x00', 'M', 'a', 'y', '\x00', 'J', 'u',
998 'n', 'e', '\x00', 'J', 'u', 'l', 'y', '\x00',
999 'A', 'u', 'g', 'u', 's', 't', '\x00', 'S',
1000 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r',
1001 '\x00', 'O', 'c', 't', 'o', 'b', 'e', 'r',
1002 '\x00', 'N', 'o', 'v', 'e', 'm', 'b', 'e',
1003 'r', '\x00', 'D', 'e', 'c', 'e', 'm', 'b',
1004 'e', 'r', '\x00', 'A', 'M', '\x00', 'P', 'M',
1005 '\x00', '%', 'a', ' ', '%', 'b', ' ', '%',
1006 'e', ' ', '%', 'H', ':', '%', 'M', ':',
1007 '%', 'S', ' ', '%', 'Y', '\x00', '%', 'm',
1008 '/', '%', 'd', '/', '%', 'y', '\x00', '%',
1009 'H', ':', '%', 'M', ':', '%', 'S', '\x00',
1010 '%', 'I', ':', '%', 'M', ':', '%', 'S',
1011 ' ', '%', 'p', '\x00', '^', '[', 'y', 'Y',
1012 ']', '\x00', '^', '[', 'n', 'N', ']', '\x00',
1015 char *nl_langinfo(nl_item item)
1020 if ((c = _NL_ITEM_CATEGORY(item)) < C_LC_ALL) {
1021 if ((i = cat_start[c] + _NL_ITEM_INDEX(item)) < cat_start[c+1]) {
1022 /* return (char *) C_locale_data + item_offset[i] + (i & 64); */
1023 return (char *) C_locale_data + nl_data[C_LC_ALL+1+i] + 2*(i & 64);
1026 return (char *) cat_start; /* Conveniently, this is the empty string. */
1028 libc_hidden_proto(nl_langinfo)
1029 libc_hidden_def(nl_langinfo)
1031 #else /* __LOCALE_C_ONLY */
1033 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
1035 libc_hidden_proto(nl_langinfo_l)
1037 char *nl_langinfo(nl_item item)
1039 return nl_langinfo_l(item, __UCLIBC_CURLOCALE);
1041 libc_hidden_proto(nl_langinfo)
1042 libc_hidden_def(nl_langinfo)
1044 #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1046 static const char empty[] = "";
1048 char *__XL_NPP(nl_langinfo)(nl_item item __LOCALE_PARAM )
1050 unsigned int c = _NL_ITEM_CATEGORY(item);
1051 unsigned int i = _NL_ITEM_INDEX(item);
1053 if ((c < LC_ALL) && (i < __LOCALE_PTR->category_item_count[c])) {
1054 return ((char **)(((char *) __LOCALE_PTR)
1055 + __LOCALE_PTR->category_offsets[c]))[i];
1058 return (char *) empty;
1060 libc_hidden_proto(__XL_NPP(nl_langinfo))
1061 libc_hidden_def(__XL_NPP(nl_langinfo))
1063 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1065 #endif /* __LOCALE_C_ONLY */
1068 /**********************************************************************/
1071 #ifdef __UCLIBC_MJN3_ONLY__
1072 #warning TODO: Move posix and utf8 strings.
1074 static const char posix[] = "POSIX";
1075 static const char utf8[] = "UTF-8";
1077 static int find_locale(int category_mask, const char *p,
1078 unsigned char *new_locale)
1081 const unsigned char *s;
1083 unsigned char lang_cult, codeset;
1085 #if defined(__LOCALE_DATA_AT_MODIFIERS_LENGTH) && 1
1086 /* Support standard locale handling for @-modifiers. */
1088 #ifdef __UCLIBC_MJN3_ONLY__
1089 #warning REMINDER: Fix buf size in find_locale.
1091 char buf[18]; /* TODO: 7+{max codeset name length} */
1094 if ((q = strchr(p,'@')) != NULL) {
1095 if ((((size_t)((q-p)-5)) > (sizeof(buf) - 5)) || (p[2] != '_')) {
1098 /* locale name at least 5 chars long and 3rd char is '_' */
1099 s = LOCALE_AT_MODIFIERS;
1101 if (!strcmp(s+2, q+1)) {
1104 s += 2 + *s; /* TODO - fix this throughout */
1109 assert(q - p < sizeof(buf));
1110 memcpy(buf, p, q-p);
1117 lang_cult = codeset = 0; /* Assume C and default codeset. */
1118 if (((*p == 'C') && !p[1]) || !strcmp(p, posix)) {
1122 if ((strlen(p) > 5) && (p[5] == '.')) { /* Codeset in locale name? */
1123 /* TODO: maybe CODESET_LIST + *s ??? */
1124 /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */
1126 if (strcmp(utf8,p+6) != 0) {/* TODO - fix! */
1129 ++codeset; /* Increment codeset first. */
1130 if (!strcmp(CODESET_LIST+*s, p+6)) {
1131 goto FIND_LANG_CULT;
1134 return 0; /* No matching codeset! */
1138 FIND_LANG_CULT: /* Find language_culture number. */
1140 do { /* TODO -- do a binary search? */
1141 /* TODO -- fix gen_mmap!*/
1142 ++lang_cult; /* Increment first since C/POSIX is 0. */
1143 if (!strncmp(s,p,5)) { /* Found a matching locale name; */
1147 } while (lang_cult < __LOCALE_DATA_NUM_LOCALE_NAMES);
1148 return 0; /* No matching language_culture! */
1150 FIND_LOCALE: /* Find locale row matching name and codeset */
1153 do { /* TODO -- do a binary search? */
1154 if ((lang_cult == *s) && ((codeset == s[1]) || (codeset == s[2]))) {
1158 if (category_mask & i) {
1159 /* Encode current locale row number. */
1160 ((unsigned char *) s)[0] = (n >> 7) | 0x80;
1161 ((unsigned char *) s)[1] = (n & 0x7f) | 0x80;
1165 } while (i < (1 << LC_ALL));
1167 return i; /* Return non-zero */
1169 s += __LOCALE_DATA_WIDTH_LOCALES;
1171 } while (n <= __LOCALE_DATA_NUM_LOCALES); /* We started at 1!!! */
1173 return 0; /* Unsupported locale. */
1176 static unsigned char *composite_locale(int category_mask, const char *locale,
1177 unsigned char *new_locale)
1179 char buf[MAX_LOCALE_STR];
1185 if (!strchr(locale,'=')) {
1186 if (!find_locale(category_mask, locale, new_locale)) {
1192 if (strlen(locale) >= sizeof(buf)) {
1195 stpcpy(buf, locale);
1198 t = strtok_r(buf, "=", &e); /* This can't fail because of strchr test above. */
1201 while (strcmp(CATEGORY_NAMES + (int) CATEGORY_NAMES[c], t)) {
1202 if (++c == LC_ALL) { /* Unknown category name! */
1206 t = strtok_r(NULL, ";", &e);
1208 if (component_mask & c) { /* Multiple components for one category. */
1211 component_mask |= c;
1212 if ((category_mask & c) && (!t || !find_locale(c, t, new_locale))) {
1215 } while ((t = strtok_r(NULL, "=", &e)) != NULL);
1217 if (category_mask & ~component_mask) { /* Category component(s) missing. */
1224 __locale_t newlocale(int category_mask, const char *locale, __locale_t base)
1226 const unsigned char *p;
1228 unsigned char new_selector[LOCALE_SELECTOR_SIZE];
1230 if (category_mask == (1 << LC_ALL)) {
1231 category_mask = LC_ALL_MASK;
1234 if (!locale || (((unsigned int)(category_mask)) > LC_ALL_MASK)) {
1236 __set_errno(EINVAL);
1237 return NULL; /* No locale or illegal/unsupported category. */
1240 #ifdef __UCLIBC_MJN3_ONLY__
1241 #warning TODO: Rename cur_locale to locale_selector.
1243 strcpy((char *) new_selector,
1244 (base ? (char *) base->cur_locale : C_LOCALE_SELECTOR));
1246 if (!*locale) { /* locale == "", so check environment. */
1247 #ifndef __UCLIBC_HAS_THREADS__
1248 static /* If no threads, then envstr can be static. */
1249 #endif /* __UCLIBC_HAS_THREADS__ */
1250 const char *envstr[4] = { "LC_ALL", NULL, "LANG", posix };
1255 if (category_mask & i) {
1256 /* Note: SUSv3 doesn't define a fallback mechanism here.
1257 * So, if LC_ALL is invalid, we do _not_ continue trying
1258 * the other environment vars. */
1259 envstr[1] = CATEGORY_NAMES + CATEGORY_NAMES[k];
1263 } while ((++j < 4) && (!(p = getenv(p)) || !*p));
1266 /* The user set something... is it valid? */
1267 /* Note: Since we don't support user-supplied locales and
1268 * alternate paths, we don't need to worry about special
1269 * handling for suid/sgid apps. */
1270 if (!find_locale(i, p, new_selector)) {
1275 } while (++k < LC_ALL);
1276 } else if (!composite_locale(category_mask, locale, new_selector)) {
1280 #ifdef __UCLIBC_MJN3_ONLY__
1281 #warning TODO: Do a compatible codeset check!
1284 /* If we get here, the new selector corresponds to a valid locale. */
1286 #ifdef __UCLIBC_MJN3_ONLY__
1287 #warning CONSIDER: Probably want a _locale_new func to allow for caching of locales.
1291 _locale_set_l(new_selector, base);
1293 base = _locale_new(new_selector);
1297 if ((base = malloc(sizeof(__uclibc_locale_t))) == NULL) {
1300 _locale_init_l(base);
1303 _locale_set_l(new_selector, base);
1308 libc_hidden_proto(newlocale)
1309 libc_hidden_def(newlocale)
1312 /**********************************************************************/
1315 #ifdef __UCLIBC_MJN3_ONLY__
1316 #warning REMINDER: When we allocate ctype tables, remember to dup them.
1319 __locale_t duplocale(__locale_t dataset)
1325 assert(dataset != LC_GLOBAL_LOCALE);
1327 if ((r = malloc(sizeof(__uclibc_locale_t))) != NULL) {
1328 n = 2*dataset->collate.max_col_index+2;
1329 if ((i2w = calloc(n, sizeof(uint16_t)))
1332 memcpy(r, dataset, sizeof(__uclibc_locale_t));
1333 r->collate.index2weight = i2w;
1334 memcpy(i2w, dataset->collate.index2weight, n * sizeof(uint16_t));
1342 libc_hidden_proto(duplocale)
1343 libc_hidden_def(duplocale)
1346 /**********************************************************************/
1349 #ifdef __UCLIBC_MJN3_ONLY__
1350 #warning REMINDER: When we allocate ctype tables, remember to free them.
1353 void freelocale(__locale_t dataset)
1355 assert(dataset != __global_locale);
1356 assert(dataset != LC_GLOBAL_LOCALE);
1358 free(dataset->collate.index2weight); /* Free collation data. */
1359 free(dataset); /* Free locale */
1363 /**********************************************************************/
1366 __locale_t uselocale(__locale_t dataset)
1371 old = __UCLIBC_CURLOCALE;
1373 if (dataset == LC_GLOBAL_LOCALE) {
1374 dataset = __global_locale;
1376 #ifdef __UCLIBC_HAS_THREADS__
1377 old = __curlocale_set(dataset);
1379 old = __curlocale_var;
1380 __curlocale_var = dataset;
1384 if (old == __global_locale) {
1385 return LC_GLOBAL_LOCALE;
1389 libc_hidden_proto(uselocale)
1390 libc_hidden_def(uselocale)
1393 /**********************************************************************/
1394 #ifdef L___curlocale
1396 #ifdef __UCLIBC_HAS_THREADS__
1398 __locale_t weak_const_function __curlocale(void)
1400 return __curlocale_var; /* This is overriden by the thread version. */
1403 __locale_t weak_function __curlocale_set(__locale_t newloc)
1405 __locale_t oldloc = __curlocale_var;
1406 assert(newloc != LC_GLOBAL_LOCALE);
1407 __curlocale_var = newloc;
1414 /**********************************************************************/
1415 #ifdef L___locale_mbrtowc_l
1417 /* NOTE: This returns an int... not size_t. Also, it is not a general
1418 * routine. It is actually a very stripped-down version of mbrtowc
1419 * that takes a __locale_t arg. This is used by strcoll and strxfrm.
1420 * It is also used above to generate wchar_t versions of the decimal point
1421 * and thousands seperator. */
1424 #ifndef __CTYPE_HAS_UTF_8_LOCALES
1425 #warning __CTYPE_HAS_UTF_8_LOCALES not set!
1427 #ifndef __CTYPE_HAS_8_BIT_LOCALES
1428 #warning __CTYPE_HAS_8_BIT_LOCALES not set!
1431 #define Cc2wc_IDX_SHIFT __LOCALE_DATA_Cc2wc_IDX_SHIFT
1432 #define Cc2wc_ROW_LEN __LOCALE_DATA_Cc2wc_ROW_LEN
1434 extern size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
1435 const char **__restrict src, size_t n,
1436 mbstate_t *ps, int allow_continuation) attribute_hidden;
1438 int attribute_hidden __locale_mbrtowc_l(wchar_t *__restrict dst,
1439 const char *__restrict src,
1442 #ifdef __CTYPE_HAS_UTF_8_LOCALES
1443 if (loc->encoding == __ctype_encoding_utf8) {
1445 const char *p = src;
1448 r = _wchar_utf8sntowcs(dst, 1, &p, SIZE_MAX, &ps, 1);
1449 return (r == 1) ? (p-src) : r; /* Need to return 0 if nul char. */
1453 #ifdef __CTYPE_HAS_8_BIT_LOCALES
1454 assert((loc->encoding == __ctype_encoding_7_bit) || (loc->encoding == __ctype_encoding_8_bit));
1456 assert(loc->encoding == __ctype_encoding_7_bit);
1459 if ((*dst = ((unsigned char)(*src))) < 0x80) { /* ASCII... */
1463 #ifdef __CTYPE_HAS_8_BIT_LOCALES
1464 if (loc->encoding == __ctype_encoding_8_bit) {
1465 wchar_t wc = *dst - 0x80;
1466 *dst = loc->tbl8c2wc[
1467 (loc->idx8c2wc[wc >> Cc2wc_IDX_SHIFT]
1468 << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))];
1479 /**********************************************************************/