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