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 <limits.h>
49 #include <stdio-bufio.h>
50 #include <sys/lock.h>
51 
52 /* values for PRINTF_LEVEL */
53 #define PRINTF_MIN 1
54 #define PRINTF_STD 2
55 #define PRINTF_LLONG 3
56 #define PRINTF_FLT 4
57 #define PRINTF_DBL 5
58 
59 /* values for SCANF_LEVEL */
60 #define SCANF_MIN 1
61 #define SCANF_STD 2
62 #define SCANF_LLONG 3
63 #define SCANF_FLT 4
64 #define SCANF_DBL 5
65 
66 struct __file_str {
67 	struct __file file;	/* main file struct */
68         char	*pos;		/* current buffer position */
69         char    *end;           /* end of buffer */
70         size_t  size;           /* size of allocated storage */
71 };
72 
73 int
74 __file_str_get(FILE *stream);
75 
76 int
77 __file_wstr_get(FILE *stream);
78 
79 int
80 __file_str_put(char c, FILE *stream);
81 
82 int
83 __file_str_put_alloc(char c, FILE *stream);
84 
85 extern const char __match_inf[];
86 extern const char __match_inity[];
87 extern const char __match_nan[];
88 
89 /* Returns 'true' if prefix of input matches pattern, independent of
90  * case. pattern is only upper case letters.
91  */
92 bool __matchcaseprefix(const char *input, const char *pattern);
93 
94 /*
95  * It is OK to discard the "const" qualifier here.  f.buf is
96  * non-const as in the generic case, this buffer is obtained
97  * by malloc().  In the scanf case however, the buffer is
98  * really only be read (by getc()), and as this our FILE f we
99  * be discarded upon exiting sscanf(), nobody will ever get
100  * a chance to get write access to it again.
101  */
102 #define FDEV_SETUP_STRING_READ(_s) {		\
103 		.file = {			\
104 			.flags = __SRD,		\
105 			.get = __file_str_get	\
106 		},				\
107 		.pos = (char *) (_s)		\
108 	}
109 
110 #define FDEV_SETUP_WSTRING_READ(_s) {		\
111 		.file = {			\
112 			.flags = __SRD,		\
113 			.get = __file_wstr_get	\
114 		},				\
115                 .pos = (char *) (_s),           \
116                 .end = (char *) (_s)            \
117 	}
118 
119 #define FDEV_SETUP_STRING_WRITE(_s, _size) {	\
120 		.file = {			\
121 			.flags = __SWR,		\
122 			.put = __file_str_put	\
123 		},				\
124 		.pos = (_s),			\
125                 .end = (_s) + (_size),          \
126 	}
127 
128 #define FDEV_SETUP_STRING_ALLOC() {		\
129 		.file = {			\
130 			.flags = __SWR,		\
131 			.put = __file_str_put_alloc	\
132 		},				\
133 		.pos = NULL,			\
134 		.end = NULL,			\
135                 .size = 0,                      \
136 	}
137 
138 #define _FDEV_BUFIO_FD(bf) ((int)((intptr_t) (bf)->ptr))
139 
140 
141 /*
142  * While there are notionally two different ways to invoke the
143  * callbacks (one with an int and the other with a pointer), they are
144  * functionally identical on many architectures. Check for that and
145  * skip the extra code.
146  */
147 #if __SIZEOF_POINTER__ == __SIZEOF_INT__ || defined(__x86_64) || defined(__arm__) || defined(__riscv)
148 #define BUFIO_ABI_MATCHES
149 #endif
150 
151 /* Buffered I/O routines for tiny stdio */
152 
bufio_read(struct __file_bufio * bf,void * buf,size_t count)153 static inline ssize_t bufio_read(struct __file_bufio *bf, void *buf, size_t count)
154 {
155 #ifndef BUFIO_ABI_MATCHES
156     if (!(bf->bflags & __BFPTR))
157         return (bf->read_int)(_FDEV_BUFIO_FD(bf), buf, count);
158 #endif
159     return (bf->read_ptr)((void *) bf->ptr, buf, count);
160 }
161 
bufio_write(struct __file_bufio * bf,const void * buf,size_t count)162 static inline ssize_t bufio_write(struct __file_bufio *bf, const void *buf, size_t count)
163 {
164 #ifndef BUFIO_ABI_MATCHES
165     if (!(bf->bflags & __BFPTR))
166         return (bf->write_int)(_FDEV_BUFIO_FD(bf), buf, count);
167 #endif
168     return (bf->write_ptr)((void *) bf->ptr, buf, count);
169 }
170 
bufio_lseek(struct __file_bufio * bf,__off_t offset,int whence)171 static inline __off_t bufio_lseek(struct __file_bufio *bf, __off_t offset, int whence)
172 {
173 #ifndef BUFIO_ABI_MATCHES
174     if (!(bf->bflags & __BFPTR)) {
175         if (bf->lseek_int)
176             return (bf->lseek_int)(_FDEV_BUFIO_FD(bf), offset, whence);
177     } else
178 #endif
179     {
180         if (bf->lseek_ptr)
181             return (bf->lseek_ptr)((void *) bf->ptr, offset, whence);
182     }
183     return _FDEV_ERR;
184 }
185 
bufio_close(struct __file_bufio * bf)186 static inline int bufio_close(struct __file_bufio *bf)
187 {
188     int ret = 0;
189 #ifndef BUFIO_ABI_MATCHES
190     if (!(bf->bflags & __BFPTR)) {
191         if (bf->close_int)
192             ret = (bf->close_int)(_FDEV_BUFIO_FD(bf));
193     } else
194 #endif
195     {
196         if (bf->close_ptr)
197             ret = (bf->close_ptr)((void *) bf->ptr);
198     }
199     return ret;
200 }
201 
202 #ifdef POSIX_IO
203 
204 #define FDEV_SETUP_POSIX(fd, buf, size, rwflags, bflags)        \
205         FDEV_SETUP_BUFIO(fd, buf, size,                         \
206                          read, write,                           \
207                          lseek, close, rwflags, bflags)
208 
209 int
210 __posix_sflags (const char *mode, int *optr);
211 
212 static inline int
__stdio_sflags(const char * mode)213 __stdio_sflags (const char *mode)
214 {
215     int omode;
216     return __posix_sflags (mode, &omode);
217 }
218 
219 #else
220 
221 int
222 __stdio_sflags (const char *mode);
223 
224 #endif
225 
226 int	__d_vfprintf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(printf, 2, 0);
227 int	__f_vfprintf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(printf, 2, 0);
228 int	__i_vfprintf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(printf, 2, 0);
229 int	__l_vfprintf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(printf, 2, 0);
230 int	__m_vfprintf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(printf, 2, 0);
231 
232 int	__d_sprintf(char *__s, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 2, 0);
233 int	__f_sprintf(char *__s, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 2, 0);
234 int	__i_sprintf(char *__s, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 2, 0);
235 int	__l_sprintf(char *__s, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 2, 0);
236 int	__m_sprintf(char *__s, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 2, 0);
237 
238 int	__d_snprintf(char *__s, size_t __n, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 3, 0);
239 int	__f_snprintf(char *__s, size_t __n, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 3, 0);
240 int	__i_snprintf(char *__s, size_t __n, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 3, 0);
241 int	__l_snprintf(char *__s, size_t __n, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 3, 0);
242 int	__m_snprintf(char *__s, size_t __n, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 3, 0);
243 
244 int	__d_vfscanf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(scanf, 2, 0);
245 int	__f_vfscanf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(scanf, 2, 0);
246 int	__i_vfscanf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(scanf, 2, 0);
247 int	__l_vfscanf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(scanf, 2, 0);
248 int	__m_vfscanf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(scanf, 2, 0);
249 
250 #if __SIZEOF_DOUBLE__ == 8
251 #define FLOAT64 double
252 #define _asdouble(x) _asfloat64(x)
253 #elif __SIZEOF_LONG_DOUBLE__ == 8
254 #define FLOAT64 long double
255 #endif
256 
257 #if __SIZEOF_DOUBLE__ == 4
258 #define FLOAT32 double
259 #define _asdouble(x) ((double) _asfloat(x))
260 #elif __SIZEOF_FLOAT__ == 4
261 #define FLOAT32 float
262 #elif __SIZEOF_LONG_DOUBLE__ == 4
263 #define FLOAT32 long double
264 #endif
265 
266 #ifdef FLOAT64
267 FLOAT64
268 __atod_engine(uint64_t m10, int e10);
269 #endif
270 
271 float
272 __atof_engine(uint32_t m10, int e10);
273 
274 #ifdef __SIZEOF_INT128__
275 typedef __uint128_t _u128;
276 typedef __int128_t _i128;
277 #define to_u128(x)              (x)
278 #define from_u128(x)            (x)
279 #define _u128_to_ld(a)          ((long double) (a))
280 #define _u128_is_zero(a)        ((a) == 0)
281 #define _i128_lt_zero(a)        ((_i128) (a) < 0)
282 #define _u128_plus_64(a,b) ((a) + (b))
283 #define _u128_plus(a,b) ((a) + (b))
284 #define _u128_minus(a,b) ((a) - (b))
285 #define _u128_minus_64(a,b) ((a) - (b))
286 #define _u128_times_10(a) ((a) * 10)
287 #define _u128_times_base(a,b)   ((a) * (b))
288 #define _u128_to_ld(a) ((long double) (a))
289 #define _u128_oflow(a)	((a) >= (((((_u128) 0xffffffffffffffffULL) << 64) | 0xffffffffffffffffULL) - 9 / 10))
290 #define _u128_zero	(_u128) 0
291 #define _u128_lshift(a,b)       ((_u128) (a) << (b))
292 #define _u128_lshift_64(a,b)    ((_u128) (a) << (b))
293 #define _u128_rshift(a,b)       ((a) >> (b))
294 #define _i128_rshift(a,b)       ((_i128) (a) >> (b))
295 #define _u128_or_64(a,b)        ((a) | (_u128) (b))
296 #define _u128_and_64(a,b)       ((uint64_t) (a) & (b))
297 #define _u128_or(a,b)           ((a) | (b))
298 #define _u128_and(a,b)          ((a) & (b))
299 #define _u128_eq(a,b)           ((a) == (b))
300 #define _u128_ge(a,b)           ((a) >= (b))
301 #define _i128_ge(a,b)           ((_i128)(a) >= (_i128)(b))
302 #define _u128_lt(a,b)           ((a) < (b))
303 #define _i128_lt(a,b)           ((_i128)(a) < (_i128)(b))
304 #define _u128_not(a)            (~(a))
305 #else
306 typedef struct {
307 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
308     uint64_t	lo, hi;
309 #else
310     uint64_t	hi, lo;
311 #endif
312 } _u128;
313 #define _u128_zero	(_u128) { 0, 0 }
314 
to_u128(uint64_t x)315 static inline _u128 to_u128(uint64_t x)
316 {
317     _u128 a = { .hi = 0, .lo = x };
318     return a;
319 }
320 
from_u128(_u128 a)321 static inline uint64_t from_u128(_u128 a)
322 {
323     return a.lo;
324 }
325 
326 static inline long double
_u128_to_ld(_u128 a)327 _u128_to_ld(_u128 a)
328 {
329     return (long double) a.hi * ((long double) (1LL << 32) * (long double) (1LL << 32)) + (long double) a.lo;
330 }
331 
332 static inline bool
_u128_is_zero(_u128 a)333 _u128_is_zero(_u128 a)
334 {
335     return a.hi == 0 && a.lo == 0;
336 }
337 
338 static inline bool
_i128_lt_zero(_u128 a)339 _i128_lt_zero(_u128 a)
340 {
341     return (int64_t) a.hi < 0;
342 }
343 
344 static inline bool
_u128_eq(_u128 a,_u128 b)345 _u128_eq(_u128 a, _u128 b)
346 {
347     return (a.hi == b.hi) && (a.lo == b.lo);
348 }
349 
350 static inline bool
_u128_lt(_u128 a,_u128 b)351 _u128_lt(_u128 a, _u128 b)
352 {
353     if (a.hi == b.hi)
354         return a.lo < b.lo;
355     return a.hi < b.hi;
356 }
357 
358 static inline bool
_i128_lt(_u128 a,_u128 b)359 _i128_lt(_u128 a, _u128 b)
360 {
361     if (a.hi == b.hi) {
362         if ((int64_t) a.hi < 0)
363             return a.lo > b.lo;
364         else
365             return a.lo < b.lo;
366     }
367     return (int64_t) a.hi < (int64_t) b.hi;
368 }
369 
370 static inline bool
_u128_ge(_u128 a,_u128 b)371 _u128_ge(_u128 a, _u128 b)
372 {
373     if (a.hi == b.hi)
374         return a.lo >= b.lo;
375     return a.hi >= b.hi;
376 }
377 
378 static inline bool
_i128_ge(_u128 a,_u128 b)379 _i128_ge(_u128 a, _u128 b)
380 {
381     if (a.hi == b.hi) {
382         if ((int64_t) a.hi < 0)
383             return a.lo <= b.lo;
384         else
385             return a.lo >= b.lo;
386     }
387     return (int64_t) a.hi >= (int64_t) b.hi;
388 }
389 
390 static inline _u128
_u128_plus_64(_u128 a,uint64_t b)391 _u128_plus_64(_u128 a, uint64_t b)
392 {
393     _u128 v;
394 
395     v.lo = a.lo + b;
396     v.hi = a.hi;
397     if (v.lo < a.lo)
398 	v.hi++;
399     return v;
400 }
401 
402 static inline _u128
_u128_plus(_u128 a,_u128 b)403 _u128_plus(_u128 a, _u128 b)
404 {
405     _u128 v;
406 
407     v.lo = a.lo + b.lo;
408     v.hi = a.hi + b.hi;
409     if (v.lo < a.lo)
410 	v.hi++;
411     return v;
412 }
413 
414 static inline _u128
_u128_minus_64(_u128 a,uint64_t b)415 _u128_minus_64(_u128 a, uint64_t b)
416 {
417     _u128 v;
418 
419     v.lo = a.lo - b;
420     v.hi = a.hi;
421     if (v.lo > a.lo)
422 	v.hi--;
423     return v;
424 }
425 
426 static inline _u128
_u128_minus(_u128 a,_u128 b)427 _u128_minus(_u128 a, _u128 b)
428 {
429     _u128 v;
430 
431     v.lo = a.lo - b.lo;
432     v.hi = a.hi - b.hi;
433     if (v.lo > a.lo)
434 	v.hi--;
435     return v;
436 }
437 
438 static inline _u128
_u128_lshift(_u128 a,int amt)439 _u128_lshift(_u128 a, int amt)
440 {
441     _u128	v;
442 
443     if (amt == 0) {
444         v = a;
445     } else if (amt < 64) {
446         v.lo = a.lo << amt;
447         v.hi = (a.lo >> (64 - amt)) | (a.hi << amt);
448     } else {
449         v.lo = 0;
450         v.hi = a.lo << (amt - 64);
451     }
452     return v;
453 }
454 
455 static inline _u128
_u128_lshift_64(uint64_t a,int amt)456 _u128_lshift_64(uint64_t a, int amt)
457 {
458     _u128	v;
459 
460     if (amt == 0) {
461         v.lo = a;
462         v.hi = 0;
463     } else if (amt < 64) {
464         v.lo = a << amt;
465         v.hi = (a >> (64 - amt));
466     } else {
467         v.lo = 0;
468         v.hi = a << (amt - 64);
469     }
470     return v;
471 }
472 
473 static inline _u128
_u128_rshift(_u128 a,int amt)474 _u128_rshift(_u128 a, int amt)
475 {
476     _u128	v;
477 
478     if (amt == 0) {
479         v = a;
480     } else if (amt < 64) {
481         v.lo = (a.hi << (64 - amt)) | (a.lo >> amt);
482         v.hi = a.hi >> amt;
483     } else {
484         v.hi = 0;
485         v.lo = a.hi >> (amt - 64);
486     }
487     return v;
488 }
489 
490 static inline _u128
_u128_and(_u128 a,_u128 b)491 _u128_and(_u128 a, _u128 b)
492 {
493     _u128       v;
494 
495     v.hi = a.hi & b.hi;
496     v.lo = a.lo & b.lo;
497     return v;
498 }
499 
500 static inline uint64_t
_u128_and_64(_u128 a,uint64_t b)501 _u128_and_64(_u128 a, uint64_t b)
502 {
503     return a.lo & b;
504 }
505 
506 static inline _u128
_u128_or(_u128 a,_u128 b)507 _u128_or(_u128 a, _u128 b)
508 {
509     _u128       v;
510 
511     v.lo = a.lo | b.lo;
512     v.hi = a.hi | b.hi;
513     return v;
514 }
515 
516 static inline _u128
_u128_or_64(_u128 a,uint64_t b)517 _u128_or_64(_u128 a, uint64_t b)
518 {
519     _u128       v;
520 
521     v.lo = a.lo | b;
522     v.hi = a.hi;
523     return v;
524 }
525 
526 static inline _u128
_u128_not(_u128 a)527 _u128_not(_u128 a)
528 {
529     _u128       v;
530 
531     v.lo = ~a.lo;
532     v.hi = ~a.hi;
533     return v;
534 }
535 
536 static inline _u128
_u128_times_10(_u128 a)537 _u128_times_10(_u128 a)
538 {
539     return _u128_plus(_u128_lshift(a, 3), _u128_lshift(a, 1));
540 }
541 
542 static inline _u128
_u128_times_base(_u128 a,int base)543 _u128_times_base(_u128 a, int base)
544 {
545     if (base == 10)
546         return _u128_times_10(a);
547     return _u128_lshift(a, 4);
548 }
549 
550 static inline bool
_u128_oflow(_u128 a)551 _u128_oflow(_u128 a)
552 {
553     return a.hi >= (0xffffffffffffffffULL - 9) / 10;
554 }
555 #endif
556 
557 #if __SIZEOF_LONG_DOUBLE__ > 8
558 static inline _u128
asuintld(long double f)559 asuintld(long double f)
560 {
561     union {
562         long double     f;
563         _u128           i;
564     } v;
565     _u128       i;
566 
567     v.f = f;
568     i = v.i;
569 #if defined(__IEEE_BIG_ENDIAN) && __SIZEOF_LONG_DOUBLE__ != 16
570     i = _u128_rshift(i, (16 - __SIZEOF_LONG_DOUBLE__) * 8);
571 #endif
572     return i;
573 }
574 
575 static inline long double
aslongdouble(_u128 i)576 aslongdouble(_u128 i)
577 {
578     union {
579         long double     f;
580         _u128           i;
581     } v;
582 
583 #if defined(__IEEE_BIG_ENDIAN) && __SIZEOF_LONG_DOUBLE__ != 16
584     i = _u128_lshift(i, (16 - __SIZEOF_LONG_DOUBLE__) * 8);
585 #endif
586     v.i = i;
587     return v.f;
588 }
589 #elif __SIZEOF_LONG_DOUBLE__ == 8
590 static inline uint64_t
asuintld(long double f)591 asuintld(long double f)
592 {
593     union {
594         long double     f;
595         uint64_t        i;
596     } v;
597 
598     v.f = f;
599     return v.i;
600 }
601 
602 static inline long double
aslongdouble(uint64_t i)603 aslongdouble(uint64_t i)
604 {
605     union {
606         long double     f;
607         uint64_t        i;
608     } v;
609 
610     v.i = i;
611     return v.f;
612 }
613 #elif __SIZEOF_LONG_DOUBLE__ == 4
614 static inline uint32_t
asuintld(long double f)615 asuintld(long double f)
616 {
617     union {
618         long double     f;
619         uint32_t        i;
620     } v;
621 
622     v.f = f;
623     return v.i;
624 }
625 
626 static inline long double
aslongdouble(uint32_t i)627 aslongdouble(uint32_t i)
628 {
629     union {
630         long double     f;
631         uint32_t        i;
632     } v;
633 
634     v.i = i;
635     return v.f;
636 }
637 #endif
638 
639 static inline bool
_u128_gt(_u128 a,_u128 b)640 _u128_gt(_u128 a, _u128 b)
641 {
642     return _u128_lt(b, a);
643 }
644 
645 long double
646 __atold_engine(_u128 m10, int e10);
647 
648 static inline uint16_t
__non_atomic_exchange_ungetc(__ungetc_t * p,__ungetc_t v)649 __non_atomic_exchange_ungetc(__ungetc_t *p, __ungetc_t v)
650 {
651 	__ungetc_t e = *p;
652 	*p = v;
653 	return e;
654 }
655 
656 static inline bool
__non_atomic_compare_exchange_ungetc(__ungetc_t * p,__ungetc_t d,__ungetc_t v)657 __non_atomic_compare_exchange_ungetc(__ungetc_t *p, __ungetc_t d, __ungetc_t v)
658 {
659 	if (*p != d)
660 		return false;
661 	*p = v;
662 	return true;
663 }
664 
665 static inline uint16_t
__non_atomic_load_ungetc(const volatile __ungetc_t * p)666 __non_atomic_load_ungetc(const volatile __ungetc_t *p)
667 {
668         return *p;
669 }
670 
671 #ifdef ATOMIC_UNGETC
672 
673 #if __PICOLIBC_UNGETC_SIZE == 4 && defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
674 #define PICOLIBC_HAVE_SYNC_COMPARE_AND_SWAP
675 #endif
676 
677 #if __PICOLIBC_UNGETC_SIZE == 2 && defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2)
678 #define PICOLIBC_HAVE_SYNC_COMPARE_AND_SWAP
679 #endif
680 
681 #ifdef PICOLIBC_HAVE_SYNC_COMPARE_AND_SWAP
682 
683 /* Use built-in atomic functions if they exist */
684 #include <stdatomic.h>
685 static inline bool
__atomic_compare_exchange_ungetc(__ungetc_t * p,__ungetc_t d,__ungetc_t v)686 __atomic_compare_exchange_ungetc(__ungetc_t *p, __ungetc_t d, __ungetc_t v)
687 {
688 	_Atomic __ungetc_t *pa = (_Atomic __ungetc_t *) p;
689         return atomic_compare_exchange_strong(pa, &d, v);
690 }
691 
692 static inline __ungetc_t
__atomic_exchange_ungetc(__ungetc_t * p,__ungetc_t v)693 __atomic_exchange_ungetc(__ungetc_t *p, __ungetc_t v)
694 {
695 	_Atomic __ungetc_t *pa = (_Atomic __ungetc_t *) p;
696 	return atomic_exchange_explicit(pa, v, memory_order_relaxed);
697 }
698 
699 static inline __ungetc_t
__atomic_load_ungetc(const volatile __ungetc_t * p)700 __atomic_load_ungetc(const volatile __ungetc_t *p)
701 {
702 	_Atomic __ungetc_t *pa = (_Atomic __ungetc_t *) p;
703         return atomic_load(pa);
704 }
705 #else
706 
707 bool
708 __atomic_compare_exchange_ungetc(__ungetc_t *p, __ungetc_t d, __ungetc_t v);
709 
710 __ungetc_t
711 __atomic_exchange_ungetc(__ungetc_t *p, __ungetc_t v);
712 
713 __ungetc_t
714 __atomic_load_ungetc(const volatile __ungetc_t *p);
715 
716 __ungetc_t
717 __picolibc_non_atomic_load_ungetc(const volatile __ungetc_t *p);
718 
719 __ungetc_t
720 __picolibc_non_atomic_exchange_ungetc(__ungetc_t *p, __ungetc_t v);
721 
722 bool
723 __picolibc_non_atomic_compare_exchange_ungetc(__ungetc_t *p,
724                                               __ungetc_t d, __ungetc_t v);
725 
726 #endif /* PICOLIBC_HAVE_SYNC_COMPARE_AND_SWAP */
727 
728 #else
729 
730 #define __atomic_compare_exchange_ungetc(p,d,v) __non_atomic_compare_exchange_ungetc(p,d,v)
731 
732 #define __atomic_exchange_ungetc(p,v) __non_atomic_exchange_ungetc(p,v)
733 
734 #define __atomic_load_ungetc(p) (*(p))
735 
736 #endif /* ATOMIC_UNGETC */
737 
738 /*
739  * This operates like _tolower on upper case letters, but also works
740  * correctly on lower case letters.
741  */
742 #define TOLOWER(c)      ((c) | ('a' - 'A'))
743 
744 /*
745  * Convert a single character to the value of the digit for any
746  * character 0 .. 9, A .. Z or a .. z
747  *
748  * Characters out of these ranges will return a value above 36
749  *
750  * Work in unsigned int type to avoid extra instructions required for
751  * unsigned char folding. The only time this matters is when
752  * subtracting '0' from values below '0', which results in very large
753  * unsigned values.
754  */
755 
756 static inline unsigned int
digit_to_val(unsigned int c)757 digit_to_val(unsigned int c)
758 {
759     /*
760      * Convert letters with some tricky code.
761      *
762      * TOLOWER(c-1) maps characters as follows (Skipping values not
763      * greater than '9' (0x39), as those are skipped by the 'if'):
764      *
765      * Minus 1, bitwise-OR ('a' - 'A') (0x20):
766      *
767      *             0x3a..0x40 -> 0x39..0x3f
768      * 0x41..0x60, 0x61..0x80 -> 0x60..0x7f
769      * 0x81..0xa0, 0xa1..0xc0 -> 0xa0..0xbf
770      * 0xc1..0xe0, 0xe1..0x00 -> 0xe0..0xff
771      *
772      * Plus '0' (0x30), minus 'a') (0x61), plus 11 (0xb), for
773      * a total of minus 0x26:
774      *
775      *             0x3a..0x40 -> 0x39..0x3f -> 0x13..0x19
776      * 0x41..0x60, 0x61..0x80 -> 0x60..0x7f -> 0x3a..0x59
777      * 0x81..0xa0, 0xa1..0xc0 -> 0xa0..0xbf -> 0x7a..0x99
778      * 0xc1..0xe0, 0xe1..0x00 -> 0xe0..0xff -> 0xba..0xd9
779      */
780 
781     if (c > '9') {
782 
783         /*
784          * For the letters, we want TOLOWER(c) - 'a' + 10, but that
785          * would map both '@' and '`' to 9.
786          *
787          * To work around this, subtract 1 before the bitwise-or so
788          * that '@' (0x40) gets mapped down to 0x3f (0x3f | 0x20)
789          * while '`' (0x60) gets mapped up to 0x7f (0x5f | 0x20),
790          * moving them away from the letters (which end up in the
791          * range 0x60..0x79). Then add the 1 back in when subtracting
792          * 'a' and adding 10.
793          *
794          * Add in '0' so that it can get subtracted out in the common
795          * code (c -= '0') below, avoiding an else clause.
796          */
797 
798         c = TOLOWER(c-1) + ('0' - 'a' + 11);
799     }
800 
801     /*
802      * Now, include the range from NUL (0x00) through '9' (0x39)
803      *
804      * Minus '0' (0x30):
805      *
806      * 0x00..0x2f                                         ->-0x30..-0x01
807      * 0x30..0x39                                         -> 0x00..0x09 *
808      *             0x3a..0x40 -> 0x39..0x3f -> 0x13..0x19 ->-0x1d..-0x17
809      * 0x41..0x60, 0x61..0x80 -> 0x60..0x7f -> 0x3a..0x59 -> 0x0a..0x29 *
810      * 0x81..0xa0, 0xa1..0xc0 -> 0xa0..0xbf -> 0x7a..0x99 -> 0x4a..0x69
811      * 0xc1..0xe0, 0xe1..0x00 -> 0xe0..0xff -> 0xba..0xd9 -> 0x8a..0xa9
812      *
813      * The first starred row has the digits '0'..'9', while the second
814      * starts with the letters 'A'..'Z' and 'a'..'z'. All of the other
815      * rows end up with values above any allowed conversion base
816      */
817 
818     c -= '0';
819     return c;
820 }
821 
822 #endif /* _STDIO_PRIVATE_H_ */
823