A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 1441 lines 45 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2002 by Gary Czvitkovicz 11 * Copyright (C) 2017 by Michael A. Sevakis 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License 15 * as published by the Free Software Foundation; either version 2 16 * of the License, or (at your option) any later version. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ****************************************************************************/ 22#include <sys/types.h> 23#include <limits.h> 24#include <string.h> 25#include <stddef.h> 26#include <stdlib.h> 27#include "system.h" 28#include "vuprintf.h" 29#include "ap_int.h" 30 31#ifndef BOOTLOADER 32 33/* Turn everything on if we have enough RAM. */ 34#if MEMORYSIZE >= 8 35# define FMT_LENMOD (0xffffffff) 36# define FMT_RADIX (0xffffffff) 37#endif 38 39#endif 40 41/* these are the defaults if no other preference is given */ 42#ifndef FMT_LENMOD 43#define FMT_LENMOD (FMT_LENMOD_l | \ 44 FMT_LENMOD_z) 45#endif /* FMT_LENMOD */ 46 47#ifndef FMT_RADIX 48#define FMT_RADIX (FMT_RADIX_c | \ 49 FMT_RADIX_d | \ 50 FMT_RADIX_p | \ 51 FMT_RADIX_s | \ 52 FMT_RADIX_u | \ 53 FMT_RADIX_x) 54#endif /* FMT_RADIX */ 55 56/** Length modifier and radix flags **/ 57 58/* compulsory length modifiers: NONE 59 * however a compatible 'l' or 'll' must be defined if another requires it */ 60#define FMT_LENMOD_h 0x001 /* signed/unsigned short (%h<radix>) */ 61#define FMT_LENMOD_hh 0x002 /* signed/unsigned char (%hh<radix>) */ 62#define FMT_LENMOD_j 0x004 /* intmax_t/uintmax_t (%j<radix>) */ 63#define FMT_LENMOD_l 0x008 /* signed/unsigned long (%l<radix>) */ 64#define FMT_LENMOD_ll 0x010 /* signed/unsigned long long (%ll<radix>) */ 65#define FMT_LENMOD_t 0x020 /* signed/unsigned ptrdiff_t (%t<radix>) */ 66#define FMT_LENMOD_z 0x040 /* size_t/ssize_t (%z<radix>) */ 67#if 0 68#define FMT_LENMOD_L 0x080 /* long double (instead of double) */ 69#else 70#define FMT_LENMOD_L 0x000 71#endif 72 73/* compulsory radixes: c, d, i, u, s */ 74#define FMT_RADIX_c 0x001 /* single character (%c) */ 75#define FMT_RADIX_d 0x002 /* signed integer type, decimal (%d %i) */ 76#define FMT_RADIX_n 0x004 /* bytes output so far (%n) */ 77#define FMT_RADIX_o 0x008 /* unsigned integer type, octal (%o) */ 78#define FMT_RADIX_p 0x010 /* pointer (%p %P) */ 79#define FMT_RADIX_s 0x020 /* string (%s) */ 80#define FMT_RADIX_u 0x040 /* unsigned integer type, decimal (%u) */ 81#define FMT_RADIX_x 0x080 /* unsigned integer type, hex (%x %X) */ 82#define FMT_RADIX_a 0x100 /* hex floating point "[-]0xh.hhhhp±d" */ 83#define FMT_RADIX_e 0x200 /* floating point with exponent "[-]d.ddde±dd" */ 84#define FMT_RADIX_f 0x400 /* floating point "[-]ddd.ddd" */ 85#define FMT_RADIX_g 0x800 /* floating point exponent or decimal depending 86 upon value and precision */ 87 88/* TODO: 'a' 'A' */ 89#define FMT_RADIX_floats (FMT_RADIX_e|FMT_RADIX_f|FMT_RADIX_g) 90 91#if (FMT_RADIX & FMT_RADIX_floats) 92/* Assumes IEEE 754 double-precision, native-endian; replace to parse and init 93 for some other format */ 94#define parse_double parse_ieee754_double 95#define init_double_chunks init_ieee754_double_chunks 96#define format_double_int10 format_ap_int10 97#define format_double_frac10 format_ap_frac10 98#endif 99 100/* avoid defining redundant functions if two or more types can use the same 101 * something not getting a macro means it gets assigned its own value and 102 * formatter */ 103 104/* l */ 105#if LONG_MIN == INT_MIN && LONG_MAX == INT_MAX 106#define val_ld val_d 107#define format_ld format_d 108#define branch_fmt_ld branch_fmt_d 109#elif !(FMT_LENMOD & FMT_LENMOD_l) /* unique */ 110#define val_ld 111#endif /* LONG_ */ 112 113#if ULONG_MAX == UINT_MAX 114#define val_lu val_u 115#define format_lu format_u 116#define branch_fmt_lu branch_fmt_u 117#elif !(FMT_LENMOD & FMT_LENMOD_l) /* unique */ 118#define val_lu 119#endif /* ULONG_ */ 120 121/* ll */ 122#if LLONG_MIN == INT_MIN && LLONG_MAX == INT_MAX 123#define val_lld val_d 124#define format_lld format_d 125#define branch_fmt_lld branch_fmt_d 126#elif LLONG_MIN == LONG_MIN && LLONG_MAX == LONG_MAX 127#define val_lld val_ld 128#define format_lld format_ld 129#define branch_fmt_lld branch_fmt_ld 130#elif !(FMT_LENMOD & FMT_LENMOD_ll) /* unique */ 131#define val_lld 132#endif /* LLONG_ */ 133 134#if ULLONG_MAX == UINT_MAX 135#define val_llu val_u 136#define format_llu format_u 137#define branch_fmt_llu branch_fmt_u 138#elif ULLONG_MAX == ULONG_MAX 139#define val_llu val_lu 140#define format_llu format_lu 141#define branch_fmt_llu branch_fmt_lu 142#elif !(FMT_LENMOD & FMT_LENMOD_ll) /* unique */ 143#define val_llu 144#endif /* ULLONG_ */ 145 146/* char/short parameter type promotions */ 147#define SCHAR_INT_ARG int 148#define UCHAR_INT_ARG int 149#define SSHRT_INT_ARG int 150#if USHRT_MAX == UINT_MAX 151#define USHRT_INT_ARG unsigned int 152#else 153#define USHRT_INT_ARG int 154#endif 155 156/* some macros to have conditional work inside macros */ 157#if (FMT_LENMOD & FMT_LENMOD_l) 158#define IF_FMT_LENMOD_l(...) __VA_ARGS__ 159#else 160#define IF_FMT_LENMOD_l(...) 161#endif 162 163#if (FMT_LENMOD & FMT_LENMOD_ll) 164#define IF_FMT_LENMOD_ll(...) __VA_ARGS__ 165#else 166#define IF_FMT_LENMOD_ll(...) 167#endif 168 169#if (FMT_RADIX & FMT_RADIX_o) 170#define IF_FMT_RADIX_o(...) __VA_ARGS__ 171#else 172#define IF_FMT_RADIX_o(...) 173#endif 174 175#if (FMT_RADIX & FMT_RADIX_x) 176#define IF_FMT_RADIX_x(...) __VA_ARGS__ 177#else 178#define IF_FMT_RADIX_x(...) 179#endif 180 181/* synthesize multicharacter constant */ 182#define LENMOD2(cv, ch) \ 183 (((cv) << CHAR_BIT) | (ch)) 184 185#define LENMOD_NONE 0 186 187#if (FMT_LENMOD & FMT_LENMOD_h) 188#define LENMOD_h 'h' 189#endif 190#if (FMT_LENMOD & FMT_LENMOD_hh) 191#define LENMOD_hh LENMOD2('h', 'h') /* 'hh' */ 192#endif 193#if (FMT_LENMOD & FMT_LENMOD_j) 194#define LENMOD_j 'j' 195#endif 196#if (FMT_LENMOD & FMT_LENMOD_l) 197#define LENMOD_l 'l' 198#endif 199#if (FMT_LENMOD & FMT_LENMOD_ll) 200#undef FMT_MAX_L 201#define LENMOD_ll LENMOD2('l', 'l') /* 'll' */ 202#endif 203#if (FMT_LENMOD & FMT_LENMOD_t) 204#define LENMOD_t 't' 205#endif 206#if (FMT_LENMOD & FMT_LENMOD_z) 207#define LENMOD_z 'z' 208#endif 209 210/* select type-compatible length modifier 211 * (a bit hacky; it should be range-based) */ 212#define LENMOD_INTCOMPAT_SEL(type, signd) \ 213 ({ int __lenmod; \ 214 size_t __size = sizeof (type); \ 215 if (__size == ((signd) ? sizeof (int) : \ 216 sizeof (unsigned int))) { \ 217 __lenmod = LENMOD_NONE; \ 218 } \ 219 else if (__size == ((signd) ? sizeof (long) : \ 220 sizeof (unsigned long))) { \ 221 IF_FMT_LENMOD_l(__lenmod = LENMOD_l;) \ 222 } \ 223 else if (__size == ((signd) ? sizeof (long long) : \ 224 sizeof (unsigned long long))) { \ 225 IF_FMT_LENMOD_ll(__lenmod = LENMOD_ll;) \ 226 } \ 227 __lenmod; }) 228 229/* call formatting function for the compatible integer type */ 230#define LENMOD_INTCOMPAT_CALL(inteqv, val, fmt_buf, x, signd) \ 231 ({ const char *__buf; \ 232 switch (inteqv) { \ 233 case LENMOD_NONE: \ 234 __buf = (signd) ? \ 235 format_d((val), (fmt_buf), (x)) : \ 236 format_u((val), (fmt_buf), (x)); \ 237 break; \ 238 IF_FMT_LENMOD_l( \ 239 case LENMOD_l: \ 240 __buf = (signd) ? \ 241 format_ld((val), (fmt_buf), (x)) : \ 242 format_lu((val), (fmt_buf), (x)); \ 243 break; \ 244 ) \ 245 IF_FMT_LENMOD_ll( \ 246 case LENMOD_ll: \ 247 __buf = (signd) ? \ 248 format_lld((val), (fmt_buf), (x)) : \ 249 format_llu((val), (fmt_buf), (x)); \ 250 break; \ 251 ) \ 252 } \ 253 __buf; \ 254 }) 255 256/* execute formatting branch for the compatible integer type */ 257#define LENMOD_INTCOMPAT_BRANCH(inteqv, val, signd) \ 258 ({ switch (inteqv) { \ 259 case LENMOD_NONE: \ 260 if (signd) { \ 261 val_d = (val); \ 262 goto branch_fmt_d; \ 263 } \ 264 else { \ 265 val_u = (val); \ 266 goto branch_fmt_u; \ 267 } \ 268 IF_FMT_LENMOD_l( \ 269 case LENMOD_l: \ 270 if (signd) { \ 271 val_ld = (val); \ 272 goto branch_fmt_ld; \ 273 } \ 274 else { \ 275 val_lu = (val); \ 276 goto branch_fmt_lu; \ 277 } \ 278 ) \ 279 IF_FMT_LENMOD_ll( \ 280 case LENMOD_ll: \ 281 if (signd) { \ 282 val_lld = (val); \ 283 goto branch_fmt_lld; \ 284 } \ 285 else { \ 286 val_llu = (val); \ 287 goto branch_fmt_llu; \ 288 } \ 289 ) \ 290 } \ 291 }) 292 293#define CONVERT_RADIX_10_SIGN(val, fmt_buf, p, signchar, type) \ 294 do { \ 295 if (val) { \ 296 unsigned type v; \ 297 \ 298 if (val < 0) { \ 299 v = (typeof (v))-(val + 1) + 1; \ 300 signchar = '-'; \ 301 } \ 302 else { \ 303 v = val; \ 304 } \ 305 \ 306 do { \ 307 *--p = (v % 10) + '0'; \ 308 v /= 10; \ 309 } while (v); \ 310 } \ 311 \ 312 if (signchar) { \ 313 p[-1] = signchar; \ 314 fmt_buf->length = 1; \ 315 break; \ 316 } \ 317 \ 318 fmt_buf->length = 0; \ 319 } while (0) 320 321#define CONVERT_RADIX_8(val, fmt_buf, p) \ 322 do { \ 323 if (val) { \ 324 typeof (val) v = val; \ 325 \ 326 do { \ 327 *--p = (v % 010) + '0'; \ 328 v /= 010; \ 329 } while (v); \ 330 } \ 331 \ 332 if (fmt_buf->length) { \ 333 *--p = '0'; \ 334 fmt_buf->length = 0; \ 335 } \ 336 } while (0) 337 338#define CONVERT_RADIX_10(val, fmt_buf, p) \ 339 do { \ 340 if (val) { \ 341 typeof (val) v = val; \ 342 \ 343 do { \ 344 *--p = (v % 10) + '0'; \ 345 v /= 10; \ 346 } while (v); \ 347 } \ 348 \ 349 fmt_buf->length = 0; \ 350 } while (0) 351 352#define CONVERT_RADIX_16(val, fmt_buf, p, x) \ 353 do { \ 354 if (val) { \ 355 const int h = x - 'X' - 0xA \ 356 + 'A' - '0'; \ 357 typeof (val) v = val; \ 358 \ 359 do { \ 360 unsigned int d = v % 0x10; \ 361 if (d >= 0xA) { \ 362 d += h; \ 363 } \ 364 *--p = d + '0'; \ 365 v /= 0x10; \ 366 } while (v); \ 367 \ 368 if (fmt_buf->length) { \ 369 p[-1] = x; \ 370 p[-2] = '0'; \ 371 fmt_buf->length = 2; \ 372 break; \ 373 } \ 374 } \ 375 \ 376 fmt_buf->length = 0; \ 377 } while (0) 378 379#define CONVERT_RADIX_NOSIGN(val, fmt_buf, p, x) \ 380 switch (x) \ 381 { \ 382 IF_FMT_RADIX_o( case 'o': \ 383 CONVERT_RADIX_8(val, fmt_buf, p); \ 384 break; ) \ 385 case 'u': \ 386 CONVERT_RADIX_10(val, fmt_buf, p); \ 387 break; \ 388 IF_FMT_RADIX_x( default: \ 389 CONVERT_RADIX_16(val, fmt_buf, p, x); \ 390 break; ) \ 391 } 392 393struct fmt_buf { 394 const char *fmt_start; /* second character of formatter after '%' */ 395 size_t length; /* length of formatted text (non-numeric) 396 or prefix (numeric) */ 397 char buf[24]; /* work buffer */ 398 char bufend[1]; /* buffer end marker and guard '0' */ 399#if (FMT_RADIX & FMT_RADIX_floats) 400 int lenmod; 401 int radixchar; 402 int signchar; 403 int alignchar; 404 int width; 405 int precision; 406 char *p; 407#endif 408}; 409 410#define PUSHCHAR(ch) \ 411 ({ int __rc = push(userp, (ch)); \ 412 count += __rc >= 0; \ 413 if (__rc <= 0) { \ 414 goto done; \ 415 } }) 416 417/* %d %i */ 418static inline const char * format_d(int val, 419 struct fmt_buf *fmt_buf, 420 int signchar) 421{ 422 char *p = fmt_buf->bufend; 423 CONVERT_RADIX_10_SIGN(val, fmt_buf, p, signchar, int); 424 return p; 425} 426 427/* %o %u %x %X */ 428static inline const char * format_u(unsigned int val, 429 struct fmt_buf *fmt_buf, 430 int radixchar) 431{ 432 char *p = fmt_buf->bufend; 433 CONVERT_RADIX_NOSIGN(val, fmt_buf, p, radixchar); 434 return p; 435} 436 437#if (FMT_LENMOD & FMT_LENMOD_l) 438#ifndef format_ld 439/* %ld %li */ 440static inline const char * format_ld(long val, 441 struct fmt_buf *fmt_buf, 442 int signchar) 443{ 444 char *p = fmt_buf->bufend; 445 CONVERT_RADIX_10_SIGN(val, fmt_buf, p, signchar, long); 446 return p; 447} 448#endif /* format_ld */ 449 450#ifndef format_lu 451/* %lo %lu %lx %lX */ 452static inline const char * format_lu(unsigned long val, 453 struct fmt_buf *fmt_buf, 454 int radixchar) 455{ 456 char *p = fmt_buf->bufend; 457 CONVERT_RADIX_NOSIGN(val, fmt_buf, p, radixchar); 458 return p; 459} 460#endif /* format_lu */ 461#endif /* FMT_LENMOD_l */ 462 463#if (FMT_LENMOD & FMT_LENMOD_ll) 464#ifndef format_lld 465/* %lld %lli */ 466static inline const char * format_lld(long long val, 467 struct fmt_buf *fmt_buf, 468 int signchar) 469{ 470 char *p = fmt_buf->bufend; 471 CONVERT_RADIX_10_SIGN(val, fmt_buf, p, signchar, long long); 472 return p; 473} 474#endif /* format_lld */ 475 476#ifndef format_llu 477/* %llo %llu %llx %llX */ 478static inline const char * format_llu(unsigned long long val, 479 struct fmt_buf *fmt_buf, 480 int radixchar) 481{ 482 char *p = fmt_buf->bufend; 483 CONVERT_RADIX_NOSIGN(val, fmt_buf, p, radixchar); 484 return p; 485} 486#endif /* format_llu */ 487#endif /* FMT_LENMOD_ll */ 488 489/* %c */ 490static inline const char * format_c(int c, 491 struct fmt_buf *fmt_buf, 492 int lenmod) 493{ 494 if (lenmod != LENMOD_NONE) { 495 return NULL; /* wchar_t support for now */ 496 } 497 498 char *p = fmt_buf->bufend; 499 fmt_buf->length = 1; 500 *--p = (unsigned char)c; 501 return p; 502} 503 504/* %s */ 505static inline const char * format_s(const void *str, 506 struct fmt_buf *fmt_buf, 507 int precision, 508 int lenmod) 509{ 510 if (lenmod != LENMOD_NONE) { 511 return NULL; /* wchar_t support for now */ 512 } 513 514 const char *s = str ? str : "(null)"; 515 size_t len; 516 /* string length may be specified by precision instead of \0- 517 terminated; however, don't go past a \0 if one is there */ 518 if (precision >= 0) { 519 const char *nil = memchr(s, '\0', (size_t) precision); 520 521 if (nil != NULL && (nil - s) < precision) 522 len = nil - s; 523 else 524 len = precision; 525 } 526 else 527 len = strlen(s); 528 529 fmt_buf->length = len; 530 return s; 531} 532 533#if (FMT_RADIX & FMT_RADIX_n) 534/* %n */ 535static inline bool format_n(void *np, 536 int count, 537 int lenmod) 538{ 539 if (lenmod != LENMOD_NONE) { 540 return false; /* int only for now */ 541 } 542 543 *(int *)np = count; 544 return true; 545} 546#endif /* FMT_RADIX_n */ 547 548#if (FMT_RADIX & FMT_RADIX_p) 549/* %p %P */ 550static inline const char * format_p(const void *p, 551 struct fmt_buf *fmt_buf, 552 int radixchar, 553 bool *numericp) 554{ 555 if (p) { 556 /* format as %#x or %#X */ 557 *numericp = true; 558 radixchar -= 'P' - 'X'; 559 fmt_buf->length = 2; 560 return LENMOD_INTCOMPAT_CALL(LENMOD_INTCOMPAT_SEL(uintptr_t, false), 561 (uintptr_t)p, fmt_buf, radixchar, false); 562 } 563 else { 564 /* format as %s */ 565 fmt_buf->length = 5; 566 return "(nil)"; 567 } 568} 569#endif /* FMT_RADIX_p */ 570 571#if (FMT_RADIX & FMT_RADIX_floats) 572/* find out how many uint32_t chunks need to be allocated, if any 573 * if none are needed, finish the init for the number here */ 574static long parse_ieee754_double(double f, 575 struct ap_int *ia, 576 struct ap_int *fa, 577 struct fmt_buf *fmt_buf) 578{ 579 long rc = 0; 580 581 union { 582 double f; 583 uint64_t f64; 584 } u = { .f = f }; 585 586 int e = ((int)(u.f64 >> 52) & 0x7ff) - 1023; /* -1023..1024 */ 587 uint64_t mantissa = u.f64 & 0x000fffffffffffffull; 588 589 if (u.f64 >> 63) { 590 fmt_buf->signchar = '-'; 591 } 592 593 if (LIKELY(e >= -8 && e <= 63)) { /* -8 to +63 */ 594 /* integer, fraction and manipulations fit in uint64_t */ 595 mantissa |= 0x0010000000000000ull; 596 ia->numchunks = 0; 597 ia->shift = 0; 598 fa->numchunks = 0; 599 600 if (e < 0) { /* -8 to -1 - fraction */ 601 long fracbits = 52 - e; 602 /* int - none */ 603 ia->len = 0; 604 ia->val = 0; 605 /* frac */ 606 fa->len = fracbits - __builtin_ctzll(mantissa); 607 fa->shift = fracbits; 608 fa->val = mantissa; 609 } 610 else if (e <= 51) { /* 0 to +51 - integer|fraction */ 611 long fracbits = 52 - e; 612 /* int */ 613 ia->len = base10exp(e) + 2; /* go up + possibly 1 longer */ 614 ia->val = mantissa >> fracbits; 615 /* frac */ 616 fa->shift = fracbits; 617 fa->val = mantissa ^ (ia->val << fracbits); 618 fa->len = fa->val ? fracbits - __builtin_ctzll(mantissa) : 0; 619 } 620 else { /* +52 to +63 - integer */ 621 /* int */ 622 ia->len = base10exp(e) + 2; 623 ia->val = mantissa << (e - 52); 624 /* frac - none */ 625 fa->len = 0; 626 fa->shift = 0; 627 fa->val = 0; 628 } 629 } 630 else if (e < 0) { /* -1023 to -9 - fraction */ 631 /* int - none */ 632 ia->numchunks = 0; 633 ia->len = 0; 634 ia->shift = 0; 635 ia->val = 0; 636 /* frac - left-justify on bit 31 of the chunk of the MSb */ 637 if (e >= -1022) { /* normal */ 638 mantissa |= 0x0010000000000000ull; 639 } 640 else { /* subnormal (including zero) */ 641 e = -1022; 642 } 643 644 if (mantissa) { 645 long fracbits = 52 - e; 646 fa->len = fracbits - __builtin_ctzll(mantissa); 647 fa->shift = 31 - ((51 - e) % 32); 648 fa->val = mantissa; 649 fa->basechunk = (fa->shift + 52) / 32; 650 fa->numchunks = (51 - e + fa->shift) / 32 + 1; 651 rc = fa->numchunks; 652 } 653 else { /* zero */ 654 fa->numchunks = 0; 655 fa->len = 0; 656 fa->shift = 0; 657 fa->val = 0; 658 } 659 } 660 else if (e <= 1023) { /* +64 to +1023 - integer */ 661 /* int - right-justify on bit 0 of the first chunk */ 662 ia->val = mantissa | 0x0010000000000000ull; 663 ia->len = base10exp(e) + 2; 664 ia->shift = (e - 52) % 32; 665 ia->basechunk = e / 32; 666 ia->numchunks = ia->basechunk + 1; 667 rc = ia->numchunks; 668 /* frac - none */ 669 fa->numchunks = 0; 670 fa->len = 0; 671 fa->shift = 0; 672 fa->val = 0; 673 } 674 else { /* +1024: INF, NAN */ 675 rc = -1 - !!mantissa; 676 } 677 678 return rc; 679} 680 681/* construct the arbitrary-precision value in the provided allocation */ 682static void init_ieee754_double_chunks(struct ap_int *a, 683 uint32_t *a_chunks) 684{ 685 long basechunk = a->basechunk; 686 long shift = a->shift; 687 uint64_t val = a->val; 688 689 a->chunks = a_chunks; 690 691 memset(a_chunks, 0, a->numchunks*sizeof (uint32_t)); 692 693 if (shift < 12) { 694 a_chunks[basechunk - 1] = val << shift; 695 a_chunks[basechunk - 0] = val >> (32 - shift); 696 } 697 else { 698 a_chunks[basechunk - 2] = val << shift; 699 a_chunks[basechunk - 1] = val >> (32 - shift); 700 a_chunks[basechunk - 0] = val >> (64 - shift); 701 } 702} 703 704/* format inf, nan strings */ 705static void format_inf_nan(struct fmt_buf *fmt_buf, long type) 706{ 707 /* certain special values */ 708 static const char text[2][2][3] = 709 { 710 { { 'I', 'N', 'F' }, { 'i', 'n', 'f' } }, 711 { { 'N', 'A', 'N' }, { 'n', 'a', 'n' } }, 712 }; 713 714 char *p = fmt_buf->buf; 715 fmt_buf->p = p; 716 fmt_buf->length = 3; 717 718 /* they also have a sign */ 719 if (fmt_buf->signchar) { 720 *p++ = fmt_buf->signchar; 721 fmt_buf->length++; 722 } 723 724 memcpy(p, &text[type][(fmt_buf->radixchar >> 5) & 0x1], 3); 725} 726 727/* %e %E %f %F %g %G */ 728static int format_double_radix(double f, 729 struct fmt_buf *fmt_buf, 730 vuprintf_push_cb push, 731 void *userp) 732{ 733 struct ap_int ia ={0}; 734 struct ap_int fa ={0}; 735 long rc = parse_double(f, &ia, &fa, fmt_buf); 736 737 if (UNLIKELY(rc < 0)) { 738 format_inf_nan(fmt_buf, -rc - 1); 739 return 0; 740 } 741 742 int count = 0; 743 744 /* default precision is 6 for all formats */ 745 int prec_rem = fmt_buf->precision < 0 ? 6 : fmt_buf->precision; 746 747 int exp = exp; 748 int explen = 0; 749 750 switch (fmt_buf->radixchar & 0x3) 751 { 752 case 3: /* %g, %G */ 753 fmt_buf->precision = prec_rem; 754 if (prec_rem) { 755 prec_rem--; 756 } 757 /* fallthrough */ 758 case 1: /* %e, %E */ 759 explen = 2; 760 break; 761 default: 762 break; 763 } 764 765 if (rc > 0 && ia.numchunks > 0) { 766 /* large integer required */ 767 init_double_chunks(&ia, alloca(rc*sizeof(*ia.chunks))); 768 rc = 0; 769 } 770 771 const int bufoffs = 6; /* log rollover + round rollover + leading zeros (%g) */ 772 long f_prec = MIN(fa.len, prec_rem + 1); 773 char buf[bufoffs + ia.len + f_prec + 1]; 774 char *p_last = &buf[bufoffs + ia.len]; 775 char *p_dec = p_last; 776 char *p_first = format_double_int10(&ia, p_last); 777 778 if (explen) { 779 if (!ia.val && fa.len) { 780 p_first = p_last = &buf[bufoffs]; 781 f_prec = -f_prec - 1; /* no lead zeros */ 782 } 783 else { /* handles 0e+0 too */ 784 exp = ia.len - 1; 785 786 if (exp) { 787 prec_rem -= exp; 788 789 if (prec_rem < 0) { 790 p_last += prec_rem + 1; 791 f_prec = 0; 792 } 793 else { 794 f_prec = MIN(fa.len, prec_rem + 1); 795 } 796 } 797 } 798 799 p_dec = p_first + 1; 800 } 801 802 if (f_prec) { 803 if (rc > 0) { 804 /* large integer required */ 805 init_double_chunks(&fa, alloca(rc*sizeof(*fa.chunks))); 806 } 807 808 p_last = format_double_frac10(&fa, p_last, f_prec); 809 810 if (f_prec < 0) { 811 f_prec = -f_prec - 1; 812 exp = f_prec - fa.len; 813 } 814 815 prec_rem -= f_prec; 816 } 817 818 if (prec_rem < 0) { 819 prec_rem = 0; 820 p_last--; 821 822 if (round_number_string10(p_last, p_last - p_first)) { 823 /* carried left */ 824 p_first--; 825 826 if (explen) { 827 /* slide everything left by 1 */ 828 exp++; 829 p_dec--; 830 p_last--; 831 } 832 } 833 } 834 835 if (explen) { 836 if ((fmt_buf->radixchar & 0x3) == 0x3) { /* g, G */ 837 /* 'g' is some weird crap */ 838 /* now that the final exponent is known and everything rounded, 839 it is possible to decide whether to format similarly to 840 'e' or 'f' */ 841 if (fmt_buf->precision > exp && exp >= -4) { /* P > X >= -4 */ 842 if (exp >= 0) { 843 /* integer digits will be in the buffer */ 844 p_dec = p_first + exp + 1; 845 } 846 else { 847 /* we didn't keep leading zeros and need to regenerate 848 them; space was reserved just in case */ 849 p_first = memset(p_dec + exp - 1, '0', -exp); 850 p_dec = p_first + 1; 851 } 852 853 /* suppress exponent */ 854 explen = 0; 855 } 856 857 if (!fmt_buf->length) { 858 /* strip any trailing zeros from the fraction */ 859 while (p_last > p_dec && p_last[-1] == '0') { 860 p_last--; 861 } 862 863 /* suppress trailing precision fill */ 864 prec_rem = 0; 865 } 866 } 867 868 if (explen) { 869 /* build exponent string: 'e±dd' */ 870 char *p = fmt_buf->bufend; 871 int signchar = '+'; 872 873 if (exp < 0) { 874 signchar = '-'; 875 exp = -exp; 876 } 877 878 while (exp || explen < 4) { 879 *--p = exp % 10 + '0'; 880 exp /= 10; 881 explen++; 882 } 883 884 *--p = signchar; 885 *--p = fmt_buf->radixchar & ~0x2; 886 } 887 } 888 889 int width = fmt_buf->width; 890 int point = p_last > p_dec || prec_rem || fmt_buf->length; 891 int length = p_last - p_first + !!fmt_buf->signchar + point + explen; 892 893 if (width) { 894 if (width - length <= prec_rem) { 895 width = 0; 896 } 897 else { 898 width -= length + prec_rem; 899 } 900 } 901 902 rc = -1; 903 904 /* left padding */ 905 if (fmt_buf->alignchar > '0') { 906 /* space-padded width -- before sign */ 907 while (width > 0) { 908 PUSHCHAR(' '); 909 width--; 910 } 911 } 912 913 if (fmt_buf->signchar) { 914 PUSHCHAR(fmt_buf->signchar); 915 } 916 917 if (fmt_buf->alignchar == '0') { 918 /* zero-padded width -- after sign */ 919 while (width > 0) { 920 PUSHCHAR('0'); 921 width--; 922 } 923 } 924 925 /* integer part */ 926 while (p_first < p_dec) { 927 PUSHCHAR(*p_first++); 928 } 929 930 /* decimal point */ 931 if (point) { 932 PUSHCHAR('.'); 933 } 934 935 /* fractional part */ 936 while (p_first < p_last) { 937 PUSHCHAR(*p_first++); 938 } 939 940 /* precision 0-padding */ 941 while (prec_rem > 0) { 942 PUSHCHAR('0'); 943 prec_rem--; 944 } 945 946 /* exponent */ 947 if (explen > 0) { 948 char *p = fmt_buf->bufend; 949 while (explen > 0) { 950 PUSHCHAR(p[-explen--]); 951 } 952 } 953 954 /* right padding */ 955 while (width > 0) { 956 PUSHCHAR(' '); 957 width--; 958 } 959 960 rc = 1; 961done: 962 fmt_buf->length = count; 963 return rc; 964} 965#endif /* FMT_RADIX_floats */ 966 967/* parse fixed width or precision field */ 968static const char * parse_number_spec(const char *fmt, 969 int ch, 970 int *out) 971{ 972 int i = ch - '0'; 973 974 while (1) { 975 ch = *fmt - '0'; 976 977 if (ch < 0 || ch > 9 || i > INT_MAX / 10 || 978 (i == INT_MAX / 10 && ch > INT_MAX % 10)) { 979 break; 980 } 981 982 i = i * 10 + ch; 983 fmt++; 984 } 985 986 *out = i; 987 return fmt; 988} 989 990int vuprintf(vuprintf_push_cb push, /* call 'push()' for each output letter */ 991 void *userp, 992 const char *fmt, 993 va_list ap) 994{ 995 int count = 0; 996 int ch; 997 998 /* macrofied identifiers share a variable with another */ 999 unsigned int val_d; 1000 unsigned int val_u; 1001 #ifndef val_ld 1002 unsigned long val_ld; 1003 #endif 1004 #ifndef val_lu 1005 unsigned long val_lu; 1006 #endif 1007 #ifndef val_lld 1008 unsigned long long val_lld; 1009 #endif 1010 #ifndef val_llu 1011 unsigned long long val_llu; 1012 #endif 1013 1014 struct fmt_buf fmt_buf; 1015 fmt_buf.bufend[0] = '0'; 1016 1017 while (1) { 1018 while (1) { 1019 if ((ch = *fmt++) == '\0') { 1020 goto done; 1021 } 1022 1023 if (ch == '%' && (ch = *fmt++) != '%') { 1024 break; 1025 } 1026 1027 PUSHCHAR(ch); 1028 } 1029 1030 /* set to defaults */ 1031 fmt_buf.fmt_start = fmt; 1032 1033 int signchar = 0; 1034 unsigned int width = 0; 1035 int lenmod = LENMOD_NONE; 1036 size_t length = 0; 1037 size_t pfxlen = 0; 1038 bool numeric = false; 1039 int alignchar = '0' + 1; 1040 int precision = -1; 1041 const char *buf = NULL; 1042 1043 /*** flags ***/ 1044 while (1) { 1045 switch (ch) 1046 { 1047 case ' ': /* <space> before non-negative value (signed conversion) */ 1048 case '+': /* '+' before non-negative value (signed conversion) */ 1049 /* '+' overrides ' ' */ 1050 if (ch > signchar) { 1051 signchar = ch; 1052 } 1053 break; 1054 case '-': /* left-justify in field */ 1055 case '0': /* zero-pad to fill field */ 1056 /* '-' overrides '0' */ 1057 if (ch < alignchar) { 1058 alignchar = ch; 1059 } 1060 break; 1061 case '#': /* number prefix (nonzero %o:'0' %x/%X:'0x') */ 1062 /* indicate; formatter updates with actual length */ 1063 pfxlen = 1; 1064 break; 1065 #if 0 1066 case '\'': /* digit grouping (non-monetary) */ 1067 break; 1068 #endif 1069 default: 1070 goto flags_done; 1071 } 1072 1073 ch = *fmt++; 1074 } 1075 flags_done: 1076 1077 /*** width ***/ 1078 if (ch == '*') { 1079 /* variable width */ 1080 int w = va_arg(ap, int); 1081 if (w < 0) { 1082 /* negative width is width with implied '-' */ 1083 width = (unsigned int)-(w + 1) + 1; 1084 alignchar = '-'; 1085 } 1086 else { 1087 width = w; 1088 } 1089 1090 ch = *fmt++; 1091 } 1092 else if (ch >= '1' && ch <= '9') { 1093 /* fixed width */ 1094 fmt = parse_number_spec(fmt, ch, &width); 1095 ch = *fmt++; 1096 } 1097 1098 /*** precision ***/ 1099 if (ch == '.') { 1100 ch = *fmt++; 1101 1102 if (ch == '*') { 1103 /* variable precision; negative precision is ignored */ 1104 precision = va_arg (ap, int); 1105 ch = *fmt++; 1106 } 1107 else if (ch >= '0' && ch <= '9') { 1108 /* fixed precision */ 1109 fmt = parse_number_spec(fmt, ch, &precision); 1110 ch = *fmt++; 1111 } 1112 } 1113 1114 /*** length modifier ***/ 1115 #if FMT_LENMOD 1116 switch (ch) 1117 { 1118 #if (FMT_LENMOD & (FMT_LENMOD_h | FMT_LENMOD_hh)) 1119 case 'h': 1120 #endif 1121 #if (FMT_LENMOD & FMT_LENMOD_j) 1122 case 'j': 1123 #endif 1124 #if (FMT_LENMOD & (FMT_LENMOD_l | FMT_LENMOD_ll)) 1125 case 'l': 1126 #endif 1127 #if (FMT_LENMOD & FMT_LENMOD_t) 1128 case 't': 1129 #endif 1130 #if (FMT_LENMOD & FMT_LENMOD_z) 1131 case 'z': 1132 #endif 1133 #if (FMT_LENMOD & FMT_LENMOD_L) 1134 case 'L': 1135 #endif 1136 lenmod = ch; 1137 ch = *fmt++; 1138 #if (FMT_LENMOD & (FMT_LENMOD_hh | FMT_LENMOD_ll)) 1139 /* doesn't matter if jj, tt or zz happen; they will be rejected 1140 by the radix handler */ 1141 if (ch == lenmod) { 1142 lenmod = LENMOD2(lenmod, ch); 1143 ch = *fmt++; 1144 } 1145 #endif 1146 } 1147 #endif /* FMT_LENMOD */ 1148 1149 /*** radix ***/ 1150 switch (ch) 1151 { 1152 /** non-numeric **/ 1153 case 'c': 1154 buf = format_c(va_arg(ap, int), &fmt_buf, lenmod); 1155 break; 1156 #if (FMT_RADIX & FMT_RADIX_n) 1157 case 'n': 1158 if (format_n(va_arg(ap, void *), count, lenmod)) { 1159 continue; /* no output */ 1160 } 1161 break; 1162 #endif 1163 case 's': 1164 buf = format_s(va_arg(ap, const void *), &fmt_buf, 1165 precision, lenmod); 1166 break; 1167 1168 /** non-integer **/ 1169 #if (FMT_RADIX & FMT_RADIX_p) 1170 case 'p': 1171 case 'P': 1172 buf = format_p(va_arg(ap, void *), &fmt_buf, ch, 1173 &numeric); 1174 break; 1175 #endif 1176 1177 #if (FMT_RADIX & FMT_RADIX_floats) 1178 /* any floats gets all of them (except with 'L' and %a, %A for now) */ 1179 case 'e': 1180 case 'E': 1181 case 'f': 1182 case 'F': 1183 case 'g': 1184 case 'G': 1185 /* LENMOD_L isn't supported for now and will be rejected automatically */ 1186 1187 /* floating point has very different spec interpretations to other 1188 formats and requires special handling */ 1189 fmt_buf.length = pfxlen; 1190 fmt_buf.lenmod = lenmod; 1191 fmt_buf.radixchar = ch; 1192 fmt_buf.signchar = signchar; 1193 fmt_buf.alignchar = alignchar; 1194 fmt_buf.width = width; 1195 fmt_buf.precision = precision; 1196 1197 ch = format_double_radix(va_arg(ap, double), &fmt_buf, push, userp); 1198 if (ch) { 1199 count += fmt_buf.length; 1200 if (ch > 0) { 1201 continue; 1202 } 1203 1204 goto done; 1205 } 1206 1207 buf = fmt_buf.p; 1208 break; 1209 #endif 1210 1211 /** signed integer **/ 1212 case 'd': 1213 case 'i': 1214 fmt_buf.length = pfxlen; 1215 1216 switch (lenmod) 1217 { 1218 case LENMOD_NONE: 1219 val_d = va_arg(ap, signed int); 1220 goto branch_fmt_d; 1221 #if (FMT_LENMOD & FMT_LENMOD_h) 1222 case LENMOD_h: 1223 val_d = (signed short)va_arg(ap, SSHRT_INT_ARG); 1224 goto branch_fmt_d; 1225 #endif 1226 #if (FMT_LENMOD & FMT_LENMOD_hh) 1227 case LENMOD_hh: 1228 val_d = (signed char)va_arg(ap, SCHAR_INT_ARG); 1229 goto branch_fmt_d; 1230 #endif 1231 #if (FMT_LENMOD & FMT_LENMOD_j) 1232 case LENMOD_j: 1233 LENMOD_INTCOMPAT_BRANCH(LENMOD_INTCOMPAT_SEL(intmax_t, true), 1234 va_arg(ap, intmax_t), true); 1235 #endif 1236 #if (FMT_LENMOD & FMT_LENMOD_l) 1237 case LENMOD_l: 1238 val_ld = va_arg(ap, signed long); 1239 goto branch_fmt_ld; 1240 #endif 1241 #if (FMT_LENMOD & FMT_LENMOD_ll) 1242 case LENMOD_ll: 1243 val_lld = va_arg(ap, signed long long); 1244 goto branch_fmt_lld; 1245 #endif 1246 #if (FMT_LENMOD & FMT_LENMOD_t) 1247 case LENMOD_t: 1248 LENMOD_INTCOMPAT_BRANCH(LENMOD_INTCOMPAT_SEL(ptrdiff_t, true), 1249 va_arg(ap, ptrdiff_t), true); 1250 #endif 1251 #if (FMT_LENMOD & FMT_LENMOD_z) 1252 case LENMOD_z: 1253 LENMOD_INTCOMPAT_BRANCH(LENMOD_INTCOMPAT_SEL(ssize_t, true), 1254 va_arg(ap, ssize_t), true); 1255 #endif 1256 } 1257 1258 /* macrofied labels share a formatter with another */ 1259 if (0) { 1260 branch_fmt_d: 1261 buf = format_d(val_d, &fmt_buf, signchar); 1262 } else if (0) { 1263 #ifndef val_ld 1264 branch_fmt_ld: 1265 buf = format_ld(val_ld, &fmt_buf, signchar); 1266 #endif 1267 } else if (0) { 1268 #ifndef val_lld 1269 branch_fmt_lld: 1270 buf = format_lld(val_lld, &fmt_buf, signchar); 1271 #endif 1272 } 1273 1274 numeric = true; 1275 break; 1276 1277 /** unsigned integer **/ 1278 #if (FMT_RADIX & FMT_RADIX_o) 1279 case 'o': 1280 #endif 1281 case 'u': 1282 #if (FMT_RADIX & FMT_RADIX_x) 1283 case 'x': 1284 case 'X': 1285 #endif 1286 fmt_buf.length = pfxlen; 1287 1288 switch (lenmod) 1289 { 1290 case LENMOD_NONE: 1291 val_u = va_arg(ap, unsigned int); 1292 goto branch_fmt_u; 1293 #if (FMT_LENMOD & FMT_LENMOD_h) 1294 case LENMOD_h: 1295 val_u = (unsigned short)va_arg(ap, USHRT_INT_ARG); 1296 goto branch_fmt_u; 1297 #endif 1298 #if (FMT_LENMOD & FMT_LENMOD_hh) 1299 case LENMOD_hh: 1300 val_u = (unsigned char)va_arg(ap, UCHAR_INT_ARG); 1301 goto branch_fmt_u; 1302 #endif 1303 #if (FMT_LENMOD & FMT_LENMOD_j) 1304 case LENMOD_j: 1305 LENMOD_INTCOMPAT_BRANCH(LENMOD_INTCOMPAT_SEL(uintmax_t, false), 1306 va_arg(ap, uintmax_t), false); 1307 #endif 1308 #if (FMT_LENMOD & FMT_LENMOD_l) 1309 case LENMOD_l: 1310 val_lu = va_arg(ap, unsigned long); 1311 goto branch_fmt_lu; 1312 #endif 1313 #if (FMT_LENMOD & FMT_LENMOD_ll) 1314 case LENMOD_ll: 1315 val_llu = va_arg(ap, unsigned long long); 1316 goto branch_fmt_llu; 1317 #endif 1318 #if (FMT_LENMOD & (FMT_LENMOD_t | FMT_LENMOD_z)) 1319 /* format "uptrdiff_t" as size_t (unless it becomes standard) */ 1320 #if (FMT_LENMOD & FMT_LENMOD_t) 1321 case LENMOD_t: 1322 #endif 1323 #if (FMT_LENMOD & FMT_LENMOD_z) 1324 case LENMOD_z: 1325 #endif 1326 LENMOD_INTCOMPAT_BRANCH(LENMOD_INTCOMPAT_SEL(size_t, false), 1327 va_arg(ap, size_t), false); 1328 #endif 1329 } 1330 1331 /* macrofied labels share a formatter with another */ 1332 if (0) { 1333 branch_fmt_u: 1334 buf = format_u(val_u, &fmt_buf, ch); 1335 } else if (0) { 1336 #ifndef val_lu 1337 branch_fmt_lu: 1338 buf = format_lu(val_lu, &fmt_buf, ch); 1339 #endif 1340 } else if (0) { 1341 #ifndef val_llu 1342 branch_fmt_llu: 1343 buf = format_llu(val_llu, &fmt_buf, ch); 1344 #endif 1345 } 1346 1347 numeric = true; 1348 break; 1349 } 1350 1351 if (buf) { 1352 /** padding **/ 1353 if (numeric) { 1354 /* numeric formats into fmt_buf.buf */ 1355 pfxlen = fmt_buf.length; 1356 length = fmt_buf.bufend - buf; 1357 1358 size_t size = pfxlen + length; 1359 1360 if (precision >= 0) { 1361 /* explicit precision */ 1362 precision -= (int)length; 1363 1364 if (precision > 0) { 1365 size += precision; 1366 } 1367 1368 width -= MIN(width, size); 1369 } 1370 else { 1371 /* default precision */ 1372 if (!length) { 1373 length = 1; 1374 size++; 1375 } 1376 1377 width -= MIN(width, size); 1378 1379 if (alignchar == '0') { 1380 /* width zero-fill */ 1381 precision = width; 1382 width = 0; 1383 } 1384 } 1385 } 1386 else { 1387 /* non-numeric: supress prefix and precision; keep length and 1388 width */ 1389 pfxlen = 0; 1390 precision = 0; 1391 length = fmt_buf.length; 1392 width -= MIN(width, length); 1393 } 1394 } 1395 else { 1396 /* format not accepted; print it literally */ 1397 buf = fmt_buf.fmt_start - 2; 1398 length = fmt - buf; 1399 width = 0; 1400 pfxlen = 0; 1401 precision = 0; 1402 } 1403 1404 /** push all the stuff **/ 1405 1406 if (alignchar != '-') { 1407 /* left padding */ 1408 while (width > 0) { 1409 PUSHCHAR(' '); 1410 width--; 1411 } 1412 } 1413 1414 /* prefix */ 1415 while (pfxlen > 0) { 1416 PUSHCHAR(buf[-pfxlen]); 1417 pfxlen--; 1418 } 1419 1420 /* 0-padding */ 1421 while (precision > 0) { 1422 PUSHCHAR('0'); 1423 precision--; 1424 } 1425 1426 /* field */ 1427 while (length > 0) { 1428 PUSHCHAR(*buf++); 1429 length--; 1430 } 1431 1432 /* right padding */ 1433 while (width > 0) { 1434 PUSHCHAR(' '); 1435 width--; 1436 } 1437 } 1438 1439done: 1440 return count; 1441}