Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/include/nolibc/stdio.h
54333 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(), fread(), 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
/* internal fread()-like function which only takes a size and returns 0 on
208
* success or EOF on error. It automatically retries on short reads.
209
*/
210
static __attribute__((unused))
211
int _fread(void *buf, size_t size, FILE *stream)
212
{
213
int fd = fileno(stream);
214
ssize_t ret;
215
216
while (size) {
217
ret = read(fd, buf, size);
218
if (ret <= 0)
219
return EOF;
220
size -= ret;
221
buf += ret;
222
}
223
return 0;
224
}
225
226
static __attribute__((unused))
227
size_t fread(void *s, size_t size, size_t nmemb, FILE *stream)
228
{
229
size_t nread;
230
231
for (nread = 0; nread < nmemb; nread++) {
232
if (_fread(s, size, stream) != 0)
233
break;
234
s += size;
235
}
236
return nread;
237
}
238
239
static __attribute__((unused))
240
int fputs(const char *s, FILE *stream)
241
{
242
return _fwrite(s, strlen(s), stream);
243
}
244
245
static __attribute__((unused))
246
int puts(const char *s)
247
{
248
if (fputs(s, stdout) == EOF)
249
return EOF;
250
return putchar('\n');
251
}
252
253
254
/* fgets() */
255
static __attribute__((unused))
256
char *fgets(char *s, int size, FILE *stream)
257
{
258
int ofs;
259
int c;
260
261
for (ofs = 0; ofs + 1 < size;) {
262
c = fgetc(stream);
263
if (c == EOF)
264
break;
265
s[ofs++] = c;
266
if (c == '\n')
267
break;
268
}
269
if (ofs < size)
270
s[ofs] = 0;
271
return ofs ? s : NULL;
272
}
273
274
275
/* fseek */
276
static __attribute__((unused))
277
int fseek(FILE *stream, long offset, int whence)
278
{
279
int fd = fileno(stream);
280
off_t ret;
281
282
ret = lseek(fd, offset, whence);
283
284
/* lseek() and fseek() differ in that lseek returns the new
285
* position or -1, fseek() returns either 0 or -1.
286
*/
287
if (ret >= 0)
288
return 0;
289
290
return -1;
291
}
292
293
294
/* minimal printf(). It supports the following formats:
295
* - %[l*]{d,u,c,x,p}
296
* - %s
297
* - unknown modifiers are ignored.
298
*/
299
typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size);
300
301
static __attribute__((unused, format(printf, 4, 0)))
302
int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args)
303
{
304
char escape, lpref, c;
305
unsigned long long v;
306
unsigned int written, width;
307
size_t len, ofs, w;
308
char tmpbuf[21];
309
const char *outstr;
310
311
written = ofs = escape = lpref = 0;
312
while (1) {
313
c = fmt[ofs++];
314
width = 0;
315
316
if (escape) {
317
/* we're in an escape sequence, ofs == 1 */
318
escape = 0;
319
320
/* width */
321
while (c >= '0' && c <= '9') {
322
width *= 10;
323
width += c - '0';
324
325
c = fmt[ofs++];
326
}
327
328
if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') {
329
char *out = tmpbuf;
330
331
if (c == 'p')
332
v = va_arg(args, unsigned long);
333
else if (lpref) {
334
if (lpref > 1)
335
v = va_arg(args, unsigned long long);
336
else
337
v = va_arg(args, unsigned long);
338
} else
339
v = va_arg(args, unsigned int);
340
341
if (c == 'd') {
342
/* sign-extend the value */
343
if (lpref == 0)
344
v = (long long)(int)v;
345
else if (lpref == 1)
346
v = (long long)(long)v;
347
}
348
349
switch (c) {
350
case 'c':
351
out[0] = v;
352
out[1] = 0;
353
break;
354
case 'd':
355
i64toa_r(v, out);
356
break;
357
case 'u':
358
u64toa_r(v, out);
359
break;
360
case 'p':
361
*(out++) = '0';
362
*(out++) = 'x';
363
__nolibc_fallthrough;
364
default: /* 'x' and 'p' above */
365
u64toh_r(v, out);
366
break;
367
}
368
outstr = tmpbuf;
369
}
370
else if (c == 's') {
371
outstr = va_arg(args, char *);
372
if (!outstr)
373
outstr="(null)";
374
}
375
else if (c == 'm') {
376
#ifdef NOLIBC_IGNORE_ERRNO
377
outstr = "unknown error";
378
#else
379
outstr = strerror(errno);
380
#endif /* NOLIBC_IGNORE_ERRNO */
381
}
382
else if (c == '%') {
383
/* queue it verbatim */
384
continue;
385
}
386
else {
387
/* modifiers or final 0 */
388
if (c == 'l') {
389
/* long format prefix, maintain the escape */
390
lpref++;
391
} else if (c == 'j') {
392
lpref = 2;
393
}
394
escape = 1;
395
goto do_escape;
396
}
397
len = strlen(outstr);
398
goto flush_str;
399
}
400
401
/* not an escape sequence */
402
if (c == 0 || c == '%') {
403
/* flush pending data on escape or end */
404
escape = 1;
405
lpref = 0;
406
outstr = fmt;
407
len = ofs - 1;
408
flush_str:
409
if (n) {
410
w = len < n ? len : n;
411
n -= w;
412
while (width-- > w) {
413
if (cb(state, " ", 1) != 0)
414
return -1;
415
written += 1;
416
}
417
if (cb(state, outstr, w) != 0)
418
return -1;
419
}
420
421
written += len;
422
do_escape:
423
if (c == 0)
424
break;
425
fmt += ofs;
426
ofs = 0;
427
continue;
428
}
429
430
/* literal char, just queue it */
431
}
432
return written;
433
}
434
435
static int __nolibc_fprintf_cb(intptr_t state, const char *buf, size_t size)
436
{
437
return _fwrite(buf, size, (FILE *)state);
438
}
439
440
static __attribute__((unused, format(printf, 2, 0)))
441
int vfprintf(FILE *stream, const char *fmt, va_list args)
442
{
443
return __nolibc_printf(__nolibc_fprintf_cb, (intptr_t)stream, SIZE_MAX, fmt, args);
444
}
445
446
static __attribute__((unused, format(printf, 1, 0)))
447
int vprintf(const char *fmt, va_list args)
448
{
449
return vfprintf(stdout, fmt, args);
450
}
451
452
static __attribute__((unused, format(printf, 2, 3)))
453
int fprintf(FILE *stream, const char *fmt, ...)
454
{
455
va_list args;
456
int ret;
457
458
va_start(args, fmt);
459
ret = vfprintf(stream, fmt, args);
460
va_end(args);
461
return ret;
462
}
463
464
static __attribute__((unused, format(printf, 1, 2)))
465
int printf(const char *fmt, ...)
466
{
467
va_list args;
468
int ret;
469
470
va_start(args, fmt);
471
ret = vfprintf(stdout, fmt, args);
472
va_end(args);
473
return ret;
474
}
475
476
static __attribute__((unused, format(printf, 2, 0)))
477
int vdprintf(int fd, const char *fmt, va_list args)
478
{
479
FILE *stream;
480
481
stream = fdopen(fd, NULL);
482
if (!stream)
483
return -1;
484
/* Technically 'stream' is leaked, but as it's only a wrapper around 'fd' that is fine */
485
return vfprintf(stream, fmt, args);
486
}
487
488
static __attribute__((unused, format(printf, 2, 3)))
489
int dprintf(int fd, const char *fmt, ...)
490
{
491
va_list args;
492
int ret;
493
494
va_start(args, fmt);
495
ret = vdprintf(fd, fmt, args);
496
va_end(args);
497
498
return ret;
499
}
500
501
static int __nolibc_sprintf_cb(intptr_t _state, const char *buf, size_t size)
502
{
503
char **state = (char **)_state;
504
505
memcpy(*state, buf, size);
506
*state += size;
507
return 0;
508
}
509
510
static __attribute__((unused, format(printf, 3, 0)))
511
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
512
{
513
char *state = buf;
514
int ret;
515
516
ret = __nolibc_printf(__nolibc_sprintf_cb, (intptr_t)&state, size, fmt, args);
517
if (ret < 0)
518
return ret;
519
buf[(size_t)ret < size ? (size_t)ret : size - 1] = '\0';
520
return ret;
521
}
522
523
static __attribute__((unused, format(printf, 3, 4)))
524
int snprintf(char *buf, size_t size, const char *fmt, ...)
525
{
526
va_list args;
527
int ret;
528
529
va_start(args, fmt);
530
ret = vsnprintf(buf, size, fmt, args);
531
va_end(args);
532
533
return ret;
534
}
535
536
static __attribute__((unused, format(printf, 2, 0)))
537
int vsprintf(char *buf, const char *fmt, va_list args)
538
{
539
return vsnprintf(buf, SIZE_MAX, fmt, args);
540
}
541
542
static __attribute__((unused, format(printf, 2, 3)))
543
int sprintf(char *buf, const char *fmt, ...)
544
{
545
va_list args;
546
int ret;
547
548
va_start(args, fmt);
549
ret = vsprintf(buf, fmt, args);
550
va_end(args);
551
552
return ret;
553
}
554
555
static __attribute__((unused))
556
int vsscanf(const char *str, const char *format, va_list args)
557
{
558
uintmax_t uval;
559
intmax_t ival;
560
int base;
561
char *endptr;
562
int matches;
563
int lpref;
564
565
matches = 0;
566
567
while (1) {
568
if (*format == '%') {
569
/* start of pattern */
570
lpref = 0;
571
format++;
572
573
if (*format == 'l') {
574
/* same as in printf() */
575
lpref = 1;
576
format++;
577
if (*format == 'l') {
578
lpref = 2;
579
format++;
580
}
581
}
582
583
if (*format == '%') {
584
/* literal % */
585
if ('%' != *str)
586
goto done;
587
str++;
588
format++;
589
continue;
590
} else if (*format == 'd') {
591
ival = strtoll(str, &endptr, 10);
592
if (lpref == 0)
593
*va_arg(args, int *) = ival;
594
else if (lpref == 1)
595
*va_arg(args, long *) = ival;
596
else if (lpref == 2)
597
*va_arg(args, long long *) = ival;
598
} else if (*format == 'u' || *format == 'x' || *format == 'X') {
599
base = *format == 'u' ? 10 : 16;
600
uval = strtoull(str, &endptr, base);
601
if (lpref == 0)
602
*va_arg(args, unsigned int *) = uval;
603
else if (lpref == 1)
604
*va_arg(args, unsigned long *) = uval;
605
else if (lpref == 2)
606
*va_arg(args, unsigned long long *) = uval;
607
} else if (*format == 'p') {
608
*va_arg(args, void **) = (void *)strtoul(str, &endptr, 16);
609
} else {
610
SET_ERRNO(EILSEQ);
611
goto done;
612
}
613
614
format++;
615
str = endptr;
616
matches++;
617
618
} else if (*format == '\0') {
619
goto done;
620
} else if (isspace(*format)) {
621
/* skip spaces in format and str */
622
while (isspace(*format))
623
format++;
624
while (isspace(*str))
625
str++;
626
} else if (*format == *str) {
627
/* literal match */
628
format++;
629
str++;
630
} else {
631
if (!matches)
632
matches = EOF;
633
goto done;
634
}
635
}
636
637
done:
638
return matches;
639
}
640
641
static __attribute__((unused, format(scanf, 2, 3)))
642
int sscanf(const char *str, const char *format, ...)
643
{
644
va_list args;
645
int ret;
646
647
va_start(args, format);
648
ret = vsscanf(str, format, args);
649
va_end(args);
650
return ret;
651
}
652
653
static __attribute__((unused))
654
void perror(const char *msg)
655
{
656
#ifdef NOLIBC_IGNORE_ERRNO
657
fprintf(stderr, "%s%sunknown error\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "");
658
#else
659
fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
660
#endif
661
}
662
663
static __attribute__((unused))
664
int setvbuf(FILE *stream __attribute__((unused)),
665
char *buf __attribute__((unused)),
666
int mode,
667
size_t size __attribute__((unused)))
668
{
669
/*
670
* nolibc does not support buffering so this is a nop. Just check mode
671
* is valid as required by the spec.
672
*/
673
switch (mode) {
674
case _IOFBF:
675
case _IOLBF:
676
case _IONBF:
677
break;
678
default:
679
return EOF;
680
}
681
682
return 0;
683
}
684
685
static __attribute__((unused))
686
const char *strerror(int errno)
687
{
688
static char buf[18] = "errno=";
689
690
i64toa_r(errno, &buf[6]);
691
692
return buf;
693
}
694
695
#endif /* _NOLIBC_STDIO_H */
696
697