xref: /linux/tools/include/nolibc/stdio.h (revision 2177dd375d087012907e389f787b21ac38bb1785)
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 /* minimal printf(). It supports the following formats:
295  *  - %[l*]{d,u,c,x,p}
296  *  - %s
297  *  - unknown modifiers are ignored.
298  *
299  * Called by vfprintf() and snprintf() to do the actual formatting.
300  * The callers provide a callback function to save the formatted data.
301  * The callback function is called multiple times:
302  *  - for each group of literal characters in the format string.
303  *  - for field padding.
304  *  - for each conversion specifier.
305  *  - with (NULL, 0) at the end of the __nolibc_printf.
306  * If the callback returns non-zero __nolibc_printf() immediately returns -1.
307  */
308 typedef int (*__nolibc_printf_cb)(void *state, const char *buf, size_t size);
309 
310 static __attribute__((unused, format(printf, 3, 0)))
311 int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list args)
312 {
313 	char escape, lpref, ch;
314 	unsigned long long v;
315 	unsigned int written, width;
316 	size_t len, ofs;
317 	char outbuf[21];
318 	const char *outstr;
319 
320 	written = ofs = escape = lpref = 0;
321 	while (1) {
322 		ch = fmt[ofs++];
323 		width = 0;
324 
325 		if (escape) {
326 			/* we're in an escape sequence, ofs == 1 */
327 			escape = 0;
328 
329 			/* width */
330 			while (ch >= '0' && ch <= '9') {
331 				width *= 10;
332 				width += ch - '0';
333 
334 				ch = fmt[ofs++];
335 			}
336 
337 			if (ch == 'c' || ch == 'd' || ch == 'u' || ch == 'x' || ch == 'p') {
338 				char *out = outbuf;
339 
340 				if (ch == 'p')
341 					v = va_arg(args, unsigned long);
342 				else if (lpref) {
343 					if (lpref > 1)
344 						v = va_arg(args, unsigned long long);
345 					else
346 						v = va_arg(args, unsigned long);
347 				} else
348 					v = va_arg(args, unsigned int);
349 
350 				if (ch == 'd') {
351 					/* sign-extend the value */
352 					if (lpref == 0)
353 						v = (long long)(int)v;
354 					else if (lpref == 1)
355 						v = (long long)(long)v;
356 				}
357 
358 				switch (ch) {
359 				case 'c':
360 					out[0] = v;
361 					out[1] = 0;
362 					break;
363 				case 'd':
364 					i64toa_r(v, out);
365 					break;
366 				case 'u':
367 					u64toa_r(v, out);
368 					break;
369 				case 'p':
370 					*(out++) = '0';
371 					*(out++) = 'x';
372 					__nolibc_fallthrough;
373 				default: /* 'x' and 'p' above */
374 					u64toh_r(v, out);
375 					break;
376 				}
377 				outstr = outbuf;
378 			}
379 			else if (ch == 's') {
380 				outstr = va_arg(args, char *);
381 				if (!outstr)
382 					outstr="(null)";
383 			}
384 			else if (ch == 'm') {
385 #ifdef NOLIBC_IGNORE_ERRNO
386 				outstr = "unknown error";
387 #else
388 				outstr = strerror(errno);
389 #endif /* NOLIBC_IGNORE_ERRNO */
390 			}
391 			else if (ch == '%') {
392 				/* queue it verbatim */
393 				continue;
394 			}
395 			else {
396 				/* modifiers or final 0 */
397 				if (ch == 'l') {
398 					/* long format prefix, maintain the escape */
399 					lpref++;
400 				} else if (ch == 'j') {
401 					lpref = 2;
402 				}
403 				escape = 1;
404 				goto do_escape;
405 			}
406 			len = strlen(outstr);
407 			goto flush_str;
408 		}
409 
410 		/* not an escape sequence */
411 		if (ch == 0 || ch == '%') {
412 			/* flush pending data on escape or end */
413 			escape = 1;
414 			lpref = 0;
415 			outstr = fmt;
416 			len = ofs - 1;
417 		flush_str:
418 			while (width-- > len) {
419 				if (cb(state, " ", 1) != 0)
420 					return -1;
421 				written += 1;
422 			}
423 			if (cb(state, outstr, len) != 0)
424 				return -1;
425 
426 			written += len;
427 		do_escape:
428 			if (ch == 0)
429 				break;
430 			fmt += ofs;
431 			ofs = 0;
432 			continue;
433 		}
434 
435 		/* literal char, just queue it */
436 	}
437 
438 	/* Request a final '\0' be added to the snprintf() output.
439 	 * This may be the only call of the cb() function.
440 	 */
441 	if (cb(state, NULL, 0) != 0)
442 		return -1;
443 
444 	return written;
445 }
446 
447 static int __nolibc_fprintf_cb(void *stream, const char *buf, size_t size)
448 {
449 	return _fwrite(buf, size, stream);
450 }
451 
452 static __attribute__((unused, format(printf, 2, 0)))
453 int vfprintf(FILE *stream, const char *fmt, va_list args)
454 {
455 	return __nolibc_printf(__nolibc_fprintf_cb, stream, fmt, args);
456 }
457 
458 static __attribute__((unused, format(printf, 1, 0)))
459 int vprintf(const char *fmt, va_list args)
460 {
461 	return vfprintf(stdout, fmt, args);
462 }
463 
464 static __attribute__((unused, format(printf, 2, 3)))
465 int fprintf(FILE *stream, const char *fmt, ...)
466 {
467 	va_list args;
468 	int ret;
469 
470 	va_start(args, fmt);
471 	ret = vfprintf(stream, fmt, args);
472 	va_end(args);
473 	return ret;
474 }
475 
476 static __attribute__((unused, format(printf, 1, 2)))
477 int printf(const char *fmt, ...)
478 {
479 	va_list args;
480 	int ret;
481 
482 	va_start(args, fmt);
483 	ret = vfprintf(stdout, fmt, args);
484 	va_end(args);
485 	return ret;
486 }
487 
488 static __attribute__((unused, format(printf, 2, 0)))
489 int vdprintf(int fd, const char *fmt, va_list args)
490 {
491 	FILE *stream;
492 
493 	stream = fdopen(fd, NULL);
494 	if (!stream)
495 		return -1;
496 	/* Technically 'stream' is leaked, but as it's only a wrapper around 'fd' that is fine */
497 	return vfprintf(stream, fmt, args);
498 }
499 
500 static __attribute__((unused, format(printf, 2, 3)))
501 int dprintf(int fd, const char *fmt, ...)
502 {
503 	va_list args;
504 	int ret;
505 
506 	va_start(args, fmt);
507 	ret = vdprintf(fd, fmt, args);
508 	va_end(args);
509 
510 	return ret;
511 }
512 
513 struct __nolibc_sprintf_cb_state {
514 	char *buf;
515 	size_t space;
516 };
517 
518 static int __nolibc_sprintf_cb(void *v_state, const char *buf, size_t size)
519 {
520 	struct __nolibc_sprintf_cb_state *state = v_state;
521 	size_t space = state->space;
522 	char *tgt;
523 
524 	/* Truncate the request to fit in the output buffer space.
525 	 * The last byte is reserved for the terminating '\0'.
526 	 * state->space can only be zero for snprintf(NULL, 0, fmt, args)
527 	 * so this normally lets through calls with 'size == 0'.
528 	 */
529 	if (size >= space) {
530 		if (space <= 1)
531 			return 0;
532 		size = space - 1;
533 	}
534 	tgt = state->buf;
535 
536 	/* __nolibc_printf() ends with cb(state, NULL, 0) to request the output
537 	 * buffer be '\0' terminated.
538 	 * That will be the only cb() call for, eg, snprintf(buf, sz, "").
539 	 * Zero lengths can occur at other times (eg "%s" for an empty string).
540 	 * Unconditionally write the '\0' byte to reduce code size, it is
541 	 * normally overwritten by the data being output.
542 	 * There is no point adding a '\0' after copied data - there is always
543 	 * another call.
544 	 */
545 	*tgt = '\0';
546 	if (size) {
547 		state->space = space - size;
548 		state->buf = tgt + size;
549 		memcpy(tgt, buf, size);
550 	}
551 
552 	return 0;
553 }
554 
555 static __attribute__((unused, format(printf, 3, 0)))
556 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
557 {
558 	struct __nolibc_sprintf_cb_state state = { .buf = buf, .space = size };
559 
560 	return __nolibc_printf(__nolibc_sprintf_cb, &state, fmt, args);
561 }
562 
563 static __attribute__((unused, format(printf, 3, 4)))
564 int snprintf(char *buf, size_t size, const char *fmt, ...)
565 {
566 	va_list args;
567 	int ret;
568 
569 	va_start(args, fmt);
570 	ret = vsnprintf(buf, size, fmt, args);
571 	va_end(args);
572 
573 	return ret;
574 }
575 
576 static __attribute__((unused, format(printf, 2, 0)))
577 int vsprintf(char *buf, const char *fmt, va_list args)
578 {
579 	return vsnprintf(buf, SIZE_MAX, fmt, args);
580 }
581 
582 static __attribute__((unused, format(printf, 2, 3)))
583 int sprintf(char *buf, const char *fmt, ...)
584 {
585 	va_list args;
586 	int ret;
587 
588 	va_start(args, fmt);
589 	ret = vsprintf(buf, fmt, args);
590 	va_end(args);
591 
592 	return ret;
593 }
594 
595 static __attribute__((unused))
596 int vsscanf(const char *str, const char *format, va_list args)
597 {
598 	uintmax_t uval;
599 	intmax_t ival;
600 	int base;
601 	char *endptr;
602 	int matches;
603 	int lpref;
604 
605 	matches = 0;
606 
607 	while (1) {
608 		if (*format == '%') {
609 			/* start of pattern */
610 			lpref = 0;
611 			format++;
612 
613 			if (*format == 'l') {
614 				/* same as in printf() */
615 				lpref = 1;
616 				format++;
617 				if (*format == 'l') {
618 					lpref = 2;
619 					format++;
620 				}
621 			}
622 
623 			if (*format == '%') {
624 				/* literal % */
625 				if ('%' != *str)
626 					goto done;
627 				str++;
628 				format++;
629 				continue;
630 			} else if (*format == 'd') {
631 				ival = strtoll(str, &endptr, 10);
632 				if (lpref == 0)
633 					*va_arg(args, int *) = ival;
634 				else if (lpref == 1)
635 					*va_arg(args, long *) = ival;
636 				else if (lpref == 2)
637 					*va_arg(args, long long *) = ival;
638 			} else if (*format == 'u' || *format == 'x' || *format == 'X') {
639 				base = *format == 'u' ? 10 : 16;
640 				uval = strtoull(str, &endptr, base);
641 				if (lpref == 0)
642 					*va_arg(args, unsigned int *) = uval;
643 				else if (lpref == 1)
644 					*va_arg(args, unsigned long *) = uval;
645 				else if (lpref == 2)
646 					*va_arg(args, unsigned long long *) = uval;
647 			} else if (*format == 'p') {
648 				*va_arg(args, void **) = (void *)strtoul(str, &endptr, 16);
649 			} else {
650 				SET_ERRNO(EILSEQ);
651 				goto done;
652 			}
653 
654 			format++;
655 			str = endptr;
656 			matches++;
657 
658 		} else if (*format == '\0') {
659 			goto done;
660 		} else if (isspace(*format)) {
661 			/* skip spaces in format and str */
662 			while (isspace(*format))
663 				format++;
664 			while (isspace(*str))
665 				str++;
666 		} else if (*format == *str) {
667 			/* literal match */
668 			format++;
669 			str++;
670 		} else {
671 			if (!matches)
672 				matches = EOF;
673 			goto done;
674 		}
675 	}
676 
677 done:
678 	return matches;
679 }
680 
681 static __attribute__((unused, format(scanf, 2, 3)))
682 int sscanf(const char *str, const char *format, ...)
683 {
684 	va_list args;
685 	int ret;
686 
687 	va_start(args, format);
688 	ret = vsscanf(str, format, args);
689 	va_end(args);
690 	return ret;
691 }
692 
693 static __attribute__((unused))
694 void perror(const char *msg)
695 {
696 #ifdef NOLIBC_IGNORE_ERRNO
697 	fprintf(stderr, "%s%sunknown error\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "");
698 #else
699 	fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
700 #endif
701 }
702 
703 static __attribute__((unused))
704 int setvbuf(FILE *stream __attribute__((unused)),
705 	    char *buf __attribute__((unused)),
706 	    int mode,
707 	    size_t size __attribute__((unused)))
708 {
709 	/*
710 	 * nolibc does not support buffering so this is a nop. Just check mode
711 	 * is valid as required by the spec.
712 	 */
713 	switch (mode) {
714 	case _IOFBF:
715 	case _IOLBF:
716 	case _IONBF:
717 		break;
718 	default:
719 		return EOF;
720 	}
721 
722 	return 0;
723 }
724 
725 static __attribute__((unused))
726 int strerror_r(int errnum, char *buf, size_t buflen)
727 {
728 	if (buflen < 18)
729 		return ERANGE;
730 
731 	__builtin_memcpy(buf, "errno=", 6);
732 	i64toa_r(errnum, buf + 6);
733 	return 0;
734 }
735 
736 static __attribute__((unused))
737 const char *strerror(int errno)
738 {
739 	static char buf[18];
740 	char *b = buf;
741 
742 	/* Force gcc to use 'register offset' to access buf[]. */
743 	_NOLIBC_OPTIMIZER_HIDE_VAR(b);
744 
745 	/* Use strerror_r() to avoid having the only .data in small programs. */
746 	strerror_r(errno, b, sizeof(buf));
747 
748 	return b;
749 }
750 
751 #endif /* _NOLIBC_STDIO_H */
752