/* Copyright (C) 2002 Manuel Novoa III * From my (incomplete) stdlib library for linux and (soon) elks. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! * * This code is currently under development. Also, I plan to port * it to elks which is a 16-bit environment with a fairly limited * compiler. Therefore, please refrain from modifying this code * and, instead, pass any bug-fixes, etc. to me. Thanks. Manuel * * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */ /* Oct 29, 2002 * Fix a couple of 'restrict' bugs in mbstowcs and wcstombs. * * Nov 21, 2002 * Add wscto{inttype} functions. */ #define _ISOC99_SOURCE /* for ULLONG primarily... */ #include <limits.h> #include <stdint.h> /* Work around gcc's refusal to create aliases. * TODO: Add in a define to disable the aliases? */ #if UINT_MAX == ULONG_MAX #ifdef L_labs #define abs __ignore_abs #endif #ifdef L_atol #define atoi __ignore_atoi #endif #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) #ifdef L_labs #define llabs __ignore_llabs #endif #ifdef L_atol #define atoll __ignore_atoll #endif #ifdef L_strtol #define strtoll __ignore_strtoll #endif #ifdef L_strtoul #define strtoull __ignore_strtoull #endif #ifdef L_wcstol #define wcstoll __ignore_wcstoll #endif #ifdef L_wcstoul #define wcstoull __ignore_wcstoull #endif #ifdef L_strtol_l #define strtoll_l __ignore_strtoll_l #endif #ifdef L_strtoul_l #define strtoull_l __ignore_strtoull_l #endif #ifdef L_wcstol_l #define wcstoll_l __ignore_wcstoll_l #endif #ifdef L_wcstoul_l #define wcstoull_l __ignore_wcstoull_l #endif #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == UINTMAX_MAX) #if defined L_labs || defined L_llabs #define imaxabs __ignore_imaxabs #endif #endif #include <stdint.h> #include <inttypes.h> #include <ctype.h> #include <errno.h> #include <assert.h> #include <unistd.h> #include <stdlib.h> #include <locale.h> #ifdef __UCLIBC_HAS_WCHAR__ #include <wchar.h> #include <wctype.h> #include <bits/uClibc_uwchar.h> #ifdef __UCLIBC_HAS_XLOCALE__ #include <xlocale.h> #endif /* __UCLIBC_HAS_XLOCALE__ */ /* TODO: clean up the following... */ #if WCHAR_MAX > 0xffffUL #define UTF_8_MAX_LEN 6 #else #define UTF_8_MAX_LEN 3 #endif #ifdef __UCLIBC_HAS_LOCALE__ #define ENCODING (__UCLIBC_CURLOCALE->encoding) #ifndef __CTYPE_HAS_UTF_8_LOCALES #ifdef L_mblen /* emit only once */ #warning __CTYPE_HAS_UTF_8_LOCALES not set! #endif #endif #else /* __UCLIBC_HAS_LOCALE__ */ #ifdef __UCLIBC_MJN3_ONLY__ #ifdef L_mblen /* emit only once */ #warning devel checks #endif #endif #ifdef __CTYPE_HAS_8_BIT_LOCALES #error __CTYPE_HAS_8_BIT_LOCALES is defined! #endif #ifdef __CTYPE_HAS_UTF_8_LOCALES #error __CTYPE_HAS_UTF_8_LOCALES is defined! #endif #endif #endif /* __UCLIBC_HAS_LOCALE__ */ /**********************************************************************/ #ifdef __UCLIBC_HAS_XLOCALE__ extern unsigned long _stdlib_strto_l_l(register const char * __restrict str, char ** __restrict endptr, int base, int sflag, __locale_t locale_arg) attribute_hidden; #if defined(ULLONG_MAX) extern unsigned long long _stdlib_strto_ll_l(register const char * __restrict str, char ** __restrict endptr, int base, int sflag, __locale_t locale_arg) attribute_hidden; #endif #ifdef __UCLIBC_HAS_WCHAR__ extern unsigned long _stdlib_wcsto_l_l(register const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base, int sflag, __locale_t locale_arg) attribute_hidden; #if defined(ULLONG_MAX) extern unsigned long long _stdlib_wcsto_ll_l(register const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base, int sflag, __locale_t locale_arg) attribute_hidden; #endif #endif /* __UCLIBC_HAS_WCHAR__ */ #endif /* __UCLIBC_HAS_XLOCALE__ */ extern unsigned long _stdlib_strto_l(register const char * __restrict str, char ** __restrict endptr, int base, int sflag) attribute_hidden; #if defined(ULLONG_MAX) extern unsigned long long _stdlib_strto_ll(register const char * __restrict str, char ** __restrict endptr, int base, int sflag) attribute_hidden; #endif #ifdef __UCLIBC_HAS_WCHAR__ extern unsigned long _stdlib_wcsto_l(register const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base, int sflag) attribute_hidden; #if defined(ULLONG_MAX) extern unsigned long long _stdlib_wcsto_ll(register const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base, int sflag) attribute_hidden; #endif #endif /* __UCLIBC_HAS_WCHAR__ */ /**********************************************************************/ #ifdef L_atof double atof(const char *nptr) { return strtod(nptr, (char **) NULL); } #endif /**********************************************************************/ #ifdef L_abs #if INT_MAX < LONG_MAX int abs(int j) { return (j >= 0) ? j : -j; } #endif /* INT_MAX < LONG_MAX */ #endif /**********************************************************************/ #ifdef L_labs long int labs(long int j) { return (j >= 0) ? j : -j; } #if UINT_MAX == ULONG_MAX #undef abs extern __typeof(labs) abs; strong_alias(labs,abs) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) #undef llabs extern __typeof(labs) llabs; strong_alias(labs,llabs) #endif #if ULONG_MAX == UINTMAX_MAX #undef imaxabs extern __typeof(labs) imaxabs; strong_alias(labs,imaxabs) #endif #endif /**********************************************************************/ #ifdef L_llabs #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) long long int llabs(long long int j) { return (j >= 0) ? j : -j; } #if (ULLONG_MAX == UINTMAX_MAX) #undef imaxabs extern __typeof(llabs) imaxabs; strong_alias(llabs,imaxabs) #endif #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ #endif /**********************************************************************/ #ifdef L_atoi #if INT_MAX < LONG_MAX int atoi(const char *nptr) { return (int) strtol(nptr, (char **) NULL, 10); } libc_hidden_def(atoi) #endif /* INT_MAX < LONG_MAX */ #endif /**********************************************************************/ #ifdef L_atol long atol(const char *nptr) { return strtol(nptr, (char **) NULL, 10); } #if UINT_MAX == ULONG_MAX #undef atoi extern __typeof(atol) atoi; /* the one in stdlib.h is not enough due to prototype mismatch */ libc_hidden_proto(atoi) strong_alias(atol,atoi) libc_hidden_def(atoi) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) #undef atoll extern __typeof(atol) atoll; strong_alias(atol,atoll) #endif #endif /**********************************************************************/ #ifdef L_atoll #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) long long atoll(const char *nptr) { return strtoll(nptr, (char **) NULL, 10); } #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ #endif /**********************************************************************/ #if defined(L_strtol) || defined(L_strtol_l) libc_hidden_proto(__XL_NPP(strtol)) long __XL_NPP(strtol)(const char * __restrict str, char ** __restrict endptr, int base __LOCALE_PARAM) { return __XL_NPP(_stdlib_strto_l)(str, endptr, base, 1 __LOCALE_ARG); } libc_hidden_def(__XL_NPP(strtol)) #if (ULONG_MAX == UINTMAX_MAX) && !defined(L_strtol_l) strong_alias(strtol,strtoimax) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) #ifdef L_strtol_l #undef strtoll_l #else #undef strtoll #endif extern __typeof(__XL_NPP(strtol)) __XL_NPP(strtoll); /* the one in stdlib.h is not enough due to prototype mismatch */ #ifdef L_strtol libc_hidden_proto(__XL_NPP(strtoll)) #endif strong_alias(__XL_NPP(strtol),__XL_NPP(strtoll)) #ifdef L_strtol libc_hidden_def(__XL_NPP(strtoll)) strong_alias(strtol,strtoq) #endif #endif #endif /**********************************************************************/ #if defined(L_strtoll) || defined(L_strtoll_l) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) long long __XL_NPP(strtoll)(const char * __restrict str, char ** __restrict endptr, int base __LOCALE_PARAM) { return (long long) __XL_NPP(_stdlib_strto_ll)(str, endptr, base, 1 __LOCALE_ARG); } #ifdef L_strtoll libc_hidden_def(__XL_NPP(strtoll)) #if (ULLONG_MAX == UINTMAX_MAX) strong_alias(strtoll,strtoimax) #endif strong_alias(strtoll,strtoq) #endif #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ #endif /**********************************************************************/ #if defined(L_strtoul) || defined(L_strtoul_l) unsigned long __XL_NPP(strtoul)(const char * __restrict str, char ** __restrict endptr, int base __LOCALE_PARAM) { return __XL_NPP(_stdlib_strto_l)(str, endptr, base, 0 __LOCALE_ARG); } libc_hidden_def(__XL_NPP(strtoul)) #if (ULONG_MAX == UINTMAX_MAX) && !defined(L_strtoul_l) strong_alias(strtoul,strtoumax) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) #ifdef L_strtoul_l #undef strtoull_l #else #undef strtoull #endif extern __typeof(__XL_NPP(strtoul)) __XL_NPP(strtoull); strong_alias(__XL_NPP(strtoul),__XL_NPP(strtoull)) #if !defined(L_strtoul_l) strong_alias(strtoul,strtouq) #endif #endif #endif /**********************************************************************/ #if defined(L_strtoull) || defined(L_strtoull_l) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) unsigned long long __XL_NPP(strtoull)(const char * __restrict str, char ** __restrict endptr, int base __LOCALE_PARAM) { return __XL_NPP(_stdlib_strto_ll)(str, endptr, base, 0 __LOCALE_ARG); } #if !defined(L_strtoull_l) #if (ULLONG_MAX == UINTMAX_MAX) strong_alias(strtoull,strtoumax) #endif strong_alias(strtoull,strtouq) #endif #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ #endif /**********************************************************************/ /* Support routines follow */ /**********************************************************************/ /* Set if we want errno set appropriately. */ /* NOTE: Implies _STRTO_ENDPTR below */ #define _STRTO_ERRNO 1 /* Set if we want support for the endptr arg. */ /* Implied by _STRTO_ERRNO. */ #define _STRTO_ENDPTR 1 #if _STRTO_ERRNO #undef _STRTO_ENDPTR #define _STRTO_ENDPTR 1 #define SET_ERRNO(X) __set_errno(X) #else #define SET_ERRNO(X) ((void)(X)) /* keep side effects */ #endif /**********************************************************************/ #if defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) #ifndef L__stdlib_strto_l #define L__stdlib_strto_l #endif #endif #if defined(L__stdlib_strto_l) || defined(L__stdlib_strto_l_l) #if defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) #define _stdlib_strto_l _stdlib_wcsto_l #define _stdlib_strto_l_l _stdlib_wcsto_l_l #define Wchar wchar_t #define Wuchar __uwchar_t #ifdef __UCLIBC_DO_XLOCALE #define ISSPACE(C) iswspace_l((C), locale_arg) #else #define ISSPACE(C) iswspace((C)) #endif #else /* defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) */ #define Wchar char #define Wuchar unsigned char #ifdef __UCLIBC_DO_XLOCALE #define ISSPACE(C) isspace_l((C), locale_arg) #else #define ISSPACE(C) isspace((C)) #endif #endif /* defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) */ #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) unsigned long attribute_hidden _stdlib_strto_l(register const Wchar * __restrict str, Wchar ** __restrict endptr, int base, int sflag) { return _stdlib_strto_l_l(str, endptr, base, sflag, __UCLIBC_CURLOCALE); } #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ /* This is the main work fuction which handles both strtol (sflag = 1) and * strtoul (sflag = 0). */ unsigned long attribute_hidden __XL_NPP(_stdlib_strto_l)(register const Wchar * __restrict str, Wchar ** __restrict endptr, int base, int sflag __LOCALE_PARAM) { unsigned long number, cutoff; #if _STRTO_ENDPTR const Wchar *fail_char; #define SET_FAIL(X) fail_char = (X) #else #define SET_FAIL(X) ((void)(X)) /* Keep side effects. */ #endif unsigned char negative, digit, cutoff_digit; assert(((unsigned int)sflag) <= 1); SET_FAIL(str); while (ISSPACE(*str)) { /* Skip leading whitespace. */ ++str; } /* Handle optional sign. */ negative = 0; switch (*str) { case '-': negative = 1; /* Fall through to increment str. */ case '+': ++str; } if (!(base & ~0x10)) { /* Either dynamic (base = 0) or base 16. */ base += 10; /* Default is 10 (26). */ if (*str == '0') { SET_FAIL(++str); base -= 2; /* Now base is 8 or 16 (24). */ if ((0x20|(*str)) == 'x') { /* WARNING: assumes ascii. */ ++str; base += base; /* Base is 16 (16 or 48). */ } } if (base > 16) { /* Adjust in case base wasn't dynamic. */ base = 16; } } number = 0; if (((unsigned)(base - 2)) < 35) { /* Legal base. */ cutoff_digit = ULONG_MAX % base; cutoff = ULONG_MAX / base; do { digit = ((Wuchar)(*str - '0') <= 9) ? /* 0..9 */ (*str - '0') : /* else */ (((Wuchar)(0x20 | *str) >= 'a') /* WARNING: assumes ascii. */ ? /* >= A/a */ ((Wuchar)(0x20 | *str) - ('a' - 10)) : /* else */ 40 /* bad value */); if (digit >= base) { break; } SET_FAIL(++str); if ((number > cutoff) || ((number == cutoff) && (digit > cutoff_digit))) { number = ULONG_MAX; negative &= sflag; SET_ERRNO(ERANGE); } else { number = number * base + digit; } } while (1); } #if _STRTO_ENDPTR if (endptr) { *endptr = (Wchar *) fail_char; } #endif { unsigned long tmp = (negative ? ((unsigned long)(-(1+LONG_MIN)))+1 : LONG_MAX); if (sflag && (number > tmp)) { number = tmp; SET_ERRNO(ERANGE); } } return negative ? (unsigned long)(-((long)number)) : number; } #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ #endif /**********************************************************************/ #if defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) #ifndef L__stdlib_strto_ll #define L__stdlib_strto_ll #endif #endif #if defined(L__stdlib_strto_ll) || defined(L__stdlib_strto_ll_l) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) #if defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) #define _stdlib_strto_ll _stdlib_wcsto_ll #define _stdlib_strto_ll_l _stdlib_wcsto_ll_l #define Wchar wchar_t #define Wuchar __uwchar_t #ifdef __UCLIBC_DO_XLOCALE #define ISSPACE(C) iswspace_l((C), locale_arg) #else #define ISSPACE(C) iswspace((C)) #endif #else /* defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) */ #define Wchar char #define Wuchar unsigned char #ifdef __UCLIBC_DO_XLOCALE #define ISSPACE(C) isspace_l((C), locale_arg) #else #define ISSPACE(C) isspace((C)) #endif #endif /* defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) */ #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) unsigned long long attribute_hidden _stdlib_strto_ll(register const Wchar * __restrict str, Wchar ** __restrict endptr, int base, int sflag) { return _stdlib_strto_ll_l(str, endptr, base, sflag, __UCLIBC_CURLOCALE); } #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ /* This is the main work fuction which handles both strtoll (sflag = 1) and * strtoull (sflag = 0). */ unsigned long long attribute_hidden __XL_NPP(_stdlib_strto_ll)(register const Wchar * __restrict str, Wchar ** __restrict endptr, int base, int sflag __LOCALE_PARAM) { unsigned long long number; #if _STRTO_ENDPTR const Wchar *fail_char; #define SET_FAIL(X) fail_char = (X) #else #define SET_FAIL(X) ((void)(X)) /* Keep side effects. */ #endif unsigned int n1; unsigned char negative, digit; assert(((unsigned int)sflag) <= 1); SET_FAIL(str); while (ISSPACE(*str)) { /* Skip leading whitespace. */ ++str; } /* Handle optional sign. */ negative = 0; switch (*str) { case '-': negative = 1; /* Fall through to increment str. */ case '+': ++str; } if (!(base & ~0x10)) { /* Either dynamic (base = 0) or base 16. */ base += 10; /* Default is 10 (26). */ if (*str == '0') { SET_FAIL(++str); base -= 2; /* Now base is 8 or 16 (24). */ if ((0x20|(*str)) == 'x') { /* WARNING: assumes ascii. */ ++str; base += base; /* Base is 16 (16 or 48). */ } } if (base > 16) { /* Adjust in case base wasn't dynamic. */ base = 16; } } number = 0; if (((unsigned)(base - 2)) < 35) { /* Legal base. */ do { digit = ((Wuchar)(*str - '0') <= 9) ? /* 0..9 */ (*str - '0') : /* else */ (((Wuchar)(0x20 | *str) >= 'a') /* WARNING: assumes ascii. */ ? /* >= A/a */ ((Wuchar)(0x20 | *str) - ('a' - 10)) : /* else */ 40 /* bad value */); if (digit >= base) { break; } SET_FAIL(++str); #if 1 /* Optional, but speeds things up in the usual case. */ if (number <= (ULLONG_MAX >> 6)) { number = number * base + digit; } else #endif { n1 = ((unsigned char) number) * base + digit; number = (number >> CHAR_BIT) * base; if (number + (n1 >> CHAR_BIT) <= (ULLONG_MAX >> CHAR_BIT)) { number = (number << CHAR_BIT) + n1; } else { /* Overflow. */ number = ULLONG_MAX; negative &= sflag; SET_ERRNO(ERANGE); } } } while (1); } #if _STRTO_ENDPTR if (endptr) { *endptr = (Wchar *) fail_char; } #endif { unsigned long long tmp = ((negative) ? ((unsigned long long)(-(1+LLONG_MIN)))+1 : LLONG_MAX); if (sflag && (number > tmp)) { number = tmp; SET_ERRNO(ERANGE); } } return negative ? (unsigned long long)(-((long long)number)) : number; } #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ #endif /**********************************************************************/ /* Made _Exit() an alias for _exit(), as per C99. */ /* #ifdef L__Exit */ /* void _Exit(int status) */ /* { */ /* _exit(status); */ /* } */ /* #endif */ /**********************************************************************/ #ifdef L_bsearch void *bsearch(const void *key, const void *base, size_t /* nmemb */ high, size_t size, int (*compar)(const void *, const void *)) { register char *p; size_t low; size_t mid; int r; if (size > 0) { /* TODO: change this to an assert?? */ low = 0; while (low < high) { mid = low + ((high - low) >> 1); /* Avoid possible overflow here. */ p = ((char *)base) + mid * size; /* Could overflow here... */ r = (*compar)(key, p); /* but that's an application problem! */ if (r > 0) { low = mid + 1; } else if (r < 0) { high = mid; } else { return p; } } } return NULL; } #endif /**********************************************************************/ #ifdef L_qsort /* This code is derived from a public domain shell sort routine by * Ray Gardner and found in Bob Stout's snippets collection. The * original code is included below in an #if 0/#endif block. * * I modified it to avoid the possibility of overflow in the wgap * calculation, as well as to reduce the generated code size with * bcc and gcc. */ void qsort(void *base, size_t nel, size_t width, int (*comp)(const void *, const void *)) { size_t wgap, i, j, k; char tmp; if ((nel > 1) && (width > 0)) { assert(nel <= ((size_t)(-1)) / width); /* check for overflow */ wgap = 0; do { wgap = 3 * wgap + 1; } while (wgap < (nel-1)/3); /* From the above, we know that either wgap == 1 < nel or */ /* ((wgap-1)/3 < (int) ((nel-1)/3) <= (nel-1)/3 ==> wgap < nel. */ wgap *= width; /* So this can not overflow if wnel doesn't. */ nel *= width; /* Convert nel to 'wnel' */ do { i = wgap; do { j = i; do { register char *a; register char *b; j -= wgap; a = j + ((char *)base); b = a + wgap; if ((*comp)(a, b) <= 0) { break; } k = width; do { tmp = *a; *a++ = *b; *b++ = tmp; } while (--k); } while (j >= wgap); i += width; } while (i < nel); wgap = (wgap - width)/3; } while (wgap); } } libc_hidden_def(qsort) /* ---------- original snippets version below ---------- */ #if 0 /* ** ssort() -- Fast, small, qsort()-compatible Shell sort ** ** by Ray Gardner, public domain 5/90 */ #include <stddef.h> void ssort(void *base, size_t nel, size_t width, int (*comp)(const void *, const void *)) { size_t wnel, gap, wgap, i, j, k; char *a, *b, tmp; wnel = width * nel; for (gap = 0; ++gap < nel;) gap *= 3; while ((gap /= 3) != 0) { wgap = width * gap; for (i = wgap; i < wnel; i += width) { for (j = i - wgap; ;j -= wgap) { a = j + (char *)base; b = a + wgap; if ((*comp)(a, b) <= 0) break; k = width; do { tmp = *a; *a++ = *b; *b++ = tmp; } while (--k); if (j < wgap) break; } } } } #endif #endif /**********************************************************************/ #ifdef L__stdlib_mb_cur_max size_t _stdlib_mb_cur_max(void) { #ifdef __CTYPE_HAS_UTF_8_LOCALES return __UCLIBC_CURLOCALE->mb_cur_max; #else #ifdef __CTYPE_HAS_8_BIT_LOCALES #ifdef __UCLIBC_MJN3_ONLY__ #warning need to change this when/if transliteration is implemented #endif #endif return 1; #endif } libc_hidden_def(_stdlib_mb_cur_max) #endif #ifdef __UCLIBC_HAS_LOCALE__ /* * The following function return 1 if the encoding is stateful, 0 if stateless. * To note, until now all the supported encoding are stateless. */ static __always_inline int is_stateful(unsigned char encoding) { switch (encoding) { case __ctype_encoding_7_bit: case __ctype_encoding_utf8: case __ctype_encoding_8_bit: return 0; default: assert(0); return -1; } } #else #define is_stateful(encoding) 0 #endif /**********************************************************************/ #ifdef L_mblen int mblen(register const char *s, size_t n) { static mbstate_t state; size_t r; if (!s) { state.__mask = 0; /* In this case we have to return 0 because the only multibyte supported encoding is utf-8, that is a stateless encoding. See mblen() documentation. */ return is_stateful(ENCODING); } if (*s == '\0') /* According to the ISO C 89 standard this is the expected behaviour. */ return 0; if ((r = mbrlen(s, n, &state)) == (size_t) -2) { /* TODO: Should we set an error state? */ state.__wc = 0xffffU; /* Make sure we're in an error state. */ return -1; /* TODO: Change error code above? */ } return r; } #endif /**********************************************************************/ #ifdef L_mbtowc int mbtowc(wchar_t *__restrict pwc, register const char *__restrict s, size_t n) { static mbstate_t state; size_t r; if (!s) { state.__mask = 0; /* In this case we have to return 0 because the only multibyte supported encoding is utf-8, that is a stateless encoding. See mbtowc() documentation. */ return is_stateful(ENCODING); } if (*s == '\0') /* According to the ISO C 89 standard this is the expected behaviour. */ return 0; if ((r = mbrtowc(pwc, s, n, &state)) == (size_t) -2) { /* TODO: Should we set an error state? */ state.__wc = 0xffffU; /* Make sure we're in an error state. */ return -1; /* TODO: Change error code above? */ } return r; } #endif /**********************************************************************/ #ifdef L_wctomb /* Note: We completely ignore state in all currently supported conversions. */ int wctomb(register char *__restrict s, wchar_t swc) { return (!s) ? /* In this case we have to return 0 because the only multibyte supported encoding is utf-8, that is a stateless encoding. See wctomb() documentation. */ is_stateful(ENCODING) : ((ssize_t) wcrtomb(s, swc, NULL)); } #endif /**********************************************************************/ #ifdef L_mbstowcs size_t mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n) { mbstate_t state; const char *e = s; /* Needed because of restrict. */ state.__mask = 0; /* Always start in initial shift state. */ return mbsrtowcs(pwcs, &e, n, &state); } #endif /**********************************************************************/ #ifdef L_wcstombs /* Note: We completely ignore state in all currently supported conversions. */ size_t wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n) { const wchar_t *e = pwcs; /* Needed because of restrict. */ return wcsrtombs(s, &e, n, NULL); } #endif /**********************************************************************/ #if defined(L_wcstol) || defined(L_wcstol_l) long __XL_NPP(wcstol)(const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base __LOCALE_PARAM) { return __XL_NPP(_stdlib_wcsto_l)(str, endptr, base, 1 __LOCALE_ARG); } #if (ULONG_MAX == UINTMAX_MAX) && !defined(L_wcstol_l) strong_alias(wcstol,wcstoimax) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) #ifdef L_wcstol_l #undef wcstoll_l #else #undef wcstoll #endif extern __typeof(__XL_NPP(wcstol)) __XL_NPP(wcstoll); strong_alias(__XL_NPP(wcstol),__XL_NPP(wcstoll)) #endif #endif /**********************************************************************/ #if defined(L_wcstoll) || defined(L_wcstoll_l) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) long long __XL_NPP(wcstoll)(const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base __LOCALE_PARAM) { return (long long) __XL_NPP(_stdlib_wcsto_ll)(str, endptr, base, 1 __LOCALE_ARG); } #if !defined(L_wcstoll_l) #if (ULLONG_MAX == UINTMAX_MAX) strong_alias(wcstoll,wcstoimax) #endif strong_alias(wcstoll,wcstoq) #endif #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ #endif /**********************************************************************/ #if defined(L_wcstoul) || defined(L_wcstoul_l) unsigned long __XL_NPP(wcstoul)(const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base __LOCALE_PARAM) { return __XL_NPP(_stdlib_wcsto_l)(str, endptr, base, 0 __LOCALE_ARG); } #if (ULONG_MAX == UINTMAX_MAX) && !defined(L_wcstoul_l) strong_alias(wcstoul,wcstoumax) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) #ifdef L_wcstoul_l #undef wcstoull_l #else #undef wcstoull #endif extern __typeof(__XL_NPP(wcstoul)) __XL_NPP(wcstoull); strong_alias(__XL_NPP(wcstoul),__XL_NPP(wcstoull)) #endif #endif /**********************************************************************/ #if defined(L_wcstoull) || defined(L_wcstoull_l) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) unsigned long long __XL_NPP(wcstoull)(const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base __LOCALE_PARAM) { return __XL_NPP(_stdlib_wcsto_ll)(str, endptr, base, 0 __LOCALE_ARG); } #if !defined(L_wcstoull_l) #if (ULLONG_MAX == UINTMAX_MAX) strong_alias(wcstoull,wcstoumax) #endif strong_alias(wcstoull,wcstouq) #endif #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ #endif /**********************************************************************/