1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
3 * minimal stdio function definitions for NOLIBC
4 * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
7 #ifndef _NOLIBC_STDIO_H
8 #define _NOLIBC_STDIO_H
23 /* Buffering mode used by setvbuf. */
24 #define _IOFBF 0 /* Fully buffered. */
25 #define _IOLBF 1 /* Line buffered. */
26 #define _IONBF 2 /* No buffering. */
28 /* just define FILE as a non-empty type. The value of the pointer gives
29 * the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE
30 * are immediately identified as abnormal entries (i.e. possible copies
31 * of valid pointers to something else).
37 static __attribute__((unused)) FILE* const stdin = (FILE*)(intptr_t)~STDIN_FILENO;
38 static __attribute__((unused)) FILE* const stdout = (FILE*)(intptr_t)~STDOUT_FILENO;
39 static __attribute__((unused)) FILE* const stderr = (FILE*)(intptr_t)~STDERR_FILENO;
41 /* provides a FILE* equivalent of fd. The mode is ignored. */
42 static __attribute__((unused))
43 FILE *fdopen(int fd, const char *mode __attribute__((unused)))
49 return (FILE*)(intptr_t)~fd;
52 /* provides the fd of stream. */
53 static __attribute__((unused))
54 int fileno(FILE *stream)
56 intptr_t i = (intptr_t)stream;
66 static __attribute__((unused))
67 int fflush(FILE *stream)
69 intptr_t i = (intptr_t)stream;
71 /* NULL is valid here. */
77 /* Don't do anything, nolibc does not support buffering. */
82 static __attribute__((unused))
83 int fclose(FILE *stream)
85 intptr_t i = (intptr_t)stream;
98 /* getc(), fgetc(), getchar() */
100 #define getc(stream) fgetc(stream)
102 static __attribute__((unused))
103 int fgetc(FILE* stream)
107 if (read(fileno(stream), &ch, 1) <= 0)
112 static __attribute__((unused))
119 /* putc(), fputc(), putchar() */
121 #define putc(c, stream) fputc(c, stream)
123 static __attribute__((unused))
124 int fputc(int c, FILE* stream)
126 unsigned char ch = c;
128 if (write(fileno(stream), &ch, 1) <= 0)
133 static __attribute__((unused))
136 return fputc(c, stdout);
140 /* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
142 /* internal fwrite()-like function which only takes a size and returns 0 on
143 * success or EOF on error. It automatically retries on short writes.
145 static __attribute__((unused))
146 int _fwrite(const void *buf, size_t size, FILE *stream)
149 int fd = fileno(stream);
152 ret = write(fd, buf, size);
161 static __attribute__((unused))
162 size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
166 for (written = 0; written < nmemb; written++) {
167 if (_fwrite(s, size, stream) != 0)
174 static __attribute__((unused))
175 int fputs(const char *s, FILE *stream)
177 return _fwrite(s, strlen(s), stream);
180 static __attribute__((unused))
181 int puts(const char *s)
183 if (fputs(s, stdout) == EOF)
185 return putchar('\n');
190 static __attribute__((unused))
191 char *fgets(char *s, int size, FILE *stream)
196 for (ofs = 0; ofs + 1 < size;) {
206 return ofs ? s : NULL;
210 /* minimal vfprintf(). It supports the following formats:
213 * - unknown modifiers are ignored.
215 static __attribute__((unused, format(printf, 2, 0)))
216 int vfprintf(FILE *stream, const char *fmt, va_list args)
218 char escape, lpref, c;
219 unsigned long long v;
220 unsigned int written;
225 written = ofs = escape = lpref = 0;
230 /* we're in an escape sequence, ofs == 1 */
232 if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') {
236 v = va_arg(args, unsigned long);
239 v = va_arg(args, unsigned long long);
241 v = va_arg(args, unsigned long);
243 v = va_arg(args, unsigned int);
246 /* sign-extend the value */
248 v = (long long)(int)v;
250 v = (long long)(long)v;
268 default: /* 'x' and 'p' above */
275 outstr = va_arg(args, char *);
280 /* queue it verbatim */
284 /* modifiers or final 0 */
286 /* long format prefix, maintain the escape */
292 len = strlen(outstr);
296 /* not an escape sequence */
297 if (c == 0 || c == '%') {
298 /* flush pending data on escape or end */
304 if (_fwrite(outstr, len, stream) != 0)
316 /* literal char, just queue it */
321 static __attribute__((unused, format(printf, 1, 0)))
322 int vprintf(const char *fmt, va_list args)
324 return vfprintf(stdout, fmt, args);
327 static __attribute__((unused, format(printf, 2, 3)))
328 int fprintf(FILE *stream, const char *fmt, ...)
334 ret = vfprintf(stream, fmt, args);
339 static __attribute__((unused, format(printf, 1, 2)))
340 int printf(const char *fmt, ...)
346 ret = vfprintf(stdout, fmt, args);
351 static __attribute__((unused))
352 void perror(const char *msg)
354 fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
357 static __attribute__((unused))
358 int setvbuf(FILE *stream __attribute__((unused)),
359 char *buf __attribute__((unused)),
361 size_t size __attribute__((unused)))
364 * nolibc does not support buffering so this is a nop. Just check mode
365 * is valid as required by the spec.
379 /* make sure to include all global symbols */
382 #endif /* _NOLIBC_STDIO_H */