xref: /linux/tools/include/nolibc/stdio.h (revision 248c7cf60c808f09044af1ce1d2c7c707696dc1e)
1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3  * minimal stdio function definitions for NOLIBC
4  * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
5  */
6 
7 /* make sure to include all global symbols */
8 #include "nolibc.h"
9 
10 #ifndef _NOLIBC_STDIO_H
11 #define _NOLIBC_STDIO_H
12 
13 #include "std.h"
14 #include "arch.h"
15 #include "errno.h"
16 #include "fcntl.h"
17 #include "types.h"
18 #include "sys.h"
19 #include "stdarg.h"
20 #include "stdlib.h"
21 #include "string.h"
22 #include "compiler.h"
23 
24 static const char *strerror(int errnum);
25 
26 #ifndef EOF
27 #define EOF (-1)
28 #endif
29 
30 /* Buffering mode used by setvbuf.  */
31 #define _IOFBF 0	/* Fully buffered. */
32 #define _IOLBF 1	/* Line buffered. */
33 #define _IONBF 2	/* No buffering. */
34 
35 /* just define FILE as a non-empty type. The value of the pointer gives
36  * the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE
37  * are immediately identified as abnormal entries (i.e. possible copies
38  * of valid pointers to something else).
39  */
40 typedef struct FILE {
41 	char dummy[1];
42 } FILE;
43 
44 static __attribute__((unused)) FILE* const stdin  = (FILE*)(intptr_t)~STDIN_FILENO;
45 static __attribute__((unused)) FILE* const stdout = (FILE*)(intptr_t)~STDOUT_FILENO;
46 static __attribute__((unused)) FILE* const stderr = (FILE*)(intptr_t)~STDERR_FILENO;
47 
48 /* provides a FILE* equivalent of fd. The mode is ignored. */
49 static __attribute__((unused))
50 FILE *fdopen(int fd, const char *mode __attribute__((unused)))
51 {
52 	if (fd < 0) {
53 		SET_ERRNO(EBADF);
54 		return NULL;
55 	}
56 	return (FILE*)(intptr_t)~fd;
57 }
58 
59 static __attribute__((unused))
60 FILE *fopen(const char *pathname, const char *mode)
61 {
62 	int flags, fd;
63 
64 	switch (*mode) {
65 	case 'r':
66 		flags = O_RDONLY;
67 		break;
68 	case 'w':
69 		flags = O_WRONLY | O_CREAT | O_TRUNC;
70 		break;
71 	case 'a':
72 		flags = O_WRONLY | O_CREAT | O_APPEND;
73 		break;
74 	default:
75 		SET_ERRNO(EINVAL); return NULL;
76 	}
77 
78 	if (mode[1] == '+')
79 		flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
80 
81 	fd = open(pathname, flags, 0666);
82 	return fdopen(fd, mode);
83 }
84 
85 /* provides the fd of stream. */
86 static __attribute__((unused))
87 int fileno(FILE *stream)
88 {
89 	intptr_t i = (intptr_t)stream;
90 
91 	if (i >= 0) {
92 		SET_ERRNO(EBADF);
93 		return -1;
94 	}
95 	return ~i;
96 }
97 
98 /* flush a stream. */
99 static __attribute__((unused))
100 int fflush(FILE *stream)
101 {
102 	intptr_t i = (intptr_t)stream;
103 
104 	/* NULL is valid here. */
105 	if (i > 0) {
106 		SET_ERRNO(EBADF);
107 		return -1;
108 	}
109 
110 	/* Don't do anything, nolibc does not support buffering. */
111 	return 0;
112 }
113 
114 /* flush a stream. */
115 static __attribute__((unused))
116 int fclose(FILE *stream)
117 {
118 	intptr_t i = (intptr_t)stream;
119 
120 	if (i >= 0) {
121 		SET_ERRNO(EBADF);
122 		return -1;
123 	}
124 
125 	if (close(~i))
126 		return EOF;
127 
128 	return 0;
129 }
130 
131 /* getc(), fgetc(), getchar() */
132 
133 #define getc(stream) fgetc(stream)
134 
135 static __attribute__((unused))
136 int fgetc(FILE* stream)
137 {
138 	unsigned char ch;
139 
140 	if (read(fileno(stream), &ch, 1) <= 0)
141 		return EOF;
142 	return ch;
143 }
144 
145 static __attribute__((unused))
146 int getchar(void)
147 {
148 	return fgetc(stdin);
149 }
150 
151 
152 /* putc(), fputc(), putchar() */
153 
154 #define putc(c, stream) fputc(c, stream)
155 
156 static __attribute__((unused))
157 int fputc(int c, FILE* stream)
158 {
159 	unsigned char ch = c;
160 
161 	if (write(fileno(stream), &ch, 1) <= 0)
162 		return EOF;
163 	return ch;
164 }
165 
166 static __attribute__((unused))
167 int putchar(int c)
168 {
169 	return fputc(c, stdout);
170 }
171 
172 
173 /* fwrite(), fread(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
174 
175 /* internal fwrite()-like function which only takes a size and returns 0 on
176  * success or EOF on error. It automatically retries on short writes.
177  */
178 static __attribute__((unused))
179 int _fwrite(const void *buf, size_t size, FILE *stream)
180 {
181 	ssize_t ret;
182 	int fd = fileno(stream);
183 
184 	while (size) {
185 		ret = write(fd, buf, size);
186 		if (ret <= 0)
187 			return EOF;
188 		size -= ret;
189 		buf += ret;
190 	}
191 	return 0;
192 }
193 
194 static __attribute__((unused))
195 size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
196 {
197 	size_t written;
198 
199 	for (written = 0; written < nmemb; written++) {
200 		if (_fwrite(s, size, stream) != 0)
201 			break;
202 		s += size;
203 	}
204 	return written;
205 }
206 
207 /* internal fread()-like function which only takes a size and returns 0 on
208  * success or EOF on error. It automatically retries on short reads.
209  */
210 static __attribute__((unused))
211 int _fread(void *buf, size_t size, FILE *stream)
212 {
213 	int fd = fileno(stream);
214 	ssize_t ret;
215 
216 	while (size) {
217 		ret = read(fd, buf, size);
218 		if (ret <= 0)
219 			return EOF;
220 		size -= ret;
221 		buf += ret;
222 	}
223 	return 0;
224 }
225 
226 static __attribute__((unused))
227 size_t fread(void *s, size_t size, size_t nmemb, FILE *stream)
228 {
229 	size_t nread;
230 
231 	for (nread = 0; nread < nmemb; nread++) {
232 		if (_fread(s, size, stream) != 0)
233 			break;
234 		s += size;
235 	}
236 	return nread;
237 }
238 
239 static __attribute__((unused))
240 int fputs(const char *s, FILE *stream)
241 {
242 	return _fwrite(s, strlen(s), stream);
243 }
244 
245 static __attribute__((unused))
246 int puts(const char *s)
247 {
248 	if (fputs(s, stdout) == EOF)
249 		return EOF;
250 	return putchar('\n');
251 }
252 
253 
254 /* fgets() */
255 static __attribute__((unused))
256 char *fgets(char *s, int size, FILE *stream)
257 {
258 	int ofs;
259 	int c;
260 
261 	for (ofs = 0; ofs + 1 < size;) {
262 		c = fgetc(stream);
263 		if (c == EOF)
264 			break;
265 		s[ofs++] = c;
266 		if (c == '\n')
267 			break;
268 	}
269 	if (ofs < size)
270 		s[ofs] = 0;
271 	return ofs ? s : NULL;
272 }
273 
274 
275 /* fseek */
276 static __attribute__((unused))
277 int fseek(FILE *stream, long offset, int whence)
278 {
279 	int fd = fileno(stream);
280 	off_t ret;
281 
282 	ret = lseek(fd, offset, whence);
283 
284 	/* lseek() and fseek() differ in that lseek returns the new
285 	 * position or -1, fseek() returns either 0 or -1.
286 	 */
287 	if (ret >= 0)
288 		return 0;
289 
290 	return -1;
291 }
292 
293 
294 /* printf(). Supports most of the normal integer and string formats.
295  *  - %[#0-+ ][width|*[.precision|*}][{l,t,z,ll,L,j,q}]{c,d,i,u,o,x,X,p,s,m,%}
296  *  - %% generates a single %
297  *  - %m outputs strerror(errno).
298  *  - %X outputs a..f the same as %x.
299  *  - No support for floating point or wide characters.
300  *  - Invalid formats are copied to the output buffer.
301  *
302  * Called by vfprintf() and snprintf() to do the actual formatting.
303  * The callers provide a callback function to save the formatted data.
304  * The callback function is called multiple times:
305  *  - for each group of literal characters in the format string.
306  *  - for field padding.
307  *  - for each conversion specifier.
308  *  - with (NULL, 0) at the end of the __nolibc_printf.
309  * If the callback returns non-zero __nolibc_printf() immediately returns -1.
310  */
311 
312 typedef int (*__nolibc_printf_cb)(void *state, const char *buf, size_t size);
313 
314 /* This code uses 'flag' variables that are indexed by the low 6 bits
315  * of characters to optimise checks for multiple characters.
316  *
317  * _NOLIBC_PF_FLAGS_CONTAIN(flags, 'a', 'b'. ...)
318  * returns non-zero if the bit for any of the specified characters is set.
319  *
320  * _NOLIBC_PF_CHAR_IS_ONE_OF(ch, 'a', 'b'. ...)
321  * returns the flag bit for ch if it is one of the specified characters.
322  * All the characters must be in the same 32 character block (non-alphabetic,
323  * upper case, or lower case) of the ASCII character set.
324  */
325 #define _NOLIBC_PF_FLAG(ch) (1u << ((ch) & 0x1f))
326 #define _NOLIBC_PF_FLAG_NZ(ch) ((ch) ? _NOLIBC_PF_FLAG(ch) : 0)
327 #define _NOLIBC_PF_FLAG8(cmp_1, cmp_2, cmp_3, cmp_4, cmp_5, cmp_6, cmp_7, cmp_8, ...) \
328 	(_NOLIBC_PF_FLAG_NZ(cmp_1) | _NOLIBC_PF_FLAG_NZ(cmp_2) | \
329 	 _NOLIBC_PF_FLAG_NZ(cmp_3) | _NOLIBC_PF_FLAG_NZ(cmp_4) | \
330 	 _NOLIBC_PF_FLAG_NZ(cmp_5) | _NOLIBC_PF_FLAG_NZ(cmp_6) | \
331 	 _NOLIBC_PF_FLAG_NZ(cmp_7) | _NOLIBC_PF_FLAG_NZ(cmp_8))
332 #define _NOLIBC_PF_FLAGS_CONTAIN(flags, ...) \
333 	((flags) & _NOLIBC_PF_FLAG8(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0))
334 #define _NOLIBC_PF_CHAR_IS_ONE_OF(ch, cmp_1, ...) \
335 	((unsigned int)(ch) - (cmp_1 & 0xe0) > 0x1f ? 0 : \
336 		_NOLIBC_PF_FLAGS_CONTAIN(_NOLIBC_PF_FLAG(ch), cmp_1, __VA_ARGS__))
337 
338 static __attribute__((unused, format(printf, 3, 0)))
339 int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list args)
340 {
341 	char ch;
342 	unsigned long long v;
343 	long long signed_v;
344 	int written, width, precision, len;
345 	unsigned int flags, ch_flag;
346 	char outbuf[2 + 31 + 22 + 1];
347 	char *out;
348 	const char *outstr;
349 	unsigned int sign_prefix;
350 
351 	written = 0;
352 	while (1) {
353 		outstr = fmt;
354 		ch = *fmt++;
355 		if (!ch)
356 			break;
357 
358 		width = 0;
359 		flags = 0;
360 		if (ch != '%') {
361 			while (*fmt && *fmt != '%')
362 				fmt++;
363 			/* Output characters from the format string. */
364 			len = fmt - outstr;
365 			goto do_output;
366 		}
367 
368 		/* we're in a format sequence */
369 
370 		/* Conversion flag characters */
371 		while (1) {
372 			ch = *fmt++;
373 			ch_flag = _NOLIBC_PF_CHAR_IS_ONE_OF(ch, ' ', '#', '+', '-', '0');
374 			if (!ch_flag)
375 				break;
376 			flags |= ch_flag;
377 		}
378 
379 		/* Width and precision */
380 		for (;; ch = *fmt++) {
381 			if (ch == '*') {
382 				precision = va_arg(args, unsigned int);
383 				ch = *fmt++;
384 			} else {
385 				for (precision = 0; ch >= '0' && ch <= '9'; ch = *fmt++)
386 					precision = precision * 10 + (ch - '0');
387 			}
388 			if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '.'))
389 				break;
390 			width = precision;
391 			if (ch != '.') {
392 				/* Default precision for strings */
393 				precision = INT_MAX;
394 				break;
395 			}
396 			flags |= _NOLIBC_PF_FLAG('.');
397 		}
398 
399 		/* Length modifier.
400 		 * They miss the conversion flags characters " #+-0" so can go into flags.
401 		 * Change both L and ll to j (all always 64bit).
402 		 */
403 		if (ch == 'L')
404 			ch = 'j';
405 		ch_flag = _NOLIBC_PF_CHAR_IS_ONE_OF(ch, 'l', 't', 'z', 'j', 'q');
406 		if (ch_flag != 0) {
407 			if (ch == 'l' && fmt[0] == 'l') {
408 				fmt++;
409 				ch_flag = _NOLIBC_PF_FLAG('j');
410 			}
411 			flags |= ch_flag;
412 			ch = *fmt++;
413 		}
414 
415 		/* Conversion specifiers. */
416 
417 		/* Numeric and pointer conversion specifiers.
418 		 *
419 		 * Use an explicit bound check (rather than _NOLIBC_PF_CHAR_IS_ONE_OF())
420 		 * so that 'X' can be allowed through.
421 		 * 'X' gets treated and 'x' because _NOLIBC_PF_FLAG() returns the same
422 		 * value for both.
423 		 *
424 		 * We need to check for "%p" or "%#x" later, merging here gives better code.
425 		 * But '#' collides with 'c' so shift right.
426 		 */
427 		ch_flag = _NOLIBC_PF_FLAG(ch) | (flags & _NOLIBC_PF_FLAG('#')) >> 1;
428 		if (((ch >= 'a' && ch <= 'z') || ch == 'X') &&
429 		    _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'i', 'u', 'o', 'x', 'p', 's')) {
430 			/* 'long' is needed for pointer/string conversions and ltz lengths.
431 			 * A single test can be used provided 'p' (the same bit as '0')
432 			 * is masked from flags.
433 			 */
434 			if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag | (flags & ~_NOLIBC_PF_FLAG('p')),
435 						     'p', 's', 'l', 't', 'z')) {
436 				v = va_arg(args, unsigned long);
437 				signed_v = (long)v;
438 			} else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, 'j', 'q')) {
439 				v = va_arg(args, unsigned long long);
440 				signed_v = v;
441 			} else {
442 				v = va_arg(args, unsigned int);
443 				signed_v = (int)v;
444 			}
445 
446 			if (ch == 'c') {
447 				/* "%c" - single character. */
448 				outbuf[0] = v;
449 				len = 1;
450 				outstr = outbuf;
451 				goto do_output;
452 			}
453 
454 			if (ch == 's') {
455 				/* "%s" - character string. */
456 				outstr = (const char  *)(uintptr_t)v;
457 				if (!outstr) {
458 					outstr = "(null)";
459 					/* Match glibc, nothing output if precision too small */
460 					len = precision >= 6 ? 6 : 0;
461 					goto do_output;
462 				}
463 				goto do_strlen_output;
464 			}
465 
466 			/* The 'sign_prefix' can be zero, one or two ("0x") characters.
467 			 * Prepended least significant byte first stopping on a zero byte.
468 			 */
469 			sign_prefix = 0;
470 
471 			if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i')) {
472 				/* "%d" and "%i" - signed decimal numbers. */
473 				if (signed_v < 0) {
474 					sign_prefix = '-';
475 					v = -(signed_v + 1);
476 					v++;
477 				} else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '+')) {
478 					sign_prefix = '+';
479 				} else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, ' ')) {
480 					sign_prefix = ' ';
481 				}
482 			} else {
483 				/* "#o" requires that the output always starts with a '0'.
484 				 * This needs another check after any zero padding to avoid
485 				 * adding an extra leading '0'.
486 				 */
487 				if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'o') &&
488 						_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, '#' - 1))
489 					sign_prefix = '0';
490 			}
491 
492 			/* The value is converted offset into the buffer so that
493 			 * 31 zero pad characters and the sign/prefix can be added in front.
494 			 * The longest digit string is 22 + 1 for octal conversions.
495 			 */
496 			out = outbuf + 2 + 31;
497 
498 			if (v == 0) {
499 				/* There are special rules for zero. */
500 				if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p')) {
501 					/* "%p" match glibc, precision is ignored */
502 					outstr = "(nil)";
503 					len = 5;
504 					goto do_output;
505 				}
506 				if (!precision) {
507 					/* Explicit %nn.0d, no digits output (except for %#.0o) */
508 					len = 0;
509 					goto prepend_sign;
510 				}
511 				/* All other formats (including "%#x") just output "0". */
512 				out[0] = '0';
513 				len = 1;
514 			} else {
515 				/* Convert the number to ascii in the required base. */
516 				unsigned long long recip;
517 				unsigned int base;
518 				if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i', 'u')) {
519 					base = 10;
520 					recip = _NOLIBC_U64TOA_RECIP(10);
521 				} else if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'o')) {
522 					base = 8;
523 					recip = _NOLIBC_U64TOA_RECIP(8);
524 				} else {
525 					base = 16;
526 					recip = _NOLIBC_U64TOA_RECIP(16);
527 					if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p', '#' - 1)) {
528 						/* "%p" and "%#x" need "0x" prepending. */
529 						sign_prefix = '0' << 8 | 'x';
530 					}
531 				}
532 				len = _nolibc_u64toa_base(v, out, base, recip);
533 			}
534 
535 			/* Add zero padding */
536 			if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '0', '.')) {
537 				if (!_NOLIBC_PF_FLAGS_CONTAIN(flags, '.')) {
538 					if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '-'))
539 						/* Left justify overrides zero pad */
540 						goto prepend_sign;
541 					/* eg "%05d", Zero pad to field width less sign.
542 					 * Note that precision can end up negative so all
543 					 * the variables have to be 'signed int'.
544 					 */
545 					precision = width;
546 					if (sign_prefix) {
547 						precision--;
548 						if (sign_prefix >= 256)
549 							precision--;
550 					}
551 				}
552 				if (precision > 31)
553 					/* Don't run off the start of outbuf[], arbitrary limit
554 					 * longer than the longest number field. */
555 					precision = 31;
556 				for (; len < precision; len++) {
557 					/* Stop gcc generating horrid code and memset(). */
558 					_NOLIBC_OPTIMIZER_HIDE_VAR(len);
559 					*--out = '0';
560 				}
561 			}
562 
563 			/* %#o has set sign_prefix to '0', but we don't want so add an extra
564 			 * leading zero here.
565 			 * Since the only other byte values of sign_prefix are ' ', '+' and '-'
566 			 * it is enough to check that out[] doesn't already start with sign_prefix.
567 			 */
568 			if (sign_prefix - *out) {
569 prepend_sign:
570 				/* Add the 0, 1 or 2 ("0x") sign/prefix characters at the front. */
571 				for (; sign_prefix; sign_prefix >>= 8) {
572 					/* Force gcc to increment len inside the loop. */
573 					_NOLIBC_OPTIMIZER_HIDE_VAR(len);
574 					len++;
575 					*--out = sign_prefix;
576 				}
577 			}
578 			outstr = out;
579 			goto do_output;
580 		}
581 
582 		if (ch == 'm') {
583 #ifdef NOLIBC_IGNORE_ERRNO
584 			outstr = "unknown error";
585 #else
586 			outstr = strerror(errno);
587 #endif /* NOLIBC_IGNORE_ERRNO */
588 			goto do_strlen_output;
589 		}
590 
591 		if (ch != '%') {
592 			/* Invalid format: back up to output the format characters */
593 			fmt = outstr + 1;
594 			/* and output a '%' now. */
595 		}
596 		/* %% is documented as a 'conversion specifier'.
597 		 * Any flags, precision or length modifier are ignored.
598 		 */
599 		len = 1;
600 		width = 0;
601 		outstr = fmt - 1;
602 		goto do_output;
603 
604 do_strlen_output:
605 		/* Open coded strnlen() (slightly smaller). */
606 		for (len = 0; len < precision; len++)
607 			if (!outstr[len])
608 				break;
609 
610 do_output:
611 		written += len;
612 
613 		/* Stop gcc back-merging this code into one of the conditionals above. */
614 		_NOLIBC_OPTIMIZER_HIDE_VAR(len);
615 
616 		/* Output the characters on the required side of any padding. */
617 		width -= len;
618 		flags = _NOLIBC_PF_FLAGS_CONTAIN(flags, '-');
619 		if (flags && cb(state, outstr, len) != 0)
620 			return -1;
621 		while (width > 0) {
622 			/* Output pad in 16 byte blocks with the small block first. */
623 			int pad_len = ((width - 1) & 15) + 1;
624 			width -= pad_len;
625 			written += pad_len;
626 			if (cb(state, "                ", pad_len) != 0)
627 				return -1;
628 		}
629 		if (!flags && cb(state, outstr, len) != 0)
630 			return -1;
631 	}
632 
633 	/* Request a final '\0' be added to the snprintf() output.
634 	 * This may be the only call of the cb() function.
635 	 */
636 	if (cb(state, NULL, 0) != 0)
637 		return -1;
638 
639 	return written;
640 }
641 
642 static int __nolibc_fprintf_cb(void *stream, const char *buf, size_t size)
643 {
644 	return _fwrite(buf, size, stream);
645 }
646 
647 static __attribute__((unused, format(printf, 2, 0)))
648 int vfprintf(FILE *stream, const char *fmt, va_list args)
649 {
650 	return __nolibc_printf(__nolibc_fprintf_cb, stream, fmt, args);
651 }
652 
653 static __attribute__((unused, format(printf, 1, 0)))
654 int vprintf(const char *fmt, va_list args)
655 {
656 	return vfprintf(stdout, fmt, args);
657 }
658 
659 static __attribute__((unused, format(printf, 2, 3)))
660 int fprintf(FILE *stream, const char *fmt, ...)
661 {
662 	va_list args;
663 	int ret;
664 
665 	va_start(args, fmt);
666 	ret = vfprintf(stream, fmt, args);
667 	va_end(args);
668 	return ret;
669 }
670 
671 static __attribute__((unused, format(printf, 1, 2)))
672 int printf(const char *fmt, ...)
673 {
674 	va_list args;
675 	int ret;
676 
677 	va_start(args, fmt);
678 	ret = vfprintf(stdout, fmt, args);
679 	va_end(args);
680 	return ret;
681 }
682 
683 static __attribute__((unused, format(printf, 2, 0)))
684 int vdprintf(int fd, const char *fmt, va_list args)
685 {
686 	FILE *stream;
687 
688 	stream = fdopen(fd, NULL);
689 	if (!stream)
690 		return -1;
691 	/* Technically 'stream' is leaked, but as it's only a wrapper around 'fd' that is fine */
692 	return vfprintf(stream, fmt, args);
693 }
694 
695 static __attribute__((unused, format(printf, 2, 3)))
696 int dprintf(int fd, const char *fmt, ...)
697 {
698 	va_list args;
699 	int ret;
700 
701 	va_start(args, fmt);
702 	ret = vdprintf(fd, fmt, args);
703 	va_end(args);
704 
705 	return ret;
706 }
707 
708 struct __nolibc_sprintf_cb_state {
709 	char *buf;
710 	size_t space;
711 };
712 
713 static int __nolibc_sprintf_cb(void *v_state, const char *buf, size_t size)
714 {
715 	struct __nolibc_sprintf_cb_state *state = v_state;
716 	size_t space = state->space;
717 	char *tgt;
718 
719 	/* Truncate the request to fit in the output buffer space.
720 	 * The last byte is reserved for the terminating '\0'.
721 	 * state->space can only be zero for snprintf(NULL, 0, fmt, args)
722 	 * so this normally lets through calls with 'size == 0'.
723 	 */
724 	if (size >= space) {
725 		if (space <= 1)
726 			return 0;
727 		size = space - 1;
728 	}
729 	tgt = state->buf;
730 
731 	/* __nolibc_printf() ends with cb(state, NULL, 0) to request the output
732 	 * buffer be '\0' terminated.
733 	 * That will be the only cb() call for, eg, snprintf(buf, sz, "").
734 	 * Zero lengths can occur at other times (eg "%s" for an empty string).
735 	 * Unconditionally write the '\0' byte to reduce code size, it is
736 	 * normally overwritten by the data being output.
737 	 * There is no point adding a '\0' after copied data - there is always
738 	 * another call.
739 	 */
740 	*tgt = '\0';
741 	if (size) {
742 		state->space = space - size;
743 		state->buf = tgt + size;
744 		memcpy(tgt, buf, size);
745 	}
746 
747 	return 0;
748 }
749 
750 static __attribute__((unused, format(printf, 3, 0)))
751 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
752 {
753 	struct __nolibc_sprintf_cb_state state = { .buf = buf, .space = size };
754 
755 	return __nolibc_printf(__nolibc_sprintf_cb, &state, fmt, args);
756 }
757 
758 static __attribute__((unused, format(printf, 3, 4)))
759 int snprintf(char *buf, size_t size, const char *fmt, ...)
760 {
761 	va_list args;
762 	int ret;
763 
764 	va_start(args, fmt);
765 	ret = vsnprintf(buf, size, fmt, args);
766 	va_end(args);
767 
768 	return ret;
769 }
770 
771 static __attribute__((unused, format(printf, 2, 0)))
772 int vsprintf(char *buf, const char *fmt, va_list args)
773 {
774 	return vsnprintf(buf, SIZE_MAX, fmt, args);
775 }
776 
777 static __attribute__((unused, format(printf, 2, 3)))
778 int sprintf(char *buf, const char *fmt, ...)
779 {
780 	va_list args;
781 	int ret;
782 
783 	va_start(args, fmt);
784 	ret = vsprintf(buf, fmt, args);
785 	va_end(args);
786 
787 	return ret;
788 }
789 
790 static __attribute__((unused))
791 int vsscanf(const char *str, const char *format, va_list args)
792 {
793 	uintmax_t uval;
794 	intmax_t ival;
795 	int base;
796 	char *endptr;
797 	int matches;
798 	int lpref;
799 
800 	matches = 0;
801 
802 	while (1) {
803 		if (*format == '%') {
804 			/* start of pattern */
805 			lpref = 0;
806 			format++;
807 
808 			if (*format == 'l') {
809 				/* same as in printf() */
810 				lpref = 1;
811 				format++;
812 				if (*format == 'l') {
813 					lpref = 2;
814 					format++;
815 				}
816 			}
817 
818 			if (*format == '%') {
819 				/* literal % */
820 				if ('%' != *str)
821 					goto done;
822 				str++;
823 				format++;
824 				continue;
825 			} else if (*format == 'd') {
826 				ival = strtoll(str, &endptr, 10);
827 				if (lpref == 0)
828 					*va_arg(args, int *) = ival;
829 				else if (lpref == 1)
830 					*va_arg(args, long *) = ival;
831 				else if (lpref == 2)
832 					*va_arg(args, long long *) = ival;
833 			} else if (*format == 'u' || *format == 'x' || *format == 'X') {
834 				base = *format == 'u' ? 10 : 16;
835 				uval = strtoull(str, &endptr, base);
836 				if (lpref == 0)
837 					*va_arg(args, unsigned int *) = uval;
838 				else if (lpref == 1)
839 					*va_arg(args, unsigned long *) = uval;
840 				else if (lpref == 2)
841 					*va_arg(args, unsigned long long *) = uval;
842 			} else if (*format == 'p') {
843 				*va_arg(args, void **) = (void *)strtoul(str, &endptr, 16);
844 			} else {
845 				SET_ERRNO(EILSEQ);
846 				goto done;
847 			}
848 
849 			format++;
850 			str = endptr;
851 			matches++;
852 
853 		} else if (*format == '\0') {
854 			goto done;
855 		} else if (isspace(*format)) {
856 			/* skip spaces in format and str */
857 			while (isspace(*format))
858 				format++;
859 			while (isspace(*str))
860 				str++;
861 		} else if (*format == *str) {
862 			/* literal match */
863 			format++;
864 			str++;
865 		} else {
866 			if (!matches)
867 				matches = EOF;
868 			goto done;
869 		}
870 	}
871 
872 done:
873 	return matches;
874 }
875 
876 static __attribute__((unused, format(scanf, 2, 3)))
877 int sscanf(const char *str, const char *format, ...)
878 {
879 	va_list args;
880 	int ret;
881 
882 	va_start(args, format);
883 	ret = vsscanf(str, format, args);
884 	va_end(args);
885 	return ret;
886 }
887 
888 static __attribute__((unused))
889 void perror(const char *msg)
890 {
891 #ifdef NOLIBC_IGNORE_ERRNO
892 	fprintf(stderr, "%s%sunknown error\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "");
893 #else
894 	fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
895 #endif
896 }
897 
898 static __attribute__((unused))
899 int setvbuf(FILE *stream __attribute__((unused)),
900 	    char *buf __attribute__((unused)),
901 	    int mode,
902 	    size_t size __attribute__((unused)))
903 {
904 	/*
905 	 * nolibc does not support buffering so this is a nop. Just check mode
906 	 * is valid as required by the spec.
907 	 */
908 	switch (mode) {
909 	case _IOFBF:
910 	case _IOLBF:
911 	case _IONBF:
912 		break;
913 	default:
914 		return EOF;
915 	}
916 
917 	return 0;
918 }
919 
920 static __attribute__((unused))
921 int strerror_r(int errnum, char *buf, size_t buflen)
922 {
923 	if (buflen < 18)
924 		return ERANGE;
925 
926 	__builtin_memcpy(buf, "errno=", 6);
927 	i64toa_r(errnum, buf + 6);
928 	return 0;
929 }
930 
931 static __attribute__((unused))
932 const char *strerror(int errnum)
933 {
934 	static char buf[18];
935 	char *b = buf;
936 
937 	/* Force gcc to use 'register offset' to access buf[]. */
938 	_NOLIBC_OPTIMIZER_HIDE_VAR(b);
939 
940 	/* Use strerror_r() to avoid having the only .data in small programs. */
941 	strerror_r(errnum, b, sizeof(buf));
942 
943 	return b;
944 }
945 
946 #endif /* _NOLIBC_STDIO_H */
947