]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libc/stdlib/stdlib.c
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libc / stdlib / stdlib.c
1 /*  Copyright (C) 2002     Manuel Novoa III
2  *  From my (incomplete) stdlib library for linux and (soon) elks.
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Library General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Library General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Library General Public
15  *  License along with this library; if not, see
16  *  <http://www.gnu.org/licenses/>.
17  */
18
19 /*  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!
20  *
21  *  This code is currently under development.  Also, I plan to port
22  *  it to elks which is a 16-bit environment with a fairly limited
23  *  compiler.  Therefore, please refrain from modifying this code
24  *  and, instead, pass any bug-fixes, etc. to me.  Thanks.  Manuel
25  *
26  *  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! */
27
28 /* Oct 29, 2002
29  * Fix a couple of 'restrict' bugs in mbstowcs and wcstombs.
30  *
31  * Nov 21, 2002
32  * Add wscto{inttype} functions.
33  */
34
35 #include <limits.h>
36 #include <stdint.h>
37 #include <stdint.h>
38 #include <inttypes.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #include <assert.h>
42 #include <unistd.h>
43
44 #include <stdlib.h>
45 #include <locale.h>
46
47 #ifdef __UCLIBC_HAS_WCHAR__
48
49 #include <wchar.h>
50 #include <wctype.h>
51 #include <bits/uClibc_uwchar.h>
52
53 /* TODO: clean up the following... */
54
55 #if WCHAR_MAX > 0xffffUL
56 #define UTF_8_MAX_LEN 6
57 #else
58 #define UTF_8_MAX_LEN 3
59 #endif
60
61 #ifdef __UCLIBC_HAS_LOCALE__
62
63 #define ENCODING                (__UCLIBC_CURLOCALE->encoding)
64 #ifndef __CTYPE_HAS_UTF_8_LOCALES
65 #ifdef L_mblen
66 /* emit only once */
67 #warning __CTYPE_HAS_UTF_8_LOCALES not set!
68 #endif
69 #endif
70
71 #else  /* __UCLIBC_HAS_LOCALE__ */
72
73 #ifdef __UCLIBC_MJN3_ONLY__
74 #ifdef L_mblen
75 /* emit only once */
76 #warning devel checks
77 #endif
78 #endif
79 #ifdef __CTYPE_HAS_8_BIT_LOCALES
80 #error __CTYPE_HAS_8_BIT_LOCALES is defined!
81 #endif
82 #ifdef __CTYPE_HAS_UTF_8_LOCALES
83 #error __CTYPE_HAS_UTF_8_LOCALES is defined!
84 #endif
85 #endif
86
87 #endif /* __UCLIBC_HAS_LOCALE__ */
88
89 /**********************************************************************/
90 #ifdef __UCLIBC_HAS_XLOCALE__
91
92 extern unsigned long
93 _stdlib_strto_l_l(register const char * __restrict str,
94                                   char ** __restrict endptr, int base, int sflag,
95                                   __locale_t locale_arg) attribute_hidden;
96
97 #if defined(ULLONG_MAX)
98 extern unsigned long long
99 _stdlib_strto_ll_l(register const char * __restrict str,
100                                    char ** __restrict endptr, int base, int sflag,
101                                   __locale_t locale_arg) attribute_hidden;
102 #endif
103
104 #ifdef __UCLIBC_HAS_WCHAR__
105 extern unsigned long
106 _stdlib_wcsto_l_l(register const wchar_t * __restrict str,
107                                   wchar_t ** __restrict endptr, int base, int sflag,
108                                   __locale_t locale_arg) attribute_hidden;
109
110 #if defined(ULLONG_MAX)
111 extern unsigned long long
112 _stdlib_wcsto_ll_l(register const wchar_t * __restrict str,
113                                    wchar_t ** __restrict endptr, int base, int sflag,
114                                   __locale_t locale_arg) attribute_hidden;
115 #endif
116 #endif /* __UCLIBC_HAS_WCHAR__ */
117
118 #endif /* __UCLIBC_HAS_XLOCALE__ */
119
120
121
122 extern unsigned long
123 _stdlib_strto_l(register const char * __restrict str,
124                                 char ** __restrict endptr, int base, int sflag) attribute_hidden;
125
126 #if defined(ULLONG_MAX)
127 extern unsigned long long
128 _stdlib_strto_ll(register const char * __restrict str,
129                                  char ** __restrict endptr, int base, int sflag) attribute_hidden;
130 #endif
131
132 #ifdef __UCLIBC_HAS_WCHAR__
133 extern unsigned long
134 _stdlib_wcsto_l(register const wchar_t * __restrict str,
135                                 wchar_t ** __restrict endptr, int base, int sflag) attribute_hidden;
136
137 #if defined(ULLONG_MAX)
138 extern unsigned long long
139 _stdlib_wcsto_ll(register const wchar_t * __restrict str,
140                                  wchar_t ** __restrict endptr, int base, int sflag) attribute_hidden;
141 #endif
142 #endif /* __UCLIBC_HAS_WCHAR__ */
143 /**********************************************************************/
144 #ifdef L_atof
145
146
147 double atof(const char *nptr)
148 {
149         return strtod(nptr, (char **) NULL);
150 }
151
152 #endif
153 /**********************************************************************/
154 #ifdef L_abs
155
156 #if INT_MAX < LONG_MAX
157
158 int abs(int j)
159 {
160         return (j >= 0) ? j : -j;
161 }
162
163 #endif /* INT_MAX < LONG_MAX */
164
165 #endif
166 /**********************************************************************/
167 #ifdef L_labs
168
169 long int labs(long int j)
170 {
171         return (j >= 0) ? j : -j;
172 }
173
174 #if UINT_MAX == ULONG_MAX
175 strong_alias_untyped(labs,abs)
176 #endif
177
178 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
179 strong_alias_untyped(labs,llabs)
180 #endif
181
182 #if ULONG_MAX == UINTMAX_MAX
183 strong_alias_untyped(labs,imaxabs)
184 #endif
185
186 #endif
187 /**********************************************************************/
188 #ifdef L_llabs
189
190 #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
191
192 long long int llabs(long long int j)
193 {
194         return (j >= 0) ? j : -j;
195 }
196
197 #if (ULLONG_MAX == UINTMAX_MAX)
198 strong_alias_untyped(llabs,imaxabs)
199 #endif
200
201 #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
202
203 #endif
204 /**********************************************************************/
205 #ifdef L_atoi
206
207 #if INT_MAX < LONG_MAX
208
209
210 int atoi(const char *nptr)
211 {
212         return (int) strtol(nptr, (char **) NULL, 10);
213 }
214 libc_hidden_def(atoi)
215
216 #endif /* INT_MAX < LONG_MAX  */
217
218 #endif
219 /**********************************************************************/
220 #ifdef L_atol
221
222
223 long atol(const char *nptr)
224 {
225         return strtol(nptr, (char **) NULL, 10);
226 }
227
228 #if UINT_MAX == ULONG_MAX
229 strong_alias_untyped(atol,atoi)
230 libc_hidden_def(atoi)
231 #endif
232
233 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
234 strong_alias_untyped(atol,atoll)
235 #endif
236
237 #endif
238 /**********************************************************************/
239 #ifdef L_atoll
240
241 #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
242
243
244 long long atoll(const char *nptr)
245 {
246         return strtoll(nptr, (char **) NULL, 10);
247 }
248
249 #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
250
251 #endif
252 /**********************************************************************/
253 #ifdef L_rpmatch
254 int rpmatch (const char *__response)
255 {
256         return (__response[0] == 'y' || __response[0] == 'Y') ? 1 :
257                 (__response[0] == 'n' || __response[0] == 'N') ? 0 : -1;
258 }
259 #endif
260 /**********************************************************************/
261 #if defined(L_strtol) || defined(L_strtol_l)
262
263 long __XL_NPP(strtol)(const char * __restrict str, char ** __restrict endptr,
264                                   int base __LOCALE_PARAM)
265 {
266         return __XL_NPP(_stdlib_strto_l)(str, endptr, base, 1 __LOCALE_ARG);
267 }
268 libc_hidden_def(__XL_NPP(strtol))
269
270 #if (ULONG_MAX == UINTMAX_MAX) && !defined(L_strtol_l)
271 strong_alias(strtol,strtoimax)
272 #endif
273
274 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
275 strong_alias_untyped(__XL_NPP(strtol),__XL_NPP(strtoll))
276 #ifdef L_strtol
277 libc_hidden_def(__XL_NPP(strtoll))
278 strong_alias(strtol,strtoq)
279 #endif
280 #endif
281
282 #endif
283 /**********************************************************************/
284 #if defined(L_strtoll) || defined(L_strtoll_l)
285
286 #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
287
288 long long __XL_NPP(strtoll)(const char * __restrict str,
289                                                 char ** __restrict endptr, int base
290                                                 __LOCALE_PARAM)
291 {
292         return (long long) __XL_NPP(_stdlib_strto_ll)(str, endptr, base, 1 __LOCALE_ARG);
293 }
294 #ifdef L_strtoll
295 libc_hidden_def(__XL_NPP(strtoll))
296 #if (ULLONG_MAX == UINTMAX_MAX)
297 strong_alias(strtoll,strtoimax)
298 #endif
299 strong_alias(strtoll,strtoq)
300 #endif
301
302 #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
303
304 #endif
305 /**********************************************************************/
306 #if defined(L_strtoul) || defined(L_strtoul_l)
307
308 unsigned long __XL_NPP(strtoul)(const char * __restrict str,
309                                                         char ** __restrict endptr, int base
310                                                         __LOCALE_PARAM)
311 {
312         return __XL_NPP(_stdlib_strto_l)(str, endptr, base, 0 __LOCALE_ARG);
313 }
314 libc_hidden_def(__XL_NPP(strtoul))
315
316 #if (ULONG_MAX == UINTMAX_MAX) && !defined(L_strtoul_l)
317 strong_alias(strtoul,strtoumax)
318 #endif
319
320 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
321 strong_alias_untyped(__XL_NPP(strtoul),__XL_NPP(strtoull))
322 #if !defined(L_strtoul_l)
323 strong_alias(strtoul,strtouq)
324 #endif
325 #endif
326
327
328 #endif
329 /**********************************************************************/
330 #if defined(L_strtoull) || defined(L_strtoull_l)
331
332 #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
333
334 unsigned long long __XL_NPP(strtoull)(const char * __restrict str,
335                                                                   char ** __restrict endptr, int base
336                                                                   __LOCALE_PARAM)
337 {
338         return __XL_NPP(_stdlib_strto_ll)(str, endptr, base, 0 __LOCALE_ARG);
339 }
340
341 #if !defined(L_strtoull_l)
342 #if (ULLONG_MAX == UINTMAX_MAX)
343 strong_alias(strtoull,strtoumax)
344 #endif
345 strong_alias(strtoull,strtouq)
346 #endif
347
348 #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
349
350 #endif
351 /**********************************************************************/
352 /* Support routines follow */
353 /**********************************************************************/
354 /* Set if we want errno set appropriately. */
355 /* NOTE: Implies _STRTO_ENDPTR below */
356 #define _STRTO_ERRNO            1
357
358 /* Set if we want support for the endptr arg. */
359 /* Implied by _STRTO_ERRNO. */
360 #define _STRTO_ENDPTR           1
361
362 #if _STRTO_ERRNO
363 #undef _STRTO_ENDPTR
364 #define _STRTO_ENDPTR           1
365 #define SET_ERRNO(X)            __set_errno(X)
366 #else
367 #define SET_ERRNO(X)            ((void)(X))     /* keep side effects */
368 #endif
369
370 /**********************************************************************/
371 #if defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l)
372 #ifndef L__stdlib_strto_l
373 #define L__stdlib_strto_l
374 #endif
375 #endif
376
377 #if defined(L__stdlib_strto_l) || defined(L__stdlib_strto_l_l)
378
379 #if defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l)
380
381 #define _stdlib_strto_l _stdlib_wcsto_l
382 #define _stdlib_strto_l_l _stdlib_wcsto_l_l
383 #define Wchar wchar_t
384 #define Wuchar __uwchar_t
385 #ifdef __UCLIBC_DO_XLOCALE
386 #define ISSPACE(C) iswspace_l((C), locale_arg)
387 #else
388 #define ISSPACE(C) iswspace((C))
389 #endif
390
391 #else  /* defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) */
392
393 #define Wchar char
394 #define Wuchar unsigned char
395 #ifdef __UCLIBC_DO_XLOCALE
396 #define ISSPACE(C) isspace_l((C), locale_arg)
397 #else
398 #define ISSPACE(C) isspace((C))
399 #endif
400
401 #endif /* defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) */
402
403 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
404
405 unsigned long attribute_hidden _stdlib_strto_l(register const Wchar * __restrict str,
406                                                           Wchar ** __restrict endptr, int base,
407                                                           int sflag)
408 {
409         return _stdlib_strto_l_l(str, endptr, base, sflag, __UCLIBC_CURLOCALE);
410 }
411
412
413 #else  /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
414
415 /* This is the main work fuction which handles both strtol (sflag = 1) and
416  * strtoul (sflag = 0). */
417
418 unsigned long attribute_hidden __XL_NPP(_stdlib_strto_l)(register const Wchar * __restrict str,
419                                                                                 Wchar ** __restrict endptr, int base,
420                                                                                 int sflag __LOCALE_PARAM)
421 {
422         unsigned long number, cutoff;
423 #if _STRTO_ENDPTR
424         const Wchar *fail_char;
425 #define SET_FAIL(X) fail_char = (X)
426 #else
427 #define SET_FAIL(X) ((void)(X)) /* Keep side effects. */
428 #endif
429         unsigned char negative, digit, cutoff_digit;
430
431         assert(((unsigned int)sflag) <= 1);
432
433         SET_FAIL(str);
434
435         while (ISSPACE(*str)) { /* Skip leading whitespace. */
436                 ++str;
437         }
438
439         /* Handle optional sign. */
440         negative = 0;
441         switch (*str) {
442                 case '-': negative = 1; /* Fall through to increment str. */
443                 case '+': ++str;
444         }
445
446         if (!(base & ~0x10)) {          /* Either dynamic (base = 0) or base 16. */
447                 base += 10;                             /* Default is 10 (26). */
448                 if (*str == '0') {
449                         SET_FAIL(++str);
450                         base -= 2;                      /* Now base is 8 or 16 (24). */
451                         if ((0x20|(*str)) == 'x') { /* WARNING: assumes ascii. */
452                                 ++str;
453                                 base += base;   /* Base is 16 (16 or 48). */
454                         }
455                 }
456
457                 if (base > 16) {                /* Adjust in case base wasn't dynamic. */
458                         base = 16;
459                 }
460         }
461
462         number = 0;
463
464         if (((unsigned)(base - 2)) < 35) { /* Legal base. */
465                 cutoff_digit = ULONG_MAX % base;
466                 cutoff = ULONG_MAX / base;
467                 do {
468                         digit = ((Wuchar)(*str - '0') <= 9)
469                                 ? /* 0..9 */ (*str - '0')
470                                 : /* else */ (((Wuchar)(0x20 | *str) >= 'a') /* WARNING: assumes ascii. */
471                                    ? /* >= A/a */ ((Wuchar)(0x20 | *str) - ('a' - 10))
472                                    : /* else   */ 40 /* bad value */);
473
474                         if (digit >= base) {
475                                 break;
476                         }
477
478                         SET_FAIL(++str);
479
480                         if ((number > cutoff)
481                                 || ((number == cutoff) && (digit > cutoff_digit))) {
482                                 number = ULONG_MAX;
483                                 negative &= sflag;
484                                 SET_ERRNO(ERANGE);
485                         } else {
486                                 number = number * base + digit;
487                         }
488                 } while (1);
489         }
490
491 #if _STRTO_ENDPTR
492         if (endptr) {
493                 *endptr = (Wchar *) fail_char;
494         }
495 #endif
496
497         {
498                 unsigned long tmp = (negative
499                                                          ? ((unsigned long)(-(1+LONG_MIN)))+1
500                                                          : LONG_MAX);
501                 if (sflag && (number > tmp)) {
502                         number = tmp;
503                         SET_ERRNO(ERANGE);
504                 }
505         }
506
507         return negative ? (unsigned long)(-((long)number)) : number;
508 }
509
510 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
511
512
513 #endif
514 /**********************************************************************/
515 #if defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l)
516 #ifndef L__stdlib_strto_ll
517 #define L__stdlib_strto_ll
518 #endif
519 #endif
520
521 #if defined(L__stdlib_strto_ll) || defined(L__stdlib_strto_ll_l)
522
523 #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
524
525 #if defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l)
526 #define _stdlib_strto_ll _stdlib_wcsto_ll
527 #define _stdlib_strto_ll_l _stdlib_wcsto_ll_l
528 #define Wchar wchar_t
529 #define Wuchar __uwchar_t
530 #ifdef __UCLIBC_DO_XLOCALE
531 #define ISSPACE(C) iswspace_l((C), locale_arg)
532 #else
533 #define ISSPACE(C) iswspace((C))
534 #endif
535
536 #else  /* defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) */
537
538 #define Wchar char
539 #define Wuchar unsigned char
540 #ifdef __UCLIBC_DO_XLOCALE
541 #define ISSPACE(C) isspace_l((C), locale_arg)
542 #else
543 #define ISSPACE(C) isspace((C))
544 #endif
545
546 #endif /* defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) */
547
548 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
549
550 unsigned long long attribute_hidden _stdlib_strto_ll(register const Wchar * __restrict str,
551                                                                         Wchar ** __restrict endptr, int base,
552                                                                         int sflag)
553 {
554         return _stdlib_strto_ll_l(str, endptr, base, sflag, __UCLIBC_CURLOCALE);
555 }
556
557
558 #else  /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
559
560 /* This is the main work fuction which handles both strtoll (sflag = 1) and
561  * strtoull (sflag = 0). */
562
563 unsigned long long attribute_hidden __XL_NPP(_stdlib_strto_ll)(register const Wchar * __restrict str,
564                                                                                           Wchar ** __restrict endptr, int base,
565                                                                                           int sflag __LOCALE_PARAM)
566 {
567         unsigned long long number;
568 #if _STRTO_ENDPTR
569         const Wchar *fail_char;
570 #define SET_FAIL(X) fail_char = (X)
571 #else
572 #define SET_FAIL(X) ((void)(X)) /* Keep side effects. */
573 #endif
574         unsigned int n1;
575         unsigned char negative, digit;
576
577         assert(((unsigned int)sflag) <= 1);
578
579         SET_FAIL(str);
580
581         while (ISSPACE(*str)) {         /* Skip leading whitespace. */
582                 ++str;
583         }
584
585         /* Handle optional sign. */
586         negative = 0;
587         switch (*str) {
588                 case '-': negative = 1; /* Fall through to increment str. */
589                 case '+': ++str;
590         }
591
592         if (!(base & ~0x10)) {          /* Either dynamic (base = 0) or base 16. */
593                 base += 10;                             /* Default is 10 (26). */
594                 if (*str == '0') {
595                         SET_FAIL(++str);
596                         base -= 2;                      /* Now base is 8 or 16 (24). */
597                         if ((0x20|(*str)) == 'x') { /* WARNING: assumes ascii. */
598                                 ++str;
599                                 base += base;   /* Base is 16 (16 or 48). */
600                         }
601                 }
602
603                 if (base > 16) {                /* Adjust in case base wasn't dynamic. */
604                         base = 16;
605                 }
606         }
607
608         number = 0;
609
610         if (((unsigned)(base - 2)) < 35) { /* Legal base. */
611                 do {
612                         digit = ((Wuchar)(*str - '0') <= 9)
613                                 ? /* 0..9 */ (*str - '0')
614                                 : /* else */ (((Wuchar)(0x20 | *str) >= 'a') /* WARNING: assumes ascii. */
615                                    ? /* >= A/a */ ((Wuchar)(0x20 | *str) - ('a' - 10))
616                                    : /* else   */ 40 /* bad value */);
617
618                         if (digit >= base) {
619                                 break;
620                         }
621
622                         SET_FAIL(++str);
623
624 #if 1
625                         /* Optional, but speeds things up in the usual case. */
626                         if (number <= (ULLONG_MAX >> 6)) {
627                                 number = number * base + digit;
628                         } else
629 #endif
630                         {
631                                 n1 = ((unsigned char) number) * base + digit;
632                                 number = (number >> CHAR_BIT) * base;
633
634                                 if (number + (n1 >> CHAR_BIT) <= (ULLONG_MAX >> CHAR_BIT)) {
635                                         number = (number << CHAR_BIT) + n1;
636                                 } else {                /* Overflow. */
637                                         number = ULLONG_MAX;
638                                         negative &= sflag;
639                                         SET_ERRNO(ERANGE);
640                                 }
641                         }
642
643                 } while (1);
644         }
645
646 #if _STRTO_ENDPTR
647         if (endptr) {
648                 *endptr = (Wchar *) fail_char;
649         }
650 #endif
651
652         {
653                 unsigned long long tmp = ((negative)
654                                                                   ? ((unsigned long long)(-(1+LLONG_MIN)))+1
655                                                                   : LLONG_MAX);
656                 if (sflag && (number > tmp)) {
657                         number = tmp;
658                         SET_ERRNO(ERANGE);
659                 }
660         }
661
662         return negative ? (unsigned long long)(-((long long)number)) : number;
663 }
664
665 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
666
667 #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
668
669 #endif
670
671 #ifdef L_bsearch
672
673 void *bsearch(const void *key, const void *base, size_t /* nmemb */ high,
674                           size_t size, int (*compar)(const void *, const void *))
675 {
676         register char *p;
677         size_t low;
678         size_t mid;
679         int r;
680
681         if (size > 0) {                         /* TODO: change this to an assert?? */
682                 low = 0;
683                 while (low < high) {
684                         mid = low + ((high - low) >> 1); /* Avoid possible overflow here. */
685                         p = ((char *)base) + mid * size; /* Could overflow here... */
686                         r = (*compar)(key, p); /* but that's an application problem! */
687                         if (r > 0) {
688                                 low = mid + 1;
689                         } else if (r < 0) {
690                                 high = mid;
691                         } else {
692                                 return p;
693                         }
694                 }
695         }
696         return NULL;
697 }
698
699 #endif
700 /**********************************************************************/
701 #ifdef L_qsort_r
702
703 /* This code is derived from a public domain shell sort routine by
704  * Ray Gardner and found in Bob Stout's snippets collection.  The
705  * original code is included below in an #if 0/#endif block.
706  *
707  * I modified it to avoid the possibility of overflow in the wgap
708  * calculation, as well as to reduce the generated code size with
709  * bcc and gcc. */
710
711 void qsort_r(void  *base,
712            size_t nel,
713            size_t width,
714            __compar_d_fn_t comp,
715                    void *arg)
716 {
717         size_t wgap, i, j, k;
718         char tmp;
719
720         if ((nel > 1) && (width > 0)) {
721                 assert(nel <= ((size_t)(-1)) / width); /* check for overflow */
722                 wgap = 0;
723                 do {
724                         wgap = 3 * wgap + 1;
725                 } while (wgap < (nel-1)/3);
726                 /* From the above, we know that either wgap == 1 < nel or */
727                 /* ((wgap-1)/3 < (int) ((nel-1)/3) <= (nel-1)/3 ==> wgap <  nel. */
728                 wgap *= width;                  /* So this can not overflow if wnel doesn't. */
729                 nel *= width;                   /* Convert nel to 'wnel' */
730                 do {
731                         i = wgap;
732                         do {
733                                 j = i;
734                                 do {
735                                         register char *a;
736                                         register char *b;
737
738                                         j -= wgap;
739                                         a = j + ((char *)base);
740                                         b = a + wgap;
741                                         if ((*comp)(a, b, arg) <= 0) {
742                                                 break;
743                                         }
744                                         k = width;
745                                         do {
746                                                 tmp = *a;
747                                                 *a++ = *b;
748                                                 *b++ = tmp;
749                                         } while (--k);
750                                 } while (j >= wgap);
751                                 i += width;
752                         } while (i < nel);
753                         wgap = (wgap - width)/3;
754                 } while (wgap);
755         }
756 }
757 libc_hidden_def(qsort_r)
758
759 /* ---------- original snippets version below ---------- */
760
761 #if 0
762 /*
763 **  ssort()  --  Fast, small, qsort()-compatible Shell sort
764 **
765 **  by Ray Gardner,  public domain   5/90
766 */
767
768 #include <stddef.h>
769
770 void ssort(void  *base,
771            size_t nel,
772            size_t width,
773            int (*comp)(const void *, const void *))
774 {
775         size_t wnel, gap, wgap, i, j, k;
776         char *a, *b, tmp;
777
778         wnel = width * nel;
779         for (gap = 0; ++gap < nel;)
780                 gap *= 3;
781         while ((gap /= 3) != 0) {
782                 wgap = width * gap;
783                 for (i = wgap; i < wnel; i += width) {
784                         for (j = i - wgap; ;j -= wgap) {
785                                 a = j + (char *)base;
786                                 b = a + wgap;
787                                 if ((*comp)(a, b) <= 0)
788                                         break;
789                                 k = width;
790                                 do {
791                                         tmp = *a;
792                                         *a++ = *b;
793                                         *b++ = tmp;
794                                 } while (--k);
795                                 if (j < wgap)
796                                         break;
797                         }
798                 }
799         }
800 }
801 #endif
802
803 #endif
804
805 #ifdef L_qsort
806 void qsort(void  *base,
807            size_t nel,
808            size_t width,
809            __compar_fn_t comp)
810 {
811         return qsort_r (base, nel, width, (__compar_d_fn_t) comp, NULL);
812 }
813 libc_hidden_def(qsort)
814 #endif
815
816 /**********************************************************************/
817 #ifdef L__stdlib_mb_cur_max
818
819 size_t _stdlib_mb_cur_max(void)
820 {
821 #ifdef __CTYPE_HAS_UTF_8_LOCALES
822         return __UCLIBC_CURLOCALE->mb_cur_max;
823 #else
824 #ifdef __CTYPE_HAS_8_BIT_LOCALES
825 #ifdef __UCLIBC_MJN3_ONLY__
826 #warning need to change this when/if transliteration is implemented
827 #endif
828 #endif
829         return 1;
830 #endif
831 }
832 libc_hidden_def(_stdlib_mb_cur_max)
833
834 #endif
835
836 #ifdef __UCLIBC_HAS_LOCALE__
837 /*
838  * The following function return 1 if the encoding is stateful, 0 if stateless.
839  * To note, until now all the supported encoding are stateless.
840  */
841
842 static __always_inline int is_stateful(unsigned char encoding)
843 {
844         switch (encoding)
845         {
846                 case __ctype_encoding_7_bit:
847                 case __ctype_encoding_utf8:
848                 case __ctype_encoding_8_bit:
849                         return 0;
850                 default:
851                         assert(0);
852                         return -1;
853         }
854 }
855 #else
856 #define is_stateful(encoding) 0
857 #endif
858
859 /**********************************************************************/
860 #ifdef L_mblen
861
862
863 int mblen(register const char *s, size_t n)
864 {
865         static mbstate_t state;
866         size_t r;
867
868         if (!s) {
869                 state.__mask = 0;
870                 /*
871                         In this case we have to return 0 because the only multibyte supported encoding
872                         is utf-8, that is a stateless encoding. See mblen() documentation.
873                 */
874                 return is_stateful(ENCODING);
875         }
876
877         if (*s == '\0')
878                 /* According to the ISO C 89 standard this is the expected behaviour.  */
879                 return 0;
880
881         if ((r = mbrlen(s, n, &state)) == (size_t) -2) {
882                 /* TODO: Should we set an error state? */
883                 state.__wc = 0xffffU;   /* Make sure we're in an error state. */
884                 return -1;              /* TODO: Change error code above? */
885         }
886         return r;
887 }
888
889 #endif
890 /**********************************************************************/
891 #ifdef L_mbtowc
892
893
894 int mbtowc(wchar_t *__restrict pwc, register const char *__restrict s, size_t n)
895 {
896         static mbstate_t state;
897         size_t r;
898
899         if (!s) {
900                 state.__mask = 0;
901                 /*
902                         In this case we have to return 0 because the only multibyte supported encoding
903                         is utf-8, that is a stateless encoding. See mbtowc() documentation.
904                 */
905
906                 return is_stateful(ENCODING);
907         }
908
909         if (*s == '\0')
910                 /* According to the ISO C 89 standard this is the expected behaviour.  */
911                 return 0;
912
913         if ((r = mbrtowc(pwc, s, n, &state)) == (size_t) -2) {
914                 /* TODO: Should we set an error state? */
915                 state.__wc = 0xffffU;   /* Make sure we're in an error state. */
916                 return -1;              /* TODO: Change error code above? */
917         }
918         return r;
919 }
920
921 #endif
922 /**********************************************************************/
923 #ifdef L_wctomb
924
925 /* Note: We completely ignore state in all currently supported conversions. */
926
927
928 int wctomb(register char *__restrict s, wchar_t swc)
929 {
930         return (!s)
931                 ?
932                 /*
933                         In this case we have to return 0 because the only multibyte supported encoding
934                         is utf-8, that is a stateless encoding. See wctomb() documentation.
935                 */
936
937                 is_stateful(ENCODING)
938                 : ((ssize_t) wcrtomb(s, swc, NULL));
939 }
940
941 #endif
942 /**********************************************************************/
943 #ifdef L_mbstowcs
944
945
946 size_t mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n)
947 {
948         mbstate_t state;
949         const char *e = s;                      /* Needed because of restrict. */
950
951         state.__mask = 0;                       /* Always start in initial shift state. */
952         return mbsrtowcs(pwcs, &e, n, &state);
953 }
954
955 #endif
956 /**********************************************************************/
957 #ifdef L_wcstombs
958
959 /* Note: We completely ignore state in all currently supported conversions. */
960
961
962 size_t wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n)
963 {
964         const wchar_t *e = pwcs;        /* Needed because of restrict. */
965
966         return wcsrtombs(s, &e, n, NULL);
967 }
968
969 #endif
970 /**********************************************************************/
971 #if defined(L_wcstol) || defined(L_wcstol_l)
972
973 long __XL_NPP(wcstol)(const wchar_t * __restrict str,
974                                   wchar_t ** __restrict endptr, int base __LOCALE_PARAM)
975 {
976         return __XL_NPP(_stdlib_wcsto_l)(str, endptr, base, 1 __LOCALE_ARG);
977 }
978
979 #if (ULONG_MAX == UINTMAX_MAX) && !defined(L_wcstol_l)
980 strong_alias(wcstol,wcstoimax)
981 #endif
982
983 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
984 strong_alias_untyped(__XL_NPP(wcstol),__XL_NPP(wcstoll))
985 #endif
986
987 #endif
988 /**********************************************************************/
989 #if defined(L_wcstoll) || defined(L_wcstoll_l)
990
991 #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
992
993 long long __XL_NPP(wcstoll)(const wchar_t * __restrict str,
994                                                 wchar_t ** __restrict endptr, int base
995                                                 __LOCALE_PARAM)
996 {
997         return (long long) __XL_NPP(_stdlib_wcsto_ll)(str, endptr, base, 1 __LOCALE_ARG);
998 }
999
1000 #if !defined(L_wcstoll_l)
1001 #if (ULLONG_MAX == UINTMAX_MAX)
1002 strong_alias(wcstoll,wcstoimax)
1003 #endif
1004 strong_alias(wcstoll,wcstoq)
1005 #endif
1006
1007 #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
1008
1009 #endif
1010 /**********************************************************************/
1011 #if defined(L_wcstoul) || defined(L_wcstoul_l)
1012
1013 unsigned long __XL_NPP(wcstoul)(const wchar_t * __restrict str,
1014                                                         wchar_t ** __restrict endptr, int base
1015                                                         __LOCALE_PARAM)
1016 {
1017         return __XL_NPP(_stdlib_wcsto_l)(str, endptr, base, 0 __LOCALE_ARG);
1018 }
1019
1020 #if (ULONG_MAX == UINTMAX_MAX) && !defined(L_wcstoul_l)
1021 strong_alias(wcstoul,wcstoumax)
1022 #endif
1023
1024 #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
1025 strong_alias_untyped(__XL_NPP(wcstoul),__XL_NPP(wcstoull))
1026 #endif
1027
1028 #endif
1029 /**********************************************************************/
1030 #if defined(L_wcstoull) || defined(L_wcstoull_l)
1031
1032 #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
1033
1034 unsigned long long __XL_NPP(wcstoull)(const wchar_t * __restrict str,
1035                                                                   wchar_t ** __restrict endptr, int base
1036                                                                   __LOCALE_PARAM)
1037 {
1038         return __XL_NPP(_stdlib_wcsto_ll)(str, endptr, base, 0 __LOCALE_ARG);
1039 }
1040
1041 #if !defined(L_wcstoull_l)
1042 #if (ULLONG_MAX == UINTMAX_MAX)
1043 strong_alias(wcstoull,wcstoumax)
1044 #endif
1045 strong_alias(wcstoull,wcstouq)
1046 #endif
1047
1048 #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
1049
1050 #endif
1051 /**********************************************************************/