Merge tag 'nfsd-6.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
[platform/kernel/linux-rpi.git] / tools / include / nolibc / stdio.h
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 #ifndef _NOLIBC_STDIO_H
8 #define _NOLIBC_STDIO_H
9
10 #include <stdarg.h>
11
12 #include "std.h"
13 #include "arch.h"
14 #include "errno.h"
15 #include "types.h"
16 #include "sys.h"
17 #include "stdlib.h"
18 #include "string.h"
19
20 #ifndef EOF
21 #define EOF (-1)
22 #endif
23
24 /* Buffering mode used by setvbuf.  */
25 #define _IOFBF 0        /* Fully buffered. */
26 #define _IOLBF 1        /* Line buffered. */
27 #define _IONBF 2        /* No buffering. */
28
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).
33  */
34 typedef struct FILE {
35         char dummy[1];
36 } FILE;
37
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;
41
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)))
45 {
46         if (fd < 0) {
47                 SET_ERRNO(EBADF);
48                 return NULL;
49         }
50         return (FILE*)(intptr_t)~fd;
51 }
52
53 /* provides the fd of stream. */
54 static __attribute__((unused))
55 int fileno(FILE *stream)
56 {
57         intptr_t i = (intptr_t)stream;
58
59         if (i >= 0) {
60                 SET_ERRNO(EBADF);
61                 return -1;
62         }
63         return ~i;
64 }
65
66 /* flush a stream. */
67 static __attribute__((unused))
68 int fflush(FILE *stream)
69 {
70         intptr_t i = (intptr_t)stream;
71
72         /* NULL is valid here. */
73         if (i > 0) {
74                 SET_ERRNO(EBADF);
75                 return -1;
76         }
77
78         /* Don't do anything, nolibc does not support buffering. */
79         return 0;
80 }
81
82 /* flush a stream. */
83 static __attribute__((unused))
84 int fclose(FILE *stream)
85 {
86         intptr_t i = (intptr_t)stream;
87
88         if (i >= 0) {
89                 SET_ERRNO(EBADF);
90                 return -1;
91         }
92
93         if (close(~i))
94                 return EOF;
95
96         return 0;
97 }
98
99 /* getc(), fgetc(), getchar() */
100
101 #define getc(stream) fgetc(stream)
102
103 static __attribute__((unused))
104 int fgetc(FILE* stream)
105 {
106         unsigned char ch;
107
108         if (read(fileno(stream), &ch, 1) <= 0)
109                 return EOF;
110         return ch;
111 }
112
113 static __attribute__((unused))
114 int getchar(void)
115 {
116         return fgetc(stdin);
117 }
118
119
120 /* putc(), fputc(), putchar() */
121
122 #define putc(c, stream) fputc(c, stream)
123
124 static __attribute__((unused))
125 int fputc(int c, FILE* stream)
126 {
127         unsigned char ch = c;
128
129         if (write(fileno(stream), &ch, 1) <= 0)
130                 return EOF;
131         return ch;
132 }
133
134 static __attribute__((unused))
135 int putchar(int c)
136 {
137         return fputc(c, stdout);
138 }
139
140
141 /* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
142
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.
145  */
146 static __attribute__((unused))
147 int _fwrite(const void *buf, size_t size, FILE *stream)
148 {
149         ssize_t ret;
150         int fd = fileno(stream);
151
152         while (size) {
153                 ret = write(fd, buf, size);
154                 if (ret <= 0)
155                         return EOF;
156                 size -= ret;
157                 buf += ret;
158         }
159         return 0;
160 }
161
162 static __attribute__((unused))
163 size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
164 {
165         size_t written;
166
167         for (written = 0; written < nmemb; written++) {
168                 if (_fwrite(s, size, stream) != 0)
169                         break;
170                 s += size;
171         }
172         return written;
173 }
174
175 static __attribute__((unused))
176 int fputs(const char *s, FILE *stream)
177 {
178         return _fwrite(s, strlen(s), stream);
179 }
180
181 static __attribute__((unused))
182 int puts(const char *s)
183 {
184         if (fputs(s, stdout) == EOF)
185                 return EOF;
186         return putchar('\n');
187 }
188
189
190 /* fgets() */
191 static __attribute__((unused))
192 char *fgets(char *s, int size, FILE *stream)
193 {
194         int ofs;
195         int c;
196
197         for (ofs = 0; ofs + 1 < size;) {
198                 c = fgetc(stream);
199                 if (c == EOF)
200                         break;
201                 s[ofs++] = c;
202                 if (c == '\n')
203                         break;
204         }
205         if (ofs < size)
206                 s[ofs] = 0;
207         return ofs ? s : NULL;
208 }
209
210
211 /* minimal vfprintf(). It supports the following formats:
212  *  - %[l*]{d,u,c,x,p}
213  *  - %s
214  *  - unknown modifiers are ignored.
215  */
216 static __attribute__((unused))
217 int vfprintf(FILE *stream, const char *fmt, va_list args)
218 {
219         char escape, lpref, c;
220         unsigned long long v;
221         unsigned int written;
222         size_t len, ofs;
223         char tmpbuf[21];
224         const char *outstr;
225
226         written = ofs = escape = lpref = 0;
227         while (1) {
228                 c = fmt[ofs++];
229
230                 if (escape) {
231                         /* we're in an escape sequence, ofs == 1 */
232                         escape = 0;
233                         if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') {
234                                 char *out = tmpbuf;
235
236                                 if (c == 'p')
237                                         v = va_arg(args, unsigned long);
238                                 else if (lpref) {
239                                         if (lpref > 1)
240                                                 v = va_arg(args, unsigned long long);
241                                         else
242                                                 v = va_arg(args, unsigned long);
243                                 } else
244                                         v = va_arg(args, unsigned int);
245
246                                 if (c == 'd') {
247                                         /* sign-extend the value */
248                                         if (lpref == 0)
249                                                 v = (long long)(int)v;
250                                         else if (lpref == 1)
251                                                 v = (long long)(long)v;
252                                 }
253
254                                 switch (c) {
255                                 case 'c':
256                                         out[0] = v;
257                                         out[1] = 0;
258                                         break;
259                                 case 'd':
260                                         i64toa_r(v, out);
261                                         break;
262                                 case 'u':
263                                         u64toa_r(v, out);
264                                         break;
265                                 case 'p':
266                                         *(out++) = '0';
267                                         *(out++) = 'x';
268                                         /* fall through */
269                                 default: /* 'x' and 'p' above */
270                                         u64toh_r(v, out);
271                                         break;
272                                 }
273                                 outstr = tmpbuf;
274                         }
275                         else if (c == 's') {
276                                 outstr = va_arg(args, char *);
277                                 if (!outstr)
278                                         outstr="(null)";
279                         }
280                         else if (c == '%') {
281                                 /* queue it verbatim */
282                                 continue;
283                         }
284                         else {
285                                 /* modifiers or final 0 */
286                                 if (c == 'l') {
287                                         /* long format prefix, maintain the escape */
288                                         lpref++;
289                                 }
290                                 escape = 1;
291                                 goto do_escape;
292                         }
293                         len = strlen(outstr);
294                         goto flush_str;
295                 }
296
297                 /* not an escape sequence */
298                 if (c == 0 || c == '%') {
299                         /* flush pending data on escape or end */
300                         escape = 1;
301                         lpref = 0;
302                         outstr = fmt;
303                         len = ofs - 1;
304                 flush_str:
305                         if (_fwrite(outstr, len, stream) != 0)
306                                 break;
307
308                         written += len;
309                 do_escape:
310                         if (c == 0)
311                                 break;
312                         fmt += ofs;
313                         ofs = 0;
314                         continue;
315                 }
316
317                 /* literal char, just queue it */
318         }
319         return written;
320 }
321
322 static __attribute__((unused))
323 int vprintf(const char *fmt, va_list args)
324 {
325         return vfprintf(stdout, fmt, args);
326 }
327
328 static __attribute__((unused, format(printf, 2, 3)))
329 int fprintf(FILE *stream, const char *fmt, ...)
330 {
331         va_list args;
332         int ret;
333
334         va_start(args, fmt);
335         ret = vfprintf(stream, fmt, args);
336         va_end(args);
337         return ret;
338 }
339
340 static __attribute__((unused, format(printf, 1, 2)))
341 int printf(const char *fmt, ...)
342 {
343         va_list args;
344         int ret;
345
346         va_start(args, fmt);
347         ret = vfprintf(stdout, fmt, args);
348         va_end(args);
349         return ret;
350 }
351
352 static __attribute__((unused))
353 void perror(const char *msg)
354 {
355         fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
356 }
357
358 static __attribute__((unused))
359 int setvbuf(FILE *stream __attribute__((unused)),
360             char *buf __attribute__((unused)),
361             int mode,
362             size_t size __attribute__((unused)))
363 {
364         /*
365          * nolibc does not support buffering so this is a nop. Just check mode
366          * is valid as required by the spec.
367          */
368         switch (mode) {
369         case _IOFBF:
370         case _IOLBF:
371         case _IONBF:
372                 break;
373         default:
374                 return EOF;
375         }
376
377         return 0;
378 }
379
380 /* make sure to include all global symbols */
381 #include "nolibc.h"
382
383 #endif /* _NOLIBC_STDIO_H */