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 #include <stdio-bufio.h>
36 #include <stdbool.h>
37 #include <sys/lock.h>
38
39 /* values for PRINTF_LEVEL */
40 #define PRINTF_STD 1
41 #define PRINTF_FLT 2
42
43 /* values for SCANF_LEVEL */
44 #define SCANF_STD 1
45 #define SCANF_FLT 2
46
47 struct __file_str {
48 struct __file file; /* main file struct */
49 char *pos; /* current buffer position */
50 char *end; /* end of buffer */
51 size_t size; /* size of allocated storage */
52 };
53
54 int
55 __file_str_get(FILE *stream);
56
57 int
58 __file_wstr_get(FILE *stream);
59
60 int
61 __file_str_put(char c, FILE *stream);
62
63 int
64 __file_str_put_alloc(char c, FILE *stream);
65
66 extern const char __match_inf[];
67 extern const char __match_inity[];
68 extern const char __match_nan[];
69
70 /* Returns 'true' if prefix of input matches pattern, independent of
71 * case. pattern is only upper case letters.
72 */
73 bool __matchcaseprefix(const char *input, const char *pattern);
74
75 /*
76 * It is OK to discard the "const" qualifier here. f.buf is
77 * non-const as in the generic case, this buffer is obtained
78 * by malloc(). In the scanf case however, the buffer is
79 * really only be read (by getc()), and as this our FILE f we
80 * be discarded upon exiting sscanf(), nobody will ever get
81 * a chance to get write access to it again.
82 */
83 #define FDEV_SETUP_STRING_READ(_s) { \
84 .file = { \
85 .flags = __SRD, \
86 .get = __file_str_get \
87 }, \
88 .pos = (char *) (_s) \
89 }
90
91 #define FDEV_SETUP_WSTRING_READ(_s) { \
92 .file = { \
93 .flags = __SRD, \
94 .get = __file_wstr_get \
95 }, \
96 .pos = (char *) (_s), \
97 .end = (char *) (_s) \
98 }
99
100 #define FDEV_SETUP_STRING_WRITE(_s, _size) { \
101 .file = { \
102 .flags = __SWR, \
103 .put = __file_str_put \
104 }, \
105 .pos = (_s), \
106 .end = (_s) + (_size), \
107 }
108
109 #define FDEV_SETUP_STRING_ALLOC() { \
110 .file = { \
111 .flags = __SWR, \
112 .put = __file_str_put_alloc \
113 }, \
114 .pos = NULL, \
115 .end = NULL, \
116 .size = 0, \
117 }
118
119 #ifdef POSIX_IO
120
121 #define FDEV_SETUP_POSIX(fd, buf, size, rwflags, bflags) \
122 FDEV_SETUP_BUFIO(fd, buf, size, \
123 read, write, \
124 lseek, close, rwflags, bflags)
125
126 int
127 __posix_sflags (const char *mode, int *optr);
128
129 #endif
130
131 int __d_vfprintf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(printf, 2, 0);
132 int __f_vfprintf(FILE *__stream, const char *__fmt, va_list __ap) __FORMAT_ATTRIBUTE__(printf, 2, 0);
133 int __d_sprintf(char *__s, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 2, 0);
134 int __f_sprintf(char *__s, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 2, 0);
135 int __d_snprintf(char *__s, size_t __n, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 3, 0);
136 int __f_snprintf(char *__s, size_t __n, const char *__fmt, ...) __FORMAT_ATTRIBUTE__(printf, 3, 0);
137
138 double
139 __atod_engine(uint64_t m10, int e10);
140
141 float
142 __atof_engine(uint32_t m10, int e10);
143
144 #ifdef __SIZEOF_INT128__
145 typedef __uint128_t _u128;
146 typedef __int128_t _i128;
147 #define to_u128(x) (x)
148 #define from_u128(x) (x)
149 #define _u128_to_ld(a) ((long double) (a))
150 #define _u128_is_zero(a) ((a) == 0)
151 #define _i128_lt_zero(a) ((_i128) (a) < 0)
152 #define _u128_plus_64(a,b) ((a) + (b))
153 #define _u128_plus(a,b) ((a) + (b))
154 #define _u128_minus(a,b) ((a) - (b))
155 #define _u128_minus_64(a,b) ((a) - (b))
156 #define _u128_times_10(a) ((a) * 10)
157 #define _u128_times_base(a,b) ((a) * (b))
158 #define _u128_to_ld(a) ((long double) (a))
159 #define _u128_oflow(a) ((a) >= (((((_u128) 0xffffffffffffffffULL) << 64) | 0xffffffffffffffffULL) - 9 / 10))
160 #define _u128_zero (_u128) 0
161 #define _u128_lshift(a,b) ((_u128) (a) << (b))
162 #define _u128_lshift_64(a,b) ((_u128) (a) << (b))
163 #define _u128_rshift(a,b) ((a) >> (b))
164 #define _i128_rshift(a,b) ((_i128) (a) >> (b))
165 #define _u128_or_64(a,b) ((a) | (_u128) (b))
166 #define _u128_and_64(a,b) ((uint64_t) (a) & (b))
167 #define _u128_or(a,b) ((a) | (b))
168 #define _u128_and(a,b) ((a) & (b))
169 #define _u128_ge(a,b) ((a) >= (b))
170 #define _i128_ge(a,b) ((_i128)(a) >= (_i128)(b))
171 #define _u128_lt(a,b) ((a) < (b))
172 #define _i128_lt(a,b) ((_i128)(a) < (_i128)(b))
173 #define _u128_not(a) (~(a))
174 #else
175 typedef struct {
176 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
177 uint64_t lo, hi;
178 #else
179 uint64_t hi, lo;
180 #endif
181 } _u128;
182 #define _u128_zero (_u128) { 0, 0 }
183
to_u128(uint64_t x)184 static inline _u128 to_u128(uint64_t x)
185 {
186 _u128 a = { .hi = 0, .lo = x };
187 return a;
188 }
189
from_u128(_u128 a)190 static inline uint64_t from_u128(_u128 a)
191 {
192 return a.lo;
193 }
194
195 static inline long double
_u128_to_ld(_u128 a)196 _u128_to_ld(_u128 a)
197 {
198 return (long double) a.hi * ((long double) (1LL << 32) * (long double) (1LL << 32)) + (long double) a.lo;
199 }
200
201 static inline bool
_u128_is_zero(_u128 a)202 _u128_is_zero(_u128 a)
203 {
204 return a.hi == 0 && a.lo == 0;
205 }
206
207 static inline bool
_i128_lt_zero(_u128 a)208 _i128_lt_zero(_u128 a)
209 {
210 return (int64_t) a.hi < 0;
211 }
212
213 static inline bool
_u128_lt(_u128 a,_u128 b)214 _u128_lt(_u128 a, _u128 b)
215 {
216 if (a.hi == b.hi)
217 return a.lo < b.lo;
218 return a.hi < b.hi;
219 }
220
221 static inline bool
_i128_lt(_u128 a,_u128 b)222 _i128_lt(_u128 a, _u128 b)
223 {
224 if (a.hi == b.hi) {
225 if ((int64_t) a.hi < 0)
226 return a.lo > b.lo;
227 else
228 return a.lo < b.lo;
229 }
230 return (int64_t) a.hi < (int64_t) b.hi;
231 }
232
233 static inline bool
_u128_ge(_u128 a,_u128 b)234 _u128_ge(_u128 a, _u128 b)
235 {
236 if (a.hi == b.hi)
237 return a.lo >= b.lo;
238 return a.hi >= b.hi;
239 }
240
241 static inline bool
_i128_ge(_u128 a,_u128 b)242 _i128_ge(_u128 a, _u128 b)
243 {
244 if (a.hi == b.hi) {
245 if ((int64_t) a.hi < 0)
246 return a.lo <= b.lo;
247 else
248 return a.lo >= b.lo;
249 }
250 return (int64_t) a.hi >= (int64_t) b.hi;
251 }
252
253 static inline _u128
_u128_plus_64(_u128 a,uint64_t b)254 _u128_plus_64(_u128 a, uint64_t b)
255 {
256 _u128 v;
257
258 v.lo = a.lo + b;
259 v.hi = a.hi;
260 if (v.lo < a.lo)
261 v.hi++;
262 return v;
263 }
264
265 static inline _u128
_u128_plus(_u128 a,_u128 b)266 _u128_plus(_u128 a, _u128 b)
267 {
268 _u128 v;
269
270 v.lo = a.lo + b.lo;
271 v.hi = a.hi + b.hi;
272 if (v.lo < a.lo)
273 v.hi++;
274 return v;
275 }
276
277 static inline _u128
_u128_minus_64(_u128 a,uint64_t b)278 _u128_minus_64(_u128 a, uint64_t b)
279 {
280 _u128 v;
281
282 v.lo = a.lo - b;
283 v.hi = a.hi;
284 if (v.lo > a.lo)
285 v.hi--;
286 return v;
287 }
288
289 static inline _u128
_u128_minus(_u128 a,_u128 b)290 _u128_minus(_u128 a, _u128 b)
291 {
292 _u128 v;
293
294 v.lo = a.lo - b.lo;
295 v.hi = a.hi - b.hi;
296 if (v.lo > a.lo)
297 v.hi--;
298 return v;
299 }
300
301 static inline _u128
_u128_lshift(_u128 a,int amt)302 _u128_lshift(_u128 a, int amt)
303 {
304 _u128 v;
305
306 if (amt == 0) {
307 v = a;
308 } else if (amt < 64) {
309 v.lo = a.lo << amt;
310 v.hi = (a.lo >> (64 - amt)) | (a.hi << amt);
311 } else {
312 v.lo = 0;
313 v.hi = a.lo << (amt - 64);
314 }
315 return v;
316 }
317
318 static inline _u128
_u128_lshift_64(uint64_t a,int amt)319 _u128_lshift_64(uint64_t a, int amt)
320 {
321 _u128 v;
322
323 if (amt == 0) {
324 v.lo = a;
325 v.hi = 0;
326 } else if (amt < 64) {
327 v.lo = a << amt;
328 v.hi = (a >> (64 - amt));
329 } else {
330 v.lo = 0;
331 v.hi = a << (amt - 64);
332 }
333 return v;
334 }
335
336 static inline _u128
_u128_rshift(_u128 a,int amt)337 _u128_rshift(_u128 a, int amt)
338 {
339 _u128 v;
340
341 if (amt == 0) {
342 v = a;
343 } else if (amt < 64) {
344 v.lo = (a.hi << (64 - amt)) | (a.lo >> amt);
345 v.hi = a.hi >> amt;
346 } else {
347 v.hi = 0;
348 v.lo = a.hi >> (amt - 64);
349 }
350 return v;
351 }
352
353 static inline _u128
_u128_and(_u128 a,_u128 b)354 _u128_and(_u128 a, _u128 b)
355 {
356 _u128 v;
357
358 v.hi = a.hi & b.hi;
359 v.lo = a.lo & b.lo;
360 return v;
361 }
362
363 static inline uint64_t
_u128_and_64(_u128 a,uint64_t b)364 _u128_and_64(_u128 a, uint64_t b)
365 {
366 return a.lo & b;
367 }
368
369 static inline _u128
_u128_or(_u128 a,_u128 b)370 _u128_or(_u128 a, _u128 b)
371 {
372 _u128 v;
373
374 v.lo = a.lo | b.lo;
375 v.hi = a.hi | b.hi;
376 return v;
377 }
378
379 static inline _u128
_u128_or_64(_u128 a,uint64_t b)380 _u128_or_64(_u128 a, uint64_t b)
381 {
382 _u128 v;
383
384 v.lo = a.lo | b;
385 v.hi = a.hi;
386 return v;
387 }
388
389 static inline _u128
_u128_not(_u128 a)390 _u128_not(_u128 a)
391 {
392 _u128 v;
393
394 v.lo = ~a.lo;
395 v.hi = ~a.hi;
396 return v;
397 }
398
399 static inline _u128
_u128_times_10(_u128 a)400 _u128_times_10(_u128 a)
401 {
402 return _u128_plus(_u128_lshift(a, 3), _u128_lshift(a, 1));
403 }
404
405 static inline _u128
_u128_times_base(_u128 a,int base)406 _u128_times_base(_u128 a, int base)
407 {
408 if (base == 10)
409 return _u128_times_10(a);
410 return _u128_lshift(a, 4);
411 }
412
413 static inline bool
_u128_oflow(_u128 a)414 _u128_oflow(_u128 a)
415 {
416 return a.hi >= (0xffffffffffffffffULL - 9) / 10;
417 }
418 #endif
419
420 static inline _u128
asuint128(long double f)421 asuint128(long double f)
422 {
423 union {
424 long double f;
425 _u128 i;
426 } v;
427
428 v.f = f;
429 return v.i;
430 }
431
432 static inline long double
aslongdouble(_u128 i)433 aslongdouble(_u128 i)
434 {
435 union {
436 long double f;
437 _u128 i;
438 } v;
439
440 v.i = i;
441 return v.f;
442 }
443
444 static inline bool
_u128_gt(_u128 a,_u128 b)445 _u128_gt(_u128 a, _u128 b)
446 {
447 return _u128_lt(b, a);
448 }
449
450 long double
451 __atold_engine(_u128 m10, int e10);
452
453 static inline uint16_t
__non_atomic_exchange_ungetc(__ungetc_t * p,__ungetc_t v)454 __non_atomic_exchange_ungetc(__ungetc_t *p, __ungetc_t v)
455 {
456 __ungetc_t e = *p;
457 *p = v;
458 return e;
459 }
460
461 static inline bool
__non_atomic_compare_exchange_ungetc(__ungetc_t * p,__ungetc_t d,__ungetc_t v)462 __non_atomic_compare_exchange_ungetc(__ungetc_t *p, __ungetc_t d, __ungetc_t v)
463 {
464 if (*p != d)
465 return false;
466 *p = v;
467 return true;
468 }
469
470 #ifdef ATOMIC_UNGETC
471
472 #if __PICOLIBC_UNGETC_SIZE == 4 && defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
473 #define PICOLIBC_HAVE_SYNC_COMPARE_AND_SWAP
474 #endif
475
476 #if __PICOLIBC_UNGETC_SIZE == 2 && defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2)
477 #define PICOLIBC_HAVE_SYNC_COMPARE_AND_SWAP
478 #endif
479
480 #ifdef PICOLIBC_HAVE_SYNC_COMPARE_AND_SWAP
481
482 /* Use built-in atomic functions if they exist */
483 #include <stdatomic.h>
484 static inline bool
__atomic_compare_exchange_ungetc(__ungetc_t * p,__ungetc_t d,__ungetc_t v)485 __atomic_compare_exchange_ungetc(__ungetc_t *p, __ungetc_t d, __ungetc_t v)
486 {
487 _Atomic __ungetc_t *pa = (_Atomic __ungetc_t *) p;
488 return atomic_compare_exchange_strong(pa, &d, v);
489 }
490
491 static inline __ungetc_t
__atomic_exchange_ungetc(__ungetc_t * p,__ungetc_t v)492 __atomic_exchange_ungetc(__ungetc_t *p, __ungetc_t v)
493 {
494 _Atomic __ungetc_t *pa = (_Atomic __ungetc_t *) p;
495 return atomic_exchange_explicit(pa, v, memory_order_relaxed);
496 }
497
498 #else
499
500 bool
501 __atomic_compare_exchange_ungetc(__ungetc_t *p, __ungetc_t d, __ungetc_t v);
502
503 __ungetc_t
504 __atomic_exchange_ungetc(__ungetc_t *p, __ungetc_t v);
505
506 #endif /* PICOLIBC_HAVE_SYNC_COMPARE_AND_SWAP */
507
508 #else
509
510 #define __atomic_compare_exchange_ungetc(p,d,v) __non_atomic_compare_exchange_ungetc(p,d,v)
511
512 #define __atomic_exchange_ungetc(p,v) __non_atomic_exchange_ungetc(p,v)
513
514 #endif /* ATOMIC_UNGETC */
515
516 #define CASE_CONVERT ('a' - 'A')
517 #define TOLOW(c) ((c) | CASE_CONVERT)
518
519 /*
520 * Convert a single character to the value of the digit for any
521 * character 0 .. 9, A .. Z or a .. z
522 *
523 * Characters out of these ranges will return a value above 36
524 *
525 * Work in unsigned int type to avoid extra instructions required for
526 * unsigned char folding. The only time this matters is when
527 * subtracting '0' from values below '0', which results in very large
528 * unsigned values.
529 */
530
531 static inline unsigned int
digit_to_val(unsigned int c)532 digit_to_val(unsigned int c)
533 {
534 /*
535 * Convert letters with some tricky code.
536 *
537 * TOLOW(c-1) maps characters as follows (Skipping values not
538 * greater than '9' (0x39), as those are skipped by the 'if'):
539 *
540 * Minus 1, bitwise-OR ('a' - 'A') (0x20):
541 *
542 * 0x3a..0x40 -> 0x39..0x3f
543 * 0x41..0x60, 0x61..0x80 -> 0x60..0x7f
544 * 0x81..0xa0, 0xa1..0xc0 -> 0xa0..0xbf
545 * 0xc1..0xe0, 0xe1..0x00 -> 0xe0..0xff
546 *
547 * Plus '0' (0x30), minus 'a') (0x61), plus 11 (0xb), for
548 * a total of minus 0x26:
549 *
550 * 0x3a..0x40 -> 0x39..0x3f -> 0x13..0x19
551 * 0x41..0x60, 0x61..0x80 -> 0x60..0x7f -> 0x3a..0x59
552 * 0x81..0xa0, 0xa1..0xc0 -> 0xa0..0xbf -> 0x7a..0x99
553 * 0xc1..0xe0, 0xe1..0x00 -> 0xe0..0xff -> 0xba..0xd9
554 */
555
556 if (c > '9') {
557
558 /*
559 * For the letters, we want TOLOW(c) - 'a' + 10, but that
560 * would map both '@' and '`' to 9.
561 *
562 * To work around this, subtract 1 before the bitwise-or so
563 * that '@' (0x40) gets mapped down to 0x3f (0x3f | 0x20)
564 * while '`' (0x60) gets mapped up to 0x7f (0x5f | 0x20),
565 * moving them away from the letters (which end up in the
566 * range 0x60..0x79). Then add the 1 back in when subtracting
567 * 'a' and adding 10.
568 *
569 * Add in '0' so that it can get subtracted out in the common
570 * code (c -= '0') below, avoiding an else clause.
571 */
572
573 c = TOLOW(c-1) + ('0' - 'a' + 11);
574 }
575
576 /*
577 * Now, include the range from NUL (0x00) through '9' (0x39)
578 *
579 * Minus '0' (0x30):
580 *
581 * 0x00..0x2f ->-0x30..-0x01
582 * 0x30..0x39 -> 0x00..0x09 *
583 * 0x3a..0x40 -> 0x39..0x3f -> 0x13..0x19 ->-0x1d..-0x17
584 * 0x41..0x60, 0x61..0x80 -> 0x60..0x7f -> 0x3a..0x59 -> 0x0a..0x29 *
585 * 0x81..0xa0, 0xa1..0xc0 -> 0xa0..0xbf -> 0x7a..0x99 -> 0x4a..0x69
586 * 0xc1..0xe0, 0xe1..0x00 -> 0xe0..0xff -> 0xba..0xd9 -> 0x8a..0xa9
587 *
588 * The first starred row has the digits '0'..'9', while the second
589 * starts with the letters 'A'..'Z' and 'a'..'z'. All of the other
590 * rows end up with values above any allowed conversion base
591 */
592
593 c -= '0';
594 return c;
595 }
596
597 #endif /* _STDIO_PRIVATE_H_ */
598