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