Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/include/nolibc/stdio.h
49411 views
1
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2
/*
3
* minimal stdio function definitions for NOLIBC
4
* Copyright (C) 2017-2021 Willy Tarreau <[email protected]>
5
*/
6
7
/* make sure to include all global symbols */
8
#include "nolibc.h"
9
10
#ifndef _NOLIBC_STDIO_H
11
#define _NOLIBC_STDIO_H
12
13
#include "std.h"
14
#include "arch.h"
15
#include "errno.h"
16
#include "fcntl.h"
17
#include "types.h"
18
#include "sys.h"
19
#include "stdarg.h"
20
#include "stdlib.h"
21
#include "string.h"
22
#include "compiler.h"
23
24
static const char *strerror(int errnum);
25
26
#ifndef EOF
27
#define EOF (-1)
28
#endif
29
30
/* Buffering mode used by setvbuf. */
31
#define _IOFBF 0 /* Fully buffered. */
32
#define _IOLBF 1 /* Line buffered. */
33
#define _IONBF 2 /* No buffering. */
34
35
/* just define FILE as a non-empty type. The value of the pointer gives
36
* the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE
37
* are immediately identified as abnormal entries (i.e. possible copies
38
* of valid pointers to something else).
39
*/
40
typedef struct FILE {
41
char dummy[1];
42
} FILE;
43
44
static __attribute__((unused)) FILE* const stdin = (FILE*)(intptr_t)~STDIN_FILENO;
45
static __attribute__((unused)) FILE* const stdout = (FILE*)(intptr_t)~STDOUT_FILENO;
46
static __attribute__((unused)) FILE* const stderr = (FILE*)(intptr_t)~STDERR_FILENO;
47
48
/* provides a FILE* equivalent of fd. The mode is ignored. */
49
static __attribute__((unused))
50
FILE *fdopen(int fd, const char *mode __attribute__((unused)))
51
{
52
if (fd < 0) {
53
SET_ERRNO(EBADF);
54
return NULL;
55
}
56
return (FILE*)(intptr_t)~fd;
57
}
58
59
static __attribute__((unused))
60
FILE *fopen(const char *pathname, const char *mode)
61
{
62
int flags, fd;
63
64
switch (*mode) {
65
case 'r':
66
flags = O_RDONLY;
67
break;
68
case 'w':
69
flags = O_WRONLY | O_CREAT | O_TRUNC;
70
break;
71
case 'a':
72
flags = O_WRONLY | O_CREAT | O_APPEND;
73
break;
74
default:
75
SET_ERRNO(EINVAL); return NULL;
76
}
77
78
if (mode[1] == '+')
79
flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
80
81
fd = open(pathname, flags, 0666);
82
return fdopen(fd, mode);
83
}
84
85
/* provides the fd of stream. */
86
static __attribute__((unused))
87
int fileno(FILE *stream)
88
{
89
intptr_t i = (intptr_t)stream;
90
91
if (i >= 0) {
92
SET_ERRNO(EBADF);
93
return -1;
94
}
95
return ~i;
96
}
97
98
/* flush a stream. */
99
static __attribute__((unused))
100
int fflush(FILE *stream)
101
{
102
intptr_t i = (intptr_t)stream;
103
104
/* NULL is valid here. */
105
if (i > 0) {
106
SET_ERRNO(EBADF);
107
return -1;
108
}
109
110
/* Don't do anything, nolibc does not support buffering. */
111
return 0;
112
}
113
114
/* flush a stream. */
115
static __attribute__((unused))
116
int fclose(FILE *stream)
117
{
118
intptr_t i = (intptr_t)stream;
119
120
if (i >= 0) {
121
SET_ERRNO(EBADF);
122
return -1;
123
}
124
125
if (close(~i))
126
return EOF;
127
128
return 0;
129
}
130
131
/* getc(), fgetc(), getchar() */
132
133
#define getc(stream) fgetc(stream)
134
135
static __attribute__((unused))
136
int fgetc(FILE* stream)
137
{
138
unsigned char ch;
139
140
if (read(fileno(stream), &ch, 1) <= 0)
141
return EOF;
142
return ch;
143
}
144
145
static __attribute__((unused))
146
int getchar(void)
147
{
148
return fgetc(stdin);
149
}
150
151
152
/* putc(), fputc(), putchar() */
153
154
#define putc(c, stream) fputc(c, stream)
155
156
static __attribute__((unused))
157
int fputc(int c, FILE* stream)
158
{
159
unsigned char ch = c;
160
161
if (write(fileno(stream), &ch, 1) <= 0)
162
return EOF;
163
return ch;
164
}
165
166
static __attribute__((unused))
167
int putchar(int c)
168
{
169
return fputc(c, stdout);
170
}
171
172
173
/* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
174
175
/* internal fwrite()-like function which only takes a size and returns 0 on
176
* success or EOF on error. It automatically retries on short writes.
177
*/
178
static __attribute__((unused))
179
int _fwrite(const void *buf, size_t size, FILE *stream)
180
{
181
ssize_t ret;
182
int fd = fileno(stream);
183
184
while (size) {
185
ret = write(fd, buf, size);
186
if (ret <= 0)
187
return EOF;
188
size -= ret;
189
buf += ret;
190
}
191
return 0;
192
}
193
194
static __attribute__((unused))
195
size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
196
{
197
size_t written;
198
199
for (written = 0; written < nmemb; written++) {
200
if (_fwrite(s, size, stream) != 0)
201
break;
202
s += size;
203
}
204
return written;
205
}
206
207
static __attribute__((unused))
208
int fputs(const char *s, FILE *stream)
209
{
210
return _fwrite(s, strlen(s), stream);
211
}
212
213
static __attribute__((unused))
214
int puts(const char *s)
215
{
216
if (fputs(s, stdout) == EOF)
217
return EOF;
218
return putchar('\n');
219
}
220
221
222
/* fgets() */
223
static __attribute__((unused))
224
char *fgets(char *s, int size, FILE *stream)
225
{
226
int ofs;
227
int c;
228
229
for (ofs = 0; ofs + 1 < size;) {
230
c = fgetc(stream);
231
if (c == EOF)
232
break;
233
s[ofs++] = c;
234
if (c == '\n')
235
break;
236
}
237
if (ofs < size)
238
s[ofs] = 0;
239
return ofs ? s : NULL;
240
}
241
242
243
/* minimal printf(). It supports the following formats:
244
* - %[l*]{d,u,c,x,p}
245
* - %s
246
* - unknown modifiers are ignored.
247
*/
248
typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size);
249
250
static __attribute__((unused, format(printf, 4, 0)))
251
int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args)
252
{
253
char escape, lpref, c;
254
unsigned long long v;
255
unsigned int written, width;
256
size_t len, ofs, w;
257
char tmpbuf[21];
258
const char *outstr;
259
260
written = ofs = escape = lpref = 0;
261
while (1) {
262
c = fmt[ofs++];
263
width = 0;
264
265
if (escape) {
266
/* we're in an escape sequence, ofs == 1 */
267
escape = 0;
268
269
/* width */
270
while (c >= '0' && c <= '9') {
271
width *= 10;
272
width += c - '0';
273
274
c = fmt[ofs++];
275
}
276
277
if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') {
278
char *out = tmpbuf;
279
280
if (c == 'p')
281
v = va_arg(args, unsigned long);
282
else if (lpref) {
283
if (lpref > 1)
284
v = va_arg(args, unsigned long long);
285
else
286
v = va_arg(args, unsigned long);
287
} else
288
v = va_arg(args, unsigned int);
289
290
if (c == 'd') {
291
/* sign-extend the value */
292
if (lpref == 0)
293
v = (long long)(int)v;
294
else if (lpref == 1)
295
v = (long long)(long)v;
296
}
297
298
switch (c) {
299
case 'c':
300
out[0] = v;
301
out[1] = 0;
302
break;
303
case 'd':
304
i64toa_r(v, out);
305
break;
306
case 'u':
307
u64toa_r(v, out);
308
break;
309
case 'p':
310
*(out++) = '0';
311
*(out++) = 'x';
312
__nolibc_fallthrough;
313
default: /* 'x' and 'p' above */
314
u64toh_r(v, out);
315
break;
316
}
317
outstr = tmpbuf;
318
}
319
else if (c == 's') {
320
outstr = va_arg(args, char *);
321
if (!outstr)
322
outstr="(null)";
323
}
324
else if (c == 'm') {
325
#ifdef NOLIBC_IGNORE_ERRNO
326
outstr = "unknown error";
327
#else
328
outstr = strerror(errno);
329
#endif /* NOLIBC_IGNORE_ERRNO */
330
}
331
else if (c == '%') {
332
/* queue it verbatim */
333
continue;
334
}
335
else {
336
/* modifiers or final 0 */
337
if (c == 'l') {
338
/* long format prefix, maintain the escape */
339
lpref++;
340
} else if (c == 'j') {
341
lpref = 2;
342
}
343
escape = 1;
344
goto do_escape;
345
}
346
len = strlen(outstr);
347
goto flush_str;
348
}
349
350
/* not an escape sequence */
351
if (c == 0 || c == '%') {
352
/* flush pending data on escape or end */
353
escape = 1;
354
lpref = 0;
355
outstr = fmt;
356
len = ofs - 1;
357
flush_str:
358
if (n) {
359
w = len < n ? len : n;
360
n -= w;
361
while (width-- > w) {
362
if (cb(state, " ", 1) != 0)
363
return -1;
364
written += 1;
365
}
366
if (cb(state, outstr, w) != 0)
367
return -1;
368
}
369
370
written += len;
371
do_escape:
372
if (c == 0)
373
break;
374
fmt += ofs;
375
ofs = 0;
376
continue;
377
}
378
379
/* literal char, just queue it */
380
}
381
return written;
382
}
383
384
static int __nolibc_fprintf_cb(intptr_t state, const char *buf, size_t size)
385
{
386
return _fwrite(buf, size, (FILE *)state);
387
}
388
389
static __attribute__((unused, format(printf, 2, 0)))
390
int vfprintf(FILE *stream, const char *fmt, va_list args)
391
{
392
return __nolibc_printf(__nolibc_fprintf_cb, (intptr_t)stream, SIZE_MAX, fmt, args);
393
}
394
395
static __attribute__((unused, format(printf, 1, 0)))
396
int vprintf(const char *fmt, va_list args)
397
{
398
return vfprintf(stdout, fmt, args);
399
}
400
401
static __attribute__((unused, format(printf, 2, 3)))
402
int fprintf(FILE *stream, const char *fmt, ...)
403
{
404
va_list args;
405
int ret;
406
407
va_start(args, fmt);
408
ret = vfprintf(stream, fmt, args);
409
va_end(args);
410
return ret;
411
}
412
413
static __attribute__((unused, format(printf, 1, 2)))
414
int printf(const char *fmt, ...)
415
{
416
va_list args;
417
int ret;
418
419
va_start(args, fmt);
420
ret = vfprintf(stdout, fmt, args);
421
va_end(args);
422
return ret;
423
}
424
425
static __attribute__((unused, format(printf, 2, 0)))
426
int vdprintf(int fd, const char *fmt, va_list args)
427
{
428
FILE *stream;
429
430
stream = fdopen(fd, NULL);
431
if (!stream)
432
return -1;
433
/* Technically 'stream' is leaked, but as it's only a wrapper around 'fd' that is fine */
434
return vfprintf(stream, fmt, args);
435
}
436
437
static __attribute__((unused, format(printf, 2, 3)))
438
int dprintf(int fd, const char *fmt, ...)
439
{
440
va_list args;
441
int ret;
442
443
va_start(args, fmt);
444
ret = vdprintf(fd, fmt, args);
445
va_end(args);
446
447
return ret;
448
}
449
450
static int __nolibc_sprintf_cb(intptr_t _state, const char *buf, size_t size)
451
{
452
char **state = (char **)_state;
453
454
memcpy(*state, buf, size);
455
*state += size;
456
return 0;
457
}
458
459
static __attribute__((unused, format(printf, 3, 0)))
460
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
461
{
462
char *state = buf;
463
int ret;
464
465
ret = __nolibc_printf(__nolibc_sprintf_cb, (intptr_t)&state, size, fmt, args);
466
if (ret < 0)
467
return ret;
468
buf[(size_t)ret < size ? (size_t)ret : size - 1] = '\0';
469
return ret;
470
}
471
472
static __attribute__((unused, format(printf, 3, 4)))
473
int snprintf(char *buf, size_t size, const char *fmt, ...)
474
{
475
va_list args;
476
int ret;
477
478
va_start(args, fmt);
479
ret = vsnprintf(buf, size, fmt, args);
480
va_end(args);
481
482
return ret;
483
}
484
485
static __attribute__((unused, format(printf, 2, 0)))
486
int vsprintf(char *buf, const char *fmt, va_list args)
487
{
488
return vsnprintf(buf, SIZE_MAX, fmt, args);
489
}
490
491
static __attribute__((unused, format(printf, 2, 3)))
492
int sprintf(char *buf, const char *fmt, ...)
493
{
494
va_list args;
495
int ret;
496
497
va_start(args, fmt);
498
ret = vsprintf(buf, fmt, args);
499
va_end(args);
500
501
return ret;
502
}
503
504
static __attribute__((unused))
505
int vsscanf(const char *str, const char *format, va_list args)
506
{
507
uintmax_t uval;
508
intmax_t ival;
509
int base;
510
char *endptr;
511
int matches;
512
int lpref;
513
514
matches = 0;
515
516
while (1) {
517
if (*format == '%') {
518
/* start of pattern */
519
lpref = 0;
520
format++;
521
522
if (*format == 'l') {
523
/* same as in printf() */
524
lpref = 1;
525
format++;
526
if (*format == 'l') {
527
lpref = 2;
528
format++;
529
}
530
}
531
532
if (*format == '%') {
533
/* literal % */
534
if ('%' != *str)
535
goto done;
536
str++;
537
format++;
538
continue;
539
} else if (*format == 'd') {
540
ival = strtoll(str, &endptr, 10);
541
if (lpref == 0)
542
*va_arg(args, int *) = ival;
543
else if (lpref == 1)
544
*va_arg(args, long *) = ival;
545
else if (lpref == 2)
546
*va_arg(args, long long *) = ival;
547
} else if (*format == 'u' || *format == 'x' || *format == 'X') {
548
base = *format == 'u' ? 10 : 16;
549
uval = strtoull(str, &endptr, base);
550
if (lpref == 0)
551
*va_arg(args, unsigned int *) = uval;
552
else if (lpref == 1)
553
*va_arg(args, unsigned long *) = uval;
554
else if (lpref == 2)
555
*va_arg(args, unsigned long long *) = uval;
556
} else if (*format == 'p') {
557
*va_arg(args, void **) = (void *)strtoul(str, &endptr, 16);
558
} else {
559
SET_ERRNO(EILSEQ);
560
goto done;
561
}
562
563
format++;
564
str = endptr;
565
matches++;
566
567
} else if (*format == '\0') {
568
goto done;
569
} else if (isspace(*format)) {
570
/* skip spaces in format and str */
571
while (isspace(*format))
572
format++;
573
while (isspace(*str))
574
str++;
575
} else if (*format == *str) {
576
/* literal match */
577
format++;
578
str++;
579
} else {
580
if (!matches)
581
matches = EOF;
582
goto done;
583
}
584
}
585
586
done:
587
return matches;
588
}
589
590
static __attribute__((unused, format(scanf, 2, 3)))
591
int sscanf(const char *str, const char *format, ...)
592
{
593
va_list args;
594
int ret;
595
596
va_start(args, format);
597
ret = vsscanf(str, format, args);
598
va_end(args);
599
return ret;
600
}
601
602
static __attribute__((unused))
603
void perror(const char *msg)
604
{
605
#ifdef NOLIBC_IGNORE_ERRNO
606
fprintf(stderr, "%s%sunknown error\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "");
607
#else
608
fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
609
#endif
610
}
611
612
static __attribute__((unused))
613
int setvbuf(FILE *stream __attribute__((unused)),
614
char *buf __attribute__((unused)),
615
int mode,
616
size_t size __attribute__((unused)))
617
{
618
/*
619
* nolibc does not support buffering so this is a nop. Just check mode
620
* is valid as required by the spec.
621
*/
622
switch (mode) {
623
case _IOFBF:
624
case _IOLBF:
625
case _IONBF:
626
break;
627
default:
628
return EOF;
629
}
630
631
return 0;
632
}
633
634
static __attribute__((unused))
635
const char *strerror(int errno)
636
{
637
static char buf[18] = "errno=";
638
639
i64toa_r(errno, &buf[6]);
640
641
return buf;
642
}
643
644
#endif /* _NOLIBC_STDIO_H */
645
646