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
24 /* Buffering mode used by setvbuf. */
25 #define _IOFBF 0 /* Fully buffered. */
26 #define _IOLBF 1 /* Line buffered. */
27 #define _IONBF 2 /* No buffering. */
29 /* just define FILE as a non-empty type. The value of the pointer gives
30 * the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE
31 * are immediately identified as abnormal entries (i.e. possible copies
32 * of valid pointers to something else).
38 static __attribute__((unused
)) FILE* const stdin
= (FILE*)(intptr_t)~STDIN_FILENO
;
39 static __attribute__((unused
)) FILE* const stdout
= (FILE*)(intptr_t)~STDOUT_FILENO
;
40 static __attribute__((unused
)) FILE* const stderr
= (FILE*)(intptr_t)~STDERR_FILENO
;
42 /* provides a FILE* equivalent of fd. The mode is ignored. */
43 static __attribute__((unused
))
44 FILE *fdopen(int fd
, const char *mode
__attribute__((unused
)))
50 return (FILE*)(intptr_t)~fd
;
53 /* provides the fd of stream. */
54 static __attribute__((unused
))
55 int fileno(FILE *stream
)
57 intptr_t i
= (intptr_t)stream
;
67 static __attribute__((unused
))
68 int fflush(FILE *stream
)
70 intptr_t i
= (intptr_t)stream
;
72 /* NULL is valid here. */
78 /* Don't do anything, nolibc does not support buffering. */
83 static __attribute__((unused
))
84 int fclose(FILE *stream
)
86 intptr_t i
= (intptr_t)stream
;
99 /* getc(), fgetc(), getchar() */
101 #define getc(stream) fgetc(stream)
103 static __attribute__((unused
))
104 int fgetc(FILE* stream
)
108 if (read(fileno(stream
), &ch
, 1) <= 0)
113 static __attribute__((unused
))
120 /* putc(), fputc(), putchar() */
122 #define putc(c, stream) fputc(c, stream)
124 static __attribute__((unused
))
125 int fputc(int c
, FILE* stream
)
127 unsigned char ch
= c
;
129 if (write(fileno(stream
), &ch
, 1) <= 0)
134 static __attribute__((unused
))
137 return fputc(c
, stdout
);
141 /* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
143 /* internal fwrite()-like function which only takes a size and returns 0 on
144 * success or EOF on error. It automatically retries on short writes.
146 static __attribute__((unused
))
147 int _fwrite(const void *buf
, size_t size
, FILE *stream
)
150 int fd
= fileno(stream
);
153 ret
= write(fd
, buf
, size
);
162 static __attribute__((unused
))
163 size_t fwrite(const void *s
, size_t size
, size_t nmemb
, FILE *stream
)
167 for (written
= 0; written
< nmemb
; written
++) {
168 if (_fwrite(s
, size
, stream
) != 0)
175 static __attribute__((unused
))
176 int fputs(const char *s
, FILE *stream
)
178 return _fwrite(s
, strlen(s
), stream
);
181 static __attribute__((unused
))
182 int puts(const char *s
)
184 if (fputs(s
, stdout
) == EOF
)
186 return putchar('\n');
191 static __attribute__((unused
))
192 char *fgets(char *s
, int size
, FILE *stream
)
197 for (ofs
= 0; ofs
+ 1 < size
;) {
207 return ofs
? s
: NULL
;
211 /* minimal vfprintf(). It supports the following formats:
214 * - unknown modifiers are ignored.
216 static __attribute__((unused
, format(printf
, 2, 0)))
217 int vfprintf(FILE *stream
, const char *fmt
, va_list args
)
219 char escape
, lpref
, c
;
220 unsigned long long v
;
221 unsigned int written
;
226 written
= ofs
= escape
= lpref
= 0;
231 /* we're in an escape sequence, ofs == 1 */
233 if (c
== 'c' || c
== 'd' || c
== 'u' || c
== 'x' || c
== 'p') {
237 v
= va_arg(args
, unsigned long);
240 v
= va_arg(args
, unsigned long long);
242 v
= va_arg(args
, unsigned long);
244 v
= va_arg(args
, unsigned int);
247 /* sign-extend the value */
249 v
= (long long)(int)v
;
251 v
= (long long)(long)v
;
268 __nolibc_fallthrough
;
269 default: /* 'x' and 'p' above */
276 outstr
= va_arg(args
, char *);
281 /* queue it verbatim */
285 /* modifiers or final 0 */
287 /* long format prefix, maintain the escape */
293 len
= strlen(outstr
);
297 /* not an escape sequence */
298 if (c
== 0 || c
== '%') {
299 /* flush pending data on escape or end */
305 if (_fwrite(outstr
, len
, stream
) != 0)
317 /* literal char, just queue it */
322 static __attribute__((unused
, format(printf
, 1, 0)))
323 int vprintf(const char *fmt
, va_list args
)
325 return vfprintf(stdout
, fmt
, args
);
328 static __attribute__((unused
, format(printf
, 2, 3)))
329 int fprintf(FILE *stream
, const char *fmt
, ...)
335 ret
= vfprintf(stream
, fmt
, args
);
340 static __attribute__((unused
, format(printf
, 1, 2)))
341 int printf(const char *fmt
, ...)
347 ret
= vfprintf(stdout
, fmt
, args
);
352 static __attribute__((unused
))
353 void perror(const char *msg
)
355 fprintf(stderr
, "%s%serrno=%d\n", (msg
&& *msg
) ? msg
: "", (msg
&& *msg
) ? ": " : "", errno
);
358 static __attribute__((unused
))
359 int setvbuf(FILE *stream
__attribute__((unused
)),
360 char *buf
__attribute__((unused
)),
362 size_t size
__attribute__((unused
)))
365 * nolibc does not support buffering so this is a nop. Just check mode
366 * is valid as required by the spec.
380 static __attribute__((unused
))
381 const char *strerror(int errno
)
383 static char buf
[18] = "errno=";
385 i64toa_r(errno
, &buf
[6]);
390 /* make sure to include all global symbols */
393 #endif /* _NOLIBC_STDIO_H */