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 /* 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))
fdopen(int fd,const char * mode)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))
fopen(const char * pathname,const char * mode)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))
fileno(FILE * stream)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))
fflush(FILE * stream)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))
fclose(FILE * stream)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))
fgetc(FILE * stream)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))
getchar(void)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))
fputc(int c,FILE * stream)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))
putchar(int c)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))
_fwrite(const void * buf,size_t size,FILE * stream)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))
fwrite(const void * s,size_t size,size_t nmemb,FILE * stream)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))
_fread(void * buf,size_t size,FILE * stream)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))
fread(void * s,size_t size,size_t nmemb,FILE * stream)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))
fputs(const char * s,FILE * stream)240 int fputs(const char *s, FILE *stream)
241 {
242 return _fwrite(s, strlen(s), stream);
243 }
244
245 static __attribute__((unused))
puts(const char * s)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))
fgets(char * s,int size,FILE * stream)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))
fseek(FILE * stream,long offset,int whence)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 /* printf(). Supports most of the normal integer and string formats.
295 * - %[#0-+ ][width|*[.precision|*}][{l,t,z,ll,L,j,q}]{c,d,i,u,o,x,X,p,s,m,%}
296 * - %% generates a single %
297 * - %m outputs strerror(errno).
298 * - %X outputs a..f the same as %x.
299 * - No support for floating point or wide characters.
300 * - Invalid formats are copied to the output buffer.
301 *
302 * Called by vfprintf() and snprintf() to do the actual formatting.
303 * The callers provide a callback function to save the formatted data.
304 * The callback function is called multiple times:
305 * - for each group of literal characters in the format string.
306 * - for field padding.
307 * - for each conversion specifier.
308 * - with (NULL, 0) at the end of the __nolibc_printf.
309 * If the callback returns non-zero __nolibc_printf() immediately returns -1.
310 */
311
312 typedef int (*__nolibc_printf_cb)(void *state, const char *buf, size_t size);
313
314 /* This code uses 'flag' variables that are indexed by the low 6 bits
315 * of characters to optimise checks for multiple characters.
316 *
317 * _NOLIBC_PF_FLAGS_CONTAIN(flags, 'a', 'b'. ...)
318 * returns non-zero if the bit for any of the specified characters is set.
319 *
320 * _NOLIBC_PF_CHAR_IS_ONE_OF(ch, 'a', 'b'. ...)
321 * returns the flag bit for ch if it is one of the specified characters.
322 * All the characters must be in the same 32 character block (non-alphabetic,
323 * upper case, or lower case) of the ASCII character set.
324 */
325 #define _NOLIBC_PF_FLAG(ch) (1u << ((ch) & 0x1f))
326 #define _NOLIBC_PF_FLAG_NZ(ch) ((ch) ? _NOLIBC_PF_FLAG(ch) : 0)
327 #define _NOLIBC_PF_FLAG8(cmp_1, cmp_2, cmp_3, cmp_4, cmp_5, cmp_6, cmp_7, cmp_8, ...) \
328 (_NOLIBC_PF_FLAG_NZ(cmp_1) | _NOLIBC_PF_FLAG_NZ(cmp_2) | \
329 _NOLIBC_PF_FLAG_NZ(cmp_3) | _NOLIBC_PF_FLAG_NZ(cmp_4) | \
330 _NOLIBC_PF_FLAG_NZ(cmp_5) | _NOLIBC_PF_FLAG_NZ(cmp_6) | \
331 _NOLIBC_PF_FLAG_NZ(cmp_7) | _NOLIBC_PF_FLAG_NZ(cmp_8))
332 #define _NOLIBC_PF_FLAGS_CONTAIN(flags, ...) \
333 ((flags) & _NOLIBC_PF_FLAG8(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0))
334 #define _NOLIBC_PF_CHAR_IS_ONE_OF(ch, cmp_1, ...) \
335 ((unsigned int)(ch) - (cmp_1 & 0xe0) > 0x1f ? 0 : \
336 _NOLIBC_PF_FLAGS_CONTAIN(_NOLIBC_PF_FLAG(ch), cmp_1, __VA_ARGS__))
337
338 static __attribute__((unused, format(printf, 3, 0)))
__nolibc_printf(__nolibc_printf_cb cb,void * state,const char * fmt,va_list args)339 int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list args)
340 {
341 char ch;
342 unsigned long long v;
343 long long signed_v;
344 int written, width, precision, len;
345 unsigned int flags, ch_flag;
346 char outbuf[2 + 31 + 22 + 1];
347 char *out;
348 const char *outstr;
349 unsigned int sign_prefix;
350 int got_width;
351
352 written = 0;
353 while (1) {
354 outstr = fmt;
355 ch = *fmt++;
356 if (!ch)
357 break;
358
359 width = 0;
360 flags = 0;
361 if (ch != '%') {
362 while (*fmt && *fmt != '%')
363 fmt++;
364 /* Output characters from the format string. */
365 len = fmt - outstr;
366 goto do_output;
367 }
368
369 /* we're in a format sequence */
370
371 /* Conversion flag characters */
372 while (1) {
373 ch = *fmt++;
374 ch_flag = _NOLIBC_PF_CHAR_IS_ONE_OF(ch, ' ', '#', '+', '-', '0');
375 if (!ch_flag)
376 break;
377 flags |= ch_flag;
378 }
379
380 /* Width and precision */
381 for (got_width = 0;; ch = *fmt++) {
382 if (ch == '*') {
383 precision = va_arg(args, int);
384 ch = *fmt++;
385 } else {
386 for (precision = 0; ch >= '0' && ch <= '9'; ch = *fmt++)
387 precision = precision * 10 + (ch - '0');
388 }
389 if (got_width)
390 break;
391 width = precision;
392 if (ch != '.') {
393 /* Default precision for strings */
394 precision = -1;
395 break;
396 }
397 got_width = 1;
398 }
399 /* A negative width (e.g. from "%*s") requests left justify. */
400 if (width < 0) {
401 width = -width;
402 flags |= _NOLIBC_PF_FLAG('-');
403 }
404
405 /* Length modifier.
406 * They miss the conversion flags characters " #+-0" so can go into flags.
407 * Change both L and ll to j (all always 64bit).
408 */
409 if (ch == 'L')
410 ch = 'j';
411 ch_flag = _NOLIBC_PF_CHAR_IS_ONE_OF(ch, 'l', 't', 'z', 'j', 'q');
412 if (ch_flag != 0) {
413 if (ch == 'l' && fmt[0] == 'l') {
414 fmt++;
415 ch_flag = _NOLIBC_PF_FLAG('j');
416 }
417 flags |= ch_flag;
418 ch = *fmt++;
419 }
420
421 /* Conversion specifiers. */
422
423 /* Numeric and pointer conversion specifiers.
424 *
425 * Use an explicit bound check (rather than _NOLIBC_PF_CHAR_IS_ONE_OF())
426 * so that 'X' can be allowed through.
427 * 'X' gets treated and 'x' because _NOLIBC_PF_FLAG() returns the same
428 * value for both.
429 *
430 * We need to check for "%p" or "%#x" later, merging here gives better code.
431 * But '#' collides with 'c' so shift right.
432 */
433 ch_flag = _NOLIBC_PF_FLAG(ch) | (flags & _NOLIBC_PF_FLAG('#')) >> 1;
434 if (((ch >= 'a' && ch <= 'z') || ch == 'X') &&
435 _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'i', 'u', 'o', 'x', 'p', 's')) {
436 /* 'long' is needed for pointer/string conversions and ltz lengths.
437 * A single test can be used provided 'p' (the same bit as '0')
438 * is masked from flags.
439 */
440 if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag | (flags & ~_NOLIBC_PF_FLAG('p')),
441 'p', 's', 'l', 't', 'z')) {
442 v = va_arg(args, unsigned long);
443 signed_v = (long)v;
444 } else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, 'j', 'q')) {
445 v = va_arg(args, unsigned long long);
446 signed_v = v;
447 } else {
448 v = va_arg(args, unsigned int);
449 signed_v = (int)v;
450 }
451
452 if (ch == 'c') {
453 /* "%c" - single character. */
454 outbuf[0] = v;
455 len = 1;
456 outstr = outbuf;
457 goto do_output;
458 }
459
460 if (ch == 's') {
461 /* "%s" - character string. */
462 outstr = (const char *)(uintptr_t)v;
463 if (!outstr) {
464 outstr = "(null)";
465 /* Match glibc, nothing output if precision too small */
466 len = precision < 0 || precision >= 6 ? 6 : 0;
467 goto do_output;
468 }
469 goto do_strlen_output;
470 }
471
472 /* The 'sign_prefix' can be zero, one or two ("0x") characters.
473 * Prepended least significant byte first stopping on a zero byte.
474 */
475 sign_prefix = 0;
476
477 if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i')) {
478 /* "%d" and "%i" - signed decimal numbers. */
479 if (signed_v < 0) {
480 sign_prefix = '-';
481 v = -(signed_v + 1);
482 v++;
483 } else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '+')) {
484 sign_prefix = '+';
485 } else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, ' ')) {
486 sign_prefix = ' ';
487 }
488 } else {
489 /* "#o" requires that the output always starts with a '0'.
490 * This needs another check after any zero padding to avoid
491 * adding an extra leading '0'.
492 */
493 if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'o') &&
494 _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, '#' - 1))
495 sign_prefix = '0';
496 }
497
498 /* The value is converted offset into the buffer so that
499 * 31 zero pad characters and the sign/prefix can be added in front.
500 * The longest digit string is 22 + 1 for octal conversions.
501 */
502 out = outbuf + 2 + 31;
503
504 if (v == 0) {
505 /* There are special rules for zero. */
506 if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p')) {
507 /* "%p" match glibc, precision is ignored */
508 outstr = "(nil)";
509 len = 5;
510 goto do_output;
511 }
512 if (!precision) {
513 /* Explicit %nn.0d, no digits output (except for %#.0o) */
514 len = 0;
515 goto prepend_sign;
516 }
517 /* All other formats (including "%#x") just output "0". */
518 out[0] = '0';
519 len = 1;
520 } else {
521 /* Convert the number to ascii in the required base. */
522 unsigned long long recip;
523 unsigned int base;
524 if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i', 'u')) {
525 base = 10;
526 recip = _NOLIBC_U64TOA_RECIP(10);
527 } else if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'o')) {
528 base = 8;
529 recip = _NOLIBC_U64TOA_RECIP(8);
530 } else {
531 base = 16;
532 recip = _NOLIBC_U64TOA_RECIP(16);
533 if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p', '#' - 1)) {
534 /* "%p" and "%#x" need "0x" prepending. */
535 sign_prefix = '0' << 8 | 'x';
536 }
537 }
538 len = _nolibc_u64toa_base(v, out, base, recip);
539 }
540
541 /* Add zero padding */
542 if (precision < 0) {
543 /* No explicit precision (or negative from "%.*s"). */
544 if (!_NOLIBC_PF_FLAGS_CONTAIN(flags, '0'))
545 goto no_zero_padding;
546 if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '-'))
547 /* Left justify overrides zero pad */
548 goto no_zero_padding;
549 /* eg "%05d", Zero pad to field width less sign.
550 * Note that precision can end up negative so all
551 * the variables have to be 'signed int'.
552 */
553 precision = width;
554 if (sign_prefix) {
555 precision--;
556 if (sign_prefix >= 256)
557 precision--;
558 }
559 }
560 if (precision > 31)
561 /* Don't run off the start of outbuf[], arbitrary limit
562 * longer than the longest number field. */
563 precision = 31;
564 for (; len < precision; len++) {
565 /* Stop gcc generating horrid code and memset(). */
566 _NOLIBC_OPTIMIZER_HIDE_VAR(len);
567 *--out = '0';
568 }
569 no_zero_padding:
570
571 /* %#o has set sign_prefix to '0', but we don't want so add an extra
572 * leading zero here.
573 * Since the only other byte values of sign_prefix are ' ', '+' and '-'
574 * it is enough to check that out[] doesn't already start with sign_prefix.
575 */
576 if (sign_prefix - *out) {
577 prepend_sign:
578 /* Add the 0, 1 or 2 ("0x") sign/prefix characters at the front. */
579 for (; sign_prefix; sign_prefix >>= 8) {
580 /* Force gcc to increment len inside the loop. */
581 _NOLIBC_OPTIMIZER_HIDE_VAR(len);
582 len++;
583 *--out = sign_prefix;
584 }
585 }
586 outstr = out;
587 goto do_output;
588 }
589
590 if (ch == 'm') {
591 #ifdef NOLIBC_IGNORE_ERRNO
592 outstr = "unknown error";
593 #else
594 outstr = strerror(errno);
595 #endif /* NOLIBC_IGNORE_ERRNO */
596 goto do_strlen_output;
597 }
598
599 if (ch != '%') {
600 /* Invalid format: back up to output the format characters */
601 fmt = outstr + 1;
602 /* and output a '%' now. */
603 }
604 /* %% is documented as a 'conversion specifier'.
605 * Any flags, precision or length modifier are ignored.
606 */
607 len = 1;
608 width = 0;
609 outstr = fmt - 1;
610 goto do_output;
611
612 do_strlen_output:
613 /* Open coded strnlen() (slightly smaller). */
614 for (len = 0; precision < 0 || len < precision; len++)
615 if (!outstr[len])
616 break;
617
618 do_output:
619 written += len;
620
621 /* Stop gcc back-merging this code into one of the conditionals above. */
622 _NOLIBC_OPTIMIZER_HIDE_VAR(len);
623
624 /* Output the characters on the required side of any padding. */
625 width -= len;
626 flags = _NOLIBC_PF_FLAGS_CONTAIN(flags, '-');
627 if (flags && cb(state, outstr, len) != 0)
628 return -1;
629 while (width > 0) {
630 /* Output pad in 16 byte blocks with the small block first. */
631 int pad_len = ((width - 1) & 15) + 1;
632 width -= pad_len;
633 written += pad_len;
634 if (cb(state, " ", pad_len) != 0)
635 return -1;
636 }
637 if (!flags && cb(state, outstr, len) != 0)
638 return -1;
639 }
640
641 /* Request a final '\0' be added to the snprintf() output.
642 * This may be the only call of the cb() function.
643 */
644 if (cb(state, NULL, 0) != 0)
645 return -1;
646
647 return written;
648 }
649
__nolibc_fprintf_cb(void * stream,const char * buf,size_t size)650 static int __nolibc_fprintf_cb(void *stream, const char *buf, size_t size)
651 {
652 return _fwrite(buf, size, stream);
653 }
654
655 static __attribute__((unused, format(printf, 2, 0)))
vfprintf(FILE * stream,const char * fmt,va_list args)656 int vfprintf(FILE *stream, const char *fmt, va_list args)
657 {
658 return __nolibc_printf(__nolibc_fprintf_cb, stream, fmt, args);
659 }
660
661 static __attribute__((unused, format(printf, 1, 0)))
vprintf(const char * fmt,va_list args)662 int vprintf(const char *fmt, va_list args)
663 {
664 return vfprintf(stdout, fmt, args);
665 }
666
667 static __attribute__((unused, format(printf, 2, 3)))
fprintf(FILE * stream,const char * fmt,...)668 int fprintf(FILE *stream, const char *fmt, ...)
669 {
670 va_list args;
671 int ret;
672
673 va_start(args, fmt);
674 ret = vfprintf(stream, fmt, args);
675 va_end(args);
676 return ret;
677 }
678
679 static __attribute__((unused, format(printf, 1, 2)))
printf(const char * fmt,...)680 int printf(const char *fmt, ...)
681 {
682 va_list args;
683 int ret;
684
685 va_start(args, fmt);
686 ret = vfprintf(stdout, fmt, args);
687 va_end(args);
688 return ret;
689 }
690
691 static __attribute__((unused, format(printf, 2, 0)))
vdprintf(int fd,const char * fmt,va_list args)692 int vdprintf(int fd, const char *fmt, va_list args)
693 {
694 FILE *stream;
695
696 stream = fdopen(fd, NULL);
697 if (!stream)
698 return -1;
699 /* Technically 'stream' is leaked, but as it's only a wrapper around 'fd' that is fine */
700 return vfprintf(stream, fmt, args);
701 }
702
703 static __attribute__((unused, format(printf, 2, 3)))
dprintf(int fd,const char * fmt,...)704 int dprintf(int fd, const char *fmt, ...)
705 {
706 va_list args;
707 int ret;
708
709 va_start(args, fmt);
710 ret = vdprintf(fd, fmt, args);
711 va_end(args);
712
713 return ret;
714 }
715
716 struct __nolibc_sprintf_cb_state {
717 char *buf;
718 size_t space;
719 };
720
__nolibc_sprintf_cb(void * v_state,const char * buf,size_t size)721 static int __nolibc_sprintf_cb(void *v_state, const char *buf, size_t size)
722 {
723 struct __nolibc_sprintf_cb_state *state = v_state;
724 size_t space = state->space;
725 char *tgt;
726
727 /* Truncate the request to fit in the output buffer space.
728 * The last byte is reserved for the terminating '\0'.
729 * state->space can only be zero for snprintf(NULL, 0, fmt, args)
730 * so this normally lets through calls with 'size == 0'.
731 */
732 if (size >= space) {
733 if (space <= 1)
734 return 0;
735 size = space - 1;
736 }
737 tgt = state->buf;
738
739 /* __nolibc_printf() ends with cb(state, NULL, 0) to request the output
740 * buffer be '\0' terminated.
741 * That will be the only cb() call for, eg, snprintf(buf, sz, "").
742 * Zero lengths can occur at other times (eg "%s" for an empty string).
743 * Unconditionally write the '\0' byte to reduce code size, it is
744 * normally overwritten by the data being output.
745 * There is no point adding a '\0' after copied data - there is always
746 * another call.
747 */
748 *tgt = '\0';
749 if (size) {
750 state->space = space - size;
751 state->buf = tgt + size;
752 memcpy(tgt, buf, size);
753 }
754
755 return 0;
756 }
757
758 static __attribute__((unused, format(printf, 3, 0)))
vsnprintf(char * buf,size_t size,const char * fmt,va_list args)759 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
760 {
761 struct __nolibc_sprintf_cb_state state = { .buf = buf, .space = size };
762
763 return __nolibc_printf(__nolibc_sprintf_cb, &state, fmt, args);
764 }
765
766 static __attribute__((unused, format(printf, 3, 4)))
snprintf(char * buf,size_t size,const char * fmt,...)767 int snprintf(char *buf, size_t size, const char *fmt, ...)
768 {
769 va_list args;
770 int ret;
771
772 va_start(args, fmt);
773 ret = vsnprintf(buf, size, fmt, args);
774 va_end(args);
775
776 return ret;
777 }
778
779 static __attribute__((unused, format(printf, 2, 0)))
vsprintf(char * buf,const char * fmt,va_list args)780 int vsprintf(char *buf, const char *fmt, va_list args)
781 {
782 return vsnprintf(buf, SIZE_MAX, fmt, args);
783 }
784
785 static __attribute__((unused, format(printf, 2, 3)))
sprintf(char * buf,const char * fmt,...)786 int sprintf(char *buf, const char *fmt, ...)
787 {
788 va_list args;
789 int ret;
790
791 va_start(args, fmt);
792 ret = vsprintf(buf, fmt, args);
793 va_end(args);
794
795 return ret;
796 }
797
798 static __attribute__((unused, format(printf, 2, 0)))
__nolibc_vasprintf(char ** strp,const char * fmt,va_list args1,va_list args2)799 int __nolibc_vasprintf(char **strp, const char *fmt, va_list args1, va_list args2)
800 {
801 int len1, len2;
802 char *buf;
803
804 len1 = vsnprintf(NULL, 0, fmt, args1);
805 if (len1 < 0)
806 return -1;
807
808 buf = malloc(len1 + 1);
809 if (!buf)
810 return -1;
811
812 len2 = vsnprintf(buf, len1 + 1, fmt, args2);
813 if (len2 < 0) {
814 free(buf);
815 return -1;
816 }
817
818 *strp = buf;
819 return len1;
820 }
821
822 static __attribute__((unused, format(printf, 2, 0)))
vasprintf(char ** strp,const char * fmt,va_list args)823 int vasprintf(char **strp, const char *fmt, va_list args)
824 {
825 va_list args2;
826 int ret;
827
828 va_copy(args2, args);
829 ret = __nolibc_vasprintf(strp, fmt, args, args2);
830 va_end(args2);
831
832 return ret;
833 }
834
835 static __attribute__((unused, format(printf, 2, 3)))
asprintf(char ** strp,const char * fmt,...)836 int asprintf(char **strp, const char *fmt, ...)
837 {
838 va_list args;
839 int ret;
840
841 va_start(args, fmt);
842 ret = vasprintf(strp, fmt, args);
843 va_end(args);
844
845 return ret;
846 }
847
848 static __attribute__((unused))
vsscanf(const char * str,const char * format,va_list args)849 int vsscanf(const char *str, const char *format, va_list args)
850 {
851 uintmax_t uval;
852 intmax_t ival;
853 int base;
854 char *endptr;
855 int matches;
856 int lpref;
857
858 matches = 0;
859
860 while (1) {
861 if (*format == '%') {
862 /* start of pattern */
863 lpref = 0;
864 format++;
865
866 if (*format == 'l') {
867 /* same as in printf() */
868 lpref = 1;
869 format++;
870 if (*format == 'l') {
871 lpref = 2;
872 format++;
873 }
874 }
875
876 if (*format == '%') {
877 /* literal % */
878 if ('%' != *str)
879 goto done;
880 str++;
881 format++;
882 continue;
883 } else if (*format == 'd') {
884 ival = strtoll(str, &endptr, 10);
885 if (lpref == 0)
886 *va_arg(args, int *) = ival;
887 else if (lpref == 1)
888 *va_arg(args, long *) = ival;
889 else if (lpref == 2)
890 *va_arg(args, long long *) = ival;
891 } else if (*format == 'u' || *format == 'x' || *format == 'X') {
892 base = *format == 'u' ? 10 : 16;
893 uval = strtoull(str, &endptr, base);
894 if (lpref == 0)
895 *va_arg(args, unsigned int *) = uval;
896 else if (lpref == 1)
897 *va_arg(args, unsigned long *) = uval;
898 else if (lpref == 2)
899 *va_arg(args, unsigned long long *) = uval;
900 } else if (*format == 'p') {
901 *va_arg(args, void **) = (void *)strtoul(str, &endptr, 16);
902 } else {
903 SET_ERRNO(EILSEQ);
904 goto done;
905 }
906
907 format++;
908 str = endptr;
909 matches++;
910
911 } else if (*format == '\0') {
912 goto done;
913 } else if (isspace(*format)) {
914 /* skip spaces in format and str */
915 while (isspace(*format))
916 format++;
917 while (isspace(*str))
918 str++;
919 } else if (*format == *str) {
920 /* literal match */
921 format++;
922 str++;
923 } else {
924 if (!matches)
925 matches = EOF;
926 goto done;
927 }
928 }
929
930 done:
931 return matches;
932 }
933
934 static __attribute__((unused, format(scanf, 2, 3)))
sscanf(const char * str,const char * format,...)935 int sscanf(const char *str, const char *format, ...)
936 {
937 va_list args;
938 int ret;
939
940 va_start(args, format);
941 ret = vsscanf(str, format, args);
942 va_end(args);
943 return ret;
944 }
945
946 static __attribute__((unused))
perror(const char * msg)947 void perror(const char *msg)
948 {
949 #ifdef NOLIBC_IGNORE_ERRNO
950 fprintf(stderr, "%s%sunknown error\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "");
951 #else
952 fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
953 #endif
954 }
955
956 static __attribute__((unused))
setvbuf(FILE * stream,char * buf,int mode,size_t size)957 int setvbuf(FILE *stream __attribute__((unused)),
958 char *buf __attribute__((unused)),
959 int mode,
960 size_t size __attribute__((unused)))
961 {
962 /*
963 * nolibc does not support buffering so this is a nop. Just check mode
964 * is valid as required by the spec.
965 */
966 switch (mode) {
967 case _IOFBF:
968 case _IOLBF:
969 case _IONBF:
970 break;
971 default:
972 return EOF;
973 }
974
975 return 0;
976 }
977
978 static __attribute__((unused))
strerror_r(int errnum,char * buf,size_t buflen)979 int strerror_r(int errnum, char *buf, size_t buflen)
980 {
981 if (buflen < 18)
982 return ERANGE;
983
984 __builtin_memcpy(buf, "errno=", 6);
985 i64toa_r(errnum, buf + 6);
986 return 0;
987 }
988
989 static __attribute__((unused))
strerror(int errnum)990 const char *strerror(int errnum)
991 {
992 static char buf[18];
993 char *b = buf;
994
995 /* Force gcc to use 'register offset' to access buf[]. */
996 _NOLIBC_OPTIMIZER_HIDE_VAR(b);
997
998 /* Use strerror_r() to avoid having the only .data in small programs. */
999 strerror_r(errnum, b, sizeof(buf));
1000
1001 return b;
1002 }
1003
1004 #endif /* _NOLIBC_STDIO_H */
1005