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