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 /* just define FILE as a non-empty type */
29 /* We define the 3 common stdio files as constant invalid pointers that
30 * are easily recognized.
32 static __attribute__((unused)) FILE* const stdin = (FILE*)-3;
33 static __attribute__((unused)) FILE* const stdout = (FILE*)-2;
34 static __attribute__((unused)) FILE* const stderr = (FILE*)-1;
36 /* getc(), fgetc(), getchar() */
38 #define getc(stream) fgetc(stream)
40 static __attribute__((unused))
41 int fgetc(FILE* stream)
46 if (stream < stdin || stream > stderr)
49 fd = 3 + (long)stream;
51 if (read(fd, &ch, 1) <= 0)
56 static __attribute__((unused))
63 /* putc(), fputc(), putchar() */
65 #define putc(c, stream) fputc(c, stream)
67 static __attribute__((unused))
68 int fputc(int c, FILE* stream)
73 if (stream < stdin || stream > stderr)
76 fd = 3 + (long)stream;
78 if (write(fd, &ch, 1) <= 0)
83 static __attribute__((unused))
86 return fputc(c, stdout);
90 /* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
92 /* internal fwrite()-like function which only takes a size and returns 0 on
93 * success or EOF on error. It automatically retries on short writes.
95 static __attribute__((unused))
96 int _fwrite(const void *buf, size_t size, FILE *stream)
101 if (stream < stdin || stream > stderr)
104 fd = 3 + (long)stream;
107 ret = write(fd, buf, size);
116 static __attribute__((unused))
117 size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
121 for (written = 0; written < nmemb; written++) {
122 if (_fwrite(s, size, stream) != 0)
129 static __attribute__((unused))
130 int fputs(const char *s, FILE *stream)
132 return _fwrite(s, strlen(s), stream);
135 static __attribute__((unused))
136 int puts(const char *s)
138 if (fputs(s, stdout) == EOF)
140 return putchar('\n');
145 static __attribute__((unused))
146 char *fgets(char *s, int size, FILE *stream)
151 for (ofs = 0; ofs + 1 < size;) {
161 return ofs ? s : NULL;
165 /* minimal vfprintf(). It supports the following formats:
168 * - unknown modifiers are ignored.
170 static __attribute__((unused))
171 int vfprintf(FILE *stream, const char *fmt, va_list args)
173 char escape, lpref, c;
174 unsigned long long v;
175 unsigned int written;
180 written = ofs = escape = lpref = 0;
185 /* we're in an escape sequence, ofs == 1 */
187 if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') {
191 v = va_arg(args, unsigned long);
194 v = va_arg(args, unsigned long long);
196 v = va_arg(args, unsigned long);
198 v = va_arg(args, unsigned int);
201 /* sign-extend the value */
203 v = (long long)(int)v;
205 v = (long long)(long)v;
223 default: /* 'x' and 'p' above */
230 outstr = va_arg(args, char *);
235 /* queue it verbatim */
239 /* modifiers or final 0 */
241 /* long format prefix, maintain the escape */
247 len = strlen(outstr);
251 /* not an escape sequence */
252 if (c == 0 || c == '%') {
253 /* flush pending data on escape or end */
259 if (_fwrite(outstr, len, stream) != 0)
271 /* literal char, just queue it */
276 static __attribute__((unused, format(printf, 2, 3)))
277 int fprintf(FILE *stream, const char *fmt, ...)
283 ret = vfprintf(stream, fmt, args);
288 static __attribute__((unused, format(printf, 1, 2)))
289 int printf(const char *fmt, ...)
295 ret = vfprintf(stdout, fmt, args);
300 static __attribute__((unused))
301 void perror(const char *msg)
303 fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
306 #endif /* _NOLIBC_STDIO_H */