]> git.saurik.com Git - apple/libplatform.git/blobdiff - src/simple/string_io.c
libplatform-254.40.4.tar.gz
[apple/libplatform.git] / src / simple / string_io.c
index 4bffac6755060e0e3fa720c41e2c4595884dac46..2f7a22523d3ec41bdaa08ebf18f76dc5b5627cea 100644 (file)
@@ -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;