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