Warning: This file is not a C or C++ file. It does not have highlighting.

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

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of linux/tools/include/nolibc/stdio.h