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