X-Git-Url: https://git.saurik.com/apple/libplatform.git/blobdiff_plain/e45b469263efe5fed40a01d25b2ace7e42243579..refs/heads/master:/src/simple/string_io.c diff --git a/src/simple/string_io.c b/src/simple/string_io.c index 4bffac6..2f7a225 100644 --- a/src/simple/string_io.c +++ b/src/simple/string_io.c @@ -147,6 +147,41 @@ put_n(BUF *b, _esc_func esc, const char *str, ssize_t n) put_c(b, esc, *str++); } +#if __LP64__ || defined(__arm64__) +static unsigned long long +udiv10(unsigned long long a, unsigned long long *rem) +{ + *rem = a % 10; + return a / 10; +} +#else +unsigned long long +udiv10(unsigned long long a, unsigned long long *rem_out) +{ + if (a <= UINT_MAX) { + *rem_out = (unsigned long long)((unsigned int)a % 10); + return (unsigned long long)((unsigned int)a / 10); + } + + // The biggest multiple of 10 that dividend might contain + unsigned long long divisor = 0xa000000000000000; + unsigned long long dividend = a; + unsigned long long quotient = 0; + + while (divisor >= 0xa) { + quotient = quotient << 1; + if (dividend >= divisor) { + dividend -= divisor; + quotient += 1; + } + divisor = divisor >> 1; + } + + *rem_out = dividend; + return quotient; +} +#endif + /* * Output the signed decimal string representing the number in "in". "width" is * the minimum field width, and "zero" is a boolean value, true for zero padding @@ -160,6 +195,7 @@ dec(BUF *b, _esc_func esc, long long in, int width, int zero) ssize_t pad; int neg = 0; unsigned long long n = (unsigned long long)in; + unsigned long long rem; if(in < 0) { neg++; @@ -169,8 +205,8 @@ dec(BUF *b, _esc_func esc, long long in, int width, int zero) *--cp = 0; if(n) { while(n) { - *--cp = (n % 10) + '0'; - n /= 10; + n = udiv10(n, &rem); + *--cp = rem + '0'; } } else *--cp = '0'; @@ -187,6 +223,35 @@ dec(BUF *b, _esc_func esc, long long in, int width, int zero) put_s(b, esc, cp); } +/* + * Output the octal string representing the number in "n". "width" is + * the minimum field width, and "zero" is a boolean value, true for zero padding + * (otherwise blank padding). + */ +static void +oct(BUF *b, _esc_func esc, unsigned long long n, int width, int zero) +{ + char buf[32]; + char *cp = buf + sizeof(buf); + ssize_t pad; + + *--cp = 0; + if (n) { + while (n) { + *--cp = (n % 8) + '0'; + n /= 8; + } + } else { + *--cp = '0'; + } + pad = width - strlen(cp); + zero = zero ? '0' : ' '; + while (pad-- > 0) { + put_c(b, esc, zero); + } + put_s(b, esc, cp); +} + /* * Output the hex string representing the number in "n". "width" is the * minimum field width, and "zero" is a boolean value, true for zero padding @@ -239,13 +304,14 @@ udec(BUF *b, _esc_func esc, unsigned long long n, int width, int zero) { char buf[32]; char *cp = buf + sizeof(buf); + unsigned long long rem; ssize_t pad; *--cp = 0; if(n) { while(n) { - *--cp = (n % 10) + '0'; - n /= 10; + n = udiv10(n, &rem); + *--cp = rem + '0'; } } else *--cp = '0'; @@ -334,6 +400,19 @@ __simple_bprintf(BUF *b, _esc_func esc, const char *fmt, va_list ap) lflag++; fmt++; continue; + case 'o': + switch (lflag) { + case 0: + oct(b, esc, va_arg(ap, int), width, zero); + break; + case 1: + oct(b, esc, va_arg(ap, long), width, zero); + break; + default: + oct(b, esc, va_arg(ap, long long), width, zero); + break; + } + break; case 'p': hex(b, esc, (unsigned long)va_arg(ap, void *), width, zero, 0, 1); break;