1 /* Copyright (c) 2002,2005, Joerg Wunsch
2    All rights reserved.
3 
4    Redistribution and use in source and binary forms, with or without
5    modification, are permitted provided that the following conditions are met:
6 
7    * Redistributions of source code must retain the above copyright
8      notice, this list of conditions and the following disclaimer.
9    * Redistributions in binary form must reproduce the above copyright
10      notice, this list of conditions and the following disclaimer in
11      the documentation and/or other materials provided with the
12      distribution.
13    * Neither the name of the copyright holders nor the names of
14      contributors may be used to endorse or promote products derived
15      from this software without specific prior written permission.
16 
17   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27   POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 /* $Id: stdio_private.h 847 2005-09-06 18:49:15Z joerg_wunsch $ */
31 
32 #ifndef _STDIO_PRIVATE_H_
33 #define _STDIO_PRIVATE_H_
34 
35 #define _GNU_SOURCE
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <stddef.h>
39 #include <stdbool.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <wchar.h>
46 #include <float.h>
47 #include <math.h>
48 #include <stdio-bufio.h>
49 #include <sys/lock.h>
50 
51 /* values for PRINTF_LEVEL */
52 #define PRINTF_MIN 1
53 #define PRINTF_STD 2
54 #define PRINTF_LLONG 3
55 #define PRINTF_FLT 4
56 #define PRINTF_DBL 5
57 
58 /* values for SCANF_LEVEL */
59 #define SCANF_MIN 1
60 #define SCANF_STD 2
61 #define SCANF_LLONG 3
62 #define SCANF_FLT 4
63 #define SCANF_DBL 5
64 
65 struct __file_str {
66 	struct __file file;	/* main file struct */
67         char	*pos;		/* current buffer position */
68         char    *end;           /* end of buffer */
69         size_t  size;           /* size of allocated storage */
70 };
71 
72 int
73 __file_str_get(FILE *stream);
74 
75 int
76 __file_wstr_get(FILE *stream);
77 
78 int
79 __file_str_put(char c, FILE *stream);
80 
81 int
82 __file_str_put_alloc(char c, FILE *stream);
83 
84 extern const char __match_inf[];
85 extern const char __match_inity[];
86 extern const char __match_nan[];
87 
88 /* Returns 'true' if prefix of input matches pattern, independent of
89  * case. pattern is only upper case letters.
90  */
91 bool __matchcaseprefix(const char *input, const char *pattern);
92 
93 /*
94  * It is OK to discard the "const" qualifier here.  f.buf is
95  * non-const as in the generic case, this buffer is obtained
96  * by malloc().  In the scanf case however, the buffer is
97  * really only be read (by getc()), and as this our FILE f we
98  * be discarded upon exiting sscanf(), nobody will ever get
99  * a chance to get write access to it again.
100  */
101 #define FDEV_SETUP_STRING_READ(_s) {		\
102 		.file = {			\
103 			.flags = __SRD,		\
104 			.get = __file_str_get	\
105 		},				\
106 		.pos = (char *) (_s)		\
107 	}
108 
109 #define FDEV_SETUP_WSTRING_READ(_s) {		\
110 		.file = {			\
111 			.flags = __SRD,		\
112 			.get = __file_wstr_get	\
113 		},				\
114                 .pos = (char *) (_s),           \
115                 .end = (char *) (_s)            \
116 	}
117 
118 #define FDEV_SETUP_STRING_WRITE(_s, _size) {	\
119 		.file = {			\
120 			.flags = __SWR,		\
121 			.put = __file_str_put	\
122 		},				\
123 		.pos = (_s),			\
124                 .end = (_s) + (_size),          \
125 	}
126 
127 #define FDEV_SETUP_STRING_ALLOC() {		\
128 		.file = {			\
129 			.flags = __SWR,		\
130 			.put = __file_str_put_alloc	\
131 		},				\
132 		.pos = NULL,			\
133 		.end = NULL,			\
134                 .size = 0,                      \
135 	}
136 
137 #ifdef POSIX_IO
138 
139 #define FDEV_SETUP_POSIX(fd, buf, size, rwflags, bflags)        \
140         FDEV_SETUP_BUFIO(fd, buf, size,                         \
141                          read, write,                           \
142                          lseek, close, rwflags, bflags)
143 
144 int
145 __posix_sflags (const char *mode, int *optr);
146 
147 static inline int
__stdio_sflags(const char * mode)148 __stdio_sflags (const char *mode)
149 {
150     int omode;
151     return __posix_sflags (mode, &omode);
152 }
153 
154 #else
155 
156 int
157 __stdio_sflags (const char *mode);
158 
159 #endif
160 
161 int	__d_vfprintf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(printf, 2, 0);
162 int	__f_vfprintf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(printf, 2, 0);
163 int	__d_sprintf(char *__s, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 2, 0);
164 int	__f_sprintf(char *__s, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 2, 0);
165 int	__d_snprintf(char *__s, size_t __n, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 3, 0);
166 int	__f_snprintf(char *__s, size_t __n, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 3, 0);
167 
168 #if __SIZEOF_DOUBLE__ == 8
169 #define FLOAT64 double
170 #define _asdouble(x) _asfloat64(x)
171 #elif __SIZEOF_LONG_DOUBLE__ == 8
172 #define FLOAT64 long double
173 #endif
174 
175 #if __SIZEOF_DOUBLE__ == 4
176 #define FLOAT32 double
177 #define _asdouble(x) ((double) _asfloat(x))
178 #elif __SIZEOF_FLOAT__ == 4
179 #define FLOAT32 float
180 #elif __SIZEOF_LONG_DOUBLE__ == 4
181 #define FLOAT32 long double
182 #endif
183 
184 #ifdef FLOAT64
185 FLOAT64
186 __atod_engine(uint64_t m10, int e10);
187 #endif
188 
189 float
190 __atof_engine(uint32_t m10, int e10);
191 
192 #ifdef __SIZEOF_INT128__
193 typedef __uint128_t _u128;
194 typedef __int128_t _i128;
195 #define to_u128(x)              (x)
196 #define from_u128(x)            (x)
197 #define _u128_to_ld(a)          ((long double) (a))
198 #define _u128_is_zero(a)        ((a) == 0)
199 #define _i128_lt_zero(a)        ((_i128) (a) < 0)
200 #define _u128_plus_64(a,b) ((a) + (b))
201 #define _u128_plus(a,b) ((a) + (b))
202 #define _u128_minus(a,b) ((a) - (b))
203 #define _u128_minus_64(a,b) ((a) - (b))
204 #define _u128_times_10(a) ((a) * 10)
205 #define _u128_times_base(a,b)   ((a) * (b))
206 #define _u128_to_ld(a) ((long double) (a))
207 #define _u128_oflow(a)	((a) >= (((((_u128) 0xffffffffffffffffULL) << 64) | 0xffffffffffffffffULL) - 9 / 10))
208 #define _u128_zero	(_u128) 0
209 #define _u128_lshift(a,b)       ((_u128) (a) << (b))
210 #define _u128_lshift_64(a,b)    ((_u128) (a) << (b))
211 #define _u128_rshift(a,b)       ((a) >> (b))
212 #define _i128_rshift(a,b)       ((_i128) (a) >> (b))
213 #define _u128_or_64(a,b)        ((a) | (_u128) (b))
214 #define _u128_and_64(a,b)       ((uint64_t) (a) & (b))
215 #define _u128_or(a,b)           ((a) | (b))
216 #define _u128_and(a,b)          ((a) & (b))
217 #define _u128_eq(a,b)           ((a) == (b))
218 #define _u128_ge(a,b)           ((a) >= (b))
219 #define _i128_ge(a,b)           ((_i128)(a) >= (_i128)(b))
220 #define _u128_lt(a,b)           ((a) < (b))
221 #define _i128_lt(a,b)           ((_i128)(a) < (_i128)(b))
222 #define _u128_not(a)            (~(a))
223 #else
224 typedef struct {
225 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
226     uint64_t	lo, hi;
227 #else
228     uint64_t	hi, lo;
229 #endif
230 } _u128;
231 #define _u128_zero	(_u128) { 0, 0 }
232 
to_u128(uint64_t x)233 static inline _u128 to_u128(uint64_t x)
234 {
235     _u128 a = { .hi = 0, .lo = x };
236     return a;
237 }
238 
from_u128(_u128 a)239 static inline uint64_t from_u128(_u128 a)
240 {
241     return a.lo;
242 }
243 
244 static inline long double
_u128_to_ld(_u128 a)245 _u128_to_ld(_u128 a)
246 {
247     return (long double) a.hi * ((long double) (1LL << 32) * (long double) (1LL << 32)) + (long double) a.lo;
248 }
249 
250 static inline bool
_u128_is_zero(_u128 a)251 _u128_is_zero(_u128 a)
252 {
253     return a.hi == 0 && a.lo == 0;
254 }
255 
256 static inline bool
_i128_lt_zero(_u128 a)257 _i128_lt_zero(_u128 a)
258 {
259     return (int64_t) a.hi < 0;
260 }
261 
262 static inline bool
_u128_eq(_u128 a,_u128 b)263 _u128_eq(_u128 a, _u128 b)
264 {
265     return (a.hi == b.hi) && (a.lo == b.lo);
266 }
267 
268 static inline bool
_u128_lt(_u128 a,_u128 b)269 _u128_lt(_u128 a, _u128 b)
270 {
271     if (a.hi == b.hi)
272         return a.lo < b.lo;
273     return a.hi < b.hi;
274 }
275 
276 static inline bool
_i128_lt(_u128 a,_u128 b)277 _i128_lt(_u128 a, _u128 b)
278 {
279     if (a.hi == b.hi) {
280         if ((int64_t) a.hi < 0)
281             return a.lo > b.lo;
282         else
283             return a.lo < b.lo;
284     }
285     return (int64_t) a.hi < (int64_t) b.hi;
286 }
287 
288 static inline bool
_u128_ge(_u128 a,_u128 b)289 _u128_ge(_u128 a, _u128 b)
290 {
291     if (a.hi == b.hi)
292         return a.lo >= b.lo;
293     return a.hi >= b.hi;
294 }
295 
296 static inline bool
_i128_ge(_u128 a,_u128 b)297 _i128_ge(_u128 a, _u128 b)
298 {
299     if (a.hi == b.hi) {
300         if ((int64_t) a.hi < 0)
301             return a.lo <= b.lo;
302         else
303             return a.lo >= b.lo;
304     }
305     return (int64_t) a.hi >= (int64_t) b.hi;
306 }
307 
308 static inline _u128
_u128_plus_64(_u128 a,uint64_t b)309 _u128_plus_64(_u128 a, uint64_t b)
310 {
311     _u128 v;
312 
313     v.lo = a.lo + b;
314     v.hi = a.hi;
315     if (v.lo < a.lo)
316 	v.hi++;
317     return v;
318 }
319 
320 static inline _u128
_u128_plus(_u128 a,_u128 b)321 _u128_plus(_u128 a, _u128 b)
322 {
323     _u128 v;
324 
325     v.lo = a.lo + b.lo;
326     v.hi = a.hi + b.hi;
327     if (v.lo < a.lo)
328 	v.hi++;
329     return v;
330 }
331 
332 static inline _u128
_u128_minus_64(_u128 a,uint64_t b)333 _u128_minus_64(_u128 a, uint64_t b)
334 {
335     _u128 v;
336 
337     v.lo = a.lo - b;
338     v.hi = a.hi;
339     if (v.lo > a.lo)
340 	v.hi--;
341     return v;
342 }
343 
344 static inline _u128
_u128_minus(_u128 a,_u128 b)345 _u128_minus(_u128 a, _u128 b)
346 {
347     _u128 v;
348 
349     v.lo = a.lo - b.lo;
350     v.hi = a.hi - b.hi;
351     if (v.lo > a.lo)
352 	v.hi--;
353     return v;
354 }
355 
356 static inline _u128
_u128_lshift(_u128 a,int amt)357 _u128_lshift(_u128 a, int amt)
358 {
359     _u128	v;
360 
361     if (amt == 0) {
362         v = a;
363     } else if (amt < 64) {
364         v.lo = a.lo << amt;
365         v.hi = (a.lo >> (64 - amt)) | (a.hi << amt);
366     } else {
367         v.lo = 0;
368         v.hi = a.lo << (amt - 64);
369     }
370     return v;
371 }
372 
373 static inline _u128
_u128_lshift_64(uint64_t a,int amt)374 _u128_lshift_64(uint64_t a, int amt)
375 {
376     _u128	v;
377 
378     if (amt == 0) {
379         v.lo = a;
380         v.hi = 0;
381     } else if (amt < 64) {
382         v.lo = a << amt;
383         v.hi = (a >> (64 - amt));
384     } else {
385         v.lo = 0;
386         v.hi = a << (amt - 64);
387     }
388     return v;
389 }
390 
391 static inline _u128
_u128_rshift(_u128 a,int amt)392 _u128_rshift(_u128 a, int amt)
393 {
394     _u128	v;
395 
396     if (amt == 0) {
397         v = a;
398     } else if (amt < 64) {
399         v.lo = (a.hi << (64 - amt)) | (a.lo >> amt);
400         v.hi = a.hi >> amt;
401     } else {
402         v.hi = 0;
403         v.lo = a.hi >> (amt - 64);
404     }
405     return v;
406 }
407 
408 static inline _u128
_u128_and(_u128 a,_u128 b)409 _u128_and(_u128 a, _u128 b)
410 {
411     _u128       v;
412 
413     v.hi = a.hi & b.hi;
414     v.lo = a.lo & b.lo;
415     return v;
416 }
417 
418 static inline uint64_t
_u128_and_64(_u128 a,uint64_t b)419 _u128_and_64(_u128 a, uint64_t b)
420 {
421     return a.lo & b;
422 }
423 
424 static inline _u128
_u128_or(_u128 a,_u128 b)425 _u128_or(_u128 a, _u128 b)
426 {
427     _u128       v;
428 
429     v.lo = a.lo | b.lo;
430     v.hi = a.hi | b.hi;
431     return v;
432 }
433 
434 static inline _u128
_u128_or_64(_u128 a,uint64_t b)435 _u128_or_64(_u128 a, uint64_t b)
436 {
437     _u128       v;
438 
439     v.lo = a.lo | b;
440     v.hi = a.hi;
441     return v;
442 }
443 
444 static inline _u128
_u128_not(_u128 a)445 _u128_not(_u128 a)
446 {
447     _u128       v;
448 
449     v.lo = ~a.lo;
450     v.hi = ~a.hi;
451     return v;
452 }
453 
454 static inline _u128
_u128_times_10(_u128 a)455 _u128_times_10(_u128 a)
456 {
457     return _u128_plus(_u128_lshift(a, 3), _u128_lshift(a, 1));
458 }
459 
460 static inline _u128
_u128_times_base(_u128 a,int base)461 _u128_times_base(_u128 a, int base)
462 {
463     if (base == 10)
464         return _u128_times_10(a);
465     return _u128_lshift(a, 4);
466 }
467 
468 static inline bool
_u128_oflow(_u128 a)469 _u128_oflow(_u128 a)
470 {
471     return a.hi >= (0xffffffffffffffffULL - 9) / 10;
472 }
473 #endif
474 
475 #if __SIZEOF_LONG_DOUBLE__ > 8
476 static inline _u128
asuintld(long double f)477 asuintld(long double f)
478 {
479     union {
480         long double     f;
481         _u128           i;
482     } v;
483     _u128       i;
484 
485     v.f = f;
486     i = v.i;
487 #if defined(__IEEE_BIG_ENDIAN) && __SIZEOF_LONG_DOUBLE__ != 16
488     i = _u128_rshift(i, (16 - __SIZEOF_LONG_DOUBLE__) * 8);
489 #endif
490     return i;
491 }
492 
493 static inline long double
aslongdouble(_u128 i)494 aslongdouble(_u128 i)
495 {
496     union {
497         long double     f;
498         _u128           i;
499     } v;
500 
501 #if defined(__IEEE_BIG_ENDIAN) && __SIZEOF_LONG_DOUBLE__ != 16
502     i = _u128_lshift(i, (16 - __SIZEOF_LONG_DOUBLE__) * 8);
503 #endif
504     v.i = i;
505     return v.f;
506 }
507 #elif __SIZEOF_LONG_DOUBLE__ == 8
508 static inline uint64_t
asuintld(long double f)509 asuintld(long double f)
510 {
511     union {
512         long double     f;
513         uint64_t        i;
514     } v;
515 
516     v.f = f;
517     return v.i;
518 }
519 
520 static inline long double
aslongdouble(uint64_t i)521 aslongdouble(uint64_t i)
522 {
523     union {
524         long double     f;
525         uint64_t        i;
526     } v;
527 
528     v.i = i;
529     return v.f;
530 }
531 #elif __SIZEOF_LONG_DOUBLE__ == 4
532 static inline uint32_t
asuintld(long double f)533 asuintld(long double f)
534 {
535     union {
536         long double     f;
537         uint32_t        i;
538     } v;
539 
540     v.f = f;
541     return v.i;
542 }
543 
544 static inline long double
aslongdouble(uint32_t i)545 aslongdouble(uint32_t i)
546 {
547     union {
548         long double     f;
549         uint32_t        i;
550     } v;
551 
552     v.i = i;
553     return v.f;
554 }
555 #endif
556 
557 static inline bool
_u128_gt(_u128 a,_u128 b)558 _u128_gt(_u128 a, _u128 b)
559 {
560     return _u128_lt(b, a);
561 }
562 
563 long double
564 __atold_engine(_u128 m10, int e10);
565 
566 static inline uint16_t
__non_atomic_exchange_ungetc(__ungetc_t * p,__ungetc_t v)567 __non_atomic_exchange_ungetc(__ungetc_t *p, __ungetc_t v)
568 {
569 	__ungetc_t e = *p;
570 	*p = v;
571 	return e;
572 }
573 
574 static inline bool
__non_atomic_compare_exchange_ungetc(__ungetc_t * p,__ungetc_t d,__ungetc_t v)575 __non_atomic_compare_exchange_ungetc(__ungetc_t *p, __ungetc_t d, __ungetc_t v)
576 {
577 	if (*p != d)
578 		return false;
579 	*p = v;
580 	return true;
581 }
582 
583 #ifdef ATOMIC_UNGETC
584 
585 #if __PICOLIBC_UNGETC_SIZE == 4 && defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
586 #define PICOLIBC_HAVE_SYNC_COMPARE_AND_SWAP
587 #endif
588 
589 #if __PICOLIBC_UNGETC_SIZE == 2 && defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2)
590 #define PICOLIBC_HAVE_SYNC_COMPARE_AND_SWAP
591 #endif
592 
593 #ifdef PICOLIBC_HAVE_SYNC_COMPARE_AND_SWAP
594 
595 /* Use built-in atomic functions if they exist */
596 #include <stdatomic.h>
597 static inline bool
__atomic_compare_exchange_ungetc(__ungetc_t * p,__ungetc_t d,__ungetc_t v)598 __atomic_compare_exchange_ungetc(__ungetc_t *p, __ungetc_t d, __ungetc_t v)
599 {
600 	_Atomic __ungetc_t *pa = (_Atomic __ungetc_t *) p;
601         return atomic_compare_exchange_strong(pa, &d, v);
602 }
603 
604 static inline __ungetc_t
__atomic_exchange_ungetc(__ungetc_t * p,__ungetc_t v)605 __atomic_exchange_ungetc(__ungetc_t *p, __ungetc_t v)
606 {
607 	_Atomic __ungetc_t *pa = (_Atomic __ungetc_t *) p;
608 	return atomic_exchange_explicit(pa, v, memory_order_relaxed);
609 }
610 
611 #else
612 
613 bool
614 __atomic_compare_exchange_ungetc(__ungetc_t *p, __ungetc_t d, __ungetc_t v);
615 
616 __ungetc_t
617 __atomic_exchange_ungetc(__ungetc_t *p, __ungetc_t v);
618 
619 #endif /* PICOLIBC_HAVE_SYNC_COMPARE_AND_SWAP */
620 
621 #else
622 
623 #define __atomic_compare_exchange_ungetc(p,d,v) __non_atomic_compare_exchange_ungetc(p,d,v)
624 
625 #define __atomic_exchange_ungetc(p,v) __non_atomic_exchange_ungetc(p,v)
626 
627 #endif /* ATOMIC_UNGETC */
628 
629 /*
630  * This operates like _tolower on upper case letters, but also works
631  * correctly on lower case letters.
632  */
633 #define TOLOWER(c)      ((c) | ('a' - 'A'))
634 
635 /*
636  * Convert a single character to the value of the digit for any
637  * character 0 .. 9, A .. Z or a .. z
638  *
639  * Characters out of these ranges will return a value above 36
640  *
641  * Work in unsigned int type to avoid extra instructions required for
642  * unsigned char folding. The only time this matters is when
643  * subtracting '0' from values below '0', which results in very large
644  * unsigned values.
645  */
646 
647 static inline unsigned int
digit_to_val(unsigned int c)648 digit_to_val(unsigned int c)
649 {
650     /*
651      * Convert letters with some tricky code.
652      *
653      * TOLOWER(c-1) maps characters as follows (Skipping values not
654      * greater than '9' (0x39), as those are skipped by the 'if'):
655      *
656      * Minus 1, bitwise-OR ('a' - 'A') (0x20):
657      *
658      *             0x3a..0x40 -> 0x39..0x3f
659      * 0x41..0x60, 0x61..0x80 -> 0x60..0x7f
660      * 0x81..0xa0, 0xa1..0xc0 -> 0xa0..0xbf
661      * 0xc1..0xe0, 0xe1..0x00 -> 0xe0..0xff
662      *
663      * Plus '0' (0x30), minus 'a') (0x61), plus 11 (0xb), for
664      * a total of minus 0x26:
665      *
666      *             0x3a..0x40 -> 0x39..0x3f -> 0x13..0x19
667      * 0x41..0x60, 0x61..0x80 -> 0x60..0x7f -> 0x3a..0x59
668      * 0x81..0xa0, 0xa1..0xc0 -> 0xa0..0xbf -> 0x7a..0x99
669      * 0xc1..0xe0, 0xe1..0x00 -> 0xe0..0xff -> 0xba..0xd9
670      */
671 
672     if (c > '9') {
673 
674         /*
675          * For the letters, we want TOLOWER(c) - 'a' + 10, but that
676          * would map both '@' and '`' to 9.
677          *
678          * To work around this, subtract 1 before the bitwise-or so
679          * that '@' (0x40) gets mapped down to 0x3f (0x3f | 0x20)
680          * while '`' (0x60) gets mapped up to 0x7f (0x5f | 0x20),
681          * moving them away from the letters (which end up in the
682          * range 0x60..0x79). Then add the 1 back in when subtracting
683          * 'a' and adding 10.
684          *
685          * Add in '0' so that it can get subtracted out in the common
686          * code (c -= '0') below, avoiding an else clause.
687          */
688 
689         c = TOLOWER(c-1) + ('0' - 'a' + 11);
690     }
691 
692     /*
693      * Now, include the range from NUL (0x00) through '9' (0x39)
694      *
695      * Minus '0' (0x30):
696      *
697      * 0x00..0x2f                                         ->-0x30..-0x01
698      * 0x30..0x39                                         -> 0x00..0x09 *
699      *             0x3a..0x40 -> 0x39..0x3f -> 0x13..0x19 ->-0x1d..-0x17
700      * 0x41..0x60, 0x61..0x80 -> 0x60..0x7f -> 0x3a..0x59 -> 0x0a..0x29 *
701      * 0x81..0xa0, 0xa1..0xc0 -> 0xa0..0xbf -> 0x7a..0x99 -> 0x4a..0x69
702      * 0xc1..0xe0, 0xe1..0x00 -> 0xe0..0xff -> 0xba..0xd9 -> 0x8a..0xa9
703      *
704      * The first starred row has the digits '0'..'9', while the second
705      * starts with the letters 'A'..'Z' and 'a'..'z'. All of the other
706      * rows end up with values above any allowed conversion base
707      */
708 
709     c -= '0';
710     return c;
711 }
712 
713 #endif /* _STDIO_PRIVATE_H_ */
714